fix stack alignment
Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
parent
f13d476a9f
commit
48206ee23c
@ -1,4 +1,4 @@
|
|||||||
use std::sync::{Arc, RwLock, mpsc::Receiver};
|
use std::sync::{mpsc::Receiver, Arc, RwLock};
|
||||||
|
|
||||||
pub use super::mmu::Memory;
|
pub use super::mmu::Memory;
|
||||||
use super::mmu::{AddressingMode, Mmu};
|
use super::mmu::{AddressingMode, Mmu};
|
||||||
@ -58,9 +58,9 @@ pub enum TickResult {
|
|||||||
Ok,
|
Ok,
|
||||||
ExitThread(u64),
|
ExitThread(u64),
|
||||||
PauseEmulation(Receiver<([i64; 8], Option<(Vec<u8>, u64)>)>),
|
PauseEmulation(Receiver<([i64; 8], Option<(Vec<u8>, u64)>)>),
|
||||||
|
CpuTrap(Trap),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Emulates a RISC-V CPU core
|
/// Emulates a RISC-V CPU core
|
||||||
pub struct Cpu {
|
pub struct Cpu {
|
||||||
clock: u64,
|
clock: u64,
|
||||||
@ -343,7 +343,6 @@ impl Cpu {
|
|||||||
|
|
||||||
/// Runs program one cycle. Fetch, decode, and execution are completed in a cycle so far.
|
/// Runs program one cycle. Fetch, decode, and execution are completed in a cycle so far.
|
||||||
pub fn tick(&mut self) -> TickResult {
|
pub fn tick(&mut self) -> TickResult {
|
||||||
let instruction_address = self.pc;
|
|
||||||
match self.tick_operate() {
|
match self.tick_operate() {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(Trap {
|
Err(Trap {
|
||||||
@ -358,7 +357,7 @@ impl Cpu {
|
|||||||
}) => {
|
}) => {
|
||||||
return TickResult::ExitThread(self.read_register(10) as u64);
|
return TickResult::ExitThread(self.read_register(10) as u64);
|
||||||
}
|
}
|
||||||
Err(e) => self.handle_exception(e, instruction_address),
|
Err(e) => return TickResult::CpuTrap(e),
|
||||||
}
|
}
|
||||||
self.mmu.tick(&mut self.csr[CSR_MIP_ADDRESS as usize]);
|
self.mmu.tick(&mut self.csr[CSR_MIP_ADDRESS as usize]);
|
||||||
self.handle_interrupt(self.pc);
|
self.handle_interrupt(self.pc);
|
||||||
@ -781,7 +780,7 @@ impl Cpu {
|
|||||||
// println!("Fetching word from {:08x}...", self.pc);
|
// println!("Fetching word from {:08x}...", self.pc);
|
||||||
self.mmu.fetch_word(self.pc).map_err(|e| {
|
self.mmu.fetch_word(self.pc).map_err(|e| {
|
||||||
self.pc = self.pc.wrapping_add(4); // @TODO: What if instruction is compressed?
|
self.pc = self.pc.wrapping_add(4); // @TODO: What if instruction is compressed?
|
||||||
// println!("Fetch error: {:x?}", e);
|
// println!("Fetch error: {:x?}", e);
|
||||||
e
|
e
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,171 +1,170 @@
|
|||||||
/// Emulates main memory.
|
/// Emulates main memory.
|
||||||
pub struct Memory {
|
pub struct Memory {
|
||||||
/// Memory content
|
/// Memory content
|
||||||
data: Vec<u64>
|
data: Vec<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Memory {
|
impl Memory {
|
||||||
/// Creates a new `Memory`
|
/// Creates a new `Memory`
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Memory {
|
Memory { data: vec![] }
|
||||||
data: vec![]
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initializes memory content.
|
/// Initializes memory content.
|
||||||
/// This method is expected to be called only once.
|
/// This method is expected to be called only once.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `capacity`
|
/// * `capacity`
|
||||||
pub fn init(&mut self, capacity: u64) {
|
pub fn init(&mut self, capacity: u64) {
|
||||||
for _i in 0..((capacity + 7) / 8) {
|
for _i in 0..((capacity + 7) / 8) {
|
||||||
self.data.push(0);
|
self.data.push(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads a byte from memory.
|
/// Reads a byte from memory.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `address`
|
/// * `address`
|
||||||
pub fn read_byte(&self, address: u64) -> u8 {
|
pub fn read_byte(&self, address: u64) -> u8 {
|
||||||
let index = (address >> 3) as usize;
|
let index = (address >> 3) as usize;
|
||||||
let pos = (address % 8) * 8;
|
let pos = (address % 8) * 8;
|
||||||
(self.data[index] >> pos) as u8
|
(self.data[index] >> pos) as u8
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads two bytes from memory.
|
/// Reads two bytes from memory.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `address`
|
/// * `address`
|
||||||
pub fn read_halfword(&self, address: u64) -> u16 {
|
pub fn read_halfword(&self, address: u64) -> u16 {
|
||||||
if (address % 2) == 0 {
|
if (address % 2) == 0 {
|
||||||
let index = (address >> 3) as usize;
|
let index = (address >> 3) as usize;
|
||||||
let pos = (address % 8) * 8;
|
let pos = (address % 8) * 8;
|
||||||
(self.data[index] >> pos) as u16
|
(self.data[index] >> pos) as u16
|
||||||
} else {
|
} else {
|
||||||
self.read_bytes(address, 2) as u16
|
self.read_bytes(address, 2) as u16
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads four bytes from memory.
|
/// Reads four bytes from memory.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `address`
|
/// * `address`
|
||||||
pub fn read_word(&self, address: u64) -> u32 {
|
pub fn read_word(&self, address: u64) -> u32 {
|
||||||
if (address % 4) == 0 {
|
if (address % 4) == 0 {
|
||||||
let index = (address >> 3) as usize;
|
let index = (address >> 3) as usize;
|
||||||
let pos = (address % 8) * 8;
|
let pos = (address % 8) * 8;
|
||||||
(self.data[index] >> pos) as u32
|
(self.data[index] >> pos) as u32
|
||||||
} else {
|
} else {
|
||||||
self.read_bytes(address, 4) as u32
|
self.read_bytes(address, 4) as u32
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads eight bytes from memory.
|
/// Reads eight bytes from memory.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `address`
|
/// * `address`
|
||||||
pub fn read_doubleword(&self, address: u64) -> u64 {
|
pub fn read_doubleword(&self, address: u64) -> u64 {
|
||||||
if (address % 8) == 0 {
|
if (address % 8) == 0 {
|
||||||
let index = (address >> 3) as usize;
|
let index = (address >> 3) as usize;
|
||||||
self.data[index]
|
self.data[index]
|
||||||
} else if (address % 4) == 0 {
|
} else if (address % 4) == 0 {
|
||||||
(self.read_word(address) as u64) | ((self.read_word(address.wrapping_add(4)) as u64) << 4)
|
(self.read_word(address) as u64)
|
||||||
} else {
|
| ((self.read_word(address.wrapping_add(4)) as u64) << 4)
|
||||||
self.read_bytes(address, 8)
|
} else {
|
||||||
}
|
self.read_bytes(address, 8)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Reads multiple bytes from memory.
|
/// Reads multiple bytes from memory.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `address`
|
/// * `address`
|
||||||
/// * `width` up to eight
|
/// * `width` up to eight
|
||||||
pub fn read_bytes(&self, address: u64, width: u64) -> u64 {
|
pub fn read_bytes(&self, address: u64, width: u64) -> u64 {
|
||||||
let mut data = 0;
|
let mut data = 0;
|
||||||
for i in 0..width {
|
for i in 0..width {
|
||||||
data |= (self.read_byte(address.wrapping_add(i)) as u64) << (i * 8);
|
data |= (self.read_byte(address.wrapping_add(i)) as u64) << (i * 8);
|
||||||
}
|
}
|
||||||
data
|
data
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes a byte to memory.
|
/// Writes a byte to memory.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `address`
|
/// * `address`
|
||||||
/// * `value`
|
/// * `value`
|
||||||
pub fn write_byte(&mut self, address: u64, value: u8) {
|
pub fn write_byte(&mut self, address: u64, value: u8) {
|
||||||
let index = (address >> 3) as usize;
|
let index = (address >> 3) as usize;
|
||||||
let pos = (address % 8) * 8;
|
let pos = (address % 8) * 8;
|
||||||
self.data[index] = (self.data[index] & !(0xff << pos)) | ((value as u64) << pos);
|
self.data[index] = (self.data[index] & !(0xff << pos)) | ((value as u64) << pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes two bytes to memory.
|
/// Writes two bytes to memory.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `address`
|
/// * `address`
|
||||||
/// * `value`
|
/// * `value`
|
||||||
pub fn write_halfword(&mut self, address: u64, value: u16) {
|
pub fn write_halfword(&mut self, address: u64, value: u16) {
|
||||||
if (address % 2) == 0 {
|
if (address % 2) == 0 {
|
||||||
let index = (address >> 3) as usize;
|
let index = (address >> 3) as usize;
|
||||||
let pos = (address % 8) * 8;
|
let pos = (address % 8) * 8;
|
||||||
self.data[index] = (self.data[index] & !(0xffff << pos)) | ((value as u64) << pos);
|
self.data[index] = (self.data[index] & !(0xffff << pos)) | ((value as u64) << pos);
|
||||||
} else {
|
} else {
|
||||||
self.write_bytes(address, value as u64, 2);
|
self.write_bytes(address, value as u64, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes four bytes to memory.
|
/// Writes four bytes to memory.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `address`
|
/// * `address`
|
||||||
/// * `value`
|
/// * `value`
|
||||||
pub fn write_word(&mut self, address: u64, value: u32) {
|
pub fn write_word(&mut self, address: u64, value: u32) {
|
||||||
if (address % 4) == 0 {
|
if (address % 4) == 0 {
|
||||||
let index = (address >> 3) as usize;
|
let index = (address >> 3) as usize;
|
||||||
let pos = (address % 8) * 8;
|
let pos = (address % 8) * 8;
|
||||||
self.data[index] = (self.data[index] & !(0xffffffff << pos)) | ((value as u64) << pos);
|
self.data[index] = (self.data[index] & !(0xffffffff << pos)) | ((value as u64) << pos);
|
||||||
} else {
|
} else {
|
||||||
self.write_bytes(address, value as u64, 4);
|
self.write_bytes(address, value as u64, 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes eight bytes to memory.
|
/// Writes eight bytes to memory.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `address`
|
/// * `address`
|
||||||
/// * `value`
|
/// * `value`
|
||||||
pub fn write_doubleword(&mut self, address: u64, value: u64) {
|
pub fn write_doubleword(&mut self, address: u64, value: u64) {
|
||||||
if (address % 8) == 0 {
|
if (address % 8) == 0 {
|
||||||
let index = (address >> 3) as usize;
|
let index = (address >> 3) as usize;
|
||||||
self.data[index] = value;
|
self.data[index] = value;
|
||||||
} else if (address % 4) == 0 {
|
} else if (address % 4) == 0 {
|
||||||
self.write_word(address, (value & 0xffffffff) as u32);
|
self.write_word(address, (value & 0xffffffff) as u32);
|
||||||
self.write_word(address.wrapping_add(4), (value >> 32) as u32);
|
self.write_word(address.wrapping_add(4), (value >> 32) as u32);
|
||||||
} else {
|
} else {
|
||||||
self.write_bytes(address, value, 8);
|
self.write_bytes(address, value, 8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write multiple bytes to memory.
|
/// Write multiple bytes to memory.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `address`
|
/// * `address`
|
||||||
/// * `value`
|
/// * `value`
|
||||||
/// * `width` up to eight
|
/// * `width` up to eight
|
||||||
pub fn write_bytes(&mut self, address: u64, value: u64, width: u64) {
|
pub fn write_bytes(&mut self, address: u64, value: u64, width: u64) {
|
||||||
for i in 0..width {
|
for i in 0..width {
|
||||||
self.write_byte(address.wrapping_add(i), (value >> (i * 8)) as u8);
|
self.write_byte(address.wrapping_add(i), (value >> (i * 8)) as u8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the address is valid memory address
|
/// Check if the address is valid memory address
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `address`
|
/// * `address`
|
||||||
pub fn validate_address(&self, address: u64) -> bool {
|
pub fn validate_address(&self, address: u64) -> bool {
|
||||||
(address as usize) < self.data.len()
|
(address as usize) < self.data.len()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Memory {
|
impl Default for Memory {
|
||||||
|
243
src/xous.rs
243
src/xous.rs
@ -75,20 +75,33 @@ struct Memory {
|
|||||||
satp: u32,
|
satp: u32,
|
||||||
connections: HashMap<u32, Box<dyn services::Service + Send + Sync>>,
|
connections: HashMap<u32, Box<dyn services::Service + Send + Sync>>,
|
||||||
memory_cmd: Sender<MemoryCommand>,
|
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>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Worker {
|
impl Worker {
|
||||||
fn new(cpu: riscv_cpu::Cpu, cmd: Sender<MemoryCommand>, tid: i64) -> Self {
|
fn new(
|
||||||
Self { cpu, cmd, tid }
|
cpu: riscv_cpu::Cpu,
|
||||||
|
cmd: Sender<MemoryCommand>,
|
||||||
|
tid: i64,
|
||||||
|
memory: Arc<RwLock<Memory>>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
cpu,
|
||||||
|
cmd,
|
||||||
|
tid,
|
||||||
|
memory,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fn run(&mut self) {
|
fn run(&mut self) {
|
||||||
use riscv_cpu::cpu::TickResult;
|
use riscv_cpu::cpu::TickResult;
|
||||||
|
// println!("Running CPU thread {}", self.tid);
|
||||||
loop {
|
loop {
|
||||||
match self.cpu.tick() {
|
match self.cpu.tick() {
|
||||||
TickResult::PauseEmulation(e) => {
|
TickResult::PauseEmulation(e) => {
|
||||||
@ -110,7 +123,21 @@ impl Worker {
|
|||||||
.send(MemoryCommand::ExitThread(self.tid as u32, val as u32))
|
.send(MemoryCommand::ExitThread(self.tid as u32, val as u32))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
// println!("Thread {} exited", self.tid);
|
// println!("Thread {} exited", self.tid);
|
||||||
break;
|
return;
|
||||||
|
}
|
||||||
|
TickResult::CpuTrap(trap) => {
|
||||||
|
self.memory.read().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"
|
||||||
|
println!(
|
||||||
|
"CPU trap at PC {:08x}, exiting thread {}: {:x?}",
|
||||||
|
self.cpu.read_pc(),
|
||||||
|
self.tid,
|
||||||
|
trap
|
||||||
|
);
|
||||||
|
self.cmd
|
||||||
|
.send(MemoryCommand::ExitThread(self.tid as u32, 1))
|
||||||
|
.unwrap();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
TickResult::Ok => {}
|
TickResult::Ok => {}
|
||||||
}
|
}
|
||||||
@ -124,21 +151,21 @@ struct WorkerHandle {
|
|||||||
|
|
||||||
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 data = 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();
|
||||||
for page in (base..(base + size as u32)).step_by(4096) {
|
for phys in (base..(base + size as u32)).step_by(4096) {
|
||||||
data.insert(page as usize, [0; 4096]);
|
backing.insert(phys as usize, [0; 4096]);
|
||||||
free_pages.insert(page as usize);
|
free_pages.insert(phys as usize);
|
||||||
}
|
}
|
||||||
// Remove the l0 page table
|
// Remove the l0 page table
|
||||||
free_pages.remove(&(MEMORY_BASE as usize + 4096));
|
assert!(free_pages.remove(&(MEMORY_BASE as usize + 4096)));
|
||||||
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 {
|
||||||
base,
|
base,
|
||||||
data,
|
data: backing,
|
||||||
allocated_pages,
|
allocated_pages,
|
||||||
free_pages,
|
free_pages,
|
||||||
l1_pt: MEMORY_BASE + 4096,
|
l1_pt: MEMORY_BASE + 4096,
|
||||||
@ -148,26 +175,74 @@ impl Memory {
|
|||||||
allocation_previous: 0x4000_0000,
|
allocation_previous: 0x4000_0000,
|
||||||
connections: HashMap::new(),
|
connections: HashMap::new(),
|
||||||
memory_cmd,
|
memory_cmd,
|
||||||
|
turbo: false,
|
||||||
},
|
},
|
||||||
memory_cmd_rx,
|
memory_cmd_rx,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn allocate_page(&mut self) -> u32 {
|
pub fn turbo(&mut self) {
|
||||||
let page = self.free_pages.pop_first().expect("out of memory");
|
self.turbo = true;
|
||||||
self.allocated_pages.insert(page);
|
|
||||||
page as u32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn free_page(&mut self, page: u32) -> Result<(), ()> {
|
pub fn normal(&mut self) {
|
||||||
let phys = self.virt_to_phys(page).ok_or(())?;
|
self.turbo = false;
|
||||||
if !self.allocated_pages.remove(&(phys as usize)) {
|
self.memory_ck();
|
||||||
panic!("Page wasn't allocated!");
|
}
|
||||||
}
|
|
||||||
self.free_pages.insert(phys as usize);
|
|
||||||
|
|
||||||
let vpn1 = ((page >> 22) & ((1 << 10) - 1)) as usize * 4;
|
fn memory_ck(&self) {
|
||||||
let vpn0 = ((page >> 12) & ((1 << 10) - 1)) as usize * 4;
|
// if self.turbo {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// let mut seen_pages = HashMap::new();
|
||||||
|
// seen_pages.insert(self.l1_pt, 0);
|
||||||
|
// for vpn1 in 0..1024 {
|
||||||
|
// let l1_entry = self.read_u32(self.l1_pt as u64 + vpn1 * 4);
|
||||||
|
// if l1_entry & MMUFLAG_VALID == 0 {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// let superpage_addr = vpn1 as u32 * (1 << 22);
|
||||||
|
|
||||||
|
// for vpn0 in 0..1024 {
|
||||||
|
// let l0_entry = self.read_u32((((l1_entry >> 10) << 12) as u64) + vpn0 as u64 * 4);
|
||||||
|
// if l0_entry & 0x1 == 0 {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// let phys = (l0_entry >> 10) << 12;
|
||||||
|
// let current = superpage_addr + vpn0 as u32 * (1 << 12);
|
||||||
|
// if let Some(existing) = seen_pages.get(&phys) {
|
||||||
|
// self.print_mmu();
|
||||||
|
// panic!(
|
||||||
|
// "Error! Page {:08x} is mapped twice! Once at {:08x} and once at {:08x}",
|
||||||
|
// phys, existing, current,
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// seen_pages.insert(phys, current);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn allocate_page(&mut self) -> u32 {
|
||||||
|
self.memory_ck();
|
||||||
|
let phys = self.free_pages.pop_first().expect("out of memory");
|
||||||
|
assert!(self.allocated_pages.insert(phys));
|
||||||
|
|
||||||
|
// The root (l1) pagetable is defined to be mapped into our virtual
|
||||||
|
// address space at this address.
|
||||||
|
if phys == 0 {
|
||||||
|
panic!("Attempt to allocate zero page");
|
||||||
|
}
|
||||||
|
self.memory_ck();
|
||||||
|
phys as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn free_page(&mut self, virt: u32) -> Result<(), ()> {
|
||||||
|
self.memory_ck();
|
||||||
|
let phys = self.virt_to_phys(virt).ok_or(())?;
|
||||||
|
|
||||||
|
let vpn1 = ((virt >> 22) & ((1 << 10) - 1)) as usize * 4;
|
||||||
|
let vpn0 = ((virt >> 12) & ((1 << 10) - 1)) as usize * 4;
|
||||||
|
|
||||||
// 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.
|
||||||
@ -178,13 +253,25 @@ impl Memory {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// println!("Deallocating page {:08x} @ {:08x}", virt, phys);
|
||||||
|
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));
|
||||||
|
|
||||||
let l0_pt_phys = ((l1_pt_entry >> 10) << 12) + vpn0 as u32;
|
let l0_pt_phys = ((l1_pt_entry >> 10) << 12) + vpn0 as u32;
|
||||||
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 mut start = self.allocation_previous;
|
let mut start = self.allocation_previous;
|
||||||
// Find a free region that will fit this page.
|
// Find a free region that will fit this page.
|
||||||
'outer: loop {
|
'outer: loop {
|
||||||
@ -199,18 +286,22 @@ impl Memory {
|
|||||||
// Allocate the region
|
// Allocate the region
|
||||||
for page in (start..(start + size as u32)).step_by(4096) {
|
for page in (start..(start + size as u32)).step_by(4096) {
|
||||||
self.ensure_page(page);
|
self.ensure_page(page);
|
||||||
|
// println!(
|
||||||
|
// "Allocated {:08x} @ {:08x}",
|
||||||
|
// page,
|
||||||
|
// self.virt_to_phys(page).unwrap()
|
||||||
|
// );
|
||||||
}
|
}
|
||||||
self.allocation_previous = start + size as u32 + 4096;
|
self.allocation_previous = start + size as u32 + 4096;
|
||||||
|
self.memory_ck();
|
||||||
Some(start)
|
Some(start)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ensure_page(&mut self, address: u32) {
|
fn ensure_page(&mut self, address: u32) {
|
||||||
|
self.memory_ck();
|
||||||
let vpn1 = ((address >> 22) & ((1 << 10) - 1)) as usize * 4;
|
let vpn1 = ((address >> 22) & ((1 << 10) - 1)) as usize * 4;
|
||||||
let vpn0 = ((address >> 12) & ((1 << 10) - 1)) as usize * 4;
|
let vpn0 = ((address >> 12) & ((1 << 10) - 1)) as usize * 4;
|
||||||
|
|
||||||
// The root (l1) pagetable is defined to be mapped into our virtual
|
|
||||||
// address space at this address.
|
|
||||||
|
|
||||||
// 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 {
|
||||||
@ -240,6 +331,52 @@ impl Memory {
|
|||||||
// 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
|
||||||
|
.allocated_pages
|
||||||
|
.contains(&(((l0_pt_entry >> 10) << 12) as usize)));
|
||||||
|
assert!(!self
|
||||||
|
.free_pages
|
||||||
|
.contains(&(((l0_pt_entry >> 10) << 12) as usize)));
|
||||||
|
self.memory_ck();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_memory_flags(&mut self, virt: u32, new_flags: u32) {
|
||||||
|
self.memory_ck();
|
||||||
|
// Ensure they're only adjusting legal flags
|
||||||
|
assert!(new_flags & !(MMUFLAG_READABLE | MMUFLAG_WRITABLE | MMUFLAG_EXECUTABLE) == 0);
|
||||||
|
|
||||||
|
let vpn1 = ((virt >> 22) & ((1 << 10) - 1)) as usize * 4;
|
||||||
|
let vpn0 = ((virt >> 12) & ((1 << 10) - 1)) as usize * 4;
|
||||||
|
|
||||||
|
// The root (l1) pagetable is defined to be mapped into our virtual
|
||||||
|
// address space at this address.
|
||||||
|
let l1_pt_entry = self.read_u32(self.l1_pt as u64 + vpn1 as u64);
|
||||||
|
|
||||||
|
// If the level 1 pagetable doesn't exist, then this address is invalid
|
||||||
|
if l1_pt_entry & MMUFLAG_VALID == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
|
if l0_pt_entry & MMUFLAG_VALID == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let old_flags = l0_pt_entry & 0xff;
|
||||||
|
|
||||||
|
// Ensure we're not adding flags
|
||||||
|
assert!(old_flags | new_flags == old_flags);
|
||||||
|
|
||||||
|
let l0_pt_entry =
|
||||||
|
(l0_pt_entry & !(MMUFLAG_READABLE | MMUFLAG_WRITABLE | MMUFLAG_EXECUTABLE)) | new_flags;
|
||||||
|
|
||||||
|
self.write_u32(
|
||||||
|
(((l1_pt_entry >> 10) << 12) + vpn0 as u32) as u64,
|
||||||
|
l0_pt_entry,
|
||||||
|
);
|
||||||
|
self.memory_ck();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_bytes(&mut self, data: &[u8], start: u32) {
|
fn write_bytes(&mut self, data: &[u8], start: u32) {
|
||||||
@ -254,35 +391,35 @@ impl Memory {
|
|||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn print_mmu(&self) {
|
pub fn print_mmu(&self) {
|
||||||
|
use crate::xous::definitions::memoryflags::MemoryFlags;
|
||||||
|
println!();
|
||||||
println!("Memory Map:");
|
println!("Memory Map:");
|
||||||
for vpn1 in (0..4096).step_by(4) {
|
for vpn1 in 0..1024 {
|
||||||
let l1_entry = self.read_u32(self.l1_pt as u64 + vpn1);
|
let l1_entry = self.read_u32(self.l1_pt as u64 + vpn1 * 4);
|
||||||
if l1_entry & MMUFLAG_VALID == 0 {
|
if l1_entry & MMUFLAG_VALID == 0 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let superpage_addr = vpn1 as u32 * (1 << 22);
|
let superpage_addr = vpn1 as u32 * (1 << 22);
|
||||||
println!(
|
println!(
|
||||||
" {:4} Superpage for {:08x} @ {:08x} (flags: {:?})",
|
" {:4} Superpage for {:08x} @ {:08x} (flags: {})",
|
||||||
vpn1,
|
vpn1,
|
||||||
superpage_addr,
|
superpage_addr,
|
||||||
(l1_entry >> 10) << 12,
|
(l1_entry >> 10) << 12,
|
||||||
// MMUFlags::from_bits(l1_entry & 0xff).unwrap()
|
MemoryFlags::from_bits(l1_entry as usize & 0xff).unwrap(),
|
||||||
l1_entry & 0xff,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
for vpn0 in (0..4096).step_by(4) {
|
for vpn0 in 0..1024 {
|
||||||
let l0_entry = self.read_u32((((l1_entry >> 10) << 12) as u64) + vpn0 as u64);
|
let l0_entry = self.read_u32((((l1_entry >> 10) << 12) as u64) + vpn0 as u64 * 4);
|
||||||
if l0_entry & 0x7 == 0 {
|
if l0_entry & 0x1 == 0 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let page_addr = vpn0 as u32 * (1 << 12);
|
let page_addr = vpn0 as u32 * (1 << 12);
|
||||||
println!(
|
println!(
|
||||||
" {:4} {:08x} -> {:08x} (flags: {:?})",
|
" {:4} {:08x} -> {:08x} (flags: {})",
|
||||||
vpn0,
|
vpn0,
|
||||||
superpage_addr + page_addr,
|
superpage_addr + page_addr,
|
||||||
(l0_entry >> 10) << 12,
|
(l0_entry >> 10) << 12,
|
||||||
// MMUFlags::from_bits(l0_entry & 0xff).unwrap()
|
MemoryFlags::from_bits(l0_entry as usize & 0xff).unwrap()
|
||||||
l0_entry & 0xff,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -424,7 +561,7 @@ impl riscv_cpu::cpu::Memory for Memory {
|
|||||||
fn syscall(&mut self, args: [i64; 8]) -> SyscallResult {
|
fn syscall(&mut self, args: [i64; 8]) -> SyscallResult {
|
||||||
let syscall: Syscall = args.into();
|
let syscall: Syscall = args.into();
|
||||||
|
|
||||||
// print!("Syscall: ");
|
// println!("Syscall {:?}", SyscallNumber::from(args[0]));
|
||||||
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);
|
||||||
@ -458,7 +595,7 @@ impl riscv_cpu::cpu::Memory for Memory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Syscall::MapMemory(phys, virt, size, _flags) => {
|
Syscall::MapMemory(phys, virt, size, _flags) => {
|
||||||
// println!(
|
// print!(
|
||||||
// "MapMemory(phys: {:08x}, virt: {:08x}, bytes: {}, flags: {:02x})",
|
// "MapMemory(phys: {:08x}, virt: {:08x}, bytes: {}, flags: {:02x})",
|
||||||
// phys, virt, size, _flags
|
// phys, virt, size, _flags
|
||||||
// );
|
// );
|
||||||
@ -471,6 +608,7 @@ impl riscv_cpu::cpu::Memory for Memory {
|
|||||||
let region = self
|
let region = self
|
||||||
.allocate_virt_region(size as usize)
|
.allocate_virt_region(size as usize)
|
||||||
.expect("out of memory");
|
.expect("out of memory");
|
||||||
|
// println!(" -> {:08x}", region);
|
||||||
[
|
[
|
||||||
SyscallResultNumber::MemoryRange as i64,
|
SyscallResultNumber::MemoryRange as i64,
|
||||||
region as i64,
|
region as i64,
|
||||||
@ -649,7 +787,10 @@ impl riscv_cpu::cpu::Memory for Memory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Syscall::UpdateMemoryFlags(_address, _range, _value) => {
|
Syscall::UpdateMemoryFlags(address, range, value) => {
|
||||||
|
for addr in address..(address + range) {
|
||||||
|
self.remove_memory_flags(addr as u32, value as u32);
|
||||||
|
}
|
||||||
[SyscallResultNumber::Ok as i64, 0, 0, 0, 0, 0, 0, 0].into()
|
[SyscallResultNumber::Ok as i64, 0, 0, 0, 0, 0, 0, 0].into()
|
||||||
}
|
}
|
||||||
Syscall::Yield => [SyscallResultNumber::Ok as i64, 0, 0, 0, 0, 0, 0, 0].into(),
|
Syscall::Yield => [SyscallResultNumber::Ok as i64, 0, 0, 0, 0, 0, 0, 0].into(),
|
||||||
@ -722,7 +863,7 @@ pub struct Machine {
|
|||||||
satp: u64,
|
satp: u64,
|
||||||
memory_cmd_sender: Sender<MemoryCommand>,
|
memory_cmd_sender: Sender<MemoryCommand>,
|
||||||
memory_cmd: Receiver<MemoryCommand>,
|
memory_cmd: Receiver<MemoryCommand>,
|
||||||
thread_id: AtomicI64,
|
thread_id_counter: AtomicI64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Machine {
|
impl Machine {
|
||||||
@ -737,7 +878,7 @@ impl Machine {
|
|||||||
satp: 0,
|
satp: 0,
|
||||||
memory_cmd,
|
memory_cmd,
|
||||||
memory_cmd_sender,
|
memory_cmd_sender,
|
||||||
thread_id: AtomicI64::new(1),
|
thread_id_counter: AtomicI64::new(1),
|
||||||
};
|
};
|
||||||
|
|
||||||
machine.load_program(program)?;
|
machine.load_program(program)?;
|
||||||
@ -760,6 +901,7 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut memory_writer = self.memory.write().unwrap();
|
let mut memory_writer = self.memory.write().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 {
|
||||||
continue;
|
continue;
|
||||||
@ -776,7 +918,8 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memory_writer.print_mmu();
|
// memory_writer.print_mmu();
|
||||||
|
memory_writer.normal();
|
||||||
|
|
||||||
// TODO: Get memory permissions correct
|
// TODO: Get memory permissions correct
|
||||||
|
|
||||||
@ -802,10 +945,11 @@ impl Machine {
|
|||||||
cpu.execute_opcode(0x10200073).map_err(LoadError::CpuTrap)?;
|
cpu.execute_opcode(0x10200073).map_err(LoadError::CpuTrap)?;
|
||||||
|
|
||||||
// Update the stack pointer
|
// Update the stack pointer
|
||||||
cpu.write_register(2, 0xc002_0000 - 4);
|
cpu.write_register(2, 0xc002_0000 - 16);
|
||||||
|
|
||||||
let cmd = self.memory_cmd_sender.clone();
|
let cmd = self.memory_cmd_sender.clone();
|
||||||
let joiner = std::thread::spawn(move || Worker::new(cpu, cmd, 0).run());
|
let memory = self.memory.clone();
|
||||||
|
let joiner = std::thread::spawn(move || Worker::new(cpu, cmd, 0, memory).run());
|
||||||
|
|
||||||
self.workers.push(WorkerHandle { joiner });
|
self.workers.push(WorkerHandle { joiner });
|
||||||
self.satp = satp;
|
self.satp = satp;
|
||||||
@ -868,7 +1012,7 @@ impl Machine {
|
|||||||
MemoryCommand::CreateThread(
|
MemoryCommand::CreateThread(
|
||||||
entry_point,
|
entry_point,
|
||||||
stack_pointer,
|
stack_pointer,
|
||||||
_stack_length,
|
stack_length,
|
||||||
argument_1,
|
argument_1,
|
||||||
argument_2,
|
argument_2,
|
||||||
argument_3,
|
argument_3,
|
||||||
@ -894,16 +1038,19 @@ impl Machine {
|
|||||||
cpu.execute_opcode(0x10200073).map_err(LoadError::CpuTrap)?;
|
cpu.execute_opcode(0x10200073).map_err(LoadError::CpuTrap)?;
|
||||||
|
|
||||||
// Update the stack pointer
|
// Update the stack pointer
|
||||||
cpu.write_register(2, stack_pointer as i64 - 16);
|
cpu.write_register(2, (stack_pointer + stack_length) as i64 - 16);
|
||||||
cpu.write_register(10, argument_1 as i64);
|
cpu.write_register(10, argument_1 as i64);
|
||||||
cpu.write_register(11, argument_2 as i64);
|
cpu.write_register(11, argument_2 as i64);
|
||||||
cpu.write_register(12, argument_3 as i64);
|
cpu.write_register(12, argument_3 as i64);
|
||||||
cpu.write_register(13, argument_4 as i64);
|
cpu.write_register(13, argument_4 as i64);
|
||||||
|
|
||||||
let cmd = self.memory_cmd_sender.clone();
|
let cmd = self.memory_cmd_sender.clone();
|
||||||
let tid = self.thread_id.fetch_add(1, Ordering::SeqCst);
|
let tid = self.thread_id_counter.fetch_add(1, Ordering::SeqCst);
|
||||||
|
let memory = self.memory.clone();
|
||||||
join_tx
|
join_tx
|
||||||
.send(std::thread::spawn(move || Worker::new(cpu, cmd, tid).run()))
|
.send(std::thread::spawn(move || {
|
||||||
|
Worker::new(cpu, cmd, tid, memory).run()
|
||||||
|
}))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
tx.send(tid).unwrap();
|
tx.send(tid).unwrap();
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
pub mod memoryflags;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub enum Message {
|
pub enum Message {
|
||||||
MutableBorrow = 0,
|
MutableBorrow = 0,
|
||||||
|
Loading…
Reference in New Issue
Block a user