2024-01-03 03:22:36 +00:00
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
|
|
2024-05-23 08:55:39 +00:00
|
|
|
|
//! Platform-specific code for the x86 platform.
|
|
|
|
|
|
|
2023-07-19 02:08:59 +00:00
|
|
|
|
pub mod boot;
|
2023-03-25 09:27:09 +00:00
|
|
|
|
pub(crate) mod cpu;
|
|
|
|
|
|
pub mod device;
|
2024-06-27 13:09:44 +00:00
|
|
|
|
pub(crate) mod ex_table;
|
2023-07-05 13:35:07 +00:00
|
|
|
|
pub mod iommu;
|
2023-04-02 05:32:03 +00:00
|
|
|
|
pub(crate) mod irq;
|
2023-09-08 04:06:27 +00:00
|
|
|
|
pub(crate) mod kernel;
|
2023-03-25 09:27:09 +00:00
|
|
|
|
pub(crate) mod mm;
|
2023-08-10 08:23:02 +00:00
|
|
|
|
pub(crate) mod pci;
|
2023-11-04 16:14:28 +00:00
|
|
|
|
pub mod qemu;
|
2024-06-29 11:54:01 +00:00
|
|
|
|
pub mod serial;
|
2024-05-23 18:58:43 +00:00
|
|
|
|
pub mod task;
|
2023-09-05 06:26:01 +00:00
|
|
|
|
#[cfg(feature = "intel_tdx")]
|
|
|
|
|
|
pub(crate) mod tdx_guest;
|
2024-05-16 07:45:44 +00:00
|
|
|
|
pub mod timer;
|
2024-05-23 19:31:21 +00:00
|
|
|
|
pub mod trap;
|
2023-03-25 09:27:09 +00:00
|
|
|
|
|
2024-07-02 02:12:06 +00:00
|
|
|
|
use core::{
|
|
|
|
|
|
arch::x86_64::{_rdrand64_step, _rdtsc},
|
|
|
|
|
|
sync::atomic::Ordering,
|
|
|
|
|
|
};
|
2023-12-06 07:03:42 +00:00
|
|
|
|
|
2023-06-27 11:56:16 +00:00
|
|
|
|
use kernel::apic::ioapic;
|
2023-07-05 13:35:07 +00:00
|
|
|
|
use log::{info, warn};
|
2024-07-11 09:18:59 +00:00
|
|
|
|
#[cfg(feature = "intel_tdx")]
|
|
|
|
|
|
use {
|
|
|
|
|
|
crate::early_println,
|
|
|
|
|
|
::tdx_guest::{init_tdx, tdcall::InitError, tdx_is_enabled},
|
|
|
|
|
|
};
|
2023-03-25 09:27:09 +00:00
|
|
|
|
|
|
|
|
|
|
pub(crate) fn before_all_init() {
|
|
|
|
|
|
enable_common_cpu_features();
|
2024-06-29 11:54:01 +00:00
|
|
|
|
serial::init();
|
2024-07-11 09:18:59 +00:00
|
|
|
|
#[cfg(feature = "intel_tdx")]
|
|
|
|
|
|
match init_tdx() {
|
|
|
|
|
|
Ok(td_info) => {
|
|
|
|
|
|
early_println!(
|
|
|
|
|
|
"Intel TDX initialized\ntd gpaw: {}, td attributes: {:?}",
|
|
|
|
|
|
td_info.gpaw,
|
|
|
|
|
|
td_info.attributes
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
Err(InitError::TdxGetVpInfoError(td_call_error)) => {
|
|
|
|
|
|
panic!(
|
|
|
|
|
|
"Intel TDX not initialized, Failed to get TD info: {:?}",
|
|
|
|
|
|
td_call_error
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
// The machine has no TDX support.
|
|
|
|
|
|
Err(_) => {}
|
|
|
|
|
|
}
|
2023-03-25 09:27:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub(crate) fn after_all_init() {
|
2023-04-02 05:41:46 +00:00
|
|
|
|
irq::init();
|
2023-03-25 09:27:09 +00:00
|
|
|
|
kernel::acpi::init();
|
2023-06-27 11:56:16 +00:00
|
|
|
|
match kernel::apic::init() {
|
|
|
|
|
|
Ok(_) => {
|
|
|
|
|
|
ioapic::init();
|
|
|
|
|
|
}
|
|
|
|
|
|
Err(err) => {
|
|
|
|
|
|
info!("APIC init error:{:?}", err);
|
|
|
|
|
|
kernel::pic::enable();
|
|
|
|
|
|
}
|
2023-03-25 09:27:09 +00:00
|
|
|
|
}
|
2024-06-29 11:54:01 +00:00
|
|
|
|
serial::callback_init();
|
2023-07-30 14:25:26 +00:00
|
|
|
|
timer::init();
|
2024-03-11 06:02:42 +00:00
|
|
|
|
#[cfg(feature = "intel_tdx")]
|
|
|
|
|
|
if !tdx_is_enabled() {
|
|
|
|
|
|
match iommu::init() {
|
|
|
|
|
|
Ok(_) => {}
|
|
|
|
|
|
Err(err) => warn!("IOMMU initialization error:{:?}", err),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
#[cfg(not(feature = "intel_tdx"))]
|
2023-07-05 13:35:07 +00:00
|
|
|
|
match iommu::init() {
|
|
|
|
|
|
Ok(_) => {}
|
|
|
|
|
|
Err(err) => warn!("IOMMU initialization error:{:?}", err),
|
|
|
|
|
|
}
|
2023-03-25 09:27:09 +00:00
|
|
|
|
// Some driver like serial may use PIC
|
|
|
|
|
|
kernel::pic::init();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub(crate) fn interrupts_ack() {
|
|
|
|
|
|
kernel::pic::ack();
|
2023-06-27 11:56:16 +00:00
|
|
|
|
if let Some(apic) = kernel::apic::APIC_INSTANCE.get() {
|
2024-04-26 02:18:48 +00:00
|
|
|
|
apic.lock_irq_disabled().eoi();
|
2023-06-27 11:56:16 +00:00
|
|
|
|
}
|
2023-03-25 09:27:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-05-30 11:25:58 +00:00
|
|
|
|
/// Returns the frequency of TSC. The unit is Hz.
|
2023-12-06 07:03:42 +00:00
|
|
|
|
pub fn tsc_freq() -> u64 {
|
|
|
|
|
|
kernel::tsc::TSC_FREQ.load(Ordering::Acquire)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Reads the current value of the processor’s time-stamp counter (TSC).
|
|
|
|
|
|
pub fn read_tsc() -> u64 {
|
2024-05-21 12:07:26 +00:00
|
|
|
|
// SAFETY: It is safe to read a time-related counter.
|
2023-12-06 07:03:42 +00:00
|
|
|
|
unsafe { _rdtsc() }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-07-02 02:12:06 +00:00
|
|
|
|
/// Reads a hardware generated 64-bit random value.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// Returns None if no random value was generated.
|
|
|
|
|
|
pub fn read_random() -> Option<u64> {
|
|
|
|
|
|
// Recommendation from "Intel® Digital Random Number Generator (DRNG) Software
|
|
|
|
|
|
// Implementation Guide" - Section 5.2.1 and "Intel® 64 and IA-32 Architectures
|
|
|
|
|
|
// Software Developer’s Manual" - Volume 1 - Section 7.3.17.1.
|
|
|
|
|
|
const RETRY_LIMIT: usize = 10;
|
|
|
|
|
|
|
|
|
|
|
|
for _ in 0..RETRY_LIMIT {
|
|
|
|
|
|
let mut val = 0;
|
|
|
|
|
|
let generated = unsafe { _rdrand64_step(&mut val) };
|
|
|
|
|
|
if generated == 1 {
|
|
|
|
|
|
return Some(val);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
None
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-07-16 16:15:54 +00:00
|
|
|
|
fn has_avx512() -> bool {
|
|
|
|
|
|
use core::arch::x86_64::{__cpuid, __cpuid_count};
|
|
|
|
|
|
|
|
|
|
|
|
let cpuid_result = unsafe { __cpuid(0) };
|
|
|
|
|
|
if cpuid_result.eax < 7 {
|
|
|
|
|
|
// CPUID function 7 is not supported
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let cpuid_result = unsafe { __cpuid_count(7, 0) };
|
|
|
|
|
|
// Check for AVX-512 Foundation (bit 16 of ebx)
|
|
|
|
|
|
cpuid_result.ebx & (1 << 16) != 0
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-03-25 09:27:09 +00:00
|
|
|
|
fn enable_common_cpu_features() {
|
|
|
|
|
|
use x86_64::registers::{control::Cr4Flags, model_specific::EferFlags, xcontrol::XCr0Flags};
|
|
|
|
|
|
let mut cr4 = x86_64::registers::control::Cr4::read();
|
2024-05-05 14:02:43 +00:00
|
|
|
|
cr4 |= Cr4Flags::FSGSBASE
|
|
|
|
|
|
| Cr4Flags::OSXSAVE
|
|
|
|
|
|
| Cr4Flags::OSFXSR
|
|
|
|
|
|
| Cr4Flags::OSXMMEXCPT_ENABLE
|
|
|
|
|
|
| Cr4Flags::PAGE_GLOBAL;
|
2023-03-25 09:27:09 +00:00
|
|
|
|
unsafe {
|
|
|
|
|
|
x86_64::registers::control::Cr4::write(cr4);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let mut xcr0 = x86_64::registers::xcontrol::XCr0::read();
|
2024-07-16 16:15:54 +00:00
|
|
|
|
xcr0 |= XCr0Flags::AVX | XCr0Flags::SSE;
|
|
|
|
|
|
|
|
|
|
|
|
if has_avx512() {
|
|
|
|
|
|
// TODO: Ensure proper saving and restoring of floating-point states
|
|
|
|
|
|
// to correctly support advanced instructions like AVX-512.
|
|
|
|
|
|
xcr0 |= XCr0Flags::OPMASK | XCr0Flags::ZMM_HI256 | XCr0Flags::HI16_ZMM;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-03-25 09:27:09 +00:00
|
|
|
|
unsafe {
|
|
|
|
|
|
x86_64::registers::xcontrol::XCr0::write(xcr0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
|
|
// enable non-executable page protection
|
|
|
|
|
|
x86_64::registers::model_specific::Efer::update(|efer| {
|
|
|
|
|
|
*efer |= EferFlags::NO_EXECUTE_ENABLE;
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|