Add mouse and clean virtio
This commit is contained in:
144
src/pci.rs
144
src/pci.rs
@@ -1,52 +1,31 @@
|
||||
use core::{
|
||||
ops::{Deref, DerefMut},
|
||||
ptr::{addr_of, addr_of_mut},
|
||||
ptr::addr_of_mut,
|
||||
};
|
||||
|
||||
use bytes_struct::VolatilePackedStruct;
|
||||
|
||||
use crate::{
|
||||
println,
|
||||
virtio::{VirtioCapability, VirtioCapabilityType, VirtioNotificationCapability},
|
||||
volatile::Volatile,
|
||||
virtio::{
|
||||
VirtioCapability, VirtioCapabilityType, VirtioNotificationCapability, VirtioPciCommonCfg,
|
||||
},
|
||||
};
|
||||
|
||||
// Configuration pour RISC-V Virt
|
||||
const PCI_ECAM_BASE: usize = 0x3000_0000;
|
||||
const VIRTIO_VENDOR_ID: u16 = 0x1af4;
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub struct VirtioPciRegion {
|
||||
pub bar_address: usize,
|
||||
pub offset: u32,
|
||||
pub length: u32,
|
||||
}
|
||||
|
||||
// Helpers ECAM
|
||||
fn pci_read<T>(bus: u8, dev: u8, func: u8, offset: u16) -> T {
|
||||
let addr = PCI_ECAM_BASE
|
||||
| ((bus as usize) << 20)
|
||||
| ((dev as usize) << 15)
|
||||
| ((func as usize) << 12)
|
||||
| (offset as usize);
|
||||
unsafe { core::ptr::read_volatile(addr as *const T) }
|
||||
}
|
||||
|
||||
fn pci_write<T>(bus: u8, dev: u8, func: u8, offset: u16, val: T) {
|
||||
let addr = PCI_ECAM_BASE
|
||||
| ((bus as usize) << 20)
|
||||
| ((dev as usize) << 15)
|
||||
| ((func as usize) << 12)
|
||||
| (offset as usize);
|
||||
unsafe { core::ptr::write_volatile(addr as *mut T, val) }
|
||||
}
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct VirtioPciCaps {
|
||||
pub common_cfg: usize,
|
||||
pub notify_cfg: usize,
|
||||
pub isr_cfg: usize,
|
||||
pub common_cfg: *mut VirtioPciCommonCfg,
|
||||
pub notify_cfg: *mut u16,
|
||||
pub isr_cfg: *mut u8,
|
||||
pub notify_multiplier: u32,
|
||||
pub irq: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[allow(unused)]
|
||||
pub struct PciDevice {
|
||||
pub bus: u8,
|
||||
pub device: u8,
|
||||
@@ -54,6 +33,7 @@ pub struct PciDevice {
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
#[derive(VolatilePackedStruct)]
|
||||
pub struct PciHeader {
|
||||
pub vendor_id: u16,
|
||||
pub device_id: u16,
|
||||
@@ -86,6 +66,7 @@ pub struct IOBar32(*mut u32);
|
||||
pub struct MemoryBar64(*mut u64);
|
||||
|
||||
#[repr(C, packed)]
|
||||
#[derive(VolatilePackedStruct)]
|
||||
pub struct PciGeneralHeader {
|
||||
pub common_header: PciHeader,
|
||||
pub bars: [u32; 6],
|
||||
@@ -101,15 +82,17 @@ pub struct PciGeneralHeader {
|
||||
pub max_lantency: u8,
|
||||
}
|
||||
#[repr(C, packed)]
|
||||
#[derive(VolatilePackedStruct)]
|
||||
pub struct PciCapability {
|
||||
pub capability_id: u8,
|
||||
pub next_ptr: u8,
|
||||
}
|
||||
|
||||
pub struct PciGeneralDevice {
|
||||
#[allow(unused)]
|
||||
pub bus: u8,
|
||||
pub device: u8,
|
||||
pub inner: *mut PciGeneralHeader,
|
||||
pub ptr: *mut PciGeneralHeader,
|
||||
}
|
||||
|
||||
impl Deref for PciGeneralDevice {
|
||||
@@ -126,6 +109,14 @@ impl DerefMut for PciGeneralDevice {
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for PciDevice {
|
||||
type Target = *mut PciHeader;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl PciDevice {
|
||||
pub fn new(bus: u8, device: u8) -> Self {
|
||||
let addr = PCI_ECAM_BASE | ((bus as usize) << 20) | ((device as usize) << 15);
|
||||
@@ -139,19 +130,6 @@ impl PciDevice {
|
||||
pub fn vendor_and_device_id(&self) -> (u16, u16) {
|
||||
(self.get_vendor_id(), self.get_device_id())
|
||||
}
|
||||
pub fn get_device_id(&self) -> u16 {
|
||||
unsafe { (*self.inner).device_id }
|
||||
}
|
||||
pub fn get_vendor_id(&self) -> u16 {
|
||||
unsafe { (*self.inner).vendor_id }
|
||||
}
|
||||
|
||||
pub fn get_command(&self) -> u16 {
|
||||
unsafe { core::ptr::read_volatile(&raw const (*self.inner).command) }
|
||||
}
|
||||
pub fn set_command(&mut self, command: u16) {
|
||||
unsafe { core::ptr::write_volatile(&raw mut (*self.inner).command, command) }
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// `self` must be a valid general PCI device.
|
||||
@@ -161,22 +139,12 @@ impl PciDevice {
|
||||
}
|
||||
|
||||
impl PciGeneralDevice {
|
||||
pub fn get_interrupt_pin(&self) -> u8 {
|
||||
unsafe { (&raw const (*self.inner).interrupt_pin).read_volatile() }
|
||||
}
|
||||
pub fn set_interrupt_irq(&mut self, irq: u8) {
|
||||
unsafe { (&raw mut (*self.inner).interrupt_line).write_volatile(irq) }
|
||||
}
|
||||
pub fn get_capabilities_pointer(&self) -> *mut PciCapability {
|
||||
unsafe {
|
||||
(self.inner as usize
|
||||
+ (&raw mut (*self.inner).capabilities_pointer).read_volatile() as usize)
|
||||
as *mut PciCapability
|
||||
}
|
||||
(self.ptr as usize + self.ptr.get_capabilities_pointer() as usize) as *mut PciCapability
|
||||
}
|
||||
pub fn capabilities(&self) -> PciCapabilitiesIterator {
|
||||
PciCapabilitiesIterator {
|
||||
base: self.inner as *mut u8,
|
||||
base: self.ptr as *mut u8,
|
||||
current: self.get_capabilities_pointer(),
|
||||
}
|
||||
}
|
||||
@@ -184,13 +152,11 @@ impl PciGeneralDevice {
|
||||
pub fn get_bars(&mut self) -> PciBarIterator {
|
||||
PciBarIterator {
|
||||
current: 0,
|
||||
base_addr: unsafe { addr_of_mut!((*self.inner).bars) as *mut u32 },
|
||||
base_addr: unsafe { addr_of_mut!((*self.ptr).bars) as *mut u32 },
|
||||
}
|
||||
}
|
||||
pub fn get_bar(&mut self, i: u8) -> PciBar {
|
||||
unsafe {
|
||||
PciBar::new((&raw mut (*self.inner).bars as *mut u32).add(i as usize) as *mut u32)
|
||||
}
|
||||
unsafe { PciBar::new((&raw mut (*self.ptr).bars as *mut u32).add(i as usize)) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,11 +190,6 @@ impl MemoryBar32 {
|
||||
pub fn base_addr(self) -> *const u8 {
|
||||
unsafe { (self.0.read_volatile() & !0b1111) as *const u8 }
|
||||
}
|
||||
pub fn allocate_if_needed(self, addr: *const u8) {
|
||||
if self.base_addr().is_null() {
|
||||
self.allocate(addr);
|
||||
}
|
||||
}
|
||||
pub fn allocate(self, addr: *const u8) {
|
||||
debug_assert!(addr as usize <= 0xFFFF_FFFF);
|
||||
unsafe { self.0.write_volatile((*self.0 & 0b11) | addr as u32) }
|
||||
@@ -270,9 +231,11 @@ impl PciBar {
|
||||
pub fn is_memory_space(self) -> bool {
|
||||
matches!(self, PciBar::Mem32(_) | PciBar::Mem64(_))
|
||||
}
|
||||
#[allow(unused)]
|
||||
pub fn is_io_space(self) -> bool {
|
||||
matches!(self, PciBar::IO32(_))
|
||||
}
|
||||
#[allow(unused)]
|
||||
pub fn is_prefetchable(self) -> bool {
|
||||
match self {
|
||||
PciBar::Mem32(pci_bar32) => pci_bar32.is_prefetchable(),
|
||||
@@ -302,7 +265,7 @@ pub struct PciDeviceIterator {
|
||||
|
||||
impl PciDeviceIterator {
|
||||
pub fn new() -> Self {
|
||||
let header_type: u32 = pci_read(0, 0, 0, 0);
|
||||
let header_type: u32 = unsafe { (PCI_ECAM_BASE as *mut u32).read_volatile() };
|
||||
if header_type & 0x80 != 0 {
|
||||
unimplemented!("Multiple PCI host controllers are not supported")
|
||||
}
|
||||
@@ -317,13 +280,12 @@ impl Iterator for PciDeviceIterator {
|
||||
if self.device == 32 {
|
||||
return None;
|
||||
}
|
||||
let dev = self.device;
|
||||
let dev = PciDevice::new(0, self.device);
|
||||
self.device += 1;
|
||||
let vendor: u16 = pci_read(0, dev, 0, 0);
|
||||
if vendor == 0xFFFF {
|
||||
if dev.get_vendor_id() == 0xFFFF {
|
||||
self.next()
|
||||
} else {
|
||||
Some(PciDevice::new(0, dev))
|
||||
Some(dev)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,8 +303,7 @@ impl Iterator for PciCapabilitiesIterator {
|
||||
} else {
|
||||
let res = self.current;
|
||||
self.current = unsafe {
|
||||
let offset =
|
||||
(&raw const (*(self.current as *const PciCapability)).next_ptr).read_volatile();
|
||||
let offset = self.current.get_next_ptr();
|
||||
if offset != 0 {
|
||||
self.base.add(offset as usize) as *mut PciCapability
|
||||
} else {
|
||||
@@ -354,26 +315,21 @@ impl Iterator for PciCapabilitiesIterator {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scan_pci_for_virtio_keyboard() -> Option<VirtioPciCaps> {
|
||||
let device = PciDeviceIterator::new()
|
||||
.find(|device| device.vendor_and_device_id() == (0x1af4, 0x1052))
|
||||
.unwrap();
|
||||
pub fn scan_virtio_keyboard_and_mouse(device: PciDevice) -> Option<VirtioPciCaps> {
|
||||
let mut device = unsafe {
|
||||
// VirtIO keyboard is a general PCI device
|
||||
device.to_general_device()
|
||||
};
|
||||
let interrupt_pin = device.get_interrupt_pin();
|
||||
let interrupt_pin = device.ptr.get_interrupt_pin();
|
||||
// Interrupt swizzling
|
||||
let irq = 32 + (device.device + interrupt_pin - 1) % 4;
|
||||
device.set_interrupt_irq(irq);
|
||||
device.ptr.set_interrupt_line(irq);
|
||||
|
||||
let command = device.get_command() | 0b110;
|
||||
device.set_command(command);
|
||||
|
||||
for (i, bar) in device.get_bars() {
|
||||
println!("bar {} {:x?}", i, bar);
|
||||
if bar.is_memory_space() && bar.base_address().is_null() {
|
||||
println!("alloc");
|
||||
bar.allocate(
|
||||
(0x5100_0000 + (device.device as u32 * 0x100_000) + (i as u32 * 0x4000))
|
||||
as *const u8,
|
||||
@@ -381,9 +337,9 @@ pub fn scan_pci_for_virtio_keyboard() -> Option<VirtioPciCaps> {
|
||||
}
|
||||
}
|
||||
|
||||
let mut common_cfg = 0;
|
||||
let mut notify_cfg = 0;
|
||||
let mut isr_cfg = 0;
|
||||
let mut common_cfg = core::ptr::null_mut();
|
||||
let mut notify_cfg = core::ptr::null_mut();
|
||||
let mut isr_cfg = core::ptr::null_mut();
|
||||
let mut notify_multiplier = 1;
|
||||
|
||||
for capability_addr in device.capabilities() {
|
||||
@@ -395,11 +351,11 @@ pub fn scan_pci_for_virtio_keyboard() -> Option<VirtioPciCaps> {
|
||||
let addr = bar_addr.wrapping_add(capability.offset as usize);
|
||||
match capability.capability_type {
|
||||
VirtioCapabilityType::Common => {
|
||||
common_cfg = addr as usize;
|
||||
common_cfg = addr as *mut VirtioPciCommonCfg;
|
||||
println!("[VirtIO] CommonCfg trouvé à 0x{:x?}", addr);
|
||||
}
|
||||
VirtioCapabilityType::Notify => {
|
||||
notify_cfg = addr as usize;
|
||||
notify_cfg = addr as *mut u16;
|
||||
notify_multiplier = unsafe {
|
||||
(*(capability_addr as *mut VirtioNotificationCapability))
|
||||
.notify_offset_multiplier
|
||||
@@ -407,7 +363,7 @@ pub fn scan_pci_for_virtio_keyboard() -> Option<VirtioPciCaps> {
|
||||
println!("[VirtIO] NotifyCfg trouvé à 0x{:x?}", addr);
|
||||
}
|
||||
VirtioCapabilityType::Isr => {
|
||||
isr_cfg = addr as usize;
|
||||
isr_cfg = addr as *mut u8;
|
||||
println!("[VirtIO] IsrCfg trouvé à 0x{:x?}", addr);
|
||||
}
|
||||
_ => {}
|
||||
@@ -416,14 +372,24 @@ pub fn scan_pci_for_virtio_keyboard() -> Option<VirtioPciCaps> {
|
||||
}
|
||||
}
|
||||
|
||||
if common_cfg != 0 && notify_cfg != 0 && isr_cfg != 0 {
|
||||
if !common_cfg.is_null() && !notify_cfg.is_null() && !isr_cfg.is_null() {
|
||||
Some(VirtioPciCaps {
|
||||
common_cfg,
|
||||
notify_cfg,
|
||||
isr_cfg,
|
||||
notify_multiplier,
|
||||
irq: irq as u32,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scan_virtio_devices() -> (Option<VirtioPciCaps>, Option<VirtioPciCaps>) {
|
||||
let mut devices =
|
||||
PciDeviceIterator::new().filter(|device| device.vendor_and_device_id() == (0x1af4, 0x1052));
|
||||
(
|
||||
devices.next().and_then(scan_virtio_keyboard_and_mouse),
|
||||
devices.next().and_then(scan_virtio_keyboard_and_mouse),
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user