aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTianhao Wang <shrik3@mailbox.org>2024-05-29 01:18:02 +0200
committerTianhao Wang <shrik3@mailbox.org>2024-06-11 15:17:10 +0200
commit959a93e653684b1ed8db4bd21eaca9831e372fb0 (patch)
tree152426d2f9eb39ff26941204aaa149840e59578a
parent590d29c3e44fc06bc79c2624fc94273434505b9d (diff)
multiboot: basic support for multiboot info
well, it's not trivial to use bios function because thanks to grub + multiboot, we are already in protected mode when the startup code takes control. Also the MB info is easier to play with than BIOS (or ACPI) Signed-off-by: Tianhao Wang <shrik3@mailbox.org>
-rw-r--r--boot/startup-x86_64.s14
-rw-r--r--defs/x86_64-linker.ld8
-rw-r--r--docs/multiboot.txt45
-rw-r--r--src/arch/x86_64/asm/e820.s2
-rw-r--r--src/lib.rs10
-rw-r--r--src/machine/mod.rs1
-rw-r--r--src/machine/multiboot.rs77
7 files changed, 150 insertions, 7 deletions
diff --git a/boot/startup-x86_64.s b/boot/startup-x86_64.s
index 448576a..6392d0f 100644
--- a/boot/startup-x86_64.s
+++ b/boot/startup-x86_64.s
@@ -11,7 +11,8 @@ MAX_MEM: equ 512
[GLOBAL startup]
[GLOBAL pml4]
[GLOBAL pdp]
-
+[GLOBAL mb_magic]
+[GLOBAL mb_info_addr]
; functions from other parts of rustubs
[EXTERN vectors_start]
[EXTERN idt]
@@ -28,6 +29,12 @@ MAX_MEM: equ 512
startup:
cld
cli
+ ; with multiboot specs, grub initialzes the registers:
+ ; EAX: magic value 0x2BADB002
+ ; EBX: 32-bit physical address of the multiboot information struct
+ ; we store them in global variables for future uses in rust code.
+ mov dword [mb_magic], eax
+ mov dword [mb_info_addr], ebx
; setup GDT by loading GDT descriptor
; see docs/x86_gdt.txt
lgdt [gdt_80]
@@ -156,6 +163,11 @@ gdt_80:
dw 4*8 - 1 ; GDT limit=24, 4 GDT entries - 1
dq gdt ; GDT address
+; multiboot info
+mb_magic:
+ dd 0x00000000
+mb_info_addr:
+ dd 0x00000000
[SECTION .bss]
diff --git a/defs/x86_64-linker.ld b/defs/x86_64-linker.ld
index caecb48..39d8876 100644
--- a/defs/x86_64-linker.ld
+++ b/defs/x86_64-linker.ld
@@ -1,5 +1,10 @@
/* defs for Multiboot headers */
+/* https://www.gnu.org/software/grub/manual/multiboot/multiboot.txt */
MB_MAGIC = 0x1badb002;
+/* bit 0
+ * all boot modules loaded along with the operating system must be
+ * aligned on page (4KB) bit 1 must include mem_* structures
+ */
MB_FLAGS = 0x3;
MB_CHKSUM = 0x100000000 - (MB_MAGIC + MB_FLAGS);
@@ -9,7 +14,8 @@ SECTIONS
.boot :
{
- header_start = .; LONG(MB_MAGIC)
+ header_start = .;
+ LONG(MB_MAGIC)
LONG(MB_FLAGS)
LONG(MB_CHKSUM)
LONG(0)
diff --git a/docs/multiboot.txt b/docs/multiboot.txt
new file mode 100644
index 0000000..4762e45
--- /dev/null
+++ b/docs/multiboot.txt
@@ -0,0 +1,45 @@
+https://www.gnu.org/software/grub/manual/multiboot/multiboot.txt
+
+ +-------------------+
+0 | flags | (required)
+ +-------------------+
+4 | mem_lower | (present if flags[0] is set)
+8 | mem_upper | (present if flags[0] is set)
+ +-------------------+
+12 | boot_device | (present if flags[1] is set)
+ +-------------------+
+16 | cmdline | (present if flags[2] is set)
+ +-------------------+
+20 | mods_count | (present if flags[3] is set)
+24 | mods_addr | (present if flags[3] is set)
+ +-------------------+
+28 - 40 | syms | (present if flags[4] or
+ | | flags[5] is set)
+ +-------------------+
+44 | mmap_length | (present if flags[6] is set)
+48 | mmap_addr | (present if flags[6] is set)
+ +-------------------+
+52 | drives_length | (present if flags[7] is set)
+56 | drives_addr | (present if flags[7] is set)
+ +-------------------+
+60 | config_table | (present if flags[8] is set)
+ +-------------------+
+64 | boot_loader_name | (present if flags[9] is set)
+ +-------------------+
+68 | apm_table | (present if flags[10] is set)
+ +-------------------+
+72 | vbe_control_info | (present if flags[11] is set)
+76 | vbe_mode_info |
+80 | vbe_mode |
+82 | vbe_interface_seg |
+84 | vbe_interface_off |
+86 | vbe_interface_len |
+ +-------------------+
+88 | framebuffer_addr | (present if flags[12] is set)
+96 | framebuffer_pitch |
+100 | framebuffer_width |
+104 | framebuffer_height|
+108 | framebuffer_bpp |
+109 | framebuffer_type |
+110-115 | color_info |
+ +-------------------+
diff --git a/src/arch/x86_64/asm/e820.s b/src/arch/x86_64/asm/e820.s
deleted file mode 100644
index 59c672a..0000000
--- a/src/arch/x86_64/asm/e820.s
+++ /dev/null
@@ -1,2 +0,0 @@
-; getting an E820 memory map, code from osdev wiki.
-; this only works in real mode ... how to do it in long mode?
diff --git a/src/lib.rs b/src/lib.rs
index 759c7c0..3651a81 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -8,13 +8,13 @@ mod ds;
mod io;
mod machine;
mod mm;
+use crate::machine::key::Modifiers;
use arch::x86_64::interrupt;
use arch::x86_64::interrupt::pic_8259;
use arch::x86_64::interrupt::pic_8259::PicDeviceInt;
use core::panic::PanicInfo;
use machine::cgascr::CGAScreen;
-
-use crate::machine::key::Modifiers;
+use machine::multiboot;
#[cfg(not(test))]
#[panic_handler]
@@ -28,14 +28,18 @@ pub extern "C" fn _entry() -> ! {
// init code
io::set_attr(0x1f);
io::clear_screen();
+ assert!(multiboot::check_magic(), "bad multiboot magic!");
+ let mbi = multiboot::get_mb_info().expect("bad multiboot info flags");
+ println!("MB INFO: {:#X?}", mbi);
interrupt::init();
pic_8259::allow(PicDeviceInt::KEYBOARD);
interrupt::interrupt_enable();
- io::print_welcome();
let mut framemap = mm::pma::FMap::new();
framemap.init();
println!("Bitmap starting from : {:p}", framemap.bm.as_ptr());
println!("Skip first {} bytes", framemap.skip_byte);
+ println!("system init .. done!");
+ // io::print_welcome();
// busy loop query keyboard
loop {
diff --git a/src/machine/mod.rs b/src/machine/mod.rs
index 46ca961..a2cf730 100644
--- a/src/machine/mod.rs
+++ b/src/machine/mod.rs
@@ -4,5 +4,6 @@ pub mod interrupt;
pub mod key;
pub mod keyctrl;
pub mod mem;
+pub mod multiboot;
// TODO: this module *should* be arch independent.
diff --git a/src/machine/multiboot.rs b/src/machine/multiboot.rs
new file mode 100644
index 0000000..3056db3
--- /dev/null
+++ b/src/machine/multiboot.rs
@@ -0,0 +1,77 @@
+use crate::io::*;
+// provide functions to parse information provided by grub multiboot
+// see docs/multiboot.txt
+extern "C" {
+ static mb_magic: u32;
+ static mb_info_addr: u32;
+}
+
+#[repr(C)]
+#[repr(packed)]
+#[derive(Debug)]
+pub struct MultibootMmap {
+ pub size: u32,
+ pub addr: u64,
+ pub len: u64,
+ pub mtype: u32,
+}
+
+#[repr(C)]
+#[repr(packed)]
+#[derive(Debug, Clone, Copy)]
+pub struct MultibootInfo {
+ pub flags: MultibootInfoFlags,
+ pub mem_lower: u32,
+ pub mem_upper: u32,
+}
+
+use bitflags::bitflags;
+bitflags! {
+ /// the MultibootInfoFlags indicate which fields are valid in the MultibootInfo
+ /// atm we only need the MEM and MMAP flags for memory management info.
+ #[derive(Copy, Clone, Debug)]
+ pub struct MultibootInfoFlags: u32 {
+ const MEM = 1 << 0;
+ const BOOT_DEVICE = 1 << 1;
+ const CMDLINE = 1 << 2;
+ const MODS = 1 << 3;
+ const SYM_TBL = 1 << 4;
+ const SHDR = 1 << 5;
+ const MMAP = 1 << 6;
+ const DRIVES = 1 << 7;
+ const CONF_TBL = 1 << 8;
+ const BL_NAME = 1 << 9;
+ const APM_TBL = 1 << 10;
+ const VBE_TBL = 1 << 11;
+ const FRAMEBUFFER = 1 << 12;
+ }
+}
+
+impl MultibootInfoFlags {
+ /// only 13 bits of the MB info flags are defined. The other flag bits must
+ /// be zero for the info block to be valie.
+ const VALID_MASK: u32 = 0x1FFF;
+
+ pub fn check_valid(&self) -> bool {
+ return self.bits() <= Self::VALID_MASK;
+ }
+}
+
+pub fn check_magic() -> bool {
+ return unsafe { mb_magic == 0x2BADB002 };
+}
+
+pub fn get_mb_info() -> Option<MultibootInfo> {
+ if !check_magic() {
+ return None;
+ }
+ let mbi = unsafe { *(mb_info_addr as *mut MultibootInfo) };
+ let flags = mbi.flags;
+ if !flags.check_valid() {
+ return None;
+ }
+ return Some(mbi);
+}
+
+// TODO: expand MultibootInfo struct defs if needed.
+