proc: Implement simple static TLS support
This commit is contained in:
parent
76d8235411
commit
8bc8b30362
@ -58,9 +58,9 @@ impl StackBuilder {
|
||||
self.sp
|
||||
}
|
||||
|
||||
fn init_common(&mut self, entry: usize, ttbr0: u64) {
|
||||
fn init_common(&mut self, entry: usize, ttbr0: u64, tpidr_el0: u64) {
|
||||
self.push(ttbr0 as _); // ttbr0_el1
|
||||
self.push(0); // tpidr_el0
|
||||
self.push(tpidr_el0 as _); // tpidr_el0
|
||||
|
||||
self.push(entry); // x30/lr
|
||||
self.push(0); // x29
|
||||
@ -91,7 +91,7 @@ impl TaskContextImpl for TaskContext {
|
||||
stack.push(entry as _);
|
||||
stack.push(arg);
|
||||
|
||||
stack.init_common(__aarch64_task_enter_kernel as _, 0);
|
||||
stack.init_common(__aarch64_task_enter_kernel as _, 0, 0);
|
||||
|
||||
let sp = stack.build();
|
||||
|
||||
@ -104,7 +104,13 @@ impl TaskContextImpl for TaskContext {
|
||||
})
|
||||
}
|
||||
|
||||
fn user(entry: usize, arg: usize, ttbr0: u64, user_stack_sp: usize) -> Result<Self, Error> {
|
||||
fn user(
|
||||
entry: usize,
|
||||
arg: usize,
|
||||
ttbr0: u64,
|
||||
user_stack_sp: usize,
|
||||
tpidr_el0: usize,
|
||||
) -> Result<Self, Error> {
|
||||
const USER_TASK_PAGES: usize = 16;
|
||||
let stack_base = phys::alloc_pages_contiguous(USER_TASK_PAGES)?.virtualize_raw();
|
||||
|
||||
@ -115,7 +121,7 @@ impl TaskContextImpl for TaskContext {
|
||||
stack.push(0);
|
||||
stack.push(user_stack_sp);
|
||||
|
||||
stack.init_common(__aarch64_task_enter_user as _, ttbr0);
|
||||
stack.init_common(__aarch64_task_enter_user as _, ttbr0, tpidr_el0 as _);
|
||||
|
||||
let sp = stack.build();
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
// vi: set ft=asm :
|
||||
|
||||
.set MSR_IA32_FS_BASE, 0xC0000100
|
||||
|
||||
.macro SAVE_TASK_STATE
|
||||
sub ${context_size}, %rsp
|
||||
|
||||
@ -8,6 +10,16 @@
|
||||
mov %r13, 16(%rsp)
|
||||
mov %r14, 24(%rsp)
|
||||
mov %r15, 32(%rsp)
|
||||
|
||||
// Store FS_BASE
|
||||
mov $MSR_IA32_FS_BASE, %ecx
|
||||
rdmsr
|
||||
mov %edx, %ecx
|
||||
shl $32, %rcx
|
||||
or %rax, %rcx
|
||||
|
||||
mov %rcx, 40(%rsp)
|
||||
|
||||
// TODO save %fs
|
||||
mov %rbp, 48(%rsp)
|
||||
|
||||
@ -24,7 +36,16 @@
|
||||
mov 16(%rsp), %r13
|
||||
mov 24(%rsp), %r14
|
||||
mov 32(%rsp), %r15
|
||||
// TODO
|
||||
|
||||
// Load FS_BASE
|
||||
// edx:eax = fs_base
|
||||
mov 40(%rsp), %rdx
|
||||
mov %edx, %eax
|
||||
shr $32, %rdx
|
||||
|
||||
mov $MSR_IA32_FS_BASE, %ecx
|
||||
wrmsr
|
||||
|
||||
// mov 40(%rsp), %fs
|
||||
mov 48(%rsp), %rbp
|
||||
|
||||
|
@ -65,14 +65,14 @@ impl StackBuilder {
|
||||
self.sp
|
||||
}
|
||||
|
||||
fn init_common(&mut self, entry: usize, cr3: u64) {
|
||||
fn init_common(&mut self, entry: usize, cr3: u64, fs_base: usize) {
|
||||
self.push(entry); // address for ret
|
||||
|
||||
// End of common context
|
||||
self.push(cr3 as _); // %cr3
|
||||
|
||||
self.push(0); // %rbp
|
||||
self.push(0); // %fs (TODO)
|
||||
self.push(fs_base); // fs_base
|
||||
self.push(0); // %r15
|
||||
self.push(0); // %r14
|
||||
self.push(0); // %r13
|
||||
@ -98,9 +98,11 @@ impl TaskContextImpl for TaskContext {
|
||||
stack.push(entry as _);
|
||||
stack.push(arg);
|
||||
|
||||
stack.init_common(__x86_64_task_enter_kernel as _, unsafe {
|
||||
KERNEL_TABLES.as_physical_address().into_raw()
|
||||
});
|
||||
stack.init_common(
|
||||
__x86_64_task_enter_kernel as _,
|
||||
unsafe { KERNEL_TABLES.as_physical_address().into_raw() },
|
||||
0,
|
||||
);
|
||||
|
||||
let sp = stack.build();
|
||||
infoln!("Kernel stack {:#x}", sp);
|
||||
@ -114,7 +116,13 @@ impl TaskContextImpl for TaskContext {
|
||||
})
|
||||
}
|
||||
|
||||
fn user(entry: usize, arg: usize, cr3: u64, user_stack_sp: usize) -> Result<Self, Error> {
|
||||
fn user(
|
||||
entry: usize,
|
||||
arg: usize,
|
||||
cr3: u64,
|
||||
user_stack_sp: usize,
|
||||
fs_base: usize,
|
||||
) -> Result<Self, Error> {
|
||||
const USER_TASK_PAGES: usize = 8;
|
||||
|
||||
let stack_base = phys::alloc_pages_contiguous(USER_TASK_PAGES)?.virtualize_raw();
|
||||
@ -125,7 +133,7 @@ impl TaskContextImpl for TaskContext {
|
||||
stack.push(arg);
|
||||
stack.push(user_stack_sp);
|
||||
|
||||
stack.init_common(__x86_64_task_enter_user as _, cr3);
|
||||
stack.init_common(__x86_64_task_enter_user as _, cr3, fs_base);
|
||||
|
||||
let sp = stack.build();
|
||||
let rsp0 = stack_base + USER_TASK_PAGES * 0x1000;
|
||||
|
270
src/proc/elf.rs
270
src/proc/elf.rs
@ -2,15 +2,22 @@
|
||||
use core::ops::DerefMut;
|
||||
|
||||
use elf::{
|
||||
abi::{PF_W, PF_X, PT_LOAD},
|
||||
abi::{PF_W, PF_X, PT_LOAD, PT_TLS},
|
||||
endian::AnyEndian,
|
||||
segment::ProgramHeader,
|
||||
ElfStream, ParseError,
|
||||
};
|
||||
use vfs::{FileRef, Read, Seek};
|
||||
use yggdrasil_abi::{error::Error, io::SeekFrom};
|
||||
|
||||
use crate::mem::{
|
||||
phys, pointer::PhysicalRefMut, process::ProcessAddressSpace, table::MapAttributes,
|
||||
use crate::{
|
||||
mem::{
|
||||
phys,
|
||||
pointer::{PhysicalRef, PhysicalRefMut},
|
||||
process::ProcessAddressSpace,
|
||||
table::{EntryLevel, MapAttributes},
|
||||
},
|
||||
task::process::{ProcessImage, ProcessTlsInfo, ProcessTlsLayout},
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
@ -56,6 +63,54 @@ fn from_parse_error(v: ParseError) -> Error {
|
||||
Error::InvalidFile
|
||||
}
|
||||
|
||||
pub fn clone_tls(space: &ProcessAddressSpace, image: &ProcessImage) -> Result<usize, Error> {
|
||||
let Some(tls) = image.tls.as_ref() else {
|
||||
// No TLS
|
||||
return Ok(0);
|
||||
};
|
||||
|
||||
assert_ne!(tls.master_copy_base, 0);
|
||||
assert_ne!(tls.layout.mem_size, 0);
|
||||
|
||||
let address = space.allocate(
|
||||
None,
|
||||
0x1000,
|
||||
|_| phys::alloc_page(),
|
||||
MapAttributes::USER_READ | MapAttributes::USER_WRITE | MapAttributes::NON_GLOBAL,
|
||||
)?;
|
||||
|
||||
debugln!(
|
||||
"Clone TLS from {:#x} (data={:#x}) to {:#x} (data={:#x})",
|
||||
tls.master_copy_base,
|
||||
tls.master_copy_base + tls.layout.data_offset,
|
||||
address,
|
||||
address + tls.layout.data_offset
|
||||
);
|
||||
debugln!("tls ptr = {:#x}", address + tls.layout.ptr_offset);
|
||||
|
||||
let src_phys = space.translate(tls.master_copy_base)?;
|
||||
let dst_phys = space.translate(address)?;
|
||||
|
||||
// Copy data
|
||||
unsafe {
|
||||
let src =
|
||||
PhysicalRef::<u8>::map_slice(src_phys.add(tls.layout.data_offset), tls.layout.mem_size);
|
||||
let mut dst =
|
||||
PhysicalRefMut::map_slice(dst_phys.add(tls.layout.data_offset), tls.layout.mem_size);
|
||||
|
||||
dst.copy_from_slice(&src);
|
||||
}
|
||||
|
||||
// Setup self-pointer
|
||||
unsafe {
|
||||
let mut dst = PhysicalRefMut::<usize>::map(dst_phys.add(tls.layout.ptr_offset));
|
||||
|
||||
*dst = address + tls.layout.ptr_offset;
|
||||
}
|
||||
|
||||
Ok(address + tls.layout.ptr_offset)
|
||||
}
|
||||
|
||||
fn load_bytes<F>(
|
||||
space: &ProcessAddressSpace,
|
||||
addr: usize,
|
||||
@ -92,69 +147,162 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Loads an ELF binary from `file` into the target address space
|
||||
pub fn load_elf_from_file(space: &ProcessAddressSpace, file: FileRef) -> Result<usize, Error> {
|
||||
let file = FileReader { file: &file };
|
||||
fn load_segment(
|
||||
space: &ProcessAddressSpace,
|
||||
phdr: &ProgramHeader,
|
||||
file: &FileReader,
|
||||
) -> Result<(), Error> {
|
||||
if phdr.p_memsz == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let attrs = match (phdr.p_flags & PF_W, phdr.p_flags & PF_X) {
|
||||
(0, 0) => MapAttributes::USER_READ,
|
||||
(_, 0) => MapAttributes::USER_WRITE | MapAttributes::USER_READ,
|
||||
(0, _) => MapAttributes::USER_READ,
|
||||
(_, _) => MapAttributes::USER_WRITE | MapAttributes::USER_READ,
|
||||
} | MapAttributes::NON_GLOBAL;
|
||||
|
||||
// Map the range
|
||||
let aligned_start = (phdr.p_vaddr as usize) & !0xFFF;
|
||||
let aligned_end = ((phdr.p_vaddr + phdr.p_memsz) as usize + 0xFFF) & !0xFFF;
|
||||
|
||||
space.map(
|
||||
aligned_start,
|
||||
aligned_end - aligned_start,
|
||||
|_| phys::alloc_page(),
|
||||
attrs,
|
||||
)?;
|
||||
|
||||
if phdr.p_filesz > 0 {
|
||||
load_bytes(
|
||||
space,
|
||||
phdr.p_vaddr as usize,
|
||||
|off, mut dst| {
|
||||
let mut source = file.file.borrow_mut();
|
||||
source.seek(SeekFrom::Start(phdr.p_offset + off as u64))?;
|
||||
source.read_exact(dst.deref_mut())
|
||||
},
|
||||
phdr.p_filesz as usize,
|
||||
)?;
|
||||
}
|
||||
|
||||
if phdr.p_memsz > phdr.p_filesz {
|
||||
let addr = (phdr.p_vaddr + phdr.p_filesz) as usize;
|
||||
let len = (phdr.p_memsz - phdr.p_filesz) as usize;
|
||||
|
||||
load_bytes(
|
||||
space,
|
||||
addr,
|
||||
|_, mut dst| {
|
||||
dst.fill(0);
|
||||
Ok(())
|
||||
},
|
||||
len,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn tls_segment(
|
||||
space: &ProcessAddressSpace,
|
||||
phdr: &ProgramHeader,
|
||||
file: &FileReader,
|
||||
) -> Result<ProcessTlsInfo, Error> {
|
||||
assert_ne!(phdr.p_memsz, 0);
|
||||
|
||||
if !phdr.p_align.is_power_of_two() {
|
||||
return Err(Error::InvalidArgument);
|
||||
}
|
||||
|
||||
let layout = ProcessTlsLayout::new(phdr.p_align as _, phdr.p_filesz as _, phdr.p_memsz as _);
|
||||
let data_offset = layout.data_offset;
|
||||
let data_size = layout.data_size;
|
||||
let mem_size = layout.mem_size;
|
||||
let aligned_size = (layout.full_size + 0xFFF) & !0xFFF;
|
||||
assert!(aligned_size <= 0x1000);
|
||||
|
||||
let base_address = space.allocate(
|
||||
None,
|
||||
aligned_size,
|
||||
|_| phys::alloc_page(),
|
||||
MapAttributes::USER_READ | MapAttributes::USER_WRITE | MapAttributes::NON_GLOBAL,
|
||||
)?;
|
||||
|
||||
debugln!(
|
||||
"Allocated TLS master copy @ {:#x}, tls={:#x}, tls_data={:#x}",
|
||||
base_address,
|
||||
base_address + layout.ptr_offset,
|
||||
base_address + layout.data_offset
|
||||
);
|
||||
|
||||
let tls = ProcessTlsInfo {
|
||||
master_copy_base: base_address,
|
||||
layout,
|
||||
};
|
||||
|
||||
if data_size > 0 {
|
||||
load_bytes(
|
||||
space,
|
||||
base_address + data_offset,
|
||||
|off, mut dst| {
|
||||
let mut source = file.file.borrow_mut();
|
||||
source.seek(SeekFrom::Start(phdr.p_offset + off as u64))?;
|
||||
source.read_exact(dst.deref_mut())
|
||||
},
|
||||
data_size,
|
||||
);
|
||||
}
|
||||
|
||||
if mem_size > data_size {
|
||||
load_bytes(
|
||||
space,
|
||||
base_address + data_offset + data_size,
|
||||
|off, mut dst| {
|
||||
dst.fill(0);
|
||||
Ok(())
|
||||
},
|
||||
mem_size - data_size,
|
||||
);
|
||||
}
|
||||
|
||||
Ok(tls)
|
||||
}
|
||||
|
||||
/// Loads an ELF binary from `file` into the target address space
|
||||
pub fn load_elf_from_file(
|
||||
space: &ProcessAddressSpace,
|
||||
file: FileRef,
|
||||
) -> Result<ProcessImage, Error> {
|
||||
let file = FileReader { file: &file };
|
||||
let elf = ElfStream::<AnyEndian, _>::open_stream(file).map_err(from_parse_error)?;
|
||||
|
||||
struct TlsInfo {
|
||||
master_address: usize,
|
||||
offset: usize,
|
||||
size: usize,
|
||||
}
|
||||
|
||||
let mut tls = None;
|
||||
|
||||
for phdr in elf.segments() {
|
||||
if phdr.p_type != PT_LOAD {
|
||||
continue;
|
||||
}
|
||||
|
||||
debugln!("LOAD {:#x?}", phdr.p_vaddr..phdr.p_vaddr + phdr.p_memsz);
|
||||
|
||||
let attrs = match (phdr.p_flags & PF_W, phdr.p_flags & PF_X) {
|
||||
(0, 0) => MapAttributes::USER_READ,
|
||||
(_, 0) => MapAttributes::USER_WRITE | MapAttributes::USER_READ,
|
||||
(0, _) => MapAttributes::USER_READ,
|
||||
(_, _) => MapAttributes::USER_WRITE | MapAttributes::USER_READ,
|
||||
} | MapAttributes::NON_GLOBAL;
|
||||
|
||||
if phdr.p_memsz > 0 {
|
||||
// Map the range
|
||||
let aligned_start = (phdr.p_vaddr as usize) & !0xFFF;
|
||||
let aligned_end = ((phdr.p_vaddr + phdr.p_memsz) as usize + 0xFFF) & !0xFFF;
|
||||
|
||||
space.map(
|
||||
aligned_start,
|
||||
aligned_end - aligned_start,
|
||||
|_| phys::alloc_page(),
|
||||
attrs,
|
||||
)?;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
if phdr.p_filesz > 0 {
|
||||
load_bytes(
|
||||
space,
|
||||
phdr.p_vaddr as usize,
|
||||
|off, mut dst| {
|
||||
let mut source = file.file.borrow_mut();
|
||||
source.seek(SeekFrom::Start(phdr.p_offset + off as u64))?;
|
||||
source.read_exact(dst.deref_mut())
|
||||
},
|
||||
phdr.p_filesz as usize,
|
||||
)?;
|
||||
}
|
||||
|
||||
if phdr.p_memsz > phdr.p_filesz {
|
||||
let addr = (phdr.p_vaddr + phdr.p_filesz) as usize;
|
||||
let len = (phdr.p_memsz - phdr.p_filesz) as usize;
|
||||
|
||||
load_bytes(
|
||||
space,
|
||||
addr,
|
||||
|_, mut dst| {
|
||||
dst.fill(0);
|
||||
Ok(())
|
||||
},
|
||||
len,
|
||||
)?;
|
||||
match phdr.p_type {
|
||||
PT_LOAD => {
|
||||
load_segment(space, phdr, &file)?;
|
||||
}
|
||||
PT_TLS => {
|
||||
assert!(tls.is_none());
|
||||
tls.replace(tls_segment(space, phdr, &file)?);
|
||||
// tls_master_address = tls_segment(space, phdr, &file)?;
|
||||
// tls_size = phdr.p_memsz as usize;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(elf.ehdr.e_entry as usize)
|
||||
Ok(ProcessImage {
|
||||
entry: elf.ehdr.e_entry as usize,
|
||||
tls,
|
||||
})
|
||||
}
|
||||
|
@ -11,11 +11,19 @@ use vfs::FileRef;
|
||||
|
||||
use crate::{
|
||||
mem::{
|
||||
phys, pointer::PhysicalRefMut, process::ProcessAddressSpace, table::MapAttributes,
|
||||
phys,
|
||||
pointer::{PhysicalRef, PhysicalRefMut},
|
||||
process::ProcessAddressSpace,
|
||||
table::MapAttributes,
|
||||
ForeignPointer,
|
||||
},
|
||||
proc,
|
||||
task::{context::TaskContextImpl, process::Process, thread::Thread, TaskContext},
|
||||
task::{
|
||||
context::TaskContextImpl,
|
||||
process::{Process, ProcessImage},
|
||||
thread::Thread,
|
||||
TaskContext,
|
||||
},
|
||||
};
|
||||
|
||||
pub struct BufferPlacer<'a> {
|
||||
@ -99,7 +107,7 @@ fn setup_program_env(
|
||||
fn setup_binary<S: Into<String>>(
|
||||
name: S,
|
||||
space: ProcessAddressSpace,
|
||||
entry: usize,
|
||||
image: ProcessImage,
|
||||
args: &[&str],
|
||||
envs: &[&str],
|
||||
) -> Result<(Arc<Process>, Arc<Thread>), Error> {
|
||||
@ -120,7 +128,7 @@ fn setup_binary<S: Into<String>>(
|
||||
|
||||
debugln!(
|
||||
"Entry: {:#x}, Stack: {:#x}..{:#x}, Args: {:#x}",
|
||||
entry,
|
||||
image.entry,
|
||||
virt_stack_base,
|
||||
virt_stack_base + USER_STACK_PAGES * 0x1000,
|
||||
virt_args_base
|
||||
@ -138,9 +146,22 @@ fn setup_binary<S: Into<String>>(
|
||||
}
|
||||
}
|
||||
|
||||
let context = TaskContext::user(entry, arg, space.as_address_with_asid(), user_sp)?;
|
||||
let tls_address = proc::elf::clone_tls(&space, &image)?;
|
||||
|
||||
Ok(Process::new_with_main(name, Arc::new(space), context))
|
||||
let context = TaskContext::user(
|
||||
image.entry,
|
||||
arg,
|
||||
space.as_address_with_asid(),
|
||||
user_sp,
|
||||
tls_address,
|
||||
)?;
|
||||
|
||||
Ok(Process::new_with_main(
|
||||
name,
|
||||
Arc::new(space),
|
||||
context,
|
||||
Some(image),
|
||||
))
|
||||
// Ok(Process::new_with_context(name, Some(space), context))
|
||||
}
|
||||
|
||||
@ -152,7 +173,7 @@ pub fn load_elf<S: Into<String>>(
|
||||
envs: &[&str],
|
||||
) -> Result<(Arc<Process>, Arc<Thread>), Error> {
|
||||
let space = ProcessAddressSpace::new()?;
|
||||
let elf_entry = proc::elf::load_elf_from_file(&space, file)?;
|
||||
let image = proc::elf::load_elf_from_file(&space, file)?;
|
||||
|
||||
setup_binary(name, space, elf_entry, args, envs)
|
||||
setup_binary(name, space, image, args, envs)
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use core::{mem::MaybeUninit, time::Duration};
|
||||
use abi::{
|
||||
error::Error,
|
||||
io::{DeviceRequest, DirectoryEntry, FileAttr, FileMode, OpenOptions, RawFd, SeekFrom},
|
||||
process::{ExitCode, Signal, SpawnOption, SpawnOptions},
|
||||
process::{ExitCode, Signal, SpawnOption, SpawnOptions, ThreadSpawnOptions},
|
||||
syscall::SyscallFunction,
|
||||
};
|
||||
use alloc::rc::Rc;
|
||||
@ -68,15 +68,14 @@ fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error>
|
||||
Ok(0)
|
||||
}
|
||||
SyscallFunction::Nanosleep => {
|
||||
todo!();
|
||||
// let seconds = args[0];
|
||||
// let nanos = args[1] as u32;
|
||||
// let duration = Duration::new(seconds, nanos);
|
||||
let seconds = args[0];
|
||||
let nanos = args[1] as u32;
|
||||
let duration = Duration::new(seconds, nanos);
|
||||
|
||||
// block! {
|
||||
// runtime::sleep(duration).await
|
||||
// }
|
||||
// .map(|_| 0)
|
||||
block! {
|
||||
runtime::sleep(duration).await
|
||||
}
|
||||
.map(|_| 0)
|
||||
}
|
||||
// Resource management
|
||||
SyscallFunction::MapMemory => {
|
||||
@ -361,6 +360,11 @@ fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error>
|
||||
Ok(pid as _)
|
||||
})
|
||||
}
|
||||
SyscallFunction::SpawnThread => {
|
||||
let options = arg_user_ref::<ThreadSpawnOptions>(args[0] as usize)?;
|
||||
let id = process.spawn_thread(options)?;
|
||||
Ok(id.as_user() as _)
|
||||
}
|
||||
SyscallFunction::Exit => {
|
||||
let code = ExitCode::from(args[0] as i32);
|
||||
// TODO separate handlers for process exit and thread exit?
|
||||
@ -368,6 +372,19 @@ fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error>
|
||||
// Process::current().exit(code);
|
||||
panic!();
|
||||
}
|
||||
SyscallFunction::SendSignal => {
|
||||
let pid = ProcessId::from(args[0] as u32);
|
||||
let signal = Signal::try_from(args[1] as u32).map_err(|_| Error::InvalidArgument)?;
|
||||
|
||||
let target = Process::get(pid).ok_or(Error::DoesNotExist)?;
|
||||
target.raise_signal(signal);
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
SyscallFunction::ExitSignal => {
|
||||
panic!("Handled elsewhere");
|
||||
// Process::current().exit_signal();
|
||||
}
|
||||
SyscallFunction::GetPid => Ok(u32::from(process.id()) as usize),
|
||||
SyscallFunction::GetSessionId => todo!(),
|
||||
SyscallFunction::GetProcessGroupId => todo!(),
|
||||
@ -419,20 +436,6 @@ fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error>
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
_ => todo!("{:?}", func),
|
||||
// SyscallFunction::SendSignal => {
|
||||
// let pid = args[0] as u32;
|
||||
// let signal = Signal::try_from(args[1] as u32).map_err(|_| Error::InvalidArgument)?;
|
||||
|
||||
// let target = Process::get(pid as _).ok_or(Error::DoesNotExist)?;
|
||||
// target.raise_signal(signal);
|
||||
|
||||
// Ok(0)
|
||||
// }
|
||||
// SyscallFunction::ExitSignal => {
|
||||
// panic!("Handled elsewhere");
|
||||
// // Process::current().exit_signal();
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,13 @@ pub trait TaskContextImpl: Sized {
|
||||
|
||||
/// Constructs a user thread context. The caller is responsible for allocating the userspace
|
||||
/// stack and setting up a valid address space for the context.
|
||||
fn user(entry: usize, arg: usize, cr3: u64, user_stack_sp: usize) -> Result<Self, Error>;
|
||||
fn user(
|
||||
entry: usize,
|
||||
arg: usize,
|
||||
cr3: u64,
|
||||
user_stack_sp: usize,
|
||||
tls_address: usize,
|
||||
) -> Result<Self, Error>;
|
||||
|
||||
/// Performs an entry into a context.
|
||||
///
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
use core::{
|
||||
fmt,
|
||||
mem::size_of,
|
||||
pin::Pin,
|
||||
sync::atomic::{AtomicU64, Ordering},
|
||||
task::{Context, Poll},
|
||||
@ -9,7 +10,7 @@ use core::{
|
||||
|
||||
use abi::{
|
||||
error::Error,
|
||||
process::{ExitCode, Signal},
|
||||
process::{ExitCode, Signal, ThreadSpawnOptions},
|
||||
};
|
||||
use alloc::{
|
||||
collections::{BTreeMap, VecDeque},
|
||||
@ -21,7 +22,17 @@ use futures_util::Future;
|
||||
use kernel_util::util::OneTimeInit;
|
||||
use vfs::VnodeRef;
|
||||
|
||||
use crate::{mem::process::ProcessAddressSpace, proc::io::ProcessIo, sync::IrqSafeSpinlock};
|
||||
use crate::{
|
||||
mem::{
|
||||
phys,
|
||||
pointer::{PhysicalRef, PhysicalRefMut},
|
||||
process::ProcessAddressSpace,
|
||||
table::MapAttributes,
|
||||
},
|
||||
proc::{self, io::ProcessIo},
|
||||
sync::IrqSafeSpinlock,
|
||||
task::context::TaskContextImpl,
|
||||
};
|
||||
|
||||
use super::{
|
||||
runtime::QueueWaker,
|
||||
@ -39,6 +50,80 @@ pub enum ProcessState {
|
||||
#[repr(transparent)]
|
||||
pub struct ProcessId(u64);
|
||||
|
||||
// TLS layout (x86-64):
|
||||
// | mem_size | uthread_size |
|
||||
// | Data .......| self, ??? |
|
||||
//
|
||||
// TLS layout (aarch64):
|
||||
// | uthread_size (0x10?) | mem_size |
|
||||
// | ??? | Data .....|
|
||||
#[derive(Debug)]
|
||||
pub struct ProcessTlsInfo {
|
||||
pub master_copy_base: usize,
|
||||
pub layout: ProcessTlsLayout,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ProcessTlsLayout {
|
||||
pub data_offset: usize,
|
||||
pub uthread_offset: usize,
|
||||
pub ptr_offset: usize,
|
||||
|
||||
pub data_size: usize,
|
||||
pub mem_size: usize,
|
||||
|
||||
pub full_size: usize,
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
impl ProcessTlsLayout {
|
||||
pub fn new(align: usize, data_size: usize, mem_size: usize) -> Self {
|
||||
debug_assert!(align.is_power_of_two());
|
||||
let tls_block0_offset = (size_of::<usize>() * 2 + align - 1) & !(align - 1);
|
||||
|
||||
let full_size = (tls_block0_offset + mem_size + align - 1) & !(align - 1);
|
||||
|
||||
Self {
|
||||
data_offset: tls_block0_offset,
|
||||
uthread_offset: 0,
|
||||
ptr_offset: 0,
|
||||
|
||||
data_size,
|
||||
mem_size,
|
||||
full_size,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
impl ProcessTlsLayout {
|
||||
pub fn new(align: usize, data_size: usize, mem_size: usize) -> Self {
|
||||
// The static TLS blocks are placed below TP
|
||||
// TP points to the TCB
|
||||
debug_assert!(align.is_power_of_two());
|
||||
let back_size = (mem_size + align - 1) & !(align - 1);
|
||||
// Self-pointer
|
||||
let forward_size = size_of::<usize>();
|
||||
|
||||
let full_size = back_size + forward_size;
|
||||
|
||||
Self {
|
||||
data_offset: 0,
|
||||
uthread_offset: back_size,
|
||||
ptr_offset: back_size,
|
||||
|
||||
data_size,
|
||||
mem_size,
|
||||
full_size,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ProcessImage {
|
||||
pub entry: usize,
|
||||
pub tls: Option<ProcessTlsInfo>,
|
||||
}
|
||||
|
||||
struct ProcessInner {
|
||||
state: ProcessState,
|
||||
|
||||
@ -56,6 +141,7 @@ pub struct Process {
|
||||
|
||||
space: Arc<ProcessAddressSpace>,
|
||||
inner: IrqSafeSpinlock<ProcessInner>,
|
||||
image: Option<ProcessImage>,
|
||||
|
||||
exit_waker: QueueWaker,
|
||||
pub io: IrqSafeSpinlock<ProcessIo>,
|
||||
@ -69,6 +155,7 @@ impl Process {
|
||||
name: S,
|
||||
space: Arc<ProcessAddressSpace>,
|
||||
context: TaskContext,
|
||||
image: Option<ProcessImage>,
|
||||
) -> (Arc<Self>, Arc<Thread>) {
|
||||
let name = name.into();
|
||||
let id = ProcessId::next();
|
||||
@ -77,6 +164,8 @@ impl Process {
|
||||
name,
|
||||
id,
|
||||
|
||||
image,
|
||||
|
||||
space: space.clone(),
|
||||
inner: IrqSafeSpinlock::new(ProcessInner {
|
||||
state: ProcessState::Running,
|
||||
@ -99,6 +188,37 @@ impl Process {
|
||||
(process, thread)
|
||||
}
|
||||
|
||||
pub fn spawn_thread(self: &Arc<Self>, options: &ThreadSpawnOptions) -> Result<ThreadId, Error> {
|
||||
debugln!(
|
||||
"Spawn thread in {} with options: {:#x?}",
|
||||
self.id(),
|
||||
options
|
||||
);
|
||||
|
||||
let tls_address = if let Some(image) = self.image.as_ref() {
|
||||
proc::elf::clone_tls(&self.space, image)?
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let space = self.space.clone();
|
||||
let context = TaskContext::user(
|
||||
options.entry as _,
|
||||
options.argument as _,
|
||||
space.as_address_with_asid(),
|
||||
options.stack_top,
|
||||
tls_address,
|
||||
)?;
|
||||
let thread = Thread::new_uthread(self.clone(), space, context);
|
||||
let id = thread.id();
|
||||
|
||||
self.inner.lock().threads.push(thread.clone());
|
||||
|
||||
thread.enqueue_somewhere();
|
||||
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
pub fn id(&self) -> ProcessId {
|
||||
self.id
|
||||
}
|
||||
|
@ -416,6 +416,13 @@ impl ThreadId {
|
||||
let id = COUNT.fetch_add(1, Ordering::SeqCst);
|
||||
Self::User(id)
|
||||
}
|
||||
|
||||
pub fn as_user(&self) -> u64 {
|
||||
match self {
|
||||
Self::Kernel(_) => panic!(),
|
||||
&Self::User(id) => id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ThreadId {
|
||||
|
Loading…
x
Reference in New Issue
Block a user