mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-09 05:16:47 +00:00
Do mapping in the wrapper
This commit is contained in:
parent
e922eaa428
commit
85d4cfdeb7
52
Cargo.lock
generated
52
Cargo.lock
generated
@ -129,6 +129,31 @@ dependencies = [
|
|||||||
"static_assertions",
|
"static_assertions",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aster-boot-wrapper"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.4.1",
|
||||||
|
"cfg-if",
|
||||||
|
"linux_boot_params",
|
||||||
|
"log",
|
||||||
|
"uart_16550",
|
||||||
|
"uefi",
|
||||||
|
"uefi-services",
|
||||||
|
"x86_64",
|
||||||
|
"xmas-elf 0.8.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aster-boot-wrapper-builder"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"bytemuck",
|
||||||
|
"serde",
|
||||||
|
"xmas-elf 0.9.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aster-console"
|
name = "aster-console"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -159,6 +184,7 @@ dependencies = [
|
|||||||
"intrusive-collections",
|
"intrusive-collections",
|
||||||
"ktest",
|
"ktest",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
"linux_boot_params",
|
||||||
"log",
|
"log",
|
||||||
"multiboot2",
|
"multiboot2",
|
||||||
"pod",
|
"pod",
|
||||||
@ -173,14 +199,6 @@ dependencies = [
|
|||||||
"x86_64",
|
"x86_64",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aster-frame-x86-boot-linux-setup"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"uart_16550",
|
|
||||||
"xmas-elf",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aster-framebuffer"
|
name = "aster-framebuffer"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -250,10 +268,10 @@ name = "aster-runner"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"aster-boot-wrapper-builder",
|
||||||
"clap",
|
"clap",
|
||||||
"glob",
|
|
||||||
"rand",
|
"rand",
|
||||||
"xmas-elf",
|
"xmas-elf 0.8.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -299,7 +317,7 @@ dependencies = [
|
|||||||
"typeflags-util",
|
"typeflags-util",
|
||||||
"virtio-input-decoder",
|
"virtio-input-decoder",
|
||||||
"vte",
|
"vte",
|
||||||
"xmas-elf",
|
"xmas-elf 0.8.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -353,7 +371,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "asterinas"
|
name = "asterinas"
|
||||||
version = "0.2.2"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aster-frame",
|
"aster-frame",
|
||||||
"aster-framebuffer",
|
"aster-framebuffer",
|
||||||
@ -956,16 +974,6 @@ dependencies = [
|
|||||||
"rle-decode-fast",
|
"rle-decode-fast",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "linux-boot-wrapper-builder"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
"bytemuck",
|
|
||||||
"serde",
|
|
||||||
"xmas-elf 0.9.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux_boot_params"
|
name = "linux_boot_params"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -34,7 +34,6 @@ panic = "unwind"
|
|||||||
members = [
|
members = [
|
||||||
"runner",
|
"runner",
|
||||||
"framework/aster-frame",
|
"framework/aster-frame",
|
||||||
"framework/aster-frame/src/arch/x86/boot/linux_boot/setup",
|
|
||||||
"framework/libs/align_ext",
|
"framework/libs/align_ext",
|
||||||
"framework/libs/boot-wrapper/builder",
|
"framework/libs/boot-wrapper/builder",
|
||||||
"framework/libs/boot-wrapper/linux-boot-params",
|
"framework/libs/boot-wrapper/linux-boot-params",
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
use std::{
|
|
||||||
error::Error,
|
|
||||||
io::Write,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
};
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
let source_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
|
|
||||||
let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap());
|
|
||||||
build_linux_setup_header(&source_dir, &out_dir)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_linux_setup_header(
|
|
||||||
source_dir: &Path,
|
|
||||||
out_dir: &Path,
|
|
||||||
) -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
||||||
// Build the setup header to ELF.
|
|
||||||
let setup_crate_dir = source_dir
|
|
||||||
.join("src")
|
|
||||||
.join("arch")
|
|
||||||
.join("x86")
|
|
||||||
.join("boot")
|
|
||||||
.join("linux_boot")
|
|
||||||
.join("setup");
|
|
||||||
let target_json = setup_crate_dir.join("x86_64-i386_protected_mode.json");
|
|
||||||
|
|
||||||
println!(
|
|
||||||
"cargo:rerun-if-changed={}",
|
|
||||||
setup_crate_dir.to_str().unwrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
let cargo = std::env::var("CARGO").unwrap();
|
|
||||||
let mut cmd = std::process::Command::new(cargo);
|
|
||||||
cmd.arg("install").arg("aster-frame-x86-boot-linux-setup");
|
|
||||||
cmd.arg("--debug");
|
|
||||||
cmd.arg("--locked");
|
|
||||||
cmd.arg("--path").arg(setup_crate_dir.to_str().unwrap());
|
|
||||||
cmd.arg("--target").arg(target_json.as_os_str());
|
|
||||||
cmd.arg("-Zbuild-std=core,compiler_builtins");
|
|
||||||
cmd.arg("-Zbuild-std-features=compiler-builtins-mem");
|
|
||||||
// Specify the installation root.
|
|
||||||
cmd.arg("--root").arg(out_dir.as_os_str());
|
|
||||||
// Specify the build target directory to avoid cargo running
|
|
||||||
// into a deadlock reading the workspace files.
|
|
||||||
cmd.arg("--target-dir").arg(out_dir.as_os_str());
|
|
||||||
cmd.env_remove("RUSTFLAGS");
|
|
||||||
cmd.env_remove("CARGO_ENCODED_RUSTFLAGS");
|
|
||||||
let output = cmd.output()?;
|
|
||||||
if !output.status.success() {
|
|
||||||
std::io::stdout().write_all(&output.stdout).unwrap();
|
|
||||||
std::io::stderr().write_all(&output.stderr).unwrap();
|
|
||||||
return Err(format!(
|
|
||||||
"Failed to build linux x86 setup header:\n\tcommand `{:?}`\n\treturned {}",
|
|
||||||
cmd, output.status
|
|
||||||
)
|
|
||||||
.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
@ -4,12 +4,13 @@
|
|||||||
.section ".boot", "awx"
|
.section ".boot", "awx"
|
||||||
.code32
|
.code32
|
||||||
|
|
||||||
// With the 32-bit entry types we should go through a common paging and machine
|
// With every entry types we could go through common paging or machine
|
||||||
// state setup routine. Thus we make a mark of protocol used in each entrypoint
|
// state setup routines. Thus we make a mark of protocol used in each entrypoint
|
||||||
// on the stack.
|
// on the stack.
|
||||||
ENTRYTYPE_MULTIBOOT = 1
|
ENTRYTYPE_MULTIBOOT = 1
|
||||||
ENTRYTYPE_MULTIBOOT2 = 2
|
ENTRYTYPE_MULTIBOOT2 = 2
|
||||||
ENTRYTYPE_LINUX_32 = 3
|
ENTRYTYPE_LINUX_32 = 3
|
||||||
|
ENTRYTYPE_LINUX_64 = 4
|
||||||
|
|
||||||
MULTIBOOT_ENTRY_MAGIC = 0x2BADB002
|
MULTIBOOT_ENTRY_MAGIC = 0x2BADB002
|
||||||
MULTIBOOT2_ENTRY_MAGIC = 0x36D76289
|
MULTIBOOT2_ENTRY_MAGIC = 0x36D76289
|
||||||
@ -39,14 +40,13 @@ __linux32_boot:
|
|||||||
.org 0x200
|
.org 0x200
|
||||||
.global __linux64_boot_tag
|
.global __linux64_boot_tag
|
||||||
__linux64_boot_tag:
|
__linux64_boot_tag:
|
||||||
// We switch back to 32-bit mode to call the 32-bit entry point.
|
// Set the kernel call stack.
|
||||||
lgdt [boot_gdtr]
|
lea rsp, [boot_stack_top]
|
||||||
mov eax, 0xb002b002 // magic for boot_params
|
push rsi // boot_params ptr from the loader
|
||||||
mov ebx, esi // struct boot_params *
|
push ENTRYTYPE_LINUX_64
|
||||||
sub rsp, 8
|
|
||||||
mov dword ptr [rsp], offset __linux32_boot
|
// Here RSP/RIP are still using low address.
|
||||||
mov dword ptr [rsp + 4], 24
|
jmp long_mode_in_low_address
|
||||||
retf
|
|
||||||
|
|
||||||
// The multiboot & multiboot2 entry point.
|
// The multiboot & multiboot2 entry point.
|
||||||
.code32
|
.code32
|
||||||
@ -274,6 +274,7 @@ gdt_end:
|
|||||||
// The page tables and the stack
|
// The page tables and the stack
|
||||||
.align 4096
|
.align 4096
|
||||||
|
|
||||||
|
.global boot_page_table_start
|
||||||
boot_page_table_start:
|
boot_page_table_start:
|
||||||
boot_pml4:
|
boot_pml4:
|
||||||
.skip 4096
|
.skip 4096
|
||||||
@ -296,6 +297,7 @@ boot_pt_32g:
|
|||||||
.skip 4096 * 512
|
.skip 4096 * 512
|
||||||
boot_page_table_end:
|
boot_page_table_end:
|
||||||
|
|
||||||
|
.global boot_stack_top
|
||||||
boot_stack_bottom:
|
boot_stack_bottom:
|
||||||
.skip 0x40000
|
.skip 0x40000
|
||||||
boot_stack_top:
|
boot_stack_top:
|
||||||
@ -335,21 +337,22 @@ long_mode:
|
|||||||
cmp rax, ENTRYTYPE_MULTIBOOT2
|
cmp rax, ENTRYTYPE_MULTIBOOT2
|
||||||
je entry_type_multiboot2
|
je entry_type_multiboot2
|
||||||
cmp rax, ENTRYTYPE_LINUX_32
|
cmp rax, ENTRYTYPE_LINUX_32
|
||||||
je entry_type_linux_32
|
je entry_type_linux
|
||||||
|
cmp rax, ENTRYTYPE_LINUX_64
|
||||||
|
je entry_type_linux
|
||||||
// Unreachable!
|
// Unreachable!
|
||||||
jmp halt
|
jmp halt
|
||||||
|
|
||||||
.extern __linux64_boot
|
.extern __linux_boot
|
||||||
.extern __multiboot_entry
|
.extern __multiboot_entry
|
||||||
.extern __multiboot2_entry
|
.extern __multiboot2_entry
|
||||||
|
|
||||||
entry_type_linux_32:
|
entry_type_linux:
|
||||||
pop rdi // boot_params ptr
|
pop rdi // boot_params ptr
|
||||||
|
|
||||||
// Clear the frame pointer to stop backtracing here.
|
|
||||||
xor rbp, rbp
|
xor rbp, rbp
|
||||||
|
|
||||||
lea rax, [rip + __linux64_boot] // jump into Rust code
|
lea rax, [rip + __linux_boot] // jump into Rust code
|
||||||
call rax
|
call rax
|
||||||
jmp halt
|
jmp halt
|
||||||
|
|
||||||
@ -357,7 +360,6 @@ entry_type_multiboot:
|
|||||||
pop rsi // the address of multiboot info
|
pop rsi // the address of multiboot info
|
||||||
pop rdi // multiboot magic
|
pop rdi // multiboot magic
|
||||||
|
|
||||||
// Clear the frame pointer to stop backtracing here.
|
|
||||||
xor rbp, rbp
|
xor rbp, rbp
|
||||||
|
|
||||||
lea rax, [rip + __multiboot_entry] // jump into Rust code
|
lea rax, [rip + __multiboot_entry] // jump into Rust code
|
||||||
@ -368,7 +370,6 @@ entry_type_multiboot2:
|
|||||||
pop rsi // the address of multiboot info
|
pop rsi // the address of multiboot info
|
||||||
pop rdi // multiboot magic
|
pop rdi // multiboot magic
|
||||||
|
|
||||||
// Clear the frame pointer to stop backtracing here.
|
|
||||||
xor rbp, rbp
|
xor rbp, rbp
|
||||||
|
|
||||||
lea rax, [rip + __multiboot2_entry] // jump into Rust code
|
lea rax, [rip + __multiboot2_entry] // jump into Rust code
|
||||||
|
@ -138,9 +138,9 @@ fn init_memory_regions(memory_regions: &'static Once<Vec<MemoryRegion>>) {
|
|||||||
memory_regions.call_once(|| non_overlapping_regions_from(regions.as_ref()));
|
memory_regions.call_once(|| non_overlapping_regions_from(regions.as_ref()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The entry point of Rust code called by the Linux 64-bit boot compatible bootloader.
|
/// The entry point of of the Rust code portion of Asterinas.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe extern "sysv64" fn __linux64_boot(params_ptr: *const BootParams) -> ! {
|
unsafe extern "sysv64" fn __linux_boot(params_ptr: *const BootParams) -> ! {
|
||||||
let params = *params_ptr;
|
let params = *params_ptr;
|
||||||
assert_eq!({ params.hdr.header }, LINUX_BOOT_HEADER_MAGIC);
|
assert_eq!({ params.hdr.header }, LINUX_BOOT_HEADER_MAGIC);
|
||||||
BOOT_PARAMS.call_once(|| params);
|
BOOT_PARAMS.call_once(|| params);
|
||||||
|
@ -5,9 +5,7 @@ use spin::Once;
|
|||||||
use crate::{
|
use crate::{
|
||||||
boot::{
|
boot::{
|
||||||
kcmdline::KCmdlineArg,
|
kcmdline::KCmdlineArg,
|
||||||
memory_region::{
|
memory_region::{non_overlapping_regions_from, MemoryRegion, MemoryRegionType},
|
||||||
non_overlapping_regions_from, MemoryRegion, MemoryRegionType,
|
|
||||||
},
|
|
||||||
BootloaderAcpiArg, BootloaderFramebufferArg,
|
BootloaderAcpiArg, BootloaderFramebufferArg,
|
||||||
},
|
},
|
||||||
config::PHYS_OFFSET,
|
config::PHYS_OFFSET,
|
||||||
|
@ -6,9 +6,7 @@ use multiboot2::{BootInformation, BootInformationHeader, MemoryAreaType};
|
|||||||
|
|
||||||
use crate::boot::{
|
use crate::boot::{
|
||||||
kcmdline::KCmdlineArg,
|
kcmdline::KCmdlineArg,
|
||||||
memory_region::{
|
memory_region::{non_overlapping_regions_from, MemoryRegion, MemoryRegionType},
|
||||||
non_overlapping_regions_from, MemoryRegion, MemoryRegionType,
|
|
||||||
},
|
|
||||||
BootloaderAcpiArg, BootloaderFramebufferArg,
|
BootloaderAcpiArg, BootloaderFramebufferArg,
|
||||||
};
|
};
|
||||||
use spin::Once;
|
use spin::Once;
|
||||||
|
@ -18,7 +18,9 @@ pub fn load_elf(file: &[u8]) {
|
|||||||
|
|
||||||
for ph in elf.program_iter() {
|
for ph in elf.program_iter() {
|
||||||
let ProgramHeader::Ph64(program) = ph else {
|
let ProgramHeader::Ph64(program) = ph else {
|
||||||
panic!("[setup] Unexpected program header type! Asterinas should be 64-bit ELF binary.");
|
panic!(
|
||||||
|
"[setup] Unexpected program header type! Asterinas should be 64-bit ELF binary."
|
||||||
|
);
|
||||||
};
|
};
|
||||||
if program.get_type().unwrap() == xmas_elf::program::Type::Load {
|
if program.get_type().unwrap() == xmas_elf::program::Type::Load {
|
||||||
load_segment(&elf, program);
|
load_segment(&elf, program);
|
||||||
|
@ -6,6 +6,8 @@ use uefi::{
|
|||||||
|
|
||||||
use linux_boot_params::BootParams;
|
use linux_boot_params::BootParams;
|
||||||
|
|
||||||
|
use crate::x86::paging::{Ia32eFlags, PageNumber, PageTableCreator};
|
||||||
|
|
||||||
#[export_name = "efi_stub_entry"]
|
#[export_name = "efi_stub_entry"]
|
||||||
extern "sysv64" fn efi_stub_entry(handle: Handle, mut system_table: SystemTable<Boot>) -> ! {
|
extern "sysv64" fn efi_stub_entry(handle: Handle, mut system_table: SystemTable<Boot>) -> ! {
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -100,7 +102,12 @@ fn efi_phase_runtime(
|
|||||||
let e820_table = &mut boot_params.e820_table;
|
let e820_table = &mut boot_params.e820_table;
|
||||||
let mut e820_entries = 0usize;
|
let mut e820_entries = 0usize;
|
||||||
for md in memory_map.entries() {
|
for md in memory_map.entries() {
|
||||||
if e820_entries >= e820_table.len() || e820_entries >= 128 {
|
if e820_entries >= e820_table.len() || e820_entries >= 127 {
|
||||||
|
unsafe {
|
||||||
|
crate::console::print_str(
|
||||||
|
"[EFI stub] Warning: number of E820 entries exceeded 128!\n",
|
||||||
|
);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
e820_table[e820_entries] = linux_boot_params::BootE820Entry {
|
e820_table[e820_entries] = linux_boot_params::BootE820Entry {
|
||||||
@ -120,6 +127,64 @@ fn efi_phase_runtime(
|
|||||||
}
|
}
|
||||||
boot_params.e820_entries = e820_entries as u8;
|
boot_params.e820_entries = e820_entries as u8;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
crate::console::print_str("[EFI stub] Setting up the page table.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make a new linear page table. The linear page table will be stored at
|
||||||
|
// 0x4000000, hoping that the firmware will not use this area.
|
||||||
|
let mut creator = unsafe {
|
||||||
|
PageTableCreator::new(
|
||||||
|
PageNumber::from_addr(0x4000000),
|
||||||
|
PageNumber::from_addr(0x8000000),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
// Map the following regions:
|
||||||
|
// - 0x0: identity map the first 4GiB;
|
||||||
|
// - 0xffff8000_00000000: linear map 4GiB to low 4 GiB;
|
||||||
|
// - 0xffffffff_80000000: linear map 2GiB to low 2 GiB;
|
||||||
|
// - 0xffff8008_00000000: linear map 1GiB to 0x00000008_00000000.
|
||||||
|
let flags = Ia32eFlags::PRESENT | Ia32eFlags::WRITABLE;
|
||||||
|
for i in 0..4 * 1024 * 1024 * 1024 / 4096 {
|
||||||
|
let from_vpn = PageNumber::from_addr(i * 4096);
|
||||||
|
let from_vpn2 = PageNumber::from_addr(i * 4096 + 0xffff8000_00000000);
|
||||||
|
let to_low_pfn = PageNumber::from_addr(i * 4096);
|
||||||
|
creator.map(from_vpn, to_low_pfn, flags);
|
||||||
|
creator.map(from_vpn2, to_low_pfn, flags);
|
||||||
|
}
|
||||||
|
for i in 0..2 * 1024 * 1024 * 1024 / 4096 {
|
||||||
|
let from_vpn = PageNumber::from_addr(i * 4096 + 0xffffffff_80000000);
|
||||||
|
let to_low_pfn = PageNumber::from_addr(i * 4096);
|
||||||
|
creator.map(from_vpn, to_low_pfn, flags);
|
||||||
|
}
|
||||||
|
for i in 0..1024 * 1024 * 1024 / 4096 {
|
||||||
|
let from_vpn = PageNumber::from_addr(i * 4096 + 0xffff8008_00000000);
|
||||||
|
let to_pfn = PageNumber::from_addr(i * 4096 + 0x00000008_00000000);
|
||||||
|
creator.map(from_vpn, to_pfn, flags);
|
||||||
|
}
|
||||||
|
// Mark this as reserved in e820 table.
|
||||||
|
e820_table[e820_entries] = linux_boot_params::BootE820Entry {
|
||||||
|
addr: 0x4000000,
|
||||||
|
size: creator.nr_frames_used() as u64 * 4096,
|
||||||
|
typ: linux_boot_params::E820Type::Reserved,
|
||||||
|
};
|
||||||
|
e820_entries += 1;
|
||||||
|
boot_params.e820_entries = e820_entries as u8;
|
||||||
|
|
||||||
|
#[cfg(feature = "debug_print")]
|
||||||
|
unsafe {
|
||||||
|
crate::console::print_str("[EFI stub] Activating the new page table.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
creator.activate(x86_64::registers::control::Cr3Flags::PAGE_LEVEL_CACHE_DISABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "debug_print")]
|
||||||
|
unsafe {
|
||||||
|
crate::console::print_str("[EFI stub] Page table activated.\n");
|
||||||
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
use crate::console::{print_hex, print_str};
|
use crate::console::{print_hex, print_str};
|
||||||
print_str("[EFI stub] Entering Asterinas entrypoint at ");
|
print_str("[EFI stub] Entering Asterinas entrypoint at ");
|
||||||
@ -127,5 +192,5 @@ fn efi_phase_runtime(
|
|||||||
print_str("\n");
|
print_str("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe { super::call_aster_entrypoint(super::ASTER_ENTRY_POINT, boot_params_ptr as u64) }
|
unsafe { super::call_aster_entrypoint(super::ASTER_ENTRY_POINT as u64, boot_params_ptr as u64) }
|
||||||
}
|
}
|
||||||
|
@ -8,4 +8,5 @@ cfg_if::cfg_if! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod paging;
|
||||||
pub mod relocation;
|
pub mod relocation;
|
||||||
|
198
framework/libs/boot-wrapper/wrapper/src/x86/paging.rs
Normal file
198
framework/libs/boot-wrapper/wrapper/src/x86/paging.rs
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
//! This module provides abstraction over the Intel IA32E paging mechanism. And
|
||||||
|
//! offers method to create linear page tables.
|
||||||
|
//!
|
||||||
|
//! Notebly, the 4-level page table has a paging structure named as follows:
|
||||||
|
//! - Level-4: Page Map Level 4 (PML4), or "the root page table";
|
||||||
|
//! - Level-3: Page Directory Pointer Table (PDPT);
|
||||||
|
//! - Level-2: Page Directory (PD);
|
||||||
|
//! - Level-1: Page Table (PT).
|
||||||
|
//! We sometimes use "level-n" page table to refer to the page table described
|
||||||
|
//! above, avoiding the use of complicated names in the Intel manual.
|
||||||
|
|
||||||
|
use x86_64::structures::paging::PhysFrame;
|
||||||
|
|
||||||
|
const TABLE_ENTRY_COUNT: usize = 512;
|
||||||
|
|
||||||
|
bitflags::bitflags! {
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct Ia32eFlags: u64 {
|
||||||
|
const PRESENT = 1 << 0;
|
||||||
|
const WRITABLE = 1 << 1;
|
||||||
|
const USER = 1 << 2;
|
||||||
|
const WRITE_THROUGH = 1 << 3;
|
||||||
|
const NO_CACHE = 1 << 4;
|
||||||
|
const ACCESSED = 1 << 5;
|
||||||
|
const DIRTY = 1 << 6;
|
||||||
|
const HUGE = 1 << 7;
|
||||||
|
const GLOBAL = 1 << 8;
|
||||||
|
const NO_EXECUTE = 1 << 63;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Ia32eEntry(u64);
|
||||||
|
|
||||||
|
/// The table in the IA32E paging specification that occupies a physical page frame.
|
||||||
|
pub struct Ia32eTable([Ia32eEntry; TABLE_ENTRY_COUNT]);
|
||||||
|
|
||||||
|
/// A page number. It could be either a physical page number or a virtual page number.
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct PageNumber(u64);
|
||||||
|
|
||||||
|
fn is_4k_page_aligned(addr: u64) -> bool {
|
||||||
|
addr & 0xfff == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PageNumber {
|
||||||
|
/// Creates a new page number from the given address.
|
||||||
|
pub fn from_addr(addr: u64) -> Self {
|
||||||
|
assert!(is_4k_page_aligned(addr));
|
||||||
|
Self(addr >> 12)
|
||||||
|
}
|
||||||
|
/// Returns the address of the page.
|
||||||
|
pub fn addr(&self) -> u64 {
|
||||||
|
self.0 << 12
|
||||||
|
}
|
||||||
|
/// Get the physical page frame as slice.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// The caller must ensure that the page number is a physical page number and
|
||||||
|
/// it is identically mapped when running the code.
|
||||||
|
unsafe fn get_page_frame(&self) -> &'static mut [u8] {
|
||||||
|
core::slice::from_raw_parts_mut(self.addr() as *mut u8, 4096)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::ops::Add<usize> for PageNumber {
|
||||||
|
type Output = Self;
|
||||||
|
fn add(self, rhs: usize) -> Self::Output {
|
||||||
|
Self(self.0 + rhs as u64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::ops::AddAssign<usize> for PageNumber {
|
||||||
|
fn add_assign(&mut self, rhs: usize) {
|
||||||
|
self.0 += rhs as u64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::ops::Sub<PageNumber> for PageNumber {
|
||||||
|
type Output = u64;
|
||||||
|
fn sub(self, rhs: PageNumber) -> Self::Output {
|
||||||
|
self.0 - rhs.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A creator for a page table.
|
||||||
|
///
|
||||||
|
/// It allocates page frames from the given physical memory range. And the first
|
||||||
|
/// page frame is always used for the PML4 table (root page table).
|
||||||
|
pub struct PageTableCreator {
|
||||||
|
first_pfn: PageNumber,
|
||||||
|
next_pfn: PageNumber,
|
||||||
|
end_pfn: PageNumber,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fills the given slice with the given value.
|
||||||
|
///
|
||||||
|
/// TODO: use `Slice::fill` instead. But it currently will fail with "invalid opcode".
|
||||||
|
unsafe fn memset(dst: &mut [u8], val: u8) {
|
||||||
|
core::arch::asm!(
|
||||||
|
"rep stosb",
|
||||||
|
inout("rcx") dst.len() => _,
|
||||||
|
inout("rdi") dst.as_mut_ptr() => _,
|
||||||
|
in("al") val,
|
||||||
|
options(nostack),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PageTableCreator {
|
||||||
|
/// Creates a new page table creator.
|
||||||
|
///
|
||||||
|
/// The input physical memory range must be at least 4 page frames. New
|
||||||
|
/// mappings will be written into the given physical memory range.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// The caller must ensure that the given physical memory range is valid.
|
||||||
|
pub unsafe fn new(first_pfn: PageNumber, end_pfn: PageNumber) -> Self {
|
||||||
|
assert!(end_pfn - first_pfn >= 4);
|
||||||
|
// Clear the first page for the PML4 table.
|
||||||
|
memset(first_pfn.get_page_frame(), 0);
|
||||||
|
Self {
|
||||||
|
first_pfn,
|
||||||
|
next_pfn: first_pfn + 1,
|
||||||
|
end_pfn,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn allocate(&mut self) -> PageNumber {
|
||||||
|
assert!(self.next_pfn < self.end_pfn);
|
||||||
|
let pfn = self.next_pfn;
|
||||||
|
self.next_pfn += 1;
|
||||||
|
unsafe {
|
||||||
|
memset(pfn.get_page_frame(), 0);
|
||||||
|
}
|
||||||
|
pfn
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map(&mut self, from: PageNumber, to: PageNumber, flags: Ia32eFlags) {
|
||||||
|
let pml4 = unsafe { &mut *(self.first_pfn.addr() as *mut Ia32eTable) };
|
||||||
|
let pml4e = pml4.index(4, from.addr());
|
||||||
|
if !pml4e.flags().contains(Ia32eFlags::PRESENT) {
|
||||||
|
let pdpt_pfn = self.allocate();
|
||||||
|
pml4e.update(pdpt_pfn.addr(), flags);
|
||||||
|
}
|
||||||
|
let pdpt = unsafe { &mut *(pml4e.paddr() as *mut Ia32eTable) };
|
||||||
|
let pdpte = pdpt.index(3, from.addr());
|
||||||
|
if !pdpte.flags().contains(Ia32eFlags::PRESENT) {
|
||||||
|
let pd_pfn = self.allocate();
|
||||||
|
pdpte.update(pd_pfn.addr(), flags);
|
||||||
|
}
|
||||||
|
let pd = unsafe { &mut *(pdpte.paddr() as *mut Ia32eTable) };
|
||||||
|
let pde = pd.index(2, from.addr());
|
||||||
|
if !pde.flags().contains(Ia32eFlags::PRESENT) {
|
||||||
|
let pt_pfn = self.allocate();
|
||||||
|
pde.update(pt_pfn.addr(), flags);
|
||||||
|
}
|
||||||
|
let pt = unsafe { &mut *(pde.paddr() as *mut Ia32eTable) };
|
||||||
|
let pte = pt.index(1, from.addr());
|
||||||
|
pte.update(to.addr(), flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn nr_frames_used(&self) -> usize {
|
||||||
|
(self.next_pfn - self.first_pfn).try_into().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Activates the created page table.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// The caller must ensure that the page table is valid.
|
||||||
|
pub unsafe fn activate(&self, flags: x86_64::registers::control::Cr3Flags) {
|
||||||
|
x86_64::registers::control::Cr3::write(
|
||||||
|
PhysFrame::from_start_address(x86_64::PhysAddr::new(self.first_pfn.addr())).unwrap(),
|
||||||
|
flags,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ia32eTable {
|
||||||
|
fn index(&mut self, level: usize, va: u64) -> &mut Ia32eEntry {
|
||||||
|
debug_assert!((1..=5).contains(&level));
|
||||||
|
let index = va as usize >> (12 + 9 * (level - 1)) & (TABLE_ENTRY_COUNT - 1);
|
||||||
|
&mut self.0[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ia32eEntry {
|
||||||
|
/// 51:12
|
||||||
|
const PHYS_ADDR_MASK: u64 = 0xF_FFFF_FFFF_F000;
|
||||||
|
|
||||||
|
fn paddr(&self) -> u64 {
|
||||||
|
self.0 & Self::PHYS_ADDR_MASK
|
||||||
|
}
|
||||||
|
fn flags(&self) -> Ia32eFlags {
|
||||||
|
Ia32eFlags::from_bits_truncate(self.0)
|
||||||
|
}
|
||||||
|
fn update(&mut self, paddr: u64, flags: Ia32eFlags) {
|
||||||
|
self.0 = (paddr & Self::PHYS_ADDR_MASK) | flags.bits();
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,3 @@
|
|||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "nightly-2023-12-22"
|
channel = "nightly-2023-12-01"
|
||||||
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
|
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user