mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 14:16:47 +00:00
feat: Add HVM boot support for x86_64 (#953)
Signed-off-by: longjin <longjin@DragonOS.org>
This commit is contained in:
parent
a8753f8fff
commit
59a6bcf6ae
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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]
|
@ -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)
|
||||
}
|
||||
}
|
@ -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
|
||||
@ -299,7 +301,6 @@ halt:
|
||||
.extern Start_Kernel
|
||||
ENTRY(_start64)
|
||||
|
||||
|
||||
// 初始化寄存器
|
||||
mov $0x10, %ax
|
||||
mov %ax, %ds
|
||||
@ -381,6 +382,7 @@ load_cr3:
|
||||
movq $__PML4E, %rax //设置页目录基地址
|
||||
|
||||
movq %rax, %cr3
|
||||
|
||||
jmp to_switch_seg
|
||||
|
||||
load_apu_cr3:
|
||||
@ -399,6 +401,7 @@ to_switch_seg:
|
||||
// 由于ljmp和lcall在GAS中不受支持,因此我们需要先伪造函数调用现场,通过lret的方式,给它跳转过去。才能更新cs寄存器
|
||||
// 实在是太妙了!Amazing!
|
||||
pushq $0x08 //段选择子
|
||||
|
||||
pushq %rax
|
||||
lretq
|
||||
|
||||
|
@ -1,13 +1,14 @@
|
||||
use core::hint::spin_loop;
|
||||
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::arch::init::multiboot::early_multiboot_init;
|
||||
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
@ -25,8 +25,8 @@ use super::{
|
||||
};
|
||||
|
||||
mod boot;
|
||||
mod multiboot;
|
||||
mod multiboot2;
|
||||
mod pvh;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ArchBootParams {}
|
||||
|
@ -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
kernel/src/arch/x86_64/init/pvh/mod.rs
Normal file
142
kernel/src/arch/x86_64/init/pvh/mod.rs
Normal 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(())
|
||||
}
|
425
kernel/src/arch/x86_64/init/pvh/param.rs
Normal file
425
kernel/src/arch/x86_64/init/pvh/param.rs
Normal 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)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -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 = .;
|
||||
}
|
||||
|
||||
|
@ -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: {:?}",
|
||||
|
@ -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!(
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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(())
|
||||
|
@ -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();
|
||||
|
@ -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 {
|
||||
/// 设置选项
|
||||
|
@ -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());
|
||||
|
@ -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();
|
||||
|
@ -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,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();
|
||||
|
@ -95,7 +95,6 @@ if [ ${ARCH} == "i386" ] || [ ${ARCH} == "x86_64" ]; then
|
||||
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;;
|
||||
|
Loading…
x
Reference in New Issue
Block a user