Refactor mem/misc char devices

This commit is contained in:
Qingsong Chen 2025-11-20 09:47:06 +00:00 committed by Tate, Hongliang Tian
parent 6df2af2e17
commit e407dc7ce9
13 changed files with 542 additions and 430 deletions

243
kernel/src/device/char.rs Normal file
View File

@ -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<Arc<dyn FileIo>>;
}
static DEVICE_REGISTRY: Mutex<BTreeMap<u32, Arc<dyn CharDevice>>> = Mutex::new(BTreeMap::new());
/// Registers a new char device.
pub fn register(device: Arc<dyn CharDevice>) -> 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<Arc<dyn CharDevice>> {
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<Arc<dyn CharDevice>> {
DEVICE_REGISTRY.lock().values().cloned().collect()
}
/// Looks up a char device of a given device ID.
pub fn lookup(id: DeviceId) -> Option<Arc<dyn CharDevice>> {
DEVICE_REGISTRY.lock().get(&id.to_raw()).cloned()
}
/// The maximum value of the major device ID of a char device.
///
/// Reference: <https://elixir.bootlin.com/linux/v6.13/source/fs/char_dev.c#L104>.
pub const MAX_MAJOR: u16 = 511;
/// The ranges of free char majors.
///
/// Reference: <https://elixir.bootlin.com/linux/v6.13/source/include/linux/fs.h#L2840>.
const DYNAMIC_MAJOR_ID_RANGES: [Range<u16>; 2] = [234..255, 384..512];
static MAJORS: Mutex<BTreeSet<u16>> = 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<MajorIdOwner> {
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<MajorIdOwner> {
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<dyn CharDevice>);
impl CharFile {
pub fn new(device: Arc<dyn CharDevice>) -> Self {
Self(device)
}
}
impl Device for CharFile {
fn type_(&self) -> DeviceType {
DeviceType::Char
}
fn id(&self) -> DeviceId {
self.0.id()
}
fn open(&self) -> Result<Box<dyn FileIo>> {
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<dyn FileIo>);
#[inherit_methods(from = "self.0")]
impl InodeIo for OpenCharFile {
fn read_at(
&self,
offset: usize,
writer: &mut VmWriter,
status_flags: StatusFlags,
) -> Result<usize>;
fn write_at(
&self,
offset: usize,
reader: &mut VmReader,
status_flags: StatusFlags,
) -> Result<usize>;
}
#[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<Mappable>;
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32>;
}

View File

@ -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<Box<dyn FileIo>> {
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<usize> {
let len = writer.avail();
writer.fill_zeros(len)?;
Ok(len)
}
fn write_at(
&self,
_offset: usize,
_reader: &mut VmReader,
_status_flags: StatusFlags,
) -> Result<usize> {
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
}
}

View File

@ -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<usize> {
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<usize> {
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<usize> {
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
}
}

View File

@ -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 <https://www.kernel.org/doc/Documentation/admin-guide/devices.txt>.
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<Arc<dyn FileIo>> {
Ok(Arc::new(self.file))
}
}
static MEM_MAJOR: Once<MajorIdOwner> = 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();
}

View File

@ -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<MajorIdOwner> = 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();
});
}

View File

@ -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<Self>,
}
impl TdxGuest {
pub fn new() -> Arc<Self> {
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<Box<dyn FileIo>> {
Ok(Box::new(Self))
fn open(&self) -> Result<Arc<dyn FileIo>> {
Ok(self.weak_self.upgrade().unwrap())
}
}

View File

@ -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<Arc<dyn Device>> {
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<Arc<dyn Device>> {
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<dyn Device>)
.ok_or(Error::with_message(
Errno::EINVAL,
"the device ID is invalid or unsupported",
)),
}
}

View File

@ -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<Box<dyn FileIo>> {
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<usize> {
Ok(0)
}
fn write_at(
&self,
_offset: usize,
reader: &mut VmReader,
_status_flags: StatusFlags,
) -> Result<usize> {
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
}
}

View File

@ -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<usize> {
// 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<Box<dyn FileIo>> {
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<usize> {
Self::getrandom(writer)
}
fn write_at(
&self,
_offset: usize,
reader: &mut VmReader,
_status_flags: StatusFlags,
) -> Result<usize> {
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
}
}

View File

@ -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<usize> {
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<Box<dyn FileIo>> {
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<usize> {
Self::getrandom(writer)
}
fn write_at(
&self,
_offset: usize,
reader: &mut VmReader,
_status_flags: StatusFlags,
) -> Result<usize> {
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
}
}

View File

@ -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<Box<dyn FileIo>> {
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<usize> {
let read_len = writer.fill_zeros(writer.avail())?;
Ok(read_len)
}
fn write_at(
&self,
_offset: usize,
reader: &mut VmReader,
_status_flags: StatusFlags,
) -> Result<usize> {
Ok(reader.remain())
}
}
impl FileIo for Zero {
fn check_seekable(&self) -> Result<()> {
Ok(())
}
fn is_offset_aware(&self) -> bool {
false
}
}

View File

@ -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 {

View File

@ -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))
}