Skip to content

Commit 7a24837

Browse files
committed
Enter unreal mode
1 parent cdfc0c3 commit 7a24837

File tree

2 files changed

+96
-0
lines changed

2 files changed

+96
-0
lines changed

bios/second_stage/src/main.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@ use byteorder::{ByteOrder, LittleEndian};
55
use core::{arch::asm, fmt::Write as _, mem::size_of, slice};
66
use mbr_nostd::{PartitionTableEntry, PartitionType};
77

8+
use crate::protected_mode::enter_unreal_mode;
9+
810
mod dap;
911
mod disk;
1012
mod fat;
13+
mod protected_mode;
1114
mod screen;
1215

1316
/// We use this partition type to store the second bootloader stage;
@@ -26,6 +29,8 @@ fn second_stage_end() -> *const u8 {
2629
pub extern "C" fn _start(disk_number: u16, partition_table_start: *const u8) {
2730
screen::Writer.write_str(" -> SECOND STAGE").unwrap();
2831

32+
enter_unreal_mode();
33+
2934
// parse partition table
3035
let partitions = {
3136
const MAX_ENTRIES: usize = 4;
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
use core::{arch::asm, mem::size_of};
2+
3+
static GDT: GdtProtectedMode = GdtProtectedMode::new();
4+
5+
#[repr(C)]
6+
pub struct GdtProtectedMode {
7+
zero: u64,
8+
code: u64,
9+
data: u64,
10+
}
11+
12+
impl GdtProtectedMode {
13+
const fn new() -> Self {
14+
let limit = {
15+
let limit_low = 0xffff;
16+
let limit_high = 0xf << 48;
17+
limit_high | limit_low
18+
};
19+
let access_common = {
20+
let present = 1 << 47;
21+
let user_segment = 1 << 44;
22+
let read_write = 1 << 41;
23+
present | user_segment | read_write
24+
};
25+
let protected_mode = 1 << 54;
26+
let granularity = 1 << 55;
27+
let base_flags = protected_mode | granularity | access_common | limit;
28+
let executable = 1 << 43;
29+
Self {
30+
zero: 0,
31+
code: base_flags | executable,
32+
data: base_flags,
33+
}
34+
}
35+
36+
fn clear_interrupts_and_load(&'static self) {
37+
let pointer = GdtPointer {
38+
base: &GDT,
39+
limit: (3 * size_of::<u64>() - 1) as u16,
40+
};
41+
42+
unsafe {
43+
asm!("cli", "lgdt [{}]", in(reg) &pointer, options(readonly, nostack, preserves_flags));
44+
}
45+
}
46+
}
47+
48+
#[repr(C, packed(2))]
49+
pub struct GdtPointer {
50+
/// Size of the DT.
51+
pub limit: u16,
52+
/// Pointer to the memory region containing the DT.
53+
pub base: *const GdtProtectedMode,
54+
}
55+
56+
unsafe impl Send for GdtPointer {}
57+
unsafe impl Sync for GdtPointer {}
58+
59+
pub fn enter_unreal_mode() {
60+
let ds: u16;
61+
unsafe {
62+
asm!("mov {0:x}, ds", out(reg) ds, options(nomem, nostack, preserves_flags));
63+
}
64+
65+
GDT.clear_interrupts_and_load();
66+
67+
// set protected mode bit
68+
let mut cr0: u32;
69+
unsafe {
70+
asm!("mov {}, cr0", out(reg) cr0, options(nomem, nostack, preserves_flags));
71+
}
72+
let cr0_protected = cr0 | 1;
73+
write_cr0(cr0_protected);
74+
75+
unsafe {
76+
asm!("mov bx, 0x10", "mov ds, bx");
77+
}
78+
79+
write_cr0(cr0);
80+
81+
unsafe {
82+
asm!("mov ds, {0:x}", in(reg) ds, options(nostack, preserves_flags));
83+
asm!("sti");
84+
85+
asm!("mov bx, 0x0f01", "mov eax, 0xb8000", "mov [eax], bx");
86+
}
87+
}
88+
89+
fn write_cr0(val: u32) {
90+
unsafe { asm!("mov cr0, {}", in(reg) val, options(nostack, preserves_flags)) };
91+
}

0 commit comments

Comments
 (0)