mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-27 03:13:23 +00:00
finish user mode execute
This commit is contained in:
@ -1,5 +1,9 @@
|
|||||||
//! CPU.
|
//! CPU.
|
||||||
|
|
||||||
|
use x86_64::registers::model_specific::FsBase;
|
||||||
|
|
||||||
|
use crate::trap::{CalleeRegs, CallerRegs, SyscallFrame, TrapFrame};
|
||||||
|
|
||||||
/// Defines a CPU-local variable.
|
/// Defines a CPU-local variable.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! cpu_local {
|
macro_rules! cpu_local {
|
||||||
@ -19,7 +23,7 @@ pub fn this_cpu() -> u32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Cpu context, including both general-purpose registers and floating-point registers.
|
/// Cpu context, including both general-purpose registers and floating-point registers.
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default, Copy)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct CpuContext {
|
pub struct CpuContext {
|
||||||
pub gp_regs: GpRegs,
|
pub gp_regs: GpRegs,
|
||||||
@ -51,8 +55,118 @@ pub struct GpRegs {
|
|||||||
pub rflag: u64,
|
pub rflag: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<SyscallFrame> for CpuContext {
|
||||||
|
fn from(syscall: SyscallFrame) -> Self {
|
||||||
|
Self {
|
||||||
|
gp_regs: GpRegs {
|
||||||
|
r8: syscall.caller.r8 as u64,
|
||||||
|
r9: syscall.caller.r9 as u64,
|
||||||
|
r10: syscall.caller.r10 as u64,
|
||||||
|
r11: syscall.caller.r11 as u64,
|
||||||
|
r12: syscall.callee.r12 as u64,
|
||||||
|
r13: syscall.callee.r13 as u64,
|
||||||
|
r14: syscall.callee.r14 as u64,
|
||||||
|
r15: syscall.callee.r15 as u64,
|
||||||
|
rdi: syscall.caller.rdi as u64,
|
||||||
|
rsi: syscall.caller.rsi as u64,
|
||||||
|
rbp: syscall.callee.rbp as u64,
|
||||||
|
rbx: syscall.callee.rbx as u64,
|
||||||
|
rdx: syscall.caller.rdx as u64,
|
||||||
|
rax: syscall.caller.rax as u64,
|
||||||
|
rcx: syscall.caller.rcx as u64,
|
||||||
|
rsp: syscall.callee.rsp as u64,
|
||||||
|
rip: 0,
|
||||||
|
rflag: 0,
|
||||||
|
},
|
||||||
|
fs_base: 0,
|
||||||
|
fp_regs: FpRegs::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<SyscallFrame> for CpuContext {
|
||||||
|
fn into(self) -> SyscallFrame {
|
||||||
|
SyscallFrame {
|
||||||
|
caller: CallerRegs {
|
||||||
|
rax: self.gp_regs.rax as usize,
|
||||||
|
rcx: self.gp_regs.rcx as usize,
|
||||||
|
rdx: self.gp_regs.rdx as usize,
|
||||||
|
rsi: self.gp_regs.rsi as usize,
|
||||||
|
rdi: self.gp_regs.rdi as usize,
|
||||||
|
r8: self.gp_regs.r8 as usize,
|
||||||
|
r9: self.gp_regs.r9 as usize,
|
||||||
|
r10: self.gp_regs.r10 as usize,
|
||||||
|
r11: self.gp_regs.r11 as usize,
|
||||||
|
},
|
||||||
|
callee: CalleeRegs {
|
||||||
|
rsp: self.gp_regs.rsp as usize,
|
||||||
|
rbx: self.gp_regs.rbx as usize,
|
||||||
|
rbp: self.gp_regs.rbp as usize,
|
||||||
|
r12: self.gp_regs.r12 as usize,
|
||||||
|
r13: self.gp_regs.r13 as usize,
|
||||||
|
r14: self.gp_regs.r14 as usize,
|
||||||
|
r15: self.gp_regs.r15 as usize,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TrapFrame> for CpuContext {
|
||||||
|
fn from(trap: TrapFrame) -> Self {
|
||||||
|
Self {
|
||||||
|
gp_regs: GpRegs {
|
||||||
|
r8: trap.regs.r8 as u64,
|
||||||
|
r9: trap.regs.r9 as u64,
|
||||||
|
r10: trap.regs.r10 as u64,
|
||||||
|
r11: trap.regs.r11 as u64,
|
||||||
|
r12: trap.id as u64,
|
||||||
|
r13: trap.err as u64,
|
||||||
|
r14: trap.cs as u64,
|
||||||
|
r15: trap.ss as u64,
|
||||||
|
rdi: trap.regs.rdi as u64,
|
||||||
|
rsi: trap.regs.rsi as u64,
|
||||||
|
rbp: 0 as u64,
|
||||||
|
rbx: 0 as u64,
|
||||||
|
rdx: trap.regs.rdx as u64,
|
||||||
|
rax: trap.regs.rax as u64,
|
||||||
|
rcx: trap.regs.rcx as u64,
|
||||||
|
rsp: trap.rsp as u64,
|
||||||
|
rip: trap.rip as u64,
|
||||||
|
rflag: trap.rflags as u64,
|
||||||
|
},
|
||||||
|
fs_base: 0,
|
||||||
|
fp_regs: FpRegs::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<TrapFrame> for CpuContext {
|
||||||
|
fn into(self) -> TrapFrame {
|
||||||
|
TrapFrame {
|
||||||
|
regs: CallerRegs {
|
||||||
|
rax: self.gp_regs.rax as usize,
|
||||||
|
rcx: self.gp_regs.rcx as usize,
|
||||||
|
rdx: self.gp_regs.rdx as usize,
|
||||||
|
rsi: self.gp_regs.rsi as usize,
|
||||||
|
rdi: self.gp_regs.rdi as usize,
|
||||||
|
r8: self.gp_regs.r8 as usize,
|
||||||
|
r9: self.gp_regs.r9 as usize,
|
||||||
|
r10: self.gp_regs.r10 as usize,
|
||||||
|
r11: self.gp_regs.r11 as usize,
|
||||||
|
},
|
||||||
|
id: self.gp_regs.r12 as usize,
|
||||||
|
err: self.gp_regs.r13 as usize,
|
||||||
|
rip: self.gp_regs.rip as usize,
|
||||||
|
cs: self.gp_regs.r14 as usize,
|
||||||
|
rflags: self.gp_regs.rflag as usize,
|
||||||
|
rsp: self.gp_regs.rsp as usize,
|
||||||
|
ss: self.gp_regs.r15 as usize,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The floating-point state of CPU.
|
/// The floating-point state of CPU.
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Copy)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct FpRegs {
|
pub struct FpRegs {
|
||||||
//buf: Aligned<A16, [u8; 512]>,
|
//buf: Aligned<A16, [u8; 512]>,
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
#![feature(alloc_error_handler)]
|
#![feature(alloc_error_handler)]
|
||||||
#![feature(core_intrinsics)]
|
#![feature(core_intrinsics)]
|
||||||
#![feature(new_uninit)]
|
#![feature(new_uninit)]
|
||||||
|
#![feature(link_llvm_intrinsics)]
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
pub mod cell;
|
pub mod cell;
|
||||||
@ -44,7 +46,6 @@ pub fn init(boot_info: &'static mut BootInfo) {
|
|||||||
let siz = boot_info.framebuffer.as_ref().unwrap() as *const FrameBuffer as usize;
|
let siz = boot_info.framebuffer.as_ref().unwrap() as *const FrameBuffer as usize;
|
||||||
device::init(boot_info.framebuffer.as_mut().unwrap());
|
device::init(boot_info.framebuffer.as_mut().unwrap());
|
||||||
device::framebuffer::WRITER.lock().as_mut().unwrap().clear();
|
device::framebuffer::WRITER.lock().as_mut().unwrap().clear();
|
||||||
println!("{:x}", siz);
|
|
||||||
trap::init();
|
trap::init();
|
||||||
let mut memory_init = false;
|
let mut memory_init = false;
|
||||||
// memory
|
// memory
|
||||||
@ -65,17 +66,6 @@ pub fn init(boot_info: &'static mut BootInfo) {
|
|||||||
panic!("memory init failed");
|
panic!("memory init failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
// breakpoint
|
|
||||||
let breakpoint_irq: Arc<&IrqLine>;
|
|
||||||
unsafe {
|
|
||||||
breakpoint_irq = IrqLine::acquire(3);
|
|
||||||
}
|
|
||||||
let a = breakpoint_irq.on_active(breakpoint_handler);
|
|
||||||
x86_64::instructions::interrupts::int3(); // breakpoint
|
|
||||||
}
|
|
||||||
|
|
||||||
fn breakpoint_handler(interrupt_information: TrapFrame) {
|
|
||||||
println!("EXCEPTION: BREAKPOINT\n{:#?}", interrupt_information);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -7,19 +7,24 @@ use crate::{
|
|||||||
*,
|
*,
|
||||||
};
|
};
|
||||||
use alloc::collections::{btree_map::Entry, BTreeMap};
|
use alloc::collections::{btree_map::Entry, BTreeMap};
|
||||||
|
use alloc::vec;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
pub struct MapArea {
|
pub struct MapArea {
|
||||||
/// flags
|
/// flags
|
||||||
pub flags: PTFlags,
|
pub flags: PTFlags,
|
||||||
|
/// start virtual address
|
||||||
|
pub start_va: VirtAddr,
|
||||||
|
/// the size of these area
|
||||||
|
pub size : usize,
|
||||||
/// all the map information
|
/// all the map information
|
||||||
pub mapper: BTreeMap<VirtAddr, VmFrame>,
|
pub mapper: BTreeMap<VirtAddr, VmFrame>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MemorySet {
|
pub struct MemorySet {
|
||||||
pub pt: PageTable,
|
pub pt: PageTable,
|
||||||
/// all the map area
|
/// all the map area, sort by the start virtual address
|
||||||
area: Option<MapArea>,
|
areas: BTreeMap<VirtAddr,MapArea>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MapArea {
|
impl MapArea {
|
||||||
@ -27,6 +32,16 @@ impl MapArea {
|
|||||||
self.mapper.len()
|
self.mapper.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clone(&self) -> Self {
|
||||||
|
let mut mapper = BTreeMap::new();
|
||||||
|
for (&va, old) in &self.mapper {
|
||||||
|
let new = PhysFrame::alloc().unwrap();
|
||||||
|
new.as_slice().copy_from_slice(old.physical_frame.exclusive_access().as_slice());
|
||||||
|
mapper.insert(va, unsafe{VmFrame::new(new)});
|
||||||
|
}
|
||||||
|
Self { start_va: self.start_va, size: self.size, flags: self.flags, mapper }
|
||||||
|
}
|
||||||
|
|
||||||
/// This function will map the vitural address to the given physical frames
|
/// This function will map the vitural address to the given physical frames
|
||||||
pub fn new(
|
pub fn new(
|
||||||
start_va: VirtAddr,
|
start_va: VirtAddr,
|
||||||
@ -42,6 +57,8 @@ impl MapArea {
|
|||||||
|
|
||||||
let mut map_area = Self {
|
let mut map_area = Self {
|
||||||
flags,
|
flags,
|
||||||
|
start_va,
|
||||||
|
size,
|
||||||
mapper: BTreeMap::new(),
|
mapper: BTreeMap::new(),
|
||||||
};
|
};
|
||||||
let mut current_va = start_va.clone();
|
let mut current_va = start_va.clone();
|
||||||
@ -82,136 +99,153 @@ impl MapArea {
|
|||||||
self.mapper.remove(&va)
|
self.mapper.remove(&va)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_data(&mut self, offset: usize, data: &[u8]) {
|
pub fn write_data(&mut self, addr: usize, data: &[u8]) {
|
||||||
let mut start = offset;
|
let mut current_start_address = addr;
|
||||||
let mut remain = data.len();
|
|
||||||
let mut processed = 0;
|
|
||||||
for (va, pa) in self.mapper.iter_mut() {
|
|
||||||
if start >= PAGE_SIZE {
|
|
||||||
start -= PAGE_SIZE;
|
|
||||||
} else {
|
|
||||||
let copy_len = (PAGE_SIZE - start).min(remain);
|
|
||||||
let src = &data[processed..processed + copy_len];
|
|
||||||
let dst = &mut pa.start_pa().kvaddr().get_bytes_array()[start..src.len() + start];
|
|
||||||
dst.copy_from_slice(src);
|
|
||||||
processed += copy_len;
|
|
||||||
remain -= copy_len;
|
|
||||||
start = 0;
|
|
||||||
if remain == 0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_data(&self, offset: usize, data: &mut [u8]) {
|
|
||||||
let mut start = offset;
|
|
||||||
let mut remain = data.len();
|
let mut remain = data.len();
|
||||||
let mut processed = 0;
|
let mut processed = 0;
|
||||||
for (va, pa) in self.mapper.iter() {
|
for (va, pa) in self.mapper.iter() {
|
||||||
if start >= PAGE_SIZE {
|
if current_start_address >= va.0 && current_start_address <va.0+PAGE_SIZE{
|
||||||
start -= PAGE_SIZE;
|
let offset = current_start_address-va.0;
|
||||||
} else {
|
let copy_len = (va.0+PAGE_SIZE - current_start_address).min(remain);
|
||||||
let copy_len = (PAGE_SIZE - start).min(remain);
|
let src = &data[processed..processed + copy_len];
|
||||||
let src = &mut data[processed..processed + copy_len];
|
let dst = &mut pa.start_pa().kvaddr().get_bytes_array()[offset..copy_len];
|
||||||
let dst = &mut pa.start_pa().kvaddr().get_bytes_array()[start..src.len() + start];
|
dst.copy_from_slice(src);
|
||||||
src.copy_from_slice(dst);
|
|
||||||
processed += copy_len;
|
processed += copy_len;
|
||||||
remain -= copy_len;
|
remain -= copy_len;
|
||||||
start = 0;
|
|
||||||
if remain == 0 {
|
if remain == 0 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
current_start_address = va.0+PAGE_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_data(&self, addr: usize, data: &mut [u8]) {
|
||||||
|
let mut start = addr;
|
||||||
|
let mut remain = data.len();
|
||||||
|
let mut processed = 0;
|
||||||
|
for (va, pa) in self.mapper.iter() {
|
||||||
|
if start >= va.0 && start <va.0+PAGE_SIZE{
|
||||||
|
let offset = start-va.0;
|
||||||
|
let copy_len = (va.0+PAGE_SIZE - start).min(remain);
|
||||||
|
let src = &mut data[processed..processed + copy_len];
|
||||||
|
let dst = &pa.start_pa().kvaddr().get_bytes_array()[offset..copy_len];
|
||||||
|
src.copy_from_slice(dst);
|
||||||
|
processed += copy_len;
|
||||||
|
remain -= copy_len;
|
||||||
|
if remain == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
start = va.0+PAGE_SIZE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for MapArea {
|
// impl Clone for MapArea {
|
||||||
fn clone(&self) -> Self {
|
// fn clone(&self) -> Self {
|
||||||
let mut mapper = BTreeMap::new();
|
// let mut mapper = BTreeMap::new();
|
||||||
for (&va, old) in &self.mapper {
|
// for (&va, old) in &self.mapper {
|
||||||
let new = VmFrame::alloc().unwrap();
|
// let new = VmFrame::alloc().unwrap();
|
||||||
new.physical_frame
|
// new.physical_frame
|
||||||
.exclusive_access()
|
// .exclusive_access()
|
||||||
.as_slice()
|
// .as_slice()
|
||||||
.copy_from_slice(old.physical_frame.exclusive_access().as_slice());
|
// .copy_from_slice(old.physical_frame.exclusive_access().as_slice());
|
||||||
mapper.insert(va, new);
|
// mapper.insert(va, new);
|
||||||
}
|
// }
|
||||||
Self {
|
// Self {
|
||||||
flags: self.flags,
|
// flags: self.flags,
|
||||||
mapper,
|
// mapper,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
impl MemorySet {
|
impl MemorySet {
|
||||||
pub fn new(area: MapArea) -> Self {
|
|
||||||
let mut pt = PageTable::new();
|
|
||||||
pt.map_area(&area);
|
|
||||||
|
|
||||||
Self {
|
pub fn map(&mut self, area: MapArea) {
|
||||||
pt: pt,
|
if area.size > 0 {
|
||||||
area: Some(area),
|
// TODO: check overlap
|
||||||
|
if let Entry::Vacant(e) = self.areas.entry(area.start_va) {
|
||||||
|
self.pt.map_area(e.insert(area));
|
||||||
|
} else {
|
||||||
|
panic!("MemorySet::map: MapArea starts from {:#x?} is existed!", area.start_va);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn zero() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
pt: PageTable::new(),
|
pt: PageTable::new(),
|
||||||
area: None,
|
areas: BTreeMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_area(&mut self, area: MapArea) {
|
|
||||||
self.pt.map_area(&area);
|
|
||||||
self.area = Some(area);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unmap(&mut self, va: VirtAddr) -> Result<()> {
|
pub fn unmap(&mut self, va: VirtAddr) -> Result<()> {
|
||||||
if self.area.is_none() {
|
if let Some(area) = self.areas.remove(&va){
|
||||||
Err(Error::InvalidArgs)
|
self.pt.unmap_area(&area);
|
||||||
} else {
|
|
||||||
self.area.take().unwrap().unmap(va);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
}else{
|
||||||
|
Err(Error::PageFault)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.pt.unmap_area(&self.area.take().unwrap());
|
for area in self.areas.values_mut() {
|
||||||
self.area = None;
|
self.pt.unmap_area(area);
|
||||||
|
}
|
||||||
|
self.areas.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_bytes(&mut self, offset: usize, data: &[u8]) -> Result<()> {
|
|
||||||
if self.area.is_none() {
|
pub fn write_bytes(&mut self, addr: usize, data: &[u8]) -> Result<()> {
|
||||||
Err(Error::InvalidArgs)
|
let mut current_addr = addr;
|
||||||
} else {
|
let mut remain = data.len();
|
||||||
self.area.take().unwrap().write_data(offset, data);
|
let start_write = false;
|
||||||
Ok(())
|
for (va,area) in self.areas.iter_mut(){
|
||||||
|
if current_addr>=va.0&& current_addr < area.size+va.0{
|
||||||
|
if !area.flags.contains(PTFlags::WRITABLE){
|
||||||
|
return Err(Error::PageFault)
|
||||||
}
|
}
|
||||||
|
area.write_data(current_addr, data);
|
||||||
|
remain -= (va.0+area.size-current_addr).min(remain);
|
||||||
|
if remain ==0{
|
||||||
|
return Ok(())
|
||||||
|
}
|
||||||
|
current_addr = va.0+area.size;
|
||||||
|
}else if start_write{
|
||||||
|
return Err(Error::PageFault)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(Error::PageFault)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_bytes(&self, offset: usize, data: &mut [u8]) -> Result<()> {
|
pub fn read_bytes(&self, addr: usize, data: &mut [u8]) -> Result<()> {
|
||||||
if self.area.is_none() {
|
let mut current_addr = addr;
|
||||||
Err(Error::InvalidArgs)
|
let mut remain = data.len();
|
||||||
} else {
|
let start_read = false;
|
||||||
self.area.as_ref().unwrap().read_data(offset, data);
|
for (va,area) in self.areas.iter(){
|
||||||
Ok(())
|
if current_addr>=va.0&& current_addr < area.size+va.0{
|
||||||
|
area.read_data(current_addr, data);
|
||||||
|
remain -= (va.0+area.size-current_addr).min(remain);
|
||||||
|
if remain ==0{
|
||||||
|
return Ok(())
|
||||||
}
|
}
|
||||||
|
current_addr = va.0+area.size;
|
||||||
|
}else if start_read{
|
||||||
|
return Err(Error::PageFault)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(Error::PageFault)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for MemorySet {
|
impl Clone for MemorySet {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
println!("clone memory set");
|
let mut ms = Self::new();
|
||||||
if self.area.is_none() {
|
for area in self.areas.values() { ms.map(area.clone()); }
|
||||||
Self::zero()
|
ms
|
||||||
} else {
|
|
||||||
Self::new(self.area.clone().unwrap())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for MemorySet {
|
impl Drop for MemorySet {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.clear();
|
self.clear();
|
||||||
@ -230,7 +264,7 @@ impl fmt::Debug for MapArea {
|
|||||||
impl fmt::Debug for MemorySet {
|
impl fmt::Debug for MemorySet {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
f.debug_struct("MemorySet")
|
f.debug_struct("MemorySet")
|
||||||
.field("areas", &self.area)
|
.field("areas", &self.areas)
|
||||||
.field("page_table_root", &self.pt.root_pa)
|
.field("page_table_root", &self.pt.root_pa)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use super::{memory_set::MapArea, *};
|
use super::{memory_set::MapArea, *};
|
||||||
use crate::cell::Cell;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{ENTRY_COUNT, KERNEL_OFFSET, PAGE_SIZE, PHYS_OFFSET},
|
config::{ENTRY_COUNT, KERNEL_OFFSET, PAGE_SIZE, PHYS_OFFSET},
|
||||||
vm::VmFrame,
|
vm::VmFrame,
|
||||||
@ -9,9 +8,6 @@ use alloc::{collections::BTreeMap, vec, vec::Vec};
|
|||||||
use core::fmt;
|
use core::fmt;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
static KERNEL_PTE: Cell<PageTableEntry> = zero();
|
|
||||||
static PHYS_PTE: Cell<PageTableEntry> = zero();
|
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref ALL_MAPPED_PTE: UPSafeCell<BTreeMap<usize, PageTableEntry>> =
|
pub static ref ALL_MAPPED_PTE: UPSafeCell<BTreeMap<usize, PageTableEntry>> =
|
||||||
unsafe { UPSafeCell::new(BTreeMap::new()) };
|
unsafe { UPSafeCell::new(BTreeMap::new()) };
|
||||||
@ -65,7 +61,6 @@ impl PageTable {
|
|||||||
for (index, pte) in map_pte.iter() {
|
for (index, pte) in map_pte.iter() {
|
||||||
p4[*index] = *pte;
|
p4[*index] = *pte;
|
||||||
}
|
}
|
||||||
println!("start_pa:{:x}", root_frame.start_pa());
|
|
||||||
Self {
|
Self {
|
||||||
root_pa: root_frame.start_pa(),
|
root_pa: root_frame.start_pa(),
|
||||||
tables: vec![root_frame],
|
tables: vec![root_frame],
|
||||||
@ -81,8 +76,6 @@ impl PageTable {
|
|||||||
println!("index:{:?},PTE:{:?}", i, a);
|
println!("index:{:?},PTE:{:?}", i, a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("kernel_pte:{:?}", p4[p4_index(VirtAddr(KERNEL_OFFSET))]);
|
|
||||||
println!("PHYS_PTE:{:?}", p4[p4_index(VirtAddr(PHYS_OFFSET))]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map(&mut self, va: VirtAddr, pa: PhysAddr, flags: PTFlags) {
|
pub fn map(&mut self, va: VirtAddr, pa: PhysAddr, flags: PTFlags) {
|
||||||
@ -210,15 +203,8 @@ pub(crate) fn init() {
|
|||||||
for i in 0..512 {
|
for i in 0..512 {
|
||||||
if !p4[i].flags().is_empty() {
|
if !p4[i].flags().is_empty() {
|
||||||
map_pte.insert(i, p4[i]);
|
map_pte.insert(i, p4[i]);
|
||||||
// println!("i:{:x},{:?}",i,p4[i]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// print how it use p4[0]
|
|
||||||
// *KERNEL_PTE.get() = p4[p4_index(VirtAddr(KERNEL_OFFSET))];
|
|
||||||
// *PHYS_PTE.get() = p4[p4_index(VirtAddr(PHYS_OFFSET))];
|
|
||||||
// println!("kernel_pte:{:?}", *KERNEL_PTE.get());
|
|
||||||
// println!("PHYS_PTE:{:?}", *PHYS_PTE.get());
|
|
||||||
|
|
||||||
// Cancel mapping in lowest addresses.
|
// Cancel mapping in lowest addresses.
|
||||||
// p4[0].0 = 0;
|
// p4[0].0 = 0;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use core::cell::{RefCell, RefMut};
|
use core::cell::{Ref, RefCell, RefMut};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
/// Wrap a static data structure inside it so that we are
|
/// Wrap a static data structure inside it so that we are
|
||||||
@ -28,4 +28,9 @@ impl<T> UPSafeCell<T> {
|
|||||||
pub fn exclusive_access(&self) -> RefMut<'_, T> {
|
pub fn exclusive_access(&self) -> RefMut<'_, T> {
|
||||||
self.inner.borrow_mut()
|
self.inner.borrow_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Panic if the data has been borrowed.
|
||||||
|
pub fn get_ref(&self) -> Ref<'_, T> {
|
||||||
|
self.inner.borrow()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,5 +5,9 @@ mod scheduler;
|
|||||||
#[allow(clippy::module_inception)]
|
#[allow(clippy::module_inception)]
|
||||||
mod task;
|
mod task;
|
||||||
|
|
||||||
|
pub use self::processor::get_idle_task_cx_ptr;
|
||||||
pub use self::scheduler::{set_scheduler, Scheduler};
|
pub use self::scheduler::{set_scheduler, Scheduler};
|
||||||
|
pub use self::task::context_switch;
|
||||||
|
pub use self::task::TaskContext;
|
||||||
|
pub use self::task::SWITCH_TO_USER_SPACE_TASK;
|
||||||
pub use self::task::{Task, TaskStatus};
|
pub use self::task::{Task, TaskStatus};
|
||||||
|
@ -45,6 +45,10 @@ pub fn current_task() -> Option<Arc<Task>> {
|
|||||||
PROCESSOR.exclusive_access().current()
|
PROCESSOR.exclusive_access().current()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_idle_task_cx_ptr() -> *mut TaskContext {
|
||||||
|
PROCESSOR.exclusive_access().get_idle_task_cx_ptr()
|
||||||
|
}
|
||||||
|
|
||||||
/// call this function to switch to other task by using GLOBAL_SCHEDULER
|
/// call this function to switch to other task by using GLOBAL_SCHEDULER
|
||||||
///
|
///
|
||||||
/// if current task is none, then it will use the default task context and it will not return to this function again
|
/// if current task is none, then it will use the default task context and it will not return to this function again
|
||||||
@ -55,7 +59,7 @@ pub fn current_task() -> Option<Arc<Task>> {
|
|||||||
pub fn schedule() {
|
pub fn schedule() {
|
||||||
let next_task = fetch_task().expect("no more task found");
|
let next_task = fetch_task().expect("no more task found");
|
||||||
let current_task_option = current_task();
|
let current_task_option = current_task();
|
||||||
let next_task_cx_ptr = &next_task.inner_exclusive_access().ctx as *const TaskContext;
|
let next_task_cx_ptr = &next_task.inner_ctx() as *const TaskContext;
|
||||||
let current_task: Arc<Task>;
|
let current_task: Arc<Task>;
|
||||||
let current_task_cx_ptr = if current_task_option.is_none() {
|
let current_task_cx_ptr = if current_task_option.is_none() {
|
||||||
PROCESSOR.exclusive_access().get_idle_task_cx_ptr()
|
PROCESSOR.exclusive_access().get_idle_task_cx_ptr()
|
||||||
|
@ -35,7 +35,6 @@ impl GlobalScheduler {
|
|||||||
/// enqueue a task using scheduler
|
/// enqueue a task using scheduler
|
||||||
/// require the scheduler is not none
|
/// require the scheduler is not none
|
||||||
pub fn enqueue(&mut self, task: Arc<Task>) {
|
pub fn enqueue(&mut self, task: Arc<Task>) {
|
||||||
println!("{:?}", self.scheduler.is_none());
|
|
||||||
self.scheduler.unwrap().enqueue(task)
|
self.scheduler.unwrap().enqueue(task)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
use core::cell::RefMut;
|
use core::cell::RefMut;
|
||||||
use core::mem::size_of;
|
use core::mem::size_of;
|
||||||
|
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
|
use crate::cell::Cell;
|
||||||
use crate::mm::PhysFrame;
|
use crate::mm::PhysFrame;
|
||||||
use crate::trap::{CalleeRegs, SyscallFrame};
|
use crate::trap::{CalleeRegs, SyscallFrame, TrapFrame};
|
||||||
use crate::user::UserSpace;
|
use crate::user::{syscall_switch_to_user_space, trap_switch_to_user_space, UserSpace};
|
||||||
use crate::{prelude::*, UPSafeCell};
|
use crate::{prelude::*, UPSafeCell};
|
||||||
|
|
||||||
use super::processor::{current_task, schedule};
|
use super::processor::{current_task, schedule, PROCESSOR};
|
||||||
use super::scheduler::add_task;
|
use super::scheduler::add_task;
|
||||||
|
|
||||||
core::arch::global_asm!(include_str!("switch.S"));
|
core::arch::global_asm!(include_str!("switch.S"));
|
||||||
@ -21,6 +24,58 @@ extern "C" {
|
|||||||
pub fn context_switch(cur: *mut TaskContext, nxt: *const TaskContext);
|
pub fn context_switch(cur: *mut TaskContext, nxt: *const TaskContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn context_switch_to_user_space() {
|
||||||
|
let task = Task::current();
|
||||||
|
let switch_space_task = SWITCH_TO_USER_SPACE_TASK.get();
|
||||||
|
if task.inner_exclusive_access().is_from_trap {
|
||||||
|
*switch_space_task.trap_frame() = *task.trap_frame();
|
||||||
|
unsafe {
|
||||||
|
trap_switch_to_user_space(
|
||||||
|
&task.user_space.as_ref().unwrap().cpu_ctx,
|
||||||
|
switch_space_task.trap_frame(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*switch_space_task.syscall_frame() = *task.syscall_frame();
|
||||||
|
unsafe {
|
||||||
|
syscall_switch_to_user_space(
|
||||||
|
&task.user_space.as_ref().unwrap().cpu_ctx,
|
||||||
|
switch_space_task.syscall_frame(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
/// This variable is mean to switch to user space and then switch back in `UserMode.execute`
|
||||||
|
///
|
||||||
|
/// When context switch to this task, there is no need to set the current task
|
||||||
|
pub static ref SWITCH_TO_USER_SPACE_TASK : Cell<Task> = unsafe{
|
||||||
|
Cell::new({
|
||||||
|
let task = Task{
|
||||||
|
func: Box::new(context_switch_to_user_space),
|
||||||
|
data: Box::new(None::<u8>),
|
||||||
|
user_space: None,
|
||||||
|
task_inner: unsafe {
|
||||||
|
UPSafeCell::new(TaskInner {
|
||||||
|
task_status: TaskStatus::Runnable,
|
||||||
|
ctx: TaskContext::default(),
|
||||||
|
is_from_trap:false,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
exit_code: usize::MAX,
|
||||||
|
kstack: KernelStack::new(),
|
||||||
|
};
|
||||||
|
task.task_inner.exclusive_access().task_status = TaskStatus::Runnable;
|
||||||
|
task.task_inner.exclusive_access().ctx.rip = context_switch_to_user_space as usize;
|
||||||
|
task.task_inner.exclusive_access().ctx.regs.rsp = task.kstack.frame.end_pa().kvaddr().0
|
||||||
|
as usize
|
||||||
|
- size_of::<usize>()
|
||||||
|
- size_of::<SyscallFrame>();
|
||||||
|
task
|
||||||
|
})};
|
||||||
|
}
|
||||||
|
|
||||||
pub struct KernelStack {
|
pub struct KernelStack {
|
||||||
frame: PhysFrame,
|
frame: PhysFrame,
|
||||||
}
|
}
|
||||||
@ -40,13 +95,15 @@ pub struct Task {
|
|||||||
user_space: Option<Arc<UserSpace>>,
|
user_space: Option<Arc<UserSpace>>,
|
||||||
task_inner: UPSafeCell<TaskInner>,
|
task_inner: UPSafeCell<TaskInner>,
|
||||||
exit_code: usize,
|
exit_code: usize,
|
||||||
/// kernel stack, note that the top is SyscallFrame
|
/// kernel stack, note that the top is SyscallFrame/TrapFrame
|
||||||
kstack: KernelStack,
|
kstack: KernelStack,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TaskInner {
|
pub struct TaskInner {
|
||||||
pub task_status: TaskStatus,
|
pub task_status: TaskStatus,
|
||||||
pub ctx: TaskContext,
|
pub ctx: TaskContext,
|
||||||
|
/// whether the task from trap. If it is Trap, then you should use read TrapFrame instead of SyscallFrame
|
||||||
|
pub is_from_trap: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Task {
|
impl Task {
|
||||||
@ -60,6 +117,11 @@ impl Task {
|
|||||||
self.task_inner.exclusive_access()
|
self.task_inner.exclusive_access()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// get inner
|
||||||
|
pub fn inner_ctx(&self) -> TaskContext {
|
||||||
|
self.task_inner.exclusive_access().ctx
|
||||||
|
}
|
||||||
|
|
||||||
/// Yields execution so that another task may be scheduled.
|
/// Yields execution so that another task may be scheduled.
|
||||||
///
|
///
|
||||||
/// Note that this method cannot be simply named "yield" as the name is
|
/// Note that this method cannot be simply named "yield" as the name is
|
||||||
@ -97,6 +159,7 @@ impl Task {
|
|||||||
UPSafeCell::new(TaskInner {
|
UPSafeCell::new(TaskInner {
|
||||||
task_status: TaskStatus::Runnable,
|
task_status: TaskStatus::Runnable,
|
||||||
ctx: TaskContext::default(),
|
ctx: TaskContext::default(),
|
||||||
|
is_from_trap: false,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
exit_code: 0,
|
exit_code: 0,
|
||||||
@ -129,6 +192,13 @@ impl Task {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn trap_frame(&self) -> &mut TrapFrame {
|
||||||
|
unsafe {
|
||||||
|
&mut *(self.kstack.frame.end_pa().kvaddr().get_mut::<TrapFrame>() as *mut TrapFrame)
|
||||||
|
.sub(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the task status.
|
/// Returns the task status.
|
||||||
pub fn status(&self) -> TaskStatus {
|
pub fn status(&self) -> TaskStatus {
|
||||||
self.task_inner.exclusive_access().task_status
|
self.task_inner.exclusive_access().task_status
|
||||||
|
@ -1,12 +1,21 @@
|
|||||||
|
use crate::task::{
|
||||||
|
context_switch, get_idle_task_cx_ptr, Task, TaskContext, SWITCH_TO_USER_SPACE_TASK,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{irq::IRQ_LIST, *};
|
use super::{irq::IRQ_LIST, *};
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn syscall_handler(f: &'static mut SyscallFrame) -> isize {
|
pub extern "C" fn syscall_handler(f: &'static mut SyscallFrame) -> isize {
|
||||||
let r = &f.caller;
|
let r = &f.caller;
|
||||||
println!("{:?}", f);
|
let current = Task::current();
|
||||||
// let ret = syscall::syscall(r.rax, [r.rdi, r.rsi, r.rdx]);
|
current.inner_exclusive_access().is_from_trap = false;
|
||||||
// current_check_signal();
|
*current.syscall_frame() = *SWITCH_TO_USER_SPACE_TASK.get().syscall_frame();
|
||||||
// ret
|
unsafe {
|
||||||
|
context_switch(
|
||||||
|
get_idle_task_cx_ptr() as *mut TaskContext,
|
||||||
|
&Task::current().inner_ctx() as *const TaskContext,
|
||||||
|
)
|
||||||
|
}
|
||||||
-1
|
-1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -20,9 +29,22 @@ const TIMER: usize = 32;
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn trap_handler(f: &'static mut TrapFrame) {
|
pub extern "C" fn trap_handler(f: &'static mut TrapFrame) {
|
||||||
|
if !is_from_kernel(f.cs){
|
||||||
|
let current = Task::current();
|
||||||
|
current.inner_exclusive_access().is_from_trap = true;
|
||||||
|
}
|
||||||
let irq_line = IRQ_LIST.get(f.id as usize).unwrap();
|
let irq_line = IRQ_LIST.get(f.id as usize).unwrap();
|
||||||
let callback_functions = irq_line.callback_list();
|
let callback_functions = irq_line.callback_list();
|
||||||
for callback_function in callback_functions.iter() {
|
for callback_function in callback_functions.iter() {
|
||||||
callback_function.call(f.clone());
|
callback_function.call(f.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn is_from_kernel(cs:usize)->bool{
|
||||||
|
if cs&0x3==0{
|
||||||
|
true
|
||||||
|
}else{
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -36,6 +36,8 @@ __trap_entry:
|
|||||||
# 将栈指针当成参数传入trap_handler
|
# 将栈指针当成参数传入trap_handler
|
||||||
mov rdi, rsp
|
mov rdi, rsp
|
||||||
call trap_handler
|
call trap_handler
|
||||||
|
__trap_return:
|
||||||
|
# judge whether the trap from kernel mode
|
||||||
mov rax, [rsp + 96] # 96 = offsetof(TrapFrame, cs)
|
mov rax, [rsp + 96] # 96 = offsetof(TrapFrame, cs)
|
||||||
and rax, 0x3
|
and rax, 0x3
|
||||||
jz __from_kernel
|
jz __from_kernel
|
||||||
@ -46,6 +48,9 @@ __from_kernel:
|
|||||||
add rsp, 16 # skip TrapFrame.err and id
|
add rsp, 16 # skip TrapFrame.err and id
|
||||||
iretq
|
iretq
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.global syscall_entry
|
.global syscall_entry
|
||||||
syscall_entry:
|
syscall_entry:
|
||||||
# syscall instruction do:
|
# syscall instruction do:
|
||||||
@ -73,7 +78,7 @@ syscall_return: # (SyscallFrame *)
|
|||||||
mov rsp, rdi
|
mov rsp, rdi
|
||||||
__syscall_return:
|
__syscall_return:
|
||||||
lea rax, [rsp + 128] # prepare new TSS.sp0, 128 = sizeof(SyscallFrame)
|
lea rax, [rsp + 128] # prepare new TSS.sp0, 128 = sizeof(SyscallFrame)
|
||||||
# 将跳到ring0要跳转的stack指针存储到4(TSS)处
|
# store the rsp in TSS
|
||||||
mov [TSS + rip + 4], rax
|
mov [TSS + rip + 4], rax
|
||||||
restore
|
restore
|
||||||
mov rbx, [rsp + 8]
|
mov rbx, [rsp + 8]
|
||||||
@ -85,12 +90,18 @@ __syscall_return:
|
|||||||
mov rsp, [rsp + 0]
|
mov rsp, [rsp + 0]
|
||||||
sysretq
|
sysretq
|
||||||
|
|
||||||
.global switch_to_user_space
|
.global syscall_switch_to_user_space
|
||||||
switch_to_user_space: # (cpu_context: *CpuContext,reg: *CallerRegs)
|
syscall_switch_to_user_space: # (cpu_context: *CpuContext,reg: *SyscallFrame)
|
||||||
# mov rflag, [rdi+136]
|
# mov rflag, [rdi+136]
|
||||||
mov rdi, rsi
|
mov rdi, rsi
|
||||||
jmp syscall_return
|
jmp syscall_return
|
||||||
|
|
||||||
|
.global trap_switch_to_user_space
|
||||||
|
trap_switch_to_user_space: # (cpu_context: *CpuContext,reg: *TrapFrame)
|
||||||
|
# mov rflag, [rdi+136]
|
||||||
|
mov rdi, rsi
|
||||||
|
mov rsp, rdi
|
||||||
|
jmp __trap_return
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,12 +4,15 @@ use crate::println;
|
|||||||
|
|
||||||
use crate::cpu::CpuContext;
|
use crate::cpu::CpuContext;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::task::Task;
|
use crate::task::{context_switch, Task, TaskContext, SWITCH_TO_USER_SPACE_TASK};
|
||||||
use crate::trap::SyscallFrame;
|
use crate::trap::{SyscallFrame, TrapFrame};
|
||||||
use crate::vm::VmSpace;
|
use crate::vm::VmSpace;
|
||||||
|
use crate::x86_64_util::get_return_address;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn switch_to_user_space(cpu_context: &CpuContext, syscall_frame: &SyscallFrame);
|
pub fn syscall_switch_to_user_space(cpu_context: &CpuContext, syscall_frame: &SyscallFrame);
|
||||||
|
/// cpu_context may delete in the future
|
||||||
|
pub fn trap_switch_to_user_space(cpu_context: &CpuContext, trap_frame: &TrapFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A user space.
|
/// A user space.
|
||||||
@ -20,7 +23,7 @@ pub struct UserSpace {
|
|||||||
/// vm space
|
/// vm space
|
||||||
vm_space: VmSpace,
|
vm_space: VmSpace,
|
||||||
/// cpu context before entering user space
|
/// cpu context before entering user space
|
||||||
cpu_ctx: CpuContext,
|
pub cpu_ctx: CpuContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserSpace {
|
impl UserSpace {
|
||||||
@ -78,6 +81,8 @@ impl UserSpace {
|
|||||||
pub struct UserMode<'a> {
|
pub struct UserMode<'a> {
|
||||||
current: Arc<Task>,
|
current: Arc<Task>,
|
||||||
user_space: &'a Arc<UserSpace>,
|
user_space: &'a Arc<UserSpace>,
|
||||||
|
context: CpuContext,
|
||||||
|
executed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// An instance of `UserMode` is bound to the current task. So it cannot be
|
// An instance of `UserMode` is bound to the current task. So it cannot be
|
||||||
@ -88,10 +93,12 @@ impl<'a> UserMode<'a> {
|
|||||||
Self {
|
Self {
|
||||||
current: Task::current(),
|
current: Task::current(),
|
||||||
user_space,
|
user_space,
|
||||||
|
context: CpuContext::default(),
|
||||||
|
executed: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Starts executing in the user mode.
|
/// Starts executing in the user mode. Make sure current task is the task in `UserMode`.
|
||||||
///
|
///
|
||||||
/// The method returns for one of three possible reasons indicated by `UserEvent`.
|
/// The method returns for one of three possible reasons indicated by `UserEvent`.
|
||||||
/// 1. The user invokes a system call;
|
/// 1. The user invokes a system call;
|
||||||
@ -102,22 +109,46 @@ impl<'a> UserMode<'a> {
|
|||||||
/// this method can be invoked again to go back to the user space.
|
/// this method can be invoked again to go back to the user space.
|
||||||
pub fn execute(&mut self) -> UserEvent {
|
pub fn execute(&mut self) -> UserEvent {
|
||||||
self.user_space.vm_space().activate();
|
self.user_space.vm_space().activate();
|
||||||
|
if !self.executed {
|
||||||
self.current.syscall_frame().caller.rcx = self.user_space.cpu_ctx.gp_regs.rip as usize;
|
self.current.syscall_frame().caller.rcx = self.user_space.cpu_ctx.gp_regs.rip as usize;
|
||||||
println!("{:?}", self.current.syscall_frame());
|
self.executed = true;
|
||||||
unsafe {
|
} else {
|
||||||
switch_to_user_space(&self.user_space.cpu_ctx, self.current.syscall_frame());
|
if self.current.inner_exclusive_access().is_from_trap {
|
||||||
|
*self.current.trap_frame() = self.context.into();
|
||||||
|
} else {
|
||||||
|
*self.current.syscall_frame() = self.context.into();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
let mut current_task_inner = self.current.inner_exclusive_access();
|
||||||
|
let binding = SWITCH_TO_USER_SPACE_TASK.get();
|
||||||
|
let next_task_inner = binding.inner_exclusive_access();
|
||||||
|
let current_ctx = &mut current_task_inner.ctx as *mut TaskContext;
|
||||||
|
let next_ctx = &next_task_inner.ctx as *const TaskContext;
|
||||||
|
drop(current_task_inner);
|
||||||
|
drop(next_task_inner);
|
||||||
|
drop(binding);
|
||||||
|
unsafe {
|
||||||
|
context_switch(current_ctx, next_ctx);
|
||||||
|
// switch_to_user_space(&self.user_space.cpu_ctx, self.current.syscall_frame());
|
||||||
|
}
|
||||||
|
if self.current.inner_exclusive_access().is_from_trap {
|
||||||
|
self.context = CpuContext::from(*self.current.trap_frame());
|
||||||
|
UserEvent::Exception
|
||||||
|
} else {
|
||||||
|
self.context = CpuContext::from(*self.current.syscall_frame());
|
||||||
|
println!("[kernel] syscall id:{}",self.context.gp_regs.rax);
|
||||||
UserEvent::Syscall
|
UserEvent::Syscall
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns an immutable reference the user-mode CPU context.
|
/// Returns an immutable reference the user-mode CPU context.
|
||||||
pub fn context(&self) -> &CpuContext {
|
pub fn context(&self) -> &CpuContext {
|
||||||
todo!()
|
&self.context
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a mutable reference the user-mode CPU context.
|
/// Returns a mutable reference the user-mode CPU context.
|
||||||
pub fn context_mut(&mut self) -> &mut CpuContext {
|
pub fn context_mut(&mut self) -> &mut CpuContext {
|
||||||
todo!()
|
&mut self.context
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ impl VmSpace {
|
|||||||
/// Creates a new VM address space.
|
/// Creates a new VM address space.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
memory_set: unsafe { UPSafeCell::new(MemorySet::zero()) },
|
memory_set: unsafe { UPSafeCell::new(MemorySet::new()) },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ impl VmSpace {
|
|||||||
if options.addr.is_none() {
|
if options.addr.is_none() {
|
||||||
return Err(Error::InvalidArgs);
|
return Err(Error::InvalidArgs);
|
||||||
}
|
}
|
||||||
self.memory_set.exclusive_access().map_area(MapArea::new(
|
self.memory_set.exclusive_access().map(MapArea::new(
|
||||||
VirtAddr(options.addr.unwrap()),
|
VirtAddr(options.addr.unwrap()),
|
||||||
frames.len() * PAGE_SIZE,
|
frames.len() * PAGE_SIZE,
|
||||||
flags,
|
flags,
|
||||||
@ -99,12 +99,12 @@ impl Default for VmSpace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl VmIo for VmSpace {
|
impl VmIo for VmSpace {
|
||||||
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> {
|
fn read_bytes(&self, vaddr: usize, buf: &mut [u8]) -> Result<()> {
|
||||||
self.memory_set.exclusive_access().read_bytes(offset, buf)
|
self.memory_set.exclusive_access().read_bytes(vaddr, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_bytes(&mut self, offset: usize, buf: &[u8]) -> Result<()> {
|
fn write_bytes(&mut self, vaddr: usize, buf: &[u8]) -> Result<()> {
|
||||||
self.memory_set.exclusive_access().write_bytes(offset, buf)
|
self.memory_set.exclusive_access().write_bytes(vaddr, buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,6 +177,15 @@ pub fn get_cr3_raw() -> usize {
|
|||||||
val
|
val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn get_return_address() -> usize {
|
||||||
|
let val: usize;
|
||||||
|
unsafe {
|
||||||
|
asm!("mov {}, [rsp]", out(reg) val);
|
||||||
|
}
|
||||||
|
val
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_cr3(pa: usize) {
|
pub fn set_cr3(pa: usize) {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -27,7 +27,6 @@ pub fn spawn_user_task_from_elf(elf_file_content: &[u8]) -> Arc<Task> {
|
|||||||
let mut user_mode = UserMode::new(user_space);
|
let mut user_mode = UserMode::new(user_space);
|
||||||
loop {
|
loop {
|
||||||
let user_event = user_mode.execute();
|
let user_event = user_mode.execute();
|
||||||
println!("get user event:{:?}", user_event);
|
|
||||||
let context = user_mode.context_mut();
|
let context = user_mode.context_mut();
|
||||||
if let HandlerResult::Exit = handle_user_event(user_event, context) {
|
if let HandlerResult::Exit = handle_user_event(user_event, context) {
|
||||||
// FIXME: How to set task status? How to set exit code of process?
|
// FIXME: How to set task status? How to set exit code of process?
|
||||||
@ -36,8 +35,6 @@ pub fn spawn_user_task_from_elf(elf_file_content: &[u8]) -> Arc<Task> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// QEMU crash when entering the task spawn function.
|
|
||||||
println!("[kxos std]:before entering task spawn");
|
|
||||||
// FIXME: set the correct type when task has no data
|
// FIXME: set the correct type when task has no data
|
||||||
Task::spawn(user_task_entry, None::<u8>, Some(user_space)).expect("spawn user task failed.")
|
Task::spawn(user_task_entry, None::<u8>, Some(user_space)).expect("spawn user task failed.")
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ global _start
|
|||||||
section .text
|
section .text
|
||||||
|
|
||||||
_start:
|
_start:
|
||||||
mov rax, 1 ; syswrite
|
mov rax, 64 ; syswrite
|
||||||
mov rdi, 1 ; fd
|
mov rdi, 1 ; fd
|
||||||
mov rsi, msg ; "Hello, world!\n",
|
mov rsi, msg ; "Hello, world!\n",
|
||||||
mov rdx, msglen ; sizeof("Hello, world!\n")
|
mov rdx, msglen ; sizeof("Hello, world!\n")
|
||||||
|
@ -19,7 +19,7 @@ fn kernel_main(boot_info: &'static mut BootInfo) -> ! {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
kxos_frame::init(boot_info);
|
kxos_frame::init(boot_info);
|
||||||
println!("finish init kxos_frame");
|
println!("[kernel] finish init kxos_frame");
|
||||||
|
|
||||||
kxos_std::init();
|
kxos_std::init();
|
||||||
kxos_std::run_first_process();
|
kxos_std::run_first_process();
|
||||||
|
Reference in New Issue
Block a user