pub mod boot;
pub(crate) mod cpu;
pub mod device;
pub(crate) mod ex_table;
pub(crate) mod io;
pub(crate) mod iommu;
pub(crate) mod irq;
pub mod kernel;
pub(crate) mod mm;
pub(crate) mod pci;
pub mod qemu;
pub(crate) mod serial;
pub(crate) mod task;
pub mod timer;
pub mod trap;
use io::construct_io_mem_allocator_builder;
use spin::Once;
use x86::cpuid::{CpuId, FeatureInfo};
#[cfg(feature = "cvm_guest")]
pub(crate) mod tdx_guest;
use core::sync::atomic::Ordering;
use log::warn;
use safety::safety;
#[cfg(feature = "cvm_guest")]
pub(crate) fn init_cvm_guest() {
match ::tdx_guest::init_tdx() {
Ok(td_info) => {
crate::early_println!(
"[kernel] Intel TDX initialized\n[kernel] td gpaw: {}, td attributes: {:?}",
td_info.gpaw,
td_info.attributes
);
}
Err(::tdx_guest::tdcall::InitError::TdxGetVpInfoError(td_call_error)) => {
panic!(
"[kernel] Intel TDX not initialized, Failed to get TD info: {:?}",
td_call_error
);
}
Err(_) => {}
}
}
static CPU_FEATURES: Once<FeatureInfo> = Once::new();
#[safety {
CallOnce(system),
Context("boot starts", "boot ends")
}]
pub(crate) unsafe fn late_init_on_bsp() {
unsafe { trap::init() };
let io_mem_builder = construct_io_mem_allocator_builder();
kernel::apic::init(&io_mem_builder).expect("APIC doesn't exist");
kernel::irq::init(&io_mem_builder);
kernel::tsc::init_tsc_freq();
timer::init_bsp();
unsafe { crate::boot::smp::boot_all_aps() };
if_tdx_enabled!({
} else {
match iommu::init(&io_mem_builder) {
Ok(_) => {}
Err(err) => warn!("IOMMU initialization error:{:?}", err),
}
});
unsafe { crate::io::init(io_mem_builder) };
}
#[safety {
CallOnce("application processor"),
PostToFunc("[`init_on_bsp`]")
}]
pub(crate) unsafe fn init_on_ap() {
timer::init_ap();
}
pub(crate) fn interrupts_ack(irq_number: usize) {
if !cpu::context::CpuException::is_cpu_exception(irq_number as u16) {
kernel::apic::get_or_init(&crate::task::disable_preempt() as _).eoi();
}
}
pub fn tsc_freq() -> u64 {
kernel::tsc::TSC_FREQ.load(Ordering::Acquire)
}
pub fn read_tsc() -> u64 {
use core::arch::x86_64::_rdtsc;
unsafe { _rdtsc() }
}
pub fn read_random() -> Option<u64> {
use core::arch::x86_64::_rdrand64_step;
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
}
fn has_avx() -> bool {
use core::arch::x86_64::{__cpuid, __cpuid_count};
let cpuid_result = unsafe { __cpuid(0) };
if cpuid_result.eax < 1 {
return false;
}
let cpuid_result = unsafe { __cpuid_count(1, 0) };
cpuid_result.ecx & (1 << 28) != 0
}
fn has_avx512() -> bool {
use core::arch::x86_64::{__cpuid, __cpuid_count};
let cpuid_result = unsafe { __cpuid(0) };
if cpuid_result.eax < 7 {
return false;
}
let cpuid_result = unsafe { __cpuid_count(7, 0) };
cpuid_result.ebx & (1 << 16) != 0
}
pub(crate) fn enable_cpu_features() {
use x86_64::registers::{control::Cr4Flags, model_specific::EferFlags, xcontrol::XCr0Flags};
CPU_FEATURES.call_once(|| {
let cpuid = CpuId::new();
cpuid.get_feature_info().unwrap()
});
cpu::context::enable_essential_features();
let mut cr4 = x86_64::registers::control::Cr4::read();
cr4 |= Cr4Flags::FSGSBASE
| Cr4Flags::OSXSAVE
| Cr4Flags::OSFXSR
| Cr4Flags::OSXMMEXCPT_ENABLE
| Cr4Flags::PAGE_GLOBAL;
unsafe {
x86_64::registers::control::Cr4::write(cr4);
}
let mut xcr0 = x86_64::registers::xcontrol::XCr0::read();
xcr0 |= XCr0Flags::SSE;
if has_avx() {
xcr0 |= XCr0Flags::AVX;
}
if has_avx512() {
xcr0 |= XCr0Flags::OPMASK | XCr0Flags::ZMM_HI256 | XCr0Flags::HI16_ZMM;
}
unsafe {
x86_64::registers::xcontrol::XCr0::write(xcr0);
}
unsafe {
x86_64::registers::model_specific::Efer::update(|efer| {
*efer |= EferFlags::NO_EXECUTE_ENABLE;
});
}
}
#[macro_export]
macro_rules! if_tdx_enabled {
($if_block:block else $else_block:block) => {{
#[cfg(feature = "cvm_guest")]
{
if ::tdx_guest::tdx_is_enabled() {
$if_block
} else {
$else_block
}
}
#[cfg(not(feature = "cvm_guest"))]
{
$else_block
}
}};
($if_block:block) => {{
#[cfg(feature = "cvm_guest")]
{
if ::tdx_guest::tdx_is_enabled() {
$if_block
}
}
}};
}
pub use if_tdx_enabled;