Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,6 @@ default = [

#! ### Syscall Features

## Enables multiple address spaces.
##
## This feature makes Hermit use traditional system calls for communicating with the kernel
## instead of using function calls.
##
## Note that this feature is not complete yet.
common-os = []

## Enables support for memory management system calls.
##
## This feature enables functions similar to [sys/mman.h].
Expand Down
8 changes: 4 additions & 4 deletions hermit-macro/src/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ fn emit_func(func: ItemFn, sig: &ParsedSig, errno: bool) -> Result<ItemFn> {
cfg_select! {
all(
feature = "kernel-stack",
not(any(target_arch = "riscv64", feature = "common-os")),
not(target_arch = "riscv64"),
) => {
unsafe { crate::arch::kernel::kernel_stack::#kernel_function_ident(#(#args,)* #kernel_ident) }
}
Expand Down Expand Up @@ -266,7 +266,7 @@ mod tests {
cfg_select! {
all(
feature = "kernel-stack",
not(any(target_arch = "riscv64", feature = "common-os")),
not(target_arch = "riscv64"),
) => {
unsafe { crate::arch::kernel::kernel_stack::kernel_function2(a, b, _sys_test) }
}
Expand Down Expand Up @@ -335,7 +335,7 @@ mod tests {
cfg_select! {
all(
feature = "kernel-stack",
not(any(target_arch = "riscv64", feature = "common-os")),
not(target_arch = "riscv64"),
) => {
unsafe { crate::arch::kernel::kernel_stack::kernel_function2(a, b, _sys_test) }
}
Expand Down Expand Up @@ -406,7 +406,7 @@ mod tests {
cfg_select! {
all(
feature = "kernel-stack",
not(any(target_arch = "riscv64", feature = "common-os")),
not(target_arch = "riscv64"),
) => {
unsafe { crate::arch::kernel::kernel_stack::kernel_function2(a, b, _sys_test) }
}
Expand Down
2 changes: 0 additions & 2 deletions src/arch/aarch64/kernel/scheduler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,6 @@ extern "C" fn task_start(_f: extern "C" fn(usize), _arg: usize) -> ! {
impl TaskFrame for Task {
fn create_stack_frame(&mut self, func: unsafe extern "C" fn(usize), arg: usize) {
// Check if TLS is allocated already and if the task uses thread-local storage.
#[cfg(not(feature = "common-os"))]
if self.tls.is_none() {
use crate::scheduler::task::tls::Tls;

Expand All @@ -297,7 +296,6 @@ impl TaskFrame for Task {
stack -= size_of::<State>();

let state = stack.as_mut_ptr::<State>();
#[cfg(not(feature = "common-os"))]
if let Some(tls) = &self.tls {
(*state).tpidr_el0 = tls.thread_ptr().expose_provenance() as u64;
}
Expand Down
2 changes: 0 additions & 2 deletions src/arch/riscv64/kernel/scheduler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,6 @@ impl TaskFrame for Task {
fn create_stack_frame(&mut self, func: unsafe extern "C" fn(usize), arg: usize) {
// Check if the task (process or thread) uses Thread-Local-Storage.
// check is TLS is already allocated
#[cfg(not(feature = "common-os"))]
if self.tls.is_none() {
use crate::scheduler::task::tls::Tls;

Expand All @@ -293,7 +292,6 @@ impl TaskFrame for Task {
stack -= size_of::<State>();

let state = stack.as_mut_ptr::<State>();
#[cfg(not(feature = "common-os"))]
if let Some(tls) = &self.tls {
(*state).tp = tls.thread_ptr().expose_provenance();
}
Expand Down
28 changes: 0 additions & 28 deletions src/arch/x86_64/kernel/gdt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ use core::sync::atomic::Ordering;
use x86_64::VirtAddr;
use x86_64::instructions::tables;
use x86_64::registers::segmentation::{CS, DS, ES, SS, Segment};
#[cfg(feature = "common-os")]
use x86_64::structures::gdt::DescriptorFlags;
use x86_64::structures::gdt::{Descriptor, GlobalDescriptorTable};
use x86_64::structures::tss::TaskStateSegment;

Expand All @@ -22,13 +20,6 @@ pub fn add_current_core() {
let gdt: &mut GlobalDescriptorTable = Box::leak(Box::new(GlobalDescriptorTable::new()));
let kernel_code_selector = gdt.append(Descriptor::kernel_code_segment());
let kernel_data_selector = gdt.append(Descriptor::kernel_data_segment());
#[cfg(feature = "common-os")]
{
let _user_code32_selector =
gdt.append(Descriptor::UserSegment(DescriptorFlags::USER_CODE32.bits()));
let _user_data64_selector = gdt.append(Descriptor::user_data_segment());
let _user_code64_selector = gdt.append(Descriptor::user_code_segment());
}

// Dynamically allocate memory for a Task-State Segment (TSS) for this core.
let tss = Box::leak(Box::new(TaskStateSegment::new()));
Expand Down Expand Up @@ -73,24 +64,5 @@ pub fn add_current_core() {
}

pub extern "C" fn set_current_kernel_stack() {
#[cfg(feature = "common-os")]
{
use x86_64::PhysAddr;
use x86_64::registers::control::Cr3;
use x86_64::structures::paging::PhysFrame;

let root = crate::scheduler::get_root_page_table();
let new_frame =
PhysFrame::from_start_address(PhysAddr::new(root.try_into().unwrap())).unwrap();

let (current_frame, val) = Cr3::read_raw();

if current_frame != new_frame {
unsafe {
Cr3::write_raw(new_frame, val);
}
}
}

core_scheduler().set_current_kernel_stack();
}
145 changes: 0 additions & 145 deletions src/arch/x86_64/kernel/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
#[cfg(feature = "common-os")]
use core::arch::asm;
use core::ptr;
#[cfg(feature = "common-os")]
use core::slice;
use core::sync::atomic::{AtomicPtr, AtomicU32, Ordering};

use x86_64::registers::control::{Cr0, Cr4};
Expand Down Expand Up @@ -30,8 +26,6 @@ pub mod processor;
pub mod scheduler;
pub mod serial;
pub mod switch;
#[cfg(feature = "common-os")]
mod syscall;
pub(crate) mod systemtime;
#[cfg(feature = "vga")]
pub mod vga;
Expand Down Expand Up @@ -153,142 +147,3 @@ pub fn print_statistics() {
pub static CPU_ONLINE: AtomicU32 = AtomicU32::new(0);

pub static CURRENT_STACK_ADDRESS: AtomicPtr<u8> = AtomicPtr::new(ptr::null_mut());

#[cfg(feature = "common-os")]
const LOADER_START: usize = 0x0100_0000_0000;
#[cfg(feature = "common-os")]
const LOADER_STACK_SIZE: usize = 0x8000;

#[cfg(feature = "common-os")]
pub fn load_application<F, T>(code_size: u64, tls_size: u64, func: F) -> T
where
F: FnOnce(&'static mut [u8], Option<&'static mut [u8]>) -> T,
{
use align_address::Align;
use free_list::PageLayout;
use memory_addresses::{PhysAddr, VirtAddr};
use x86_64::structures::paging::{PageSize, Size4KiB as BasePageSize};

use crate::arch::mm::paging::{self, PageTableEntryFlags, PageTableEntryFlagsExt};
use crate::mm::{FrameAlloc, PageRangeAllocator};

let code_size = (code_size as usize + LOADER_STACK_SIZE).align_up(BasePageSize::SIZE as usize);
let layout = PageLayout::from_size_align(code_size, BasePageSize::SIZE as usize).unwrap();
let frame_range = FrameAlloc::allocate(layout).unwrap();
let physaddr = PhysAddr::from(frame_range.start());

let mut flags = PageTableEntryFlags::empty();
flags.normal().writable().user().execute_enable();
paging::map::<BasePageSize>(
VirtAddr::from(LOADER_START),
physaddr,
code_size / BasePageSize::SIZE as usize,
flags,
);

let loader_start_ptr = ptr::with_exposed_provenance_mut(LOADER_START);
let code_slice = unsafe { slice::from_raw_parts_mut(loader_start_ptr, code_size) };

if tls_size > 0 {
// To access TLS blocks on x86-64, TLS offsets are *subtracted* from the thread register value.
// So the thread pointer needs to be `block_ptr + tls_offset`.
// GNU style TLS requires `fs:0` to represent the same address as the thread pointer.
// Since the thread pointer points to the end of the TLS blocks, we need to store it there.
let tcb_size = size_of::<*mut ()>();
let tls_offset = tls_size as usize;

let tls_memsz = (tls_offset + tcb_size).align_up(BasePageSize::SIZE as usize);
let layout = PageLayout::from_size(tls_memsz).unwrap();
let frame_range = FrameAlloc::allocate(layout).unwrap();
let physaddr = PhysAddr::from(frame_range.start());

let mut flags = PageTableEntryFlags::empty();
flags.normal().writable().user().execute_disable();
let tls_virt = VirtAddr::from(LOADER_START + code_size + BasePageSize::SIZE as usize);
paging::map::<BasePageSize>(
tls_virt,
physaddr,
tls_memsz / BasePageSize::SIZE as usize,
flags,
);
let block =
unsafe { slice::from_raw_parts_mut(tls_virt.as_mut_ptr(), tls_offset + tcb_size) };
for elem in block.iter_mut() {
*elem = 0;
}

// thread_ptr = block_ptr + tls_offset
let thread_ptr = block[tls_offset..].as_mut_ptr().cast::<()>();
unsafe {
thread_ptr.cast::<*mut ()>().write(thread_ptr);
}
processor::writefs(thread_ptr.expose_provenance());

func(code_slice, Some(block))
} else {
func(code_slice, None)
}
}

#[cfg(feature = "common-os")]
pub unsafe fn jump_to_user_land(entry_point: usize, code_size: usize, arg: &[&str]) -> ! {
use alloc::ffi::CString;

use align_address::Align;
use x86_64::structures::paging::{PageSize, Size4KiB as BasePageSize};

use crate::arch::kernel::scheduler::TaskStacks;

info!("Create new file descriptor table");
core_scheduler().recreate_objmap().unwrap();

let entry_point: usize = LOADER_START | entry_point;
let stack_pointer: usize = LOADER_START
+ (code_size + LOADER_STACK_SIZE).align_up(BasePageSize::SIZE.try_into().unwrap())
- 8;

let stack_pointer = stack_pointer - 128 /* red zone */ - arg.len() * size_of::<*mut u8>();
let stack_ptr = ptr::with_exposed_provenance_mut::<*mut u8>(stack_pointer);
let argv = unsafe { slice::from_raw_parts_mut(stack_ptr, arg.len()) };
let len = arg.iter().fold(0, |acc, x| acc + x.len() + 1);
// align stack pointer to fulfill the requirements of the x86_64 ABI
let stack_pointer = (stack_pointer - len).align_down(16) - size_of::<usize>();

let mut pos: usize = 0;
for (i, s) in arg.iter().enumerate() {
let s = CString::new(*s).unwrap();
let bytes = s.as_bytes_with_nul();
argv[i] = ptr::with_exposed_provenance_mut::<u8>(stack_pointer + pos);
pos += bytes.len();

unsafe {
argv[i].copy_from_nonoverlapping(bytes.as_ptr(), bytes.len());
}
}

debug!("Jump to user space at 0x{entry_point:x}, stack pointer 0x{stack_pointer:x}");

unsafe {
asm!(
"and rsp, {0}",
"swapgs",
"push {1}",
"push {2}",
"push {3}",
"push {4}",
"push {5}",
"mov rdi, {6}",
"mov rsi, {7}",
"iretq",
const u64::MAX - (TaskStacks::MARKER_SIZE as u64 - 1),
const 0x23usize,
in(reg) stack_pointer,
const 0x1202u64,
const 0x2busize,
in(reg) entry_point,
in(reg) argv.len(),
in(reg) argv.as_ptr(),
options(nostack, noreturn)
);
}
}
31 changes: 0 additions & 31 deletions src/arch/x86_64/kernel/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -874,37 +874,6 @@ pub fn configure() {
}
}

// enable support of syscall and sysret
#[cfg(feature = "common-os")]
{
use x86_64::PrivilegeLevel;
use x86_64::registers::model_specific::{LStar, SFMask, Star};
use x86_64::registers::rflags::RFlags;
use x86_64::structures::gdt::SegmentSelector;

use crate::arch::kernel::syscall;

let has_syscall = match cpuid.get_extended_processor_and_feature_identifiers() {
Some(finfo) => finfo.has_syscall_sysret(),
None => false,
};

if has_syscall {
info!("Enable SYSCALL support");
} else {
panic!("Syscall support is missing");
}
let cs_sysret = SegmentSelector::new(5, PrivilegeLevel::Ring3);
let ss_sysret = SegmentSelector::new(4, PrivilegeLevel::Ring3);
let cs_syscall = SegmentSelector::new(1, PrivilegeLevel::Ring0);
let ss_syscall = SegmentSelector::new(2, PrivilegeLevel::Ring0);
Star::write(cs_sysret, ss_sysret, cs_syscall, ss_syscall).unwrap();
let syscall_handler_addr = syscall::syscall_handler as *const ();
let syscall_handler_addr = VirtAddr::from_ptr(syscall_handler_addr);
LStar::write(syscall_handler_addr);
SFMask::write(RFlags::INTERRUPT_FLAG); // clear IF flag during system call
}

// Initialize the FS register, which is later used for Thread-Local Storage.
writefs(0);

Expand Down
5 changes: 0 additions & 5 deletions src/arch/x86_64/kernel/scheduler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@ use crate::scheduler::{PerCoreSchedulerExt, timer_interrupts};

#[repr(C, packed)]
struct State {
#[cfg(feature = "common-os")]
/// GS register
gs: u64,
/// FS register for TLS support
fs: u64,
/// R15 register
Expand Down Expand Up @@ -269,7 +266,6 @@ extern "C" fn task_entry(func: extern "C" fn(usize), arg: usize) -> ! {
impl TaskFrame for Task {
fn create_stack_frame(&mut self, func: unsafe extern "C" fn(usize), arg: usize) {
// Check if TLS is allocated already and if the task uses thread-local storage.
#[cfg(not(feature = "common-os"))]
if self.tls.is_none() {
use crate::scheduler::task::tls::Tls;

Expand All @@ -286,7 +282,6 @@ impl TaskFrame for Task {
stack -= size_of::<State>();

let state = stack.as_mut_ptr::<State>();
#[cfg(not(feature = "common-os"))]
if let Some(tls) = &self.tls {
(*state).fs = tls.thread_ptr().addr() as u64;
}
Expand Down
Loading
Loading