Initial setup/testing

This commit is contained in:
Ryan Kennedy 2020-04-06 22:29:29 -05:00
parent 39ad683665
commit df0660f5ed
4 changed files with 222 additions and 0 deletions

76
src/devices/bochs.rs Normal file
View file

@ -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<u16>,
data_port: Port<u16>,
pci_device: PciDevice,
}
impl BochsDevice {
pub fn new() -> Option<BochsDevice> {
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 }
}
}
}

4
src/devices/mod.rs Normal file
View file

@ -0,0 +1,4 @@
pub mod bochs;
mod pci;
pub use bochs::BochsDevice;

141
src/devices/pci.rs Normal file
View file

@ -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<PciDevice> {
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()
}
}

View file

@ -9,6 +9,7 @@
pub mod colors;
pub mod configurations;
pub mod devices;
pub mod drawing;
pub mod fonts;
pub mod registers;