diff --git a/kernel/src/device/char.rs b/kernel/src/device/char.rs new file mode 100644 index 000000000..a4968b24b --- /dev/null +++ b/kernel/src/device/char.rs @@ -0,0 +1,243 @@ +// SPDX-License-Identifier: MPL-2.0 + +//! A subsystem for character devices (or char devices for short). + +#![expect(dead_code)] + +use core::ops::Range; + +use device_id::{DeviceId, MajorId}; +use inherit_methods_macro::inherit_methods; + +use crate::{ + events::IoEvents, + fs::{ + device::{add_node, Device, DeviceType}, + file_handle::Mappable, + fs_resolver::FsResolver, + inode_handle::FileIo, + utils::{InodeIo, IoctlCmd, StatusFlags}, + }, + prelude::*, + process::signal::{PollHandle, Pollable}, +}; + +/// A character device. +pub trait CharDevice: Send + Sync + Debug { + /// Returns the name of this char device that should appear in devtmpfs (usually under `/dev`). + fn devtmpfs_name(&self) -> DevtmpfsName<'_>; + + /// Returns the device ID. + fn id(&self) -> DeviceId; + + /// Opens the char device, returning a file-like object that the userspace can interact with by doing I/O. + /// + /// Multiple calls to this method return the same object (at least logically). + fn open(&self) -> Result>; +} + +static DEVICE_REGISTRY: Mutex>> = Mutex::new(BTreeMap::new()); + +/// Registers a new char device. +pub fn register(device: Arc) -> Result<()> { + let mut registry = DEVICE_REGISTRY.lock(); + let id = device.id().to_raw(); + if registry.contains_key(&id) { + return_errno_with_message!(Errno::EEXIST, "char device already exists"); + } + registry.insert(id, device); + + Ok(()) +} + +/// Unregisters an existing char device, returning the device if found. +pub fn unregister(id: DeviceId) -> Result> { + DEVICE_REGISTRY + .lock() + .remove(&id.to_raw()) + .ok_or(Error::with_message( + Errno::ENOENT, + "char device does not exist", + )) +} + +/// Collects all char devices. +pub fn collect_all() -> Vec> { + DEVICE_REGISTRY.lock().values().cloned().collect() +} + +/// Looks up a char device of a given device ID. +pub fn lookup(id: DeviceId) -> Option> { + DEVICE_REGISTRY.lock().get(&id.to_raw()).cloned() +} + +/// The maximum value of the major device ID of a char device. +/// +/// Reference: . +pub const MAX_MAJOR: u16 = 511; + +/// The ranges of free char majors. +/// +/// Reference: . +const DYNAMIC_MAJOR_ID_RANGES: [Range; 2] = [234..255, 384..512]; + +static MAJORS: Mutex> = Mutex::new(BTreeSet::new()); + +/// Acquires a major ID. +/// +/// The returned `MajorIdOwner` object represents the ownership to the major ID. +/// Until the object is dropped, this major ID cannot be acquired via `acquire_major` or `allocate_major` again. +pub fn acquire_major(major: MajorId) -> Result { + if major.get() > MAX_MAJOR { + return_errno_with_message!(Errno::EINVAL, "invalid major ID"); + } + + if MAJORS.lock().insert(major.get()) { + Ok(MajorIdOwner(major)) + } else { + return_errno_with_message!(Errno::EEXIST, "major ID already acquired") + } +} + +/// Allocates a major ID. +/// +/// The returned `MajorIdOwner` object represents the ownership to the major ID. +/// Until the object is dropped, this major ID cannot be acquired via `acquire_major` or `allocate_major` again. +pub fn allocate_major() -> Result { + let mut majors = MAJORS.lock(); + + for id in DYNAMIC_MAJOR_ID_RANGES + .iter() + .flat_map(|range| range.clone().rev()) + { + if majors.insert(id) { + return Ok(MajorIdOwner(MajorId::new(id))); + } + } + + return_errno_with_message!(Errno::ENOSPC, "no more major IDs available"); +} + +/// An owned major ID. +/// +/// Each instances of this type will unregister the major ID when dropped. +pub struct MajorIdOwner(MajorId); + +impl MajorIdOwner { + /// Returns the major ID. + pub fn get(&self) -> MajorId { + self.0 + } +} + +impl Drop for MajorIdOwner { + fn drop(&mut self) { + MAJORS.lock().remove(&self.0.get()); + } +} + +/// A device's name under devtmpfs. +/// +/// A `DevtmpfsName` consists of two parts: +/// 1. The device name; +/// 2. The class name. +/// +/// # Examples +/// +/// If you want a device to appear as `/dev/zero`, +/// then assign it a name of `DevtmpfsName::new("zero", None)`. +/// +/// If you want to a device to appear as `/dev/input/event0`, +/// then assign it a name of `DevtmpfsName::new("event0", Some("input"))`. +pub struct DevtmpfsName<'a> { + dev_name: &'a str, + class_name: Option<&'a str>, +} + +impl<'a> DevtmpfsName<'a> { + pub fn new(dev_name: &'a str, class_name: Option<&'a str>) -> Self { + Self { + dev_name, + class_name, + } + } + + pub fn dev_name(&self) -> &'a str { + self.dev_name + } + + pub fn class_name(&self) -> Option<&'a str> { + self.class_name + } +} + +pub(super) fn init_in_first_process(fs_resolver: &FsResolver) -> Result<()> { + for device in collect_all() { + let name = device.devtmpfs_name().dev_name().to_string(); + let device = Arc::new(CharFile::new(device)); + add_node(device, &name, fs_resolver)?; + } + + Ok(()) +} + +/// Represents a character device inode in the filesystem. +/// +/// Only implements the `Device` trait. +#[derive(Debug)] +pub struct CharFile(Arc); + +impl CharFile { + pub fn new(device: Arc) -> Self { + Self(device) + } +} + +impl Device for CharFile { + fn type_(&self) -> DeviceType { + DeviceType::Char + } + + fn id(&self) -> DeviceId { + self.0.id() + } + + fn open(&self) -> Result> { + Ok(Box::new(OpenCharFile(self.0.open()?))) + } +} + +/// Represents an opened character device file ready for I/O operations. +/// +/// Does not implement the `Device` trait but provides full implementations +/// for I/O related traits. +pub struct OpenCharFile(Arc); + +#[inherit_methods(from = "self.0")] +impl InodeIo for OpenCharFile { + fn read_at( + &self, + offset: usize, + writer: &mut VmWriter, + status_flags: StatusFlags, + ) -> Result; + fn write_at( + &self, + offset: usize, + reader: &mut VmReader, + status_flags: StatusFlags, + ) -> Result; +} + +#[inherit_methods(from = "self.0")] +impl Pollable for OpenCharFile { + fn poll(&self, mask: IoEvents, poller: Option<&mut PollHandle>) -> IoEvents; +} + +#[inherit_methods(from = "self.0")] +impl FileIo for OpenCharFile { + fn check_seekable(&self) -> Result<()>; + fn is_offset_aware(&self) -> bool; + fn mappable(&self) -> Result; + fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result; +} diff --git a/kernel/src/device/full.rs b/kernel/src/device/full.rs deleted file mode 100644 index 3347cf242..000000000 --- a/kernel/src/device/full.rs +++ /dev/null @@ -1,70 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 - -use device_id::{DeviceId, MajorId, MinorId}; - -use crate::{ - events::IoEvents, - fs::{ - device::{Device, DeviceType}, - inode_handle::FileIo, - utils::{InodeIo, StatusFlags}, - }, - prelude::*, - process::signal::{PollHandle, Pollable}, -}; - -pub struct Full; - -impl Device for Full { - fn type_(&self) -> DeviceType { - DeviceType::Char - } - - fn id(&self) -> DeviceId { - // The same value as Linux - DeviceId::new(MajorId::new(1), MinorId::new(7)) - } - - fn open(&self) -> Result> { - Ok(Box::new(Self)) - } -} - -impl Pollable for Full { - fn poll(&self, mask: IoEvents, _poller: Option<&mut PollHandle>) -> IoEvents { - let events = IoEvents::IN | IoEvents::OUT; - events & mask - } -} - -impl InodeIo for Full { - fn read_at( - &self, - _offset: usize, - writer: &mut VmWriter, - _status_flags: StatusFlags, - ) -> Result { - let len = writer.avail(); - writer.fill_zeros(len)?; - Ok(len) - } - - fn write_at( - &self, - _offset: usize, - _reader: &mut VmReader, - _status_flags: StatusFlags, - ) -> Result { - return_errno_with_message!(Errno::ENOSPC, "no space left on /dev/full") - } -} - -impl FileIo for Full { - fn check_seekable(&self) -> Result<()> { - Ok(()) - } - - fn is_offset_aware(&self) -> bool { - false - } -} diff --git a/kernel/src/device/mem/file.rs b/kernel/src/device/mem/file.rs new file mode 100644 index 000000000..775558954 --- /dev/null +++ b/kernel/src/device/mem/file.rs @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: MPL-2.0 + +use alloc::vec; + +use ostd::mm::{FallibleVmWrite, VmReader, VmWriter}; + +use crate::{ + error::Errno, + events::IoEvents, + fs::{ + inode_handle::FileIo, + utils::{InodeIo, StatusFlags}, + }, + prelude::Result, + process::signal::{PollHandle, Pollable}, + return_errno_with_message, + util::random, +}; + +pub fn geturandom(writer: &mut VmWriter) -> Result { + const IO_CAPABILITY: usize = 4096; + + if !writer.has_avail() { + return Ok(0); + } + + let mut buffer = vec![0; writer.avail().min(IO_CAPABILITY)]; + let mut written_bytes = 0; + + while writer.has_avail() { + random::getrandom(&mut buffer[..writer.avail().min(IO_CAPABILITY)]); + match writer.write_fallible(&mut VmReader::from(buffer.as_slice())) { + Ok(len) => written_bytes += len, + Err((err, 0)) if written_bytes == 0 => return Err(err.into()), + Err((_, len)) => return Ok(written_bytes + len), + } + } + + Ok(written_bytes) +} + +// TODO: Support true randomness by collecting environment noise. +pub use geturandom as getrandom; + +#[derive(Debug, Copy, Clone)] +#[expect(dead_code)] +pub(super) enum MemFile { + Mem, + Kmem, + Null, + Port, + Zero, + Core, + Full, + Random, + Urandom, + Aio, + Kmsg, + Oldmem, +} + +impl MemFile { + pub(super) fn minor(&self) -> u32 { + match self { + MemFile::Mem => 1, + MemFile::Kmem => 2, + MemFile::Null => 3, + MemFile::Port => 4, + MemFile::Zero => 5, + MemFile::Core => 6, + MemFile::Full => 7, + MemFile::Random => 8, + MemFile::Urandom => 9, + MemFile::Aio => 10, + MemFile::Kmsg => 11, + MemFile::Oldmem => 12, + } + } + + pub(super) fn name(&self) -> &str { + match self { + MemFile::Mem => "mem", + MemFile::Kmem => "kmem", + MemFile::Null => "null", + MemFile::Port => "port", + MemFile::Zero => "zero", + MemFile::Core => "core", + MemFile::Full => "full", + MemFile::Random => "random", + MemFile::Urandom => "urandom", + MemFile::Aio => "aio", + MemFile::Kmsg => "kmsg", + MemFile::Oldmem => "oldmem", + } + } +} + +impl Pollable for MemFile { + fn poll(&self, mask: IoEvents, _poller: Option<&mut PollHandle>) -> IoEvents { + let events = IoEvents::IN | IoEvents::OUT; + events & mask + } +} + +impl InodeIo for MemFile { + fn read_at( + &self, + _offset: usize, + writer: &mut VmWriter, + _status_flags: StatusFlags, + ) -> Result { + match self { + MemFile::Full | MemFile::Zero => { + let len = writer.avail(); + writer.fill_zeros(len)?; + Ok(len) + } + MemFile::Null => Ok(0), + MemFile::Random => getrandom(writer), + MemFile::Urandom => geturandom(writer), + _ => return_errno_with_message!(Errno::EINVAL, "read is not supported yet"), + } + } + + fn write_at( + &self, + _offset: usize, + reader: &mut VmReader, + _status_flags: StatusFlags, + ) -> Result { + match self { + MemFile::Null | MemFile::Random | MemFile::Urandom | MemFile::Zero => { + let len = reader.remain(); + reader.skip(len); + Ok(len) + } + MemFile::Full => { + return_errno_with_message!(Errno::ENOSPC, "no space left on /dev/full") + } + _ => return_errno_with_message!(Errno::ENAVAIL, "write is not supported yet"), + } + } +} + +impl FileIo for MemFile { + fn check_seekable(&self) -> Result<()> { + Ok(()) + } + + fn is_offset_aware(&self) -> bool { + false + } +} diff --git a/kernel/src/device/mem/mod.rs b/kernel/src/device/mem/mod.rs new file mode 100644 index 000000000..6a0214317 --- /dev/null +++ b/kernel/src/device/mem/mod.rs @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: MPL-2.0 + +//! Memory devices. +//! +//! Character device with major number 1. The minor numbers are mapped as follows: +//! - 1 = /dev/mem Physical memory access +//! - 2 = /dev/kmem OBSOLETE - replaced by /proc/kcore +//! - 3 = /dev/null Null device +//! - 4 = /dev/port I/O port access +//! - 5 = /dev/zero Null byte source +//! - 6 = /dev/core OBSOLETE - replaced by /proc/kcore +//! - 7 = /dev/full Returns ENOSPC on write +//! - 8 = /dev/random Nondeterministic random number gen. +//! - 9 = /dev/urandom Faster, less secure random number gen. +//! - 10 = /dev/aio Asynchronous I/O notification interface +//! - 11 = /dev/kmsg Writes to this come out as printk's, reads export the buffered printk records. +//! - 12 = /dev/oldmem OBSOLETE - replaced by /proc/vmcore +//! +//! See . + +mod file; + +use alloc::sync::Arc; + +use device_id::{DeviceId, MajorId, MinorId}; +use file::MemFile; +pub use file::{getrandom, geturandom}; +use spin::Once; + +use super::char::{acquire_major, register, CharDevice, MajorIdOwner}; +use crate::{device::char::DevtmpfsName, fs::inode_handle::FileIo, prelude::*}; + +/// A memory device. +#[derive(Debug)] +pub struct MemDevice { + id: DeviceId, + file: MemFile, +} + +impl MemDevice { + fn new(file: MemFile) -> Self { + let major = MEM_MAJOR.get().unwrap().get(); + let minor = MinorId::new(file.minor()); + + Self { + id: DeviceId::new(major, minor), + file, + } + } +} + +impl CharDevice for MemDevice { + fn devtmpfs_name(&self) -> DevtmpfsName { + DevtmpfsName::new(self.file.name(), None) + } + + fn id(&self) -> DeviceId { + self.id + } + + fn open(&self) -> Result> { + Ok(Arc::new(self.file)) + } +} + +static MEM_MAJOR: Once = Once::new(); + +pub(super) fn init_in_first_kthread() { + MEM_MAJOR.call_once(|| acquire_major(MajorId::new(1)).unwrap()); + + register(Arc::new(MemDevice::new(MemFile::Full))).unwrap(); + register(Arc::new(MemDevice::new(MemFile::Null))).unwrap(); + register(Arc::new(MemDevice::new(MemFile::Random))).unwrap(); + register(Arc::new(MemDevice::new(MemFile::Urandom))).unwrap(); + register(Arc::new(MemDevice::new(MemFile::Zero))).unwrap(); +} diff --git a/kernel/src/device/misc/mod.rs b/kernel/src/device/misc/mod.rs new file mode 100644 index 000000000..1abd5b496 --- /dev/null +++ b/kernel/src/device/misc/mod.rs @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MPL-2.0 + +//! Misc devices. +//! +//! Character device with major number 10. + +use device_id::MajorId; +use spin::Once; + +use super::char::{acquire_major, MajorIdOwner}; + +#[cfg(all(target_arch = "x86_64", feature = "cvm_guest"))] +pub mod tdxguest; + +static MISC_MAJOR: Once = Once::new(); + +pub(super) fn init_in_first_kthread() { + MISC_MAJOR.call_once(|| acquire_major(MajorId::new(10)).unwrap()); + + #[cfg(target_arch = "x86_64")] + ostd::if_tdx_enabled!({ + super::char::register(tdxguest::TdxGuest::new()).unwrap(); + }); +} diff --git a/kernel/src/device/tdxguest/mod.rs b/kernel/src/device/misc/tdxguest.rs similarity index 92% rename from kernel/src/device/tdxguest/mod.rs rename to kernel/src/device/misc/tdxguest.rs index b9cdf9303..3a629821d 100644 --- a/kernel/src/device/tdxguest/mod.rs +++ b/kernel/src/device/misc/tdxguest.rs @@ -1,12 +1,13 @@ // SPDX-License-Identifier: MPL-2.0 +use alloc::sync::{Arc, Weak}; use core::{ mem::{offset_of, size_of}, time::Duration, }; use aster_util::{field_ptr, safe_ptr::SafePtr}; -use device_id::{DeviceId, MajorId, MinorId}; +use device_id::{DeviceId, MinorId}; use ostd::{ const_assert, mm::{ @@ -22,9 +23,9 @@ use tdx_guest::{ }; use crate::{ + device::char::{CharDevice, DevtmpfsName}, events::IoEvents, fs::{ - device::{Device, DeviceType}, inode_handle::FileIo, utils::{InodeIo, IoctlCmd, StatusFlags}, }, @@ -32,19 +33,38 @@ use crate::{ process::signal::{PollHandle, Pollable}, }; -pub struct TdxGuest; +const TDX_GUEST_MINOR: u32 = 0x7b; -impl Device for TdxGuest { - fn type_(&self) -> DeviceType { - DeviceType::Misc +/// The `/dev/tdx_guest` device. +#[derive(Debug)] +pub struct TdxGuest { + id: DeviceId, + weak_self: Weak, +} + +impl TdxGuest { + pub fn new() -> Arc { + let major = super::MISC_MAJOR.get().unwrap().get(); + let minor = MinorId::new(TDX_GUEST_MINOR); + + Arc::new_cyclic(|weak| Self { + id: DeviceId::new(major, minor), + weak_self: weak.clone(), + }) + } +} + +impl CharDevice for TdxGuest { + fn devtmpfs_name(&self) -> DevtmpfsName { + DevtmpfsName::new("tdx_guest", None) } fn id(&self) -> DeviceId { - DeviceId::new(MajorId::new(0xa), MinorId::new(0x7b)) + self.id } - fn open(&self) -> Result> { - Ok(Box::new(Self)) + fn open(&self) -> Result> { + Ok(self.weak_self.upgrade().unwrap()) } } diff --git a/kernel/src/device/mod.rs b/kernel/src/device/mod.rs index 423d930ea..4ed7ea546 100644 --- a/kernel/src/device/mod.rs +++ b/kernel/src/device/mod.rs @@ -1,24 +1,18 @@ // SPDX-License-Identifier: MPL-2.0 +mod char; mod disk; -mod full; -mod null; +mod mem; +pub mod misc; mod pty; -mod random; mod shm; pub mod tty; -mod urandom; -mod zero; - -#[cfg(all(target_arch = "x86_64", feature = "cvm_guest"))] -pub mod tdxguest; use alloc::format; use device_id::DeviceId; +pub use mem::{getrandom, geturandom}; pub use pty::{new_pty_pair, PtyMaster, PtySlave}; -pub use random::Random; -pub use urandom::Urandom; use crate::{ fs::{ @@ -32,6 +26,8 @@ use crate::{ pub fn init_in_first_kthread() { disk::init_in_first_kthread(); + mem::init_in_first_kthread(); + misc::init_in_first_kthread(); } /// Init the device node in fs, must be called after mounting rootfs. @@ -43,12 +39,6 @@ pub fn init_in_first_process(ctx: &Context) -> Result<()> { let dev_path = fs_resolver.lookup(&FsPath::try_from("/dev")?)?; dev_path.mount(RamFs::new(), PerMountFlags::default(), ctx)?; - let null = Arc::new(null::Null); - add_node(null, "null", &fs_resolver)?; - - let zero = Arc::new(zero::Zero); - add_node(zero, "zero", &fs_resolver)?; - tty::init(); let tty = Arc::new(tty::TtyDevice); @@ -61,24 +51,12 @@ pub fn init_in_first_process(ctx: &Context) -> Result<()> { add_node(tty.clone(), &format!("tty{}", index), &fs_resolver)?; } - #[cfg(target_arch = "x86_64")] - ostd::if_tdx_enabled!({ - add_node(Arc::new(tdxguest::TdxGuest), "tdx_guest", &fs_resolver)?; - }); - - let random = Arc::new(random::Random); - add_node(random, "random", &fs_resolver)?; - - let urandom = Arc::new(urandom::Urandom); - add_node(urandom, "urandom", &fs_resolver)?; - - let full = Arc::new(full::Full); - add_node(full, "full", &fs_resolver)?; - pty::init_in_first_process(&fs_resolver, ctx)?; shm::init_in_first_process(&fs_resolver, ctx)?; + char::init_in_first_process(&fs_resolver)?; + disk::init_in_first_process(&fs_resolver)?; Ok(()) @@ -93,11 +71,6 @@ pub fn get_device(devid: DeviceId) -> Result> { let minor = devid.minor().get(); match (major, minor) { - (1, 3) => Ok(Arc::new(null::Null)), - (1, 5) => Ok(Arc::new(zero::Zero)), - (1, 7) => Ok(Arc::new(full::Full)), - (1, 8) => Ok(Arc::new(random::Random)), - (1, 9) => Ok(Arc::new(urandom::Urandom)), (4, minor) => { let Some(tty) = tty::iter_n_tty().nth(minor as usize) else { return_errno_with_message!(Errno::EINVAL, "the TTY minor ID is invalid"); @@ -105,6 +78,11 @@ pub fn get_device(devid: DeviceId) -> Result> { Ok(tty.clone()) } (5, 0) => Ok(Arc::new(tty::TtyDevice)), - _ => return_errno_with_message!(Errno::EINVAL, "the device ID is invalid or unsupported"), + _ => char::lookup(devid) + .map(|device| Arc::new(char::CharFile::new(device)) as Arc) + .ok_or(Error::with_message( + Errno::EINVAL, + "the device ID is invalid or unsupported", + )), } } diff --git a/kernel/src/device/null.rs b/kernel/src/device/null.rs deleted file mode 100644 index e04159f21..000000000 --- a/kernel/src/device/null.rs +++ /dev/null @@ -1,70 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 - -use device_id::{DeviceId, MajorId, MinorId}; - -use crate::{ - events::IoEvents, - fs::{ - device::{Device, DeviceType}, - inode_handle::FileIo, - utils::{InodeIo, StatusFlags}, - }, - prelude::*, - process::signal::{PollHandle, Pollable}, -}; - -pub struct Null; - -impl Device for Null { - fn type_(&self) -> DeviceType { - DeviceType::Char - } - - fn id(&self) -> DeviceId { - // The same value as Linux - DeviceId::new(MajorId::new(1), MinorId::new(3)) - } - - fn open(&self) -> Result> { - Ok(Box::new(Self)) - } -} - -impl Pollable for Null { - fn poll(&self, mask: IoEvents, _poller: Option<&mut PollHandle>) -> IoEvents { - let events = IoEvents::IN | IoEvents::OUT; - events & mask - } -} - -impl InodeIo for Null { - fn read_at( - &self, - _offset: usize, - _writer: &mut VmWriter, - _status_flags: StatusFlags, - ) -> Result { - Ok(0) - } - - fn write_at( - &self, - _offset: usize, - reader: &mut VmReader, - _status_flags: StatusFlags, - ) -> Result { - let len = reader.remain(); - reader.skip(len); - Ok(len) - } -} - -impl FileIo for Null { - fn check_seekable(&self) -> Result<()> { - Ok(()) - } - - fn is_offset_aware(&self) -> bool { - false - } -} diff --git a/kernel/src/device/random.rs b/kernel/src/device/random.rs deleted file mode 100644 index be1e69933..000000000 --- a/kernel/src/device/random.rs +++ /dev/null @@ -1,78 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 - -use device_id::{DeviceId, MajorId, MinorId}; - -use super::Urandom; -use crate::{ - events::IoEvents, - fs::{ - device::{Device, DeviceType}, - inode_handle::FileIo, - utils::{InodeIo, StatusFlags}, - }, - prelude::*, - process::signal::{PollHandle, Pollable}, -}; - -pub struct Random; - -impl Random { - pub fn getrandom(writer: &mut VmWriter) -> Result { - // TODO: Support true randomness by collecting environment noise. - Urandom::getrandom(writer) - } -} - -impl Device for Random { - fn type_(&self) -> DeviceType { - DeviceType::Char - } - - fn id(&self) -> DeviceId { - // The same value as Linux - DeviceId::new(MajorId::new(1), MinorId::new(8)) - } - - fn open(&self) -> Result> { - Ok(Box::new(Self)) - } -} - -impl Pollable for Random { - fn poll(&self, mask: IoEvents, _poller: Option<&mut PollHandle>) -> IoEvents { - let events = IoEvents::IN | IoEvents::OUT; - events & mask - } -} - -impl InodeIo for Random { - fn read_at( - &self, - _offset: usize, - writer: &mut VmWriter, - _status_flags: StatusFlags, - ) -> Result { - Self::getrandom(writer) - } - - fn write_at( - &self, - _offset: usize, - reader: &mut VmReader, - _status_flags: StatusFlags, - ) -> Result { - let len = reader.remain(); - reader.skip(len); - Ok(len) - } -} - -impl FileIo for Random { - fn check_seekable(&self) -> Result<()> { - Ok(()) - } - - fn is_offset_aware(&self) -> bool { - false - } -} diff --git a/kernel/src/device/urandom.rs b/kernel/src/device/urandom.rs deleted file mode 100644 index 013a90edf..000000000 --- a/kernel/src/device/urandom.rs +++ /dev/null @@ -1,95 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 - -use device_id::{DeviceId, MajorId, MinorId}; - -use crate::{ - events::IoEvents, - fs::{ - device::{Device, DeviceType}, - inode_handle::FileIo, - utils::{InodeIo, StatusFlags}, - }, - prelude::*, - process::signal::{PollHandle, Pollable}, - util::random::getrandom, -}; - -pub struct Urandom; - -impl Urandom { - pub fn getrandom(writer: &mut VmWriter) -> Result { - const IO_CAPABILITY: usize = 4096; - - if !writer.has_avail() { - return Ok(0); - } - - let mut buffer = vec![0; writer.avail().min(IO_CAPABILITY)]; - let mut written_bytes = 0; - - while writer.has_avail() { - getrandom(&mut buffer[..writer.avail().min(IO_CAPABILITY)]); - match writer.write_fallible(&mut VmReader::from(buffer.as_slice())) { - Ok(len) => written_bytes += len, - Err((err, 0)) if written_bytes == 0 => return Err(err.into()), - Err((_, len)) => return Ok(written_bytes + len), - } - } - - Ok(written_bytes) - } -} - -impl Device for Urandom { - fn type_(&self) -> DeviceType { - DeviceType::Char - } - - fn id(&self) -> DeviceId { - // The same value as Linux - DeviceId::new(MajorId::new(1), MinorId::new(9)) - } - - fn open(&self) -> Result> { - Ok(Box::new(Self)) - } -} - -impl Pollable for Urandom { - fn poll(&self, mask: IoEvents, _poller: Option<&mut PollHandle>) -> IoEvents { - let events = IoEvents::IN | IoEvents::OUT; - events & mask - } -} - -impl InodeIo for Urandom { - fn read_at( - &self, - _offset: usize, - writer: &mut VmWriter, - _status_flags: StatusFlags, - ) -> Result { - Self::getrandom(writer) - } - - fn write_at( - &self, - _offset: usize, - reader: &mut VmReader, - _status_flags: StatusFlags, - ) -> Result { - let len = reader.remain(); - reader.skip(len); - Ok(len) - } -} - -impl FileIo for Urandom { - fn check_seekable(&self) -> Result<()> { - Ok(()) - } - - fn is_offset_aware(&self) -> bool { - false - } -} diff --git a/kernel/src/device/zero.rs b/kernel/src/device/zero.rs deleted file mode 100644 index 94d0d5804..000000000 --- a/kernel/src/device/zero.rs +++ /dev/null @@ -1,69 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 - -use device_id::{DeviceId, MajorId, MinorId}; - -use crate::{ - events::IoEvents, - fs::{ - device::{Device, DeviceType}, - inode_handle::FileIo, - utils::{InodeIo, StatusFlags}, - }, - prelude::*, - process::signal::{PollHandle, Pollable}, -}; - -pub struct Zero; - -impl Device for Zero { - fn type_(&self) -> DeviceType { - DeviceType::Char - } - - fn id(&self) -> DeviceId { - // The same value as Linux - DeviceId::new(MajorId::new(1), MinorId::new(5)) - } - - fn open(&self) -> Result> { - Ok(Box::new(Self)) - } -} - -impl Pollable for Zero { - fn poll(&self, mask: IoEvents, _poller: Option<&mut PollHandle>) -> IoEvents { - let events = IoEvents::IN | IoEvents::OUT; - events & mask - } -} - -impl InodeIo for Zero { - fn read_at( - &self, - _offset: usize, - writer: &mut VmWriter, - _status_flags: StatusFlags, - ) -> Result { - let read_len = writer.fill_zeros(writer.avail())?; - Ok(read_len) - } - - fn write_at( - &self, - _offset: usize, - reader: &mut VmReader, - _status_flags: StatusFlags, - ) -> Result { - Ok(reader.remain()) - } -} - -impl FileIo for Zero { - fn check_seekable(&self) -> Result<()> { - Ok(()) - } - - fn is_offset_aware(&self) -> bool { - false - } -} diff --git a/kernel/src/security/tsm.rs b/kernel/src/security/tsm.rs index 73cd49ab9..f3c12c0f3 100644 --- a/kernel/src/security/tsm.rs +++ b/kernel/src/security/tsm.rs @@ -25,7 +25,7 @@ use ostd::{ sync::RwMutex, }; -use crate::{device::tdxguest::tdx_get_quote, fs::configfs}; +use crate::{device::misc::tdxguest::tdx_get_quote, fs::configfs}; #[derive(Debug)] struct Tsm { diff --git a/kernel/src/syscall/getrandom.rs b/kernel/src/syscall/getrandom.rs index 588191adb..e45474172 100644 --- a/kernel/src/syscall/getrandom.rs +++ b/kernel/src/syscall/getrandom.rs @@ -25,9 +25,9 @@ pub fn sys_getrandom(buf: Vaddr, count: usize, flags: u32, ctx: &Context) -> Res let user_space = ctx.user_space(); let mut writer = user_space.writer(buf, count)?; let read_len = if flags.contains(GetRandomFlags::GRND_RANDOM) { - device::Random::getrandom(&mut writer)? + device::getrandom(&mut writer)? } else { - device::Urandom::getrandom(&mut writer)? + device::geturandom(&mut writer)? }; Ok(SyscallReturn::Return(read_len as isize)) }