diff options
Diffstat (limited to 'utils/hwstub/stub')
-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 |
6 files changed, 200 insertions, 3 deletions
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; |