Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ You can run linux in your browser.
$ cargo run -p app -- -i fixtures/linux.bin -d fixtures/default.dtb
```

The terminal is put into raw mode while the emulator runs, so every keystroke including
`Ctrl-C` is delivered to the guest. Press `Ctrl-A` `x` to quit the emulator, or `Ctrl-A`
`Ctrl-A` to send a literal `Ctrl-A` to the guest.

## WASI

```sh
Expand Down
4 changes: 3 additions & 1 deletion app/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ edition = "2021"
[dependencies]
anyhow = "1.0.75"
clap = { version = "4.4.11", features = ["derive"] }
core = { path = "../core" }
# Aliased because a dependency literally named `core` shadows the `core`
# built-in crate inside macro expansions such as clap's derive.
r2_core = { path = "../core", package = "core" }
devices = { path = "../devices" }
device_interfaces = { path = "../device_interfaces" }

Expand Down
2 changes: 1 addition & 1 deletion app/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::path::PathBuf;

use anyhow::{bail, Result};

use core::{
use r2_core::{
bus::{Bus, RAM_START},
clint::Clint,
start,
Expand Down
128 changes: 82 additions & 46 deletions core/src/bus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ pub struct Bus<T, S> {
pub ram: Vec<u8>,
pub clint: Clint<T>,
pub serial: S,
/// 8250 line control register. Its top bit (DLAB) turns registers 0 and 1 into the
/// baud rate divisor latches, so it has to be tracked to keep the guest from
/// mistaking a divisor for a character.
lcr: u8,
divisor: u16,
pub power_off: bool,
pub reboot: bool,
}
Expand All @@ -19,6 +24,8 @@ impl<T, S> Bus<T, S> {
ram,
clint,
serial,
lcr: 0,
divisor: 0,
power_off: false,
reboot: false,
}
Expand All @@ -31,6 +38,44 @@ impl<T, S> Bus<T, S> {
pub fn replace_ram(&mut self, ram: Vec<u8>) -> Vec<u8> {
std::mem::replace(&mut self.ram, ram)
}

/// Translates a physical address into a RAM offset, rejecting anything the guest
/// should not be able to reach. Stray accesses have to be reported to the guest as a
/// fault rather than taking the emulator down with it.
fn ram_offset(&self, addr: u32, size: u32) -> Option<usize> {
let offset = addr.checked_sub(RAM_START)? as usize;
(offset + size as usize <= self.ram.len()).then_some(offset)
}

fn dlab(&self) -> bool {
self.lcr & 0x80 != 0
}
}

const UART_RBR_THR: u32 = 0x0;
const UART_IER: u32 = 0x1;
const UART_LCR: u32 = 0x3;

impl<T, S: device_interfaces::SerialInterface> Bus<T, S> {
fn serial_read(&self, reg: u32) -> u8 {
match reg {
UART_RBR_THR if self.dlab() => self.divisor as u8,
UART_IER if self.dlab() => (self.divisor >> 8) as u8,
_ => self.serial.read(reg),
}
}

fn serial_write(&mut self, reg: u32, v: u8) {
match reg {
UART_RBR_THR if self.dlab() => self.divisor = (self.divisor & 0xff00) | v as u16,
UART_IER if self.dlab() => self.divisor = (self.divisor & 0x00ff) | ((v as u16) << 8),
UART_LCR => {
self.lcr = v;
self.serial.write(reg, v as u32);
}
_ => self.serial.write(reg, v as u32),
}
}
}

impl<T, S> BusController for Bus<T, S>
Expand Down Expand Up @@ -58,16 +103,15 @@ where
{
fn read8(&self, addr: u32) -> Result<u8, BusException> {
match addr {
0x1100bffc => Ok(self.clint.read(addr) as u8),
0x1100bff8 => Ok(self.clint.read(addr) as u8),
0x10000000..=0x100000ff => {
let addr = addr & 0xffff;
Ok(self.serial.read(addr))
}
0x1100bffc => Ok(self.clint.read(addr & 0xffff) as u8),
0x1100bff8 => Ok(self.clint.read(addr & 0xffff) as u8),
0x10000000..=0x100000ff => Ok(self.serial_read(addr & 0x7)),
0x10000100..=0x12000000 => Ok(0),
_ => {
let addr = addr.wrapping_sub(RAM_START);
Ok(self.ram[addr as usize])
let offset = self
.ram_offset(addr, 1)
.ok_or(BusException::LoadAccessFault)?;
Ok(self.ram[offset])
}
}
}
Expand All @@ -77,19 +121,15 @@ where
return Err(BusException::LoadAddressMisaligned);
}
match addr {
0x1100bffc => Ok(self.clint.read(addr) as u16),
0x1100bff8 => Ok(self.clint.read(addr) as u16),
0x10000000..=0x100000ff => {
let addr = addr & 0xffff;
Ok(self.serial.read(addr) as u16)
}
0x1100bffc => Ok(self.clint.read(addr & 0xffff) as u16),
0x1100bff8 => Ok(self.clint.read(addr & 0xffff) as u16),
0x10000000..=0x100000ff => Ok(self.serial_read(addr & 0x7) as u16),
0x10000100..=0x12000000 => Ok(0),
_ => {
let addr = addr.wrapping_sub(RAM_START);
Ok(u16::from_le_bytes([
self.ram[addr as usize],
self.ram[addr as usize + 1],
]))
let offset = self
.ram_offset(addr, 2)
.ok_or(BusException::LoadAccessFault)?;
Ok(u16::from_le_bytes([self.ram[offset], self.ram[offset + 1]]))
}
}
}
Expand All @@ -101,18 +141,17 @@ where
match addr {
0x1100bffc => Ok(self.clint.read(addr & 0xffff)),
0x1100bff8 => Ok(self.clint.read(addr & 0xffff)),
0x10000000..=0x100000ff => {
let addr = addr & 0xffff;
Ok(self.serial.read(addr) as u32)
}
0x10000000..=0x100000ff => Ok(self.serial_read(addr & 0x7) as u32),
0x10000100..=0x12000000 => Ok(0),
_ => {
let addr = addr.wrapping_sub(RAM_START);
let offset = self
.ram_offset(addr, 4)
.ok_or(BusException::LoadAccessFault)?;
Ok(u32::from_le_bytes([
self.ram[addr as usize],
self.ram[addr as usize + 1],
self.ram[addr as usize + 2],
self.ram[addr as usize + 3],
self.ram[offset],
self.ram[offset + 1],
self.ram[offset + 2],
self.ram[offset + 3],
]))
}
}
Expand All @@ -131,14 +170,13 @@ where
// mtime
0x11004004 => self.clint.write(addr & 0xffff, v as u32),
0x11004000 => self.clint.write(addr & 0xffff, v as u32),
0x10000000..=0x100000ff => {
let addr = addr & 0xffff;
self.serial.write(addr, v as u32);
}
0x10000000..=0x100000ff => self.serial_write(addr & 0x7, v),
0x10000100..=0x12000000 => {}
_ => {
let addr = addr.wrapping_sub(RAM_START);
self.ram[addr as usize] = v;
let offset = self
.ram_offset(addr, 1)
.ok_or(BusException::StoreAccessFault)?;
self.ram[offset] = v;
}
};
Ok(())
Expand All @@ -157,14 +195,13 @@ where
// mtime
0x11004004 => self.clint.write(addr & 0xffff, v as u32),
0x11004000 => self.clint.write(addr & 0xffff, v as u32),
0x10000000..=0x100000ff => {
let addr = addr & 0xffff;
self.serial.write(addr, v as u32);
}
0x10000000..=0x100000ff => self.serial_write(addr & 0x7, v as u8),
0x10000100..=0x12000000 => {}
_ => {
let addr = addr.wrapping_sub(RAM_START);
self.ram[addr as usize..addr as usize + 2].copy_from_slice(&v.to_le_bytes());
let offset = self
.ram_offset(addr, 2)
.ok_or(BusException::StoreAccessFault)?;
self.ram[offset..offset + 2].copy_from_slice(&v.to_le_bytes());
}
};
Ok(())
Expand All @@ -183,14 +220,13 @@ where
// mtime
0x11004004 => self.clint.write(addr & 0xffff, v),
0x11004000 => self.clint.write(addr & 0xffff, v),
0x10000000..=0x100000ff => {
let addr = addr & 0xffff;
self.serial.write(addr, v);
}
0x10000000..=0x100000ff => self.serial_write(addr & 0x7, v as u8),
0x10000100..=0x12000000 => {}
_ => {
let addr = addr.wrapping_sub(RAM_START);
self.ram[addr as usize..addr as usize + 4].copy_from_slice(&v.to_le_bytes());
let offset = self
.ram_offset(addr, 4)
.ok_or(BusException::StoreAccessFault)?;
self.ram[offset..offset + 4].copy_from_slice(&v.to_le_bytes());
}
};
Ok(())
Expand Down
46 changes: 28 additions & 18 deletions core/src/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,10 +243,17 @@ impl<B: BusController + BusWriter + BusReader> Cpu<B> {

self.cycle = self.cycle.wrapping_add(1);

let Ok(ir) = self.bus.read32(self.pc) else {
self.record_exception(Exception::InstructionAddressMisaligned, self.pc);
self.process_exception();
return CpuState::Active;
let ir = match self.bus.read32(self.pc) {
Ok(ir) => ir,
Err(e) => {
let e = match e {
BusException::LoadAddressMisaligned => Exception::InstructionAddressMisaligned,
_ => Exception::InstructionAccessFault,
};
self.record_exception(e, self.pc);
self.process_exception();
return CpuState::Active;
}
};

match ir & 0x7f {
Expand Down Expand Up @@ -289,7 +296,7 @@ impl<B: BusController + BusWriter + BusReader> Cpu<B> {
return CpuState::Active;
}

self.pc += 4;
self.pc = self.pc.wrapping_add(4);
self.process_exception();
CpuState::Active
}
Expand Down Expand Up @@ -337,7 +344,7 @@ impl<B: BusController + BusWriter + BusReader> Cpu<B> {
| ((ir & 0x00100000) >> 9)
| (ir & 0x000ff000);
let rel = if rel & 0x00100000 != 0 { rel | 0xffe00000 } else { rel } as i32;
let v = self.pc + 4;
let v = self.pc.wrapping_add(4);
self.pc = (self.pc as i64 + rel as i64 - 4) as u32;
self.write_back(rd, v);
}
Expand All @@ -346,7 +353,7 @@ impl<B: BusController + BusWriter + BusReader> Cpu<B> {
let rd = helpers::rd(ir);
let imm = ir >> 20;
let imm_s = imm | if (imm & 0x800) != 0 { 0xfffff000 } else { 0 };
let v = self.pc + 4;
let v = self.pc.wrapping_add(4);
let rs1 = self.x[helpers::rs1(ir)];
self.pc = (((rs1 as i64 + imm_s as i32 as i64) & !1) - 4) as u32;
self.write_back(rd, v)
Expand Down Expand Up @@ -387,23 +394,23 @@ impl<B: BusController + BusWriter + BusReader> Cpu<B> {
match (ir >> 12) & 0x7 {
// LB, LH, LW, LBU, LHU
0b000 => match self.bus.read8(rsval) {
Ok(v) => self.x[rd] = (v as i8) as u32,
Ok(v) => self.write_back(rd, (v as i8) as u32),
Err(e) => self.record_exception(e.into(), rsval),
},
0b001 => match self.bus.read16(rsval) {
Ok(v) => self.x[rd] = (v as i16) as u32,
Ok(v) => self.write_back(rd, (v as i16) as u32),
Err(e) => self.record_exception(e.into(), rsval),
},
0b010 => match self.bus.read32(rsval) {
Ok(v) => self.x[rd] = v,
Ok(v) => self.write_back(rd, v),
Err(e) => self.record_exception(e.into(), rsval),
},
0b100 => match self.bus.read8(rsval) {
Ok(v) => self.x[rd] = v as u32,
Ok(v) => self.write_back(rd, v as u32),
Err(e) => self.record_exception(e.into(), rsval),
},
0b101 => match self.bus.read16(rsval) {
Ok(v) => self.x[rd] = v as u32,
Ok(v) => self.write_back(rd, v as u32),
Err(e) => self.record_exception(e.into(), rsval),
},
_ => {
Expand Down Expand Up @@ -573,11 +580,14 @@ impl<B: BusController + BusWriter + BusReader> Cpu<B> {
0b001 => v = ((rs1 as i32 as i64).wrapping_mul(rs2 as i32 as i64) >> 32) as u32, // MULH
0b010 => v = ((rs1 as i32 as i64).wrapping_mul(rs2 as i64) >> 32) as u32, // MULHSU
0b011 => v = ((rs1 as u64).wrapping_mul(rs2 as u64) >> 32) as u32, // MULHU
0b100 => v = if rs2 == 0 { !0 } else { (rs1).wrapping_div(rs2) }, // DIV
0b100 => {
// DIV
v = if rs2 == 0 { !0 } else { (rs1 as i32).wrapping_div(rs2 as i32) as u32 }
}
0b101 => v = if rs2 == 0 { u32::MAX } else { rs1 / rs2 }, // DIVU
0b110 if rs2 == 0 => v = 0, // REM
0b110 if rs2 == 0 => v = 0, // REM
0b110 => v = (rs1 as i32).wrapping_rem(rs2 as i32) as u32, // REM
0b111 => v = if rs2 == 0 { rs1 } else { rs1 % rs2 }, // REMU
0b111 => v = if rs2 == 0 { rs1 } else { rs1 % rs2 }, // REMU
_ => {
self.record_exception(Exception::IllegalInstruction, ir);
}
Expand Down Expand Up @@ -673,14 +683,14 @@ impl<B: BusController + BusWriter + BusReader> Cpu<B> {
//WFI
self.mstatus |= 8;
self.wait_for_interrupt = true; //Inform environment we want to go to sleep.
self.pc += 4;
self.pc = self.pc.wrapping_add(4);
} else if (csr & 0xff) == 0x02 {
// MRET
let prev_mstatus = self.mstatus;
let prev_mode: u32 = self.previous_mode.into();
self.mstatus = ((prev_mstatus & 0x80) >> 4) | (prev_mode << 11) | 0x80;
self.previous_mode = PrivilegeMode::from(prev_mstatus >> 11);
self.pc = self.mepc - 4;
self.previous_mode = PrivilegeMode::from((prev_mstatus >> 11) & 0b11);
self.pc = self.mepc.wrapping_sub(4);
} else {
match csr {
0 if self.previous_mode != PrivilegeMode::User => {
Expand Down
Loading
Loading