Context switch

This commit is contained in:
2021-08-20 13:15:25 +03:00
parent fe4c2f7c77
commit f60c3ac644
9 changed files with 198 additions and 23 deletions
+5
View File
@@ -107,6 +107,11 @@ impl<T: AddressSpace> VirtualAddress<T> {
core::slice::from_raw_parts_mut(self.0 as *mut _, count)
}
#[inline(always)]
pub fn as_mut_ptr<U>(self) -> *mut U {
self.0 as *mut U
}
#[inline(always)]
pub unsafe fn as_mut<U>(self) -> &'static mut U {
&mut *(self.0 as *mut U)
+1 -1
View File
@@ -2,5 +2,5 @@
#[derive(PartialEq, Debug, Clone, Copy)]
pub enum Errno {
OutOfMemory
}
+2
View File
@@ -30,5 +30,7 @@ struct ExceptionContext {
#[no_mangle]
extern "C" fn exc_handler(context: ExceptionContext) -> ! {
debug!("Unhandled exception");
loop {}
}
+2 -7
View File
@@ -8,11 +8,10 @@ pub mod debug;
pub mod arch;
pub mod boot;
pub mod mem;
pub mod proc;
pub use mem::KernelSpace;
use core::fmt::{self, Write};
use address::PhysicalAddress;
use mem::phys::UsableMemory;
#[derive(Clone)]
@@ -45,11 +44,7 @@ extern "C" fn kernel_main() -> ! {
mem::phys::initialize(iter);
}
loop {
unsafe {
llvm_asm!("wfe");
}
}
proc::enter();
}
use core::panic::PanicInfo;
+40 -7
View File
@@ -1,13 +1,17 @@
use super::{PageInfo, PageUsage};
use crate::KernelSpace;
use crate::{KernelSpace, mem::PAGE_SIZE};
use address::{PhysicalAddress, VirtualAddress};
use core::mem::{self, MaybeUninit};
use error::Errno;
use spin::Mutex;
pub unsafe trait Manager {
fn alloc_page(&mut self) -> Result<PhysicalAddress, Errno>;
fn alloc_contiguous_pages(&mut self, count: usize) -> Result<PhysicalAddress, Errno>;
fn alloc_page(&mut self, pu: PageUsage) -> Result<PhysicalAddress, Errno>;
fn alloc_contiguous_pages(
&mut self,
pu: PageUsage,
count: usize,
) -> Result<PhysicalAddress, Errno>;
fn free_page(&mut self, page: PhysicalAddress) -> Result<(), Errno>;
// TODO status()
@@ -48,11 +52,40 @@ impl SimpleManager {
}
unsafe impl Manager for SimpleManager {
fn alloc_page(&mut self) -> Result<PhysicalAddress, Errno> {
todo!()
fn alloc_page(&mut self, pu: PageUsage) -> Result<PhysicalAddress, Errno> {
for index in 0..self.pages.len() {
let mut page = self.pages[index].lock();
if page.usage == PageUsage::Available {
page.usage = pu;
page.refcount = 1;
return Ok(PhysicalAddress::from(index * PAGE_SIZE));
}
}
Err(Errno::OutOfMemory)
}
fn alloc_contiguous_pages(&mut self, _count: usize) -> Result<PhysicalAddress, Errno> {
todo!()
fn alloc_contiguous_pages(
&mut self,
pu: PageUsage,
count: usize,
) -> Result<PhysicalAddress, Errno> {
'l0: for i in 0..self.pages.len() {
for j in 0..count {
if self.pages[i + j].lock().usage != PageUsage::Available {
continue 'l0;
}
}
for j in 0..count {
let mut page = self.pages[i + j].lock();
assert!(page.usage == PageUsage::Available);
page.usage = pu;
page.refcount = 1;
}
return Ok(PhysicalAddress::from(i * PAGE_SIZE));
}
Err(Errno::OutOfMemory)
}
fn free_page(&mut self, _page: PhysicalAddress) -> Result<(), Errno> {
todo!()
+5 -5
View File
@@ -14,7 +14,7 @@ pub use pbox::PhysBox;
type ManagerImpl = SimpleManager;
#[derive(PartialEq, Debug)]
#[derive(PartialEq, Debug, Clone, Copy)]
pub enum PageUsage {
Reserved,
Available,
@@ -34,16 +34,16 @@ pub struct UsableMemory {
const MAX_PAGES: usize = 1024;
pub fn alloc_page() -> Result<PhysicalAddress, Errno> {
MANAGER.lock().as_mut().unwrap().alloc_page()
pub fn alloc_page(pu: PageUsage) -> Result<PhysicalAddress, Errno> {
MANAGER.lock().as_mut().unwrap().alloc_page(pu)
}
pub fn alloc_contiguous_pages(count: usize) -> Result<PhysicalAddress, Errno> {
pub fn alloc_contiguous_pages(pu: PageUsage, count: usize) -> Result<PhysicalAddress, Errno> {
MANAGER
.lock()
.as_mut()
.unwrap()
.alloc_contiguous_pages(count)
.alloc_contiguous_pages(pu, count)
}
pub fn free_page(page: PhysicalAddress) -> Result<(), Errno> {
+4 -3
View File
@@ -1,3 +1,4 @@
use super::PageUsage;
use address::PhysicalAddress;
use error::Errno;
@@ -7,10 +8,10 @@ pub struct PhysBox {
}
impl PhysBox {
pub fn new() -> Result<Self, Errno> {
pub fn new(pu: PageUsage) -> Result<Self, Errno> {
Ok(Self {
base: super::alloc_page()?,
count: 1
base: super::alloc_page(pu)?,
count: 1,
})
}
}
+38
View File
@@ -0,0 +1,38 @@
.section .text
context_enter_kernel:
ldp x0, xzr, [sp, #0]
ldp lr, x1, [sp, #16]
mov sp, x1
ret
context_switch:
// Store old callee-saved regs on stack
sub sp, sp, #96
stp x19, x20, [sp, #0]
stp x21, x22, [sp, #16]
stp x23, x24, [sp, #32]
stp x25, x26, [sp, #48]
stp x27, x29, [sp, #64]
stp xzr, lr, [sp, #80]
// Store old stack pointer
mov x19, sp
str x19, [x1]
context_switch_to:
// Load new stack
ldr x0, [x0]
mov sp, x0
// Load new callee-saved regs on stack
ldp x19, x20, [sp, #0]
ldp x21, x22, [sp, #16]
ldp x23, x24, [sp, #32]
ldp x25, x26, [sp, #48]
ldp x27, x29, [sp, #64]
ldp xzr, lr, [sp, #80]
add sp, sp, #96
// Simulate/perform a return
ret
+101
View File
@@ -0,0 +1,101 @@
use crate::{
mem::phys::{self, PageUsage},
KernelSpace,
};
use address::VirtualAddress;
use core::mem::{size_of, MaybeUninit};
global_asm!(include_str!("context.S"));
#[repr(C)]
struct Context {
kernel_sp: VirtualAddress<KernelSpace>,
}
struct Stack {
bp: VirtualAddress<KernelSpace>,
sp: VirtualAddress<KernelSpace>,
tp: VirtualAddress<KernelSpace>,
}
impl Context {
fn new_kernel(entry: usize, arg: usize) -> Context {
let kstack_phys = phys::alloc_contiguous_pages(PageUsage::Kernel, 4).unwrap();
let mut stack = unsafe { Stack::new(kstack_phys.into(), 4096 * 4) };
stack.push(stack.tp); // popped into stack register before ERET
stack.push(entry); // ELR before ERET
stack.push(0usize); // padding
stack.push(arg);
stack.push(context_enter_kernel as usize); // x30 LR
stack.push(0usize); // padding
stack.push(0usize); // x29
stack.push(0usize); // x27
stack.push(0usize); // x26
stack.push(0usize); // x25
stack.push(0usize); // x24
stack.push(0usize); // x23
stack.push(0usize); // x22
stack.push(0usize); // x21
stack.push(0usize); // x20
stack.push(0usize); // x19
Context {
kernel_sp: stack.sp,
}
}
}
impl Stack {
pub unsafe fn new(bp: VirtualAddress<KernelSpace>, size: usize) -> Stack {
Stack {
bp,
sp: bp + size,
tp: bp + size,
}
}
pub fn push<A: Into<usize>>(&mut self, value: A) {
if self.sp == self.bp {
panic!("Stack overflow");
}
self.sp -= size_of::<usize>();
unsafe {
core::ptr::write(self.sp.as_mut_ptr(), value.into());
}
}
}
extern "C" {
fn context_switch_to(dst: *mut Context);
fn context_switch(dst: *mut Context, src: *mut Context);
fn context_enter_kernel();
}
fn f0(arg: usize) {
loop {
unsafe {
debug!("{}", arg);
if arg == 0 {
context_switch(C1.as_mut_ptr(), C0.as_mut_ptr());
} else {
context_switch(C0.as_mut_ptr(), C1.as_mut_ptr());
}
}
}
}
static mut C0: MaybeUninit<Context> = MaybeUninit::uninit();
static mut C1: MaybeUninit<Context> = MaybeUninit::uninit();
pub fn enter() -> ! {
unsafe {
C0.write(Context::new_kernel(f0 as usize, 0));
C1.write(Context::new_kernel(f0 as usize, 1));
context_switch_to(C0.as_mut_ptr());
}
loop {}
}