mirror of
https://github.com/sgmarz/osblog.git
synced 2024-11-27 20:03:32 +04:00
Updated to allow for system calls that change process state
This commit is contained in:
parent
e39f6b71c5
commit
599627b74a
@ -38,9 +38,6 @@ m_trap_vector:
|
|||||||
# in cpu.rs we have a structure of:
|
# in cpu.rs we have a structure of:
|
||||||
# 32 gp regs 0
|
# 32 gp regs 0
|
||||||
# 32 fp regs 256
|
# 32 fp regs 256
|
||||||
# SATP register 512
|
|
||||||
# Trap stack 520
|
|
||||||
# CPU HARTID 528
|
|
||||||
# We use t6 as the temporary register because it is the very
|
# We use t6 as the temporary register because it is the very
|
||||||
# bottom register (x31)
|
# bottom register (x31)
|
||||||
.set i, 0
|
.set i, 0
|
||||||
@ -99,15 +96,22 @@ switch_to_user:
|
|||||||
# a2 - SATP Register
|
# a2 - SATP Register
|
||||||
csrw mscratch, a0
|
csrw mscratch, a0
|
||||||
|
|
||||||
// Load program counter
|
# Load program counter
|
||||||
ld a1, 520(a0)
|
ld a1, 520(a0)
|
||||||
// Load satp
|
# Load satp
|
||||||
ld a2, 512(a0)
|
ld a2, 512(a0)
|
||||||
|
# Load processor mode
|
||||||
|
ld a3, 552(a0)
|
||||||
|
# Pid
|
||||||
|
# ld a4, 544(a0)
|
||||||
|
|
||||||
# 1 << 7 is MPIE
|
# 1 << 7 is MPIE
|
||||||
# Since user mode is 00, we don't need to set anything
|
# Since user mode is 00, we don't need to set anything
|
||||||
# in MPP (bits 12:11)
|
# in MPP (bits 12:11)
|
||||||
li t0, 1 << 7 | 1 << 5
|
li t0, 1 << 7 | 1 << 5
|
||||||
|
# Combine enable bits with mode bits.
|
||||||
|
slli a3, a3, 11
|
||||||
|
or t0, t0, a3
|
||||||
csrw mstatus, t0
|
csrw mstatus, t0
|
||||||
csrw mepc, a1
|
csrw mepc, a1
|
||||||
csrw satp, a2
|
csrw satp, a2
|
||||||
@ -128,11 +132,21 @@ switch_to_user:
|
|||||||
load_gp %i, t6
|
load_gp %i, t6
|
||||||
.set i, i+1
|
.set i, i+1
|
||||||
.endr
|
.endr
|
||||||
# j .
|
|
||||||
mret
|
mret
|
||||||
|
|
||||||
|
|
||||||
.global make_syscall
|
.global make_syscall
|
||||||
make_syscall:
|
make_syscall:
|
||||||
|
# We're setting this up to work with libgloss
|
||||||
|
# They want a7 to be the system call number and all parameters
|
||||||
|
# in a0 - a5
|
||||||
|
mv a7, a0
|
||||||
|
mv a0, a1
|
||||||
|
mv a1, a2
|
||||||
|
mv a2, a3
|
||||||
|
mv a3, a4
|
||||||
|
mv a4, a5
|
||||||
|
mv a5, a6
|
||||||
ecall
|
ecall
|
||||||
ret
|
ret
|
||||||
|
@ -20,10 +20,18 @@ pub enum SatpMode {
|
|||||||
Sv48 = 9,
|
Sv48 = 9,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(usize)]
|
||||||
|
pub enum CpuMode {
|
||||||
|
User = 0,
|
||||||
|
Supervisor = 1,
|
||||||
|
Machine = 3,
|
||||||
|
}
|
||||||
|
|
||||||
/// The trap frame is set into a structure
|
/// The trap frame is set into a structure
|
||||||
/// and packed into each hart's mscratch register.
|
/// and packed into each hart's mscratch register.
|
||||||
/// This allows for quick reference and full
|
/// This allows for quick reference and full
|
||||||
/// context switch handling.
|
/// context switch handling.
|
||||||
|
/// To make offsets easier, everything will be a usize (8 bytes)
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct TrapFrame {
|
pub struct TrapFrame {
|
||||||
@ -33,6 +41,8 @@ pub struct TrapFrame {
|
|||||||
pub pc: usize, // 520
|
pub pc: usize, // 520
|
||||||
pub hartid: usize, // 528
|
pub hartid: usize, // 528
|
||||||
pub qm: usize, // 536
|
pub qm: usize, // 536
|
||||||
|
pub pid: usize, // 544
|
||||||
|
pub mode: usize, // 552
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rust requires that we initialize our structures
|
/// Rust requires that we initialize our structures
|
||||||
@ -51,6 +61,8 @@ impl TrapFrame {
|
|||||||
pc: 0,
|
pc: 0,
|
||||||
hartid: 0,
|
hartid: 0,
|
||||||
qm: 1,
|
qm: 1,
|
||||||
|
pid: 0,
|
||||||
|
mode: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,15 +3,8 @@
|
|||||||
// Stephen Marz
|
// Stephen Marz
|
||||||
// 27 Nov 2019
|
// 27 Nov 2019
|
||||||
|
|
||||||
use crate::{cpu::{TrapFrame, satp_fence_asid, build_satp, SatpMode},
|
use crate::{cpu::{build_satp, satp_fence_asid, CpuMode, SatpMode, TrapFrame},
|
||||||
page::{alloc,
|
page::{alloc, dealloc, map, unmap, zalloc, EntryBits, Table, PAGE_SIZE}};
|
||||||
dealloc,
|
|
||||||
map,
|
|
||||||
unmap,
|
|
||||||
zalloc,
|
|
||||||
EntryBits,
|
|
||||||
Table,
|
|
||||||
PAGE_SIZE}};
|
|
||||||
use alloc::collections::vec_deque::VecDeque;
|
use alloc::collections::vec_deque::VecDeque;
|
||||||
|
|
||||||
// How many pages are we going to give a process for their
|
// How many pages are we going to give a process for their
|
||||||
@ -42,6 +35,56 @@ extern "C" {
|
|||||||
fn make_syscall(a: usize) -> usize;
|
fn make_syscall(a: usize) -> usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set a process' state to running. This doesn't do any checks.
|
||||||
|
/// If this PID is not found, this returns false. Otherwise, it
|
||||||
|
/// returns true.
|
||||||
|
pub fn set_running(pid: u16) -> bool {
|
||||||
|
// Yes, this is O(n). A better idea here would be a static list
|
||||||
|
// of process pointers.
|
||||||
|
let mut retval = false;
|
||||||
|
unsafe {
|
||||||
|
if let Some(mut pl) = PROCESS_LIST.take() {
|
||||||
|
for proc in pl.iter_mut() {
|
||||||
|
if proc.pid == pid {
|
||||||
|
proc.set_state(ProcessState::Running);
|
||||||
|
retval = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Now, we no longer need the owned Deque, so we hand it
|
||||||
|
// back by replacing the PROCESS_LIST's None with the
|
||||||
|
// Some(pl).
|
||||||
|
PROCESS_LIST.replace(pl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
retval
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set a process' state to waiting. This doesn't do any checks.
|
||||||
|
/// If this PID is not found, this returns false. Otherwise, it
|
||||||
|
/// returns true.
|
||||||
|
pub fn set_waiting(pid: u16) -> bool {
|
||||||
|
// Yes, this is O(n). A better idea here would be a static list
|
||||||
|
// of process pointers.
|
||||||
|
let mut retval = false;
|
||||||
|
unsafe {
|
||||||
|
if let Some(mut pl) = PROCESS_LIST.take() {
|
||||||
|
for proc in pl.iter_mut() {
|
||||||
|
if proc.pid == pid {
|
||||||
|
proc.set_state(ProcessState::Waiting);
|
||||||
|
retval = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Now, we no longer need the owned Deque, so we hand it
|
||||||
|
// back by replacing the PROCESS_LIST's None with the
|
||||||
|
// Some(pl).
|
||||||
|
PROCESS_LIST.replace(pl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
retval
|
||||||
|
}
|
||||||
|
|
||||||
/// We will eventually move this function out of here, but its
|
/// We will eventually move this function out of here, but its
|
||||||
/// job is just to take a slot in the process list.
|
/// job is just to take a slot in the process list.
|
||||||
fn init_process() {
|
fn init_process() {
|
||||||
@ -50,6 +93,7 @@ fn init_process() {
|
|||||||
let mut i: usize = 0;
|
let mut i: usize = 0;
|
||||||
loop {
|
loop {
|
||||||
i += 1;
|
i += 1;
|
||||||
|
// Eventually, this will be a sleep system call.
|
||||||
if i > 100_000_000 {
|
if i > 100_000_000 {
|
||||||
unsafe {
|
unsafe {
|
||||||
make_syscall(1);
|
make_syscall(1);
|
||||||
@ -89,6 +133,61 @@ pub fn add_process_default(pr: fn()) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add a kernel process.
|
||||||
|
pub fn add_kernel_process(func: fn()) {
|
||||||
|
// This is the Rust-ism that really trips up C++ programmers.
|
||||||
|
// PROCESS_LIST is wrapped in an Option<> enumeration, which
|
||||||
|
// means that the Option owns the Deque. We can only borrow from
|
||||||
|
// it or move ownership to us. In this case, we choose the
|
||||||
|
// latter, where we move ownership to us, add a process, and
|
||||||
|
// then move ownership back to the PROCESS_LIST.
|
||||||
|
// This allows mutual exclusion as anyone else trying to grab
|
||||||
|
// the process list will get None rather than the Deque.
|
||||||
|
if let Some(mut pl) = unsafe { PROCESS_LIST.take() } {
|
||||||
|
// .take() will replace PROCESS_LIST with None and give
|
||||||
|
// us the only copy of the Deque.
|
||||||
|
let func_addr = func as usize;
|
||||||
|
let func_vaddr = func_addr; //- 0x6000_0000;
|
||||||
|
// println!("func_addr = {:x} -> {:x}", func_addr, func_vaddr);
|
||||||
|
// We will convert NEXT_PID below into an atomic increment when
|
||||||
|
// we start getting into multi-hart processing. For now, we want
|
||||||
|
// a process. Get it to work, then improve it!
|
||||||
|
let mut ret_proc = Process { frame: zalloc(1) as *mut TrapFrame,
|
||||||
|
stack: alloc(STACK_PAGES),
|
||||||
|
pid: unsafe { NEXT_PID },
|
||||||
|
root: zalloc(1) as *mut Table,
|
||||||
|
state: ProcessState::Running,
|
||||||
|
data: ProcessData::zero(),
|
||||||
|
sleep_until: 0, };
|
||||||
|
unsafe {
|
||||||
|
NEXT_PID += 1;
|
||||||
|
}
|
||||||
|
// Now we move the stack pointer to the bottom of the
|
||||||
|
// allocation. The spec shows that register x2 (2) is the stack
|
||||||
|
// pointer.
|
||||||
|
// We could use ret_proc.stack.add, but that's an unsafe
|
||||||
|
// function which would require an unsafe block. So, convert it
|
||||||
|
// to usize first and then add PAGE_SIZE is better.
|
||||||
|
// We also need to set the stack adjustment so that it is at the
|
||||||
|
// bottom of the memory and far away from heap allocations.
|
||||||
|
unsafe {
|
||||||
|
(*ret_proc.frame).pc = func_vaddr;
|
||||||
|
(*ret_proc.frame).regs[2] = ret_proc.stack as usize + STACK_PAGES * 4096;
|
||||||
|
(*ret_proc.frame).mode = CpuMode::Machine as usize;
|
||||||
|
(*ret_proc.frame).pid = ret_proc.pid as usize;
|
||||||
|
}
|
||||||
|
pl.push_back(ret_proc);
|
||||||
|
// Now, we no longer need the owned Deque, so we hand it
|
||||||
|
// back by replacing the PROCESS_LIST's None with the
|
||||||
|
// Some(pl).
|
||||||
|
unsafe { PROCESS_LIST.replace(pl); }
|
||||||
|
}
|
||||||
|
// TODO: When we get to multi-hart processing, we need to keep
|
||||||
|
// trying to grab the process list. We can do this with an
|
||||||
|
// atomic instruction. but right now, we're a single-processor
|
||||||
|
// computer.
|
||||||
|
}
|
||||||
|
|
||||||
/// This should only be called once, and its job is to create
|
/// This should only be called once, and its job is to create
|
||||||
/// the init process. Right now, this process is in the kernel,
|
/// the init process. Right now, this process is in the kernel,
|
||||||
/// but later, it should call the shell.
|
/// but later, it should call the shell.
|
||||||
@ -147,21 +246,31 @@ impl Process {
|
|||||||
pub fn get_frame_address(&self) -> usize {
|
pub fn get_frame_address(&self) -> usize {
|
||||||
self.frame as usize
|
self.frame as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_program_counter(&self) -> usize {
|
pub fn get_program_counter(&self) -> usize {
|
||||||
unsafe { (*self.frame).pc }
|
unsafe { (*self.frame).pc }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_table_address(&self) -> usize {
|
pub fn get_table_address(&self) -> usize {
|
||||||
self.root as usize
|
self.root as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_state(&self) -> &ProcessState {
|
pub fn get_state(&self) -> &ProcessState {
|
||||||
&self.state
|
&self.state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_state(&mut self, ps: ProcessState) {
|
||||||
|
self.state = ps;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_pid(&self) -> u16 {
|
pub fn get_pid(&self) -> u16 {
|
||||||
self.pid
|
self.pid
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_sleep_until(&self) -> usize {
|
pub fn get_sleep_until(&self) -> usize {
|
||||||
self.sleep_until
|
self.sleep_until
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_default(func: fn()) -> Self {
|
pub fn new_default(func: fn()) -> Self {
|
||||||
let func_addr = func as usize;
|
let func_addr = func as usize;
|
||||||
let func_vaddr = func_addr; //- 0x6000_0000;
|
let func_vaddr = func_addr; //- 0x6000_0000;
|
||||||
@ -169,15 +278,13 @@ impl Process {
|
|||||||
// We will convert NEXT_PID below into an atomic increment when
|
// We will convert NEXT_PID below into an atomic increment when
|
||||||
// we start getting into multi-hart processing. For now, we want
|
// we start getting into multi-hart processing. For now, we want
|
||||||
// a process. Get it to work, then improve it!
|
// a process. Get it to work, then improve it!
|
||||||
let mut ret_proc =
|
let mut ret_proc = Process { frame: zalloc(1) as *mut TrapFrame,
|
||||||
Process { frame: zalloc(1) as *mut TrapFrame,
|
|
||||||
stack: alloc(STACK_PAGES),
|
stack: alloc(STACK_PAGES),
|
||||||
pid: unsafe { NEXT_PID },
|
pid: unsafe { NEXT_PID },
|
||||||
root: zalloc(1) as *mut Table,
|
root: zalloc(1) as *mut Table,
|
||||||
state: ProcessState::Running,
|
state: ProcessState::Running,
|
||||||
data: ProcessData::zero(),
|
data: ProcessData::zero(),
|
||||||
sleep_until: 0
|
sleep_until: 0, };
|
||||||
};
|
|
||||||
unsafe {
|
unsafe {
|
||||||
satp_fence_asid(NEXT_PID as usize);
|
satp_fence_asid(NEXT_PID as usize);
|
||||||
NEXT_PID += 1;
|
NEXT_PID += 1;
|
||||||
@ -194,50 +301,37 @@ impl Process {
|
|||||||
unsafe {
|
unsafe {
|
||||||
(*ret_proc.frame).pc = func_vaddr;
|
(*ret_proc.frame).pc = func_vaddr;
|
||||||
(*ret_proc.frame).regs[2] = STACK_ADDR + PAGE_SIZE * STACK_PAGES;
|
(*ret_proc.frame).regs[2] = STACK_ADDR + PAGE_SIZE * STACK_PAGES;
|
||||||
|
(*ret_proc.frame).mode = CpuMode::User as usize;
|
||||||
|
(*ret_proc.frame).pid = ret_proc.pid as usize;
|
||||||
}
|
}
|
||||||
// Map the stack on the MMU
|
// Map the stack on the MMU
|
||||||
let pt;
|
let pt;
|
||||||
unsafe {
|
unsafe {
|
||||||
pt = &mut *ret_proc.root;
|
pt = &mut *ret_proc.root;
|
||||||
(*ret_proc.frame).satp = build_satp(SatpMode::Sv39, ret_proc.pid as usize, ret_proc.root as usize);
|
(*ret_proc.frame).satp =
|
||||||
|
build_satp(SatpMode::Sv39, ret_proc.pid as usize, ret_proc.root as usize);
|
||||||
}
|
}
|
||||||
// We need to map the stack onto the user process' virtual
|
// We need to map the stack onto the user process' virtual
|
||||||
// memory This gets a little hairy because we need to also map
|
// memory This gets a little hairy because we need to also map
|
||||||
// the function code too.
|
// the function code too.
|
||||||
for i in 0..STACK_PAGES {
|
for i in 0..STACK_PAGES {
|
||||||
let addr = i * PAGE_SIZE;
|
let addr = i * PAGE_SIZE;
|
||||||
map(
|
map(pt, STACK_ADDR + addr, saddr + addr, EntryBits::UserReadWrite.val(), 0);
|
||||||
pt,
|
|
||||||
STACK_ADDR + addr,
|
|
||||||
saddr + addr,
|
|
||||||
EntryBits::UserReadWrite.val(),
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
// println!("Set stack from 0x{:016x} -> 0x{:016x}", STACK_ADDR + addr, saddr + addr);
|
// println!("Set stack from 0x{:016x} -> 0x{:016x}", STACK_ADDR + addr, saddr + addr);
|
||||||
}
|
}
|
||||||
// Map the program counter on the MMU and other bits
|
// Map the program counter on the MMU and other bits
|
||||||
for i in 0..=100 {
|
for i in 0..=100 {
|
||||||
let modifier = i * 0x1000;
|
let modifier = i * 0x1000;
|
||||||
map(
|
map(pt, func_vaddr + modifier, func_addr + modifier, EntryBits::UserReadWriteExecute.val(), 0);
|
||||||
pt,
|
|
||||||
func_vaddr + modifier,
|
|
||||||
func_addr + modifier,
|
|
||||||
EntryBits::UserReadWriteExecute.val(),
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
// This is the make_syscall function
|
// This is the make_syscall function
|
||||||
// The reason we need this is because we're running a process
|
// The reason we need this is because we're running a process
|
||||||
// that is inside of the kernel. When we start loading from a block
|
// that is inside of the kernel. When we start loading from a block
|
||||||
// devices, we can load the instructions anywhere in memory.
|
// devices, we can load the instructions anywhere in memory.
|
||||||
map(pt, 0x8000_0000, 0x8000_0000, EntryBits::UserReadExecute.val(), 0);
|
for i in 0..=7 {
|
||||||
map(pt, 0x8000_1000, 0x8000_1000, EntryBits::UserReadExecute.val(), 0);
|
let addr = 0x8000_0000 | i << 12;
|
||||||
map(pt, 0x8000_2000, 0x8000_2000, EntryBits::UserReadExecute.val(), 0);
|
map(pt, addr, addr, EntryBits::UserReadExecute.val(), 0);
|
||||||
map(pt, 0x8000_3000, 0x8000_3000, EntryBits::UserReadExecute.val(), 0);
|
}
|
||||||
map(pt, 0x8000_4000, 0x8000_4000, EntryBits::UserReadExecute.val(), 0);
|
|
||||||
map(pt, 0x8000_5000, 0x8000_5000, EntryBits::UserReadExecute.val(), 0);
|
|
||||||
map(pt, 0x8000_6000, 0x8000_6000, EntryBits::UserReadExecute.val(), 0);
|
|
||||||
map(pt, 0x8000_7000, 0x8000_7000, EntryBits::UserReadExecute.val(), 0);
|
|
||||||
ret_proc
|
ret_proc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,12 @@
|
|||||||
use crate::process::{ProcessState, PROCESS_LIST};
|
use crate::process::{ProcessState, PROCESS_LIST};
|
||||||
|
|
||||||
pub fn schedule() -> usize {
|
pub fn schedule() -> usize {
|
||||||
|
let mut frame_addr: usize = 0x1111;
|
||||||
unsafe {
|
unsafe {
|
||||||
if let Some(mut pl) = PROCESS_LIST.take() {
|
if let Some(mut pl) = PROCESS_LIST.take() {
|
||||||
|
let mut done = false;
|
||||||
|
while !done {
|
||||||
pl.rotate_left(1);
|
pl.rotate_left(1);
|
||||||
let mut frame_addr: usize = 0;
|
|
||||||
// let mut mepc: usize = 0;
|
// let mut mepc: usize = 0;
|
||||||
// let mut satp: usize = 0;
|
// let mut satp: usize = 0;
|
||||||
// let mut pid: usize = 0;
|
// let mut pid: usize = 0;
|
||||||
@ -18,6 +20,8 @@ pub fn schedule() -> usize {
|
|||||||
ProcessState::Running => {
|
ProcessState::Running => {
|
||||||
frame_addr =
|
frame_addr =
|
||||||
prc.get_frame_address();
|
prc.get_frame_address();
|
||||||
|
done = true;
|
||||||
|
// println!("Process is running on frame 0x{:x}", frame_addr);
|
||||||
// satp = prc.get_table_address();
|
// satp = prc.get_table_address();
|
||||||
// pid = prc.get_pid() as usize;
|
// pid = prc.get_pid() as usize;
|
||||||
},
|
},
|
||||||
@ -25,17 +29,12 @@ pub fn schedule() -> usize {
|
|||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// println!("Scheduling {}", pid);
|
}
|
||||||
PROCESS_LIST.replace(pl);
|
PROCESS_LIST.replace(pl);
|
||||||
if frame_addr != 0 {
|
}
|
||||||
// MODE 8 is 39-bit virtual address MMU
|
else {
|
||||||
// I'm using the PID as the address space
|
println!("could not take process list");
|
||||||
// identifier to hopefully help with (not?)
|
|
||||||
// flushing the TLB whenever we switch
|
|
||||||
// processes.
|
|
||||||
return frame_addr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
frame_addr
|
||||||
0
|
|
||||||
}
|
}
|
||||||
|
@ -3,13 +3,13 @@
|
|||||||
// Stephen Marz
|
// Stephen Marz
|
||||||
// 3 Jan 2020
|
// 3 Jan 2020
|
||||||
|
|
||||||
use crate::cpu::TrapFrame;
|
use crate::{block::process_read, cpu::TrapFrame};
|
||||||
|
|
||||||
pub fn do_syscall(mepc: usize, frame: *mut TrapFrame) -> usize {
|
pub fn do_syscall(mepc: usize, frame: *mut TrapFrame) -> usize {
|
||||||
let syscall_number;
|
let syscall_number;
|
||||||
unsafe {
|
unsafe {
|
||||||
// A0 is X10, so it's register number 10.
|
// A7 is X17, so it's register number 17.
|
||||||
syscall_number = (*frame).regs[10];
|
syscall_number = (*frame).regs[17];
|
||||||
// for i in 0..32 {
|
// for i in 0..32 {
|
||||||
// print!("regs[{:02}] = 0x{:08x} ", i, (*frame).regs[i]);
|
// print!("regs[{:02}] = 0x{:08x} ", i, (*frame).regs[i]);
|
||||||
// if (i+1) % 4 == 0 {
|
// if (i+1) % 4 == 0 {
|
||||||
@ -17,8 +17,52 @@ pub fn do_syscall(mepc: usize, frame: *mut TrapFrame) -> usize {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
// These system call numbers come from libgloss so that we can use newlib
|
||||||
|
// for our system calls.
|
||||||
|
// Libgloss wants the system call number in A7 and arguments in A0..A6
|
||||||
|
// #define SYS_getcwd 17
|
||||||
|
// #define SYS_dup 23
|
||||||
|
// #define SYS_fcntl 25
|
||||||
|
// #define SYS_faccessat 48
|
||||||
|
// #define SYS_chdir 49
|
||||||
|
// #define SYS_openat 56
|
||||||
|
// #define SYS_close 57
|
||||||
|
// #define SYS_getdents 61
|
||||||
|
// #define SYS_lseek 62
|
||||||
|
// #define SYS_read 63
|
||||||
|
// #define SYS_write 64
|
||||||
|
// #define SYS_writev 66
|
||||||
|
// #define SYS_pread 67
|
||||||
|
// #define SYS_pwrite 68
|
||||||
|
// #define SYS_fstatat 79
|
||||||
|
// #define SYS_fstat 80
|
||||||
|
// #define SYS_exit 93
|
||||||
|
// #define SYS_exit_group 94
|
||||||
|
// #define SYS_kill 129
|
||||||
|
// #define SYS_rt_sigaction 134
|
||||||
|
// #define SYS_times 153
|
||||||
|
// #define SYS_uname 160
|
||||||
|
// #define SYS_gettimeofday 169
|
||||||
|
// #define SYS_getpid 172
|
||||||
|
// #define SYS_getuid 174
|
||||||
|
// #define SYS_geteuid 175
|
||||||
|
// #define SYS_getgid 176
|
||||||
|
// #define SYS_getegid 177
|
||||||
|
// #define SYS_brk 214
|
||||||
|
// #define SYS_munmap 215
|
||||||
|
// #define SYS_mremap 216
|
||||||
|
// #define SYS_mmap 222
|
||||||
|
// #define SYS_open 1024
|
||||||
|
// #define SYS_link 1025
|
||||||
|
// #define SYS_unlink 1026
|
||||||
|
// #define SYS_mkdir 1030
|
||||||
|
// #define SYS_access 1033
|
||||||
|
// #define SYS_stat 1038
|
||||||
|
// #define SYS_lstat 1039
|
||||||
|
// #define SYS_time 1062
|
||||||
|
// #define SYS_getmainvars 2011
|
||||||
match syscall_number {
|
match syscall_number {
|
||||||
0 => {
|
0 | 93 => {
|
||||||
// Exit
|
// Exit
|
||||||
// Currently, we cannot kill a process, it runs forever. We will delete
|
// Currently, we cannot kill a process, it runs forever. We will delete
|
||||||
// the process later and free the resources, but for now, we want to get
|
// the process later and free the resources, but for now, we want to get
|
||||||
@ -29,9 +73,23 @@ pub fn do_syscall(mepc: usize, frame: *mut TrapFrame) -> usize {
|
|||||||
println!("Test syscall");
|
println!("Test syscall");
|
||||||
mepc + 4
|
mepc + 4
|
||||||
},
|
},
|
||||||
|
63 => unsafe {
|
||||||
|
// Read system call
|
||||||
|
// This is an asynchronous call. This will get the process going. We won't hear the answer until
|
||||||
|
// we an interrupt back.
|
||||||
|
let _ = process_read(
|
||||||
|
(*frame).pid as u16,
|
||||||
|
(*frame).regs[10],
|
||||||
|
(*frame).regs[11] as *mut u8,
|
||||||
|
(*frame).regs[12] as u32,
|
||||||
|
(*frame).regs[13] as u64,
|
||||||
|
);
|
||||||
|
// If we return 0, the trap handler will schedule another process.
|
||||||
|
0
|
||||||
|
},
|
||||||
_ => {
|
_ => {
|
||||||
println!("Unknown syscall number {}", syscall_number);
|
println!("Unknown syscall number {}", syscall_number);
|
||||||
mepc + 4
|
mepc + 4
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -37,11 +37,15 @@ extern "C" fn m_trap(epc: usize,
|
|||||||
// number. So, here we narrow down just the cause number.
|
// number. So, here we narrow down just the cause number.
|
||||||
let cause_num = cause & 0xfff;
|
let cause_num = cause & 0xfff;
|
||||||
let mut return_pc = epc;
|
let mut return_pc = epc;
|
||||||
|
unsafe {
|
||||||
|
(*frame).pc = return_pc;
|
||||||
|
}
|
||||||
if is_async {
|
if is_async {
|
||||||
// Asynchronous trap
|
// Asynchronous trap
|
||||||
match cause_num {
|
match cause_num {
|
||||||
3 => {
|
3 => {
|
||||||
// Machine software
|
// We will use this to awaken our other CPUs so they can process
|
||||||
|
// processes.
|
||||||
println!("Machine software interrupt CPU #{}", hart);
|
println!("Machine software interrupt CPU #{}", hart);
|
||||||
},
|
},
|
||||||
7 => {
|
7 => {
|
||||||
@ -80,19 +84,19 @@ extern "C" fn m_trap(epc: usize,
|
|||||||
// them later.
|
// them later.
|
||||||
loop {}
|
loop {}
|
||||||
},
|
},
|
||||||
8 => {
|
8 | 9 | 11 => unsafe {
|
||||||
// Environment (system) call from User mode
|
// Environment (system) call from User, Supervisor, and Machine modes
|
||||||
// println!("E-call from User mode! CPU#{} -> 0x{:08x}", hart, epc);
|
// println!("E-call from User mode! CPU#{} -> 0x{:08x}", hart, epc);
|
||||||
return_pc = do_syscall(return_pc, frame);
|
return_pc = do_syscall(return_pc, frame);
|
||||||
},
|
if return_pc == 0 {
|
||||||
9 => {
|
// We are about to schedule something else here, so we need to store PAST
|
||||||
// Environment (system) call from Supervisor mode
|
// the system call so that when we resume this process, we're after the ecall.
|
||||||
println!("E-call from Supervisor mode! CPU#{} -> 0x{:08x}", hart, epc);
|
(*frame).pc += 4;
|
||||||
return_pc = do_syscall(return_pc, frame);
|
let frame = schedule();
|
||||||
},
|
// let p = frame as *const crate::process::Process;
|
||||||
11 => {
|
schedule_next_context_switch(1);
|
||||||
// Environment (system) call from Machine mode
|
rust_switch_to_user(frame);
|
||||||
panic!("E-call from Machine mode! CPU#{} -> 0x{:08x}\n", hart, epc);
|
}
|
||||||
},
|
},
|
||||||
// Page faults
|
// Page faults
|
||||||
12 => {
|
12 => {
|
||||||
|
Loading…
Reference in New Issue
Block a user