diff --git a/kernel/src/console.rs b/kernel/src/console.rs index 846c24783..92d17f859 100644 --- a/kernel/src/console.rs +++ b/kernel/src/console.rs @@ -4,8 +4,10 @@ // // Author: Joerg Roedel +use crate::error::SvsmError; +use crate::io::IOPort; use crate::locking::SpinLock; -use crate::serial::{Terminal, DEFAULT_SERIAL_PORT}; +use crate::serial::{SerialPort, Terminal, DEFAULT_SERIAL_PORT}; use crate::utils::immut_after_init::{ImmutAfterInitCell, ImmutAfterInitResult}; use core::fmt; @@ -27,14 +29,23 @@ static WRITER: SpinLock = SpinLock::new(Console { writer: &DEFAULT_SERIAL_PORT, }); static CONSOLE_INITIALIZED: ImmutAfterInitCell = ImmutAfterInitCell::new(false); +static CONSOLE_SERIAL: ImmutAfterInitCell> = ImmutAfterInitCell::uninit(); -pub fn init_console(writer: &'static dyn Terminal) -> ImmutAfterInitResult<()> { +fn init_console(writer: &'static dyn Terminal) -> ImmutAfterInitResult<()> { WRITER.lock().writer = writer; CONSOLE_INITIALIZED.reinit(&true)?; log::info!("COCONUT Secure Virtual Machine Service Module"); Ok(()) } +pub fn init_svsm_console(writer: &'static dyn IOPort, port: u16) -> Result<(), SvsmError> { + CONSOLE_SERIAL + .init(&SerialPort::new(writer, port)) + .map_err(|_| SvsmError::Console)?; + (*CONSOLE_SERIAL).init(); + init_console(&*CONSOLE_SERIAL).map_err(|_| SvsmError::Console) +} + #[doc(hidden)] pub fn _print(args: fmt::Arguments<'_>) { use core::fmt::Write; diff --git a/kernel/src/greq/services.rs b/kernel/src/greq/services.rs index a1c213cc4..6e91b2948 100644 --- a/kernel/src/greq/services.rs +++ b/kernel/src/greq/services.rs @@ -121,7 +121,9 @@ mod tests { use alloc::vec; - let sp = svsm_test_io(IORequest::GetLaunchMeasurement); + let sp = svsm_test_io().unwrap(); + + sp.put_byte(IORequest::GetLaunchMeasurement as u8); let mut expected_measurement = [0u8; 48]; for byte in &mut expected_measurement { diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 5b3ec4119..250b94e0b 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -34,7 +34,6 @@ pub mod requests; pub mod serial; pub mod sev; pub mod string; -pub mod svsm_console; pub mod svsm_paging; pub mod syscall; pub mod task; diff --git a/kernel/src/platform/native.rs b/kernel/src/platform/native.rs index efa2d00b6..7d7aa5250 100644 --- a/kernel/src/platform/native.rs +++ b/kernel/src/platform/native.rs @@ -5,25 +5,19 @@ // Author: Jon Lange use crate::address::{PhysAddr, VirtAddr}; -use crate::console::init_console; +use crate::console::init_svsm_console; use crate::cpu::cpuid::CpuidResult; use crate::cpu::msr::write_msr; use crate::cpu::percpu::PerCpu; use crate::error::SvsmError; -use crate::io::IOPort; +use crate::io::{IOPort, DEFAULT_IO_DRIVER}; use crate::platform::{PageEncryptionMasks, PageStateChangeOp, PageValidateOp, SvsmPlatform}; -use crate::serial::SerialPort; -use crate::svsm_console::NativeIOPort; use crate::types::PageSize; -use crate::utils::immut_after_init::ImmutAfterInitCell; use crate::utils::MemoryRegion; #[cfg(debug_assertions)] use crate::mm::virt_to_phys; -static CONSOLE_IO: NativeIOPort = NativeIOPort::new(); -static CONSOLE_SERIAL: ImmutAfterInitCell> = ImmutAfterInitCell::uninit(); - const APIC_MSR_ICR: u32 = 0x830; #[derive(Clone, Copy, Debug)] @@ -45,11 +39,7 @@ impl SvsmPlatform for NativePlatform { fn env_setup(&mut self, debug_serial_port: u16, _vtom: usize) -> Result<(), SvsmError> { // In the native platform, console output does not require the use of // any platform services, so it can be initialized immediately. - CONSOLE_SERIAL - .init(&SerialPort::new(&CONSOLE_IO, debug_serial_port)) - .map_err(|_| SvsmError::Console)?; - (*CONSOLE_SERIAL).init(); - init_console(&*CONSOLE_SERIAL).map_err(|_| SvsmError::Console) + init_svsm_console(&DEFAULT_IO_DRIVER, debug_serial_port) } fn env_setup_late(&mut self, _debug_serial_port: u16) -> Result<(), SvsmError> { @@ -86,7 +76,7 @@ impl SvsmPlatform for NativePlatform { fn setup_guest_host_comm(&mut self, _cpu: &PerCpu, _is_bsp: bool) {} fn get_io_port(&self) -> &'static dyn IOPort { - &CONSOLE_IO + &DEFAULT_IO_DRIVER } fn page_state_change( diff --git a/kernel/src/platform/snp.rs b/kernel/src/platform/snp.rs index 6ba2c0e69..3efb69b57 100644 --- a/kernel/src/platform/snp.rs +++ b/kernel/src/platform/snp.rs @@ -5,7 +5,7 @@ // Author: Jon Lange use crate::address::{Address, PhysAddr, VirtAddr}; -use crate::console::init_console; +use crate::console::init_svsm_console; use crate::cpu::cpuid::{cpuid_table, CpuidResult}; use crate::cpu::percpu::{current_ghcb, this_cpu, PerCpu}; use crate::error::ApicError::Registration; @@ -14,14 +14,15 @@ use crate::greq::driver::guest_request_driver_init; use crate::io::IOPort; use crate::mm::{PerCPUPageMappingGuard, PAGE_SIZE, PAGE_SIZE_2M}; use crate::platform::{PageEncryptionMasks, PageStateChangeOp, PageValidateOp, SvsmPlatform}; -use crate::serial::SerialPort; +use crate::sev::ghcb::GHCBIOSize; use crate::sev::hv_doorbell::current_hv_doorbell; -use crate::sev::msr_protocol::{hypervisor_ghcb_features, verify_ghcb_version, GHCBHvFeatures}; +use crate::sev::msr_protocol::{ + hypervisor_ghcb_features, request_termination_msr, verify_ghcb_version, GHCBHvFeatures, +}; use crate::sev::status::vtom_enabled; use crate::sev::{ init_hypervisor_ghcb_features, pvalidate_range, sev_status_init, sev_status_verify, PvalidateOp, }; -use crate::svsm_console::SVSMIOPort; use crate::types::PageSize; use crate::utils::immut_after_init::ImmutAfterInitCell; use crate::utils::MemoryRegion; @@ -31,8 +32,7 @@ use crate::mm::virt_to_phys; use core::sync::atomic::{AtomicU32, Ordering}; -static CONSOLE_IO: SVSMIOPort = SVSMIOPort::new(); -static CONSOLE_SERIAL: ImmutAfterInitCell> = ImmutAfterInitCell::uninit(); +static GHCB_IO_DRIVER: GHCBIOPort = GHCBIOPort::new(); static VTOM: ImmutAfterInitCell = ImmutAfterInitCell::uninit(); @@ -91,11 +91,7 @@ impl SvsmPlatform for SnpPlatform { } fn env_setup_late(&mut self, debug_serial_port: u16) -> Result<(), SvsmError> { - CONSOLE_SERIAL - .init(&SerialPort::new(&CONSOLE_IO, debug_serial_port)) - .map_err(|_| SvsmError::Console)?; - (*CONSOLE_SERIAL).init(); - init_console(&*CONSOLE_SERIAL).map_err(|_| SvsmError::Console)?; + init_svsm_console(&GHCB_IO_DRIVER, debug_serial_port)?; sev_status_verify(); init_hypervisor_ghcb_features()?; Ok(()) @@ -163,7 +159,7 @@ impl SvsmPlatform for SnpPlatform { } fn get_io_port(&self) -> &'static dyn IOPort { - &CONSOLE_IO + &GHCB_IO_DRIVER } fn page_state_change( @@ -282,3 +278,59 @@ impl SvsmPlatform for SnpPlatform { current_ghcb().ap_create(vmsa_pa, cpu.get_apic_id().into(), 0, sev_features) } } + +#[derive(Clone, Copy, Debug, Default)] +pub struct GHCBIOPort {} + +impl GHCBIOPort { + pub const fn new() -> Self { + GHCBIOPort {} + } +} + +impl IOPort for GHCBIOPort { + fn outb(&self, port: u16, value: u8) { + let ret = current_ghcb().ioio_out(port, GHCBIOSize::Size8, value as u64); + if ret.is_err() { + request_termination_msr(); + } + } + + fn inb(&self, port: u16) -> u8 { + let ret = current_ghcb().ioio_in(port, GHCBIOSize::Size8); + match ret { + Ok(v) => (v & 0xff) as u8, + Err(_e) => request_termination_msr(), + } + } + + fn outw(&self, port: u16, value: u16) { + let ret = current_ghcb().ioio_out(port, GHCBIOSize::Size16, value as u64); + if ret.is_err() { + request_termination_msr(); + } + } + + fn inw(&self, port: u16) -> u16 { + let ret = current_ghcb().ioio_in(port, GHCBIOSize::Size16); + match ret { + Ok(v) => (v & 0xffff) as u16, + Err(_e) => request_termination_msr(), + } + } + + fn outl(&self, port: u16, value: u32) { + let ret = current_ghcb().ioio_out(port, GHCBIOSize::Size32, value as u64); + if ret.is_err() { + request_termination_msr(); + } + } + + fn inl(&self, port: u16) -> u32 { + let ret = current_ghcb().ioio_in(port, GHCBIOSize::Size32); + match ret { + Ok(v) => (v & 0xffffffff) as u32, + Err(_e) => request_termination_msr(), + } + } +} diff --git a/kernel/src/platform/tdp.rs b/kernel/src/platform/tdp.rs index 9a665f911..6ba12e878 100644 --- a/kernel/src/platform/tdp.rs +++ b/kernel/src/platform/tdp.rs @@ -5,23 +5,16 @@ // Author: Peter Fang use crate::address::{PhysAddr, VirtAddr}; -use crate::console::init_console; +use crate::console::init_svsm_console; use crate::cpu::cpuid::CpuidResult; use crate::cpu::percpu::PerCpu; use crate::error::SvsmError; -use crate::io::IOPort; +use crate::io::{IOPort, DEFAULT_IO_DRIVER}; use crate::platform::{PageEncryptionMasks, PageStateChangeOp, PageValidateOp, SvsmPlatform}; -use crate::serial::SerialPort; -use crate::svsm_console::SVSMIOPort; use crate::types::PageSize; use crate::utils::immut_after_init::ImmutAfterInitCell; use crate::utils::MemoryRegion; -// FIXME - SVSMIOPort doesn't work on TDP, but the platform does not yet have -// an alternative available. -static CONSOLE_IO: SVSMIOPort = SVSMIOPort::new(); -static CONSOLE_SERIAL: ImmutAfterInitCell> = ImmutAfterInitCell::uninit(); - static VTOM: ImmutAfterInitCell = ImmutAfterInitCell::uninit(); #[derive(Clone, Copy, Debug)] @@ -45,11 +38,7 @@ impl SvsmPlatform for TdpPlatform { } fn env_setup_late(&mut self, debug_serial_port: u16) -> Result<(), SvsmError> { - CONSOLE_SERIAL - .init(&SerialPort::new(&CONSOLE_IO, debug_serial_port)) - .map_err(|_| SvsmError::Console)?; - (*CONSOLE_SERIAL).init(); - init_console(&*CONSOLE_SERIAL).map_err(|_| SvsmError::Console) + init_svsm_console(&DEFAULT_IO_DRIVER, debug_serial_port) } fn env_setup_svsm(&self) -> Result<(), SvsmError> { @@ -83,7 +72,9 @@ impl SvsmPlatform for TdpPlatform { fn setup_guest_host_comm(&mut self, _cpu: &PerCpu, _is_bsp: bool) {} fn get_io_port(&self) -> &'static dyn IOPort { - &CONSOLE_IO + // FIXME - the default I/O port implementation doesn't work on TDP, + // but the platform does not yet have an alternative available. + &DEFAULT_IO_DRIVER } fn page_state_change( diff --git a/kernel/src/svsm_console.rs b/kernel/src/svsm_console.rs deleted file mode 100644 index 5b828cf11..000000000 --- a/kernel/src/svsm_console.rs +++ /dev/null @@ -1,119 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2022-2023 SUSE LLC -// -// Author: Joerg Roedel - -use crate::cpu::percpu::current_ghcb; -use crate::io::IOPort; -use crate::sev::ghcb::GHCBIOSize; -use crate::sev::msr_protocol::request_termination_msr; - -use core::arch::asm; - -#[derive(Clone, Copy, Debug, Default)] -pub struct SVSMIOPort {} - -impl SVSMIOPort { - pub const fn new() -> Self { - SVSMIOPort {} - } -} - -impl IOPort for SVSMIOPort { - fn outb(&self, port: u16, value: u8) { - let ret = current_ghcb().ioio_out(port, GHCBIOSize::Size8, value as u64); - if ret.is_err() { - request_termination_msr(); - } - } - - fn inb(&self, port: u16) -> u8 { - let ret = current_ghcb().ioio_in(port, GHCBIOSize::Size8); - match ret { - Ok(v) => (v & 0xff) as u8, - Err(_e) => request_termination_msr(), - } - } - - fn outw(&self, port: u16, value: u16) { - let ret = current_ghcb().ioio_out(port, GHCBIOSize::Size16, value as u64); - if ret.is_err() { - request_termination_msr(); - } - } - - fn inw(&self, port: u16) -> u16 { - let ret = current_ghcb().ioio_in(port, GHCBIOSize::Size16); - match ret { - Ok(v) => (v & 0xffff) as u16, - Err(_e) => request_termination_msr(), - } - } - - fn outl(&self, port: u16, value: u32) { - let ret = current_ghcb().ioio_out(port, GHCBIOSize::Size32, value as u64); - if ret.is_err() { - request_termination_msr(); - } - } - - fn inl(&self, port: u16) -> u32 { - let ret = current_ghcb().ioio_in(port, GHCBIOSize::Size32); - match ret { - Ok(v) => (v & 0xffffffff) as u32, - Err(_e) => request_termination_msr(), - } - } -} - -#[derive(Clone, Copy, Debug, Default)] -pub struct NativeIOPort {} - -impl NativeIOPort { - pub const fn new() -> Self { - NativeIOPort {} - } -} - -impl IOPort for NativeIOPort { - fn outb(&self, port: u16, value: u8) { - unsafe { - asm!("out %al, %dx", - in("dx") port, - in("al") value, - options(att_syntax)); - } - } - - fn inb(&self, port: u16) -> u8 { - let mut ret: u8; - unsafe { - asm!("in %dx, %al", - in("dx") port, - out("al") ret, - options(att_syntax)); - } - ret - } - - fn outw(&self, port: u16, value: u16) { - unsafe { - asm!("out %ax, %dx", - in("dx") port, - in("ax") value, - options(att_syntax)); - } - } - - fn inw(&self, port: u16) -> u16 { - let mut ret: u16; - unsafe { - asm!("in %dx, %al", - in("dx") port, - out("ax") ret, - options(att_syntax)); - } - ret - } -} diff --git a/kernel/src/testing.rs b/kernel/src/testing.rs index 23554e185..8650e8d16 100644 --- a/kernel/src/testing.rs +++ b/kernel/src/testing.rs @@ -4,13 +4,11 @@ use test::ShouldPanic; use crate::{ cpu::percpu::current_ghcb, locking::{LockGuard, SpinLock}, - serial::{SerialPort, Terminal}, + platform::SVSM_PLATFORM, + serial::SerialPort, sev::ghcb::GHCBIOSize, - svsm_console::SVSMIOPort, }; -use core::sync::atomic::{AtomicBool, Ordering}; - #[macro_export] macro_rules! assert_eq_warn { ($left:expr, $right:expr) => { @@ -30,10 +28,7 @@ macro_rules! assert_eq_warn { } pub use assert_eq_warn; -static SERIAL_INITIALIZED: AtomicBool = AtomicBool::new(false); -static IOPORT: SVSMIOPort = SVSMIOPort::new(); -static SERIAL_PORT: SpinLock> = - SpinLock::new(SerialPort::new(&IOPORT, 0x2e8 /*COM4*/)); +static SERIAL_PORT: SpinLock>> = SpinLock::new(None); /// Byte used to tell the host the request we need for the test. /// These values must be aligned with `test_io()` in scripts/test-in-svsm.sh @@ -49,17 +44,15 @@ pub enum IORequest { /// used in a test. The request (first byte) is sent by this function, so the /// caller can start using the serial port according to the request implemented /// in `test_io()` in scripts/test-in-svsm.sh -pub fn svsm_test_io(req: IORequest) -> LockGuard<'static, SerialPort<'static>> { - let sp = SERIAL_PORT.lock(); - if SERIAL_INITIALIZED - .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) - .is_ok() - { - sp.init(); +pub fn svsm_test_io() -> LockGuard<'static, Option>> { + let mut sp = SERIAL_PORT.lock(); + if sp.is_none() { + let io_port = SVSM_PLATFORM.as_dyn_ref().get_io_port(); + let serial_port = SerialPort::new(io_port, 0x2e8 /*COM4*/); + *sp = Some(serial_port); + serial_port.init(); } - sp.put_byte(req as u8); - sp }