diff --git a/Cargo.lock b/Cargo.lock index d00dd5209b..4bd4d978a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -98,8 +98,10 @@ name = "redox_bootloader" version = "0.1.0" dependencies = [ "linked_list_allocator", + "log", "redox_syscall", "redoxfs", + "spin", ] [[package]] @@ -114,7 +116,7 @@ dependencies = [ [[package]] name = "redoxfs" version = "0.5.0" -source = "git+https://gitlab.redox-os.org/redox-os/redoxfs.git?branch=0.5.0#13d220fe6e954be4bbf7e20ccd117761474ae446" +source = "git+https://gitlab.redox-os.org/redox-os/redoxfs.git?branch=0.5.0#a551f3a0b7ea2b004c62665c2bf4003b49ea7eb6" dependencies = [ "aes", "generic-array", @@ -143,6 +145,15 @@ name = "simple_endian" version = "0.2.1" source = "git+https://github.com/michalfita/simple-endian-rs.git?rev=7210f40881d16f7f2e3d8d40f6381fa222843caa#7210f40881d16f7f2e3d8d40f6381fa222843caa" +[[package]] +name = "spin" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "511254be0c5bcf062b019a6c89c01a664aa359ded62f78aa72c6fc137c0590e5" +dependencies = [ + "lock_api", +] + [[package]] name = "spinning_top" version = "0.2.4" diff --git a/Cargo.toml b/Cargo.toml index 080c29bfdd..aee708ffae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,10 +8,11 @@ name = "bootloader" path = "src/lib.rs" crate-type = ["staticlib"] - [dependencies] linked_list_allocator = "0.9.1" +log = "0.4.14" redox_syscall = "0.2.10" +spin = "0.9.2" [dependencies.redoxfs] git = "https://gitlab.redox-os.org/redox-os/redoxfs.git" diff --git a/Makefile b/Makefile index d6ffed877e..77ff9fcdee 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,22 @@ build/bootloader.bin: build/bootloader.elf $(ARCH)/** mkdir -p build nasm -f bin -o $@ -l $@.lst -D STAGE3=$< -i$(ARCH) $(ARCH)/bootloader.asm -build/harddrive.bin: build/bootloader.bin +build/filesystem: + mkdir -p build + rm -f $@.partial + mkdir $@.partial + fallocate -l 1MiB $@.partial/kernel + mv $@.partial $@ + + +build/filesystem.bin: build/filesystem + mkdir -p build + rm -f $@.partial + fallocate -l 255MiB $@.partial + redoxfs-ar $@.partial $< + mv $@.partial $@ + +build/harddrive.bin: build/bootloader.bin build/filesystem.bin mkdir -p build rm -f $@.partial fallocate -l 256MiB $@.partial @@ -34,6 +49,7 @@ build/harddrive.bin: build/bootloader.bin $(PARTED) -s -a minimal $@.partial mkpart primary 1MiB 100% dd if=$< of=$@.partial bs=1 count=446 conv=notrunc dd if=$< of=$@.partial bs=512 skip=1 seek=1 conv=notrunc + dd if=build/filesystem.bin of=$@.partial bs=1MiB seek=1 conv=notrunc mv $@.partial $@ qemu: build/harddrive.bin diff --git a/src/disk.rs b/src/disk.rs index 937ef187b4..8181c65a12 100644 --- a/src/disk.rs +++ b/src/disk.rs @@ -30,12 +30,13 @@ impl DiskAddressPacket { } pub struct DiskBios { + boot_disk: u8, thunk13: extern "C" fn(), } impl DiskBios { - pub fn new(thunk13: extern "C" fn()) -> Self { - Self { thunk13 } + pub fn new(boot_disk: u8, thunk13: extern "C" fn()) -> Self { + Self { boot_disk, thunk13 } } } @@ -47,8 +48,7 @@ impl Disk for DiskBios { let mut data = ThunkData::new(); data.ax = 0x4200; - //TODO: get original drive number! - data.dx = 0x0080; + data.dx = self.boot_disk as u16; data.si = DISK_ADDRESS_PACKET_ADDR as u16; data.with(self.thunk13); @@ -66,12 +66,17 @@ impl Disk for DiskBios { } unsafe fn write_at(&mut self, block: u64, buffer: &[u8]) -> Result { - //TODO - Ok(0) + log::error!( + "DiskBios::write_at(0x{:X}, 0x{:X}:0x{:X}) not allowed", + block, + buffer.as_ptr() as usize, + buffer.len() + ); + Err(Error::new(EIO)) } fn size(&mut self) -> Result { - //TODO - Ok(0) + log::error!("DiskBios::size not implemented"); + Err(Error::new(EIO)) } } diff --git a/src/lib.rs b/src/lib.rs index 88150dcdde..74a679a49f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,12 +14,16 @@ use core::{ slice, }; use linked_list_allocator::LockedHeap; +use log::{error, info}; +use self::disk::DiskBios; +use self::logger::LOGGER; use self::thunk::ThunkData; use self::vbe::{VbeCardInfo, VbeModeInfo}; use self::vga::{VgaTextBlock, VgaTextColor, Vga}; mod disk; +mod logger; mod panic; mod thunk; mod vbe; @@ -37,8 +41,11 @@ const VGA_ADDR: usize = 0xB8000; #[global_allocator] static ALLOCATOR: LockedHeap = LockedHeap::empty(); +static mut VGA: Vga = unsafe { Vga::new(VGA_ADDR as *mut VgaTextBlock, 80, 25) }; + #[no_mangle] pub unsafe extern "C" fn kstart( + boot_disk: usize, thunk10: extern "C" fn(), thunk13: extern "C" fn(), thunk15: extern "C" fn(), @@ -59,13 +66,15 @@ pub unsafe extern "C" fn kstart( data.with(thunk10); } - let mut vga = Vga::new(VGA_ADDR as *mut VgaTextBlock, 80, 25); - - for i in 0..vga.blocks.len() { - vga.blocks[i].char = 0; - vga.blocks[i].color = - ((VgaTextColor::DarkGray as u8) << 4) | - (VgaTextColor::White as u8); + { + // Clear VGA console + let blocks = VGA.blocks(); + for i in 0..blocks.len() { + blocks[i] = VgaTextBlock { + char: 0, + color: ((VGA.bg as u8) << 4) | (VGA.fg as u8), + }; + } } // Initialize allocator at the end of stage 3 with a meager 1 MiB @@ -76,6 +85,35 @@ pub unsafe extern "C" fn kstart( let heap_size = 1024 * 1024; ALLOCATOR.lock().init(heap_start, heap_size); + // Set logger + LOGGER.init(); + + // Locate RedoxFS + { + //TODO: ensure boot_disk is 8-bit + info!("DISK {:02X}", boot_disk); + let disk = DiskBios::new(boot_disk as u8, thunk13); + //TODO: get block from partition table + let block = 1024 * 1024 / redoxfs::BLOCK_SIZE; + match redoxfs::FileSystem::open(disk, Some(block), false) { + Ok(mut fs) => { + info!("RedoxFS {} MiB", fs.header.size() / 1024 / 1024); + + match fs.tx(|tx| tx.find_node(redoxfs::TreePtr::root(), "kernel")) { + Ok(node) => { + info!("Kernel {} MiB", node.data().size() / 1024 / 1024); + }, + Err(err) => { + error!("Failed to find kernel file: {:?}", err); + } + } + }, + Err(err) => { + error!("Failed to open RedoxFS: {:?}", err); + } + } + } + let mut modes = Vec::new(); { // Get card info @@ -133,20 +171,22 @@ pub unsafe extern "C" fn kstart( format!("{:>4}x{:<4} {:>3}:{:<3}", w, h, aspect_w, aspect_h) )); } else { - writeln!(vga, "Failed to read VBE mode 0x{:04X} info: 0x{:04X}", mode, data.ax); + error!("Failed to read VBE mode 0x{:04X} info: 0x{:04X}", mode, data.ax); } } } else { - writeln!(vga, "Failed to read VBE card info: 0x{:04X}", data.ax); + error!("Failed to read VBE card info: 0x{:04X}", data.ax); } } // Sort modes by pixel area, reversed modes.sort_by(|a, b| (b.1 * b.2).cmp(&(a.1 * a.2))); - writeln!(vga, "Arrow keys and space select mode, enter to continue"); + writeln!(VGA, "Arrow keys and enter select mode").unwrap(); //TODO 0x4F03 VBE function to get current mode + let off_x = VGA.x; + let off_y = VGA.y; let rows = 12; let mut selected = modes.get(0).map_or(0, |x| x.0); loop { @@ -158,18 +198,18 @@ pub unsafe extern "C" fn kstart( row = 0; } - vga.x = 1 + col * 20; - vga.y = 1 + row; + VGA.x = off_x + col * 20; + VGA.y = off_y + row; if *mode == selected { - vga.bg = VgaTextColor::White; - vga.fg = VgaTextColor::Black; + VGA.bg = VgaTextColor::White; + VGA.fg = VgaTextColor::Black; } else { - vga.bg = VgaTextColor::DarkGray; - vga.fg = VgaTextColor::White; + VGA.bg = VgaTextColor::DarkGray; + VGA.fg = VgaTextColor::White; } - write!(vga, "{}", text); + write!(VGA, "{}", text).unwrap(); row += 1; } diff --git a/src/logger.rs b/src/logger.rs new file mode 100644 index 0000000000..d6c225f6c8 --- /dev/null +++ b/src/logger.rs @@ -0,0 +1,31 @@ +use core::fmt::Write; +use log::{Level, LevelFilter, Log, Metadata, Record, SetLoggerError}; + +use crate::VGA; + +pub static LOGGER: Logger = Logger; + +pub struct Logger; + +impl Logger { + pub fn init(&'static self) { + log::set_logger(self).unwrap(); + log::set_max_level(LevelFilter::Info); + } +} + +impl Log for Logger { + fn enabled(&self, metadata: &Metadata) -> bool { + true + } + + fn log(&self, record: &Record) { + if self.enabled(record.metadata()) { + unsafe { + writeln!(VGA, "{} - {}", record.level(), record.args()).unwrap(); + } + } + } + + fn flush(&self) {} +} diff --git a/src/vga.rs b/src/vga.rs index 949ae635bc..1987005296 100644 --- a/src/vga.rs +++ b/src/vga.rs @@ -29,7 +29,7 @@ pub enum VgaTextColor { } pub struct Vga { - pub blocks: &'static mut [VgaTextBlock], + pub ptr: *mut VgaTextBlock, pub width: usize, pub height: usize, pub x: usize, @@ -39,12 +39,9 @@ pub struct Vga { } impl Vga { - pub unsafe fn new(ptr: *mut VgaTextBlock, width: usize, height: usize) -> Self { + pub const unsafe fn new(ptr: *mut VgaTextBlock, width: usize, height: usize) -> Self { Self { - blocks: slice::from_raw_parts_mut( - ptr, - width * height - ), + ptr, width, height, x: 0, @@ -53,10 +50,18 @@ impl Vga { fg: VgaTextColor::White, } } + + pub unsafe fn blocks(&mut self) -> &'static mut [VgaTextBlock] { + slice::from_raw_parts_mut( + self.ptr, + self.width * self.height, + ) + } } impl fmt::Write for Vga { fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> { + let mut blocks = unsafe { self.blocks() }; for c in s.chars() { if self.x >= self.width { self.x = 0; @@ -67,9 +72,9 @@ impl fmt::Write for Vga { for x in 0..self.width { let i = y * self.width + x; let j = i - self.width; - self.blocks[j] = self.blocks[i]; + blocks[j] = blocks[i]; if y + 1 == self.height { - self.blocks[i].char = 0; + blocks[i].char = 0; } } } @@ -85,15 +90,15 @@ impl fmt::Write for Vga { }, _ => { let i = self.y * self.width + self.x; - if let Some(block) = self.blocks.get_mut(i) { + if let Some(block) = blocks.get_mut(i) { block.char = c as u8; block.color = ((self.bg as u8) << 4) | (self.fg as u8); } + self.x += 1; } } - self.x += 1; } Ok(()) diff --git a/x86/stage2.asm b/x86/stage2.asm index 058826d1c7..17eb0c63fd 100644 --- a/x86/stage2.asm +++ b/x86/stage2.asm @@ -130,6 +130,9 @@ protected_mode: push eax mov eax, thunk.int10 push eax + xor eax, eax + mov al, [disk] + push eax mov eax, [args.stage3_base] call [eax + 0x18] .halt: