Move some conditionally compiled code from common files into arch-gated files
This commit is contained in:
@@ -175,7 +175,7 @@ exception_stack!(synchronous_exception_at_el0, |stack| {
|
||||
0b010101 => {
|
||||
let scratch = &stack.scratch;
|
||||
let ret = syscall::syscall(
|
||||
scratch.x8, scratch.x0, scratch.x1, scratch.x2, scratch.x3, scratch.x4, stack,
|
||||
scratch.x8, scratch.x0, scratch.x1, scratch.x2, scratch.x3, scratch.x4,
|
||||
);
|
||||
stack.scratch.x0 = ret;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ interrupt_stack!(syscall, |stack| {
|
||||
scratch.edx,
|
||||
preserved.esi,
|
||||
preserved.edi,
|
||||
stack,
|
||||
);
|
||||
stack.scratch.eax = ret;
|
||||
})
|
||||
|
||||
@@ -75,7 +75,6 @@ pub unsafe extern "C" fn __inner_syscall_instruction(stack: *mut InterruptStack)
|
||||
scratch.rdx,
|
||||
scratch.r10,
|
||||
scratch.r8,
|
||||
&mut *stack,
|
||||
);
|
||||
(*stack).scratch.rax = ret;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
use crate::{
|
||||
arch::{device::cpu::registers::control_regs, interrupt::InterruptStack, paging::PageMapper},
|
||||
context::{context::Kstack, memory::Table},
|
||||
percpu::PercpuBlock,
|
||||
syscall::FloatRegisters,
|
||||
};
|
||||
use core::{arch::asm, mem, mem::offset_of, ptr, sync::atomic::AtomicBool};
|
||||
use rmm::TableKind;
|
||||
use spin::Once;
|
||||
|
||||
use crate::{percpu::PercpuBlock, syscall::FloatRegisters};
|
||||
use syscall::{EnvRegisters, Error, Result, ENOMEM};
|
||||
|
||||
/// This must be used by the kernel to ensure that context switches are done atomically
|
||||
/// Compare and exchange this to true when beginning a context switch on any CPU
|
||||
@@ -62,23 +68,49 @@ impl Context {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_stack(&mut self, address: usize) {
|
||||
fn set_stack(&mut self, address: usize) {
|
||||
self.sp = address;
|
||||
}
|
||||
|
||||
pub fn set_x28(&mut self, x28: usize) {
|
||||
fn set_x28(&mut self, x28: usize) {
|
||||
self.x28 = x28;
|
||||
}
|
||||
|
||||
pub fn set_lr(&mut self, address: usize) {
|
||||
fn set_lr(&mut self, address: usize) {
|
||||
self.lr = address;
|
||||
}
|
||||
|
||||
pub fn set_context_handle(&mut self) {
|
||||
fn set_context_handle(&mut self) {
|
||||
let address = self as *const _ as usize;
|
||||
self.tpidrro_el0 = address;
|
||||
}
|
||||
|
||||
pub(crate) fn setup_initial_call(
|
||||
&mut self,
|
||||
stack: &Kstack,
|
||||
func: extern "C" fn(),
|
||||
userspace_allowed: bool,
|
||||
) {
|
||||
let mut stack_top = stack.initial_top();
|
||||
|
||||
const INT_REGS_SIZE: usize = core::mem::size_of::<InterruptStack>();
|
||||
|
||||
if userspace_allowed {
|
||||
unsafe {
|
||||
// Zero-initialize InterruptStack registers.
|
||||
stack_top = stack_top.sub(INT_REGS_SIZE);
|
||||
stack_top.write_bytes(0_u8, INT_REGS_SIZE);
|
||||
(&mut *stack_top.cast::<InterruptStack>()).init();
|
||||
}
|
||||
}
|
||||
|
||||
self.set_lr(crate::interrupt::syscall::enter_usermode as usize);
|
||||
self.set_x28(func as usize);
|
||||
self.set_context_handle();
|
||||
|
||||
self.set_stack(stack_top as usize);
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn dump(&self) {
|
||||
println!("elr_el1: 0x{:016x}", self.elr_el1);
|
||||
@@ -131,6 +163,36 @@ impl super::Context {
|
||||
scratch.x8, scratch.x0, scratch.x1, scratch.x2, scratch.x3, scratch.x4,
|
||||
])
|
||||
}
|
||||
|
||||
pub(crate) fn write_current_env_regs(&self, regs: EnvRegisters) -> Result<()> {
|
||||
unsafe {
|
||||
control_regs::tpidr_el0_write(regs.tpidr_el0 as u64);
|
||||
control_regs::tpidrro_el0_write(regs.tpidrro_el0 as u64);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn write_env_regs(&mut self, regs: EnvRegisters) -> Result<()> {
|
||||
self.arch.tpidr_el0 = regs.tpidr_el0;
|
||||
self.arch.tpidrro_el0 = regs.tpidrro_el0;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn read_current_env_regs(&self) -> Result<EnvRegisters> {
|
||||
unsafe {
|
||||
Ok(EnvRegisters {
|
||||
tpidr_el0: control_regs::tpidr_el0() as usize,
|
||||
tpidrro_el0: control_regs::tpidrro_el0() as usize,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn read_env_regs(&self) -> Result<EnvRegisters> {
|
||||
Ok(EnvRegisters {
|
||||
tpidr_el0: self.arch.tpidr_el0,
|
||||
tpidrro_el0: self.arch.tpidrro_el0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub static EMPTY_CR3: Once<rmm::PhysicalAddress> = Once::new();
|
||||
@@ -324,3 +386,13 @@ unsafe extern "C" fn switch_to_inner(_prev: &mut Context, _next: &mut Context) {
|
||||
options(noreturn),
|
||||
);
|
||||
}
|
||||
|
||||
/// Allocates a new empty utable
|
||||
pub fn setup_new_utable() -> Result<Table> {
|
||||
let utable = unsafe {
|
||||
PageMapper::create(TableKind::User, crate::memory::TheFrameAllocator)
|
||||
.ok_or(Error::new(ENOMEM))?
|
||||
};
|
||||
|
||||
Ok(Table { utable })
|
||||
}
|
||||
|
||||
+113
-1
@@ -6,8 +6,15 @@ use crate::{
|
||||
syscall::FloatRegisters,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
arch::{interrupt::InterruptStack, paging::PageMapper},
|
||||
context::{context::Kstack, memory::Table},
|
||||
memory::RmmA,
|
||||
};
|
||||
use core::mem::offset_of;
|
||||
use rmm::{Arch, TableKind, VirtualAddress};
|
||||
use spin::Once;
|
||||
use syscall::{error::*, EnvRegisters};
|
||||
|
||||
/// This must be used by the kernel to ensure that context switches are done atomically
|
||||
/// Compare and exchange this to true when beginning a context switch on any CPU
|
||||
@@ -62,10 +69,41 @@ impl Context {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_stack(&mut self, address: usize) {
|
||||
fn set_stack(&mut self, address: usize) {
|
||||
self.esp = address;
|
||||
}
|
||||
|
||||
pub(crate) fn setup_initial_call(
|
||||
&mut self,
|
||||
stack: &Kstack,
|
||||
func: extern "C" fn(),
|
||||
userspace_allowed: bool,
|
||||
) {
|
||||
let mut stack_top = stack.initial_top();
|
||||
|
||||
const INT_REGS_SIZE: usize = core::mem::size_of::<InterruptStack>();
|
||||
|
||||
unsafe {
|
||||
if userspace_allowed {
|
||||
// Zero-initialize InterruptStack registers.
|
||||
stack_top = stack_top.sub(INT_REGS_SIZE);
|
||||
stack_top.write_bytes(0_u8, INT_REGS_SIZE);
|
||||
(&mut *stack_top.cast::<InterruptStack>()).init();
|
||||
|
||||
stack_top = stack_top.sub(core::mem::size_of::<usize>());
|
||||
stack_top
|
||||
.cast::<usize>()
|
||||
.write(crate::interrupt::syscall::enter_usermode as usize);
|
||||
}
|
||||
|
||||
stack_top = stack_top.sub(core::mem::size_of::<usize>());
|
||||
stack_top.cast::<usize>().write(func as usize);
|
||||
}
|
||||
|
||||
self.set_stack(stack_top as usize);
|
||||
}
|
||||
}
|
||||
|
||||
impl super::Context {
|
||||
pub fn get_fx_regs(&self) -> FloatRegisters {
|
||||
let mut regs = unsafe { self.kfx.as_ptr().cast::<FloatRegisters>().read() };
|
||||
@@ -121,6 +159,50 @@ impl super::Context {
|
||||
regs.preserved.edi,
|
||||
])
|
||||
}
|
||||
|
||||
pub(crate) fn write_current_env_regs(&mut self, regs: EnvRegisters) -> Result<()> {
|
||||
if RmmA::virt_is_valid(VirtualAddress::new(regs.fsbase as usize))
|
||||
&& RmmA::virt_is_valid(VirtualAddress::new(regs.gsbase as usize))
|
||||
{
|
||||
unsafe {
|
||||
(&mut *pcr()).gdt[GDT_USER_FS].set_offset(regs.fsbase);
|
||||
(&mut *pcr()).gdt[GDT_USER_GS].set_offset(regs.gsbase);
|
||||
}
|
||||
self.arch.fsbase = regs.fsbase as usize;
|
||||
self.arch.gsbase = regs.gsbase as usize;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::new(EINVAL))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn write_env_regs(&mut self, regs: EnvRegisters) -> Result<()> {
|
||||
if RmmA::virt_is_valid(VirtualAddress::new(regs.fsbase as usize))
|
||||
&& RmmA::virt_is_valid(VirtualAddress::new(regs.gsbase as usize))
|
||||
{
|
||||
self.arch.fsbase = regs.fsbase as usize;
|
||||
self.arch.gsbase = regs.gsbase as usize;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::new(EINVAL))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn read_current_env_regs(&self) -> Result<EnvRegisters> {
|
||||
unsafe {
|
||||
Ok(EnvRegisters {
|
||||
fsbase: (&*pcr()).gdt[GDT_USER_FS].offset(),
|
||||
gsbase: (&*pcr()).gdt[GDT_USER_GS].offset(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn read_env_regs(&self) -> Result<EnvRegisters> {
|
||||
Ok(EnvRegisters {
|
||||
fsbase: self.arch.fsbase as u32,
|
||||
gsbase: self.arch.gsbase as u32,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub static EMPTY_CR3: Once<rmm::PhysicalAddress> = Once::new();
|
||||
@@ -227,3 +309,33 @@ unsafe extern "cdecl" fn switch_to_inner() {
|
||||
options(noreturn),
|
||||
);
|
||||
}
|
||||
|
||||
/// Allocates a new identically mapped ktable and empty utable (same memory on x86)
|
||||
pub fn setup_new_utable() -> Result<Table> {
|
||||
use crate::memory::KernelMapper;
|
||||
|
||||
let utable = unsafe {
|
||||
PageMapper::create(TableKind::User, crate::memory::TheFrameAllocator)
|
||||
.ok_or(Error::new(ENOMEM))?
|
||||
};
|
||||
|
||||
{
|
||||
let active_ktable = KernelMapper::lock();
|
||||
|
||||
let copy_mapping = |p4_no| unsafe {
|
||||
let entry = active_ktable
|
||||
.table()
|
||||
.entry(p4_no)
|
||||
.unwrap_or_else(|| panic!("expected kernel PML {} to be mapped", p4_no));
|
||||
|
||||
utable.table().set_entry(p4_no, entry)
|
||||
};
|
||||
|
||||
// Copy higher half (kernel) mappings
|
||||
for i in 512..1024 {
|
||||
copy_mapping(i);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Table { utable })
|
||||
}
|
||||
|
||||
+123
-2
@@ -5,8 +5,15 @@ use core::{
|
||||
|
||||
use crate::syscall::FloatRegisters;
|
||||
|
||||
use crate::{
|
||||
arch::{interrupt::InterruptStack, paging::PageMapper},
|
||||
context::{context::Kstack, memory::Table},
|
||||
memory::RmmA,
|
||||
};
|
||||
use core::mem::offset_of;
|
||||
use rmm::{Arch, TableKind, VirtualAddress};
|
||||
use spin::Once;
|
||||
use syscall::{error::*, EnvRegisters};
|
||||
use x86::msr;
|
||||
|
||||
/// This must be used by the kernel to ensure that context switches are done atomically
|
||||
@@ -74,9 +81,39 @@ impl Context {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_stack(&mut self, address: usize) {
|
||||
fn set_stack(&mut self, address: usize) {
|
||||
self.rsp = address;
|
||||
}
|
||||
|
||||
pub(crate) fn setup_initial_call(
|
||||
&mut self,
|
||||
stack: &Kstack,
|
||||
func: extern "C" fn(),
|
||||
userspace_allowed: bool,
|
||||
) {
|
||||
let mut stack_top = stack.initial_top();
|
||||
|
||||
const INT_REGS_SIZE: usize = core::mem::size_of::<InterruptStack>();
|
||||
|
||||
unsafe {
|
||||
if userspace_allowed {
|
||||
// Zero-initialize InterruptStack registers.
|
||||
stack_top = stack_top.sub(INT_REGS_SIZE);
|
||||
stack_top.write_bytes(0_u8, INT_REGS_SIZE);
|
||||
(&mut *stack_top.cast::<InterruptStack>()).init();
|
||||
|
||||
stack_top = stack_top.sub(core::mem::size_of::<usize>());
|
||||
stack_top
|
||||
.cast::<usize>()
|
||||
.write(crate::interrupt::syscall::enter_usermode as usize);
|
||||
}
|
||||
|
||||
stack_top = stack_top.sub(core::mem::size_of::<usize>());
|
||||
stack_top.cast::<usize>().write(func as usize);
|
||||
}
|
||||
|
||||
self.set_stack(stack_top as usize);
|
||||
}
|
||||
}
|
||||
impl super::Context {
|
||||
pub fn get_fx_regs(&self) -> FloatRegisters {
|
||||
@@ -121,7 +158,7 @@ impl super::Context {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn current_syscall(&self) -> Option<[usize; 6]> {
|
||||
pub(crate) fn current_syscall(&self) -> Option<[usize; 6]> {
|
||||
if !self.inside_syscall {
|
||||
return None;
|
||||
}
|
||||
@@ -136,6 +173,54 @@ impl super::Context {
|
||||
scratch.r8,
|
||||
])
|
||||
}
|
||||
|
||||
pub(crate) fn read_current_env_regs(&self) -> Result<EnvRegisters> {
|
||||
// TODO: Avoid rdmsr if fsgsbase is not enabled, if this is worth optimizing for.
|
||||
unsafe {
|
||||
Ok(EnvRegisters {
|
||||
fsbase: msr::rdmsr(msr::IA32_FS_BASE),
|
||||
gsbase: msr::rdmsr(msr::IA32_KERNEL_GSBASE),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn read_env_regs(&self) -> Result<EnvRegisters> {
|
||||
Ok(EnvRegisters {
|
||||
fsbase: self.arch.fsbase as u64,
|
||||
gsbase: self.arch.gsbase as u64,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn write_current_env_regs(&mut self, regs: EnvRegisters) -> Result<()> {
|
||||
if RmmA::virt_is_valid(VirtualAddress::new(regs.fsbase as usize))
|
||||
&& RmmA::virt_is_valid(VirtualAddress::new(regs.gsbase as usize))
|
||||
{
|
||||
unsafe {
|
||||
x86::msr::wrmsr(x86::msr::IA32_FS_BASE, regs.fsbase as u64);
|
||||
// We have to write to KERNEL_GSBASE, because when the kernel returns to
|
||||
// userspace, it will have executed SWAPGS first.
|
||||
x86::msr::wrmsr(x86::msr::IA32_KERNEL_GSBASE, regs.gsbase as u64);
|
||||
}
|
||||
self.arch.fsbase = regs.fsbase as usize;
|
||||
self.arch.gsbase = regs.gsbase as usize;
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::new(EINVAL))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn write_env_regs(&mut self, regs: EnvRegisters) -> Result<()> {
|
||||
if RmmA::virt_is_valid(VirtualAddress::new(regs.fsbase as usize))
|
||||
&& RmmA::virt_is_valid(VirtualAddress::new(regs.gsbase as usize))
|
||||
{
|
||||
self.arch.fsbase = regs.fsbase as usize;
|
||||
self.arch.gsbase = regs.gsbase as usize;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::new(EINVAL))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub static EMPTY_CR3: Once<rmm::PhysicalAddress> = Once::new();
|
||||
@@ -302,3 +387,39 @@ unsafe extern "sysv64" fn switch_to_inner(_prev: &mut Context, _next: &mut Conte
|
||||
options(noreturn),
|
||||
);
|
||||
}
|
||||
|
||||
/// Allocates a new identically mapped ktable and empty utable (same memory on x86_64).
|
||||
pub fn setup_new_utable() -> Result<Table> {
|
||||
use crate::memory::{KernelMapper, TheFrameAllocator};
|
||||
|
||||
let utable = unsafe {
|
||||
PageMapper::create(TableKind::User, TheFrameAllocator).ok_or(Error::new(ENOMEM))?
|
||||
};
|
||||
|
||||
{
|
||||
let active_ktable = KernelMapper::lock();
|
||||
|
||||
let copy_mapping = |p4_no| unsafe {
|
||||
let entry = active_ktable
|
||||
.table()
|
||||
.entry(p4_no)
|
||||
.unwrap_or_else(|| panic!("expected kernel PML {} to be mapped", p4_no));
|
||||
|
||||
utable.table().set_entry(p4_no, entry)
|
||||
};
|
||||
// TODO: Just copy all 256 mappings? Or copy KERNEL_PML4+KERNEL_PERCPU_PML4 (needed for
|
||||
// paranoid ISRs which can occur anywhere; we don't want interrupts to triple fault!) and
|
||||
// map lazily via page faults in the kernel.
|
||||
|
||||
// Copy kernel image mapping
|
||||
copy_mapping(crate::KERNEL_PML4);
|
||||
|
||||
// Copy kernel heap mapping
|
||||
copy_mapping(crate::KERNEL_HEAP_PML4);
|
||||
|
||||
// Copy physmap mapping
|
||||
copy_mapping(crate::PHYS_PML4);
|
||||
}
|
||||
|
||||
Ok(Table { utable })
|
||||
}
|
||||
|
||||
+1
-78
@@ -12,6 +12,7 @@ use syscall::{error::*, flag::MapFlags, GrantFlags, MunmapFlags};
|
||||
|
||||
use crate::{
|
||||
arch::paging::PAGE_SIZE,
|
||||
context::arch::setup_new_utable,
|
||||
cpu_set::LogicalCpuSet,
|
||||
memory::{
|
||||
deallocate_frame, deallocate_p2frame, get_page_info, init_frame, the_zeroed_frame,
|
||||
@@ -2258,84 +2259,6 @@ impl Drop for Table {
|
||||
}
|
||||
}
|
||||
|
||||
/// Allocates a new empty utable
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
pub fn setup_new_utable() -> Result<Table> {
|
||||
let utable = unsafe {
|
||||
PageMapper::create(TableKind::User, crate::memory::TheFrameAllocator)
|
||||
.ok_or(Error::new(ENOMEM))?
|
||||
};
|
||||
|
||||
Ok(Table { utable })
|
||||
}
|
||||
|
||||
/// Allocates a new identically mapped ktable and empty utable (same memory on x86)
|
||||
#[cfg(target_arch = "x86")]
|
||||
pub fn setup_new_utable() -> Result<Table> {
|
||||
use crate::memory::KernelMapper;
|
||||
|
||||
let utable = unsafe {
|
||||
PageMapper::create(TableKind::User, crate::memory::TheFrameAllocator)
|
||||
.ok_or(Error::new(ENOMEM))?
|
||||
};
|
||||
|
||||
{
|
||||
let active_ktable = KernelMapper::lock();
|
||||
|
||||
let copy_mapping = |p4_no| unsafe {
|
||||
let entry = active_ktable
|
||||
.table()
|
||||
.entry(p4_no)
|
||||
.unwrap_or_else(|| panic!("expected kernel PML {} to be mapped", p4_no));
|
||||
|
||||
utable.table().set_entry(p4_no, entry)
|
||||
};
|
||||
|
||||
// Copy higher half (kernel) mappings
|
||||
for i in 512..1024 {
|
||||
copy_mapping(i);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Table { utable })
|
||||
}
|
||||
|
||||
/// Allocates a new identically mapped ktable and empty utable (same memory on x86_64).
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn setup_new_utable() -> Result<Table> {
|
||||
use crate::memory::{KernelMapper, TheFrameAllocator};
|
||||
|
||||
let utable = unsafe {
|
||||
PageMapper::create(TableKind::User, TheFrameAllocator).ok_or(Error::new(ENOMEM))?
|
||||
};
|
||||
|
||||
{
|
||||
let active_ktable = KernelMapper::lock();
|
||||
|
||||
let copy_mapping = |p4_no| unsafe {
|
||||
let entry = active_ktable
|
||||
.table()
|
||||
.entry(p4_no)
|
||||
.unwrap_or_else(|| panic!("expected kernel PML {} to be mapped", p4_no));
|
||||
|
||||
utable.table().set_entry(p4_no, entry)
|
||||
};
|
||||
// TODO: Just copy all 256 mappings? Or copy KERNEL_PML4+KERNEL_PERCPU_PML4 (needed for
|
||||
// paranoid ISRs which can occur anywhere; we don't want interrupts to triple fault!) and
|
||||
// map lazily via page faults in the kernel.
|
||||
|
||||
// Copy kernel image mapping
|
||||
copy_mapping(crate::KERNEL_PML4);
|
||||
|
||||
// Copy kernel heap mapping
|
||||
copy_mapping(crate::KERNEL_HEAP_PML4);
|
||||
|
||||
// Copy physmap mapping
|
||||
copy_mapping(crate::PHYS_PML4);
|
||||
}
|
||||
|
||||
Ok(Table { utable })
|
||||
}
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum AccessMode {
|
||||
Read,
|
||||
|
||||
+3
-37
@@ -11,7 +11,6 @@ use syscall::ENOMEM;
|
||||
use crate::{
|
||||
context::memory::AddrSpaceWrapper,
|
||||
cpu_set::LogicalCpuSet,
|
||||
interrupt::InterruptStack,
|
||||
paging::{RmmA, RmmArch, TableKind},
|
||||
percpu::PercpuBlock,
|
||||
sync::WaitMap,
|
||||
@@ -182,42 +181,9 @@ pub fn spawn(
|
||||
{
|
||||
let mut context = context_lock.write();
|
||||
let _ = context.set_addr_space(Some(AddrSpaceWrapper::new()?));
|
||||
|
||||
let mut stack_top = stack.initial_top();
|
||||
|
||||
const INT_REGS_SIZE: usize = core::mem::size_of::<crate::interrupt::InterruptStack>();
|
||||
|
||||
if userspace_allowed {
|
||||
unsafe {
|
||||
// Zero-initialize InterruptStack registers.
|
||||
stack_top = stack_top.sub(INT_REGS_SIZE);
|
||||
stack_top.write_bytes(0_u8, INT_REGS_SIZE);
|
||||
(&mut *stack_top.cast::<InterruptStack>()).init();
|
||||
}
|
||||
}
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
unsafe {
|
||||
if userspace_allowed {
|
||||
stack_top = stack_top.sub(core::mem::size_of::<usize>());
|
||||
stack_top
|
||||
.cast::<usize>()
|
||||
.write(crate::interrupt::syscall::enter_usermode as usize);
|
||||
}
|
||||
|
||||
stack_top = stack_top.sub(core::mem::size_of::<usize>());
|
||||
stack_top.cast::<usize>().write(func as usize);
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
{
|
||||
context
|
||||
.arch
|
||||
.set_lr(crate::interrupt::syscall::enter_usermode as usize);
|
||||
context.arch.set_x28(func as usize);
|
||||
context.arch.set_context_handle();
|
||||
}
|
||||
|
||||
context.arch.set_stack(stack_top as usize);
|
||||
context
|
||||
.arch
|
||||
.setup_initial_call(&stack, func, userspace_allowed);
|
||||
|
||||
context.kstack = Some(stack);
|
||||
context.userspace = userspace_allowed;
|
||||
|
||||
+1
-1
@@ -356,7 +356,7 @@ impl SchemeList {
|
||||
}
|
||||
}
|
||||
for name in remove {
|
||||
assert!(names.remove(&name).is_some());
|
||||
assert!(names.swap_remove(&name).is_some());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-134
@@ -1630,147 +1630,19 @@ impl ContextHandle {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
|
||||
fn write_env_regs(context: Arc<RwSpinlock<Context>>, regs: EnvRegisters) -> Result<()> {
|
||||
use crate::device::cpu::registers::control_regs;
|
||||
|
||||
if context::is_current(&context) {
|
||||
unsafe {
|
||||
control_regs::tpidr_el0_write(regs.tpidr_el0 as u64);
|
||||
control_regs::tpidrro_el0_write(regs.tpidrro_el0 as u64);
|
||||
}
|
||||
context::current().write().write_current_env_regs(regs)
|
||||
} else {
|
||||
try_stop_context(context, |context| {
|
||||
context.arch.tpidr_el0 = regs.tpidr_el0;
|
||||
context.arch.tpidrro_el0 = regs.tpidrro_el0;
|
||||
Ok(())
|
||||
})?;
|
||||
try_stop_context(context, |context| context.write_env_regs(regs))
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
fn write_env_regs(context: Arc<RwSpinlock<Context>>, regs: EnvRegisters) -> Result<()> {
|
||||
if !(RmmA::virt_is_valid(VirtualAddress::new(regs.fsbase as usize))
|
||||
&& RmmA::virt_is_valid(VirtualAddress::new(regs.gsbase as usize)))
|
||||
{
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
|
||||
fn read_env_regs(context: Arc<RwSpinlock<Context>>) -> Result<EnvRegisters> {
|
||||
if context::is_current(&context) {
|
||||
unsafe {
|
||||
(&mut *crate::gdt::pcr()).gdt[crate::gdt::GDT_USER_FS].set_offset(regs.fsbase);
|
||||
(&mut *crate::gdt::pcr()).gdt[crate::gdt::GDT_USER_GS].set_offset(regs.gsbase);
|
||||
|
||||
match context.write().arch {
|
||||
ref mut arch => {
|
||||
arch.fsbase = regs.fsbase as usize;
|
||||
arch.gsbase = regs.gsbase as usize;
|
||||
}
|
||||
}
|
||||
}
|
||||
context::current().read().read_current_env_regs()
|
||||
} else {
|
||||
try_stop_context(context, |context| {
|
||||
context.arch.fsbase = regs.fsbase as usize;
|
||||
context.arch.gsbase = regs.gsbase as usize;
|
||||
Ok(())
|
||||
})?;
|
||||
try_stop_context(context, |context| context.read_env_regs())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn write_env_regs(context: Arc<RwSpinlock<Context>>, regs: EnvRegisters) -> Result<()> {
|
||||
use crate::memory::RmmA;
|
||||
use rmm::Arch;
|
||||
if !(RmmA::virt_is_valid(VirtualAddress::new(regs.fsbase as usize))
|
||||
&& RmmA::virt_is_valid(VirtualAddress::new(regs.gsbase as usize)))
|
||||
{
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
|
||||
if context::is_current(&context) {
|
||||
unsafe {
|
||||
x86::msr::wrmsr(x86::msr::IA32_FS_BASE, regs.fsbase as u64);
|
||||
// We have to write to KERNEL_GSBASE, because when the kernel returns to
|
||||
// userspace, it will have executed SWAPGS first.
|
||||
x86::msr::wrmsr(x86::msr::IA32_KERNEL_GSBASE, regs.gsbase as u64);
|
||||
|
||||
match context::current().write().arch {
|
||||
ref mut arch => {
|
||||
arch.fsbase = regs.fsbase as usize;
|
||||
arch.gsbase = regs.gsbase as usize;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try_stop_context(context, |context| {
|
||||
context.arch.fsbase = regs.fsbase as usize;
|
||||
context.arch.gsbase = regs.gsbase as usize;
|
||||
Ok(())
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
fn read_env_regs(context: Arc<RwSpinlock<Context>>) -> Result<EnvRegisters> {
|
||||
use crate::device::cpu::registers::control_regs;
|
||||
|
||||
let (tpidr_el0, tpidrro_el0) = if context::is_current(&context) {
|
||||
unsafe {
|
||||
(
|
||||
control_regs::tpidr_el0() as usize,
|
||||
control_regs::tpidrro_el0() as usize,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
try_stop_context(context, |context| {
|
||||
Ok((context.arch.tpidr_el0, context.arch.tpidrro_el0))
|
||||
})?
|
||||
};
|
||||
Ok(EnvRegisters {
|
||||
tpidr_el0,
|
||||
tpidrro_el0,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
fn read_env_regs(context: Arc<RwSpinlock<Context>>) -> Result<EnvRegisters> {
|
||||
let (fsbase, gsbase) = if context::is_current(&context) {
|
||||
unsafe {
|
||||
(
|
||||
(&*crate::gdt::pcr()).gdt[crate::gdt::GDT_USER_FS].offset() as u64,
|
||||
(&*crate::gdt::pcr()).gdt[crate::gdt::GDT_USER_GS].offset() as u64,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
try_stop_context(context, |context| {
|
||||
Ok((context.arch.fsbase as u64, context.arch.gsbase as u64))
|
||||
})?
|
||||
};
|
||||
Ok(EnvRegisters {
|
||||
fsbase: fsbase as _,
|
||||
gsbase: gsbase as _,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn read_env_regs(context: Arc<RwSpinlock<Context>>) -> Result<EnvRegisters> {
|
||||
// TODO: Avoid rdmsr if fsgsbase is not enabled, if this is worth optimizing for.
|
||||
let (fsbase, gsbase) = if context::is_current(&context) {
|
||||
unsafe {
|
||||
(
|
||||
x86::msr::rdmsr(x86::msr::IA32_FS_BASE),
|
||||
x86::msr::rdmsr(x86::msr::IA32_KERNEL_GSBASE),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
try_stop_context(context, |context| {
|
||||
Ok((context.arch.fsbase as u64, context.arch.gsbase as u64))
|
||||
})?
|
||||
};
|
||||
Ok(EnvRegisters {
|
||||
fsbase: fsbase as _,
|
||||
gsbase: gsbase as _,
|
||||
})
|
||||
}
|
||||
|
||||
+3
-10
@@ -24,7 +24,7 @@ use self::{
|
||||
usercopy::UserSlice,
|
||||
};
|
||||
|
||||
use crate::{interrupt::InterruptStack, percpu::PercpuBlock};
|
||||
use crate::percpu::PercpuBlock;
|
||||
|
||||
use crate::{
|
||||
context::{memory::AddrSpace, process::ProcessId},
|
||||
@@ -60,15 +60,8 @@ pub mod usercopy;
|
||||
|
||||
/// This function is the syscall handler of the kernel, it is composed of an inner function that returns a `Result<usize>`. After the inner function runs, the syscall
|
||||
/// function calls [`Error::mux`] on it.
|
||||
pub fn syscall(
|
||||
a: usize,
|
||||
b: usize,
|
||||
c: usize,
|
||||
d: usize,
|
||||
e: usize,
|
||||
f: usize,
|
||||
_stack: &mut InterruptStack,
|
||||
) -> usize {
|
||||
#[must_use]
|
||||
pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> usize {
|
||||
#[inline(always)]
|
||||
fn inner(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> Result<usize> {
|
||||
let fd = FileHandle::from(b);
|
||||
|
||||
Reference in New Issue
Block a user