diff --git a/Cargo.lock b/Cargo.lock index da30ad9b..9db00054 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -110,6 +110,7 @@ dependencies = [ "cfg-if", "gimli", "iced-x86", + "id-alloc", "inherit-methods-macro", "int-to-c-enum", "intrusive-collections", @@ -214,6 +215,7 @@ dependencies = [ "getrandom", "getset", "hashbrown 0.14.3", + "id-alloc", "inherit-methods-macro", "int-to-c-enum", "intrusive-collections", @@ -276,7 +278,6 @@ dependencies = [ "aster-frame", "aster-rights", "aster-rights-proc", - "bitvec", "inherit-methods-macro", "ktest", "pod", @@ -299,6 +300,7 @@ dependencies = [ "bitflags 1.3.2", "bytes", "component", + "id-alloc", "int-to-c-enum", "log", "pod", @@ -316,6 +318,7 @@ dependencies = [ "aster-nix", "aster-time", "component", + "id-alloc", "x86_64", ] @@ -741,6 +744,13 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "id-alloc" +version = "0.1.0" +dependencies = [ + "bitvec", +] + [[package]] name = "ident_case" version = "1.0.1" diff --git a/Cargo.toml b/Cargo.toml index 49621566..30aad62f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = [ "framework/aster-frame", "framework/libs/align_ext", "framework/libs/aster-main", + "framework/libs/id-alloc", "framework/libs/linux-bzimage/builder", "framework/libs/linux-bzimage/boot-params", "framework/libs/linux-bzimage/setup", diff --git a/Makefile b/Makefile index 4b1d35d1..4e049cea 100644 --- a/Makefile +++ b/Makefile @@ -76,6 +76,7 @@ export NON_OSDK_CRATES := \ framework/libs/align_ext \ framework/libs/aster-main \ + framework/libs/id-alloc \ framework/libs/linux-bzimage/builder \ framework/libs/linux-bzimage/boot-params \ framework/libs/ktest \ diff --git a/framework/aster-frame/Cargo.toml b/framework/aster-frame/Cargo.toml index 221a28a1..f25140f0 100644 --- a/framework/aster-frame/Cargo.toml +++ b/framework/aster-frame/Cargo.toml @@ -22,6 +22,7 @@ int-to-c-enum = { path = "../../kernel/libs/int-to-c-enum" } # So we set a fixed version 0.9.5 for this crate intrusive-collections = "=0.9.5" ktest = { path = "../libs/ktest" } +id-alloc = { path = "../libs/id-alloc" } lazy_static = { version = "1.0", features = ["spin_no_std"] } log = "0.4" pod = { git = "https://github.com/asterinas/pod", rev = "d7dba56" } diff --git a/framework/aster-frame/src/arch/x86/irq.rs b/framework/aster-frame/src/arch/x86/irq.rs index 8f67c787..1dd5b47a 100644 --- a/framework/aster-frame/src/arch/x86/irq.rs +++ b/framework/aster-frame/src/arch/x86/irq.rs @@ -2,17 +2,14 @@ use alloc::{boxed::Box, fmt::Debug, sync::Arc, vec::Vec}; +use id_alloc::IdAlloc; use spin::Once; use trapframe::TrapFrame; -use crate::{ - sync::{Mutex, SpinLock, SpinLockGuard}, - util::recycle_allocator::RecycleAllocator, -}; +use crate::sync::{Mutex, SpinLock, SpinLockGuard}; -/// The IRQ numbers which are not using -pub(crate) static NOT_USING_IRQ: SpinLock = - SpinLock::new(RecycleAllocator::with_start_max(32, 256)); +/// The global allocator for software defined IRQ lines. +pub(crate) static IRQ_ALLOCATOR: Once> = Once::new(); pub(crate) static IRQ_LIST: Once> = Once::new(); @@ -25,6 +22,18 @@ pub(crate) fn init() { }); } IRQ_LIST.call_once(|| list); + CALLBACK_ID_ALLOCATOR.call_once(|| Mutex::new(IdAlloc::with_capacity(256))); + IRQ_ALLOCATOR.call_once(|| { + // As noted in the Intel 64 and IA-32 rchitectures Software Developer’s Manual, + // Volume 3A, Section 6.2, the first 32 interrupts are reserved for specific + // usages. And the rest from 32 to 255 are available for external user-defined + // interrupts. + let mut id_alloc = IdAlloc::with_capacity(256); + for i in 0..32 { + id_alloc.alloc_specific(i).unwrap(); + } + SpinLock::new(id_alloc) + }); } pub(crate) fn enable_local() { @@ -43,7 +52,7 @@ pub(crate) fn is_local_enabled() -> bool { x86_64::instructions::interrupts::are_enabled() } -static ID_ALLOCATOR: Mutex = Mutex::new(RecycleAllocator::new()); +static CALLBACK_ID_ALLOCATOR: Once> = Once::new(); pub struct CallbackElement { function: Box, @@ -102,14 +111,14 @@ impl IrqLine { where F: Fn(&TrapFrame) + Sync + Send + 'static, { - let allocate_id = ID_ALLOCATOR.lock().alloc(); + let allocated_id = CALLBACK_ID_ALLOCATOR.get().unwrap().lock().alloc().unwrap(); self.callback_list.lock().push(CallbackElement { function: Box::new(callback), - id: allocate_id, + id: allocated_id, }); IrqCallbackHandle { irq_num: self.irq_num, - id: allocate_id, + id: allocated_id, } } } @@ -134,6 +143,6 @@ impl Drop for IrqCallbackHandle { .callback_list .lock(); a.retain(|item| item.id != self.id); - ID_ALLOCATOR.lock().dealloc(self.id); + CALLBACK_ID_ALLOCATOR.get().unwrap().lock().free(self.id); } } diff --git a/framework/aster-frame/src/lib.rs b/framework/aster-frame/src/lib.rs index 8a7cb810..df5bf86f 100644 --- a/framework/aster-frame/src/lib.rs +++ b/framework/aster-frame/src/lib.rs @@ -41,7 +41,6 @@ pub mod task; pub mod timer; pub mod trap; pub mod user; -mod util; pub mod vm; #[cfg(feature = "intel_tdx")] diff --git a/framework/aster-frame/src/trap/irq.rs b/framework/aster-frame/src/trap/irq.rs index c1bbc3e3..4cfa302b 100644 --- a/framework/aster-frame/src/trap/irq.rs +++ b/framework/aster-frame/src/trap/irq.rs @@ -5,7 +5,7 @@ use core::fmt::Debug; use trapframe::TrapFrame; use crate::{ - arch::irq::{self, IrqCallbackHandle, NOT_USING_IRQ}, + arch::irq::{self, IrqCallbackHandle, IRQ_ALLOCATOR}, prelude::*, task::{disable_preempt, DisablePreemptGuard}, Error, @@ -28,20 +28,20 @@ pub struct IrqLine { impl IrqLine { pub fn alloc_specific(irq: u8) -> Result { - if NOT_USING_IRQ.lock().get_target(irq as usize) { - Ok(Self::new(irq)) - } else { - Err(Error::NotEnoughResources) - } + IRQ_ALLOCATOR + .get() + .unwrap() + .lock() + .alloc_specific(irq as usize) + .map(|irq_num| Self::new(irq_num as u8)) + .ok_or(Error::NotEnoughResources) } pub fn alloc() -> Result { - let irq_num = NOT_USING_IRQ.lock().alloc(); - if irq_num == usize::MAX { - Err(Error::NotEnoughResources) - } else { - Ok(Self::new(irq_num as u8)) - } + let Some(irq_num) = IRQ_ALLOCATOR.get().unwrap().lock().alloc() else { + return Err(Error::NotEnoughResources); + }; + Ok(Self::new(irq_num as u8)) } fn new(irq_num: u8) -> Self { @@ -87,7 +87,11 @@ impl Clone for IrqLine { impl Drop for IrqLine { fn drop(&mut self) { if Arc::strong_count(&self.irq) == 1 { - NOT_USING_IRQ.lock().dealloc(self.irq_num as usize); + IRQ_ALLOCATOR + .get() + .unwrap() + .lock() + .free(self.irq_num as usize); } } } diff --git a/framework/aster-frame/src/util/mod.rs b/framework/aster-frame/src/util/mod.rs deleted file mode 100644 index 0c94155a..00000000 --- a/framework/aster-frame/src/util/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 - -pub mod recycle_allocator; diff --git a/framework/aster-frame/src/util/recycle_allocator.rs b/framework/aster-frame/src/util/recycle_allocator.rs deleted file mode 100644 index 9d171a53..00000000 --- a/framework/aster-frame/src/util/recycle_allocator.rs +++ /dev/null @@ -1,94 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 - -use alloc::vec::Vec; - -#[derive(Debug)] -pub struct RecycleAllocator { - current: usize, - recycled: Vec, - skip: Vec, - max: usize, -} - -impl RecycleAllocator { - pub const fn new() -> Self { - RecycleAllocator { - current: 0, - recycled: Vec::new(), - skip: Vec::new(), - max: usize::MAX - 1, - } - } - - pub const fn with_start_max(start: usize, max: usize) -> Self { - RecycleAllocator { - current: start, - recycled: Vec::new(), - skip: Vec::new(), - max, - } - } - - #[allow(unused)] - pub fn alloc(&mut self) -> usize { - if let Some(id) = self.recycled.pop() { - return id; - } - // recycle list is empty, need to use current to allocate an id. - // it should skip the element in skip list - while self.skip.contains(&self.current) { - self.current += 1; - } - if self.current == self.max { - return usize::MAX; - } - self.current += 1; - self.current - 1 - } - /// deallocate a id, it should fit one of the following requirement, otherwise it will panic: - /// - /// 1. It is in the skip list - /// - /// 2. It smaller than current and not in recycled list - #[allow(unused)] - pub fn dealloc(&mut self, id: usize) { - if !self.skip.contains(&id) { - assert!(id < self.current); - assert!( - !self.recycled.iter().any(|i| *i == id), - "id {} has been deallocated!", - id - ); - } else { - // if the value is in skip list, then remove it from the skip list - self.skip.retain(|value| *value != id); - } - self.recycled.push(id); - } - - /// get target id in the list, it will return true if the target can used, false if can not used. - /// the target need to meet one of the following requirement so that it can used: - /// - /// 1. It is in the recycled list - /// - /// 2. It is bigger than the current, smaller than max and not in the skip list - /// - pub fn get_target(&mut self, target: usize) -> bool { - if target >= self.max { - return false; - } - if target >= self.current { - if self.skip.contains(&target) { - false - } else { - self.skip.push(target); - true - } - } else if self.recycled.contains(&target) { - self.recycled.retain(|value| *value != target); - true - } else { - false - } - } -} diff --git a/framework/libs/id-alloc/Cargo.toml b/framework/libs/id-alloc/Cargo.toml new file mode 100644 index 00000000..1ccca346 --- /dev/null +++ b/framework/libs/id-alloc/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "id-alloc" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +bitvec = { version = "1.0", default-features = false, features = ["alloc"] } diff --git a/kernel/libs/aster-util/src/id_allocator.rs b/framework/libs/id-alloc/src/lib.rs similarity index 88% rename from kernel/libs/aster-util/src/id_allocator.rs rename to framework/libs/id-alloc/src/lib.rs index 71033fd1..63286e2f 100644 --- a/kernel/libs/aster-util/src/id_allocator.rs +++ b/framework/libs/id-alloc/src/lib.rs @@ -1,5 +1,8 @@ // SPDX-License-Identifier: MPL-2.0 +#![cfg_attr(not(test), no_std)] +#![forbid(unsafe_code)] + use core::{fmt::Debug, ops::Range}; use bitvec::prelude::BitVec; @@ -145,6 +148,27 @@ impl IdAlloc { } } + /// Allocate a specific ID. + /// + /// If the ID is already allocated, it returns `None`, otherwise it + /// returns the allocated ID. + /// + /// # Panic + /// + /// If the `id` is out of bounds, this method will panic. + pub fn alloc_specific(&mut self, id: usize) -> Option { + if self.bitset[id] { + return None; + } + self.bitset.set(id, true); + if id == self.first_available_id { + self.first_available_id = (id + 1..self.bitset.len()) + .find(|&i| !self.bitset[i]) + .map_or(self.bitset.len(), |i| i); + } + Some(id) + } + /// Returns true if the `id` is allocated. /// /// # Panic diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 6f2d3ab1..ff7f39fd 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -4,6 +4,7 @@ version = "0.4.0" edition = "2021" [dependencies] +id-alloc = { path = "../framework/libs/id-alloc" } aster-frame = { path = "../framework/aster-frame" } aster-nix = { path = "aster-nix" } component = { path = "libs/comp-sys/component" } diff --git a/kernel/aster-nix/Cargo.toml b/kernel/aster-nix/Cargo.toml index e8f60650..dfdd1bf8 100644 --- a/kernel/aster-nix/Cargo.toml +++ b/kernel/aster-nix/Cargo.toml @@ -21,6 +21,7 @@ typeflags = { path = "../libs/typeflags" } typeflags-util = { path = "../libs/typeflags-util" } aster-rights-proc = { path = "../libs/aster-rights-proc" } aster-util = { path = "../libs/aster-util" } +id-alloc = { path = "../../framework/libs/id-alloc" } int-to-c-enum = { path = "../libs/int-to-c-enum" } cpio-decoder = { path = "../libs/cpio-decoder" } ascii = { version = "1.1", default-features = false, features = ["alloc"] } diff --git a/kernel/aster-nix/src/fs/devpts/mod.rs b/kernel/aster-nix/src/fs/devpts/mod.rs index 4d0a37e2..228d03f4 100644 --- a/kernel/aster-nix/src/fs/devpts/mod.rs +++ b/kernel/aster-nix/src/fs/devpts/mod.rs @@ -2,7 +2,8 @@ use core::time::Duration; -use aster_util::{id_allocator::IdAlloc, slot_vec::SlotVec}; +use aster_util::slot_vec::SlotVec; +use id_alloc::IdAlloc; use self::{ptmx::Ptmx, slave::PtySlaveInode}; use crate::{ diff --git a/kernel/aster-nix/src/fs/ext2/block_group.rs b/kernel/aster-nix/src/fs/ext2/block_group.rs index c7436641..b21cdc1a 100644 --- a/kernel/aster-nix/src/fs/ext2/block_group.rs +++ b/kernel/aster-nix/src/fs/ext2/block_group.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MPL-2.0 -use aster_util::id_allocator::IdAlloc; +use id_alloc::IdAlloc; use super::{ block_ptr::Ext2Bid, diff --git a/kernel/comps/virtio/Cargo.toml b/kernel/comps/virtio/Cargo.toml index bbdfeae1..9137bf6e 100644 --- a/kernel/comps/virtio/Cargo.toml +++ b/kernel/comps/virtio/Cargo.toml @@ -17,6 +17,7 @@ aster-console = { path = "../console" } aster-frame = { path = "../../../framework/aster-frame" } aster-util = { path = "../../libs/aster-util" } aster-rights = { path = "../../libs/aster-rights" } +id-alloc = { path = "../../../framework/libs/id-alloc" } typeflags-util = { path = "../../libs/typeflags-util" } pod = { git = "https://github.com/asterinas/pod", rev = "d7dba56" } component = { path = "../../libs/comp-sys/component" } diff --git a/kernel/comps/virtio/src/device/block/device.rs b/kernel/comps/virtio/src/device/block/device.rs index ff311d16..4c70432b 100644 --- a/kernel/comps/virtio/src/device/block/device.rs +++ b/kernel/comps/virtio/src/device/block/device.rs @@ -13,7 +13,8 @@ use aster_frame::{ trap::TrapFrame, vm::{DmaDirection, DmaStream, DmaStreamSlice, VmAllocOptions, VmIo}, }; -use aster_util::{id_allocator::IdAlloc, safe_ptr::SafePtr}; +use aster_util::safe_ptr::SafePtr; +use id_alloc::IdAlloc; use log::info; use pod::Pod; diff --git a/kernel/libs/aster-util/Cargo.toml b/kernel/libs/aster-util/Cargo.toml index b821939c..19ad22ce 100644 --- a/kernel/libs/aster-util/Cargo.toml +++ b/kernel/libs/aster-util/Cargo.toml @@ -11,7 +11,6 @@ pod = { git = "https://github.com/asterinas/pod", rev = "d7dba56" } typeflags-util = { path = "../typeflags-util" } aster-rights-proc = { path = "../aster-rights-proc" } aster-rights = { path = "../aster-rights" } -bitvec = { version = "1.0", default-features = false, features = ["alloc"] } inherit-methods-macro = { git = "https://github.com/asterinas/inherit-methods-macro", rev = "98f7e3e" } ktest = { path = "../../../framework/libs/ktest" } [features] diff --git a/kernel/libs/aster-util/src/lib.rs b/kernel/libs/aster-util/src/lib.rs index 3777fe45..27bc910f 100644 --- a/kernel/libs/aster-util/src/lib.rs +++ b/kernel/libs/aster-util/src/lib.rs @@ -9,7 +9,6 @@ extern crate alloc; pub mod coeff; pub mod dup; -pub mod id_allocator; pub mod safe_ptr; pub mod slot_vec; pub mod union_read_ptr;