Skip to content

Commit 48cd6dc

Browse files
committed
Load E820 memory map and put everything together
1 parent 557c034 commit 48cd6dc

8 files changed

Lines changed: 132 additions & 47 deletions

File tree

bios/common/src/lib.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,18 @@
33
pub mod racy_cell;
44

55
#[cfg_attr(feature = "debug", derive(Debug))]
6-
#[derive(Clone, Copy)]
6+
#[repr(C)]
77
pub struct BiosInfo {
88
pub stage_4: Region,
99
pub kernel: Region,
10-
pub memory_map: Region,
1110
pub framebuffer: FramebufferInfo,
11+
pub memory_map_addr: u32,
12+
pub memory_map_len: u16,
1213
}
1314

1415
#[cfg_attr(feature = "debug", derive(Debug))]
1516
#[derive(Clone, Copy)]
17+
#[repr(C)]
1618
pub struct FramebufferInfo {
1719
pub region: Region,
1820
pub width: u16,
@@ -24,13 +26,15 @@ pub struct FramebufferInfo {
2426

2527
#[cfg_attr(feature = "debug", derive(Debug))]
2628
#[derive(Clone, Copy)]
29+
#[repr(C)]
2730
pub struct Region {
2831
pub start: u64,
2932
pub len: u64,
3033
}
3134

3235
#[cfg_attr(feature = "debug", derive(Debug))]
3336
#[derive(Clone, Copy)]
37+
#[repr(C)]
3438
pub enum PixelFormat {
3539
Rgb,
3640
Bgr,
@@ -40,3 +44,12 @@ pub enum PixelFormat {
4044
blue_position: u8,
4145
},
4246
}
47+
48+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
49+
#[repr(C)]
50+
pub struct E820MemoryRegion {
51+
pub start_addr: u64,
52+
pub len: u64,
53+
pub region_type: u32,
54+
pub acpi_extended_attributes: u32,
55+
}

bios/stage-2/src/main.rs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use mbr_nostd::{PartitionTableEntry, PartitionType};
1616
mod dap;
1717
mod disk;
1818
mod fat;
19+
mod memory_map;
1920
mod protected_mode;
2021
mod screen;
2122
mod vesa;
@@ -41,7 +42,11 @@ static mut DISK_BUFFER: AlignedArrayBuffer<0x4000> = AlignedArrayBuffer {
4142

4243
#[no_mangle]
4344
#[link_section = ".start"]
44-
pub extern "C" fn _start(disk_number: u16, partition_table_start: *const u8) {
45+
pub extern "C" fn _start(disk_number: u16, partition_table_start: *const u8) -> ! {
46+
start(disk_number, partition_table_start)
47+
}
48+
49+
fn start(disk_number: u16, partition_table_start: *const u8) -> ! {
4550
screen::Writer.write_str(" -> SECOND STAGE\n").unwrap();
4651

4752
enter_unreal_mode();
@@ -100,6 +105,9 @@ pub extern "C" fn _start(disk_number: u16, partition_table_start: *const u8) {
100105
let kernel_len = load_file("kernel-x86_64", KERNEL_DST, &mut fs, &mut disk, disk_buffer);
101106
writeln!(screen::Writer, "kernel loaded at {KERNEL_DST:#p}").unwrap();
102107

108+
let memory_map = memory_map::query_memory_map().unwrap();
109+
writeln!(screen::Writer, "{memory_map:x?}").unwrap();
110+
103111
let mut vesa_info = vesa::VesaInfo::query(disk_buffer).unwrap();
104112
let vesa_mode = vesa_info.get_best_mode(1000, 1000).unwrap().unwrap();
105113
writeln!(
@@ -111,9 +119,7 @@ pub extern "C" fn _start(disk_number: u16, partition_table_start: *const u8) {
111119
.unwrap();
112120
vesa_mode.enable().unwrap();
113121

114-
// TODO: Retrieve memory map
115-
116-
let info = BiosInfo {
122+
let mut info = BiosInfo {
117123
stage_4: Region {
118124
start: stage_4_dst as u64,
119125
len: stage_4_len,
@@ -122,8 +128,8 @@ pub extern "C" fn _start(disk_number: u16, partition_table_start: *const u8) {
122128
start: KERNEL_DST as u64,
123129
len: kernel_len,
124130
},
125-
// TODO
126-
memory_map: Region { start: 0, len: 0 },
131+
memory_map_addr: memory_map.as_mut_ptr() as u32,
132+
memory_map_len: memory_map.len().try_into().unwrap(),
127133
framebuffer: FramebufferInfo {
128134
region: Region {
129135
start: vesa_mode.framebuffer_start.into(),
@@ -137,7 +143,7 @@ pub extern "C" fn _start(disk_number: u16, partition_table_start: *const u8) {
137143
},
138144
};
139145

140-
enter_protected_mode_and_jump_to_stage_3(STAGE_3_DST, &info);
146+
enter_protected_mode_and_jump_to_stage_3(STAGE_3_DST, &mut info);
141147

142148
loop {}
143149
}

bios/stage-2/src/memory_map.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// From http://wiki.osdev.org/Detecting_Memory_(x86)#Getting_an_E820_Memory_Map
2+
3+
use crate::split_array_ref;
4+
use bootloader_x86_64_bios_common::{racy_cell::RacyCell, E820MemoryRegion};
5+
use core::arch::asm;
6+
7+
static MEMORY_MAP: RacyCell<[E820MemoryRegion; 100]> = RacyCell::new(
8+
[E820MemoryRegion {
9+
start_addr: 0,
10+
len: 0,
11+
region_type: 0,
12+
acpi_extended_attributes: 0,
13+
}; 100],
14+
);
15+
16+
/// use the INT 0x15, eax= 0xE820 BIOS function to get a memory map
17+
pub fn query_memory_map() -> Result<&'static mut [E820MemoryRegion], ()> {
18+
const SMAP: u32 = 0x534D4150;
19+
20+
let memory_map = unsafe { MEMORY_MAP.get_mut() };
21+
22+
let mut i = 0;
23+
24+
let mut offset = 0;
25+
let buf = [0u8; 24];
26+
loop {
27+
let mut ret = 0;
28+
let mut buf_written_len = 0;
29+
unsafe {
30+
asm!(
31+
"int 0x15",
32+
inout ("eax") 0xe820 => ret,
33+
in("edx") SMAP,
34+
inout("ebx") offset,
35+
inout("ecx") buf.len() => buf_written_len,
36+
in("di") &buf
37+
)
38+
};
39+
if ret != SMAP {
40+
return Err(());
41+
}
42+
43+
if buf_written_len != 0 {
44+
let buf = &buf[..buf_written_len];
45+
46+
let (&base_raw, rest) = split_array_ref(&buf);
47+
let (&len_raw, rest) = split_array_ref(rest);
48+
let (&kind_raw, rest) = split_array_ref(rest);
49+
let acpi_extended_raw: [u8; 4] = rest.try_into().unwrap_or_default();
50+
51+
let len = u64::from_ne_bytes(len_raw);
52+
if len != 0 {
53+
memory_map[i] = E820MemoryRegion {
54+
start_addr: u64::from_ne_bytes(base_raw),
55+
len,
56+
region_type: u32::from_ne_bytes(kind_raw),
57+
acpi_extended_attributes: u32::from_ne_bytes(acpi_extended_raw),
58+
};
59+
i += 1;
60+
}
61+
}
62+
63+
if offset == 0 {
64+
break;
65+
}
66+
}
67+
68+
Ok(&mut memory_map[..i])
69+
}

bios/stage-2/src/protected_mode.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ pub unsafe fn read_from_protected_mode(ptr: *mut u8) -> u8 {
104104
res
105105
}
106106

107-
pub fn enter_protected_mode_and_jump_to_stage_3(entry_point: *const u8, info: &BiosInfo) {
107+
pub fn enter_protected_mode_and_jump_to_stage_3(entry_point: *const u8, info: &mut BiosInfo) {
108108
unsafe { asm!("cli") };
109109
set_protected_mode_bit();
110110
unsafe {

bios/stage-3/src/main.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ mod screen;
1212

1313
#[no_mangle]
1414
#[link_section = ".start"]
15-
pub extern "C" fn _start(info: &BiosInfo) {
15+
pub extern "C" fn _start(info: &mut BiosInfo) {
1616
screen::init(info.framebuffer);
1717
// Writer.clear_screen();
18-
writeln!(Writer, "Third Stage ({info:#x?})").unwrap();
18+
writeln!(Writer, "Third Stage ({info:x?})").unwrap();
1919

2020
// set up identity mapping, enable paging, and switch CPU into long
2121
// mode (32-bit compatibility mode)
@@ -28,7 +28,7 @@ pub extern "C" fn _start(info: &BiosInfo) {
2828
}
2929

3030
#[no_mangle]
31-
pub fn enter_long_mode_and_jump_to_stage_4(info: &BiosInfo) {
31+
pub fn enter_long_mode_and_jump_to_stage_4(info: &mut BiosInfo) {
3232
let _ = writeln!(Writer, "Paging init done, jumping to stage 4");
3333
unsafe {
3434
asm!(

bios/stage-4/src/main.rs

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
#![no_std]
22
#![no_main]
33

4-
use crate::memory_descriptor::E820MemoryRegion;
4+
use crate::memory_descriptor::MemoryRegion;
55
use crate::screen::Writer;
66
use bootloader_api::info::{FrameBufferInfo, PixelFormat};
7-
use bootloader_x86_64_bios_common::BiosInfo;
7+
use bootloader_x86_64_bios_common::{BiosInfo, E820MemoryRegion};
88
use bootloader_x86_64_common::{
99
legacy_memory_region::LegacyFrameAllocator, load_and_switch_to_kernel, logger::LOGGER, Kernel,
1010
PageTables, SystemInfo,
@@ -28,24 +28,26 @@ mod screen;
2828

2929
#[no_mangle]
3030
#[link_section = ".start"]
31-
pub extern "C" fn _start(info: &BiosInfo) -> ! {
31+
pub extern "C" fn _start(info: &mut BiosInfo) -> ! {
3232
screen::init(info.framebuffer);
3333
writeln!(Writer, "4th Stage").unwrap();
3434
writeln!(Writer, "{info:x?}").unwrap();
3535

36-
let e820_memory_map = {
37-
assert!(info.memory_map.start != 0, "memory map address must be set");
38-
let ptr = usize_from(info.memory_map.start) as *const E820MemoryRegion;
39-
unsafe {
40-
slice::from_raw_parts(
41-
ptr,
42-
usize_from(info.memory_map.len / size_of::<E820MemoryRegion>() as u64),
43-
)
44-
}
36+
let memory_map: &mut [E820MemoryRegion] = unsafe {
37+
core::slice::from_raw_parts_mut(
38+
info.memory_map_addr as *mut _,
39+
info.memory_map_len.try_into().unwrap(),
40+
)
4541
};
46-
let max_phys_addr = e820_memory_map
42+
43+
memory_map.sort_unstable_by_key(|e| e.start_addr);
44+
45+
let max_phys_addr = memory_map
4746
.iter()
48-
.map(|r| r.start_addr + r.len)
47+
.map(|r| {
48+
writeln!(Writer, "start: {:#x}, len: {:#x}", r.start_addr, r.len).unwrap();
49+
r.start_addr + r.len
50+
})
4951
.max()
5052
.expect("no physical memory regions found");
5153

@@ -57,21 +59,24 @@ pub extern "C" fn _start(info: &BiosInfo) -> ! {
5759
let mut frame_allocator = {
5860
let kernel_end = PhysFrame::containing_address(kernel_start + kernel_size - 1u64);
5961
let next_free = kernel_end + 1;
60-
LegacyFrameAllocator::new_starting_at(next_free, e820_memory_map.iter().copied())
62+
LegacyFrameAllocator::new_starting_at(
63+
next_free,
64+
memory_map.iter().copied().map(MemoryRegion),
65+
)
6166
};
6267

63-
// We identity-map all memory, so the offset between physical and virtual addresses is 0
68+
// We identity-mapped all memory, so the offset between physical and virtual addresses is 0
6469
let phys_offset = VirtAddr::new(0);
6570

6671
let mut bootloader_page_table = {
6772
let frame = x86_64::registers::control::Cr3::read().0;
6873
let table: *mut PageTable = (phys_offset + frame.start_address().as_u64()).as_mut_ptr();
6974
unsafe { OffsetPageTable::new(&mut *table, phys_offset) }
7075
};
71-
// identity-map remaining physical memory (first gigabyte is already identity-mapped)
76+
// identity-map remaining physical memory (first 10 gigabytes are already identity-mapped)
7277
{
7378
let start_frame: PhysFrame<Size2MiB> =
74-
PhysFrame::containing_address(PhysAddr::new(4096 * 512 * 512));
79+
PhysFrame::containing_address(PhysAddr::new(4096 * 512 * 512 * 10));
7580
let end_frame = PhysFrame::containing_address(PhysAddr::new(max_phys_addr - 1));
7681
for frame in PhysFrame::range_inclusive(start_frame, end_frame) {
7782
unsafe {
Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
use bootloader_api::info::MemoryRegionKind;
2+
use bootloader_x86_64_bios_common::E820MemoryRegion;
23
use bootloader_x86_64_common::legacy_memory_region::LegacyMemoryRegion;
34
use x86_64::PhysAddr;
45

5-
impl LegacyMemoryRegion for E820MemoryRegion {
6+
impl LegacyMemoryRegion for MemoryRegion {
67
fn start(&self) -> PhysAddr {
7-
PhysAddr::new(self.start_addr)
8+
PhysAddr::new(self.0.start_addr)
89
}
910

1011
fn len(&self) -> u64 {
11-
self.len
12+
self.0.len
1213
}
1314

1415
fn kind(&self) -> MemoryRegionKind {
15-
match self.region_type {
16+
match self.0.region_type {
1617
1 => MemoryRegionKind::Usable,
1718
other => MemoryRegionKind::UnknownBios(other),
1819
}
@@ -29,9 +30,4 @@ impl LegacyMemoryRegion for E820MemoryRegion {
2930
#[doc(hidden)]
3031
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3132
#[repr(C)]
32-
pub struct E820MemoryRegion {
33-
pub start_addr: u64,
34-
pub len: u64,
35-
pub region_type: u32,
36-
pub acpi_extended_attributes: u32,
37-
}
33+
pub struct MemoryRegion(pub E820MemoryRegion);

tests/runner/src/lib.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,9 @@ const QEMU_ARGS: &[&str] = &[
55
"isa-debug-exit,iobase=0xf4,iosize=0x04",
66
"-serial",
77
"stdio",
8-
// "-display",
9-
// "none",
8+
"-display",
9+
"none",
1010
"--no-reboot",
11-
// "-d",
12-
// "int",
13-
"-s",
14-
// "-S",
1511
];
1612

1713
pub fn run_test_kernel(kernel_binary_path: &str) {

0 commit comments

Comments
 (0)