1
1
Эх сурвалжийг харах

MSI allocation (unfinished)

徐启航 1 жил өмнө
parent
commit
39e4736a27

+ 10 - 0
h2o/kernel/src/cpu/intr.rs

@@ -1,6 +1,7 @@
 mod imp;
 
 use alloc::sync::Arc;
+use core::ops::Range;
 
 use archop::Azy;
 
@@ -26,6 +27,15 @@ pub enum IsaIrq {
     Ide1 = 15,
 }
 
+#[derive(Debug, Clone)]
+pub struct Msi {
+    pub target_address: u32,
+    pub target_data: u32,
+
+    pub vecs: Range<u8>,
+    pub cpu: usize,
+}
+
 pub type IntrHandler = fn(*mut u8);
 
 static GSI_RES: Azy<Arc<Resource<u32>>> = Azy::new(|| {

+ 6 - 5
h2o/kernel/src/cpu/x86_64/apic.rs

@@ -1,7 +1,7 @@
 pub mod ipi;
 pub mod timer;
 
-use alloc::{collections::BTreeMap, sync::Arc};
+use alloc::collections::BTreeMap;
 use core::{
     arch::asm,
     ops::{BitOr, BitOrAssign},
@@ -18,14 +18,15 @@ use crate::mem::space::{self, Flags, PhysTrait};
 
 pub static LAPIC_ID: RwLock<BTreeMap<usize, u32>> = RwLock::new(BTreeMap::new());
 static LAPIC_BASE: Azy<usize> = Azy::new(|| {
-    let phys =
-        space::new_phys(PAddr::new(0xFEE00000), PAGE_SIZE).expect("Failed to acquire LAPIC base");
+    let phys = space::new_phys(PAddr::new(minfo::LAPIC_BASE), PAGE_SIZE)
+        .expect("Failed to acquire LAPIC base");
+    let layout = space::page_aligned(phys.len());
     space::KRL
         .map(
             None,
-            Arc::clone(&phys),
+            phys,
             0,
-            space::page_aligned(phys.len()),
+            layout,
             Flags::READABLE | Flags::WRITABLE | Flags::UNCACHED,
         )
         .expect("Failed to allocate memory")

+ 51 - 12
h2o/kernel/src/cpu/x86_64/intr.rs

@@ -14,7 +14,11 @@ use spin::Mutex;
 pub use self::def::{ExVec, ALLOC_VEC};
 use super::apic::{Polarity, TriggerMode, LAPIC_ID};
 use crate::{
-    cpu::{arch::seg::ndt::USR_CODE_X64, intr::IntrHandler, time::Instant},
+    cpu::{
+        arch::seg::ndt::USR_CODE_X64,
+        intr::{IntrHandler, Msi},
+        time::Instant,
+    },
     dev::ioapic,
     mem::space::PageFaultErrCode,
     sched::{
@@ -58,6 +62,21 @@ impl Manager {
         })
     }
 
+    #[inline]
+    pub fn config(gsi: u32, trig_mode: TriggerMode, polarity: Polarity) -> sv_call::Result {
+        PREEMPT.scope(|| unsafe { ioapic::chip().lock().config(gsi, trig_mode, polarity) })
+    }
+
+    #[inline]
+    pub fn mask(gsi: u32, masked: bool) -> sv_call::Result {
+        PREEMPT.scope(|| unsafe { ioapic::chip().lock().mask(gsi, masked) })
+    }
+
+    #[inline]
+    pub fn eoi(gsi: u32) -> sv_call::Result {
+        PREEMPT.scope(|| unsafe { ioapic::chip().lock().eoi(gsi) })
+    }
+
     pub fn select_cpu() -> usize {
         MANAGER
             .iter()
@@ -85,7 +104,7 @@ impl Manager {
         let apic_id = *LAPIC_ID.read().get(&cpu).ok_or(sv_call::EINVAL)?;
         let manager = MANAGER.get(cpu).ok_or(sv_call::ENODEV)?;
 
-        let vec = manager.map.lock().allocate_with::<_, sv_call::Error>(
+        let vec = manager.map.lock().allocate_with(
             1,
             |_| {
                 manager.count.fetch_add(1, Ordering::SeqCst);
@@ -124,19 +143,39 @@ impl Manager {
         Ok(())
     }
 
-    #[inline]
-    pub fn config(gsi: u32, trig_mode: TriggerMode, polarity: Polarity) -> sv_call::Result {
-        PREEMPT.scope(|| unsafe { ioapic::chip().lock().config(gsi, trig_mode, polarity) })
-    }
+    pub fn allocate_msi(num_vec: u8, cpu: usize) -> sv_call::Result<Msi> {
+        const MAX_NUM_VEC: u8 = 32;
+        let num_vec = num_vec
+            .checked_next_power_of_two()
+            .filter(|&size| size <= MAX_NUM_VEC)
+            .ok_or(sv_call::EINVAL)?;
 
-    #[inline]
-    pub fn mask(gsi: u32, masked: bool) -> sv_call::Result {
-        PREEMPT.scope(|| unsafe { ioapic::chip().lock().mask(gsi, masked) })
+        let manager = MANAGER.get(cpu).ok_or(sv_call::ENODEV)?;
+        let apic_id = *LAPIC_ID.read().get(&cpu).ok_or(sv_call::EINVAL)?;
+
+        let start = PREEMPT.scope(|| {
+            manager.map.lock().allocate_with(
+                num_vec,
+                |_| {
+                    manager.count.fetch_add(num_vec as usize, Ordering::SeqCst);
+                    Ok(())
+                },
+                sv_call::ENOMEM,
+            )
+        })?;
+
+        Ok(Msi {
+            target_address: minfo::LAPIC_BASE as u32 | (apic_id << 12),
+            target_data: start as u32,
+            vecs: start..(start + num_vec),
+            cpu,
+        })
     }
 
-    #[inline]
-    pub fn eoi(gsi: u32) -> sv_call::Result {
-        PREEMPT.scope(|| unsafe { ioapic::chip().lock().eoi(gsi) })
+    pub fn deallocate_msi(msi: Msi) -> sv_call::Result {
+        let manager = MANAGER.get(msi.cpu).ok_or(sv_call::ENODEV)?;
+        PREEMPT.scope(|| manager.map.lock().remove(msi.vecs.start));
+        Ok(())
     }
 }
 

+ 2 - 2
h2o/libs/collection_ex/src/range_map.rs

@@ -29,7 +29,7 @@ impl<K, V> RangeMap<K, V> {
         &self.range
     }
 
-    pub fn allocate_with<F, E>(&mut self, size: K, value: F, no_fit: impl Into<E>) -> Result<K, E>
+    pub fn allocate_with<F, E>(&mut self, size: K, value: F, no_fit: E) -> Result<K, E>
     where
         K: Ord + Sub<Output = K> + Add<Output = K> + Copy,
         F: FnOnce(Range<K>) -> Result<V, E>,
@@ -55,7 +55,7 @@ impl<K, V> RangeMap<K, V> {
             self.inner.entry(start).or_insert((range, value));
             Ok(start)
         } else {
-            Err(no_fit.into())
+            Err(no_fit)
         }
     }
 

+ 2 - 0
h2o/libs/minfo/src/lib.rs

@@ -10,6 +10,8 @@ pub const KARGS_BASE: usize = 0x1000;
 
 pub const TRAMPOLINE_RANGE: core::ops::Range<usize> = 0..0x100000;
 
+pub const LAPIC_BASE: usize = 0xFEE0_0000;
+
 pub const INITIAL_ID_SPACE: usize = 0x1_0000_0000;
 
 pub use pmm::{KMEM_PHYS_BASE, PF_SIZE};