diff --git a/src/lib.rs b/src/lib.rs index 5a2f6c7eee..6ce69889c9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,12 @@ #![no_std] +#![feature(asm)] #![feature(lang_items)] #![feature(llvm_asm)] -use core::slice; +use core::{ + ptr, + slice, +}; mod panic; @@ -32,8 +36,61 @@ pub enum VgaTextColor { White = 15, } +#[derive(Clone, Copy)] +#[repr(packed)] +pub struct ThunkData { + di: u16, + si: u16, + bp: u16, + sp: u16, + bx: u16, + dx: u16, + cx: u16, + ax: u16, +} + +impl ThunkData { + pub const STACK: usize = 0x7C00; + + pub fn new() -> Self { + Self { + di: 0, + si: 0, + bp: 0, + sp: Self::STACK as u16, + bx: 0, + dx: 0, + cx: 0, + ax: 0, + } + } + + pub unsafe fn save(&self) { + ptr::write((Self::STACK - 16) as *mut ThunkData, *self); + } + + pub unsafe fn load(&mut self) { + *self = ptr::read((Self::STACK - 16) as *const ThunkData); + } + + pub unsafe fn with(&mut self, f: extern "C" fn()) { + self.save(); + f(); + self.load(); + } +} + #[no_mangle] -pub unsafe extern "C" fn kstart() -> ! { +pub unsafe extern "C" fn kstart( + thunk10: extern "C" fn(), + thunk13: extern "C" fn(), +) -> ! { + { + let mut data = ThunkData::new(); + data.ax = 0x03; + data.with(thunk10); + } + let vga = slice::from_raw_parts_mut( 0xb8000 as *mut VgaTextBlock, 80 * 25 diff --git a/x86/startup-x86.asm b/x86/startup-x86.asm index ac8f0c77b9..882b51a537 100644 --- a/x86/startup-x86.asm +++ b/x86/startup-x86.asm @@ -10,12 +10,12 @@ startup_arch: mov cr0, eax ; far jump to load CS with 32 bit segment - jmp gdt.kernel_code:protected_mode + jmp gdt.pm32_code:protected_mode USE32 protected_mode: ; load all the other segments with 32 bit data segments - mov eax, gdt.kernel_data + mov eax, gdt.pm32_data mov ds, eax mov es, eax mov fs, eax @@ -25,6 +25,10 @@ protected_mode: mov esp, 0x800000 - 128 ; entry point + mov eax, thunk.int13 + push eax + mov eax, thunk.int10 + push eax mov eax, [args.kernel_base] call [eax + 0x18] .halt: @@ -32,6 +36,8 @@ protected_mode: hlt jmp .halt +%include "thunk.asm" + gdtr: dw gdt.end + 1 ; size dd gdt ; offset @@ -40,23 +46,43 @@ gdt: .null equ $ - gdt dq 0 -.kernel_code equ $ - gdt +.pm32_code equ $ - gdt istruc GDTEntry at GDTEntry.limitl, dw 0xFFFF at GDTEntry.basel, dw 0 at GDTEntry.basem, db 0 at GDTEntry.attribute, db attrib.present | attrib.user | attrib.code | attrib.readable - at GDTEntry.flags__limith, db 0xFF | flags.granularity | flags.default_operand_size + at GDTEntry.flags__limith, db 0xF | flags.granularity | flags.default_operand_size at GDTEntry.baseh, db 0 iend -.kernel_data equ $ - gdt +.pm32_data equ $ - gdt istruc GDTEntry at GDTEntry.limitl, dw 0xFFFF at GDTEntry.basel, dw 0 at GDTEntry.basem, db 0 at GDTEntry.attribute, db attrib.present | attrib.user | attrib.writable - at GDTEntry.flags__limith, db 0xFF | flags.granularity | flags.default_operand_size + at GDTEntry.flags__limith, db 0xF | flags.granularity | flags.default_operand_size + at GDTEntry.baseh, db 0 + iend + +.pm16_code equ $ - gdt + istruc GDTEntry + at GDTEntry.limitl, dw 0xFFFF + at GDTEntry.basel, dw 0 + at GDTEntry.basem, db 0 + at GDTEntry.attribute, db attrib.present | attrib.user | attrib.code | attrib.readable + at GDTEntry.flags__limith, db 0xF + at GDTEntry.baseh, db 0 + iend + +.pm16_data equ $ - gdt + istruc GDTEntry + at GDTEntry.limitl, dw 0xFFFF + at GDTEntry.basel, dw 0 + at GDTEntry.basem, db 0 + at GDTEntry.attribute, db attrib.present | attrib.user | attrib.writable + at GDTEntry.flags__limith, db 0xF at GDTEntry.baseh, db 0 iend diff --git a/x86/thunk.asm b/x86/thunk.asm new file mode 100644 index 0000000000..a54e34c17f --- /dev/null +++ b/x86/thunk.asm @@ -0,0 +1,108 @@ +USE32 +thunk: +.int10: + mov dword [.func], .int10_real + jmp .enter + +.int13: + mov dword [.func], .int13_real + jmp .enter + +.func: dd 0 +.esp: dd 0 +.cr0: dd 0 + +.enter: + ; save flags + pushfd + + ; save registers + pushad + + ; save esp + mov [.esp], esp + + ; far jump to protected mode 16-bit + jmp gdt.pm16_code:.pm16 + +.exit: + ; set segment selectors to 32-bit protected mode + mov eax, gdt.pm32_data + mov ds, eax + mov es, eax + mov fs, eax + mov gs, eax + mov ss, eax + + ; restore esp + mov esp, [.esp] + + ; restore registers + popad + + ; restore flags + popfd + + ; return + ret + +USE16 +.int10_real: + sti + int 0x10 + cli + ; ret + +.int13_real: + sti + int 0x13 + cli + ret + +.pm16: + ; set segment selectors to protected mode 16-bit + mov eax, gdt.pm16_data + mov ds, eax + mov es, eax + mov fs, eax + mov gs, eax + mov ss, eax + + ; save cr0 + mov eax, cr0 + mov [.cr0], eax + + ; disable paging and protected mode + and eax, 0x7FFFFFFE + mov cr0, eax + + ; far jump to real mode + jmp 0:.real + +.real: + ; set segment selectors to real mode + mov eax, 0 + mov ds, eax + mov es, eax + mov fs, eax + mov gs, eax + mov ss, eax + + ; set stack + mov esp, 0x7C00 - 16 + + ; load registers + popa + + ; call real mode function + call [.func] + + ; save registers + pusha + + ; restore cr0, will enable protected mode + mov eax, [.cr0] + mov cr0, eax + + ; far jump to protected mode 32-bit + jmp gdt.pm32_code:.exit diff --git a/x86/unreal.asm b/x86/unreal.asm index 691a8920f0..a1059ea9a3 100644 --- a/x86/unreal.asm +++ b/x86/unreal.asm @@ -48,7 +48,7 @@ unreal_gdt: at GDTEntry.basel, dw 0x0 at GDTEntry.basem, db 0x0 at GDTEntry.attribute, db attrib.present | attrib.user | attrib.writable - at GDTEntry.flags__limith, db 0xFF | flags.granularity | flags.default_operand_size + at GDTEntry.flags__limith, db 0xF | flags.granularity | flags.default_operand_size at GDTEntry.baseh, db 0x0 iend .end equ $ - unreal_gdt