stuff
This commit is contained in:
parent
4cd397b564
commit
1b68909633
|
@ -3,3 +3,4 @@
|
||||||
*.img
|
*.img
|
||||||
*.elf
|
*.elf
|
||||||
*.map
|
*.map
|
||||||
|
notes
|
||||||
|
|
22
Makefile
22
Makefile
|
@ -1,6 +1,11 @@
|
||||||
|
|
||||||
|
OPENOCD_HOST ?= localhost
|
||||||
|
OPENOCD_PORT_GDB ?= 3333
|
||||||
|
OPENOCD_PORT_TELNET ?= 4444
|
||||||
|
PREFIX ?= arm-none-eabi-
|
||||||
|
|
||||||
CC = arm-none-eabi-gcc
|
CC = $(PREFIX)gcc
|
||||||
|
GDB ?= $(PREFIX)gdb
|
||||||
|
|
||||||
CGENFLAGS = -mcpu=arm926ej-s -mthumb-interwork -fno-pie
|
CGENFLAGS = -mcpu=arm926ej-s -mthumb-interwork -fno-pie
|
||||||
WARN = -Wall -Wextra -Werror
|
WARN = -Wall -Wextra -Werror
|
||||||
|
@ -14,7 +19,7 @@ LDFLAGS = -static -nostartfiles -T bsp/fx3.ld -Wl,-z,max-page-size=4096,-Map,$(b
|
||||||
|
|
||||||
VPATH = bsp
|
VPATH = bsp
|
||||||
|
|
||||||
OBJS = main.o usb.o gpif.o gctl.o gpio.o uart.o util.o dma.o irq.o cache.o vectors.o
|
OBJS = main.o usb.o gpif.o gctl.o gpio.o uart.o util.o dma.o irq.o cache.o vectors.o jazelle.o nl-glue.o
|
||||||
|
|
||||||
all : jazelle.img
|
all : jazelle.img
|
||||||
|
|
||||||
|
@ -27,4 +32,17 @@ clean :
|
||||||
jazelle.elf : $(OBJS)
|
jazelle.elf : $(OBJS)
|
||||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
|
||||||
|
|
||||||
|
openocd-launch:
|
||||||
|
openocd -c "bindto $(OPENOCD_HOST)" -f ./arm926ejs_fx3.cfg -c init # TODO: ports
|
||||||
|
|
||||||
|
openocd-load: jazelle.elf
|
||||||
|
printf 'reset halt\nload_image jazelle.elf\nexit\n' \
|
||||||
|
| nc $(OPENOCD_HOST) $(OPENOCD_PORT_TELNET)
|
||||||
|
|
||||||
|
gdb:
|
||||||
|
$(GDB) -ex 'target extended-remote $(OPENOCD_HOST):$(OPENOCD_PORT_GDB)' \
|
||||||
|
-ex 'set $$pc=_start' -ex 'b jazelle_exec' -ex c jazelle.elf
|
||||||
|
|
||||||
-include $(OBJS:.o=.d)
|
-include $(OBJS:.o=.d)
|
||||||
|
|
||||||
|
.PHONY: all clean openocd-launch openocd-load gdb
|
||||||
|
|
30
README.md
30
README.md
|
@ -28,7 +28,7 @@ $ openocd -f ./arm926ejs_fx3.cfg -c "transport select jtag" -c "adapter speed 10
|
||||||
|
|
||||||
```
|
```
|
||||||
$ printf 'reset halt\nload_image jazelle.elf\nexit\n' | nc localhost 4444
|
$ printf 'reset halt\nload_image jazelle.elf\nexit\n' | nc localhost 4444
|
||||||
gdb -ex 'target extended-remote localhost:3333' -ex 'set $pc=_start' -ex 'b jazelle_exec' -ex c jazelle.elf
|
$ arm-none-eabi-gdb -ex 'target extended-remote localhost:3333' -ex 'set $pc=_start' -ex 'b jazelle_exec' -ex c jazelle.elf
|
||||||
```
|
```
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
@ -42,17 +42,17 @@ Jazelle info this project is based on:
|
||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
* Figure out Jazelle stuff:
|
* Figure out Jazelle stuff:
|
||||||
* Which bytecode instructions are supported on which Jazelle versions?
|
* [ ] Which bytecode instructions are supported on which Jazelle versions?
|
||||||
* How exactly does the stack work? (When a handler function is being called)
|
* [x] How exactly does the stack work? (When a handler function is being called)
|
||||||
* How exactly does the Jazelle status register work?
|
* [ ] How exactly does the Jazelle status register work?
|
||||||
* What control registers are there that influence the execution?
|
* [ ] What control registers are there that influence the execution?
|
||||||
* Is it possible to force execute a certain instruction using the handler
|
* [ ] Is it possible to force execute a certain instruction using the handler
|
||||||
instead of the default in-hardware execution?
|
instead of the default in-hardware execution?
|
||||||
* ...
|
* [ ] ...
|
||||||
* How does one call regular ARM/Thumb code from inside Jazelle?
|
* [ ] How does one call regular ARM/Thumb code from inside Jazelle?
|
||||||
* ...
|
* [ ] ...
|
||||||
* Verify what Hackspire and libjz have, to check if it is correct
|
* [ ] Verify what Hackspire and libjz have, to check if it is correct
|
||||||
* Look at what Hackspire and libjz don't have and try to complete it
|
* [ ] Look at what Hackspire and libjz don't have and try to complete it
|
||||||
* Port this code to the ARM11 using either Raspberry Pi v1 baremetal, or 3DS
|
* [ ] Port this code to the ARM11 using either Raspberry Pi v1 baremetal, or
|
||||||
homebrew with kernel privileges (and do tests on these to check for different
|
3DS homebrew with kernel privileges (and do tests on these to check for
|
||||||
Jazelle versions)
|
different Jazelle versions)
|
||||||
|
|
|
@ -38,7 +38,7 @@ void Fx3UartInit(uint32_t baud_rate, Fx3UartParity_t parity, Fx3UartStopBits_t s
|
||||||
Fx3WriteReg32(FX3_UART_POWER, 0);
|
Fx3WriteReg32(FX3_UART_POWER, 0);
|
||||||
Fx3UtilDelayUs(10);
|
Fx3UtilDelayUs(10);
|
||||||
Fx3WriteReg32(FX3_UART_POWER, FX3_UART_POWER_RESETN);
|
Fx3WriteReg32(FX3_UART_POWER, FX3_UART_POWER_RESETN);
|
||||||
while(!(Fx3ReadReg32(FX3_UART_POWER) & FX3_UART_POWER_ACTIVE))
|
for (int i = 0; !(Fx3ReadReg32(FX3_UART_POWER) & FX3_UART_POWER_ACTIVE) && i < 1000*1000; ++i)
|
||||||
;
|
;
|
||||||
|
|
||||||
/* Configure and enable UART */
|
/* Configure and enable UART */
|
||||||
|
@ -77,6 +77,6 @@ extern void Fx3UartTxString(const char *str)
|
||||||
|
|
||||||
void Fx3UartTxFlush(void)
|
void Fx3UartTxFlush(void)
|
||||||
{
|
{
|
||||||
while(!(Fx3ReadReg32(FX3_UART_STATUS) & FX3_UART_STATUS_TX_DONE))
|
for (int i = 0; !(Fx3ReadReg32(FX3_UART_STATUS) & FX3_UART_STATUS_TX_DONE) && i < 1000*1000; ++i)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,210 @@
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
// known ID table:
|
||||||
|
// Chip name | ARM core | Jazelle ID
|
||||||
|
// ------------+------------+-----------
|
||||||
|
// ??? | ARM7EJ-S | ???
|
||||||
|
// Cypress FX3 | ARM926EJ-S | 0x64100004
|
||||||
|
// TI Nspire | ARM926EJ-S?| 0x64100004?
|
||||||
|
// RPi v1.?? | ARM11??? | ???
|
||||||
|
// Ninty ?3DS | ARM11MPCore| 0x74100064?
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
__attribute__((__naked__))
|
||||||
|
static uint32_t jazelle_get_id(void) {
|
||||||
|
asm volatile(
|
||||||
|
"mrc p14, 7, r0, c0, c0, 0\n"
|
||||||
|
"bx lr\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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?
|
||||||
|
*/
|
||||||
|
|
||||||
|
// https://github.com/SonoSooS/libjz/wiki/Java-instruction-set
|
||||||
|
static uint8_t bytecode[] = {
|
||||||
|
0x06, // iconst_3
|
||||||
|
0x07, // iconst_4
|
||||||
|
0x05, // iconst_2
|
||||||
|
0x6C, // idiv
|
||||||
|
0x04, // iconst_1
|
||||||
|
0x60, // iadd
|
||||||
|
0x60, // iadd
|
||||||
|
0xAC, // ireturn
|
||||||
|
};
|
||||||
|
|
||||||
|
__attribute__((__aligned__(1024)))
|
||||||
|
static struct {
|
||||||
|
void* handlers[512];
|
||||||
|
uint8_t stack[256];
|
||||||
|
uint8_t locals[256];
|
||||||
|
} jazelle_block;
|
||||||
|
|
||||||
|
__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(
|
||||||
|
// 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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t jazelle_exit_save;
|
||||||
|
|
||||||
|
__attribute__((__naked__))
|
||||||
|
static void handler_ireturn(void) {
|
||||||
|
int result;
|
||||||
|
asm volatile(
|
||||||
|
"ldr %[res], [r6, #-4]!\n"
|
||||||
|
:[res]"=r"(result)
|
||||||
|
);
|
||||||
|
printf("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();
|
||||||
|
}
|
||||||
|
|
||||||
|
__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 {r5-r7,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"
|
||||||
|
"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 {r5-r7,lr}\n"
|
||||||
|
"bx lr\n"
|
||||||
|
|
||||||
|
".pool\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void jazelle_main(void) {
|
||||||
|
uint32_t id = jazelle_get_id();
|
||||||
|
printf("hello world! jazelle ID=0x%lx\r\n", id);
|
||||||
|
|
||||||
|
int r = jazelle_exec(bytecode);
|
||||||
|
|
||||||
|
printf("retcode=%d\r\n", r);
|
||||||
|
}
|
||||||
|
|
108
main.c
108
main.c
|
@ -13,65 +13,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
static uint8_t bytecode[] = {
|
extern void jazelle_main(void);
|
||||||
0x05, // iconst_2
|
|
||||||
0x05, // iconst_2
|
|
||||||
0x60, // iadd
|
|
||||||
0xAC, // ireturn
|
|
||||||
};
|
|
||||||
|
|
||||||
__attribute__((__aligned__(1024)))
|
|
||||||
static struct {
|
|
||||||
void* handlers[512];
|
|
||||||
uint8_t stack[256];
|
|
||||||
uint8_t locals[256];
|
|
||||||
} jazelle_block;
|
|
||||||
|
|
||||||
static void handler_ireturn(void) {
|
|
||||||
int32_t result;
|
|
||||||
asm volatile(
|
|
||||||
"ldr %[res], [r6, #-4]!\n"
|
|
||||||
"bkpt #1\n"
|
|
||||||
:[res]"=r"(result)
|
|
||||||
);
|
|
||||||
while (true); // a
|
|
||||||
}
|
|
||||||
|
|
||||||
static void jazelle_exec(const uint8_t* bytecode) {
|
|
||||||
jazelle_block.handlers[0xAC] = handler_ireturn;
|
|
||||||
const void* block = &jazelle_block;
|
|
||||||
|
|
||||||
asm volatile(
|
|
||||||
"push {lr}\n"
|
|
||||||
// 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"
|
|
||||||
|
|
||||||
"mov lr, %[bc]\n"
|
|
||||||
|
|
||||||
// init handler table pointer and stack pointer
|
|
||||||
"mov r5, %[blk]\n"
|
|
||||||
"add r6, r5, #0x800\n"
|
|
||||||
"add r7, r5, #0x900\n"
|
|
||||||
|
|
||||||
// switch to jazelle mode
|
|
||||||
"adr r12, .Lno_jazelle\n"
|
|
||||||
"bxj r12\n"
|
|
||||||
"bkpt #0\n"
|
|
||||||
"b .Lend\n"
|
|
||||||
".Lno_jazelle:\n"
|
|
||||||
"mov r0, #0\n"
|
|
||||||
"mcr p14, 7, r0, c1, c0, 0\n"
|
|
||||||
"mcr p14, 7, r0, c2, c0, 0\n"
|
|
||||||
"bkpt #2\n"
|
|
||||||
".Lend:\n"
|
|
||||||
"pop {lr}\n"
|
|
||||||
:
|
|
||||||
:[bc]"r"(bytecode),[blk]"r"(block)
|
|
||||||
:"r0","r12","r5","r6","r7","memory");
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
|
@ -81,12 +23,14 @@ int main(void)
|
||||||
Fx3GctlInitClock();
|
Fx3GctlInitClock();
|
||||||
*(volatile uint32_t *)(void *)0x400020e8 = 0;
|
*(volatile uint32_t *)(void *)0x400020e8 = 0;
|
||||||
Fx3GctlInitIoMatrix(FX3_GCTL_ALTFUNC_GPIF32BIT_UART_I2S);
|
Fx3GctlInitIoMatrix(FX3_GCTL_ALTFUNC_GPIF32BIT_UART_I2S);
|
||||||
/*Fx3UartInit(115200, FX3_UART_NO_PARITY, FX3_UART_1_STOP_BIT);
|
Fx3UartInit(115200, FX3_UART_NO_PARITY, FX3_UART_1_STOP_BIT);
|
||||||
Fx3UartTxString("\nhello world\n");
|
/*while (true) {
|
||||||
Fx3UartTxFlush();
|
Fx3UartTxString("\nhello world\n");
|
||||||
|
Fx3UartTxFlush();
|
||||||
|
}*/
|
||||||
|
|
||||||
Fx3GpioInitClock();
|
Fx3GpioInitClock();
|
||||||
Fx3GpioSetupSimple(45,
|
/*Fx3GpioSetupSimple(45,
|
||||||
FX3_GPIO_SIMPLE_ENABLE |
|
FX3_GPIO_SIMPLE_ENABLE |
|
||||||
FX3_GPIO_SIMPLE_INPUT_EN);
|
FX3_GPIO_SIMPLE_INPUT_EN);
|
||||||
Fx3GpioSetupSimple(54,
|
Fx3GpioSetupSimple(54,
|
||||||
|
@ -103,44 +47,8 @@ int main(void)
|
||||||
|
|
||||||
Fx3IrqEnableInterrupts();*/
|
Fx3IrqEnableInterrupts();*/
|
||||||
|
|
||||||
jazelle_exec(bytecode);
|
jazelle_main();
|
||||||
|
|
||||||
while (true) ; // a
|
while (true) ; // a
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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)];
|
|
||||||
Fx3UartTxString(file);
|
|
||||||
Fx3UartTxChar(':');
|
|
||||||
/* 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;
|
|
||||||
Fx3UartTxString(linestr);
|
|
||||||
Fx3UartTxString(": ");
|
|
||||||
}
|
|
||||||
if (func != NULL) {
|
|
||||||
Fx3UartTxString(func);
|
|
||||||
Fx3UartTxString(": ");
|
|
||||||
}
|
|
||||||
Fx3UartTxString("Assertion ");
|
|
||||||
if (failedexpr != NULL) {
|
|
||||||
Fx3UartTxChar('`');
|
|
||||||
Fx3UartTxString(failedexpr);
|
|
||||||
Fx3UartTxString("' ");
|
|
||||||
}
|
|
||||||
Fx3UartTxString("failed.\n");
|
|
||||||
for(;;)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
|
||||||
|
/* glue code for Newlib */
|
||||||
|
|
||||||
|
#include <bsp/uart.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
/* 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)];
|
||||||
|
Fx3UartTxString(file);
|
||||||
|
Fx3UartTxChar(':');
|
||||||
|
/* 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;
|
||||||
|
Fx3UartTxString(linestr);
|
||||||
|
Fx3UartTxString(": ");
|
||||||
|
}
|
||||||
|
if (func != NULL) {
|
||||||
|
Fx3UartTxString(func);
|
||||||
|
Fx3UartTxString(": ");
|
||||||
|
}
|
||||||
|
Fx3UartTxString("Assertion ");
|
||||||
|
if (failedexpr != NULL) {
|
||||||
|
Fx3UartTxChar('`');
|
||||||
|
Fx3UartTxString(failedexpr);
|
||||||
|
Fx3UartTxString("' ");
|
||||||
|
}
|
||||||
|
Fx3UartTxString("failed.\n");
|
||||||
|
Fx3UartTxFlush();
|
||||||
|
for(;;) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _write(int fd, char* data, int size) {
|
||||||
|
if (fd >= 0 && fd < 3) {
|
||||||
|
if (size > 0)
|
||||||
|
Fx3UartTxBytes((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;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue