proc: implement proper TLS for i686

This commit is contained in:
Mark Poliakov 2024-11-18 00:05:52 +02:00
parent e0e39d2f23
commit 961ff9ff6f
6 changed files with 110 additions and 57 deletions

View File

@ -74,6 +74,8 @@ pub struct InterruptFrame {
struct Inner { struct Inner {
// 0x00 // 0x00
sp: usize, sp: usize,
gs_base: usize,
} }
#[allow(dead_code)] #[allow(dead_code)]
@ -88,11 +90,29 @@ pub struct TaskContextImpl<
cr3: u32, cr3: u32,
tss_esp0: u32, tss_esp0: u32,
gs_base: usize,
_pd: PhantomData<(K, PA)>, _pd: PhantomData<(K, PA)>,
} }
impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddress>>
TaskContextImpl<K, PA>
{
unsafe fn store_state(&self) {
if let Some(fpu) = self.fpu_context.as_ref() {
FpuContext::store(fpu.get());
}
}
unsafe fn load_state(&self) {
if let Some(fpu) = self.fpu_context.as_ref() {
FpuContext::restore(fpu.get());
}
gdt::set_gs_base((*self.inner.get()).gs_base);
TSS.esp0 = self.tss_esp0;
CR3.set(self.cr3 as _);
}
}
impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddress>> impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddress>>
TaskContext<K, PA> for TaskContextImpl<K, PA> TaskContext<K, PA> for TaskContextImpl<K, PA>
{ {
@ -123,14 +143,16 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
let fpu_context = FpuContext::new(true); let fpu_context = FpuContext::new(true);
Ok(Self { Ok(Self {
inner: UnsafeCell::new(Inner { sp }), inner: UnsafeCell::new(Inner {
sp,
gs_base: context.thread_pointer,
}),
fpu_context: Some(UnsafeCell::new(fpu_context)), fpu_context: Some(UnsafeCell::new(fpu_context)),
stack_base_phys, stack_base_phys,
stack_size: USER_TASK_PAGES * 0x1000, stack_size: USER_TASK_PAGES * 0x1000,
tss_esp0: esp0 as _, tss_esp0: esp0 as _,
cr3: context.address_space.try_into().unwrap(), cr3: context.address_space.try_into().unwrap(),
gs_base: context.thread_pointer,
_pd: PhantomData, _pd: PhantomData,
}) })
@ -166,61 +188,42 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
// TODO stack is leaked // TODO stack is leaked
Ok(Self { Ok(Self {
inner: UnsafeCell::new(Inner { sp }), inner: UnsafeCell::new(Inner { sp, gs_base: 0 }),
fpu_context: None, fpu_context: None,
stack_base_phys, stack_base_phys,
stack_size: KERNEL_TASK_PAGES * 0x1000, stack_size: KERNEL_TASK_PAGES * 0x1000,
tss_esp0: 0, tss_esp0: 0,
cr3, cr3,
gs_base: 0,
_pd: PhantomData, _pd: PhantomData,
}) })
} }
unsafe fn switch(&self, from: &Self) { unsafe fn switch(&self, from: &Self) {
let dst = self.inner.get(); if core::ptr::addr_eq(self, from) {
let src = from.inner.get(); return;
if dst != src {
// Save the old context
if let Some(src_fpu) = from.fpu_context.as_ref() {
FpuContext::store(src_fpu.get());
}
// Load next context
if let Some(dst_fpu) = self.fpu_context.as_ref() {
FpuContext::restore(dst_fpu.get());
}
gdt::set_gs_base(self.gs_base);
TSS.esp0 = self.tss_esp0;
CR3.set(self.cr3 as _);
__i686_switch_task(dst, src);
} }
from.store_state();
self.load_state();
__i686_switch_task(self.inner.get(), from.inner.get());
} }
unsafe fn enter(&self) -> ! { unsafe fn enter(&self) -> ! {
if let Some(dst_fpu) = self.fpu_context.as_ref() { self.load_state();
FpuContext::restore(dst_fpu.get());
}
gdt::set_gs_base(self.gs_base);
TSS.esp0 = self.tss_esp0;
CR3.set(self.cr3 as _);
__i686_enter_task(self.inner.get()) __i686_enter_task(self.inner.get())
} }
unsafe fn switch_and_drop(&self, thread: *const ()) { unsafe fn switch_and_drop(&self, thread: *const ()) {
if let Some(dst_fpu) = self.fpu_context.as_ref() { self.load_state();
FpuContext::restore(dst_fpu.get()); __i686_switch_and_drop(self.inner.get(), thread);
} }
gdt::set_gs_base(self.gs_base);
TSS.esp0 = self.tss_esp0;
CR3.set(self.cr3 as _);
__i686_switch_and_drop(self.inner.get(), thread) fn set_thread_pointer(&self, tp: usize) {
unsafe { (*self.inner.get()).gs_base = tp };
gdt::set_gs_base(tp);
} }
} }

View File

@ -1,6 +1,6 @@
#![allow(missing_docs)] #![allow(missing_docs)]
use abi::error::Error; use abi::{error::Error, process::ThreadOption};
pub fn get_thread_pointer() -> usize { pub fn get_thread_pointer() -> usize {
let tp: usize; let tp: usize;
@ -11,5 +11,5 @@ pub fn get_thread_pointer() -> usize {
} }
pub unsafe fn set_thread_pointer(value: usize) -> Result<(), Error> { pub unsafe fn set_thread_pointer(value: usize) -> Result<(), Error> {
todo!() crate::sys::set_thread_option(&ThreadOption::ThreadPointer(value))
} }

View File

@ -76,6 +76,8 @@ pub fn clone_tls(image: &TlsImage, tcb_size: usize) -> Result<(usize, usize), Er
// Zero the TCB after the self-pointer // Zero the TCB after the self-pointer
tcb[size_of::<usize>()..].fill(0); tcb[size_of::<usize>()..].fill(0);
crate::debug_trace!("TLS: base={:#x}, tp={:#x}", base, tp);
Ok((base, tp)) Ok((base, tp))
} }

View File

@ -0,0 +1,33 @@
use elf::relocation::{Rel, Rela};
use crate::{error::Error, object::ResolvedSymbol, state::State};
use super::{RelValue, RelaValue, Relocation};
impl Relocation for Rela {
type Value = RelaValue;
fn resolve(
&self,
_state: &State,
_name: &str,
_symbol: &ResolvedSymbol,
_load_base: usize,
) -> Result<Option<Self::Value>, Error> {
unimplemented!("rela-type relocations are not implemented for i686")
}
}
impl Relocation for Rel {
type Value = RelValue;
fn resolve(
&self,
state: &State,
name: &str,
symbol: &ResolvedSymbol,
load_base: usize,
) -> Result<Option<Self::Value>, Error> {
todo!()
}
}

View File

@ -2,11 +2,17 @@ use crate::{error::Error, mapping::Mapping, object::ResolvedSymbol, state::State
#[cfg(any(target_arch = "x86_64", rust_analyzer))] #[cfg(any(target_arch = "x86_64", rust_analyzer))]
mod x86_64; mod x86_64;
#[cfg(any(target_arch = "x86", rust_analyzer))]
mod i686;
pub enum RelaValue { pub enum RelaValue {
QWord(i64), QWord(i64),
} }
pub enum RelValue {
}
pub trait RelocationValue { pub trait RelocationValue {
fn write(&self, mapping: &mut Mapping, offset: u64); fn write(&self, mapping: &mut Mapping, offset: u64);
} }
@ -30,3 +36,9 @@ impl RelocationValue for RelaValue {
} }
} }
} }
impl RelocationValue for RelValue {
fn write(&self, mapping: &mut Mapping, offset: u64) {
match *self {}
}
}

View File

@ -9,7 +9,7 @@ use walkdir::WalkDir;
use crate::{ use crate::{
build::{c, cargo::CargoBuilder}, build::{c, cargo::CargoBuilder},
check::AllOk, check::AllOk,
env::BuildEnv, env::{Arch, BuildEnv},
error::Error, error::Error,
util, util,
}; };
@ -62,8 +62,6 @@ const PROGRAMS: &[(&str, &str)] = &[
("crypt", "bin/crypt"), ("crypt", "bin/crypt"),
("dyn-loader", "libexec/dyn-loader"), ("dyn-loader", "libexec/dyn-loader"),
// TODO: proper process for C program builds // TODO: proper process for C program builds
("c-test", "c-test"),
("c-test-static", "c-test-static"),
]; ];
fn build_userspace( fn build_userspace(
@ -73,8 +71,11 @@ fn build_userspace(
) -> Result<(), Error> { ) -> Result<(), Error> {
log::info!("Building userspace"); log::info!("Building userspace");
CargoBuilder::Userspace(env).build(env.workspace_root.join("userspace"))?; CargoBuilder::Userspace(env).build(env.workspace_root.join("userspace"))?;
CargoBuilder::Userspace(env).build(env.workspace_root.join("userspace/dynload-program"))?; // TODO other architectures
c::build_c(env, extra)?; if env.arch == Arch::x86_64 {
CargoBuilder::Userspace(env).build(env.workspace_root.join("userspace/dynload-program"))?;
c::build_c(env, extra)?;
}
Ok(()) Ok(())
} }
@ -116,20 +117,22 @@ fn build_rootfs<S: AsRef<Path>, D: AsRef<Path>>(
// TODO this is a temporary hack // TODO this is a temporary hack
fs::create_dir_all(rootfs_dir.join("lib"))?; fs::create_dir_all(rootfs_dir.join("lib"))?;
util::copy_file( // TODO other architectures
env.workspace_root.join(format!( if env.arch == Arch::x86_64 {
"userspace/dynload-program/target/{}-unknown-yggdrasil/{}/dynload-program", util::copy_file(
env.arch.name(), env.workspace_root.join(format!(
env.profile.name() "userspace/dynload-program/target/{}-unknown-yggdrasil/{}/dynload-program",
)), env.arch.name(),
rootfs_dir.join("dynload-program"), env.profile.name()
)?; )),
util::copy_file(format!( rootfs_dir.join("dynload-program"),
"/home/alnyan/build/ygg/toolchain/build/host/stage1-std/{}-unknown-yggdrasil/release/libstd.so", )?;
env.arch.name()
), rootfs_dir.join("lib/libstd.so"))?;
log::info!("Installing ygglibc"); util::copy_file(format!(
"/home/alnyan/build/ygg/toolchain/build/host/stage1-std/{}-unknown-yggdrasil/release/libstd.so",
env.arch.name()
), rootfs_dir.join("lib/libstd.so"))?;
}
log::info!("Installing extras"); log::info!("Installing extras");
for (src, dst) in install_extra { for (src, dst) in install_extra {