Skip to content

Commit e30332a

Browse files
bors[bot]mkroening
andauthored
Merge #231
231: Migrate to naked functions r=stlankes a=mkroening Fixes #222. Co-authored-by: Martin Kröning <[email protected]>
2 parents 98f5b77 + 22a4b46 commit e30332a

File tree

11 files changed

+250
-320
lines changed

11 files changed

+250
-320
lines changed

src/arch/mod.rs

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -62,21 +62,12 @@ pub use crate::arch::x86_64::kernel::processor;
6262
#[cfg(target_arch = "x86_64")]
6363
pub use crate::arch::x86_64::kernel::scheduler;
6464
#[cfg(target_arch = "x86_64")]
65+
pub use crate::arch::x86_64::kernel::switch;
66+
#[cfg(target_arch = "x86_64")]
6567
pub use crate::arch::x86_64::kernel::systemtime::get_boot_time;
6668
#[cfg(all(target_arch = "x86_64", target_os = "hermit"))]
6769
pub use crate::arch::x86_64::kernel::{boot_application_processors, boot_processor_init};
6870
#[cfg(target_arch = "x86_64")]
6971
pub use crate::arch::x86_64::kernel::{
7072
get_processor_count, message_output_init, output_message_buf, output_message_byte,
7173
};
72-
73-
#[cfg(test)]
74-
pub unsafe fn switch_to_task(_old_stack: *mut usize, _new_stack: usize) {}
75-
#[cfg(test)]
76-
pub unsafe fn switch_to_fpu_owner(_old_stack: *mut usize, _new_stack: usize) {}
77-
78-
#[cfg(not(test))]
79-
extern "C" {
80-
pub fn switch_to_task(old_stack: *mut usize, new_stack: usize);
81-
pub fn switch_to_fpu_owner(old_stack: *mut usize, new_stack: usize);
82-
}

src/arch/x86_64/kernel/gdt.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,6 @@ pub fn add_current_core() {
135135
}
136136
}
137137

138-
#[inline(never)]
139-
#[no_mangle]
140-
pub fn set_current_kernel_stack() {
138+
pub extern "C" fn set_current_kernel_stack() {
141139
core_scheduler().set_current_kernel_stack();
142140
}

src/arch/x86_64/kernel/mod.rs

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,13 @@ pub mod scheduler;
4242
pub mod serial;
4343
#[cfg(feature = "smp")]
4444
mod smp_boot_code;
45+
#[cfg(not(test))]
46+
mod start;
47+
pub mod switch;
4548
pub mod systemtime;
4649
#[cfg(feature = "vga")]
4750
mod vga;
4851

49-
#[cfg(not(test))]
50-
global_asm!(include_str!("start.s"));
51-
#[cfg(all(not(test), not(feature = "fsgsbase")))]
52-
global_asm!(include_str!("switch.s"));
53-
#[cfg(all(not(test), feature = "fsgsbase"))]
54-
global_asm!(include_str!("switch_fsgsbase.s"));
55-
5652
const SERIAL_PORT_BAUDRATE: u32 = 115_200;
5753

5854
/// Map between Core ID and per-core scheduler
@@ -89,6 +85,44 @@ pub struct BootInfo {
8985
hcmask: [u8; 4],
9086
}
9187

88+
impl BootInfo {
89+
const LAYOUT: Self = Self {
90+
magic_number: 0,
91+
version: 0,
92+
base: 0,
93+
limit: 0,
94+
image_size: 0,
95+
tls_start: 0,
96+
tls_filesz: 0,
97+
tls_memsz: 0,
98+
current_stack_address: 0,
99+
current_percore_address: 0,
100+
host_logical_addr: 0,
101+
boot_gtod: 0,
102+
mb_info: 0,
103+
cmdline: 0,
104+
cmdsize: 0,
105+
cpu_freq: 0,
106+
boot_processor: 0,
107+
cpu_online: 0,
108+
possible_cpus: 0,
109+
current_boot_id: 0,
110+
uartport: 0,
111+
single_kernel: 0,
112+
uhyve: 0,
113+
hcip: [0; 4],
114+
hcgateway: [0; 4],
115+
hcmask: [0; 4],
116+
};
117+
118+
pub const fn current_stack_address_offset() -> isize {
119+
let layout = Self::LAYOUT;
120+
let start = ptr::addr_of!(layout);
121+
let stack = ptr::addr_of!(layout.current_stack_address);
122+
unsafe { stack.cast::<u8>().offset_from(start.cast()) }
123+
}
124+
}
125+
92126
/// Kernel header to announce machine features
93127
#[cfg(not(target_os = "hermit"))]
94128
static mut BOOT_INFO: *mut BootInfo = ptr::null_mut();

src/arch/x86_64/kernel/scheduler.rs

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ pub enum TaskStacks {
8484
}
8585

8686
impl TaskStacks {
87+
/// Size of the debug marker at the very top of each stack.
88+
///
89+
/// We have a marker at the very top of the stack for debugging (`0xdeadbeef`), which should not be overridden.
90+
pub const MARKER_SIZE: usize = 0x10;
91+
8792
pub fn new(size: usize) -> TaskStacks {
8893
let user_stack_size = if size < KERNEL_STACK_SIZE {
8994
KERNEL_STACK_SIZE
@@ -148,9 +153,11 @@ impl TaskStacks {
148153

149154
pub fn from_boot_stacks() -> TaskStacks {
150155
let tss = unsafe { &(*PERCORE.tss.get()) };
151-
let stack = VirtAddr::from_usize(tss.rsp[0] as usize + 0x10 - KERNEL_STACK_SIZE);
156+
let stack =
157+
VirtAddr::from_usize(tss.rsp[0] as usize + Self::MARKER_SIZE - KERNEL_STACK_SIZE);
152158
debug!("Using boot stack {:#X}", stack);
153-
let ist0 = VirtAddr::from_usize(tss.ist[0] as usize + 0x10 - KERNEL_STACK_SIZE);
159+
let ist0 =
160+
VirtAddr::from_usize(tss.ist[0] as usize + Self::MARKER_SIZE - KERNEL_STACK_SIZE);
154161
debug!("IST0 is located at {:#X}", ist0);
155162

156163
TaskStacks::Boot(BootStack { stack, ist0 })
@@ -327,15 +334,28 @@ impl Clone for TaskTLS {
327334
}
328335

329336
#[cfg(not(target_os = "hermit"))]
330-
extern "C" fn task_start(func: extern "C" fn(usize), arg: usize, user_stack: u64) {}
337+
extern "C" fn task_start(_f: extern "C" fn(usize), _arg: usize, _user_stack: u64) -> ! {
338+
unimplemented!()
339+
}
331340

332341
#[cfg(target_os = "hermit")]
333-
extern "C" {
334-
fn task_start(func: extern "C" fn(usize), arg: usize, user_stack: u64);
342+
#[naked]
343+
extern "C" fn task_start(_f: extern "C" fn(usize), _arg: usize, _user_stack: u64) -> ! {
344+
// `f` is in the `rdi` register
345+
// `arg` is in the `rsi` register
346+
// `user_stack` is in the `rdx` register
347+
348+
unsafe {
349+
asm!(
350+
"mov rsp, rdx",
351+
"sti",
352+
"jmp {task_entry}",
353+
task_entry = sym task_entry,
354+
options(noreturn)
355+
)
356+
}
335357
}
336358

337-
#[inline(never)]
338-
#[no_mangle]
339359
extern "C" fn task_entry(func: extern "C" fn(usize), arg: usize) -> ! {
340360
// Call the actual entry point of the task.
341361
func(arg);
@@ -356,8 +376,8 @@ impl TaskFrame for Task {
356376

357377
unsafe {
358378
// Set a marker for debugging at the very top.
359-
let mut stack =
360-
self.stacks.get_kernel_stack() + self.stacks.get_kernel_stack_size() - 0x10u64;
379+
let mut stack = self.stacks.get_kernel_stack() + self.stacks.get_kernel_stack_size()
380+
- TaskStacks::MARKER_SIZE;
361381
*stack.as_mut_ptr::<u64>() = 0xDEAD_BEEFu64;
362382

363383
// Put the State structure expected by the ASM switch() function on the stack.
@@ -378,8 +398,9 @@ impl TaskFrame for Task {
378398

379399
// Set the task's stack pointer entry to the stack we have just crafted.
380400
self.last_stack_pointer = stack;
381-
self.user_stack_pointer =
382-
self.stacks.get_user_stack() + self.stacks.get_user_stack_size() - 0x10u64;
401+
self.user_stack_pointer = self.stacks.get_user_stack()
402+
+ self.stacks.get_user_stack_size()
403+
- TaskStacks::MARKER_SIZE;
383404

384405
// rdx is required to intialize the stack
385406
(*state).rdx = self.user_stack_pointer.as_u64() - mem::size_of::<u64>() as u64;

src/arch/x86_64/kernel/start.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
use crate::{
2+
kernel::{pre_init, scheduler::TaskStacks, BootInfo},
3+
KERNEL_STACK_SIZE,
4+
};
5+
6+
#[no_mangle]
7+
#[naked]
8+
pub extern "C" fn _start(_boot_info: &'static mut BootInfo) -> ! {
9+
// boot_info is in the `rdi` register
10+
11+
// validate signature
12+
const _F: unsafe fn(&'static mut BootInfo) -> ! = pre_init;
13+
14+
unsafe {
15+
asm!(
16+
// initialize stack pointer
17+
"mov rsp, [rdi + {current_stack_address_offset}]",
18+
"add rsp, {stack_top_offset}",
19+
"mov rbp, rsp",
20+
"call {pre_init}",
21+
current_stack_address_offset = const BootInfo::current_stack_address_offset(),
22+
stack_top_offset = const KERNEL_STACK_SIZE - TaskStacks::MARKER_SIZE,
23+
pre_init = sym pre_init,
24+
options(noreturn)
25+
)
26+
}
27+
}

src/arch/x86_64/kernel/start.s

Lines changed: 0 additions & 32 deletions
This file was deleted.

src/arch/x86_64/kernel/switch.rs

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
use crate::set_current_kernel_stack;
2+
3+
#[cfg(feature = "fsgsbase")]
4+
macro_rules! push_fs {
5+
() => {
6+
r#"
7+
rdfsbase rax
8+
push rax
9+
"#
10+
};
11+
}
12+
13+
#[cfg(feature = "fsgsbase")]
14+
macro_rules! pop_fs {
15+
() => {
16+
r#"
17+
pop rax
18+
wrfsbase rax
19+
"#
20+
};
21+
}
22+
23+
#[cfg(not(feature = "fsgsbase"))]
24+
macro_rules! push_fs {
25+
() => {
26+
r#"
27+
mov ecx, 0xc0000100 // FS.Base Model Specific Register
28+
rdmsr
29+
sub rsp, 8
30+
mov [rsp+4], edx
31+
mov [rsp], eax
32+
"#
33+
};
34+
}
35+
36+
#[cfg(not(feature = "fsgsbase"))]
37+
macro_rules! pop_fs {
38+
() => {
39+
r#"
40+
mov ecx, 0xc0000100 // FS.Base Model Specific Register
41+
mov edx, [rsp+4]
42+
mov eax, [rsp]
43+
add rsp, 8
44+
wrmsr
45+
"#
46+
};
47+
}
48+
49+
macro_rules! save_context {
50+
() => {
51+
concat!(
52+
r#"
53+
pushfq
54+
push rax
55+
push rcx
56+
push rdx
57+
push rbx
58+
push rbp
59+
push rsi
60+
push rdi
61+
push r8
62+
push r9
63+
push r10
64+
push r11
65+
push r12
66+
push r13
67+
push r14
68+
push r15
69+
"#,
70+
push_fs!()
71+
)
72+
};
73+
}
74+
75+
macro_rules! restore_context {
76+
() => {
77+
concat!(
78+
pop_fs!(),
79+
r#"
80+
pop r15
81+
pop r14
82+
pop r13
83+
pop r12
84+
pop r11
85+
pop r10
86+
pop r9
87+
pop r8
88+
pop rdi
89+
pop rsi
90+
pop rbp
91+
pop rbx
92+
pop rdx
93+
pop rcx
94+
pop rax
95+
popfq
96+
ret
97+
"#
98+
)
99+
};
100+
}
101+
102+
#[naked]
103+
pub unsafe extern "C" fn switch_to_task(_old_stack: *mut usize, _new_stack: usize) {
104+
// `old_stack` is in `rdi` register
105+
// `new_stack` is in `rsi` register
106+
107+
asm!(
108+
save_context!(),
109+
// Store the old `rsp` behind `old_stack`
110+
"mov [rdi], rsp",
111+
// Set `rsp` to `new_stack`
112+
"mov rsp, rsi",
113+
// Set task switched flag
114+
"mov rax, cr0",
115+
"or rax, 8",
116+
"mov cr0, rax",
117+
// Set stack pointer in TSS
118+
"call {set_current_kernel_stack}",
119+
restore_context!(),
120+
set_current_kernel_stack = sym set_current_kernel_stack,
121+
options(noreturn)
122+
);
123+
}
124+
125+
/// Performa a context switch to an idle task or a task, which alread is owner
126+
/// of the FPU.
127+
#[naked]
128+
pub unsafe extern "C" fn switch_to_fpu_owner(_old_stack: *mut usize, _new_stack: usize) {
129+
// `old_stack` is in `rdi` register
130+
// `new_stack` is in `rsi` register
131+
132+
asm!(
133+
save_context!(),
134+
// Store the old `rsp` behind `old_stack`
135+
"mov [rdi], rsp",
136+
// Set `rsp` to `new_stack`
137+
"mov rsp, rsi",
138+
// Don't set task switched flag, as we switch to fpu owner.
139+
// Set stack pointer in TSS
140+
"call {set_current_kernel_stack}",
141+
restore_context!(),
142+
set_current_kernel_stack = sym set_current_kernel_stack,
143+
options(noreturn),
144+
);
145+
}

0 commit comments

Comments
 (0)