diff --git a/.cargo/config.toml b/.cargo/config.toml index 8e84a7d..f072b50 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -10,4 +10,3 @@ build-std-features = ["compiler-builtins-mem"] rustflags = [ "-C", "link-arg=-Tilm.ld", ] -runner = "just runner" diff --git a/justfile b/justfile index 5252ad1..0820995 100644 --- a/justfile +++ b/justfile @@ -1,4 +1,5 @@ release := "" +qemu_flags := "" cargo_flags := "" + if release != "" { "--release" } else { "" } bin_path := if release != "" { "target/riscv64/release" } else { "target/riscv64/debug" } @@ -15,31 +16,28 @@ build_user_prog prog: RUSTFLAGS="-C relocation-model=pic -C link-arg=-Tuser.ld -C link-arg=-pie" cargo b {{ cargo_flags }} --package {{ prog }} riscv64-elf-strip {{ bin_path / prog }} cp {{ bin_path / prog }} {{ "mnt/usr/bin" / prog }} - # riscv64-elf-objcopy -O binary {{ bin_path / prog }} {{ "mnt/usr/bin" / prog }} build: mount_filesystem (map_dir "user" f"just release=\"{{release}}\" cargo_flags=\"{{cargo_flags}}\" build_user_prog") cargo b {{ cargo_flags }} just sync_filesystem -run: build - cargo r {{ cargo_flags }} +run: build (runner f"{{bin_path / "kernel-rust"}}") map_dir dir recipe: @for file in `ls {{ dir }}`; do \ {{ recipe }} $file ; \ done -qemu := "qemu-system-riscv64 \ +qemu := f"qemu-system-riscv64 \ -machine virt \ + -serial mon:stdio \ -device bochs-display \ - -global virtio-mmio.force-legacy=false \ - -device virtio-keyboard-device,bus=virtio-mmio-bus.0 \ + -device virtio-keyboard-pci \ -device loader,file=disk.img,addr=0x90000000 \ - -bios none -m 512M" + -bios none -m 512M {{qemu_flags}}" -# \ -# -d guest_errors,unimp \ -# -trace \"virtio*\"" +# -trace \"virtio*\" +# -d guest_errors,unimp,int" perf: build {{ qemu }} -perfmap -kernel {{ bin_path / "kernel-rust" }}& diff --git a/src/boot.rs b/src/boot.rs index e6274e9..4ec8835 100644 --- a/src/boot.rs +++ b/src/boot.rs @@ -7,12 +7,7 @@ use core::arch::naked_asm; use crate::{ clear_csr, interrupt::{setup_machine_trap_handler, setup_supervisor_trap_handler}, - mret, set_csr, supervisor_mode_entry, - virtio::{ - Virtqueue, - input::{VirtioInputDriver, init_plic_m_mode}, - }, - write_csr, + mret, set_csr, supervisor_mode_entry, write_csr, }; pub mod sbi; diff --git a/src/interrupt.rs b/src/interrupt.rs index 4a2d602..f6de92e 100644 --- a/src/interrupt.rs +++ b/src/interrupt.rs @@ -215,7 +215,7 @@ unsafe extern "C" fn supervisor_trap_handler( // 2. Écrire l'IRQ (Complete) <--- INDISPENSABLE core::ptr::write_volatile(S_MODE_CLAIM_COMPLETE, irq); - KBD_DRIVER.handle_interrupt(); + KBD_DRIVER.as_mut().unwrap().handle_interrupt(); } else { panic!() } diff --git a/src/io.rs b/src/io.rs index 5b14239..e9448cb 100644 --- a/src/io.rs +++ b/src/io.rs @@ -62,10 +62,10 @@ macro_rules! print { #[macro_export] macro_rules! println { () => { - $crate::print!("\n\r"); + $crate::print!("\n\r") }; ($($args:expr),*) => { $crate::print!($($args),*); - $crate::println!(); + $crate::println!() }; } diff --git a/src/main.rs b/src/main.rs index e8f86da..931e628 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,11 +16,15 @@ use log::info; use crate::{ io::init_log, + pci::scan_pci_for_virtio_keyboard, riscv::enable_supervisor_interrupt, scheduler::{SCHEDULER, idle}, user::{proc2, test}, vga::Vga, - virtio::{Virtqueue, input::{VirtioInputDriver, init_plic_m_mode}}, + virtio::{ + Virtqueue, + input::{VirtioPciDriver, init_plic_pci}, + }, virtual_fs::init_file_system, }; @@ -32,6 +36,7 @@ mod fs; mod interrupt; mod io; mod panic_handler; +mod pci; mod process; mod riscv; mod scheduler; @@ -57,9 +62,8 @@ const _: () = assert!(core::mem::size_of::() == core::mem::size_of:: // 1. Allouer de la mémoire statique alignée pour la queue static mut KBD_QUEUE: Virtqueue = unsafe { core::mem::zeroed() }; -// 2. Initialisation (adresse 0x10001000 typique pour QEMU virt machine) -pub static mut KBD_DRIVER: VirtioInputDriver = - unsafe { VirtioInputDriver::new(0x10001000, &mut KBD_QUEUE) }; +pub static mut KBD_DRIVER: Option = None; + #[unsafe(no_mangle)] pub extern "C" fn supervisor_mode_entry() { unsafe { @@ -84,8 +88,16 @@ pub extern "C" fn supervisor_mode_entry() { enable_supervisor_interrupt(); unsafe { - KBD_DRIVER.init(); - init_plic_m_mode(); + 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); } idle(); } diff --git a/src/pci.rs b/src/pci.rs new file mode 100644 index 0000000..2982bac --- /dev/null +++ b/src/pci.rs @@ -0,0 +1,174 @@ +use crate::println; + +// 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_u32(bus: u8, dev: u8, func: u8, offset: u16) -> u32 { + 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 u32) } +} + +fn pci_write_u32(bus: u8, dev: u8, func: u8, offset: u16, val: u32) { + 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 u32, val) } +} +#[derive(Copy, Clone, Debug)] +pub struct VirtioPciCaps { + pub common_cfg: usize, + pub notify_cfg: usize, + pub isr_cfg: usize, + pub notify_multiplier: u32, +} + +pub struct PciDevice { + device_id: u8, +} + +impl PciDevice { + pub fn new(device_id: u8) -> Self { + Self { device_id } + } +} + +pub fn pci_iter() { + « +} + +pub fn scan_pci_for_virtio_keyboard() -> Option { + // Sur RISC-V Virt, on scanne généralement le bus 0 + for dev in 0..32 { + let vdev = pci_read_u32(0, dev, 0, 0x00); + let vendor = (vdev & 0xffff) as u16; + let device = (vdev >> 16) as u16; + + // On cherche le Vendor ID VirtIO (0x1AF4) + // et le Device ID Keyboard (0x1012 ou 0x1052 pour Modern) + if vendor == 0x1af4 && (device >= 0x1000 && device <= 0x107f) { + // Dans ta boucle de scan, après avoir trouvé le device + let interrupt_pin = (pci_read_u32(0, dev, 0, 0x3C) >> 8) & 0xFF; // Offset 0x3D + let irq = 32 + (dev as u32 + interrupt_pin - 1) % 4; + + let old_val = pci_read_u32(0, 2, 0, 0x3C); + + // On garde les 24 bits du haut (Interrupt Pin, etc.) et on change les 8 bits du bas + let new_val = (old_val & 0xFFFFFF00) | irq; + + pci_write_u32(0, 2, 0, 0x3C, new_val); + + println!( + "VirtIO Keyboard sur Slot {}, PIN {}, mappé sur IRQ PLIC {}", + dev, interrupt_pin, irq + ); // ACTIVER l'accès mémoire et le bus mastering (PCI Command) + let cmd = pci_read_u32(0, dev, 0, 0x04); + pci_write_u32(0, dev, 0, 0x04, cmd | 0x6); + + let mut common_cfg = 0; + let mut notify_cfg = 0; + let mut isr_cfg = 0; + + // On initialise le multiplicateur à 1 par défaut + let mut notify_multiplier: u32 = 1; + + // 1. Activer le Bus Master et le Memory Space globalement pour ce périphérique avant de commencer + let old_cmd = pci_read_u32(0, dev, 0, 0x04); + pci_write_u32(0, dev, 0, 0x04, old_cmd | 0x06); + + // 2. Boucle d'assignation des BARs (AVANT de lire les capabilities) + let mut bar_idx = 0; + while bar_idx < 6 { + let bar_reg = 0x10 + (bar_idx * 4); + let bar_val = pci_read_u32(0, dev, 0, bar_reg); + + // Si le BAR veut de la mémoire (bit 0 == 0) et n'est pas mappé + if bar_val & 0x1 == 0 && (bar_val & 0xFFFF_FFF0) == 0 { + let new_addr = + 0x5100_0000 + (dev as u32 * 0x100_000) + (bar_idx as u32 * 0x4000); + println!("ALLOCATE BAR {} at {:x}", bar_idx, new_addr); + pci_write_u32(0, dev, 0, bar_reg, new_addr | (bar_val & 0xF)); + + // Gérer les BAR 64-bits (ils consomment deux slots) + if (bar_val >> 1) & 0x3 == 2 { + println!("bar {} is 64 bits", bar_idx); + pci_write_u32(0, dev, 0, bar_reg + 4, 0); + + bar_idx += 1 + } + pci_write_u32(0, dev, 0, bar_reg, new_addr); + let confirm = pci_read_u32(0, dev, 0, bar_reg); + println!("BAR confirmé : {:x}", confirm); + } + bar_idx += 1 + } + let mut cap_ptr = (pci_read_u32(0, dev, 0, 0x34) & 0xFF) as u16; + + while cap_ptr != 0 { + let header = pci_read_u32(0, dev, 0, cap_ptr); + let cap_id = (header & 0xFF) as u8; + let next_ptr = ((header >> 8) & 0xFF) as u16; + let v_type = ((header >> 24) & 0xFF) as u8; + + if cap_id == 0x09 { + // VirtIO Vendor Capability + let bar_idx = (pci_read_u32(0, dev, 0, cap_ptr + 4) & 0xFF) as u8; + let offset = pci_read_u32(0, dev, 0, cap_ptr + 8) as usize; + + // VirtIO : bar_idx doit être entre 0 et 5. 0xFF signifie "ignoré". + if bar_idx <= 5 { + let bar_reg_offset = 0x10 + (bar_idx as u16 * 4); + let mut bar_val = pci_read_u32(0, dev, 0, bar_reg_offset); + + let bar_addr = (bar_val & 0xFFFF_FFF0) as usize; + let final_addr = bar_addr + offset; + + match v_type { + 1 => { + common_cfg = final_addr; + println!("[VirtIO] CommonCfg trouvé à 0x{:x}", final_addr); + } + 2 => { + notify_cfg = final_addr; + // TRÈS IMPORTANT : Lire le multiplicateur (offset 16 de la capability) + notify_multiplier = pci_read_u32(0, dev, 0, cap_ptr + 16); + println!( + "[VirtIO] NotifyCfg trouvé à 0x{:x} (mult: {})", + final_addr, notify_multiplier + ); + } + 3 => { + isr_cfg = final_addr; + println!("[VirtIO] IsrCfg trouvé à 0x{:x}", final_addr); + } + _ => {} + } + } + } + cap_ptr = next_ptr; + } + if common_cfg != 0 && notify_cfg != 0 && isr_cfg != 0 { + return Some(VirtioPciCaps { + common_cfg, + notify_cfg, + isr_cfg, + notify_multiplier, + }); + } + } + } + None +} diff --git a/src/virtio/input.rs b/src/virtio/input.rs index af9ee4e..0eaf601 100644 --- a/src/virtio/input.rs +++ b/src/virtio/input.rs @@ -5,24 +5,33 @@ use core::{ use crate::{ println, - uart::write_char_uart, - virtio::{ - QUEUE_SIZE, STATUS_ACKNOWLEDGE, STATUS_DRIVER, STATUS_DRIVER_OK, VIRTIO_MMIO_INTERRUPT_ACK, - VIRTIO_MMIO_QUEUE_NUM, VIRTIO_MMIO_QUEUE_NUM_MAX, VIRTIO_MMIO_QUEUE_PFN, - VIRTIO_MMIO_QUEUE_SEL, VIRTIO_MMIO_STATUS, VirtioInputEvent, Virtqueue, - }, + virtio::{QUEUE_SIZE, VirtioInputEvent, Virtqueue}, }; -pub struct VirtioInputDriver { - base_addr: usize, + +pub struct VirtioPciDriver { + // Les 3 zones clés du PCI Modern + common_cfg: usize, + notify_cfg: usize, + isr_cfg: usize, + 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) } -impl VirtioInputDriver { - pub const unsafe fn new(base_addr: usize, queue_mem: &'static mut Virtqueue) -> Self { +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 { Self { - base_addr, + common_cfg, + notify_cfg, + isr_cfg, queue: queue_mem, event_pool: [VirtioInputEvent { event_type: 0, @@ -30,146 +39,127 @@ impl VirtioInputDriver { value: 0, }; QUEUE_SIZE], last_used_idx: 0, + notify_off: notify_mult, } } pub unsafe fn init(&mut self) { - unsafe { - // 1. Reset & Status (Ack + Driver) - self.write_reg(0x070, 0); - self.write_reg(0x070, 1 | 2); + 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 - // 2. Négociation Features (Obligatoire en Modern pour débloquer les queues) - self.write_reg(0x024, 1); // Select Page 1 - let f1 = self.read_reg(0x010); - self.write_reg(0x020, f1 | 1); // On accepte VERSION_1 (Bit 32 global) + // --- 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.write_reg(0x070, 1 | 2 | 8); // STATUS_FEATURES_OK - if (self.read_reg(0x070) & 8) == 0 { - panic!("Features rejected"); - } - - // 3. Configuration de la Queue - self.write_reg(0x030, 0); // Select Queue 0 - let max = self.read_reg(0x034); // QUEUE_NUM_MAX - self.write_reg(0x038, QUEUE_SIZE as u32); - - // 4. Envoi des adresses 64 bits (Plus besoin de PFN !) - let desc_addr = &self.queue.descriptors as *const _ as u64; - self.write_reg(0x080, (desc_addr & 0xffffffff) as u32); - self.write_reg(0x084, (desc_addr >> 32) as u32); - - let avail_addr = &self.queue.available as *const _ as u64; - self.write_reg(0x090, (avail_addr & 0xffffffff) as u32); - self.write_reg(0x094, (avail_addr >> 32) as u32); - - let used_addr = &self.queue.used as *const _ as u64; - self.write_reg(0x0a0, (used_addr & 0xffffffff) as u32); - self.write_reg(0x0a4, (used_addr >> 32) as u32); - - // 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].len = core::mem::size_of::() as u32; - self.queue.descriptors[i].flags = 2; // Writeable - self.queue.available.ring[i] = i as u16; - } - self.queue - .available - .idx - .store(QUEUE_SIZE as u16, Ordering::Release); - - // 6. ACTIVATION (L'étape que tout le monde oublie en Modern) - self.write_reg(0x044, 1); // QUEUE_READY - - // 7. DRIVER_OK - self.write_reg(0x070, 1 | 2 | 4 | 8); - - self.activate_queue(); + self.write_common_u8(0x14, 1 | 2 | 8); // FEATURES_OK + if (self.read_common_u8(0x14) & 8) == 0 { + panic!("PCI Virtio: Features rejected"); } - } - unsafe fn activate_queue(&mut self) { + + // --- 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 + + // --- 4. Adresses 64 bits --- + let desc_addr = &self.queue.descriptors as *const _ 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 + + 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 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 + + // --- 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].len = core::mem::size_of::() as u32; + self.queue.descriptors[i].flags = 2; // VRING_DESC_F_WRITE + self.queue.available.ring[i] = i as u16; + } + self.queue + .available + .idx + .store(QUEUE_SIZE as u16, Ordering::Release); + + // --- 6. Activation --- + self.write_common_u16(0x1C, 1); // queue_enable = 1 + + if self.read_common_u16(0x1C) == 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); + unsafe { - // 1. Sélectionner la queue - self.write_reg(0x030, 0); - - // 2. Écrire la taille (doit correspondre à tes structures Rust) - self.write_reg(0x038, QUEUE_SIZE as u32); - - // 3. Écrire les adresses (ORDRE CRITIQUE : LOW puis HIGH) - let desc_addr = &self.queue.descriptors as *const _ as u64; - self.write_reg(0x080, desc_addr as u32); // DescLow - self.write_reg(0x084, (desc_addr >> 32) as u32); // DescHigh - - let avail_addr = &self.queue.available as *const _ as u64; - self.write_reg(0x090, avail_addr as u32); // AvailLow - self.write_reg(0x094, (avail_addr >> 32) as u32); // AvailHigh - - let used_addr = &self.queue.used as *const _ as u64; - self.write_reg(0x0a0, used_addr as u32); // UsedLow - self.write_reg(0x0a4, (used_addr >> 32) as u32); // UsedHigh - - // 4. LE KICK : Activer la queue - self.write_reg(0x044, 1); // QUEUE_READY = 1 - - // 5. SYNC : On s'assure que le périphérique a bien pris le READY - if self.read_reg(0x044) == 0 { - panic!("La queue refuse de passer en READY. Vérifiez les adresses !"); - } + core::ptr::write_volatile(notify_addr as *mut u16, 0); // 0 = index de la queue } } - /// Appelé lors d'une interruption clavier pub fn handle_interrupt(&mut self) { - let used_idx = self.queue.used.idx.load(Ordering::Acquire); + // 1. Lire et acquitter l'ISR PCI (Indispensable pour baisser la ligne IRQ) + let isr = unsafe { read_volatile(self.isr_cfg as *const u8) }; + if isr & 1 == 0 { + return; + } // Pas une interruption de queue + let used_idx = self.queue.used.idx.load(Ordering::Acquire); while self.last_used_idx != used_idx { let ring_slot = self.last_used_idx as usize % QUEUE_SIZE; let used_elem = &self.queue.used.ring[ring_slot]; - let event = &self.event_pool[used_elem.id as usize]; if event.event_type == 1 { - // EV_KEY - self.on_key(event.code, event.value); + println!("key pressed"); + // self.on_key(event.code, event.value); } - // Recyclage du descripteur : on le rend disponible à nouveau - let avail_idx = self.queue.available.idx.load(Ordering::Relaxed) as usize % QUEUE_SIZE; - self.queue.available.ring[avail_idx] = used_elem.id as u16; + // Recyclage + let avail_head = self.queue.available.idx.load(Ordering::Relaxed) as usize % QUEUE_SIZE; + self.queue.available.ring[avail_head] = used_elem.id as u16; self.queue.available.idx.fetch_add(1, Ordering::Release); self.last_used_idx = self.last_used_idx.wrapping_add(1); } - // Acquitter l'interruption + // Notifier qu'on a traité les buffers (si besoin) unsafe { - self.write_reg(VIRTIO_MMIO_INTERRUPT_ACK, 1); + write_volatile(self.notify_cfg as *mut u16, 0); } } - fn on_key(&self, code: u16, value: u32) { - let state = match value { - 1 => "Pressed", - 0 => "Released", - 2 => "Repeat", - _ => "Unknown", - }; - // write_char_uart((b'0' + (code / 10) as u8 % 10) as char); - // write_char_uart((b'0' + (code % 10) as u8) as char); - write_char_uart(code as u8 as char); - write_char_uart('\n'); - write_char_uart('\r'); - // Ici, implémentez votre conversion Scancode -> ASCII - // println!("Key Code: {} - State: {}", code, state); + // 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_reg(&self, offset: usize, val: u32) { - unsafe { write_volatile((self.base_addr + offset) as *mut u32, val) }; + unsafe fn write_common_u16(&self, off: usize, val: u16) { + write_volatile((self.common_cfg + off) as *mut u16, val); } - - unsafe fn read_reg(&self, offset: usize) -> u32 { - unsafe { read_volatile((self.base_addr + offset) as *const u32) } + 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) } } @@ -177,16 +167,20 @@ pub const PLIC_BASE: usize = 0x0c00_0000; pub const IRQ_VIRTIO: u32 = 1; pub const S_MODE_CLAIM_COMPLETE: *mut u32 = 0x0c20_1004 as *mut u32; -pub unsafe fn init_plic_m_mode() { - // 1. Priority : identique pour tous les modes - let priority_ptr = (PLIC_BASE + 4 * IRQ_VIRTIO as usize) as *mut u32; +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) }; - // 2. Enable : Pour Hart 0 M-Mode, l'offset est 0x2000 - let enable_ptr = (PLIC_BASE + 0x2080) as *mut u32; - unsafe { enable_ptr.write_volatile(1 << IRQ_VIRTIO) }; - - // 3. Threshold : Pour Hart 0 M-Mode, l'offset est 0x200000 + // 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) }; + + // Activer l'IRQ pour le S-Mode (Hart 0) + // 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; + unsafe { + let current = enable_ptr.read_volatile(); + enable_ptr.write_volatile(current | (1 << (irq % 32))); + } } diff --git a/test.pdf b/test.pdf new file mode 100644 index 0000000..6caab70 Binary files /dev/null and b/test.pdf differ