Skip to content

Commit

Permalink
misc
Browse files Browse the repository at this point in the history
  • Loading branch information
neuschaefer committed Dec 7, 2023
1 parent af8a5ac commit 8711cf6
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 56 deletions.
12 changes: 10 additions & 2 deletions .github/workflows/arm926.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,13 @@ jobs:
container:
image: debian:latest
steps:
- run: echo hello
- run: uname -a
# APT sandboxing is broken on my machine, see https://codeberg.org/neuschaefer/jzvm/issues/16
- run: apt-get -o APT::Sandbox::User=root update && apt-get -o APT::Sandbox::User=root install -y cargo git

# Unfortunately, actions are written in Node.js, which doesn't run on ARMv5[1],
# so we can't use actions.
# [1]: https://packages.debian.org/bookworm/nodejs "dep: armv6k-support"
#- uses: actions/checkout@v3

- run: git clone "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY" jzvm
- run: cd jzvm && cargo test
7 changes: 0 additions & 7 deletions .github/workflows/build.yml

This file was deleted.

9 changes: 9 additions & 0 deletions .github/workflows/x86.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- run: apt-get update && apt-get install -y git cargo
- uses: actions/checkout@v3
- run: cargo run
- run: cargo test
106 changes: 63 additions & 43 deletions src/exec/arm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ mod regs {
}

#[derive(Debug)]
struct HandlerTable([u32; 0x105]);
//struct HandlerTable([u32; 0x105]);
struct HandlerTable([u32; 0x200]);

use std::alloc::LayoutError;
impl HandlerTable {
Expand Down Expand Up @@ -116,88 +117,107 @@ impl Executor for ARMExecutor {

unsafe {
let mut pc = ctx.code.as_ptr().add(state.pc);
let mut sp = ctx.stack.as_ptr().add(state.sp);
let locals = ctx.locals.as_ptr();
let mut exit_code: u32;
let handler_table = self.handler_table.0.as_mut_ptr();

println!("entry: {handler_table:?}, pc: {pc:?}, sp: {sp:?}, locals: {locals:?}");

asm!(
"push {{r3-r8, r12, lr}}",

"mov r5, {handler_table}",
"mov r6, r2",
"mov r7, {locals}",

"adr r1, 100f",
"mov r3, #0",
"1:",
"str r1, [r5, r3]",
"add r3, #4",
"cmp r3, #0x400",
"ble 1b",

"adr r1, 400f",
"str r1, [r5, #0x400]",
"adr r1, 404f",
"str r1, [r5, #0x404]",
"adr r1, 409f",
"str r1, [r5, #0x40c]",
"adr r1, 410f",
"str r1, [r5, #0x410]",
"adr r1, 414f",
"str r1, [r5, #0x414]",

"adr r12, 900f",
"mov lr, r0",

"mov r0, #0",
"mov r1, #0",
"mov r2, #0",
"mov r3, #0",
"mov r4, #0",
"mov r5, {handler_table}",
"mov r6, {stack_pointer}",
"mov r7, {locals}",

"adr r0, 400f",
"str r0, [r5, #0x400]",
"adr r0, 404f",
"str r0, [r5, #0x404]",
"adr r0, 409f",
"str r0, [r5, #0x40c]",
"adr r0, 410f",
"str r0, [r5, #0x410]",
"adr r0, 414f",
"str r0, [r5, #0x414]",

"adr r12, 900f",
"mov lr, {pc}",
"bxj r12",

"100:", // Opcode handler
"mov {exit_code}, #0x100",
"mov r1, #0x100",
"ldrb r0, [lr]",
"orr {exit_code}, r0",
"orr r1, r0",
"b 999f",

"400:", // Null pointer exception
"mov {exit_code}, #0x00",
"mov r1, #0x00",
"b 999f",

"404:", // Array index out of bounds exception
"mov {exit_code}, #0x04",
"mov r1, #0x04",
"b 999f",

"409:", // Jazelle disabled
"mov {exit_code}, #0x0c",
"mov r1, #0x0c",
"b 999f",

"410:", // Configuration invalid
"mov {exit_code}, #0x10",
"mov r1, #0x10",
"b 999f",

"414:", // Prefetch abort
"mov {exit_code}, #0x14",
"mov r1, #0x14",
"b 999f",

"900:", // Jazelle unsupported
"mov {exit_code}, #0xff",
"mov r1, #0xff",
"b 999f",

"999:", // exit
"mov {pc}, lr",
"mov r0, lr",
"mov r2, r6",

"pop {{r3-r8, r12, lr}}",

// inputs
handler_table = in(reg) self.handler_table.0.as_ptr(),
stack_pointer = in(reg) state.sp,
locals = in(reg) ctx.locals.as_ptr(),
pc = inout(reg) pc,
handler_table = in(reg) handler_table,
locals = in(reg) locals,
inout("r2") sp,
inout("r0") pc,

// outputs
exit_code = out(reg) exit_code,
out("r1") exit_code,
);

println!("exit code: {exit_code}, pc: {pc:?}");
}

// Currently:
//
// - Jazelle state is entered successfully
// - Java instructions are executed until ireturn
// - The ireturn handler is called, resulting in a segfault at 0x0deadac0
// - The computed value is actually on the stack!
// (gdb) p *state.stack
// $1 = [5, 0 <repeats 1023 times>]
state.pc = pc.offset_from(ctx.code.as_ptr()) as usize;
state.sp = sp.offset_from(ctx.stack.as_ptr()) as usize;
println!("exit code: {exit_code:x}, pc: {pc:?} ({}), sp: {sp:?} ({})", state.pc, state.sp);

Err(ExitCondition::OpcodeHandler(0x42))
match exit_code {
0x00 => Err(ExitCondition::NullPointerException),
0x04 => Err(ExitCondition::ArrayIndexOutOfBounds),
x if (0x100..0x200).contains(&x) => Err(ExitCondition::OpcodeHandler((x & 0xff) as u8)),
x => unreachable!("Jazelle exit status {x:x}"),
}
}
}

fn get_id(&self) -> Option<u32> {
Expand Down
4 changes: 2 additions & 2 deletions src/exec/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ pub enum ExitCondition {
PCOutOfBounds,

/// A null value was dereferenced
_NullPointerException,
NullPointerException,

/// An array was accessed out-of-bounds
_ArrayIndexOutOfBounds
ArrayIndexOutOfBounds
}

impl fmt::Display for ExitCondition {
Expand Down
4 changes: 2 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ fn main() -> Result<(), Box<dyn Error>> {
let mut state = exec::State::default();
let mut exec = exec::new()?;

let code = [
let code = vec![
op::iconst_2,
op::iconst_3,
op::iadd,
op::breakpoint,
];
let mut ctx = exec::Context {
code: &code,
locals: &mut vec![],
locals: &mut vec![0],
stack: &mut vec![0; 2],
};

Expand Down
33 changes: 33 additions & 0 deletions src/op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,38 @@ pub const iconst_0: u8 = 0x03;
pub const iconst_1: u8 = 0x04;
pub const iconst_2: u8 = 0x05;
pub const iconst_3: u8 = 0x06;
pub const iconst_4: u8 = 0x07;
pub const iconst_5: u8 = 0x08;
pub const lconst_0: u8 = 0x09;
pub const lconst_1: u8 = 0x0a;
pub const fconst_0: u8 = 0x0b;
pub const fconst_1: u8 = 0x0c;
pub const fconst_2: u8 = 0x0d;
pub const dconst_0: u8 = 0x0e;
pub const dconst_1: u8 = 0x0f;
pub const bipush: u8 = 0x10;
pub const sipush: u8 = 0x11;
pub const ldc: u8 = 0x12;
pub const ldc_w: u8 = 0x13;
pub const ldc2_w: u8 = 0x14;
pub const iload: u8 = 0x15;
pub const lload: u8 = 0x16;
pub const fload: u8 = 0x17;
pub const dload: u8 = 0x18;
pub const aload: u8 = 0x19;
pub const iload_0: u8 = 0x1a;
pub const iload_1: u8 = 0x1b;
pub const iload_2: u8 = 0x1c;
pub const iload_3: u8 = 0x1d;
pub const lload_0: u8 = 0x1e;
pub const lload_1: u8 = 0x1f;
pub const lload_2: u8 = 0x20;
pub const lload_3: u8 = 0x21;
pub const fload_0: u8 = 0x22;
pub const fload_1: u8 = 0x23;
pub const fload_2: u8 = 0x24;
pub const fload_3: u8 = 0x25;
pub const iadd: u8 = 0x60;
pub const breakpoint: u8 = 0xca;
pub const impdep1: u8 = 0xfe;
pub const impdep2: u8 = 0xff;
43 changes: 43 additions & 0 deletions tests/exec/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ impl TestVM {
}

#[test]
#[ignore]
fn test_00_nop() {
let mut exec = exec::new().unwrap();
let pre = TestVM::from_code(vec![op::nop, op::breakpoint]);
Expand All @@ -51,3 +52,45 @@ fn test_00_nop() {
});
}
}

#[test]
#[ignore]
fn test_01_aconst_null() {
let mut exec = exec::new().unwrap();
let pre = TestVM::from_code(vec![op::aconst_null, op::breakpoint]);
let mut post = pre.clone();

assert_eq!(pre.code[0], 0x01);

unsafe {
let (mut ctx, mut state) = post.ctx();
assert_eq!(exec.execute(&mut ctx, &mut state), Err(exec::ExitCondition::OpcodeHandler(op::breakpoint)));
assert_eq!(post, TestVM {
state: exec::State { pc: 1, sp: 1 },
.. pre
});
}
}

#[test]
fn test_02_iconst_m1() {
let mut exec = exec::new().unwrap();
let pre = TestVM::from_code(vec![op::iconst_m1, op::breakpoint]);
let mut post = pre.clone();

assert_eq!(pre.code[0], 0x02);

unsafe {
let (mut ctx, mut state) = post.ctx();
assert_eq!(exec.execute(&mut ctx, &mut state), Err(exec::ExitCondition::OpcodeHandler(op::breakpoint)));
assert_eq!(post, TestVM {
state: exec::State { pc: 1, sp: 1 },
stack: {
let mut v = pre.stack.clone();
v[0] = 0xffffffff;
v
},
.. pre
});
}
}

0 comments on commit 8711cf6

Please sign in to comment.