Browse Source

feat: 允许通过multiboot引导(直到acpi初始化报错) (#914)

LoGin 6 months ago
parent
commit
db7c782a9a

+ 2 - 1
kernel/Cargo.toml

@@ -63,6 +63,7 @@ lru = "0.12.3"
 # target为x86_64时,使用下面的依赖
 [target.'cfg(target_arch = "x86_64")'.dependencies]
 mini-backtrace = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/mini-backtrace.git", rev = "e0b1d90940" }
+multiboot = { path = "crates/multiboot" }
 multiboot2 = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/multiboot2", rev = "05739aab40" }
 raw-cpuid = "11.0.1"
 x86 = "=0.52.0"
@@ -90,4 +91,4 @@ debug = true   # Controls whether the compiler passes `-g`
 
 # The release profile, used for `cargo build --release`
 [profile.release]
-debug = false
+debug = true

+ 8 - 0
kernel/crates/multiboot/Cargo.toml

@@ -0,0 +1,8 @@
+[package]
+name = "multiboot"
+version = "0.1.0"
+edition = "2021"
+authors = ["longjin <[email protected]>", "Dan Schatzberg <[email protected]>", "Adrian Danis <[email protected]>", "Stephane Duverger <[email protected]>", "Niklas Sombert <[email protected]>", "Paul Cacheux <[email protected]>"]
+license = "GPL-2.0"
+
+[dependencies]

+ 555 - 0
kernel/crates/multiboot/src/lib.rs

@@ -0,0 +1,555 @@
+//! Multiboot v1 library
+//!
+//! This crate is partitially modified from `https://github.com/gz/rust-multiboot` && asterinas
+//!
+//! The main structs to interact with are [`Multiboot`] for the Multiboot information
+//! passed from the bootloader to the kernel at runtime and [`Header`] for the static
+//! information passed from the kernel to the bootloader in the kernel image.
+//!
+//!
+//! # Additional documentation
+//!   * https://www.gnu.org/software/grub/manual/multiboot/multiboot.html
+//!   * http://git.savannah.gnu.org/cgit/grub.git/tree/doc/multiboot.texi?h=multiboot
+//!
+//! [`Multiboot`]: information/struct.Multiboot.html
+//! [`Header`]: header/struct.Header.html
+#![no_std]
+
+use core::ffi::CStr;
+
+pub const MAGIC: u32 = 0x2BADB002;
+
+/// The ‘boot_device’ field.
+///
+/// Partition numbers always start from zero. Unused partition
+/// bytes must be set to 0xFF. For example, if the disk is partitioned
+/// using a simple one-level DOS partitioning scheme, then
+/// ‘part’ contains the DOS partition number, and ‘part2’ and ‘part3’
+/// are both 0xFF. As another example, if a disk is partitioned first into
+/// DOS partitions, and then one of those DOS partitions is subdivided
+/// into several BSD partitions using BSD's disklabel strategy, then ‘part1’
+/// contains the DOS partition number, ‘part2’ contains the BSD sub-partition
+/// within that DOS partition, and ‘part3’ is 0xFF.
+///
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct BootDevice {
+    /// Contains the bios drive number as understood by
+    /// the bios INT 0x13 low-level disk interface: e.g. 0x00 for the
+    /// first floppy disk or 0x80 for the first hard disk.
+    pub drive: u8,
+    /// Specifies the top-level partition number.
+    pub partition1: u8,
+    /// Specifies a sub-partition in the top-level partition
+    pub partition2: u8,
+    /// Specifies a sub-partition in the 2nd-level partition
+    pub partition3: u8,
+}
+
+impl BootDevice {
+    /// Is partition1 a valid partition?
+    pub fn partition1_is_valid(&self) -> bool {
+        self.partition1 != 0xff
+    }
+
+    /// Is partition2 a valid partition?
+    pub fn partition2_is_valid(&self) -> bool {
+        self.partition2 != 0xff
+    }
+
+    /// Is partition3 a valid partition?
+    pub fn partition3_is_valid(&self) -> bool {
+        self.partition3 != 0xff
+    }
+}
+
+impl Default for BootDevice {
+    fn default() -> Self {
+        Self {
+            drive: 0xff,
+            partition1: 0xff,
+            partition2: 0xff,
+            partition3: 0xff,
+        }
+    }
+}
+
+/// Representation of Multiboot Information according to specification.
+///
+/// Reference: https://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Boot-information-format
+///
+///```text
+///         +-------------------+
+/// 0       | flags             |    (required)
+///         +-------------------+
+/// 4       | mem_lower         |    (present if flags[0] is set)
+/// 8       | mem_upper         |    (present if flags[0] is set)
+///         +-------------------+
+/// 12      | boot_device       |    (present if flags[1] is set)
+///         +-------------------+
+/// 16      | cmdline           |    (present if flags[2] is set)
+///         +-------------------+
+/// 20      | mods_count        |    (present if flags[3] is set)
+/// 24      | mods_addr         |    (present if flags[3] is set)
+///         +-------------------+
+/// 28 - 40 | syms              |    (present if flags[4] or
+///         |                   |                flags[5] is set)
+///         +-------------------+
+/// 44      | mmap_length       |    (present if flags[6] is set)
+/// 48      | mmap_addr         |    (present if flags[6] is set)
+///         +-------------------+
+/// 52      | drives_length     |    (present if flags[7] is set)
+/// 56      | drives_addr       |    (present if flags[7] is set)
+///         +-------------------+
+/// 60      | config_table      |    (present if flags[8] is set)
+///         +-------------------+
+/// 64      | boot_loader_name  |    (present if flags[9] is set)
+///         +-------------------+
+/// 68      | apm_table         |    (present if flags[10] is set)
+///         +-------------------+
+/// 72      | vbe_control_info  |    (present if flags[11] is set)
+/// 76      | vbe_mode_info     |
+/// 80      | vbe_mode          |
+/// 82      | vbe_interface_seg |
+/// 84      | vbe_interface_off |
+/// 86      | vbe_interface_len |
+///         +-------------------+
+/// 88      | framebuffer_addr  |    (present if flags[12] is set)
+/// 96      | framebuffer_pitch |
+/// 100     | framebuffer_width |
+/// 104     | framebuffer_height|
+/// 108     | framebuffer_bpp   |
+/// 109     | framebuffer_type  |
+/// 110-115 | color_info        |
+///         +-------------------+
+///```
+///
+#[allow(dead_code)]
+#[derive(Debug, Copy, Clone)]
+#[repr(C, packed)]
+pub struct MultibootInfo {
+    /// Indicate whether the below field exists.
+    flags: u32,
+
+    /// Physical memory low.
+    mem_lower: u32,
+    /// Physical memory high.
+    mem_upper: u32,
+
+    /// Indicates which BIOS disk device the boot loader loaded the OS image from.
+    boot_device: BootDevice,
+
+    /// Command line passed to kernel.
+    cmdline: u32,
+
+    /// Modules count.
+    pub mods_count: u32,
+    /// The start address of modules list, each module structure format:
+    /// ```text
+    ///         +-------------------+
+    /// 0       | mod_start         |
+    /// 4       | mod_end           |
+    ///         +-------------------+
+    /// 8       | string            |
+    ///         +-------------------+
+    /// 12      | reserved (0)      |
+    ///         +-------------------+
+    /// ```
+    mods_paddr: u32,
+
+    /// If flags[4] = 1, then the field starting at byte 28 are valid:
+    /// ```text
+    ///         +-------------------+
+    /// 28      | tabsize           |
+    /// 32      | strsize           |
+    /// 36      | addr              |
+    /// 40      | reserved (0)      |
+    ///         +-------------------+
+    /// ```
+    /// These indicate where the symbol table from kernel image can be found.
+    ///
+    /// If flags[5] = 1, then the field starting at byte 28 are valid:
+    /// ```text
+    ///         +-------------------+
+    /// 28      | num               |
+    /// 32      | size              |
+    /// 36      | addr              |
+    /// 40      | shndx             |
+    ///         +-------------------+
+    /// ```
+    /// These indicate where the section header table from an ELF kernel is,
+    /// the size of each entry, number of entries, and the string table used as the index of names.
+    symbols: [u8; 16],
+
+    memory_map_len: u32,
+    memory_map_paddr: u32,
+
+    drives_length: u32,
+    drives_addr: u32,
+
+    config_table: u32,
+
+    /// bootloader name paddr
+    pub boot_loader_name: u32,
+
+    apm_table: u32,
+
+    vbe_table: VbeInfo,
+
+    pub framebuffer_table: FramebufferTable,
+}
+
+impl MultibootInfo {
+    /// If true, then the `mem_upper` and `mem_lower` fields are valid.
+    pub const FLAG_MEMORY_BOUNDS: u32 = 1 << 0;
+    /// If true, then the `boot_device` field is valid.
+    pub const FLAG_BOOT_DEVICE: u32 = 1 << 1;
+    /// If true, then the `cmdline` field is valid.
+    pub const FLAG_CMDLINE: u32 = 1 << 2;
+    /// If true, then the `mods_count` and `mods_addr` fields are valid.
+    pub const FLAG_MODULES: u32 = 1 << 3;
+    /// If true, then the `symbols` field is valid.
+    pub const FLAG_SYMBOLS: u32 = 1 << 4;
+
+    pub unsafe fn memory_map(&self, ops: &'static dyn MultibootOps) -> MemoryEntryIter {
+        let mmap_addr = ops.phys_2_virt(self.memory_map_paddr as usize);
+        let mmap_len = self.memory_map_len as usize;
+        MemoryEntryIter {
+            cur_ptr: mmap_addr,
+            region_end_vaddr: mmap_addr + mmap_len,
+        }
+    }
+
+    pub unsafe fn modules(&self, ops: &'static dyn MultibootOps) -> Option<ModulesIter> {
+        if !self.has_modules() {
+            return None;
+        }
+
+        let mods_addr = ops.phys_2_virt(self.mods_paddr as usize);
+        let end = mods_addr + (self.mods_count as usize) * core::mem::size_of::<MBModule>();
+        Some(ModulesIter {
+            cur_ptr: mods_addr,
+            region_end_vaddr: end,
+        })
+    }
+
+    pub unsafe fn cmdline(&self, ops: &'static dyn MultibootOps) -> Option<&str> {
+        if !self.has_cmdline() {
+            return None;
+        }
+
+        let cmdline_vaddr = ops.phys_2_virt(self.cmdline as usize);
+
+        let cstr = CStr::from_ptr(cmdline_vaddr as *const i8);
+        cstr.to_str().ok()
+    }
+
+    #[inline]
+    pub fn has_memory_bounds(&self) -> bool {
+        self.flags & Self::FLAG_MEMORY_BOUNDS != 0
+    }
+
+    #[inline]
+    pub fn has_boot_device(&self) -> bool {
+        self.flags & Self::FLAG_BOOT_DEVICE != 0
+    }
+
+    #[inline]
+    pub fn has_cmdline(&self) -> bool {
+        self.flags & Self::FLAG_CMDLINE != 0
+    }
+
+    #[inline]
+    pub fn has_modules(&self) -> bool {
+        self.flags & Self::FLAG_MODULES != 0
+    }
+
+    #[inline]
+    pub fn has_symbols(&self) -> bool {
+        self.flags & Self::FLAG_SYMBOLS != 0
+    }
+}
+
+pub trait MultibootOps {
+    fn phys_2_virt(&self, paddr: usize) -> usize;
+}
+
+#[derive(Debug, Copy, Clone)]
+#[repr(C, packed)]
+pub struct VbeInfo {
+    pub control_info: u32,
+    pub mode_info: u32,
+    pub mode: u16,
+    pub interface_seg: u16,
+    pub interface_off: u16,
+    pub interface_len: u16,
+}
+
+#[derive(Debug, Copy, Clone)]
+#[repr(C, packed)]
+pub struct FramebufferTable {
+    pub paddr: u64,
+    pub pitch: u32,
+    pub width: u32,
+    pub height: u32,
+    pub bpp: u8,
+    pub typ: u8,
+    color_info: ColorInfo,
+}
+
+impl FramebufferTable {
+    /// Get the color info from this table.
+    pub fn color_info(&self) -> Option<ColorInfoType> {
+        unsafe {
+            match self.typ {
+                0 => Some(ColorInfoType::Palette(self.color_info.palette)),
+                1 => Some(ColorInfoType::Rgb(self.color_info.rgb)),
+                2 => Some(ColorInfoType::Text),
+                _ => None,
+            }
+        }
+    }
+}
+
+/// Safe wrapper for `ColorInfo`
+#[derive(Debug)]
+pub enum ColorInfoType {
+    Palette(ColorInfoPalette),
+    Rgb(ColorInfoRgb),
+    Text,
+}
+
+/// Multiboot format for the frambuffer color info
+///
+/// According to the spec, if type == 0, it's indexed color and
+///<rawtext>
+///         +----------------------------------+
+/// 110     | framebuffer_palette_addr         |
+/// 114     | framebuffer_palette_num_colors   |
+///         +----------------------------------+
+///</rawtext>
+/// The address points to an array of `ColorDescriptor`s.
+/// If type == 1, it's RGB and
+///<rawtext>
+///        +----------------------------------+
+///110     | framebuffer_red_field_position   |
+///111     | framebuffer_red_mask_size        |
+///112     | framebuffer_green_field_position |
+///113     | framebuffer_green_mask_size      |
+///114     | framebuffer_blue_field_position  |
+///115     | framebuffer_blue_mask_size       |
+///        +----------------------------------+
+///</rawtext>
+/// (If type == 2, it's just text.)
+#[repr(C)]
+#[derive(Clone, Copy)]
+union ColorInfo {
+    palette: ColorInfoPalette,
+    rgb: ColorInfoRgb,
+    _union_align: [u32; 2usize],
+}
+
+impl core::fmt::Debug for ColorInfo {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        unsafe {
+            f.debug_struct("ColorInfo")
+                .field("palette", &self.palette)
+                .field("rgb", &self.rgb)
+                .finish()
+        }
+    }
+}
+
+// default type is 0, so indexed color
+impl Default for ColorInfo {
+    fn default() -> Self {
+        Self {
+            palette: ColorInfoPalette {
+                palette_addr: 0,
+                palette_num_colors: 0,
+            },
+        }
+    }
+}
+
+/// Information for indexed color mode
+#[repr(C)]
+#[derive(Debug, Clone, Copy)]
+pub struct ColorInfoPalette {
+    palette_addr: u32,
+    palette_num_colors: u16,
+}
+
+/// Information for direct RGB color mode
+#[repr(C)]
+#[derive(Debug, Clone, Copy)]
+pub struct ColorInfoRgb {
+    pub red_field_position: u8,
+    pub red_mask_size: u8,
+    pub green_field_position: u8,
+    pub green_mask_size: u8,
+    pub blue_field_position: u8,
+    pub blue_mask_size: u8,
+}
+
+/// Types that define if the memory is usable or not.
+#[derive(Debug, PartialEq, Eq)]
+pub enum MemoryType {
+    /// memory, available to OS
+    Available = 1,
+    /// reserved, not available (rom, mem map dev)
+    Reserved = 2,
+    /// ACPI Reclaim Memory
+    ACPI = 3,
+    /// ACPI NVS Memory
+    NVS = 4,
+    /// defective RAM modules
+    Defect = 5,
+}
+
+/// A memory entry in the memory map header info region.
+///
+/// The memory layout of the entry structure doesn't fit in any scheme
+/// provided by Rust:
+///
+/// ```text
+///         +-------------------+   <- start of the struct pointer
+/// -4      | size              |
+///         +-------------------+
+/// 0       | base_addr         |
+/// 8       | length            |
+/// 16      | type              |
+///         +-------------------+
+/// ```
+///
+/// The start of a entry is not 64-bit aligned. Although the boot
+/// protocol may provide the `mmap_addr` 64-bit aligned when added with
+/// 4, it is not guaranteed. So we need to use pointer arithmetic to
+/// access the fields.
+pub struct MemoryEntry {
+    ptr: usize,
+}
+
+impl MemoryEntry {
+    pub fn size(&self) -> u32 {
+        // SAFETY: the entry can only be contructed from a valid address.
+        unsafe { (self.ptr as *const u32).read_unaligned() }
+    }
+
+    pub fn base_addr(&self) -> u64 {
+        // SAFETY: the entry can only be contructed from a valid address.
+        unsafe { ((self.ptr + 4) as *const u64).read_unaligned() }
+    }
+
+    pub fn length(&self) -> u64 {
+        // SAFETY: the entry can only be contructed from a valid address.
+        unsafe { ((self.ptr + 12) as *const u64).read_unaligned() }
+    }
+
+    pub fn memory_type(&self) -> MemoryType {
+        let typ_val = unsafe { ((self.ptr + 20) as *const u8).read_unaligned() };
+        // The meaning of the values are however documented clearly by the manual.
+        match typ_val {
+            1 => MemoryType::Available,
+            2 => MemoryType::Reserved,
+            3 => MemoryType::ACPI,
+            4 => MemoryType::NVS,
+            5 => MemoryType::Defect,
+            _ => MemoryType::Reserved,
+        }
+    }
+}
+
+/// A memory entry iterator in the memory map header info region.
+#[derive(Debug, Copy, Clone)]
+pub struct MemoryEntryIter {
+    cur_ptr: usize,
+    region_end_vaddr: usize,
+}
+
+impl Iterator for MemoryEntryIter {
+    type Item = MemoryEntry;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.cur_ptr >= self.region_end_vaddr {
+            return None;
+        }
+        let entry = MemoryEntry { ptr: self.cur_ptr };
+        self.cur_ptr += entry.size() as usize + 4;
+        Some(entry)
+    }
+}
+
+/// Multiboot format to information about module
+#[repr(C)]
+pub struct MBModule {
+    /// Start address of module in memory.
+    start: u32,
+
+    /// End address of module in memory.
+    end: u32,
+
+    /// The `string` field provides an arbitrary string to be associated
+    /// with that particular boot module.
+    ///
+    /// It is a zero-terminated ASCII string, just like the kernel command line.
+    /// The `string` field may be 0 if there is no string associated with the module.
+    /// Typically the string might be a command line (e.g. if the operating system
+    /// treats boot modules as executable programs), or a pathname
+    /// (e.g. if the operating system treats boot modules as files in a file system),
+    /// but its exact use is specific to the operating system.
+    string: u32,
+
+    /// Must be zero.
+    reserved: u32,
+}
+
+impl MBModule {
+    #[inline]
+    pub fn start(&self) -> u32 {
+        self.start
+    }
+
+    #[inline]
+    pub fn end(&self) -> u32 {
+        self.end
+    }
+
+    pub fn string(&self) -> u32 {
+        self.string
+    }
+
+    pub fn reserved(&self) -> u32 {
+        self.reserved
+    }
+}
+
+impl core::fmt::Debug for MBModule {
+    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+        write!(
+            f,
+            "MBModule {{ start: {}, end: {}, string: {}, reserved: {} }}",
+            self.start, self.end, self.string, self.reserved
+        )
+    }
+}
+
+#[derive(Debug, Copy, Clone)]
+pub struct ModulesIter {
+    cur_ptr: usize,
+    region_end_vaddr: usize,
+}
+
+impl Iterator for ModulesIter {
+    type Item = MBModule;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.cur_ptr >= self.region_end_vaddr {
+            return None;
+        }
+        let mb_module = unsafe { (self.cur_ptr as *const MBModule).read() };
+
+        self.cur_ptr += core::mem::size_of::<MBModule>();
+        Some(mb_module)
+    }
+}

+ 81 - 57
kernel/src/arch/x86_64/asm/head.S

@@ -7,8 +7,8 @@
 
 // 以下是来自 multiboot2 规范的定义
 //  How many bytes from the start of the file we search for the header.
-#define MULTIBOOT_SEARCH 32768
-#define MULTIBOOT_HEADER_ALIGN 8
+#define MULTIBOOT2_SEARCH 32768
+#define MULTIBOOT2_HEADER_ALIGN 8
 
 //  The magic field should contain this.
 #define MULTIBOOT2_HEADER_MAGIC 0xe85250d6
@@ -16,59 +16,59 @@
 
 
 //  Alignment of multiboot modules.
-#define MULTIBOOT_MOD_ALIGN 0x00001000
+#define MULTIBOOT2_MOD_ALIGN 0x00001000
 
 //  Alignment of the multiboot info structure.
-#define MULTIBOOT_INFO_ALIGN 0x00000008
+#define MULTIBOOT2_INFO_ALIGN 0x00000008
 
 //  Flags set in the 'flags' member of the multiboot header.
 
-#define MULTIBOOT_TAG_ALIGN 8
-#define MULTIBOOT_TAG_TYPE_END 0
-#define MULTIBOOT_TAG_TYPE_CMDLINE 1
-#define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME 2
-#define MULTIBOOT_TAG_TYPE_MODULE 3
-#define MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 4
-#define MULTIBOOT_TAG_TYPE_BOOTDEV 5
-#define MULTIBOOT_TAG_TYPE_MMAP 6
-#define MULTIBOOT_TAG_TYPE_VBE 7
-#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8
-#define MULTIBOOT_TAG_TYPE_ELF_SECTIONS 9
-#define MULTIBOOT_TAG_TYPE_APM 10
-#define MULTIBOOT_TAG_TYPE_EFI32 11
-#define MULTIBOOT_TAG_TYPE_EFI64 12
-#define MULTIBOOT_TAG_TYPE_SMBIOS 13
-#define MULTIBOOT_TAG_TYPE_ACPI_OLD 14
-#define MULTIBOOT_TAG_TYPE_ACPI_NEW 15
-#define MULTIBOOT_TAG_TYPE_NETWORK 16
-#define MULTIBOOT_TAG_TYPE_EFI_MMAP 17
-#define MULTIBOOT_TAG_TYPE_EFI_BS 18
-#define MULTIBOOT_TAG_TYPE_EFI32_IH 19
-#define MULTIBOOT_TAG_TYPE_EFI64_IH 20
-#define MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR 21
-
-#define MULTIBOOT_HEADER_TAG_END 0
-#define MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 1
-#define MULTIBOOT_HEADER_TAG_ADDRESS 2
-#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS 3
-#define MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS 4
-#define MULTIBOOT_HEADER_TAG_FRAMEBUFFER 5
-#define MULTIBOOT_HEADER_TAG_MODULE_ALIGN 6
-#define MULTIBOOT_HEADER_TAG_EFI_BS 7
-#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI32 8
-#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64 9
-#define MULTIBOOT_HEADER_TAG_RELOCATABLE 10
-
-#define MULTIBOOT_ARCHITECTURE_I386 0
-#define MULTIBOOT_ARCHITECTURE_MIPS32 4
-#define MULTIBOOT_HEADER_TAG_OPTIONAL 1
-
-#define MULTIBOOT_LOAD_PREFERENCE_NONE 0
-#define MULTIBOOT_LOAD_PREFERENCE_LOW 1
-#define MULTIBOOT_LOAD_PREFERENCE_HIGH 2
-
-#define MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED 1
-#define MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2
+#define MULTIBOOT2_TAG_ALIGN 8
+#define MULTIBOOT2_TAG_TYPE_END 0
+#define MULTIBOOT2_TAG_TYPE_CMDLINE 1
+#define MULTIBOOT2_TAG_TYPE_BOOT_LOADER_NAME 2
+#define MULTIBOOT2_TAG_TYPE_MODULE 3
+#define MULTIBOOT2_TAG_TYPE_BASIC_MEMINFO 4
+#define MULTIBOOT2_TAG_TYPE_BOOTDEV 5
+#define MULTIBOOT2_TAG_TYPE_MMAP 6
+#define MULTIBOOT2_TAG_TYPE_VBE 7
+#define MULTIBOOT2_TAG_TYPE_FRAMEBUFFER 8
+#define MULTIBOOT2_TAG_TYPE_ELF_SECTIONS 9
+#define MULTIBOOT2_TAG_TYPE_APM 10
+#define MULTIBOOT2_TAG_TYPE_EFI32 11
+#define MULTIBOOT2_TAG_TYPE_EFI64 12
+#define MULTIBOOT2_TAG_TYPE_SMBIOS 13
+#define MULTIBOOT2_TAG_TYPE_ACPI_OLD 14
+#define MULTIBOOT2_TAG_TYPE_ACPI_NEW 15
+#define MULTIBOOT2_TAG_TYPE_NETWORK 16
+#define MULTIBOOT2_TAG_TYPE_EFI_MMAP 17
+#define MULTIBOOT2_TAG_TYPE_EFI_BS 18
+#define MULTIBOOT2_TAG_TYPE_EFI32_IH 19
+#define MULTIBOOT2_TAG_TYPE_EFI64_IH 20
+#define MULTIBOOT2_TAG_TYPE_LOAD_BASE_ADDR 21
+
+#define MULTIBOOT2_HEADER_TAG_END 0
+#define MULTIBOOT2_HEADER_TAG_INFORMATION_REQUEST 1
+#define MULTIBOOT2_HEADER_TAG_ADDRESS 2
+#define MULTIBOOT2_HEADER_TAG_ENTRY_ADDRESS 3
+#define MULTIBOOT2_HEADER_TAG_CONSOLE_FLAGS 4
+#define MULTIBOOT2_HEADER_TAG_FRAMEBUFFER 5
+#define MULTIBOOT2_HEADER_TAG_MODULE_ALIGN 6
+#define MULTIBOOT2_HEADER_TAG_EFI_BS 7
+#define MULTIBOOT2_HEADER_TAG_ENTRY_ADDRESS_EFI32 8
+#define MULTIBOOT2_HEADER_TAG_ENTRY_ADDRESS_EFI64 9
+#define MULTIBOOT2_HEADER_TAG_RELOCATABLE 10
+
+#define MULTIBOOT2_ARCHITECTURE_I386 0
+#define MULTIBOOT2_ARCHITECTURE_MIPS32 4
+#define MULTIBOOT2_HEADER_TAG_OPTIONAL 1
+
+#define MULTIBOOT2_LOAD_PREFERENCE_NONE 0
+#define MULTIBOOT2_LOAD_PREFERENCE_LOW 1
+#define MULTIBOOT2_LOAD_PREFERENCE_HIGH 2
+
+#define MULTIBOOT2_CONSOLE_FLAGS_CONSOLE_REQUIRED 1
+#define MULTIBOOT2_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2
 
 //  This should be in %eax.
 #define MULTIBOOT_BOOTLOADER_MAGIC 0x2badb002
@@ -94,8 +94,14 @@
 
 .section ".multiboot_header", "a"
 
+#define MB_FLAGS_FB 0x4
+
+// reference: https://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Header-graphics-fields
+#define MB_HEADER_GRAPHIC_MODE_LINEAR 0
+#define MB_HEADER_GRAPHIC_MODE_TEXT 1
+
 MB_MAGIC = 0x1BADB002
-MB_FLAGS = 0
+MB_FLAGS = MB_FLAGS_FB
 MB_CHECKSUM = -(MB_MAGIC + MB_FLAGS)
 
 .code32
@@ -104,24 +110,42 @@ multiboot_header:
     .long MB_MAGIC
     .long MB_FLAGS
     .long MB_CHECKSUM
+    // header_addr if flags[16] is set
+    .long 0
+    // load_addr if flags[16] is set
+    .long 0
+    // load_end_addr if flags[16] is set
+    .long 0
+    // bss_end_addr if flags[16] is set
+    .long 0
+    // entry_addr if flags[16] is set
+    .long 0
+    // mode_type if flags[2] is set
+    .long MB_HEADER_GRAPHIC_MODE_LINEAR
+    // width if flags[2] is set
+    .long 1440
+    // height if flags[2] is set
+    .long 900
+    // depth if flags[2] is set
+    .long 32
 
 
 // multiboot2 文件头
 // 计算头长度
 .SET MB2_HEADER_LENGTH, multiboot2_header_end - multiboot2_header
 // 计算校验和
-.SET MB2_CHECKSUM, -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT_ARCHITECTURE_I386 + MB2_HEADER_LENGTH)
+.SET MB2_CHECKSUM, -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT2_ARCHITECTURE_I386 + MB2_HEADER_LENGTH)
 // 8 字节对齐
 .code32
 .section .multiboot2_header
-.align MULTIBOOT_HEADER_ALIGN
+.align MULTIBOOT2_HEADER_ALIGN
 // 声明所属段
 
 multiboot2_header:
     // 魔数
     .long MULTIBOOT2_HEADER_MAGIC
     // 架构
-    .long MULTIBOOT_ARCHITECTURE_I386
+    .long MULTIBOOT2_ARCHITECTURE_I386
     // 头长度
     .long MB2_HEADER_LENGTH
     // 校验和
@@ -131,15 +155,15 @@ multiboot2_header:
 // 设置帧缓冲区(同时在这里设置qemu的分辨率, 默认为: 1440*900, 还支持: 640*480, 等)
 .align 8
 framebuffer_tag_start:
-    .short MULTIBOOT_HEADER_TAG_FRAMEBUFFER
-    .short MULTIBOOT_HEADER_TAG_OPTIONAL
+    .short MULTIBOOT2_HEADER_TAG_FRAMEBUFFER
+    .short MULTIBOOT2_HEADER_TAG_OPTIONAL
     .long framebuffer_tag_end - framebuffer_tag_start
     .long 1440   // 宽
     .long 900   // 高
     .long 32
 framebuffer_tag_end:
 .align 8
-	.short MULTIBOOT_HEADER_TAG_END
+	.short MULTIBOOT2_HEADER_TAG_END
     // 结束标记
     .short 0
     .long 8

+ 3 - 4
kernel/src/arch/x86_64/init/boot.rs

@@ -1,5 +1,7 @@
 use system_error::SystemError;
 
+use crate::arch::init::multiboot::early_multiboot_init;
+
 use super::multiboot2::early_multiboot2_init;
 
 const BOOT_ENTRY_TYPE_MULTIBOOT: u64 = 1;
@@ -38,10 +40,7 @@ pub(super) fn early_boot_init(
 ) -> Result<(), SystemError> {
     let boot_protocol = BootProtocol::try_from(boot_entry_type)?;
     match boot_protocol {
-        BootProtocol::Multiboot => {
-            // early_multiboot_init(arg1, arg2);
-            unimplemented!();
-        }
+        BootProtocol::Multiboot => early_multiboot_init(arg1 as u32, arg2),
         BootProtocol::Multiboot2 => early_multiboot2_init(arg1 as u32, arg2),
         BootProtocol::Linux32 => {
             // linux32_init(arg1, arg2);

+ 1 - 0
kernel/src/arch/x86_64/init/mod.rs

@@ -25,6 +25,7 @@ use super::{
 };
 
 mod boot;
+mod multiboot;
 mod multiboot2;
 
 #[derive(Debug)]

+ 191 - 0
kernel/src/arch/x86_64/init/multiboot.rs

@@ -0,0 +1,191 @@
+use core::ffi::CStr;
+
+use alloc::string::{String, ToString};
+
+use multiboot::MultibootInfo;
+use system_error::SystemError;
+
+use crate::{
+    arch::MMArch,
+    driver::{
+        serial::serial8250::send_to_default_serial8250_port,
+        video::fbdev::{
+            base::{BootTimeScreenInfo, BootTimeVideoType},
+            vesafb::vesafb_early_map,
+        },
+    },
+    init::{
+        boot::{register_boot_callbacks, BootCallbacks, BootloaderAcpiArg},
+        boot_params,
+    },
+    libs::lazy_init::Lazy,
+    mm::{memblock::mem_block_manager, MemoryManagementArch, PhysAddr},
+};
+
+static MB1_INFO: Lazy<MultibootInfo> = Lazy::new();
+
+struct Mb1Ops;
+
+impl multiboot::MultibootOps for Mb1Ops {
+    fn phys_2_virt(&self, paddr: usize) -> usize {
+        unsafe { MMArch::phys_2_virt(PhysAddr::new(paddr)).unwrap().data() }
+    }
+}
+struct Mb1Callback;
+
+impl BootCallbacks for Mb1Callback {
+    fn init_bootloader_name(&self) -> Result<Option<String>, SystemError> {
+        let info = MB1_INFO.get();
+        if info.boot_loader_name != 0 {
+            // SAFETY: the bootloader name is C-style zero-terminated string.
+            unsafe {
+                let cstr_ptr =
+                    MMArch::phys_2_virt(PhysAddr::new(info.boot_loader_name as usize)).unwrap();
+                let cstr = CStr::from_ptr(cstr_ptr.data() as *const i8);
+
+                let result = cstr.to_str().unwrap_or("unknown").to_string();
+                return Ok(Some(result));
+            }
+        }
+        Ok(None)
+    }
+
+    fn init_acpi_args(&self) -> Result<BootloaderAcpiArg, SystemError> {
+        // MB1不提供rsdp信息。因此,将来需要让内核支持从UEFI获取RSDP表。
+        Ok(BootloaderAcpiArg::NotProvided)
+    }
+
+    fn init_kernel_cmdline(&self) -> Result<(), SystemError> {
+        let info = MB1_INFO.get();
+
+        if !info.has_cmdline() {
+            log::debug!("No kernel command line found in multiboot1 info");
+            return Ok(());
+        }
+
+        if let Some(cmdline) = unsafe { info.cmdline(&Mb1Ops) } {
+            let mut guard = boot_params().write_irqsave();
+            guard.boot_cmdline_append(cmdline.as_bytes());
+
+            log::info!("Kernel command line: {}\n", cmdline);
+        }
+
+        Ok(())
+    }
+
+    fn early_init_framebuffer_info(
+        &self,
+        scinfo: &mut BootTimeScreenInfo,
+    ) -> Result<(), SystemError> {
+        let info = MB1_INFO.get();
+        let fb_table = info.framebuffer_table;
+        let width = fb_table.width;
+        let height = fb_table.height;
+        scinfo.is_vga = true;
+        scinfo.lfb_base = PhysAddr::new(fb_table.paddr as usize);
+        let fb_type = fb_table.color_info().unwrap();
+
+        match fb_type {
+            multiboot::ColorInfoType::Palette(_) => todo!(),
+            multiboot::ColorInfoType::Rgb(rgb) => {
+                scinfo.lfb_width = width;
+                scinfo.lfb_height = height;
+                scinfo.video_type = BootTimeVideoType::Vlfb;
+                scinfo.lfb_depth = fb_table.bpp;
+                scinfo.red_pos = rgb.red_field_position;
+                scinfo.red_size = rgb.red_mask_size;
+                scinfo.green_pos = rgb.green_field_position;
+                scinfo.green_size = rgb.green_mask_size;
+                scinfo.blue_pos = rgb.blue_field_position;
+                scinfo.blue_size = rgb.blue_mask_size;
+            }
+            multiboot::ColorInfoType::Text => {
+                scinfo.origin_video_cols = width as u8;
+                scinfo.origin_video_lines = height as u8;
+                scinfo.video_type = BootTimeVideoType::Mda;
+                scinfo.lfb_depth = 8;
+            }
+        }
+        scinfo.lfb_size = (width * height * ((scinfo.lfb_depth as u32 + 7) / 8)) as usize;
+
+        scinfo.lfb_virt_base = Some(vesafb_early_map(scinfo.lfb_base, scinfo.lfb_size)?);
+
+        return Ok(());
+    }
+
+    fn early_init_memory_blocks(&self) -> Result<(), SystemError> {
+        let info = MB1_INFO.get();
+        let mut total_mem_size = 0usize;
+        let mut usable_mem_size = 0usize;
+        for entry in unsafe { info.memory_map(&Mb1Ops) } {
+            let start = PhysAddr::new(entry.base_addr() as usize);
+            let size = entry.length() as usize;
+            let area_typ = entry.memory_type();
+            total_mem_size += size;
+
+            match area_typ {
+                multiboot::MemoryType::Available => {
+                    usable_mem_size += size;
+                    mem_block_manager()
+                        .add_block(start, size)
+                        .unwrap_or_else(|e| {
+                            log::warn!(
+                                "Failed to add memory block: base={:?}, size={:#x}, error={:?}",
+                                start,
+                                size,
+                                e
+                            );
+                        });
+                }
+                _ => {
+                    mem_block_manager()
+                        .reserve_block(start, size)
+                        .unwrap_or_else(|e| {
+                            log::warn!(
+                                "Failed to reserve memory block: base={:?}, size={:#x}, error={:?}",
+                                start,
+                                size,
+                                e
+                            );
+                        });
+                }
+            }
+        }
+        send_to_default_serial8250_port("init_memory_area_from_multiboot1 end\n\0".as_bytes());
+        log::info!(
+            "Total memory size: {:#x}, Usable memory size: {:#x}",
+            total_mem_size,
+            usable_mem_size
+        );
+
+        if let Some(modules_iter) = unsafe { info.modules(&Mb1Ops) } {
+            for m in modules_iter {
+                let base = PhysAddr::new(m.start() as usize);
+                let size = m.end() as usize - m.start() as usize;
+                mem_block_manager()
+                    .reserve_block(base, size)
+                    .unwrap_or_else(|e| {
+                        log::warn!(
+                        "Failed to reserve modules memory block: base={:?}, size={:#x}, error={:?}",
+                        base,
+                        size,
+                        e
+                    );
+                    });
+            }
+        }
+
+        Ok(())
+    }
+}
+
+pub(super) fn early_multiboot_init(boot_magic: u32, boot_info: u64) -> Result<(), SystemError> {
+    assert_eq!(boot_magic, multiboot::MAGIC);
+    let boot_info = unsafe { MMArch::phys_2_virt(PhysAddr::new(boot_info as usize)).unwrap() };
+    let mb1_info = unsafe { (boot_info.data() as *const MultibootInfo).as_ref().unwrap() };
+    MB1_INFO.init(*mb1_info);
+
+    register_boot_callbacks(&Mb1Callback);
+
+    Ok(())
+}

+ 1 - 1
kernel/src/arch/x86_64/init/multiboot2.rs

@@ -131,7 +131,7 @@ impl BootCallbacks for Mb2Callback {
             }
         };
 
-        scinfo.lfb_size = (width * height * ((fb_tag.bpp() as u32 + 7) / 8)) as usize;
+        scinfo.lfb_size = (width * height * ((scinfo.lfb_depth as u32 + 7) / 8)) as usize;
 
         scinfo.lfb_virt_base = Some(vesafb_early_map(scinfo.lfb_base, scinfo.lfb_size)?);
 

+ 1 - 1
kernel/src/arch/x86_64/link.lds

@@ -9,7 +9,7 @@ SECTIONS
 	//KERNEL_VMA = 0;
 	. = 0;
 	. = 0x100000;
-	
+	_default_kernel_load_base = .;
 	.boot.text :
 	{
 		KEEP(*(.multiboot_header))

+ 2 - 1
kernel/src/arch/x86_64/mm/mod.rs

@@ -141,12 +141,13 @@ impl MemoryManagementArch for X86_64MMArch {
             fn _edata();
             fn _erodata();
             fn _end();
+            fn _default_kernel_load_base();
         }
 
         Self::init_xd_rsvd();
 
         let bootstrap_info = X86_64MMBootstrapInfo {
-            kernel_load_base_paddr: 0,
+            kernel_load_base_paddr: _default_kernel_load_base as usize,
             kernel_code_start: _text as usize,
             kernel_code_end: _etext as usize,
             kernel_data_end: _edata as usize,

+ 1 - 1
kernel/src/driver/video/fbdev/base/mod.rs

@@ -882,7 +882,7 @@ impl FixedScreenInfo {
     ///
     /// 长度为16的字符数组
     pub const fn name2id(name: &str) -> [char; 16] {
-        let mut id = [0 as char; 16];
+        let mut id = [0u8 as char; 16];
         let mut i = 0;
 
         while i < 15 && i < name.len() {

+ 5 - 1
kernel/src/init/boot.rs

@@ -151,7 +151,11 @@ pub fn boot_callbacks() -> &'static dyn BootCallbacks {
 pub(super) fn boot_callback_except_early() {
     boot_callbacks()
         .init_kernel_cmdline()
-        .expect("Failed to init kernel cmdline");
+        .inspect_err(|e| {
+            log::error!("Failed to init kernel cmdline: {:?}", e);
+        })
+        .ok();
+
     let mut boot_params = boot_params().write();
     boot_params.bootloader_name = boot_callbacks()
         .init_bootloader_name()