From 352c68e31e794cff2347d5f11d399b9f57776bad Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Sun, 10 Dec 2023 12:51:53 +0200 Subject: [PATCH] dev/block: NVMe drive enumeration --- Cargo.toml | 1 + lib/device-api/Cargo.toml | 4 +- lib/device-api/macros/Cargo.toml | 2 +- src/debug.rs | 36 +++++--- src/device/bus/pci/space/mod.rs | 2 +- src/device/nvme/command.rs | 137 +++++++++++++++++++++++++++++- src/device/nvme/drive.rs | 87 +++++++++++++++++++ src/device/nvme/mod.rs | 139 +++++++++++++++++++++++++++---- src/device/nvme/queue.rs | 26 +++--- src/fs/devfs.rs | 20 ++++- src/init.rs | 1 - src/main.rs | 4 +- 12 files changed, 406 insertions(+), 53 deletions(-) create mode 100644 src/device/nvme/drive.rs diff --git a/Cargo.toml b/Cargo.toml index 960cd447..bbb1ec79 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ device-api = { path = "lib/device-api", features = ["derive"] } kernel-util = { path = "lib/kernel-util" } memtables = { path = "lib/memtables" } vmalloc = { path = "lib/vmalloc" } +device-api-macros = { path = "lib/device-api/macros" } atomic_enum = "0.2.0" bitflags = "2.3.3" diff --git a/lib/device-api/Cargo.toml b/lib/device-api/Cargo.toml index 814a018b..ff5aca07 100644 --- a/lib/device-api/Cargo.toml +++ b/lib/device-api/Cargo.toml @@ -7,8 +7,8 @@ edition = "2021" [dependencies] yggdrasil-abi = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-abi.git" } -macros = { path = "macros", optional = true } +device-api-macros = { path = "macros", optional = true } [features] default = [] -derive = ["macros"] +derive = ["device-api-macros"] diff --git a/lib/device-api/macros/Cargo.toml b/lib/device-api/macros/Cargo.toml index aee949a6..8c3983aa 100644 --- a/lib/device-api/macros/Cargo.toml +++ b/lib/device-api/macros/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "macros" +name = "device-api-macros" version = "0.1.0" edition = "2021" diff --git a/src/debug.rs b/src/debug.rs index 4b6c7cf7..6ceb6113 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -200,21 +200,35 @@ pub static RING_LOGGER_SINK: RingLoggerSink = RingLoggerSink::new(); /// Prints a hex-dump of a slice, appending a virtual address offset to the output pub fn hex_dump(level: LogLevel, addr_offset: usize, data: &[u8]) { - for (i, b) in data.iter().enumerate() { - if i % 16 == 0 { - log_print_raw!(level, "{:X}: ", addr_offset + i) + const WINDOW_SIZE: usize = 16; + let window_count = (data.len() + WINDOW_SIZE) / WINDOW_SIZE; + + for iw in 0..window_count { + let off = iw * WINDOW_SIZE; + let len = core::cmp::min(data.len() - off, WINDOW_SIZE); + let window = &data[off..off + len]; + + log_print_raw!(level, "{:04X}: ", addr_offset + off); + for i in 0..WINDOW_SIZE { + if i < window.len() { + log_print_raw!(level, "{:02X}", window[i]); + } else { + log_print_raw!(level, " "); + } + + if i % 2 == 1 { + log_print_raw!(level, " "); + } } - log_print_raw!(level, "{:02X}", b); - - if i % 16 == 15 { - log_print_raw!(level, "\n"); - } else if i % 2 == 1 { - log_print_raw!(level, " "); + for &ch in window { + if ch.is_ascii_graphic() || ch == b' ' { + log_print_raw!(level, "{}", ch as char); + } else { + log_print_raw!(level, "."); + } } - } - if data.len() % 16 != 0 { log_print_raw!(level, "\n"); } } diff --git a/src/device/bus/pci/space/mod.rs b/src/device/bus/pci/space/mod.rs index 7a2e0977..51773391 100644 --- a/src/device/bus/pci/space/mod.rs +++ b/src/device/bus/pci/space/mod.rs @@ -301,7 +301,7 @@ pub trait PciConfigurationSpace { } /// Locates a capability within this configuration space - fn capability<'s, C: PciCapability>(&'s self) -> Option> { + fn capability(&self) -> Option> { self.capability_iter().find_map(|(id, offset)| { if id == C::ID { Some(C::data(self, offset)) diff --git a/src/device/nvme/command.rs b/src/device/nvme/command.rs index 10fb324a..efb875ae 100644 --- a/src/device/nvme/command.rs +++ b/src/device/nvme/command.rs @@ -2,6 +2,8 @@ use core::fmt::{self, Write}; +use tock_registers::{interfaces::Readable, register_structs, registers::ReadOnly, UIntLike}; + use crate::{ device::nvme::queue::PhysicalRegionPage, mem::{address::IntoRaw, PhysicalAddress}, @@ -33,6 +35,22 @@ pub enum ControllerType { Administrative, } +// I/O commands + +#[derive(Clone, Copy, Debug)] +pub struct IoRead { + pub nsid: u32, + pub lba: u64, + pub count: u32, +} + +#[derive(Clone, Copy, Debug)] +pub struct IoWrite { + pub nsid: u32, + pub lba: u64, + pub count: u32, +} + // Requests #[derive(Clone, Copy, Debug)] @@ -41,7 +59,15 @@ pub enum SetFeatureRequest { } #[derive(Clone, Copy, Debug)] -pub struct IdentifyControllerRequest { +pub struct IdentifyControllerRequest; + +#[derive(Clone, Copy, Debug)] +pub struct IdentifyActiveNamespaceIdListRequest { + pub start_id: u32, +} + +#[derive(Clone, Copy, Debug)] +pub struct IdentifyNamespaceRequest { pub nsid: u32, } @@ -81,11 +107,34 @@ pub struct IdentifyControllerResponse { pub cntrltype: ControllerType, } +#[derive(Clone, Copy, Debug)] +#[repr(C)] +pub struct IdentifyActiveNamespaceIdListResponse { + pub entries: [u32; 1024], +} + +register_structs! { + #[allow(non_snake_case)] + pub IdentifyNamespaceResponse { + (0 => NSZE: ReadOnly), + (8 => _0), + (25 => NLBAF: ReadOnly), + (26 => FLBAS: ReadOnly), + (27 => _1), + (128 => LBAFS: [ReadOnly; 64]), + (384 => _2), + (4096 => @END), + } +} + +#[derive(Clone, Copy, Debug)] +#[repr(transparent)] +pub struct LbaFormat(u32); + impl Command for IdentifyControllerRequest { fn fill_sqe(&self, sqe: &mut SubmissionQueueEntry) { sqe.command.set_opcode(0x06); sqe.command_specific[0] = 0x01; - sqe.nsid = self.nsid; } } @@ -93,6 +142,62 @@ impl Request for IdentifyControllerRequest { type Response = IdentifyControllerResponse; } +impl Command for IdentifyActiveNamespaceIdListRequest { + fn fill_sqe(&self, sqe: &mut SubmissionQueueEntry) { + sqe.command.set_opcode(0x06); + sqe.command_specific[0] = 0x02; + sqe.nsid = self.start_id; + } +} + +impl Request for IdentifyActiveNamespaceIdListRequest { + type Response = IdentifyActiveNamespaceIdListResponse; +} + +impl Command for IdentifyNamespaceRequest { + fn fill_sqe(&self, sqe: &mut SubmissionQueueEntry) { + sqe.command.set_opcode(0x06); + sqe.command_specific[0] = 0x00; + sqe.nsid = self.nsid; + } +} + +impl Request for IdentifyNamespaceRequest { + type Response = IdentifyNamespaceResponse; +} + +impl IdentifyNamespaceResponse { + pub fn current_lba_fmt_idx(&self) -> usize { + let flbas = self.FLBAS.get(); + let mut index = flbas & 0xF; + if self.NLBAF.get() > 16 { + index |= (flbas & 0xE0) >> 1; + } + index as usize + } + + pub fn lba_fmt(&self, idx: usize) -> Option { + if idx >= self.NLBAF.get() as usize { + return None; + } + Some(LbaFormat(self.LBAFS[idx].get())) + } + + pub fn total_lba_count(&self) -> u64 { + self.NSZE.get() + } +} + +impl LbaFormat { + pub fn lba_data_size(&self) -> Option { + let lbads = (self.0 >> 16) & 0xFF; + if lbads < 9 { + return None; + } + Some(1 << lbads) + } +} + impl Command for SetFeatureRequest { fn fill_sqe(&self, sqe: &mut SubmissionQueueEntry) { sqe.command.set_opcode(0x09); @@ -111,7 +216,7 @@ impl Command for SetFeatureRequest { impl Command for CreateIoCompletionQueue { fn fill_sqe(&self, sqe: &mut SubmissionQueueEntry) { sqe.command.set_opcode(0x05); - sqe.data_pointer[1] = PhysicalRegionPage::with_addr(self.data.into_raw()); + sqe.data_pointer[0] = PhysicalRegionPage::with_addr(self.data); sqe.command_specific[0] = ((self.size as u32 - 1) << 16) | self.id; sqe.command_specific[1] = (self.vector << 16) | 3; } @@ -120,7 +225,7 @@ impl Command for CreateIoCompletionQueue { impl Command for CreateIoSubmissionQueue { fn fill_sqe(&self, sqe: &mut SubmissionQueueEntry) { sqe.command.set_opcode(0x01); - sqe.data_pointer[1] = PhysicalRegionPage::with_addr(self.data.into_raw()); + sqe.data_pointer[0] = PhysicalRegionPage::with_addr(self.data); sqe.command_specific[0] = ((self.size as u32 - 1) << 16) | self.id; // Medium priority sqe.command_specific[1] = (self.cq_id << 16) | 1; @@ -140,3 +245,27 @@ impl fmt::Debug for String { Ok(()) } } + +impl Command for IoRead { + fn fill_sqe(&self, sqe: &mut SubmissionQueueEntry) { + assert!(self.count < 65536); + + sqe.command.set_opcode(0x02); + sqe.command_specific[0] = self.lba as u32; + sqe.command_specific[1] = (self.lba >> 32) as u32; + sqe.command_specific[2] = self.count; + sqe.nsid = self.nsid; + } +} + +impl Command for IoWrite { + fn fill_sqe(&self, sqe: &mut SubmissionQueueEntry) { + assert!(self.count < 65536); + + sqe.command.set_opcode(0x01); + sqe.command_specific[0] = self.lba as u32; + sqe.command_specific[1] = (self.lba >> 32) as u32; + sqe.command_specific[2] = self.count; + sqe.nsid = self.nsid; + } +} diff --git a/src/device/nvme/drive.rs b/src/device/nvme/drive.rs new file mode 100644 index 00000000..4914c8a9 --- /dev/null +++ b/src/device/nvme/drive.rs @@ -0,0 +1,87 @@ +use abi::{error::Error, io::DeviceRequest}; +use alloc::{boxed::Box, format}; +use vfs::BlockDevice; + +use crate::{device::nvme::command::IdentifyNamespaceRequest, fs::devfs}; + +use super::{error::NvmeError, NvmeController}; + +#[allow(unused)] +pub struct NvmeDrive { + controller: &'static NvmeController, + nsid: u32, + total_lba_count: u64, + lba_size: u64, +} + +impl NvmeDrive { + pub async fn create( + controller: &'static NvmeController, + nsid: u32, + ) -> Result<&'static NvmeDrive, NvmeError> { + let admin_q = controller.admin_q.get(); + let identify = admin_q.request(IdentifyNamespaceRequest { nsid })?.await?; + + let current_lba_format_idx = identify.current_lba_fmt_idx(); + let current_lba_format = identify.lba_fmt(current_lba_format_idx).unwrap(); + let lba_size = current_lba_format.lba_data_size().unwrap(); + let total_lba_count = identify.total_lba_count(); + + debugln!( + "ns = {}, lba = {}B, size = {}M", + nsid, + lba_size, + (total_lba_count * lba_size) / (1024 * 1024) + ); + + let dev = Box::leak(Box::new(NvmeDrive { + controller, + nsid, + total_lba_count, + lba_size, + })); + + // TODO add the drive as a block device + let node_name = format!("nvme{}n{}", controller.controller_id.get(), nsid); + devfs::add_named_block_device(dev, node_name).ok(); + + // TODO probe partitions + + Ok(dev) + } + + // TODO proper interface for reading/writing blocks + // pub async fn read_block( + // &self, + // lba: u64, + // block: &mut PhysicalRefMut<'_, [u8]>, + // ) -> Result<(), NvmeError> { + // self.controller.read_block(self.nsid, lba, block).await + // } + + // pub async fn write_block( + // &self, + // lba: u64, + // block: &PhysicalRefMut<'_, [u8]>, + // ) -> Result<(), NvmeError> { + // self.controller.write_block(self.nsid, lba, block).await + // } +} + +impl BlockDevice for NvmeDrive { + fn read(&'static self, _pos: u64, _buf: &mut [u8]) -> Result { + todo!() + } + + fn write(&'static self, _pos: u64, _buf: &[u8]) -> Result { + todo!() + } + + fn size(&self) -> Result { + Ok(self.lba_size * self.total_lba_count) + } + + fn device_request(&self, _req: &mut DeviceRequest) -> Result<(), Error> { + todo!() + } +} diff --git a/src/device/nvme/mod.rs b/src/device/nvme/mod.rs index cbaae53d..6c23bf9d 100644 --- a/src/device/nvme/mod.rs +++ b/src/device/nvme/mod.rs @@ -2,7 +2,7 @@ use core::{mem::size_of, time::Duration}; use abi::error::Error; -use alloc::vec::Vec; +use alloc::{collections::BTreeMap, vec::Vec}; use device_api::{interrupt::MsiHandler, Device}; use kernel_util::{sync::IrqSafeSpinlock, util::OneTimeInit}; use tock_registers::{ @@ -18,13 +18,17 @@ use crate::{ capability::MsiXCapability, PciBaseAddress, PciCommandRegister, PciConfigurationSpace, }, nvme::{ - command::IdentifyControllerRequest, + command::{ + IdentifyActiveNamespaceIdListRequest, IdentifyControllerRequest, IoRead, IoWrite, + }, + drive::NvmeDrive, queue::{CompletionQueueEntry, SubmissionQueueEntry}, }, }, mem::{ - address::{FromRaw, IntoRaw}, + address::{AsPhysicalAddress, FromRaw, IntoRaw}, device::{DeviceMemoryIo, DeviceMemoryIoMut}, + pointer::PhysicalRefMut, PhysicalAddress, }, task::runtime, @@ -39,6 +43,7 @@ use self::{ use super::bus::pci::{capability::MsiXEntry, FromPciBus, PciDeviceInfo}; mod command; +mod drive; mod error; mod queue; @@ -113,6 +118,8 @@ pub struct NvmeController { admin_q: OneTimeInit>, ioqs: OneTimeInit>>, vector_table: IrqSafeSpinlock>, + drive_table: IrqSafeSpinlock>, + controller_id: OneTimeInit, doorbell_shift: usize, } @@ -120,17 +127,21 @@ pub struct NvmeController { impl Regs { unsafe fn doorbell_ptr(&self, shift: usize, completion: bool, queue_index: usize) -> *mut u32 { let doorbell_base = (self as *const Regs as *mut Regs).addr() + 0x1000; - let offset = (queue_index << shift) + completion as usize * 4; + let offset = ((queue_index << shift) + completion as usize) * 4; (doorbell_base + offset) as *mut u32 } } impl NvmeController { async fn late_init(&'static self) -> Result<(), NvmeError> { - // runtime::spawn(self.poll_task()).expect("Couldn't spawn NVMe poll task"); + register_nvme_controller(self); + let admin_q = self.admin_q.get(); - infoln!("SETUP"); + // Identify the controller + let _identify = admin_q.request(IdentifyControllerRequest)?.await?; + + // TODO do something with identify_controller // Request a CQ/SQ pair for I/O admin_q @@ -140,12 +151,7 @@ impl NvmeController { // Allocate the queue let (sq_doorbell, cq_doorbell) = unsafe { self.doorbell_pair(1) }; let io_q = - QueuePair::new(0, 32, sq_doorbell, cq_doorbell).map_err(NvmeError::MemoryError)?; - - // Identify the controller - let identify = admin_q - .request(IdentifyControllerRequest { nsid: 0 })? - .await?; + QueuePair::new(1, 0, 32, sq_doorbell, cq_doorbell).map_err(NvmeError::MemoryError)?; // Create the queue on the device side admin_q @@ -165,7 +171,86 @@ impl NvmeController { }) .await?; - loop {} + self.ioqs.init(Vec::from_iter([io_q])); + + // Identify namespaces + self.enumerate_namespaces().await?; + + Ok(()) + } + + async fn enumerate_namespaces(&'static self) -> Result<(), NvmeError> { + let admin_q = self.admin_q.get(); + + let namespaces = admin_q + .request(IdentifyActiveNamespaceIdListRequest { start_id: 0 })? + .await?; + + let count = namespaces.entries.iter().position(|&x| x == 0).unwrap(); + let list = &namespaces.entries[..count]; + + for &nsid in list { + match NvmeDrive::create(self, nsid).await { + Ok(drive) => { + self.drive_table.lock().insert(nsid, drive); + } + Err(error) => { + warnln!("Could not create nvme drive, nsid={}: {:?}", nsid, error); + } + } + } + + Ok(()) + } + + pub async fn read_block( + &'static self, + nsid: u32, + lba: u64, + buffer: &mut PhysicalRefMut<'_, [u8]>, + ) -> Result<(), NvmeError> { + let ioq = &self.ioqs.get()[0]; + let buffer_address = unsafe { buffer.as_physical_address() }; + + debugln!("read nsid={}, lba={:#x}", nsid, lba); + let cmd_id = ioq.submit( + IoRead { + nsid, + lba, + count: 1, + }, + &[buffer_address], + true, + ); + + ioq.wait_for_completion(cmd_id, ()).await?; + + Ok(()) + } + + pub async fn write_block( + &'static self, + nsid: u32, + lba: u64, + buffer: &PhysicalRefMut<'_, [u8]>, + ) -> Result<(), NvmeError> { + let ioq = &self.ioqs.get()[0]; + let buffer_address = unsafe { buffer.as_physical_address() }; + + debugln!("write nsid={}, lba={:#x}", nsid, lba); + let cmd_id = ioq.submit( + IoWrite { + nsid, + lba, + count: 1, + }, + &[buffer_address], + true, + ); + + ioq.wait_for_completion(cmd_id, ()).await?; + + Ok(()) } unsafe fn doorbell_pair(&self, idx: usize) -> (*mut u32, *mut u32) { @@ -177,9 +262,15 @@ impl NvmeController { } impl MsiHandler for NvmeController { - fn handle_msi(&self, vector: usize) -> bool { - debugln!("handle_msi {}", vector); - self.admin_q.get().process_completions() != 0 + fn handle_msi(&self, _vector: usize) -> bool { + // TODO check MSI-X pending bits + self.admin_q.get().process_completions(); + if let Some(qs) = self.ioqs.try_get() { + for q in qs { + q.process_completions(); + } + } + true } } @@ -211,7 +302,9 @@ impl Device for NvmeController { // Setup the admin queue (index 0) let admin_sq_doorbell = unsafe { regs.doorbell_ptr(self.doorbell_shift, false, 0) }; let admin_cq_doorbell = unsafe { regs.doorbell_ptr(self.doorbell_shift, true, 0) }; + debugln!("sq_doorbell for adminq = {:p}", admin_sq_doorbell); let admin_q = QueuePair::new( + 0, 0, queue_slots as usize, admin_sq_doorbell, @@ -296,14 +389,26 @@ impl FromPciBus for NvmeController { // Disable the controller regs.CC.modify(CC::ENABLE::CLEAR); - let doorbell_shift = regs.CAP.read(CAP::DSTRD) as usize + 2; + let doorbell_shift = regs.CAP.read(CAP::DSTRD) as usize + 1; Ok(Self { regs: IrqSafeSpinlock::new(regs), admin_q: OneTimeInit::new(), ioqs: OneTimeInit::new(), vector_table: IrqSafeSpinlock::new(vt), + drive_table: IrqSafeSpinlock::new(BTreeMap::new()), + controller_id: OneTimeInit::new(), doorbell_shift, }) } } + +static NVME_CONTROLLERS: IrqSafeSpinlock> = + IrqSafeSpinlock::new(Vec::new()); + +pub fn register_nvme_controller(ctrl: &'static NvmeController) { + let mut list = NVME_CONTROLLERS.lock(); + let id = list.len(); + list.push(ctrl); + ctrl.controller_id.init(id); +} diff --git a/src/device/nvme/queue.rs b/src/device/nvme/queue.rs index 31a8ee14..88693f55 100644 --- a/src/device/nvme/queue.rs +++ b/src/device/nvme/queue.rs @@ -50,7 +50,7 @@ pub struct CommandDword0(u32); pub struct SubmissionQueueEntry { pub command: CommandDword0, // 0 pub nsid: u32, // 1 - _0: [u32; 2], // 2, 3 + pub io_data: [u32; 2], // 2, 3 pub metadata_pointer: u64, // 4, 5 pub data_pointer: [PhysicalRegionPage; 2], // 6, 7, 8, 9 pub command_specific: [u32; 6], // 10, 11, 12, 13, 14, 15 @@ -89,12 +89,13 @@ struct Inner<'a> { } // TODO PageBox? +#[allow(unused)] pub struct QueuePair<'a> { base: PhysicalAddress, page_count: usize, + id: u32, vector: usize, - sq_base: PhysicalAddress, cq_base: PhysicalAddress, @@ -110,8 +111,8 @@ impl PhysicalRegionPage { Self(0) } - pub const fn with_addr(addr: u64) -> Self { - Self(addr) + pub const fn with_addr(address: PhysicalAddress) -> Self { + Self(address.into_raw()) } } @@ -240,13 +241,14 @@ impl<'a, T> Queue<'a, T> { wrapped } - pub fn is_empty(&self) -> bool { - self.head == self.tail - } + // pub fn is_empty(&self) -> bool { + // self.head == self.tail + // } } impl<'a> QueuePair<'a> { pub fn new( + id: u32, vector: usize, capacity: usize, sq_doorbell: *mut u32, @@ -281,6 +283,7 @@ impl<'a> QueuePair<'a> { Ok(Self { completion_notify: QueueWaker::new(), + id, vector, base, page_count, @@ -350,7 +353,7 @@ impl<'a> QueuePair<'a> { match ranges.len() { 1 => { - sqe.data_pointer[0] = PhysicalRegionPage::with_addr(ranges[0].into_raw()); + sqe.data_pointer[0] = PhysicalRegionPage::with_addr(ranges[0]); sqe.data_pointer[1] = PhysicalRegionPage::null(); } 0 => { @@ -397,7 +400,7 @@ impl<'a> QueuePair<'a> { 'r: 'a, { assert_ne!(size_of::(), 0); - assert!(size_of::() < 0x1000); + assert!(size_of::() <= 0x1000); let page = phys::alloc_page().map_err(NvmeError::MemoryError)?; // TODO PageBox @@ -424,8 +427,8 @@ impl<'a> QueuePair<'a> { n += 1; let sub_queue_id = cmp.sub_queue_id(); - // TODO support queues other than admin q - assert_eq!(sub_queue_id, 0); + // TODO allow several sqs receive completions through one cq? + assert_eq!(sub_queue_id, self.id); let sub_queue_head = cmp.sub_queue_head(); let cmp = *cmp; @@ -442,7 +445,6 @@ impl<'a> QueuePair<'a> { let command_id = cmp.command_id(); if inner.pending.remove(&command_id) { - debugln!("Insert completion: {}", command_id); inner.completed.insert(command_id, cmp); } } diff --git a/src/fs/devfs.rs b/src/fs/devfs.rs index c43a7869..74f9651d 100644 --- a/src/fs/devfs.rs +++ b/src/fs/devfs.rs @@ -6,7 +6,7 @@ use alloc::{format, string::String}; use kernel_util::util::OneTimeInit; use vfs::{ impls::{read_fn_node, MemoryDirectory}, - CharDevice, Node, NodeFlags, NodeRef, + BlockDevice, CharDevice, Node, NodeFlags, NodeRef, }; use crate::proc::random; @@ -37,7 +37,8 @@ pub fn root() -> &'static NodeRef { DEVFS_ROOT.get() } -fn _add_char_device(dev: &'static dyn CharDevice, name: String) -> Result<(), Error> { +/// Adds a character device with a custom name +pub fn add_named_char_device(dev: &'static dyn CharDevice, name: String) -> Result<(), Error> { infoln!("Add char device: {}", name); let node = Node::char(dev, NodeFlags::IN_MEMORY_PROPS); @@ -45,6 +46,19 @@ fn _add_char_device(dev: &'static dyn CharDevice, name: String) -> Result<(), Er DEVFS_ROOT.get().add_child(name, node) } +/// Adds a block device with a custom name +pub fn add_named_block_device>( + dev: &'static dyn BlockDevice, + name: S, +) -> Result<(), Error> { + let name = name.into(); + infoln!("Add block device: {}", name); + + let node = Node::block(dev, NodeFlags::IN_MEMORY_PROPS); + + DEVFS_ROOT.get().add_child(name, node) +} + /// Adds a character device to the devfs pub fn add_char_device(dev: &'static dyn CharDevice, kind: CharDeviceType) -> Result<(), Error> { static TTY_COUNT: AtomicUsize = AtomicUsize::new(0); @@ -58,7 +72,7 @@ pub fn add_char_device(dev: &'static dyn CharDevice, kind: CharDeviceType) -> Re let value = count.fetch_add(1, Ordering::AcqRel); let name = format!("{}{}", prefix, value); - _add_char_device(dev, name) + add_named_char_device(dev, name) } /// Adds "pseudo"-devices to the filesystem (i.e. /dev/random) diff --git a/src/init.rs b/src/init.rs index be2265b3..9579d0ed 100644 --- a/src/init.rs +++ b/src/init.rs @@ -25,7 +25,6 @@ fn setup_root() -> Result { /// initialization has finished. pub fn kinit() -> Result<(), Error> { infoln!("In main"); - loop {} #[cfg(feature = "fb_console")] { diff --git a/src/main.rs b/src/main.rs index 4fdc7cb7..e73e5093 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,7 +19,9 @@ strict_provenance, slice_ptr_get, slice_split_once, - iter_collect_into + iter_collect_into, + iter_next_chunk, + exact_size_is_empty )] #![allow( clippy::new_without_default,