return AuthenticAMD

This commit is contained in:
Masato Imai
2025-06-25 07:16:36 +00:00
parent bd96723361
commit 993776487b
3 changed files with 63 additions and 21 deletions

View File

@@ -6,7 +6,7 @@ use super::{vcpu::VCpu, vmcs::VmxLeaf};
pub fn handle_cpuid_exit(vcpu: &mut VCpu) { pub fn handle_cpuid_exit(vcpu: &mut VCpu) {
let regs = &mut vcpu.guest_registers; let regs = &mut vcpu.guest_registers;
let vendor: &[u8; 12] = b"miHypervisor"; let vendor: &[u8; 12] = b"AuthenticAMD";
let brand_string: &[u8; 48] = b"mii Hypervisor CPU on Intel VT-x \0"; let brand_string: &[u8; 48] = b"mii Hypervisor CPU on Intel VT-x \0";
let vendor = unsafe { core::mem::transmute::<&[u8; 12], &[u32; 3]>(vendor) }; let vendor = unsafe { core::mem::transmute::<&[u8; 12], &[u32; 3]>(vendor) };

View File

@@ -133,6 +133,13 @@ impl ShadowMsr {
} }
x86::msr::IA32_KERNEL_GSBASE => Self::shadow_read(vcpu, msr_kind), x86::msr::IA32_KERNEL_GSBASE => Self::shadow_read(vcpu, msr_kind),
0x1b => Self::shadow_read(vcpu, msr_kind), 0x1b => Self::shadow_read(vcpu, msr_kind),
0x8b => Self::set_ret_val(vcpu, 0x8701021),
0xc0011029 => Self::set_ret_val(vcpu, 0x3000310e08202),
0xc0010000 => Self::set_ret_val(vcpu, 0x130076),
0xc0010001 => Self::set_ret_val(vcpu, 0),
0xc0010002 => Self::set_ret_val(vcpu, 0),
0xc0010003 => Self::set_ret_val(vcpu, 0),
0xc0010007 => Self::set_ret_val(vcpu, 0),
_ => { _ => {
panic!("Unhandled RDMSR: {:#x}", msr_kind); panic!("Unhandled RDMSR: {:#x}", msr_kind);
} }
@@ -172,6 +179,7 @@ impl ShadowMsr {
x86::msr::IA32_FS_BASE => unsafe { vmwrite(vmcs::guest::FS_BASE, value).unwrap() }, x86::msr::IA32_FS_BASE => unsafe { vmwrite(vmcs::guest::FS_BASE, value).unwrap() },
x86::msr::IA32_GS_BASE => unsafe { vmwrite(vmcs::guest::GS_BASE, value).unwrap() }, x86::msr::IA32_GS_BASE => unsafe { vmwrite(vmcs::guest::GS_BASE, value).unwrap() },
0x1b => Self::shadow_write(vcpu, msr_kind), 0x1b => Self::shadow_write(vcpu, msr_kind),
0xc0010007 => Self::shadow_write(vcpu, msr_kind),
_ => { _ => {
panic!("Unhandled WRMSR: {:#x}", msr_kind); panic!("Unhandled WRMSR: {:#x}", msr_kind);

View File

@@ -50,7 +50,8 @@ use super::{
const SIZE_2MIB: u64 = 2 * 1024 * 1024; const SIZE_2MIB: u64 = 2 * 1024 * 1024;
static EPT_FRAME_ALLOCATOR: AtomicPtr<BootInfoFrameAllocator> = AtomicPtr::new(core::ptr::null_mut()); static EPT_FRAME_ALLOCATOR: AtomicPtr<BootInfoFrameAllocator> =
AtomicPtr::new(core::ptr::null_mut());
#[repr(C)] #[repr(C)]
pub struct VCpu { pub struct VCpu {
@@ -193,7 +194,7 @@ impl VCpu {
mapper: &OffsetPageTable<'static>, mapper: &OffsetPageTable<'static>,
) { ) {
EPT_FRAME_ALLOCATOR.store(frame_allocator as *mut _, Ordering::Release); EPT_FRAME_ALLOCATOR.store(frame_allocator as *mut _, Ordering::Release);
self.vmxon.activate_vmxon().unwrap(); self.vmxon.activate_vmxon().unwrap();
let revision_id = unsafe { rdmsr(x86::msr::IA32_VMX_BASIC) } as u32; let revision_id = unsafe { rdmsr(x86::msr::IA32_VMX_BASIC) } as u32;
@@ -241,7 +242,7 @@ impl VCpu {
let cmdline_start = linux::LAYOUT_CMDLINE as u64; let cmdline_start = linux::LAYOUT_CMDLINE as u64;
let cmdline_end = cmdline_start + cmdline_max_size as u64; let cmdline_end = cmdline_start + cmdline_max_size as u64;
let cmdline_bytes = b"console=ttyS0 earlyprintk=serial nokaslr\0"; let cmdline_bytes = b"console=ttyS0 earlyprintk=serial nokaslr\0";
self.load_image(cmdline_bytes, cmdline_start as usize); self.load_image(cmdline_bytes, cmdline_start as usize);
@@ -272,21 +273,23 @@ impl VCpu {
pub fn load_image(&mut self, image: &[u8], addr: usize) { pub fn load_image(&mut self, image: &[u8], addr: usize) {
info!("Loading image at {:#x}, size: {} bytes", addr, image.len()); info!("Loading image at {:#x}, size: {} bytes", addr, image.len());
let start_page = addr & !0xFFF; let start_page = addr & !0xFFF;
let end_page = ((addr + image.len() - 1) & !0xFFF) + 0x1000; let end_page = ((addr + image.len() - 1) & !0xFFF) + 0x1000;
unsafe { unsafe {
let frame_allocator_ptr = EPT_FRAME_ALLOCATOR.load(Ordering::Acquire); let frame_allocator_ptr = EPT_FRAME_ALLOCATOR.load(Ordering::Acquire);
if !frame_allocator_ptr.is_null() { if !frame_allocator_ptr.is_null() {
let frame_allocator = &mut *(frame_allocator_ptr as *mut BootInfoFrameAllocator); let frame_allocator = &mut *(frame_allocator_ptr as *mut BootInfoFrameAllocator);
let mut current_page = start_page; let mut current_page = start_page;
while current_page < end_page { while current_page < end_page {
if self.ept.get_phys_addr(current_page as u64).is_none() { if self.ept.get_phys_addr(current_page as u64).is_none() {
if let Some(frame) = frame_allocator.allocate_frame() { if let Some(frame) = frame_allocator.allocate_frame() {
let hpa = frame.start_address().as_u64(); let hpa = frame.start_address().as_u64();
self.ept.map_4k(current_page as u64, hpa, frame_allocator).unwrap(); self.ept
.map_4k(current_page as u64, hpa, frame_allocator)
.unwrap();
} else { } else {
panic!("Failed to allocate frame for image at {:#x}", current_page); panic!("Failed to allocate frame for image at {:#x}", current_page);
} }
@@ -295,7 +298,7 @@ impl VCpu {
} }
} }
} }
for (i, &byte) in image.iter().enumerate() { for (i, &byte) in image.iter().enumerate() {
let gpa = addr + i; let gpa = addr + i;
self.ept.set(gpa as u64, byte).unwrap(); self.ept.set(gpa as u64, byte).unwrap();
@@ -305,8 +308,10 @@ impl VCpu {
pub fn setup_guest_memory(&mut self, frame_allocator: &mut BootInfoFrameAllocator) -> u64 { pub fn setup_guest_memory(&mut self, frame_allocator: &mut BootInfoFrameAllocator) -> u64 {
let guest_memory_size = 2 * 1024 * 1024 * 1024; let guest_memory_size = 2 * 1024 * 1024 * 1024;
info!("Setting up guest memory with on-demand allocation (reported size: {}MB)", info!(
guest_memory_size / (1024 * 1024)); "Setting up guest memory with on-demand allocation (reported size: {}MB)",
guest_memory_size / (1024 * 1024)
);
self.load_kernel(linux::BZIMAGE, guest_memory_size); self.load_kernel(linux::BZIMAGE, guest_memory_size);
@@ -354,6 +359,7 @@ impl VCpu {
.set(x86::msr::MSR_C5_PMON_BOX_CTRL, 0) .set(x86::msr::MSR_C5_PMON_BOX_CTRL, 0)
.unwrap(); .unwrap();
self.guest_msr.set(0x1b, 0).unwrap(); self.guest_msr.set(0x1b, 0).unwrap();
self.guest_msr.set(0xc0010007, 0).unwrap();
vmwrite( vmwrite(
vmcs::control::VMEXIT_MSR_LOAD_ADDR_FULL, vmcs::control::VMEXIT_MSR_LOAD_ADDR_FULL,
@@ -981,7 +987,10 @@ impl VCpu {
fn handle_ept_violation(&mut self, gpa: u64) { fn handle_ept_violation(&mut self, gpa: u64) {
if gpa >= 2 * 1024 * 1024 * 1024 { if gpa >= 2 * 1024 * 1024 * 1024 {
panic!("EPT Violation: Guest tried to access memory beyond 2GB at {:#x}", gpa); panic!(
"EPT Violation: Guest tried to access memory beyond 2GB at {:#x}",
gpa
);
} }
unsafe { unsafe {
@@ -989,19 +998,22 @@ impl VCpu {
if frame_allocator_ptr.is_null() { if frame_allocator_ptr.is_null() {
panic!("EPT Violation: Frame allocator not initialized!"); panic!("EPT Violation: Frame allocator not initialized!");
} }
let frame_allocator = &mut *(frame_allocator_ptr as *mut BootInfoFrameAllocator); let frame_allocator = &mut *(frame_allocator_ptr as *mut BootInfoFrameAllocator);
match frame_allocator.allocate_frame() { match frame_allocator.allocate_frame() {
Some(frame) => { Some(frame) => {
let hpa = frame.start_address().as_u64(); let hpa = frame.start_address().as_u64();
if let Err(e) = self.ept.map_4k(gpa, hpa, frame_allocator) { if let Err(e) = self.ept.map_4k(gpa, hpa, frame_allocator) {
panic!("Failed to map page at GPA {:#x}: {}", gpa, e); panic!("Failed to map page at GPA {:#x}: {}", gpa, e);
} }
} }
None => { None => {
panic!("EPT Violation: Out of memory! Cannot allocate frame for GPA {:#x}", gpa); panic!(
"EPT Violation: Out of memory! Cannot allocate frame for GPA {:#x}",
gpa
);
} }
} }
} }
@@ -1153,29 +1165,51 @@ impl VCpu {
0x01 => match instruction_bytes[2] { 0x01 => match instruction_bytes[2] {
0xCA => { 0xCA => {
unsafe { unsafe {
let rflags = vmread(vmcs::guest::RFLAGS).unwrap(); let rflags =
vmwrite(vmcs::guest::RFLAGS, rflags & !(1 << 18)).unwrap(); vmread(vmcs::guest::RFLAGS).unwrap();
vmwrite(
vmcs::guest::RFLAGS,
rflags & !(1 << 18),
)
.unwrap();
} }
self.step_next_inst().unwrap(); self.step_next_inst().unwrap();
} }
0xCB => { 0xCB => {
unsafe { unsafe {
let rflags = vmread(vmcs::guest::RFLAGS).unwrap(); let rflags =
vmwrite(vmcs::guest::RFLAGS, rflags | (1 << 18)).unwrap(); vmread(vmcs::guest::RFLAGS).unwrap();
vmwrite(
vmcs::guest::RFLAGS,
rflags | (1 << 18),
)
.unwrap();
} }
self.step_next_inst().unwrap(); self.step_next_inst().unwrap();
} }
_ => { _ => {
info!(
"VMExit: Exception {} at RIP {:#x} with instruction bytes: {:?}",
vector, rip, &instruction_bytes
);
self.inject_exception(vector, error_code).unwrap(); self.inject_exception(vector, error_code).unwrap();
} }
}, },
_ => { _ => {
info!(
"VMExit: Exception {} at RIP {:#x} with instruction bytes: {:?}",
vector, rip, &instruction_bytes
);
self.inject_exception(vector, error_code).unwrap(); self.inject_exception(vector, error_code).unwrap();
} }
} }
} }
} }
_ => { _ => {
info!(
"VMExit: Exception {} at RIP {:#x} with instruction bytes: {:?}",
vector, rip, &instruction_bytes
);
self.inject_exception(vector, error_code).unwrap(); self.inject_exception(vector, error_code).unwrap();
} }
} }
@@ -1215,7 +1249,7 @@ impl VCpu {
let translation_valid = (exit_qualification & 0x100) != 0; let translation_valid = (exit_qualification & 0x100) != 0;
let page_addr = guest_address & !0xFFF; let page_addr = guest_address & !0xFFF;
self.handle_ept_violation(page_addr); self.handle_ept_violation(page_addr);
} }
_ => { _ => {