unfinished stuff, also zynq
This commit is contained in:
parent
1b68909633
commit
852c438b10
|
@ -4,3 +4,4 @@
|
|||
*.elf
|
||||
*.map
|
||||
notes
|
||||
*.html
|
||||
|
|
8
Makefile
8
Makefile
|
@ -8,7 +8,7 @@ CC = $(PREFIX)gcc
|
|||
GDB ?= $(PREFIX)gdb
|
||||
|
||||
CGENFLAGS = -mcpu=arm926ej-s -mthumb-interwork -fno-pie
|
||||
WARN = -Wall -Wextra -Werror
|
||||
WARN = -Wall -Wextra -Werror=return-type -Werror=implicit-function-declaration
|
||||
OPTIMIZE = -g -Og
|
||||
INCLUDE = -I.
|
||||
GENDEP = -MMD -MP
|
||||
|
@ -41,7 +41,11 @@ openocd-load: jazelle.elf
|
|||
|
||||
gdb:
|
||||
$(GDB) -ex 'target extended-remote $(OPENOCD_HOST):$(OPENOCD_PORT_GDB)' \
|
||||
-ex 'set $$pc=_start' -ex 'b jazelle_exec' -ex c jazelle.elf
|
||||
-ex 'set $$pc=_start' \
|
||||
$(GDB_EXTRA_CMDS) \
|
||||
-ex c jazelle.elf
|
||||
|
||||
# -ex 'b jazelle_exec' \
|
||||
|
||||
-include $(OBJS:.o=.d)
|
||||
|
||||
|
|
290
jazelle.c
290
jazelle.c
|
@ -3,21 +3,35 @@
|
|||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.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?
|
||||
// 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"
|
||||
"bx lr\n"
|
||||
);
|
||||
}
|
||||
|
||||
__attribute__((__naked__))
|
||||
static uint32_t jazelle_get_id(void) {
|
||||
asm volatile(
|
||||
|
@ -26,6 +40,13 @@ static uint32_t jazelle_get_id(void) {
|
|||
);
|
||||
}
|
||||
|
||||
__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)
|
||||
|
@ -49,24 +70,60 @@ static uint32_t jazelle_get_id(void) {
|
|||
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
|
||||
};
|
||||
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"
|
||||
//"bkpt #0\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 {r4-r12,lr}\n"
|
||||
"bx lr\n"
|
||||
|
||||
".pool\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
__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) {
|
||||
|
@ -95,6 +152,7 @@ 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"
|
||||
|
@ -107,16 +165,15 @@ static void handler_idiv(void) {
|
|||
);
|
||||
}
|
||||
|
||||
static uint32_t jazelle_exit_save;
|
||||
|
||||
__attribute__((__naked__))
|
||||
static void handler_ireturn(void) {
|
||||
int result;
|
||||
asm volatile(
|
||||
//"bkpt #4\n"
|
||||
"ldr %[res], [r6, #-4]!\n"
|
||||
:[res]"=r"(result)
|
||||
);
|
||||
printf("result=%d\r\n", result); // FIXME: save & restore r0-r3 if ret implemented properly
|
||||
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
|
||||
|
@ -130,56 +187,6 @@ static void handler_ireturn(void) {
|
|||
__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;
|
||||
|
@ -199,12 +206,131 @@ static int jazelle_exec(const uint8_t* bytecode) {
|
|||
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);
|
||||
|
||||
|
||||
|
||||
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();
|
||||
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);
|
||||
|
||||
if (r == 0) {
|
||||
//r = jazelle_exec(bytecode_test1);
|
||||
//iprintf("retcode=%d\r\n", r);
|
||||
|
||||
uint8_t hflags[256/8];
|
||||
jazelle_test_handlers(hflags);
|
||||
|
||||
for (int i = 0; i < 0x100; ++i) {
|
||||
if (hflags[i>>3]&(1<<(i&7))) {
|
||||
iprintf("bytecode 0x%02x: uses handler\r\n", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (true) ;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
*.elf
|
||||
*.o
|
||||
__pycache__/
|
|
@ -0,0 +1,38 @@
|
|||
|
||||
PREFIX ?= arm-none-eabi-
|
||||
CC = $(PREFIX)gcc
|
||||
CFLAGS = -mcpu=cortex-a9
|
||||
LDFLAGS = -T zynq.ld -nostartfiles -nostdlib
|
||||
GDB ?= $(PREFIX)gdb
|
||||
PYTHON3 ?= python3
|
||||
NC ?= nc
|
||||
|
||||
OPENOCD_HOST ?= 172.16.10.2
|
||||
OPENOCD_PORT_GDB ?= 3333
|
||||
OPENOCD_PORT_TELNET ?= 4444
|
||||
|
||||
default: all
|
||||
|
||||
all: zynq.elf
|
||||
|
||||
zynq.o: zynq.c
|
||||
$(CC) $(CFLAGS) -c -o "$@" "$<"
|
||||
|
||||
zynq.elf: zynq.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o "$@" $^
|
||||
|
||||
openocd-load: zynq.elf
|
||||
{ $(PYTHON3) ./elf2oocd.py "$<"; echo exit; } | $(NC) $(OPENOCD_HOST) $(OPENOCD_PORT_TELNET)
|
||||
# printf 'halt\nload_image zynq.elf\nexit\n' \
|
||||
# | nc $(OPENOCD_HOST) $(OPENOCD_PORT_TELNET)
|
||||
|
||||
gdb: zynq.elf
|
||||
$(GDB) -ex 'target extended-remote $(OPENOCD_HOST):$(OPENOCD_PORT_GDB)' \
|
||||
-ex 'set $$pc=_start' \
|
||||
$(GDB_EXTRA_CMDS) \
|
||||
zynq.elf
|
||||
|
||||
clean:
|
||||
@$(RM) -v zynq.o zynq.elf
|
||||
|
||||
.PHONY: gdb openocd-load all default clean
|
|
@ -0,0 +1,49 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import struct, sys
|
||||
|
||||
import hackyelf
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
printf("Usage: %s <input.elf> > <output.cfg>" % sys.argv[0], file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
elfblob = None
|
||||
with open(sys.argv[1], 'rb') as f:
|
||||
elfblob = f.read()
|
||||
|
||||
elf = hackyelf.parse(elfblob)
|
||||
|
||||
print("""
|
||||
|
||||
# TODO: reset halt maybe?
|
||||
halt
|
||||
|
||||
""")
|
||||
|
||||
endian = '<' if elf.ident[5] == 1 else '>'
|
||||
for phdr in elf.phdrs:
|
||||
lenbytes = min(phdr.filesz, phdr.memsz)
|
||||
zerobytes = phdr.memsz - lenbytes
|
||||
|
||||
baseaddr = phdr.paddr if phdr.paddr else phdr.vaddr
|
||||
# text/data
|
||||
lenm4 = lenbytes - (lenbytes & 3)
|
||||
data = struct.unpack('%c%dI' % (endian, lenm4>>2), elfblob[phdr.off:(phdr.off+lenm4)])
|
||||
for i in range(0, lenbytes, 4):
|
||||
print("mww 0x%08x 0x%08x" % ((baseaddr + i), data[i>>2]))
|
||||
if lenm4 != lenbytes:
|
||||
for i in range(lenm4, lenbytes):
|
||||
print("mwb 0x%08x 0x%02x" % ((baseaddr + i), elfblob[phdr.off + i]))
|
||||
|
||||
# bss
|
||||
if zerobytes:
|
||||
print("mwb 0x%08x 0x00 0x%08x" % ((baseaddr + lenbytes), zerobytes))
|
||||
|
||||
|
||||
print("""
|
||||
|
||||
# set pc to entrypoint
|
||||
reg pc 0x%08x
|
||||
|
||||
""" % elf.entry)
|
|
@ -0,0 +1,431 @@
|
|||
|
||||
# from https://github.com/porocyon/smol , which is WTFPL-2.0
|
||||
|
||||
# stolen from the contrib folder in https://github.com/blackle/LZMA-Vizualizer
|
||||
# (i.e. I'm stealing it from myself)
|
||||
|
||||
# custom elf parser because a standard one wouldn't be trustable because the
|
||||
# ELFs we're parsing will be a bit wonky anyway
|
||||
|
||||
from struct import unpack
|
||||
from typing import *
|
||||
|
||||
|
||||
ELFCLASS32 = 1
|
||||
ELFCLASS64 = 2
|
||||
|
||||
EM_386 = 3
|
||||
EM_X86_64 = 62
|
||||
|
||||
PT_NULL = 0
|
||||
PT_LOAD = 1
|
||||
PT_DYNAMIC = 2
|
||||
PT_INTERP = 3
|
||||
|
||||
DT_NULL = 0
|
||||
DT_NEEDED = 1
|
||||
DT_PLTGOT = 3
|
||||
DT_STRTAB = 5
|
||||
DT_SYMTAB = 6
|
||||
DT_RELA = 7
|
||||
DT_RELASZ = 8
|
||||
DT_RELAENT = 9
|
||||
DT_STRSZ = 10
|
||||
DT_SYMENT = 11
|
||||
DT_SONAME = 14
|
||||
DT_REL = 17
|
||||
DT_RELSZ = 18
|
||||
DT_RELENT = 19
|
||||
DT_PLTREL = 20
|
||||
DT_DEBUG = 21
|
||||
DT_TEXTREL = 22
|
||||
DT_JMPREL = 23
|
||||
DT_BIND_NOW= 24
|
||||
|
||||
SHT_NULL = 0
|
||||
SHT_PROGBITS = 1
|
||||
SHT_SYMTAB = 2
|
||||
SHT_STRTAB = 3
|
||||
SHT_RELA = 4
|
||||
SHT_DYNAMIC = 6
|
||||
SHT_NOBITS = 8
|
||||
SHT_REL = 9
|
||||
SHT_DYNSYM = 11
|
||||
|
||||
SHF_WRITE = 1<<0
|
||||
SHF_ALLOC = 1<<1
|
||||
SHF_EXECINSTR = 1<<2
|
||||
SHF_MERGE = 1<<4
|
||||
SHF_STRINGS = 1<<5
|
||||
SHF_INFO_LINK = 1<<6
|
||||
|
||||
STB_LOCAL = 0
|
||||
STB_GLOBAL = 1
|
||||
STB_WEAK = 2
|
||||
|
||||
STT_NOTYPE = 0
|
||||
STT_OBJECT = 1
|
||||
STT_FUNC = 2
|
||||
STT_SECTION= 3
|
||||
STT_FILE = 4
|
||||
STT_COMMON = 5
|
||||
STT_TLS = 6
|
||||
STT_GNU_IFUNC = 10
|
||||
|
||||
STV_DEFAULT = 0
|
||||
STV_INTERNAL = 1
|
||||
STV_HIDDEN = 2
|
||||
STV_PROTECTED = 3
|
||||
|
||||
class Phdr(NamedTuple):
|
||||
ptype: int
|
||||
off : int
|
||||
vaddr: int
|
||||
paddr: int
|
||||
filesz: int
|
||||
memsz: int
|
||||
flags: int
|
||||
align: int
|
||||
|
||||
class Dyn(NamedTuple):
|
||||
tag: int
|
||||
val: int
|
||||
|
||||
class Shdr(NamedTuple):
|
||||
name: Union[int, str]
|
||||
type: int
|
||||
flags: int
|
||||
addr: int
|
||||
offset: int
|
||||
size: int
|
||||
link: int
|
||||
info: int
|
||||
addralign: int
|
||||
entsize: int
|
||||
|
||||
class Sym(NamedTuple):
|
||||
name: str
|
||||
value: int
|
||||
size: int
|
||||
type: int
|
||||
binding: int
|
||||
visibility: int
|
||||
shndx: int
|
||||
|
||||
class Rel(NamedTuple):
|
||||
offset: int
|
||||
symbol: Sym
|
||||
type: int
|
||||
class Rela(NamedTuple):
|
||||
offset: int
|
||||
symbol: Sym
|
||||
type: int
|
||||
addend: int
|
||||
Reloc = Union[Rel, Rela]
|
||||
|
||||
class ELF(NamedTuple):
|
||||
data : bytes
|
||||
ident : bytes
|
||||
eclass: int
|
||||
mach : int
|
||||
entry : int
|
||||
phdrs : Sequence[Phdr]
|
||||
dyn : Sequence[Dyn]
|
||||
shdrs : Sequence[Shdr]
|
||||
symtab: Sequence[Sym]
|
||||
dynsym: Sequence[Sym]
|
||||
relocs: Sequence[Reloc]
|
||||
is32bit: bool
|
||||
|
||||
def readstr(data: bytes, off: int) -> str:
|
||||
strb = bytearray()
|
||||
while data[off] != 0 and off < len(data):
|
||||
strb.append(data[off])
|
||||
off = off + 1
|
||||
return strb.decode('utf-8')
|
||||
|
||||
# yeah, there's some code duplication here
|
||||
# idgaf
|
||||
|
||||
def parse_phdr32(data: bytes, phoff:int, phentsz:int, phnum:int) -> Sequence[Phdr]:
|
||||
ps = []
|
||||
for off in range(phoff, phoff+phentsz*phnum, phentsz):
|
||||
ptype, off, vaddr, paddr, filesz, memsz, flags, align = \
|
||||
unpack('<IIIIIIII', data[off:off+8*4])
|
||||
p = Phdr(ptype, off, vaddr, paddr, filesz, memsz, flags, align)
|
||||
ps.append(p)
|
||||
|
||||
return ps
|
||||
|
||||
def parse_dyn32(data: bytes, dynp: Phdr) -> Dyn:
|
||||
ds = []
|
||||
|
||||
off = dynp.off
|
||||
while True:
|
||||
tag, val = unpack('<II', data[off:off+2*4])
|
||||
ds.append(Dyn(tag, val))
|
||||
|
||||
if tag == DT_NULL: break
|
||||
off = off + 2*4
|
||||
|
||||
return ds
|
||||
|
||||
def parse_reloc32(data: bytes, reloff: int, nrel: int, entsz: int, syms: Sequence[Sym], rela: bool) -> Reloc:
|
||||
rr=[]
|
||||
|
||||
for off in range(reloff, reloff+entsz*nrel, entsz):
|
||||
off, inf, add = unpack('<IIi', data[off:(off+12)]) if rela \
|
||||
else (*unpack('<Ii', data[off:(off+8)]),0)
|
||||
|
||||
sym = syms[inf >> 8]
|
||||
type = inf & 0xff
|
||||
rr.append(Rela(off, sym, type, add) if rela else Rel(off, sym, type))
|
||||
|
||||
return rr
|
||||
|
||||
def parse_shdr32(data: bytes, shoff: int, shentsz: int, shnum: int,
|
||||
shstrndx: int) -> Sequence[Shdr]:
|
||||
if shnum*shentsz+shoff > len(data) or shentsz==0 or shnum==0 or shoff==0:
|
||||
print("snum*shentsz+shoff",shnum*shentsz+shoff)
|
||||
print("len(data)",len(data))
|
||||
print("shentsz",shentsz)
|
||||
print("shnum",shnum)
|
||||
print("shoff",shoff)
|
||||
return []
|
||||
|
||||
ss = []
|
||||
for off in range(shoff, shoff+shentsz*shnum, shentsz):
|
||||
noff, typ, flags, addr, off, size, link, info, align, entsz = \
|
||||
unpack('<IIIIIIIIII', data[off:off+10*4])
|
||||
s = Shdr(noff, typ, flags, addr, off, size, link, info, align, entsz)
|
||||
ss.append(s)
|
||||
|
||||
if shstrndx < shnum:
|
||||
shstr = ss[shstrndx]
|
||||
for i in range(len(ss)):
|
||||
sname = readstr(data, shstr.offset + ss[i].name) \
|
||||
if ss[i].name < shstr.size else None
|
||||
ss[i] = Shdr(sname, ss[i].type, ss[i].flags, ss[i].addr,
|
||||
ss[i].offset, ss[i].size, ss[i].link, ss[i].info,
|
||||
ss[i].addralign, ss[i].entsize)
|
||||
|
||||
return ss
|
||||
|
||||
def parse_sym32(data: bytes, sym: Shdr, strt: Shdr) -> Sequence[Sym]:
|
||||
ss = []
|
||||
for off in range(sym.offset, sym.offset+sym.size, sym.entsize):
|
||||
noff, val, sz, info, other, shndx = \
|
||||
unpack('<IIIBBH', data[off:off+3*4+2+2])
|
||||
|
||||
sn = readstr(data, strt.offset + noff) \
|
||||
if noff < strt.size else None
|
||||
s = Sym(sn, val, sz, (info & 15), (info >> 4), other, shndx)
|
||||
ss.append(s)
|
||||
return ss#sorted(ss, key=lambda x:x.value)
|
||||
|
||||
def parse_32(data: bytes) -> ELF:
|
||||
ident = data[:16]
|
||||
eclass = data[4]
|
||||
mach = unpack('<H', data[18:18+2])[0]
|
||||
entry = unpack('<I', data[24:24+4])[0]
|
||||
|
||||
phoff = unpack('<I', data[28:28+4])[0]
|
||||
shoff = unpack('<I', data[32:32+4])[0]
|
||||
phentsz = unpack('<H', data[42:42+2])[0]
|
||||
phnum = unpack('<H', data[44:44+2])[0]
|
||||
shentsz = unpack('<H', data[46:46+2])[0]
|
||||
shnum = unpack('<H', data[48:48+2])[0]
|
||||
shstrndx= unpack('<H', data[50:50+2])[0]
|
||||
|
||||
phdrs = [] if phentsz == 0 else parse_phdr32(data, phoff, phentsz, phnum)
|
||||
dyn = None
|
||||
|
||||
for p in phdrs:
|
||||
if p.ptype == PT_DYNAMIC:
|
||||
dyn = parse_dyn32(data, p)
|
||||
break
|
||||
|
||||
shdrs = parse_shdr32(data, shoff, shentsz, shnum, shstrndx)
|
||||
#print("shdrs",shdrs)
|
||||
|
||||
symtabsh = [s for s in shdrs if s.type == SHT_SYMTAB and s.name == ".symtab"]
|
||||
strtabsh = [s for s in shdrs if s.type == SHT_STRTAB and s.name == ".strtab"]
|
||||
dynsymsh = [s for s in shdrs if s.type == SHT_SYMTAB and s.name == ".dynsym"]
|
||||
dynstrsh = [s for s in shdrs if s.type == SHT_STRTAB and s.name == ".dynstr"]
|
||||
relash = [s for s in shdrs if s.type == SHT_RELA]
|
||||
relsh = [s for s in shdrs if s.type == SHT_REL]
|
||||
|
||||
#print("symtab",symtabsh)
|
||||
#print("strtab",strtabsh)
|
||||
|
||||
assert len(symtabsh) < 2
|
||||
assert len(strtabsh) < 2
|
||||
assert len(dynsymsh) < 2
|
||||
assert len(dynstrsh) < 2
|
||||
|
||||
symtab, dynsym = None, None
|
||||
if len(symtabsh) and len(strtabsh):
|
||||
symtab = parse_sym32(data, symtabsh[0], strtabsh[0]) \
|
||||
if len(shdrs) > 0 else []
|
||||
if len(dynsymsh) and len(dynstrsh):
|
||||
dynsym = parse_sym32(data, symtabsh[0], strtabsh[0]) \
|
||||
if len(shdrs) > 0 else []
|
||||
|
||||
relocs = []
|
||||
|
||||
# TODO: use sh.link to use the correct symbol table
|
||||
for sh in relash:
|
||||
relocs += parse_reloc32(data, sh.offset, sh.size//sh.entsize,
|
||||
sh.entsize, symtab, True)
|
||||
for sh in relsh:
|
||||
relocs += parse_reloc32(data, sh.offset, sh.size//sh.entsize,
|
||||
sh.entsize, symtab, False)
|
||||
# TODO: relocs from DT_RELA, DT_REL
|
||||
|
||||
return ELF(data, ident, eclass, mach, entry, phdrs, dyn, shdrs,
|
||||
symtab, dynsym, relocs, True)
|
||||
|
||||
def parse_phdr64(data: bytes, phoff:int, phentsz:int, phnum:int) -> Sequence[Phdr]:
|
||||
ps = []
|
||||
for off in range(phoff, phoff+phentsz*phnum, phentsz):
|
||||
# TODO # what is TODO exactly??
|
||||
ptype, flags, off, vaddr, paddr, filesz, memsz, align = \
|
||||
unpack('<IIQQQQQQ', data[off:off+2*4+6*8])
|
||||
p = Phdr(ptype, off, vaddr, paddr, filesz, memsz, flags, align)
|
||||
ps.append(p)
|
||||
|
||||
return ps
|
||||
|
||||
def parse_dyn64(data: bytes, dynp: Phdr) -> Dyn:
|
||||
ds = []
|
||||
|
||||
off = dynp.off
|
||||
while True:
|
||||
tag, val = unpack('<QQ', data[off:off+2*8])
|
||||
ds.append(Dyn(tag, val))
|
||||
|
||||
if tag == DT_NULL: break
|
||||
off = off + 2*8
|
||||
|
||||
return ds
|
||||
|
||||
def parse_reloc64(data: bytes, reloff: int, nrel: int, entsz: int, syms: Sequence[Sym], rela: bool) -> Reloc:
|
||||
rr=[]
|
||||
|
||||
for off in range(reloff, reloff+entsz*nrel, entsz):
|
||||
off, inf, add = unpack('<QQq', data[off:(off+24)]) if rela \
|
||||
else (*unpack('<Qq', data[off:(off+16)]),0)
|
||||
|
||||
sym = syms[inf >> 32]
|
||||
type = inf & 0xffffffff
|
||||
rr.append(Rela(off, sym, type, add) if rela else Rel(off, sym, type))
|
||||
|
||||
return rr
|
||||
|
||||
def parse_shdr64(data: bytes, shoff: int, shentsz: int, shnum: int,
|
||||
shstrndx: int) -> Sequence[Shdr]:
|
||||
|
||||
if shnum*shentsz+shoff > len(data) or shentsz==0 or shnum==0 or shoff==0:
|
||||
return []
|
||||
|
||||
ss = []
|
||||
for off in range(shoff, shoff+shentsz*shnum, shentsz):
|
||||
noff, typ, flags, addr, off, size, link, info, align, entsz = \
|
||||
unpack('<IIQQQQIIQQ', data[off:off+4*4+6*8])
|
||||
s = Shdr(noff, typ, flags, addr, off, size, link, info, align, entsz)
|
||||
ss.append(s)
|
||||
|
||||
if shstrndx < shnum:
|
||||
shstr = ss[shstrndx]
|
||||
for i in range(len(ss)):
|
||||
sname = readstr(data, shstr.offset + ss[i].name) \
|
||||
if ss[i].name < shstr.size else None
|
||||
ss[i] = Shdr(sname, ss[i].type, ss[i].flags, ss[i].addr,
|
||||
ss[i].offset, ss[i].size, ss[i].link, ss[i].info,
|
||||
ss[i].addralign, ss[i].entsize)
|
||||
|
||||
return ss
|
||||
|
||||
def parse_sym64(data: bytes, sym: Shdr, strt: Shdr) -> Sequence[Sym]:
|
||||
ss = []
|
||||
for off in range(sym.offset, sym.offset+sym.size, sym.entsize):
|
||||
noff, info, other, shndx, value, sz = \
|
||||
unpack('<IBBHQQ', data[off:off+4+2+2+8*2])
|
||||
|
||||
sn = readstr(data, strt.offset + noff) \
|
||||
if noff < strt.size else None
|
||||
s = Sym(sn, value, sz, (info & 15), (info >> 4), other, shndx)
|
||||
ss.append(s)
|
||||
return ss#sorted(ss, key=lambda x:x.value)
|
||||
|
||||
def parse_64(data: bytes) -> ELF:
|
||||
ident = data[:16]
|
||||
eclass = data[4]
|
||||
mach = unpack('<H', data[18:18+2])[0]
|
||||
entry = unpack('<Q', data[24:24+8])[0]
|
||||
|
||||
phoff = unpack('<Q', data[32:32+8])[0]
|
||||
shoff = unpack('<Q', data[40:40+8])[0]
|
||||
phentsz = unpack('<H', data[54:54+2])[0]
|
||||
phnum = unpack('<H', data[56:56+2])[0]
|
||||
shentsz = unpack('<H', data[58:58+2])[0]
|
||||
shnum = unpack('<H', data[60:60+2])[0]
|
||||
shstrndx= unpack('<H', data[62:62+2])[0]
|
||||
|
||||
phdrs = [] if phentsz == 0 else parse_phdr64(data, phoff, phentsz, phnum)
|
||||
dyn = None
|
||||
|
||||
for p in phdrs:
|
||||
if p.ptype == PT_DYNAMIC:
|
||||
dyn = parse_dyn64(data, p)
|
||||
break
|
||||
|
||||
shdrs = [] if shentsz == 0 else parse_shdr64(data, shoff, shentsz, shnum, shstrndx)
|
||||
|
||||
symtabsh = [s for s in shdrs if s.type == SHT_SYMTAB and s.name == ".symtab"]
|
||||
strtabsh = [s for s in shdrs if s.type == SHT_STRTAB and s.name == ".strtab"]
|
||||
dynsymsh = [s for s in shdrs if s.type == SHT_SYMTAB and s.name == ".dynsym"]
|
||||
dynstrsh = [s for s in shdrs if s.type == SHT_STRTAB and s.name == ".dynstr"]
|
||||
relash = [s for s in shdrs if s.type == SHT_RELA]
|
||||
relsh = [s for s in shdrs if s.type == SHT_REL]
|
||||
|
||||
assert len(symtabsh) < 2
|
||||
assert len(strtabsh) < 2
|
||||
assert len(dynsymsh) < 2
|
||||
assert len(dynstrsh) < 2
|
||||
|
||||
symtab, dynsym = None, None
|
||||
if len(symtabsh) and len(strtabsh):
|
||||
symtab = parse_sym64(data, symtabsh[0], strtabsh[0]) \
|
||||
if len(shdrs) > 0 else []
|
||||
if len(dynsymsh) and len(dynstrsh):
|
||||
dynsym = parse_sym64(data, symtabsh[0], strtabsh[0]) \
|
||||
if len(shdrs) > 0 else []
|
||||
|
||||
relocs = []
|
||||
|
||||
# TODO: use sh.link to use the correct symbol table
|
||||
for sh in relash:
|
||||
relocs += parse_reloc32(data, sh.offset, sh.size//sh.entsize,
|
||||
sh.entsize, symtab, True)
|
||||
for sh in relsh:
|
||||
relocs += parse_reloc32(data, sh.offset, sh.size//sh.entsize,
|
||||
sh.entsize, symtab, False)
|
||||
# TODO: relocs from DT_RELA, DT_REL
|
||||
|
||||
return ELF(data, ident, eclass, mach, entry, phdrs, dyn, shdrs,
|
||||
symtab, dynsym, relocs, False)
|
||||
|
||||
def parse(data: bytes) -> ELF:
|
||||
assert data[:4] == b'\x7FELF', "Not a valid ELF file" # good enough
|
||||
|
||||
ecls = data[4]
|
||||
if ecls == ELFCLASS32: return parse_32(data)
|
||||
elif ecls == ELFCLASS64: return parse_64(data)
|
||||
else:
|
||||
emch = unpack('<H', data[18:18+2])[0]
|
||||
if emch == EM_386: return parse_32(data)
|
||||
elif emch == EM_X86_64: return parse_64(data)
|
||||
|
||||
assert False, "bad E_CLASS %d" % ecls
|
||||
|
|
@ -0,0 +1,248 @@
|
|||
|
||||
#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"
|
||||
"bx lr\n"
|
||||
);
|
||||
}
|
||||
|
||||
__attribute__((__naked__))
|
||||
static uint32_t jazelle_get_id(void) {
|
||||
asm volatile(
|
||||
"mrc p14, 7, r0, c0, c0, 0\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(
|
||||
"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();
|
||||
//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, =0xffffff00\n"
|
||||
"bl main\n"
|
||||
"1: b 1b\n"
|
||||
".pool\n"
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0xffff0000;
|
||||
|
||||
.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