diff options
26 files changed, 2063 insertions, 1195 deletions
diff --git a/utils/hwstub/hwemul_protocol.h b/utils/hwstub/hwstub_protocol.h index f11fd91352..41be3957e8 100644 --- a/utils/hwstub/hwemul_protocol.h +++ b/utils/hwstub/hwstub_protocol.h @@ -18,19 +18,19 @@ * KIND, either express or implied. * ****************************************************************************/ -#ifndef __HWEMUL_PROTOCOL__ -#define __HWEMUL_PROTOCOL__ +#ifndef __HWSTUB_PROTOCOL__ +#define __HWSTUB_PROTOCOL__ -#define HWEMUL_CLASS 0xfe -#define HWEMUL_SUBCLASS 0xac -#define HWEMUL_PROTOCOL 0x1d +#define HWSTUB_CLASS 0xfe +#define HWSTUB_SUBCLASS 0xac +#define HWSTUB_PROTOCOL 0x1d -#define HWEMUL_VERSION_MAJOR 2 -#define HWEMUL_VERSION_MINOR 8 -#define HWEMUL_VERSION_REV 2 +#define HWSTUB_VERSION_MAJOR 2 +#define HWSTUB_VERSION_MINOR 9 +#define HWSTUB_VERSION_REV 2 -#define HWEMUL_USB_VID 0xfee1 -#define HWEMUL_USB_PID 0xdead +#define HWSTUB_USB_VID 0xfee1 +#define HWSTUB_USB_PID 0xdead /** * Control commands @@ -41,22 +41,22 @@ */ /* list of commands */ -#define HWEMUL_GET_INFO 0 /* mandatory */ -#define HWEMUL_GET_LOG 1 /* optional */ -#define HWEMUL_RW_MEM 2 /* optional */ -#define HWEMUL_CALL 3 /* optional */ -#define HWEMUL_JUMP 4 /* optional */ -#define HWEMUL_AES_OTP 5 /* optional */ +#define HWSTUB_GET_INFO 0 /* mandatory */ +#define HWSTUB_GET_LOG 1 /* optional */ +#define HWSTUB_RW_MEM 2 /* optional */ +#define HWSTUB_CALL 3 /* optional */ +#define HWSTUB_JUMP 4 /* optional */ +#define HWSTUB_AES_OTP 5 /* optional */ /** - * HWEMUL_GET_INFO: get some information about an aspect of the device. + * HWSTUB_GET_INFO: get some information about an aspect of the device. * The wIndex field of the SETUP specifies which information to get. */ /* list of possible information */ -#define HWEMUL_INFO_VERSION 0 -#define HWEMUL_INFO_LAYOUT 1 -#define HWEMUL_INFO_STMP 2 -#define HWEMUL_INFO_FEATURES 3 +#define HWSTUB_INFO_VERSION 0 +#define HWSTUB_INFO_LAYOUT 1 +#define HWSTUB_INFO_STMP 2 +#define HWSTUB_INFO_FEATURES 3 struct usb_resp_info_version_t { @@ -86,11 +86,11 @@ struct usb_resp_info_stmp_t } __attribute__((packed)); /* list of possible features */ -#define HWEMUL_FEATURE_LOG (1 << 0) -#define HWEMUL_FEATURE_MEM (1 << 1) -#define HWEMUL_FEATURE_CALL (1 << 2) -#define HWEMUL_FEATURE_JUMP (1 << 2) -#define HWEMUL_FEATURE_AES_OTP (1 << 3) +#define HWSTUB_FEATURE_LOG (1 << 0) +#define HWSTUB_FEATURE_MEM (1 << 1) +#define HWSTUB_FEATURE_CALL (1 << 2) +#define HWSTUB_FEATURE_JUMP (1 << 2) +#define HWSTUB_FEATURE_AES_OTP (1 << 3) struct usb_resp_info_features_t { @@ -98,30 +98,32 @@ struct usb_resp_info_features_t }; /** - * HWEMUL_GET_LOG: only if has HWEMUL_FEATURE_LOG. + * HWSTUB_GET_LOG: only if has HWSTUB_FEATURE_LOG. * The log is returned as part of the control transfer. */ /** - * HWEMUL_RW_MEM: only if has HWEMUL_FEATURE_MEM. + * HWSTUB_RW_MEM: only if has HWSTUB_FEATURE_MEM. * The 32-bit address is split into two parts. * The low 16-bit are stored in wValue and the upper * 16-bit are stored in wIndex. Depending on the transfer direction, - * the transfer is either a read or a write. */ + * the transfer is either a read or a write. + * The read/write on the device are guaranteed to be 16-bit/32-bit when + * possible, making it suitable to read/write registers. */ /** - * HWEMUL_x: only if has HWEMUL_FEATURE_x where x=CALL or JUMP. + * HWSTUB_x: only if has HWSTUB_FEATURE_x where x=CALL or JUMP. * The 32-bit address is split into two parts. * The low 16-bit are stored in wValue and the upper * 16-bit are stored in wIndex. Depending on the transfer direction, * the transfer is either a read or a write. */ /** - * HWEMUL_AES_OTP: only if has HWEMUL_FEATURE_AES_OTP. + * HWSTUB_AES_OTP: only if has HWSTUB_FEATURE_AES_OTP. * The control transfer contains the data to be en/decrypted and the data * is sent back on the interrupt endpoint. The first 16-bytes of the data * are interpreted as the IV. The output format is the same. * The wValue field contains the parameters of the process. */ -#define HWEMUL_AES_OTP_ENCRYPT (1 << 0) +#define HWSTUB_AES_OTP_ENCRYPT (1 << 0) -#endif /* __HWEMUL_PROTOCOL__ */ +#endif /* __HWSTUB_PROTOCOL__ */ diff --git a/utils/hwstub/lib/Makefile b/utils/hwstub/lib/Makefile index 7280fe8e38..7c455e4586 100644 --- a/utils/hwstub/lib/Makefile +++ b/utils/hwstub/lib/Makefile @@ -2,26 +2,19 @@ CC=gcc AR=ar CFLAGS=-W -Wall -O2 `pkg-config --cflags libusb-1.0` -std=c99 -g -fPIC LDFLAGS=`pkg-config --libs libusb-1.0` -fPIC -LIB=libhwemul.a -REGTOOLS=../../regtools -DESC=$(REGTOOLS)/desc -HWEMULGEN=$(REGTOOLS)/hwemulgen -HWEMULSOC_PREFIX=hwemul_soc -SRC=$(wildcard *.c) $(HWEMULSOC_PREFIX).c +LIB=libhwstub.a +SRC=$(wildcard *.c) OBJ=$(SRC:.c=.o) -all: $(LIB) $(EXEC) +all: $(LIB) -$(HWEMULSOC_PREFIX).c $(HWEMULSOC_PREFIX).h: - $(HWEMULGEN) $(DESC)/*.xml $(HWEMULSOC_PREFIX) - -%.o: %.c $(HWEMULSOC_PREFIX).h +%.o: %.c $(CC) $(CFLAGS) -c -o $@ $< $(LIB): $(OBJ) $(AR) rcs $@ $^ clean: - rm -rf $(OBJ) $(LIB) $(HWEMULSOC_PREFIX).c $(HWEMULSOC_PREFIX).h + rm -rf $(OBJ) $(LIB) diff --git a/utils/hwstub/lib/hwemul_protocol.h b/utils/hwstub/lib/hwemul_protocol.h deleted file mode 100644 index d3ffb6ce00..0000000000 --- a/utils/hwstub/lib/hwemul_protocol.h +++ /dev/null @@ -1 +0,0 @@ -#include "../hwemul_protocol.h" diff --git a/utils/hwstub/lib/hwemul.c b/utils/hwstub/lib/hwstub.c index 3e2e6de38a..92010e710b 100644 --- a/utils/hwstub/lib/hwemul.c +++ b/utils/hwstub/lib/hwstub.c @@ -18,15 +18,14 @@ * KIND, either express or implied. * ****************************************************************************/ -#include "hwemul.h" -#include "hwemul_soc.h" +#include "hwstub.h" #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif /* requires then ->handle field only */ -int hwemul_probe(struct hwemul_device_t *dev) +int hwstub_probe(struct hwstub_device_t *dev) { libusb_device *mydev = libusb_get_device(dev->handle); @@ -44,9 +43,9 @@ int hwemul_probe(struct hwemul_device_t *dev) const struct libusb_interface_descriptor *interface = &config->interface[intf].altsetting[0]; if(interface->bNumEndpoints != 3 || - interface->bInterfaceClass != HWEMUL_CLASS || - interface->bInterfaceSubClass != HWEMUL_SUBCLASS || - interface->bInterfaceProtocol != HWEMUL_PROTOCOL) + interface->bInterfaceClass != HWSTUB_CLASS || + interface->bInterfaceSubClass != HWSTUB_SUBCLASS || + interface->bInterfaceProtocol != HWSTUB_PROTOCOL) continue; dev->intf = intf; dev->bulk_in = dev->bulk_out = dev->int_in = -1; @@ -73,26 +72,26 @@ int hwemul_probe(struct hwemul_device_t *dev) return libusb_claim_interface(dev->handle, intf); } -int hwemul_release(struct hwemul_device_t *dev) +int hwstub_release(struct hwstub_device_t *dev) { return libusb_release_interface(dev->handle, dev->intf); } -int hwemul_get_info(struct hwemul_device_t *dev, uint16_t idx, void *info, size_t sz) +int hwstub_get_info(struct hwstub_device_t *dev, uint16_t idx, void *info, size_t sz) { return libusb_control_transfer(dev->handle, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN, - HWEMUL_GET_INFO, 0, idx, info, sz, 1000); + HWSTUB_GET_INFO, 0, idx, info, sz, 1000); } -int hwemul_get_log(struct hwemul_device_t *dev, void *buf, size_t sz) +int hwstub_get_log(struct hwstub_device_t *dev, void *buf, size_t sz) { return libusb_control_transfer(dev->handle, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN, - HWEMUL_GET_LOG, 0, 0, buf, sz, 1000); + HWSTUB_GET_LOG, 0, 0, buf, sz, 1000); } -int hwemul_rw_mem(struct hwemul_device_t *dev, int read, uint32_t addr, void *buf, size_t sz) +int hwstub_rw_mem(struct hwstub_device_t *dev, int read, uint32_t addr, void *buf, size_t sz) { size_t tot_sz = 0; while(sz) @@ -101,7 +100,7 @@ int hwemul_rw_mem(struct hwemul_device_t *dev, int read, uint32_t addr, void *bu int ret = libusb_control_transfer(dev->handle, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE | (read ? LIBUSB_ENDPOINT_IN : LIBUSB_ENDPOINT_OUT), - HWEMUL_RW_MEM, addr & 0xffff, addr >> 16, buf, xfer, 1000); + HWSTUB_RW_MEM, addr & 0xffff, addr >> 16, buf, xfer, 1000); if(ret != xfer) return ret; sz -= xfer; @@ -112,23 +111,23 @@ int hwemul_rw_mem(struct hwemul_device_t *dev, int read, uint32_t addr, void *bu return tot_sz; } -int hwemul_call(struct hwemul_device_t *dev, uint32_t addr) +int hwstub_call(struct hwstub_device_t *dev, uint32_t addr) { return libusb_control_transfer(dev->handle, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE | - LIBUSB_ENDPOINT_OUT, HWEMUL_CALL, addr & 0xffff, addr >> 16, NULL, 0, + LIBUSB_ENDPOINT_OUT, HWSTUB_CALL, addr & 0xffff, addr >> 16, NULL, 0, 1000); } -int hwemul_jump(struct hwemul_device_t *dev, uint32_t addr) +int hwstub_jump(struct hwstub_device_t *dev, uint32_t addr) { return libusb_control_transfer(dev->handle, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE | - LIBUSB_ENDPOINT_OUT, HWEMUL_JUMP, addr & 0xffff, addr >> 16, NULL, 0, + LIBUSB_ENDPOINT_OUT, HWSTUB_JUMP, addr & 0xffff, addr >> 16, NULL, 0, 1000); } -const char *hwemul_get_product_string(struct usb_resp_info_stmp_t *stmp) +const char *hwstub_get_product_string(struct usb_resp_info_stmp_t *stmp) { switch(stmp->chipid) { @@ -139,7 +138,7 @@ const char *hwemul_get_product_string(struct usb_resp_info_stmp_t *stmp) } } -const char *hwemul_get_rev_string(struct usb_resp_info_stmp_t *stmp) +const char *hwstub_get_rev_string(struct usb_resp_info_stmp_t *stmp) { switch(stmp->chipid) { @@ -159,11 +158,11 @@ const char *hwemul_get_rev_string(struct usb_resp_info_stmp_t *stmp) } } -int hwemul_aes_otp(struct hwemul_device_t *dev, void *buf, size_t sz, uint16_t param) +int hwstub_aes_otp(struct hwstub_device_t *dev, void *buf, size_t sz, uint16_t param) { int ret = libusb_control_transfer(dev->handle, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE | - LIBUSB_ENDPOINT_OUT, HWEMUL_AES_OTP, param, 0, buf, sz, + LIBUSB_ENDPOINT_OUT, HWSTUB_AES_OTP, param, 0, buf, sz, 1000); if(ret <0 || (unsigned)ret != sz) return -1; diff --git a/utils/hwstub/lib/hwemul.h b/utils/hwstub/lib/hwstub.h index 376ba65381..ed058dfa3b 100644 --- a/utils/hwstub/lib/hwemul.h +++ b/utils/hwstub/lib/hwstub.h @@ -18,12 +18,15 @@ * KIND, either express or implied. * ****************************************************************************/ -#ifndef __HWEMUL__ -#define __HWEMUL__ +#ifndef __HWSTUB__ +#define __HWSTUB__ #include <libusb.h> -#include "hwemul_protocol.h" -#include "hwemul_soc.h" +#include "hwstub_protocol.h" + +#ifdef __cplusplus +extern "C" { +#endif /** * @@ -31,7 +34,7 @@ * */ -struct hwemul_device_t +struct hwstub_device_t { libusb_device_handle *handle; int intf; @@ -41,23 +44,27 @@ struct hwemul_device_t }; /* Requires then ->handle field only. Returns 0 on success */ -int hwemul_probe(struct hwemul_device_t *dev); +int hwstub_probe(struct hwstub_device_t *dev); /* Returns 0 on success */ -int hwemul_release(struct hwemul_device_t *dev); +int hwstub_release(struct hwstub_device_t *dev); /* Returns number of bytes filled */ -int hwemul_get_info(struct hwemul_device_t *dev, uint16_t idx, void *info, size_t sz); +int hwstub_get_info(struct hwstub_device_t *dev, uint16_t idx, void *info, size_t sz); /* Returns number of bytes filled */ -int hwemul_get_log(struct hwemul_device_t *dev, void *buf, size_t sz); +int hwstub_get_log(struct hwstub_device_t *dev, void *buf, size_t sz); /* Returns number of bytes written/read or <0 on error */ -int hwemul_rw_mem(struct hwemul_device_t *dev, int read, uint32_t addr, void *buf, size_t sz); +int hwstub_rw_mem(struct hwstub_device_t *dev, int read, uint32_t addr, void *buf, size_t sz); /* Returns <0 on error */ -int hwemul_call(struct hwemul_device_t *dev, uint32_t addr); -int hwemul_jump(struct hwemul_device_t *dev, uint32_t addr); +int hwstub_call(struct hwstub_device_t *dev, uint32_t addr); +int hwstub_jump(struct hwstub_device_t *dev, uint32_t addr); /* Returns <0 on error. The size must be a multiple of 16. */ -int hwemul_aes_otp(struct hwemul_device_t *dev, void *buf, size_t sz, uint16_t param); +int hwstub_aes_otp(struct hwstub_device_t *dev, void *buf, size_t sz, uint16_t param); + +const char *hwstub_get_product_string(struct usb_resp_info_stmp_t *stmp); +const char *hwstub_get_rev_string(struct usb_resp_info_stmp_t *stmp); -const char *hwemul_get_product_string(struct usb_resp_info_stmp_t *stmp); -const char *hwemul_get_rev_string(struct usb_resp_info_stmp_t *stmp); +#ifdef __cplusplus +} // extern "C" +#endif -#endif /* __HWEMUL__ */
\ No newline at end of file +#endif /* __HWSTUB__ */
\ No newline at end of file diff --git a/utils/hwstub/lib/hwstub_protocol.h b/utils/hwstub/lib/hwstub_protocol.h new file mode 100644 index 0000000000..35510fa9b2 --- /dev/null +++ b/utils/hwstub/lib/hwstub_protocol.h @@ -0,0 +1 @@ +#include "../hwstub_protocol.h" diff --git a/utils/hwstub/stmp/Makefile b/utils/hwstub/stmp/Makefile index ca61fe392d..7fd33c3d9e 100644 --- a/utils/hwstub/stmp/Makefile +++ b/utils/hwstub/stmp/Makefile @@ -1,58 +1,51 @@ -PREFIX?=arm-elf-eabi- -CC=$(PREFIX)gcc -LD=$(PREFIX)gcc -AS=$(PREFIX)gcc -OC=$(PREFIX)objcopy -SBTOOLS=../../sbtools/ +# +# common +# +CC=arm-elf-eabi-gcc +LD=arm-elf-eabi-gcc +AS=arm-elf-eabi-gcc +OC=arm-elf-eabi-objcopy CFLAGS=-W -Wall -Wundef -O -nostdlib -ffreestanding -Wstrict-prototypes -pipe -std=gnu99 -mcpu=arm926ej-s -fomit-frame-pointer -Wno-pointer-sign -Wno-override-init -ffunction-sections -CFLAGS_3700=$(CFLAGS) -DHAVE_STMP3700 ASFLAGS=$(CFLAGS) -D__ASSEMBLER__ -ASFLAGS_3700=$(CFLAGS_3700) -D__ASSEMBLER__ OCFLAGS= -LINKER_FILE=hwemul.lds -LDFLAGS=-lgcc -Os -nostdlib -Tlink.lds -Wl,-Map,hwemul.map -LDFLAGS_3700=-lgcc -Os -nostdlib -Tlink.lds -Wl,-Map,hwemul3700.map +LINKER_FILE=hwstub.lds +TMP_LDS=link.lds +TMP_MAP=hwstub.map +LDFLAGS=-lgcc -Os -nostdlib -T$(TMP_LDS) -Wl,-Map,$(TMP_MAP) SRC_C=$(wildcard *.c) SRC_S=$(wildcard *.S) OBJ_C=$(SRC_C:.c=.o) OBJ_S=$(SRC_S:.S=.o) -OBJ_C_3700=$(SRC_C:.c=.3700.o) -OBJ_S_3700=$(SRC_S:.S=.3700.o) OBJ=$(OBJ_C) $(OBJ_S) -OBJ_3700=$(OBJ_C_3700) $(OBJ_S_3700) OBJ_EXCEPT_CRT0=$(filter-out crt0.o,$(OBJ)) -OBJ_EXCEPT_CRT0_3700=$(filter-out crt0.3700.o,$(OBJ_3700)) DEPS=$(OBJ:.o=.d) -EXEC_ELF=hwemul.elf -EXEC_SB=hwemul.sb -EXEC_ELF_3700=hwemul3700.elf -EXEC_SB_3700=hwemul3700.sb +EXEC_ELF=hwstub.elf +# +# image production +# +TOOLS=../../../tools +SBTOOLS=../../imxtools/sbtools + +# sb (stmp37xx) +EXEC_SB=hwstub.sb ELF2SB=$(SBTOOLS)/elftosb -d -ELF2SB_CMD=-c hwemul.db -ELF2SB_KEY=-z -SBLOADER=$(SBTOOLS)/sbloader -SBLOADER_CMD=0 $(EXEC_SB) -SBLOADER_CMD_3700=0 $(EXEC_SB_3700) +ELF2SB_CMD=-c hwstub.db +ELF2SB_KEY?=-z -TOOLS=../../../../tools/ -SCRAMBLE=$(TOOLS)/scramble +# sb1 (stmp36xx) +EXEC_SB1=hwstub.sb1 +ELF2SB1_CMD=-loadjump $(EXEC_ELF) +ELF2SB1_KEY?= +ELF2SB1=$(SBTOOLS)/elftosb1 -d -EXEC=$(EXEC_SB) $(EXEC_SB_3700) $(EXEC_ELF) $(EXEC_ELF_3700) +EXEC=$(EXEC_ELF) $(EXEC_SB) $(EXEC_SB1) all: $(EXEC) # pull in dependency info for *existing* .o files -include $(DEPS) -%.3700.o: %.c - $(CC) $(CFLAGS_3700) -c -o $@ $< - $(CC) -MM $(CFLAGS_3700) $*.c > $*.d - @cp -f $*.d $*.d.tmp - @sed -e 's/.*://' -e 's/\\$$//' < $*.d.tmp | fmt -1 | \ - sed -e 's/^ *//' -e 's/$$/:/' >> $*.d - @rm -f $*.d.tmp - %.o: %.c $(CC) $(CFLAGS) -c -o $@ $< $(CC) -MM $(CFLAGS) $*.c > $*.d @@ -61,32 +54,20 @@ all: $(EXEC) sed -e 's/^ *//' -e 's/$$/:/' >> $*.d @rm -f $*.d.tmp -%.3700.o: %.S - $(AS) $(ASFLAGS_3700) -c -o $@ $< - %.o: %.S $(AS) $(ASFLAGS) -c -o $@ $< -link.lds: $(LINKER_FILE) +$(TMP_LDS): $(LINKER_FILE) $(CC) -E -x c - < $< | sed '/#/d' > $@ - -$(EXEC_ELF): $(OBJ) link.lds + +$(EXEC_ELF): $(OBJ) $(TMP_LDS) $(LD) $(LDFLAGS) -o $@ $(OBJ_EXCEPT_CRT0) $(EXEC_SB): $(EXEC_ELF) $(ELF2SB) $(ELF2SB_CMD) $(ELF2SB_KEY) -o $@ -$(EXEC_ELF_3700): $(OBJ_3700) link.lds - $(LD) $(LDFLAGS_3700) -o $@ $(OBJ_EXCEPT_CRT0_3700) - -$(EXEC_SB_3700): $(EXEC_ELF_3700) - $(ELF2SB) $(ELF2SB_CMD) $(ELF2SB_KEY) -o $@ - -sbload: $(EXEC_SB) - $(SBLOADER) $(SBLOADER_CMD) - -sbload3700: $(EXEC_SB_3700) - $(SBLOADER) $(SBLOADER_CMD_3700) +$(EXEC_SB1): $(EXEC_ELF) + $(ELF2SB1) $(ELF2SB1_CMD) $(ELF2SB1_KEY) -o $@ clean: - rm -rf $(OBJ) $(OBJ_3700) $(DEPS) $(EXEC) *.map + rm -rf $(OBJ) $(DEPS) $(EXEC) $(TMP_LDS) $(TMP_MAP)
\ No newline at end of file diff --git a/utils/hwstub/stmp/config.h b/utils/hwstub/stmp/config.h index 6bd995e147..9d6de07f33 100644 --- a/utils/hwstub/stmp/config.h +++ b/utils/hwstub/stmp/config.h @@ -18,8 +18,8 @@ * KIND, either express or implied. * ****************************************************************************/ -#ifndef __HWEMUL_CONFIG__ -#define __HWEMUL_CONFIG__ +#ifndef __HWSTUB_CONFIG__ +#define __HWSTUB_CONFIG__ #define MEMORYSIZE 0 #define STACK_SIZE 0x1000 @@ -30,4 +30,27 @@ #define DRAM_ORIG 0x40000000 #define DRAM_SIZE (MEMORYSIZE * 0x100000) -#endif /* __HWEMUL_CONFIG__ */ +#define CPU_ARM +#define ARM_ARCH 5 + +#if defined(CPU_ARM) && defined(__ASSEMBLER__) +/* ARMv4T doesn't switch the T bit when popping pc directly, we must use BX */ +.macro ldmpc cond="", order="ia", regs +#if ARM_ARCH == 4 && defined(USE_THUMB) + ldm\cond\order sp!, { \regs, lr } + bx\cond lr +#else + ldm\cond\order sp!, { \regs, pc } +#endif +.endm +.macro ldrpc cond="" +#if ARM_ARCH == 4 && defined(USE_THUMB) + ldr\cond lr, [sp], #4 + bx\cond lr +#else + ldr\cond pc, [sp], #4 +#endif +.endm +#endif + +#endif /* __HWSTUB_CONFIG__ */ diff --git a/utils/hwstub/stmp/format.h b/utils/hwstub/stmp/format.h index a514c882ba..2ad4229f1e 100644 --- a/utils/hwstub/stmp/format.h +++ b/utils/hwstub/stmp/format.h @@ -18,12 +18,12 @@ * KIND, either express or implied. * ****************************************************************************/ -#ifndef __HWEMUL_FORMAT__ -#define __HWEMUL_FORMAT__ +#ifndef __HWSTUB_FORMAT__ +#define __HWSTUB_FORMAT__ #include <stdarg.h> void vuprintf(int (*push)(void *userp, unsigned char data), void *userp, const char *fmt, va_list ap); -#endif /* __HWEMUL_FORMAT__ */ +#endif /* __HWSTUB_FORMAT__ */ diff --git a/utils/hwstub/stmp/hwemul.db b/utils/hwstub/stmp/hwstub.db index 7a6f930f57..1a085da50a 100644 --- a/utils/hwstub/stmp/hwemul.db +++ b/utils/hwstub/stmp/hwstub.db @@ -20,12 +20,12 @@ ****************************************************************************/ sources { - hwemul = "hwemul.elf"; + hwstub = "hwstub.elf"; } section(0) { - load hwemul; - jump hwemul(1); + load hwstub; + jump hwstub(1); } diff --git a/utils/hwstub/stmp/hwemul.lds b/utils/hwstub/stmp/hwstub.lds index 7e3ac747a2..61504a3e75 100644 --- a/utils/hwstub/stmp/hwemul.lds +++ b/utils/hwstub/stmp/hwstub.lds @@ -38,6 +38,7 @@ SECTIONS { oc_codestart = .; *(.text*) + *(.icode*) *(.data*) *(.rodata*) } > OCRAM diff --git a/utils/hwstub/stmp/link.lds b/utils/hwstub/stmp/link.lds deleted file mode 100644 index 97b259955f..0000000000 --- a/utils/hwstub/stmp/link.lds +++ /dev/null @@ -1,49 +0,0 @@ - -ENTRY(start) -OUTPUT_FORMAT(elf32-littlearm) -OUTPUT_ARCH(arm) -STARTUP(crt0.o) - - - -MEMORY -{ - OCRAM : ORIGIN = 0, LENGTH = 0x8000 -} - -SECTIONS -{ - .octext : - { - oc_codestart = .; - *(.text*) - *(.data*) - *(.rodata*) - } > OCRAM - - .bss (NOLOAD) : - { - bss_start = .; - *(.bss) - bss_end = .; - } > OCRAM - - .stack (NOLOAD) : - { - oc_codeend = .; - oc_stackstart = .; - . += 0x1000; - oc_stackend = .; - oc_bufferstart = .; - } > OCRAM - - .ocend (0 + 0x8000) (NOLOAD) : - { - oc_bufferend = .; - } > OCRAM - - /DISCARD/ : - { - *(.eh_frame) - } -} diff --git a/utils/hwstub/stmp/logf.h b/utils/hwstub/stmp/logf.h index 5aa882a630..48c8c2c9b9 100644 --- a/utils/hwstub/stmp/logf.h +++ b/utils/hwstub/stmp/logf.h @@ -18,8 +18,8 @@ * KIND, either express or implied. * ****************************************************************************/ -#ifndef __HWEMUL_LOGF__ -#define __HWEMUL_LOGF__ +#ifndef __HWSTUB_LOGF__ +#define __HWSTUB_LOGF__ #include "stddef.h" #include <stdarg.h> @@ -28,4 +28,4 @@ void enable_logf(bool en); void logf(const char *fmt, ...); size_t logf_readback(char *buf, size_t max_size); -#endif /* __HWEMUL_LOGF__ */ +#endif /* __HWSTUB_LOGF__ */ diff --git a/utils/hwstub/stmp/main.c b/utils/hwstub/stmp/main.c index 09bb6c7714..845f3842ea 100644 --- a/utils/hwstub/stmp/main.c +++ b/utils/hwstub/stmp/main.c @@ -34,118 +34,20 @@ extern unsigned char oc_bufferend[]; /** * - * Pin control + * Global * */ -#define HW_PINCTRL_BASE 0x80018000 - -#define HW_PINCTRL_CTRL (*(volatile uint32_t *)(HW_PINCTRL_BASE + 0x0)) -#define HW_PINCTRL_MUXSEL(i) (*(volatile uint32_t *)(HW_PINCTRL_BASE + 0x100 + (i) * 0x10)) -#define HW_PINCTRL_DRIVE(i) (*(volatile uint32_t *)(HW_PINCTRL_BASE + 0x200 + (i) * 0x10)) -#ifdef HAVE_STMP3700 -#define HW_PINCTRL_PULL(i) (*(volatile uint32_t *)(HW_PINCTRL_BASE + 0x300 + (i) * 0x10)) -#define HW_PINCTRL_DOUT(i) (*(volatile uint32_t *)(HW_PINCTRL_BASE + 0x400 + (i) * 0x10)) -#define HW_PINCTRL_DIN(i) (*(volatile uint32_t *)(HW_PINCTRL_BASE + 0x500 + (i) * 0x10)) -#define HW_PINCTRL_DOE(i) (*(volatile uint32_t *)(HW_PINCTRL_BASE + 0x600 + (i) * 0x10)) -#define HW_PINCTRL_PIN2IRQ(i) (*(volatile uint32_t *)(HW_PINCTRL_BASE + 0x700 + (i) * 0x10)) -#define HW_PINCTRL_IRQEN(i) (*(volatile uint32_t *)(HW_PINCTRL_BASE + 0x800 + (i) * 0x10)) -#define HW_PINCTRL_IRQLEVEL(i) (*(volatile uint32_t *)(HW_PINCTRL_BASE + 0x900 + (i) * 0x10)) -#define HW_PINCTRL_IRQPOL(i) (*(volatile uint32_t *)(HW_PINCTRL_BASE + 0xa00 + (i) * 0x10)) -#define HW_PINCTRL_IRQSTAT(i) (*(volatile uint32_t *)(HW_PINCTRL_BASE + 0xb00 + (i) * 0x10)) -#else -#define HW_PINCTRL_PULL(i) (*(volatile uint32_t *)(HW_PINCTRL_BASE + 0x400 + (i) * 0x10)) -#define HW_PINCTRL_DOUT(i) (*(volatile uint32_t *)(HW_PINCTRL_BASE + 0x500 + (i) * 0x10)) -#define HW_PINCTRL_DIN(i) (*(volatile uint32_t *)(HW_PINCTRL_BASE + 0x600 + (i) * 0x10)) -#define HW_PINCTRL_DOE(i) (*(volatile uint32_t *)(HW_PINCTRL_BASE + 0x700 + (i) * 0x10)) -#define HW_PINCTRL_PIN2IRQ(i) (*(volatile uint32_t *)(HW_PINCTRL_BASE + 0x800 + (i) * 0x10)) -#define HW_PINCTRL_IRQEN(i) (*(volatile uint32_t *)(HW_PINCTRL_BASE + 0x900 + (i) * 0x10)) -#define HW_PINCTRL_IRQLEVEL(i) (*(volatile uint32_t *)(HW_PINCTRL_BASE + 0xa00 + (i) * 0x10)) -#define HW_PINCTRL_IRQPOL(i) (*(volatile uint32_t *)(HW_PINCTRL_BASE + 0xb00 + (i) * 0x10)) -#define HW_PINCTRL_IRQSTAT(i) (*(volatile uint32_t *)(HW_PINCTRL_BASE + 0xc00 + (i) * 0x10)) -#endif - -#define PINCTRL_FUNCTION_MAIN 0 -#define PINCTRL_FUNCTION_ALT1 1 -#define PINCTRL_FUNCTION_ALT2 2 -#define PINCTRL_FUNCTION_GPIO 3 - -#define PINCTRL_DRIVE_4mA 0 -#define PINCTRL_DRIVE_8mA 1 -#define PINCTRL_DRIVE_12mA 2 -#define PINCTRL_DRIVE_16mA 3 /* not available on all pins */ - -typedef void (*pin_irq_cb_t)(int bank, int pin); - -static inline void imx233_pinctrl_init(void) +enum stmp_family_t { - __REG_CLR(HW_PINCTRL_CTRL) = __BLOCK_CLKGATE | __BLOCK_SFTRST; -} - -static inline void imx233_set_pin_drive_strength(unsigned bank, unsigned pin, unsigned strength) -{ - __REG_CLR(HW_PINCTRL_DRIVE(4 * bank + pin / 8)) = 3 << (4 * (pin % 8)); - __REG_SET(HW_PINCTRL_DRIVE(4 * bank + pin / 8)) = strength << (4 * (pin % 8)); -} - -static inline void imx233_enable_gpio_output(unsigned bank, unsigned pin, bool enable) -{ - if(enable) - __REG_SET(HW_PINCTRL_DOE(bank)) = 1 << pin; - else - __REG_CLR(HW_PINCTRL_DOE(bank)) = 1 << pin; -} - -static inline void imx233_enable_gpio_output_mask(unsigned bank, uint32_t pin_mask, bool enable) -{ - if(enable) - __REG_SET(HW_PINCTRL_DOE(bank)) = pin_mask; - else - __REG_CLR(HW_PINCTRL_DOE(bank)) = pin_mask; -} - -static inline void imx233_set_gpio_output(unsigned bank, unsigned pin, bool value) -{ - if(value) - __REG_SET(HW_PINCTRL_DOUT(bank)) = 1 << pin; - else - __REG_CLR(HW_PINCTRL_DOUT(bank)) = 1 << pin; -} - -static inline void imx233_set_gpio_output_mask(unsigned bank, uint32_t pin_mask, bool value) -{ - if(value) - __REG_SET(HW_PINCTRL_DOUT(bank)) = pin_mask; - else - __REG_CLR(HW_PINCTRL_DOUT(bank)) = pin_mask; -} - -static inline uint32_t imx233_get_gpio_input_mask(unsigned bank, uint32_t pin_mask) -{ - return HW_PINCTRL_DIN(bank) & pin_mask; -} - -static inline void imx233_set_pin_function(unsigned bank, unsigned pin, unsigned function) -{ - __REG_CLR(HW_PINCTRL_MUXSEL(2 * bank + pin / 16)) = 3 << (2 * (pin % 16)); - __REG_SET(HW_PINCTRL_MUXSEL(2 * bank + pin / 16)) = function << (2 * (pin % 16)); -} - -static inline void imx233_enable_pin_pullup(unsigned bank, unsigned pin, bool enable) -{ - if(enable) - __REG_SET(HW_PINCTRL_PULL(bank)) = 1 << pin; - else - __REG_CLR(HW_PINCTRL_PULL(bank)) = 1 << pin; -} + UNKNOWN, + STMP3600, + STMP3700, + STMP3770, + STMP3780 +}; -static inline void imx233_enable_pin_pullup_mask(unsigned bank, uint32_t pin_msk, bool enable) -{ - if(enable) - __REG_SET(HW_PINCTRL_PULL(bank)) = pin_msk; - else - __REG_CLR(HW_PINCTRL_PULL(bank)) = pin_msk; -} +enum stmp_family_t g_stmp_family = UNKNOWN; /** * @@ -458,287 +360,38 @@ static void usb_drv_configure_endpoint(int ep_num, int type) /** * - * Clock control + * Clkctrl * - **/ -#define __CLK_CLKGATE (1 << 31) -#define __CLK_BUSY (1 << 29) + */ #define HW_CLKCTRL_BASE 0x80040000 #define HW_CLKCTRL_PLLCTRL0 (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x0)) +#define HW_CLKCTRL_PLLCTRL0__BYPASS (1 << 17) /* STMP3600 only */ #define HW_CLKCTRL_PLLCTRL0__POWER (1 << 16) #define HW_CLKCTRL_PLLCTRL0__EN_USB_CLKS (1 << 18) -#define HW_CLKCTRL_PLLCTRL0__DIV_SEL_BP 20 -#define HW_CLKCTRL_PLLCTRL0__DIV_SEL_BM (3 << 20) #define HW_CLKCTRL_PLLCTRL1 (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x10)) +#define HW_CLKCTRL_PLLCTRL1__LOCK (1 << 31) -#define HW_CLKCTRL_CPU (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x20)) -#define HW_CLKCTRL_CPU__DIV_CPU_BP 0 -#define HW_CLKCTRL_CPU__DIV_CPU_BM 0x3f -#define HW_CLKCTRL_CPU__INTERRUPT_WAIT (1 << 12) -#define HW_CLKCTRL_CPU__DIV_XTAL_BP 16 -#define HW_CLKCTRL_CPU__DIV_XTAL_BM (0x3ff << 16) -#define HW_CLKCTRL_CPU__DIV_XTAL_FRAC_EN (1 << 26) -#define HW_CLKCTRL_CPU__BUSY_REF_CPU (1 << 28) - -#define HW_CLKCTRL_HBUS (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x30)) -#define HW_CLKCTRL_HBUS__DIV_BP 0 -#define HW_CLKCTRL_HBUS__DIV_BM 0x1f -#define HW_CLKCTRL_HBUS__DIV_FRAC_EN (1 << 5) -#define HW_CLKCTRL_HBUS__SLOW_DIV_BP 16 -#define HW_CLKCTRL_HBUS__SLOW_DIV_BM (0x7 << 16) -#define HW_CLKCTRL_HBUS__AUTO_SLOW_MODE (1 << 20) - -#define HW_CLKCTRL_XBUS (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x40)) -#define HW_CLKCTRL_XBUS__DIV_BP 0 -#define HW_CLKCTRL_XBUS__DIV_BM 0x3ff -#define HW_CLKCTRL_XBUS__BUSY (1 << 31) - -#define HW_CLKCTRL_XTAL (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x50)) -#define HW_CLKCTRL_XTAL__TIMROT_CLK32K_GATE (1 << 26) -#define HW_CLKCTRL_XTAL__DRI_CLK24M_GATE (1 << 28) -#define HW_CLKCTRL_XTAL__PWM_CLK24M_GATE (1 << 29) -#define HW_CLKCTRL_XTAL__FILT_CLK24M_GATE (1 << 30) - -#define HW_CLKCTRL_PIX (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x60)) -#define HW_CLKCTRL_PIX__DIV_BP 0 -#define HW_CLKCTRL_PIX__DIV_BM 0xfff - -#define HW_CLKCTRL_SSP (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x70)) -#define HW_CLKCTRL_SSP__DIV_BP 0 -#define HW_CLKCTRL_SSP__DIV_BM 0x1ff - -#define HW_CLKCTRL_EMI (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0xa0)) -#define HW_CLKCTRL_EMI__DIV_EMI_BP 0 -#define HW_CLKCTRL_EMI__DIV_EMI_BM 0x3f -#define HW_CLKCTRL_EMI__DIV_XTAL_BP 8 -#define HW_CLKCTRL_EMI__DIV_XTAL_BM (0xf << 8) -#define HW_CLKCTRL_EMI__BUSY_REF_EMI (1 << 28) -#define HW_CLKCTRL_EMI__SYNC_MODE_EN (1 << 30) -#define HW_CLKCTRL_EMI__CLKGATE (1 << 31) - -#ifdef HAVE_STMP3770 -#define HW_CLKCTRL_CLKSEQ (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0xe0)) -#else -#define HW_CLKCTRL_CLKSEQ (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x110)) -#endif -#define HW_CLKCTRL_CLKSEQ__BYPASS_PIX (1 << 1) -#define HW_CLKCTRL_CLKSEQ__BYPASS_SSP (1 << 5) -#define HW_CLKCTRL_CLKSEQ__BYPASS_EMI (1 << 6) -#define HW_CLKCTRL_CLKSEQ__BYPASS_CPU (1 << 7) - -#ifdef HAVE_STMP3770 -#define HW_CLKCTRL_FRAC (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0xd0)) -#else -#define HW_CLKCTRL_FRAC (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0xf0)) -#endif -#define HW_CLKCTRL_FRAC_CPU (*(volatile uint8_t *)(HW_CLKCTRL_BASE + 0xf0)) -#define HW_CLKCTRL_FRAC_EMI (*(volatile uint8_t *)(HW_CLKCTRL_BASE + 0xf1)) -#define HW_CLKCTRL_FRAC_PIX (*(volatile uint8_t *)(HW_CLKCTRL_BASE + 0xf2)) -#define HW_CLKCTRL_FRAC_IO (*(volatile uint8_t *)(HW_CLKCTRL_BASE + 0xf3)) -#define HW_CLKCTRL_FRAC_XX__XXDIV_BM 0x3f -#define HW_CLKCTRL_FRAC_XX__XX_STABLE (1 << 6) -#define HW_CLKCTRL_FRAC_XX__CLKGATEXX (1 << 7) - -#define HW_CLKCTRL_RESET (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x120)) -#define HW_CLKCTRL_RESET_CHIP 0x2 -#define HW_CLKCTRL_RESET_DIG 0x1 - -/** - * - * DMA - * - */ - -/******** - * APHB * - ********/ - -#define HW_APBH_BASE 0x80004000 - -/* APHB channels */ -#define HW_APBH_SSP(ssp) ssp - -#define HW_APBH_CTRL0 (*(volatile uint32_t *)(HW_APBH_BASE + 0x0)) -#define HW_APBH_CTRL0__FREEZE_CHANNEL(i) (1 << (i)) -#define HW_APBH_CTRL0__CLKGATE_CHANNEL(i) (1 << ((i) + 8)) -#define HW_APBH_CTRL0__RESET_CHANNEL(i) (1 << ((i) + 16)) -#define HW_APBH_CTRL0__APB_BURST4_EN (1 << 28) -#define HW_APBH_CTRL0__APB_BURST8_EN (1 << 29) - -#define HW_APBH_CTRL1 (*(volatile uint32_t *)(HW_APBH_BASE + 0x10)) -#define HW_APBH_CTRL1__CHx_CMDCMPLT_IRQ(i) (1 << (i)) -#define HW_APBH_CTRL1__CHx_CMDCMPLT_IRQ_EN(i) (1 << ((i) + 16)) - -#define HW_APBH_CTRL2 (*(volatile uint32_t *)(HW_APBH_BASE + 0x20)) -#define HW_APBH_CTRL2__CHx_ERROR_IRQ(i) (1 << (i)) -#define HW_APBH_CTRL2__CHx_ERROR_STATUS(i) (1 << ((i) + 16)) - -#define HW_APBH_CHx_CURCMDAR(i) (*(volatile uint32_t *)(HW_APBH_BASE + 0x40 + 0x70 * (i))) - -#define HW_APBH_CHx_NXTCMDAR(i) (*(volatile uint32_t *)(HW_APBH_BASE + 0x50 + 0x70 * (i))) - -#define HW_APBH_CHx_CMD(i) (*(volatile uint32_t *)(HW_APBH_BASE + 0x60 + 0x70 * (i))) - -#define HW_APBH_CHx_BAR(i) (*(volatile uint32_t *)(HW_APBH_BASE + 0x70 + 0x70 * (i))) - -#define HW_APBH_CHx_SEMA(i) (*(volatile uint32_t *)(HW_APBH_BASE + 0x80 + 0x70 * (i))) - -#define HW_APBH_CHx_DEBUG1(i) (*(volatile uint32_t *)(HW_APBH_BASE + 0x90 + 0x70 * (i))) - -#define HW_APBH_CHx_DEBUG2(i) (*(volatile uint32_t *)(HW_APBH_BASE + 0xa0 + 0x70 * (i))) -#define HW_APBH_CHx_DEBUG2__AHB_BYTES_BP 0 -#define HW_APBH_CHx_DEBUG2__AHB_BYTES_BM 0xffff -#define HW_APBH_CHx_DEBUG2__APB_BYTES_BP 16 -#define HW_APBH_CHx_DEBUG2__APB_BYTES_BM 0xffff0000 - -/******** - * APHX * - ********/ - -/* APHX channels */ -#define HW_APBX_AUDIO_ADC 0 -#define HW_APBX_AUDIO_DAC 1 -#define HW_APBX_I2C 3 - -#define HW_APBX_BASE 0x80024000 - -#define HW_APBX_CTRL0 (*(volatile uint32_t *)(HW_APBX_BASE + 0x0)) - -#define HW_APBX_CTRL1 (*(volatile uint32_t *)(HW_APBX_BASE + 0x10)) -#define HW_APBX_CTRL1__CHx_CMDCMPLT_IRQ(i) (1 << (i)) -#define HW_APBX_CTRL1__CHx_CMDCMPLT_IRQ_EN(i) (1 << ((i) + 16)) - -#define HW_APBX_CTRL2 (*(volatile uint32_t *)(HW_APBX_BASE + 0x20)) -#define HW_APBX_CTRL2__CHx_ERROR_IRQ(i) (1 << (i)) -#define HW_APBX_CTRL2__CHx_ERROR_STATUS(i) (1 << ((i) + 16)) +/* STMP3600 only */ +#define HW_CLKCTRL_CPUCLKCTRL (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x20)) +#define HW_CLKCTRL_CPUCLKCTRL__DIV_BP 0 +#define HW_CLKCTRL_CPUCLKCTRL__DIV_BM 0x3ff +#define HW_CLKCTRL_CPUCLKCTRL__WAIT_PLL_LOCK (1 << 30) -#define HW_APBX_CHANNEL_CTRL (*(volatile uint32_t *)(HW_APBX_BASE + 0x30)) -#define HW_APBX_CHANNEL_CTRL__FREEZE_CHANNEL(i) (1 << (i)) -#define HW_APBX_CHANNEL_CTRL__RESET_CHANNEL(i) (1 << ((i) + 16)) +/* STMP3600 */ +#define HW_CLKCTRL_HBUSCLKCTRL (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x30)) -#define HW_APBX_CHx_CURCMDAR(i) (*(volatile uint32_t *)(HW_APBX_BASE + 0x100 + (i) * 0x70)) +/* STMP3600 only */ +#define HW_CLKCTRL_XBUSCLKCTRL (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x40)) +#define HW_CLKCTRL_XBUSCLKCTRL__DIV_BP 0 +#define HW_CLKCTRL_XBUSCLKCTRL__DIV_BM 0x3ff -#define HW_APBX_CHx_NXTCMDAR(i) (*(volatile uint32_t *)(HW_APBX_BASE + 0x110 + (i) * 0x70)) - -#define HW_APBX_CHx_CMD(i) (*(volatile uint32_t *)(HW_APBX_BASE + 0x120 + (i) * 0x70)) - -#define HW_APBX_CHx_BAR(i) (*(volatile uint32_t *)(HW_APBX_BASE + 0x130 + (i) * 0x70)) - -#define HW_APBX_CHx_SEMA(i) (*(volatile uint32_t *)(HW_APBX_BASE + 0x140 + (i) * 0x70)) - -#define HW_APBX_CHx_DEBUG1(i) (*(volatile uint32_t *)(HW_APBX_BASE + 0x150 + (i) * 0x70)) - -#define HW_APBX_CHx_DEBUG2(i) (*(volatile uint32_t *)(HW_APBX_BASE + 0x160 + (i) * 0x70)) -#define HW_APBX_CHx_DEBUG2__AHB_BYTES_BP 0 -#define HW_APBX_CHx_DEBUG2__AHB_BYTES_BM 0xffff -#define HW_APBX_CHx_DEBUG2__APB_BYTES_BP 16 -#define HW_APBX_CHx_DEBUG2__APB_BYTES_BM 0xffff0000 - -/********** - * COMMON * - **********/ - -struct apb_dma_command_t -{ - struct apb_dma_command_t *next; - uint32_t cmd; - void *buffer; - /* PIO words follow */ -}; - -#define APBH_DMA_CHANNEL(i) i -#define APBX_DMA_CHANNEL(i) ((i) | 0x10) -#define APB_IS_APBX_CHANNEL(x) ((x) & 0x10) -#define APB_GET_DMA_CHANNEL(x) ((x) & 0xf) - -#define APB_SSP(ssp) APBH_DMA_CHANNEL(HW_APBH_SSP(ssp)) -#define APB_AUDIO_ADC APBX_DMA_CHANNEL(HW_APBX_AUDIO_ADC) -#define APB_AUDIO_DAC APBX_DMA_CHANNEL(HW_APBX_AUDIO_DAC) -#define APB_I2C APBX_DMA_CHANNEL(HW_APBX_I2C) - -#define HW_APB_CHx_CMD__COMMAND_BM 0x3 -#define HW_APB_CHx_CMD__COMMAND__NO_XFER 0 -#define HW_APB_CHx_CMD__COMMAND__WRITE 1 -#define HW_APB_CHx_CMD__COMMAND__READ 2 -#define HW_APB_CHx_CMD__COMMAND__SENSE 3 -#define HW_APB_CHx_CMD__CHAIN (1 << 2) -#define HW_APB_CHx_CMD__IRQONCMPLT (1 << 3) -/* those two are only available on APHB */ -#define HW_APBH_CHx_CMD__NANDLOCK (1 << 4) -#define HW_APBH_CHx_CMD__NANDWAIT4READY (1 << 5) -#define HW_APB_CHx_CMD__SEMAPHORE (1 << 6) -#define HW_APB_CHx_CMD__WAIT4ENDCMD (1 << 7) -/* An errata advise not to use it */ -//#define HW_APB_CHx_CMD__HALTONTERMINATE (1 << 8) -#define HW_APB_CHx_CMD__CMDWORDS_BM 0xf000 -#define HW_APB_CHx_CMD__CMDWORDS_BP 12 -#define HW_APB_CHx_CMD__XFER_COUNT_BM 0xffff0000 -#define HW_APB_CHx_CMD__XFER_COUNT_BP 16 -/* For software use */ -#define HW_APB_CHx_CMD__UNUSED_BP 8 -#define HW_APB_CHx_CMD__UNUSED_BM (0xf << 8) -#define HW_APB_CHx_CMD__UNUSED_MAGIC (0xa << 8) - -#define HW_APB_CHx_SEMA__PHORE_BM 0xff0000 -#define HW_APB_CHx_SEMA__PHORE_BP 16 - -/* A single descriptor cannot transfer more than 2^16 bytes */ -#define IMX233_MAX_SINGLE_DMA_XFER_SIZE (1 << 16) - -static void imx233_dma_init(void) -{ - __REG_CLR(HW_APBH_CTRL0) = __BLOCK_CLKGATE | __BLOCK_SFTRST; - __REG_CLR(HW_APBX_CTRL0) = __BLOCK_CLKGATE | __BLOCK_SFTRST; -} - -static void imx233_dma_reset_channel(unsigned chan) -{ - volatile uint32_t *ptr; - uint32_t bm; - if(APB_IS_APBX_CHANNEL(chan)) - { - ptr = &HW_APBX_CHANNEL_CTRL; - bm = HW_APBX_CHANNEL_CTRL__RESET_CHANNEL(APB_GET_DMA_CHANNEL(chan)); - } - else - { - ptr = &HW_APBH_CTRL0; - bm = HW_APBH_CTRL0__RESET_CHANNEL(APB_GET_DMA_CHANNEL(chan)); - } - __REG_SET(*ptr) = bm; - /* wait for end of reset */ - while(*ptr & bm) - ; -} - -static void imx233_dma_start_command(unsigned chan, struct apb_dma_command_t *cmd) -{ - if(APB_IS_APBX_CHANNEL(chan)) - { - HW_APBX_CHx_NXTCMDAR(APB_GET_DMA_CHANNEL(chan)) = (uint32_t)cmd; - HW_APBX_CHx_SEMA(APB_GET_DMA_CHANNEL(chan)) = 1; - } - else - { - HW_APBH_CHx_NXTCMDAR(APB_GET_DMA_CHANNEL(chan)) = (uint32_t)cmd; - HW_APBH_CHx_SEMA(APB_GET_DMA_CHANNEL(chan)) = 1; - } -} - -static void imx233_dma_wait_completion(unsigned chan) -{ - volatile uint32_t *sema; - if(APB_IS_APBX_CHANNEL(chan)) - sema = &HW_APBX_CHx_SEMA(APB_GET_DMA_CHANNEL(chan)); - else - sema = &HW_APBH_CHx_SEMA(APB_GET_DMA_CHANNEL(chan)); - - while(*sema & HW_APB_CHx_SEMA__PHORE_BM) - ; -} +/* STMP3600 only */ +#define HW_CLKCTRL_UTMICLKCTRL (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x70)) +#define HW_CLKCTRL_UTMICLKCTRL__UTMI_CLK30M_GATE (1 << 30) +#define HW_CLKCTRL_UTMICLKCTRL__UTMI_CLK120M_GATE (1 << 31) /** * @@ -751,8 +404,6 @@ static void imx233_dma_wait_completion(unsigned chan) #define HW_DIGCTL_CTRL (*(volatile uint32_t *)(HW_DIGCTL_BASE + 0)) #define HW_DIGCTL_CTRL__USB_CLKGATE (1 << 2) -#define HW_DIGCTL_HCLKCOUNT (*(volatile uint32_t *)(HW_DIGCTL_BASE + 0x20)) - #define HW_DIGCTL_MICROSECONDS (*(volatile uint32_t *)(HW_DIGCTL_BASE + 0xC0)) #define HW_DIGCTL_CHIPID (*(volatile uint32_t *)(HW_DIGCTL_BASE + 0x310)) @@ -786,7 +437,6 @@ static void udelay(unsigned us) /* USB Phy */ #define HW_USBPHY_BASE 0x8007C000 #define HW_USBPHY_PWD (*(volatile uint32_t *)(HW_USBPHY_BASE + 0)) -#define HW_USBPHY_PWD__ALL (7 << 10 | 0xf << 17) #define HW_USBPHY_CTRL (*(volatile uint32_t *)(HW_USBPHY_BASE + 0x30)) @@ -852,17 +502,9 @@ struct dcp_packet_t * */ -void memcpy(uint8_t *dst, const uint8_t *src, uint32_t length) -{ - for(uint32_t i = 0; i < length; i++) - dst[i] = src[i]; -} - -void memset(uint8_t *dst, uint8_t fill, uint32_t length) -{ - for(uint32_t i = 0; i < length; i++) - dst[i] = fill; -} +void memcpy(void *dest, const void *src, size_t n); +void memmove(void *dest, const void *src, size_t n); +void memset(void *dst, int value, size_t n); /** * @@ -880,9 +522,9 @@ static struct usb_device_descriptor __attribute__((aligned(2))) .bDeviceSubClass = 0, .bDeviceProtocol = 0, .bMaxPacketSize0 = 64, - .idVendor = HWEMUL_USB_VID, - .idProduct = HWEMUL_USB_PID, - .bcdDevice = HWEMUL_VERSION_MAJOR << 8 | HWEMUL_VERSION_MINOR, + .idVendor = HWSTUB_USB_VID, + .idProduct = HWSTUB_USB_PID, + .bcdDevice = HWSTUB_VERSION_MAJOR << 8 | HWSTUB_VERSION_MINOR, .iManufacturer = 1, .iProduct = 2, .iSerialNumber = 3, @@ -913,9 +555,9 @@ static struct usb_interface_descriptor __attribute__((aligned(2))) .bInterfaceNumber = 0, .bAlternateSetting = 0, .bNumEndpoints = 3, - .bInterfaceClass = HWEMUL_CLASS, - .bInterfaceSubClass = HWEMUL_SUBCLASS, - .bInterfaceProtocol = HWEMUL_PROTOCOL, + .bInterfaceClass = HWSTUB_CLASS, + .bInterfaceSubClass = HWSTUB_SUBCLASS, + .bInterfaceProtocol = HWSTUB_PROTOCOL, .iInterface = 4 }; @@ -966,9 +608,9 @@ static struct usb_string_descriptor __attribute__((aligned(2))) 28, USB_DT_STRING, {'A', 'c', 'i', 'd', ' ', - '0' + (HWEMUL_VERSION_MAJOR >> 4), '0' + (HWEMUL_VERSION_MAJOR & 0xf), '.', - '0' + (HWEMUL_VERSION_MINOR >> 4), '0' + (HWEMUL_VERSION_MINOR & 0xf), '.', - '0' + (HWEMUL_VERSION_REV >> 4), '0' + (HWEMUL_VERSION_REV & 0xf) } + '0' + (HWSTUB_VERSION_MAJOR >> 4), '0' + (HWSTUB_VERSION_MAJOR & 0xf), '.', + '0' + (HWSTUB_VERSION_MINOR >> 4), '0' + (HWSTUB_VERSION_MINOR & 0xf), '.', + '0' + (HWSTUB_VERSION_REV >> 4), '0' + (HWSTUB_VERSION_REV & 0xf) } }; /* this is stringid #0: languages supported */ @@ -1138,9 +780,9 @@ static void handle_std_req(struct usb_ctrlrequest *req) struct usb_resp_info_version_t g_version = { - .major = HWEMUL_VERSION_MAJOR, - .minor = HWEMUL_VERSION_MINOR, - .revision = HWEMUL_VERSION_REV + .major = HWSTUB_VERSION_MAJOR, + .minor = HWSTUB_VERSION_MINOR, + .revision = HWSTUB_VERSION_REV }; struct usb_resp_info_layout_t g_layout; @@ -1149,8 +791,8 @@ struct usb_resp_info_stmp_t g_stmp; struct usb_resp_info_features_t g_features = { - .feature_mask = HWEMUL_FEATURE_LOG | HWEMUL_FEATURE_MEM | - HWEMUL_FEATURE_CALL | HWEMUL_FEATURE_JUMP | HWEMUL_FEATURE_AES_OTP + .feature_mask = HWSTUB_FEATURE_LOG | HWSTUB_FEATURE_MEM | + HWSTUB_FEATURE_CALL | HWSTUB_FEATURE_JUMP | HWSTUB_FEATURE_AES_OTP }; static void fill_layout_info(void) @@ -1177,21 +819,21 @@ static void handle_get_info(struct usb_ctrlrequest *req) int size = 0; switch(req->wIndex) { - case HWEMUL_INFO_VERSION: + case HWSTUB_INFO_VERSION: ptr = &g_version; size = sizeof(g_version); break; - case HWEMUL_INFO_LAYOUT: + case HWSTUB_INFO_LAYOUT: fill_layout_info(); ptr = &g_layout; size = sizeof(g_layout); break; - case HWEMUL_INFO_STMP: + case HWSTUB_INFO_STMP: fill_stmp_info(); ptr = &g_stmp; size = sizeof(g_stmp); break; - case HWEMUL_INFO_FEATURES: + case HWSTUB_INFO_FEATURES: ptr = &g_features; size = sizeof(g_features); break; @@ -1249,17 +891,22 @@ static void handle_call_jump(struct usb_ctrlrequest *req) { uint32_t addr = req->wValue | req->wIndex << 16; - if(req->bRequest == HWEMUL_CALL) + if(req->bRequest == HWSTUB_CALL) ((void (*)(void))addr)(); else + { + /* disconnect to make sure usb/dma won't interfere */ + REG_USBCMD &= ~USBCMD_RUN; + REG_USBCMD |= USBCMD_CTRL_RESET; asm volatile("bx %0\n" : : "r" (addr) : "memory"); + } } static void do_aes_otp(void *buffer, unsigned length, unsigned params) { static struct dcp_packet_t dcp_packet; - bool encrypt = !!(params & HWEMUL_AES_OTP_ENCRYPT); + bool encrypt = !!(params & HWSTUB_AES_OTP_ENCRYPT); /* reset DCP */ __REG_SET(HW_DCP_CTRL) = 0x80000000; /* clear clock gate */ @@ -1307,20 +954,20 @@ static void handle_class_dev_req(struct usb_ctrlrequest *req) { switch(req->bRequest) { - case HWEMUL_GET_INFO: + case HWSTUB_GET_INFO: handle_get_info(req); break; - case HWEMUL_GET_LOG: + case HWSTUB_GET_LOG: handle_get_log(req); break; - case HWEMUL_RW_MEM: + case HWSTUB_RW_MEM: handle_rw_mem(req); break; - case HWEMUL_CALL: - case HWEMUL_JUMP: + case HWSTUB_CALL: + case HWSTUB_JUMP: handle_call_jump(req); break; - case HWEMUL_AES_OTP: + case HWSTUB_AES_OTP: handle_aes_otp(req); break; default: @@ -1348,19 +995,68 @@ static void handle_class_req(struct usb_ctrlrequest *req) void main(uint32_t arg) { usb_buffer_size = oc_buffersize; - - logf("hwemul %d.%d.%d\n", HWEMUL_VERSION_MAJOR, HWEMUL_VERSION_MINOR, - HWEMUL_VERSION_REV); + + logf("hwstub %d.%d.%d\n", HWSTUB_VERSION_MAJOR, HWSTUB_VERSION_MINOR, + HWSTUB_VERSION_REV); logf("argument: 0x%08x\n", arg); + /* detect family */ + uint16_t product_code = __XTRACT(HW_DIGCTL_CHIPID, PRODUCT_CODE); + if(product_code >= 0x3600 && product_code < 0x3700) + { + logf("identified STMP3600 family\n"); + g_stmp_family = STMP3600; + } + else if(product_code == 0x3700) + { + logf("identified STMP3700 family\n"); + g_stmp_family = STMP3700; + } + else if(product_code == 0x37b0) + { + logf("identified STMP3770 family\n"); + g_stmp_family = STMP3770; + } + else if(product_code == 0x3780) + { + logf("identified STMP3780 family\n"); + g_stmp_family = STMP3780; + } + else + logf("cannot identify family: 0x%x\n", product_code); + /* we don't know if USB was connected or not. In USB recovery mode it will * but in other cases it might not be. In doubt, disconnect */ REG_USBCMD &= ~USBCMD_RUN; + if(g_stmp_family == STMP3600) + { + /* CPU clock is always derived from PLL, if we switch to PLL, cpu will + * run at 480 MHz unprepared ! That's bad so prepare to run at slow sleed + * (1.2MHz) for a safe transition */ + HW_CLKCTRL_CPUCLKCTRL = HW_CLKCTRL_CPUCLKCTRL__WAIT_PLL_LOCK | 400; + /* We need to ensure that XBUS < HBUS but HBUS will be 1.2 MHz after the + * switch so lower XBUS too */ + HW_CLKCTRL_XBUSCLKCTRL = 20; + /* Power PLL */ + __REG_SET(HW_CLKCTRL_PLLCTRL0) = HW_CLKCTRL_PLLCTRL0__POWER; + HW_CLKCTRL_PLLCTRL0 = (HW_CLKCTRL_PLLCTRL0 & ~0x3ff) | 480; + /* Wait lock */ + while(!(HW_CLKCTRL_PLLCTRL1 & HW_CLKCTRL_PLLCTRL1__LOCK)); + /* Switch to PLL source */ + __REG_CLR(HW_CLKCTRL_PLLCTRL0) = HW_CLKCTRL_PLLCTRL0__BYPASS; + /* Get back XBUS = 24 MHz and CPU = HBUS = 64MHz */ + HW_CLKCTRL_CPUCLKCTRL = 7; + HW_CLKCTRL_HBUSCLKCTRL = 7; + HW_CLKCTRL_XBUSCLKCTRL = 1; + __REG_CLR(HW_CLKCTRL_UTMICLKCTRL) = HW_CLKCTRL_UTMICLKCTRL__UTMI_CLK120M_GATE; + __REG_CLR(HW_CLKCTRL_UTMICLKCTRL) = HW_CLKCTRL_UTMICLKCTRL__UTMI_CLK30M_GATE; + } + else + __REG_SET(HW_CLKCTRL_PLLCTRL0) = HW_CLKCTRL_PLLCTRL0__POWER; /* enable USB PHY PLL */ __REG_SET(HW_CLKCTRL_PLLCTRL0) = HW_CLKCTRL_PLLCTRL0__EN_USB_CLKS; /* power up USB PHY */ __REG_CLR(HW_USBPHY_CTRL) = __BLOCK_CLKGATE | __BLOCK_SFTRST; - //__REG_CLR(HW_USBPHY_PWD) = HW_USBPHY_PWD__ALL; HW_USBPHY_PWD = 0; /* enable USB controller */ __REG_CLR(HW_DIGCTL_CTRL) = HW_DIGCTL_CTRL__USB_CLKGATE; @@ -1382,7 +1078,7 @@ void main(uint32_t arg) REG_ENDPTSETUPSTAT = EPSETUP_STATUS_EP0; /* run! */ REG_USBCMD |= USBCMD_RUN; - + while(1) { /* wait for setup */ diff --git a/utils/hwstub/stmp/memcpy.S b/utils/hwstub/stmp/memcpy.S new file mode 100644 index 0000000000..2a55fb5656 --- /dev/null +++ b/utils/hwstub/stmp/memcpy.S @@ -0,0 +1,176 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 Free Software Foundation, Inc. + * This file was originally part of the GNU C Library + * Contributed to glibc by MontaVista Software, Inc. (written by Nicolas Pitre) + * Adapted for Rockbox by Daniel Ankers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "config.h" + +/* + * Endian independent macros for shifting bytes within registers. + */ +#ifndef __ARMEB__ +#define pull lsr +#define push lsl +#else +#define pull lsl +#define push lsr +#endif + +/* Prototype: void *memcpy(void *dest, const void *src, size_t n); */ + + .section .icode,"ax",%progbits + + .align 2 + .global memcpy + .type memcpy,%function + +memcpy: + stmfd sp!, {r0, r4, lr} + + subs r2, r2, #4 + blt 8f + ands ip, r0, #3 + bne 9f + ands ip, r1, #3 + bne 10f + +1: subs r2, r2, #(28) + stmfd sp!, {r5 - r8} + blt 5f + +2: +3: +4: ldmia r1!, {r3, r4, r5, r6, r7, r8, ip, lr} + subs r2, r2, #32 + stmia r0!, {r3, r4, r5, r6, r7, r8, ip, lr} + bge 3b + +5: ands ip, r2, #28 + rsb ip, ip, #32 + addne pc, pc, ip @ C is always clear here + b 7f +6: nop + ldr r3, [r1], #4 + ldr r4, [r1], #4 + ldr r5, [r1], #4 + ldr r6, [r1], #4 + ldr r7, [r1], #4 + ldr r8, [r1], #4 + ldr lr, [r1], #4 + + add pc, pc, ip + nop + nop + str r3, [r0], #4 + str r4, [r0], #4 + str r5, [r0], #4 + str r6, [r0], #4 + str r7, [r0], #4 + str r8, [r0], #4 + str lr, [r0], #4 + +7: ldmfd sp!, {r5 - r8} + +8: movs r2, r2, lsl #31 + ldrneb r3, [r1], #1 + ldrcsb r4, [r1], #1 + ldrcsb ip, [r1] + strneb r3, [r0], #1 + strcsb r4, [r0], #1 + strcsb ip, [r0] + + ldmpc regs="r0, r4" + +9: rsb ip, ip, #4 + cmp ip, #2 + ldrgtb r3, [r1], #1 + ldrgeb r4, [r1], #1 + ldrb lr, [r1], #1 + strgtb r3, [r0], #1 + strgeb r4, [r0], #1 + subs r2, r2, ip + strb lr, [r0], #1 + blt 8b + ands ip, r1, #3 + beq 1b + +10: bic r1, r1, #3 + cmp ip, #2 + ldr lr, [r1], #4 + beq 17f + bgt 18f + + + .macro forward_copy_shift pull push + + subs r2, r2, #28 + blt 14f + +11: stmfd sp!, {r5 - r9} + +12: +13: ldmia r1!, {r4, r5, r6, r7} + mov r3, lr, pull #\pull + subs r2, r2, #32 + ldmia r1!, {r8, r9, ip, lr} + orr r3, r3, r4, push #\push + mov r4, r4, pull #\pull + orr r4, r4, r5, push #\push + mov r5, r5, pull #\pull + orr r5, r5, r6, push #\push + mov r6, r6, pull #\pull + orr r6, r6, r7, push #\push + mov r7, r7, pull #\pull + orr r7, r7, r8, push #\push + mov r8, r8, pull #\pull + orr r8, r8, r9, push #\push + mov r9, r9, pull #\pull + orr r9, r9, ip, push #\push + mov ip, ip, pull #\pull + orr ip, ip, lr, push #\push + stmia r0!, {r3, r4, r5, r6, r7, r8, r9, ip} + bge 12b + + ldmfd sp!, {r5 - r9} + +14: ands ip, r2, #28 + beq 16f + +15: mov r3, lr, pull #\pull + ldr lr, [r1], #4 + subs ip, ip, #4 + orr r3, r3, lr, push #\push + str r3, [r0], #4 + bgt 15b + +16: sub r1, r1, #(\push / 8) + b 8b + + .endm + + + forward_copy_shift pull=8 push=24 + +17: forward_copy_shift pull=16 push=16 + +18: forward_copy_shift pull=24 push=8 + diff --git a/utils/hwstub/stmp/memmove.S b/utils/hwstub/stmp/memmove.S new file mode 100644 index 0000000000..d8cab048be --- /dev/null +++ b/utils/hwstub/stmp/memmove.S @@ -0,0 +1,190 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 Free Software Foundation, Inc. + * This file was originally part of the GNU C Library + * Contributed to glibc by MontaVista Software, Inc. (written by Nicolas Pitre) + * Adapted for Rockbox by Daniel Ankers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "config.h" + +/* + * Endian independent macros for shifting bytes within registers. + */ +#ifndef __ARMEB__ +#define pull lsr +#define push lsl +#else +#define pull lsl +#define push lsr +#endif + + .text + +/* + * Prototype: void *memmove(void *dest, const void *src, size_t n); + * + * Note: + * + * If the memory regions don't overlap, we simply branch to memcpy which is + * normally a bit faster. Otherwise the copy is done going downwards. + */ + + .section .icode,"ax",%progbits + + .align 2 + .global memmove + .type memmove,%function + +memmove: + + subs ip, r0, r1 + cmphi r2, ip + bls memcpy + + stmfd sp!, {r0, r4, lr} + add r1, r1, r2 + add r0, r0, r2 + subs r2, r2, #4 + blt 8f + ands ip, r0, #3 + bne 9f + ands ip, r1, #3 + bne 10f + +1: subs r2, r2, #(28) + stmfd sp!, {r5 - r8} + blt 5f + +2: +3: +4: ldmdb r1!, {r3, r4, r5, r6, r7, r8, ip, lr} + subs r2, r2, #32 + stmdb r0!, {r3, r4, r5, r6, r7, r8, ip, lr} + bge 3b + +5: ands ip, r2, #28 + rsb ip, ip, #32 + addne pc, pc, ip @ C is always clear here + b 7f +6: nop + ldr r3, [r1, #-4]! + ldr r4, [r1, #-4]! + ldr r5, [r1, #-4]! + ldr r6, [r1, #-4]! + ldr r7, [r1, #-4]! + ldr r8, [r1, #-4]! + ldr lr, [r1, #-4]! + + add pc, pc, ip + nop + nop + str r3, [r0, #-4]! + str r4, [r0, #-4]! + str r5, [r0, #-4]! + str r6, [r0, #-4]! + str r7, [r0, #-4]! + str r8, [r0, #-4]! + str lr, [r0, #-4]! + +7: ldmfd sp!, {r5 - r8} + +8: movs r2, r2, lsl #31 + ldrneb r3, [r1, #-1]! + ldrcsb r4, [r1, #-1]! + ldrcsb ip, [r1, #-1] + strneb r3, [r0, #-1]! + strcsb r4, [r0, #-1]! + strcsb ip, [r0, #-1] + ldmpc regs="r0, r4" + +9: cmp ip, #2 + ldrgtb r3, [r1, #-1]! + ldrgeb r4, [r1, #-1]! + ldrb lr, [r1, #-1]! + strgtb r3, [r0, #-1]! + strgeb r4, [r0, #-1]! + subs r2, r2, ip + strb lr, [r0, #-1]! + blt 8b + ands ip, r1, #3 + beq 1b + +10: bic r1, r1, #3 + cmp ip, #2 + ldr r3, [r1, #0] + beq 17f + blt 18f + + + .macro backward_copy_shift push pull + + subs r2, r2, #28 + blt 14f + +11: stmfd sp!, {r5 - r9} + +12: +13: ldmdb r1!, {r7, r8, r9, ip} + mov lr, r3, push #\push + subs r2, r2, #32 + ldmdb r1!, {r3, r4, r5, r6} + orr lr, lr, ip, pull #\pull + mov ip, ip, push #\push + orr ip, ip, r9, pull #\pull + mov r9, r9, push #\push + orr r9, r9, r8, pull #\pull + mov r8, r8, push #\push + orr r8, r8, r7, pull #\pull + mov r7, r7, push #\push + orr r7, r7, r6, pull #\pull + mov r6, r6, push #\push + orr r6, r6, r5, pull #\pull + mov r5, r5, push #\push + orr r5, r5, r4, pull #\pull + mov r4, r4, push #\push + orr r4, r4, r3, pull #\pull + stmdb r0!, {r4 - r9, ip, lr} + bge 12b + + ldmfd sp!, {r5 - r9} + +14: ands ip, r2, #28 + beq 16f + +15: mov lr, r3, push #\push + ldr r3, [r1, #-4]! + subs ip, ip, #4 + orr lr, lr, r3, pull #\pull + str lr, [r0, #-4]! + bgt 15b + +16: add r1, r1, #(\pull / 8) + b 8b + + .endm + + + backward_copy_shift push=8 pull=24 + +17: backward_copy_shift push=16 pull=16 + +18: backward_copy_shift push=24 pull=8 + + diff --git a/utils/hwstub/stmp/memset.S b/utils/hwstub/stmp/memset.S new file mode 100644 index 0000000000..682da874ce --- /dev/null +++ b/utils/hwstub/stmp/memset.S @@ -0,0 +1,98 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Thom Johansen + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "config.h" + + .section .icode,"ax",%progbits + + .align 2 + +/* The following code is based on code found in Linux kernel version 2.6.15.3 + * linux/arch/arm/lib/memset.S + * + * Copyright (C) 1995-2000 Russell King + */ + +/* This code will align a pointer for memset, if needed */ +1: cmp r2, #4 @ 1 do we have enough + blt 5f @ 1 bytes to align with? + cmp r3, #2 @ 1 + strgtb r1, [r0, #-1]! @ 1 + strgeb r1, [r0, #-1]! @ 1 + strb r1, [r0, #-1]! @ 1 + sub r2, r2, r3 @ 1 r2 = r2 - r3 + b 2f + + .global memset + .type memset,%function +memset: + add r0, r0, r2 @ we'll write backwards in memory + ands r3, r0, #3 @ 1 unaligned? + bne 1b @ 1 +2: +/* + * we know that the pointer in r0 is aligned to a word boundary. + */ + orr r1, r1, r1, lsl #8 + orr r1, r1, r1, lsl #16 + mov r3, r1 + cmp r2, #16 + blt 5f +/* + * We need an extra register for this loop - save the return address and + * use the LR + */ + str lr, [sp, #-4]! + mov ip, r1 + mov lr, r1 + +3: subs r2, r2, #64 + stmgedb r0!, {r1, r3, ip, lr} @ 64 bytes at a time. + stmgedb r0!, {r1, r3, ip, lr} + stmgedb r0!, {r1, r3, ip, lr} + stmgedb r0!, {r1, r3, ip, lr} + bgt 3b + ldrpc cond=eq @ Now <64 bytes to go. +/* + * No need to correct the count; we're only testing bits from now on + */ + tst r2, #32 + stmnedb r0!, {r1, r3, ip, lr} + stmnedb r0!, {r1, r3, ip, lr} + tst r2, #16 + stmnedb r0!, {r1, r3, ip, lr} + ldr lr, [sp], #4 + +5: tst r2, #8 + stmnedb r0!, {r1, r3} + tst r2, #4 + strne r1, [r0, #-4]! +/* + * When we get here, we've got less than 4 bytes to zero. We + * may have an unaligned pointer as well. + */ +6: tst r2, #2 + strneb r1, [r0, #-1]! + strneb r1, [r0, #-1]! + tst r2, #1 + strneb r1, [r0, #-1]! + bx lr +.end: + .size memset,.end-memset diff --git a/utils/hwstub/stmp/protocol.h b/utils/hwstub/stmp/protocol.h index d3ffb6ce00..35510fa9b2 100644 --- a/utils/hwstub/stmp/protocol.h +++ b/utils/hwstub/stmp/protocol.h @@ -1 +1 @@ -#include "../hwemul_protocol.h" +#include "../hwstub_protocol.h" diff --git a/utils/hwstub/stmp/stddef.h b/utils/hwstub/stmp/stddef.h index 9d59d2913c..9bfd767750 100644 --- a/utils/hwstub/stmp/stddef.h +++ b/utils/hwstub/stmp/stddef.h @@ -18,8 +18,8 @@ * KIND, either express or implied. * ****************************************************************************/ -#ifndef __HWEMUL_STDDEF__ -#define __HWEMUL_STDDEF__ +#ifndef __HWSTUB_STDDEF__ +#define __HWSTUB_STDDEF__ #include "stdint.h" @@ -29,4 +29,4 @@ typedef int32_t ssize_t; #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) -#endif /* __HWEMUL_STDDEF__ */ +#endif /* __HWSTUB_STDDEF__ */ diff --git a/utils/hwstub/stmp/string.h b/utils/hwstub/stmp/string.h index 7ef460ea6e..184144e525 100644 --- a/utils/hwstub/stmp/string.h +++ b/utils/hwstub/stmp/string.h @@ -18,8 +18,8 @@ * KIND, either express or implied. * ****************************************************************************/ -#ifndef __HWEMUL_STRING__ -#define __HWEMUL_STRING__ +#ifndef __HWSTUB_STRING__ +#define __HWSTUB_STRING__ #include "stddef.h" @@ -27,4 +27,4 @@ void memset(void *dst, int c, size_t n); void memcpy(void *dst, const void *src, size_t n); size_t strlen(const char *s); -#endif /* __HWEMUL_STRING__ */ +#endif /* __HWSTUB_STRING__ */ diff --git a/utils/hwstub/stmp/system.h b/utils/hwstub/stmp/system.h index c1babe7d87..e5aea12051 100644 --- a/utils/hwstub/stmp/system.h +++ b/utils/hwstub/stmp/system.h @@ -18,8 +18,8 @@ * KIND, either express or implied. * ****************************************************************************/ -#ifndef __HWEMUL_SYSTEM__ -#define __HWEMUL_SYSTEM__ +#ifndef __HWSTUB_SYSTEM__ +#define __HWSTUB_SYSTEM__ #define IRQ_ENABLED 0x00 #define IRQ_DISABLED 0x80 @@ -114,5 +114,5 @@ static inline int disable_interrupt_save(int mask) return cpsr; } -#endif /* __HWEMUL_SYSTEM__ */ +#endif /* __HWSTUB_SYSTEM__ */ diff --git a/utils/hwstub/tools/Makefile b/utils/hwstub/tools/Makefile index 3466a4e776..6db0c709b1 100644 --- a/utils/hwstub/tools/Makefile +++ b/utils/hwstub/tools/Makefile @@ -1,22 +1,38 @@ CC=gcc -AR=ar -HWEMUL_LIB_DIR=../lib -CFLAGS=-W -Wall -O2 `pkg-config --cflags libusb-1.0` -std=c99 -g -I$(HWEMUL_LIB_DIR) -LDFLAGS=`pkg-config --libs libusb-1.0` -lreadline -EXEC=hwemul_tool -HWEMUL_LIB=$(HWEMUL_LIB_DIR)/libhwemul.a +CXX=g++ +LD=g++ +HWSTUB_LIB_DIR=../lib +REGTOOLS_LIB_DIR=../../regtools/lib +CFLAGS=-Wall -O2 `pkg-config --cflags libusb-1.0` -std=c99 -g -I$(HWSTUB_LIB_DIR) -I$(REGTOOLS_LIB_DIR) `pkg-config --cflags lua5.2` +CXXFLAGS=-Wall -O2 `pkg-config --cflags libusb-1.0` -g -I$(HWSTUB_LIB_DIR) -I$(REGTOOLS_LIB_DIR) `pkg-config --cflags lua5.2` +LDFLAGS=`pkg-config --libs libusb-1.0` `pkg-config --libs lua5.2` -lreadline -L$(HWSTUB_LIB_DIR) -L$(REGTOOLS_LIB_DIR) -lsocdesc -lhwstub `xml2-config --libs` +EXEC=hwstub_shell hwstub_load SRC=$(wildcard *.c) -OBJ=$(SRC:.c=.o) +SRCXX=$(wildcard *.cpp) +OBJ=$(SRC:.c=.o) $(SRCXX:.cpp=.o) +LIBS=$(HWSTUB_LIB_DIR)/libhwstub.a $(REGTOOLS_LIB_DIR)/libsocdesc.a all: $(EXEC) +$(HWSTUB_LIB_DIR)/libhwstub.a: + make -C $(HWSTUB_LIB_DIR) + +$(REGTOOLS_LIB_DIR)/libsocdesc.a: + make -C $(REGTOOLS_LIB_DIR) + %.o: %.c $(CC) $(CFLAGS) -c -o $@ $< -hwemul_tool: hwemul_tool.o $(HWEMUL_LIB) - $(CC) -o $@ $^ $(LDFLAGS) +%.o: %.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< + +hwstub_shell: hwstub_shell.o $(LIBS) + $(LD) -o $@ $^ $(LDFLAGS) + +hwstub_load: hwstub_load.o $(LIBS) + $(LD) -o $@ $^ $(LDFLAGS) clean: - rm -rf $(OBJ) $(LIB) + rm -rf $(OBJ) $(LIB) $(EXEC) diff --git a/utils/hwstub/tools/hwemul_tool.c b/utils/hwstub/tools/hwemul_tool.c deleted file mode 100644 index d75cd7a957..0000000000 --- a/utils/hwstub/tools/hwemul_tool.c +++ /dev/null @@ -1,558 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2012 by Amaury Pouly - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include "hwemul.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <getopt.h> -#include <stdbool.h> -#include <readline/readline.h> -#include <readline/history.h> - -bool g_quiet = false; -struct hwemul_device_t hwdev; -struct hwemul_soc_t *cur_soc = NULL; - -void print_log(struct hwemul_device_t *hwdev) -{ - do - { - char buffer[128]; - int length = hwemul_get_log(hwdev, buffer, sizeof(buffer) - 1); - if(length <= 0) - break; - buffer[length] = 0; - printf("%s", buffer); - }while(1); -} - -int print_help() -{ - printf("Commands:\n"); - printf(" help\t\tDisplay this help\n"); - printf(" call <addr>\tCall address <addr>\n"); - printf(" quit\t\tQuit this session\n"); - printf(" read32 <addr>\tRead a 32-bit word at <addr>\n"); - printf(" write32 <value> <addr>\tRead the 32-bit word <value> at <addr>\n"); - printf(" read <regname>\tRead a register by name\n"); - printf(" read <regname>.<field>\tRead a register field by name\n"); - printf(" soc <socname>\tSelect the soc description to use\n"); - printf(" write <value> <regname>\tWrite a register by name\n"); - printf(" write <value <regname>.<field>\tWrite a register field by name\n"); - printf(" NOTE: if the register is SCT variant, no read is performed.\n"); - return 1; -} - -int syntax_error(char *str) -{ - printf("Syntax error at '%s'. Type 'help' to get some help.\n", str); - return 1; -} - -int parse_uint32(char *str, uint32_t *u) -{ - char *end; - *u = strtoul(str, &end, 0); - return *end == 0; -} - -int do_call(uint32_t a) -{ - hwemul_call(&hwdev, a); - return 1; -} - -int parse_call() -{ - char *arg = strtok(NULL, " "); - uint32_t addr; - if(arg && parse_uint32(arg, &addr)) - return do_call(addr); - else - return syntax_error(arg); -} - -int do_read32(uint32_t a) -{ - uint32_t val; - if(hwemul_rw_mem(&hwdev, 1, a, &val, sizeof(val)) == sizeof(val)) - printf("%#x = %#x\n", a, val); - else - printf("read error at %#x\n", a); - return 1; -} - -int parse_read32() -{ - char *arg = strtok(NULL, " "); - uint32_t addr; - if(arg && parse_uint32(arg, &addr)) - return do_read32(addr); - else - return syntax_error(arg); -} - -int do_write32(uint32_t val, uint32_t a) -{ - if(hwemul_rw_mem(&hwdev, 0, a, &val, sizeof(val)) == sizeof(val)) - printf("data written\n"); - else - printf("write error at %#x\n", a); - return 1; -} - -int parse_write32() -{ - char *arg = strtok(NULL, " "); - uint32_t val; - if(!arg || !parse_uint32(arg, &val)) - return syntax_error(arg); - uint32_t addr; - arg = strtok(NULL, " "); - if(arg && parse_uint32(arg, &addr)) - return do_write32(val, addr); - else - return syntax_error(arg); -} - -struct hwemul_soc_t *find_soc_by_name(const char *soc) -{ - struct hwemul_soc_list_t *list = hwemul_get_soc_list(); - for(size_t i = 0; i < list->nr_socs; i++) - if(strcmp(soc, list->socs[i]->name) == 0) - return list->socs[i]; - return NULL; -} - -struct hwemul_soc_reg_t *find_reg_by_name(struct hwemul_soc_t *soc, const char *reg) -{ - for(size_t i = 0; i < soc->nr_regs; i++) - if(strcmp(reg, soc->regs_by_name[i]->name) == 0) - return soc->regs_by_name[i]; - return NULL; -} - -struct hwemul_soc_reg_field_t *find_field_by_name(struct hwemul_soc_reg_t *reg, const char *field) -{ - for(size_t i = 0; i < reg->nr_fields; i++) - if(strcmp(field, reg->fields_by_name[i]->name) == 0) - return reg->fields_by_name[i]; - return NULL; -} - - -int do_read(char *regname) -{ - char *dot = strchr(regname, '.'); - if(dot != NULL) - *dot++ = 0; - if(cur_soc == NULL) - { - printf("No soc selected!\n"); - return 1; - } - struct hwemul_soc_reg_t *reg = find_reg_by_name(cur_soc, regname); - if(reg == NULL) - { - printf("no reg '%s' found\n", regname); - return 1; - } - uint32_t val; - if(hwemul_rw_mem(&hwdev, 1, reg->addr, &val, sizeof(val)) != sizeof(val)) - { - printf("read error at %#x\n", reg->addr); - return 1; - } - if(dot) - { - struct hwemul_soc_reg_field_t *field = find_field_by_name(reg, dot); - if(field == NULL) - { - printf("no field '%s' found\n", dot); - return 1; - } - val >>= field->first_bit; - val &= (1 << (field->last_bit - field->first_bit + 1)) - 1; - printf("%s.%s = %#x\n", regname, dot, val); - } - else - printf("%s = %#x\n", regname, val); - return 1; -} - -int parse_read() -{ - char *arg = strtok(NULL, " "); - if(arg) - return do_read(arg); - else - return syntax_error(arg); -} - -int do_soc(char *soc) -{ - struct hwemul_soc_t *s = find_soc_by_name(soc); - if(s == NULL) - printf("no soc '%s' found\n", soc); - else - cur_soc = s; - return 1; -} - -int parse_soc() -{ - char *arg = strtok(NULL, " "); - if(arg) - return do_soc(arg); - else - return syntax_error(arg); -} - -int do_write(uint32_t val, char *regname) -{ - char *dot = strchr(regname, '.'); - if(dot != NULL) - *dot++ = 0; - if(cur_soc == NULL) - { - printf("No soc selected!\n"); - return 1; - } - struct hwemul_soc_reg_t *reg = find_reg_by_name(cur_soc, regname); - int is_sct = 0; - uint32_t addr_off = 0; - if(reg == NULL) - { - size_t len = strlen(regname); - /* try SCT variant */ - if(strcmp(regname + len - 4, "_SET") == 0) - addr_off = 4; - else if(strcmp(regname + len - 4, "_CLR") == 0) - addr_off = 8; - else if(strcmp(regname + len - 4, "_TOG") == 0) - addr_off = 12; - else - { - printf("no reg '%s' found\n", regname); - return 1; - } - is_sct = 1; - regname[len - 4] = 0; - reg = find_reg_by_name(cur_soc, regname); - if(reg == NULL) - { - printf("no reg '%s' found\n", regname); - return 1; - } - } - if(dot) - { - struct hwemul_soc_reg_field_t *field = find_field_by_name(reg, dot); - if(field == NULL) - { - printf("no field '%s' found\n", dot); - return 1; - } - uint32_t actual_val = 0; - if(!is_sct) - { - if(hwemul_rw_mem(&hwdev, 1, reg->addr, &actual_val, sizeof(actual_val)) != sizeof(actual_val)) - { - printf("read error at %#x\n", reg->addr); - return 1; - } - printf("read %#x at %#x\n", actual_val, reg->addr); - } - uint32_t mask = ((1 << (field->last_bit - field->first_bit + 1)) - 1) << field->first_bit; - printf("mask=%#x\n", mask); - val = (actual_val & ~mask) | ((val << field->first_bit) & mask); - } - printf("write %#x to %#x\n", val, reg->addr + addr_off); - if(hwemul_rw_mem(&hwdev, 0, reg->addr + addr_off, &val, sizeof(val)) != sizeof(val)) - { - printf("write error at %#x\n", reg->addr); - return 1; - } - return 1; -} - -int parse_write() -{ - char *arg = strtok(NULL, " "); - uint32_t val; - if(!arg || !parse_uint32(arg, &val)) - return syntax_error(arg); - arg = strtok(NULL, " "); - if(arg) - return do_write(val, arg); - else - return syntax_error(arg); -} - -int parse_command(char *cmd) -{ - if(strcmp(cmd, "help") == 0) - return print_help(); - if(strcmp(cmd, "quit") == 0) - return 0; - if(strcmp(cmd, "call") == 0) - return parse_call(); - if(strcmp(cmd, "read32") == 0) - return parse_read32(); - if(strcmp(cmd, "write32") == 0) - return parse_write32(); - if(strcmp(cmd, "read") == 0) - return parse_read(); - if(strcmp(cmd, "soc") == 0) - return parse_soc(); - if(strcmp(cmd, "write") == 0) - return parse_write(); - return syntax_error(cmd); -} - -void interactive_mode(void) -{ - rl_bind_key('\t', rl_complete); - while(1) - { - char *input = readline("> "); - if(!input) - break; - add_history(input); - int ret = parse_command(input); - free(input); - if(ret == 0) - break; - } -} - -void usage(void) -{ - printf("hwemul_tool, compiled with hwemul %d.%d.%d\n", - HWEMUL_VERSION_MAJOR, HWEMUL_VERSION_MINOR, HWEMUL_VERSION_REV); - printf("available soc descriptions:"); - for(unsigned i = 0; i < hwemul_get_soc_list()->nr_socs; i++) - printf(" %s", hwemul_get_soc_list()->socs[i]->name); - printf("\n"); - printf("usage: hwemul_tool [options]\n"); - printf("options:\n"); - printf(" --help/-?\tDisplay this help\n"); - printf(" --quiet/-q\tQuiet non-command messages\n"); - exit(1); -} - -int main(int argc, char **argv) -{ - while(1) - { - static struct option long_options[] = - { - {"help", no_argument, 0, '?'}, - {"quiet", no_argument, 0, 'q'}, - {0, 0, 0, 0} - }; - - int c = getopt_long(argc, argv, "?q", long_options, NULL); - if(c == -1) - break; - switch(c) - { - case -1: - break; - case 'q': - g_quiet = true; - break; - case '?': - usage(); - break; - default: - abort(); - } - } - - if(argc - optind != 0) - { - usage(); - return 1; - } - - libusb_context *ctx; - libusb_init(&ctx); - libusb_set_debug(ctx, 3); - - if(!g_quiet) - printf("Looking for device %#04x:%#04x...\n", HWEMUL_USB_VID, HWEMUL_USB_PID); - - libusb_device_handle *handle = libusb_open_device_with_vid_pid(ctx, - HWEMUL_USB_VID, HWEMUL_USB_PID); - if(handle == NULL) - { - printf("No device found\n"); - return 1; - } - - libusb_device *mydev = libusb_get_device(handle); - if(!g_quiet) - { - printf("device found at %d:%d\n", - libusb_get_bus_number(mydev), - libusb_get_device_address(mydev)); - } - hwdev.handle = handle; - if(hwemul_probe(&hwdev)) - { - printf("Cannot probe device!\n"); - return 1; - } - - struct usb_resp_info_version_t ver; - int ret = hwemul_get_info(&hwdev, HWEMUL_INFO_VERSION, &ver, sizeof(ver)); - if(ret != sizeof(ver)) - { - printf("Cannot get version!\n"); - goto Lerr; - } - if(!g_quiet) - printf("Device version: %d.%d.%d\n", ver.major, ver.minor, ver.revision); - - struct usb_resp_info_layout_t layout; - ret = hwemul_get_info(&hwdev, HWEMUL_INFO_LAYOUT, &layout, sizeof(layout)); - if(ret != sizeof(layout)) - { - printf("Cannot get layout: %d\n", ret); - goto Lerr; - } - if(!g_quiet) - { - printf("Device layout:\n"); - printf(" Code: 0x%x (0x%x)\n", layout.oc_code_start, layout.oc_code_size); - printf(" Stack: 0x%x (0x%x)\n", layout.oc_stack_start, layout.oc_stack_size); - printf(" Buffer: 0x%x (0x%x)\n", layout.oc_buffer_start, layout.oc_buffer_size); - } - - struct usb_resp_info_features_t features; - ret = hwemul_get_info(&hwdev, HWEMUL_INFO_FEATURES, &features, sizeof(features)); - if(ret != sizeof(features)) - { - printf("Cannot get features: %d\n", ret); - goto Lerr; - } - if(!g_quiet) - { - printf("Device features:"); - if(features.feature_mask & HWEMUL_FEATURE_LOG) - printf(" log"); - if(features.feature_mask & HWEMUL_FEATURE_MEM) - printf(" mem"); - if(features.feature_mask & HWEMUL_FEATURE_CALL) - printf(" call"); - if(features.feature_mask & HWEMUL_FEATURE_JUMP) - printf(" jump"); - if(features.feature_mask & HWEMUL_FEATURE_AES_OTP) - printf(" aes_otp"); - printf("\n"); - } - - struct usb_resp_info_stmp_t stmp; - ret = hwemul_get_info(&hwdev, HWEMUL_INFO_STMP, &stmp, sizeof(stmp)); - if(ret != sizeof(stmp)) - { - printf("Cannot get stmp: %d\n", ret); - goto Lerr; - } - if(!g_quiet) - { - printf("Device stmp:\n"); - printf(" chip ID: %x (%s)\n", stmp.chipid,hwemul_get_product_string(&stmp)); - printf(" revision: %d (%s)\n", stmp.rev, hwemul_get_rev_string(&stmp)); - printf(" supported: %d\n", stmp.is_supported); - } - - if(!g_quiet) - { - void *rom = malloc(64 * 1024); - ret = hwemul_rw_mem(&hwdev, 1, 0xc0000000, rom, 64 * 1024); - if(ret != 64 * 1024) - { - printf("Cannot read ROM: %d\n", ret); - goto Lerr; - } - - printf("ROM successfully read!\n"); - FILE *f = fopen("rom.bin", "wb"); - fwrite(rom, 64 * 1024, 1, f); - fclose(f); - } - - if(!g_quiet) - { - struct - { - uint8_t iv[16]; - uint8_t data[16]; - } __attribute__((packed)) dcp_test; - - for(int i = 0; i < 16; i++) - dcp_test.iv[i] = rand(); - for(int i = 0; i < 16; i++) - dcp_test.data[i] = rand(); - printf("DCP\n"); - printf(" IN\n"); - printf(" IV:"); - for(int i = 0; i < 16; i++) - printf(" %02x", dcp_test.iv[i]); - printf("\n"); - printf(" IV:"); - for(int i = 0; i < 16; i++) - printf(" %02x", dcp_test.data[i]); - printf("\n"); - - if(!hwemul_aes_otp(&hwdev, &dcp_test, sizeof(dcp_test), HWEMUL_AES_OTP_ENCRYPT)) - { - printf(" OUT\n"); - printf(" IV:"); - for(int i = 0; i < 16; i++) - printf(" %02x", dcp_test.iv[i]); - printf("\n"); - printf(" IV:"); - for(int i = 0; i < 16; i++) - printf(" %02x", dcp_test.data[i]); - printf("\n"); - } - else - printf("DCP error!\n"); - } - - if(!g_quiet) - printf("Starting interactive session. Type 'help' to get help.\n"); - - interactive_mode(); - - Lerr: - if(features.feature_mask & HWEMUL_FEATURE_LOG) - { - if(!g_quiet) - printf("Device log:\n"); - print_log(&hwdev); - } - hwemul_release(&hwdev); - return 1; -} diff --git a/utils/hwstub/tools/hwstub_load.cpp b/utils/hwstub/tools/hwstub_load.cpp new file mode 100644 index 0000000000..d58eb83396 --- /dev/null +++ b/utils/hwstub/tools/hwstub_load.cpp @@ -0,0 +1,316 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2013 by Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "hwstub.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> +#include <stdbool.h> +#include <ctype.h> + +struct player_info_t +{ + const char *name; + const char *username; + int modelnum; +}; + +enum image_type_t +{ + IT_RAW, + IT_ROCKBOX, + IT_DETECT, + /* positive values reserved for rockbox-specific models */ +}; + +struct player_info_t players[] = +{ + { "zenv", "Zen V", 85 }, + { "zmoz", "Zen Mozaic", 87 }, + { "zen", "Zen", 88 }, + { "zxfi", "Zen X-Fi", 86 }, + { NULL, 0 }, +}; + +enum image_type_t detect_type(unsigned char *buffer, size_t size) +{ + if(size < 8) + return IT_RAW; + int player; + for(player = 0; players[player].name; player++) + if(memcmp(buffer + 4, players[player].name, 4) == 0) + break; + if(players[player].name == NULL) + return IT_RAW; + unsigned long checksum = players[player].modelnum; + for(size_t i = 8; i < size; i++) + checksum += buffer[i]; + unsigned long expected = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3]; + if(checksum != expected) + return IT_RAW; + return IT_ROCKBOX; +} + +const char *get_player_name(unsigned char *buffer) +{ + for(int player = 0; players[player].name; player++) + if(memcmp(buffer, players[player].name, 4) == 0) + return players[player].username; + return NULL; +} + +bool could_be_rockbox(unsigned char *buffer, size_t size) +{ + /* usually target use 3 or 4 digits */ + if(size >= 8 && isprint(buffer[4]) && isprint(buffer[5]) && isprint(buffer[6]) && + (isprint(buffer[7]) || buffer[7] == 0)) + { + unsigned long checksum = 0; + for(size_t i = 8; i < size; i++) + checksum += buffer[i]; + unsigned long expected = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3]; + unsigned long expected_modelnm = expected - checksum; + if(expected_modelnm < 150) + fprintf(stderr, "This file looks like a valid rockbox image but I don't know this player: %.4s (modelnum=%ld)\n", + buffer + 4, expected_modelnm); + else + fprintf(stderr, "This file could be a valid rockbox image but I don't know this player and the checksum is strange: %.4s\n", + buffer + 4); + return true; + } + else + return false; +} + +void usage(void) +{ + printf("usage: hwstub_load [options] <addr> <file>\n"); + printf("options:\n"); + printf(" --help/-? Display this help\n"); + printf(" --quiet/-q Quiet output\n"); + printf(" --type/-t <t> Override file type\n"); + printf("file types:\n"); + printf(" raw Load a raw binary blob\n"); + printf(" rockbox Load a rockbox image produced by scramble\n"); + printf(" detect Try to guess the format\n"); + printf("known players:"); + for(int i = 0; players[i].name; i++) + printf(" %s", players[i].name); + printf("\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + bool quiet = false; + struct hwstub_device_t hwdev; + enum image_type_t type = IT_DETECT; + + // parse command line + while(1) + { + static struct option long_options[] = + { + {"help", no_argument, 0, '?'}, + {"quiet", no_argument, 0, 'q'}, + {"type", required_argument, 0, 't'}, + {0, 0, 0, 0} + }; + + int c = getopt_long(argc, argv, "?qt:", long_options, NULL); + if(c == -1) + break; + switch(c) + { + case -1: + break; + case 'q': + quiet = true; + break; + case '?': + usage(); + break; + case 't': + if(strcmp(optarg, "raw") == 0) + type = IT_RAW; + else if(strcmp(optarg, "rockbox") == 0) + type = IT_ROCKBOX; + else if(strcmp(optarg, "detect") == 0) + type = IT_DETECT; + else + { + fprintf(stderr, "Unknown file type '%s'\n", optarg); + return 1; + } + break; + default: + abort(); + } + } + + if(optind + 2 != argc) + usage(); + + char *end; + unsigned long addr = strtoul(argv[optind], &end, 0); + if(*end) + { + fprintf(stderr, "Invalid load address\n"); + return 2; + } + + FILE *f = fopen(argv[optind + 1], "rb"); + if(f == NULL) + { + fprintf(stderr, "Cannot open file for reading: %m\n"); + return 3; + } + fseek(f, 0, SEEK_END); + size_t size = ftell(f); + fseek(f, 0, SEEK_SET); + unsigned char *buffer = (unsigned char*)malloc(size); + fread(buffer, size, 1, f); + fclose(f); + + if(type == IT_ROCKBOX || type == IT_DETECT) + { + enum image_type_t det = detect_type(buffer, size); + if(type == IT_ROCKBOX && det != IT_ROCKBOX) + { + if(!could_be_rockbox(buffer, size)) + fprintf(stderr, "This file does not appear to be valid rockbox image.\n"); + return 4; + } + if(type == IT_DETECT && det == IT_RAW) + could_be_rockbox(buffer, size); + type = det; + if(type == IT_ROCKBOX) + { + if(!quiet) + printf("Rockox image is for player %s (%.4s)\n", get_player_name(buffer + 4), buffer + 4); + memmove(buffer, buffer + 8, size - 8); + size -= 8; + } + } + + if(!quiet) + { + if(type == IT_RAW) + printf("Loading raw image at %#lx\n", addr); + else + printf("Loading rockbox image at %#lx\n", addr); + } + + // create usb context + libusb_context *ctx; + libusb_init(&ctx); + libusb_set_debug(ctx, 3); + + // look for device + if(!quiet) + printf("Looking for device %#04x:%#04x...\n", HWSTUB_USB_VID, HWSTUB_USB_PID); + + libusb_device_handle *handle = libusb_open_device_with_vid_pid(ctx, + HWSTUB_USB_VID, HWSTUB_USB_PID); + if(handle == NULL) + { + fprintf(stderr, "No device found\n"); + return 1; + } + + // admin stuff + libusb_device *mydev = libusb_get_device(handle); + if(!quiet) + { + printf("device found at %d:%d\n", + libusb_get_bus_number(mydev), + libusb_get_device_address(mydev)); + } + hwdev.handle = handle; + if(hwstub_probe(&hwdev)) + { + fprintf(stderr, "Cannot probe device!\n"); + return 1; + } + + // get hwstub information + struct usb_resp_info_version_t hwdev_ver; + int ret = hwstub_get_info(&hwdev, HWSTUB_INFO_VERSION, &hwdev_ver, sizeof(hwdev_ver)); + if(ret != sizeof(hwdev_ver)) + { + fprintf(stderr, "Cannot get version!\n"); + goto Lerr; + } + if(hwdev_ver.major != HWSTUB_VERSION_MAJOR || hwdev_ver.minor < HWSTUB_VERSION_MINOR) + { + printf("Warning: this tool is possibly incompatible with your device:\n"); + printf("Device version: %d.%d.%d\n", hwdev_ver.major, hwdev_ver.minor, hwdev_ver.revision); + printf("Host version: %d.%d.%d\n", HWSTUB_VERSION_MAJOR, HWSTUB_VERSION_MINOR, HWSTUB_VERSION_REV); + } + + // get features + struct usb_resp_info_features_t hwdev_features; + ret = hwstub_get_info(&hwdev, HWSTUB_INFO_FEATURES, &hwdev_features, sizeof(hwdev_features)); + if(ret != sizeof(hwdev_features)) + { + fprintf(stderr, "Cannot get features: %d\n", ret); + goto Lerr; + } + if(!(hwdev_features.feature_mask & HWSTUB_RW_MEM)) + { + fprintf(stderr, "Device doesn't support R/W commands\n"); + goto Lerr; + } + if(!(hwdev_features.feature_mask & HWSTUB_JUMP)) + { + fprintf(stderr, "Device doesn't support jump commands\n"); + goto Lerr; + } + ret = hwstub_rw_mem(&hwdev, 0, addr, buffer, size); + if(ret != (int)size) + { + fprintf(stderr, "Image write failed\n"); + goto Lerr; + } + hwstub_jump(&hwdev, addr); + + hwstub_release(&hwdev); + return 0; + + Lerr: + // display log if handled + if(hwdev_features.feature_mask & HWSTUB_FEATURE_LOG) + { + fprintf(stderr, "Device log:\n"); + do + { + char buffer[128]; + int length = hwstub_get_log(&hwdev, buffer, sizeof(buffer) - 1); + if(length <= 0) + break; + buffer[length] = 0; + fprintf(stderr, "%s", buffer); + }while(1); + } + hwstub_release(&hwdev); + return 1; +} + diff --git a/utils/hwstub/tools/hwstub_shell.cpp b/utils/hwstub/tools/hwstub_shell.cpp new file mode 100644 index 0000000000..58147319e0 --- /dev/null +++ b/utils/hwstub/tools/hwstub_shell.cpp @@ -0,0 +1,873 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2012 by Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "hwstub.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> +#include <stdbool.h> +#include <readline/readline.h> +#include <readline/history.h> +#include <lua.hpp> +#include "soc_desc.hpp" + +#if LUA_VERSION_NUM < 502 +#warning You need at least lua 5.2 +#endif + +/** + * Global variables + */ +bool g_quiet = false; +struct hwstub_device_t g_hwdev; +struct usb_resp_info_version_t g_hwdev_ver; +struct usb_resp_info_layout_t g_hwdev_layout; +struct usb_resp_info_features_t g_hwdev_features; +struct usb_resp_info_stmp_t g_hwdev_stmp; +lua_State *g_lua; + +/** + * hw specific + */ + +void print_log(struct hwstub_device_t *hwdev) +{ + do + { + char buffer[128]; + int length = hwstub_get_log(hwdev, buffer, sizeof(buffer) - 1); + if(length <= 0) + break; + buffer[length] = 0; + printf("%s", buffer); + }while(1); +} + +/** + * Lua specific + */ +int my_lua_help(lua_State *state) +{ + bool has_sub = false; + // implement help() in C so that we do not rely on the init to implement it + // help can take optional arguments + int n = lua_gettop(state); + + lua_getglobal(state, "hwstub"); + if(!lua_istable(state, -1)) + goto Lerr; + lua_getfield(state, -1, "help"); + if(!lua_istable(state, -1)) + goto Lerr; + + for(int i = 1; i <= n; i++) + { + lua_pushvalue(state, i); + lua_gettable(state, -2); + if(lua_isnil(state, -1)) + { + printf("I don't know subtopic '%s'!\n", lua_tostring(state, i)); + return 0; + } + if(!lua_istable(state, -1)) + { + printf("Subtopic '%s' is not a table!\n", lua_tostring(state, i)); + return 0; + } + } + + printf("================[ HELP "); + for(int i = 1; i <= n; i++) + printf("> %s ", lua_tostring(state, i)); + printf("]================\n"); + + lua_pushnil(state); + while(lua_next(state, -2)) + { + // key is at -2 and value at -1 + if(lua_isstring(state, -1)) + printf("%s\n", lua_tostring(state, -1)); + else if(lua_istable(state, -1)) + has_sub = true; + // pop value but keep key + lua_pop(state, 1); + } + + if(has_sub) + { + printf("\n"); + printf("You can get more information on the following subtopics:\n"); + lua_pushnil(state); + while(lua_next(state, -2)) + { + // key is at -2 and value at -1 + if(lua_istable(state, -1)) + printf("* %s\n", lua_tostring(state, -2)); + // pop value but keep key + lua_pop(state, 1); + } + } + printf("================[ STOP ]================\n"); + + return 0; + + Lerr: + printf("There is a problem with the Lua context. Help is expected to be in hwstub.help\n"); + printf("You must have messed badly the environment.\n"); + return 0; +} + +typedef soc_word_t (*hw_readn_fn_t)(lua_State *state, soc_addr_t addr); +typedef void (*hw_writen_fn_t)(lua_State *state, soc_addr_t addr, soc_word_t val); + +soc_word_t hw_read8(lua_State *state, soc_addr_t addr) +{ + uint8_t u; + if(hwstub_rw_mem(&g_hwdev, 1, addr, &u, sizeof(u)) != sizeof(u)) + luaL_error(state, "fail to read8 @ %p", addr); + return u; +} + +soc_word_t hw_read16(lua_State *state, soc_addr_t addr) +{ + uint16_t u; + if(hwstub_rw_mem(&g_hwdev, 1, addr, &u, sizeof(u)) != sizeof(u)) + luaL_error(state, "fail to read16 @ %p", addr); + return u; +} + +soc_word_t hw_read32(lua_State *state, soc_addr_t addr) +{ + uint32_t u; + if(hwstub_rw_mem(&g_hwdev, 1, addr, &u, sizeof(u)) != sizeof(u)) + luaL_error(state, "fail to read32 @ %p", addr); + return u; +} + +void hw_write8(lua_State *state, soc_addr_t addr, soc_word_t val) +{ + uint8_t u = val; + if(hwstub_rw_mem(&g_hwdev, 0, addr, &u, sizeof(u)) != sizeof(u)) + luaL_error(state, "fail to write8 @ %p", addr); +} + +void hw_write16(lua_State *state, soc_addr_t addr, soc_word_t val) +{ + uint16_t u = val; + if(hwstub_rw_mem(&g_hwdev, 0, addr, &u, sizeof(u)) != sizeof(u)) + luaL_error(state, "fail to write16 @ %p", addr); +} + +void hw_write32(lua_State *state, soc_addr_t addr, soc_word_t val) +{ + uint32_t u = val; + if(hwstub_rw_mem(&g_hwdev, 0, addr, &u, sizeof(u)) != sizeof(u)) + luaL_error(state, "fail to write32 @ %p", addr); +} + +int my_lua_readn(lua_State *state) +{ + hw_readn_fn_t fn = (hw_readn_fn_t)lua_touserdata(state, lua_upvalueindex(1)); + int n = lua_gettop(state); + if(n != 1) + luaL_error(state, "readn takes a single argument"); + lua_pushunsigned(state, fn(state, luaL_checkunsigned(state, 1))); + return 1; +} + +int my_lua_writen(lua_State *state) +{ + hw_writen_fn_t fn = (hw_writen_fn_t)lua_touserdata(state, lua_upvalueindex(1)); + int n = lua_gettop(state); + if(n != 2) + luaL_error(state, "writen takes two arguments"); + fn(state, luaL_checkunsigned(state, 1), luaL_checkunsigned(state, 2)); + return 0; +} + +int my_lua_printlog(lua_State *state) +{ + print_log(&g_hwdev); + return 0; +} + +bool my_lua_import_hwstub() +{ + int oldtop = lua_gettop(g_lua); + + lua_newtable(g_lua); // hwstub + + lua_newtable(g_lua); // options + lua_pushboolean(g_lua, g_quiet); + lua_setfield(g_lua, -2, "quiet"); + lua_setfield(g_lua, -2, "options"); + + lua_newtable(g_lua); // dev + lua_newtable(g_lua); // version + lua_pushinteger(g_lua, g_hwdev_ver.major); + lua_setfield(g_lua, -2, "major"); + lua_pushinteger(g_lua, g_hwdev_ver.minor); + lua_setfield(g_lua, -2, "minor"); + lua_pushinteger(g_lua, g_hwdev_ver.revision); + lua_setfield(g_lua, -2, "revision"); + lua_setfield(g_lua, -2, "version"); + + lua_newtable(g_lua); // layout + lua_newtable(g_lua); // ocram + lua_newtable(g_lua); // code + lua_pushinteger(g_lua, g_hwdev_layout.oc_code_start); + lua_setfield(g_lua, -2, "start"); + lua_pushinteger(g_lua, g_hwdev_layout.oc_code_size); + lua_setfield(g_lua, -2, "size"); + lua_setfield(g_lua, -2, "code"); + lua_newtable(g_lua); // stack + lua_pushinteger(g_lua, g_hwdev_layout.oc_stack_start); + lua_setfield(g_lua, -2, "start"); + lua_pushinteger(g_lua, g_hwdev_layout.oc_stack_size); + lua_setfield(g_lua, -2, "size"); + lua_setfield(g_lua, -2, "stack"); + lua_newtable(g_lua); // buffer + lua_pushinteger(g_lua, g_hwdev_layout.oc_buffer_start); + lua_setfield(g_lua, -2, "start"); + lua_pushinteger(g_lua, g_hwdev_layout.oc_buffer_size); + lua_setfield(g_lua, -2, "size"); + lua_setfield(g_lua, -2, "buffer"); + lua_setfield(g_lua, -2, "ocram"); + lua_setfield(g_lua, -2, "layout"); + + lua_newtable(g_lua); // stmp + lua_pushinteger(g_lua, g_hwdev_stmp.chipid); + lua_setfield(g_lua, -2, "chipid"); + lua_pushinteger(g_lua, g_hwdev_stmp.rev); + lua_setfield(g_lua, -2, "rev"); + lua_setfield(g_lua, -2, "stmp"); + + lua_newtable(g_lua); // features + lua_pushboolean(g_lua, !!(g_hwdev_features.feature_mask & HWSTUB_FEATURE_LOG)); + lua_setfield(g_lua, -2, "log"); + lua_pushboolean(g_lua, !!(g_hwdev_features.feature_mask & HWSTUB_FEATURE_MEM)); + lua_setfield(g_lua, -2, "mem"); + lua_pushboolean(g_lua, !!(g_hwdev_features.feature_mask & HWSTUB_FEATURE_CALL)); + lua_setfield(g_lua, -2, "call"); + lua_pushboolean(g_lua, !!(g_hwdev_features.feature_mask & HWSTUB_FEATURE_JUMP)); + lua_setfield(g_lua, -2, "jump"); + lua_pushboolean(g_lua, !!(g_hwdev_features.feature_mask & HWSTUB_FEATURE_AES_OTP)); + lua_setfield(g_lua, -2, "aes_otp"); + lua_setfield(g_lua, -2, "features"); + + lua_pushlightuserdata(g_lua, (void *)&hw_read8); + lua_pushcclosure(g_lua, my_lua_readn, 1); + lua_setfield(g_lua, -2, "read8"); + lua_pushlightuserdata(g_lua, (void *)&hw_read16); + lua_pushcclosure(g_lua, my_lua_readn, 1); + lua_setfield(g_lua, -2, "read16"); + lua_pushlightuserdata(g_lua, (void *)&hw_read32); + lua_pushcclosure(g_lua, my_lua_readn, 1); + lua_setfield(g_lua, -2, "read32"); + + lua_pushlightuserdata(g_lua, (void *)&hw_write8); + lua_pushcclosure(g_lua, my_lua_writen, 1); + lua_setfield(g_lua, -2, "write8"); + lua_pushlightuserdata(g_lua, (void *)&hw_write16); + lua_pushcclosure(g_lua, my_lua_writen, 1); + lua_setfield(g_lua, -2, "write16"); + lua_pushlightuserdata(g_lua, (void *)&hw_write32); + lua_pushcclosure(g_lua, my_lua_writen, 1); + lua_setfield(g_lua, -2, "write32"); + lua_pushcclosure(g_lua, my_lua_printlog, 0); + lua_setfield(g_lua, -2, "print_log"); + + lua_setfield(g_lua, -2, "dev"); + + lua_newtable(g_lua); // host + lua_newtable(g_lua); // version + lua_pushinteger(g_lua, HWSTUB_VERSION_MAJOR); + lua_setfield(g_lua, -2, "major"); + lua_pushinteger(g_lua, HWSTUB_VERSION_MINOR); + lua_setfield(g_lua, -2, "minor"); + lua_pushinteger(g_lua, HWSTUB_VERSION_REV); + lua_setfield(g_lua, -2, "revision"); + lua_setfield(g_lua, -2, "version"); + lua_setfield(g_lua, -2, "host"); + + lua_newtable(g_lua); // soc + lua_setfield(g_lua, -2, "soc"); + + lua_newtable(g_lua); // help + lua_pushinteger(g_lua, 1); + lua_pushstring(g_lua, "This is the help for hwstub_tool. This tools uses Lua to interpret commands."); + lua_settable(g_lua, -3); + lua_pushinteger(g_lua, 2); + lua_pushstring(g_lua, "You can get help by running help(). Help is organised in topics and subtopics and so on."); + lua_settable(g_lua, -3); + lua_pushinteger(g_lua, 3); + lua_pushstring(g_lua, "If you want to access the help of topic x, subtopic y, subsubtopic z, type help(x,y,z)."); + lua_settable(g_lua, -3); + lua_pushinteger(g_lua, 4); + lua_pushstring(g_lua, "Example: help(\"hwstub\")."); + lua_settable(g_lua, -3); + lua_setfield(g_lua, -2, "help"); + + lua_setglobal(g_lua, "hwstub"); + + lua_pushcfunction(g_lua, my_lua_help); + lua_setglobal(g_lua, "help"); + + if(lua_gettop(g_lua) != oldtop) + { + printf("internal error: unbalanced my_lua_import_soc"); + return false; + } + return true; +} + +int my_lua_read_reg(lua_State *state) +{ + int n = lua_gettop(state); + if(n != 0) + luaL_error(state, "read() takes no argument"); + soc_addr_t addr = lua_tounsigned(state, lua_upvalueindex(1)); + lua_pushunsigned(state, hw_read32(state, addr)); + return 1; +} + +int my_lua_write_reg(lua_State *state) +{ + int n = lua_gettop(state); + if(n != 1) + luaL_error(state, "write() takes one argument"); + soc_word_t val = luaL_checkunsigned(state, 1); + soc_addr_t addr = lua_tounsigned(state, lua_upvalueindex(1)); + hw_write32(state, addr, val); + return 0; +} + +int my_lua_read_field(lua_State *state) +{ + int n = lua_gettop(state); + if(n != 0) + luaL_error(state, "read() takes no argument"); + soc_addr_t addr = lua_tounsigned(state, lua_upvalueindex(1)); + soc_word_t shift = lua_tounsigned(state, lua_upvalueindex(2)); + soc_word_t mask = lua_tounsigned(state, lua_upvalueindex(3)); + lua_pushunsigned(state, (hw_read32(state, addr) >> shift) & mask); + return 1; +} + +int my_lua_write_field(lua_State *state) +{ + int n = lua_gettop(state); + if(n != 0 && n!= 1) + luaL_error(state, "write() takes one or no argument"); + soc_addr_t addr = lua_tounsigned(state, lua_upvalueindex(1)); + soc_word_t shift = lua_tounsigned(state, lua_upvalueindex(2)); + soc_word_t mask = lua_tounsigned(state, lua_upvalueindex(3)); + bool is_sct = lua_toboolean(state, lua_upvalueindex(5)); + + soc_word_t value = mask; + if(n == 1) + { + if(!lua_isnumber(state, 1) && lua_isstring(state, 1)) + { + lua_pushvalue(state, lua_upvalueindex(4)); + lua_pushvalue(state, 1); + lua_gettable(state, -2); + if(lua_isnil(state, -1)) + luaL_error(state, "field has no value %s", lua_tostring(state, 1)); + value = luaL_checkunsigned(state, -1); + lua_pop(state, 2); + } + else + value = luaL_checkunsigned(state, 1); + value &= mask; + } + + if(!is_sct) + value = value << shift | (hw_read32(state, addr) & ~(mask << shift)); + else + value <<= shift; + + hw_write32(state, addr, value); + return 0; +} + +void my_lua_create_field(soc_addr_t addr, const soc_reg_field_t& field, bool sct) +{ + lua_newtable(g_lua); + + lua_pushstring(g_lua, field.name.c_str()); + lua_setfield(g_lua, -2, "name"); + + lua_pushunsigned(g_lua, addr); + lua_setfield(g_lua, -2, "addr"); + + lua_pushboolean(g_lua, sct); + lua_setfield(g_lua, -2, "sct"); + + lua_pushunsigned(g_lua, field.first_bit); + lua_setfield(g_lua, -2, "first_bit"); + + lua_pushunsigned(g_lua, field.last_bit); + lua_setfield(g_lua, -2, "last_bit"); + + lua_pushunsigned(g_lua, field.bitmask()); + lua_setfield(g_lua, -2, "bitmask"); + + soc_word_t local_bitmask = field.bitmask() >> field.first_bit; + lua_pushunsigned(g_lua, local_bitmask); + lua_setfield(g_lua, -2, "local_bitmask"); + + lua_pushunsigned(g_lua, addr); + lua_pushunsigned(g_lua, field.first_bit); + lua_pushunsigned(g_lua, local_bitmask); + lua_pushcclosure(g_lua, my_lua_read_field, 3); + lua_setfield(g_lua, -2, "read"); + + lua_pushunsigned(g_lua, addr); + lua_pushunsigned(g_lua, field.first_bit); + lua_pushunsigned(g_lua, local_bitmask); + lua_pushvalue(g_lua, -4); + lua_pushboolean(g_lua, false); + lua_pushcclosure(g_lua, my_lua_write_field, 5); + lua_setfield(g_lua, -2, "write"); + + if(sct) + { + lua_pushunsigned(g_lua, addr + 4); + lua_pushunsigned(g_lua, field.first_bit); + lua_pushunsigned(g_lua, local_bitmask); + lua_pushvalue(g_lua, -4); + lua_pushboolean(g_lua, true); + lua_pushcclosure(g_lua, my_lua_write_field, 5); + lua_setfield(g_lua, -2, "set"); + + lua_pushunsigned(g_lua, addr + 8); + lua_pushunsigned(g_lua, field.first_bit); + lua_pushunsigned(g_lua, local_bitmask); + lua_pushvalue(g_lua, -4); + lua_pushboolean(g_lua, true); + lua_pushcclosure(g_lua, my_lua_write_field, 5); + lua_setfield(g_lua, -2, "clr"); + + lua_pushunsigned(g_lua, addr + 12); + lua_pushunsigned(g_lua, field.first_bit); + lua_pushunsigned(g_lua, local_bitmask); + lua_pushvalue(g_lua, -4); + lua_pushboolean(g_lua, true); + lua_pushcclosure(g_lua, my_lua_write_field, 5); + lua_setfield(g_lua, -2, "tog"); + } + + for(size_t i = 0; i < field.value.size(); i++) + { + lua_pushunsigned(g_lua, field.value[i].value); + lua_setfield(g_lua, -2, field.value[i].name.c_str()); + } +} + +void my_lua_create_reg(soc_addr_t addr, size_t index, const soc_reg_t& reg) +{ + lua_newtable(g_lua); + + lua_pushstring(g_lua, reg.addr[index].name.c_str()); + lua_setfield(g_lua, -2, "name"); + + lua_pushunsigned(g_lua, addr + reg.addr[index].addr); + lua_setfield(g_lua, -2, "addr"); + + lua_pushboolean(g_lua, !!(reg.flags & REG_HAS_SCT)); + lua_setfield(g_lua, -2, "sct"); + + lua_pushunsigned(g_lua, addr + reg.addr[index].addr); + lua_pushcclosure(g_lua, my_lua_read_reg, 1); + lua_setfield(g_lua, -2, "read"); + + lua_pushunsigned(g_lua, addr + reg.addr[index].addr); + lua_pushcclosure(g_lua, my_lua_write_reg, 1); + lua_setfield(g_lua, -2, "write"); + + if(reg.flags & REG_HAS_SCT) + { + lua_pushunsigned(g_lua, addr + reg.addr[index].addr + 4); + lua_pushcclosure(g_lua, my_lua_write_reg, 1); + lua_setfield(g_lua, -2, "set"); + + lua_pushunsigned(g_lua, addr + reg.addr[index].addr + 8); + lua_pushcclosure(g_lua, my_lua_write_reg, 1); + lua_setfield(g_lua, -2, "clr"); + + lua_pushunsigned(g_lua, addr + reg.addr[index].addr + 12); + lua_pushcclosure(g_lua, my_lua_write_reg, 1); + lua_setfield(g_lua, -2, "tog"); + } + + for(size_t i = 0; i < reg.field.size(); i++) + { + my_lua_create_field(addr + reg.addr[index].addr, reg.field[i], + reg.flags & REG_HAS_SCT); + lua_setfield(g_lua, -2, reg.field[i].name.c_str()); + } +} + +void my_lua_create_dev(size_t index, const soc_dev_t& dev) +{ + lua_newtable(g_lua); + + lua_pushstring(g_lua, dev.addr[index].name.c_str()); + lua_setfield(g_lua, -2, "name"); + + lua_pushunsigned(g_lua, dev.addr[index].addr); + lua_setfield(g_lua, -2, "addr"); + + for(size_t i = 0; i < dev.reg.size(); i++) + { + bool table = dev.reg[i].addr.size() > 1; + if(table) + lua_newtable(g_lua); + else + lua_pushnil(g_lua); + + for(size_t k = 0; k < dev.reg[i].addr.size(); k++) + { + my_lua_create_reg(dev.addr[index].addr, k, dev.reg[i]); + if(table) + { + lua_pushinteger(g_lua, k); + lua_pushvalue(g_lua, -2); + lua_settable(g_lua, -4); + } + lua_setfield(g_lua, -3, dev.reg[i].addr[k].name.c_str()); + } + + if(table) + lua_setfield(g_lua, -2, dev.reg[i].name.c_str()); + else + lua_pop(g_lua, 1); + } +} + +bool my_lua_import_soc(const soc_t& soc) +{ + int oldtop = lua_gettop(g_lua); + + lua_getglobal(g_lua, "hwstub"); + lua_getfield(g_lua, -1, "soc"); + + lua_newtable(g_lua); + + lua_pushstring(g_lua, soc.name.c_str()); + lua_setfield(g_lua, -2, "name"); + + lua_pushstring(g_lua, soc.desc.c_str()); + lua_setfield(g_lua, -2, "desc"); + + for(size_t i = 0; i < soc.dev.size(); i++) + { + bool table = soc.dev[i].addr.size() > 1; + if(table) + lua_newtable(g_lua); + else + lua_pushnil(g_lua); + + for(size_t k = 0; k < soc.dev[i].addr.size(); k++) + { + my_lua_create_dev(k, soc.dev[i]); + if(table) + { + lua_pushinteger(g_lua, k + 1); + lua_pushvalue(g_lua, -2); + lua_settable(g_lua, -4); + } + lua_setfield(g_lua, -3, soc.dev[i].addr[k].name.c_str()); + } + + if(table) + lua_setfield(g_lua, -2, soc.dev[i].name.c_str()); + else + lua_pop(g_lua, 1); + } + + lua_setfield(g_lua, -2, soc.name.c_str()); + + lua_pop(g_lua, 2); + + if(lua_gettop(g_lua) != oldtop) + { + printf("internal error: unbalanced my_lua_import_soc\n"); + return false; + } + return true; +} + +bool my_lua_import_soc(const std::vector< soc_t >& socs) +{ + for(size_t i = 0; i < socs.size(); i++) + { + if(!g_quiet) + printf("importing %s...\n", socs[i].name.c_str()); + if(!my_lua_import_soc(socs[i])) + return false; + } + return true; +} + +/** + * glue + */ + +void usage(void) +{ + printf("hwstub_tool, compiled with hwstub %d.%d.%d\n", + HWSTUB_VERSION_MAJOR, HWSTUB_VERSION_MINOR, HWSTUB_VERSION_REV); + printf("\n"); + printf("usage: hwstub_tool [options] <soc desc files>\n"); + printf("options:\n"); + printf(" --help/-?\tDisplay this help\n"); + printf(" --quiet/-q\tQuiet non-command messages\n"); + printf(" -i <init>\tSet lua init file (default is init.lua)\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + const char *lua_init = "init.lua"; + // parse command line + while(1) + { + static struct option long_options[] = + { + {"help", no_argument, 0, '?'}, + {"quiet", no_argument, 0, 'q'}, + {0, 0, 0, 0} + }; + + int c = getopt_long(argc, argv, "?qi:", long_options, NULL); + if(c == -1) + break; + switch(c) + { + case -1: + break; + case 'q': + g_quiet = true; + break; + case '?': + usage(); + break; + case 'i': + lua_init = optarg; + break; + default: + abort(); + } + } + + // load register descriptions + std::vector< soc_t > socs; + for(int i = optind; i < argc; i++) + if(!soc_desc_parse_xml(argv[i], socs)) + { + printf("Cannot load description '%s'\n", argv[i]); + return 2; + } + + // create usb context + libusb_context *ctx; + libusb_init(&ctx); + libusb_set_debug(ctx, 3); + + // look for device + if(!g_quiet) + printf("Looking for device %#04x:%#04x...\n", HWSTUB_USB_VID, HWSTUB_USB_PID); + + libusb_device_handle *handle = libusb_open_device_with_vid_pid(ctx, + HWSTUB_USB_VID, HWSTUB_USB_PID); + if(handle == NULL) + { + printf("No device found\n"); + return 1; + } + + // admin stuff + libusb_device *mydev = libusb_get_device(handle); + if(!g_quiet) + { + printf("device found at %d:%d\n", + libusb_get_bus_number(mydev), + libusb_get_device_address(mydev)); + } + g_hwdev.handle = handle; + if(hwstub_probe(&g_hwdev)) + { + printf("Cannot probe device!\n"); + return 1; + } + + // get hwstub information + int ret = hwstub_get_info(&g_hwdev, HWSTUB_INFO_VERSION, &g_hwdev_ver, sizeof(g_hwdev_ver)); + if(ret != sizeof(g_hwdev_ver)) + { + printf("Cannot get version!\n"); + goto Lerr; + } + if(g_hwdev_ver.major != HWSTUB_VERSION_MAJOR || g_hwdev_ver.minor < HWSTUB_VERSION_MINOR) + { + printf("Warning: this tool is possibly incompatible with your device:\n"); + printf("Device version: %d.%d.%d\n", g_hwdev_ver.major, g_hwdev_ver.minor, g_hwdev_ver.revision); + printf("Host version: %d.%d.%d\n", HWSTUB_VERSION_MAJOR, HWSTUB_VERSION_MINOR, HWSTUB_VERSION_REV); + } + + // get memory layout information + ret = hwstub_get_info(&g_hwdev, HWSTUB_INFO_LAYOUT, &g_hwdev_layout, sizeof(g_hwdev_layout)); + if(ret != sizeof(g_hwdev_layout)) + { + printf("Cannot get layout: %d\n", ret); + goto Lerr; + } + + // get features + ret = hwstub_get_info(&g_hwdev, HWSTUB_INFO_FEATURES, &g_hwdev_features, sizeof(g_hwdev_features)); + if(ret != sizeof(g_hwdev_features)) + { + printf("Cannot get features: %d\n", ret); + goto Lerr; + } + + // get STMP specific information + ret = hwstub_get_info(&g_hwdev, HWSTUB_INFO_STMP, &g_hwdev_stmp, sizeof(g_hwdev_stmp)); + if(ret != sizeof(g_hwdev_stmp)) + { + printf("Cannot get stmp: %d\n", ret); + goto Lerr; + } + + // dump ROM + if(!g_quiet) + { + void *rom = malloc(64 * 1024); + ret = hwstub_rw_mem(&g_hwdev, 1, 0xc0000000, rom, 64 * 1024); + if(ret != 64 * 1024) + { + printf("Cannot read ROM: %d\n", ret); + goto Lerr; + } + + printf("ROM successfully read!\n"); + FILE *f = fopen("rom.bin", "wb"); + fwrite(rom, 64 * 1024, 1, f); + fclose(f); + } + + // test DCP +#if 0 + if(!g_quiet) + { + struct + { + uint8_t iv[16]; + uint8_t data[16]; + } __attribute__((packed)) dcp_test; + + for(int i = 0; i < 16; i++) + dcp_test.iv[i] = rand(); + for(int i = 0; i < 16; i++) + dcp_test.data[i] = rand(); + printf("DCP\n"); + printf(" IN\n"); + printf(" IV:"); + for(int i = 0; i < 16; i++) + printf(" %02x", dcp_test.iv[i]); + printf("\n"); + printf(" IV:"); + for(int i = 0; i < 16; i++) + printf(" %02x", dcp_test.data[i]); + printf("\n"); + + if(!hwstub_aes_otp(&g_hwdev, &dcp_test, sizeof(dcp_test), HWSTUB_AES_OTP_ENCRYPT)) + { + printf(" OUT\n"); + printf(" IV:"); + for(int i = 0; i < 16; i++) + printf(" %02x", dcp_test.iv[i]); + printf("\n"); + printf(" IV:"); + for(int i = 0; i < 16; i++) + printf(" %02x", dcp_test.data[i]); + printf("\n"); + } + else + printf("DCP error!\n"); + } +#endif + + /** Init lua */ + + // create lua state + g_lua = luaL_newstate(); + if(g_lua == NULL) + { + printf("Cannot create lua state\n"); + return 1; + } + // import hwstub + if(!my_lua_import_hwstub()) + printf("Cannot import hwstub description into Lua context\n"); + // open all standard libraires + luaL_openlibs(g_lua); + // import socs + if(!my_lua_import_soc(socs)) + printf("Cannot import SoC descriptions into Lua context\n"); + + if(luaL_dofile(g_lua, lua_init)) + printf("error in init: %s\n", lua_tostring(g_lua, -1)); + lua_pop(g_lua, lua_gettop(g_lua)); + + /** start interactive mode */ + if(!g_quiet) + printf("Starting interactive lua session. Type 'help()' to get some help\n"); + + // use readline to provide some history and completion + rl_bind_key('\t', rl_complete); + while(1) + { + char *input = readline("> "); + if(!input) + break; + add_history(input); + // evaluate string + if(luaL_dostring(g_lua, input)) + printf("error: %s\n", lua_tostring(g_lua, -1)); + // pop everything to start from a clean stack + lua_pop(g_lua, lua_gettop(g_lua)); + free(input); + } + + Lerr: + // display log if handled + if(g_hwdev_features.feature_mask & HWSTUB_FEATURE_LOG) + { + if(!g_quiet) + printf("Device log:\n"); + print_log(&g_hwdev); + } + hwstub_release(&g_hwdev); + return 1; +} diff --git a/utils/hwstub/tools/init.lua b/utils/hwstub/tools/init.lua new file mode 100644 index 0000000000..142c77e20a --- /dev/null +++ b/utils/hwstub/tools/init.lua @@ -0,0 +1,104 @@ +-- init code for hwstub_tools + +-- +-- HELP +-- +HELP = hwstub.help + +function HELP:create_topic(name) + self[name] = { create_topic = HELP.create_topic, add = HELP.add, get_topic = HELP.get_topic } + return self[name] +end + +function HELP:get_topic(name) + return self[name] +end + +function HELP:add(text) + table.insert(self, text) +end + +do + local h = HELP:create_topic("hwstub") + h:add("This tool uses a number of well-defined namespaces (tables) to organise its features.") + h:add("The hwstub table contains a number of information and functions related to the tool itself.") + h:add("Of particular interest are") + h:add("* hwstub.host which holds host specific information.") + h:add("* hwstub.dev which holds device specific information. See DEV") + h:add("* hwstub.help (aka HELP) which holds the help. See HELP."); + h:add("* hwstub.soc which holds soc specific information. See HW"); + + h = HELP:create_topic("HELP"); + h:add("This variable redirects to hwstub.help and provides access to the help system."); + h:add("You can enhance the help using the following methods on any topic (including HELP itself)."); + h:add("* t:create_topic(s) to create a new subtopic named s under topic t"); + h:add("* t:add(s) to add a help line to topic t"); + h:add("* t:get_topic(s) to get the subtopic s under topic t"); + + h = HELP:create_topic("DEV"); + h:add("This variable redirects to hwstub.dev and provides direct access to the device."); + h:add("It contains some information about the device and the following methods."); + h:add("* read8/16/32(a) reads a 8/16/32-bit integer at address a"); + h:add("* write8/16/32(a, v) writes the 8/16/32-bit integer v at address a"); + + h = HELP:create_topic("HW"); + h:add("This variable redirects to the current soc under hwstub.soc and should be changed by calling hwstub:soc:select only."); + h:add("The complete register tree can be found under HW in a well organise fashion."); + h:add("* HW.dev points to device dev"); + h:add("* HW.dev[i] points to device devi if there are several copies of the device at different addresses."); + h:add("* HW.dev.reg points to the register reg under dev"); + h:add("* HW.dev.reg[i] points to the register regi if there are several copies."); + h:add("* HW.dev.reg.f points to the field f under register reg."); + h:add("* HW.dev.reg.f.v gives the value of named value v of field f."); + h:add("* All registers can be read using HW.dev.reg.read() and written using HW.dev.reg.write(v)."); + h:add("* Register with a SCT variant also implement HW.dev.reg.set/clr/tog(v)."); + h:add("* All register field can be read using HW.dev.reg.f.read() and written using HW.dev.reg.f.write(v)."); + h:add("* Field writes can either give a integer or a named value to write(v)."); + h:add("* Register with a SCT variant also implement HW.dev.reg.f.set/clr/tog(v) with the same properties."); + h:add("* All devices, registers and fields also have descriptions available such as addresses."); +end + +-- +-- INFO +-- + +if not hwstub.options.quiet then + print("information") + print(" hwstub") + print(" version: " .. string.format("%d.%d.%d", hwstub.host.version.major, + hwstub.host.version.minor, hwstub.host.version.revision)) + print(" device") + print(" version: " .. string.format("%d.%d.%d", hwstub.dev.version.major, + hwstub.dev.version.minor, hwstub.dev.version.revision)) + print(" layout") + print(" on-chip ram") + print(" code: " .. string.format("%#x bytes @ %#x", + hwstub.dev.layout.ocram.code.size, hwstub.dev.layout.ocram.code.start)) + print(" stack: " .. string.format("%#x bytes @ %#x", + hwstub.dev.layout.ocram.stack.size, hwstub.dev.layout.ocram.stack.start)) + print(" buffer: " .. string.format("%#x bytes @ %#x", + hwstub.dev.layout.ocram.buffer.size, hwstub.dev.layout.ocram.buffer.start)) + print(" features"); + print(" log: " .. tostring(hwstub.dev.features.log)) + print(" mem: " .. tostring(hwstub.dev.features.mem)) + print(" call: " .. tostring(hwstub.dev.features.call)) + print(" jump: " .. tostring(hwstub.dev.features.jump)) + print(" aes_otp: " .. tostring(hwstub.dev.features.aes_otp)) +end + +-- +-- SOC +-- +function hwstub.soc:select(soc) + if self[soc] == nil then return false end + print("Selecting soc " .. soc .. ". Redirecting HW to hwstub.soc." .. soc) + HW = self[soc] + return true +end + +-- +-- DEV +-- +DEV = hwstub.dev + +require "lua/load" |