forked from AbleOS/ableos
back into virtio work
This commit is contained in:
parent
a001a7e168
commit
08c2cf73ea
|
@ -18,17 +18,13 @@ run-args = [
|
||||||
"-smp",
|
"-smp",
|
||||||
"cores=2",
|
"cores=2",
|
||||||
|
|
||||||
"-device",
|
|
||||||
"cirrus-vga",
|
|
||||||
|
|
||||||
# "-device",
|
|
||||||
# "virtio-blk-pci,drive=drive0,id=virtblk0,num-queues=4",
|
|
||||||
# A simple example of a boot image
|
|
||||||
# "-drive",
|
|
||||||
# "file=disk.qcow2,if=none,id=drive0",
|
|
||||||
|
|
||||||
"-device",
|
"-soundhw", "pcspk",
|
||||||
"virtio-rng",
|
"-device", "virtio-gpu-pci",
|
||||||
|
|
||||||
|
# "-machine", "pcspk-audiodev=0",
|
||||||
|
|
||||||
|
|
||||||
"-qmp",
|
"-qmp",
|
||||||
"unix:../qmp-sock,server,nowait"
|
"unix:../qmp-sock,server,nowait"
|
||||||
|
|
|
@ -43,8 +43,7 @@ static IDT: Lazy<InterruptDescriptorTable> = Lazy::new(|| {
|
||||||
.set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX);
|
.set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This gives fast interrupts
|
reset_pit_for_cpu();
|
||||||
set_pit_frequency(1000);
|
|
||||||
|
|
||||||
idt[InterruptIndex::Timer.as_usize()].set_handler_fn(timer_interrupt_handler);
|
idt[InterruptIndex::Timer.as_usize()].set_handler_fn(timer_interrupt_handler);
|
||||||
idt[InterruptIndex::Keyboard.as_usize()].set_handler_fn(keyboard_interrupt_handler);
|
idt[InterruptIndex::Keyboard.as_usize()].set_handler_fn(keyboard_interrupt_handler);
|
||||||
|
@ -151,13 +150,29 @@ pub fn init_idt() {
|
||||||
IDT.load();
|
IDT.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_pit_frequency(freq: u32) {
|
pub fn set_pit_frequency(pit: u16, freq: u32) {
|
||||||
let divisor: u16 = (1193180 / freq).try_into().unwrap();
|
let divisor: u16 = (1193180 / freq).try_into().unwrap();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
outb(0x36, 0x43);
|
outb(0x36, 0x43);
|
||||||
|
|
||||||
outb((divisor & 0xFF) as u8, 0x40);
|
outb((divisor & 0xFF) as u8, 0x39 + pit);
|
||||||
outb((divisor >> 8) as u8, 0x40);
|
outb((divisor >> 8) as u8, 0x40 + pit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn set_pit_1(freq: u32) {
|
||||||
|
set_pit_frequency(1, freq);
|
||||||
|
}
|
||||||
|
pub fn set_pit_2(freq: u32) {
|
||||||
|
set_pit_frequency(2, freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_pit_3(freq: u32) {
|
||||||
|
set_pit_frequency(3, freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reset_pit_for_cpu() {
|
||||||
|
set_pit_1(1000);
|
||||||
|
set_pit_2(1000);
|
||||||
|
set_pit_3(1000);
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
pub mod character_devs;
|
pub mod character_devs;
|
||||||
pub mod id;
|
|
||||||
pub mod pci_inner;
|
|
||||||
|
|
||||||
mod dev_vterm;
|
mod dev_vterm;
|
||||||
|
|
||||||
|
pub mod id;
|
||||||
|
pub mod pci;
|
||||||
|
pub mod pci_inner;
|
||||||
|
|
||||||
pub use self::Device::*;
|
pub use self::Device::*;
|
||||||
|
|
||||||
use crate::devices::dev_vterm::VTerm;
|
use crate::devices::dev_vterm::VTerm;
|
||||||
|
|
178
ableos/src/devices/pci/enums.rs
Normal file
178
ableos/src/devices/pci/enums.rs
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
/// The major class specification for a PCI device.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Hash)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
#[repr(C)]
|
||||||
|
pub enum PciClass {
|
||||||
|
Unclassified = 0x00,
|
||||||
|
MassStorage = 0x01,
|
||||||
|
Network = 0x02,
|
||||||
|
Display = 0x03,
|
||||||
|
Multimedia = 0x04,
|
||||||
|
Memory = 0x05,
|
||||||
|
Bridge = 0x06,
|
||||||
|
Other = 0xFF,
|
||||||
|
}
|
||||||
|
impl PciClass {
|
||||||
|
/// Convert a u8 into the corresponding PciClass
|
||||||
|
pub fn from_u8(n: u8) -> PciClass {
|
||||||
|
match n {
|
||||||
|
0x00 => PciClass::Unclassified,
|
||||||
|
0x01 => PciClass::MassStorage,
|
||||||
|
0x02 => PciClass::Network,
|
||||||
|
0x03 => PciClass::Display,
|
||||||
|
0x04 => PciClass::Multimedia,
|
||||||
|
0x05 => PciClass::Memory,
|
||||||
|
0x06 => PciClass::Bridge,
|
||||||
|
_ => PciClass::Other,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Convert a PciClass to its u8 representation
|
||||||
|
pub fn as_u8(&self) -> u8 {
|
||||||
|
*self as u8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<u8> for PciClass {
|
||||||
|
/// Convert a u8 into the corresponding PciClass
|
||||||
|
fn from(n: u8) -> Self {
|
||||||
|
Self::from_u8(n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_camel_case_types, dead_code)]
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
#[repr(C)]
|
||||||
|
/// Full class specification (type and subtype) for a PCI device.
|
||||||
|
///
|
||||||
|
/// Uses non-camel-case types for readability.
|
||||||
|
pub enum PciFullClass {
|
||||||
|
Unclassified_NonVgaCompatible = 0x0000,
|
||||||
|
Unclassified_VgaCompatible = 0x0001,
|
||||||
|
|
||||||
|
MassStorage_ScsiBus = 0x0100,
|
||||||
|
MassStorage_IDE = 0x0101,
|
||||||
|
MassStorage_Floppy = 0x0102,
|
||||||
|
MassStorage_IpiBus = 0x0103,
|
||||||
|
MassStorage_RAID = 0x0104,
|
||||||
|
MassStorage_ATA = 0x0105,
|
||||||
|
MassStorage_SATA = 0x0106,
|
||||||
|
MassStorage_SerialSCSI = 0x0107,
|
||||||
|
MassStorage_NVM = 0x0108,
|
||||||
|
MassStorage_Other = 0x0180,
|
||||||
|
|
||||||
|
Network_Ethernet = 0x0200,
|
||||||
|
Network_TokenRing = 0x0201,
|
||||||
|
Network_FDDI = 0x0202,
|
||||||
|
Network_ATM = 0x0203,
|
||||||
|
Network_ISDN = 0x0204,
|
||||||
|
Network_WorldFlip = 0x0205,
|
||||||
|
Network_PICMG = 0x0206,
|
||||||
|
Network_Infiniband = 0x0207,
|
||||||
|
Network_Fabric = 0x0208,
|
||||||
|
Network_Other = 0x0280,
|
||||||
|
|
||||||
|
Display_VGA = 0x0300,
|
||||||
|
Display_XGA = 0x0301,
|
||||||
|
Display_3D = 0x0302,
|
||||||
|
Display_Other = 0x0380,
|
||||||
|
|
||||||
|
Multimedia_Video = 0x0400,
|
||||||
|
Multimedia_AudioController = 0x0401,
|
||||||
|
Multimedia_Telephony = 0x0402,
|
||||||
|
Multimedia_AudioDevice = 0x0403,
|
||||||
|
Multimedia_Other = 0x0480,
|
||||||
|
|
||||||
|
Memory_RAM = 0x0500,
|
||||||
|
Memory_Flash = 0x0501,
|
||||||
|
Memory_Other = 0x0580,
|
||||||
|
|
||||||
|
Bridge_Host = 0x0600,
|
||||||
|
Bridge_ISA = 0x0601,
|
||||||
|
Bridge_EISA = 0x0602,
|
||||||
|
Bridge_MCA = 0x0603,
|
||||||
|
Bridge_PciToPci = 0x0604,
|
||||||
|
Bridge_PCMCIA = 0x0605,
|
||||||
|
Bridge_NuBus = 0x0606,
|
||||||
|
Bridge_CardBus = 0x0607,
|
||||||
|
Bridge_RACEway = 0x0608,
|
||||||
|
Bridge_PciToPciSemiTransparent = 0x0609,
|
||||||
|
Bridge_InfinibandToPci = 0x060A,
|
||||||
|
Bridge_Other = 0x0680,
|
||||||
|
|
||||||
|
Unknown = 0xFFFF,
|
||||||
|
}
|
||||||
|
impl PciFullClass {
|
||||||
|
// listen, i know this sucks, but i didn't want to include
|
||||||
|
// `num`, `num-traits` and `num-derive` as dependencies for
|
||||||
|
// this crate just for a convenience function
|
||||||
|
/// Convert a u16 into the corresponding PciFullClass
|
||||||
|
pub fn from_u16(n: u16) -> PciFullClass {
|
||||||
|
match n {
|
||||||
|
0x0000 => PciFullClass::Unclassified_NonVgaCompatible,
|
||||||
|
0x0001 => PciFullClass::Unclassified_VgaCompatible,
|
||||||
|
|
||||||
|
0x0100 => PciFullClass::MassStorage_ScsiBus,
|
||||||
|
0x0101 => PciFullClass::MassStorage_IDE,
|
||||||
|
0x0102 => PciFullClass::MassStorage_Floppy,
|
||||||
|
0x0103 => PciFullClass::MassStorage_IpiBus,
|
||||||
|
0x0104 => PciFullClass::MassStorage_RAID,
|
||||||
|
0x0105 => PciFullClass::MassStorage_ATA,
|
||||||
|
0x0106 => PciFullClass::MassStorage_SATA,
|
||||||
|
0x0107 => PciFullClass::MassStorage_SerialSCSI,
|
||||||
|
0x0108 => PciFullClass::MassStorage_NVM,
|
||||||
|
0x0180 => PciFullClass::MassStorage_Other,
|
||||||
|
|
||||||
|
0x0200 => PciFullClass::Network_Ethernet,
|
||||||
|
0x0201 => PciFullClass::Network_TokenRing,
|
||||||
|
0x0202 => PciFullClass::Network_FDDI,
|
||||||
|
0x0203 => PciFullClass::Network_ATM,
|
||||||
|
0x0204 => PciFullClass::Network_ISDN,
|
||||||
|
0x0205 => PciFullClass::Network_WorldFlip,
|
||||||
|
0x0206 => PciFullClass::Network_PICMG,
|
||||||
|
0x0207 => PciFullClass::Network_Infiniband,
|
||||||
|
0x0208 => PciFullClass::Network_Fabric,
|
||||||
|
0x0280 => PciFullClass::Network_Other,
|
||||||
|
|
||||||
|
0x0300 => PciFullClass::Display_VGA,
|
||||||
|
0x0301 => PciFullClass::Display_XGA,
|
||||||
|
0x0302 => PciFullClass::Display_3D,
|
||||||
|
0x0380 => PciFullClass::Display_Other,
|
||||||
|
|
||||||
|
0x0400 => PciFullClass::Multimedia_Video,
|
||||||
|
0x0401 => PciFullClass::Multimedia_AudioController,
|
||||||
|
0x0402 => PciFullClass::Multimedia_Telephony,
|
||||||
|
0x0403 => PciFullClass::Multimedia_AudioDevice,
|
||||||
|
0x0480 => PciFullClass::Multimedia_Other,
|
||||||
|
|
||||||
|
0x0500 => PciFullClass::Memory_RAM,
|
||||||
|
0x0501 => PciFullClass::Memory_Flash,
|
||||||
|
0x0580 => PciFullClass::Memory_Other,
|
||||||
|
|
||||||
|
0x0600 => PciFullClass::Bridge_Host,
|
||||||
|
0x0601 => PciFullClass::Bridge_ISA,
|
||||||
|
0x0602 => PciFullClass::Bridge_EISA,
|
||||||
|
0x0603 => PciFullClass::Bridge_MCA,
|
||||||
|
0x0604 => PciFullClass::Bridge_PciToPci,
|
||||||
|
0x0605 => PciFullClass::Bridge_PCMCIA,
|
||||||
|
0x0606 => PciFullClass::Bridge_NuBus,
|
||||||
|
0x0607 => PciFullClass::Bridge_CardBus,
|
||||||
|
0x0608 => PciFullClass::Bridge_RACEway,
|
||||||
|
0x0609 => PciFullClass::Bridge_PciToPciSemiTransparent,
|
||||||
|
0x060A => PciFullClass::Bridge_InfinibandToPci,
|
||||||
|
0x0680 => PciFullClass::Bridge_Other,
|
||||||
|
|
||||||
|
_ => PciFullClass::Unknown,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Convert a PciFullClass to its u16 representation
|
||||||
|
pub fn as_u16(&self) -> u16 {
|
||||||
|
*self as u16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<u16> for PciFullClass {
|
||||||
|
/// Convert a u16 into the corresponding PciFullClass
|
||||||
|
fn from(n: u16) -> Self {
|
||||||
|
Self::from_u16(n)
|
||||||
|
}
|
||||||
|
}
|
227
ableos/src/devices/pci/mod.rs
Normal file
227
ableos/src/devices/pci/mod.rs
Normal file
|
@ -0,0 +1,227 @@
|
||||||
|
// The MIT License (MIT)
|
||||||
|
// Copyright (c) 2021 trashbyte
|
||||||
|
// See LICENSE.txt for full license
|
||||||
|
|
||||||
|
#![feature(asm)]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
use alloc::{format, string::String, vec::Vec};
|
||||||
|
use core::fmt::{Display, Error, Formatter};
|
||||||
|
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde;
|
||||||
|
|
||||||
|
mod enums;
|
||||||
|
pub use enums::*;
|
||||||
|
|
||||||
|
pub mod port;
|
||||||
|
use port::*;
|
||||||
|
|
||||||
|
// PciDeviceInfo ///////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
/// A struct containing info about a PCI device.
|
||||||
|
pub struct PciDeviceInfo {
|
||||||
|
pub device: u8,
|
||||||
|
pub bus: u8,
|
||||||
|
pub device_id: u16,
|
||||||
|
pub vendor_id: u16,
|
||||||
|
pub full_class: PciFullClass,
|
||||||
|
pub header_type: u8,
|
||||||
|
pub bars: [u32; 6],
|
||||||
|
pub supported_fns: [bool; 8],
|
||||||
|
pub interrupt_line: u8,
|
||||||
|
pub interrupt_pin: u8,
|
||||||
|
}
|
||||||
|
impl PciDeviceInfo {
|
||||||
|
/// Get the class of the PCI device as a PciClass
|
||||||
|
pub fn class(&self) -> PciClass {
|
||||||
|
PciClass::from_u8(((self.full_class.as_u16() >> 8) & 0xFF) as u8)
|
||||||
|
}
|
||||||
|
/// Get the full class of the PCI device as a PciFullClass
|
||||||
|
pub fn subclass(&self) -> PciClass {
|
||||||
|
PciClass::from_u8((self.full_class.as_u16() & 0xFF) as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Display for PciDeviceInfo {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
|
||||||
|
let vendor_name = name_for_vendor_id(self.vendor_id);
|
||||||
|
writeln!(
|
||||||
|
f,
|
||||||
|
"Device {:X} | Bus {:X} | Vendor: {}",
|
||||||
|
self.device, self.bus, vendor_name
|
||||||
|
)?;
|
||||||
|
writeln!(
|
||||||
|
f,
|
||||||
|
" Class: {:?} ({:#06X})",
|
||||||
|
self.full_class,
|
||||||
|
self.full_class.as_u16()
|
||||||
|
)?;
|
||||||
|
writeln!(f, " Header type: {:X}", self.header_type)?;
|
||||||
|
write!(f, " Supported functions: 0")?;
|
||||||
|
for (i, b) in self.supported_fns.iter().enumerate().skip(1) {
|
||||||
|
if *b {
|
||||||
|
write!(f, ", {}", i)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeln!(f)?;
|
||||||
|
write!(f, " BARs: [ ")?;
|
||||||
|
for i in self.bars.iter() {
|
||||||
|
if *i == 0 {
|
||||||
|
write!(f, "0x0 ")?;
|
||||||
|
} else {
|
||||||
|
write!(f, "{:#010X} ", i)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeln!(f, "]")?;
|
||||||
|
writeln!(
|
||||||
|
f,
|
||||||
|
" Interrupt line / pin: {} / {}",
|
||||||
|
self.interrupt_line, self.interrupt_pin
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public functions ////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/// Converts a u16 vendor id into a human-readable name.
|
||||||
|
pub fn name_for_vendor_id(vendor_id: u16) -> String {
|
||||||
|
match vendor_id {
|
||||||
|
0x8086 => "Intel Corp. (0x8086)".into(),
|
||||||
|
0x1234 => "QEMU (0x1234)".into(),
|
||||||
|
_ => format!("Unknown({:#06X})", vendor_id),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Brute force scans for devices 0-31 on buses 0-255.
|
||||||
|
pub fn brute_force_scan() -> Vec<PciDeviceInfo> {
|
||||||
|
let mut infos = Vec::new();
|
||||||
|
for bus in 0u8..=255 {
|
||||||
|
for device in 0u8..32 {
|
||||||
|
if let Some(info) = check_device(bus, device) {
|
||||||
|
infos.push(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
infos
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal functions //////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
fn check_device(bus: u8, device: u8) -> Option<PciDeviceInfo> {
|
||||||
|
assert!(device < 32);
|
||||||
|
let function = 0u8;
|
||||||
|
|
||||||
|
let (device_id, vendor_id) = get_ids(bus, device, function);
|
||||||
|
if vendor_id == 0xFFFF {
|
||||||
|
// Device doesn't exist
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let class = unsafe { pci_config_read(bus, device, 0, 0x8) };
|
||||||
|
let class = (class >> 16) & 0x0000FFFF;
|
||||||
|
let pci_class = PciFullClass::from_u16(class as u16);
|
||||||
|
let header_type = get_header_type(bus, device, function);
|
||||||
|
|
||||||
|
let mut supported_fns = [true, false, false, false, false, false, false, false];
|
||||||
|
if (header_type & 0x80) != 0 {
|
||||||
|
// It is a multi-function device, so check remaining functions
|
||||||
|
for function in 0u8..8 {
|
||||||
|
if get_ids(bus, device, function).1 != 0xFFFF {
|
||||||
|
if check_function(bus, device, function) {
|
||||||
|
supported_fns[function as usize] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut bars = [0, 0, 0, 0, 0, 0];
|
||||||
|
unsafe {
|
||||||
|
bars[0] = pci_config_read(bus, device, 0, 0x10);
|
||||||
|
bars[1] = pci_config_read(bus, device, 0, 0x14);
|
||||||
|
bars[2] = pci_config_read(bus, device, 0, 0x18);
|
||||||
|
bars[3] = pci_config_read(bus, device, 0, 0x1C);
|
||||||
|
bars[4] = pci_config_read(bus, device, 0, 0x20);
|
||||||
|
bars[5] = pci_config_read(bus, device, 0, 0x24);
|
||||||
|
}
|
||||||
|
|
||||||
|
let last_row = unsafe { pci_config_read(bus, device, 0, 0x3C) };
|
||||||
|
|
||||||
|
Some(PciDeviceInfo {
|
||||||
|
device,
|
||||||
|
bus,
|
||||||
|
device_id,
|
||||||
|
vendor_id,
|
||||||
|
full_class: pci_class,
|
||||||
|
header_type,
|
||||||
|
bars,
|
||||||
|
supported_fns,
|
||||||
|
interrupt_line: (last_row & 0xFF) as u8,
|
||||||
|
interrupt_pin: ((last_row >> 8) & 0xFF) as u8,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn pci_config_read(bus: u8, device: u8, func: u8, offset: u8) -> u32 {
|
||||||
|
let bus = bus as u32;
|
||||||
|
let device = device as u32;
|
||||||
|
let func = func as u32;
|
||||||
|
let offset = offset as u32;
|
||||||
|
// construct address param
|
||||||
|
let address =
|
||||||
|
((bus << 16) | (device << 11) | (func << 8) | (offset & 0xfc) | 0x80000000) as u32;
|
||||||
|
|
||||||
|
// write address
|
||||||
|
unsafe {
|
||||||
|
Port::<u32>::new(0xCF8).write(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
// read data
|
||||||
|
unsafe { Port::<u32>::new(0xCFC).read() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
unsafe fn pci_config_write(bus: u8, device: u8, func: u8, offset: u8, value: u32) {
|
||||||
|
let bus = bus as u32;
|
||||||
|
let device = device as u32;
|
||||||
|
let func = func as u32;
|
||||||
|
let offset = offset as u32;
|
||||||
|
// construct address param
|
||||||
|
let address =
|
||||||
|
((bus << 16) | (device << 11) | (func << 8) | (offset & 0xfc) | 0x80000000) as u32;
|
||||||
|
|
||||||
|
// write address
|
||||||
|
unsafe {
|
||||||
|
Port::<u32>::new(0xCF8).write(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write data
|
||||||
|
unsafe {
|
||||||
|
Port::<u32>::new(0xCFC).write(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_header_type(bus: u8, device: u8, function: u8) -> u8 {
|
||||||
|
assert!(device < 32);
|
||||||
|
assert!(function < 8);
|
||||||
|
let res = unsafe { pci_config_read(bus, device, function, 0x0C) };
|
||||||
|
((res >> 16) & 0xFF) as u8
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_function(bus: u8, device: u8, function: u8) -> bool {
|
||||||
|
assert!(device < 32);
|
||||||
|
assert!(function < 8);
|
||||||
|
get_ids(bus, device, function).1 != 0xFFFF
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_ids(bus: u8, device: u8, function: u8) -> (u16, u16) {
|
||||||
|
assert!(device < 32);
|
||||||
|
assert!(function < 8);
|
||||||
|
let res = unsafe { pci_config_read(bus, device, function, 0) };
|
||||||
|
let dev_id = ((res >> 16) & 0xFFFF) as u16;
|
||||||
|
let vnd_id = (res & 0xFFFF) as u16;
|
||||||
|
(dev_id, vnd_id)
|
||||||
|
}
|
72
ableos/src/devices/pci/port.rs
Normal file
72
ableos/src/devices/pci/port.rs
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
/// Trait for limiting [Port] to only being able to read/write u8/16/32.
|
||||||
|
pub(crate) trait PortRW {
|
||||||
|
/// Read a value (self) from the port
|
||||||
|
unsafe fn read_port(port: u16) -> Self;
|
||||||
|
/// Write a value (self) to the port
|
||||||
|
unsafe fn write_port(port: u16, value: Self);
|
||||||
|
}
|
||||||
|
|
||||||
|
// PortRW Implementations //////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
impl PortRW for u8 {
|
||||||
|
unsafe fn read_port(port: u16) -> Self {
|
||||||
|
let value: u8;
|
||||||
|
asm!("in al, dx", out("al") value, in("dx") port, options(nomem, nostack, preserves_flags));
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn write_port(port: u16, value: Self) {
|
||||||
|
asm!("out dx, al", in("dx") port, in("al") value, options(nomem, nostack, preserves_flags));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PortRW for u16 {
|
||||||
|
unsafe fn read_port(port: u16) -> Self {
|
||||||
|
let value: u16;
|
||||||
|
asm!("in ax, dx", out("ax") value, in("dx") port, options(nomem, nostack, preserves_flags));
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn write_port(port: u16, value: Self) {
|
||||||
|
asm!("out dx, ax", in("dx") port, in("ax") value, options(nomem, nostack, preserves_flags));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PortRW for u32 {
|
||||||
|
unsafe fn read_port(port: u16) -> Self {
|
||||||
|
let value: u32;
|
||||||
|
asm!("in eax, dx", out("eax") value, in("dx") port, options(nomem, nostack, preserves_flags));
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn write_port(port: u16, value: Self) {
|
||||||
|
asm!("out dx, eax", in("dx") port, in("eax") value, options(nomem, nostack, preserves_flags));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A simple wrapper around the asm instructions needed to read/write I/O ports.
|
||||||
|
pub(crate) struct Port<T: PortRW> {
|
||||||
|
addr: u16,
|
||||||
|
_phantom: PhantomData<T>,
|
||||||
|
}
|
||||||
|
impl<T: PortRW> Port<T> {
|
||||||
|
/// Create a new `Port` with the given address and data size
|
||||||
|
pub(crate) fn new(addr: u16) -> Self {
|
||||||
|
Self {
|
||||||
|
addr,
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read a value from the port
|
||||||
|
pub(crate) unsafe fn read(&self) -> T {
|
||||||
|
T::read_port(self.addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write a value to the port
|
||||||
|
pub(crate) unsafe fn write(&self, value: T) {
|
||||||
|
T::write_port(self.addr, value);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
//!
|
//!
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
pub enum Vendors {
|
pub enum Vendors {
|
||||||
ThreeDfxInteractiveInc = 0x121a,
|
ThreeDfxInteractiveInc = 0x121a,
|
||||||
ThreeDLabs = 0x3d3d,
|
ThreeDLabs = 0x3d3d,
|
||||||
|
|
|
@ -34,10 +34,7 @@ impl log::Log for SimpleLogger {
|
||||||
record.args()
|
record.args()
|
||||||
);
|
);
|
||||||
// kprint!("{}", msg);
|
// kprint!("{}", msg);
|
||||||
// NOTE: This needs to be fixed before merge
|
|
||||||
if KERNEL_CONF.logging.log_to_serial {
|
if KERNEL_CONF.logging.log_to_serial {
|
||||||
// #[track_caller]
|
|
||||||
|
|
||||||
serial_println!(
|
serial_println!(
|
||||||
"[{}{}{}][{}{}{}] {}",
|
"[{}{}{}][{}{}{}] {}",
|
||||||
color.0,
|
color.0,
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
use cpuio::{inb, inl, outb, outl};
|
use cpuio::{inb, inl, inw, outb, outl, outw};
|
||||||
|
|
||||||
pub fn read32(reg: u16) -> u32 {
|
pub fn read32(reg: u16) -> u32 {
|
||||||
unsafe { inl(reg) }
|
unsafe { inl(reg) }
|
||||||
}
|
}
|
||||||
|
pub fn read16(reg: u16) -> u16 {
|
||||||
|
unsafe { inw(reg) as u16 }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn read8(reg: u16) -> u8 {
|
pub fn read8(reg: u16) -> u8 {
|
||||||
unsafe { inb(reg) }
|
unsafe { inb(reg) }
|
||||||
|
@ -12,6 +15,10 @@ pub fn write32(reg: u16, val: u32) {
|
||||||
unsafe { outl(val, reg) }
|
unsafe { outl(val, reg) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn write16(reg: u16, val: u16) {
|
||||||
|
unsafe { outw(val, reg) }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn write8(reg: u16, val: u8) {
|
pub fn write8(reg: u16, val: u8) {
|
||||||
unsafe { outb(val, reg) }
|
unsafe { outb(val, reg) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1,5 @@
|
||||||
pub mod rust_2021;
|
pub mod rust_2021;
|
||||||
|
|
||||||
|
pub use core::assert;
|
||||||
|
pub use core::option::Option::Some;
|
||||||
|
pub use core::option::*;
|
||||||
|
|
|
@ -2,6 +2,7 @@ pub use crate::print::*;
|
||||||
pub use crate::serial_print::*;
|
pub use crate::serial_print::*;
|
||||||
pub use alloc::{boxed::Box, format, string::*, vec, vec::*};
|
pub use alloc::{boxed::Box, format, string::*, vec, vec::*};
|
||||||
pub use core::arch::asm;
|
pub use core::arch::asm;
|
||||||
|
|
||||||
pub use core::prelude::rust_2021::*;
|
pub use core::prelude::rust_2021::*;
|
||||||
pub use core::prelude::v1::*;
|
pub use core::prelude::v1::*;
|
||||||
pub use log::{debug, info, trace, warn};
|
pub use log::{debug, info, trace, warn};
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
use core::alloc::Layout;
|
use core::alloc::Layout;
|
||||||
|
|
||||||
|
use crate::arch::interrupts::{reset_pit_for_cpu, set_pit_2};
|
||||||
|
use crate::devices::{pci, pci_inner};
|
||||||
use crate::encoding::bin;
|
use crate::encoding::bin;
|
||||||
|
use crate::port_io::{read32, read8, write8};
|
||||||
use crate::rhai_shell::shell;
|
use crate::rhai_shell::shell;
|
||||||
use crate::wasm_jumploader::run_program;
|
use crate::wasm_jumploader::run_program;
|
||||||
use acpi::{AcpiTables, PlatformInfo};
|
use acpi::{AcpiTables, PlatformInfo};
|
||||||
|
use cpuio::outb;
|
||||||
use genfs::Fs;
|
use genfs::Fs;
|
||||||
|
|
||||||
/// Experimental scratchpad for testing.
|
/// Experimental scratchpad for testing.
|
||||||
|
@ -16,14 +20,33 @@ pub fn scratchpad() {
|
||||||
foo: (None) -> (Num);
|
foo: (None) -> (Num);
|
||||||
}";
|
}";
|
||||||
let axel = axel::parse(axel_raw.to_string());
|
let axel = axel::parse(axel_raw.to_string());
|
||||||
|
|
||||||
for node in axel {
|
for node in axel {
|
||||||
info!("{:?}", node);
|
info!("{:?}", node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use crate::devices::pci::brute_force_scan;
|
||||||
|
let infos = brute_force_scan();
|
||||||
|
for device in infos {
|
||||||
|
match device.vendor_id {
|
||||||
|
0x1af4 => {
|
||||||
|
info!("Found virtio device");
|
||||||
|
use crate::virtio::device_handler;
|
||||||
|
device_handler(device);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
info!("Found unknown device");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sound(1000);
|
||||||
|
// sound_off();
|
||||||
|
|
||||||
// acpi();
|
// acpi();
|
||||||
real_shell();
|
real_shell();
|
||||||
}
|
}
|
||||||
|
use crate::port_io::write16;
|
||||||
pub fn pci_fun() {}
|
|
||||||
|
|
||||||
pub fn acpi() {
|
pub fn acpi() {
|
||||||
let acpi_handler = AcpiStruct {};
|
let acpi_handler = AcpiStruct {};
|
||||||
|
@ -176,3 +199,31 @@ pub fn command_parser(user: String, command: String) {
|
||||||
|
|
||||||
use crate::filesystem::FILE_SYSTEM;
|
use crate::filesystem::FILE_SYSTEM;
|
||||||
use genfs::OpenOptions;
|
use genfs::OpenOptions;
|
||||||
|
|
||||||
|
pub fn sound(n_frequency: u32) {
|
||||||
|
let div: u32;
|
||||||
|
let tmp: u8;
|
||||||
|
|
||||||
|
div = 1193180 / n_frequency;
|
||||||
|
unsafe {
|
||||||
|
outb(0xb6, 0x43);
|
||||||
|
|
||||||
|
set_pit_2(div);
|
||||||
|
|
||||||
|
//And play the sound using the PC speaker
|
||||||
|
tmp = inb(0x61);
|
||||||
|
if tmp != (tmp | 3) {
|
||||||
|
outb(tmp | 3, 0x61);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sound_off() {
|
||||||
|
unsafe {
|
||||||
|
let tmp = inb(0x61) & 0xFC;
|
||||||
|
outb(tmp, 0x61)
|
||||||
|
};
|
||||||
|
reset_pit_for_cpu();
|
||||||
|
}
|
||||||
|
|
||||||
|
use cpuio::inb;
|
||||||
|
|
|
@ -9,6 +9,26 @@ pub struct VirtioDevice {
|
||||||
status: VirtioDeviceStatus,
|
status: VirtioDeviceStatus,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use crate::devices::pci::PciDeviceInfo;
|
||||||
|
|
||||||
|
pub fn device_handler(device: PciDeviceInfo) {
|
||||||
|
use crate::devices::pci::PciClass::*;
|
||||||
|
match device.class() {
|
||||||
|
// Unclassified => todo!(),
|
||||||
|
// MassStorage => todo!(),
|
||||||
|
// Network => todo!(),
|
||||||
|
Display => {
|
||||||
|
trace!("Display found");
|
||||||
|
println!("{}", device.interrupt_pin);
|
||||||
|
}
|
||||||
|
// Multimedia => todo!(),
|
||||||
|
// Memory => todo!(),
|
||||||
|
// Bridge => todo!(),
|
||||||
|
// Other => todo!(),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub enum VirtioDeviceStatus {
|
pub enum VirtioDeviceStatus {
|
||||||
// Indicates that the guest OS has found the device and recognized it as a valid virtio device.
|
// Indicates that the guest OS has found the device and recognized it as a valid virtio device.
|
||||||
|
@ -59,3 +79,16 @@ pub struct VirtioDeviceNotification {
|
||||||
pub index: u32,
|
pub index: u32,
|
||||||
pub value: u32,
|
pub value: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Vring {
|
||||||
|
pub addr: u64,
|
||||||
|
pub len: u32,
|
||||||
|
pub flags: u16,
|
||||||
|
pub next: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct VringAvail {
|
||||||
|
pub flags: u16,
|
||||||
|
pub idx: u16,
|
||||||
|
pub ring: [u16; 0xFFFF],
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,9 @@ pub mod host_functions;
|
||||||
|
|
||||||
use crate::{filesystem::FILE_SYSTEM, wasm_jumploader::host_functions::HostExternals};
|
use crate::{filesystem::FILE_SYSTEM, wasm_jumploader::host_functions::HostExternals};
|
||||||
use genfs::{Fs, OpenOptions};
|
use genfs::{Fs, OpenOptions};
|
||||||
use wasmi::{ImportsBuilder, ModuleInstance};
|
use wasmi::{
|
||||||
|
ImportsBuilder, MemoryDescriptor, ModuleImportResolver, ModuleInstance, StackRecycler,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn interp() {
|
pub fn interp() {
|
||||||
trace!("Interpreting...");
|
trace!("Interpreting...");
|
||||||
|
@ -101,17 +103,24 @@ pub fn interp() {
|
||||||
pub fn run_program(program: Vec<u8>) {
|
pub fn run_program(program: Vec<u8>) {
|
||||||
// Load wasm binary and prepare it for instantiation.
|
// Load wasm binary and prepare it for instantiation.
|
||||||
let module = wasmi::Module::from_buffer(&program).expect("failed to load wasm");
|
let module = wasmi::Module::from_buffer(&program).expect("failed to load wasm");
|
||||||
|
|
||||||
trace!("Loaded wasm binary");
|
trace!("Loaded wasm binary");
|
||||||
let imports = ImportsBuilder::new().with_resolver("env", &host_functions::HostExternals {});
|
let imports = ImportsBuilder::new().with_resolver("env", &host_functions::HostExternals {});
|
||||||
trace!("Created imports");
|
trace!("Created imports");
|
||||||
|
|
||||||
// Instantiate a module with empty imports and
|
// Instantiate a module with empty imports and
|
||||||
// assert that there is no `start` function.
|
// assert that there is no `start` function.
|
||||||
let instance = ModuleInstance::new(&module, &imports); // .expect("failed to instantiate wasm module")
|
let instance = ModuleInstance::new(&module, &imports);
|
||||||
|
|
||||||
|
// .expect("failed to instantiate wasm module")
|
||||||
|
|
||||||
|
use wasmi::GlobalRef;
|
||||||
match instance {
|
match instance {
|
||||||
Ok(inst) => {
|
Ok(inst) => {
|
||||||
let instance = inst.assert_no_start();
|
let mut instance = inst.assert_no_start();
|
||||||
|
|
||||||
|
let abc = instance.globals().capacity();
|
||||||
|
|
||||||
let mut is_driver = false;
|
let mut is_driver = false;
|
||||||
let _is_program = false;
|
let _is_program = false;
|
||||||
let mut has_driver_entry = false;
|
let mut has_driver_entry = false;
|
||||||
|
|
Loading…
Reference in a new issue