almost got out-of-memory test working
Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
parent
4b2e4b0548
commit
abef5b7db3
16
Cargo.lock
generated
16
Cargo.lock
generated
@ -13,6 +13,14 @@ dependencies = [
|
|||||||
"scroll",
|
"scroll",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jurubas"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"goblin",
|
||||||
|
"riscv-cpu",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.20"
|
version = "0.4.20"
|
||||||
@ -47,14 +55,6 @@ dependencies = [
|
|||||||
name = "riscv-cpu"
|
name = "riscv-cpu"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rouns"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"goblin",
|
|
||||||
"riscv-cpu",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scroll"
|
name = "scroll"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
workspace = { members = ["crates/riscv-cpu"] }
|
workspace = { members = ["crates/riscv-cpu"] }
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "rouns"
|
name = "jurubas"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
riscv-cpu = { path = "crates/riscv-cpu" }
|
riscv-cpu = { path = "crates/riscv-cpu" }
|
||||||
goblin = { version = "0.7.1", features = [ "std", "elf32", "alloc" ]}
|
goblin = { version = "0.7.1", features = [ "std", "elf32", "alloc" ]}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use std::sync::{mpsc::Receiver, Arc, RwLock};
|
use std::sync::{mpsc::Receiver, Arc, Mutex};
|
||||||
|
|
||||||
pub use super::mmu::Memory;
|
pub use super::mmu::Memory;
|
||||||
use super::mmu::{AddressingMode, Mmu};
|
use super::mmu::{AddressingMode, Mmu};
|
||||||
@ -54,10 +54,12 @@ pub const MIP_SEIP: u64 = 0x200;
|
|||||||
const MIP_STIP: u64 = 0x020;
|
const MIP_STIP: u64 = 0x020;
|
||||||
const MIP_SSIP: u64 = 0x002;
|
const MIP_SSIP: u64 = 0x002;
|
||||||
|
|
||||||
|
pub type ResponseData = ([i64; 8], Option<(Vec<u8>, u64)>);
|
||||||
|
|
||||||
pub enum TickResult {
|
pub enum TickResult {
|
||||||
Ok,
|
Ok,
|
||||||
ExitThread(u64),
|
ExitThread(u64),
|
||||||
PauseEmulation(Receiver<([i64; 8], Option<(Vec<u8>, u64)>)>),
|
PauseEmulation(Receiver<ResponseData>),
|
||||||
CpuTrap(Trap),
|
CpuTrap(Trap),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,9 +76,8 @@ pub struct Cpu {
|
|||||||
pc: u64,
|
pc: u64,
|
||||||
csr: [u64; CSR_CAPACITY],
|
csr: [u64; CSR_CAPACITY],
|
||||||
mmu: Mmu,
|
mmu: Mmu,
|
||||||
memory: Arc<RwLock<dyn Memory + Send + Sync>>,
|
memory: Arc<Mutex<dyn Memory + Send + Sync>>,
|
||||||
reservation: u64, // @TODO: Should support multiple address reservations
|
reservation: Option<u64>, // @TODO: Should support multiple address reservations
|
||||||
is_reservation_set: bool,
|
|
||||||
_dump_flag: bool,
|
_dump_flag: bool,
|
||||||
// decode_cache: DecodeCache,
|
// decode_cache: DecodeCache,
|
||||||
unsigned_data_mask: u64,
|
unsigned_data_mask: u64,
|
||||||
@ -127,7 +128,7 @@ pub enum TrapType {
|
|||||||
UserExternalInterrupt,
|
UserExternalInterrupt,
|
||||||
SupervisorExternalInterrupt,
|
SupervisorExternalInterrupt,
|
||||||
MachineExternalInterrupt,
|
MachineExternalInterrupt,
|
||||||
PauseEmulation(std::sync::mpsc::Receiver<([i64; 8], Option<(Vec<u8>, u64)>)>),
|
PauseEmulation(Receiver<ResponseData>),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _get_privilege_mode_name(mode: &PrivilegeMode) -> &'static str {
|
fn _get_privilege_mode_name(mode: &PrivilegeMode) -> &'static str {
|
||||||
@ -225,11 +226,11 @@ pub struct CpuBuilder {
|
|||||||
xlen: Xlen,
|
xlen: Xlen,
|
||||||
pc: u64,
|
pc: u64,
|
||||||
sp: u64,
|
sp: u64,
|
||||||
memory: Arc<RwLock<dyn Memory + Send + Sync>>,
|
memory: Arc<Mutex<dyn Memory + Send + Sync>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CpuBuilder {
|
impl CpuBuilder {
|
||||||
pub fn new(memory: Arc<RwLock<dyn Memory + Send + Sync>>) -> Self {
|
pub fn new(memory: Arc<Mutex<dyn Memory + Send + Sync>>) -> Self {
|
||||||
CpuBuilder {
|
CpuBuilder {
|
||||||
xlen: Xlen::Bit64,
|
xlen: Xlen::Bit64,
|
||||||
memory,
|
memory,
|
||||||
@ -266,7 +267,7 @@ impl Cpu {
|
|||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `Terminal`
|
/// * `Terminal`
|
||||||
pub fn new(memory: Arc<RwLock<dyn Memory + Send + Sync>>) -> Self {
|
pub fn new(memory: Arc<Mutex<dyn Memory + Send + Sync>>) -> Self {
|
||||||
Cpu {
|
Cpu {
|
||||||
clock: 0,
|
clock: 0,
|
||||||
xlen: Xlen::Bit64,
|
xlen: Xlen::Bit64,
|
||||||
@ -277,8 +278,7 @@ impl Cpu {
|
|||||||
pc: 0,
|
pc: 0,
|
||||||
csr: [0; CSR_CAPACITY],
|
csr: [0; CSR_CAPACITY],
|
||||||
mmu: Mmu::new(Xlen::Bit64, memory.clone()),
|
mmu: Mmu::new(Xlen::Bit64, memory.clone()),
|
||||||
reservation: 0,
|
reservation: None,
|
||||||
is_reservation_set: false,
|
|
||||||
_dump_flag: false,
|
_dump_flag: false,
|
||||||
// decode_cache: DecodeCache::new(),
|
// decode_cache: DecodeCache::new(),
|
||||||
unsigned_data_mask: 0xffffffffffffffff,
|
unsigned_data_mask: 0xffffffffffffffff,
|
||||||
@ -563,11 +563,6 @@ impl Cpu {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_exception(&mut self, exception: Trap, instruction_address: u64) {
|
|
||||||
println!("!!! Exception Trap !!!: {:x?}", exception);
|
|
||||||
self.handle_trap(exception, instruction_address, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_trap(&mut self, trap: Trap, instruction_address: u64, is_interrupt: bool) -> bool {
|
fn handle_trap(&mut self, trap: Trap, instruction_address: u64, is_interrupt: bool) -> bool {
|
||||||
let current_privilege_encoding = get_privilege_encoding(&self.privilege_mode) as u64;
|
let current_privilege_encoding = get_privilege_encoding(&self.privilege_mode) as u64;
|
||||||
let cause = get_trap_cause(&trap, &self.xlen);
|
let cause = get_trap_cause(&trap, &self.xlen);
|
||||||
@ -2448,7 +2443,7 @@ const INSTRUCTIONS: [Instruction; INSTRUCTION_NUM] = [
|
|||||||
for (src, dest) in cpu.x[10..].iter().zip(args.iter_mut()) {
|
for (src, dest) in cpu.x[10..].iter().zip(args.iter_mut()) {
|
||||||
*dest = *src;
|
*dest = *src;
|
||||||
}
|
}
|
||||||
match cpu.memory.write().unwrap().syscall(args) {
|
match cpu.memory.lock().unwrap().syscall(args) {
|
||||||
super::mmu::SyscallResult::Ok(result) => {
|
super::mmu::SyscallResult::Ok(result) => {
|
||||||
for (src, dest) in result.iter().zip(cpu.x[10..].iter_mut()) {
|
for (src, dest) in result.iter().zip(cpu.x[10..].iter_mut()) {
|
||||||
*dest = *src;
|
*dest = *src;
|
||||||
@ -2938,14 +2933,11 @@ const INSTRUCTIONS: [Instruction; INSTRUCTION_NUM] = [
|
|||||||
operation: |cpu, word, _address| {
|
operation: |cpu, word, _address| {
|
||||||
let f = parse_format_r(word);
|
let f = parse_format_r(word);
|
||||||
// @TODO: Implement properly
|
// @TODO: Implement properly
|
||||||
cpu.x[f.rd] = match cpu.mmu.load_doubleword(cpu.x[f.rs1] as u64) {
|
let address = cpu.x[f.rs1] as u64;
|
||||||
Ok(data) => {
|
cpu.x[f.rd] = cpu.mmu.load_doubleword(address)? as i64;
|
||||||
cpu.is_reservation_set = true;
|
if cpu.mmu.reserve(address) {
|
||||||
cpu.reservation = cpu.x[f.rs1] as u64; // Is virtual address ok?
|
cpu.reservation = Some(address);
|
||||||
data as i64
|
|
||||||
}
|
}
|
||||||
Err(e) => return Err(e),
|
|
||||||
};
|
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
disassemble: dump_format_r,
|
disassemble: dump_format_r,
|
||||||
@ -2957,14 +2949,11 @@ const INSTRUCTIONS: [Instruction; INSTRUCTION_NUM] = [
|
|||||||
operation: |cpu, word, _address| {
|
operation: |cpu, word, _address| {
|
||||||
let f = parse_format_r(word);
|
let f = parse_format_r(word);
|
||||||
// @TODO: Implement properly
|
// @TODO: Implement properly
|
||||||
cpu.x[f.rd] = match cpu.mmu.load_word(cpu.x[f.rs1] as u64) {
|
let address = cpu.x[f.rs1] as u64;
|
||||||
Ok(data) => {
|
cpu.x[f.rd] = cpu.mmu.load_word(address)? as i64;
|
||||||
cpu.is_reservation_set = true;
|
if cpu.mmu.reserve(address) {
|
||||||
cpu.reservation = cpu.x[f.rs1] as u64; // Is virtual address ok?
|
cpu.reservation = Some(address);
|
||||||
data as i32 as i64
|
|
||||||
}
|
}
|
||||||
Err(e) => return Err(e),
|
|
||||||
};
|
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
disassemble: dump_format_r,
|
disassemble: dump_format_r,
|
||||||
@ -3223,19 +3212,14 @@ const INSTRUCTIONS: [Instruction; INSTRUCTION_NUM] = [
|
|||||||
operation: |cpu, word, _address| {
|
operation: |cpu, word, _address| {
|
||||||
let f = parse_format_r(word);
|
let f = parse_format_r(word);
|
||||||
// @TODO: Implement properly
|
// @TODO: Implement properly
|
||||||
cpu.x[f.rd] = match cpu.is_reservation_set && cpu.reservation == (cpu.x[f.rs1] as u64) {
|
let address = cpu.x[f.rs1] as u64;
|
||||||
true => match cpu
|
if Some(address) == cpu.reservation.take() {
|
||||||
.mmu
|
cpu.mmu.store_doubleword(address, cpu.x[f.rs2] as u64)?;
|
||||||
.store_doubleword(cpu.x[f.rs1] as u64, cpu.x[f.rs2] as u64)
|
cpu.mmu.clear_reservation(address);
|
||||||
{
|
cpu.x[f.rd] = 0;
|
||||||
Ok(()) => {
|
return Ok(());
|
||||||
cpu.is_reservation_set = false;
|
|
||||||
0
|
|
||||||
}
|
}
|
||||||
Err(e) => return Err(e),
|
cpu.x[f.rd] = 1;
|
||||||
},
|
|
||||||
false => 1,
|
|
||||||
};
|
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
disassemble: dump_format_r,
|
disassemble: dump_format_r,
|
||||||
@ -3247,16 +3231,14 @@ const INSTRUCTIONS: [Instruction; INSTRUCTION_NUM] = [
|
|||||||
operation: |cpu, word, _address| {
|
operation: |cpu, word, _address| {
|
||||||
let f = parse_format_r(word);
|
let f = parse_format_r(word);
|
||||||
// @TODO: Implement properly
|
// @TODO: Implement properly
|
||||||
cpu.x[f.rd] = match cpu.is_reservation_set && cpu.reservation == (cpu.x[f.rs1] as u64) {
|
let address = cpu.x[f.rs1] as u64;
|
||||||
true => match cpu.mmu.store_word(cpu.x[f.rs1] as u64, cpu.x[f.rs2] as u32) {
|
if Some(address) == cpu.reservation.take() {
|
||||||
Ok(()) => {
|
cpu.mmu.clear_reservation(address);
|
||||||
cpu.is_reservation_set = false;
|
cpu.mmu.store_word(address, cpu.x[f.rs2] as u32)?;
|
||||||
0
|
cpu.x[f.rd] = 0;
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
Err(e) => return Err(e),
|
cpu.x[f.rd] = 1;
|
||||||
},
|
|
||||||
false => 1,
|
|
||||||
};
|
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
disassemble: dump_format_r,
|
disassemble: dump_format_r,
|
||||||
@ -4144,77 +4126,3 @@ mod test_cpu {
|
|||||||
assert_eq!(memory_base, cpu.read_pc());
|
assert_eq!(memory_base, cpu.read_pc());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
|
|
||||||
mod test_decode_cache {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn initialize() {
|
|
||||||
let _cache = DecodeCache::new();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn insert() {
|
|
||||||
let mut cache = DecodeCache::new();
|
|
||||||
cache.insert(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn get() {
|
|
||||||
let mut cache = DecodeCache::new();
|
|
||||||
cache.insert(1, 2);
|
|
||||||
|
|
||||||
// Cache hit test
|
|
||||||
match cache.get(1) {
|
|
||||||
Some(index) => assert_eq!(2, index),
|
|
||||||
None => panic!("Unexpected cache miss"),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Cache miss test
|
|
||||||
match cache.get(2) {
|
|
||||||
Some(_index) => panic!("Unexpected cache hit"),
|
|
||||||
None => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn lru() {
|
|
||||||
let mut cache = DecodeCache::new();
|
|
||||||
cache.insert(0, 1);
|
|
||||||
|
|
||||||
match cache.get(0) {
|
|
||||||
Some(index) => assert_eq!(1, index),
|
|
||||||
None => panic!("Unexpected cache miss"),
|
|
||||||
};
|
|
||||||
|
|
||||||
for i in 1..DECODE_CACHE_ENTRY_NUM + 1 {
|
|
||||||
cache.insert(i as u32, i + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The oldest entry should have been removed because of the overflow
|
|
||||||
match cache.get(0) {
|
|
||||||
Some(_index) => panic!("Unexpected cache hit"),
|
|
||||||
None => {}
|
|
||||||
};
|
|
||||||
|
|
||||||
// With this .get(), the entry with the word "1" moves to the tail of the list
|
|
||||||
// and the entry with the word "2" becomes the oldest entry.
|
|
||||||
match cache.get(1) {
|
|
||||||
Some(index) => assert_eq!(2, index),
|
|
||||||
None => {}
|
|
||||||
};
|
|
||||||
|
|
||||||
// The oldest entry with the word "2" will be removed due to the overflow
|
|
||||||
cache.insert(
|
|
||||||
DECODE_CACHE_ENTRY_NUM as u32 + 1,
|
|
||||||
DECODE_CACHE_ENTRY_NUM + 2,
|
|
||||||
);
|
|
||||||
|
|
||||||
match cache.get(2) {
|
|
||||||
Some(_index) => panic!("Unexpected cache hit"),
|
|
||||||
None => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
pub mod cpu;
|
pub mod cpu;
|
||||||
pub mod memory;
|
|
||||||
pub mod mmu;
|
pub mod mmu;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub mod memory;
|
||||||
|
|
||||||
pub use cpu::{Cpu, CpuBuilder, Xlen};
|
pub use cpu::{Cpu, CpuBuilder, Xlen};
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
/// Emulates main memory.
|
/// Emulates main memory.
|
||||||
pub struct Memory {
|
pub struct Memory { /// Memory content
|
||||||
/// Memory content
|
|
||||||
data: Vec<u64>,
|
data: Vec<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
sync::mpsc::Receiver,
|
||||||
sync::{Arc, RwLock},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::cpu::{decode_privilege_mode, PrivilegeMode, Trap, TrapType, Xlen};
|
use crate::cpu::{decode_privilege_mode, PrivilegeMode, ResponseData, Trap, TrapType, Xlen};
|
||||||
|
|
||||||
pub enum SyscallResult {
|
pub enum SyscallResult {
|
||||||
Ok([i64; 8]),
|
Ok([i64; 8]),
|
||||||
Defer(std::sync::mpsc::Receiver<([i64; 8], Option<(Vec<u8>, u64)>)>),
|
Defer(Receiver<ResponseData>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<[i64; 8]> for SyscallResult {
|
impl From<[i64; 8]> for SyscallResult {
|
||||||
@ -16,8 +16,8 @@ impl From<[i64; 8]> for SyscallResult {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<std::sync::mpsc::Receiver<([i64; 8], Option<(Vec<u8>, u64)>)>> for SyscallResult {
|
impl From<std::sync::mpsc::Receiver<ResponseData>> for SyscallResult {
|
||||||
fn from(receiver: std::sync::mpsc::Receiver<([i64; 8], Option<(Vec<u8>, u64)>)>) -> Self {
|
fn from(receiver: std::sync::mpsc::Receiver<ResponseData>) -> Self {
|
||||||
SyscallResult::Defer(receiver)
|
SyscallResult::Defer(receiver)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -33,6 +33,9 @@ pub trait Memory {
|
|||||||
fn write_u64(&mut self, p_address: u64, value: u64);
|
fn write_u64(&mut self, p_address: u64, value: u64);
|
||||||
fn validate_address(&self, address: u64) -> bool;
|
fn validate_address(&self, address: u64) -> bool;
|
||||||
fn syscall(&mut self, args: [i64; 8]) -> SyscallResult;
|
fn syscall(&mut self, args: [i64; 8]) -> SyscallResult;
|
||||||
|
fn translate(&self, v_address: u64) -> Option<u64>;
|
||||||
|
fn reserve(&mut self, p_address: u64) -> bool;
|
||||||
|
fn clear_reservation(&mut self, p_address: u64);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emulates Memory Management Unit. It holds the Main memory and peripheral
|
/// Emulates Memory Management Unit. It holds the Main memory and peripheral
|
||||||
@ -46,29 +49,13 @@ pub struct Mmu {
|
|||||||
ppn: u64,
|
ppn: u64,
|
||||||
addressing_mode: AddressingMode,
|
addressing_mode: AddressingMode,
|
||||||
privilege_mode: PrivilegeMode,
|
privilege_mode: PrivilegeMode,
|
||||||
memory: Arc<RwLock<dyn Memory + Send + Sync>>,
|
memory: Arc<Mutex<dyn Memory + Send + Sync>>,
|
||||||
|
|
||||||
// /// The size of main memory (if initialized)
|
// /// The size of main memory (if initialized)
|
||||||
// memory_length: Option<NonZeroU64>,
|
// memory_length: Option<NonZeroU64>,
|
||||||
/// Address translation can be affected `mstatus` (MPRV, MPP in machine mode)
|
/// Address translation can be affected `mstatus` (MPRV, MPP in machine mode)
|
||||||
/// then `Mmu` has copy of it.
|
/// then `Mmu` has copy of it.
|
||||||
mstatus: u64,
|
mstatus: u64,
|
||||||
|
|
||||||
/// Address translation page cache. Experimental feature.
|
|
||||||
/// The cache is cleared when translation mapping can be changed;
|
|
||||||
/// xlen, ppn, privilege_mode, or addressing_mode is updated.
|
|
||||||
/// Precisely it isn't good enough because page table entries
|
|
||||||
/// can be updated anytime with store instructions, of course
|
|
||||||
/// very depending on how pages are mapped tho.
|
|
||||||
/// But observing all page table entries is high cost so
|
|
||||||
/// ignoring so far. Then this cache optimization can cause a bug
|
|
||||||
/// due to unexpected (meaning not in page fault handler)
|
|
||||||
/// page table entry update. So this is experimental feature and
|
|
||||||
/// disabled by default. If you want to enable, use `enable_page_cache()`.
|
|
||||||
page_cache_enabled: bool,
|
|
||||||
fetch_page_cache: HashMap<u64, u64>,
|
|
||||||
load_page_cache: HashMap<u64, u64>,
|
|
||||||
store_page_cache: HashMap<u64, u64>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -100,7 +87,7 @@ impl Mmu {
|
|||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `xlen`
|
/// * `xlen`
|
||||||
pub fn new(xlen: Xlen, memory: Arc<RwLock<dyn Memory + Send + Sync>>) -> Self {
|
pub fn new(xlen: Xlen, memory: Arc<Mutex<dyn Memory + Send + Sync>>) -> Self {
|
||||||
Mmu {
|
Mmu {
|
||||||
// clock: 0,
|
// clock: 0,
|
||||||
xlen,
|
xlen,
|
||||||
@ -109,10 +96,6 @@ impl Mmu {
|
|||||||
privilege_mode: PrivilegeMode::Machine,
|
privilege_mode: PrivilegeMode::Machine,
|
||||||
memory,
|
memory,
|
||||||
mstatus: 0,
|
mstatus: 0,
|
||||||
page_cache_enabled: false,
|
|
||||||
fetch_page_cache: HashMap::default(),
|
|
||||||
load_page_cache: HashMap::default(),
|
|
||||||
store_page_cache: HashMap::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,37 +105,6 @@ impl Mmu {
|
|||||||
/// * `xlen`
|
/// * `xlen`
|
||||||
pub fn update_xlen(&mut self, xlen: Xlen) {
|
pub fn update_xlen(&mut self, xlen: Xlen) {
|
||||||
self.xlen = xlen;
|
self.xlen = xlen;
|
||||||
self.clear_page_cache();
|
|
||||||
}
|
|
||||||
|
|
||||||
// /// Initializes Main memory. This method is expected to be called only once.
|
|
||||||
// ///
|
|
||||||
// /// # Arguments
|
|
||||||
// /// * `capacity`
|
|
||||||
// pub fn init_memory(&mut self, capacity: u64) {
|
|
||||||
// assert!(self.memory_length.is_none());
|
|
||||||
// self.memory_length = Some(NonZeroU64::new(capacity).unwrap());
|
|
||||||
// self.memory.init(capacity);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub fn memory_size(&self) -> u64 {
|
|
||||||
// self.memory_length.unwrap().get()
|
|
||||||
// }
|
|
||||||
|
|
||||||
/// Enables or disables page cache optimization.
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
/// * `enabled`
|
|
||||||
pub fn enable_page_cache(&mut self, enabled: bool) {
|
|
||||||
self.page_cache_enabled = enabled;
|
|
||||||
self.clear_page_cache();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clears page cache entries
|
|
||||||
fn clear_page_cache(&mut self) {
|
|
||||||
self.fetch_page_cache.clear();
|
|
||||||
self.load_page_cache.clear();
|
|
||||||
self.store_page_cache.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runs one cycle of MMU and peripheral devices.
|
/// Runs one cycle of MMU and peripheral devices.
|
||||||
@ -164,7 +116,6 @@ impl Mmu {
|
|||||||
/// * `new_addressing_mode`
|
/// * `new_addressing_mode`
|
||||||
pub fn update_addressing_mode(&mut self, new_addressing_mode: AddressingMode) {
|
pub fn update_addressing_mode(&mut self, new_addressing_mode: AddressingMode) {
|
||||||
self.addressing_mode = new_addressing_mode;
|
self.addressing_mode = new_addressing_mode;
|
||||||
self.clear_page_cache();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates privilege mode
|
/// Updates privilege mode
|
||||||
@ -173,7 +124,6 @@ impl Mmu {
|
|||||||
/// * `mode`
|
/// * `mode`
|
||||||
pub fn update_privilege_mode(&mut self, mode: PrivilegeMode) {
|
pub fn update_privilege_mode(&mut self, mode: PrivilegeMode) {
|
||||||
self.privilege_mode = mode;
|
self.privilege_mode = mode;
|
||||||
self.clear_page_cache();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates mstatus copy. `CPU` needs to call this method whenever
|
/// Updates mstatus copy. `CPU` needs to call this method whenever
|
||||||
@ -191,7 +141,6 @@ impl Mmu {
|
|||||||
/// * `ppn`
|
/// * `ppn`
|
||||||
pub fn update_ppn(&mut self, ppn: u64) {
|
pub fn update_ppn(&mut self, ppn: u64) {
|
||||||
self.ppn = ppn;
|
self.ppn = ppn;
|
||||||
self.clear_page_cache();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trim_to_xlen(&self, address: u64) -> u64 {
|
fn trim_to_xlen(&self, address: u64) -> u64 {
|
||||||
@ -426,7 +375,7 @@ impl Mmu {
|
|||||||
/// * `p_address` Physical address
|
/// * `p_address` Physical address
|
||||||
pub(crate) fn load_raw(&self, p_address: u64) -> u8 {
|
pub(crate) fn load_raw(&self, p_address: u64) -> u8 {
|
||||||
self.memory
|
self.memory
|
||||||
.read()
|
.lock() // .read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.read_u8(self.trim_to_xlen(p_address))
|
.read_u8(self.trim_to_xlen(p_address))
|
||||||
}
|
}
|
||||||
@ -438,7 +387,7 @@ impl Mmu {
|
|||||||
/// * `p_address` Physical address
|
/// * `p_address` Physical address
|
||||||
fn load_halfword_raw(&self, p_address: u64) -> u16 {
|
fn load_halfword_raw(&self, p_address: u64) -> u16 {
|
||||||
self.memory
|
self.memory
|
||||||
.read()
|
.lock() // .read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.read_u16(self.trim_to_xlen(p_address))
|
.read_u16(self.trim_to_xlen(p_address))
|
||||||
}
|
}
|
||||||
@ -450,7 +399,7 @@ impl Mmu {
|
|||||||
/// * `p_address` Physical address
|
/// * `p_address` Physical address
|
||||||
pub fn load_word_raw(&self, p_address: u64) -> u32 {
|
pub fn load_word_raw(&self, p_address: u64) -> u32 {
|
||||||
self.memory
|
self.memory
|
||||||
.read()
|
.lock() // .read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.read_u32(self.trim_to_xlen(p_address))
|
.read_u32(self.trim_to_xlen(p_address))
|
||||||
}
|
}
|
||||||
@ -462,7 +411,7 @@ impl Mmu {
|
|||||||
/// * `p_address` Physical address
|
/// * `p_address` Physical address
|
||||||
fn load_doubleword_raw(&self, p_address: u64) -> u64 {
|
fn load_doubleword_raw(&self, p_address: u64) -> u64 {
|
||||||
self.memory
|
self.memory
|
||||||
.read()
|
.lock() // .read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.read_u64(self.trim_to_xlen(p_address))
|
.read_u64(self.trim_to_xlen(p_address))
|
||||||
}
|
}
|
||||||
@ -475,7 +424,7 @@ impl Mmu {
|
|||||||
/// * `value` data written
|
/// * `value` data written
|
||||||
pub(crate) fn store_raw(&self, p_address: u64, value: u8) {
|
pub(crate) fn store_raw(&self, p_address: u64, value: u8) {
|
||||||
self.memory
|
self.memory
|
||||||
.write()
|
.lock() // .write()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.write_u8(self.trim_to_xlen(p_address), value)
|
.write_u8(self.trim_to_xlen(p_address), value)
|
||||||
}
|
}
|
||||||
@ -488,7 +437,7 @@ impl Mmu {
|
|||||||
/// * `value` data written
|
/// * `value` data written
|
||||||
pub(crate) fn store_halfword_raw(&self, p_address: u64, value: u16) {
|
pub(crate) fn store_halfword_raw(&self, p_address: u64, value: u16) {
|
||||||
self.memory
|
self.memory
|
||||||
.write()
|
.lock() // .write()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.write_u16(self.trim_to_xlen(p_address), value)
|
.write_u16(self.trim_to_xlen(p_address), value)
|
||||||
}
|
}
|
||||||
@ -501,7 +450,7 @@ impl Mmu {
|
|||||||
/// * `value` data written
|
/// * `value` data written
|
||||||
pub(crate) fn store_word_raw(&self, p_address: u64, value: u32) {
|
pub(crate) fn store_word_raw(&self, p_address: u64, value: u32) {
|
||||||
self.memory
|
self.memory
|
||||||
.write()
|
.lock() // .write()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.write_u32(self.trim_to_xlen(p_address), value)
|
.write_u32(self.trim_to_xlen(p_address), value)
|
||||||
}
|
}
|
||||||
@ -514,7 +463,7 @@ impl Mmu {
|
|||||||
/// * `value` data written
|
/// * `value` data written
|
||||||
fn store_doubleword_raw(&self, p_address: u64, value: u64) {
|
fn store_doubleword_raw(&self, p_address: u64, value: u64) {
|
||||||
self.memory
|
self.memory
|
||||||
.write()
|
.lock() // .write()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.write_u64(self.trim_to_xlen(p_address), value)
|
.write_u64(self.trim_to_xlen(p_address), value)
|
||||||
}
|
}
|
||||||
@ -529,14 +478,38 @@ impl Mmu {
|
|||||||
.ok()
|
.ok()
|
||||||
.map(|p_address| {
|
.map(|p_address| {
|
||||||
self.memory
|
self.memory
|
||||||
.write()
|
.lock() // .read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.validate_address(self.trim_to_xlen(p_address))
|
.validate_address(self.trim_to_xlen(p_address))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn reserve(&mut self, p_address: u64) -> bool {
|
||||||
|
self.memory
|
||||||
|
.lock() // .write()
|
||||||
|
.unwrap()
|
||||||
|
.reserve(self.trim_to_xlen(p_address))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_reservation(&mut self, p_address: u64) {
|
||||||
|
self.memory
|
||||||
|
.lock() // .write()
|
||||||
|
.unwrap()
|
||||||
|
.clear_reservation(self.trim_to_xlen(p_address))
|
||||||
|
}
|
||||||
|
|
||||||
fn translate_address(&self, v_address: u64, access_type: &MemoryAccessType) -> Result<u64, ()> {
|
fn translate_address(&self, v_address: u64, access_type: &MemoryAccessType) -> Result<u64, ()> {
|
||||||
self.translate_address_with_privilege_mode(v_address, access_type, self.privilege_mode)
|
if let AddressingMode::None = self.addressing_mode {
|
||||||
|
Ok(v_address)
|
||||||
|
} else {
|
||||||
|
// self.memory.lock() // .read().unwrap().translate(v_address).ok_or(())
|
||||||
|
let phys = self.translate_address_with_privilege_mode(
|
||||||
|
v_address,
|
||||||
|
access_type,
|
||||||
|
self.privilege_mode,
|
||||||
|
)?;
|
||||||
|
Ok(phys)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn translate_address_with_privilege_mode(
|
fn translate_address_with_privilege_mode(
|
||||||
@ -546,18 +519,6 @@ impl Mmu {
|
|||||||
privilege_mode: PrivilegeMode,
|
privilege_mode: PrivilegeMode,
|
||||||
) -> Result<u64, ()> {
|
) -> Result<u64, ()> {
|
||||||
let address = self.trim_to_xlen(v_address);
|
let address = self.trim_to_xlen(v_address);
|
||||||
let v_page = address & !0xfff;
|
|
||||||
if let Some(p_page) = match self.page_cache_enabled {
|
|
||||||
true => match access_type {
|
|
||||||
MemoryAccessType::Execute => self.fetch_page_cache.get(&v_page),
|
|
||||||
MemoryAccessType::Read => self.load_page_cache.get(&v_page),
|
|
||||||
MemoryAccessType::Write => self.store_page_cache.get(&v_page),
|
|
||||||
MemoryAccessType::DontCare => None,
|
|
||||||
},
|
|
||||||
false => None,
|
|
||||||
} {
|
|
||||||
return Ok(p_page | (address & 0xfff));
|
|
||||||
}
|
|
||||||
|
|
||||||
match self.addressing_mode {
|
match self.addressing_mode {
|
||||||
AddressingMode::None => Ok(address),
|
AddressingMode::None => Ok(address),
|
||||||
@ -618,24 +579,6 @@ impl Mmu {
|
|||||||
panic!("AddressingMode SV48 is not supported yet.");
|
panic!("AddressingMode SV48 is not supported yet.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if self.page_cache_enabled {
|
|
||||||
// match p_address {
|
|
||||||
// Ok(p_address) => {
|
|
||||||
// let p_page = p_address & !0xfff;
|
|
||||||
// match access_type {
|
|
||||||
// MemoryAccessType::Execute => self.fetch_page_cache.insert(v_page, p_page),
|
|
||||||
// MemoryAccessType::Read => self.load_page_cache.insert(v_page, p_page),
|
|
||||||
// MemoryAccessType::Write => self.store_page_cache.insert(v_page, p_page),
|
|
||||||
// MemoryAccessType::DontCare => None,
|
|
||||||
// };
|
|
||||||
// Ok(p_address)
|
|
||||||
// }
|
|
||||||
// Err(()) => Err(()),
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// p_address
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn traverse_page(
|
fn traverse_page(
|
||||||
@ -766,99 +709,3 @@ impl Mmu {
|
|||||||
Ok(p_address)
|
Ok(p_address)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub struct MemoryWrapper {
|
|
||||||
// memory: Memory,
|
|
||||||
// dram_base: u64,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// impl MemoryWrapper {
|
|
||||||
// fn new(dram_base: u64) -> Self {
|
|
||||||
// MemoryWrapper {
|
|
||||||
// memory: Memory::new(),
|
|
||||||
// dram_base,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fn init(&mut self, capacity: u64) {
|
|
||||||
// self.memory.init(capacity);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub fn read_byte(&self, p_address: u64) -> u8 {
|
|
||||||
// debug_assert!(
|
|
||||||
// p_address >= self.dram_base,
|
|
||||||
// "Memory address must equals to or bigger than self.dram_base. {:X}",
|
|
||||||
// p_address
|
|
||||||
// );
|
|
||||||
// self.memory.read_byte(p_address - self.dram_base)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub fn read_halfword(&self, p_address: u64) -> u16 {
|
|
||||||
// debug_assert!(
|
|
||||||
// p_address >= self.dram_base && p_address.wrapping_add(1) >= self.dram_base,
|
|
||||||
// "Memory address must equals to or bigger than self.dram_base. {:X}",
|
|
||||||
// p_address
|
|
||||||
// );
|
|
||||||
// self.memory.read_halfword(p_address - self.dram_base)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub fn read_word(&self, p_address: u64) -> u32 {
|
|
||||||
// debug_assert!(
|
|
||||||
// p_address >= self.dram_base && p_address.wrapping_add(3) >= self.dram_base,
|
|
||||||
// "Memory address must equals to or bigger than self.dram_base. {:X}",
|
|
||||||
// p_address
|
|
||||||
// );
|
|
||||||
// self.memory.read_word(p_address - self.dram_base)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub fn read_doubleword(&self, p_address: u64) -> u64 {
|
|
||||||
// debug_assert!(
|
|
||||||
// p_address >= self.dram_base && p_address.wrapping_add(7) >= self.dram_base,
|
|
||||||
// "Memory address must equals to or bigger than self.dram_base. {:X}",
|
|
||||||
// p_address
|
|
||||||
// );
|
|
||||||
// self.memory.read_doubleword(p_address - self.dram_base)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub fn write_byte(&mut self, p_address: u64, value: u8) {
|
|
||||||
// debug_assert!(
|
|
||||||
// p_address >= self.dram_base,
|
|
||||||
// "Memory address must equals to or bigger than self.dram_base. {:X}",
|
|
||||||
// p_address
|
|
||||||
// );
|
|
||||||
// self.memory.write_byte(p_address - self.dram_base, value)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub fn write_halfword(&mut self, p_address: u64, value: u16) {
|
|
||||||
// debug_assert!(
|
|
||||||
// p_address >= self.dram_base && p_address.wrapping_add(1) >= self.dram_base,
|
|
||||||
// "Memory address must equals to or bigger than self.dram_base. {:X}",
|
|
||||||
// p_address
|
|
||||||
// );
|
|
||||||
// self.memory
|
|
||||||
// .write_halfword(p_address - self.dram_base, value)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub fn write_word(&mut self, p_address: u64, value: u32) {
|
|
||||||
// debug_assert!(
|
|
||||||
// p_address >= self.dram_base && p_address.wrapping_add(3) >= self.dram_base,
|
|
||||||
// "Memory address must equals to or bigger than self.dram_base. {:X}",
|
|
||||||
// p_address
|
|
||||||
// );
|
|
||||||
// self.memory.write_word(p_address - self.dram_base, value)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub fn write_doubleword(&mut self, p_address: u64, value: u64) {
|
|
||||||
// debug_assert!(
|
|
||||||
// p_address >= self.dram_base && p_address.wrapping_add(7) >= self.dram_base,
|
|
||||||
// "Memory address must equals to or bigger than self.dram_base. {:X}",
|
|
||||||
// p_address
|
|
||||||
// );
|
|
||||||
// self.memory
|
|
||||||
// .write_doubleword(p_address - self.dram_base, value)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub fn validate_address(&self, address: u64) -> bool {
|
|
||||||
// self.memory.validate_address(address - self.dram_base)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
337
src/xous.rs
337
src/xous.rs
@ -8,11 +8,17 @@ use std::{
|
|||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicI64, Ordering},
|
atomic::{AtomicI64, Ordering},
|
||||||
mpsc::{Receiver, Sender},
|
mpsc::{Receiver, Sender},
|
||||||
Arc, RwLock,
|
Arc, Mutex,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::xous::definitions::SyscallErrorNumber;
|
||||||
|
|
||||||
const MEMORY_BASE: u32 = 0x8000_0000;
|
const MEMORY_BASE: u32 = 0x8000_0000;
|
||||||
|
const ALLOCATION_START: u32 = 0x4000_0000;
|
||||||
|
const ALLOCATION_END: u32 = ALLOCATION_START + 5 * 1024 * 1024;
|
||||||
|
const HEAP_START: u32 = 0xa000_0000;
|
||||||
|
const HEAP_END: u32 = HEAP_START + 5 * 1024 * 1024;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum LoadError {
|
pub enum LoadError {
|
||||||
@ -45,6 +51,7 @@ const MMUFLAG_ACCESSED: u32 = 0x40;
|
|||||||
const MMUFLAG_DIRTY: u32 = 0x80;
|
const MMUFLAG_DIRTY: u32 = 0x80;
|
||||||
|
|
||||||
impl std::error::Error for LoadError {}
|
impl std::error::Error for LoadError {}
|
||||||
|
pub type ResponseData = ([i64; 8], Option<(Vec<u8>, u64)>);
|
||||||
|
|
||||||
enum MemoryCommand {
|
enum MemoryCommand {
|
||||||
Exit,
|
Exit,
|
||||||
@ -59,30 +66,14 @@ enum MemoryCommand {
|
|||||||
u32, /* argument 4 */
|
u32, /* argument 4 */
|
||||||
Sender<i64>, /* Thread ID */
|
Sender<i64>, /* Thread ID */
|
||||||
),
|
),
|
||||||
JoinThread(u32, Sender<([i64; 8], Option<(Vec<u8>, u64)>)>),
|
JoinThread(u32, Sender<ResponseData>),
|
||||||
}
|
|
||||||
|
|
||||||
struct Memory {
|
|
||||||
base: u32,
|
|
||||||
data: HashMap<usize, [u8; 4096]>,
|
|
||||||
allocated_pages: BTreeSet<usize>,
|
|
||||||
free_pages: BTreeSet<usize>,
|
|
||||||
heap_start: u32,
|
|
||||||
heap_size: u32,
|
|
||||||
// allocation_start: u32,
|
|
||||||
allocation_previous: u32,
|
|
||||||
l1_pt: u32,
|
|
||||||
satp: u32,
|
|
||||||
connections: HashMap<u32, Box<dyn services::Service + Send + Sync>>,
|
|
||||||
memory_cmd: Sender<MemoryCommand>,
|
|
||||||
turbo: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Worker {
|
struct Worker {
|
||||||
cpu: riscv_cpu::Cpu,
|
cpu: riscv_cpu::Cpu,
|
||||||
cmd: Sender<MemoryCommand>,
|
cmd: Sender<MemoryCommand>,
|
||||||
tid: i64,
|
tid: i64,
|
||||||
memory: Arc<RwLock<Memory>>,
|
memory: Arc<Mutex<Memory>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Worker {
|
impl Worker {
|
||||||
@ -90,7 +81,7 @@ impl Worker {
|
|||||||
cpu: riscv_cpu::Cpu,
|
cpu: riscv_cpu::Cpu,
|
||||||
cmd: Sender<MemoryCommand>,
|
cmd: Sender<MemoryCommand>,
|
||||||
tid: i64,
|
tid: i64,
|
||||||
memory: Arc<RwLock<Memory>>,
|
memory: Arc<Mutex<Memory>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
cpu,
|
cpu,
|
||||||
@ -126,7 +117,7 @@ impl Worker {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
TickResult::CpuTrap(trap) => {
|
TickResult::CpuTrap(trap) => {
|
||||||
self.memory.read().unwrap().print_mmu();
|
self.memory.lock().unwrap().print_mmu();
|
||||||
// called `Result::unwrap()` on an `Err` value: "Valid bit is 0, or read is 0 and write is 1 at 40002fec: 000802e6"
|
// called `Result::unwrap()` on an `Err` value: "Valid bit is 0, or read is 0 and write is 1 at 40002fec: 000802e6"
|
||||||
println!(
|
println!(
|
||||||
"CPU trap at PC {:08x}, exiting thread {}: {:x?}",
|
"CPU trap at PC {:08x}, exiting thread {}: {:x?}",
|
||||||
@ -149,18 +140,39 @@ struct WorkerHandle {
|
|||||||
joiner: std::thread::JoinHandle<()>,
|
joiner: std::thread::JoinHandle<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Memory {
|
||||||
|
base: u32,
|
||||||
|
data: HashMap<usize, [u8; 4096]>,
|
||||||
|
allocated_pages: BTreeSet<usize>,
|
||||||
|
free_pages: BTreeSet<usize>,
|
||||||
|
heap_start: u32,
|
||||||
|
heap_size: u32,
|
||||||
|
// allocation_start: u32,
|
||||||
|
allocation_previous: u32,
|
||||||
|
l1_pt: u32,
|
||||||
|
satp: u32,
|
||||||
|
connections: HashMap<u32, Box<dyn services::Service + Send + Sync>>,
|
||||||
|
memory_cmd: Sender<MemoryCommand>,
|
||||||
|
translation_cache: HashMap<u32, u32>,
|
||||||
|
allocated_bytes: u32,
|
||||||
|
reservations: HashSet<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
impl Memory {
|
impl Memory {
|
||||||
pub fn new(base: u32, size: usize) -> (Self, Receiver<MemoryCommand>) {
|
pub fn new(base: u32, size: usize) -> (Self, Receiver<MemoryCommand>) {
|
||||||
let mut backing = HashMap::new();
|
let mut backing = HashMap::new();
|
||||||
let mut free_pages = BTreeSet::new();
|
let mut free_pages = BTreeSet::new();
|
||||||
let mut allocated_pages = BTreeSet::new();
|
let mut allocated_pages = BTreeSet::new();
|
||||||
|
|
||||||
|
// Populate the backing table as well as the list of free pages
|
||||||
for phys in (base..(base + size as u32)).step_by(4096) {
|
for phys in (base..(base + size as u32)).step_by(4096) {
|
||||||
backing.insert(phys as usize, [0; 4096]);
|
backing.insert(phys as usize, [0; 4096]);
|
||||||
free_pages.insert(phys as usize);
|
free_pages.insert(phys as usize);
|
||||||
}
|
}
|
||||||
// Remove the l0 page table
|
// Allocate the l0 page table
|
||||||
assert!(free_pages.remove(&(MEMORY_BASE as usize + 4096)));
|
assert!(free_pages.remove(&(MEMORY_BASE as usize + 4096)));
|
||||||
assert!(allocated_pages.insert(MEMORY_BASE as usize + 4096));
|
assert!(allocated_pages.insert(MEMORY_BASE as usize + 4096));
|
||||||
|
|
||||||
let (memory_cmd, memory_cmd_rx) = std::sync::mpsc::channel();
|
let (memory_cmd, memory_cmd_rx) = std::sync::mpsc::channel();
|
||||||
(
|
(
|
||||||
Self {
|
Self {
|
||||||
@ -170,27 +182,20 @@ impl Memory {
|
|||||||
free_pages,
|
free_pages,
|
||||||
l1_pt: MEMORY_BASE + 4096,
|
l1_pt: MEMORY_BASE + 4096,
|
||||||
satp: ((4096 + MEMORY_BASE) >> 12) | 0x8000_0000,
|
satp: ((4096 + MEMORY_BASE) >> 12) | 0x8000_0000,
|
||||||
heap_start: 0x6000_0000,
|
heap_start: HEAP_START,
|
||||||
heap_size: 0,
|
heap_size: 0,
|
||||||
allocation_previous: 0x4000_0000,
|
allocation_previous: ALLOCATION_START,
|
||||||
connections: HashMap::new(),
|
connections: HashMap::new(),
|
||||||
memory_cmd,
|
memory_cmd,
|
||||||
turbo: false,
|
translation_cache: HashMap::new(),
|
||||||
|
allocated_bytes: 4096,
|
||||||
|
reservations: HashSet::new(),
|
||||||
},
|
},
|
||||||
memory_cmd_rx,
|
memory_cmd_rx,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn turbo(&mut self) {
|
// fn memory_ck(&self) {
|
||||||
self.turbo = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn normal(&mut self) {
|
|
||||||
self.turbo = false;
|
|
||||||
self.memory_ck();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn memory_ck(&self) {
|
|
||||||
// if self.turbo {
|
// if self.turbo {
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
@ -221,28 +226,37 @@ impl Memory {
|
|||||||
// seen_pages.insert(phys, current);
|
// seen_pages.insert(phys, current);
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
fn allocate_page(&mut self) -> u32 {
|
/// Allocate a physical page from RAM.
|
||||||
self.memory_ck();
|
fn allocate_phys_page(&mut self) -> Option<u32> {
|
||||||
let phys = self.free_pages.pop_first().expect("out of memory");
|
let Some(phys) = self.free_pages.pop_first() else {
|
||||||
|
// panic!(
|
||||||
|
// "out of memory when attempting to allocate a page. There are {} bytes allocated.",
|
||||||
|
// self.allocated_bytes
|
||||||
|
// );
|
||||||
|
return None;
|
||||||
|
};
|
||||||
assert!(self.allocated_pages.insert(phys));
|
assert!(self.allocated_pages.insert(phys));
|
||||||
|
self.allocated_bytes += 4096;
|
||||||
|
|
||||||
// The root (l1) pagetable is defined to be mapped into our virtual
|
// The root (l1) pagetable is defined to be mapped into our virtual
|
||||||
// address space at this address.
|
// address space at this address.
|
||||||
if phys == 0 {
|
if phys == 0 {
|
||||||
panic!("Attempt to allocate zero page");
|
panic!("Attempt to allocate zero page");
|
||||||
}
|
}
|
||||||
self.memory_ck();
|
Some(phys as u32)
|
||||||
phys as u32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn free_page(&mut self, virt: u32) -> Result<(), ()> {
|
fn free_virt_page(&mut self, virt: u32) -> Result<(), ()> {
|
||||||
self.memory_ck();
|
let phys = self
|
||||||
let phys = self.virt_to_phys(virt).ok_or(())?;
|
.virt_to_phys(virt)
|
||||||
|
.ok_or(())
|
||||||
|
.expect("tried to free a page that was allocated");
|
||||||
|
|
||||||
let vpn1 = ((virt >> 22) & ((1 << 10) - 1)) as usize * 4;
|
let vpn1 = ((virt >> 22) & ((1 << 10) - 1)) as usize * 4;
|
||||||
let vpn0 = ((virt >> 12) & ((1 << 10) - 1)) as usize * 4;
|
let vpn0 = ((virt >> 12) & ((1 << 10) - 1)) as usize * 4;
|
||||||
|
self.allocated_bytes -= 4096;
|
||||||
|
|
||||||
// The root (l1) pagetable is defined to be mapped into our virtual
|
// The root (l1) pagetable is defined to be mapped into our virtual
|
||||||
// address space at this address.
|
// address space at this address.
|
||||||
@ -250,68 +264,123 @@ impl Memory {
|
|||||||
// If the level 1 pagetable doesn't exist, then this address is invalid
|
// If the level 1 pagetable doesn't exist, then this address is invalid
|
||||||
let l1_pt_entry = self.read_u32(self.l1_pt as u64 + vpn1 as u64);
|
let l1_pt_entry = self.read_u32(self.l1_pt as u64 + vpn1 as u64);
|
||||||
if l1_pt_entry & MMUFLAG_VALID == 0 {
|
if l1_pt_entry & MMUFLAG_VALID == 0 {
|
||||||
return Ok(());
|
panic!("Tried to free a page where the level 1 pagetable didn't exist");
|
||||||
}
|
}
|
||||||
|
|
||||||
// println!("Deallocating page {:08x} @ {:08x}", virt, phys);
|
assert!(self.allocated_pages.remove(&(phys as usize)));
|
||||||
if !self.allocated_pages.remove(&(phys as usize)) {
|
|
||||||
// self.print_mmu();
|
|
||||||
panic!(
|
|
||||||
"Page {:08x} @ {:08x} wasn't in the list of allocated pages!",
|
|
||||||
phys, virt
|
|
||||||
);
|
|
||||||
}
|
|
||||||
assert!(self.free_pages.insert(phys as usize));
|
assert!(self.free_pages.insert(phys as usize));
|
||||||
|
assert!(self.translation_cache.remove(&virt).is_some());
|
||||||
|
|
||||||
let l0_pt_phys = ((l1_pt_entry >> 10) << 12) + vpn0 as u32;
|
let l0_pt_phys = ((l1_pt_entry >> 10) << 12) + vpn0 as u32;
|
||||||
|
assert!(self.read_u32(l0_pt_phys as u64) & MMUFLAG_VALID != 0);
|
||||||
self.write_u32(l0_pt_phys as u64, 0);
|
self.write_u32(l0_pt_phys as u64, 0);
|
||||||
self.memory_ck();
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn allocate_virt_region(&mut self, size: usize) -> Option<u32> {
|
fn allocate_virt_region(&mut self, size: usize) -> Option<u32> {
|
||||||
self.memory_ck();
|
let size = size as u32;
|
||||||
let mut start = self.allocation_previous;
|
// Look for a sequence of `size` pages that are free.
|
||||||
// Find a free region that will fit this page.
|
let mut address = None;
|
||||||
'outer: loop {
|
for potential_start in (self.allocation_previous..ALLOCATION_END - size)
|
||||||
for page in (start..(start + size as u32)).step_by(4096) {
|
.step_by(4096)
|
||||||
if self.virt_to_phys(page).is_some() {
|
.chain((ALLOCATION_START..self.allocation_previous - size).step_by(4096))
|
||||||
start = page + 4096;
|
{
|
||||||
continue 'outer;
|
let mut all_free = true;
|
||||||
}
|
for check_page in (potential_start..potential_start + size).step_by(4096) {
|
||||||
}
|
if self.virt_to_phys(check_page).is_some() {
|
||||||
|
all_free = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Allocate the region
|
|
||||||
for page in (start..(start + size as u32)).step_by(4096) {
|
|
||||||
self.ensure_page(page);
|
|
||||||
// println!(
|
|
||||||
// "Allocated {:08x} @ {:08x}",
|
|
||||||
// page,
|
|
||||||
// self.virt_to_phys(page).unwrap()
|
|
||||||
// );
|
|
||||||
}
|
}
|
||||||
self.allocation_previous = start + size as u32 + 4096;
|
if all_free {
|
||||||
self.memory_ck();
|
self.allocation_previous = potential_start + size;
|
||||||
Some(start)
|
address = Some(potential_start);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(address) = address {
|
||||||
|
let mut error_mark = None;
|
||||||
|
for page in (address..(address + size)).step_by(4096) {
|
||||||
|
if self.ensure_page(page).is_none() {
|
||||||
|
error_mark = Some(page);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(error_mark) = error_mark {
|
||||||
|
for page in (address..error_mark).step_by(4096) {
|
||||||
|
self.free_virt_page(page).unwrap();
|
||||||
|
}
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
address
|
||||||
|
// for potential_start in (start..initial).step_by(PAGE_SIZE) {
|
||||||
|
// let mut all_free = true;
|
||||||
|
// for check_page in (potential_start..potential_start + size).step_by(PAGE_SIZE) {
|
||||||
|
// if !crate::arch::mem::address_available(check_page) {
|
||||||
|
// all_free = false;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if all_free {
|
||||||
|
// match kind {
|
||||||
|
// xous_kernel::MemoryType::Default => {
|
||||||
|
// process_inner.mem_default_last = potential_start
|
||||||
|
// }
|
||||||
|
// xous_kernel::MemoryType::Messages => {
|
||||||
|
// process_inner.mem_message_last = potential_start
|
||||||
|
// }
|
||||||
|
// other => panic!("invalid kind: {:?}", other),
|
||||||
|
// }
|
||||||
|
// return Ok(potential_start as *mut u8);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// Err(xous_kernel::Error::BadAddress)
|
||||||
|
|
||||||
|
// let mut start = self.allocation_previous;
|
||||||
|
// // Find a free region that will fit this page.
|
||||||
|
// 'outer: loop {
|
||||||
|
// for page in (start..(start + size as u32)).step_by(4096) {
|
||||||
|
// // If this page is allocated, skip it
|
||||||
|
// if self.virt_to_phys(page).is_some() {
|
||||||
|
// start = page + 4096;
|
||||||
|
// continue 'outer;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// // Allocate the region
|
||||||
|
// for page in (start..(start + size as u32)).step_by(4096) {
|
||||||
|
// self.ensure_page(page);
|
||||||
|
// // println!(
|
||||||
|
// // "Allocated {:08x} @ {:08x}",
|
||||||
|
// // page,
|
||||||
|
// // self.virt_to_phys(page).unwrap()
|
||||||
|
// // );
|
||||||
|
// }
|
||||||
|
// self.allocation_previous = start + size as u32 + 4096;
|
||||||
|
// Some(start)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ensure_page(&mut self, address: u32) {
|
fn ensure_page(&mut self, virt: u32) -> Option<bool> {
|
||||||
self.memory_ck();
|
let mut allocated = false;
|
||||||
let vpn1 = ((address >> 22) & ((1 << 10) - 1)) as usize * 4;
|
let vpn1 = ((virt >> 22) & ((1 << 10) - 1)) as usize * 4;
|
||||||
let vpn0 = ((address >> 12) & ((1 << 10) - 1)) as usize * 4;
|
let vpn0 = ((virt >> 12) & ((1 << 10) - 1)) as usize * 4;
|
||||||
|
|
||||||
// If the level 1 pagetable doesn't exist, then this address is invalid
|
// If the level 1 pagetable doesn't exist, then this address is invalid
|
||||||
let mut l1_pt_entry = self.read_u32(self.l1_pt as u64 + vpn1 as u64);
|
let mut l1_pt_entry = self.read_u32(self.l1_pt as u64 + vpn1 as u64);
|
||||||
if l1_pt_entry & MMUFLAG_VALID == 0 {
|
if l1_pt_entry & MMUFLAG_VALID == 0 {
|
||||||
// Allocate a new page for the level 1 pagetable
|
// Allocate a new page for the level 1 pagetable
|
||||||
let l0_pt_phys = self.allocate_page();
|
let Some(l0_pt_phys) = self.allocate_phys_page() else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
// println!("Allocating level 0 pagetable at {:08x}", l0_pt_phys);
|
// println!("Allocating level 0 pagetable at {:08x}", l0_pt_phys);
|
||||||
l1_pt_entry =
|
l1_pt_entry =
|
||||||
((l0_pt_phys >> 12) << 10) | MMUFLAG_VALID | MMUFLAG_DIRTY | MMUFLAG_ACCESSED;
|
((l0_pt_phys >> 12) << 10) | MMUFLAG_VALID | MMUFLAG_DIRTY | MMUFLAG_ACCESSED;
|
||||||
// Map the level 1 pagetable into the root pagetable
|
// Map the level 1 pagetable into the root pagetable
|
||||||
self.write_u32(self.l1_pt as u64 + vpn1 as u64, l1_pt_entry);
|
self.write_u32(self.l1_pt as u64 + vpn1 as u64, l1_pt_entry);
|
||||||
|
allocated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let l0_pt_phys = ((l1_pt_entry >> 10) << 12) + vpn0 as u32;
|
let l0_pt_phys = ((l1_pt_entry >> 10) << 12) + vpn0 as u32;
|
||||||
@ -319,8 +388,10 @@ impl Memory {
|
|||||||
|
|
||||||
// Ensure the entry hasn't already been mapped.
|
// Ensure the entry hasn't already been mapped.
|
||||||
if l0_pt_entry & MMUFLAG_VALID == 0 {
|
if l0_pt_entry & MMUFLAG_VALID == 0 {
|
||||||
let page_phys = self.allocate_page();
|
let Some(phys) = self.allocate_phys_page() else {
|
||||||
l0_pt_entry = ((page_phys >> 12) << 10)
|
return None;
|
||||||
|
};
|
||||||
|
l0_pt_entry = ((phys >> 12) << 10)
|
||||||
| MMUFLAG_VALID
|
| MMUFLAG_VALID
|
||||||
| MMUFLAG_WRITABLE
|
| MMUFLAG_WRITABLE
|
||||||
| MMUFLAG_READABLE
|
| MMUFLAG_READABLE
|
||||||
@ -330,6 +401,8 @@ impl Memory {
|
|||||||
| MMUFLAG_ACCESSED;
|
| MMUFLAG_ACCESSED;
|
||||||
// Map the level 0 pagetable into the level 1 pagetable
|
// Map the level 0 pagetable into the level 1 pagetable
|
||||||
self.write_u32(l0_pt_phys as u64, l0_pt_entry);
|
self.write_u32(l0_pt_phys as u64, l0_pt_entry);
|
||||||
|
assert!(self.translation_cache.insert(virt, phys).is_none());
|
||||||
|
allocated = true;
|
||||||
}
|
}
|
||||||
assert!(self
|
assert!(self
|
||||||
.allocated_pages
|
.allocated_pages
|
||||||
@ -337,11 +410,10 @@ impl Memory {
|
|||||||
assert!(!self
|
assert!(!self
|
||||||
.free_pages
|
.free_pages
|
||||||
.contains(&(((l0_pt_entry >> 10) << 12) as usize)));
|
.contains(&(((l0_pt_entry >> 10) << 12) as usize)));
|
||||||
self.memory_ck();
|
Some(allocated)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_memory_flags(&mut self, virt: u32, new_flags: u32) {
|
fn remove_memory_flags(&mut self, virt: u32, new_flags: u32) {
|
||||||
self.memory_ck();
|
|
||||||
// Ensure they're only adjusting legal flags
|
// Ensure they're only adjusting legal flags
|
||||||
assert!(new_flags & !(MMUFLAG_READABLE | MMUFLAG_WRITABLE | MMUFLAG_EXECUTABLE) == 0);
|
assert!(new_flags & !(MMUFLAG_READABLE | MMUFLAG_WRITABLE | MMUFLAG_EXECUTABLE) == 0);
|
||||||
|
|
||||||
@ -376,7 +448,6 @@ impl Memory {
|
|||||||
(((l1_pt_entry >> 10) << 12) + vpn0 as u32) as u64,
|
(((l1_pt_entry >> 10) << 12) + vpn0 as u32) as u64,
|
||||||
l0_pt_entry,
|
l0_pt_entry,
|
||||||
);
|
);
|
||||||
self.memory_ck();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_bytes(&mut self, data: &[u8], start: u32) {
|
fn write_bytes(&mut self, data: &[u8], start: u32) {
|
||||||
@ -444,12 +515,13 @@ impl Memory {
|
|||||||
|
|
||||||
let l0_pt_entry = self.read_u32((((l1_pt_entry >> 10) << 12) + vpn0 as u32) as u64);
|
let l0_pt_entry = self.read_u32((((l1_pt_entry >> 10) << 12) + vpn0 as u32) as u64);
|
||||||
|
|
||||||
// Ensure the entry hasn't already been mapped.
|
// Check if the mapping is valid
|
||||||
if l0_pt_entry & MMUFLAG_VALID == 0 {
|
if l0_pt_entry & MMUFLAG_VALID == 0 {
|
||||||
return None;
|
None
|
||||||
}
|
} else {
|
||||||
Some(((l0_pt_entry >> 10) << 12) | offset)
|
Some(((l0_pt_entry >> 10) << 12) | offset)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl riscv_cpu::cpu::Memory for Memory {
|
impl riscv_cpu::cpu::Memory for Memory {
|
||||||
@ -565,22 +637,26 @@ impl riscv_cpu::cpu::Memory for Memory {
|
|||||||
match syscall {
|
match syscall {
|
||||||
Syscall::IncreaseHeap(bytes, _flags) => {
|
Syscall::IncreaseHeap(bytes, _flags) => {
|
||||||
// println!("IncreaseHeap({} bytes, flags: {:02x})", bytes, _flags);
|
// println!("IncreaseHeap({} bytes, flags: {:02x})", bytes, _flags);
|
||||||
|
let increase_bytes = bytes as u32;
|
||||||
let heap_address = self.heap_start + self.heap_size;
|
let heap_address = self.heap_start + self.heap_size;
|
||||||
match bytes {
|
if self.heap_size.wrapping_add(increase_bytes) > HEAP_END {
|
||||||
bytes if bytes < 0 => {
|
[
|
||||||
self.heap_size -= bytes.unsigned_abs() as u32;
|
SyscallResultNumber::Error as i64,
|
||||||
panic!("Reducing size not supported!");
|
SyscallErrorNumber::OutOfMemory as i64,
|
||||||
}
|
0,
|
||||||
bytes if bytes > 0 => {
|
0,
|
||||||
for new_address in
|
0,
|
||||||
(heap_address..(heap_address + bytes as u32)).step_by(4096)
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
]
|
||||||
|
.into()
|
||||||
|
} else {
|
||||||
|
for new_address in (heap_address..(heap_address + increase_bytes)).step_by(4096)
|
||||||
{
|
{
|
||||||
self.ensure_page(new_address);
|
self.ensure_page(new_address);
|
||||||
}
|
}
|
||||||
self.heap_size += bytes as u32;
|
self.heap_size += increase_bytes;
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
[
|
[
|
||||||
SyscallResultNumber::MemoryRange as i64,
|
SyscallResultNumber::MemoryRange as i64,
|
||||||
heap_address as i64,
|
heap_address as i64,
|
||||||
@ -593,6 +669,7 @@ impl riscv_cpu::cpu::Memory for Memory {
|
|||||||
]
|
]
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Syscall::MapMemory(phys, virt, size, _flags) => {
|
Syscall::MapMemory(phys, virt, size, _flags) => {
|
||||||
// print!(
|
// print!(
|
||||||
@ -605,10 +682,7 @@ impl riscv_cpu::cpu::Memory for Memory {
|
|||||||
if phys != 0 {
|
if phys != 0 {
|
||||||
unimplemented!("Non-zero phys address");
|
unimplemented!("Non-zero phys address");
|
||||||
}
|
}
|
||||||
let region = self
|
if let Some(region) = self.allocate_virt_region(size as usize) {
|
||||||
.allocate_virt_region(size as usize)
|
|
||||||
.expect("out of memory");
|
|
||||||
// println!(" -> {:08x}", region);
|
|
||||||
[
|
[
|
||||||
SyscallResultNumber::MemoryRange as i64,
|
SyscallResultNumber::MemoryRange as i64,
|
||||||
region as i64,
|
region as i64,
|
||||||
@ -620,6 +694,24 @@ impl riscv_cpu::cpu::Memory for Memory {
|
|||||||
0,
|
0,
|
||||||
]
|
]
|
||||||
.into()
|
.into()
|
||||||
|
} else {
|
||||||
|
// self.print_mmu();
|
||||||
|
println!(
|
||||||
|
"Couldn't find a free spot to allocate {} bytes of virtual memory, or out of memory",
|
||||||
|
size as usize
|
||||||
|
);
|
||||||
|
[
|
||||||
|
SyscallResultNumber::Error as i64,
|
||||||
|
SyscallErrorNumber::OutOfMemory as i64,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
]
|
||||||
|
.into()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Syscall::Connect(id) => {
|
Syscall::Connect(id) => {
|
||||||
// println!(
|
// println!(
|
||||||
@ -832,7 +924,7 @@ impl riscv_cpu::cpu::Memory for Memory {
|
|||||||
Syscall::UnmapMemory(address, size) => {
|
Syscall::UnmapMemory(address, size) => {
|
||||||
// println!("UnmapMemory({:08x}, {})", address, size);
|
// println!("UnmapMemory({:08x}, {})", address, size);
|
||||||
for offset in (address..address + size).step_by(4096) {
|
for offset in (address..address + size).step_by(4096) {
|
||||||
self.free_page(offset as u32).unwrap();
|
self.free_virt_page(offset as u32).unwrap();
|
||||||
}
|
}
|
||||||
[SyscallResultNumber::Ok as i64, 0, 0, 0, 0, 0, 0, 0].into()
|
[SyscallResultNumber::Ok as i64, 0, 0, 0, 0, 0, 0, 0].into()
|
||||||
}
|
}
|
||||||
@ -855,10 +947,27 @@ impl riscv_cpu::cpu::Memory for Memory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn translate(&self, v_address: u64) -> Option<u64> {
|
||||||
|
let v_address = v_address as u32;
|
||||||
|
let ppn = v_address & !0xfff;
|
||||||
|
let offset = v_address & 0xfff;
|
||||||
|
self.translation_cache
|
||||||
|
.get(&ppn)
|
||||||
|
.map(|x| (*x + offset) as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reserve(&mut self, p_address: u64) -> bool {
|
||||||
|
self.reservations.insert(p_address as u32)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_reservation(&mut self, p_address: u64) {
|
||||||
|
self.reservations.remove(&(p_address as u32));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Machine {
|
pub struct Machine {
|
||||||
memory: Arc<RwLock<Memory>>,
|
memory: Arc<Mutex<Memory>>,
|
||||||
workers: Vec<WorkerHandle>,
|
workers: Vec<WorkerHandle>,
|
||||||
satp: u64,
|
satp: u64,
|
||||||
memory_cmd_sender: Sender<MemoryCommand>,
|
memory_cmd_sender: Sender<MemoryCommand>,
|
||||||
@ -870,7 +979,7 @@ impl Machine {
|
|||||||
pub fn new(program: &[u8]) -> Result<Self, LoadError> {
|
pub fn new(program: &[u8]) -> Result<Self, LoadError> {
|
||||||
let (memory, memory_cmd) = Memory::new(MEMORY_BASE, 16 * 1024 * 1024);
|
let (memory, memory_cmd) = Memory::new(MEMORY_BASE, 16 * 1024 * 1024);
|
||||||
let memory_cmd_sender = memory.memory_cmd.clone();
|
let memory_cmd_sender = memory.memory_cmd.clone();
|
||||||
let memory = Arc::new(RwLock::new(memory));
|
let memory = Arc::new(Mutex::new(memory));
|
||||||
|
|
||||||
let mut machine = Self {
|
let mut machine = Self {
|
||||||
memory,
|
memory,
|
||||||
@ -900,8 +1009,7 @@ impl Machine {
|
|||||||
return Err(LoadError::BitSizeError);
|
return Err(LoadError::BitSizeError);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut memory_writer = self.memory.write().unwrap();
|
let mut memory_writer = self.memory.lock().unwrap();
|
||||||
memory_writer.turbo();
|
|
||||||
for sh in elf.section_headers {
|
for sh in elf.section_headers {
|
||||||
if sh.sh_flags as u32 & goblin::elf::section_header::SHF_ALLOC == 0 {
|
if sh.sh_flags as u32 & goblin::elf::section_header::SHF_ALLOC == 0 {
|
||||||
// println!(
|
// println!(
|
||||||
@ -918,7 +1026,9 @@ impl Machine {
|
|||||||
|
|
||||||
if sh.sh_type & goblin::elf::section_header::SHT_NOBITS != 0 {
|
if sh.sh_type & goblin::elf::section_header::SHT_NOBITS != 0 {
|
||||||
for addr in sh.sh_addr..(sh.sh_addr + sh.sh_size) {
|
for addr in sh.sh_addr..(sh.sh_addr + sh.sh_size) {
|
||||||
memory_writer.ensure_page(addr.try_into().unwrap());
|
memory_writer
|
||||||
|
.ensure_page(addr.try_into().unwrap())
|
||||||
|
.expect("out of memory");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
memory_writer.write_bytes(
|
memory_writer.write_bytes(
|
||||||
@ -928,16 +1038,13 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memory_writer.normal();
|
|
||||||
|
|
||||||
// TODO: Get memory permissions correct
|
|
||||||
|
|
||||||
let satp = memory_writer.satp.into();
|
let satp = memory_writer.satp.into();
|
||||||
|
|
||||||
// Ensure stack is allocated
|
// Ensure stack is allocated
|
||||||
for page in (0xc000_0000..0xc002_0000).step_by(4096) {
|
for page in (0xc000_0000..0xc002_0000).step_by(4096) {
|
||||||
memory_writer.ensure_page(page);
|
memory_writer.ensure_page(page).expect("out of memory");
|
||||||
}
|
}
|
||||||
|
drop(memory_writer);
|
||||||
|
|
||||||
cpu.write_csr(riscv_cpu::cpu::CSR_SATP_ADDRESS, satp)
|
cpu.write_csr(riscv_cpu::cpu::CSR_SATP_ADDRESS, satp)
|
||||||
.map_err(|_| LoadError::SatpWriteError)?;
|
.map_err(|_| LoadError::SatpWriteError)?;
|
||||||
|
@ -26,6 +26,38 @@ pub enum SyscallResultNumber {
|
|||||||
Scalar5 = 20,
|
Scalar5 = 20,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub enum SyscallErrorNumber {
|
||||||
|
NoError = 0,
|
||||||
|
BadAlignment = 1,
|
||||||
|
BadAddress = 2,
|
||||||
|
OutOfMemory = 3,
|
||||||
|
MemoryInUse = 4,
|
||||||
|
InterruptNotFound = 5,
|
||||||
|
InterruptInUse = 6,
|
||||||
|
InvalidString = 7,
|
||||||
|
ServerExists = 8,
|
||||||
|
ServerNotFound = 9,
|
||||||
|
ProcessNotFound = 10,
|
||||||
|
ProcessNotChild = 11,
|
||||||
|
ProcessTerminated = 12,
|
||||||
|
Timeout = 13,
|
||||||
|
InternalError = 14,
|
||||||
|
ServerQueueFull = 15,
|
||||||
|
ThreadNotAvailable = 16,
|
||||||
|
UnhandledSyscall = 17,
|
||||||
|
InvalidSyscall = 18,
|
||||||
|
ShareViolation = 19,
|
||||||
|
InvalidThread = 20,
|
||||||
|
InvalidPID = 21,
|
||||||
|
UnknownError = 22,
|
||||||
|
AccessDenied = 23,
|
||||||
|
UseBeforeInit = 24,
|
||||||
|
DoubleFree = 25,
|
||||||
|
DebugInProgress = 26,
|
||||||
|
InvalidLimit = 27,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Syscall {
|
pub enum Syscall {
|
||||||
Unknown([i64; 8]),
|
Unknown([i64; 8]),
|
||||||
|
@ -2,16 +2,20 @@ use std::sync::mpsc::Receiver;
|
|||||||
pub mod log;
|
pub mod log;
|
||||||
pub mod ticktimer;
|
pub mod ticktimer;
|
||||||
|
|
||||||
|
pub type ResponseData = ([i64; 8], Option<(Vec<u8>, u64)>);
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub enum ScalarResult {
|
pub enum ScalarResult {
|
||||||
Scalar1(u32),
|
Scalar1(u32),
|
||||||
Scalar2([u32; 2]),
|
Scalar2([u32; 2]),
|
||||||
Scalar5([u32; 5]),
|
Scalar5([u32; 5]),
|
||||||
WaitForResponse(Receiver<([i64; 8], Option<(Vec<u8>, u64)>)>),
|
WaitForResponse(Receiver<ResponseData>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub enum LendResult {
|
pub enum LendResult {
|
||||||
MemoryReturned([u32; 2]),
|
MemoryReturned([u32; 2]),
|
||||||
WaitForResponse(Receiver<([i64; 8], Option<(Vec<u8>, u64)>)>),
|
WaitForResponse(Receiver<ResponseData>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Service {
|
pub trait Service {
|
||||||
|
@ -39,10 +39,12 @@ impl Service for Log {
|
|||||||
let print_buffer = &buf[0..extra[1] as usize];
|
let print_buffer = &buf[0..extra[1] as usize];
|
||||||
// println!("Log stdout:");
|
// println!("Log stdout:");
|
||||||
std::io::stdout().write_all(print_buffer).unwrap();
|
std::io::stdout().write_all(print_buffer).unwrap();
|
||||||
|
std::io::stdout().flush().unwrap();
|
||||||
} else if opcode == LogLendOpcode::StandardError as u32 {
|
} else if opcode == LogLendOpcode::StandardError as u32 {
|
||||||
let print_buffer = &buf[0..extra[1] as usize];
|
let print_buffer = &buf[0..extra[1] as usize];
|
||||||
// println!("Log stderr:");
|
// println!("Log stderr:");
|
||||||
std::io::stderr().write_all(print_buffer).unwrap();
|
std::io::stderr().write_all(print_buffer).unwrap();
|
||||||
|
std::io::stderr().flush().unwrap();
|
||||||
} else {
|
} else {
|
||||||
panic!("Log lend {}: {} {:x?}", sender, opcode, buf);
|
panic!("Log lend {}: {} {:x?}", sender, opcode, buf);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user