Skip to content

Commit

Permalink
Merge branch 'impl'
Browse files Browse the repository at this point in the history
  • Loading branch information
sarahspberrypi committed Jan 4, 2024
2 parents c444c99 + 8b5d2a3 commit 205ffd5
Show file tree
Hide file tree
Showing 12 changed files with 538 additions and 63 deletions.
3 changes: 1 addition & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,6 @@ members = [
exclude = [
"hermit-builtins",
]

[patch.crates-io]
hermit-entry = { git = "https://github.com/sarahspberrypi/hermit-entry.git" }
108 changes: 107 additions & 1 deletion src/arch/x86_64/kernel/acpi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ static SLP_TYPA: OnceCell<u8> = OnceCell::new();

/// The "Root System Description Pointer" structure providing pointers to all other ACPI tables.
#[repr(C, packed)]
#[derive(Debug)]
struct AcpiRsdp {
signature: [u8; 8],
checksum: u8,
Expand Down Expand Up @@ -87,6 +88,9 @@ impl AcpiSdtHeader {
fn signature(&self) -> &str {
str::from_utf8(&self.signature).unwrap()
}
pub fn header_start_address(&self) -> usize {
self as *const _ as usize
}
}

/// A convenience structure to work with an ACPI table.
Expand Down Expand Up @@ -309,6 +313,16 @@ fn detect_rsdp(start_address: PhysAddr, end_address: PhysAddr) -> Result<&'stati
/// Detects ACPI support of the computer system.
/// Returns a reference to the ACPI RSDP within the Ok() if successful or an empty Err() on failure.
fn detect_acpi() -> Result<&'static AcpiRsdp, ()> {
// For UEFI Systems, the tables are already mapped so we only need to return a proper reference to the table
if crate::arch::kernel::is_uefi() {
let rsdp = crate::arch::kernel::get_rsdp_addr();
trace!("rsdp detected successfully at {rsdp:#x?}");
let rsdp = unsafe { &*(rsdp as *const AcpiRsdp) };
if &rsdp.signature != b"RSD PTR " {
panic!("RSDP Address not valid!");
}
return Ok(rsdp);
}
// Get the address of the EBDA.
let frame =
PhysFrame::<BasePageSize>::containing_address(x86_64::PhysAddr::new(EBDA_PTR_LOCATION.0));
Expand Down Expand Up @@ -412,7 +426,17 @@ fn parse_fadt(fadt: AcpiTable<'_>) {
} else {
PhysAddr(fadt_table.dsdt.into())
};
let dsdt = AcpiTable::map(dsdt_address);
let dsdt = if !crate::arch::kernel::is_uefi() {
AcpiTable::map(dsdt_address)
} else {
// For UEFI Systems, the tables are already mapped so we only need to return a proper reference to the table
let table = unsafe { (dsdt_address.0 as *const AcpiSdtHeader).as_ref().unwrap() };
AcpiTable {
header: table,
allocated_virtual_address: VirtAddr(dsdt_address.0),
allocated_length: table.length as usize,
}
};

// Check it.
assert!(
Expand Down Expand Up @@ -527,3 +551,85 @@ pub fn init() {
}
}
}

pub fn init_uefi() {
// Detect the RSDP and get a pointer to either the XSDT (64-bit) or RSDT (32-bit), whichever is available.
// Both are called RSDT in the following.
let rsdp = detect_acpi().expect("Hermit requires an ACPI-compliant system");
let rsdt_physical_address = if rsdp.revision >= 2 {
PhysAddr(rsdp.xsdt_physical_address)
} else {
PhysAddr(rsdp.rsdt_physical_address.into())
};

//Load RSDT
let rsdt = &unsafe { *(rsdt_physical_address.0 as *const AcpiSdtHeader) };
trace!("RSDT: {rsdt:#x?}");

// The RSDT contains pointers to all available ACPI tables.
// Iterate through them.
let mut current_address = rsdt_physical_address.0 as usize + mem::size_of::<AcpiRsdp>();
trace!("RSDT start address at {current_address:#x}");
let nr_entries =
(rsdt.length as usize - mem::size_of::<AcpiRsdp>()) / mem::size_of::<AcpiSdtHeader>();
let end_addr = current_address + nr_entries * mem::size_of::<AcpiSdtHeader>();
while current_address < end_addr {
trace!("current_address: {current_address:#x}");

// Depending on the RSDP revision, either an XSDT or an RSDT has been chosen above.
// The XSDT contains 64-bit pointers whereas the RSDT has 32-bit pointers.
let table_physical_address = if rsdp.revision >= 2 {
let address = PhysAddr(unsafe { ptr::read_unaligned(current_address as *const u64) });
current_address += mem::size_of::<u64>();
address
} else {
let address =
PhysAddr((unsafe { ptr::read_unaligned(current_address as *const u32) }).into());
current_address += mem::size_of::<u32>();
address
};

trace!("table_physical_address: {table_physical_address:#x}");

let table = unsafe {
(table_physical_address.0 as *const AcpiSdtHeader)
.as_ref()
.unwrap()
};

trace!("table: {table:#x?}");

let signature = table.signature();

debug!("Found ACPI table: {signature:#?}");

if signature == "APIC" {
// This is a "Multiple APIC Descriptor Table" (MADT) aka "APIC Table"
// Check and save the entire APIC table for the get_apic_table() call
assert!(
verify_checksum(table.header_start_address(), table.length as usize).is_ok(),
"MADT at {table_physical_address:#x} has invalid checksum"
);
let madt: AcpiTable<'static> = AcpiTable {
header: table,
allocated_virtual_address: VirtAddr(table_physical_address.0),
allocated_length: table.length as usize,
};
MADT.set(madt).unwrap();
trace!("setting MADT successful");
} else if signature == "FACP" {
// This is the "Fixed ACPI Description Table" (FADT) aka "Fixed ACPI Control Pointer" (FACP)
// Check and parse this table for the poweroff() call
assert!(
verify_checksum(table.header_start_address(), table.length as usize).is_ok(),
"FADT at {table_physical_address:#x} has invalid checksum"
);
let fadt: AcpiTable<'static> = AcpiTable {
header: table,
allocated_virtual_address: VirtAddr(table_physical_address.0),
allocated_length: table.length as usize,
};
parse_fadt(fadt);
}
}
}
1 change: 0 additions & 1 deletion src/arch/x86_64/kernel/apic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -723,7 +723,6 @@ pub fn boot_application_processors() {
flags,
);
}

unsafe {
ptr::copy_nonoverlapping(
smp_boot_code.as_ptr(),
Expand Down
31 changes: 29 additions & 2 deletions src/arch/x86_64/kernel/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,33 @@ pub fn get_limit() -> usize {
boot_info().hardware_info.phys_addr_range.end as usize
}

pub fn get_start() -> usize {
boot_info().hardware_info.phys_addr_range.start as usize
}

pub fn is_uefi() -> Result<(), ()> {
match boot_info().platform_info {
PlatformInfo::Uefi { .. } => true,
PlatformInfo::LinuxBootParams { .. } => false,
PlatformInfo::Uhyve { .. } => false,
PlatformInfo::Multiboot { .. } => false,
}
}

pub fn get_rsdp_addr() -> u64 {
match boot_info().platform_info {
PlatformInfo::Uefi { rsdp_addr } => rsdp_addr,
_ => 0,
}
}

pub fn get_mbinfo() -> VirtAddr {
match boot_info().platform_info {
PlatformInfo::Multiboot {
multiboot_info_addr,
..
} => VirtAddr(multiboot_info_addr.get()),
PlatformInfo::Uefi { .. } => VirtAddr(0),
PlatformInfo::LinuxBootParams { .. } => VirtAddr(0),
PlatformInfo::Uhyve { .. } => VirtAddr(0),
}
Expand All @@ -83,6 +104,7 @@ pub fn get_possible_cpus() -> u32 {
use core::cmp;

match boot_info().platform_info {
PlatformInfo::Uefi { .. } => apic::local_apic_id_count(),
PlatformInfo::LinuxBootParams { .. } => apic::local_apic_id_count(),
PlatformInfo::Multiboot { .. } => apic::local_apic_id_count(),
// FIXME: Remove get_processor_count after a transition period for uhyve 0.1.3 adoption
Expand All @@ -106,6 +128,7 @@ pub fn get_processor_count() -> u32 {
pub fn is_uhyve_with_pci() -> bool {
match boot_info().platform_info {
PlatformInfo::Multiboot { .. } => false,
PlatformInfo::Uefi { .. } => false,
PlatformInfo::LinuxBootParams { .. } => false,
PlatformInfo::Uhyve { has_pci, .. } => has_pci,
}
Expand All @@ -115,7 +138,7 @@ pub fn args() -> Option<&'static str> {
match boot_info().platform_info {
PlatformInfo::Multiboot { command_line, .. } => command_line,
PlatformInfo::LinuxBootParams { command_line, .. } => command_line,
PlatformInfo::Uhyve { .. } => None,
PlatformInfo::Uhyve { .. } | PlatformInfo::Uefi { .. } => None,
}
}

Expand Down Expand Up @@ -175,7 +198,11 @@ pub fn boot_processor_init() {
}
if !env::is_uhyve() {
#[cfg(feature = "acpi")]
acpi::init();
if is_uefi() {
acpi::init_uefi();
} else {
acpi::init();
}
}

apic::init();
Expand Down
3 changes: 2 additions & 1 deletion src/arch/x86_64/kernel/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,7 @@ impl CpuFrequency {
fn detect_from_uhyve() -> Result<u16, ()> {
match boot_info().platform_info {
PlatformInfo::Multiboot { .. } => Err(()),
PlatformInfo::Uefi { .. } => Err(()),
PlatformInfo::LinuxBootParams { .. } => Err(()),
PlatformInfo::Uhyve { cpu_freq, .. } => Ok(u16::try_from(
cpu_freq.map(NonZeroU32::get).unwrap_or_default() / 1000,
Expand Down Expand Up @@ -1016,7 +1017,7 @@ pub fn shutdown() -> ! {
Err(()) => {
match boot_info().platform_info {
PlatformInfo::LinuxBootParams { .. } => triple_fault(),
PlatformInfo::Multiboot { .. } => {
PlatformInfo::Multiboot { .. } | PlatformInfo::Uefi { .. } => {
// Try QEMU's debug exit
let exit_handler = qemu_exit::X86::new(0xf4, 3);
exit_handler.exit_success()
Expand Down
7 changes: 7 additions & 0 deletions src/arch/x86_64/kernel/systemtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,13 @@ pub fn init() {
let boot_time = current_time - processor::get_timer_ticks();
OffsetDateTime::from_unix_timestamp_nanos(boot_time as i128 * 1000).unwrap()
}
PlatformInfo::Uefi { .. } => {
// Get the current time in microseconds since the epoch (1970-01-01) from the x86 RTC.
// Subtract the timer ticks to get the actual time when HermitCore-rs was booted.
let current_time = without_interrupts(|| Rtc::new().get_microseconds_since_epoch());
let boot_time = current_time - processor::get_timer_ticks();
OffsetDateTime::from_unix_timestamp_nanos(boot_time as i128 * 1000).unwrap()
}
PlatformInfo::LinuxBootParams { .. } => {
// Get the current time in microseconds since the epoch (1970-01-01) from the x86 RTC.
// Subtract the timer ticks to get the actual time when Hermit was booted.
Expand Down
Loading

0 comments on commit 205ffd5

Please sign in to comment.