diff --git a/firmware/common/locking.h b/firmware/common/locking.h new file mode 100644 index 000000000..392b689de --- /dev/null +++ b/firmware/common/locking.h @@ -0,0 +1,55 @@ +/* + * Copyright 2024 Great Scott Gadgets + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __LOCKING_H__ +#define __LOCKING_H__ + +#include + +#include + +/* Primitives for implementing locking. + * + * Must always be used in a pair, with a call to load_exclusive being + * followed immediately or near-immediately by a call to store_exclusive(). + * Failure to observe this rule may lead to undefined results. */ + +// Use ldrex and strex directly if available. +// Otherwise, disable interrupts to ensure exclusivity. +#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) + #define load_exclusive __ldrex + #define store_exclusive __strex +#else +static inline uint32_t load_exclusive(volatile uint32_t* addr) +{ + __disable_irq(); + return *addr; +} + +static inline uint32_t store_exclusive(uint32_t val, volatile uint32_t* addr) +{ + *addr = val; + __enable_irq(); + return 0; +} +#endif + +#endif /* __LOCKING_H__ */ diff --git a/firmware/common/usb.c b/firmware/common/usb.c index b2ebd2f93..3b8c8b468 100644 --- a/firmware/common/usb.c +++ b/firmware/common/usb.c @@ -29,7 +29,7 @@ #include "usb_standard_request.h" #include -#include +#include #include #include diff --git a/firmware/common/usb_queue.c b/firmware/common/usb_queue.c index 5d19089ee..a4cab94a0 100644 --- a/firmware/common/usb_queue.c +++ b/firmware/common/usb_queue.c @@ -27,8 +27,8 @@ #include #include -#include +#include "locking.h" #include "usb.h" #include "usb_queue.h" @@ -73,10 +73,10 @@ static usb_transfer_t* allocate_transfer(usb_queue_t* const queue) } do { - transfer = (void*) __ldrex((uint32_t*) &queue->free_transfers); - aborted = - __strex((uint32_t) transfer->next, - (uint32_t*) &queue->free_transfers); + transfer = (void*) load_exclusive((uint32_t*) &queue->free_transfers); + aborted = store_exclusive( + (uint32_t) transfer->next, + (uint32_t*) &queue->free_transfers); } while (aborted); transfer->next = NULL; return transfer; @@ -88,9 +88,11 @@ static void free_transfer(usb_transfer_t* const transfer) usb_queue_t* const queue = transfer->queue; bool aborted; do { - transfer->next = (void*) __ldrex((uint32_t*) &queue->free_transfers); - aborted = - __strex((uint32_t) transfer, (uint32_t*) &queue->free_transfers); + transfer->next = + (void*) load_exclusive((uint32_t*) &queue->free_transfers); + aborted = store_exclusive( + (uint32_t) transfer, + (uint32_t*) &queue->free_transfers); } while (aborted); }