Recognize kernel memory regions in the Linux boot path

This commit is contained in:
Zhang Junyang
2023-12-13 16:25:16 +08:00
committed by Tate, Hongliang Tian
parent d4b6eea97d
commit 487e0cdd15
11 changed files with 117 additions and 58 deletions

View File

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

View File

@ -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,

View File

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

View File

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

View File

@ -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}",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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