From b1e7539f195207d6547e4be229807fa8c8d011ab Mon Sep 17 00:00:00 2001 From: Purdea Andrei Date: Fri, 27 Sep 2024 00:30:04 +0300 Subject: [PATCH] firmware: fix race conditions in control out transfers (-2 bytes XRAM). Before this change, the EP0BUF buffer used by control out transfers could be overwritten by new control transfers before the firmware is finished processing the previous control transfer. The easiest way to illustrate this problem would be to run in a different terminal the following: ```bash while true; do lsusb -v -d 20b7:9db1 > /dev/null; done ``` While this is running, glasglow is completely unusable. Presumably even a single lsusb run could cause corruption, if it happens to be issued at the wrong time. With this change glasgow is now usable, even if the above loop is running. Please see https://github.com/whitequark/libfx2/pull/18 for more details. --- firmware/main.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/firmware/main.c b/firmware/main.c index d4f8bcc00..1a6838c88 100644 --- a/firmware/main.c +++ b/firmware/main.c @@ -476,12 +476,13 @@ void handle_pending_usb_setup() { } SETUP_EP0_BUF(chunk_len); } else { - SETUP_EP0_BUF(0); + SETUP_EP0_OUT_BUF(); while(EP0CS & _BUSY); if(!eeprom_write(arg_chip, arg_addr, EP0BUF, chunk_len, /*double_byte=*/true, page_size, timeout)) { goto stall_ep0_return; } + ACK_EP0(); } arg_len -= chunk_len; @@ -505,9 +506,10 @@ void handle_pending_usb_setup() { return; } } else { - SETUP_EP0_BUF(0); + SETUP_EP0_OUT_BUF(); while(EP0CS & _BUSY); fpga_reg_write(EP0BUF, arg_len); + ACK_EP0(); return; } } @@ -547,12 +549,13 @@ void handle_pending_usb_setup() { while(arg_len > 0) { uint8_t chunk_len = arg_len < 64 ? arg_len : 64; - SETUP_EP0_BUF(0); + SETUP_EP0_OUT_BUF(); while(EP0CS & _BUSY); fpga_load(EP0BUF, chunk_len); arg_len -= chunk_len; } + ACK_EP0(); bitstream_idx = arg_idx; return; @@ -569,9 +572,10 @@ void handle_pending_usb_setup() { SETUP_EP0_BUF(CONFIG_SIZE_BITSTREAM_ID); } else { if(fpga_start()) { - SETUP_EP0_BUF(0); + SETUP_EP0_OUT_BUF(); while(EP0CS & _BUSY); xmemcpy(glasgow_config.bitstream_id, EP0BUF, CONFIG_SIZE_BITSTREAM_ID); + ACK_EP0(); } else { goto stall_ep0_return; }