This commit is contained in:
@ -36,6 +36,8 @@ pub fn setup_exec_controls() -> Result<(), &'static str> {
|
||||
primary_exec_ctrl.set_hlt(true);
|
||||
primary_exec_ctrl.set_activate_secondary_controls(true);
|
||||
primary_exec_ctrl.set_use_msr_bitmap(false);
|
||||
primary_exec_ctrl.set_unconditional_io(false);
|
||||
primary_exec_ctrl.set_use_io_bitmap(true);
|
||||
|
||||
primary_exec_ctrl.write()?;
|
||||
|
||||
|
@ -1,5 +1,11 @@
|
||||
use x86::vmx::vmcs;
|
||||
use x86_64::structures::paging::{FrameAllocator, PhysFrame, Size4KiB};
|
||||
|
||||
use super::qual::QualIo;
|
||||
use crate::{info, vmm::x86_64::intel::register::GuestRegisters};
|
||||
use crate::{
|
||||
info,
|
||||
vmm::x86_64::intel::{register::GuestRegisters, vmwrite},
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Serial {
|
||||
@ -17,6 +23,11 @@ pub enum InitPhase {
|
||||
Initialized,
|
||||
}
|
||||
|
||||
enum ReadSel {
|
||||
IRR,
|
||||
ISR,
|
||||
}
|
||||
|
||||
pub struct PIC {
|
||||
pub primary_mask: u8,
|
||||
pub secondary_mask: u8,
|
||||
@ -24,6 +35,12 @@ pub struct PIC {
|
||||
pub secondary_phase: InitPhase,
|
||||
pub primary_base: u8,
|
||||
pub secondary_base: u8,
|
||||
pub primary_irr: u8,
|
||||
pub primary_isr: u8,
|
||||
pub secondary_irr: u8,
|
||||
pub secondary_isr: u8,
|
||||
pub primary_read_sel: ReadSel,
|
||||
pub secondary_read_sel: ReadSel,
|
||||
}
|
||||
|
||||
impl PIC {
|
||||
@ -35,6 +52,12 @@ impl PIC {
|
||||
secondary_phase: InitPhase::Uninitialized,
|
||||
primary_base: 0,
|
||||
secondary_base: 0,
|
||||
primary_irr: 0,
|
||||
primary_isr: 0,
|
||||
secondary_irr: 0,
|
||||
secondary_isr: 0,
|
||||
primary_read_sel: ReadSel::IRR,
|
||||
secondary_read_sel: ReadSel::IRR,
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,6 +97,20 @@ impl PIC {
|
||||
|
||||
pub fn handle_pic_in(&self, regs: &mut GuestRegisters, qual: QualIo) {
|
||||
match qual.port() {
|
||||
0x20 => {
|
||||
let v = match self.primary_read_sel {
|
||||
ReadSel::IRR => self.primary_irr,
|
||||
ReadSel::ISR => self.primary_isr,
|
||||
};
|
||||
regs.rax = v as u64;
|
||||
}
|
||||
0xA0 => {
|
||||
let v = match self.secondary_read_sel {
|
||||
ReadSel::IRR => self.secondary_irr,
|
||||
ReadSel::ISR => self.secondary_isr,
|
||||
};
|
||||
regs.rax = v as u64;
|
||||
}
|
||||
0x21 => match self.primary_phase {
|
||||
InitPhase::Uninitialized | InitPhase::Initialized => {
|
||||
regs.rax = self.primary_mask as u64;
|
||||
@ -96,7 +133,15 @@ impl PIC {
|
||||
match qual.port() {
|
||||
0x20 => match dx {
|
||||
0x11 => pic.primary_phase = InitPhase::Phase1,
|
||||
0x60..=0x67 => {}
|
||||
0x0A => pic.primary_read_sel = ReadSel::ISR,
|
||||
0x0B => pic.primary_read_sel = ReadSel::IRR,
|
||||
0x20 => {
|
||||
pic.primary_isr = 0;
|
||||
}
|
||||
0x60..=0x67 => {
|
||||
let irq = dx & 0x7;
|
||||
pic.primary_isr &= !(1 << irq);
|
||||
}
|
||||
_ => panic!("Primary PIC command: {:#x}", dx),
|
||||
},
|
||||
0x21 => match pic.primary_phase {
|
||||
@ -115,7 +160,15 @@ impl PIC {
|
||||
},
|
||||
0xA0 => match dx {
|
||||
0x11 => pic.secondary_phase = InitPhase::Phase1,
|
||||
0x60..=0x67 => {}
|
||||
0x0A => pic.secondary_read_sel = ReadSel::ISR,
|
||||
0x0B => pic.secondary_read_sel = ReadSel::IRR,
|
||||
0x20 => {
|
||||
pic.secondary_isr = 0;
|
||||
}
|
||||
0x60..=0x67 => {
|
||||
let irq = dx & 0x7;
|
||||
pic.secondary_isr &= !(1 << irq);
|
||||
}
|
||||
_ => panic!("Secondary PIC command: {:#x}", dx),
|
||||
},
|
||||
0xA1 => match pic.secondary_phase {
|
||||
@ -136,3 +189,68 @@ impl PIC {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IOBitmap {
|
||||
pub bitmap_a: PhysFrame,
|
||||
pub bitmap_b: PhysFrame,
|
||||
}
|
||||
|
||||
impl IOBitmap {
|
||||
pub fn new(frame_allocator: &mut impl FrameAllocator<Size4KiB>) -> Self {
|
||||
let bitmap_a = frame_allocator
|
||||
.allocate_frame()
|
||||
.expect("Failed to allocate I/O bitmap A");
|
||||
let bitmap_b = frame_allocator
|
||||
.allocate_frame()
|
||||
.expect("Failed to allocate I/O bitmap B");
|
||||
|
||||
Self { bitmap_a, bitmap_b }
|
||||
}
|
||||
|
||||
pub fn setup(&mut self) -> Result<(), &'static str> {
|
||||
let bitmap_a_addr = self.bitmap_a.start_address().as_u64() as usize;
|
||||
let bitmap_b_addr = self.bitmap_b.start_address().as_u64() as usize;
|
||||
|
||||
unsafe {
|
||||
core::ptr::write_bytes(bitmap_a_addr as *mut u8, u8::MAX, 4096);
|
||||
core::ptr::write_bytes(bitmap_b_addr as *mut u8, u8::MAX, 4096);
|
||||
}
|
||||
|
||||
self.set_io_ports(0x02F8..=0x03FF);
|
||||
self.set_io_ports(0x0040..=0x0047);
|
||||
|
||||
vmwrite(vmcs::control::IO_BITMAP_A_ADDR_FULL, bitmap_a_addr as u64)?;
|
||||
vmwrite(vmcs::control::IO_BITMAP_B_ADDR_FULL, bitmap_b_addr as u64)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_io_ports(&mut self, ports: core::ops::RangeInclusive<u16>) {
|
||||
for port in ports {
|
||||
if port <= 0x7FFF {
|
||||
let byte_index = port as usize / 8;
|
||||
let bit_index = port as usize % 8;
|
||||
|
||||
self.get_bitmap_a()[byte_index] &= !(1 << bit_index);
|
||||
} else {
|
||||
let adjusted_port = port - 0x8000;
|
||||
let byte_index = adjusted_port as usize / 8;
|
||||
let bit_index = adjusted_port as usize % 8;
|
||||
|
||||
self.get_bitmap_b()[byte_index] &= !(1 << bit_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_bitmap_a(&self) -> &mut [u8] {
|
||||
unsafe {
|
||||
core::slice::from_raw_parts_mut(self.bitmap_a.start_address().as_u64() as *mut u8, 4096)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_bitmap_b(&self) -> &mut [u8] {
|
||||
unsafe {
|
||||
core::slice::from_raw_parts_mut(self.bitmap_b.start_address().as_u64() as *mut u8, 4096)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,8 +12,9 @@ use crate::{
|
||||
common::{self, read_msr},
|
||||
intel::{
|
||||
auditor, controls, cpuid, ept,
|
||||
io::IOBitmap,
|
||||
msr::{self, ShadowMsr},
|
||||
qual::QualCr,
|
||||
qual::{QualCr, QualIo},
|
||||
register::GuestRegisters,
|
||||
vmcs::{
|
||||
self,
|
||||
@ -44,6 +45,8 @@ pub struct IntelVCpu {
|
||||
pub host_msr: ShadowMsr,
|
||||
pub guest_msr: ShadowMsr,
|
||||
pub ia32e_enabled: bool,
|
||||
pic: super::io::PIC,
|
||||
io_bitmap: IOBitmap,
|
||||
}
|
||||
|
||||
impl IntelVCpu {
|
||||
@ -97,6 +100,14 @@ impl IntelVCpu {
|
||||
|
||||
self.step_next_inst()?;
|
||||
}
|
||||
VmxExitReason::IO_INSTRUCTION => {
|
||||
let qual = vmread(vmcs::ro::EXIT_QUALIFICATION)?;
|
||||
let qual_io = QualIo::from(qual);
|
||||
|
||||
self.pic.handle_io(&mut self.guest_registers, qual_io);
|
||||
|
||||
self.step_next_inst()?;
|
||||
}
|
||||
VmxExitReason::EPT_VIOLATION => {
|
||||
let guest_address = vmread(vmcs::ro::GUEST_PHYSICAL_ADDR_FULL)?;
|
||||
info!("EPT Violation at guest address: {:#x}", guest_address);
|
||||
@ -185,6 +196,7 @@ impl IntelVCpu {
|
||||
controls::setup_exit_controls()?;
|
||||
Self::setup_host_state()?;
|
||||
self.setup_guest_state()?;
|
||||
self.io_bitmap.setup()?;
|
||||
|
||||
self.init_guest_memory(frame_allocator)?;
|
||||
|
||||
@ -676,6 +688,8 @@ impl VCpu for IntelVCpu {
|
||||
host_msr: ShadowMsr::new(),
|
||||
guest_msr: ShadowMsr::new(),
|
||||
ia32e_enabled: false,
|
||||
pic: super::io::PIC::new(),
|
||||
io_bitmap: IOBitmap::new(frame_allocator),
|
||||
})
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user