1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
//! Context and ring switching
use core::{arch::asm, fmt};
use crate::arch::regs::Flags;
use super::gdt::SegmentSelector;
/// Prepare for return from interrupt to user,
/// the expected current stack layout is:
///
/// ```text
/// _____________________________
/// | User Data Segment Selector |
/// | User Stack Pointer |
/// | EFLAGS (Interrupts enabled) |
/// | User Code Segment Selector |
/// | Target Instruction Pointer |
/// ```
pub extern "C" fn switch_to_user(
ds: SegmentSelector,
sp: *mut u32,
cs: SegmentSelector,
ip: *mut (),
) -> ! {
unsafe {
let eflags = u32::from(Flags::new().with_interrupt(true));
// Note: use "iretd", "iret" emits the wrong instruction!
todo!("A1: Implement ring switch")
}
}
/// Starts the thread for the first time
#[inline(never)]
pub unsafe extern "C" fn context_launch(thread: &Registers) {
asm!(
"mov esp,[eax+16]",
// load context
"mov ebx,[eax+0]",
"mov esi,[eax+4]",
"mov edi,[eax+8]",
"mov ebp,[eax+12]",
in("eax") thread,
options(nostack)
)
}
/// Switches between two threads
#[inline(never)]
pub unsafe extern "C" fn context_switch(current: &mut Registers, next: &Registers) {
asm!(
// save context
"mov [eax+0],ebx",
"mov [eax+4],esi",
"mov [eax+8],edi",
"mov [eax+12],ebp",
"mov [eax+16],esp",
// switch stack
"mov esp,[ecx+16]",
// load context
"mov ebx,[ecx+0]",
"mov esi,[ecx+4]",
"mov edi,[ecx+8]",
"mov ebp,[ecx+12]",
in("eax") current,
in("ecx") next,
options(nostack)
)
}
/// Non-volatile registers that have to survive function calls.
///
/// See <https://wiki.osdev.org/Calling_Conventions>
#[derive(Copy, Clone)]
#[repr(C)]
pub struct Registers {
pub ebx: u32,
pub esi: u32,
pub edi: u32,
pub ebp: u32,
pub esp: u32,
}
impl Registers {
pub const fn new() -> Registers {
Registers {
ebx: 0,
esi: 0,
edi: 0,
ebp: 0,
esp: 0,
}
}
}
impl fmt::Debug for Registers {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self {
ebx,
esi,
edi,
ebp,
esp,
} = self;
write!(
f,
"Registers {{ ebx: {ebx:x}, esi: {esi:x}, \
edi: {edi:x}, ebp: {ebp:x}, esp: {esp:x} }}"
)
}
}