396 lines
9.0 KiB
Rust

use core::{arch::global_asm, cell::UnsafeCell, marker::PhantomData};
use kernel_arch_interface::{
mem::{KernelTableManager, PhysicalMemoryAllocator},
task::{StackBuilder, TaskContext, TaskFrame, UserContextInfo},
};
use libk_mm_interface::address::{AsPhysicalAddress, PhysicalAddress};
use tock_registers::interfaces::Writeable;
use yggdrasil_abi::{arch::SavedFrame, error::Error};
use crate::{gdt::TSS, mem::KERNEL_TABLES, registers::CR3};
#[repr(C)]
pub struct ExceptionFrame {
pub eax: u32,
pub ecx: u32,
pub edx: u32,
pub ebx: u32,
pub ebp: u32,
pub esi: u32,
pub edi: u32,
pub exc_number: u32,
pub exc_code: u32,
pub eip: u32,
pub cs: u32,
pub eflags: u32,
esp: u32,
ss: u32,
}
#[derive(Debug)]
#[repr(C)]
pub struct SyscallFrame {
pub eax: usize,
// ebx, ecx, edx, esi, edi, ebp
pub args: [usize; 6],
pub eip: u32,
pub cs: u32,
pub eflags: u32,
pub esp: u32,
pub ss: u32,
}
#[repr(C)]
pub struct InterruptFrame {
pub eax: u32,
pub ecx: u32,
pub edx: u32,
pub ebx: u32,
pub ebp: u32,
pub esi: u32,
pub edi: u32,
pub irq_number: u32,
pub eip: u32,
pub cs: u32,
pub eflags: u32,
esp: u32,
ss: u32,
}
#[repr(C, align(0x10))]
struct Inner {
// 0x00
sp: usize,
}
#[allow(dead_code)]
pub struct TaskContextImpl<
K: KernelTableManager,
PA: PhysicalMemoryAllocator<Address = PhysicalAddress>,
> {
inner: UnsafeCell<Inner>,
stack_base_phys: PhysicalAddress,
stack_size: usize,
cr3: u32,
tss_esp0: u32,
_pd: PhantomData<(K, PA)>,
}
impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddress>>
TaskContext<K, PA> for TaskContextImpl<K, PA>
{
const SIGNAL_STACK_EXTRA_ALIGN: usize = 0;
const USER_STACK_EXTRA_ALIGN: usize = 0;
fn user(context: UserContextInfo) -> Result<Self, Error> {
const USER_TASK_PAGES: usize = 8;
let stack_base_phys = PA::allocate_contiguous_pages(USER_TASK_PAGES)?;
let stack_base = stack_base_phys.raw_virtualize::<K>();
let mut stack = StackBuilder::new(stack_base, USER_TASK_PAGES * 0x1000);
stack.push(0x200);
stack.push(context.entry as _);
stack.push(context.stack_pointer);
setup_common_context(&mut stack, __i686_task_enter_user as _);
let sp = stack.build();
let esp0 = stack_base + USER_TASK_PAGES * 0x1000;
Ok(Self {
inner: UnsafeCell::new(Inner { sp }),
stack_base_phys,
stack_size: USER_TASK_PAGES * 0x1000,
tss_esp0: esp0 as _,
cr3: context.address_space.try_into().unwrap(),
_pd: PhantomData,
})
}
fn kernel(
entry: extern "C" fn(usize) -> !,
arg: usize,
) -> Result<Self, yggdrasil_abi::error::Error> {
const KERNEL_TASK_PAGES: usize = 32;
let stack_base_phys = PA::allocate_contiguous_pages(KERNEL_TASK_PAGES)?;
let stack_base = stack_base_phys.raw_virtualize::<K>();
let mut stack = StackBuilder::new(stack_base, KERNEL_TASK_PAGES * 0x1000);
// Entry and argument
stack.push(entry as _);
stack.push(arg);
// XXX
setup_common_context(&mut stack, __i686_task_enter_kernel as _);
let sp = stack.build();
// TODO stack is leaked
Ok(Self {
inner: UnsafeCell::new(Inner { sp }),
stack_base_phys,
stack_size: KERNEL_TASK_PAGES * 0x1000,
tss_esp0: 0,
cr3: unsafe { KERNEL_TABLES.as_physical_address() }
.try_into_u32()
.unwrap(),
_pd: PhantomData,
})
}
unsafe fn switch(&self, from: &Self) {
let dst = self.inner.get();
let src = from.inner.get();
if dst != src {
TSS.esp0 = self.tss_esp0;
CR3.set(self.cr3);
__i686_switch_task(dst, src);
}
}
unsafe fn enter(&self) -> ! {
TSS.esp0 = self.tss_esp0;
CR3.set(self.cr3);
__i686_enter_task(self.inner.get())
}
unsafe fn switch_and_drop(&self, thread: *const ()) {
TSS.esp0 = self.tss_esp0;
CR3.set(self.cr3);
__i686_switch_and_drop(self.inner.get(), thread)
}
}
fn setup_common_context(builder: &mut StackBuilder, entry: usize) {
builder.push(entry);
builder.push(0); // %edi
builder.push(0); // %esi
builder.push(0); // %ebp
builder.push(0); // %ebx
}
extern "C" {
fn __i686_task_enter_kernel();
fn __i686_task_enter_user();
fn __i686_task_enter_from_fork();
fn __i686_enter_task(to: *mut Inner) -> !;
fn __i686_switch_task(to: *mut Inner, from: *mut Inner);
fn __i686_switch_and_drop(to: *mut Inner, from: *const ());
}
impl TaskFrame for SyscallFrame {
fn store(&self) -> SavedFrame {
SavedFrame {
eax: self.eax as _,
ecx: self.args[1] as _,
edx: self.args[2] as _,
ebx: self.args[0] as _,
ebp: self.args[5] as _,
esi: self.args[3] as _,
edi: self.args[4] as _,
user_ip: self.eip,
user_sp: self.esp,
eflags: self.eflags,
}
}
fn restore(&mut self, saved: &SavedFrame) {
todo!()
}
fn user_sp(&self) -> usize {
todo!()
}
fn user_ip(&self) -> usize {
todo!()
}
fn argument(&self) -> u64 {
todo!()
}
fn set_user_sp(&mut self, value: usize) {
self.esp = value as _;
}
fn set_user_ip(&mut self, value: usize) {
self.eip = value as _;
}
fn set_argument(&mut self, value: u64) {
// TODO implement ABI for passing 64-bit values via EAX/EDX
if value & (1 << 63) != 0 {
assert_eq!(value & 0xFFFFFFFF00000000, 0xFFFFFFFF00000000);
}
self.eax = value as usize;
}
fn set_single_step(&mut self, step: bool) {
todo!()
}
fn set_return_value(&mut self, value: u64) {
// TODO implement ABI for returning 64-bit values via EAX/EDX
if value & (1 << 63) != 0 {
assert_eq!(value & 0xFFFFFFFF00000000, 0xFFFFFFFF00000000);
}
self.eax = value as usize;
}
}
impl TaskFrame for InterruptFrame {
fn store(&self) -> SavedFrame {
SavedFrame {
eax: self.eax,
ecx: self.ecx,
edx: self.edx,
ebx: self.ebx,
ebp: self.ebp,
esi: self.esi,
edi: self.edi,
user_ip: self.eip,
user_sp: self.esp,
eflags: self.eflags,
}
}
fn restore(&mut self, saved: &SavedFrame) {
todo!()
}
fn user_sp(&self) -> usize {
todo!()
}
fn user_ip(&self) -> usize {
todo!()
}
fn argument(&self) -> u64 {
todo!()
}
fn set_user_sp(&mut self, value: usize) {
self.esp = value as u32;
}
fn set_user_ip(&mut self, value: usize) {
self.eip = value as u32;
}
fn set_argument(&mut self, value: u64) {
// TODO implement ABI for returning 64-bit values via EAX/EDX
if value & (1 << 63) != 0 {
assert_eq!(value & 0xFFFFFFFF00000000, 0xFFFFFFFF00000000);
}
self.eax = value as u32;
}
fn set_single_step(&mut self, step: bool) {
todo!()
}
fn set_return_value(&mut self, value: u64) {
// TODO implement ABI for returning 64-bit values via EAX/EDX
if value & (1 << 63) != 0 {
assert_eq!(value & 0xFFFFFFFF00000000, 0xFFFFFFFF00000000);
}
self.eax = value as u32;
}
}
impl TaskFrame for ExceptionFrame {
fn store(&self) -> SavedFrame {
SavedFrame {
eax: self.eax,
ecx: self.ecx,
edx: self.edx,
ebx: self.ebx,
ebp: self.ebp,
esi: self.esi,
edi: self.edi,
user_ip: self.eip,
user_sp: self.esp,
eflags: self.eflags,
}
}
fn restore(&mut self, saved: &SavedFrame) {
todo!()
}
fn user_sp(&self) -> usize {
todo!()
}
fn user_ip(&self) -> usize {
todo!()
}
fn argument(&self) -> u64 {
todo!()
}
fn set_user_sp(&mut self, value: usize) {
self.esp = value as u32;
}
fn set_user_ip(&mut self, value: usize) {
self.eip = value as u32;
}
fn set_argument(&mut self, value: u64) {
// TODO implement ABI for returning 64-bit values via EAX/EDX
if value & (1 << 63) != 0 {
assert_eq!(value & 0xFFFFFFFF00000000, 0xFFFFFFFF00000000);
}
self.eax = value as u32;
}
fn set_single_step(&mut self, step: bool) {
todo!()
}
fn set_return_value(&mut self, value: u64) {
// TODO implement ABI for returning 64-bit values via EAX/EDX
if value & (1 << 63) != 0 {
assert_eq!(value & 0xFFFFFFFF00000000, 0xFFFFFFFF00000000);
}
self.eax = value as u32;
}
}
global_asm!(include_str!("context.S"), options(att_syntax));