From cb54b4d409d0cded42f42aedc34a033358ff0dc8 Mon Sep 17 00:00:00 2001 From: sys64738 Date: Sat, 29 Jan 2022 19:09:46 +0100 Subject: [PATCH] rpi baremetal stuff --- jazelle.c | 32 ++++-- rpi/Makefile | 19 +++- rpi/nl-glue.c | 98 +++++++++++++++++ rpi/rpi.c | 288 ++++++++++---------------------------------------- rpi/rpi.ld | 25 +++-- rpi/vectors.s | 113 ++++++++++++++++++++ 6 files changed, 324 insertions(+), 251 deletions(-) create mode 100644 rpi/nl-glue.c create mode 100644 rpi/vectors.s diff --git a/jazelle.c b/jazelle.c index 679fec0..b0b365c 100644 --- a/jazelle.c +++ b/jazelle.c @@ -39,6 +39,7 @@ // newlib assumed #include +#include #include #endif // platform @@ -50,7 +51,7 @@ // Cypress FX3 | ARM926EJ-S | 0x41069265 | 0x07926069 | 0x64100004 // TI Nspire | ARM926EJ-S?| 0x41069265?| ??? | 0x64100004? // TODO // Wii Starlet | ARM926EJ-S?| ??? | ??? | ??? // TODO -// RPi v1.2 B+ |ARM1176JZF-S| 0x410FB767 | 0x07B7617F | 0x74100064 +// RPi v1.2 B+ |ARM1176JZF-S| 0x410FB767 | 0x07B7617F | 0x74100064 // FIXME: insn enumeration broken due to caching or something // Ninty .3DS | ARM11MPCore| 0x410FB025?| ??? | 0x74100064? // TODO // ??? TODO | Cortex-A8 | ??? | ??? | ??? // Xilinx Zynq7| Cortex-A9MP| 0x413FC090 | 0x4BA00477 | 0xF4100168 @@ -203,14 +204,15 @@ static void DC_FlushAll(void) { "add r1, r1, #0x40000000\n" "cmp r1, #0\n" "bne outer_loop\n" -#elif __ARM_ARCH == 6 && defined(__ARM_ARCH_6KZ__) "mov r0, #0\n" - "mcr p15, 0, r0, c7, c10, 0\n" // clean & flush entire data cache +#elif __ARM_ARCH == 6 && defined(__ARM_ARCH_6KZ__) + // FIXME: ARM11 code no worky + "mov r0, #0\n" + "mcr p15, 0, r0, c7, c14, 0\n" // Clean and Invalidate Entire Data Cache #else #error "wut" #endif - "mov r0, #0\n" "mcr p15, 0, r0, c7, c10, 4 @ drain write buffer\n" // ARM9, ARM11 ok "bx lr\n" : @@ -221,9 +223,22 @@ static void DC_FlushAll(void) { __attribute__((__unused__)) static inline void DC_InvalidateAll(void) { asm volatile("mcr p15, 0, %0, c7, c6, 0" : : "r"(0)); // ARM9, ARM11 ok +#if __ARM_ARCH == 6 + // FIXME: ARM11 code no worky + asm volatile("mcr p15, 0, %0, c7, c7, 0" : : "r"(0)); // ARM9, ARM11 ok + asm volatile("mcr p15, 0, %0, c8, c7, 0" : : "r"(0)); // invalidate tlb + asm volatile("mcr p15, 0, %0, c7, c10, 4" : : "r"(0)); // dsb +#endif } static inline void IC_InvalidateAll(void) { asm volatile("mcr p15, 0, %0, c7, c5, 0" : : "r"(0)); // ARM9, ARM11 ok +#if __ARM_ARCH == 6 + // FIXME: ARM11 code no worky + asm volatile("mcr p15, 0, %0, c7, c7, 0" : : "r"(0)); // ARM9, ARM11 ok + asm volatile("mcr p15, 0, %0, c8, c7, 0" : : "r"(0)); // invalidate tlb + asm volatile("mcr p15, 0, %0, c7, c10, 4" : : "r"(0)); // dsb + asm volatile("mcr p15, 0, %0, c7, c5, 4" : : "r"(0)); // flush prefetch buffer +#endif } #elif __ARM_ARCH == 7 && defined(__ARM_ARCH_7A__) #include "cache_cortexa.c" /* go sue me */ @@ -340,13 +355,15 @@ static void handler_idiv(void) { // r0 = 3 // r1 = 4 // r2 = 2 - // editing the above has no effect + // editing the above has no effect (not on ARM9, nor on ARM11) // NOTE: these depend on the stack content, i.e. it's not a moving register // window. pushes happen in the following order: r0,r1,r2,r3 // TODO: when the 'register stack cache' is full, what happens? does // it loop or does it act in a FIFO way, moving r0<-r1<-r2<-r3? // how can the fillrate be known??? (libjz says r5 & 3 but i // dont see anything like that, maybe its an ARM11 thing?) + // TODO: Hackspire also says something about the low bits of r5, not + // seeing this on ARM9 nor ARM11... // "r4: Copy of local variable 0. Only valid when local variable 0 is a // single word (i.e. int, float, or Object; not long or double)" // -Hackspire @@ -526,8 +543,9 @@ static uint8_t bytecode_test1[] = { 0x06, // iconst_3 0x07, // iconst_4 0x05, // iconst_2 - 0xFE, // ??? (r5 readout) + // FIXME: if we put 0xFE here instead, the end result is 11 on RPi. why? 0x6C, // idiv + 0xFE, // ??? (r5 readout) 0x04, // iconst_1 0x60, // iadd 0x60, // iadd @@ -562,7 +580,7 @@ void jazelle_main(void) { uint32_t aid = arm_get_id(); uint32_t jid = jazelle_get_id(); iprintf("hello world! ARM coreID=0x%lx jazelle ID=0x%lx\r\n", aid, jid); - while (jid == 0) ; + if (jid == 0) return; int r = jazelle_exec(bytecode_test1); iprintf("retcode=%d; r5 was 0x%08lx\r\n", r, backup_r5); diff --git a/rpi/Makefile b/rpi/Makefile index f5796c3..a740ba0 100644 --- a/rpi/Makefile +++ b/rpi/Makefile @@ -5,8 +5,8 @@ OPENOCD_PORT_TELNET ?= 4444 PREFIX ?= arm-none-eabi- CC = $(PREFIX)gcc -CFLAGS = -mcpu=arm1176jzf-s -Wall -LDFLAGS = -T rpi.ld -nostartfiles -nostdlib +CFLAGS = -mcpu=arm1176jzf-s -Wall -O2 +LDFLAGS = -T rpi.ld -nostartfiles -Wl,-Map=rpi.map -Wl,--cref GDB ?= $(PREFIX)gdb PYTHON3 ?= python3 NC ?= nc @@ -16,13 +16,13 @@ LNXCC = $(LNXPREFIX)gcc default: all -all: rpi.elf +all: rpi.elf rpi.img rpi.o: rpi.c $(CC) $(CFLAGS) -c -o "$@" "$<" -rpi.elf: rpi.o - $(CC) $(CFLAGS) $(LDFLAGS) -o "$@" $^ +vectors.o: vectors.s + $(CC) -mcpu=arm1176jzf-s -c -o "$@" "$<" #jazelle.S: ../jazelle.c # $(CC) $(CFLAGS) -S -o "$@" "$<" @@ -30,6 +30,15 @@ rpi.elf: rpi.o jazelle.o: ../jazelle.c $(CC) $(CFLAGS) -c -o "$@" "$<" +nl-glue.o: nl-glue.c + $(CC) $(CFLAGS) -c -o "$@" "$<" + +rpi.elf: rpi.o vectors.o nl-glue.o jazelle.o + $(CC) $(CFLAGS) $(LDFLAGS) -o "$@" $^ + +rpi.img: rpi.elf + $(PREFIX)objcopy -O binary "$<" "$@" + jazlinux: linux.c ../jazelle.c $(LNXCC) $(CLFAGS) -o "$@" $^ diff --git a/rpi/nl-glue.c b/rpi/nl-glue.c new file mode 100644 index 0000000..dcb8cbe --- /dev/null +++ b/rpi/nl-glue.c @@ -0,0 +1,98 @@ + +/* glue code for Newlib */ + +#include +#include + +void uart_putc(char c); +void uart_puts(const char* s); +void uart_putdata(const uint8_t* p, size_t size); + +/* Newlib's assert() calls this function if the assertion fails */ +void __assert_func (const char *file, int line, const char *func, const char *failedexpr) +{ + if (file != NULL) { + char linestrbuf[16], *linestr = &linestrbuf[sizeof(linestrbuf)]; + uart_puts(file); + uart_putc(':'); + /* Avoid using newlib functions like itoa so as not to trigger + a recursive assert... */ + *--linestr = '\0'; + while (line >= 10 && linestr != &linestrbuf[1]) { + *--linestr = '0' + (line % 10); + line /= 10; + } + *--linestr = '0' + line; + uart_puts(linestr); + uart_puts(": "); + } + if (func != NULL) { + uart_puts(func); + uart_puts(": "); + } + uart_puts("Assertion "); + if (failedexpr != NULL) { + uart_putc('`'); + uart_puts(failedexpr); + uart_puts("' "); + } + uart_puts("failed.\n"); + //Fx3UartTxFlush(); + for(;;) ; +} + +int _write(int fd, char* data, int size) { + if (fd >= 0 && fd < 3) { + if (size > 0) + uart_putdata((const uint8_t*)data, (size_t)size); + //Fx3UartTxFlush(); + return size; + } + + return -1; +} + +int _close(int fd) { (void)fd; return 0; } + +int _stat(char *file, struct stat *st) { + (void)file; + st->st_mode = S_IFCHR; + return 0; +} + +int _read(int fd, char *ptr, int len) { (void)fd; (void)ptr; (void)len; return 0; } + +int _lseek(int fd, int ptr, int dir) { (void)fd; (void)ptr; (void)dir; return 0; } + +int _isatty(int fd) { (void)fd; return 1; } + +int _fstat(int fd, struct stat *st) { + (void)fd; + st->st_mode = S_IFCHR; + return 0; +} + +#define HEAPSIZE (256*1024*1024) +extern uint8_t _heap[]; + +caddr_t _sbrk_r(int incr) { + static uint8_t* heap_end = 0; + uint8_t* prev_heap_end; + + /* initialize */ + if (heap_end == 0) + heap_end = _heap; + + prev_heap_end = heap_end; + + if (heap_end + incr - _heap > HEAPSIZE) { + /* heap overflow - announce on stderr */ + _write (2, "Heap overflow!\r\n", 16); + for (;;) asm volatile("nop"); + } + + heap_end += incr; + + return (caddr_t)prev_heap_end; +} + diff --git a/rpi/rpi.c b/rpi/rpi.c index e70cd36..3123f1e 100644 --- a/rpi/rpi.c +++ b/rpi/rpi.c @@ -5,245 +5,71 @@ #include #include -// known ID table: -// Chip name | ARM core | ARM CPUID | JTAG IDCODE | Jazelle ID -// ------------+------------+------------+-------------+----------- Jazelle DBX: -// ??? | ARM7EJ-S | ??? | ??? | ??? -// Cypress FX3 | ARM926EJ-S | 0x41069265 | 0x07926069 | 0x64100004 -// TI Nspire | ARM926EJ-S?| 0x41069265?| ??? | 0x64100004? -// RPi v1.?? | ARM11??? | ??? | ??? | ??? -// Ninty ?3DS | ARM11MPCore| 0x410FB025?| ??? | 0x74100064? -// Xilinx Zynq7| Cortex-A9MP| 0x413FC090 | 0x4BA00477 | 0xF4100168 -// ------------+------------+------------+-------------+----------- Jazelle RCT: -// Xilinx Zynq7| Cortex-A9MP| 0x413FC090 | 0x4BA00477 | 0xF4100168 -// TODO: others (BeagleBoard Cortex-A8? Other A9s?) +//------------------------------------------------------------------------- +//------------------------------------------------------------------------- -// TODO: immediate next steps: -// * check if we can override jazelle insn execution with custom handlers -// * check what the control registers actually do -// * enumerate what all insns do +extern void jazelle_main(void); -__attribute__((__naked__)) -static uint32_t arm_get_id(void) { - asm volatile( - "mrc p15, 0, r0, c0, c0, 0\n" - "bkpt #4\n" - "bx lr\n" - ); +#define GPFSEL1 (*(volatile uint32_t*)0x20200004) +#define GPSET0 (*(volatile uint32_t*)0x2020001C) +#define GPCLR0 (*(volatile uint32_t*)0x20200028) +#define GPPUD (*(volatile uint32_t*)0x20200094) +#define GPPUDCLK0 (*(volatile uint32_t*)0x20200098) + +#define AUX_ENABLES (*(volatile uint32_t*)0x20215004) +#define AUX_MU_IO_REG (*(volatile uint32_t*)0x20215040) +#define AUX_MU_IER_REG (*(volatile uint32_t*)0x20215044) +#define AUX_MU_IIR_REG (*(volatile uint32_t*)0x20215048) +#define AUX_MU_LCR_REG (*(volatile uint32_t*)0x2021504C) +#define AUX_MU_MCR_REG (*(volatile uint32_t*)0x20215050) +#define AUX_MU_LSR_REG (*(volatile uint32_t*)0x20215054) +#define AUX_MU_MSR_REG (*(volatile uint32_t*)0x20215058) +#define AUX_MU_SCRATCH (*(volatile uint32_t*)0x2021505C) +#define AUX_MU_CNTL_REG (*(volatile uint32_t*)0x20215060) +#define AUX_MU_STAT_REG (*(volatile uint32_t*)0x20215064) +#define AUX_MU_BAUD_REG (*(volatile uint32_t*)0x20215068) + +void uart_putc(char c) { + while (!(AUX_MU_LSR_REG & 0x20)) asm volatile("nop"); + + AUX_MU_IO_REG = c; +} +void uart_puts(const char* s) { + for (; s && *s; ++s) { + uart_putc(*s); + } +} +void uart_putdata(const uint8_t* p, size_t size) { + for (size_t i = 0; i < size; ++i) { + uart_putc((char)p[i]); + } } -__attribute__((__naked__)) -static uint32_t jazelle_get_id(void) { - asm volatile( - "mrc p14, 7, r0, c0, c0, 0\n" - "bkpt #5\n" - "bx lr\n" - ); -} +int main() { + AUX_ENABLES=1; + AUX_MU_IER_REG=0; + AUX_MU_CNTL_REG=0; + AUX_MU_LCR_REG=3; + AUX_MU_MCR_REG=0; + AUX_MU_IER_REG=0; + AUX_MU_IIR_REG=0xC6; + AUX_MU_BAUD_REG=270; -__attribute__((__aligned__(1024))) -static struct { - void* handlers[512]; - uint8_t stack[256]; - uint8_t locals[256]; -} jazelle_block; + uint32_t ra = GPFSEL1; + ra&=~(7<<12); //gpio14 + ra|=2<<12; //alt5 + GPFSEL1=ra; -/* - * c0: Jazelle Identity register (read-only) - Bits 0-11: Subarchitecture-defined bits (reads as 4, meaning unknown) - Bits 12-19: Subarchitecture (reads as 0, Jazelle V1 according to documentation) - Bits 20-27: Implementor (reads as 0x41, ARM Limited according to documentation) - Bits 28-31: Architecture (reads as 6, ARMv5TEJ according to documentation) - c1: Operating System Control register - Bit 0: Configuration Disabled (CD) (documented) - Bit 1: Configuration Valid (CV) (documented) - c2: Main Configuration register - Bit 0: Jazelle Enable (JE) (documented) - Bits 26-28: Unknown - Bit 29: If set, array object contains its elements directly, otherwise it contains a pointer to its elements - Bit 31: Disable array instructions if set? - c3: Array object layout register - Bits 0-7: Unknown - Bits 8-11: Offset (in words) within array object of first element or of pointer to first element - Bits 12-15: Offset (in words) within array object of length - Bit 16: If set, offset to length is subtracted, otherwise added - Bits 17-19: Array length shift value (number of elements = stored length >> this) - Bits 20-21: Disable array instructions if set? - */ + GPPUD=0; + for (int ra=0;ra<150;ra++) asm volatile("nop"); + GPPUDCLK0=(1<<14); + for (int ra=0;ra<150;ra++) asm volatile("nop"); + GPPUDCLK0=0; -static uint32_t jazelle_exit_save; + AUX_MU_CNTL_REG=2; + //uart_putc('A'); -__attribute__((__naked__)) -static int jazelle_exec_native(const void* bytecode, const void* block) { - // inline asm parameters seems to be borking in GCC sooooo lets do it this way - (void)bytecode; (void)block; (void)&jazelle_exit_save; - asm volatile( - "push {r4-r12,lr}\n" - - "mov lr, r0\n" - - // init handler table pointer and stack pointer - "mov r5, r1\n" - "add r6, r5, #0x800\n" - "add r7, r5, #0x900\n" - // "r8: Pointer to constant pool? (haven't checked this yet)" -Hackspire - - // set configuration valid & jazelle enable bits - "mov r0, #2\n" - "mcr p14, 7, r0, c1, c0, 0\n" - "mov r0, #1\n" - "mcr p14, 7, r0, c2, c0, 0\n" - - // apparently there's no good way to find the exit point from jazelle, - // so we're going to hack that into the stuff now - "ldr r12, =jazelle_exit_save\n" - "adr r0, .Ljazend\n" - "str r0, [r12]\n" - - // switch to jazelle mode - "adr r12, .Lno_jazelle\n" - "bxj r12\n" - - ".Ljazend:\n" - "mov r0, #0\n" - "b .Lend\n" - - ".Lno_jazelle:\n" - "bkpt #1\n" - "mov r0, #1\n" - - ".Lend:\n" - "mov r5, #0\n" - "mcr p14, 7, %r5, c1, c0, 0\n" - "mcr p14, 7, %r5, c2, c0, 0\n" - - "pop {r4-r12,lr}\n" - "bx lr\n" - - ".pool\n" - ); -} - - - -__attribute__((__naked__)) -static void handler_idiv(void) { - // r0 = 3 - // r1 = 4 - // r2 = 2 - // editing the above has no effect - // NOTE: these depend on the stack content, i.e. it's not a moving register - // window. pushes happen in the following order: r0,r1,r2,r3 - // TODO: when the 'register stack cache' is full, what happens? does - // it loop or does it act in a FIFO way, moving r0<-r1<-r2<-r3? - // how can the fillrate be known??? (libjz says r5 & 3 but i - // dont see anything like that, maybe its an ARM11 thing?) - // "r4: Copy of local variable 0. Only valid when local variable 0 is a - // single word (i.e. int, float, or Object; not long or double)" - // -Hackspire - // - // [r6-4] is stack top (2) - // [r6-8] is 4 - // etc - // use the above to manipulate the stack, eg. "iadd" is implemented as: - // - add r1, r2 // or equivalently, read from stack i guess - // - str r1, [r6, #-8] // store to the place where it will be read - // - sub r6, #4 // pop off & discard stack top element - // NOTE: this input usage (with r1 and r2) is NOT robust at all, use memory - // reads instead! - - asm volatile( - "bkpt #3\n" - // FIXME: read out stack contents in a better way - "add r1, r2\n" - "str r1, [r6,#-8]\n" - "sub r6, #4\n" - - // return to jazelle (yes lr has to be incremented otherwise the - // current instruction keeps getting executed in a loop) - "add lr, #1\n" - "bxj r12\n" // FIXME: r12 can be modified by jazelle so it should be restored to something - ); -} - -__attribute__((__naked__)) -static void handler_ireturn(void) { - int result; - asm volatile( - "bkpt #2\n" - "ldr %[res], [r6, #-4]!\n" - :[res]"=r"(result) - ); - //iprintf("result=%d\r\n", result); // FIXME: save & restore r0-r3 if ret implemented properly - - // get back to original code - // TODO: later stage: get back to previous bytecode stuff - asm volatile( - "ldr r12, %[exsav]\n" - "bx r12\n" - : - :[exsav]"m"(jazelle_exit_save) - :"r12" - ); - __builtin_unreachable(); -} - -static int jazelle_exec(const uint8_t* bytecode) { - jazelle_block.handlers[0x6C] = handler_idiv; - jazelle_block.handlers[0xAC] = handler_ireturn; -/* - * +000-3FF: Unhandled bytecodes - The stack is flushed to memory before calling any of these handlers, so they may modify r0-r3 freely - +400: Null pointer exception - +404: Array index out of bounds exception - +40C: Jazelle mode entered with JE = 0 - +410: Configuration invalid (Jazelle mode entered with CV = 0) - CV is automatically set to 1 on entering this handler - +414: Prefetch abort occurred in middle of instruction - -Hackspire - */ - const void* block = &jazelle_block; - - return jazelle_exec_native(bytecode, block); -} - - -// https://github.com/SonoSooS/libjz/wiki/Java-instruction-set -static uint8_t bytecode_test1[] = { - 0x06, // iconst_3 - 0x07, // iconst_4 - 0x05, // iconst_2 - 0x6C, // idiv - 0x04, // iconst_1 - 0x60, // iadd - 0x60, // iadd - 0xAC, // ireturn -}; - -void jazelle_main(void) { - uint32_t aid = arm_get_id(); - uint32_t jid = jazelle_get_id(); - asm volatile("bkpt #0\n"); - //iprintf("hello world! ARM coreID=0x%lx jazelle ID=0x%lx\r\n", aid, jid); - while (jid == 0) ; - - int r = jazelle_exec(bytecode_test1); - //iprintf("retcode=%d\r\n", r); - - while (true) ; -} - -void main(void) { jazelle_main(); -} -__attribute__((__naked__, __section__(".entry"))) -void _start(void) { - asm volatile( - "ldr sp, =0x00010000\n" - "bl main\n" - "1: b 1b\n" - ".pool\n" - ); + return 0; } - diff --git a/rpi/rpi.ld b/rpi/rpi.ld index 986f714..e6f8903 100644 --- a/rpi/rpi.ld +++ b/rpi/rpi.ld @@ -1,35 +1,44 @@ ENTRY(_start) +MEMORY +{ + ram : ORIGIN = 0x8000, LENGTH = 0x80000 +} + SECTIONS { - . = 0x00001000; + /*. = 0x00001000;*/ .text : { *(.entry*) *(.text*) *(.rodata*) - } + } > ram .data : { *(.data*) - } + } > ram - .ARM.extab : + /*.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) - } + } > ram __exidx_start = .; .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) - } - __exidx_end = .; + } > ram + __exidx_end = .;*/ + __bss_start = .; .bss : { *(.bss*) - } + } > ram + __bss_end = .; + + _heap = .; } diff --git a/rpi/vectors.s b/rpi/vectors.s new file mode 100644 index 0000000..6687d37 --- /dev/null +++ b/rpi/vectors.s @@ -0,0 +1,113 @@ +@ vim: set ft=armv5: + +.section ".entry", "awx", %progbits +.global VECTORS +VECTORS: + ldr pc, reset_handler + ldr pc, undefined_handler + ldr pc, swi_handler + ldr pc, prefetch_handler + ldr pc, data_handler + ldr pc, unused_handler + ldr pc, irq_handler + ldr pc, fiq_handler + +reset_handler: + .4byte _start +undefined_handler: + .4byte hang +swi_handler: + .4byte hang +prefetch_handler: + .4byte hang +data_handler: + .4byte hang +unused_handler: + .4byte hang +irq_handler: + .4byte hang +fiq_handler: + .4byte hang + + +.global _start +_start: + @ copy over exception vectors + mov r0, #0x8000 + mov r1, #0 + ldmia r0!, {r2-r9} + stmia r1!, {r2-r9} + ldmia r0!, {r2-r9} + stmia r1!, {r2-r9} + + @ IRQ mode + mov r0, #0xd2 + msr cpsr_c, r0 + mov sp, #0x8000 + @ FIQ mode + mov r0, #0xd1 + msr cpsr_c, r0 + mov sp, #0x4000 + @ SVC mode + mov r0, #0xd3 + msr cpsr_c, r0 + mov sp, #0x08000000 + + mov r0, #0 + mcr p15, 0, r0, c3, c0, 0 @ disable write buffer + mcr p15, 0, r0, c2, c0, 0 @ disable icache & dcache + mcr p15, 0, r0, c2, c0, 1 + + @ disable stuff + mrc p15, 0, r0, c1, c0, 0 + ldr r1, =((1<<12)|(1<<2)|(1<<0)) @ icache/dcache/mpu enable bits + bic r0, r1 + mcr p15, 0, r0, c1, c0, 0 + + @ clear bss + ldr r0, =__bss_start + ldr r1, =__bss_end + mov r2, #0 + mov r3, #0 +zeroloop: + strd r2, r3, [r0], #8 + cmp r0, r1 + bne zeroloop + + bl main + + @ fallthru +hang: + b hang + +.pool + +/*.section ".text.utils", "ax", %progbits + +.global PUT32 +PUT32: + str r1,[r0] + bx lr + +.global GET32 +GET32: + ldr r0,[r0] +;@ bx lr + +.global dummy +dummy: + bx lr*/ + + + +;@------------------------------------------------------------------------- +;@ +;@ Copyright (c) 2012 David Welch dwelch@dwelch.com +;@ +;@ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +;@ +;@ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +;@ +;@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +;@ +;@-------------------------------------------------------------------------