abi: rework device_request/filesystem_control
This commit is contained in:
parent
2e3af98822
commit
26d8b9b3bd
@ -9,10 +9,7 @@ use async_trait::async_trait;
|
||||
use device_api::device::Device;
|
||||
use libk::{device::char::CharDevice, vfs::FileReadiness};
|
||||
use libk_util::{ring::LossyRingQueue, OneTimeInit};
|
||||
use yggdrasil_abi::{
|
||||
error::Error,
|
||||
io::{DeviceRequest, KeyboardKeyEvent},
|
||||
};
|
||||
use yggdrasil_abi::{error::Error, io::KeyboardKeyEvent};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct KeyboardDevice;
|
||||
@ -59,8 +56,11 @@ impl CharDevice for KeyboardDevice {
|
||||
false
|
||||
}
|
||||
|
||||
fn device_request(&self, _req: &mut DeviceRequest) -> Result<(), Error> {
|
||||
todo!()
|
||||
fn device_request(&self, option: u32, buffer: &mut [u8], len: usize) -> Result<usize, Error> {
|
||||
let _ = option;
|
||||
let _ = buffer;
|
||||
let _ = len;
|
||||
Err(Error::InvalidOperation)
|
||||
}
|
||||
|
||||
fn is_terminal(&self) -> bool {
|
||||
|
@ -4,7 +4,7 @@ use alloc::{boxed::Box, sync::Arc};
|
||||
use async_trait::async_trait;
|
||||
use device_api::device::Device;
|
||||
use libk_mm::{PageBox, PageProvider, PageSlice};
|
||||
use yggdrasil_abi::{error::Error, io::DeviceRequest};
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
use crate::vfs::{CommonImpl, NodeRef};
|
||||
|
||||
@ -193,8 +193,10 @@ pub trait BlockDevice: Device + PageProvider {
|
||||
fn block_count(&self) -> u64;
|
||||
fn max_blocks_per_request(&self) -> usize;
|
||||
|
||||
fn device_request(&self, request: &mut DeviceRequest) -> Result<(), Error> {
|
||||
let _ = request;
|
||||
fn device_request(&self, option: u32, buffer: &mut [u8], len: usize) -> Result<usize, Error> {
|
||||
let _ = option;
|
||||
let _ = buffer;
|
||||
let _ = len;
|
||||
Err(Error::InvalidOperation)
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use alloc::{boxed::Box, sync::Arc};
|
||||
use async_trait::async_trait;
|
||||
use device_api::device::Device;
|
||||
use libk_mm::{address::PhysicalAddress, table::MapAttributes, PageProvider, PageSlice};
|
||||
use yggdrasil_abi::{error::Error, io::DeviceRequest};
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
use super::BlockDevice;
|
||||
|
||||
@ -108,8 +108,8 @@ impl BlockDevice for Partition {
|
||||
self.device.is_writeable()
|
||||
}
|
||||
|
||||
fn device_request(&self, request: &mut DeviceRequest) -> Result<(), Error> {
|
||||
self.device.device_request(request)
|
||||
fn device_request(&self, option: u32, buffer: &mut [u8], len: usize) -> Result<usize, Error> {
|
||||
self.device.device_request(option, buffer, len)
|
||||
}
|
||||
|
||||
fn max_blocks_per_request(&self) -> usize {
|
||||
|
@ -3,7 +3,7 @@ use core::{any::Any, ops::Deref};
|
||||
use alloc::{boxed::Box, sync::Arc};
|
||||
use async_trait::async_trait;
|
||||
use device_api::device::Device;
|
||||
use yggdrasil_abi::{error::Error, io::DeviceRequest};
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
use crate::vfs::{CommonImpl, FileReadiness, NodeRef};
|
||||
|
||||
@ -35,8 +35,11 @@ pub trait CharDevice: Device + FileReadiness {
|
||||
false
|
||||
}
|
||||
|
||||
fn device_request(&self, request: &mut DeviceRequest) -> Result<(), Error> {
|
||||
let _ = request;
|
||||
fn device_request(&self, option: u32, buffer: &mut [u8], len: usize) -> Result<usize, Error> {
|
||||
let _ = option;
|
||||
let _ = buffer;
|
||||
let _ = len;
|
||||
log::warn!("device_request unimplemented: {option:#x}");
|
||||
Err(Error::InvalidOperation)
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,8 @@ use libk_mm::{address::PhysicalAddress, table::MapAttributes, PageProvider, L3_P
|
||||
use yggdrasil_abi::{
|
||||
bitflags,
|
||||
error::Error,
|
||||
io::{DeviceRequest, Framebuffer},
|
||||
io::device::{self, DeviceRequestVariant, Framebuffer, VideoRequestVariant},
|
||||
option::RequestValue,
|
||||
process::ProcessId,
|
||||
};
|
||||
|
||||
@ -158,27 +159,40 @@ impl BlockDevice for DisplayWrapper {
|
||||
Err(Error::InvalidOperation)
|
||||
}
|
||||
|
||||
fn device_request(&self, req: &mut DeviceRequest) -> Result<(), Error> {
|
||||
let process = Thread::current().process_id();
|
||||
fn device_request(&self, option: u32, buffer: &mut [u8], len: usize) -> Result<usize, Error> {
|
||||
let _ = len;
|
||||
|
||||
match req {
|
||||
DeviceRequest::AcquireDevice => self.lock(DisplayOwner::Process(process)),
|
||||
DeviceRequest::ReleaseDevice => self.unlock(DisplayOwner::Process(process)),
|
||||
DeviceRequest::GetActiveFramebuffer(framebuffer) => {
|
||||
if let Ok(option) = DeviceRequestVariant::try_from(option) {
|
||||
let process = Thread::current().process_id();
|
||||
return match option {
|
||||
DeviceRequestVariant::AcquireDevice => {
|
||||
self.lock(DisplayOwner::Process(process))?;
|
||||
device::AcquireDevice::store_response(&(), buffer)
|
||||
}
|
||||
DeviceRequestVariant::ReleaseDevice => {
|
||||
self.unlock(DisplayOwner::Process(process))?;
|
||||
device::ReleaseDevice::store_response(&(), buffer)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let option = VideoRequestVariant::try_from(option)?;
|
||||
match option {
|
||||
VideoRequestVariant::GetActiveFramebuffer => {
|
||||
let mode = self.active_display_mode().ok_or(Error::DoesNotExist)?;
|
||||
let info = self.active_framebuffer().map_err(|_| Error::DoesNotExist)?;
|
||||
|
||||
framebuffer.write(Framebuffer {
|
||||
let framebuffer = Framebuffer {
|
||||
width: mode.width,
|
||||
height: mode.height,
|
||||
size: info.size,
|
||||
stride: info.stride,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
};
|
||||
device::GetActiveFramebuffer::store_response(&framebuffer, buffer)
|
||||
}
|
||||
VideoRequestVariant::FlushDisplay => {
|
||||
self.synchronize()?;
|
||||
device::FlushDisplay::store_response(&(), buffer)
|
||||
}
|
||||
DeviceRequest::FlushDisplay => self.synchronize(),
|
||||
_ => Err(Error::InvalidOperation),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,11 +21,11 @@ use yggdrasil_abi::{
|
||||
error::Error,
|
||||
io::{
|
||||
options::{self, FileOptionVariant},
|
||||
DeviceRequest, DirectoryEntry, FileMode, OpenOptions, RawFd, SeekFrom, TerminalOptions,
|
||||
TerminalSize, TimerOptions,
|
||||
DirectoryEntry, FileMode, OpenOptions, RawFd, SeekFrom, TerminalOptions, TerminalSize,
|
||||
TimerOptions,
|
||||
},
|
||||
option::OptionValue,
|
||||
process::{ProcessWait, WaitFlags},
|
||||
option::{OptionValue, RequestValue},
|
||||
process::{ProcessGroupId, ProcessWait, WaitFlags},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@ -33,25 +33,13 @@ use crate::{
|
||||
task::process::Process,
|
||||
vfs::{
|
||||
channel::ChannelDescriptor,
|
||||
// device::{BlockDeviceWrapper, CharDeviceWrapper},
|
||||
node::NodeRef,
|
||||
traits::{Read, Seek, Write},
|
||||
FdPoll,
|
||||
FileReadiness,
|
||||
Node,
|
||||
// PseudoTerminalMaster,
|
||||
// PseudoTerminalSlave,
|
||||
SharedMemory,
|
||||
TimerFile,
|
||||
FdPoll, FileReadiness, Node, SharedMemory, TimerFile,
|
||||
},
|
||||
};
|
||||
|
||||
use self::{
|
||||
// device::{BlockFile, CharFile},
|
||||
directory::DirectoryFile,
|
||||
pipe::PipeEnd,
|
||||
regular::RegularFile,
|
||||
};
|
||||
use self::{directory::DirectoryFile, pipe::PipeEnd, regular::RegularFile};
|
||||
|
||||
use super::{
|
||||
pid::PidFile,
|
||||
@ -111,7 +99,7 @@ pub trait TerminalHalf {
|
||||
fn read_nonblocking(&self, buf: &mut [u8]) -> Result<usize, Error>;
|
||||
fn write(&self, buf: &[u8]) -> Result<usize, Error>;
|
||||
fn poll_read(&self, cx: &mut Context<'_>) -> Poll<Result<(), Error>>;
|
||||
fn device_request(&self, req: &mut DeviceRequest) -> Result<(), Error>;
|
||||
fn device_request(&self, option: u32, buffer: &mut [u8], len: usize) -> Result<usize, Error>;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -359,18 +347,21 @@ impl File {
|
||||
}
|
||||
|
||||
/// Performs a device-specific request
|
||||
pub fn device_request(&self, req: &mut DeviceRequest) -> Result<(), Error> {
|
||||
if let DeviceRequest::IsTerminal(value) = req {
|
||||
*value = self.is_terminal();
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
pub fn device_request(
|
||||
&self,
|
||||
option: u32,
|
||||
buffer: &mut [u8],
|
||||
len: usize,
|
||||
) -> Result<usize, Error> {
|
||||
match &self.inner {
|
||||
FileInner::Char(f) => f.device.device_request(req),
|
||||
FileInner::Block(f) => f.device.device_request(req),
|
||||
FileInner::PtySlave(half) => half.half.device_request(req),
|
||||
FileInner::PtyMaster(half) => half.half.device_request(req),
|
||||
_ => Err(Error::InvalidOperation),
|
||||
FileInner::Char(f) => f.device.device_request(option, buffer, len),
|
||||
FileInner::Block(f) => f.device.device_request(option, buffer, len),
|
||||
FileInner::PtySlave(half) => half.half.device_request(option, buffer, len),
|
||||
FileInner::PtyMaster(half) => half.half.device_request(option, buffer, len),
|
||||
_ => {
|
||||
log::warn!("device_request {option:#x}: not a device");
|
||||
Err(Error::InvalidOperation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -407,6 +398,20 @@ impl File {
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_terminal_group(&self, group_id: ProcessGroupId) -> Result<(), Error> {
|
||||
use yggdrasil_abi::io::device as abi_device;
|
||||
|
||||
let mut buffer = [0; 8];
|
||||
let len = abi_device::SetTerminalGroup::store_request(&group_id, &mut buffer)?;
|
||||
self.device_request(
|
||||
abi_device::SetTerminalGroup::VARIANT.into(),
|
||||
&mut buffer,
|
||||
len,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl PageProvider for File {
|
||||
|
@ -3,7 +3,7 @@ use core::mem::MaybeUninit;
|
||||
use libk_util::ext::OptionExt;
|
||||
use yggdrasil_abi::{
|
||||
error::Error,
|
||||
io::{DeviceRequest, DirectoryEntry, FileMode, GroupId, OpenOptions, UserId},
|
||||
io::{DirectoryEntry, FileMode, GroupId, OpenOptions, UserId},
|
||||
};
|
||||
|
||||
use crate::vfs::{
|
||||
@ -18,10 +18,15 @@ impl Node {
|
||||
// Devices
|
||||
|
||||
/// Performs a device-specific function on a the device node
|
||||
pub fn device_request(self: &NodeRef, req: &mut DeviceRequest) -> Result<(), Error> {
|
||||
pub fn device_request(
|
||||
self: &NodeRef,
|
||||
option: u32,
|
||||
buffer: &mut [u8],
|
||||
len: usize,
|
||||
) -> Result<usize, Error> {
|
||||
match &self.data {
|
||||
NodeImpl::Block(dev) => dev.device_request(req),
|
||||
NodeImpl::Char(dev) => dev.device_request(req),
|
||||
NodeImpl::Block(dev) => dev.device_request(option, buffer, len),
|
||||
NodeImpl::Char(dev) => dev.device_request(option, buffer, len),
|
||||
_ => Err(Error::InvalidOperation),
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ use async_trait::async_trait;
|
||||
use libk_util::{ring::LossyRingQueue, sync::spin_rwlock::IrqSafeRwLock};
|
||||
use yggdrasil_abi::{
|
||||
error::Error,
|
||||
io::{DeviceRequest, TerminalOptions, TerminalSize},
|
||||
io::{TerminalOptions, TerminalSize},
|
||||
};
|
||||
|
||||
use super::{
|
||||
@ -115,8 +115,8 @@ impl TerminalHalf for PseudoTerminalSlave {
|
||||
self.0.input().poll_read(cx).map(Ok)
|
||||
}
|
||||
|
||||
fn device_request(&self, req: &mut DeviceRequest) -> Result<(), Error> {
|
||||
self.0.handle_device_request(req)
|
||||
fn device_request(&self, option: u32, buffer: &mut [u8], len: usize) -> Result<usize, Error> {
|
||||
self.0.handle_device_request(option, buffer, len)
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,8 +142,8 @@ impl TerminalHalf for PseudoTerminalMaster {
|
||||
self.0.output().poll_read(cx).map(Ok)
|
||||
}
|
||||
|
||||
fn device_request(&self, req: &mut DeviceRequest) -> Result<(), Error> {
|
||||
self.0.handle_device_request(req)
|
||||
fn device_request(&self, option: u32, buffer: &mut [u8], len: usize) -> Result<usize, Error> {
|
||||
self.0.handle_device_request(option, buffer, len)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,9 +14,11 @@ use libk_util::{
|
||||
use yggdrasil_abi::{
|
||||
error::Error,
|
||||
io::{
|
||||
DeviceRequest, KeyboardKey, KeyboardKeyEvent, TerminalInputOptions, TerminalLineOptions,
|
||||
TerminalOptions, TerminalOutputOptions, TerminalSize,
|
||||
device::{self, TerminalRequestVariant},
|
||||
KeyboardKey, KeyboardKeyEvent, TerminalInputOptions, TerminalLineOptions, TerminalOptions,
|
||||
TerminalOutputOptions, TerminalSize,
|
||||
},
|
||||
option::RequestValue,
|
||||
process::{ProcessGroupId, Signal},
|
||||
};
|
||||
|
||||
@ -182,30 +184,39 @@ impl<O: TerminalOutput> Terminal<O> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_device_request(&self, req: &mut DeviceRequest) -> Result<(), Error> {
|
||||
match req {
|
||||
DeviceRequest::SetTerminalGroup(group) => {
|
||||
self.input.set_signal_pgroup(*group);
|
||||
Ok(())
|
||||
pub fn handle_device_request(
|
||||
&self,
|
||||
option: u32,
|
||||
buffer: &mut [u8],
|
||||
len: usize,
|
||||
) -> Result<usize, Error> {
|
||||
let input = &buffer[..len];
|
||||
let option = TerminalRequestVariant::try_from(option)?;
|
||||
match option {
|
||||
TerminalRequestVariant::SetTerminalGroup => {
|
||||
let pgroup = device::SetTerminalGroup::load_request(input)?;
|
||||
*self.input.signal_pgroup.write() = Some(pgroup);
|
||||
device::SetTerminalGroup::store_response(&(), buffer)
|
||||
}
|
||||
DeviceRequest::GetTerminalOptions(options) => {
|
||||
options.write(*self.config.read());
|
||||
Ok(())
|
||||
}
|
||||
DeviceRequest::SetTerminalOptions(options) => {
|
||||
self.input.flush();
|
||||
*self.config.write() = *options;
|
||||
Ok(())
|
||||
}
|
||||
DeviceRequest::SetTerminalSize(size) => {
|
||||
TerminalRequestVariant::SetTerminalSize => {
|
||||
// TODO SIGWINCH?
|
||||
self.output.set_size(*size)
|
||||
let size = device::SetTerminalSize::load_request(input)?;
|
||||
self.output.set_size(size)?;
|
||||
device::SetTerminalSize::store_response(&(), buffer)
|
||||
}
|
||||
DeviceRequest::GetTerminalSize(size) => {
|
||||
size.write(self.output.size());
|
||||
Ok(())
|
||||
TerminalRequestVariant::GetTerminalSize => {
|
||||
device::GetTerminalSize::store_response(&self.output.size(), buffer)
|
||||
}
|
||||
_ => Err(Error::InvalidOperation),
|
||||
TerminalRequestVariant::SetTerminalOptions => {
|
||||
let options = device::SetTerminalOptions::load_request(input)?;
|
||||
self.input.flush();
|
||||
*self.config.write() = options;
|
||||
device::SetTerminalOptions::store_response(&(), buffer)
|
||||
}
|
||||
TerminalRequestVariant::GetTerminalOptions => {
|
||||
device::GetTerminalOptions::store_response(&*self.config.read(), buffer)
|
||||
}
|
||||
TerminalRequestVariant::IsTerminal => device::IsTerminal::store_response(&(), buffer),
|
||||
}
|
||||
}
|
||||
|
||||
@ -313,10 +324,6 @@ impl TerminalInput {
|
||||
let data = lock.flush();
|
||||
self.ready_ring.write_multiple(data);
|
||||
}
|
||||
|
||||
pub fn set_signal_pgroup(&self, value: ProcessGroupId) {
|
||||
self.signal_pgroup.write().replace(value);
|
||||
}
|
||||
}
|
||||
|
||||
impl InputBuffer {
|
||||
@ -382,8 +389,8 @@ impl<O: TerminalOutput> CharDevice for Terminal<O> {
|
||||
true
|
||||
}
|
||||
|
||||
fn device_request(&self, req: &mut DeviceRequest) -> Result<(), Error> {
|
||||
self.handle_device_request(req)
|
||||
fn device_request(&self, option: u32, buffer: &mut [u8], len: usize) -> Result<usize, Error> {
|
||||
self.handle_device_request(option, buffer, len)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,12 +2,13 @@
|
||||
|
||||
use core::ptr::NonNull;
|
||||
|
||||
use abi::path::Path;
|
||||
use abi::{io::filesystem::FilesystemRequestVariant, path::Path};
|
||||
use alloc::sync::Arc;
|
||||
use ext2::Ext2Fs;
|
||||
use libk::{
|
||||
block,
|
||||
fs::{devfs, sysfs},
|
||||
vfs::{self, register_root, FilesystemMountOption, IoContext, NodeRef},
|
||||
vfs::{self, register_root, Filesystem, FilesystemMountOption, IoContext, NodeRef},
|
||||
};
|
||||
use libk_mm::{
|
||||
address::{PhysicalAddress, Virtualize},
|
||||
@ -95,3 +96,49 @@ fn create_filesystem<'a, I: IntoIterator<Item = FilesystemMountOption<'a>>>(
|
||||
|
||||
Ok(root)
|
||||
}
|
||||
|
||||
/// Global filesystem control request
|
||||
pub fn global_control(option: u32, buffer: &mut [u8], len: usize) -> Result<usize, Error> {
|
||||
let _ = buffer;
|
||||
let _ = len;
|
||||
|
||||
let option = FilesystemRequestVariant::try_from(option)?;
|
||||
match option {
|
||||
FilesystemRequestVariant::FlushCache => {
|
||||
block! {
|
||||
let roots = vfs::filesystem_roots();
|
||||
for root in roots.read().iter() {
|
||||
if let Some(fs) = root.filesystem() {
|
||||
if let Err(error) = fs.flush().await {
|
||||
log::error!("{:?} flush: {error:?}", fs.display_name());
|
||||
}
|
||||
}
|
||||
}
|
||||
}?;
|
||||
|
||||
return Ok(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Specific filesystem control request
|
||||
pub fn filesystem_control(
|
||||
fs: Arc<dyn Filesystem>,
|
||||
option: u32,
|
||||
buffer: &mut [u8],
|
||||
len: usize,
|
||||
) -> Result<usize, Error> {
|
||||
let _ = buffer;
|
||||
let _ = len;
|
||||
|
||||
if let Ok(option) = FilesystemRequestVariant::try_from(option) {
|
||||
match option {
|
||||
FilesystemRequestVariant::FlushCache => {
|
||||
block!(fs.flush().await)??;
|
||||
return Ok(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
todo!()
|
||||
}
|
||||
|
@ -3,10 +3,9 @@ use core::{mem::MaybeUninit, time::Duration};
|
||||
use abi::{
|
||||
error::Error,
|
||||
io::{
|
||||
AccessMode, ChannelPublisherId, DeviceRequest, DirectoryEntry, FileAttr, FileControl,
|
||||
FileMetadataUpdate, FileMode, FileSync, FilesystemControl, MessageDestination, OpenOptions,
|
||||
PollControl, RawFd, ReceivedMessageMetadata, RemoveFlags, Rename, SeekFrom, SentMessage,
|
||||
TerminalOptions, TerminalSize, TimerOptions,
|
||||
AccessMode, ChannelPublisherId, DirectoryEntry, FileAttr, FileMetadataUpdate, FileMode,
|
||||
FileSync, MessageDestination, OpenOptions, PollControl, RawFd, ReceivedMessageMetadata,
|
||||
RemoveFlags, Rename, SeekFrom, SentMessage, TerminalOptions, TerminalSize, TimerOptions,
|
||||
},
|
||||
process::{ProcessWait, WaitFlags},
|
||||
};
|
||||
@ -14,11 +13,14 @@ use alloc::boxed::Box;
|
||||
use libk::{
|
||||
block,
|
||||
task::thread::Thread,
|
||||
vfs::{self, File, MessagePayload, Read, Seek, Write},
|
||||
vfs::{File, MessagePayload, Read, Seek, Write},
|
||||
};
|
||||
use libk_util::io::{ReadAt, WriteAt};
|
||||
|
||||
use crate::syscall::{at_fd, run_with_io, run_with_io_at};
|
||||
use crate::{
|
||||
fs,
|
||||
syscall::{at_fd, run_with_io, run_with_io_at},
|
||||
};
|
||||
|
||||
// I/O
|
||||
pub(crate) fn open(
|
||||
@ -297,11 +299,18 @@ pub(crate) fn read_link(at: Option<RawFd>, path: &str, buffer: &mut [u8]) -> Res
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn device_request(fd: RawFd, req: &mut DeviceRequest) -> Result<(), Error> {
|
||||
pub(crate) fn device_request(
|
||||
fd: RawFd,
|
||||
option: u32,
|
||||
buffer: &mut [u8],
|
||||
len: usize,
|
||||
) -> Result<usize, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |io| io.files.file(fd)?.device_request(req))
|
||||
run_with_io(&process, |io| {
|
||||
io.files.file(fd)?.device_request(option, buffer, len)
|
||||
})
|
||||
}
|
||||
|
||||
// Misc I/O
|
||||
@ -514,31 +523,15 @@ pub(crate) fn receive_message(
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn file_control(_fd: RawFd, _control: &mut FileControl) -> Result<(), Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub(crate) fn filesystem_control(
|
||||
fd: Option<RawFd>,
|
||||
control: &mut FilesystemControl,
|
||||
) -> Result<(), Error> {
|
||||
match (fd, control) {
|
||||
// Flush all caches
|
||||
(None, FilesystemControl::FlushCache) => {
|
||||
block! {
|
||||
let roots = vfs::filesystem_roots();
|
||||
for root in roots.read().iter() {
|
||||
if let Some(fs) = root.filesystem() {
|
||||
if let Err(error) = fs.flush().await {
|
||||
log::error!("{:?} flush: {error:?}", fs.display_name());
|
||||
}
|
||||
}
|
||||
}
|
||||
}?;
|
||||
Ok(())
|
||||
}
|
||||
// Specific filesystem action
|
||||
(Some(fd), FilesystemControl::FlushCache) => {
|
||||
option: u32,
|
||||
buffer: &mut [u8],
|
||||
len: usize,
|
||||
) -> Result<usize, Error> {
|
||||
match fd {
|
||||
None => fs::global_control(option, buffer, len),
|
||||
Some(fd) => {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
@ -546,9 +539,10 @@ pub(crate) fn filesystem_control(
|
||||
let file = io.files.file(fd)?;
|
||||
let node = file.node().ok_or(Error::InvalidOperation)?;
|
||||
if let Some(fs) = node.filesystem() {
|
||||
block!(fs.flush().await)??;
|
||||
fs::filesystem_control(fs, option, buffer, len)
|
||||
} else {
|
||||
Err(Error::InvalidArgument)
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ use core::{
|
||||
|
||||
use abi::{
|
||||
error::Error,
|
||||
io::DeviceRequest,
|
||||
mem::{MappingFlags, MappingSource},
|
||||
process::{
|
||||
ExitCode, MutexOperation, ProcessGroupId, ProcessId, ProcessOption, ProcessWait, Signal,
|
||||
@ -170,14 +169,11 @@ pub(crate) fn spawn_process(options: &SpawnOptions<'_>) -> Result<ProcessId, Err
|
||||
}) {
|
||||
log::debug!("{} requested terminal {:?}", pid, fd);
|
||||
let file = child_io.files.file(fd)?;
|
||||
// let node = file.node().ok_or(Error::InvalidFile)?;
|
||||
let mut req = DeviceRequest::SetTerminalGroup(child_process.group_id());
|
||||
file.device_request(&mut req)?;
|
||||
file.set_terminal_group(child_process.group_id())?;
|
||||
|
||||
if let Some(node) = file.node() {
|
||||
child_process.set_session_terminal(node.clone());
|
||||
}
|
||||
// node.device_request(&mut req)?;
|
||||
}
|
||||
|
||||
drop(child_io);
|
||||
@ -191,10 +187,6 @@ pub(crate) fn spawn_process(options: &SpawnOptions<'_>) -> Result<ProcessId, Err
|
||||
Ok(pid as _)
|
||||
});
|
||||
|
||||
//if let Err(error) = result {
|
||||
// log::error!("spawn({options:#?}) -> {result:?}");
|
||||
//}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
|
@ -9,10 +9,12 @@ pub trait Deserializer<'de> {
|
||||
fn read_i16(&mut self) -> Result<i16, Self::Error>;
|
||||
fn read_i32(&mut self) -> Result<i32, Self::Error>;
|
||||
fn read_i64(&mut self) -> Result<i64, Self::Error>;
|
||||
fn read_isize(&mut self) -> Result<isize, Self::Error>;
|
||||
fn read_u8(&mut self) -> Result<u8, Self::Error>;
|
||||
fn read_u16(&mut self) -> Result<u16, Self::Error>;
|
||||
fn read_u32(&mut self) -> Result<u32, Self::Error>;
|
||||
fn read_u64(&mut self) -> Result<u64, Self::Error>;
|
||||
fn read_usize(&mut self) -> Result<usize, Self::Error>;
|
||||
|
||||
fn read_enum_variant(&mut self) -> Result<u32, Self::Error>;
|
||||
}
|
||||
|
@ -10,11 +10,13 @@ pub trait Serializer {
|
||||
fn write_i16(&mut self, value: i16) -> Result<(), Self::Error>;
|
||||
fn write_i32(&mut self, value: i32) -> Result<(), Self::Error>;
|
||||
fn write_i64(&mut self, value: i64) -> Result<(), Self::Error>;
|
||||
fn write_isize(&mut self, value: isize) -> Result<(), Self::Error>;
|
||||
|
||||
fn write_u8(&mut self, value: u8) -> Result<(), Self::Error>;
|
||||
fn write_u16(&mut self, value: u16) -> Result<(), Self::Error>;
|
||||
fn write_u32(&mut self, value: u32) -> Result<(), Self::Error>;
|
||||
fn write_u64(&mut self, value: u64) -> Result<(), Self::Error>;
|
||||
fn write_usize(&mut self, value: usize) -> Result<(), Self::Error>;
|
||||
|
||||
fn write_enum_variant(&mut self, index: u32) -> Result<(), Self::Error>;
|
||||
}
|
||||
|
@ -76,6 +76,14 @@ impl Serializer for WireSerializer<'_> {
|
||||
self.write_naked_bytes(&value.to_ne_bytes())
|
||||
}
|
||||
|
||||
fn write_isize(&mut self, value: isize) -> Result<(), Self::Error> {
|
||||
self.write_naked_bytes(&value.to_ne_bytes())
|
||||
}
|
||||
|
||||
fn write_usize(&mut self, value: usize) -> Result<(), Self::Error> {
|
||||
self.write_naked_bytes(&value.to_ne_bytes())
|
||||
}
|
||||
|
||||
fn write_str(&mut self, data: &str) -> Result<(), Self::Error> {
|
||||
self.write_bytes(data.as_bytes())
|
||||
}
|
||||
@ -151,6 +159,20 @@ impl<'de> Deserializer<'de> for WireDeserializer<'de> {
|
||||
.map_err(|_| Error)
|
||||
}
|
||||
|
||||
fn read_isize(&mut self) -> Result<isize, Self::Error> {
|
||||
self.read_naked_bytes(size_of::<isize>())?
|
||||
.try_into()
|
||||
.map(isize::from_ne_bytes)
|
||||
.map_err(|_| Error)
|
||||
}
|
||||
|
||||
fn read_usize(&mut self) -> Result<usize, Self::Error> {
|
||||
self.read_naked_bytes(size_of::<usize>())?
|
||||
.try_into()
|
||||
.map(usize::from_ne_bytes)
|
||||
.map_err(|_| Error)
|
||||
}
|
||||
|
||||
fn read_str(&mut self) -> Result<&'de str, Self::Error> {
|
||||
let bytes = self.read_bytes()?;
|
||||
core::str::from_utf8(bytes).map_err(|_| Error)
|
||||
|
@ -29,7 +29,6 @@ extern {
|
||||
type ReceivedMessageMetadata = yggdrasil_abi::io::ReceivedMessageMetadata;
|
||||
type DeviceRequest = yggdrasil_abi::io::DeviceRequest;
|
||||
type FileMetadataUpdate = yggdrasil_abi::io::FileMetadataUpdate;
|
||||
type FileControl = yggdrasil_abi::io::FileControl;
|
||||
type FilesystemControl = yggdrasil_abi::io::FilesystemControl;
|
||||
type Rename = yggdrasil_abi::io::Rename;
|
||||
|
||||
@ -77,8 +76,7 @@ syscall get_system_info(info: &mut SystemInfo) -> Result<()>;
|
||||
syscall mount(opts: &MountOptions<'_>) -> Result<()>;
|
||||
syscall unmount(opts: &UnmountOptions) -> Result<()>;
|
||||
syscall load_module(path: &str) -> Result<()>;
|
||||
syscall file_control(fd: RawFd, control: &mut FileControl) -> Result<()>;
|
||||
syscall filesystem_control(fd: Option<RawFd>, control: &mut FilesystemControl) -> Result<()>;
|
||||
syscall filesystem_control(fd: Option<RawFd>, option: u32, value: &mut [u8], len: usize) -> Result<usize>;
|
||||
|
||||
// Memory management
|
||||
syscall map_memory(
|
||||
@ -142,7 +140,7 @@ syscall rename(rename: &Rename<'_>) -> Result<()>;
|
||||
syscall clone_fd(source: RawFd, target: Option<RawFd>) -> Result<RawFd>;
|
||||
syscall update_metadata(at: Option<RawFd>, path: &str, update: &FileMetadataUpdate) -> Result<()>;
|
||||
syscall get_metadata(at: Option<RawFd>, path: &str, metadata: &mut MaybeUninit<FileAttr>, follow: bool) -> Result<()>;
|
||||
syscall device_request(fd: RawFd, req: &mut DeviceRequest) -> Result<()>;
|
||||
syscall device_request(fd: RawFd, option: u32, value: &mut [u8], len: usize) -> Result<usize>;
|
||||
|
||||
// Misc I/O
|
||||
syscall open_channel(name: &str, subscribe: bool) -> Result<RawFd>;
|
||||
|
@ -1,8 +1,7 @@
|
||||
use core::mem::MaybeUninit;
|
||||
//! Device data structures and options
|
||||
use abi_serde::{des::Deserializer, ser::Serializer, Deserialize, Serialize};
|
||||
|
||||
use crate::generated::ProcessGroupId;
|
||||
|
||||
use super::terminal;
|
||||
use crate::{io::terminal, process::ProcessGroupId};
|
||||
|
||||
/// Represents a video device framebuffer
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
@ -18,32 +17,66 @@ pub struct Framebuffer {
|
||||
pub size: usize,
|
||||
}
|
||||
|
||||
// TODO make this accept references when "reading" something
|
||||
/// Describes device-specific requests
|
||||
#[derive(Clone, Debug)]
|
||||
#[repr(C)]
|
||||
#[non_exhaustive]
|
||||
pub enum DeviceRequest {
|
||||
/// Configure the terminal's options
|
||||
SetTerminalOptions(terminal::TerminalOptions),
|
||||
/// Read the terminal's options
|
||||
GetTerminalOptions(MaybeUninit<terminal::TerminalOptions>),
|
||||
/// Set a new terminal size
|
||||
SetTerminalSize(terminal::TerminalSize),
|
||||
/// Return the terminal's size
|
||||
GetTerminalSize(MaybeUninit<terminal::TerminalSize>),
|
||||
/// Sets a foreground process group ID for the terminal
|
||||
SetTerminalGroup(ProcessGroupId),
|
||||
/// Returns `true` if a file/device is a terminal
|
||||
IsTerminal(bool),
|
||||
request_group!(
|
||||
#[doc = "Terminal device requests"]
|
||||
pub enum TerminalRequestVariant<'de> {
|
||||
#[doc = "Update the terminal options"]
|
||||
0x1000: SetTerminalOptions(terminal::TerminalOptions, ()),
|
||||
#[doc = "Query the terminal options"]
|
||||
0x1001: GetTerminalOptions((), terminal::TerminalOptions),
|
||||
#[doc = "Update the terminal size"]
|
||||
0x1002: SetTerminalSize(terminal::TerminalSize, ()),
|
||||
#[doc = "Query the terminal size"]
|
||||
0x1003: GetTerminalSize((), terminal::TerminalSize),
|
||||
#[doc = "Update the terminal's foreground process group ID"]
|
||||
0x1004: SetTerminalGroup(ProcessGroupId, ()),
|
||||
#[doc = "Dummy option to test if a device is a terminal"]
|
||||
0x1005: IsTerminal((), ()),
|
||||
}
|
||||
);
|
||||
|
||||
/// "Acquires" ownership of the device, preventing others from accessing it
|
||||
AcquireDevice,
|
||||
/// "Releases" ownership of the device
|
||||
ReleaseDevice,
|
||||
request_group!(
|
||||
#[doc = "Common device requests"]
|
||||
pub enum DeviceRequestVariant<'de> {
|
||||
#[doc = "\"Acquire\" ownership of the device, preventing others from accessing it"]
|
||||
0x0001: AcquireDevice((), ()),
|
||||
#[doc = "\"Releases\" ownership of the device"]
|
||||
0x0002: ReleaseDevice((), ()),
|
||||
}
|
||||
);
|
||||
|
||||
/// Retrieves display's currently active framebuffer info
|
||||
GetActiveFramebuffer(MaybeUninit<Framebuffer>),
|
||||
/// Tells the display driver to send the framebuffer data to the display
|
||||
FlushDisplay,
|
||||
request_group!(
|
||||
#[doc = "Video/graphics device requests"]
|
||||
pub enum VideoRequestVariant<'de> {
|
||||
#[doc = "Retrieves the display's currently active framebuffer info"]
|
||||
0x2000: GetActiveFramebuffer((), Framebuffer),
|
||||
// TODO allow flushing a region of the display
|
||||
#[doc = "Tells the display driver to send the framebuffer data to the display"]
|
||||
0x2001: FlushDisplay((), ()),
|
||||
}
|
||||
);
|
||||
|
||||
impl<'de> Deserialize<'de> for Framebuffer {
|
||||
fn deserialize<D: Deserializer<'de>>(deserializer: &mut D) -> Result<Self, D::Error> {
|
||||
let width = deserializer.read_u32()?;
|
||||
let height = deserializer.read_u32()?;
|
||||
let stride = deserializer.read_usize()?;
|
||||
let size = deserializer.read_usize()?;
|
||||
Ok(Self {
|
||||
width,
|
||||
height,
|
||||
stride,
|
||||
size,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Framebuffer {
|
||||
fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
|
||||
serializer.write_u32(self.width)?;
|
||||
serializer.write_u32(self.height)?;
|
||||
serializer.write_usize(self.stride)?;
|
||||
serializer.write_usize(self.size)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -6,10 +6,6 @@ use crate::time::SystemTime;
|
||||
|
||||
use super::FileMode;
|
||||
|
||||
/// Describes an action done on a file descriptor
|
||||
#[derive(Debug)]
|
||||
pub enum FileControl {}
|
||||
|
||||
/// Describes an operation to perform when updating certain file metadata elements
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum FileMetadataUpdateMode {
|
||||
|
@ -1,8 +1,9 @@
|
||||
//! Filesystem management functions and structures
|
||||
|
||||
/// Describes an action performed on a filesystem
|
||||
#[derive(Debug)]
|
||||
pub enum FilesystemControl {
|
||||
/// Flushes the filesystem cache
|
||||
FlushCache,
|
||||
}
|
||||
request_group!(
|
||||
#[doc = "Common filesystem requests"]
|
||||
pub enum FilesystemRequestVariant<'de> {
|
||||
#[doc = "Flush filesystem data/metadata cache"]
|
||||
0x1000: FlushCache((), ()),
|
||||
}
|
||||
);
|
||||
|
@ -3,9 +3,9 @@
|
||||
pub mod options;
|
||||
|
||||
mod channel;
|
||||
mod device;
|
||||
pub mod device;
|
||||
mod file;
|
||||
mod filesystem;
|
||||
pub mod filesystem;
|
||||
mod input;
|
||||
mod terminal;
|
||||
|
||||
@ -14,11 +14,7 @@ pub use crate::generated::{
|
||||
OpenOptions, PollControl, RawFd, RemoveFlags, TimerOptions, UnmountOptions, UserId,
|
||||
};
|
||||
pub use channel::{ChannelPublisherId, MessageDestination, ReceivedMessageMetadata, SentMessage};
|
||||
pub use device::{DeviceRequest, Framebuffer};
|
||||
pub use file::{
|
||||
FileControl, FileMetadataUpdate, FileMetadataUpdateMode, FileTimesUpdate, SeekFrom,
|
||||
};
|
||||
pub use filesystem::FilesystemControl;
|
||||
pub use file::{FileMetadataUpdate, FileMetadataUpdateMode, FileTimesUpdate, SeekFrom};
|
||||
pub use input::{KeyboardKey, KeyboardKeyCode, KeyboardKeyEvent};
|
||||
pub use terminal::{
|
||||
TerminalControlCharacters, TerminalInputOptions, TerminalLineOptions, TerminalOptions,
|
||||
|
@ -1,3 +1,5 @@
|
||||
use abi_serde::{des::Deserializer, ser::Serializer, Deserialize, Serialize};
|
||||
|
||||
pub use crate::generated::{
|
||||
TerminalControlCharacters, TerminalInputOptions, TerminalLineOptions, TerminalOptions,
|
||||
TerminalOutputOptions, TerminalSize,
|
||||
@ -62,3 +64,108 @@ impl Default for TerminalOptions {
|
||||
Self::const_default()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for TerminalLineOptions {
|
||||
fn deserialize<D: Deserializer<'de>>(deserializer: &mut D) -> Result<Self, D::Error> {
|
||||
Ok(unsafe { Self::from_raw(deserializer.read_u32()?) })
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for TerminalLineOptions {
|
||||
fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
|
||||
serializer.write_u32(self.bits())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for TerminalInputOptions {
|
||||
fn deserialize<D: Deserializer<'de>>(deserializer: &mut D) -> Result<Self, D::Error> {
|
||||
Ok(unsafe { Self::from_raw(deserializer.read_u32()?) })
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for TerminalInputOptions {
|
||||
fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
|
||||
serializer.write_u32(self.bits())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for TerminalOutputOptions {
|
||||
fn deserialize<D: Deserializer<'de>>(deserializer: &mut D) -> Result<Self, D::Error> {
|
||||
Ok(unsafe { Self::from_raw(deserializer.read_u32()?) })
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for TerminalOutputOptions {
|
||||
fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
|
||||
serializer.write_u32(self.bits())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for TerminalControlCharacters {
|
||||
fn deserialize<D: Deserializer<'de>>(deserializer: &mut D) -> Result<Self, D::Error> {
|
||||
let eof = deserializer.read_u8()?;
|
||||
let interrupt = deserializer.read_u8()?;
|
||||
let erase = deserializer.read_u8()?;
|
||||
let werase = deserializer.read_u8()?;
|
||||
let kill = deserializer.read_u8()?;
|
||||
Ok(Self {
|
||||
eof,
|
||||
interrupt,
|
||||
erase,
|
||||
werase,
|
||||
kill,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for TerminalControlCharacters {
|
||||
fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
|
||||
serializer.write_u8(self.eof)?;
|
||||
serializer.write_u8(self.interrupt)?;
|
||||
serializer.write_u8(self.erase)?;
|
||||
serializer.write_u8(self.werase)?;
|
||||
serializer.write_u8(self.kill)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for TerminalOptions {
|
||||
fn deserialize<D: Deserializer<'de>>(deserializer: &mut D) -> Result<Self, D::Error> {
|
||||
let line = TerminalLineOptions::deserialize(deserializer)?;
|
||||
let input = TerminalInputOptions::deserialize(deserializer)?;
|
||||
let output = TerminalOutputOptions::deserialize(deserializer)?;
|
||||
let chars = TerminalControlCharacters::deserialize(deserializer)?;
|
||||
Ok(Self {
|
||||
line,
|
||||
input,
|
||||
output,
|
||||
chars,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for TerminalOptions {
|
||||
fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
|
||||
self.line.serialize(serializer)?;
|
||||
self.input.serialize(serializer)?;
|
||||
self.output.serialize(serializer)?;
|
||||
self.chars.serialize(serializer)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for TerminalSize {
|
||||
fn deserialize<D: Deserializer<'de>>(deserializer: &mut D) -> Result<Self, D::Error> {
|
||||
let rows = deserializer.read_usize()?;
|
||||
let columns = deserializer.read_usize()?;
|
||||
Ok(Self { rows, columns })
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for TerminalSize {
|
||||
fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
|
||||
serializer.write_usize(self.rows)?;
|
||||
serializer.write_usize(self.columns)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,26 @@ pub trait OptionValue<'de> {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait RequestValue<'de> {
|
||||
type Request: Deserialize<'de> + Serialize;
|
||||
type Response: Deserialize<'de> + Serialize;
|
||||
type Variant: Copy + Into<u32> + TryFrom<u32, Error = Error>;
|
||||
const VARIANT: Self::Variant;
|
||||
|
||||
fn store_request(value: &Self::Request, buffer: &mut [u8]) -> Result<usize, Error> {
|
||||
Ok(wire::to_slice(value, buffer)?)
|
||||
}
|
||||
fn store_response(value: &Self::Response, buffer: &mut [u8]) -> Result<usize, Error> {
|
||||
Ok(wire::to_slice(value, buffer)?)
|
||||
}
|
||||
fn load_request(buffer: &'de [u8]) -> Result<Self::Request, Error> {
|
||||
Ok(wire::from_slice(buffer)?)
|
||||
}
|
||||
fn load_response(buffer: &'de [u8]) -> Result<Self::Response, Error> {
|
||||
Ok(wire::from_slice(buffer)?)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait OptionSizeHint {
|
||||
const SIZE_HINT: usize;
|
||||
}
|
||||
@ -61,3 +81,44 @@ macro_rules! option_group {
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! request_group {
|
||||
(
|
||||
$(#[$enum_meta:meta])*
|
||||
$vis:vis enum $variant_ty:ident<$lifetime:lifetime> {
|
||||
$(
|
||||
$(#[$variant_meta:meta])*
|
||||
$discriminant:literal: $variant:ident $(# $size_hint:literal)? ($request:ty, $response:ty)
|
||||
),* $(,)?
|
||||
}
|
||||
) => {
|
||||
$crate::primitive_enum! {
|
||||
$(#[$enum_meta])*
|
||||
$vis enum $variant_ty: u32 {
|
||||
$(
|
||||
$(#[$variant_meta])*
|
||||
$variant = $discriminant
|
||||
),*
|
||||
}
|
||||
}
|
||||
|
||||
$(
|
||||
$(#[$variant_meta])*
|
||||
$vis struct $variant;
|
||||
|
||||
impl<$lifetime> $crate::option::RequestValue<$lifetime> for $variant {
|
||||
type Variant = $variant_ty;
|
||||
type Request = $request;
|
||||
type Response = $response;
|
||||
const VARIANT: Self::Variant = $variant_ty::$variant;
|
||||
}
|
||||
|
||||
$(
|
||||
impl $crate::option::OptionSizeHint for $variant {
|
||||
const SIZE_HINT: usize = $size_hint;
|
||||
}
|
||||
)?
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ pub use crate::generated::{
|
||||
ExecveOptions, ProcessGroupId, ProcessId, Signal, SignalEntryData, SpawnFlags, SpawnOptions,
|
||||
ThreadId, ThreadSpawnOptions, WaitFlags,
|
||||
};
|
||||
use abi_serde::{des::Deserializer, ser::Serializer, Deserialize, Serialize};
|
||||
pub use exit::ExitCode;
|
||||
pub use thread::ThreadOption;
|
||||
|
||||
@ -227,3 +228,15 @@ impl Signal {
|
||||
!matches!(self, Self::Killed)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for ProcessGroupId {
|
||||
fn deserialize<D: Deserializer<'de>>(deserializer: &mut D) -> Result<Self, D::Error> {
|
||||
deserializer.read_u32().map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for ProcessGroupId {
|
||||
fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
|
||||
serializer.write_u32(self.0)
|
||||
}
|
||||
}
|
||||
|
13
lib/runtime/src/io/device.rs
Normal file
13
lib/runtime/src/io/device.rs
Normal file
@ -0,0 +1,13 @@
|
||||
pub use abi::io::{device::*, MountOptions, UnmountOptions};
|
||||
|
||||
use abi::{error::Error, io::RawFd, option::RequestValue};
|
||||
|
||||
pub fn device_request<'de, T: RequestValue<'de>>(
|
||||
fd: RawFd,
|
||||
buffer: &'de mut [u8],
|
||||
request: &T::Request,
|
||||
) -> Result<T::Response, Error> {
|
||||
let len = T::store_request(request, buffer)?;
|
||||
let len = unsafe { crate::sys::device_request(fd, T::VARIANT.into(), buffer, len) }?;
|
||||
T::load_response(&buffer[..len])
|
||||
}
|
13
lib/runtime/src/io/filesystem.rs
Normal file
13
lib/runtime/src/io/filesystem.rs
Normal file
@ -0,0 +1,13 @@
|
||||
use abi::{error::Error, io::RawFd, option::RequestValue};
|
||||
|
||||
pub use abi::io::filesystem::*;
|
||||
|
||||
pub fn filesystem_control<'de, T: RequestValue<'de>>(
|
||||
fd: Option<RawFd>,
|
||||
buffer: &'de mut [u8],
|
||||
request: &T::Request,
|
||||
) -> Result<T::Response, Error> {
|
||||
let len = T::store_request(request, buffer)?;
|
||||
let len = unsafe { crate::sys::filesystem_control(fd, T::VARIANT.into(), buffer, len) }?;
|
||||
T::load_response(&buffer[..len])
|
||||
}
|
@ -1,16 +1,5 @@
|
||||
#![allow(missing_docs)]
|
||||
|
||||
pub mod device {
|
||||
pub use abi::io::{DeviceRequest, Framebuffer, MountOptions, UnmountOptions};
|
||||
}
|
||||
|
||||
pub mod terminal {
|
||||
pub use abi::io::{
|
||||
TerminalInputOptions, TerminalLineOptions, TerminalOptions, TerminalOutputOptions,
|
||||
TerminalSize,
|
||||
};
|
||||
}
|
||||
|
||||
pub mod message_channel {
|
||||
pub use abi::io::{
|
||||
ChannelPublisherId, MessageDestination, ReceivedMessageMetadata, SentMessage,
|
||||
@ -21,8 +10,6 @@ pub mod poll {
|
||||
pub use abi::io::PollControl;
|
||||
}
|
||||
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
pub use abi::io::{
|
||||
options, AccessMode, DirectoryEntry, FileAttr, FileMetadataUpdate, FileMetadataUpdateMode,
|
||||
FileMode, FileSync, FileTimesUpdate, FileType, OpenOptions, RawFd, RemoveFlags, Rename,
|
||||
@ -30,19 +17,16 @@ pub use abi::io::{
|
||||
};
|
||||
pub use abi::option::OptionSizeHint;
|
||||
|
||||
pub mod device;
|
||||
pub mod filesystem;
|
||||
pub mod paths;
|
||||
pub mod terminal;
|
||||
pub use paths::*;
|
||||
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use abi::{error::Error, option::OptionValue};
|
||||
|
||||
use device::DeviceRequest;
|
||||
|
||||
pub fn is_terminal(f: RawFd) -> bool {
|
||||
let mut option = DeviceRequest::IsTerminal(false);
|
||||
let res = unsafe { crate::sys::device_request(f, &mut option) };
|
||||
matches!((res, option), (Ok(()), DeviceRequest::IsTerminal(true)))
|
||||
}
|
||||
|
||||
pub fn remove_file(at: Option<RawFd>, path: &str) -> Result<(), Error> {
|
||||
unsafe { crate::sys::remove(at, path, RemoveFlags::empty()) }
|
||||
}
|
||||
|
39
lib/runtime/src/io/terminal.rs
Normal file
39
lib/runtime/src/io/terminal.rs
Normal file
@ -0,0 +1,39 @@
|
||||
pub use abi::io::{
|
||||
TerminalInputOptions, TerminalLineOptions, TerminalOptions, TerminalOutputOptions, TerminalSize,
|
||||
};
|
||||
|
||||
use abi::{error::Error, io::RawFd};
|
||||
|
||||
use super::device::{self, device_request};
|
||||
|
||||
pub fn get_terminal_options(fd: RawFd) -> Result<TerminalOptions, Error> {
|
||||
let mut buffer = [0; 64];
|
||||
device_request::<device::GetTerminalOptions>(fd, &mut buffer, &())
|
||||
}
|
||||
pub fn set_terminal_options(fd: RawFd, options: &TerminalOptions) -> Result<(), Error> {
|
||||
let mut buffer = [0; 64];
|
||||
device_request::<device::SetTerminalOptions>(fd, &mut buffer, options)
|
||||
}
|
||||
pub fn update_terminal_options<F: FnOnce(TerminalOptions) -> TerminalOptions>(
|
||||
fd: RawFd,
|
||||
mapper: F,
|
||||
) -> Result<TerminalOptions, Error> {
|
||||
let old = get_terminal_options(fd)?;
|
||||
let new = mapper(old);
|
||||
set_terminal_options(fd, &new)?;
|
||||
Ok(old)
|
||||
}
|
||||
|
||||
pub fn get_terminal_size(fd: RawFd) -> Result<TerminalSize, Error> {
|
||||
let mut buffer = [0; 32];
|
||||
device_request::<device::GetTerminalSize>(fd, &mut buffer, &())
|
||||
}
|
||||
pub fn set_terminal_size(fd: RawFd, size: &TerminalSize) -> Result<(), Error> {
|
||||
let mut buffer = [0; 32];
|
||||
device_request::<device::SetTerminalSize>(fd, &mut buffer, &size)
|
||||
}
|
||||
|
||||
pub fn is_terminal(fd: RawFd) -> bool {
|
||||
let mut buffer = [0; 0];
|
||||
device_request::<device::IsTerminal>(fd, &mut buffer, &()).is_ok()
|
||||
}
|
1
userspace/Cargo.lock
generated
1
userspace/Cargo.lock
generated
@ -752,6 +752,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"thiserror",
|
||||
"yggdrasil-rt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1,9 +1,8 @@
|
||||
use std::{
|
||||
fs::OpenOptions,
|
||||
mem::MaybeUninit,
|
||||
os::yggdrasil::io::{
|
||||
device::{DeviceRequest, FdDeviceRequest},
|
||||
mapping::FileMapping,
|
||||
os::{
|
||||
fd::AsRawFd,
|
||||
yggdrasil::{io::mapping::FileMapping, rt::io::device},
|
||||
},
|
||||
path::Path,
|
||||
};
|
||||
@ -28,16 +27,15 @@ impl Display<'_> {
|
||||
pub fn open(framebuffer: impl AsRef<Path>) -> Result<Self, Error> {
|
||||
let file = OpenOptions::new().open(framebuffer)?;
|
||||
|
||||
let framebuffer = unsafe {
|
||||
file.device_request(&mut DeviceRequest::AcquireDevice)?;
|
||||
|
||||
let mut request = DeviceRequest::GetActiveFramebuffer(MaybeUninit::uninit());
|
||||
file.device_request(&mut request)?;
|
||||
let DeviceRequest::GetActiveFramebuffer(framebuffer) = request else {
|
||||
unreachable!()
|
||||
};
|
||||
framebuffer.assume_init()
|
||||
};
|
||||
let mut buffer = [0; 128];
|
||||
device::device_request::<device::AcquireDevice>(file.as_raw_fd(), &mut buffer, &())
|
||||
.map_err(std::io::Error::from)?;
|
||||
let framebuffer = device::device_request::<device::GetActiveFramebuffer>(
|
||||
file.as_raw_fd(),
|
||||
&mut buffer,
|
||||
&(),
|
||||
)
|
||||
.map_err(std::io::Error::from)?;
|
||||
|
||||
let width = framebuffer.width as usize;
|
||||
let height = framebuffer.height as usize;
|
||||
@ -59,11 +57,8 @@ impl Display<'_> {
|
||||
}
|
||||
|
||||
pub fn flush(&mut self) {
|
||||
unsafe {
|
||||
self.mapping
|
||||
.device_request(&mut DeviceRequest::FlushDisplay)
|
||||
.ok()
|
||||
};
|
||||
let mut buffer = [0; 0];
|
||||
device::device_request::<device::FlushDisplay>(self.mapping.as_raw_fd(), &mut buffer, &()).ok();
|
||||
}
|
||||
|
||||
pub fn width(&self) -> usize {
|
||||
|
@ -1,10 +1,7 @@
|
||||
use std::{
|
||||
io::{self, Stdin},
|
||||
ops::{Deref, DerefMut},
|
||||
os::{
|
||||
fd::AsRawFd,
|
||||
yggdrasil::io::terminal::{update_terminal_options, TerminalOptions},
|
||||
},
|
||||
os::yggdrasil::io::terminal::{update_terminal_options, TerminalOptions},
|
||||
};
|
||||
|
||||
use crate::sys::RawStdin;
|
||||
@ -16,9 +13,7 @@ pub struct RawStdinImpl<'a> {
|
||||
|
||||
impl<'a> RawStdin<'a> for RawStdinImpl<'a> {
|
||||
fn new(stdin: &'a mut Stdin) -> io::Result<Self> {
|
||||
let saved = unsafe {
|
||||
update_terminal_options(stdin.as_raw_fd(), |_| TerminalOptions::raw_input())
|
||||
}?;
|
||||
let saved = unsafe { update_terminal_options(stdin, |_| TerminalOptions::raw_input()) }?;
|
||||
Ok(Self {
|
||||
inner: stdin,
|
||||
saved,
|
||||
@ -28,7 +23,7 @@ impl<'a> RawStdin<'a> for RawStdinImpl<'a> {
|
||||
|
||||
impl Drop for RawStdinImpl<'_> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { update_terminal_options(self.inner.as_raw_fd(), |_| self.saved).ok() };
|
||||
unsafe { update_terminal_options(self.inner, |_| self.saved).ok() };
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,5 +11,8 @@ thiserror.workspace = true
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
libc = "0.2.150"
|
||||
|
||||
[target.'cfg(target_os = "yggdrasil")'.dependencies]
|
||||
yggdrasil-rt.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
@ -1,10 +1,11 @@
|
||||
use std::{
|
||||
io::{self, Stdout},
|
||||
mem::MaybeUninit,
|
||||
os::{fd::AsRawFd, yggdrasil::io::{
|
||||
device::{DeviceRequest, FdDeviceRequest},
|
||||
terminal::{update_terminal_options, TerminalOptions},
|
||||
}},
|
||||
os::{
|
||||
fd::AsRawFd,
|
||||
yggdrasil::io::terminal::{
|
||||
get_terminal_size, set_terminal_options, update_terminal_options, TerminalOptions,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
pub struct RawMode(TerminalOptions);
|
||||
@ -14,26 +15,20 @@ impl RawMode {
|
||||
///
|
||||
/// May leave the terminal in broken state, unsafe.
|
||||
pub unsafe fn enter<F: AsRawFd>(stdin: &F) -> io::Result<Self> {
|
||||
update_terminal_options(stdin.as_raw_fd(), |_| TerminalOptions::raw_input()).map(RawMode)
|
||||
update_terminal_options(stdin, |_| TerminalOptions::raw_input()).map(Self)
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// May leave the terminal in broken state, unsafe.
|
||||
pub unsafe fn leave<F: AsRawFd>(&self, stdin: &F) {
|
||||
update_terminal_options(stdin.as_raw_fd(), |_| self.0).ok();
|
||||
set_terminal_options(stdin, &self.0).ok();
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn terminal_size(stdout: &Stdout) -> io::Result<(usize, usize)> {
|
||||
let mut req = DeviceRequest::GetTerminalSize(MaybeUninit::uninit());
|
||||
if stdout.device_request(&mut req).is_err() {
|
||||
// Fallback
|
||||
return Ok((80, 20));
|
||||
match get_terminal_size(stdout) {
|
||||
Ok(size) => Ok((size.columns, size.rows)),
|
||||
Err(_) => Ok((80, 20)),
|
||||
}
|
||||
let DeviceRequest::GetTerminalSize(size) = req else {
|
||||
unreachable!();
|
||||
};
|
||||
let size = size.assume_init();
|
||||
Ok((size.columns, size.rows))
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
use std::os::yggdrasil::{
|
||||
io::{
|
||||
device::{DeviceRequest, FdDeviceRequest},
|
||||
pipe,
|
||||
use std::os::{
|
||||
fd::AsRawFd,
|
||||
yggdrasil::{
|
||||
rt::io::device,
|
||||
io::pipe,
|
||||
process::{self, CommandExt, ExitStatusExt, ProcessGroupId},
|
||||
signal::{set_signal_handler, Signal, SignalHandler},
|
||||
},
|
||||
process::{self, CommandExt, ExitStatusExt, ProcessGroupId},
|
||||
signal::{set_signal_handler, Signal, SignalHandler},
|
||||
};
|
||||
use std::{
|
||||
io::{self, stdin},
|
||||
@ -20,7 +21,9 @@ pub struct Pipe {
|
||||
}
|
||||
|
||||
fn set_terminal_group(group_id: ProcessGroupId) -> Result<(), io::Error> {
|
||||
unsafe { stdin().device_request(&mut DeviceRequest::SetTerminalGroup(group_id)) }
|
||||
let mut buffer = [0; 64];
|
||||
device::device_request::<device::SetTerminalGroup>(stdin().as_raw_fd(), &mut buffer, &group_id)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn spawn_pipeline(
|
||||
@ -93,7 +96,7 @@ impl From<ExitStatus> for Outcome {
|
||||
} else if let Some(sig) = value.signal() {
|
||||
match sig {
|
||||
Ok(sig) => Self::Killed(sig as _),
|
||||
Err(sig) => Self::Killed(sig as _)
|
||||
Err(sig) => Self::Killed(sig as _),
|
||||
}
|
||||
} else {
|
||||
todo!()
|
||||
|
@ -4,10 +4,8 @@ use std::{
|
||||
env,
|
||||
io::{self, stdin, stdout, BufRead, Write},
|
||||
os::{
|
||||
yggdrasil::io::{
|
||||
device::{DeviceRequest, FdDeviceRequest},
|
||||
terminal::start_terminal_session,
|
||||
},
|
||||
fd::AsRawFd,
|
||||
yggdrasil::{io::terminal::start_terminal_session, rt::io::device},
|
||||
},
|
||||
process::{Command, ExitCode},
|
||||
};
|
||||
@ -68,12 +66,14 @@ fn main() -> ExitCode {
|
||||
debug_trace!("Login attempt {}", attempt_number);
|
||||
|
||||
// "Attach" the terminal
|
||||
unsafe {
|
||||
let group_id = std::os::yggdrasil::process::group_id();
|
||||
stdin()
|
||||
.device_request(&mut DeviceRequest::SetTerminalGroup(group_id))
|
||||
.expect("Could not attach the terminal");
|
||||
}
|
||||
let group_id = std::os::yggdrasil::process::group_id();
|
||||
let mut buffer = [0; 8];
|
||||
device::device_request::<device::SetTerminalGroup>(
|
||||
stdin().as_raw_fd(),
|
||||
&mut buffer,
|
||||
&group_id,
|
||||
)
|
||||
.expect("Could not attach the terminal");
|
||||
|
||||
if let Err(err) = login_attempt(attempt_number % 3 == 0) {
|
||||
eprintln!("login: {}", err);
|
||||
|
@ -1,9 +1,10 @@
|
||||
use std::process::ExitCode;
|
||||
|
||||
use yggdrasil_abi::io::FilesystemControl;
|
||||
use yggdrasil_rt::io::filesystem as fs;
|
||||
|
||||
fn run() -> Result<(), yggdrasil_rt::Error> {
|
||||
unsafe { yggdrasil_rt::sys::filesystem_control(None, &mut FilesystemControl::FlushCache) }
|
||||
let mut buffer = [0; 0];
|
||||
fs::filesystem_control::<fs::FlushCache>(None, &mut buffer, &())
|
||||
}
|
||||
|
||||
pub fn main() -> ExitCode {
|
||||
|
@ -8,11 +8,11 @@ use std::{
|
||||
yggdrasil::{
|
||||
self,
|
||||
io::{
|
||||
device::{DeviceRequest, FdDeviceRequest},
|
||||
poll::PollChannel,
|
||||
terminal::{create_pty, TerminalOptions, TerminalSize},
|
||||
},
|
||||
process::CommandExt,
|
||||
rt::io::device,
|
||||
},
|
||||
},
|
||||
process::{Child, Command, ExitCode, Stdio},
|
||||
@ -193,11 +193,13 @@ impl Terminal<'_> {
|
||||
let columns = width / ds.font.width() as usize;
|
||||
|
||||
let term_size = TerminalSize { rows, columns };
|
||||
unsafe {
|
||||
pty_master
|
||||
.device_request(&mut DeviceRequest::SetTerminalSize(term_size))
|
||||
.unwrap();
|
||||
}
|
||||
let mut buffer = [0; 64];
|
||||
device::device_request::<device::SetTerminalSize>(
|
||||
pty_master.as_raw_fd(),
|
||||
&mut buffer,
|
||||
&term_size,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
s.resize(
|
||||
width / ds.font.width() as usize,
|
||||
|
Loading…
x
Reference in New Issue
Block a user