diff --git a/Cargo.lock b/Cargo.lock index 5023a397..dace63ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -252,6 +252,7 @@ dependencies = [ "bootloader-x86_64-common", "bootloader_api", "log", + "raw-cpuid", "serde-json-core", "uefi", "x86_64", diff --git a/api/Cargo.toml b/api/Cargo.toml index ef687b0c..8d075843 100644 --- a/api/Cargo.toml +++ b/api/Cargo.toml @@ -6,9 +6,5 @@ repository.workspace = true edition = "2021" description = "Makes a kernel compatible with the bootloader crate" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] - [dev-dependencies] rand = "0.8.4" diff --git a/api/src/info.rs b/api/src/info.rs index 965fcf40..064c4216 100644 --- a/api/src/info.rs +++ b/api/src/info.rs @@ -63,6 +63,9 @@ pub struct BootInfo { /// Virtual address of the loaded kernel image. pub kernel_image_offset: u64, + /// UEFI runtime table address (if running on UEFI) + pub rt_table_addr: Optional, + #[doc(hidden)] pub _test_sentinel: u64, } @@ -85,6 +88,7 @@ impl BootInfo { kernel_addr: 0, kernel_len: 0, kernel_image_offset: 0, + rt_table_addr: Optional::None, _test_sentinel: 0, } } diff --git a/bios/stage-4/src/main.rs b/bios/stage-4/src/main.rs index 260dd622..6042e463 100644 --- a/bios/stage-4/src/main.rs +++ b/bios/stage-4/src/main.rs @@ -129,13 +129,21 @@ pub extern "C" fn _start(info: &mut BiosInfo) -> ! { }; #[allow(deprecated)] - if config.frame_buffer.minimum_framebuffer_height.is_none() { - config.frame_buffer.minimum_framebuffer_height = + if config + .frame_buffer_physical + .minimum_framebuffer_height + .is_none() + { + config.frame_buffer_physical.minimum_framebuffer_height = kernel.config.frame_buffer.minimum_framebuffer_height; } #[allow(deprecated)] - if config.frame_buffer.minimum_framebuffer_width.is_none() { - config.frame_buffer.minimum_framebuffer_width = + if config + .frame_buffer_physical + .minimum_framebuffer_width + .is_none() + { + config.frame_buffer_physical.minimum_framebuffer_width = kernel.config.frame_buffer.minimum_framebuffer_width; } let framebuffer_info = init_logger( @@ -164,6 +172,7 @@ pub extern "C" fn _start(info: &mut BiosInfo) -> ! { _ => Some(info.ramdisk.start), }, ramdisk_len: info.ramdisk.len, + rt_table_addr: None, }; load_and_switch_to_kernel(kernel, config, frame_allocator, page_tables, system_info); diff --git a/common/config/src/lib.rs b/common/config/src/lib.rs index 1b294331..2ee11fc0 100644 --- a/common/config/src/lib.rs +++ b/common/config/src/lib.rs @@ -7,8 +7,11 @@ use serde::{Deserialize, Serialize}; #[serde(default)] #[non_exhaustive] pub struct BootConfig { - /// Configuration for the frame buffer setup. - pub frame_buffer: FrameBuffer, + /// Configuration for the frame buffer setup on physical hardware. + pub frame_buffer_physical: FrameBuffer, + + /// Configuration for the frame buffer setup in a virtual machine + pub frame_buffer_virtual: FrameBuffer, /// The minimum log level that is printed to the screen during boot. /// @@ -32,7 +35,8 @@ pub struct BootConfig { impl Default for BootConfig { fn default() -> Self { Self { - frame_buffer: Default::default(), + frame_buffer_virtual: Default::default(), + frame_buffer_physical: Default::default(), log_level: Default::default(), frame_buffer_logging: true, serial_logging: true, diff --git a/common/src/lib.rs b/common/src/lib.rs index 3c407644..20c5c4cc 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -5,7 +5,7 @@ use crate::legacy_memory_region::{LegacyFrameAllocator, LegacyMemoryRegion}; use bootloader_api::{ config::Mapping, - info::{FrameBuffer, FrameBufferInfo, MemoryRegion, TlsTemplate}, + info::{FrameBuffer, FrameBufferInfo, MemoryRegion, Optional, TlsTemplate}, BootInfo, BootloaderConfig, }; use bootloader_boot_config::{BootConfig, LevelFilter}; @@ -80,6 +80,11 @@ pub struct SystemInfo { pub rsdp_addr: Option, pub ramdisk_addr: Option, pub ramdisk_len: u64, + + /// UEFI runtime table address (if running on UEFI). + /// + /// Use a raw pointer from your kernel to this address to access UEFI Runtime Services. + pub rt_table_addr: Option, } /// The physical address of the framebuffer and information about the framebuffer. @@ -551,6 +556,11 @@ where info.kernel_len = mappings.kernel_slice_len as _; info.kernel_image_offset = mappings.kernel_image_offset.as_u64(); info._test_sentinel = boot_config._test_sentinel; + info.rt_table_addr = if let Some(addr) = system_info.rt_table_addr { + Optional::Some(addr) + } else { + Optional::None + }; info }); diff --git a/uefi/Cargo.toml b/uefi/Cargo.toml index 80168be5..fc0b1837 100644 --- a/uefi/Cargo.toml +++ b/uefi/Cargo.toml @@ -16,3 +16,4 @@ log = "0.4.14" x86_64 = "0.14.8" serde-json-core = "0.5.0" uefi = "0.20.0" +raw-cpuid = "10.7.0" diff --git a/uefi/src/main.rs b/uefi/src/main.rs index 93dfb6c7..160ef517 100644 --- a/uefi/src/main.rs +++ b/uefi/src/main.rs @@ -13,6 +13,7 @@ use core::{ ops::{Deref, DerefMut}, ptr, slice, }; +use raw_cpuid::{CpuId, Hypervisor}; use uefi::{ prelude::{entry, Boot, Handle, Status, SystemTable}, proto::{ @@ -97,13 +98,21 @@ fn main_inner(image: Handle, mut st: SystemTable) -> Status { }; #[allow(deprecated)] - if config.frame_buffer.minimum_framebuffer_height.is_none() { - config.frame_buffer.minimum_framebuffer_height = + if config + .frame_buffer_physical + .minimum_framebuffer_height + .is_none() + { + config.frame_buffer_physical.minimum_framebuffer_height = kernel.config.frame_buffer.minimum_framebuffer_height; } #[allow(deprecated)] - if config.frame_buffer.minimum_framebuffer_width.is_none() { - config.frame_buffer.minimum_framebuffer_width = + if config + .frame_buffer_physical + .minimum_framebuffer_width + .is_none() + { + config.frame_buffer_physical.minimum_framebuffer_width = kernel.config.frame_buffer.minimum_framebuffer_width; } let framebuffer = init_logger(image, &st, &config); @@ -166,6 +175,7 @@ fn main_inner(image: Handle, mut st: SystemTable) -> Status { }, ramdisk_addr, ramdisk_len, + rt_table_addr: Some(system_table.get_current_system_table_addr()), }; bootloader_x86_64_common::load_and_switch_to_kernel( @@ -472,25 +482,82 @@ fn init_logger( let mode = { let modes = gop.modes(); - match ( - config - .frame_buffer - .minimum_framebuffer_height - .map(|v| usize::try_from(v).unwrap()), - config - .frame_buffer - .minimum_framebuffer_width - .map(|v| usize::try_from(v).unwrap()), - ) { - (Some(height), Some(width)) => modes - .filter(|m| { - let res = m.info().resolution(); - res.1 >= height && res.0 >= width - }) - .last(), - (Some(height), None) => modes.filter(|m| m.info().resolution().1 >= height).last(), - (None, Some(width)) => modes.filter(|m| m.info().resolution().0 >= width).last(), - _ => None, + + if let Some(hypervisor) = CpuId::new().get_hypervisor_info() { + if let Hypervisor::Xen = hypervisor.identify() { + // Use same rules as real hardware since Xen uses the whole screen + match ( + config + .frame_buffer_physical + .minimum_framebuffer_height + .map(|v| usize::try_from(v).unwrap()), + config + .frame_buffer_physical + .minimum_framebuffer_width + .map(|v| usize::try_from(v).unwrap()), + ) { + (Some(height), Some(width)) => modes + .filter(|m| { + let res = m.info().resolution(); + res.1 >= height && res.0 >= width + }) + .last(), + (Some(height), None) => { + modes.filter(|m| m.info().resolution().1 >= height).last() + } + (None, Some(width)) => { + modes.filter(|m| m.info().resolution().0 >= width).last() + } + _ => None, + } + } else { + match ( + config + .frame_buffer_virtual + .minimum_framebuffer_height + .map(|v| usize::try_from(v).unwrap()), + config + .frame_buffer_virtual + .minimum_framebuffer_width + .map(|v| usize::try_from(v).unwrap()), + ) { + (Some(height), Some(width)) => modes + .filter(|m| { + let res = m.info().resolution(); + res.1 >= height && res.0 >= width + }) + .last(), + (Some(height), None) => { + modes.filter(|m| m.info().resolution().1 >= height).last() + } + (None, Some(width)) => { + modes.filter(|m| m.info().resolution().0 >= width).last() + } + _ => None, + } + } + } else { + // On real hardware; set rules accordingly + match ( + config + .frame_buffer_physical + .minimum_framebuffer_height + .map(|v| usize::try_from(v).unwrap()), + config + .frame_buffer_physical + .minimum_framebuffer_width + .map(|v| usize::try_from(v).unwrap()), + ) { + (Some(height), Some(width)) => modes + .filter(|m| { + let res = m.info().resolution(); + res.1 >= height && res.0 >= width + }) + .last(), + (Some(height), None) => modes.filter(|m| m.info().resolution().1 >= height).last(), + (None, Some(width)) => modes.filter(|m| m.info().resolution().0 >= width).last(), + _ => None, + } } }; if let Some(mode) = mode {