[Cryptech-Commits] [sw/stm32] 02/02: This time for sure - async receive, and everything that flows from that.

git at cryptech.is git at cryptech.is
Sun Apr 24 17:13:43 UTC 2016


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

paul at psgd.org pushed a commit to branch rtos
in repository sw/stm32.

commit e2e066e137465343cb5143a045196a3e5bddc47f
Author: Paul Selkirk <paul at psgd.org>
AuthorDate: Sun Apr 24 13:05:40 2016 -0400

    This time for sure - async receive, and everything that flows from that.
---
 .../TARGET_CRYPTECH_DEV_BRIDGE/stm32f4xx_hal_msp.c |   6 +-
 projects/hsm/Makefile                              |   2 -
 projects/hsm/main.c                                | 197 +++++++++++++++++----
 stm-init.c                                         |   2 -
 stm-uart.h                                         |   2 +
 5 files changed, 174 insertions(+), 35 deletions(-)

diff --git a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_DEV_BRIDGE/stm32f4xx_hal_msp.c b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_DEV_BRIDGE/stm32f4xx_hal_msp.c
index 85ecb32..e4446be 100644
--- a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_DEV_BRIDGE/stm32f4xx_hal_msp.c
+++ b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_DEV_BRIDGE/stm32f4xx_hal_msp.c
@@ -126,8 +126,10 @@ void HAL_UART_MspInit(UART_HandleTypeDef* huart)
     GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
     GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
-  }
 
+    HAL_NVIC_SetPriority(USART2_IRQn, 0, 1);
+    HAL_NVIC_EnableIRQ(USART2_IRQn);
+  }
 }
 
 void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
@@ -141,6 +143,8 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
        PA3     ------> USART2_RX
     */
     HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2 | GPIO_PIN_3);
+
+    HAL_NVIC_DisableIRQ(USART2_IRQn);
   }
 }
 
diff --git a/projects/hsm/Makefile b/projects/hsm/Makefile
index b933653..a7b0e82 100644
--- a/projects/hsm/Makefile
+++ b/projects/hsm/Makefile
@@ -14,7 +14,6 @@ $(PROJ).elf: $(OBJS) $(BOARD_OBJS) $(LIBS)
 	$(CC) $(CFLAGS) $^ -o $@ -T$(LDSCRIPT) -g -Wl,-Map=$(PROJ).map
 	$(OBJCOPY) -O ihex $(PROJ).elf $(PROJ).hex
 	$(OBJCOPY) -O binary $(PROJ).elf $(PROJ).bin
-	$(OBJDUMP) -St $(PROJ).elf >$(PROJ).lst
 	$(SIZE) $(PROJ).elf
 
 clean:
@@ -23,4 +22,3 @@ clean:
 	rm -f *.hex
 	rm -f *.bin
 	rm -f *.map
-	rm -f *.lst
diff --git a/projects/hsm/main.c b/projects/hsm/main.c
index 6c3d2e3..95483ee 100644
--- a/projects/hsm/main.c
+++ b/projects/hsm/main.c
@@ -32,6 +32,19 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+/*
+ * This is the main RPC server moddule. It creates a new thread to deal
+ * with each request, to prevent a long-running request (e.g. RSA keygen)
+ * from blocking independent requests from other clients. This has a
+ * number of consequences. We can't do a blocking receive in the main
+ * thread, because that prevents the dispatch thread from transmitting the
+ * response (because they both want to lock the UART - see
+ * stm32f4xx_hal_uart.c). So we have to do a non-blocking receive with a
+ * callback routine. But we can't create a thread from the callback
+ * routine, because it's in the context of an ISR, so we raise a semaphore
+ * for the main thread to create the dispatch thread.
+ */
+
 #include "cmsis_os.h"
 
 #include "stm-init.h"
@@ -43,88 +56,212 @@
 #define HAL_OK HAL_OKAY
 
 #include "hal.h"
+#include "hal_internal.h"	/* hal_rpc_sendto, hal_rpc_recvfrom */
+#include "xdr_internal.h"	/* hal_xdr_encode_int */
+
+/* RPC buffers. For each active RPC, there will be two - input and output.
+ */
 
-/* declared in hal_internal.h */
-extern hal_error_t hal_rpc_sendto(const uint8_t * const buf, const size_t len, void *opaque);
-extern hal_error_t hal_rpc_recvfrom(uint8_t * const buf, size_t * const len, void **opaque);
+#ifndef NUM_RPC_BUFFER
+/* An arbitrary number, but we don't expect to have more than 8 concurrent
+ * RPC requests.
+ */
+#define NUM_RPC_BUFFER 16
+#endif
 
 #ifndef MAX_PKT_SIZE
+/* Another arbitrary number, more or less driven by the 4096-bit RSA
+ * keygen test.
+ */
 #define MAX_PKT_SIZE 4096
 #endif
 
+/* The thread entry point takes a single void* argument, so we bundle the
+ * packet buffer and length arguments together.
+ */
 typedef struct {
-    void *opaque;
     size_t len;
     uint8_t buf[MAX_PKT_SIZE];
 } rpc_buffer_t;
 
-osPoolDef(rpc_buffer_pool, 16, rpc_buffer_t);
+osPoolDef(rpc_buffer_pool, NUM_RPC_BUFFER, rpc_buffer_t);
 osPoolId  rpc_buffer_pool;
 
-rpc_buffer_t *rpc_buffer_alloc(void)
+static rpc_buffer_t *rpc_buffer_alloc(void)
 {
-    rpc_buffer_t *rbuf = (rpc_buffer_t *)osPoolCAlloc(rpc_buffer_pool);
-    if (rbuf)
-	rbuf->len = sizeof(rbuf->buf);
-    return rbuf;
+    return (rpc_buffer_t *)osPoolCAlloc(rpc_buffer_pool);
 }
 
+/* A mutex to arbitrate concurrent UART transmits, from RPC responses.
+ */
 osMutexId  uart_mutex;
 osMutexDef(uart_mutex);
 
-void dispatch_thread(void const *args)
+/* Borrowed from xdr.c. We know the target architecture is little-endian,
+ * but we pretend for the sake of appearances.
+ */
+#ifdef __ARMEL__                /* little endian */
+static inline uint32_t htonl(uint32_t w)
+{
+  return
+    ((w & 0x000000ff) << 24) +
+    ((w & 0x0000ff00) << 8) +
+    ((w & 0x00ff0000) >> 8) +
+    ((w & 0xff000000) >> 24);
+}
+#else
+#define htonl(x) (x)
+#endif
+
+/* Thread entry point for the RPC request handler.
+ */
+static void dispatch_thread(void const *args)
 {
     rpc_buffer_t *ibuf = (rpc_buffer_t *)args;
-    rpc_buffer_t *obuf = rpc_buffer_alloc();	// NULL check
-    obuf->opaque = ibuf->opaque;
+    rpc_buffer_t *obuf = rpc_buffer_alloc();
+    if (obuf == NULL) {
+        uint32_t err = htonl(HAL_ERROR_ALLOCATION_FAILURE);
+        osMutexWait(uart_mutex, osWaitForever);
+        hal_rpc_sendto((uint8_t *)&err, 4, NULL);
+        osMutexRelease(uart_mutex);
+        osPoolFree(rpc_buffer_pool, ibuf);
+        Error_Handler();
+    }
+    obuf->len = sizeof(obuf->buf);
     hal_rpc_server_dispatch(ibuf->buf, ibuf->len, obuf->buf, &obuf->len);
     osPoolFree(rpc_buffer_pool, ibuf);
     osMutexWait(uart_mutex, osWaitForever);
-    hal_rpc_sendto(obuf->buf, obuf->len, obuf->opaque);
+    hal_error_t ret = hal_rpc_sendto(obuf->buf, obuf->len, NULL);
     osMutexRelease(uart_mutex);
     osPoolFree(rpc_buffer_pool, obuf);
+    if (ret != HAL_OK)
+        Error_Handler();
 }
 osThreadDef(dispatch_thread, osPriorityNormal, DEFAULT_STACK_SIZE);
 
-void rpc_server_main(void)
+/* Semaphore to inform the main thread that there's a new RPC request.
+ */
+osSemaphoreId rpc_sem;
+osSemaphoreDef(rpc_sem);
+
+static uint8_t c;		/* current character received from UART */
+static rpc_buffer_t *ibuf;	/* current RPC input buffer */
+
+/* Add a byte to the input buffer.
+ */
+static inline void ibuf_push(uint8_t c) {
+    if (ibuf->len < MAX_PKT_SIZE)
+        ibuf->buf[ibuf->len++] = c;
+}
+
+/* Callback for HAL_UART_Receive_IT().
+ */
+void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
 {
-    hal_error_t ret;
-    
-    while (1) {
-	rpc_buffer_t *ibuf = rpc_buffer_alloc();	// NULL check
-	// separate allocations for struct and block of memory?
-	ret = hal_rpc_recvfrom(ibuf->buf, &ibuf->len, &ibuf->opaque);
-        if (ret == HAL_OK) {
-	    osThreadCreate(osThread(dispatch_thread), (void *)ibuf);
+/* SLIP special characters */
+#define END             0300    /* indicates end of packet */
+#define ESC             0333    /* indicates byte stuffing */
+#define ESC_END         0334    /* ESC ESC_END means END data byte */
+#define ESC_ESC         0335    /* ESC ESC_ESC means ESC data byte */
+
+    static int esc_flag = 0;	/* previous char was ESC */
+
+    /* got 1 char - un-SLIP it */
+    switch (c) {
+    case END:
+        if (ibuf->len)
+            osSemaphoreRelease(rpc_sem);
+        break;
+    case ESC:
+        esc_flag = 1;
+        break;
+    default:
+        if (esc_flag) {
+            esc_flag = 0;
+            switch (c) {
+            case ESC_END:
+                ibuf_push(END);
+                break;
+            case ESC_ESC:
+                ibuf_push(ESC);
+                break;
+            default:
+                ibuf_push(c);
+            }
+        }
+        else {
+            ibuf_push(c);
         }
+        break;
     }
+
+    HAL_UART_Receive_IT(huart, &c, 1);
+}
+
+/* UART interrupt handler. This eventually calls HAL_UART_RxCpltCallback.
+ */
+void USART2_IRQHandler(void)
+{
+    HAL_UART_IRQHandler(&huart2);
 }
 
+/* The main thread. After the system setup, it waits for the RPC-request
+ * semaphore from HAL_UART_RxCpltCallback, and spawns a dispatch thread.
+ */
 int main()
 {
     stm_init();
 
 #ifdef TARGET_CRYPTECH_DEV_BRIDGE
-    // Blink blue LED for six seconds to not upset the Novena at boot.
+    /* Wait six seconds to not upset the Novena at boot. */
     led_on(LED_BLUE);
     for (int i = 0; i < 12; i++) {
 	osDelay(500);
 	led_toggle(LED_BLUE);
     }
+    led_off(LED_BLUE);
+    led_on(LED_GREEN);
 #endif
-    // prepare fmc interface
+    /* Prepare FMC interface. */
     fmc_init();
 
+    /* Haaaack. probe_cores() calls malloc(), which works from the main
+     * thread, but not from a spawned thread. It would be better to
+     * rewrite it to use static memory, but for now, just force it to
+     * probe early.
+     */
+    hal_core_iterate(NULL);
+
     rpc_buffer_pool = osPoolCreate(osPool(rpc_buffer_pool));
     uart_mutex = osMutexCreate(osMutex(uart_mutex));
+    rpc_sem = osSemaphoreCreate(osSemaphore(rpc_sem), 0);
 
 #ifdef TARGET_CRYPTECH_ALPHA
-    // Launch other threads:
-    // - admin thread on USART1
-    // - csprng warm-up thread?
+    /* Launch other threads:
+     * - admin thread on USART1
+     * - csprng warm-up thread?
+     */
 #endif
 
     if (hal_rpc_server_init() != HAL_OK)
-	return 1;
-    rpc_server_main();
+	Error_Handler();
+
+    ibuf = rpc_buffer_alloc();
+    if (ibuf == NULL)
+        /* Something is badly wrong. */
+        Error_Handler();
+
+    /* Start the non-blocking receive */
+    HAL_UART_Receive_IT(&huart2, &c, 1);
+
+    while (1) {
+        osSemaphoreWait(rpc_sem, osWaitForever);
+        if (osThreadCreate(osThread(dispatch_thread), (void *)ibuf) == NULL)
+            Error_Handler();
+        while ((ibuf = rpc_buffer_alloc()) == NULL);
+        /* XXX There's a potential race condition, where another request
+         * could write into the old ibuf, or into the null pointer if
+         * we're out of ibufs.
+         */
+    }
 }
diff --git a/stm-init.c b/stm-init.c
index a2c04d8..f6b3aa1 100644
--- a/stm-init.c
+++ b/stm-init.c
@@ -78,8 +78,6 @@ void stm_init(void)
 /* USART2 init function */
 static void MX_USART2_UART_Init(void)
 {
-  extern UART_HandleTypeDef huart2;
-
   huart2.Instance = USART2;
   huart2.Init.BaudRate = USART2_BAUD_RATE;
   huart2.Init.WordLength = UART_WORDLENGTH_8B;
diff --git a/stm-uart.h b/stm-uart.h
index 67e9d75..caf87b3 100644
--- a/stm-uart.h
+++ b/stm-uart.h
@@ -39,6 +39,8 @@
 
 #define USART2_BAUD_RATE	115200
 
+extern UART_HandleTypeDef huart2;
+
 extern HAL_StatusTypeDef uart_send_char(uint8_t ch);
 extern HAL_StatusTypeDef uart_recv_char(uint8_t *cp);
 extern HAL_StatusTypeDef uart_send_string(char *s);



More information about the Commits mailing list