mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-30 18:41:11 +00:00
USB: Fix memcpy routines
The memcpy like routines for moving to and from usb packet RAM couldn't deal with all unaligned uses, this fixes their behavior. In particular, a previous caller might assume that the packet RAM addresses were contiguous and attempt to break up a call into two separate chunks (as the queue insertion/removal code does). But this can lead to invalid pointers passed to these memcpy routines. A much cleaner solution is to make the packet RAM address space contiguous. To do so the memcpy routines take packet RAM addresses instead of AHB address space mapped addresses and __usb_ram_start needed to change to be of type usb_uint so that pointer arithmatic on it worked correctly on all platforms, this also allowed the usb_sram_addr macro to be simplified. Signed-off-by: Anton Staaf <robotboy@chromium.org> BRANCH=None BUG=None TEST=make buildall -j Verify that USB still works on Ryu and discovery-stm32f072 Change-Id: I479461f07a3203f1e6e0cf9705f512a5a43c4646 Reviewed-on: https://chromium-review.googlesource.com/264764 Trybot-Ready: Anton Staaf <robotboy@chromium.org> Tested-by: Anton Staaf <robotboy@chromium.org> Reviewed-by: Anton Staaf <robotboy@chromium.org> Commit-Queue: Anton Staaf <robotboy@chromium.org>
This commit is contained in:
committed by
ChromeOS Commit Bot
parent
0016de8250
commit
8c0cef2607
@@ -17,7 +17,8 @@
|
|||||||
|
|
||||||
static size_t rx_read(struct usb_stream_config const *config)
|
static size_t rx_read(struct usb_stream_config const *config)
|
||||||
{
|
{
|
||||||
size_t count = btable_ep[config->endpoint].rx_count & 0x3ff;
|
uintptr_t address = btable_ep[config->endpoint].rx_addr;
|
||||||
|
size_t count = btable_ep[config->endpoint].rx_count & 0x3ff;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Only read the received USB packet if there is enough space in the
|
* Only read the received USB packet if there is enough space in the
|
||||||
@@ -27,17 +28,18 @@ static size_t rx_read(struct usb_stream_config const *config)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return producer_write_memcpy(&config->producer,
|
return producer_write_memcpy(&config->producer,
|
||||||
config->rx_ram,
|
(void *) address,
|
||||||
count,
|
count,
|
||||||
memcpy_from_usbram);
|
memcpy_from_usbram);
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t tx_write(struct usb_stream_config const *config)
|
static size_t tx_write(struct usb_stream_config const *config)
|
||||||
{
|
{
|
||||||
size_t count = consumer_read_memcpy(&config->consumer,
|
uintptr_t address = btable_ep[config->endpoint].tx_addr;
|
||||||
config->tx_ram,
|
size_t count = consumer_read_memcpy(&config->consumer,
|
||||||
config->tx_size,
|
(void *) address,
|
||||||
memcpy_to_usbram);
|
config->tx_size,
|
||||||
|
memcpy_to_usbram);
|
||||||
|
|
||||||
btable_ep[config->endpoint].tx_count = count;
|
btable_ep[config->endpoint].tx_count = count;
|
||||||
|
|
||||||
|
|||||||
@@ -77,6 +77,8 @@ struct stm32_endpoint btable_ep[USB_EP_COUNT]
|
|||||||
static usb_uint ep0_buf_tx[USB_MAX_PACKET_SIZE / 2] __usb_ram;
|
static usb_uint ep0_buf_tx[USB_MAX_PACKET_SIZE / 2] __usb_ram;
|
||||||
static usb_uint ep0_buf_rx[USB_MAX_PACKET_SIZE / 2] __usb_ram;
|
static usb_uint ep0_buf_rx[USB_MAX_PACKET_SIZE / 2] __usb_ram;
|
||||||
|
|
||||||
|
#define EP0_BUF_TX_SRAM_ADDR ((void *) usb_sram_addr(ep0_buf_tx))
|
||||||
|
|
||||||
static int set_addr;
|
static int set_addr;
|
||||||
/* remaining size of descriptor data to transfer */
|
/* remaining size of descriptor data to transfer */
|
||||||
static int desc_left;
|
static int desc_left;
|
||||||
@@ -155,7 +157,7 @@ static void ep0_rx(void)
|
|||||||
desc_ptr = desc + USB_MAX_PACKET_SIZE;
|
desc_ptr = desc + USB_MAX_PACKET_SIZE;
|
||||||
len = USB_MAX_PACKET_SIZE;
|
len = USB_MAX_PACKET_SIZE;
|
||||||
}
|
}
|
||||||
memcpy_to_usbram(ep0_buf_tx, desc, len);
|
memcpy_to_usbram(EP0_BUF_TX_SRAM_ADDR, desc, len);
|
||||||
if (type == USB_DT_CONFIGURATION)
|
if (type == USB_DT_CONFIGURATION)
|
||||||
/* set the real descriptor size */
|
/* set the real descriptor size */
|
||||||
ep0_buf_tx[1] = USB_DESC_SIZE;
|
ep0_buf_tx[1] = USB_DESC_SIZE;
|
||||||
@@ -166,7 +168,7 @@ static void ep0_rx(void)
|
|||||||
} else if (req == (USB_DIR_IN | (USB_REQ_GET_STATUS << 8))) {
|
} else if (req == (USB_DIR_IN | (USB_REQ_GET_STATUS << 8))) {
|
||||||
uint16_t zero = 0;
|
uint16_t zero = 0;
|
||||||
/* Get status */
|
/* Get status */
|
||||||
memcpy_to_usbram(ep0_buf_tx, (void *)&zero, 2);
|
memcpy_to_usbram(EP0_BUF_TX_SRAM_ADDR, (void *)&zero, 2);
|
||||||
btable_ep[0].tx_count = 2;
|
btable_ep[0].tx_count = 2;
|
||||||
STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID,
|
STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID,
|
||||||
EP_STATUS_OUT /*null OUT transaction */);
|
EP_STATUS_OUT /*null OUT transaction */);
|
||||||
@@ -208,7 +210,7 @@ static void ep0_tx(void)
|
|||||||
if (desc_ptr) {
|
if (desc_ptr) {
|
||||||
/* we have an on-going descriptor transfer */
|
/* we have an on-going descriptor transfer */
|
||||||
int len = MIN(desc_left, USB_MAX_PACKET_SIZE);
|
int len = MIN(desc_left, USB_MAX_PACKET_SIZE);
|
||||||
memcpy_to_usbram(ep0_buf_tx, desc_ptr, len);
|
memcpy_to_usbram(EP0_BUF_TX_SRAM_ADDR, desc_ptr, len);
|
||||||
btable_ep[0].tx_count = len;
|
btable_ep[0].tx_count = len;
|
||||||
desc_left -= len;
|
desc_left -= len;
|
||||||
desc_ptr += len;
|
desc_ptr += len;
|
||||||
@@ -346,21 +348,15 @@ int usb_is_enabled(void)
|
|||||||
|
|
||||||
void *memcpy_to_usbram(void *dest, const void *src, size_t n)
|
void *memcpy_to_usbram(void *dest, const void *src, size_t n)
|
||||||
{
|
{
|
||||||
/*
|
int unaligned = (((uintptr_t) dest) & 1);
|
||||||
* The d pointer needs to be volatile to prevent GCC from possibly
|
usb_uint *d = &__usb_ram_start[((uintptr_t) dest) / 2];
|
||||||
* breaking writes to the USB packet RAM into multiple 16-bit writes,
|
uint8_t *s = (uint8_t *) src;
|
||||||
* which, due to the way the AHB2APB bridge works would clobber what
|
int i;
|
||||||
* we write with 32-bit extensions of the 16-bit writes.
|
|
||||||
*/
|
|
||||||
int i;
|
|
||||||
uint8_t *s = (uint8_t *) src;
|
|
||||||
usb_uint volatile *d = (usb_uint volatile *)((uintptr_t) dest & ~1);
|
|
||||||
|
|
||||||
if ((((uintptr_t) dest) & 1) && n) {
|
/*
|
||||||
/*
|
* Handle unaligned leading byte via read/modify/write.
|
||||||
* The first destination byte is not aligned, perform a read/
|
*/
|
||||||
* modify/write.
|
if (unaligned && n) {
|
||||||
*/
|
|
||||||
*d = (*d & ~0xff00) | (*s << 8);
|
*d = (*d & ~0xff00) | (*s << 8);
|
||||||
n--;
|
n--;
|
||||||
s++;
|
s++;
|
||||||
@@ -382,13 +378,16 @@ void *memcpy_to_usbram(void *dest, const void *src, size_t n)
|
|||||||
|
|
||||||
void *memcpy_from_usbram(void *dest, const void *src, size_t n)
|
void *memcpy_from_usbram(void *dest, const void *src, size_t n)
|
||||||
{
|
{
|
||||||
int i;
|
int unaligned = (((uintptr_t) src) & 1);
|
||||||
usb_uint *s = (usb_uint *)((uintptr_t) src & ~1);
|
usb_uint const *s = &__usb_ram_start[((uintptr_t) src) / 2];
|
||||||
uint8_t *d = (uint8_t *) dest;
|
uint8_t *d = (uint8_t *) dest;
|
||||||
|
int i;
|
||||||
|
|
||||||
if ((((uintptr_t) src) & 1) && n) {
|
if (unaligned && n) {
|
||||||
*d++ = *s++ >> 8;
|
*d = *s >> 8;
|
||||||
n--;
|
n--;
|
||||||
|
s++;
|
||||||
|
d++;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < n / 2; i++) {
|
for (i = 0; i < n / 2; i++) {
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ static usb_uint hid_ep_buf[HID_REPORT_SIZE / 2] __usb_ram;
|
|||||||
|
|
||||||
void set_keyboard_report(uint64_t rpt)
|
void set_keyboard_report(uint64_t rpt)
|
||||||
{
|
{
|
||||||
memcpy_to_usbram(hid_ep_buf, &rpt, sizeof(rpt));
|
memcpy_to_usbram((void *) usb_sram_addr(hid_ep_buf), &rpt, sizeof(rpt));
|
||||||
/* enable TX */
|
/* enable TX */
|
||||||
STM32_TOGGLE_EP(USB_EP_HID, EP_TX_MASK, EP_TX_VALID, 0);
|
STM32_TOGGLE_EP(USB_EP_HID, EP_TX_MASK, EP_TX_VALID, 0);
|
||||||
}
|
}
|
||||||
@@ -124,7 +124,8 @@ static int hid_iface_request(usb_uint *ep0_buf_rx, usb_uint *ep0_buf_tx)
|
|||||||
(USB_REQ_GET_DESCRIPTOR << 8))) &&
|
(USB_REQ_GET_DESCRIPTOR << 8))) &&
|
||||||
(ep0_buf_rx[1] == (USB_HID_DT_REPORT << 8))) {
|
(ep0_buf_rx[1] == (USB_HID_DT_REPORT << 8))) {
|
||||||
/* Setup : HID specific : Get Report descriptor */
|
/* Setup : HID specific : Get Report descriptor */
|
||||||
memcpy_to_usbram(ep0_buf_tx, report_desc,
|
memcpy_to_usbram((void *) usb_sram_addr(ep0_buf_tx),
|
||||||
|
report_desc,
|
||||||
sizeof(report_desc));
|
sizeof(report_desc));
|
||||||
btable_ep[0].tx_count = MIN(ep0_buf_rx[3],
|
btable_ep[0].tx_count = MIN(ep0_buf_rx[3],
|
||||||
sizeof(report_desc));
|
sizeof(report_desc));
|
||||||
|
|||||||
@@ -57,11 +57,6 @@ extern const struct hook_data __hooks_second_end[];
|
|||||||
extern const struct deferred_data __deferred_funcs[];
|
extern const struct deferred_data __deferred_funcs[];
|
||||||
extern const struct deferred_data __deferred_funcs_end[];
|
extern const struct deferred_data __deferred_funcs_end[];
|
||||||
|
|
||||||
/* USB data */
|
|
||||||
extern const uint8_t __usb_desc[];
|
|
||||||
extern const uint8_t __usb_desc_end[];
|
|
||||||
extern const uint16_t __usb_ram_start[];
|
|
||||||
|
|
||||||
/* I2C fake devices for unit testing */
|
/* I2C fake devices for unit testing */
|
||||||
extern const struct test_i2c_read_dev __test_i2c_read8[];
|
extern const struct test_i2c_read_dev __test_i2c_read8[];
|
||||||
extern const struct test_i2c_read_dev __test_i2c_read8_end[];
|
extern const struct test_i2c_read_dev __test_i2c_read8_end[];
|
||||||
|
|||||||
@@ -235,13 +235,18 @@ struct usb_setup_packet {
|
|||||||
#define USB_EP_DESC(i, num) USB_CONF_DESC(CONCAT4(iface, i, _1ep, num))
|
#define USB_EP_DESC(i, num) USB_CONF_DESC(CONCAT4(iface, i, _1ep, num))
|
||||||
#define USB_CUSTOM_DESC(i, name) USB_CONF_DESC(CONCAT4(iface, i, _2, name))
|
#define USB_CUSTOM_DESC(i, name) USB_CONF_DESC(CONCAT4(iface, i, _2, name))
|
||||||
|
|
||||||
#define USB_DESC_SIZE (__usb_desc_end - __usb_desc)
|
|
||||||
|
|
||||||
/* Helpers for managing the USB controller dedicated RAM */
|
/* Helpers for managing the USB controller dedicated RAM */
|
||||||
|
|
||||||
/* primitive to access the words in USB RAM */
|
/* primitive to access the words in USB RAM */
|
||||||
typedef CONFIG_USB_RAM_ACCESS_TYPE usb_uint;
|
typedef CONFIG_USB_RAM_ACCESS_TYPE usb_uint;
|
||||||
|
|
||||||
|
/* USB Linker data */
|
||||||
|
extern const uint8_t __usb_desc[];
|
||||||
|
extern const uint8_t __usb_desc_end[];
|
||||||
|
extern usb_uint __usb_ram_start[];
|
||||||
|
|
||||||
|
#define USB_DESC_SIZE (__usb_desc_end - __usb_desc)
|
||||||
|
|
||||||
struct stm32_endpoint {
|
struct stm32_endpoint {
|
||||||
volatile usb_uint tx_addr;
|
volatile usb_uint tx_addr;
|
||||||
volatile usb_uint tx_count;
|
volatile usb_uint tx_count;
|
||||||
@@ -261,22 +266,20 @@ void usb_read_setup_packet(usb_uint *buffer, struct usb_setup_packet *packet);
|
|||||||
* Copy data to and from the USB dedicated RAM and take care of the weird
|
* Copy data to and from the USB dedicated RAM and take care of the weird
|
||||||
* addressing. These functions correctly handle unaligned accesses to the USB
|
* addressing. These functions correctly handle unaligned accesses to the USB
|
||||||
* memory. They have the same prototype as memcpy, allowing them to be used
|
* memory. They have the same prototype as memcpy, allowing them to be used
|
||||||
* in places that expect memcpy.
|
* in places that expect memcpy. The void pointer used to represent a location
|
||||||
|
* in the USB dedicated RAM should be the offset in that address space, not the
|
||||||
|
* AHB address space.
|
||||||
*
|
*
|
||||||
* The USB packet RAM is attached to the processor via the AHB2APB bridge. This
|
* The USB packet RAM is attached to the processor via the AHB2APB bridge. This
|
||||||
* bridge performs manipulations of read and write accesses as per the note in
|
* bridge performs manipulations of read and write accesses as per the note in
|
||||||
* section 2.1 of RM0091. The upshot is that it is OK to read from the packet
|
* section 2.1 of RM0091. The upshot is that custom memcpy like routines need
|
||||||
* RAM using 8-bit or 16-bit accesses, but not 32-bit, and it is only really OK
|
* to be employed.
|
||||||
* to write to the packet RAM using 16-bit accesses. Thus custom memcpy like
|
|
||||||
* routines need to be employed.
|
|
||||||
*/
|
*/
|
||||||
void *memcpy_to_usbram(void *dest, const void *src, size_t n);
|
void *memcpy_to_usbram(void *dest, const void *src, size_t n);
|
||||||
void *memcpy_from_usbram(void *dest, const void *src, size_t n);
|
void *memcpy_from_usbram(void *dest, const void *src, size_t n);
|
||||||
|
|
||||||
/* Compute the address inside dedicate SRAM for the USB controller */
|
/* Compute the address inside dedicate SRAM for the USB controller */
|
||||||
#define usb_sram_addr(x) \
|
#define usb_sram_addr(x) ((x - __usb_ram_start) * sizeof(uint16_t))
|
||||||
(((uint32_t)(x) - (uint32_t)__usb_ram_start) \
|
|
||||||
/ (sizeof(usb_uint)/sizeof(uint16_t)))
|
|
||||||
|
|
||||||
/* These descriptors defined in board code */
|
/* These descriptors defined in board code */
|
||||||
extern const void * const usb_strings[];
|
extern const void * const usb_strings[];
|
||||||
|
|||||||
Reference in New Issue
Block a user