extern crate core; extern crate multiboot; use core::mem; use multiboot::information::{ ColorInfoRgb, ColorInfoType, ElfSymbols, FramebufferTable, MemoryEntry, MemoryManagement, MemoryType, Module, Multiboot, MultibootInfo, PAddr, SymbolType, }; struct Mem { string_buffer: [u8; 5], module_buffer: [u8; 16], } impl Mem { fn new() -> Self { Self { string_buffer: [0; 5], module_buffer: [0; 16], } } } impl MemoryManagement for Mem { unsafe fn paddr_to_slice(&self, _addr: PAddr, _size: usize) -> Option<&'static [u8]> { None } unsafe fn allocate(&mut self, length: usize) -> Option<(PAddr, &mut [u8])> { match length { 5 => Some((0x12345678, &mut self.string_buffer)), // for our test string 16 => Some((0xaaaaaaaa, &mut self.module_buffer)), // four our test module _ => None, } } unsafe fn deallocate(&mut self, addr: PAddr) { if addr != 0 { unimplemented!() } } } #[test] /// Just create an empty struct. fn empty() { let mut mem = Mem::new(); let mut info = MultibootInfo::default(); let mut multiboot = Multiboot::from_ref(&mut info, &mut mem); // this has no effect here, but it should still work multiboot.set_memory_bounds(None); multiboot.set_command_line(None); multiboot.set_modules(None); multiboot.set_symbols(None); multiboot.set_memory_regions(None); multiboot.set_boot_loader_name(None); multiboot.set_framebuffer_table(None); let expected: [u8; 120] = [ 0x00, 0x00, 0x00, 0x00, // flags 0x00, 0x00, 0x00, 0x00, // mem_lower 0x00, 0x00, 0x00, 0x00, // mem_upper 0xff, 0xff, 0xff, 0xff, // boot_device 0x00, 0x00, 0x00, 0x00, // cmdline 0x00, 0x00, 0x00, 0x00, // mods_count 0x00, 0x00, 0x00, 0x00, // mods_addr 0x00, 0x00, 0x00, 0x00, // syms1 0x00, 0x00, 0x00, 0x00, // syms2 0x00, 0x00, 0x00, 0x00, // syms3 0x00, 0x00, 0x00, 0x00, // syms4 0x00, 0x00, 0x00, 0x00, // mmap_length 0x00, 0x00, 0x00, 0x00, // mmap_addr 0x00, 0x00, 0x00, 0x00, // drives_length 0x00, 0x00, 0x00, 0x00, // drives_addr 0x00, 0x00, 0x00, 0x00, // config_table 0x00, 0x00, 0x00, 0x00, // boot_loader_name 0x00, 0x00, 0x00, 0x00, // apm_table 0x00, 0x00, 0x00, 0x00, // vbe_control_info 0x00, 0x00, 0x00, 0x00, // vbe_mode_info 0x00, 0x00, // vbe_mode 0x00, 0x00, // vbe_interface_seg 0x00, 0x00, // vbe_interface_off 0x00, 0x00, // vbe_interface_len 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // framebuffer_addr 0x00, 0x00, 0x00, 0x00, // framebuffer_pitch 0x00, 0x00, 0x00, 0x00, // framebuffer_width 0x00, 0x00, 0x00, 0x00, // framebuffer_height 0x00, // framebuffer_bpp 0x00, // framebuffer_type 0x00, 0x00, // alignment 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // color_info 0x00, 0x00, // alignment ]; assert_eq!(multiboot_info_to_bytes(info), expected); } #[test] /// Set memory bounds. fn memory_bounds() { let mut mem = Mem::new(); let mut info = MultibootInfo::default(); let mut multiboot = Multiboot::from_ref(&mut info, &mut mem); multiboot.set_memory_bounds(Some((640, 8 * 1024))); let expected: [u8; 120] = [ 0x01, 0x00, 0x00, 0x00, // flags 0x80, 0x02, 0x00, 0x00, // mem_lower 0x00, 0x20, 0x00, 0x00, // mem_upper 0xff, 0xff, 0xff, 0xff, // boot_device 0x00, 0x00, 0x00, 0x00, // cmdline 0x00, 0x00, 0x00, 0x00, // mods_count 0x00, 0x00, 0x00, 0x00, // mods_addr 0x00, 0x00, 0x00, 0x00, // syms1 0x00, 0x00, 0x00, 0x00, // syms2 0x00, 0x00, 0x00, 0x00, // syms3 0x00, 0x00, 0x00, 0x00, // syms4 0x00, 0x00, 0x00, 0x00, // mmap_length 0x00, 0x00, 0x00, 0x00, // mmap_addr 0x00, 0x00, 0x00, 0x00, // drives_length 0x00, 0x00, 0x00, 0x00, // drives_addr 0x00, 0x00, 0x00, 0x00, // config_table 0x00, 0x00, 0x00, 0x00, // boot_loader_name 0x00, 0x00, 0x00, 0x00, // apm_table 0x00, 0x00, 0x00, 0x00, // vbe_control_info 0x00, 0x00, 0x00, 0x00, // vbe_mode_info 0x00, 0x00, // vbe_mode 0x00, 0x00, // vbe_interface_seg 0x00, 0x00, // vbe_interface_off 0x00, 0x00, // vbe_interface_len 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // framebuffer_addr 0x00, 0x00, 0x00, 0x00, // framebuffer_pitch 0x00, 0x00, 0x00, 0x00, // framebuffer_width 0x00, 0x00, 0x00, 0x00, // framebuffer_height 0x00, // framebuffer_bpp 0x00, // framebuffer_type 0x00, 0x00, // alignment 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // color_info 0x00, 0x00, // alignment ]; assert_eq!(multiboot_info_to_bytes(info), expected); } #[test] /// Also set the command line. fn command_line() { let mut mem = Mem::new(); let mut info = MultibootInfo::default(); let mut multiboot = Multiboot::from_ref(&mut info, &mut mem); multiboot.set_command_line(Some("test")); let expected: [u8; 120] = [ 0x04, 0x00, 0x00, 0x00, // flags 0x00, 0x00, 0x00, 0x00, // mem_lower 0x00, 0x00, 0x00, 0x00, // mem_upper 0xff, 0xff, 0xff, 0xff, // boot_device 0x78, 0x56, 0x34, 0x12, // cmdline 0x00, 0x00, 0x00, 0x00, // mods_count 0x00, 0x00, 0x00, 0x00, // mods_addr 0x00, 0x00, 0x00, 0x00, // syms1 0x00, 0x00, 0x00, 0x00, // syms2 0x00, 0x00, 0x00, 0x00, // syms3 0x00, 0x00, 0x00, 0x00, // syms4 0x00, 0x00, 0x00, 0x00, // mmap_length 0x00, 0x00, 0x00, 0x00, // mmap_addr 0x00, 0x00, 0x00, 0x00, // drives_length 0x00, 0x00, 0x00, 0x00, // drives_addr 0x00, 0x00, 0x00, 0x00, // config_table 0x00, 0x00, 0x00, 0x00, // boot_loader_name 0x00, 0x00, 0x00, 0x00, // apm_table 0x00, 0x00, 0x00, 0x00, // vbe_control_info 0x00, 0x00, 0x00, 0x00, // vbe_mode_info 0x00, 0x00, // vbe_mode 0x00, 0x00, // vbe_interface_seg 0x00, 0x00, // vbe_interface_off 0x00, 0x00, // vbe_interface_len 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // framebuffer_addr 0x00, 0x00, 0x00, 0x00, // framebuffer_pitch 0x00, 0x00, 0x00, 0x00, // framebuffer_width 0x00, 0x00, 0x00, 0x00, // framebuffer_height 0x00, // framebuffer_bpp 0x00, // framebuffer_type 0x00, 0x00, // alignment 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // color_info 0x00, 0x00, // alignment ]; assert_eq!(multiboot_info_to_bytes(info), expected); assert_eq!(mem.string_buffer, [0x74, 0x65, 0x73, 0x74, 0x00]); // 'test' } #[test] /// Set modules. fn modules() { let mut mem = Mem::new(); let mut info = MultibootInfo::default(); let mut multiboot = Multiboot::from_ref(&mut info, &mut mem); multiboot.set_modules(Some(&[Module::new(0x12345678, 0x87654321, Some("test"))])); let expected: [u8; 120] = [ 0x08, 0x00, 0x00, 0x00, // flags 0x00, 0x00, 0x00, 0x00, // mem_lower 0x00, 0x00, 0x00, 0x00, // mem_upper 0xff, 0xff, 0xff, 0xff, // boot_device 0x00, 0x00, 0x00, 0x00, // cmdline 0x01, 0x00, 0x00, 0x00, // mods_count 0xaa, 0xaa, 0xaa, 0xaa, // mods_addr 0x00, 0x00, 0x00, 0x00, // syms1 0x00, 0x00, 0x00, 0x00, // syms2 0x00, 0x00, 0x00, 0x00, // syms3 0x00, 0x00, 0x00, 0x00, // syms4 0x00, 0x00, 0x00, 0x00, // mmap_length 0x00, 0x00, 0x00, 0x00, // mmap_addr 0x00, 0x00, 0x00, 0x00, // drives_length 0x00, 0x00, 0x00, 0x00, // drives_addr 0x00, 0x00, 0x00, 0x00, // config_table 0x00, 0x00, 0x00, 0x00, // boot_loader_name 0x00, 0x00, 0x00, 0x00, // apm_table 0x00, 0x00, 0x00, 0x00, // vbe_control_info 0x00, 0x00, 0x00, 0x00, // vbe_mode_info 0x00, 0x00, // vbe_mode 0x00, 0x00, // vbe_interface_seg 0x00, 0x00, // vbe_interface_off 0x00, 0x00, // vbe_interface_len 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // framebuffer_addr 0x00, 0x00, 0x00, 0x00, // framebuffer_pitch 0x00, 0x00, 0x00, 0x00, // framebuffer_width 0x00, 0x00, 0x00, 0x00, // framebuffer_height 0x00, // framebuffer_bpp 0x00, // framebuffer_type 0x00, 0x00, // alignment 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // color_info 0x00, 0x00, // alignment ]; assert_eq!(multiboot_info_to_bytes(info), expected); assert_eq!(mem.string_buffer, [0x74, 0x65, 0x73, 0x74, 0x00]); // 'test' assert_eq!( mem.module_buffer, [ 0x78, 0x56, 0x34, 0x12, // start 0x21, 0x43, 0x65, 0x87, // end 0x78, 0x56, 0x34, 0x12, // TEST_STR 0x00, 0x00, 0x00, 0x00 // reserved ] ); } #[test] /// Set symbols. fn symbols() { let mut mem = Mem::new(); let mut info = MultibootInfo::default(); let mut multiboot = Multiboot::from_ref(&mut info, &mut mem); multiboot.set_symbols(Some(SymbolType::Elf(ElfSymbols::from_addr( 1, 8, 0x12345678, 0, )))); let expected: [u8; 120] = [ 0x20, 0x00, 0x00, 0x00, // flags 0x00, 0x00, 0x00, 0x00, // mem_lower 0x00, 0x00, 0x00, 0x00, // mem_upper 0xff, 0xff, 0xff, 0xff, // boot_device 0x00, 0x00, 0x00, 0x00, // cmdline 0x00, 0x00, 0x00, 0x00, // mods_count 0x00, 0x00, 0x00, 0x00, // mods_addr 0x01, 0x00, 0x00, 0x00, // syms1 0x08, 0x00, 0x00, 0x00, // syms2 0x78, 0x56, 0x34, 0x12, // syms3 0x00, 0x00, 0x00, 0x00, // syms4 0x00, 0x00, 0x00, 0x00, // mmap_length 0x00, 0x00, 0x00, 0x00, // mmap_addr 0x00, 0x00, 0x00, 0x00, // drives_length 0x00, 0x00, 0x00, 0x00, // drives_addr 0x00, 0x00, 0x00, 0x00, // config_table 0x00, 0x00, 0x00, 0x00, // boot_loader_name 0x00, 0x00, 0x00, 0x00, // apm_table 0x00, 0x00, 0x00, 0x00, // vbe_control_info 0x00, 0x00, 0x00, 0x00, // vbe_mode_info 0x00, 0x00, // vbe_mode 0x00, 0x00, // vbe_interface_seg 0x00, 0x00, // vbe_interface_off 0x00, 0x00, // vbe_interface_len 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // framebuffer_addr 0x00, 0x00, 0x00, 0x00, // framebuffer_pitch 0x00, 0x00, 0x00, 0x00, // framebuffer_width 0x00, 0x00, 0x00, 0x00, // framebuffer_height 0x00, // framebuffer_bpp 0x00, // framebuffer_type 0x00, 0x00, // alignment 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // color_info 0x00, 0x00, // alignment ]; assert_eq!(multiboot_info_to_bytes(info), expected); } #[test] /// Set memory regions. fn mmap() { let mut mem = Mem::new(); let mut info = MultibootInfo::default(); let mut multiboot = Multiboot::from_ref(&mut info, &mut mem); multiboot.set_memory_regions(Some((0x12345678, 1))); let expected: [u8; 120] = [ 0x40, 0x00, 0x00, 0x00, // flags 0x00, 0x00, 0x00, 0x00, // mem_lower 0x00, 0x00, 0x00, 0x00, // mem_upper 0xff, 0xff, 0xff, 0xff, // boot_device 0x00, 0x00, 0x00, 0x00, // cmdline 0x00, 0x00, 0x00, 0x00, // mods_count 0x00, 0x00, 0x00, 0x00, // mods_addr 0x00, 0x00, 0x00, 0x00, // syms1 0x00, 0x00, 0x00, 0x00, // syms2 0x00, 0x00, 0x00, 0x00, // syms3 0x00, 0x00, 0x00, 0x00, // syms4 0x18, 0x00, 0x00, 0x00, // mmap_length 0x78, 0x56, 0x34, 0x12, // mmap_addr 0x00, 0x00, 0x00, 0x00, // drives_length 0x00, 0x00, 0x00, 0x00, // drives_addr 0x00, 0x00, 0x00, 0x00, // config_table 0x00, 0x00, 0x00, 0x00, // boot_loader_name 0x00, 0x00, 0x00, 0x00, // apm_table 0x00, 0x00, 0x00, 0x00, // vbe_control_info 0x00, 0x00, 0x00, 0x00, // vbe_mode_info 0x00, 0x00, // vbe_mode 0x00, 0x00, // vbe_interface_seg 0x00, 0x00, // vbe_interface_off 0x00, 0x00, // vbe_interface_len 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // framebuffer_addr 0x00, 0x00, 0x00, 0x00, // framebuffer_pitch 0x00, 0x00, 0x00, 0x00, // framebuffer_width 0x00, 0x00, 0x00, 0x00, // framebuffer_height 0x00, // framebuffer_bpp 0x00, // framebuffer_type 0x00, 0x00, // alignment 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // color_info 0x00, 0x00, // alignment ]; assert_eq!(multiboot_info_to_bytes(info), expected); let memory_entry = MemoryEntry::new(0x12345678, 4096, MemoryType::Defect); let expected_entry: [u8; 24] = [ 0x14, 0x00, 0x00, 0x00, // size 0x78, 0x56, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00, // base_addr 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // length 0x05, 0x00, 0x00, 0x00, // type ]; assert_eq!( unsafe { mem::transmute::<_, [u8; 24]>(memory_entry) }, expected_entry ); } #[test] /// Also set the boot loader name. fn boot_loader_name() { let mut mem = Mem::new(); let mut info = MultibootInfo::default(); let mut multiboot = Multiboot::from_ref(&mut info, &mut mem); multiboot.set_boot_loader_name(Some("test")); let expected: [u8; 120] = [ 0x00, 0x02, 0x00, 0x00, // flags 0x00, 0x00, 0x00, 0x00, // mem_lower 0x00, 0x00, 0x00, 0x00, // mem_upper 0xff, 0xff, 0xff, 0xff, // boot_device 0x00, 0x00, 0x00, 0x00, // cmdline 0x00, 0x00, 0x00, 0x00, // mods_count 0x00, 0x00, 0x00, 0x00, // mods_addr 0x00, 0x00, 0x00, 0x00, // syms1 0x00, 0x00, 0x00, 0x00, // syms2 0x00, 0x00, 0x00, 0x00, // syms3 0x00, 0x00, 0x00, 0x00, // syms4 0x00, 0x00, 0x00, 0x00, // mmap_length 0x00, 0x00, 0x00, 0x00, // mmap_addr 0x00, 0x00, 0x00, 0x00, // drives_length 0x00, 0x00, 0x00, 0x00, // drives_addr 0x00, 0x00, 0x00, 0x00, // config_table 0x78, 0x56, 0x34, 0x12, // boot_loader_name 0x00, 0x00, 0x00, 0x00, // apm_table 0x00, 0x00, 0x00, 0x00, // vbe_control_info 0x00, 0x00, 0x00, 0x00, // vbe_mode_info 0x00, 0x00, // vbe_mode 0x00, 0x00, // vbe_interface_seg 0x00, 0x00, // vbe_interface_off 0x00, 0x00, // vbe_interface_len 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // framebuffer_addr 0x00, 0x00, 0x00, 0x00, // framebuffer_pitch 0x00, 0x00, 0x00, 0x00, // framebuffer_width 0x00, 0x00, 0x00, 0x00, // framebuffer_height 0x00, // framebuffer_bpp 0x00, // framebuffer_type 0x00, 0x00, // alignment 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // color_info 0x00, 0x00, // alignment ]; assert_eq!(multiboot_info_to_bytes(info), expected); assert_eq!(mem.string_buffer, [0x74, 0x65, 0x73, 0x74, 0x00]); // 'test' } #[test] /// Set framebuffer information. fn framebuffer() { let mut mem = Mem::new(); let mut info = MultibootInfo::default(); let mut multiboot = Multiboot::from_ref(&mut info, &mut mem); multiboot.set_framebuffer_table(Some(FramebufferTable::new( 0x12345678, 800 * 4, 800, 600, 32, ColorInfoType::Rgb(ColorInfoRgb { red_field_position: 0, red_mask_size: 8, green_field_position: 8, green_mask_size: 8, blue_field_position: 16, blue_mask_size: 8, }), ))); let expected: [u8; 120] = [ 0x00, 0x10, 0x00, 0x00, // flags 0x00, 0x00, 0x00, 0x00, // mem_lower 0x00, 0x00, 0x00, 0x00, // mem_upper 0xff, 0xff, 0xff, 0xff, // boot_device 0x00, 0x00, 0x00, 0x00, // cmdline 0x00, 0x00, 0x00, 0x00, // mods_count 0x00, 0x00, 0x00, 0x00, // mods_addr 0x00, 0x00, 0x00, 0x00, // syms1 0x00, 0x00, 0x00, 0x00, // syms2 0x00, 0x00, 0x00, 0x00, // syms3 0x00, 0x00, 0x00, 0x00, // syms4 0x00, 0x00, 0x00, 0x00, // mmap_length 0x00, 0x00, 0x00, 0x00, // mmap_addr 0x00, 0x00, 0x00, 0x00, // drives_length 0x00, 0x00, 0x00, 0x00, // drives_addr 0x00, 0x00, 0x00, 0x00, // config_table 0x00, 0x00, 0x00, 0x00, // boot_loader_name 0x00, 0x00, 0x00, 0x00, // apm_table 0x00, 0x00, 0x00, 0x00, // vbe_control_info 0x00, 0x00, 0x00, 0x00, // vbe_mode_info 0x00, 0x00, // vbe_mode 0x00, 0x00, // vbe_interface_seg 0x00, 0x00, // vbe_interface_off 0x00, 0x00, // vbe_interface_len 0x78, 0x56, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00, // framebuffer_addr 0x80, 0x0c, 0x00, 0x00, // framebuffer_pitch 0x20, 0x03, 0x00, 0x00, // framebuffer_width 0x58, 0x02, 0x00, 0x00, // framebuffer_height 0x20, // framebuffer_bpp 0x01, // framebuffer_type 0x00, 0x00, // alignment 0x00, 0x08, 0x08, 0x08, 0x10, 0x08, // color_info 0x00, 0x00, // alignment ]; assert_eq!(multiboot_info_to_bytes(info), expected); } fn multiboot_info_to_bytes(info: MultibootInfo) -> [u8; 120] { assert_eq!(mem::size_of::(), 120); let mut bytes = [0; 120]; let info_bytes: [u8; 120] = unsafe { mem::transmute(info) }; for (index, byte) in info_bytes.iter().enumerate() { // ignore padding bytes if ![0x6E, 0x6F, 0x76, 0x77].contains(&index) { bytes[index] = *byte; } } bytes }