summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorMarcin Bukat <marcin.bukat@gmail.com>2014-11-18 23:27:26 +0100
committerMarcin Bukat <marcin.bukat@gmail.com>2014-11-18 23:30:44 +0100
commitcd04a5f1aadc8e2ec4e787f5ba4cc8c38a579314 (patch)
tree63e9f095451aeba0139152c8742d0af67413690a /utils
parent794169a18f644eea32de20b26646381137545e2d (diff)
downloadrockbox-cd04a5f1aadc8e2ec4e787f5ba4cc8c38a579314.tar.gz
rockbox-cd04a5f1aadc8e2ec4e787f5ba4cc8c38a579314.zip
hwstub/qeditor: add support for atomic read/writes
The current code assumed that READ/WRITE would produce atomic read/writes for 8/16/32-bit words, which in turned put assumption on the memcpy function. Since some memcpy implementation do not always guarantee such strong assumption, introduce two new operation READ/WRITE_ATOMIC which provide the necessary tools to do correct read and write to register in a single memory access. Change-Id: I37451bd5057bb0dcaf5a800d8aef8791c792a090
Diffstat (limited to 'utils')
-rw-r--r--utils/hwstub/hwstub_protocol.h10
-rw-r--r--utils/hwstub/lib/hwstub.c40
-rw-r--r--utils/hwstub/lib/hwstub.h5
-rw-r--r--utils/hwstub/stub/SOURCES2
-rw-r--r--utils/hwstub/stub/asm/arm/atomic_rw.S58
-rw-r--r--utils/hwstub/stub/asm/mips/atomic_rw.S61
-rw-r--r--utils/hwstub/stub/main.c72
-rw-r--r--utils/hwstub/stub/protocol.h2
-rw-r--r--utils/hwstub/stub/target.h8
-rw-r--r--utils/hwstub/tools/hwstub_shell.cpp12
-rw-r--r--utils/hwstub/tools/init.lua4
-rw-r--r--utils/regtools/qeditor/backend.cpp4
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
157struct hwstub_read_req_t 162struct 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 */
167struct hwstub_write_req_t 173struct 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
143static int _hwstub_read(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz) 143static 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
157static int _hwstub_write(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz) 158static 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
172int 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
180int 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 */
171int hwstub_read(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz) 189int 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 */
188int hwstub_write(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz) 206int 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
228int 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
210int hwstub_exec(struct hwstub_device_t *dev, uint32_t addr, uint16_t flags) 234int 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
53int hwstub_get_log(struct hwstub_device_t *dev, void *buf, size_t sz); 53int 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 */
55int hwstub_read(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz); 55int hwstub_read(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz);
56int hwstub_write(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz); 56int hwstub_read_atomic(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz);
57int hwstub_write(struct hwstub_device_t *dev, uint32_t addr, const void *buf, size_t sz);
58int hwstub_write_atomic(struct hwstub_device_t *dev, uint32_t addr, const void *buf, size_t sz);
57int hwstub_rw_mem(struct hwstub_device_t *dev, int read, uint32_t addr, void *buf, size_t sz); 59int hwstub_rw_mem(struct hwstub_device_t *dev, int read, uint32_t addr, void *buf, size_t sz);
60int 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 */
59int hwstub_exec(struct hwstub_device_t *dev, uint32_t addr, uint16_t flags); 62int hwstub_exec(struct hwstub_device_t *dev, uint32_t addr, uint16_t flags);
60int hwstub_call(struct hwstub_device_t *dev, uint32_t addr); 63int 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 @@
2asm/arm/memcpy.S 2asm/arm/memcpy.S
3asm/arm/memmove.S 3asm/arm/memmove.S
4asm/arm/memset.S 4asm/arm/memset.S
5asm/arm/atomic_rw.S
5#elif defined(CPU_MIPS) 6#elif defined(CPU_MIPS)
6asm/mips/memcpy.S 7asm/mips/memcpy.S
7asm/mips/memset.S 8asm/mips/memset.S
9asm/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
35target_read8:
36 ldrb r0, [r0]
37 bx lr
38
39target_read16:
40 ldrh r0, [r0]
41 bx lr
42
43target_read32:
44 ldr r0, [r0]
45 bx lr
46
47target_write8:
48 strb r1, [r0]
49 bx lr
50
51target_write16:
52 strh r1, [r0]
53 bx lr
54
55target_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
37target_read8:
38 jr ra
39 lbu v0, 0(a0)
40
41target_read16:
42 jr ra
43 lhu v0, 0(a0)
44
45target_read32:
46 jr ra
47 lw v0, 0(a0)
48
49target_write8:
50 jr ra
51 sb a1, 0(a0)
52
53target_write16:
54 jr ra
55 sh a1, 0(a0)
56
57target_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... */
361uint8_t __attribute__((weak)) target_read8(const void *addr)
362{
363 return *(volatile uint8_t *)addr;
364}
365
366uint16_t __attribute__((weak)) target_read16(const void *addr)
367{
368 return *(volatile uint16_t *)addr;
369}
370
371uint32_t __attribute__((weak)) target_read32(const void *addr)
372{
373 return *(volatile uint32_t *)addr;
374}
375
376void __attribute__((weak)) target_write8(void *addr, uint8_t val)
377{
378 *(volatile uint8_t *)addr = val;
379}
380
381void __attribute__((weak)) target_write16(void *addr, uint16_t val)
382{
383 *(volatile uint16_t *)addr = val;
384}
385
386void __attribute__((weak)) target_write32(void *addr, uint32_t val)
387{
388 *(volatile uint32_t *)addr = val;
389}
390
391static 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
359static void handle_read(struct usb_ctrlrequest *req) 402static 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
436static 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
387static void handle_write(struct usb_ctrlrequest *req) 447static 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);
33void target_udelay(int us); 33void target_udelay(int us);
34/* Wait for a short time (ms <= 1000) */ 34/* Wait for a short time (ms <= 1000) */
35void target_mdelay(int ms); 35void target_mdelay(int ms);
36/* Read a n-bit word atomically */
37uint8_t target_read8(const void *addr);
38uint16_t target_read16(const void *addr);
39uint32_t target_read32(const void *addr);
40/* Write a n-bit word atomically */
41void target_write8(void *addr, uint8_t val);
42void target_write16(void *addr, uint16_t val);
43void target_write32(void *addr, uint32_t val);
36 44
37/* mandatory for all targets */ 45/* mandatory for all targets */
38extern struct hwstub_target_desc_t target_descriptor; 46extern 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
144soc_word_t hw_read8(lua_State *state, soc_addr_t addr) 144soc_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)
152soc_word_t hw_read16(lua_State *state, soc_addr_t addr) 152soc_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)
160soc_word_t hw_read32(lua_State *state, soc_addr_t addr) 160soc_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)
168void hw_write8(lua_State *state, soc_addr_t addr, soc_word_t val) 168void 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
175void hw_write16(lua_State *state, soc_addr_t addr, soc_word_t val) 175void 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
182void hw_write32(lua_State *state, soc_addr_t addr, soc_word_t val) 182void 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