├── LICENSE.txt ├── README.md ├── data └── jz.S └── src ├── jz.c └── jz.h /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright(C) 2021 SonoSooS (https://github.com/SonoSooS) 2 | All Rights Reserved 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libjz 2 | 3 | Based on the minimal amount of publically available information, and an unmeasurable amount of bruteforcing and observation, finally there is a driver and documentation on how to unlock and use the Jazelle core included (and most likely hidden) in some ARM CPU cores. 4 | 5 | You can also reimplement this driver yourself based on the information documented in the [wiki tab](../../wiki). 6 | 7 | ## CPU compatibility 8 | 9 | While all CPUs with `J` in their name should have Jazelle in them (like `ARM926EJ-S` or `ARMv5TEJ`), in some cases it's not so obvious (for example some if not all `ARM11 MPCore` (`ARMv6K`) CPUs should have it). 10 | 11 | The best bet is to run the below instructions in kernel mode to see if the Jazelle core exists or not. You know there is a Jazelle core if you don't get any CPU exception, and you get a value with some high and some low bits set with middle bits being mostly if not all zero (in `r0` in this example). 12 | > MOV r0, #2 13 | > MCR p14, 7, r0, c1, c0, 0 14 | > MRC p14, 7, r0, c0, c0, 0 15 | On my ARM11 MPCore I get `0x74100064`. 16 | 17 | A rule of thumb is that ARM7TDMI (ARMv4 ?) is too old to hava Jazelle, while ARMv7 CPUs are highly unlikely to have it due to being too new. 18 | 19 | Here are a few CPUs which are known to have Jazelle in them: 20 | - `ARM7EJ-S` (`ARMv5TEJ`) 21 | - `ARM926EJ-S` (`ARMv5TEJ`) 22 | - `ARM11MPCore` (`ARMv6K`) 23 | 24 | Currently only the Jazelle core found in `ARM11MPCore` (`0x74100064`) is supported. Please open an issue if you need support for a different Jazelle identifier. 25 | 26 | ## Kernel compatibility 27 | 28 | Currently libjz has only been developed and tested on a Nintendo 3DS running in usermode under Nintendo's Horizon kernel with kernel code execution support. 29 | 30 | Any kernel should work if it can unlock Jazelle for you, or if you can enter kernel mode to unlock it yourself with a `jzk*` prefix function. 31 | 32 | > Please note that functions starting with `jzk*` can only be executed in kernel mode, and will cause undefined instruction when attempted to be executed in usermode. 33 | 34 | # License 35 | 36 | See `LICENSE.txt`. You may use this driver in personal projects freely. 37 | 38 | If you want to distribute your project with this driver, please include a link to my github user page in your program where it's easily user-accessible (like in your program's about section, or in the copyright printout in a console application). 39 | -------------------------------------------------------------------------------- /data/jz.S: -------------------------------------------------------------------------------- 1 | .3ds 2 | .arm 3 | 4 | .create outfile,0 5 | 6 | ; Offset to jzState where exception address is stored 7 | o_excaddr equ 8 << 2 8 | 9 | .align 4 10 | jz_hdr: ; in-header offset table 11 | 12 | .word jz_stub - jz_hdr 13 | .word jz_user_handler - jz_hdr 14 | .word jz_ehandler - jz_hdr 15 | 16 | .word jz_test - jz_hdr 17 | 18 | .align 4 19 | 20 | .function jz_stub ; r0 = jzState*, r1 = JPC, r2 = handler, r3 = userdata 21 | ; Save AAPCS regs 22 | PUSH {r4 - r12, LR} 23 | 24 | MOV r9, r0 ; Save state ptr to reg 25 | MOV LR, r1 ; Set JPC 26 | MOV r10, r2 ; Save handler ptr 27 | MOV r11, r3 ; Save userdata ptr 28 | 29 | LDMIA r9, {r0 - r7} ; Load Jazelle state from jzState 30 | MOV r8, #0 ; Debug const ptr??? 31 | 32 | ADD r12, PC, (fail_bxj - . - 8) ; Set "fallback" Jazelle handler to fail 33 | .dcd 0xE12FFF20 + 12; BXJ r12 34 | 35 | fail_bxj: 36 | MVN r0, #0 ; Unable to enter Jazelle state for some reason (-1) 37 | 38 | skip_bxj: 39 | ; it's the handler's job to store the regs in r9 40 | ;STMIA r9, {r0 - r7} 41 | 42 | ; Load AAPCS regs 43 | POP {r4 - r12, PC} 44 | .endfunc 45 | 46 | 47 | .function jz_user_handler 48 | STMIA r9, {r0 - r7} ; Save Jazelle state (faster to save r0-r3 than to skip saving them unnecessarily) 49 | 50 | PUSH {r8 - r12, LR} ; AAPCS Thumb save 51 | ; AAPCS saves rest in callee 52 | 53 | MOV r0, r9 ; jzState 54 | MOV r1, LR ; JPC 55 | MOV r2, r11 ; userdata 56 | MOV r3, r12 ; JumpID (corrupted by Jazelle) 57 | BLX r10 58 | 59 | ; APPCS restores rest in callee 60 | POP {r8 - r12, LR} ; AAPCS Thumb restore 61 | 62 | CMP r0, #0 ; Check valid return ptr 63 | 64 | MOVNE LR, r0 ; Set JPC to valid ptr 65 | LDMNEIA r9, {r0 - r7} ; LDMIANE, restore Jazelle state if valid ptr 66 | SUBNE r12, PC, (. - fail_bxj + 8) 67 | .dcd 0x112FFF20 + 12 ; BXJNE r12 68 | 69 | B skip_bxj ; Return from Jazelle state back to C on invalid ptr 70 | .endfunc 71 | 72 | .function jz_ehandler 73 | STMIA r9, {r0 - r7} ; Save Jazelle state back to jzState 74 | STR LR, [r9, o_excaddr] ; Store error address 75 | ADD r0, r12, #1 ; Set exception code from JumpID (corrupted by Jazelle) 76 | B skip_bxj ; Return from Jazelle back to C 77 | .endfunc 78 | 79 | jz_test: 80 | 81 | .byte 0x12, 2 ; 00: ldc #2 82 | .byte 0x3C ; 02: istore_1 83 | .byte 0x1B ; 03: iload_1 84 | .byte 0x99, 0x00, 0x09 ; 04: ifeq 0D (+9h) 85 | .byte 0x84, 0x01, 0xFF ; 07: iinc #1, -1 86 | .byte 0xA7, 0xFF, 0xF9 ; 0A: goto 03 (-7h) 87 | .byte 0xB1 ; 0D: return 88 | 89 | .close 90 | -------------------------------------------------------------------------------- /src/jz.c: -------------------------------------------------------------------------------- 1 | #include "jz.h" 2 | 3 | 4 | 5 | void jzkHwEnable(bool enable, bool userland) 6 | { 7 | uint32_t reg; 8 | 9 | MRC(reg, 14, 7, 1, 0, 0); 10 | if(userland) 11 | reg |= 2; 12 | else 13 | reg &= ~2; 14 | MCR(reg, 14, 7, 1, 0, 0); 15 | 16 | MRC(reg, 14, 7, 2, 0, 0); 17 | if(enable) 18 | reg |= 1; 19 | else 20 | reg &= ~1; 21 | MCR(reg, 14, 7, 2, 0, 0); 22 | } 23 | -------------------------------------------------------------------------------- /src/jz.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #ifdef _MSC_VER 7 | #define MRC(rD,pc,op1,r1,r2,op2) rD = _MoveFromCoprocessor(pc, op1, r1, r2, op2) 8 | #define MCR(rD,pc,op1,r1,r2,op2) _MoveToCoprocessor(rD, pc, op1, r1, r2, op2) 9 | #else 10 | #define MRC(rD,pc,op1,r1,r2,op2) asm volatile("MRC p" #pc ", " #op1 ", %0, c" #r1 ", c" #r2 ", " #op2 "\n\t" : "=r"(rD)) 11 | #define MCR(rD,pc,op1,r1,r2,op2) asm volatile("MCR p" #pc ", " #op1 ", %0, c" #r1 ", c" #r2 ", " #op2 "\n\t" :: "r"(rD)) 12 | #endif 13 | 14 | 15 | typedef int8_t jzByte; 16 | typedef uint16_t jzChar; 17 | typedef int16_t jzShort; 18 | typedef int32_t jzInt; 19 | typedef int64_t jzLong; 20 | 21 | typedef uint8_t jzBytecode; 22 | 23 | typedef struct jz_vectordata 24 | { 25 | void* Handler[256]; // naked noreturn callback 26 | void* ErrHandler[8]; // ??? 27 | } jzVector; 28 | 29 | typedef struct jz_state 30 | { 31 | jzInt StackIn[4]; // r0 - r3 32 | jzInt Local0; // r4 33 | jzInt VectorData; // r5 34 | jzInt* StackTop; // r6 35 | jzInt* LocalPool; // r7 36 | const jzBytecode* ExceptionAddr; // Address of exception 37 | } jzState; 38 | 39 | 40 | typedef jzBytecode const*(*jzUserHandlerCb)(jzState* state, const jzBytecode* JPC, void* userdata, jzInt cbData); 41 | typedef jzInt(*jzEnterPfn)(jzState* state, const jzBytecode* JPC, jzUserHandlerCb callback, void* userdata); 42 | 43 | 44 | void jzkHwEnable(bool enable, bool userland); 45 | 46 | 47 | --------------------------------------------------------------------------------