diff options
-rw-r--r-- | utils/hwstub/hwstub_protocol.h | 10 | ||||
-rw-r--r-- | utils/hwstub/lib/hwstub.c | 40 | ||||
-rw-r--r-- | utils/hwstub/lib/hwstub.h | 5 | ||||
-rw-r--r-- | utils/hwstub/stub/SOURCES | 2 | ||||
-rw-r--r-- | utils/hwstub/stub/asm/arm/atomic_rw.S | 58 | ||||
-rw-r--r-- | utils/hwstub/stub/asm/mips/atomic_rw.S | 61 | ||||
-rw-r--r-- | utils/hwstub/stub/main.c | 72 | ||||
-rw-r--r-- | utils/hwstub/stub/protocol.h | 2 | ||||
-rw-r--r-- | utils/hwstub/stub/target.h | 8 | ||||
-rw-r--r-- | utils/hwstub/tools/hwstub_shell.cpp | 12 | ||||
-rw-r--r-- | utils/hwstub/tools/init.lua | 4 | ||||
-rw-r--r-- | utils/regtools/qeditor/backend.cpp | 4 |
12 files changed, 254 insertions, 24 deletions
diff --git a/utils/hwstub/hwstub_protocol.h b/utils/hwstub/hwstub_protocol.h index 33081d3ca2..1fe982323d 100644 --- a/utils/hwstub/hwstub_protocol.h +++ b/utils/hwstub/hwstub_protocol.h | |||
@@ -26,7 +26,7 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | #define HWSTUB_VERSION_MAJOR 4 | 28 | #define HWSTUB_VERSION_MAJOR 4 |
29 | #define HWSTUB_VERSION_MINOR 0 | 29 | #define HWSTUB_VERSION_MINOR 1 |
30 | 30 | ||
31 | #define HWSTUB_VERSION__(maj, min) #maj"."#min | 31 | #define HWSTUB_VERSION__(maj, min) #maj"."#min |
32 | #define HWSTUB_VERSION_(maj, min) HWSTUB_VERSION__(maj, min) | 32 | #define HWSTUB_VERSION_(maj, min) HWSTUB_VERSION__(maj, min) |
@@ -140,6 +140,8 @@ struct hwstub_device_desc_t | |||
140 | #define HWSTUB_READ2 0x42 | 140 | #define HWSTUB_READ2 0x42 |
141 | #define HWSTUB_WRITE 0x43 | 141 | #define HWSTUB_WRITE 0x43 |
142 | #define HWSTUB_EXEC 0x44 | 142 | #define HWSTUB_EXEC 0x44 |
143 | #define HWSTUB_READ2_ATOMIC 0x45 | ||
144 | #define HWSTUB_WRITE_ATOMIC 0x46 | ||
143 | 145 | ||
144 | /** | 146 | /** |
145 | * HWSTUB_GET_LOG: | 147 | * HWSTUB_GET_LOG: |
@@ -147,11 +149,14 @@ struct hwstub_device_desc_t | |||
147 | */ | 149 | */ |
148 | 150 | ||
149 | /** | 151 | /** |
150 | * HWSTUB_READ and HWSTUB_READ2: | 152 | * HWSTUB_READ and HWSTUB_READ2(_ATOMIC): |
151 | * Read a range of memory. The request works in two steps: first the host | 153 | * Read a range of memory. The request works in two steps: first the host |
152 | * sends HWSTUB_READ with the parameters (address, length) and then | 154 | * sends HWSTUB_READ with the parameters (address, length) and then |
153 | * a HWSTUB_READ2 to retrieve the buffer. Both requests must use the same | 155 | * a HWSTUB_READ2 to retrieve the buffer. Both requests must use the same |
154 | * ID in wValue, otherwise the second request will be STALLed. | 156 | * ID in wValue, otherwise the second request will be STALLed. |
157 | * HWSTUB_READ2_ATOMIC behaves the same as HWSTUB_READ2 except that the read | ||
158 | * is guaranteed to be atomic (ie performed as a single memory access) and | ||
159 | * will be STALLed if atomicity can not be ensured. | ||
155 | */ | 160 | */ |
156 | 161 | ||
157 | struct hwstub_read_req_t | 162 | struct hwstub_read_req_t |
@@ -163,6 +168,7 @@ struct hwstub_read_req_t | |||
163 | * HWSTUB_WRITE | 168 | * HWSTUB_WRITE |
164 | * Write a range of memory. The payload starts with the following header, everything | 169 | * Write a range of memory. The payload starts with the following header, everything |
165 | * which follows is data. | 170 | * which follows is data. |
171 | * HWSTUB_WRITE_ATOMIC behaves the same except it is atomic. See HWSTUB_READ2_ATOMIC. | ||
166 | */ | 172 | */ |
167 | struct hwstub_write_req_t | 173 | struct hwstub_write_req_t |
168 | { | 174 | { |
diff --git a/utils/hwstub/lib/hwstub.c b/utils/hwstub/lib/hwstub.c index 6ae0400a66..d3908585da 100644 --- a/utils/hwstub/lib/hwstub.c +++ b/utils/hwstub/lib/hwstub.c | |||
@@ -140,7 +140,8 @@ int hwstub_get_log(struct hwstub_device_t *dev, void *buf, size_t sz) | |||
140 | HWSTUB_GET_LOG, 0, dev->intf, buf, sz, 1000); | 140 | HWSTUB_GET_LOG, 0, dev->intf, buf, sz, 1000); |
141 | } | 141 | } |
142 | 142 | ||
143 | static int _hwstub_read(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz) | 143 | static int _hwstub_read(struct hwstub_device_t *dev, uint8_t breq, uint32_t addr, |
144 | void *buf, size_t sz) | ||
144 | { | 145 | { |
145 | struct hwstub_read_req_t read; | 146 | struct hwstub_read_req_t read; |
146 | read.dAddress = addr; | 147 | read.dAddress = addr; |
@@ -151,10 +152,11 @@ static int _hwstub_read(struct hwstub_device_t *dev, uint32_t addr, void *buf, s | |||
151 | return -1; | 152 | return -1; |
152 | return libusb_control_transfer(dev->handle, | 153 | return libusb_control_transfer(dev->handle, |
153 | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_IN, | 154 | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_IN, |
154 | HWSTUB_READ2, dev->id++, dev->intf, buf, sz, 1000); | 155 | breq, dev->id++, dev->intf, buf, sz, 1000); |
155 | } | 156 | } |
156 | 157 | ||
157 | static int _hwstub_write(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz) | 158 | static int _hwstub_write(struct hwstub_device_t *dev, uint8_t breq, uint32_t addr, |
159 | const void *buf, size_t sz) | ||
158 | { | 160 | { |
159 | size_t hdr_sz = sizeof(struct hwstub_write_req_t); | 161 | size_t hdr_sz = sizeof(struct hwstub_write_req_t); |
160 | struct hwstub_write_req_t *req = malloc(sz + hdr_sz); | 162 | struct hwstub_write_req_t *req = malloc(sz + hdr_sz); |
@@ -162,18 +164,34 @@ static int _hwstub_write(struct hwstub_device_t *dev, uint32_t addr, void *buf, | |||
162 | memcpy(req + 1, buf, sz); | 164 | memcpy(req + 1, buf, sz); |
163 | int size = libusb_control_transfer(dev->handle, | 165 | int size = libusb_control_transfer(dev->handle, |
164 | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT, | 166 | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT, |
165 | HWSTUB_WRITE, dev->id++, dev->intf, (void *)req, sz + hdr_sz, 1000); | 167 | breq, dev->id++, dev->intf, (void *)req, sz + hdr_sz, 1000); |
166 | free(req); | 168 | free(req); |
167 | return size - hdr_sz; | 169 | return size - hdr_sz; |
168 | } | 170 | } |
169 | 171 | ||
172 | int hwstub_read_atomic(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz) | ||
173 | { | ||
174 | /* reject any read greater than the buffer, it makes no sense anyway */ | ||
175 | if(sz > dev->buf_sz) | ||
176 | return -1; | ||
177 | return _hwstub_read(dev, HWSTUB_READ2_ATOMIC, addr, buf, sz); | ||
178 | } | ||
179 | |||
180 | int hwstub_write_atomic(struct hwstub_device_t *dev, uint32_t addr, const void *buf, size_t sz) | ||
181 | { | ||
182 | /* reject any write greater than the buffer, it makes no sense anyway */ | ||
183 | if(sz + sizeof(struct hwstub_write_req_t) > dev->buf_sz) | ||
184 | return -1; | ||
185 | return _hwstub_write(dev, HWSTUB_WRITE_ATOMIC, addr, buf, sz); | ||
186 | } | ||
187 | |||
170 | /* Intermediate function which make sure we don't overflow the device buffer */ | 188 | /* Intermediate function which make sure we don't overflow the device buffer */ |
171 | int hwstub_read(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz) | 189 | int hwstub_read(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz) |
172 | { | 190 | { |
173 | int cnt = 0; | 191 | int cnt = 0; |
174 | while(sz > 0) | 192 | while(sz > 0) |
175 | { | 193 | { |
176 | int xfer = _hwstub_read(dev, addr, buf, MIN(sz, dev->buf_sz)); | 194 | int xfer = _hwstub_read(dev, HWSTUB_READ2, addr, buf, MIN(sz, dev->buf_sz)); |
177 | if(xfer < 0) | 195 | if(xfer < 0) |
178 | return xfer; | 196 | return xfer; |
179 | sz -= xfer; | 197 | sz -= xfer; |
@@ -185,13 +203,13 @@ int hwstub_read(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz | |||
185 | } | 203 | } |
186 | 204 | ||
187 | /* Intermediate function which make sure we don't overflow the device buffer */ | 205 | /* Intermediate function which make sure we don't overflow the device buffer */ |
188 | int hwstub_write(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz) | 206 | int hwstub_write(struct hwstub_device_t *dev, uint32_t addr, const void *buf, size_t sz) |
189 | { | 207 | { |
190 | int cnt = 0; | 208 | int cnt = 0; |
191 | while(sz > 0) | 209 | while(sz > 0) |
192 | { | 210 | { |
193 | int xfer = _hwstub_write(dev, addr, buf, MIN(sz, dev->buf_sz - | 211 | int xfer = _hwstub_write(dev, HWSTUB_WRITE, addr, buf, |
194 | sizeof(struct hwstub_write_req_t))); | 212 | MIN(sz, dev->buf_sz - sizeof(struct hwstub_write_req_t))); |
195 | if(xfer < 0) | 213 | if(xfer < 0) |
196 | return xfer; | 214 | return xfer; |
197 | sz -= xfer; | 215 | sz -= xfer; |
@@ -207,6 +225,12 @@ int hwstub_rw_mem(struct hwstub_device_t *dev, int read, uint32_t addr, void *bu | |||
207 | return read ? hwstub_read(dev, addr, buf, sz) : hwstub_write(dev, addr, buf, sz); | 225 | return read ? hwstub_read(dev, addr, buf, sz) : hwstub_write(dev, addr, buf, sz); |
208 | } | 226 | } |
209 | 227 | ||
228 | int hwstub_rw_mem_atomic(struct hwstub_device_t *dev, int read, uint32_t addr, void *buf, size_t sz) | ||
229 | { | ||
230 | return read ? hwstub_read_atomic(dev, addr, buf, sz) : | ||
231 | hwstub_write_atomic(dev, addr, buf, sz); | ||
232 | } | ||
233 | |||
210 | int hwstub_exec(struct hwstub_device_t *dev, uint32_t addr, uint16_t flags) | 234 | int hwstub_exec(struct hwstub_device_t *dev, uint32_t addr, uint16_t flags) |
211 | { | 235 | { |
212 | struct hwstub_exec_req_t exec; | 236 | struct hwstub_exec_req_t exec; |
diff --git a/utils/hwstub/lib/hwstub.h b/utils/hwstub/lib/hwstub.h index d7d6ceb8ef..4d12de8eda 100644 --- a/utils/hwstub/lib/hwstub.h +++ b/utils/hwstub/lib/hwstub.h | |||
@@ -53,8 +53,11 @@ int hwstub_get_desc(struct hwstub_device_t *dev, uint16_t desc, void *info, size | |||
53 | int hwstub_get_log(struct hwstub_device_t *dev, void *buf, size_t sz); | 53 | int hwstub_get_log(struct hwstub_device_t *dev, void *buf, size_t sz); |
54 | /* Returns number of bytes written/read or <0 on error */ | 54 | /* Returns number of bytes written/read or <0 on error */ |
55 | int hwstub_read(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz); | 55 | int hwstub_read(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz); |
56 | int hwstub_write(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz); | 56 | int hwstub_read_atomic(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz); |
57 | int hwstub_write(struct hwstub_device_t *dev, uint32_t addr, const void *buf, size_t sz); | ||
58 | int hwstub_write_atomic(struct hwstub_device_t *dev, uint32_t addr, const void *buf, size_t sz); | ||
57 | int hwstub_rw_mem(struct hwstub_device_t *dev, int read, uint32_t addr, void *buf, size_t sz); | 59 | int hwstub_rw_mem(struct hwstub_device_t *dev, int read, uint32_t addr, void *buf, size_t sz); |
60 | int hwstub_rw_mem_atomic(struct hwstub_device_t *dev, int read, uint32_t addr, void *buf, size_t sz); | ||
58 | /* Returns <0 on error */ | 61 | /* Returns <0 on error */ |
59 | int hwstub_exec(struct hwstub_device_t *dev, uint32_t addr, uint16_t flags); | 62 | int hwstub_exec(struct hwstub_device_t *dev, uint32_t addr, uint16_t flags); |
60 | int hwstub_call(struct hwstub_device_t *dev, uint32_t addr); | 63 | int hwstub_call(struct hwstub_device_t *dev, uint32_t addr); |
diff --git a/utils/hwstub/stub/SOURCES b/utils/hwstub/stub/SOURCES index 1b0b56072d..c91580c966 100644 --- a/utils/hwstub/stub/SOURCES +++ b/utils/hwstub/stub/SOURCES | |||
@@ -2,9 +2,11 @@ | |||
2 | asm/arm/memcpy.S | 2 | asm/arm/memcpy.S |
3 | asm/arm/memmove.S | 3 | asm/arm/memmove.S |
4 | asm/arm/memset.S | 4 | asm/arm/memset.S |
5 | asm/arm/atomic_rw.S | ||
5 | #elif defined(CPU_MIPS) | 6 | #elif defined(CPU_MIPS) |
6 | asm/mips/memcpy.S | 7 | asm/mips/memcpy.S |
7 | asm/mips/memset.S | 8 | asm/mips/memset.S |
9 | asm/mips/atomic_rw.S | ||
8 | #else | 10 | #else |
9 | #error "Unimplemented ISA" | 11 | #error "Unimplemented ISA" |
10 | #endif | 12 | #endif |
diff --git a/utils/hwstub/stub/asm/arm/atomic_rw.S b/utils/hwstub/stub/asm/arm/atomic_rw.S new file mode 100644 index 0000000000..cb6272b4dc --- /dev/null +++ b/utils/hwstub/stub/asm/arm/atomic_rw.S | |||
@@ -0,0 +1,58 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Marcin Bukat | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * as published by the Free Software Foundation; either version 2 | ||
14 | * of the License, or (at your option) any later version. | ||
15 | * | ||
16 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
17 | * KIND, either express or implied. | ||
18 | * | ||
19 | ****************************************************************************/ | ||
20 | |||
21 | .section .text, "ax", %progbits | ||
22 | .global target_read8 | ||
23 | .type target_read8, %function | ||
24 | .global target_read16 | ||
25 | .type target_read16, %function | ||
26 | .global target_read32 | ||
27 | .type target_read32, %function | ||
28 | .global target_write8 | ||
29 | .type target_write8, %function | ||
30 | .global target_write16 | ||
31 | .type target_write16, %function | ||
32 | .global target_write32 | ||
33 | .type target_write32, %function | ||
34 | |||
35 | target_read8: | ||
36 | ldrb r0, [r0] | ||
37 | bx lr | ||
38 | |||
39 | target_read16: | ||
40 | ldrh r0, [r0] | ||
41 | bx lr | ||
42 | |||
43 | target_read32: | ||
44 | ldr r0, [r0] | ||
45 | bx lr | ||
46 | |||
47 | target_write8: | ||
48 | strb r1, [r0] | ||
49 | bx lr | ||
50 | |||
51 | target_write16: | ||
52 | strh r1, [r0] | ||
53 | bx lr | ||
54 | |||
55 | target_write32: | ||
56 | str r1, [r0] | ||
57 | bx lr | ||
58 | |||
diff --git a/utils/hwstub/stub/asm/mips/atomic_rw.S b/utils/hwstub/stub/asm/mips/atomic_rw.S new file mode 100644 index 0000000000..47c4213a5d --- /dev/null +++ b/utils/hwstub/stub/asm/mips/atomic_rw.S | |||
@@ -0,0 +1,61 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Marcin Bukat | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * as published by the Free Software Foundation; either version 2 | ||
14 | * of the License, or (at your option) any later version. | ||
15 | * | ||
16 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
17 | * KIND, either express or implied. | ||
18 | * | ||
19 | ****************************************************************************/ | ||
20 | #include "mips.h" | ||
21 | |||
22 | .set noreorder | ||
23 | .section .text, "ax", %progbits | ||
24 | .global target_read8 | ||
25 | .type target_read8, %function | ||
26 | .global target_read16 | ||
27 | .type target_read16, %function | ||
28 | .global target_read32 | ||
29 | .type target_read32, %function | ||
30 | .global target_write8 | ||
31 | .type target_write8, %function | ||
32 | .global target_write16 | ||
33 | .type target_write16, %function | ||
34 | .global target_write32 | ||
35 | .type target_write32, %function | ||
36 | |||
37 | target_read8: | ||
38 | jr ra | ||
39 | lbu v0, 0(a0) | ||
40 | |||
41 | target_read16: | ||
42 | jr ra | ||
43 | lhu v0, 0(a0) | ||
44 | |||
45 | target_read32: | ||
46 | jr ra | ||
47 | lw v0, 0(a0) | ||
48 | |||
49 | target_write8: | ||
50 | jr ra | ||
51 | sb a1, 0(a0) | ||
52 | |||
53 | target_write16: | ||
54 | jr ra | ||
55 | sh a1, 0(a0) | ||
56 | |||
57 | target_write32: | ||
58 | jr ra | ||
59 | sw a1, 0(a0) | ||
60 | |||
61 | .set reorder | ||
diff --git a/utils/hwstub/stub/main.c b/utils/hwstub/stub/main.c index 4e54b8fd89..3604cfdae0 100644 --- a/utils/hwstub/stub/main.c +++ b/utils/hwstub/stub/main.c | |||
@@ -356,6 +356,49 @@ static void handle_get_log(struct usb_ctrlrequest *req) | |||
356 | enable_logf(true); | 356 | enable_logf(true); |
357 | } | 357 | } |
358 | 358 | ||
359 | /* default implementation, relying on the compiler to produce correct code, | ||
360 | * targets should reimplement this... */ | ||
361 | uint8_t __attribute__((weak)) target_read8(const void *addr) | ||
362 | { | ||
363 | return *(volatile uint8_t *)addr; | ||
364 | } | ||
365 | |||
366 | uint16_t __attribute__((weak)) target_read16(const void *addr) | ||
367 | { | ||
368 | return *(volatile uint16_t *)addr; | ||
369 | } | ||
370 | |||
371 | uint32_t __attribute__((weak)) target_read32(const void *addr) | ||
372 | { | ||
373 | return *(volatile uint32_t *)addr; | ||
374 | } | ||
375 | |||
376 | void __attribute__((weak)) target_write8(void *addr, uint8_t val) | ||
377 | { | ||
378 | *(volatile uint8_t *)addr = val; | ||
379 | } | ||
380 | |||
381 | void __attribute__((weak)) target_write16(void *addr, uint16_t val) | ||
382 | { | ||
383 | *(volatile uint16_t *)addr = val; | ||
384 | } | ||
385 | |||
386 | void __attribute__((weak)) target_write32(void *addr, uint32_t val) | ||
387 | { | ||
388 | *(volatile uint32_t *)addr = val; | ||
389 | } | ||
390 | |||
391 | static bool read_atomic(void *dst, void *src, size_t sz) | ||
392 | { | ||
393 | switch(sz) | ||
394 | { | ||
395 | case 1: *(uint8_t *)dst = target_read8(src); return true; | ||
396 | case 2: *(uint16_t *)dst = target_read16(src); return true; | ||
397 | case 4: *(uint32_t *)dst = target_read32(src); return true; | ||
398 | default: return false; | ||
399 | } | ||
400 | } | ||
401 | |||
359 | static void handle_read(struct usb_ctrlrequest *req) | 402 | static void handle_read(struct usb_ctrlrequest *req) |
360 | { | 403 | { |
361 | static uint32_t last_addr = 0; | 404 | static uint32_t last_addr = 0; |
@@ -377,13 +420,30 @@ static void handle_read(struct usb_ctrlrequest *req) | |||
377 | { | 420 | { |
378 | if(id != last_id) | 421 | if(id != last_id) |
379 | return usb_drv_stall(EP_CONTROL, true, true); | 422 | return usb_drv_stall(EP_CONTROL, true, true); |
380 | memcpy(usb_buffer, (void *)last_addr, req->wLength); | 423 | if(req->bRequest == HWSTUB_READ2_ATOMIC) |
424 | { | ||
425 | if(!read_atomic(usb_buffer, (void *)last_addr, req->wLength)) | ||
426 | return usb_drv_stall(EP_CONTROL, true, true); | ||
427 | } | ||
428 | else | ||
429 | memcpy(usb_buffer, (void *)last_addr, req->wLength); | ||
381 | asm volatile("nop" : : : "memory"); | 430 | asm volatile("nop" : : : "memory"); |
382 | usb_drv_send(EP_CONTROL, usb_buffer, req->wLength); | 431 | usb_drv_send(EP_CONTROL, usb_buffer, req->wLength); |
383 | usb_drv_recv(EP_CONTROL, NULL, 0); | 432 | usb_drv_recv(EP_CONTROL, NULL, 0); |
384 | } | 433 | } |
385 | }; | 434 | }; |
386 | 435 | ||
436 | static bool write_atomic(void *dst, void *src, size_t sz) | ||
437 | { | ||
438 | switch(sz) | ||
439 | { | ||
440 | case 1: target_write8(dst, *(uint8_t *)src); return true; | ||
441 | case 2: target_write16(dst, *(uint16_t *)src); return true; | ||
442 | case 4: target_write32(dst, *(uint32_t *)src); return true; | ||
443 | default: return false; | ||
444 | } | ||
445 | } | ||
446 | |||
387 | static void handle_write(struct usb_ctrlrequest *req) | 447 | static void handle_write(struct usb_ctrlrequest *req) |
388 | { | 448 | { |
389 | int size = usb_drv_recv(EP_CONTROL, usb_buffer, req->wLength); | 449 | int size = usb_drv_recv(EP_CONTROL, usb_buffer, req->wLength); |
@@ -392,7 +452,13 @@ static void handle_write(struct usb_ctrlrequest *req) | |||
392 | int sz_hdr = sizeof(struct hwstub_write_req_t); | 452 | int sz_hdr = sizeof(struct hwstub_write_req_t); |
393 | if(size < sz_hdr) | 453 | if(size < sz_hdr) |
394 | return usb_drv_stall(EP_CONTROL, true, true); | 454 | return usb_drv_stall(EP_CONTROL, true, true); |
395 | memcpy((void *)write->dAddress, usb_buffer + sz_hdr, size - sz_hdr); | 455 | if(req->bRequest == HWSTUB_WRITE_ATOMIC) |
456 | { | ||
457 | if(!write_atomic((void *)write->dAddress, usb_buffer + sz_hdr, size - sz_hdr)) | ||
458 | return usb_drv_stall(EP_CONTROL, true, true); | ||
459 | } | ||
460 | else | ||
461 | memcpy((void *)write->dAddress, usb_buffer + sz_hdr, size - sz_hdr); | ||
396 | usb_drv_send(EP_CONTROL, NULL, 0); | 462 | usb_drv_send(EP_CONTROL, NULL, 0); |
397 | } | 463 | } |
398 | 464 | ||
@@ -451,8 +517,10 @@ static void handle_class_intf_req(struct usb_ctrlrequest *req) | |||
451 | return handle_get_log(req); | 517 | return handle_get_log(req); |
452 | case HWSTUB_READ: | 518 | case HWSTUB_READ: |
453 | case HWSTUB_READ2: | 519 | case HWSTUB_READ2: |
520 | case HWSTUB_READ2_ATOMIC: | ||
454 | return handle_read(req); | 521 | return handle_read(req); |
455 | case HWSTUB_WRITE: | 522 | case HWSTUB_WRITE: |
523 | case HWSTUB_WRITE_ATOMIC: | ||
456 | return handle_write(req); | 524 | return handle_write(req); |
457 | case HWSTUB_EXEC: | 525 | case HWSTUB_EXEC: |
458 | return handle_exec(req); | 526 | return handle_exec(req); |
diff --git a/utils/hwstub/stub/protocol.h b/utils/hwstub/stub/protocol.h index e358bb0a36..d551342d4b 100644 --- a/utils/hwstub/stub/protocol.h +++ b/utils/hwstub/stub/protocol.h | |||
@@ -1,3 +1,3 @@ | |||
1 | #include "../hwstub_protocol.h" | 1 | #include "../hwstub_protocol.h" |
2 | 2 | ||
3 | #define HWSTUB_VERSION_REV 1 \ No newline at end of file | 3 | #define HWSTUB_VERSION_REV 0 \ No newline at end of file |
diff --git a/utils/hwstub/stub/target.h b/utils/hwstub/stub/target.h index cb17401a9c..5cd049d04f 100644 --- a/utils/hwstub/stub/target.h +++ b/utils/hwstub/stub/target.h | |||
@@ -33,6 +33,14 @@ void target_get_config_desc(void *buffer, int *size); | |||
33 | void target_udelay(int us); | 33 | void target_udelay(int us); |
34 | /* Wait for a short time (ms <= 1000) */ | 34 | /* Wait for a short time (ms <= 1000) */ |
35 | void target_mdelay(int ms); | 35 | void target_mdelay(int ms); |
36 | /* Read a n-bit word atomically */ | ||
37 | uint8_t target_read8(const void *addr); | ||
38 | uint16_t target_read16(const void *addr); | ||
39 | uint32_t target_read32(const void *addr); | ||
40 | /* Write a n-bit word atomically */ | ||
41 | void target_write8(void *addr, uint8_t val); | ||
42 | void target_write16(void *addr, uint16_t val); | ||
43 | void target_write32(void *addr, uint32_t val); | ||
36 | 44 | ||
37 | /* mandatory for all targets */ | 45 | /* mandatory for all targets */ |
38 | extern struct hwstub_target_desc_t target_descriptor; | 46 | extern struct hwstub_target_desc_t target_descriptor; |
diff --git a/utils/hwstub/tools/hwstub_shell.cpp b/utils/hwstub/tools/hwstub_shell.cpp index b2838ebed0..30d1ac3b3f 100644 --- a/utils/hwstub/tools/hwstub_shell.cpp +++ b/utils/hwstub/tools/hwstub_shell.cpp | |||
@@ -144,7 +144,7 @@ typedef void (*hw_writen_fn_t)(lua_State *state, soc_addr_t addr, soc_word_t val | |||
144 | soc_word_t hw_read8(lua_State *state, soc_addr_t addr) | 144 | soc_word_t hw_read8(lua_State *state, soc_addr_t addr) |
145 | { | 145 | { |
146 | uint8_t u; | 146 | uint8_t u; |
147 | if(hwstub_rw_mem(g_hwdev, 1, addr, &u, sizeof(u)) != sizeof(u)) | 147 | if(hwstub_rw_mem_atomic(g_hwdev, 1, addr, &u, sizeof(u)) != sizeof(u)) |
148 | luaL_error(state, "fail to read8 @ %p", addr); | 148 | luaL_error(state, "fail to read8 @ %p", addr); |
149 | return u; | 149 | return u; |
150 | } | 150 | } |
@@ -152,7 +152,7 @@ soc_word_t hw_read8(lua_State *state, soc_addr_t addr) | |||
152 | soc_word_t hw_read16(lua_State *state, soc_addr_t addr) | 152 | soc_word_t hw_read16(lua_State *state, soc_addr_t addr) |
153 | { | 153 | { |
154 | uint16_t u; | 154 | uint16_t u; |
155 | if(hwstub_rw_mem(g_hwdev, 1, addr, &u, sizeof(u)) != sizeof(u)) | 155 | if(hwstub_rw_mem_atomic(g_hwdev, 1, addr, &u, sizeof(u)) != sizeof(u)) |
156 | luaL_error(state, "fail to read16 @ %p", addr); | 156 | luaL_error(state, "fail to read16 @ %p", addr); |
157 | return u; | 157 | return u; |
158 | } | 158 | } |
@@ -160,7 +160,7 @@ soc_word_t hw_read16(lua_State *state, soc_addr_t addr) | |||
160 | soc_word_t hw_read32(lua_State *state, soc_addr_t addr) | 160 | soc_word_t hw_read32(lua_State *state, soc_addr_t addr) |
161 | { | 161 | { |
162 | uint32_t u; | 162 | uint32_t u; |
163 | if(hwstub_rw_mem(g_hwdev, 1, addr, &u, sizeof(u)) != sizeof(u)) | 163 | if(hwstub_rw_mem_atomic(g_hwdev, 1, addr, &u, sizeof(u)) != sizeof(u)) |
164 | luaL_error(state, "fail to read32 @ %p", addr); | 164 | luaL_error(state, "fail to read32 @ %p", addr); |
165 | return u; | 165 | return u; |
166 | } | 166 | } |
@@ -168,21 +168,21 @@ soc_word_t hw_read32(lua_State *state, soc_addr_t addr) | |||
168 | void hw_write8(lua_State *state, soc_addr_t addr, soc_word_t val) | 168 | void hw_write8(lua_State *state, soc_addr_t addr, soc_word_t val) |
169 | { | 169 | { |
170 | uint8_t u = val; | 170 | uint8_t u = val; |
171 | if(hwstub_rw_mem(g_hwdev, 0, addr, &u, sizeof(u)) != sizeof(u)) | 171 | if(hwstub_rw_mem_atomic(g_hwdev, 0, addr, &u, sizeof(u)) != sizeof(u)) |
172 | luaL_error(state, "fail to write8 @ %p", addr); | 172 | luaL_error(state, "fail to write8 @ %p", addr); |
173 | } | 173 | } |
174 | 174 | ||
175 | void hw_write16(lua_State *state, soc_addr_t addr, soc_word_t val) | 175 | void hw_write16(lua_State *state, soc_addr_t addr, soc_word_t val) |
176 | { | 176 | { |
177 | uint16_t u = val; | 177 | uint16_t u = val; |
178 | if(hwstub_rw_mem(g_hwdev, 0, addr, &u, sizeof(u)) != sizeof(u)) | 178 | if(hwstub_rw_mem_atomic(g_hwdev, 0, addr, &u, sizeof(u)) != sizeof(u)) |
179 | luaL_error(state, "fail to write16 @ %p", addr); | 179 | luaL_error(state, "fail to write16 @ %p", addr); |
180 | } | 180 | } |
181 | 181 | ||
182 | void hw_write32(lua_State *state, soc_addr_t addr, soc_word_t val) | 182 | void hw_write32(lua_State *state, soc_addr_t addr, soc_word_t val) |
183 | { | 183 | { |
184 | uint32_t u = val; | 184 | uint32_t u = val; |
185 | if(hwstub_rw_mem(g_hwdev, 0, addr, &u, sizeof(u)) != sizeof(u)) | 185 | if(hwstub_rw_mem_atomic(g_hwdev, 0, addr, &u, sizeof(u)) != sizeof(u)) |
186 | luaL_error(state, "fail to write32 @ %p", addr); | 186 | luaL_error(state, "fail to write32 @ %p", addr); |
187 | } | 187 | } |
188 | 188 | ||
diff --git a/utils/hwstub/tools/init.lua b/utils/hwstub/tools/init.lua index 1fe0e0d734..aaca8b6c82 100644 --- a/utils/hwstub/tools/init.lua +++ b/utils/hwstub/tools/init.lua | |||
@@ -38,8 +38,8 @@ do | |||
38 | h = HELP:create_topic("DEV"); | 38 | h = HELP:create_topic("DEV"); |
39 | h:add("This variable redirects to hwstub.dev and provides direct access to the device."); | 39 | h:add("This variable redirects to hwstub.dev and provides direct access to the device."); |
40 | h:add("It contains some information about the device and the following methods."); | 40 | h:add("It contains some information about the device and the following methods."); |
41 | h:add("* read8/16/32(a) reads a 8/16/32-bit integer at address a"); | 41 | h:add("* read8/16/32(a) reads a 8/16/32-bit integer at address a atomically"); |
42 | h:add("* write8/16/32(a, v) writes the 8/16/32-bit integer v at address a"); | 42 | h:add("* write8/16/32(a, v) writes the 8/16/32-bit integer v at address a atomically"); |
43 | h:add("* print_log() prints the device log"); | 43 | h:add("* print_log() prints the device log"); |
44 | 44 | ||
45 | h = HELP:create_topic("HW"); | 45 | h = HELP:create_topic("HW"); |
diff --git a/utils/regtools/qeditor/backend.cpp b/utils/regtools/qeditor/backend.cpp index 570ae4d01f..e73263d30a 100644 --- a/utils/regtools/qeditor/backend.cpp +++ b/utils/regtools/qeditor/backend.cpp | |||
@@ -266,7 +266,7 @@ bool HWStubDevice::ReadMem(soc_addr_t addr, size_t length, void *buffer) | |||
266 | { | 266 | { |
267 | if(!m_hwdev) | 267 | if(!m_hwdev) |
268 | return false; | 268 | return false; |
269 | int ret = hwstub_rw_mem(m_hwdev, 1, addr, buffer, length); | 269 | int ret = hwstub_rw_mem_atomic(m_hwdev, 1, addr, buffer, length); |
270 | return ret >= 0 && (size_t)ret == length; | 270 | return ret >= 0 && (size_t)ret == length; |
271 | } | 271 | } |
272 | 272 | ||
@@ -274,7 +274,7 @@ bool HWStubDevice::WriteMem(soc_addr_t addr, size_t length, void *buffer) | |||
274 | { | 274 | { |
275 | if(!m_hwdev) | 275 | if(!m_hwdev) |
276 | return false; | 276 | return false; |
277 | int ret = hwstub_rw_mem(m_hwdev, 0, addr, buffer, length); | 277 | int ret = hwstub_rw_mem_atomic(m_hwdev, 0, addr, buffer, length); |
278 | return ret >= 0 && (size_t)ret == length; | 278 | return ret >= 0 && (size_t)ret == length; |
279 | } | 279 | } |
280 | 280 | ||