mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-24 09:53:24 +00:00
Recognize kernel memory regions in the Linux boot path
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
d4b6eea97d
commit
487e0cdd15
14
.github/workflows/integration_test.yml
vendored
14
.github/workflows/integration_test.yml
vendored
@ -24,16 +24,14 @@ jobs:
|
|||||||
id: boot_test_mb2
|
id: boot_test_mb2
|
||||||
run: make run AUTO_TEST=boot ENABLE_KVM=0 BOOT_PROTOCOL=multiboot2 RELEASE_MODE=1
|
run: make run AUTO_TEST=boot ENABLE_KVM=0 BOOT_PROTOCOL=multiboot2 RELEASE_MODE=1
|
||||||
|
|
||||||
# FIXME: Syscall test under Linux Boot Protocol fails at JobControlTest
|
- name: Boot Test (MicroVM)
|
||||||
# We should re-enable syscall tests after fixing the bug.
|
id: boot_test_microvm
|
||||||
|
run: make run AUTO_TEST=boot ENABLE_KVM=0 BOOT_METHOD=microvm RELEASE_MODE=1
|
||||||
|
|
||||||
- name: Boot Test (Linux Boot Protocol)
|
- name: Boot Test (Linux Boot Protocol)
|
||||||
id: boot_test_linux
|
id: boot_test_linux
|
||||||
run: make run AUTO_TEST=boot ENABLE_KVM=0 BOOT_PROTOCOL=linux RELEASE_MODE=1
|
run: make run AUTO_TEST=boot ENABLE_KVM=0 BOOT_PROTOCOL=linux RELEASE_MODE=1
|
||||||
|
|
||||||
- name: Regression Test (Multiboot2)
|
|
||||||
id: regression_test_linux
|
|
||||||
run: make run AUTO_TEST=regression ENABLE_KVM=0 BOOT_PROTOCOL=multiboot2 RELEASE_MODE=1
|
|
||||||
|
|
||||||
- name: Syscall Test (MicroVM)
|
- name: Syscall Test (MicroVM)
|
||||||
id: syscall_test_microvm
|
id: syscall_test_microvm
|
||||||
run: make run AUTO_TEST=syscall ENABLE_KVM=0 BOOT_METHOD=microvm RELEASE_MODE=1
|
run: make run AUTO_TEST=syscall ENABLE_KVM=0 BOOT_METHOD=microvm RELEASE_MODE=1
|
||||||
@ -45,3 +43,7 @@ jobs:
|
|||||||
- name: Syscall Test at Ext2 (MicroVM)
|
- name: Syscall Test at Ext2 (MicroVM)
|
||||||
id: syscall_test_at_ext2_microvm
|
id: syscall_test_at_ext2_microvm
|
||||||
run: make run AUTO_TEST=syscall SYSCALL_TEST_DIR=/ext2 ENABLE_KVM=0 BOOT_METHOD=microvm RELEASE_MODE=1
|
run: make run AUTO_TEST=syscall SYSCALL_TEST_DIR=/ext2 ENABLE_KVM=0 BOOT_METHOD=microvm RELEASE_MODE=1
|
||||||
|
|
||||||
|
- name: Regression Test (Linux Boot Protocol)
|
||||||
|
id: regression_test_linux
|
||||||
|
run: make run AUTO_TEST=regression ENABLE_KVM=0 BOOT_PROTOCOL=linux RELEASE_MODE=1
|
||||||
|
@ -5,7 +5,9 @@ use spin::Once;
|
|||||||
use crate::{
|
use crate::{
|
||||||
boot::{
|
boot::{
|
||||||
kcmdline::KCmdlineArg,
|
kcmdline::KCmdlineArg,
|
||||||
memory_region::{non_overlapping_regions_from, MemoryRegion, MemoryRegionType},
|
memory_region::{
|
||||||
|
non_overlapping_regions_from, MemoryRegion, MemoryRegionType,
|
||||||
|
},
|
||||||
BootloaderAcpiArg, BootloaderFramebufferArg,
|
BootloaderAcpiArg, BootloaderFramebufferArg,
|
||||||
},
|
},
|
||||||
config::PHYS_OFFSET,
|
config::PHYS_OFFSET,
|
||||||
|
@ -6,7 +6,9 @@ use multiboot2::{BootInformation, BootInformationHeader, MemoryAreaType};
|
|||||||
|
|
||||||
use crate::boot::{
|
use crate::boot::{
|
||||||
kcmdline::KCmdlineArg,
|
kcmdline::KCmdlineArg,
|
||||||
memory_region::{non_overlapping_regions_from, MemoryRegion, MemoryRegionType},
|
memory_region::{
|
||||||
|
non_overlapping_regions_from, MemoryRegion, MemoryRegionType,
|
||||||
|
},
|
||||||
BootloaderAcpiArg, BootloaderFramebufferArg,
|
BootloaderAcpiArg, BootloaderFramebufferArg,
|
||||||
};
|
};
|
||||||
use spin::Once;
|
use spin::Once;
|
||||||
|
@ -56,7 +56,7 @@ fn init_tsc_mode() {
|
|||||||
fn determine_tsc_freq_via_pit() -> u64 {
|
fn determine_tsc_freq_via_pit() -> u64 {
|
||||||
let mut irq = IrqLine::alloc_specific(super::TIMER_IRQ_NUM.load(Ordering::Relaxed)).unwrap();
|
let mut irq = IrqLine::alloc_specific(super::TIMER_IRQ_NUM.load(Ordering::Relaxed)).unwrap();
|
||||||
irq.on_active(pit_callback);
|
irq.on_active(pit_callback);
|
||||||
let mut io_apic = IO_APIC.get().unwrap().get(0).unwrap().lock();
|
let mut io_apic = IO_APIC.get().unwrap().first().unwrap().lock();
|
||||||
debug_assert_eq!(io_apic.interrupt_base(), 0);
|
debug_assert_eq!(io_apic.interrupt_base(), 0);
|
||||||
io_apic.enable(2, irq.clone()).unwrap();
|
io_apic.enable(2, irq.clone()).unwrap();
|
||||||
drop(io_apic);
|
drop(io_apic);
|
||||||
@ -87,7 +87,7 @@ fn determine_tsc_freq_via_pit() -> u64 {
|
|||||||
IN_TIME += 1;
|
IN_TIME += 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mut io_apic = IO_APIC.get().unwrap().get(0).unwrap().lock();
|
let mut io_apic = IO_APIC.get().unwrap().first().unwrap().lock();
|
||||||
io_apic.disable(2).unwrap();
|
io_apic.disable(2).unwrap();
|
||||||
drop(io_apic);
|
drop(io_apic);
|
||||||
let tsc_count = _rdtsc();
|
let tsc_count = _rdtsc();
|
||||||
|
@ -84,9 +84,12 @@ pub(crate) fn init(regions: &[MemoryRegion]) {
|
|||||||
let mut allocator = FrameAllocator::<32>::new();
|
let mut allocator = FrameAllocator::<32>::new();
|
||||||
for region in regions.iter() {
|
for region in regions.iter() {
|
||||||
if region.typ() == MemoryRegionType::Usable {
|
if region.typ() == MemoryRegionType::Usable {
|
||||||
// Make the memory region page-aligned
|
// Make the memory region page-aligned, and skip if it is too small.
|
||||||
let start = region.base().align_up(PAGE_SIZE) / PAGE_SIZE;
|
let start = region.base().align_up(PAGE_SIZE) / PAGE_SIZE;
|
||||||
let end = (region.base() + region.len()).align_down(PAGE_SIZE) / PAGE_SIZE;
|
let end = (region.base() + region.len()).align_down(PAGE_SIZE) / PAGE_SIZE;
|
||||||
|
if end <= start {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
allocator.add_frame(start, end);
|
allocator.add_frame(start, end);
|
||||||
info!(
|
info!(
|
||||||
"Found usable region, start:{:x}, end:{:x}",
|
"Found usable region, start:{:x}, end:{:x}",
|
||||||
|
@ -12,6 +12,7 @@ unsafe fn memcpy(dst: *mut u8, src: *const u8, size: usize) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Load the kernel ELF payload to memory.
|
||||||
pub fn load_elf(file: &[u8]) {
|
pub fn load_elf(file: &[u8]) {
|
||||||
let elf = xmas_elf::ElfFile::new(file).unwrap();
|
let elf = xmas_elf::ElfFile::new(file).unwrap();
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ extern "sysv64" fn efi_handover_entry(
|
|||||||
fn efi_phase_boot(
|
fn efi_phase_boot(
|
||||||
handle: Handle,
|
handle: Handle,
|
||||||
system_table: SystemTable<Boot>,
|
system_table: SystemTable<Boot>,
|
||||||
boot_params: *mut BootParams,
|
boot_params_ptr: *mut BootParams,
|
||||||
) -> ! {
|
) -> ! {
|
||||||
// Safety: this init function is only called once.
|
// Safety: this init function is only called once.
|
||||||
unsafe { crate::console::init() };
|
unsafe { crate::console::init() };
|
||||||
@ -50,7 +50,7 @@ fn efi_phase_boot(
|
|||||||
uefi_services::println!("[EFI stub] Relocations applied.");
|
uefi_services::println!("[EFI stub] Relocations applied.");
|
||||||
|
|
||||||
uefi_services::println!("[EFI stub] Loading payload.");
|
uefi_services::println!("[EFI stub] Loading payload.");
|
||||||
let payload = unsafe { crate::get_payload(&*boot_params) };
|
let payload = unsafe { crate::get_payload(&*boot_params_ptr) };
|
||||||
crate::loader::load_elf(payload);
|
crate::loader::load_elf(payload);
|
||||||
|
|
||||||
uefi_services::println!("[EFI stub] Exiting EFI boot services.");
|
uefi_services::println!("[EFI stub] Exiting EFI boot services.");
|
||||||
@ -63,7 +63,7 @@ fn efi_phase_boot(
|
|||||||
};
|
};
|
||||||
let (system_table, memory_map) = system_table.exit_boot_services(memory_type);
|
let (system_table, memory_map) = system_table.exit_boot_services(memory_type);
|
||||||
|
|
||||||
efi_phase_runtime(system_table, memory_map, boot_params);
|
efi_phase_runtime(system_table, memory_map, boot_params_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn efi_phase_runtime(
|
fn efi_phase_runtime(
|
||||||
@ -75,36 +75,10 @@ fn efi_phase_runtime(
|
|||||||
crate::console::print_str("[EFI stub] Entered runtime services.\n");
|
crate::console::print_str("[EFI stub] Entered runtime services.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
let boot_params = unsafe { &mut *boot_params_ptr };
|
|
||||||
|
|
||||||
// Write memory map to e820 table in boot_params.
|
|
||||||
let e820_table = &mut boot_params.e820_table;
|
|
||||||
let mut e820_entries = 0;
|
|
||||||
for md in memory_map.entries() {
|
|
||||||
if e820_entries >= e820_table.len() || e820_entries >= 128 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
e820_table[e820_entries] = linux_boot_params::BootE820Entry {
|
|
||||||
addr: md.phys_start as u64,
|
|
||||||
size: md.page_count as u64 * 4096,
|
|
||||||
typ: match md.ty {
|
|
||||||
uefi::table::boot::MemoryType::CONVENTIONAL => linux_boot_params::E820Type::Ram,
|
|
||||||
uefi::table::boot::MemoryType::RESERVED => linux_boot_params::E820Type::Reserved,
|
|
||||||
uefi::table::boot::MemoryType::ACPI_RECLAIM => linux_boot_params::E820Type::Acpi,
|
|
||||||
uefi::table::boot::MemoryType::ACPI_NON_VOLATILE => {
|
|
||||||
linux_boot_params::E820Type::Nvs
|
|
||||||
}
|
|
||||||
_ => linux_boot_params::E820Type::Reserved,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
e820_entries += 1;
|
|
||||||
}
|
|
||||||
boot_params.e820_entries = e820_entries as u8;
|
|
||||||
|
|
||||||
#[cfg(feature = "debug_print")]
|
#[cfg(feature = "debug_print")]
|
||||||
unsafe {
|
unsafe {
|
||||||
use crate::console::{print_hex, print_str};
|
use crate::console::{print_hex, print_str};
|
||||||
print_str("[EFI stub debug] Memory map:\n");
|
print_str("[EFI stub debug] EFI Memory map:\n");
|
||||||
for md in memory_map.entries() {
|
for md in memory_map.entries() {
|
||||||
// crate::println!(" [{:#x}] {:#x} ({:#x})", md.ty.0, md.phys_start, md.page_count);
|
// crate::println!(" [{:#x}] {:#x} ({:#x})", md.ty.0, md.phys_start, md.page_count);
|
||||||
print_str(" [");
|
print_str(" [");
|
||||||
@ -120,6 +94,32 @@ fn efi_phase_runtime(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let boot_params = unsafe { &mut *boot_params_ptr };
|
||||||
|
|
||||||
|
// Write memory map to e820 table in boot_params.
|
||||||
|
let e820_table = &mut boot_params.e820_table;
|
||||||
|
let mut e820_entries = 0usize;
|
||||||
|
for md in memory_map.entries() {
|
||||||
|
if e820_entries >= e820_table.len() || e820_entries >= 128 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
e820_table[e820_entries] = linux_boot_params::BootE820Entry {
|
||||||
|
addr: md.phys_start as u64,
|
||||||
|
size: md.page_count as u64 * 4096,
|
||||||
|
typ: match md.ty {
|
||||||
|
uefi::table::boot::MemoryType::CONVENTIONAL => linux_boot_params::E820Type::Ram,
|
||||||
|
uefi::table::boot::MemoryType::RESERVED => linux_boot_params::E820Type::Reserved,
|
||||||
|
uefi::table::boot::MemoryType::ACPI_RECLAIM => linux_boot_params::E820Type::Acpi,
|
||||||
|
uefi::table::boot::MemoryType::ACPI_NON_VOLATILE => {
|
||||||
|
linux_boot_params::E820Type::Nvs
|
||||||
|
}
|
||||||
|
_ => linux_boot_params::E820Type::Unusable,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
e820_entries += 1;
|
||||||
|
}
|
||||||
|
boot_params.e820_entries = e820_entries as u8;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
use crate::console::{print_hex, print_str};
|
use crate::console::{print_hex, print_str};
|
||||||
print_str("[EFI stub] Entering Jinux entrypoint at ");
|
print_str("[EFI stub] Entering Jinux entrypoint at ");
|
||||||
|
@ -158,16 +158,37 @@ impl Credentials_ {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ruid) = ruid && *ruid != self.ruid() && *ruid != self.euid() && (!ruid_may_be_old_suid || *ruid != self.suid()) {
|
if let Some(ruid) = ruid
|
||||||
return_errno_with_message!(Errno::EPERM, "ruid can only be one of old ruid, old euid (and old suid).");
|
&& *ruid != self.ruid()
|
||||||
|
&& *ruid != self.euid()
|
||||||
|
&& (!ruid_may_be_old_suid || *ruid != self.suid())
|
||||||
|
{
|
||||||
|
return_errno_with_message!(
|
||||||
|
Errno::EPERM,
|
||||||
|
"ruid can only be one of old ruid, old euid (and old suid)."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(euid) = euid && *euid != self.ruid() && *euid != self.euid() && *euid != self.suid() {
|
if let Some(euid) = euid
|
||||||
return_errno_with_message!(Errno::EPERM, "euid can only be one of old ruid, old euid and old suid.")
|
&& *euid != self.ruid()
|
||||||
|
&& *euid != self.euid()
|
||||||
|
&& *euid != self.suid()
|
||||||
|
{
|
||||||
|
return_errno_with_message!(
|
||||||
|
Errno::EPERM,
|
||||||
|
"euid can only be one of old ruid, old euid and old suid."
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(suid) = suid && *suid != self.ruid() && *suid != self.euid() && *suid != self.suid() {
|
if let Some(suid) = suid
|
||||||
return_errno_with_message!(Errno::EPERM, "suid can only be one of old ruid, old euid and old suid.")
|
&& *suid != self.ruid()
|
||||||
|
&& *suid != self.euid()
|
||||||
|
&& *suid != self.suid()
|
||||||
|
{
|
||||||
|
return_errno_with_message!(
|
||||||
|
Errno::EPERM,
|
||||||
|
"suid can only be one of old ruid, old euid and old suid."
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -291,16 +312,37 @@ impl Credentials_ {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(rgid) = rgid && *rgid != self.rgid() && *rgid != self.egid() && (!rgid_may_be_old_sgid || *rgid != self.sgid()) {
|
if let Some(rgid) = rgid
|
||||||
return_errno_with_message!(Errno::EPERM, "rgid can only be one of old rgid, old egid (and old sgid).");
|
&& *rgid != self.rgid()
|
||||||
|
&& *rgid != self.egid()
|
||||||
|
&& (!rgid_may_be_old_sgid || *rgid != self.sgid())
|
||||||
|
{
|
||||||
|
return_errno_with_message!(
|
||||||
|
Errno::EPERM,
|
||||||
|
"rgid can only be one of old rgid, old egid (and old sgid)."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(egid) = egid && *egid != self.rgid() && *egid != self.egid() && *egid != self.sgid() {
|
if let Some(egid) = egid
|
||||||
return_errno_with_message!(Errno::EPERM, "egid can only be one of old rgid, old egid and old sgid.")
|
&& *egid != self.rgid()
|
||||||
|
&& *egid != self.egid()
|
||||||
|
&& *egid != self.sgid()
|
||||||
|
{
|
||||||
|
return_errno_with_message!(
|
||||||
|
Errno::EPERM,
|
||||||
|
"egid can only be one of old rgid, old egid and old sgid."
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(sgid) = sgid && *sgid != self.rgid() && *sgid != self.egid() && *sgid != self.sgid() {
|
if let Some(sgid) = sgid
|
||||||
return_errno_with_message!(Errno::EPERM, "sgid can only be one of old rgid, old egid and old sgid.")
|
&& *sgid != self.rgid()
|
||||||
|
&& *sgid != self.egid()
|
||||||
|
&& *sgid != self.sgid()
|
||||||
|
{
|
||||||
|
return_errno_with_message!(
|
||||||
|
Errno::EPERM,
|
||||||
|
"sgid can only be one of old rgid, old egid and old sgid."
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -101,12 +101,17 @@ impl PosixThread {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(signum) = signum && *signum == SIGCONT {
|
if let Some(signum) = signum
|
||||||
|
&& *signum == SIGCONT
|
||||||
|
{
|
||||||
let receiver_sid = self.process().session().unwrap().sid();
|
let receiver_sid = self.process().session().unwrap().sid();
|
||||||
if receiver_sid == sender.sid() {
|
if receiver_sid == sender.sid() {
|
||||||
return Ok(())
|
return Ok(());
|
||||||
} else {
|
} else {
|
||||||
return_errno_with_message!(Errno::EPERM, "sigcont requires that sender and receiver belongs to the same session");
|
return_errno_with_message!(
|
||||||
|
Errno::EPERM,
|
||||||
|
"sigcont requires that sender and receiver belongs to the same session"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ pub mod signals;
|
|||||||
pub use events::{SigEvents, SigEventsFilter};
|
pub use events::{SigEvents, SigEventsFilter};
|
||||||
pub use pauser::Pauser;
|
pub use pauser::Pauser;
|
||||||
pub use poll::{Pollee, Poller};
|
pub use poll::{Pollee, Poller};
|
||||||
pub use sig_stack::{SigStack, SigStackFlags, SigStackStatus};
|
pub use sig_stack::{SigStack, SigStackFlags};
|
||||||
|
|
||||||
use align_ext::AlignExt;
|
use align_ext::AlignExt;
|
||||||
use aster_frame::cpu::UserContext;
|
use aster_frame::cpu::UserContext;
|
||||||
|
@ -49,7 +49,9 @@ fn set_new_stack(sig_stack_addr: Vaddr, old_stack: Option<&SigStack>) -> Result<
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(old_stack) = old_stack && old_stack.is_active() {
|
if let Some(old_stack) = old_stack
|
||||||
|
&& old_stack.is_active()
|
||||||
|
{
|
||||||
return_errno_with_message!(Errno::EPERM, "the old stack is active now");
|
return_errno_with_message!(Errno::EPERM, "the old stack is active now");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user