[Cryptech-Commits] [sw/stm32] 08/09: Add FPGA bitstream upload command to cli-test.

git at cryptech.is git at cryptech.is
Wed May 18 19:16:19 UTC 2016


This is an automated email from the git hooks/post-receive script.

fredrik at thulin.net pushed a commit to branch master
in repository sw/stm32.

commit 523d1f66453e9b92835ecc661085e4575426e661
Author: Fredrik Thulin <fredrik at thulin.net>
AuthorDate: Wed May 18 21:14:52 2016 +0200

    Add FPGA bitstream upload command to cli-test.
    
    This code needs more error checking etc. but together with the Python
    script 'filetransfer', a new bitstream may be loaded into the FPGA
    config memory like this:
    
    filetransfer --fpga /path/to/bitstream
    
    The bitstream is identified by 'file' e.g. like this:
    
    alpha_test_top.bit: Xilinx BIT data - from
    alpha_test_top.ncd;UserID=0xFFFFFFFF - for 7a200tfbg484 - built
    2016/05/12(13:59:24) - data length 0xe0164
---
 .../TARGET_CRYPTECH_ALPHA/stm32f4xx_hal_msp.c      |   2 +-
 projects/cli-test/cli-test.c                       |  92 ++++++++++++++-
 projects/cli-test/filetransfer                     | 126 ++++++++++++++++-----
 stm-fpgacfg.c                                      |  17 +++
 stm-fpgacfg.h                                      |   3 +
 stm-init.c                                         |  12 +-
 6 files changed, 219 insertions(+), 33 deletions(-)

diff --git a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_hal_msp.c b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_hal_msp.c
index c6a8a67..d0f814e 100644
--- a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_hal_msp.c
+++ b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_hal_msp.c
@@ -216,7 +216,7 @@ void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
     GPIO_InitTypeDef GPIO_InitStruct;
     if (hspi->Instance == SPI2) {
 	/* Peripheral clock enable */
-	__HAL_RCC_SPI2_CLK_ENABLE();
+	__SPI2_CLK_ENABLE();
 
 	/* SPI2 is the FPGA config memory.
 	 *
diff --git a/projects/cli-test/cli-test.c b/projects/cli-test/cli-test.c
index 6102d32..922fcba 100644
--- a/projects/cli-test/cli-test.c
+++ b/projects/cli-test/cli-test.c
@@ -35,6 +35,7 @@
 #include "stm-init.h"
 #include "stm-led.h"
 #include "stm-uart.h"
+#include "stm-fpgacfg.h"
 #include "mgmt-cli.h"
 
 #include <string.h>
@@ -56,15 +57,65 @@ int cmd_show_cpuspeed(struct cli_def *cli, const char *command, char *argv[], in
 
 int cmd_filetransfer(struct cli_def *cli, const char *command, char *argv[], int argc)
 {
+    uint32_t filesize = 0, crc = 0, my_crc = 0, n = 256, counter = 0;
+    uint8_t buf[256];
+
+    cli_print(cli, "OK, write file size (4 bytes), data in %li byte chunks, CRC-32 (4 bytes)", n);
+
+    uart_receive_bytes(STM_UART_MGMT, (void *) &filesize, 4, 1000);
+    cli_print(cli, "File size %li", filesize);
+
+    while (filesize) {
+	if (filesize < n) {
+	    n = filesize;
+	}
+
+	if (uart_receive_bytes(STM_UART_MGMT, (void *) &buf, n, 1000) != HAL_OK) {
+	    cli_print(cli, "Receive timed out");
+	    return CLI_ERROR;
+	}
+	filesize -= n;
+	my_crc = update_crc(my_crc, buf, n);
+	counter++;
+	uart_send_bytes(STM_UART_MGMT, (void *) &counter, 4);
+    }
+
+    cli_print(cli, "Send CRC-32");
+    uart_receive_bytes(STM_UART_MGMT, (void *) &crc, 4, 1000);
+    cli_print(cli, "CRC-32 %li", crc);
+    if (crc == my_crc) {
+	cli_print(cli, "CRC checksum MATCHED");
+    } else {
+	cli_print(cli, "CRC checksum did NOT match");
+    }
+
+    return CLI_OK;
+}
+
+int cmd_fpga_bitstream_upload(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
     uint32_t filesize = 0, crc = 0, my_crc = 0, n = 4096, counter = 0;
     uint8_t buf[4096];
 
-    cli_print(cli, "OK, write file size (4 bytes), data in 4096 byte chunks, CRC-32 (4 bytes)");
+    fpgacfg_give_access_to_stm32();
+
+    cli_print(cli, "Checking if FPGA config memory is accessible");
+    if (n25q128_check_id() != 1) {
+	cli_print(cli, "ERROR: FPGA config memory not accessible. Check that jumpers JP7 and JP8 are installed.");
+	return CLI_ERROR;
+    }
+
+    cli_print(cli, "OK, write FPGA bitstream file size (4 bytes), data in 4096 byte chunks, CRC-32 (4 bytes)");
 
     uart_receive_bytes(STM_UART_MGMT, (void *) &filesize, 4, 1000);
     cli_print(cli, "File size %li", filesize);
 
     while (filesize) {
+	uint32_t page, offset;
+	uint8_t *ptr;
+
+	memset(buf, 0xff, 4096);
+
 	if (filesize < n) {
 	    n = filesize;
 	}
@@ -75,6 +126,33 @@ int cmd_filetransfer(struct cli_def *cli, const char *command, char *argv[], int
 	}
 	filesize -= n;
 	my_crc = update_crc(my_crc, buf, n);
+
+	if ((counter % (N25Q128_SECTOR_SIZE / 4096)) == 0) {
+	    /* first page in sector, need to erase sector */
+	    offset = (counter * 4096) / N25Q128_SECTOR_SIZE;
+	    if (! n25q128_erase_sector(offset)) {
+		cli_print(cli, "Failed erasing sector at offset %li (counter = %li)", offset, counter);
+		return CLI_ERROR;
+	    }
+	    /* XXX add timeout and check for < 0 */
+	    while (n25q128_get_wip_flag()) { HAL_Delay(10); };
+	}
+
+	ptr = buf;
+	for (page = 0; page < 4096 / N25Q128_PAGE_SIZE; page++) {
+	    offset = counter * (4096 / N25Q128_PAGE_SIZE) + page;
+	    if (! n25q128_write_page(offset, ptr)) {
+		cli_print(cli, "Failed writing page %li at offset %li (counter = %li)", page, offset, counter);
+		return CLI_ERROR;
+	    }
+	    ptr += N25Q128_PAGE_SIZE;
+
+	    /* XXX add timeout and check for < 0 */
+	    while (n25q128_get_wip_flag()) { HAL_Delay(10); };
+
+	    /* XXX read back data and verify it */
+	}
+
 	counter++;
 	uart_send_bytes(STM_UART_MGMT, (void *) &counter, 4);
     }
@@ -88,6 +166,8 @@ int cmd_filetransfer(struct cli_def *cli, const char *command, char *argv[], int
 	cli_print(cli, "CRC checksum did NOT match");
     }
 
+    fpgacfg_give_access_to_fpga();
+
     return CLI_OK;
 }
 
@@ -119,6 +199,12 @@ main()
     struct cli_command cmd_filetransfer_s = {(char *) "filetransfer", cmd_filetransfer, 0,
                                              (char *) "Test file transfering",
                                              PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL, NULL, NULL};
+
+    struct cli_command cmd_fpga_s = {(char *) "fpga", NULL, 0, NULL, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL, NULL, NULL};
+    struct cli_command cmd_fpga_bitstream_s = {(char *) "bitstream", NULL, 0, NULL, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL, NULL, NULL};
+    struct cli_command cmd_fpga_bitstream_upload_s = {(char *) "upload", cmd_fpga_bitstream_upload, 0,
+						      (char *) "Upload new FPGA bitstream",
+						      PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL, NULL, NULL};
     struct cli_command cmd_reboot_s = {(char *) "reboot", cmd_reboot, 0,
 				       (char *) "Reboot the STM32",
 				       PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL, NULL, NULL};
@@ -136,6 +222,10 @@ main()
 
     cli_register_command2(&cli, &cmd_filetransfer_s, NULL);
 
+    cli_register_command2(&cli, &cmd_fpga_s, NULL);
+    cli_register_command2(&cli, &cmd_fpga_bitstream_s, &cmd_fpga_s);
+    cli_register_command2(&cli, &cmd_fpga_bitstream_upload_s, &cmd_fpga_bitstream_s);
+
     cli_register_command2(&cli, &cmd_reboot_s, NULL);
 
     led_off(LED_RED);
diff --git a/projects/cli-test/filetransfer b/projects/cli-test/filetransfer
index 674a7f1..2b74570 100755
--- a/projects/cli-test/filetransfer
+++ b/projects/cli-test/filetransfer
@@ -1,13 +1,74 @@
 #!/usr/bin/python
-
+#
+# Copyright (c) 2016, NORDUnet A/S All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+# - Redistributions of source code must retain the above copyright notice,
+#   this list of conditions and the following disclaimer.
+#
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+#
+# - Neither the name of the NORDUnet nor the names of its contributors may
+#   be used to endorse or promote products derived from this software
+#   without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""
+Utility to test file upload (or FPGA bitstream upload.
+"""
 import os
 import sys
 import time
 import struct
 import serial
+import argparse
 
 from binascii import crc32
 
+CHUNK_SIZE = 256
+FPGA_CHUNK_SIZE = 4096
+
+
+def parse_args():
+    """
+    Parse the command line arguments
+    """
+    parser = argparse.ArgumentParser(description = "File uploader",
+                                     add_help = True,
+                                     formatter_class = argparse.ArgumentDefaultsHelpFormatter,
+                                     )
+
+    parser.add_argument('--fpga',
+                        dest='fpga',
+                        action='store_true', default=False,
+                        help='Perform FPGA bitstream upload',
+                        )
+
+    parser.add_argument('--device',
+                        dest='device',
+                        default='/dev/ttyUSB0',
+                        help='Name of management port USB serial device',
+                        )
+
+    # positional argument(s)
+    parser.add_argument('filename')
+
+    return parser.parse_args()
+
 
 def _write(dst, data):
     for i in range(len(data)):
@@ -46,41 +107,45 @@ def _execute(dst, cmd):
     response = _read(dst)
     return response
 
-def send_file(filename, device='/dev/ttyUSB0', initiate=True):
+def send_file(filename, args, dst):
     s = os.stat(filename)
     size = s.st_size
     src = open(filename, 'rb')
-
-    dst = serial.Serial(device, 921600, timeout=0.1)
-
-    if initiate:
+    if args.fpga:
+        # Skip header in FPGA bitstream file
+        size -= 0x64
+        src.read(0x64)
+        chunk_size = FPGA_CHUNK_SIZE
+        response = _execute(dst, 'fpga bitstream upload')
+    else:
+        chunk_size = CHUNK_SIZE
         response = _execute(dst, 'filetransfer')
-        if 'OK' not in response:
-            sys.stderr.write('Device did not accept the filetransfer command (got {!r})\n'.format(response))
-            return False
+    if 'OK' not in response:
+        sys.stderr.write('Device did not accept the upload command (got {!r})\n'.format(response))
+        return False
 
+    crc = 0
+    counter = 0
     # 1. Write size of file (4 bytes)
     _write(dst, struct.pack('<I', size))
     _read(dst)
     # 2. Write file contents while calculating CRC-32
-    crc = 0
-    counter = 0
     while True:
-        data = src.read(4096)
+        data = src.read(chunk_size)
         if not data:
             break
         dst.write(data)
-        print("Wrote {!s} bytes".format(len(data)))
+        print("Wrote {!s} bytes (chunk {!s}/{!s})".format(len(data), counter, int(size / chunk_size)))
         # read ACK (a counter of number of 4k chunks received)
         while True:
-            ack = dst.read(4)
-            if len(ack) == 4:
+            ack_bytes = dst.read(4)
+            if len(ack_bytes) == 4:
                 break
-            print('ERROR: Did not receive an ACK, got {!r}'.format(ack))
-            dst.write('\r')
-        new_counter = struct.unpack('<I', ack)[0]
-        if new_counter != counter + 1:
-            print('ERROR: Did not receive the expected counter as ACK (got {!r}/{!r}, not {!r})'.format(new_counter, ack, counter))
+            print('ERROR: Did not receive an ACK, got {!r}'.format(ack_bytes))
+            dst.write('\r')  # eventually get back to the CLI prompt
+        ack = struct.unpack('<I', ack_bytes)[0]
+        if ack != counter + 1:
+            print('ERROR: Did not receive the expected counter as ACK (got {!r}/{!r}, not {!r})'.format(ack, ack_bytes, counter))
             flush = dst.read(100)
             print('FLUSH data: {!r}'.format(flush))
             return False
@@ -95,16 +160,21 @@ def send_file(filename, device='/dev/ttyUSB0', initiate=True):
     _read(dst)
 
     src.close()
-    dst.close()
     return True
 
 
-if len(sys.argv) != 2:
-    sys.stderr.write('Syntax: {!s} filename\n'.format(sys.argv[0]))
-    sys.exit(1)
-
-if send_file(sys.argv[1]):
-    sys.exit(0)
+def main(args):
+    dst = serial.Serial(args.device, 921600, timeout=2)
+    send_file(args.filename, args, dst)
+    dst.close()
+    return True
 
-sys.exit(1)
+if __name__ == '__main__':
+    try:
+        args = parse_args()
+        if main(args):
+            sys.exit(0)
+        sys.exit(1)
+    except KeyboardInterrupt:
+        pass
 
diff --git a/stm-fpgacfg.c b/stm-fpgacfg.c
index 0026b9e..0d255e5 100644
--- a/stm-fpgacfg.c
+++ b/stm-fpgacfg.c
@@ -34,6 +34,7 @@
 
 #include "stm32f4xx_hal.h"
 #include "stm-fpgacfg.h"
+#include "stm-init.h"
 
 SPI_HandleTypeDef hspi_fpgacfg;
 
@@ -277,3 +278,19 @@ int _n25q128_get_wel_flag(void)
     // done
     return ((spi_rx[1] >> 1) & 1);
 }
+
+void fpgacfg_give_access_to_stm32()
+{
+    // fpga disable = 1
+    HAL_GPIO_WritePin(GPIOI, GPIO_PIN_14, GPIO_PIN_SET);
+    // arm enable = 0
+    HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6, GPIO_PIN_RESET);
+}
+
+void fpgacfg_give_access_to_fpga()
+{
+    // fpga disable = 0
+    HAL_GPIO_WritePin(GPIOI, GPIO_PIN_14, GPIO_PIN_RESET);
+    // arm enable = 1
+    HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6, GPIO_PIN_SET);
+}
diff --git a/stm-fpgacfg.h b/stm-fpgacfg.h
index bed3b38..fa5c4ef 100644
--- a/stm-fpgacfg.h
+++ b/stm-fpgacfg.h
@@ -75,6 +75,9 @@ extern int n25q128_read_page(uint32_t page_offset, uint8_t *page_buffer);
 extern int n25q128_write_page(uint32_t page_offset, uint8_t *page_buffer);
 extern int n25q128_erase_sector(uint32_t sector_offset);
 
+extern void fpgacfg_give_access_to_stm32(void);
+extern void fpgacfg_give_access_to_fpga(void);
+
 extern SPI_HandleTypeDef hspi_fpgacfg;
 
 #endif /* __STM32_FPGACFG_H */
diff --git a/stm-init.c b/stm-init.c
index 4421b21..9b86a30 100644
--- a/stm-init.c
+++ b/stm-init.c
@@ -81,6 +81,12 @@ void stm_init(void)
   /* Initialize all configured peripherals */
 #ifdef HAL_GPIO_MODULE_ENABLED
   MX_GPIO_Init();
+  #ifdef HAL_SPI_MODULE_ENABLED
+  /* Give the FPGA access to it's bitstream ASAP (maybe this should actually
+   * be done in the application, before calling stm_init()).
+   */
+  fpgacfg_give_access_to_fpga();
+  #endif
 #endif
 #ifdef HAL_UART_MODULE_ENABLED
   MX_USART1_UART_Init();
@@ -161,9 +167,9 @@ static void MX_GPIO_Init(void)
   /* Set up GPIOs to manage access to the FPGA config memory. */
 
   /* GPIO Ports Clock Enable */
-  __HAL_RCC_GPIOI_CLK_ENABLE();
-  __HAL_RCC_GPIOF_CLK_ENABLE();
-  __HAL_RCC_GPIOB_CLK_ENABLE();
+  __GPIOI_CLK_ENABLE();
+  __GPIOF_CLK_ENABLE();
+  __GPIOB_CLK_ENABLE();
 
   /*Configure GPIO pin Output Level */
   HAL_GPIO_WritePin(PROM_FPGA_DIS_GPIO_Port, PROM_FPGA_DIS_Pin, GPIO_PIN_RESET);



More information about the Commits mailing list