Skip to content
This repository was archived by the owner on Sep 1, 2024. It is now read-only.

Commit 01796ad

Browse files
committed
Hypervisor appears to work for all processors
1 parent 667f833 commit 01796ad

File tree

6 files changed

+196
-148
lines changed

6 files changed

+196
-148
lines changed

driver/src/main.rs

+71-58
Original file line numberDiff line numberDiff line change
@@ -1,105 +1,118 @@
1+
// This crate provides the core functionality for initializing a hypervisor environment
2+
// within a UEFI application. It demonstrates advanced features such as custom panic handlers,
3+
// early logging, and direct manipulation of loaded image properties for hypervisor initialization.
4+
15
#![feature(new_uninit)]
26
#![feature(panic_info_message)]
37
#![no_main]
48
#![no_std]
59

610
extern crate alloc;
711

8-
use core::ffi::c_void;
912
use {
10-
crate::{
11-
processor::MpManager,
12-
virtualize::{switch_stack_and_virtualize_core, zap_relocations},
13-
},
14-
hypervisor::{
15-
global::GlobalState,
16-
intel::capture::{capture_registers, GuestRegisters},
17-
logger,
18-
},
13+
crate::processor::start_hypervisor_on_all_processors,
14+
hypervisor::logger,
1915
log::*,
20-
uefi::prelude::*,
16+
uefi::{prelude::*, proto::loaded_image::LoadedImage},
2117
};
2218

2319
pub mod processor;
2420
pub mod virtualize;
2521

26-
// Change as you like
22+
/// Custom panic handler for the UEFI application.
23+
///
24+
/// # Arguments
25+
///
26+
/// * `info` - Information about the panic, including the location and optional message.
2727
#[cfg(not(test))]
2828
#[panic_handler]
2929
fn panic_handler(info: &core::panic::PanicInfo) -> ! {
30+
// Log the file, line, and column of the panic.
3031
if let Some(location) = info.location() {
3132
error!(
3233
"[-] Panic in {} at ({}, {}):",
3334
location.file(),
3435
location.line(),
3536
location.column()
3637
);
38+
// Log the panic message if available.
3739
if let Some(message) = info.message() {
3840
error!("[-] {}", message);
3941
}
4042
}
4143

44+
// Enter an infinite loop as the panic handler should not return.
4245
loop {}
4346
}
4447

48+
/// Entry point for the UEFI application.
49+
///
50+
/// Initializes logging, UEFI services, and attempts to start the hypervisor on all processors.
51+
///
52+
/// # Arguments
53+
///
54+
/// * `_image_handle` - Handle to the loaded image of the application.
55+
/// * `system_table` - Reference to the UEFI System Table.
56+
///
57+
/// # Returns
58+
///
59+
/// The status of the application execution. Returns `Status::SUCCESS` on successful execution,
60+
/// or `Status::ABORTED` if the hypervisor fails to install.
4561
#[entry]
4662
fn main(_image_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
47-
// Initialize the COM2 port logger with level filter set to Info.
63+
// Initialize logging with the COM2 port and set the level filter to Trace.
4864
logger::init(LevelFilter::Trace);
4965

50-
//com_logger::builder().base(0x2f8).filter(LevelFilter::Trace).setup();
51-
66+
// Initialize UEFI services.
5267
uefi_services::init(&mut system_table).unwrap();
5368

5469
info!("The Matrix is an illusion");
5570

56-
// Get the MP Services (MultiProcessor Services) Protocol
57-
let mp_manager = match MpManager::new(system_table.boot_services()) {
58-
Ok(mp_manager) => mp_manager,
59-
Err(e) => panic!("Failed to get MP Services: {:?}", e),
60-
};
61-
62-
// Get the processor count
63-
let processor_count = match mp_manager.processor_count() {
64-
Ok(processor_count) => processor_count,
65-
Err(e) => panic!("Failed to get processor count: {:?}", e),
66-
};
67-
68-
info!("Total processors: {}", processor_count.total);
69-
info!("Enabled processors: {}", processor_count.enabled);
70-
7171
zap_relocations(&system_table);
7272

73-
// Capture the register values to be used as an initial state of the VM.
74-
let mut guest_registers = GuestRegisters::default();
75-
unsafe { capture_registers(&mut guest_registers) }
76-
77-
// Since we captured RIP just above, the VM will start running from here.
78-
// Check if our hypervisor is already loaded. If so, done, otherwise, continue installing the hypervisor.
79-
if !mp_manager.is_virtualized() {
80-
debug!("Virtualizing the system");
81-
mp_manager.set_virtualized();
82-
83-
let mut global_state = GlobalState::new(guest_registers);
84-
85-
if processor_count.enabled == 1 {
86-
info!("Found only one processor, virtualizing it");
87-
switch_stack_and_virtualize_core(&mut global_state as *mut _ as *mut c_void);
88-
} else {
89-
info!("Found multiple processors, virtualizing all of them");
90-
match mp_manager.start_virtualization_on_all_processors(
91-
switch_stack_and_virtualize_core,
92-
&mut global_state as *mut _ as *mut c_void,
93-
) {
94-
Ok(_) => debug!("Virtualization started on all processors"),
95-
Err(e) => panic!("Failed to start virtualization on all processors: {:?}", e),
96-
}
73+
// Attempt to start the hypervisor on all processors.
74+
match start_hypervisor_on_all_processors(&system_table) {
75+
Ok(_) => debug!("Hypervisor installed successfully"),
76+
Err(e) => {
77+
error!("Failed to install hypervisor: {:?}", e);
78+
return Status::ABORTED;
9779
}
9880
}
9981

100-
info!("The hypervisor has been installed successfully!");
101-
102-
system_table.boot_services().stall(20_000_000);
103-
82+
// Return success status to UEFI environment.
10483
Status::SUCCESS
10584
}
85+
86+
/// Nullifies the relocation table of the loaded UEFI image to prevent relocation.
87+
///
88+
/// This function manipulates the loaded image's PE header to zero out the relocation table,
89+
/// preventing UEFI from applying patches to the hypervisor code during the transition
90+
/// from physical-mode to virtual-mode addressing by the operating system.
91+
///
92+
/// # Arguments
93+
///
94+
/// * `system_table` - Reference to the UEFI System Table.
95+
pub fn zap_relocations(system_table: &SystemTable<Boot>) {
96+
let boot_service = system_table.boot_services();
97+
98+
// Obtain the current loaded image protocol.
99+
let loaded_image = boot_service
100+
.open_protocol_exclusive::<LoadedImage>(boot_service.image_handle())
101+
.unwrap();
102+
103+
// Extract the image base address and size.
104+
let (image_base, image_size) = loaded_image.info();
105+
let image_base = image_base as usize;
106+
let image_range = image_base..image_base + image_size as usize;
107+
108+
// Log the image base address range for debugging purposes.
109+
debug!("Image base: {:#x?}", image_range);
110+
111+
// Unsafe block to directly modify the PE header of the loaded image.
112+
// This operation nullifies the relocation table to prevent UEFI from
113+
// applying relocations to the hypervisor code.
114+
unsafe {
115+
*((image_base + 0x128) as *mut u32) = 0; // Zero out the relocation table offset.
116+
*((image_base + 0x12c) as *mut u32) = 0; // Zero out the relocation table size.
117+
}
118+
}

driver/src/processor.rs

+113-17
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,165 @@
1-
//! This module provides utility functions for processor-related operations in UEFI.
1+
//! This module provides utility functions for processor-related operations in UEFI,
2+
//! facilitating the initialization of virtualization across multiple processors.
23
34
use {
5+
crate::virtualize::virtualize_system,
46
core::{
57
ffi::c_void,
68
sync::atomic::{AtomicU64, Ordering},
79
},
10+
hypervisor::intel::capture::{capture_registers, GuestRegisters},
11+
log::*,
812
uefi::{
913
prelude::*,
1014
proto::pi::mp::{MpServices, Procedure, ProcessorCount},
1115
table::boot::ScopedProtocol,
1216
},
1317
};
1418

15-
/// Atomic bitset used to track which processors have been virtualized.
16-
static VIRTUALIZED_BITSET: AtomicU64 = AtomicU64::new(0);
19+
/// Tracks the virtualization status of processors.
20+
///
21+
/// Each bit in this `AtomicU64` represents the virtualization status of a processor:
22+
/// a set bit indicates that the processor has been virtualized.
23+
pub static VIRTUALIZED_BITSET: AtomicU64 = AtomicU64::new(0);
1724

1825
pub struct MpManager<'a> {
26+
/// UEFI MP Services Protocol instance.
1927
mp_services: ScopedProtocol<'a, MpServices>,
2028
}
2129

2230
impl<'a> MpManager<'a> {
23-
/// Creates a new instance of MpManager, acquiring the MP Services Protocol.
31+
/// Creates a new `MpManager` instance by acquiring the MP Services Protocol.
32+
///
33+
/// # Arguments
34+
///
35+
/// * `bt` - A reference to the UEFI Boot Services.
36+
///
37+
/// # Returns
38+
///
39+
/// A result containing the new `MpManager` instance or an error.
2440
pub fn new(bt: &'a BootServices) -> uefi::Result<Self> {
2541
let handle = bt.get_handle_for_protocol::<MpServices>()?;
2642
let mp_services = bt.open_protocol_exclusive::<MpServices>(handle)?;
2743
Ok(Self { mp_services })
2844
}
2945

46+
/// Initiates virtualization on all processors by executing the provided procedure.
47+
///
48+
/// # Arguments
49+
///
50+
/// * `procedure` - The function to execute on all application processors.
51+
/// * `procedure_argument` - A pointer to the argument to pass to the procedure.
52+
///
53+
/// # Returns
54+
///
55+
/// A result indicating success or failure of the operation.
3056
pub fn start_virtualization_on_all_processors(
3157
&self,
3258
procedure: Procedure,
3359
procedure_argument: *mut c_void,
3460
) -> uefi::Result<()> {
35-
// The `procedure` is an `extern "efiapi" fn(_: *mut c_void)` compatible with `Procedure`
36-
// and performs the necessary actions to initialize virtualization per-processor.
37-
self.mp_services.startup_all_aps(
38-
false, // Run on all processors simultaneously.
39-
procedure,
40-
procedure_argument,
41-
None, // No associated event.
42-
None, // No timeout.
43-
)
61+
self.mp_services
62+
.startup_all_aps(false, procedure, procedure_argument, None, None)
4463
}
4564

4665
/// Determines if the current processor is already virtualized.
66+
///
67+
/// # Returns
68+
///
69+
/// True if the current processor is virtualized, false otherwise.
4770
pub fn is_virtualized(&self) -> bool {
4871
let current_processor_index = self.current_processor_index().unwrap_or(0);
4972
let bit = 1 << current_processor_index;
50-
VIRTUALIZED_BITSET.load(Ordering::Relaxed) & bit != 0
73+
VIRTUALIZED_BITSET.load(Ordering::SeqCst) & bit != 0
5174
}
5275

5376
/// Marks the current processor as virtualized.
5477
pub fn set_virtualized(&self) {
5578
let current_processor_index = self.current_processor_index().unwrap_or(0);
5679
let bit = 1 << current_processor_index;
57-
VIRTUALIZED_BITSET.fetch_or(bit, Ordering::Relaxed);
80+
VIRTUALIZED_BITSET.fetch_or(bit, Ordering::SeqCst);
5881
}
5982

60-
/// Returns the number of active logical processors.
83+
/// Retrieves the number of active logical processors.
84+
///
85+
/// # Returns
86+
///
87+
/// A result containing the processor count or an error.
6188
pub fn processor_count(&self) -> uefi::Result<ProcessorCount> {
6289
self.mp_services.get_number_of_processors()
6390
}
6491

65-
/// Gets the processor number of the logical processor that the caller is running on.
92+
/// Identifies the index of the logical processor that is calling this method.
93+
///
94+
/// # Returns
95+
///
96+
/// A result containing the processor index or an error.
6697
pub fn current_processor_index(&self) -> uefi::Result<usize> {
6798
self.mp_services.who_am_i()
6899
}
69100
}
101+
102+
/// Starts the hypervisor on all processors.
103+
///
104+
/// # Arguments
105+
///
106+
/// * `system_table` - A reference to the UEFI System Table.
107+
///
108+
/// # Returns
109+
///
110+
/// A result indicating the success or failure of starting the hypervisor.
111+
pub fn start_hypervisor_on_all_processors(system_table: &SystemTable<Boot>) -> uefi::Result<()> {
112+
let mp_manager = MpManager::new(system_table.boot_services())?;
113+
let processor_count = mp_manager.processor_count()?;
114+
115+
info!(
116+
"Total processors: {}, Enabled processors: {}",
117+
processor_count.total, processor_count.enabled
118+
);
119+
120+
if processor_count.enabled == 1 {
121+
info!("Found only one processor, virtualizing it");
122+
start_hypervisor(&mp_manager);
123+
} else {
124+
info!("Found multiple processors, virtualizing all of them");
125+
mp_manager.start_virtualization_on_all_processors(
126+
start_hypervisor_on_ap,
127+
&mp_manager as *const _ as *mut _,
128+
)?;
129+
}
130+
131+
info!("The hypervisor has been installed successfully!");
132+
133+
Ok(())
134+
}
135+
136+
/// Hypervisor initialization procedure for Application Processors (APs).
137+
///
138+
/// # Arguments
139+
///
140+
/// * `procedure_argument` - A pointer to the `MpManager` instance.
141+
extern "efiapi" fn start_hypervisor_on_ap(procedure_argument: *mut c_void) {
142+
let mp_manager = unsafe { &*(procedure_argument as *const MpManager) };
143+
start_hypervisor(mp_manager);
144+
}
145+
146+
/// Initiates the virtualization process.
147+
///
148+
/// # Arguments
149+
///
150+
/// * `mp_manager` - A reference to the `MpManager` to check and set virtualization status.
151+
fn start_hypervisor(mp_manager: &MpManager) {
152+
let mut guest_registers = GuestRegisters::default();
153+
// Unsafe block to capture the current CPU's register state.
154+
unsafe { capture_registers(&mut guest_registers) };
155+
156+
// After capturing RIP, Guest execution will begin here. We then check for an existing hypervisor:
157+
// if absent, proceed with installation; otherwise, no further action is needed.
158+
159+
// Proceed with virtualization only if the current processor is not yet virtualized.
160+
if !mp_manager.is_virtualized() {
161+
debug!("Virtualizing the system");
162+
mp_manager.set_virtualized();
163+
virtualize_system(&guest_registers);
164+
}
165+
}

0 commit comments

Comments
 (0)