From a0188056f06fcdf080f2906ec53870f1f05d9b77 Mon Sep 17 00:00:00 2001 From: Masato Imai Date: Sun, 24 Aug 2025 12:14:02 +0000 Subject: [PATCH] Serial I/O virtualization #2 --- nel_os_kernel/src/serial.rs | 9 +++++ nel_os_kernel/src/vmm/x86_64/intel/io.rs | 48 +++++++++++++++++++++++- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/nel_os_kernel/src/serial.rs b/nel_os_kernel/src/serial.rs index faf3484..5ee848b 100644 --- a/nel_os_kernel/src/serial.rs +++ b/nel_os_kernel/src/serial.rs @@ -47,6 +47,15 @@ pub fn _print(args: ::core::fmt::Arguments) { }); } +#[inline(always)] +pub fn write_byte(byte: u8) { + use x86_64::instructions::interrupts; + + interrupts::without_interrupts(|| { + SERIAL1.lock().send(byte); + }); +} + #[macro_export] macro_rules! print { ($($arg:tt)*) => { diff --git a/nel_os_kernel/src/vmm/x86_64/intel/io.rs b/nel_os_kernel/src/vmm/x86_64/intel/io.rs index 0937f8a..3e7884f 100644 --- a/nel_os_kernel/src/vmm/x86_64/intel/io.rs +++ b/nel_os_kernel/src/vmm/x86_64/intel/io.rs @@ -1,10 +1,14 @@ -use x86::vmx::{self, vmcs}; +use x86::{ + io::inb, + vmx::{self, vmcs}, +}; use x86_64::structures::paging::{FrameAllocator, PhysFrame, Size4KiB}; use super::qual::QualIo; use crate::{ info, interrupt::subscriber::InterruptContext, + serial, vmm::x86_64::intel::{ register::GuestRegisters, vmcs::controls::EntryIntrInfo, vmread, vmwrite, }, @@ -37,6 +41,12 @@ pub enum ReadSel { Isr, } +#[derive(Debug, Clone, Copy, Default)] +pub struct Serial { + pub ier: u8, + pub mcr: u8, +} + pub struct Pic { pub primary_mask: u8, pub secondary_mask: u8, @@ -50,6 +60,7 @@ pub struct Pic { pub secondary_isr: u8, pub primary_read_sel: ReadSel, pub secondary_read_sel: ReadSel, + pub serial: Serial, } impl Pic { @@ -67,6 +78,7 @@ impl Pic { secondary_isr: 0, primary_read_sel: ReadSel::Irr, secondary_read_sel: ReadSel::Irr, + serial: Serial::default(), } } @@ -188,6 +200,7 @@ impl Pic { 0x20..=0x21 => self.handle_pic_in(regs, qual), 0xA0..=0xA1 => self.handle_pic_in(regs, qual), 0x0070..=0x0071 => regs.rax = 0, + 0x03F..=0x03FF => self.handle_serial_in(regs, qual), _ => regs.rax = 0, } } @@ -198,11 +211,43 @@ impl Pic { 0xC000..=0xCFFF => {} //ignore 0x20..=0x21 => self.handle_pic_out(regs, qual), 0xA0..=0xA1 => self.handle_pic_out(regs, qual), + 0x03F8..=0x03FF => self.handle_serial_out(regs, qual), 0x0070..=0x0071 => {} //ignore _ => {} } } + fn handle_serial_in(&self, regs: &mut GuestRegisters, qual: QualIo) { + match qual.port() { + 0x3F8 => regs.rax = unsafe { inb(qual.port()).into() }, + 0x3F9 => regs.rax = self.serial.ier as u64, + 0x3FA => regs.rax = unsafe { inb(qual.port()).into() }, + 0x3FB => regs.rax = 0, + 0x3FC => regs.rax = self.serial.mcr as u64, + 0x3FD => regs.rax = unsafe { inb(qual.port()).into() }, + 0x3FE => regs.rax = unsafe { inb(qual.port()).into() }, + 0x3FF => regs.rax = 0, + _ => { + panic!("Serial in: invalid port: {:#x}", qual.port()); + } + } + } + + fn handle_serial_out(&mut self, regs: &mut GuestRegisters, qual: QualIo) { + match qual.port() { + 0x3F8 => serial::write_byte(regs.rax as u8), + 0x3F9 => self.serial.ier = regs.rax as u8, + 0x3FA => {} + 0x3FB => {} + 0x3FC => self.serial.mcr = regs.rax as u8, + 0x3FD => {} + 0x3FF => {} + _ => { + panic!("Serial out: invalid port: {:#x}", qual.port()); + } + } + } + fn handle_pic_in(&self, regs: &mut GuestRegisters, qual: QualIo) { match qual.port() { 0x20 => { @@ -324,7 +369,6 @@ impl IOBitmap { 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)?;