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

This commit is contained in:
LoGin 2024-09-06 20:04:36 +08:00 committed by GitHub
parent 886ce28516
commit db7c782a9a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 847 additions and 63 deletions

View File

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

View File

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

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

View File

@ -7,8 +7,8 @@
// multiboot2
// How many bytes from the start of the file we search for the header.
#define MULTIBOOT_SEARCH 32768
#define MULTIBOOT_HEADER_ALIGN 8
#define MULTIBOOT2_SEARCH 32768
#define MULTIBOOT2_HEADER_ALIGN 8
// The magic field should contain this.
#define MULTIBOOT2_HEADER_MAGIC 0xe85250d6
@ -16,59 +16,59 @@
// Alignment of multiboot modules.
#define MULTIBOOT_MOD_ALIGN 0x00001000
#define MULTIBOOT2_MOD_ALIGN 0x00001000
// Alignment of the multiboot info structure.
#define MULTIBOOT_INFO_ALIGN 0x00000008
#define MULTIBOOT2_INFO_ALIGN 0x00000008
// Flags set in the 'flags' member of the multiboot header.
#define MULTIBOOT_TAG_ALIGN 8
#define MULTIBOOT_TAG_TYPE_END 0
#define MULTIBOOT_TAG_TYPE_CMDLINE 1
#define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME 2
#define MULTIBOOT_TAG_TYPE_MODULE 3
#define MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 4
#define MULTIBOOT_TAG_TYPE_BOOTDEV 5
#define MULTIBOOT_TAG_TYPE_MMAP 6
#define MULTIBOOT_TAG_TYPE_VBE 7
#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8
#define MULTIBOOT_TAG_TYPE_ELF_SECTIONS 9
#define MULTIBOOT_TAG_TYPE_APM 10
#define MULTIBOOT_TAG_TYPE_EFI32 11
#define MULTIBOOT_TAG_TYPE_EFI64 12
#define MULTIBOOT_TAG_TYPE_SMBIOS 13
#define MULTIBOOT_TAG_TYPE_ACPI_OLD 14
#define MULTIBOOT_TAG_TYPE_ACPI_NEW 15
#define MULTIBOOT_TAG_TYPE_NETWORK 16
#define MULTIBOOT_TAG_TYPE_EFI_MMAP 17
#define MULTIBOOT_TAG_TYPE_EFI_BS 18
#define MULTIBOOT_TAG_TYPE_EFI32_IH 19
#define MULTIBOOT_TAG_TYPE_EFI64_IH 20
#define MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR 21
#define MULTIBOOT2_TAG_ALIGN 8
#define MULTIBOOT2_TAG_TYPE_END 0
#define MULTIBOOT2_TAG_TYPE_CMDLINE 1
#define MULTIBOOT2_TAG_TYPE_BOOT_LOADER_NAME 2
#define MULTIBOOT2_TAG_TYPE_MODULE 3
#define MULTIBOOT2_TAG_TYPE_BASIC_MEMINFO 4
#define MULTIBOOT2_TAG_TYPE_BOOTDEV 5
#define MULTIBOOT2_TAG_TYPE_MMAP 6
#define MULTIBOOT2_TAG_TYPE_VBE 7
#define MULTIBOOT2_TAG_TYPE_FRAMEBUFFER 8
#define MULTIBOOT2_TAG_TYPE_ELF_SECTIONS 9
#define MULTIBOOT2_TAG_TYPE_APM 10
#define MULTIBOOT2_TAG_TYPE_EFI32 11
#define MULTIBOOT2_TAG_TYPE_EFI64 12
#define MULTIBOOT2_TAG_TYPE_SMBIOS 13
#define MULTIBOOT2_TAG_TYPE_ACPI_OLD 14
#define MULTIBOOT2_TAG_TYPE_ACPI_NEW 15
#define MULTIBOOT2_TAG_TYPE_NETWORK 16
#define MULTIBOOT2_TAG_TYPE_EFI_MMAP 17
#define MULTIBOOT2_TAG_TYPE_EFI_BS 18
#define MULTIBOOT2_TAG_TYPE_EFI32_IH 19
#define MULTIBOOT2_TAG_TYPE_EFI64_IH 20
#define MULTIBOOT2_TAG_TYPE_LOAD_BASE_ADDR 21
#define MULTIBOOT_HEADER_TAG_END 0
#define MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 1
#define MULTIBOOT_HEADER_TAG_ADDRESS 2
#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS 3
#define MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS 4
#define MULTIBOOT_HEADER_TAG_FRAMEBUFFER 5
#define MULTIBOOT_HEADER_TAG_MODULE_ALIGN 6
#define MULTIBOOT_HEADER_TAG_EFI_BS 7
#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI32 8
#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64 9
#define MULTIBOOT_HEADER_TAG_RELOCATABLE 10
#define MULTIBOOT2_HEADER_TAG_END 0
#define MULTIBOOT2_HEADER_TAG_INFORMATION_REQUEST 1
#define MULTIBOOT2_HEADER_TAG_ADDRESS 2
#define MULTIBOOT2_HEADER_TAG_ENTRY_ADDRESS 3
#define MULTIBOOT2_HEADER_TAG_CONSOLE_FLAGS 4
#define MULTIBOOT2_HEADER_TAG_FRAMEBUFFER 5
#define MULTIBOOT2_HEADER_TAG_MODULE_ALIGN 6
#define MULTIBOOT2_HEADER_TAG_EFI_BS 7
#define MULTIBOOT2_HEADER_TAG_ENTRY_ADDRESS_EFI32 8
#define MULTIBOOT2_HEADER_TAG_ENTRY_ADDRESS_EFI64 9
#define MULTIBOOT2_HEADER_TAG_RELOCATABLE 10
#define MULTIBOOT_ARCHITECTURE_I386 0
#define MULTIBOOT_ARCHITECTURE_MIPS32 4
#define MULTIBOOT_HEADER_TAG_OPTIONAL 1
#define MULTIBOOT2_ARCHITECTURE_I386 0
#define MULTIBOOT2_ARCHITECTURE_MIPS32 4
#define MULTIBOOT2_HEADER_TAG_OPTIONAL 1
#define MULTIBOOT_LOAD_PREFERENCE_NONE 0
#define MULTIBOOT_LOAD_PREFERENCE_LOW 1
#define MULTIBOOT_LOAD_PREFERENCE_HIGH 2
#define MULTIBOOT2_LOAD_PREFERENCE_NONE 0
#define MULTIBOOT2_LOAD_PREFERENCE_LOW 1
#define MULTIBOOT2_LOAD_PREFERENCE_HIGH 2
#define MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED 1
#define MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2
#define MULTIBOOT2_CONSOLE_FLAGS_CONSOLE_REQUIRED 1
#define MULTIBOOT2_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2
// This should be in %eax.
#define MULTIBOOT_BOOTLOADER_MAGIC 0x2badb002
@ -94,8 +94,14 @@
.section ".multiboot_header", "a"
#define MB_FLAGS_FB 0x4
// reference: https://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Header-graphics-fields
#define MB_HEADER_GRAPHIC_MODE_LINEAR 0
#define MB_HEADER_GRAPHIC_MODE_TEXT 1
MB_MAGIC = 0x1BADB002
MB_FLAGS = 0
MB_FLAGS = MB_FLAGS_FB
MB_CHECKSUM = -(MB_MAGIC + MB_FLAGS)
.code32
@ -104,24 +110,42 @@ multiboot_header:
.long MB_MAGIC
.long MB_FLAGS
.long MB_CHECKSUM
// header_addr if flags[16] is set
.long 0
// load_addr if flags[16] is set
.long 0
// load_end_addr if flags[16] is set
.long 0
// bss_end_addr if flags[16] is set
.long 0
// entry_addr if flags[16] is set
.long 0
// mode_type if flags[2] is set
.long MB_HEADER_GRAPHIC_MODE_LINEAR
// width if flags[2] is set
.long 1440
// height if flags[2] is set
.long 900
// depth if flags[2] is set
.long 32
// multiboot2
//
.SET MB2_HEADER_LENGTH, multiboot2_header_end - multiboot2_header
//
.SET MB2_CHECKSUM, -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT_ARCHITECTURE_I386 + MB2_HEADER_LENGTH)
.SET MB2_CHECKSUM, -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT2_ARCHITECTURE_I386 + MB2_HEADER_LENGTH)
// 8
.code32
.section .multiboot2_header
.align MULTIBOOT_HEADER_ALIGN
.align MULTIBOOT2_HEADER_ALIGN
//
multiboot2_header:
//
.long MULTIBOOT2_HEADER_MAGIC
//
.long MULTIBOOT_ARCHITECTURE_I386
.long MULTIBOOT2_ARCHITECTURE_I386
//
.long MB2_HEADER_LENGTH
//
@ -131,15 +155,15 @@ multiboot2_header:
// (qemu, : 1440*900, : 640*480, )
.align 8
framebuffer_tag_start:
.short MULTIBOOT_HEADER_TAG_FRAMEBUFFER
.short MULTIBOOT_HEADER_TAG_OPTIONAL
.short MULTIBOOT2_HEADER_TAG_FRAMEBUFFER
.short MULTIBOOT2_HEADER_TAG_OPTIONAL
.long framebuffer_tag_end - framebuffer_tag_start
.long 1440 //
.long 900 //
.long 32
framebuffer_tag_end:
.align 8
.short MULTIBOOT_HEADER_TAG_END
.short MULTIBOOT2_HEADER_TAG_END
//
.short 0
.long 8

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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