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

Commit

Permalink
vmxon works
Browse files Browse the repository at this point in the history
  • Loading branch information
memN0ps committed Feb 14, 2024
1 parent 19d9802 commit d3e5da9
Show file tree
Hide file tree
Showing 18 changed files with 1,704 additions and 6 deletions.
35 changes: 29 additions & 6 deletions driver/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,41 @@
#![no_main]
#![no_std]

use log::*;
use uefi::prelude::*;
extern crate alloc;

use {
log::*,
uefi::prelude::*,
hypervisor::vmm::is_hypervisor_present,
crate::{virtualize::virtualize_system, capture::{capture_registers, GuestRegisters}},
};

pub mod virtualize;

#[entry]
fn main(_image_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
com_logger::builder().filter(LevelFilter::Debug).setup();
// Initialize the COM2 port logger with level filter set to Info.
com_logger::builder().base(0x2f8).filter(LevelFilter::Trace).setup();

uefi_services::init(&mut system_table).unwrap();

info!("Hello, world!");
info!("The Matrix is an illusion");

// Capture the register values to be used as an initial state of the VM.
let mut regs = GuestRegisters::default();
unsafe { capture_registers(&mut regs) }

// Since we captured RIP just above, the VM will start running from here.
// Check if our hypervisor is already loaded. If so, done, otherwise, continue
// installing the hypervisor.
if !is_hypervisor_present() {
debug!("Virtualizing the system");
virtualize_system(&regs, &system_table);
}

info!("The hypervisor has been installed successfully!");

system_table.boot_services().stall(10_000_000);
//system_table.boot_services().stall(10_000_000);

Status::SUCCESS
}
}
77 changes: 77 additions & 0 deletions driver/src/virtualize.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use {
alloc::alloc::{alloc_zeroed, handle_alloc_error},
core::{alloc::Layout, arch::global_asm},
hypervisor::{
intel::{
capture::GuestRegisters, page::Page
},
vmm::start_hypervisor
},
log::debug,
uefi::{
proto::loaded_image::LoadedImage,
table::{Boot, SystemTable},
},
};

pub fn virtualize_system(regs: &GuestRegisters, system_table: &SystemTable<Boot>) {
let boot_service = system_table.boot_services();

// Open the loaded image protocol to get the current image base and image size.
let loaded_image = boot_service.
open_protocol_exclusive::<LoadedImage>(boot_service.image_handle())
.unwrap();

// Get the current image base and image size.
let (image_base, image_size) = loaded_image.info();

let image_base = image_base as usize;

let image_range = image_base..image_base + image_size as usize;
debug!("Image base: {:#x?}", image_range);

// Prevent relocation by zapping the Relocation Table in the PE header. UEFI
// keeps the list of runtime drivers and applies patches into their code and
// data according to relocation information, as address translation switches
// from physical-mode to virtual-mode when the OS starts. This causes a problem
// with us because the host part keeps running under physical-mode, as the
// host has its own page tables. Relocation ends up breaking the host code.
// The easiest way is prevented this from happening is to nullify the relocation
// table.
unsafe {
*((image_base + 0x128) as *mut u32) = 0;
*((image_base + 0x12c) as *mut u32) = 0;
}

// Allocate separate stack space. This is never freed.
let layout = Layout::array::<Page>(0x10).unwrap();

let stack = unsafe { alloc_zeroed(layout) };

if stack.is_null() {
handle_alloc_error(layout);
}

let stack_base = stack as u64 + layout.size() as u64 - 0x10;
debug!("Stack range: {:#x?}", stack_base..stack as u64);

unsafe { switch_stack(regs, start_hypervisor as usize, stack_base) };
}

extern "efiapi" {
/// Jumps to the landing code with the new stack pointer.
fn switch_stack(regs: &GuestRegisters, landing_code: usize, stack_base: u64) -> !;
}

global_asm!(r#"
// The module containing the `switch_stack` function.
// Jumps to the landing code with the new stack pointer.
//
// fn switch_stack(regs: &GuestRegisters, landing_code: usize, stack_base: u64) -> !
.global switch_stack
switch_stack:
xchg bx, bx
mov rsp, r8
jmp rdx
"#);
90 changes: 90 additions & 0 deletions hypervisor/src/intel/capture.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
use core::arch::global_asm;

extern "efiapi" {
/// Captures current general purpose registers, RFLAGS, RSP, and RIP.
pub fn capture_registers(registers: &mut GuestRegisters);
}

/// The collection of the guest general purpose register values.
#[derive(Clone, Copy, Debug, Default)]
#[repr(C)]
pub struct GuestRegisters {
rax: u64,
rbx: u64,
rcx: u64,
rdx: u64,
rdi: u64,
rsi: u64,
rbp: u64,
r8: u64,
r9: u64,
r10: u64,
r11: u64,
r12: u64,
r13: u64,
r14: u64,
r15: u64,
rflags: u64,
rsp: u64,
rip: u64,
}

global_asm!(r#"
// The module containing the `capture_registers` function.
// Offsets to each field in the GuestRegisters struct.
.set registers_rax, 0x0
.set registers_rbx, 0x8
.set registers_rcx, 0x10
.set registers_rdx, 0x18
.set registers_rdi, 0x20
.set registers_rsi, 0x28
.set registers_rbp, 0x30
.set registers_r8, 0x38
.set registers_r9, 0x40
.set registers_r10, 0x48
.set registers_r11, 0x50
.set registers_r12, 0x58
.set registers_r13, 0x60
.set registers_r14, 0x68
.set registers_r15, 0x70
.set registers_rflags, 0x78
.set registers_rsp, 0x80
.set registers_rip, 0x88
// Captures current general purpose registers, RFLAGS, RSP, and RIP.
//
// extern "efiapi" fn capture_registers(registers: &mut GuestRegisters)
.global capture_registers
capture_registers:
// Capture general purpose registers.
mov [rcx + registers_rax], rax
mov [rcx + registers_rbx], rbx
mov [rcx + registers_rcx], rcx
mov [rcx + registers_rdx], rdx
mov [rcx + registers_rsi], rsi
mov [rcx + registers_rdi], rdi
mov [rcx + registers_rbp], rbp
mov [rcx + registers_r8], r8
mov [rcx + registers_r9], r9
mov [rcx + registers_r10], r10
mov [rcx + registers_r11], r11
mov [rcx + registers_r12], r12
mov [rcx + registers_r13], r13
mov [rcx + registers_r14], r14
mov [rcx + registers_r15], r15
// Capture RFLAGS, RSP, and RIP.
pushfq
pop rax
mov [rcx + registers_rflags], rax
mov rax, rsp
add rax, 8
mov [rcx + registers_rsp], rax
mov rax, [rsp]
mov [rcx + registers_rip], rax
ret
"#);
3 changes: 3 additions & 0 deletions hypervisor/src/intel/ept/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// pub mod hooks;
pub mod mtrr;
pub mod paging;
Loading

0 comments on commit d3e5da9

Please sign in to comment.