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 {
// 0x00
sp: usize,
gs_base: usize,
}
#[allow(dead_code)]
@ -88,11 +90,29 @@ pub struct TaskContextImpl<
cr3: u32,
tss_esp0: u32,
gs_base: usize,
_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>>
TaskContext<K, PA> for TaskContextImpl<K, PA>
{
@ -123,14 +143,16 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
let fpu_context = FpuContext::new(true);
Ok(Self {
inner: UnsafeCell::new(Inner { sp }),
inner: UnsafeCell::new(Inner {
sp,
gs_base: context.thread_pointer,
}),
fpu_context: Some(UnsafeCell::new(fpu_context)),
stack_base_phys,
stack_size: USER_TASK_PAGES * 0x1000,
tss_esp0: esp0 as _,
cr3: context.address_space.try_into().unwrap(),
gs_base: context.thread_pointer,
_pd: PhantomData,
})
@ -166,61 +188,42 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
// TODO stack is leaked
Ok(Self {
inner: UnsafeCell::new(Inner { sp }),
inner: UnsafeCell::new(Inner { sp, gs_base: 0 }),
fpu_context: None,
stack_base_phys,
stack_size: KERNEL_TASK_PAGES * 0x1000,
tss_esp0: 0,
cr3,
gs_base: 0,
_pd: PhantomData,
})
}
unsafe fn switch(&self, from: &Self) {
let dst = self.inner.get();
let src = from.inner.get();
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());
if core::ptr::addr_eq(self, from) {
return;
}
gdt::set_gs_base(self.gs_base);
TSS.esp0 = self.tss_esp0;
CR3.set(self.cr3 as _);
from.store_state();
self.load_state();
__i686_switch_task(dst, src);
}
__i686_switch_task(self.inner.get(), from.inner.get());
}
unsafe fn enter(&self) -> ! {
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 _);
self.load_state();
__i686_enter_task(self.inner.get())
}
unsafe fn switch_and_drop(&self, thread: *const ()) {
if let Some(dst_fpu) = self.fpu_context.as_ref() {
FpuContext::restore(dst_fpu.get());
self.load_state();
__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)]
use abi::error::Error;
use abi::{error::Error, process::ThreadOption};
pub fn get_thread_pointer() -> usize {
let tp: usize;
@ -11,5 +11,5 @@ pub fn get_thread_pointer() -> usize {
}
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
tcb[size_of::<usize>()..].fill(0);
crate::debug_trace!("TLS: base={:#x}, tp={:#x}", 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))]
mod x86_64;
#[cfg(any(target_arch = "x86", rust_analyzer))]
mod i686;
pub enum RelaValue {
QWord(i64),
}
pub enum RelValue {
}
pub trait RelocationValue {
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::{
build::{c, cargo::CargoBuilder},
check::AllOk,
env::BuildEnv,
env::{Arch, BuildEnv},
error::Error,
util,
};
@ -62,8 +62,6 @@ const PROGRAMS: &[(&str, &str)] = &[
("crypt", "bin/crypt"),
("dyn-loader", "libexec/dyn-loader"),
// TODO: proper process for C program builds
("c-test", "c-test"),
("c-test-static", "c-test-static"),
];
fn build_userspace(
@ -73,8 +71,11 @@ fn build_userspace(
) -> Result<(), Error> {
log::info!("Building userspace");
CargoBuilder::Userspace(env).build(env.workspace_root.join("userspace"))?;
// TODO other architectures
if env.arch == Arch::x86_64 {
CargoBuilder::Userspace(env).build(env.workspace_root.join("userspace/dynload-program"))?;
c::build_c(env, extra)?;
}
Ok(())
}
@ -116,6 +117,8 @@ fn build_rootfs<S: AsRef<Path>, D: AsRef<Path>>(
// TODO this is a temporary hack
fs::create_dir_all(rootfs_dir.join("lib"))?;
// TODO other architectures
if env.arch == Arch::x86_64 {
util::copy_file(
env.workspace_root.join(format!(
"userspace/dynload-program/target/{}-unknown-yggdrasil/{}/dynload-program",
@ -124,12 +127,12 @@ fn build_rootfs<S: AsRef<Path>, D: AsRef<Path>>(
)),
rootfs_dir.join("dynload-program"),
)?;
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 ygglibc");
}
log::info!("Installing extras");
for (src, dst) in install_extra {