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_hlt(true);
|
||||||
primary_exec_ctrl.set_activate_secondary_controls(true);
|
primary_exec_ctrl.set_activate_secondary_controls(true);
|
||||||
primary_exec_ctrl.set_use_msr_bitmap(false);
|
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()?;
|
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 super::qual::QualIo;
|
||||||
use crate::{info, vmm::x86_64::intel::register::GuestRegisters};
|
use crate::{
|
||||||
|
info,
|
||||||
|
vmm::x86_64::intel::{register::GuestRegisters, vmwrite},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Serial {
|
pub struct Serial {
|
||||||
@ -17,6 +23,11 @@ pub enum InitPhase {
|
|||||||
Initialized,
|
Initialized,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum ReadSel {
|
||||||
|
IRR,
|
||||||
|
ISR,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct PIC {
|
pub struct PIC {
|
||||||
pub primary_mask: u8,
|
pub primary_mask: u8,
|
||||||
pub secondary_mask: u8,
|
pub secondary_mask: u8,
|
||||||
@ -24,6 +35,12 @@ pub struct PIC {
|
|||||||
pub secondary_phase: InitPhase,
|
pub secondary_phase: InitPhase,
|
||||||
pub primary_base: u8,
|
pub primary_base: u8,
|
||||||
pub secondary_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 {
|
impl PIC {
|
||||||
@ -35,6 +52,12 @@ impl PIC {
|
|||||||
secondary_phase: InitPhase::Uninitialized,
|
secondary_phase: InitPhase::Uninitialized,
|
||||||
primary_base: 0,
|
primary_base: 0,
|
||||||
secondary_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) {
|
pub fn handle_pic_in(&self, regs: &mut GuestRegisters, qual: QualIo) {
|
||||||
match qual.port() {
|
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 {
|
0x21 => match self.primary_phase {
|
||||||
InitPhase::Uninitialized | InitPhase::Initialized => {
|
InitPhase::Uninitialized | InitPhase::Initialized => {
|
||||||
regs.rax = self.primary_mask as u64;
|
regs.rax = self.primary_mask as u64;
|
||||||
@ -96,7 +133,15 @@ impl PIC {
|
|||||||
match qual.port() {
|
match qual.port() {
|
||||||
0x20 => match dx {
|
0x20 => match dx {
|
||||||
0x11 => pic.primary_phase = InitPhase::Phase1,
|
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),
|
_ => panic!("Primary PIC command: {:#x}", dx),
|
||||||
},
|
},
|
||||||
0x21 => match pic.primary_phase {
|
0x21 => match pic.primary_phase {
|
||||||
@ -115,7 +160,15 @@ impl PIC {
|
|||||||
},
|
},
|
||||||
0xA0 => match dx {
|
0xA0 => match dx {
|
||||||
0x11 => pic.secondary_phase = InitPhase::Phase1,
|
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),
|
_ => panic!("Secondary PIC command: {:#x}", dx),
|
||||||
},
|
},
|
||||||
0xA1 => match pic.secondary_phase {
|
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},
|
common::{self, read_msr},
|
||||||
intel::{
|
intel::{
|
||||||
auditor, controls, cpuid, ept,
|
auditor, controls, cpuid, ept,
|
||||||
|
io::IOBitmap,
|
||||||
msr::{self, ShadowMsr},
|
msr::{self, ShadowMsr},
|
||||||
qual::QualCr,
|
qual::{QualCr, QualIo},
|
||||||
register::GuestRegisters,
|
register::GuestRegisters,
|
||||||
vmcs::{
|
vmcs::{
|
||||||
self,
|
self,
|
||||||
@ -44,6 +45,8 @@ pub struct IntelVCpu {
|
|||||||
pub host_msr: ShadowMsr,
|
pub host_msr: ShadowMsr,
|
||||||
pub guest_msr: ShadowMsr,
|
pub guest_msr: ShadowMsr,
|
||||||
pub ia32e_enabled: bool,
|
pub ia32e_enabled: bool,
|
||||||
|
pic: super::io::PIC,
|
||||||
|
io_bitmap: IOBitmap,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntelVCpu {
|
impl IntelVCpu {
|
||||||
@ -97,6 +100,14 @@ impl IntelVCpu {
|
|||||||
|
|
||||||
self.step_next_inst()?;
|
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 => {
|
VmxExitReason::EPT_VIOLATION => {
|
||||||
let guest_address = vmread(vmcs::ro::GUEST_PHYSICAL_ADDR_FULL)?;
|
let guest_address = vmread(vmcs::ro::GUEST_PHYSICAL_ADDR_FULL)?;
|
||||||
info!("EPT Violation at guest address: {:#x}", guest_address);
|
info!("EPT Violation at guest address: {:#x}", guest_address);
|
||||||
@ -185,6 +196,7 @@ impl IntelVCpu {
|
|||||||
controls::setup_exit_controls()?;
|
controls::setup_exit_controls()?;
|
||||||
Self::setup_host_state()?;
|
Self::setup_host_state()?;
|
||||||
self.setup_guest_state()?;
|
self.setup_guest_state()?;
|
||||||
|
self.io_bitmap.setup()?;
|
||||||
|
|
||||||
self.init_guest_memory(frame_allocator)?;
|
self.init_guest_memory(frame_allocator)?;
|
||||||
|
|
||||||
@ -676,6 +688,8 @@ impl VCpu for IntelVCpu {
|
|||||||
host_msr: ShadowMsr::new(),
|
host_msr: ShadowMsr::new(),
|
||||||
guest_msr: ShadowMsr::new(),
|
guest_msr: ShadowMsr::new(),
|
||||||
ia32e_enabled: false,
|
ia32e_enabled: false,
|
||||||
|
pic: super::io::PIC::new(),
|
||||||
|
io_bitmap: IOBitmap::new(frame_allocator),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user