WIP: Let userspace manage fsbase/gsbase and TLS.

This commit is contained in:
4lDO2
2021-08-01 12:09:22 +02:00
parent 0968e4f87e
commit 3eedbeb14d
13 changed files with 283 additions and 214 deletions
+15 -22
View File
@@ -36,10 +36,16 @@ pub struct Context {
rbp: usize,
/// Stack pointer
rsp: usize,
/// FSBASE
pub fsbase: usize,
/// GSBASE
gsbase: usize,
/// FSBASE.
///
/// NOTE: Same fsgsbase behavior as with gsbase.
pub(crate) fsbase: usize,
/// GSBASE.
///
/// NOTE: Without fsgsbase, this register will strictly be equal to the register value when
/// running. With fsgsbase, this is neither saved nor restored upon every syscall (there is no
/// need to!), and thus it must be re-read from the register before copying this struct.
pub(crate) gsbase: usize,
/// FX valid?
loadable: AbiCompatBool,
}
@@ -52,7 +58,7 @@ enum AbiCompatBool {
}
impl Context {
pub fn new(pid: usize) -> Context {
pub fn new() -> Context {
Context {
loadable: AbiCompatBool::False,
fx: 0,
@@ -65,13 +71,10 @@ impl Context {
r15: 0,
rbp: 0,
rsp: 0,
fsbase: crate::USER_TCB_OFFSET + pid * crate::memory::PAGE_SIZE,
fsbase: 0,
gsbase: 0,
}
}
pub fn update_tcb(&mut self, pid: usize) {
self.fsbase = crate::USER_TCB_OFFSET + pid * crate::memory::PAGE_SIZE;
}
pub fn get_page_utable(&mut self) -> usize {
self.cr3
@@ -147,19 +150,10 @@ impl Context {
}
}
macro_rules! switch_msr(
macro_rules! load_msr(
($name:literal, $offset:literal) => {
concat!("
// EDX:EAX <= MSR
mov ecx, {", $name, "}
rdmsr
shl rdx, 32
mov edx, eax
// Save old, load new.
mov [rdi + {", $offset, "}], rdx
mov rdx, [rsi + {", $offset, "}]
mov eax, edx
shr rdx, 32
@@ -198,10 +192,9 @@ macro_rules! switch_fsgsbase(
#[cfg(not(feature = "x86_fsgsbase"))]
macro_rules! switch_fsgsbase(
() => {
// TODO: Is it faster to perform two 32-bit memory accesses, rather than shifting?
concat!(
switch_msr!("MSR_FSBASE", "off_fsbase"),
switch_msr!("MSR_KERNELGSBASE", "off_gsbase"),
load_msr!("MSR_FSBASE", "off_fsbase"),
load_msr!("MSR_KERNELGSBASE", "off_gsbase"),
)
}
);
+63 -12
View File
@@ -9,6 +9,7 @@ use core::{
alloc::{GlobalAlloc, Layout},
cmp::Ordering,
mem,
ptr::NonNull,
};
use spin::RwLock;
@@ -20,7 +21,9 @@ use crate::context::memory::{UserGrants, Memory, SharedMemory, Tls};
use crate::ipi::{ipi, IpiKind, IpiTarget};
use crate::scheme::{SchemeNamespace, FileHandle};
use crate::sync::WaitMap;
use crate::syscall::data::SigAction;
use crate::syscall::error::{Result, Error, ENOMEM};
use crate::syscall::flag::{SIG_DFL, SigActionFlags};
/// Unique identifier for a context (i.e. `pid`).
@@ -203,9 +206,9 @@ pub struct Context {
/// Current system call
pub syscall: Option<(usize, usize, usize, usize, usize, usize)>,
/// Head buffer to use when system call buffers are not page aligned
pub syscall_head: Box<[u8]>,
pub syscall_head: AlignedBox<[u8; PAGE_SIZE], PAGE_SIZE>,
/// Tail buffer to use when system call buffers are not page aligned
pub syscall_tail: Box<[u8]>,
pub syscall_tail: AlignedBox<[u8; PAGE_SIZE], PAGE_SIZE>,
/// Context is halting parent
pub vfork: bool,
/// Context is being waited on
@@ -230,8 +233,6 @@ pub struct Context {
pub stack: Option<SharedMemory>,
/// User signal stack
pub sigstack: Option<Memory>,
/// User Thread local storage
pub tls: Option<Tls>,
/// User grants
pub grants: Arc<RwLock<UserGrants>>,
/// The name of the context
@@ -253,12 +254,63 @@ pub struct Context {
pub ptrace_stop: bool
}
impl Context {
pub fn new(id: ContextId) -> Context {
let syscall_head = unsafe { Box::from_raw(crate::ALLOCATOR.alloc(Layout::from_size_align_unchecked(PAGE_SIZE, PAGE_SIZE)) as *mut [u8; PAGE_SIZE]) };
let syscall_tail = unsafe { Box::from_raw(crate::ALLOCATOR.alloc(Layout::from_size_align_unchecked(PAGE_SIZE, PAGE_SIZE)) as *mut [u8; PAGE_SIZE]) };
// Necessary because GlobalAlloc::dealloc requires the layout to be the same, and therefore Box
// cannot be used for increased alignment directly.
// TODO: move to common?
pub struct AlignedBox<T, const ALIGN: usize> {
inner: Unique<T>,
}
pub unsafe trait ValidForZero {}
unsafe impl<const N: usize> ValidForZero for [u8; N] {}
Context {
impl<T, const ALIGN: usize> AlignedBox<T, ALIGN> {
const LAYOUT: core::alloc::Layout = {
const fn max(a: usize, b: usize) -> usize {
if a > b { a } else { b }
}
match core::alloc::Layout::from_size_align(mem::size_of::<T>(), max(mem::align_of::<T>(), ALIGN)) {
Ok(l) => l,
Err(_) => panic!("layout validation failed at compile time"),
}
};
#[inline(always)]
pub fn try_zeroed() -> Result<Self>
where
T: ValidForZero,
{
Ok(unsafe {
let ptr = crate::ALLOCATOR.alloc_zeroed(Self::LAYOUT);
if ptr.is_null() {
return Err(Error::new(ENOMEM))?;
}
Self {
inner: Unique::new_unchecked(ptr.cast()),
}
})
}
}
impl<T, const ALIGN: usize> core::fmt::Debug for AlignedBox<T, ALIGN> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "[aligned box at {:p}, size {} alignment {}]", self.inner.as_ptr(), mem::size_of::<T>(), mem::align_of::<T>())
}
}
impl<T, const ALIGN: usize> Drop for AlignedBox<T, ALIGN> {
fn drop(&mut self) {
unsafe {
core::ptr::drop_in_place(self.inner.as_ptr());
crate::ALLOCATOR.dealloc(self.inner.as_ptr().cast(), Self::LAYOUT);
}
}
}
impl Context {
pub fn new(id: ContextId) -> Result<Context> {
let syscall_head = AlignedBox::try_zeroed()?;
let syscall_tail = AlignedBox::try_zeroed()?;
Ok(Context {
id,
pgid: id,
ppid: ContextId::from(0),
@@ -282,7 +334,7 @@ impl Context {
waitpid: Arc::new(WaitMap::new()),
pending: VecDeque::new(),
wake: None,
arch: arch::Context::new(id.into()),
arch: arch::Context::new(),
kfx: None,
kstack: None,
ksig: None,
@@ -290,7 +342,6 @@ impl Context {
image: Vec::new(),
stack: None,
sigstack: None,
tls: None,
grants: Arc::new(RwLock::new(UserGrants::default())),
name: Arc::new(RwLock::new(String::new().into_boxed_str())),
cwd: Arc::new(RwLock::new(String::new())),
@@ -305,7 +356,7 @@ impl Context {
); 128])),
regs: None,
ptrace_stop: false
}
})
}
/// Make a relative path absolute
+1 -1
View File
@@ -69,7 +69,7 @@ impl ContextList {
let id = ContextId::from(self.next_id);
self.next_id += 1;
assert!(self.map.insert(id, Arc::new(RwLock::new(Context::new(id)))).is_none());
assert!(self.map.insert(id, Arc::new(RwLock::new(Context::new(id)?))).is_none());
Ok(self.map.get(&id).expect("Failed to insert new context. ID is out of bounds."))
}