Add mouse and clean virtio
This commit is contained in:
10
.gdbinit
10
.gdbinit
@@ -1,6 +1,6 @@
|
||||
# file target/riscv64/debug/kernel-rust
|
||||
file target/riscv64/debug/kernel-rust
|
||||
target remote localhost:1234
|
||||
# break machine_mode_entry
|
||||
break *0x800bf000
|
||||
add-symbol-file target/riscv64/debug/test_pic 0x800bf000
|
||||
# c
|
||||
break machine_mode_entry
|
||||
# break *0x800bf000
|
||||
# add-symbol-file target/riscv64/debug/test_pic 0x800bf000
|
||||
c
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[workspace]
|
||||
resolver = "3"
|
||||
members = ["crates/io","crates/os-std", "crates/shared", "user/*"]
|
||||
members = ["crates/bytes-struct","crates/io","crates/os-std", "crates/shared", "user/*"]
|
||||
|
||||
[package]
|
||||
name = "kernel-rust"
|
||||
@@ -11,6 +11,7 @@ edition = "2024"
|
||||
bitflags = "2"
|
||||
embedded-alloc = "0.7"
|
||||
kernel-macros = { path = "crates/kernel-macros" }
|
||||
bytes-struct = { path = "crates/bytes-struct" }
|
||||
log = "0.4"
|
||||
critical-section = { version = "1", features = ["restore-state-bool"] }
|
||||
bffs = { path = "crates/bffs", features = ["alloc"] }
|
||||
|
||||
12
crates/bytes-struct/Cargo.toml
Normal file
12
crates/bytes-struct/Cargo.toml
Normal file
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "bytes-struct"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = "1"
|
||||
quote = "1"
|
||||
syn = { version = "2", features = ["full"] }
|
||||
70
crates/bytes-struct/src/lib.rs
Normal file
70
crates/bytes-struct/src/lib.rs
Normal file
@@ -0,0 +1,70 @@
|
||||
use core::iter::Iterator;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use syn::{Meta, parse_macro_input, spanned::Spanned};
|
||||
|
||||
#[proc_macro_derive(VolatilePackedStruct, attributes(read_only))]
|
||||
pub fn derive_volatile_packed_struct(item: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(item as syn::DeriveInput);
|
||||
|
||||
if !input.attrs.iter().any(|attr| match &attr.meta {
|
||||
Meta::List(list) => list.path.segments.last().is_some_and(|s| s.ident == "repr"),
|
||||
_ => false,
|
||||
}) {
|
||||
return syn::Error::new(
|
||||
input.span(),
|
||||
"Item should use a #[repr(packed)] representation",
|
||||
)
|
||||
.into_compile_error()
|
||||
.into();
|
||||
}
|
||||
|
||||
let fields = match input.data {
|
||||
syn::Data::Struct(data_struct) => match data_struct.fields {
|
||||
syn::Fields::Named(fields_named) => fields_named,
|
||||
syn::Fields::Unnamed(_) | syn::Fields::Unit => unimplemented!(),
|
||||
},
|
||||
syn::Data::Enum(_) => unimplemented!(),
|
||||
syn::Data::Union(_) => unimplemented!(),
|
||||
};
|
||||
|
||||
let mut getters = Vec::new();
|
||||
let mut setters = Vec::new();
|
||||
|
||||
for field in fields.named {
|
||||
let field_name = field.ident.unwrap();
|
||||
if field_name.to_string().starts_with("_") {
|
||||
continue;
|
||||
}
|
||||
let ty = field.ty;
|
||||
let getter_name = format_ident!("get_{}", field_name);
|
||||
let setter_name = format_ident!("set_{}", field_name);
|
||||
|
||||
getters.push(quote! {
|
||||
pub fn #getter_name(self: *const Self) -> #ty {
|
||||
unsafe {
|
||||
(&raw const (*self).#field_name).read_volatile()
|
||||
}
|
||||
}
|
||||
});
|
||||
setters.push(quote! {
|
||||
pub fn #setter_name(self: *mut Self, value: #ty) {
|
||||
unsafe {
|
||||
(&raw mut (*self).#field_name).write_volatile(value);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let struct_path = input.ident;
|
||||
let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl();
|
||||
|
||||
quote! {
|
||||
impl #impl_generics #struct_path #type_generics #where_clause {
|
||||
#(#getters)*
|
||||
#(#setters)*
|
||||
}
|
||||
}
|
||||
.into()
|
||||
}
|
||||
1
justfile
1
justfile
@@ -33,6 +33,7 @@ qemu := f"qemu-system-riscv64 \
|
||||
-serial mon:stdio \
|
||||
-device bochs-display \
|
||||
-device virtio-keyboard-pci \
|
||||
-device virtio-mouse-pci \
|
||||
-device loader,file=disk.img,addr=0x90000000 \
|
||||
-bios none -m 512M {{qemu_flags}}"
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//! kernel when interacting with machine-mode services.
|
||||
#[non_exhaustive]
|
||||
#[repr(usize)]
|
||||
pub enum EextensionID {
|
||||
pub enum ExtensionID {
|
||||
Time = 0x54494D45,
|
||||
}
|
||||
|
||||
|
||||
@@ -9,16 +9,16 @@ use log::info;
|
||||
use shared::syscall::SysCall;
|
||||
|
||||
use crate::{
|
||||
KBD_DRIVER,
|
||||
boot::sbi::{EextensionID, TimerFunctionID},
|
||||
clear_csr, println,
|
||||
KBD_DRIVER, MOUSE_DRIVER,
|
||||
boot::sbi::{ExtensionID, TimerFunctionID},
|
||||
clear_csr,
|
||||
process::{ExecutionContext, exit_process, sleep},
|
||||
read_csr,
|
||||
riscv::disable_interrupt,
|
||||
scheduler::SCHEDULER,
|
||||
set_csr, syscall,
|
||||
time::{IRQ_M_EXTERNAL, IRQ_M_TIMER, setup_next_timer_interrupt},
|
||||
virtio::input::S_MODE_CLAIM_COMPLETE,
|
||||
virtio::input::HANDLING_INTERRUPT,
|
||||
virtual_fs::{FILE_SYSTEM, VirtualFileSystem},
|
||||
write_csr,
|
||||
};
|
||||
@@ -58,7 +58,7 @@ unsafe extern "C" fn machine_trap_handler(
|
||||
|
||||
#[allow(clippy::single_match)]
|
||||
match eid {
|
||||
c if c == EextensionID::Time as usize => match fid {
|
||||
c if c == ExtensionID::Time as usize => match fid {
|
||||
c if c == TimerFunctionID::SetTimer as usize => {
|
||||
clear_csr!(mip, 1 << 5);
|
||||
}
|
||||
@@ -199,7 +199,7 @@ unsafe extern "C" fn supervisor_trap_handler(
|
||||
"ecall",
|
||||
in("a0") 0,
|
||||
in("a6") TimerFunctionID::SetTimer as u64,
|
||||
in("a7") EextensionID::Time as u64,
|
||||
in("a7") ExtensionID::Time as u64,
|
||||
clobber_abi("system")
|
||||
);
|
||||
}
|
||||
@@ -207,17 +207,21 @@ unsafe extern "C" fn supervisor_trap_handler(
|
||||
SCHEDULER.lock().schedule(&mut interrupt_state);
|
||||
}
|
||||
9 => {
|
||||
println!("click");
|
||||
let irq = core::ptr::read_volatile(S_MODE_CLAIM_COMPLETE);
|
||||
unsafe {
|
||||
let irq = core::ptr::read_volatile((HANDLING_INTERRUPT + 0x1004) as *const u32);
|
||||
|
||||
if irq != 0 {
|
||||
// ... Traiter l'interruption VirtIO ici ...
|
||||
if irq != 0 {
|
||||
if irq == 34 {
|
||||
KBD_DRIVER.handle_interrupt();
|
||||
} else if irq == 35 {
|
||||
MOUSE_DRIVER.handle_interrupt();
|
||||
}
|
||||
|
||||
// 2. Écrire l'IRQ (Complete) <--- INDISPENSABLE
|
||||
core::ptr::write_volatile(S_MODE_CLAIM_COMPLETE, irq);
|
||||
KBD_DRIVER.as_mut().unwrap().handle_interrupt();
|
||||
} else {
|
||||
panic!()
|
||||
// Complete interrupt
|
||||
core::ptr::write_volatile((HANDLING_INTERRUPT + 0x1004) as *mut u32, irq);
|
||||
} else {
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
||||
80
src/main.rs
80
src/main.rs
@@ -19,8 +19,9 @@ use embedded_alloc::LlffHeap as Heap;
|
||||
use log::info;
|
||||
|
||||
use crate::{
|
||||
draw::{Color, Draw},
|
||||
io::init_log,
|
||||
pci::{PciDeviceIterator, scan_pci_for_virtio_keyboard},
|
||||
pci::{PciDeviceIterator, scan_virtio_devices},
|
||||
riscv::enable_supervisor_interrupt,
|
||||
scheduler::{SCHEDULER, idle},
|
||||
user::{proc2, test},
|
||||
@@ -54,7 +55,6 @@ mod vga;
|
||||
mod virtio;
|
||||
mod virtual_console;
|
||||
mod virtual_fs;
|
||||
mod volatile;
|
||||
|
||||
pub const HEAP_SIZE: usize = 1024 * 1024 * 32; // 32Mo RAM
|
||||
#[global_allocator]
|
||||
@@ -64,13 +64,56 @@ static HEAP_INITIALIZED: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
// Usize is assumed to be an u64 in the whole kernel
|
||||
const _: () = assert!(core::mem::size_of::<usize>() == core::mem::size_of::<u64>());
|
||||
|
||||
#[cfg(not(target_endian = "little"))]
|
||||
compile_error! {"This kernel implementation assume endianness is little-endian. Some memory access like PCI could not work in big-endian."}
|
||||
|
||||
// 1. Allouer de la mémoire statique alignée pour la queue
|
||||
static mut KBD_QUEUE: Virtqueue = unsafe { core::mem::zeroed() };
|
||||
pub static mut KBD_DRIVER: Option<VirtioPciDriver> = None;
|
||||
pub static mut KBD_DRIVER: VirtioPciDriver = unsafe {
|
||||
VirtioPciDriver::new(
|
||||
|event| {
|
||||
if event.is_key() {
|
||||
let event = event.as_key_event();
|
||||
println!("key, {:#?}", event);
|
||||
} else {
|
||||
println!("key pressed, {:#?}", event);
|
||||
}
|
||||
},
|
||||
&mut KBD_QUEUE,
|
||||
)
|
||||
};
|
||||
|
||||
pub static mut MOUSE_POSITION: (u16, u16) = (0, 0);
|
||||
|
||||
static mut MOUSE_QUEUE: Virtqueue = unsafe { core::mem::zeroed() };
|
||||
pub static mut MOUSE_DRIVER: VirtioPciDriver = unsafe {
|
||||
VirtioPciDriver::new(
|
||||
|event| {
|
||||
if event.is_relative() {
|
||||
let event = event.as_relative_event();
|
||||
|
||||
vga::Vga.write_pixel_unsafe(MOUSE_POSITION.0, MOUSE_POSITION.1, Color::BLACK);
|
||||
|
||||
match event.code {
|
||||
virtio::input::EventCodeRelative::X => {
|
||||
MOUSE_POSITION.0 = (MOUSE_POSITION.0 as i32 + event.value) as u16
|
||||
}
|
||||
virtio::input::EventCodeRelative::Y => {
|
||||
MOUSE_POSITION.1 = (MOUSE_POSITION.1 as i32 + event.value) as u16
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
vga::Vga.write_pixel_unsafe(MOUSE_POSITION.0, MOUSE_POSITION.1, Color::RED);
|
||||
|
||||
// println!("mouse moved relatively, {:#?}", event);
|
||||
} else {
|
||||
// println!("mouse moved, {:#?}", event);
|
||||
}
|
||||
},
|
||||
&mut MOUSE_QUEUE,
|
||||
)
|
||||
};
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn supervisor_mode_entry() {
|
||||
@@ -100,16 +143,25 @@ pub extern "C" fn supervisor_mode_entry() {
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let pci_info = scan_pci_for_virtio_keyboard().unwrap();
|
||||
KBD_DRIVER = Some(VirtioPciDriver::new(
|
||||
pci_info.common_cfg,
|
||||
pci_info.notify_cfg,
|
||||
pci_info.isr_cfg,
|
||||
pci_info.notify_multiplier,
|
||||
&mut KBD_QUEUE,
|
||||
));
|
||||
KBD_DRIVER.as_mut().unwrap().init();
|
||||
init_plic_pci(34);
|
||||
let (pci_keyboard, pci_mouse) = scan_virtio_devices();
|
||||
let (pci_keyboard, pci_mouse) = (pci_keyboard.unwrap(), pci_mouse.unwrap());
|
||||
|
||||
KBD_DRIVER.init(
|
||||
pci_keyboard.common_cfg,
|
||||
pci_keyboard.notify_cfg,
|
||||
pci_keyboard.isr_cfg,
|
||||
pci_keyboard.notify_multiplier,
|
||||
);
|
||||
|
||||
MOUSE_DRIVER.init(
|
||||
pci_mouse.common_cfg,
|
||||
pci_mouse.notify_cfg,
|
||||
pci_mouse.isr_cfg,
|
||||
pci_mouse.notify_multiplier,
|
||||
);
|
||||
|
||||
init_plic_pci(pci_keyboard.irq);
|
||||
init_plic_pci(pci_mouse.irq);
|
||||
}
|
||||
idle();
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use alloc::{format, string::ToString};
|
||||
use log::error;
|
||||
|
||||
use crate::{
|
||||
HEAP, HEAP_INITIALIZED,
|
||||
HEAP_INITIALIZED,
|
||||
draw::{Color, Draw, FONT_HEIGHT},
|
||||
uart::write_uart,
|
||||
vga::Vga,
|
||||
|
||||
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),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,22 +2,8 @@ pub mod input;
|
||||
|
||||
use core::sync::atomic::AtomicU16;
|
||||
|
||||
// --- Constantes VirtIO ---
|
||||
const VIRTIO_MMIO_MAGIC_VALUE: usize = 0x000;
|
||||
const VIRTIO_MMIO_VERSION: usize = 0x004;
|
||||
const VIRTIO_MMIO_DEVICE_ID: usize = 0x008;
|
||||
const VIRTIO_MMIO_STATUS: usize = 0x070;
|
||||
const VIRTIO_MMIO_GUEST_PAGE_SIZE: usize = 0x028;
|
||||
const VIRTIO_MMIO_QUEUE_SEL: usize = 0x030;
|
||||
const VIRTIO_MMIO_QUEUE_NUM_MAX: usize = 0x034;
|
||||
const VIRTIO_MMIO_QUEUE_NUM: usize = 0x038;
|
||||
const VIRTIO_MMIO_QUEUE_PFN: usize = 0x040;
|
||||
const VIRTIO_MMIO_INTERRUPT_ACK: usize = 0x064;
|
||||
|
||||
const STATUS_ACKNOWLEDGE: u32 = 1;
|
||||
const STATUS_DRIVER: u32 = 2;
|
||||
const STATUS_DRIVER_OK: u32 = 4;
|
||||
const STATUS_FEATURES_OK: u32 = 8;
|
||||
use bitflags::bitflags;
|
||||
use bytes_struct::VolatilePackedStruct;
|
||||
|
||||
const QUEUE_SIZE: usize = 128; // Puissance de 2 obligatoire
|
||||
|
||||
@@ -57,17 +43,8 @@ pub struct UsedElement {
|
||||
pub len: u32,
|
||||
}
|
||||
|
||||
// --- Structure de l'événement Clavier ---
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct VirtioInputEvent {
|
||||
pub event_type: u16,
|
||||
pub code: u16,
|
||||
pub value: u32,
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, VolatilePackedStruct)]
|
||||
pub struct VirtioCapability {
|
||||
pub capability_id: u8,
|
||||
pub next_ptr: u8,
|
||||
@@ -88,6 +65,7 @@ pub struct VirtioNotificationCapability {
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[repr(u8)]
|
||||
#[allow(unused)]
|
||||
pub enum VirtioCapabilityType {
|
||||
/// Common configuration
|
||||
Common = 1,
|
||||
@@ -104,3 +82,66 @@ pub enum VirtioCapabilityType {
|
||||
/// Vendor-specific data
|
||||
Vendor = 9,
|
||||
}
|
||||
|
||||
#[repr(C, packed(4))]
|
||||
#[derive(Debug, Clone, Copy, VolatilePackedStruct)]
|
||||
pub struct VirtioPciCommonCfg {
|
||||
// About the whole device.
|
||||
/// read-write
|
||||
device_feature_select: u32,
|
||||
/// read-only for driver
|
||||
device_feature: u32,
|
||||
/// read-write
|
||||
driver_feature_select: u32,
|
||||
/// read-write
|
||||
driver_feature: u32,
|
||||
/// read-write
|
||||
config_msix_vector: u16,
|
||||
/// read-only for driver
|
||||
num_queues: u16,
|
||||
/// read-write
|
||||
device_status: DeviceStatus,
|
||||
/// read-only for driver
|
||||
config_generation: u8,
|
||||
|
||||
// About a specific virtqueue.
|
||||
/// read-write
|
||||
queue_select: u16,
|
||||
/// read-write
|
||||
queue_size: u16,
|
||||
/// read-write
|
||||
queue_msix_vector: u16,
|
||||
/// read-write
|
||||
queue_enable: u16,
|
||||
/// read-only for driver
|
||||
queue_notify_off: u16,
|
||||
/// read-write
|
||||
queue_desc: u64,
|
||||
/// read-write
|
||||
queue_driver: u64,
|
||||
/// read-write
|
||||
queue_device: u64,
|
||||
/// read-only for driver
|
||||
queue_notify_data: u16,
|
||||
/// read-write
|
||||
queue_reset: u16,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct DeviceStatus: u8 {
|
||||
const Reinitialized = 0;
|
||||
/// Indicates that the guest OS has found the device and recognized it as a valid virtio device.
|
||||
const Acknowledge = 1;
|
||||
/// Indicates that the guest OS knows how to drive the device. Note: There could be a significant (or infinite) delay before setting this bit. For example, under Linux, drivers can be loadable modules.
|
||||
const Driver = 2;
|
||||
/// Indicates that something went wrong in the guest, and it has given up on the device. This could be an internal error, or the driver didn’t like the device for some reason, or even a fatal error during device operation.
|
||||
const Failed = 128;
|
||||
/// Indicates that the driver has acknowledged all the features it understands, and feature negotiation is complete.
|
||||
const FeaturesOk = 8;
|
||||
/// Indicates that the driver is set up and ready to drive the device.
|
||||
const DriverOk = 4;
|
||||
/// Indicates that the device has experienced an error from which it can’t recover.
|
||||
const DeviceNeedsReset = 64;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,87 +1,160 @@
|
||||
use core::{
|
||||
ptr::{read_volatile, write_volatile},
|
||||
sync::atomic::Ordering,
|
||||
};
|
||||
use core::{ptr::write_volatile, sync::atomic::Ordering};
|
||||
|
||||
use bytes_struct::VolatilePackedStruct;
|
||||
|
||||
use crate::{
|
||||
println,
|
||||
virtio::{QUEUE_SIZE, VirtioInputEvent, Virtqueue},
|
||||
virtio::{DeviceStatus, QUEUE_SIZE, VirtioPciCommonCfg, Virtqueue},
|
||||
};
|
||||
|
||||
pub struct VirtioPciDriver {
|
||||
// Les 3 zones clés du PCI Modern
|
||||
common_cfg: usize,
|
||||
notify_cfg: usize,
|
||||
isr_cfg: usize,
|
||||
pub struct VirtioPciDriver<F: Fn(&VirtioInputEvent) = fn(&VirtioInputEvent)> {
|
||||
common_cfg: *mut VirtioPciCommonCfg,
|
||||
notify_cfg: *mut u16,
|
||||
isr_cfg: *mut u8,
|
||||
|
||||
queue: &'static mut Virtqueue,
|
||||
event_pool: [VirtioInputEvent; QUEUE_SIZE],
|
||||
last_used_idx: u16,
|
||||
notify_off: u32, // Multiplier from PCI notify capability (used to compute notify address)
|
||||
|
||||
handle_event: F,
|
||||
}
|
||||
|
||||
impl VirtioPciDriver {
|
||||
pub const unsafe fn new(
|
||||
common_cfg: usize,
|
||||
notify_cfg: usize,
|
||||
isr_cfg: usize,
|
||||
notify_mult: u32,
|
||||
queue_mem: &'static mut Virtqueue,
|
||||
) -> Self {
|
||||
#[repr(u16)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum EventType {
|
||||
Sync = 0,
|
||||
Key = 1,
|
||||
Relative = 2,
|
||||
Absolute = 3,
|
||||
}
|
||||
|
||||
#[repr(u16)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum EventCodeRelative {
|
||||
X = 0,
|
||||
Y = 1,
|
||||
Wheel = 8,
|
||||
}
|
||||
|
||||
#[repr(u16)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum EventCodeValue {
|
||||
Released = 0,
|
||||
Pressed = 1,
|
||||
AutomaticRepetition = 2,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct VirtioInputEvent {
|
||||
pub event_type: EventType,
|
||||
pub code: u16,
|
||||
pub value: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct VirtioRelativeEvent {
|
||||
pub event_type: EventType,
|
||||
pub code: EventCodeRelative,
|
||||
pub value: i32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct VirtioKeyEvent {
|
||||
pub event_type: EventType,
|
||||
pub code: u16,
|
||||
pub value: EventCodeValue,
|
||||
}
|
||||
|
||||
impl VirtioInputEvent {
|
||||
pub fn is_relative(&self) -> bool {
|
||||
self.event_type == EventType::Relative
|
||||
}
|
||||
pub unsafe fn as_relative_event(&self) -> &VirtioRelativeEvent {
|
||||
unsafe { &*(self as *const Self as *const VirtioRelativeEvent) }
|
||||
}
|
||||
pub fn is_key(&self) -> bool {
|
||||
self.event_type == EventType::Key
|
||||
}
|
||||
pub unsafe fn as_key_event(&self) -> &VirtioKeyEvent {
|
||||
unsafe { &*(self as *const Self as *const VirtioKeyEvent) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Fn(&VirtioInputEvent)> VirtioPciDriver<F> {
|
||||
pub const unsafe fn new(handle_event: F, queue_mem: &'static mut Virtqueue) -> Self {
|
||||
Self {
|
||||
common_cfg,
|
||||
notify_cfg,
|
||||
isr_cfg,
|
||||
common_cfg: core::ptr::null_mut(),
|
||||
notify_cfg: core::ptr::null_mut(),
|
||||
isr_cfg: core::ptr::null_mut(),
|
||||
queue: queue_mem,
|
||||
event_pool: [VirtioInputEvent {
|
||||
event_type: 0,
|
||||
event_type: EventType::Sync,
|
||||
code: 0,
|
||||
value: 0,
|
||||
}; QUEUE_SIZE],
|
||||
last_used_idx: 0,
|
||||
notify_off: notify_mult,
|
||||
notify_off: 0,
|
||||
handle_event,
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn init(&mut self) {
|
||||
println!("{:x}", self.common_cfg);
|
||||
pub unsafe fn init(
|
||||
&mut self,
|
||||
common_cfg: *mut VirtioPciCommonCfg,
|
||||
notify_cfg: *mut u16,
|
||||
isr_cfg: *mut u8,
|
||||
notify_mult: u32,
|
||||
) {
|
||||
self.common_cfg = common_cfg;
|
||||
self.notify_cfg = notify_cfg;
|
||||
self.isr_cfg = isr_cfg;
|
||||
self.notify_off = notify_mult;
|
||||
|
||||
println!("{:x?}", self.common_cfg);
|
||||
// --- 1. Reset & Status ---
|
||||
self.write_common_u8(0x14, 0); // device_status
|
||||
self.write_common_u8(0x14, 1 | 2); // ACK | DRIVER
|
||||
self.common_cfg
|
||||
.set_device_status(DeviceStatus::Reinitialized);
|
||||
self.common_cfg
|
||||
.set_device_status(DeviceStatus::Acknowledge | DeviceStatus::Driver);
|
||||
|
||||
// --- 2. Négociation Features (Bit 32 = Version 1) ---
|
||||
self.write_common_u32(0x08, 1); // driver_feature_select = page 1
|
||||
let f1 = self.read_common_u32(0x0C); // driver_feature
|
||||
self.write_common_u32(0x0C, f1 | 1); // Accepter VIRTIO_F_VERSION_1
|
||||
self.common_cfg.set_driver_feature_select(1); // Page 1
|
||||
let f1 = self.common_cfg.get_driver_feature();
|
||||
self.common_cfg.set_driver_feature(f1 | 1); // bit 32 VIRTIO_F_VERSION_1
|
||||
|
||||
self.write_common_u8(0x14, 1 | 2 | 8); // FEATURES_OK
|
||||
if (self.read_common_u8(0x14) & 8) == 0 {
|
||||
self.common_cfg.set_device_status(
|
||||
DeviceStatus::Acknowledge | DeviceStatus::Driver | DeviceStatus::FeaturesOk,
|
||||
);
|
||||
if !self
|
||||
.common_cfg
|
||||
.get_device_status()
|
||||
.contains(DeviceStatus::FeaturesOk)
|
||||
{
|
||||
panic!("PCI Virtio: Features rejected");
|
||||
}
|
||||
|
||||
// --- 3. Configuration de la Queue 0 ---
|
||||
self.write_common_u16(0x16, 0); // queue_select = 0
|
||||
|
||||
// Fixer la taille
|
||||
self.write_common_u16(0x18, QUEUE_SIZE as u16); // queue_size
|
||||
self.common_cfg.set_queue_select(0);
|
||||
self.common_cfg.set_queue_size(QUEUE_SIZE as u16);
|
||||
|
||||
// --- 4. Adresses 64 bits ---
|
||||
let desc_addr = &self.queue.descriptors as *const _ as u64;
|
||||
let desc_addr = self.queue.descriptors.as_ptr() as u64;
|
||||
println!("desc_addr: {:x}", desc_addr);
|
||||
self.write_common_u32(0x20, (desc_addr & 0xffffffff) as u32); // queue_desc_lo
|
||||
self.write_common_u32(0x24, (desc_addr >> 32) as u32); // queue_desc_hi
|
||||
self.common_cfg.set_queue_desc(desc_addr);
|
||||
|
||||
let avail_addr = &self.queue.available as *const _ as u64;
|
||||
self.write_common_u32(0x28, (avail_addr & 0xffffffff) as u32); // queue_avail_lo
|
||||
self.write_common_u32(0x2C, (avail_addr >> 32) as u32); // queue_avail_hi
|
||||
let avail_addr = &raw const self.queue.available as u64;
|
||||
self.common_cfg.set_queue_driver(avail_addr);
|
||||
|
||||
let used_addr = &self.queue.used as *const _ as u64;
|
||||
self.write_common_u32(0x30, (used_addr & 0xffffffff) as u32); // queue_used_lo
|
||||
self.write_common_u32(0x34, (used_addr >> 32) as u32); // queue_used_hi
|
||||
let used_addr = &raw const self.queue.used as u64;
|
||||
self.common_cfg.set_queue_device(used_addr);
|
||||
|
||||
// --- 5. Remplissage initial ---
|
||||
for i in 0..QUEUE_SIZE {
|
||||
self.queue.descriptors[i].addr = &self.event_pool[i] as *const _ as u64;
|
||||
self.queue.descriptors[i].addr = &raw const self.event_pool[i] as u64;
|
||||
self.queue.descriptors[i].len = core::mem::size_of::<VirtioInputEvent>() as u32;
|
||||
self.queue.descriptors[i].flags = 2; // VRING_DESC_F_WRITE
|
||||
self.queue.available.ring[i] = i as u16;
|
||||
@@ -92,30 +165,37 @@ impl VirtioPciDriver {
|
||||
.store(QUEUE_SIZE as u16, Ordering::Release);
|
||||
|
||||
// --- 6. Activation ---
|
||||
self.write_common_u16(0x1C, 1); // queue_enable = 1
|
||||
self.common_cfg.set_queue_enable(1);
|
||||
|
||||
if self.read_common_u16(0x1C) == 0 {
|
||||
if self.common_cfg.get_queue_enable() == 0 {
|
||||
panic!("Le périphérique refuse d'activer la queue !");
|
||||
}
|
||||
|
||||
// --- 7. Driver OK (must be set after queue is enabled) ---
|
||||
self.write_common_u8(0x14, 1 | 2 | 4 | 8);
|
||||
|
||||
// --- 8. PREMIER KICK ---
|
||||
// Compute the notify address for queue 0 using the multiplier provided by PCI capability
|
||||
let notify_addr = self.notify_cfg + (self.notify_off as usize * 0);
|
||||
self.common_cfg.set_device_status(
|
||||
DeviceStatus::Acknowledge
|
||||
| DeviceStatus::Driver
|
||||
| DeviceStatus::DriverOk
|
||||
| DeviceStatus::FeaturesOk,
|
||||
);
|
||||
|
||||
unsafe {
|
||||
core::ptr::write_volatile(notify_addr as *mut u16, 0); // 0 = index de la queue
|
||||
// --- 8. PREMIER KICK ---
|
||||
// Compute the notify address for queue 0 using the multiplier provided by PCI capability
|
||||
let notify_addr = self.notify_cfg.byte_add(
|
||||
self.notify_off as usize * self.common_cfg.get_queue_notify_off() as usize,
|
||||
);
|
||||
core::ptr::write_volatile(notify_addr, 0); // 0 = index de la queue
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_interrupt(&mut self) {
|
||||
// 1. Lire et acquitter l'ISR PCI (Indispensable pour baisser la ligne IRQ)
|
||||
let isr = unsafe { read_volatile(self.isr_cfg as *const u8) };
|
||||
let isr = unsafe { self.isr_cfg.read_volatile() };
|
||||
if isr & 1 == 0 {
|
||||
// Not a queue interrupt
|
||||
return;
|
||||
} // Pas une interruption de queue
|
||||
}
|
||||
|
||||
let used_idx = self.queue.used.idx.load(Ordering::Acquire);
|
||||
while self.last_used_idx != used_idx {
|
||||
@@ -123,10 +203,7 @@ impl VirtioPciDriver {
|
||||
let used_elem = &self.queue.used.ring[ring_slot];
|
||||
let event = &self.event_pool[used_elem.id as usize];
|
||||
|
||||
if event.event_type == 1 {
|
||||
println!("key pressed");
|
||||
// self.on_key(event.code, event.value);
|
||||
}
|
||||
(self.handle_event)(event);
|
||||
|
||||
// Recyclage
|
||||
let avail_head = self.queue.available.idx.load(Ordering::Relaxed) as usize % QUEUE_SIZE;
|
||||
@@ -136,49 +213,35 @@ impl VirtioPciDriver {
|
||||
self.last_used_idx = self.last_used_idx.wrapping_add(1);
|
||||
}
|
||||
|
||||
// Notifier qu'on a traité les buffers (si besoin)
|
||||
unsafe {
|
||||
write_volatile(self.notify_cfg as *mut u16, 0);
|
||||
write_volatile(self.notify_cfg, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Helpers de lecture/écriture (Note : PCI utilise des tailles mixtes u8/u16/u32)
|
||||
unsafe fn write_common_u8(&self, off: usize, val: u8) {
|
||||
write_volatile((self.common_cfg + off) as *mut u8, val);
|
||||
}
|
||||
unsafe fn write_common_u16(&self, off: usize, val: u16) {
|
||||
write_volatile((self.common_cfg + off) as *mut u16, val);
|
||||
}
|
||||
unsafe fn write_common_u32(&self, off: usize, val: u32) {
|
||||
write_volatile((self.common_cfg + off) as *mut u32, val);
|
||||
}
|
||||
unsafe fn read_common_u8(&self, off: usize) -> u8 {
|
||||
read_volatile((self.common_cfg + off) as *const u8)
|
||||
}
|
||||
unsafe fn read_common_u16(&self, off: usize) -> u16 {
|
||||
read_volatile((self.common_cfg + off) as *const u16)
|
||||
}
|
||||
unsafe fn read_common_u32(&self, off: usize) -> u32 {
|
||||
read_volatile((self.common_cfg + off) as *const u32)
|
||||
}
|
||||
}
|
||||
|
||||
pub const PLIC_BASE: usize = 0x0c00_0000;
|
||||
pub const IRQ_VIRTIO: u32 = 1;
|
||||
pub const PLIC_BASE: usize = 0x0C00_0000;
|
||||
pub const HANDLING_INTERRUPT: usize = PLIC_BASE + 0x20_0000;
|
||||
pub const ENABLE_INTERRUPT: usize = PLIC_BASE + 0x2000;
|
||||
|
||||
pub const S_MODE_CLAIM_COMPLETE: *mut u32 = 0x0c20_1004 as *mut u32;
|
||||
#[repr(C, packed)]
|
||||
#[derive(Debug, Clone, Copy, VolatilePackedStruct)]
|
||||
pub struct PlicHandlingInterrupt {
|
||||
pub priority_threshold: u32,
|
||||
pub claim: u32,
|
||||
}
|
||||
|
||||
/// See https://wiki.osdev.org/PLIC
|
||||
pub fn init_plic_pci(irq: u32) {
|
||||
let priority_ptr = (PLIC_BASE + (irq as usize * 4)) as *mut u32;
|
||||
unsafe { priority_ptr.write_volatile(1) };
|
||||
|
||||
// Mettre le Threshold à 0 pour Hart 0 S-Mode (offset 0x201000)
|
||||
let threshold_ptr = (PLIC_BASE + 0x201000) as *mut u32;
|
||||
unsafe { threshold_ptr.write_volatile(0) };
|
||||
// Mettre le Threshold à 0 pour Hart 0 S-Mode (context 1)
|
||||
let handling_interrupt = (HANDLING_INTERRUPT + 0x1000) as *mut PlicHandlingInterrupt;
|
||||
handling_interrupt.set_priority_threshold(0);
|
||||
|
||||
// Activer l'IRQ pour le S-Mode (Hart 0)
|
||||
// Activer l'IRQ pour le S-Mode (Hart 0) (context 1)
|
||||
// Attention : l'enable bit pour l'IRQ 33 est le bit 1 du deuxième mot u32
|
||||
let enable_reg_offset = (irq / 32) as usize * 4;
|
||||
let enable_ptr = (PLIC_BASE + 0x2080 + enable_reg_offset) as *mut u32;
|
||||
let enable_ptr = (ENABLE_INTERRUPT + 0x80 + (irq / 32) as usize * 4) as *mut u32;
|
||||
unsafe {
|
||||
let current = enable_ptr.read_volatile();
|
||||
enable_ptr.write_volatile(current | (1 << (irq % 32)));
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Volatile<T>(T);
|
||||
|
||||
impl<T> Volatile<T> {
|
||||
pub unsafe fn read_volatile(self: *const Self) -> T {
|
||||
unsafe { core::ptr::read_volatile(self as *const T) }
|
||||
}
|
||||
pub unsafe fn write_volatile(self: *mut Self, value: T) {
|
||||
unsafe { core::ptr::write_volatile(self as *mut T, value) }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user