diff --git a/.cargo/config.toml b/.cargo/config.toml index aba5614..823bd87 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,5 +1,5 @@ [build] -target = ".cargo/target-i386.json" +target = ".cargo/target-protected-i386.json" [unstable] build-std = ["core", "compiler_builtins"] diff --git a/.cargo/linker-multiboot.ld b/.cargo/linker-multiboot.ld index c66d158..966934e 100644 --- a/.cargo/linker-multiboot.ld +++ b/.cargo/linker-multiboot.ld @@ -1,4 +1,4 @@ -ENTRY(start) +ENTRY(start_stub) SECTIONS { . = 1M; diff --git a/Cargo.toml b/Cargo.toml index bd76f83..18b0899 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,11 +13,3 @@ panic = "abort" [profile.dev] panic = "abort" - -[profile.release.package.microloader-mbr] -codegen-units = 1 -opt-level = "z" - -[profile.release.package.microloader-vba] -codegen-units = 1 -opt-level = "z" diff --git a/Makefile b/Makefile index 4a7fd27..44c49a1 100644 --- a/Makefile +++ b/Makefile @@ -7,9 +7,11 @@ RUST_DEP := Cargo.toml Cargo.lock $(shell find .cargo -type f) $(shell find deps KERNELFILE = $(OXIDE_MULTIBOOT) $(KERNELFILE): $(shell find members/oxide -type f) $(RUST_DEP) - cargo b -r --target=.cargo/target-protected-i386.json --package oxide + cargo b -r --package oxide BOOTLOADER ?= grub +# Must not contain '/' with current limitations +CMDLINE ?= include mk/make_bootloader/$(BOOTLOADER).mk .PHONY: clean \ @@ -24,6 +26,6 @@ run-bootloader-qemu-nographic: $(OUTIMG) qemu-system-x86_64 -nographic -drive format=raw,file=$(OUTIMG) # one day qemu will support multiboot2 run-qemu: $(KERNELFILE) - qemu-system-x86_64 -kernel $(KERNELFILE) + qemu-system-x86_64 -kernel $(KERNELFILE) -append $(CMDLINE) run-qemu-nographic: $(KERNELFILE) - qemu-system-x86_64 -nographic -kernel $(KERNELFILE) + qemu-system-x86_64 -nographic -kernel $(KERNELFILE) -append $(CMDLINE) diff --git a/extra/grub_iso.cfg b/extra/grub_iso.cfg index 53479b5..5182144 100644 --- a/extra/grub_iso.cfg +++ b/extra/grub_iso.cfg @@ -2,6 +2,6 @@ set timeout=2 set default=0 menuentry "OxideOS" { - multiboot2 /boot/kernel.bin + multiboot2 /boot/kernel.bin $args boot } diff --git a/members/oxide/src/main.rs b/members/oxide/src/main.rs index bd18d7e..adbc83e 100644 --- a/members/oxide/src/main.rs +++ b/members/oxide/src/main.rs @@ -2,11 +2,15 @@ #![no_main] #![deny(clippy::float_arithmetic)] #![feature( + arbitrary_self_types, + arbitrary_self_types_pointers, + associated_type_defaults, + const_convert, const_range, const_trait_impl, - const_convert, + decl_macro, generic_const_exprs, - associated_type_defaults + ptr_metadata )] /// Triggers a linker failure if this reaches that phase @@ -19,19 +23,22 @@ fn panic(_info: &PanicInfo) -> ! { unsafe { __PANIC_HANDLER_WAS_LINKED__DO_NOT_DEFINE() }; } -use core::{arch::asm, hint::black_box, panic::PanicInfo}; +use core::{arch::asm, fmt::Write as _, hint::black_box, panic::PanicInfo}; -use crate::vga::{ColorNibble, VgaBuffer, VgaColor}; +use crate::{ + multiboot2::bif, + vga::{ColorNibble, VgaBuffer, VgaColor}, +}; pub mod multiboot2; +pub mod start_stub; pub mod vga; #[used] #[unsafe(link_section = ".multiboot2_header")] static HEADER: multiboot2::Header = multiboot2::Header::new(); -#[unsafe(no_mangle)] -fn start() -> ! { +extern "C" fn start(boot_info: &bif::FixedPart) -> ! { let mut vga = unsafe { VgaBuffer::::new_uninitialized() }; vga.write_at(0, 1, b'H'); @@ -42,12 +49,53 @@ fn start() -> ! { vt.set_color(VgaColor::new(ColorNibble::BLUE, ColorNibble::GREEN)); vt.put_at(10, 5); vt.slide(); - vt.write(b"testinggg"); - // loop { - // for x in b'a'..b'z' { - // vt.write(&[x]); - // } - // } + vt.print_n(boot_info as *const _ as usize as u32); + vt.write(b"testinggg\ntags:\n"); + + let tags = bif::TagsIter::new(boot_info); + for tag in tags { + sleep_short(); + + vt.print_n(tag.typ()); + vt.write(b": "); + let Some(tag) = tag.tag() else { + vt.write(b"unknown tag\n"); + continue; + }; + + // this single line pulls like half of the fmt module which means ~ 7.5KiB of BS + let _ = writeln!(&mut vt, "{tag:?}"); + + // tbh I prefer these, I need to like, write u8 chars, on the TTY level like I really care + // about writting binary, still need to differenciate a slice of u8's and a asciistr, + // AsciiChar looks innteresting in std and could make astr = [AsciiChar], the thing I don't + // like is that disply is straight up against non-utf8 output, so I'd have to make my own + // raw-display?? but then Im going all against rust, no Display or Derive std macros + // either... + // + // match tag { + // bif::TagTagged::BootCommandLine(_) => vt.write(b"BootCommandLine\n"), + // bif::TagTagged::BasicMemoryInformation(_) => vt.write(b"BasicMemoryInformation\n"), + // bif::TagTagged::BIOSBootDevice(_) => vt.write(b"BIOSBootDevice\n"), + // bif::TagTagged::Terminate(_) => vt.write(b"Terminate\n"), + // bif::TagTagged::BootLoaderName(_) => vt.write(b"BootLoaderName\n"), + // bif::TagTagged::ImageLoadBasePhyAddr(_) => vt.write(b"ImageLoadBasePhyAddr\n"), + // } + // + // + // Somebody else, body else, body elseeee, e- e- e- elsee + // + // I don't know what to do, 'cause when you are around then I'm aaaaaalll over youuuu + // + // I always think about it, I can't play it coooool + // + // Blazing in your heeeeell, he- he- he- heeeellllll~ + // + } + + for _ in 0..=30 { + sleep_short(); + } for _ in 0..=5 { sleep_short(); @@ -63,6 +111,7 @@ fn start() -> ! { fn sleep_short() { let mut n = 0_u64; while n < 100_000_000 { + #[allow(clippy::unit_arg)] black_box(n += 1); } } diff --git a/members/oxide/src/multiboot2.rs b/members/oxide/src/multiboot2.rs index b807f6a..e9ff536 100644 --- a/members/oxide/src/multiboot2.rs +++ b/members/oxide/src/multiboot2.rs @@ -39,4 +39,175 @@ impl Default for Header { #[derive(Clone, Copy, PartialEq, Eq)] pub enum HeaderArchitecture { ProtectedI386 = 0, + MIPS32 = 4, +} + +pub mod bif { + //! # Boot Information Format + //! + //! + + use core::ptr; + + pub trait TagType { + const ID: u32 = 4; + } + + pub mod types { + macro tagset($taggedvis:vis $taggedname:ident { $( $typname:ident ($typn:expr) { $($typprop:ident : $typpropty:ty),* $(,)? } ),* $(,)? }) { + $( + #[repr(C)] + #[derive(Debug)] + pub struct $typname { $(pub $typprop: $typpropty),* } + + impl super::TagType for $typname { + const ID: u32 = $typn; + } + )* + + #[derive(Debug)] + $taggedvis enum $taggedname<'a> { + $( $typname(&'a $typname) ),* + } + } + + tagset! { pub TagTagged { + + Terminate(0) {}, + BootCommandLine(1) { + string: [u8], + }, + BootLoaderName(2) { + string: [u8], + }, + BasicMemoryInformation(4) { + mem_lower: u32, + mem_upper: u32, + }, + BIOSBootDevice(5) { + biosdev: u32, + partition: u32, + sub_partition: u32, + }, + ImageLoadBasePhyAddr(21) { + load_base_addr: u32, + }, + }} + } + + pub use types::TagTagged; + + #[repr(C)] + pub struct TagHead { + typ: u32, + size: u32, + __end: (), + } + + impl TagHead { + pub fn typ(&self) -> u32 { + self.typ + } + + pub fn size(&self) -> u32 { + self.size + } + + pub fn aligned8_size(&self) -> u32 { + (self.size + 7) & !7 + } + + /// Gets the reference of the next laying in memory tag, considering this one's size. + /// + /// # Safety + /// + /// Assumes there's a contiguous one in memory. + pub unsafe fn next(&self) -> &Self { + unsafe { &*ptr::from_ref(self).byte_add(self.aligned8_size() as usize) } + } + + pub fn tag<'a>(&self) -> Option> { + let typ = self.typ; + let size = self.size; + + let contents_addr = ptr::addr_of!(self.__end).cast::<()>(); + + macro typ_match(match $var:ident { $($name:ident)* } fat { $($fatname:ident)* }) { + match $var { + $( + types::$name::ID => Some(TagTagged::$name(unsafe { + &*core::ptr::from_raw_parts::( + contents_addr, + (), + ) + })) + ),*, + $( + types::$fatname::ID => Some(TagTagged::$fatname(unsafe { + &*core::ptr::from_raw_parts::( + contents_addr, + size as usize - core::mem::size_of::(), + ) + })) + ),*, + _ => None, + } + } + + typ_match!(match typ { + BasicMemoryInformation + BIOSBootDevice + Terminate + ImageLoadBasePhyAddr + } fat { + BootCommandLine + BootLoaderName + }) + } + } + + // --- + + /// Represents the fixed part of the BIF + #[repr(C, align(8))] + pub struct FixedPart { + pub total_size: u32, + _reserved: u32, + __end: (), + } + + /// Iterator for the tags of a [`FixedPart`] + pub struct TagsIter<'a> { + rem_size: u32, + next_ref: &'a TagHead, + } + + impl<'a> TagsIter<'a> { + pub fn new(fixed: &FixedPart) -> Self { + let rem_size = fixed.total_size - core::mem::size_of::() as u32; + let next_ptr = unsafe { &*core::ptr::addr_of!(fixed.__end).cast() }; + + Self { + rem_size, + next_ref: next_ptr, + } + } + } + + impl<'a> Iterator for TagsIter<'a> { + type Item = &'a TagHead; + + fn next(&mut self) -> Option<&'a TagHead> { + if self.rem_size > 0 { + let this_ref = self.next_ref; + self.rem_size -= this_ref.aligned8_size(); + // SAFETY: if there were no tags left we'd reach rem_size and not use this referece + // any further + self.next_ref = unsafe { this_ref.next() }; + Some(this_ref) + } else { + None + } + } + } } diff --git a/members/oxide/src/start_stub.rs b/members/oxide/src/start_stub.rs new file mode 100644 index 0000000..f09b6dd --- /dev/null +++ b/members/oxide/src/start_stub.rs @@ -0,0 +1,16 @@ +//! + +use core::arch::naked_asm; + +#[cfg(target_arch = "x86")] +#[unsafe(no_mangle)] +#[unsafe(naked)] +unsafe extern "C" fn start_stub() -> ! { + // In cdecl, protected i386, the first argument is passed in the stack + + // Sadly need to call bcs stack expectations, I wanna make a extern natural compiled thing for + // this. + + const _: extern "C" fn(&crate::multiboot2::bif::FixedPart) -> ! = crate::start; + naked_asm!("push ebx", "call {}", sym crate::start); +} diff --git a/members/oxide/src/vga/mod.rs b/members/oxide/src/vga/mod.rs index 891ecfa..9562d52 100644 --- a/members/oxide/src/vga/mod.rs +++ b/members/oxide/src/vga/mod.rs @@ -54,7 +54,7 @@ impl VgaBuffer { where [[(u8, u8); M::WIDTH as usize]; M::HEIGHT as usize]:, { - unsafe { core::mem::transmute(Self::VGA_ADDR) } + unsafe { &mut *Self::VGA_ADDR.cast() } } } diff --git a/members/oxide/src/vga/vt.rs b/members/oxide/src/vga/vt.rs index 6fd7648..e73c143 100644 --- a/members/oxide/src/vga/vt.rs +++ b/members/oxide/src/vga/vt.rs @@ -1,3 +1,5 @@ +use core::fmt::Write; + use crate::vga::{ColorNibble, TextMode, VgaBuffer, VgaColor}; pub struct Writer { @@ -52,6 +54,18 @@ where } } + pub fn print_n(&mut self, n: u32) { + const BASE: u32 = 10; + + if n == 0 { + // TODO: print a 0 if no recursion in the future + } else { + let digit = (n % BASE) as u8; + self.print_n(n / 10); + self.write(&[b'0' + digit]); + } + } + pub fn write(&mut self, data: &[u8]) { const BAD_CHAR_COL: VgaColor = VgaColor::new(ColorNibble::WHITE, ColorNibble::RED); @@ -94,3 +108,13 @@ where } } } + +impl Write for Writer +where + [[(u8, u8); M::WIDTH as usize]; M::HEIGHT as usize]:, +{ + fn write_str(&mut self, s: &str) -> core::fmt::Result { + self.write(s.as_bytes()); + Ok(()) + } +} diff --git a/mk/make_bootloader/grub.mk b/mk/make_bootloader/grub.mk index a9d4343..a71ea98 100644 --- a/mk/make_bootloader/grub.mk +++ b/mk/make_bootloader/grub.mk @@ -6,4 +6,5 @@ $(OUTIMG): $(KERNELFILE) $(GRUB_CFG) mkdir -p $(GRUB_DIR)/boot/grub cp $(KERNELFILE) $(GRUB_DIR)/boot/kernel.bin cp $(GRUB_CFG) $(GRUB_DIR)/boot/grub/grub.cfg + sed -i 's/$$args/$(CMDLINE)/' $(GRUB_DIR)/boot/grub/grub.cfg grub-mkrescue -o $@ $(GRUB_DIR)