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

Signed-off-by: longjin <longjin@DragonOS.org>
This commit is contained in:
LoGin 2024-10-09 21:36:18 +08:00 committed by GitHub
parent a8753f8fff
commit 59a6bcf6ae
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 696 additions and 826 deletions

View File

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

View File

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

View File

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

View File

@ -1,8 +0,0 @@
[package]
name = "multiboot"
version = "0.1.0"
edition = "2021"
authors = ["longjin <longjin@dragonos.org>", "Dan Schatzberg <schatzberg.dan@gmail.com>", "Adrian Danis <Adrian.Danis@nicta.com.au>", "Stephane Duverger <stephane.duverger@gmail.com>", "Niklas Sombert <niklas@ytvwld.de>", "Paul Cacheux <paulcacheux@gmail.com>"]
license = "GPL-2.0"
[dependencies]

View File

@ -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)
}
}

View File

@ -17,7 +17,7 @@ ifeq ($(UNWIND_ENABLE), yes)
CFLAGS_UNWIND = -funwind-tables CFLAGS_UNWIND = -funwind-tables
ifeq ($(ARCH), x86_64) ifeq ($(ARCH), x86_64)
LDFLAGS_UNWIND = --eh-frame-hdr 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
endif endif

View File

@ -79,6 +79,7 @@
#define BOOT_ENTRY_TYPE_MULTIBOOT2 2 #define BOOT_ENTRY_TYPE_MULTIBOOT2 2
#define BOOT_ENTRY_TYPE_LINUX_32 3 #define BOOT_ENTRY_TYPE_LINUX_32 3
#define BOOT_ENTRY_TYPE_LINUX_64 4 #define BOOT_ENTRY_TYPE_LINUX_64 4
#define BOOT_ENTRY_TYPE_LINUX_32_PVH 5
// -m64 64 // -m64 64
// 32 32 64 // 32 32 64
@ -92,6 +93,19 @@
// 32 // 32
.code32 .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" .section ".multiboot_header", "a"
#define MB_FLAGS_FB 0x4 #define MB_FLAGS_FB 0x4
@ -104,31 +118,6 @@ MB_MAGIC = 0x1BADB002
MB_FLAGS = MB_FLAGS_FB MB_FLAGS = MB_FLAGS_FB
MB_CHECKSUM = -(MB_MAGIC + MB_FLAGS) 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 // multiboot2
// //
@ -169,7 +158,20 @@ framebuffer_tag_end:
.long 8 .long 8
multiboot2_header_end: 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 .global _start
@ -181,7 +183,7 @@ multiboot2_header_end:
ENTRY(_start) ENTRY(_start)
// //
cli cli
// multiboot2_info/ multiboot_info // multiboot2_info/ multiboot_info
mov %ebx, mb_entry_info mov %ebx, mb_entry_info
//mov %ebx, %e8 //mov %ebx, %e8
@ -299,7 +301,6 @@ halt:
.extern Start_Kernel .extern Start_Kernel
ENTRY(_start64) ENTRY(_start64)
// //
mov $0x10, %ax mov $0x10, %ax
mov %ax, %ds mov %ax, %ds
@ -372,7 +373,7 @@ ENTRY(_start64)
add $8, %eax add $8, %eax
loop .fill_pt_64_2 loop .fill_pt_64_2
// ==== CR3 // ==== CR3
@ -381,6 +382,7 @@ load_cr3:
movq $__PML4E, %rax // movq $__PML4E, %rax //
movq %rax, %cr3 movq %rax, %cr3
jmp to_switch_seg jmp to_switch_seg
load_apu_cr3: load_apu_cr3:
@ -394,11 +396,12 @@ load_apu_cr3:
jmp to_switch_seg jmp to_switch_seg
to_switch_seg: to_switch_seg:
movq switch_seg(%rip), %rax movq switch_seg(%rip), %rax
// ljmplcallGASlretcs // ljmplcallGASlretcs
// Amazing // Amazing
pushq $0x08 // pushq $0x08 //
pushq %rax pushq %rax
lretq lretq

View File

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

View File

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

View File

@ -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(())
}

View File

@ -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(())
}

View File

@ -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)
)
);
}
}

View File

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

View File

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

View File

@ -506,7 +506,7 @@ impl DeviceManager {
} }
let kobject_parent = self.get_device_parent(&device, deivce_parent)?; let kobject_parent = self.get_device_parent(&device, deivce_parent)?;
if let Some(ref kobj) = kobject_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 { if let Some(kobject_parent) = kobject_parent {
// debug!( // debug!(

View File

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

View File

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

View File

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

View File

@ -1169,6 +1169,30 @@ pub enum BootTimeVideoType {
Efi, 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)] #[derive(Debug, Default)]
pub struct FbCursor { pub struct FbCursor {
/// 设置选项 /// 设置选项

View File

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

View File

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

View File

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

View File

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

View File

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