tests: gadget0: test for unaligned buffer read/writes.

This currently fails on stm32F072, which is expected but not normal.
See GH issues #401 , #461
This commit is contained in:
fenugrec 2016-04-14 22:17:25 -04:00 committed by Karl Palsson
parent c585336766
commit c3512f4de5
2 changed files with 86 additions and 8 deletions

View File

@ -318,3 +318,54 @@ class TestControlTransfer_Reads(unittest.TestCase):
self.assertEqual(len(q), 10, "In this case, should have gotten wLen back")
class TestUnaligned(unittest.TestCase):
"""
M0 and M0+ cores don't support unaligned memory accesses. These test
how the stack behaves with aligned vs unaligned buffers.
https://github.com/libopencm3/libopencm3/issues/401
https://github.com/libopencm3/libopencm3/issues/461
"""
def setUp(self):
self.dev = usb.core.find(idVendor=0xcafe, idProduct=0xcafe, custom_match=find_by_serial(DUT_SERIAL))
self.assertIsNotNone(self.dev, "Couldn't find locm3 gadget0 device")
self.cfg = uu.find_descriptor(self.dev, bConfigurationValue=2)
self.assertIsNotNone(self.cfg, "Config 2 should exist")
self.dev.set_configuration(self.cfg);
self.req = uu.CTRL_OUT | uu.CTRL_TYPE_VENDOR | uu.CTRL_RECIPIENT_INTERFACE
self.intf = self.cfg[(0, 0)]
# heh, kinda gross...
self.ep_out = [ep for ep in self.intf if uu.endpoint_direction(ep.bEndpointAddress) == uu.ENDPOINT_OUT][0]
self.ep_in = [ep for ep in self.intf if uu.endpoint_direction(ep.bEndpointAddress) == uu.ENDPOINT_IN][0]
def tearDown(self):
uu.dispose_resources(self.dev)
def set_unaligned(self):
# GZ_REQ_SET_UNALIGNED
x = self.dev.ctrl_transfer(self.req, 4, 0, 0)
def set_aligned(self):
# GZ_REQ_SET_ALIGNED
x = self.dev.ctrl_transfer(self.req, 3, 0, 0)
def do_readwrite(self):
"""
transfer garbage data to/from bulk EP; alignment issues will hardfault the target
"""
data = [x for x in range(int(self.ep_out.wMaxPacketSize / 2))]
written = self.dev.write(self.ep_out, data)
self.assertEqual(written, len(data), "Should have written all bytes plz")
read_size = self.ep_in.wMaxPacketSize * 10
data = self.dev.read(self.ep_in, read_size)
self.assertEqual(len(data), read_size, "Should have read as much as we asked for")
def test_aligned(self):
self.set_aligned()
self.do_readwrite()
def test_unaligned(self):
self.set_unaligned()
self.do_readwrite()

View File

@ -45,6 +45,8 @@
*/
#define GZ_REQ_SET_PATTERN 1
#define GZ_REQ_PRODUCE 2
#define GZ_REQ_SET_ALIGNED 3
#define GZ_REQ_SET_UNALIGNED 4
#define INTEL_COMPLIANCE_WRITE 0x5b
#define INTEL_COMPLIANCE_READ 0x5c
@ -177,42 +179,60 @@ static usbd_device *our_dev;
static struct {
uint8_t pattern;
int pattern_counter;
int test_unaligned; /* If 0 (default), use 16-bit aligned buffers. This should not be declared as bool */
} state = {
.pattern = 0,
.pattern_counter = 0,
.test_unaligned = 0,
};
static void gadget0_ss_out_cb(usbd_device *usbd_dev, uint8_t ep)
{
(void) ep;
uint16_t x;
/* TODO - if you're really keen, perf test this. tiva implies it matters */
/* char buf[64] __attribute__ ((aligned(4))); */
char buf[BULK_EP_MAXPACKET];
uint8_t buf[BULK_EP_MAXPACKET + 1] __attribute__ ((aligned(2)));
uint8_t *dest;
trace_send_blocking8(0, 'O');
uint16_t x = usbd_ep_read_packet(usbd_dev, ep, buf, sizeof(buf));
if (state.test_unaligned) {
dest = buf + 1;
} else {
dest = buf;
}
x = usbd_ep_read_packet(usbd_dev, ep, dest, BULK_EP_MAXPACKET);
trace_send_blocking8(1, x);
}
static void gadget0_ss_in_cb(usbd_device *usbd_dev, uint8_t ep)
{
(void) usbd_dev;
uint8_t buf[BULK_EP_MAXPACKET + 1] __attribute__ ((aligned(2)));
uint8_t *src;
trace_send_blocking8(0, 'I');
uint8_t buf[BULK_EP_MAXPACKET];
if (state.test_unaligned) {
src = buf + 1;
} else {
src = buf;
}
switch (state.pattern) {
case 0:
memset(buf, 0, sizeof(buf));
memset(src, 0, BULK_EP_MAXPACKET);
break;
case 1:
for (unsigned i = 0; i < sizeof(buf); i++) {
buf[i] = state.pattern_counter++ % 63;
for (unsigned i = 0; i < BULK_EP_MAXPACKET; i++) {
src[i] = state.pattern_counter++ % 63;
}
break;
}
uint16_t x = usbd_ep_write_packet(usbd_dev, ep, buf, sizeof(buf));
uint16_t x = usbd_ep_write_packet(usbd_dev, ep, src, BULK_EP_MAXPACKET);
/* As we are calling write in the callback, this should never fail */
trace_send_blocking8(2, x);
if (x != sizeof(buf)) {
if (x != BULK_EP_MAXPACKET) {
ER_DPRINTF("failed to write?: %d\n", x);
}
/*assert(x == sizeof(buf));*/
@ -256,6 +276,12 @@ static int gadget0_control_request(usbd_device *usbd_dev,
case INTEL_COMPLIANCE_READ:
ER_DPRINTF("unimplemented!");
return USBD_REQ_NOTSUPP;
case GZ_REQ_SET_UNALIGNED:
state.test_unaligned = 1;
return USBD_REQ_HANDLED;
case GZ_REQ_SET_ALIGNED:
state.test_unaligned = 0;
return USBD_REQ_HANDLED;
case GZ_REQ_PRODUCE:
ER_DPRINTF("fake loopback of %d\n", req->wValue);
if (req->wValue > sizeof(usbd_control_buffer)) {
@ -280,6 +306,7 @@ static void gadget0_set_config(usbd_device *usbd_dev, uint16_t wValue)
ER_DPRINTF("set cfg %d\n", wValue);
switch (wValue) {
case GZ_CFG_SOURCESINK:
state.test_unaligned = 0;
usbd_ep_setup(usbd_dev, 0x01, USB_ENDPOINT_ATTR_BULK, BULK_EP_MAXPACKET,
gadget0_ss_out_cb);
usbd_ep_setup(usbd_dev, 0x82, USB_ENDPOINT_ATTR_BULK, BULK_EP_MAXPACKET,