io bitmap
Some checks failed
Check / Build ISO (nightly-2025-04-27) (push) Failing after 45s

This commit is contained in:
Masato Imai
2025-08-22 12:18:50 +00:00
parent de21059b53
commit 94cbcd6a1f
3 changed files with 138 additions and 4 deletions

View File

@ -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()?;

View File

@ -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)
}
}
}

View File

@ -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),
}) })
} }