abi: rework device_request/filesystem_control

This commit is contained in:
Mark Poliakov 2025-01-11 14:08:10 +02:00
parent 2e3af98822
commit 26d8b9b3bd
36 changed files with 625 additions and 281 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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),
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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;
}
)?
)*
};
}

View File

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

View 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])
}

View 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])
}

View File

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

View 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
View File

@ -752,6 +752,7 @@ version = "0.1.0"
dependencies = [
"libc",
"thiserror",
"yggdrasil-rt",
]
[[package]]

View File

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

View File

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

View File

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

View File

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

View File

@ -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!()

View File

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

View File

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

View File

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