instruction enumeration, simple rpi test stuff
This commit is contained in:
parent
852c438b10
commit
809ad7cf87
2
Makefile
2
Makefile
|
@ -7,7 +7,7 @@ PREFIX ?= arm-none-eabi-
|
|||
CC = $(PREFIX)gcc
|
||||
GDB ?= $(PREFIX)gdb
|
||||
|
||||
CGENFLAGS = -mcpu=arm926ej-s -mthumb-interwork -fno-pie
|
||||
CGENFLAGS = -mcpu=arm926ej-s -mthumb-interwork -fno-pie -DARM9
|
||||
WARN = -Wall -Wextra -Werror=return-type -Werror=implicit-function-declaration
|
||||
OPTIMIZE = -g -Og
|
||||
INCLUDE = -I.
|
||||
|
|
329
jazelle.c
329
jazelle.c
|
@ -8,38 +8,100 @@
|
|||
// known ID table:
|
||||
// Chip name | ARM core | ARM CPUID | JTAG IDCODE | Jazelle ID
|
||||
// ------------+------------+------------+-------------+----------- Jazelle DBX:
|
||||
// ??? | ARM7EJ-S | ??? | ??? | ???
|
||||
// ??? TODO | ARM7EJ-S | ??? | ??? | ???
|
||||
// Cypress FX3 | ARM926EJ-S | 0x41069265 | 0x07926069 | 0x64100004
|
||||
// TI Nspire | ARM926EJ-S?| 0x41069265?| ??? | 0x64100004?
|
||||
// RPi v1.?? | ARM11??? | ??? | ??? | ???
|
||||
// Ninty ?3DS | ARM11MPCore| 0x410FB025?| ??? | 0x74100064?
|
||||
// TI Nspire | ARM926EJ-S?| 0x41069265?| ??? | 0x64100004? // TODO
|
||||
// Wii Starlet | ARM926EJ-S?| ??? | ??? | ??? // TODO
|
||||
// RPi v1.2 B+ |ARM1176JZF-S| 0x410FB767 | 0x07B7617F | 0x74100064
|
||||
// Ninty .3DS | ARM11MPCore| 0x410FB025?| ??? | 0x74100064? // TODO
|
||||
// ??? TODO | Cortex-A8 | ??? | ??? | ???
|
||||
// Xilinx Zynq7| Cortex-A9MP| 0x413FC090 | 0x4BA00477 | 0xF4100168
|
||||
// ------------+------------+------------+-------------+----------- Jazelle RCT:
|
||||
// Xilinx Zynq7| Cortex-A9MP| 0x413FC090 | 0x4BA00477 | 0xF4100168
|
||||
//
|
||||
// TODO: others (BeagleBoard Cortex-A8? Other A9s?)
|
||||
// ------------+------------+------------+-------------+----------- Nothing:
|
||||
// Qcom MSM8255| S2 Scorpion| 0x517100F2 | ??? | 0x00000000
|
||||
|
||||
// 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__))
|
||||
/*
|
||||
|
||||
Cypress FX3:
|
||||
|
||||
bytecode IDs that use a handler:
|
||||
0x0f, 0x12, 0x13, 0x14, 0x53, 0x62, 0x63, 0x66, 0x67, 0x6a, 0x6b, 0x6c,
|
||||
0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x77, 0x79, 0x7b, 0x7d, 0x86,
|
||||
0x87, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x95, 0x96, 0x97,
|
||||
0x98, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4,
|
||||
0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbf, 0xc0, 0xc1,
|
||||
0xc2, 0xc3, 0xc4, 0xc5, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
|
||||
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb,
|
||||
0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
|
||||
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3,
|
||||
0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe
|
||||
0xff is hardwired to bkpt #0
|
||||
|
||||
*/
|
||||
|
||||
#if !defined(__linux__) || defined(_LINUX_KERNEL_H)
|
||||
inline
|
||||
#endif
|
||||
static uint32_t arm_get_id(void) {
|
||||
asm volatile(
|
||||
"mrc p15, 0, r0, c0, c0, 0\n"
|
||||
"bx lr\n"
|
||||
);
|
||||
#if defined(__linux__) && !defined(_LINUX_KERNEL_H)
|
||||
// TODO: read out /sys/devices/system/cpu/cpu*/regs/identification/midr_el1 or /proc/cpuinfo
|
||||
#else
|
||||
// NOTE: requires kernel mode execution level to read
|
||||
uint32_t res;
|
||||
asm volatile("mrc p15, 0, %0, c0, c0, 0\n":"=r"(res));
|
||||
return res;
|
||||
#endif
|
||||
}
|
||||
|
||||
__attribute__((__naked__))
|
||||
static uint32_t jazelle_get_id(void) {
|
||||
asm volatile(
|
||||
"mrc p14, 7, r0, c0, c0, 0\n"
|
||||
"bx lr\n"
|
||||
);
|
||||
inline static uint32_t jazelle_get_id(void) {
|
||||
uint32_t res;
|
||||
asm volatile("mrc p14, 7, %0, c0, c0, 0\n":"=r"(res));
|
||||
return res;
|
||||
}
|
||||
|
||||
// TODO: use different implementations when porting to other stuff
|
||||
#if defined(__linux__) && !defined(_LINUX_KERNEL_H)
|
||||
#error "TODO: implement cache flushes for Linux userspace"
|
||||
#elif defined(ARM9)
|
||||
__attribute__((__naked__))
|
||||
static void DC_FlushAll() {
|
||||
asm volatile(
|
||||
" mov r1, #0\n"
|
||||
"outer_loop:\n"
|
||||
" mov r0, #0\n"
|
||||
"inner_loop:\n"
|
||||
" orr r2, r1, r0 @ generate segment and line address\n"
|
||||
" mcr p15, 0, r2, c7, c14, 2 @ clean and flush the line\n"
|
||||
" add r0, r0, #32\n"
|
||||
" cmp r0, #0x1000/4\n"
|
||||
" bne inner_loop\n"
|
||||
" add r1, r1, #0x40000000\n"
|
||||
" cmp r1, #0\n"
|
||||
" bne outer_loop\n"
|
||||
|
||||
" mov r0, #0\n"
|
||||
" mcr p15, 0, r0, c7, c10, 4 @ drain write buffer\n"
|
||||
" bx lr\n"
|
||||
:::"memory");
|
||||
}
|
||||
static inline void DC_InvalidateAll() {
|
||||
asm volatile("mcr p15, 0, %0, c7, c6, 0" : : "r"(0));
|
||||
}
|
||||
static inline void IC_InvalidateAll() {
|
||||
asm volatile("mcr p15, 0, %0, c7, c5, 0" : : "r"(0));
|
||||
}
|
||||
#else
|
||||
// TODO: ARM11
|
||||
// TODO: Cortex-A[89]
|
||||
#error "TODO: define data and instruction cache functions for your target!"
|
||||
#endif
|
||||
|
||||
__attribute__((__aligned__(1024)))
|
||||
static struct {
|
||||
void* handlers[512];
|
||||
|
@ -98,7 +160,6 @@ static int jazelle_exec_native(const void* bytecode, const void* block) {
|
|||
"ldr r12, =jazelle_exit_save\n"
|
||||
"adr r0, .Ljazend\n"
|
||||
"str r0, [r12]\n"
|
||||
//"bkpt #0\n"
|
||||
|
||||
// switch to jazelle mode
|
||||
"adr r12, .Lno_jazelle\n"
|
||||
|
@ -152,7 +213,6 @@ static void handler_idiv(void) {
|
|||
// 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"
|
||||
|
@ -169,7 +229,6 @@ __attribute__((__naked__))
|
|||
static void handler_ireturn(void) {
|
||||
int result;
|
||||
asm volatile(
|
||||
//"bkpt #4\n"
|
||||
"ldr %[res], [r6, #-4]!\n"
|
||||
:[res]"=r"(result)
|
||||
);
|
||||
|
@ -187,6 +246,121 @@ static void handler_ireturn(void) {
|
|||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static int was_exec = -1;
|
||||
|
||||
__attribute__((__naked__))
|
||||
static void handler_wasexec() {
|
||||
asm volatile(
|
||||
// set was_exec flag
|
||||
"mov r0, #1\n"
|
||||
"str r0, %[we]\n"
|
||||
// get back to original stuff
|
||||
"ldr r12, %[exsav]\n"
|
||||
"bx r12"
|
||||
:
|
||||
:[exsav]"m"(jazelle_exit_save)
|
||||
,[we]"m"(was_exec)
|
||||
:"r0","r12"
|
||||
);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
__attribute__((__naked__))
|
||||
static void handler_noexec() {
|
||||
asm volatile(
|
||||
// get back to original stuff
|
||||
"ldr r12, %[exsav]\n"
|
||||
"bx r12"
|
||||
:
|
||||
:[exsav]"m"(jazelle_exit_save)
|
||||
:"r0","r12"
|
||||
);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
static uint8_t bytecode_testh[] = {
|
||||
0x06, 0x06,
|
||||
0x07, 0x07,
|
||||
0x05, 0x05,
|
||||
0x04, 0x04,
|
||||
0x6C, // +8
|
||||
0x00, 0x00, 0x00, 0x00, // up to 4 nops of argument bytes eg for invokeXYZ
|
||||
0x00, 0x00, 0x00, 0x00, // except 2nd byte is 3 for goto offset (BE) (3 aka iconst_0)
|
||||
0xBA, // +17 // invokedynamic, complex enough to never be implemented in hw
|
||||
0x00, 0x00, 0x00, 0x00, // up to 4 nops of argument bytes eg for invokeXYZ
|
||||
};
|
||||
|
||||
static void jazelle_test_handlers(uint8_t hflags[256/8]) {
|
||||
memset(hflags, 0, 256/8);
|
||||
for (int i = 0x00; i < 0xff /* bytecode 0xff is hardwired to bkpt #0 */; ++i) {
|
||||
if (i == 0xba) {
|
||||
hflags[i>>3]|=(1<<(i&7));
|
||||
continue; // yeah
|
||||
}
|
||||
|
||||
bytecode_testh[8] = i;
|
||||
memset(&bytecode_testh[9], 0, 8);
|
||||
switch (i) { // need offset fixups for some instructions
|
||||
case 0xa7: // goto
|
||||
case 0xa8: // jsr
|
||||
bytecode_testh[10] = 3;
|
||||
break;
|
||||
case 0xa9: // ret
|
||||
bytecode_testh[9] = 1;
|
||||
break;
|
||||
case 0xc8: // goto_w
|
||||
case 0xc9: // jsr_w
|
||||
bytecode_testh[12] = 3;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
memset(&jazelle_block, 0, sizeof jazelle_block);
|
||||
// initialize local 1 for a return address for the 'ret' opcode
|
||||
uint32_t retval = &bytecode_testh[17];
|
||||
jazelle_block.locals[4] = retval >> 0;
|
||||
jazelle_block.locals[5] = retval >> 8;
|
||||
jazelle_block.locals[6] = retval >>16;
|
||||
jazelle_block.locals[7] = retval >>24;
|
||||
|
||||
DC_FlushAll();
|
||||
DC_InvalidateAll();
|
||||
IC_InvalidateAll();
|
||||
|
||||
jazelle_block.handlers[i] = handler_wasexec;
|
||||
jazelle_block.handlers[0xba] = handler_noexec;
|
||||
|
||||
was_exec = 0;
|
||||
jazelle_exec_native(bytecode_testh, &jazelle_block);
|
||||
|
||||
if (was_exec == 1) {
|
||||
hflags[i>>3]|=(1<<(i&7));
|
||||
//iprintf("bytecode 0x%02x: uses handler\r\n", i);
|
||||
} else {
|
||||
//iprintf("bytecode 0x%02x: hw\r\n", i);
|
||||
}
|
||||
|
||||
jazelle_block.handlers[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
};
|
||||
|
||||
// returns 6 if idiv implemented natively, else 10
|
||||
static int jazelle_exec(const uint8_t* bytecode) {
|
||||
jazelle_block.handlers[0x6C] = handler_idiv;
|
||||
jazelle_block.handlers[0xAC] = handler_ireturn;
|
||||
|
@ -206,108 +380,6 @@ static int jazelle_exec(const uint8_t* bytecode) {
|
|||
return jazelle_exec_native(bytecode, block);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static int was_exec = -1;
|
||||
|
||||
__attribute__((__naked__))
|
||||
static void handler_wasexec() {
|
||||
asm volatile(
|
||||
//"bkpt #1\n"
|
||||
// set was_exec flag
|
||||
"mov r0, #1\n"
|
||||
"str r0, %[we]\n"
|
||||
// get back to original stuff
|
||||
"ldr r12, %[exsav]\n"
|
||||
"bx r12"
|
||||
:
|
||||
:[exsav]"m"(jazelle_exit_save)
|
||||
,[we]"m"(was_exec)
|
||||
:"r0","r12"
|
||||
);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
__attribute__((__naked__))
|
||||
static void handler_noexec() {
|
||||
asm volatile(
|
||||
//"bkpt #2\n"
|
||||
// clear was_exec flag
|
||||
//"mov r0, #0\n"
|
||||
//"str r0, %[we]\n"
|
||||
// get back to original stuff
|
||||
"ldr r12, %[exsav]\n"
|
||||
"bx r12"
|
||||
:
|
||||
:[exsav]"m"(jazelle_exit_save)
|
||||
//,[we]"m"(was_exec)
|
||||
:"r0","r12"
|
||||
);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
static uint8_t bytecode_testh[] = {
|
||||
0x06,
|
||||
0x07,
|
||||
0x05,
|
||||
0x6C,
|
||||
0x00, 0x00, 0x00, 0x00, // up to 4 nops of argument bytes eg for invokeXYZ
|
||||
0xBA,
|
||||
0x00, 0x00, 0x00, 0x00, // up to 4 nops of argument bytes eg for invokeXYZ
|
||||
|
||||
/*0x06, 0x06, 0x06, 0x06, // pre-fill the stack a bit
|
||||
0x00, // target instruction to test
|
||||
0x00, 0x00, 0x00, 0x00, // up to 4 nops of argument bytes eg for invokeXYZ
|
||||
0xba, // invokedynamic, this one is complex enough that it'll reliably
|
||||
// never be implemented in hardware*/
|
||||
};
|
||||
|
||||
static void jazelle_test_handlers(uint8_t hflags[256/8]) {
|
||||
memset(hflags, 0, 256/8);
|
||||
for (int i = 0x6C; i < 0x100; ++i) {
|
||||
if (i == 0xba) {
|
||||
hflags[i>>3]|=(1<<(i&7));
|
||||
continue; // yeah
|
||||
}
|
||||
|
||||
//iprintf("bc 0x%02x\r\n", i);
|
||||
bytecode_testh[3] = i;
|
||||
//memset(&jazelle_block, 0, sizeof jazelle_block);
|
||||
jazelle_block.handlers[i] = handler_wasexec;
|
||||
jazelle_block.handlers[0xba] = handler_noexec;
|
||||
|
||||
was_exec = 0;
|
||||
jazelle_exec_native(bytecode_testh, &jazelle_block);
|
||||
|
||||
if (was_exec == 1) {
|
||||
hflags[i>>3]|=(1<<(i&7));
|
||||
iprintf("bytecode 0x%02x: uses handler\r\n", i);
|
||||
} else if (was_exec != 0) { // unchanged
|
||||
iprintf("bytecode 0x%02x: wut?\r\n", i);
|
||||
} else {
|
||||
//iprintf("bytecode 0x%02x: hw\r\n", i);
|
||||
}
|
||||
|
||||
jazelle_block.handlers[i] = NULL;
|
||||
//asm volatile("bkpt #7\n");
|
||||
}
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
@ -318,17 +390,18 @@ void jazelle_main(void) {
|
|||
iprintf("retcode=%d\r\n", r);
|
||||
|
||||
if (r == 0) {
|
||||
//r = jazelle_exec(bytecode_test1);
|
||||
//iprintf("retcode=%d\r\n", r);
|
||||
|
||||
uint8_t hflags[256/8];
|
||||
static uint8_t hflags[256/8];
|
||||
jazelle_test_handlers(hflags);
|
||||
|
||||
for (int i = 0; i < 0x100; ++i) {
|
||||
iprintf("bytecode IDs that use a handler:\r\n\t");
|
||||
for (int i = 0, has = 0; i < 0x100; ++i) {
|
||||
if (hflags[i>>3]&(1<<(i&7))) {
|
||||
iprintf("bytecode 0x%02x: uses handler\r\n", i);
|
||||
iprintf("%s0x%02x", ((has&15) ? ", " : ""), i);
|
||||
++has;
|
||||
if ((has & 15) == 0) iprintf("\r\n\t");
|
||||
}
|
||||
}
|
||||
printf("\r\n");
|
||||
}
|
||||
|
||||
while (true) ;
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
|
||||
OPENOCD_HOST ?= localhost
|
||||
OPENOCD_PORT_GDB ?= 3333
|
||||
OPENOCD_PORT_TELNET ?= 4444
|
||||
PREFIX ?= arm-none-eabi-
|
||||
|
||||
CC = $(PREFIX)gcc
|
||||
CFLAGS = -mcpu=arm1176jzf-s
|
||||
LDFLAGS = -T rpi.ld -nostartfiles -nostdlib
|
||||
GDB ?= $(PREFIX)gdb
|
||||
PYTHON3 ?= python3
|
||||
NC ?= nc
|
||||
|
||||
default: all
|
||||
|
||||
all: rpi.elf
|
||||
|
||||
rpi.o: rpi.c
|
||||
$(CC) $(CFLAGS) -c -o "$@" "$<"
|
||||
|
||||
rpi.elf: rpi.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o "$@" $^
|
||||
|
||||
openocd-launch:
|
||||
openocd -f interface/cmsis-dap.cfg -c "transport select jtag" \
|
||||
-c "adapter speed 50" -f target/bcm2835.cfg \
|
||||
-c init -c scan_chain
|
||||
|
||||
openocd-load: rpi.elf
|
||||
printf 'halt\nload_image rpi.elf\nexit\n' \
|
||||
| nc $(OPENOCD_HOST) $(OPENOCD_PORT_TELNET)
|
||||
|
||||
gdb:
|
||||
$(GDB) -ex 'target extended-remote $(OPENOCD_HOST):$(OPENOCD_PORT_GDB)' \
|
||||
-ex 'set $$pc=_start' \
|
||||
$(GDB_EXTRA_CMDS) \
|
||||
rpi.elf
|
||||
|
||||
clean:
|
||||
@$(RM) -v rpi.o rpi.elf
|
||||
|
||||
.PHONY: all clean openocd-launch openocd-load gdb
|
|
@ -0,0 +1,249 @@
|
|||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// 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
|
||||
|
||||
__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"
|
||||
);
|
||||
}
|
||||
|
||||
__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"
|
||||
);
|
||||
}
|
||||
|
||||
__attribute__((__aligned__(1024)))
|
||||
static struct {
|
||||
void* handlers[512];
|
||||
uint8_t stack[256];
|
||||
uint8_t locals[256];
|
||||
} jazelle_block;
|
||||
|
||||
/*
|
||||
* 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?
|
||||
*/
|
||||
|
||||
static uint32_t jazelle_exit_save;
|
||||
|
||||
__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"
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x00001000;
|
||||
|
||||
.text :
|
||||
{
|
||||
*(.entry*)
|
||||
*(.text*)
|
||||
*(.rodata*)
|
||||
}
|
||||
.data :
|
||||
{
|
||||
*(.data*)
|
||||
}
|
||||
|
||||
.ARM.extab :
|
||||
{
|
||||
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||
}
|
||||
__exidx_start = .;
|
||||
.ARM.exidx :
|
||||
{
|
||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||
}
|
||||
__exidx_end = .;
|
||||
|
||||
.bss :
|
||||
{
|
||||
*(.bss*)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue