diff --git a/src/devices/bochs.rs b/src/devices/bochs.rs new file mode 100644 index 0000000..f51b3ba --- /dev/null +++ b/src/devices/bochs.rs @@ -0,0 +1,76 @@ +use super::pci::{find_pci_device, PciDevice, PciHeader}; +use x86_64::instructions::port::Port; + +const BOCHS_ID: u32 = 0x1111_1234; +const BOCHS_INDEX_PORT_ADDRESS: u16 = 0x01CE; +const BOCHS_DATA_PORT_ADDRESS: u16 = 0x01CF; + +const VBE_DISPI_INDEX_XRES: u16 = 0x01; +const VBE_DISPI_INDEX_YRES: u16 = 0x02; +const VBE_DISPI_INDEX_BPP: u16 = 0x03; +const VBE_DISPI_INDEX_ENABLE: u16 = 0x04; + +const VBE_DISPI_GETCAPS: u16 = 0x02; + +#[derive(Debug, Copy, Clone)] +pub struct Capabilities { + width: u16, + height: u16, + bpp: u16, +} + +#[derive(Debug)] +pub struct BochsDevice { + index_port: Port, + data_port: Port, + pci_device: PciDevice, +} + +impl BochsDevice { + pub fn new() -> Option { + if let Some(pci_device) = find_pci_device(BOCHS_ID) { + let index_port = Port::new(BOCHS_INDEX_PORT_ADDRESS); + let data_port = Port::new(BOCHS_DATA_PORT_ADDRESS); + Some(BochsDevice { + pci_device, + index_port, + data_port, + }) + } else { + None + } + } + + pub fn base_address(&self) -> u32 { + match self.pci_device.pci_header { + PciHeader::PciHeaderType0 { base_addresses, .. } => base_addresses[0] & 0xFFFF_FFF0, + } + } + + pub fn capabilities(&mut self) -> Capabilities { + unsafe { + // Save original value of VBE_DISPI_INDEX_ENABLE + self.index_port.write(VBE_DISPI_INDEX_ENABLE); + let original_value = self.data_port.read(); + self.data_port.write(VBE_DISPI_GETCAPS); + + // Read max width + self.index_port.write(VBE_DISPI_INDEX_XRES); + let width = self.data_port.read(); + + // Read max height + self.index_port.write(VBE_DISPI_INDEX_YRES); + let height = self.data_port.read(); + + // Read max bpp + self.index_port.write(VBE_DISPI_INDEX_BPP); + let bpp = self.data_port.read(); + + // Restore original VBE_DISPI_INDEX_ENABLE + self.index_port.write(VBE_DISPI_INDEX_ENABLE); + self.data_port.write(original_value); + + Capabilities { width, height, bpp } + } + } +} diff --git a/src/devices/mod.rs b/src/devices/mod.rs new file mode 100644 index 0000000..16e8e0b --- /dev/null +++ b/src/devices/mod.rs @@ -0,0 +1,4 @@ +pub mod bochs; +mod pci; + +pub use bochs::BochsDevice; diff --git a/src/devices/pci.rs b/src/devices/pci.rs new file mode 100644 index 0000000..f9573d5 --- /dev/null +++ b/src/devices/pci.rs @@ -0,0 +1,141 @@ +use x86_64::instructions::port::Port; + +const BUSSES: u32 = 256; +const SLOTS: u32 = 32; +const FUNCTIONS: u32 = 8; + +const CONFIG_ADDRESS: u16 = 0xCF8; +const DATA_ADDRESS: u16 = 0xCFC; + +#[derive(Debug, Copy, Clone)] +pub(crate) struct PciDevice { + vendor_id: u16, + device_id: u16, + command: u16, + status: u16, + revision_id: u8, + prog_if: u8, + sub_class: u8, + base_class: u8, + cache_line_size: u8, + latency_timer: u8, + header_type: u8, + bist: u8, + pub(crate) pci_header: PciHeader, +} + +#[derive(Debug, Copy, Clone)] +pub(crate) enum PciHeader { + PciHeaderType0 { + base_addresses: [u32; 6], + cis: u32, + sub_vendor_id: u16, + sub_system_id: u16, + rom_base_address: u32, + reserved_2: [u32; 2], + interrupt_line: u8, + interrupt_pin: u8, + minimum_grant: u8, + maximum_latency: u8, + }, +} + +pub(crate) fn find_pci_device(device_id: u32) -> Option { + for bus in 0..BUSSES { + for slot in 0..SLOTS { + for function in 0..FUNCTIONS { + let address = (bus << 16) | (slot << 11) | (function << 8) | 0x8000_0000; + if read_offset(address, 0) == device_id { + return Some(read_device(address)); + } + } + } + } + None +} + +fn read_device(address: u32) -> PciDevice { + let (device_id, vendor_id) = read_2_words(address, 0x00); + let (status, command) = read_2_words(address, 0x04); + let (base_class, sub_class, prog_if, revision_id) = read_4_bytes(address, 0x08); + let (bist, header_type, latency_timer, cache_line_size) = read_4_bytes(address, 0x0C); + let pci_header = read_header_type_0(address); + + PciDevice { + vendor_id, + device_id, + status, + command, + base_class, + sub_class, + prog_if, + revision_id, + bist, + header_type, + latency_timer, + cache_line_size, + pci_header, + } +} + +fn read_header_type_0(address: u32) -> PciHeader { + let mut base_addresses = [0u32; 6]; + base_addresses[0] = read_offset(address, 0x10); + base_addresses[1] = read_offset(address, 0x14); + base_addresses[2] = read_offset(address, 0x18); + base_addresses[3] = read_offset(address, 0x1C); + base_addresses[4] = read_offset(address, 0x20); + base_addresses[5] = read_offset(address, 0x24); + let cis = read_offset(address, 0x28); + let (sub_system_id, sub_vendor_id) = read_2_words(address, 0x2C); + let rom_base_address = read_offset(address, 0x30); + let mut reserved_2 = [0u32; 2]; + reserved_2[0] = read_offset(address, 0x34); + reserved_2[1] = read_offset(address, 0x38); + let (maximum_latency, minimum_grant, interrupt_pin, interrupt_line) = + read_4_bytes(address, 0x3C); + + PciHeader::PciHeaderType0 { + base_addresses, + cis, + sub_system_id, + sub_vendor_id, + rom_base_address, + reserved_2, + maximum_latency, + minimum_grant, + interrupt_pin, + interrupt_line, + } +} + +fn read_2_words(address: u32, offset: u32) -> (u16, u16) { + let value = read_offset(address, offset); + let high_word = (value >> 16) as u16; + let low_word = value as u16; + (high_word, low_word) +} + +fn read_4_bytes(address: u32, offset: u32) -> (u8, u8, u8, u8) { + let value = read_offset(address, offset); + let high_word_high_byte = (value >> 24) as u8; + let high_word_low_byte = (value >> 16) as u8; + let low_word_high_byte = (value >> 8) as u8; + let low_wird_low_byte = value as u8; + ( + high_word_high_byte, + high_word_low_byte, + low_word_high_byte, + low_wird_low_byte, + ) +} + +fn read_offset(mut address: u32, offset: u32) -> u32 { + let mut config_address = Port::new(CONFIG_ADDRESS); + let mut data_address = Port::new(DATA_ADDRESS); + address |= offset & 0xFC; + unsafe { + config_address.write(address); + data_address.read() + } +} diff --git a/src/lib.rs b/src/lib.rs index 06b9ff5..1690279 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,7 @@ pub mod colors; pub mod configurations; +pub mod devices; pub mod drawing; pub mod fonts; pub mod registers;