Browse Source

feat: Add HVM boot support for x86_64 (#953)

Signed-off-by: longjin <[email protected]>
LoGin 5 months ago
parent
commit
59a6bcf6ae

+ 1 - 1
build-scripts/Cargo.toml

@@ -2,4 +2,4 @@
 members = [
     "kernel_build",
 ]
-resolver = "2"
+resolver = "2"

+ 5 - 0
docs/kernel/boot/bootloader.md

@@ -3,6 +3,11 @@
 ## X86_64
 
 - [x] multiboot2
+- [x] HVM/PVH
+
+### x86_64下的HVM/PVH启动
+
+在DragonOS的note段,有一段PVH header,允许qemu使用`-kernel`参数启动DragonOS内核。
 
 ## RISC-V 64
 

+ 1 - 2
kernel/Cargo.toml

@@ -62,7 +62,6 @@ 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 +89,4 @@ debug = true   # Controls whether the compiler passes `-g`
 
 # The release profile, used for `cargo build --release`
 [profile.release]
-debug = true
+debug = false

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

@@ -1,8 +0,0 @@
-[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]

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

@@ -1,555 +0,0 @@
-//! 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)
-    }
-}

+ 1 - 1
kernel/src/Makefile

@@ -17,7 +17,7 @@ ifeq ($(UNWIND_ENABLE), yes)
     CFLAGS_UNWIND = -funwind-tables
 ifeq ($(ARCH), x86_64)
     LDFLAGS_UNWIND = --eh-frame-hdr
-    RUSTFLAGS_UNWIND = -Cforce-unwind-tables -Clink-arg=-Wl,eh_frame.ld 
+    RUSTFLAGS_UNWIND = -Cforce-unwind-tables -Clink-arg=-Wl,eh_frame.ld
 endif
 endif
 

+ 33 - 30
kernel/src/arch/x86_64/asm/head.S

@@ -79,6 +79,7 @@
 #define BOOT_ENTRY_TYPE_MULTIBOOT2  2
 #define BOOT_ENTRY_TYPE_LINUX_32  3
 #define BOOT_ENTRY_TYPE_LINUX_64  4
+#define BOOT_ENTRY_TYPE_LINUX_32_PVH 5
 
 // 直接用 -m64 编译出来的是 64 位代码,
 // 但是启动后的机器是 32 位的,相当于在 32 位机器上跑 64 位程序。
@@ -92,6 +93,19 @@
 // 声明这一段代码以 32 位模式编译
 .code32
 
+/* PVH Header with pvh_start_addr = __linux32_pvh_boot */
+
+	.pushsection .note.dragonos, "a", @note
+	.align 4
+	.long 2f - 1f
+	.long 4f - 3f
+	.long 18
+	1:.asciz "Xen"
+	2:.align 4
+	3:.long __linux32_pvh_boot
+	4:.align 4
+	.popsection
+
 .section ".multiboot_header", "a"
 
 #define MB_FLAGS_FB 0x4
@@ -104,31 +118,6 @@ MB_MAGIC = 0x1BADB002
 MB_FLAGS = MB_FLAGS_FB
 MB_CHECKSUM = -(MB_MAGIC + MB_FLAGS)
 
-.code32
-multiboot_header:
-    .align 8
-    .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 文件头
 // 计算头长度
@@ -169,7 +158,20 @@ framebuffer_tag_end:
     .long 8
 multiboot2_header_end:
 
-.section .bootstrap
+// direct_linux32_boot启动的内核入口
+.section .bootstrap, "a"
+.code32
+.global __linux32_pvh_boot
+__linux32_pvh_boot:
+    cli
+    cld
+    // start info 指针
+    mov %ebx, mb_entry_info
+    mov $BOOT_ENTRY_TYPE_LINUX_32_PVH, %ebx
+    mov %ebx, boot_entry_type
+    jmp protected_mode_setup
+
+.code32
 
 
 .global _start
@@ -181,7 +183,7 @@ multiboot2_header_end:
 ENTRY(_start)
     // 关中断
     cli
-    
+
     // multiboot2_info/ multiboot_info 结构体指针
     mov %ebx, mb_entry_info
     //mov %ebx, %e8
@@ -299,7 +301,6 @@ halt:
 .extern Start_Kernel
 ENTRY(_start64)
 
-
     // 初始化寄存器
     mov $0x10, %ax
     mov %ax, %ds
@@ -372,7 +373,7 @@ ENTRY(_start64)
     add $8, %eax
     loop .fill_pt_64_2
 
-
+    
 
 // ==== 加载CR3寄存器
 
@@ -381,6 +382,7 @@ load_cr3:
     movq $__PML4E, %rax //设置页目录基地址
     
     movq %rax, %cr3
+    
     jmp to_switch_seg
 
 load_apu_cr3:
@@ -394,11 +396,12 @@ load_apu_cr3:
     jmp to_switch_seg
 
 to_switch_seg:
-
+    
     movq switch_seg(%rip), %rax
     // 由于ljmp和lcall在GAS中不受支持,因此我们需要先伪造函数调用现场,通过lret的方式,给它跳转过去。才能更新cs寄存器
     // 实在是太妙了!Amazing!
     pushq $0x08 //段选择子
+
     pushq %rax
     lretq
 

+ 10 - 12
kernel/src/arch/x86_64/init/boot.rs

@@ -1,13 +1,14 @@
-use system_error::SystemError;
+use core::hint::spin_loop;
 
-use crate::arch::init::multiboot::early_multiboot_init;
+use system_error::SystemError;
 
-use super::multiboot2::early_multiboot2_init;
+use super::{multiboot2::early_multiboot2_init, pvh::early_linux32_pvh_init};
 
 const BOOT_ENTRY_TYPE_MULTIBOOT: u64 = 1;
 const BOOT_ENTRY_TYPE_MULTIBOOT2: u64 = 2;
 const BOOT_ENTRY_TYPE_LINUX_32: u64 = 3;
 const BOOT_ENTRY_TYPE_LINUX_64: u64 = 4;
+const BOOT_ENTRY_TYPE_LINUX_32_PVH: u64 = 5;
 
 #[derive(Debug)]
 #[repr(u64)]
@@ -16,6 +17,7 @@ enum BootProtocol {
     Multiboot2,
     Linux32,
     Linux64,
+    Linux32Pvh,
 }
 
 impl TryFrom<u64> for BootProtocol {
@@ -27,6 +29,7 @@ impl TryFrom<u64> for BootProtocol {
             BOOT_ENTRY_TYPE_MULTIBOOT2 => Ok(BootProtocol::Multiboot2),
             BOOT_ENTRY_TYPE_LINUX_32 => Ok(BootProtocol::Linux32),
             BOOT_ENTRY_TYPE_LINUX_64 => Ok(BootProtocol::Linux64),
+            BOOT_ENTRY_TYPE_LINUX_32_PVH => Ok(BootProtocol::Linux32Pvh),
             _ => Err(SystemError::EINVAL),
         }
     }
@@ -40,15 +43,10 @@ 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 as u32, arg2),
         BootProtocol::Multiboot2 => early_multiboot2_init(arg1 as u32, arg2),
-        BootProtocol::Linux32 => {
-            // linux32_init(arg1, arg2);
-            unimplemented!();
-        }
-        BootProtocol::Linux64 => {
-            // linux64_init(arg1, arg2);
-            unimplemented!();
-        }
+        BootProtocol::Linux32 | BootProtocol::Linux64 | BootProtocol::Multiboot => loop {
+            spin_loop();
+        },
+        BootProtocol::Linux32Pvh => early_linux32_pvh_init(arg2 as usize),
     }
 }

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

@@ -25,8 +25,8 @@ use super::{
 };
 
 mod boot;
-mod multiboot;
 mod multiboot2;
+mod pvh;
 
 #[derive(Debug)]
 pub struct ArchBootParams {}

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

@@ -1,191 +0,0 @@
-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(())
-}

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

@@ -0,0 +1,142 @@
+//! x86/HVM启动
+//!
+//! 初始化代码可参考:https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/platform/pvh/enlighten.c#45
+use alloc::string::{String, ToString};
+use core::{ffi::CStr, hint::spin_loop};
+use param::{E820Type, HvmMemmapTableEntry, HvmStartInfo};
+use system_error::SystemError;
+
+use crate::{
+    arch::MMArch,
+    driver::{
+        serial::serial8250::send_to_default_serial8250_port, video::fbdev::base::BootTimeScreenInfo,
+    },
+    init::{
+        boot::{register_boot_callbacks, BootCallbacks, BootloaderAcpiArg},
+        boot_params,
+    },
+    libs::lazy_init::Lazy,
+    mm::{memblock::mem_block_manager, MemoryManagementArch, PhysAddr},
+};
+
+mod param;
+
+static START_INFO: Lazy<HvmStartInfo> = Lazy::new();
+
+struct PvhBootCallback;
+
+impl BootCallbacks for PvhBootCallback {
+    fn init_bootloader_name(&self) -> Result<Option<String>, SystemError> {
+        return Ok(Some("x86 PVH".to_string()));
+    }
+
+    fn init_acpi_args(&self) -> Result<BootloaderAcpiArg, SystemError> {
+        let rsdp_paddr = PhysAddr::new(START_INFO.get().rsdp_paddr as usize);
+        if rsdp_paddr.data() != 0 {
+            Ok(BootloaderAcpiArg::Rsdp(rsdp_paddr))
+        } else {
+            Ok(BootloaderAcpiArg::NotProvided)
+        }
+    }
+
+    fn init_kernel_cmdline(&self) -> Result<(), SystemError> {
+        let cmdline_c_str: &CStr = unsafe {
+            CStr::from_ptr(
+                MMArch::phys_2_virt(PhysAddr::new(START_INFO.get().cmdline_paddr as usize))
+                    .unwrap()
+                    .data() as *const i8,
+            )
+        };
+        let cmdline = cmdline_c_str.to_str().unwrap();
+        boot_params()
+            .write_irqsave()
+            .boot_cmdline_append(cmdline.as_bytes());
+        log::info!("pvh boot cmdline: {:?}", cmdline_c_str);
+        Ok(())
+    }
+
+    fn early_init_framebuffer_info(
+        &self,
+        _scinfo: &mut BootTimeScreenInfo,
+    ) -> Result<(), SystemError> {
+        return Err(SystemError::ENODEV);
+    }
+
+    fn early_init_memory_blocks(&self) -> Result<(), SystemError> {
+        let start_info = START_INFO.get();
+        let mut total_mem_size = 0usize;
+        let mut usable_mem_size = 0usize;
+        send_to_default_serial8250_port("init_memory_area by pvh boot\n\0".as_bytes());
+
+        if (start_info.version > 0) && start_info.memmap_entries > 0 {
+            let mut ep = unsafe {
+                MMArch::phys_2_virt(PhysAddr::new(start_info.memmap_paddr as usize)).unwrap()
+            }
+            .data() as *const HvmMemmapTableEntry;
+
+            for _ in 0..start_info.memmap_entries {
+                let entry = unsafe { *ep };
+                let start = PhysAddr::new(entry.addr as usize);
+                let size = entry.size as usize;
+                let typ = E820Type::from(entry.type_);
+
+                total_mem_size += size;
+                match typ {
+                    param::E820Type::Ram => {
+                        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
+                                );
+                            });
+                    }
+                }
+                ep = unsafe { ep.add(1) };
+            }
+        }
+        send_to_default_serial8250_port("init_memory_area_from pvh boot end\n\0".as_bytes());
+        log::info!(
+            "Total memory size: {:#x}, Usable memory size: {:#x}",
+            total_mem_size,
+            usable_mem_size
+        );
+        Ok(())
+    }
+}
+
+#[inline(never)]
+pub(super) fn early_linux32_pvh_init(params_ptr: usize) -> Result<(), SystemError> {
+    let start_info = unsafe { *(params_ptr as *const HvmStartInfo) };
+    if start_info.magic != HvmStartInfo::XEN_HVM_START_MAGIC_VALUE {
+        send_to_default_serial8250_port(
+            "early_linux32_pvh_init failed: Magic number not matched.\n\0".as_bytes(),
+        );
+
+        loop {
+            spin_loop();
+        }
+    }
+
+    START_INFO.init(start_info);
+
+    register_boot_callbacks(&PvhBootCallback);
+    send_to_default_serial8250_port("early_linux32_pvh_init done.\n\0".as_bytes());
+    Ok(())
+}

+ 425 - 0
kernel/src/arch/x86_64/init/pvh/param.rs

@@ -0,0 +1,425 @@
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Copyright (c) 2016, Citrix Systems, Inc.
+ */
+
+/*
+ * automatically generated by rust-bindgen using:
+ *
+ * # bindgen start_info.h -- -include stdint.h > start_info.rs
+ *
+ * From the canonical version in upstream Xen repository
+ * xen/include/public/arch-x86/hvm/start_info.h
+ * at commit:
+ * b4642c32c4d079916d5607ddda0232aae5e1690e
+ *
+ * The generated file has been edited to eliminate unnecessary
+ * definitions, add comments, and relocate definitions and tests for clarity.
+ * Added Default to the list of traits that are automatically derived.
+ *
+ * The definitions in this file are intended to be exported and used by a particular
+ * VMM implementation in order to boot a Linux guest using the PVH entry point as
+ * specified in the x86/HVM direct boot ABI.
+ * These structures contain all the required information (cmdline address, ACPI RSDP,
+ * memory maps, etc) that must be written to guest memory before starting guest
+ * execution by jumping to the PVH entry point address.
+ * A comparable set of definitions to hvm_start_info and hvm_memmap_table_entry in this
+ * file would be the boot_params and boot_e820_entry definitions used by the Linux
+ * 64-bit boot protocol.
+ *
+ * Start of day structure passed to PVH guests and to HVM guests in %ebx.
+ *
+ * NOTE: nothing will be loaded at physical address 0, so a 0 value in any
+ * of the address fields should be treated as not present.
+ *
+ *  0 +----------------+
+ *    | magic          | Contains the magic value XEN_HVM_START_MAGIC_VALUE
+ *    |                | ("xEn3" with the 0x80 bit of the "E" set).
+ *  4 +----------------+
+ *    | version        | Version of this structure. Current version is 1. New
+ *    |                | versions are guaranteed to be backwards-compatible.
+ *  8 +----------------+
+ *    | flags          | SIF_xxx flags.
+ * 12 +----------------+
+ *    | nr_modules     | Number of modules passed to the kernel.
+ * 16 +----------------+
+ *    | modlist_paddr  | Physical address of an array of modules
+ *    |                | (layout of the structure below).
+ * 24 +----------------+
+ *    | cmdline_paddr  | Physical address of the command line,
+ *    |                | a zero-terminated ASCII string.
+ * 32 +----------------+
+ *    | rsdp_paddr     | Physical address of the RSDP ACPI data structure.
+ * 40 +----------------+
+ *    | memmap_paddr   | Physical address of the (optional) memory map. Only
+ *    |                | present in version 1 and newer of the structure.
+ * 48 +----------------+
+ *    | memmap_entries | Number of entries in the memory map table. Zero
+ *    |                | if there is no memory map being provided. Only
+ *    |                | present in version 1 and newer of the structure.
+ * 52 +----------------+
+ *    | reserved       | Version 1 and newer only.
+ * 56 +----------------+
+ *
+ * The layout of each entry in the module structure is the following:
+ *
+ *  0 +----------------+
+ *    | paddr          | Physical address of the module.
+ *  8 +----------------+
+ *    | size           | Size of the module in bytes.
+ * 16 +----------------+
+ *    | cmdline_paddr  | Physical address of the command line,
+ *    |                | a zero-terminated ASCII string.
+ * 24 +----------------+
+ *    | reserved       |
+ * 32 +----------------+
+ *
+ * The layout of each entry in the memory map table is as follows:
+ *
+ *  0 +----------------+
+ *    | addr           | Base address
+ *  8 +----------------+
+ *    | size           | Size of mapping in bytes
+ * 16 +----------------+
+ *    | type           | Type of mapping as defined between the hypervisor
+ *    |                | and guest. See XEN_HVM_MEMMAP_TYPE_* values below.
+ * 20 +----------------|
+ *    | reserved       |
+ * 24 +----------------+
+ *
+ * The address and sizes are always a 64bit little endian unsigned integer.
+ *
+ * NB: Xen on x86 will always try to place all the data below the 4GiB
+ * boundary.
+ *
+ * Version numbers of the hvm_start_info structure have evolved like this:
+ *
+ * Version 0:  Initial implementation.
+ *
+ * Version 1:  Added the memmap_paddr/memmap_entries fields (plus 4 bytes of
+ *             padding) to the end of the hvm_start_info struct. These new
+ *             fields can be used to pass a memory map to the guest. The
+ *             memory map is optional and so guests that understand version 1
+ *             of the structure must check that memmap_entries is non-zero
+ *             before trying to read the memory map.
+ */
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone, Default)]
+pub struct HvmStartInfo {
+    pub magic: u32,
+    pub version: u32,
+    pub flags: u32,
+    pub nr_modules: u32,
+    pub modlist_paddr: u64,
+    pub cmdline_paddr: u64,
+    pub rsdp_paddr: u64,
+    pub memmap_paddr: u64,
+    pub memmap_entries: u32,
+    pub reserved: u32,
+}
+
+impl HvmStartInfo {
+    pub const XEN_HVM_START_MAGIC_VALUE: u32 = 0x336ec578;
+}
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone, Default)]
+pub struct HvmModlistEntry {
+    pub paddr: u64,
+    pub size: u64,
+    pub cmdline_paddr: u64,
+    pub reserved: u64,
+}
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone, Default)]
+pub struct HvmMemmapTableEntry {
+    pub addr: u64,
+    pub size: u64,
+    pub type_: u32,
+    pub reserved: u32,
+}
+
+/// The E820 types known to the kernel.
+#[derive(Copy, Clone, Debug)]
+#[repr(u32)]
+pub enum E820Type {
+    Ram = 1,
+    Reserved = 2,
+    Acpi = 3,
+    Nvs = 4,
+    Unusable = 5,
+    Pmem = 7,
+    Pram = 12,
+    SoftReserved = 0xefffffff,
+    ReservedKern = 128,
+}
+
+impl From<u32> for E820Type {
+    fn from(val: u32) -> Self {
+        match val {
+            1 => E820Type::Ram,
+            2 => E820Type::Reserved,
+            3 => E820Type::Acpi,
+            4 => E820Type::Nvs,
+            5 => E820Type::Unusable,
+            7 => E820Type::Pmem,
+            12 => E820Type::Pram,
+            0xefffffff => E820Type::SoftReserved,
+            128 => E820Type::ReservedKern,
+            _ => E820Type::Reserved,
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn bindgen_test_layout_hvm_start_info() {
+        const UNINIT: ::std::mem::MaybeUninit<HvmStartInfo> = ::std::mem::MaybeUninit::uninit();
+        let ptr = UNINIT.as_ptr();
+        assert_eq!(
+            ::std::mem::size_of::<HvmStartInfo>(),
+            56usize,
+            concat!("Size of: ", stringify!(hvm_start_info))
+        );
+        assert_eq!(
+            ::std::mem::align_of::<HvmStartInfo>(),
+            8usize,
+            concat!("Alignment of ", stringify!(hvm_start_info))
+        );
+        assert_eq!(
+            unsafe { ::std::ptr::addr_of!((*ptr).magic) as usize - ptr as usize },
+            0usize,
+            concat!(
+                "Offset of field: ",
+                stringify!(hvm_start_info),
+                "::",
+                stringify!(magic)
+            )
+        );
+        assert_eq!(
+            unsafe { ::std::ptr::addr_of!((*ptr).version) as usize - ptr as usize },
+            4usize,
+            concat!(
+                "Offset of field: ",
+                stringify!(hvm_start_info),
+                "::",
+                stringify!(version)
+            )
+        );
+        assert_eq!(
+            unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize },
+            8usize,
+            concat!(
+                "Offset of field: ",
+                stringify!(hvm_start_info),
+                "::",
+                stringify!(flags)
+            )
+        );
+        assert_eq!(
+            unsafe { ::std::ptr::addr_of!((*ptr).nr_modules) as usize - ptr as usize },
+            12usize,
+            concat!(
+                "Offset of field: ",
+                stringify!(hvm_start_info),
+                "::",
+                stringify!(nr_modules)
+            )
+        );
+        assert_eq!(
+            unsafe { ::std::ptr::addr_of!((*ptr).modlist_paddr) as usize - ptr as usize },
+            16usize,
+            concat!(
+                "Offset of field: ",
+                stringify!(hvm_start_info),
+                "::",
+                stringify!(modlist_paddr)
+            )
+        );
+        assert_eq!(
+            unsafe { ::std::ptr::addr_of!((*ptr).cmdline_paddr) as usize - ptr as usize },
+            24usize,
+            concat!(
+                "Offset of field: ",
+                stringify!(hvm_start_info),
+                "::",
+                stringify!(cmdline_paddr)
+            )
+        );
+        assert_eq!(
+            unsafe { ::std::ptr::addr_of!((*ptr).rsdp_paddr) as usize - ptr as usize },
+            32usize,
+            concat!(
+                "Offset of field: ",
+                stringify!(hvm_start_info),
+                "::",
+                stringify!(rsdp_paddr)
+            )
+        );
+        assert_eq!(
+            unsafe { ::std::ptr::addr_of!((*ptr).memmap_paddr) as usize - ptr as usize },
+            40usize,
+            concat!(
+                "Offset of field: ",
+                stringify!(hvm_start_info),
+                "::",
+                stringify!(memmap_paddr)
+            )
+        );
+        assert_eq!(
+            unsafe { ::std::ptr::addr_of!((*ptr).memmap_entries) as usize - ptr as usize },
+            48usize,
+            concat!(
+                "Offset of field: ",
+                stringify!(hvm_start_info),
+                "::",
+                stringify!(memmap_entries)
+            )
+        );
+        assert_eq!(
+            unsafe { ::std::ptr::addr_of!((*ptr).reserved) as usize - ptr as usize },
+            52usize,
+            concat!(
+                "Offset of field: ",
+                stringify!(hvm_start_info),
+                "::",
+                stringify!(reserved)
+            )
+        );
+    }
+
+    #[test]
+    fn bindgen_test_layout_hvm_modlist_entry() {
+        const UNINIT: ::std::mem::MaybeUninit<HvmModlistEntry> = ::std::mem::MaybeUninit::uninit();
+        let ptr = UNINIT.as_ptr();
+        assert_eq!(
+            ::std::mem::size_of::<HvmModlistEntry>(),
+            32usize,
+            concat!("Size of: ", stringify!(hvm_modlist_entry))
+        );
+        assert_eq!(
+            ::std::mem::align_of::<HvmModlistEntry>(),
+            8usize,
+            concat!("Alignment of ", stringify!(hvm_modlist_entry))
+        );
+        assert_eq!(
+            unsafe { ::std::ptr::addr_of!((*ptr).paddr) as usize - ptr as usize },
+            0usize,
+            concat!(
+                "Offset of field: ",
+                stringify!(hvm_modlist_entry),
+                "::",
+                stringify!(paddr)
+            )
+        );
+        assert_eq!(
+            unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize },
+            8usize,
+            concat!(
+                "Offset of field: ",
+                stringify!(hvm_modlist_entry),
+                "::",
+                stringify!(size)
+            )
+        );
+        assert_eq!(
+            unsafe { ::std::ptr::addr_of!((*ptr).cmdline_paddr) as usize - ptr as usize },
+            16usize,
+            concat!(
+                "Offset of field: ",
+                stringify!(hvm_modlist_entry),
+                "::",
+                stringify!(cmdline_paddr)
+            )
+        );
+        assert_eq!(
+            unsafe { ::std::ptr::addr_of!((*ptr).reserved) as usize - ptr as usize },
+            24usize,
+            concat!(
+                "Offset of field: ",
+                stringify!(hvm_modlist_entry),
+                "::",
+                stringify!(reserved)
+            )
+        );
+    }
+
+    #[test]
+    fn bindgen_test_layout_hvm_memmap_table_entry() {
+        const UNINIT: ::std::mem::MaybeUninit<HvmMemmapTableEntry> =
+            ::std::mem::MaybeUninit::uninit();
+        let ptr = UNINIT.as_ptr();
+        assert_eq!(
+            ::std::mem::size_of::<HvmMemmapTableEntry>(),
+            24usize,
+            concat!("Size of: ", stringify!(hvm_memmap_table_entry))
+        );
+        assert_eq!(
+            ::std::mem::align_of::<HvmMemmapTableEntry>(),
+            8usize,
+            concat!("Alignment of ", stringify!(hvm_memmap_table_entry))
+        );
+        assert_eq!(
+            unsafe { ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize },
+            0usize,
+            concat!(
+                "Offset of field: ",
+                stringify!(hvm_memmap_table_entry),
+                "::",
+                stringify!(addr)
+            )
+        );
+        assert_eq!(
+            unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize },
+            8usize,
+            concat!(
+                "Offset of field: ",
+                stringify!(hvm_memmap_table_entry),
+                "::",
+                stringify!(size)
+            )
+        );
+        assert_eq!(
+            unsafe { ::std::ptr::addr_of!((*ptr).type_) as usize - ptr as usize },
+            16usize,
+            concat!(
+                "Offset of field: ",
+                stringify!(hvm_memmap_table_entry),
+                "::",
+                stringify!(type_)
+            )
+        );
+        assert_eq!(
+            unsafe { ::std::ptr::addr_of!((*ptr).reserved) as usize - ptr as usize },
+            20usize,
+            concat!(
+                "Offset of field: ",
+                stringify!(hvm_memmap_table_entry),
+                "::",
+                stringify!(reserved)
+            )
+        );
+    }
+}

+ 6 - 2
kernel/src/arch/x86_64/link.lds

@@ -14,15 +14,17 @@ SECTIONS
 	{
 		KEEP(*(.multiboot_header))
 		KEEP(*(.multiboot2_header))
+		
 		*(.bootstrap)
 		*(.bootstrap.code64)
 		*(.bootstrap.data)
+		
 		. = ALIGN(4096);
 	}
 
-	. = 0x1000000;
-	. += KERNEL_VMA;
+
 	. = ALIGN(32768);
+	. += KERNEL_VMA;
 	text_start_pa = .;
 	.text (text_start_pa): AT(text_start_pa - KERNEL_VMA)
 	{
@@ -55,6 +57,8 @@ SECTIONS
 		_rodata = .;	
 		*(.rodata)
 		*(.rodata.*)
+		*(.note.gnu.*)
+		*(.fixup)
 		_erodata = .;
 	}
 

+ 1 - 0
kernel/src/driver/acpi/mod.rs

@@ -81,6 +81,7 @@ impl AcpiManager {
         let table_paddr: PhysAddr = match acpi_args {
             BootloaderAcpiArg::Rsdt(rsdpv1) => Self::rsdp_paddr(&rsdpv1),
             BootloaderAcpiArg::Xsdt(rsdpv2) => Self::rsdp_paddr(&rsdpv2),
+            BootloaderAcpiArg::Rsdp(rsdp) => rsdp,
             _ => {
                 error!(
                     "AcpiManager::map_tables(): unsupported acpi_args: {:?}",

+ 1 - 1
kernel/src/driver/base/device/mod.rs

@@ -506,7 +506,7 @@ impl DeviceManager {
         }
         let kobject_parent = self.get_device_parent(&device, deivce_parent)?;
         if let Some(ref kobj) = kobject_parent {
-            log::info!("kobject parent: {:?}", kobj.name());
+            log::debug!("kobject parent: {:?}", kobj.name());
         }
         if let Some(kobject_parent) = kobject_parent {
             // debug!(

+ 5 - 0
kernel/src/driver/tty/tty_driver.rs

@@ -284,6 +284,11 @@ impl TtyDriver {
             if err == SystemError::ENOSYS {
                 return self.standard_install(tty);
             } else {
+                log::error!(
+                    "driver_install_tty: Failed to install. name: {}, err: {:?}",
+                    tty.core().name(),
+                    err
+                );
                 return Err(err);
             }
         }

+ 5 - 4
kernel/src/driver/tty/virtual_terminal/mod.rs

@@ -495,9 +495,10 @@ pub struct DrawRegion {
 #[inline(never)]
 pub fn vty_init() -> Result<(), SystemError> {
     if let Ok(tty_console_driver_inner) = TtyConsoleDriverInner::new() {
+        const NAME: &str = "tty";
         let console_driver = TtyDriver::new(
             MAX_NR_CONSOLES,
-            "tty",
+            NAME,
             0,
             Major::TTY_MAJOR,
             0,
@@ -507,8 +508,8 @@ pub fn vty_init() -> Result<(), SystemError> {
             None,
         );
 
-        TtyDriverManager::tty_register_driver(console_driver).inspect(|_| {
-            log::error!("tty console: register driver failed");
+        TtyDriverManager::tty_register_driver(console_driver).inspect_err(|e| {
+            log::error!("tty console: register driver {} failed: {:?}", NAME, e);
         })?;
     }
 
@@ -520,7 +521,7 @@ fn vty_late_init() -> Result<(), SystemError> {
     let (_, console_driver) =
         TtyDriverManager::lookup_tty_driver(DeviceNumber::new(Major::TTY_MAJOR, 0))
             .ok_or(SystemError::ENODEV)?;
-    console_driver.init_tty_device(None)?;
+    console_driver.init_tty_device(None).ok();
 
     vc_manager().setup_default_vc();
     Ok(())

+ 4 - 2
kernel/src/driver/video/fbdev/base/fbcon/framebuffer_console.rs

@@ -185,10 +185,12 @@ impl ConsoleSwitch for BlittingFbConsole {
         }
         let fb = fb.unwrap();
         if fb.is_none() {
-            panic!(
+            log::warn!(
                 "The Framebuffer with FbID {} has not been initialized yet.",
                 vc_data.index
-            )
+            );
+
+            return Err(SystemError::ENODEV);
         }
 
         let fb = fb.as_ref().unwrap().clone();

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

@@ -1169,6 +1169,30 @@ pub enum BootTimeVideoType {
     Efi,
 }
 
+impl From<u8> for BootTimeVideoType {
+    fn from(value: u8) -> Self {
+        match value {
+            0 => BootTimeVideoType::UnDefined,
+            0x10 => BootTimeVideoType::Mda,
+            0x11 => BootTimeVideoType::Cga,
+            0x20 => BootTimeVideoType::EgaM,
+            0x21 => BootTimeVideoType::EgaC,
+            0x22 => BootTimeVideoType::VgaC,
+            0x23 => BootTimeVideoType::Vlfb,
+            0x30 => BootTimeVideoType::PicaS3,
+            0x31 => BootTimeVideoType::MipsG364,
+            0x33 => BootTimeVideoType::Sgi,
+            0x40 => BootTimeVideoType::TgaC,
+            0x50 => BootTimeVideoType::Sun,
+            0x51 => BootTimeVideoType::SunPci,
+            0x60 => BootTimeVideoType::Pmac,
+            0x70 => BootTimeVideoType::Efi,
+
+            _ => BootTimeVideoType::UnDefined,
+        }
+    }
+}
+
 #[derive(Debug, Default)]
 pub struct FbCursor {
     /// 设置选项

+ 12 - 3
kernel/src/driver/video/mod.rs

@@ -21,6 +21,10 @@ pub mod fbdev;
 
 static mut __MAMAGER: Option<VideoRefreshManager> = None;
 
+#[inline]
+pub fn has_video_refresh_manager() -> bool {
+    return unsafe { __MAMAGER.is_some() };
+}
 pub fn video_refresh_manager() -> &'static VideoRefreshManager {
     return unsafe {
         __MAMAGER
@@ -73,9 +77,13 @@ impl VideoRefreshManager {
     /**
      * VBE帧缓存区的地址重新映射
      */
-    fn init_frame_buffer(&self) {
-        info!("Re-mapping VBE frame buffer...");
+    fn init_frame_buffer(&self) -> Result<(), SystemError> {
         let mut bp = boot_params().write_irqsave();
+        // 没有VBE
+        if bp.screen_info.lfb_base.data() == 0 {
+            return Err(SystemError::ENODEV);
+        }
+        info!("Re-mapping VBE frame buffer...");
         let buf_size = bp.screen_info.lfb_size;
 
         let mmio_guard = mmio_pool().create_mmio(page_align_up(buf_size)).unwrap();
@@ -100,6 +108,7 @@ impl VideoRefreshManager {
         };
 
         info!("VBE frame buffer successfully Re-mapped!");
+        Ok(())
     }
 
     /**
@@ -111,7 +120,7 @@ impl VideoRefreshManager {
      */
     pub fn video_reinitialize(&self, level: bool) -> Result<(), SystemError> {
         if !level {
-            self.init_frame_buffer();
+            self.init_frame_buffer()?;
         } else {
             // 开启屏幕计时刷新
             assert!(self.run_video_refresh());

+ 7 - 2
kernel/src/init/init.rs

@@ -1,3 +1,5 @@
+use log::warn;
+
 use crate::{
     arch::{
         init::{early_setup_arch, setup_arch, setup_arch_post},
@@ -55,8 +57,11 @@ fn do_start_kernel() {
     early_setup_arch().expect("setup_arch failed");
     unsafe { mm_init() };
 
-    scm_reinit().unwrap();
-    textui_init().unwrap();
+    if scm_reinit().is_ok() {
+        if let Err(e) = textui_init() {
+            warn!("Failed to init textui: {:?}", e);
+        }
+    }
 
     boot_callback_except_early();
     init_intertrait();

+ 2 - 5
kernel/src/init/initial_kthread.rs

@@ -20,7 +20,8 @@ use super::initcall::do_initcalls;
 
 pub fn initial_kernel_thread() -> i32 {
     kernel_init().unwrap_or_else(|err| {
-        panic!("Failed to initialize kernel: {:?}", err);
+        log::error!("Failed to initialize kernel: {:?}", err);
+        panic!()
     });
 
     switch_to_user();
@@ -29,10 +30,6 @@ pub fn initial_kernel_thread() -> i32 {
 fn kernel_init() -> Result<(), SystemError> {
     KernelThreadMechanism::init_stage2();
     kenrel_init_freeable()?;
-
-    // 由于目前加锁,速度过慢,所以先不开启双缓冲
-    // scm_enable_double_buffer().expect("Failed to enable double buffer");
-
     #[cfg(target_arch = "x86_64")]
     crate::driver::disk::ahci::ahci_init()
         .inspect_err(|e| log::error!("ahci_init failed: {:?}", e))

+ 8 - 4
kernel/src/libs/lib_ui/screen_manager.rs

@@ -8,7 +8,10 @@ use alloc::{boxed::Box, collections::LinkedList, string::String, sync::Arc};
 use system_error::SystemError;
 
 use crate::{
-    driver::{serial::serial8250::send_to_default_serial8250_port, video::video_refresh_manager},
+    driver::{
+        serial::serial8250::send_to_default_serial8250_port,
+        video::{has_video_refresh_manager, video_refresh_manager},
+    },
     libs::{lib_ui::textui::textui_is_enable_put_to_window, rwlock::RwLock, spinlock::SpinLock},
     mm::{mmio_buddy::MMIOSpaceGuard, VirtAddr},
 };
@@ -430,9 +433,10 @@ pub fn scm_reinit() -> Result<(), SystemError> {
 
 #[allow(dead_code)]
 fn true_scm_reinit() -> Result<(), SystemError> {
-    video_refresh_manager()
-        .video_reinitialize(false)
-        .expect("video reinitialize failed");
+    if !has_video_refresh_manager() {
+        return Err(SystemError::ENODEV);
+    }
+    video_refresh_manager().video_reinitialize(false)?;
 
     // 遍历当前所有使用帧缓冲区的框架,更新地址
     let device_buffer = video_refresh_manager().device_buffer().clone();

+ 2 - 2
tools/run-qemu.sh

@@ -94,8 +94,7 @@ if [ ${ARCH} == "i386" ] || [ ${ARCH} == "x86_64" ]; then
     else
       QEMU_DEVICES_DISK="-device virtio-blk-pci,drive=disk -device pci-bridge,chassis_nr=1,id=pci.1 -device pcie-root-port "
     fi
-    
-    
+
 else
     QEMU_MACHINE=" -machine virt,memory-backend=${QEMU_MEMORY_BACKEND} -cpu sifive-u54 "
     QEMU_DEVICES_DISK="-device virtio-blk-device,drive=disk "
@@ -132,6 +131,7 @@ while true;do
               QEMU_SERIAL=" -serial mon:stdio "
               QEMU_MONITOR=""
               QEMU_ARGUMENT+=" --nographic "
+              QEMU_ARGUMENT+=" -kernel ../bin/kernel/kernel.elf "
 
               ;;
         esac;shift 2;;