diff --git a/Makefile b/Makefile index 0ca1e7bf777d275ad240668770d019fa746d0dbc..aaef11cce026a1233240c3befe9a61c621a33e81 100644 --- a/Makefile +++ b/Makefile @@ -56,6 +56,7 @@ KERNEL_DEPS := ${BOOT_OBJ} ${KERNEL_LIB} LD_M_x86_64 := elf_x86_64 LD_M_x86 := elf_i386 LD_FLAGS ?= +#LD_FLAGS += --whole-archive LD_FLAGS += ${KERNEL_DEPS} LD_FLAGS += -o ${KERNEL_ELF} LD_FLAGS += --gc-sections @@ -82,6 +83,13 @@ QEMU_FLAGS += -kernel ${KERNEL_ELF} qemu : ${KERNEL_ELF} ${QEMU_${ARCH}} ${QEMU_FLAGS} -.PHONY : build qemu +# objdump +objdump : ${KERNEL_ELF} + objdump -D ${KERNEL_ELF} + +readelf : ${KERNEL_ELF} + readelf --all ${KERNEL_ELF} + +.PHONY : build qemu objdump readelf # end diff --git a/src/arch/x86_64/link.ld b/src/arch/x86_64/link.ld index ae313ee218f5225a7688de46aa7efbee9c872eb4..874eb9bed9f802b5e4d5e33e116831be639ed98d 100644 --- a/src/arch/x86_64/link.ld +++ b/src/arch/x86_64/link.ld @@ -3,8 +3,12 @@ ENTRY(start) SECTIONS { . = 1M; + .multiboot : ALIGN(4k) { + KEEP(*(.multiboot)) + KEEP(*(.multiboot_rust)) + } + .boot : ALIGN(4k) { - KEEP(*(.multiboot1)) *(.boot) } diff --git a/src/arch/x86_64/mod.rs b/src/arch/x86_64/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..f3dcc9932f43b006432368a4ca24923103ec4405 --- /dev/null +++ b/src/arch/x86_64/mod.rs @@ -0,0 +1,12 @@ +// both cannot coexist (AFAIK.) and QEMU +// cannot boot multiboot2 kernels directly +// +// so multiboot1 it is .. temporarily + +// multiboot1 header and glue code +#[cfg(all())] +mod multiboot1; + +// multiboot2 header and glue code +#[cfg(any())] +mod multiboot2; diff --git a/src/arch/x86_64/multiboot1.rs b/src/arch/x86_64/multiboot1.rs new file mode 100644 index 0000000000000000000000000000000000000000..3a61044346ae6ccf6ea4a6270223d9bfbeb605c3 --- /dev/null +++ b/src/arch/x86_64/multiboot1.rs @@ -0,0 +1,82 @@ +use core::ffi::CStr; + +#[allow(unused)] +#[repr(C)] +struct Multiboot1Header { + magic: u32, + flags: u32, + checksum: u32, + + _unused: [u32; 5], // header_addr, load_addr, load_end_addr, bss_end_addr, entry_addr + + mode_type: u32, + width: u32, + height: u32, + depth: u32, +} + +const MAGIC: u32 = 0x1BADB002; +const ALIGN: u32 = 1 << 0; +const MEMINFO: u32 = 1 << 1; +const VIDEO: u32 = 1 << 2; +const FLAGS: u32 = ALIGN | MEMINFO | VIDEO; + +#[used] +#[no_mangle] +#[link_section = ".multiboot"] +static MULTIBOOT1_HEADER: Multiboot1Header = Multiboot1Header { + magic: MAGIC, + flags: FLAGS, + checksum: (0x100000000 - (MAGIC + FLAGS) as u64) as u32, + + _unused: [0; 5], + + mode_type: 0, // 0 = linear graphics + width: 0, // 0 = no preference + height: 0, // 0 = no preference + depth: 0, // 0 = no preference +}; + +#[derive(Debug, Clone, Copy)] +#[repr(C)] +struct Multiboot1Information { + flags: u32, + optional: [u8; 112], +} + +impl Multiboot1Information { + fn bootloader_name(&self) -> Option<&str> { + if (self.flags & 1 << 9) != 0 { + let ptr = u32::from_le_bytes((self.optional[60..=64]).try_into().ok()?) as _; + let s = unsafe { CStr::from_ptr(ptr) }; + let s = s.to_str().ok()?; + + Some(s) + } else { + None + } + } + + fn framebuffer(&self) -> Option<&[u8]> { + if (self.flags & 1 << 12) != 0 { + Some(&self.optional[84..]) + } else { + None + } + } +} + +#[no_mangle] +extern "C" fn kernel_main(magic_num: u64) { + let mb1_info_pointer = magic_num & u32::MAX as u64; + let mb1_info = unsafe { *(mb1_info_pointer as *const Multiboot1Information) }; + + crate::println!( + "\0{:?}\n{:#b}\n{:?}", + mb1_info.bootloader_name(), + mb1_info.flags, + mb1_info.framebuffer(), + ); + + crate::kernel_main(); +} diff --git a/src/arch/x86_64/multiboot2.rs b/src/arch/x86_64/multiboot2.rs new file mode 100644 index 0000000000000000000000000000000000000000..892aac2015781eb8740eab28c1353312f3cfa986 --- /dev/null +++ b/src/arch/x86_64/multiboot2.rs @@ -0,0 +1,32 @@ +#[allow(unused)] +#[repr(C)] +pub struct Multiboot2Header { + magic: u32, + architecture: u32, + header_length: u32, + checksum: u32, + end_tag_0: u32, + end_tag_1: u32, +} + +const MAGIC: u32 = 0xE85250D6; +const ARCH: u32 = 0; // 32 bit (protected mode) +const LEN: u32 = core::mem::size_of::<Multiboot2Header>() as u32; +const CHECKSUM: u32 = (0x100000000 - (MAGIC + ARCH + LEN) as u64) as u32; + +#[used] +#[no_mangle] +#[link_section = ".multiboot"] +pub static MULTIBOOT2_HEADER: Multiboot2Header = Multiboot2Header { + magic: MAGIC, + architecture: ARCH, + header_length: LEN, + checksum: CHECKSUM, + end_tag_0: 0, + end_tag_1: 8, +}; + +#[no_mangle] +pub extern "C" fn kernel_main(_magic_num: u64) { + crate::kernel_main(); +} diff --git a/src/arch/x86_64/start.asm b/src/arch/x86_64/start.asm index 6bfa8215fa2cb6f414678d6be8b3e4d2e88ddce1..4bcb16a1cf4400c5567236c7066abe21b6555037 100644 --- a/src/arch/x86_64/start.asm +++ b/src/arch/x86_64/start.asm @@ -2,38 +2,13 @@ extern kernel_main ;; ---------- - ;; Multiboot2 - ;; ---------- - - section .multiboot2 - -header_start: - dd 0xE85250D6 ;; multiboot2 magic - dd 0 ;; arch: 32 bit (protected mode) - dd header_end - header_start ;; header length - dd 0x100000000 - (0xE85250D6 + header_end - header_start) ;; checksum - - dd 0 ;; end tag - dd 8 -header_end: - - ;; ---------- - ;; Multiboot1 + ;; Boot entry ;; ---------- - section .multiboot1 - dd 0x1BADB002 ;; multiboot1 magic - dd 3 ;; flags - dd 0x100000000 - (0x1BADB002 + 3) ;; checksum - section .boot global start bits 32 - ;; ---------- - ;; Boot entry - ;; ---------- - start: cli cld @@ -43,6 +18,8 @@ start: ;; support checks call check_multiboot1 + push ebx + push ebx call check_cpuid call check_long_mode @@ -201,7 +178,8 @@ long_mode_start: ; print 'OK' mov dword [0xb8000], 0x2F4B2F4F - mov rdi, 42 + ;; take the multiboot info struct pointer + pop rdi call kernel_main .halt: hlt diff --git a/src/lib.rs b/src/lib.rs index ed0fe1bb3178cc4a8f8e215234b3cd6816c67dc7..82848fbdcbeb0a92a347c671f894b03a3db9f0e1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,9 @@ #![no_std] #![no_main] +#[path = "arch/x86_64/mod.rs"] +pub mod arch; + pub mod vga; #[panic_handler] @@ -8,12 +11,11 @@ fn panic_handler(_: &core::panic::PanicInfo) -> ! { loop {} } -#[no_mangle] -#[link_section = ".boot"] -pub extern "C" fn kernel_main(magic_num: u64) -> ! { +fn kernel_main() -> ! { // null byte clears the VGA buffer - print!("\0"); - println!("Hello from Hyperion, magic_num = {magic_num}"); + // print!("\0"); + + // println!("Hello from Hyperion, pointer = {pointer:#x}, fb = {fb:#x}"); loop { unsafe {