diff --git a/src/acpi/fadt.rs b/src/acpi/fadt.rs index c565f578ae..ee3ed7c2fc 100644 --- a/src/acpi/fadt.rs +++ b/src/acpi/fadt.rs @@ -77,7 +77,10 @@ pub fn init(sdt: &Sdt) { // offsets (per the ACPI spec); reading them as u32/u64 is // safe because all of them are at 4-byte or 8-byte aligned // offsets on x86_64. - let data = sdt.data_address() as *const u8; + // Use the SDT start address, not data_address() (which points past the + // 36-byte SDT header). The offsets below are absolute offsets from the + // start of the FADT table per ACPI 6.5 §5.2.9. + let data = sdt as *const _ as *const u8; unsafe { // PM1a_CNT is at offset 56 in the FADT (ACPI 6.5 §5.2.9 // Table 5.6). 32-bit General-Purpose Event Register Block 0 diff --git a/src/acpi/mod.rs b/src/acpi/mod.rs index 2ab2e17168..f82ab9a078 100644 --- a/src/acpi/mod.rs +++ b/src/acpi/mod.rs @@ -150,25 +150,31 @@ pub unsafe fn init(already_supplied_rsdp: Option>) { // TODO: Enumerate processors in userspace, and then provide an ACPI-independent interface // to initialize enumerated processors to userspace? + info!("GSBASE before Madt::init: {:#x}", x86::msr::rdmsr(x86::msr::IA32_GS_BASE)); Madt::init(); + info!("GSBASE after Madt::init: {:#x}", x86::msr::rdmsr(x86::msr::IA32_GS_BASE)); //TODO: support this on any arch // SPCR must be initialized after MADT for interrupt controllers #[cfg(target_arch = "aarch64")] spcr::Spcr::init(); // TODO: Let userspace setup HPET, and then provide an interface to specify which timer to // use? + info!("GSBASE before Hpet::init: {:#x}", x86::msr::rdmsr(x86::msr::IA32_GS_BASE)); Hpet::init(); + info!("GSBASE after Hpet::init: {:#x}", x86::msr::rdmsr(x86::msr::IA32_GS_BASE)); #[cfg(target_arch = "aarch64")] gtdt::Gtdt::init(); // Phase II: parse the FADT to extract the PM1a_CNT // and PM1a_STS port addresses used by the S3 entry // path. Hardware-agnostic — works on any platform // with a working FADT. + info!("GSBASE before fadt::init: {:#x}", x86::msr::rdmsr(x86::msr::IA32_GS_BASE)); if let Some(fadt_sdts) = find_sdt("FACP").first() { fadt::init(fadt_sdts); } else { warn!("ACPI: no FADT (FACP) found, S3 entry path disabled"); } + info!("GSBASE after fadt::init: {:#x}", x86::msr::rdmsr(x86::msr::IA32_GS_BASE)); // Phase II.X.W: parse the FACS to extract the // xfirmware_waking_vector. This is the address the // platform firmware jumps to on S3 wake. The kernel's @@ -180,7 +186,9 @@ pub unsafe fn init(already_supplied_rsdp: Option>) { // field (64-bit) or firmware_ctrl field (32-bit). // The FADT parser caches the FACS address. We use // the FADT's x_firmware_ctrl to find the FACS SDT. + info!("GSBASE before facs::init: {:#x}", x86::msr::rdmsr(x86::msr::IA32_GS_BASE)); let facs_addr = fadt::x_firmware_ctrl(); + info!("FACS x_firmware_ctrl = {:#x}", facs_addr); if facs_addr != 0 { // SAFETY: The FACS address is a physical // address stored in the FADT. The boot-time page diff --git a/src/arch/x86_shared/device/tsc.rs b/src/arch/x86_shared/device/tsc.rs index bfcf7a68ae..1312459439 100644 --- a/src/arch/x86_shared/device/tsc.rs +++ b/src/arch/x86_shared/device/tsc.rs @@ -134,6 +134,13 @@ pub unsafe fn init() -> bool { .supp_feats .contains(KvmFeatureBits::CLOCKSOURCE2 | KvmFeatureBits::CLOCKSOURCE_STABLE) { + let gsbase = x86::msr::rdmsr(x86::msr::IA32_GS_BASE); + debug!("tsc::init: IA32_GS_BASE = {:#x}", gsbase); + if gsbase == 0 { + debug!("tsc::init: GSBASE is zero, skipping KVM TSC"); + return false; + } + let frame = allocate_frame().expect("failed to allocate timer page"); x86::msr::wrmsr(MSR_KVM_SYSTEM_TIME_NEW, (frame.base().data() as u64) | 1); let ptr = crate::memory::RmmA::phys_to_virt(frame.base()).data() diff --git a/src/arch/x86_shared/gdt.rs b/src/arch/x86_shared/gdt.rs index cad344f3c2..d670aaf78e 100644 --- a/src/arch/x86_shared/gdt.rs +++ b/src/arch/x86_shared/gdt.rs @@ -332,9 +332,10 @@ pub unsafe fn install_pcr(pcr_ptr: *mut ProcessorControlRegion) { segmentation::load_es(SegmentSelector::from_raw(0)); segmentation::load_fs(SegmentSelector::from_raw(0)); - // What happens when GS is loaded with a NULL selector, is undefined on Intel CPUs. However, - // GSBASE is set later. - segmentation::load_gs(SegmentSelector::from_raw(0)); + // Loading GS with a NULL selector leaves the resulting GSBASE undefined on some CPUs and + // hypervisors (e.g. KVM). Use the kernel data selector so the segment is present, then set + // the actual base via IA32_GS_BASE. + segmentation::load_gs(SegmentSelector::new(GDT_KERNEL_DATA as u16, Ring::Ring0)); // Ensure that GSBASE always points to the PCR in kernel space. x86::msr::wrmsr(x86::msr::IA32_GS_BASE, pcr as *mut _ as usize as u64); diff --git a/src/arch/x86_shared/start.rs b/src/arch/x86_shared/start.rs index 7a7c0ae815..abaa353fb9 100644 --- a/src/arch/x86_shared/start.rs +++ b/src/arch/x86_shared/start.rs @@ -96,6 +96,7 @@ unsafe extern "C" fn start(args_ptr: *const KernelArgs, stack_end: usize) -> ! { // Set up GDT gdt::init_bsp(stack_end); + info!("GSBASE after init_bsp: {:#x}", x86::msr::rdmsr(x86::msr::IA32_GS_BASE)); // Set up IDT idt::init_bsp(); @@ -108,12 +109,15 @@ unsafe extern "C" fn start(args_ptr: *const KernelArgs, stack_end: usize) -> ! { // Initialize paging paging::init(); + info!("GSBASE after paging::init: {:#x}", x86::msr::rdmsr(x86::msr::IA32_GS_BASE)); #[cfg(target_arch = "x86_64")] crate::arch::alternative::early_init(true); + info!("GSBASE after alternative::early_init: {:#x}", x86::msr::rdmsr(x86::msr::IA32_GS_BASE)); // Set up syscall instruction interrupt::syscall::init(); + info!("GSBASE after syscall::init: {:#x}", x86::msr::rdmsr(x86::msr::IA32_GS_BASE)); // Setup kernel heap allocator::init(); @@ -124,17 +128,22 @@ unsafe extern "C" fn start(args_ptr: *const KernelArgs, stack_end: usize) -> ! { // Initialize miscellaneous processor features #[cfg(target_arch = "x86_64")] crate::arch::misc::init(LogicalCpuId::BSP); + info!("GSBASE after misc::init: {:#x}", x86::msr::rdmsr(x86::msr::IA32_GS_BASE)); // Initialize devices device::init(); + info!("GSBASE after device::init: {:#x}", x86::msr::rdmsr(x86::msr::IA32_GS_BASE)); // Read ACPI tables, starts APs if cfg!(feature = "acpi") { + info!("GSBASE before acpi::init: {:#x}", x86::msr::rdmsr(x86::msr::IA32_GS_BASE)); crate::acpi::init(args.acpi_rsdp()); + info!("GSBASE after acpi::init: {:#x}", x86::msr::rdmsr(x86::msr::IA32_GS_BASE)); device::init_after_acpi(); } crate::profiling::init(); + info!("GSBASE before init_noncore: {:#x}", x86::msr::rdmsr(x86::msr::IA32_GS_BASE)); // Initialize all of the non-core devices not otherwise needed to complete initialization device::init_noncore();