diff --git a/Cargo.lock b/Cargo.lock index ba66d4f9..ad331dfe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -69,9 +69,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" [[package]] name = "bitvec" @@ -297,6 +297,12 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" +[[package]] +name = "limine" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90b240f611eba0b43bf3e97478d87f12322c6c0f540bdad885c3e8c4a0d57333" + [[package]] name = "linked_list_allocator" version = "0.10.6" @@ -370,9 +376,11 @@ dependencies = [ "geodate", "lazy_static", "libm", + "limine", "linked_list_allocator", "littlewing", "miniz_oxide", + "multiboot2", "nom", "num-bigint", "num-traits", @@ -392,6 +400,30 @@ dependencies = [ "x86_64", ] +[[package]] +name = "multiboot2" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89797c447846ff7c39eebf22b1c6ce1c6d8721d0dced9771fc142d10cc2a4e97" +dependencies = [ + "bitflags 2.11.1", + "log", + "multiboot2-common", + "ptr_meta", + "thiserror", + "uefi-raw", +] + +[[package]] +name = "multiboot2-common" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6892f2795001adb0f6e4c124de90b68f9edc4bf52b8d81b14dac45cb361f1cca" +dependencies = [ + "ptr_meta", + "thiserror", +] + [[package]] name = "no-std-compat" version = "0.4.1" @@ -507,6 +539,26 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "ptr_meta" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9a0cf95a1196af61d4f1cbdab967179516d9a4a4312af1f31948f8f6224a79" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7347867d0a7e1208d93b46767be83e2b8f978c3dad35f775ac8d8847551d6fe1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "quote" version = "1.0.37" @@ -570,7 +622,7 @@ version = "11.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.11.1", ] [[package]] @@ -700,18 +752,18 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "thiserror" -version = "2.0.4" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f49a1853cf82743e3b7950f77e0f4d622ca36cf4317cba00c767838bac8d490" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.4" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8381894bb3efe0c4acac3ded651301ceee58a15d47c2e34885ed1908ad667061" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", @@ -765,11 +817,27 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94d293f51425981fdb1b766beae254dbb711a17e8c4b549dc69b9b7ee0d478d5" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.11.1", "rustversion", "x86", ] +[[package]] +name = "uefi-raw" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8aff2f4f2b556a36a201d335a1e0a57754967a96857b1f47a52d5a23825cac84" +dependencies = [ + "bitflags 2.11.1", + "uguid", +] + +[[package]] +name = "uguid" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c8352f8c05e47892e7eaf13b34abd76a7f4aeaf817b716e88789381927f199c" + [[package]] name = "unicode-ident" version = "1.0.12" @@ -848,7 +916,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f042214de98141e9c8706e8192b73f56494087cc55ebec28ce10f26c5c364ae" dependencies = [ "bit_field", - "bitflags 2.4.1", + "bitflags 2.11.1", "rustversion", "volatile", ] diff --git a/Cargo.toml b/Cargo.toml index a5df4fa6..f2dfc262 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,8 @@ default = ["video"] video = [] serial = [] userspace = [] +limine = [] +multiboot = [] [dependencies] acpi = "5.0.0" @@ -25,9 +27,11 @@ chumsky = { version = "0.12.0", default-features = false } geodate = { version = "0.5.0", default-features = false } lazy_static = { version = "1.5.0", features = ["spin_no_std"] } libm = "0.2.16" +limine = "0.6.3" linked_list_allocator = "0.10.6" littlewing = { version = "0.8.0", default-features = false } miniz_oxide = "0.9.1" +multiboot2 = "0.24.1" nom = { version = "8.0.0", default-features = false, features = ["alloc"] } num-bigint = { version = "0.4.6", default-features = false } num-traits = { version = "0.2.19", default-features = false } diff --git a/Makefile b/Makefile index f4815497..f67817c5 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ user-nasm: sh -c "printf '\x7FBIN' | cat - dsk/bin/{}.tmp > dsk/bin/{}" rm dsk/bin/*.tmp -user-cargo-opts = --no-default-features --features userspace --release +user-cargo-opts = --release --no-default-features --features userspace # FIXME: Userspace alloc panic when the default `lld` linker is used because it # sets the entry point 0x200000 which is used by the kernel, so we use `ld` to @@ -59,10 +59,11 @@ img = disk.img $(img): qemu-img create $(img) 32M -cargo-opts = --no-default-features --features $(output) --bin moros +cargo-opts = --bin moros ifeq ($(mode),release) cargo-opts += --release endif +cargo-opts += --no-default-features --features $(output) # Rebuild MOROS if the features list changed image: $(img) @@ -72,7 +73,7 @@ image: $(img) dd conv=notrunc if=$(bin) of=$(img) qemu-opts = -name "MOROS $$MOROS_VERSION" \ - -m $(memory) -smp $(smp) -drive file=$(img),format=raw \ + -m $(memory) -smp $(smp) \ -audiodev $(audio),id=a0 -machine pcspk-audiodev=a0 \ -audio driver=$(audio),model=$(snd) \ -netdev user,id=e0,hostfwd=tcp::8080-:80 -device $(nic),netdev=e0 @@ -108,13 +109,41 @@ endif # > gdb target/x86_64-moros/debug/moros -ex "target remote :1234" qemu: - qemu-system-x86_64 $(qemu-opts) + qemu-system-x86_64 $(qemu-opts) -hda $(img) test: cargo test --release --lib --no-default-features --features serial -- \ -m $(memory) -cpu core2duo -display none -serial stdio \ -device isa-debug-exit,iobase=0xF4,iosize=0x04 +# Require llvm lld mtools +limine-setup: + cd tmp + wget https://github.com/Limine-Bootloader/Limine/releases/download/v11.3.1/limine-11.3.1.tar.gz + cd limine-11.3.1 + ./configure --enable-bios --enable-bios-cd + make + cd .. + cp limine-11.3.1/bin/limine-bios-cd.bin boot/limine/ + cp limine-11.3.1/bin/limine-bios.sys boot/limine/ + +limine-proto = limine# limine, multiboot + +limine-image: RUSTFLAGS = -C link-arg=-Ttmp/boot/$(limine-proto).ld -C link-arg=-z -C link-arg=norelro +limine-image: + cargo build $(cargo-opts),$(limine-proto) + cp target/x86_64-moros/release/moros tmp/boot/kernel.elf + find tmp/boot + cat tmp/boot/limine/limine.conf + xorriso -as mkisofs \ + -b limine/limine-bios-cd.bin \ + -no-emul-boot -boot-load-size 4 -boot-info-table \ + --protective-msdos-label \ + tmp/boot -o boot.img + +limine-qemu: + qemu-system-x86_64 -cdrom boot.img $(qemu-opts) + website: cd www && sh build.sh diff --git a/src/lib.rs b/src/lib.rs index 4617c4e3..33ae1963 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,6 +31,10 @@ pub fn init(memory_map: &MemoryMap, offset: u64) { sys::pic::init(); // Enable interrupts sys::serial::init(); sys::keyboard::init(); + + #[cfg(feature = "limine")] + return; // FIXME + sys::clk::init(); let v = option_env!("MOROS_VERSION").unwrap_or(env!("CARGO_PKG_VERSION")); diff --git a/src/main.rs b/src/main.rs index b793b1d0..30885b08 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,6 @@ extern crate alloc; -use bootloader::{entry_point, BootInfo}; use core::panic::PanicInfo; use alloc::string::ToString; use moros::api::console::Style; @@ -11,12 +10,165 @@ use moros::{ error, warning, hlt_loop, eprint, eprintln, print, println, sys, usr }; -entry_point!(main); +#[cfg(not(any(feature = "limine", feature = "multiboot")))] +mod bootloader_main { + use super::*; + use bootloader::{entry_point, BootInfo}; -fn main(boot_info: &'static BootInfo) -> ! { - let memory_map = moros::extract_memory_map(boot_info); - let offset = boot_info.physical_memory_offset; - moros::init(&memory_map, offset); + entry_point!(main); + + fn main(boot_info: &'static BootInfo) -> ! { + let memory_map = moros::extract_memory_map(boot_info); + let offset = boot_info.physical_memory_offset; + moros::init(&memory_map, offset); + exec(); + } +} + +#[cfg(feature = "limine")] +mod limine_main { + use super::*; + + use moros::sys::mem::MemoryMap; + use moros::sys::mem::MemoryRegion; + use moros::sys::mem::MemoryRegionType; + use limine::request::{MemmapRequest, HhdmRequest, FramebufferRequest}; + use limine::{BaseRevision, RequestsStartMarker, RequestsEndMarker}; + use limine::memmap; + + #[used] + #[link_section = ".limine_reqs"] + static BASE_REVISION: BaseRevision = BaseRevision::new(); + + #[used] + #[link_section = ".limine_req_start"] + static REQUESTS_START: RequestsStartMarker = RequestsStartMarker::new(); + + #[used] + #[link_section = ".limine_reqs"] + static MEMMAP_REQUEST: MemmapRequest = MemmapRequest::new(); + + #[used] + #[link_section = ".limine_reqs"] + static HHDM_REQUEST: HhdmRequest = HhdmRequest::new(); + + #[used] + #[link_section = ".limine_reqs"] + static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new(); + + #[used] + #[link_section = ".limine_req_end"] + static REQUESTS_END: RequestsEndMarker = RequestsEndMarker::new(); + + #[no_mangle] + extern "C" fn _start() -> ! { + if let Some(res) = FRAMEBUFFER_REQUEST.response() { + if let Some(fb) = res.framebuffers().first() { + let ptr = fb.address() as *mut u32; + let n = 10 * fb.width as usize; + for i in 0..n { + unsafe { *ptr.add(i) = 0x00FF00FF; } // Draw pink pixel + } + } + } + + let hhdm = HHDM_REQUEST.response().unwrap(); + let memmap = MEMMAP_REQUEST.response().unwrap(); + + let mut memory_map = MemoryMap::new(); + for entry in memmap.entries() { + let kind = match entry.type_ { + memmap::MEMMAP_USABLE => MemoryRegionType::Usable, + _ => MemoryRegionType::Reserved, + }; + memory_map.add(MemoryRegion::new(entry.base, entry.length, kind)); + } + + moros::init(&memory_map, hhdm.offset); + + if let Some(res) = FRAMEBUFFER_REQUEST.response() { + if let Some(fb) = res.framebuffers().first() { + let ptr = fb.address() as *mut u32; + let n = 10 * fb.width as usize; + for i in n..(2 * n) { + unsafe { *ptr.add(i) = 0x0000FFFF; } // Draw cyan pixel + } + } + } + + hlt_loop(); + exec(); + } +} + +#[cfg(feature = "multiboot")] +mod multiboot_main { + use super::*; + + use moros::sys::mem::MemoryMap; + use moros::sys::mem::MemoryRegion; + use moros::sys::mem::MemoryRegionType; + use multiboot2::{BootInformation, BootInformationHeader}; + + #[used] + #[link_section = ".multiboot"] + static MULTIBOOT_HEADER: [u32; 6] = [ + 0xE85250D6, // magic + 0, // architecture: i386 + 24, // header length (6 * 4 bytes) + 0u32.wrapping_sub(0xE85250D6u32.wrapping_add(24)), // checksum + 0, // end tag type + 8, // end tag size + ]; + + core::arch::global_asm!( + ".section .text", + ".global _start", + "_start:", + "mov edi, ebx", + "mov esi, eax", + "call main", + "hlt", + ); + + #[no_mangle] + pub extern "C" fn main(mb2_info: u32, mb2_magic: u32) -> ! { + let vga = 0xB8000 as *mut u8; + let msg = b"MOROS loading..."; + for (i, &byte) in msg.iter().enumerate() { + unsafe { + *vga.add(i * 2) = byte; + *vga.add(i * 2 + 1) = 0x0F; + } + } + + if mb2_magic == multiboot2::MAGIC { + let boot_info = unsafe { + BootInformation::load(mb2_info as *const BootInformationHeader).unwrap() + }; + if let Some(memory_map_tag) = boot_info.memory_map_tag() { + // FIXME: This is never reached + use multiboot2::MemoryAreaType as Mem; + let mut memory_map = MemoryMap::new(); + for region in memory_map_tag.memory_areas() { + let addr = region.start_address(); + let size = region.size(); + let kind = match region.typ().into() { + Mem::Available => MemoryRegionType::Usable, + _ => MemoryRegionType::Reserved, + }; + memory_map.add(MemoryRegion::new(addr, size, kind)); + }; + let offset = 0; + moros::init(&memory_map, offset); + } + } + + exec(); + } +} + +pub fn exec() -> ! { print!("\x1b[?25h"); // Enable cursor loop { if let Some(cmd) = option_env!("MOROS_CMD") { @@ -25,22 +177,18 @@ fn main(boot_info: &'static BootInfo) -> ! { usr::shell::exec(cmd).ok(); sys::acpi::shutdown(); } else { - user_boot(); - } - } -} - -fn user_boot() { - let script = "/ini/boot.sh"; - if sys::fs::File::open(script).is_some() { - usr::shell::main(&["shell", script]).ok(); - } else { - if sys::fs::is_mounted() { - error!("Could not find '{}'", script); - } else { - warning!("MFS not found, run 'install' to setup the system"); + let script = "/ini/boot.sh"; + if sys::fs::File::open(script).is_some() { + usr::shell::main(&["shell", script]).ok(); + } else { + if sys::fs::is_mounted() { + error!("Could not find '{}'", script); + } else { + warning!("MFS not found, run 'install' to setup the system"); + } + usr::shell::main(&["shell"]).ok(); + } } - usr::shell::main(&["shell"]).ok(); } } diff --git a/src/sys/vga/mod.rs b/src/sys/vga/mod.rs index 5b425afb..dc0bd259 100644 --- a/src/sys/vga/mod.rs +++ b/src/sys/vga/mod.rs @@ -132,10 +132,5 @@ pub fn init() { set_attr_ctrl_reg(0xE, 0x3E); set_attr_ctrl_reg(0xF, 0x3F); - //Palette::default().write(); - - disable_blinking(); - disable_underline(); - - WRITER.lock().clear_screen(); + screen::set_80x25_mode(); } diff --git a/src/sys/vga/screen.rs b/src/sys/vga/screen.rs index de53b04a..5c34e4c2 100644 --- a/src/sys/vga/screen.rs +++ b/src/sys/vga/screen.rs @@ -78,7 +78,7 @@ fn set_mode(mode: ModeName) { ModeName::T80x25 => T_80_25, ModeName::G320x200x256 => G_320_200_256, ModeName::G640x480x16 => G_640_480_16, - }.to_vec(); + }; interrupts::without_interrupts(|| { let mut misc_write: Port = Port::new(MISC_WRITE_REG); @@ -149,13 +149,16 @@ fn is_80x25_mode() -> bool { } } -fn set_80x25_mode() { +pub fn set_80x25_mode() { + let restorable = MODE.lock().is_some(); clear_screen(); set_mode(ModeName::T80x25); disable_blinking(); disable_underline(); - palette::restore_palette(); - font::restore_font(); + if restorable { + palette::restore_palette(); + font::restore_font(); + } } fn set_320x200_mode() { diff --git a/tmp/boot/limine/limine.conf b/tmp/boot/limine/limine.conf new file mode 100644 index 00000000..c6840700 --- /dev/null +++ b/tmp/boot/limine/limine.conf @@ -0,0 +1,12 @@ +timeout: 10 +graphics: no + +/MOROS (Limine) + protocol: limine + resolution: 640x480x32 + kernel_path: boot():/kernel.elf + +/MOROS (Multiboot2) + protocol: multiboot2 + textmode: yes + kernel_path: boot():/kernel.elf