Compare commits

...

2 Commits

Author SHA1 Message Date
Masato Imai
1606184551 Serial I/O buffer #2
All checks were successful
Check / Build ISO (nightly-2025-04-27) (push) Successful in 42s
2025-08-24 12:24:53 +00:00
Masato Imai
a0188056f0 Serial I/O virtualization #2 2025-08-24 12:14:02 +00:00
2 changed files with 106 additions and 2 deletions

View File

@@ -47,6 +47,27 @@ 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);
});
}
#[inline(always)]
pub fn write_bytes(bytes: &[u8]) {
use x86_64::instructions::interrupts;
interrupts::without_interrupts(|| {
let mut serial = SERIAL1.lock();
for &b in bytes {
serial.send(b);
}
});
}
#[macro_export] #[macro_export]
macro_rules! print { macro_rules! print {
($($arg:tt)*) => { ($($arg:tt)*) => {

View File

@@ -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 x86_64::structures::paging::{FrameAllocator, PhysFrame, Size4KiB};
use super::qual::QualIo; use super::qual::QualIo;
use crate::{ use crate::{
info, info,
interrupt::subscriber::InterruptContext, interrupt::subscriber::InterruptContext,
serial,
vmm::x86_64::intel::{ vmm::x86_64::intel::{
register::GuestRegisters, vmcs::controls::EntryIntrInfo, vmread, vmwrite, register::GuestRegisters, vmcs::controls::EntryIntrInfo, vmread, vmwrite,
}, },
@@ -37,6 +41,12 @@ pub enum ReadSel {
Isr, Isr,
} }
#[derive(Debug, Clone, Copy, Default)]
pub struct Serial {
pub ier: u8,
pub mcr: u8,
}
pub struct Pic { pub struct Pic {
pub primary_mask: u8, pub primary_mask: u8,
pub secondary_mask: u8, pub secondary_mask: u8,
@@ -50,6 +60,8 @@ pub struct Pic {
pub secondary_isr: u8, pub secondary_isr: u8,
pub primary_read_sel: ReadSel, pub primary_read_sel: ReadSel,
pub secondary_read_sel: ReadSel, pub secondary_read_sel: ReadSel,
pub serial: Serial,
pub serial_buffer: SerialBuffer,
} }
impl Pic { impl Pic {
@@ -67,6 +79,8 @@ impl Pic {
secondary_isr: 0, secondary_isr: 0,
primary_read_sel: ReadSel::Irr, primary_read_sel: ReadSel::Irr,
secondary_read_sel: ReadSel::Irr, secondary_read_sel: ReadSel::Irr,
serial: Serial::default(),
serial_buffer: SerialBuffer::default(),
} }
} }
@@ -188,6 +202,7 @@ impl Pic {
0x20..=0x21 => self.handle_pic_in(regs, qual), 0x20..=0x21 => self.handle_pic_in(regs, qual),
0xA0..=0xA1 => self.handle_pic_in(regs, qual), 0xA0..=0xA1 => self.handle_pic_in(regs, qual),
0x0070..=0x0071 => regs.rax = 0, 0x0070..=0x0071 => regs.rax = 0,
0x03F..=0x03FF => self.handle_serial_in(regs, qual),
_ => regs.rax = 0, _ => regs.rax = 0,
} }
} }
@@ -198,11 +213,53 @@ impl Pic {
0xC000..=0xCFFF => {} //ignore 0xC000..=0xCFFF => {} //ignore
0x20..=0x21 => self.handle_pic_out(regs, qual), 0x20..=0x21 => self.handle_pic_out(regs, qual),
0xA0..=0xA1 => 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 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 => {
let byte = regs.rax as u8;
if self.serial_buffer.end < self.serial_buffer.buffer.len() {
self.serial_buffer.buffer[self.serial_buffer.end] = byte;
self.serial_buffer.end += 1;
}
if byte == b'\n' || self.serial_buffer.end == self.serial_buffer.buffer.len() {
self.serial_buffer.flush();
}
}
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) { fn handle_pic_in(&self, regs: &mut GuestRegisters, qual: QualIo) {
match qual.port() { match qual.port() {
0x20 => { 0x20 => {
@@ -324,7 +381,6 @@ impl IOBitmap {
core::ptr::write_bytes(bitmap_b_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); self.set_io_ports(0x0040..=0x0047);
vmwrite(vmcs::control::IO_BITMAP_A_ADDR_FULL, bitmap_a_addr as u64)?; vmwrite(vmcs::control::IO_BITMAP_A_ADDR_FULL, bitmap_a_addr as u64)?;
@@ -362,3 +418,30 @@ impl IOBitmap {
} }
} }
} }
#[derive(Debug, Clone, Copy)]
pub struct SerialBuffer {
pub buffer: [u8; 1024],
pub end: usize,
}
impl SerialBuffer {
pub fn flush(&mut self) {
if self.end == 0 {
return;
}
serial::write_bytes(&self.buffer[..self.end]);
self.end = 0;
}
}
impl Default for SerialBuffer {
fn default() -> Self {
Self {
buffer: [0; 1024],
end: 0,
}
}
}