abi: split definitions into multiple files
This commit is contained in:
parent
12b481398d
commit
ae09849fda
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -1930,13 +1930,8 @@ dependencies = [
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
"serde",
|
||||
"yggdrasil-abi-def",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yggdrasil-abi-def"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "yggdrasil-kernel"
|
||||
version = "0.1.0"
|
||||
@ -1989,7 +1984,6 @@ dependencies = [
|
||||
"ygg_driver_usb_xhci",
|
||||
"ygg_driver_virtio_net",
|
||||
"yggdrasil-abi",
|
||||
"yggdrasil-abi-def",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2004,5 +1998,4 @@ dependencies = [
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
"yggdrasil-abi",
|
||||
"yggdrasil-abi-def",
|
||||
]
|
||||
|
@ -11,7 +11,6 @@ members = [
|
||||
"kernel/tools/gentables",
|
||||
"kernel",
|
||||
"lib/abi",
|
||||
"lib/abi-def",
|
||||
"lib/libyalloc",
|
||||
"lib/runtime",
|
||||
]
|
||||
|
@ -74,7 +74,6 @@ kernel-arch-x86_64 = { path = "arch/x86_64" }
|
||||
|
||||
[build-dependencies]
|
||||
prettyplease = "0.2.15"
|
||||
yggdrasil-abi-def = { path = "../lib/abi-def" }
|
||||
abi-generator = { path = "../tool/abi-generator" }
|
||||
|
||||
[features]
|
||||
|
@ -39,15 +39,28 @@ fn build_x86_64() {
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_syscall_dispatcher<P: AsRef<Path>>(out_dir: P) {
|
||||
fn load_abi_definitions<P: AsRef<Path>>(path: P) -> String {
|
||||
let mut content = String::new();
|
||||
for file in fs::read_dir(path).unwrap() {
|
||||
let file = file.unwrap();
|
||||
if file.path().extension().map(|x| x == "abi").unwrap_or(false) {
|
||||
println!("cargo:rerun-if-changed={}", file.path().display());
|
||||
content.extend(fs::read_to_string(file.path()));
|
||||
}
|
||||
}
|
||||
content
|
||||
}
|
||||
|
||||
fn generate_syscall_dispatcher<A: AsRef<Path>, P: AsRef<Path>>(abi_path: A, out_dir: P) {
|
||||
let abi = load_abi_definitions(abi_path);
|
||||
let abi: AbiBuilder = AbiBuilder::from_string(
|
||||
yggdrasil_abi_def::ABI_FILE,
|
||||
&abi,
|
||||
TargetEnv {
|
||||
thin_pointer_width: TypeWidth::U64,
|
||||
fat_pointer_width: TypeWidth::U128,
|
||||
},
|
||||
)
|
||||
.unwrap_fancy(yggdrasil_abi_def::ABI_FILE);
|
||||
.unwrap_fancy(&abi);
|
||||
|
||||
let generated_dispatcher = out_dir.as_ref().join("generated_dispatcher.rs");
|
||||
let file = prettyplease::unparse(
|
||||
@ -62,7 +75,7 @@ fn main() {
|
||||
let out_dir = env::var("OUT_DIR").unwrap();
|
||||
let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
|
||||
|
||||
generate_syscall_dispatcher(out_dir);
|
||||
generate_syscall_dispatcher("../lib/abi/def", out_dir);
|
||||
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
|
||||
|
@ -835,7 +835,11 @@ mod impls {
|
||||
mod generated {
|
||||
#![allow(unreachable_code)]
|
||||
|
||||
use abi::{io::ChannelPublisherId, process::ProcessId, SyscallFunction};
|
||||
use abi::{
|
||||
io::ChannelPublisherId,
|
||||
process::{ExecveOptions, ProcessId},
|
||||
SyscallFunction,
|
||||
};
|
||||
use abi_lib::SyscallRegister;
|
||||
|
||||
use super::{
|
||||
|
1
lib/abi-def/.gitignore
vendored
1
lib/abi-def/.gitignore
vendored
@ -1 +0,0 @@
|
||||
/target
|
7
lib/abi-def/Cargo.lock
generated
7
lib/abi-def/Cargo.lock
generated
@ -1,7 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "yggdrasil-abi-def"
|
||||
version = "0.1.0"
|
@ -1,6 +0,0 @@
|
||||
[package]
|
||||
name = "yggdrasil-abi-def"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
@ -1 +0,0 @@
|
||||
pub const ABI_FILE: &str = include_str!("../yggdrasil.abi");
|
@ -17,7 +17,6 @@ bytemuck = { version = "1.14.0", features = ["derive"], optional = true }
|
||||
abi-lib = { path = "../../lib/abi-lib" }
|
||||
|
||||
[build-dependencies]
|
||||
yggdrasil-abi-def = { path = "../abi-def" }
|
||||
abi-generator = { path = "../../tool/abi-generator" }
|
||||
prettyplease = "0.2.15"
|
||||
|
||||
|
@ -6,18 +6,31 @@ use abi_generator::{
|
||||
TargetEnv,
|
||||
};
|
||||
|
||||
fn generate_abi() {
|
||||
fn load_abi_definitions<P: AsRef<Path>>(path: P) -> String {
|
||||
let mut content = String::new();
|
||||
for file in fs::read_dir(path).unwrap() {
|
||||
let file = file.unwrap();
|
||||
if file.path().extension().map(|x| x == "abi").unwrap_or(false) {
|
||||
println!("cargo:rerun-if-changed={}", file.path().display());
|
||||
content.extend(fs::read_to_string(file.path()));
|
||||
}
|
||||
}
|
||||
content
|
||||
}
|
||||
|
||||
fn generate_abi<P: AsRef<Path>>(abi_path: P) {
|
||||
let output_dir = std::env::var("OUT_DIR").expect("$OUT_DIR not set");
|
||||
let generated_types = Path::new(&output_dir).join("generated_types.rs");
|
||||
|
||||
let abi = load_abi_definitions(abi_path);
|
||||
let abi = AbiBuilder::from_string(
|
||||
yggdrasil_abi_def::ABI_FILE,
|
||||
&abi,
|
||||
TargetEnv {
|
||||
thin_pointer_width: TypeWidth::U64,
|
||||
fat_pointer_width: TypeWidth::U64,
|
||||
},
|
||||
)
|
||||
.unwrap_fancy(yggdrasil_abi_def::ABI_FILE);
|
||||
.unwrap_fancy(&abi);
|
||||
|
||||
let types = prettyplease::unparse(
|
||||
&abi.emit_file(true, false)
|
||||
@ -28,5 +41,5 @@ fn generate_abi() {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
generate_abi();
|
||||
generate_abi("def");
|
||||
}
|
||||
|
30
lib/abi/def/error.abi
Normal file
30
lib/abi/def/error.abi
Normal file
@ -0,0 +1,30 @@
|
||||
// vi:syntax=yggdrasil_abi:
|
||||
|
||||
enum Error(u32) {
|
||||
OutOfMemory = 1,
|
||||
AlreadyExists = 2,
|
||||
NotImplemented = 3,
|
||||
DoesNotExist = 4,
|
||||
InvalidFile = 5,
|
||||
InvalidArgument = 6,
|
||||
Interrupted = 7,
|
||||
WouldBlock = 8,
|
||||
UnrecognizedExecutable = 9,
|
||||
InvalidOperation = 10,
|
||||
InvalidMemoryOperation = 11,
|
||||
NotADirectory = 12,
|
||||
IsADirectory = 13,
|
||||
ReadOnly = 14,
|
||||
PermissionDenied = 15,
|
||||
AddrInUse = 16,
|
||||
QueueFull = 17,
|
||||
BufferTooSmall = 18,
|
||||
ConnectionReset = 19,
|
||||
MissingData = 20,
|
||||
NetworkUnreachable = 21,
|
||||
TimedOut = 22,
|
||||
ConnectionRefused = 23,
|
||||
HostUnreachable = 24,
|
||||
UndefinedSyscall = 25,
|
||||
DirectoryNotEmpty = 26,
|
||||
}
|
191
lib/abi/def/io.abi
Normal file
191
lib/abi/def/io.abi
Normal file
@ -0,0 +1,191 @@
|
||||
// vi:syntax=yggdrasil_abi:
|
||||
|
||||
// abi::io
|
||||
|
||||
newtype RawFd(u32);
|
||||
|
||||
newtype UserId(u32);
|
||||
newtype GroupId(u32);
|
||||
|
||||
newtype ChannelPublisherId(u32);
|
||||
|
||||
bitfield FileMode(u32) {
|
||||
/// Other user execution access
|
||||
OTHER_EXEC: 0,
|
||||
/// Other user write access
|
||||
OTHER_WRITE: 1,
|
||||
/// Other user read access
|
||||
OTHER_READ: 2,
|
||||
|
||||
/// Group execution access
|
||||
GROUP_EXEC: 3,
|
||||
/// Group write access
|
||||
GROUP_WRITE: 4,
|
||||
/// Group read access
|
||||
GROUP_READ: 5,
|
||||
|
||||
/// User execution access
|
||||
USER_EXEC: 6,
|
||||
/// User write access
|
||||
USER_WRITE: 7,
|
||||
/// User read access
|
||||
USER_READ: 8,
|
||||
}
|
||||
|
||||
bitfield OpenOptions(u32) {
|
||||
/// The file is to be opened with read capability
|
||||
READ: 0,
|
||||
/// The file is to be opened with write capability
|
||||
WRITE: 1,
|
||||
|
||||
/// Open file at the end
|
||||
APPEND: 2,
|
||||
/// Truncate the file to zero bytes when opening
|
||||
TRUNCATE: 3,
|
||||
|
||||
/// Create the file if it does not exist
|
||||
CREATE: 4,
|
||||
/// When combined with CREATE, will fail if the file already exists
|
||||
CREATE_EXCL: 5,
|
||||
}
|
||||
|
||||
enum FileType(u32) {
|
||||
/// Regular file
|
||||
File = 1,
|
||||
/// Directory
|
||||
Directory = 2,
|
||||
/// Not yet implemented
|
||||
Symlink = 3,
|
||||
/// Block device
|
||||
Block = 4,
|
||||
/// Character device (e.g. terminal)
|
||||
Char = 5,
|
||||
}
|
||||
|
||||
/// Describes metadata associated with a filesystem entry
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
#[repr(C)]
|
||||
struct FileAttr {
|
||||
/// Data size for files, UNSPECIFIED for the rest
|
||||
pub size: u64,
|
||||
/// Entry type
|
||||
pub ty: FileType,
|
||||
/// Entry access permissions
|
||||
pub mode: FileMode,
|
||||
|
||||
/// Owner user ID
|
||||
pub uid: UserId,
|
||||
/// Owner group ID
|
||||
pub gid: GroupId,
|
||||
}
|
||||
|
||||
/// Raw directory entry representation
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[repr(C)]
|
||||
struct DirectoryEntry {
|
||||
/// Name of the entry
|
||||
pub name: FixedString<256>,
|
||||
/// Type of the entry
|
||||
pub ty: FileType,
|
||||
}
|
||||
|
||||
enum PollControl(u32) {
|
||||
AddFd = 1,
|
||||
}
|
||||
|
||||
// abi::io::terminal
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[repr(C)]
|
||||
struct TerminalControlCharacters {
|
||||
/// End-of-file character (0x04, ^D)
|
||||
pub eof: u8,
|
||||
/// Erase character (0x7F, ^?)
|
||||
pub erase: u8,
|
||||
/// Word erase character (0x17, ^W)
|
||||
pub werase: u8,
|
||||
/// Interrupt character (0x03, ^C)
|
||||
pub interrupt: u8,
|
||||
/// Kill character (0x15, ^U)
|
||||
pub kill: u8,
|
||||
}
|
||||
|
||||
/// Controls the line discipline of the terminal
|
||||
#[default(SIGNAL | CANONICAL | ECHO | ECHO_ERASE | ECHO_KILL | ECHO_NL)]
|
||||
bitfield TerminalLineOptions(u32) {
|
||||
/// Enables signal processing for special bytes (INTR, QUIT, etc.)
|
||||
SIGNAL: 0,
|
||||
/// Enables canonical mode
|
||||
CANONICAL: 1,
|
||||
/// Echo input characters back
|
||||
ECHO: 2,
|
||||
/// If CANONICAL is set, ERASE character erases chars, WORD_ERASE erases words
|
||||
ECHO_ERASE: 3,
|
||||
/// If CANONICAL is set, KILL erases lines
|
||||
ECHO_KILL: 4,
|
||||
/// If CANONICAL is set, echo newline even if ECHO is not set
|
||||
ECHO_NL: 5,
|
||||
}
|
||||
|
||||
/// Defines how output to the terminal should be processed
|
||||
#[default(NL_TO_CRNL)]
|
||||
bitfield TerminalOutputOptions(u32) {
|
||||
/// Translate \n to \r\n
|
||||
NL_TO_CRNL: 0,
|
||||
}
|
||||
|
||||
/// Defines how input should be presented to the reader
|
||||
#[default(CR_TO_NL)]
|
||||
bitfield TerminalInputOptions(u32) {
|
||||
/// Translate \n to \r on input
|
||||
NL_TO_CR: 0,
|
||||
/// Translate \r to \n on input
|
||||
CR_TO_NL: 1,
|
||||
}
|
||||
|
||||
/// Terminal I/O transformation and control settings
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[repr(C)]
|
||||
struct TerminalOptions {
|
||||
/// Controls output processing
|
||||
pub output: TerminalOutputOptions,
|
||||
/// Controls input processing
|
||||
pub input: TerminalInputOptions,
|
||||
/// Controls special bytes and line discipline
|
||||
pub line: TerminalLineOptions,
|
||||
/// Specifies control characters of the terminal
|
||||
pub chars: TerminalControlCharacters,
|
||||
}
|
||||
|
||||
/// Describes terminal size in rows and columns
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[repr(C)]
|
||||
struct TerminalSize {
|
||||
/// Number of text rows
|
||||
pub rows: usize,
|
||||
/// Number of text columns
|
||||
pub columns: usize,
|
||||
}
|
||||
|
||||
// abi::io::device
|
||||
|
||||
/// Describes how a mount operation should be performed
|
||||
#[derive(Clone, Debug)]
|
||||
#[repr(C)]
|
||||
struct MountOptions<'a> {
|
||||
/// Block device to use as a mount source. May be empty when mounting virtual filesystems.
|
||||
pub source: Option<&'a str>,
|
||||
/// Filesystem to use when mounting. Empty means "deduce automatically" and source must be set.
|
||||
pub filesystem: Option<&'a str>,
|
||||
/// Path to a directory to mount the filesystem to
|
||||
pub target: &'a str,
|
||||
}
|
||||
|
||||
/// Describes how an unmount operation should be performed
|
||||
#[derive(Clone, Debug)]
|
||||
#[repr(C)]
|
||||
struct UnmountOptions {
|
||||
/// Path to the mountpoint to unmount
|
||||
pub mountpoint: &'static str,
|
||||
}
|
||||
|
@ -1,27 +1,26 @@
|
||||
use crate::io::RawFd;
|
||||
// vi:syntax=yggdrasil_abi:
|
||||
|
||||
use super::ProcessId;
|
||||
|
||||
/// Defines an optional argument for controlling process creation
|
||||
#[derive(Debug)]
|
||||
pub enum SpawnOption {
|
||||
/// Indicates a new process should inherit a file descriptor from its creator
|
||||
InheritFile {
|
||||
/// FD on the creator side
|
||||
source: RawFd,
|
||||
/// What FD number should be used in the child
|
||||
child: RawFd,
|
||||
},
|
||||
/// The new process should be placed in the specified group
|
||||
SetProcessGroup(ProcessId),
|
||||
/// Gain terminal control for the given FD
|
||||
GainTerminal(RawFd),
|
||||
enum Signal(u32) {
|
||||
/// Process has tried to perform an illegal memory operation
|
||||
MemoryAccessViolation = 1,
|
||||
/// Process has hit a breakpoint or was aborted
|
||||
Aborted = 2,
|
||||
/// Process was killed
|
||||
Killed = 3,
|
||||
/// Process was interrupted
|
||||
Interrupted = 4,
|
||||
}
|
||||
|
||||
newtype ProcessId(u32);
|
||||
newtype ProcessGroupId(u32);
|
||||
newtype ThreadId(u32);
|
||||
|
||||
// Spawn
|
||||
|
||||
/// Controls how processes are created
|
||||
#[derive(Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub struct SpawnOptions<'a> {
|
||||
struct SpawnOptions<'a> {
|
||||
/// Creator-relative path to the binary to execute
|
||||
pub program: &'a str,
|
||||
/// Arguments to the child process
|
||||
@ -36,7 +35,7 @@ pub struct SpawnOptions<'a> {
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub struct ExecveOptions<'a> {
|
||||
struct ExecveOptions<'a> {
|
||||
pub program: &'a str,
|
||||
pub arguments: &'a [&'a str],
|
||||
pub environment: &'a [&'a str],
|
||||
@ -45,7 +44,7 @@ pub struct ExecveOptions<'a> {
|
||||
/// Controls how threads are spawned within a process
|
||||
#[derive(Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub struct ThreadSpawnOptions {
|
||||
struct ThreadSpawnOptions {
|
||||
/// Thread entry function
|
||||
pub entry: extern "C" fn(u64) -> !,
|
||||
/// Thread argument value
|
||||
@ -54,3 +53,15 @@ pub struct ThreadSpawnOptions {
|
||||
/// the thread.
|
||||
pub stack_top: usize,
|
||||
}
|
||||
|
||||
// Signal
|
||||
|
||||
/// Data provided by the kernel to signal entry function
|
||||
#[derive(Clone, Debug)]
|
||||
#[repr(C)]
|
||||
struct SignalEntryData {
|
||||
/// Which signal was issued
|
||||
pub signal: Signal,
|
||||
/// Saved frame of the context that was interrupted
|
||||
pub frame: SavedFrame,
|
||||
}
|
@ -5,14 +5,13 @@ extern {
|
||||
type SocketAddr = core::net::SocketAddr;
|
||||
type AtomicU32 = core::sync::atomic::AtomicU32;
|
||||
|
||||
// TODO "tagged union" enums are not yet implemented
|
||||
type MappingSource;
|
||||
|
||||
type SystemInfo = yggdrasil_abi::system::SystemInfo;
|
||||
|
||||
type SignalEntryData = yggdrasil_abi::process::SignalEntryData;
|
||||
type SpawnOptions = yggdrasil_abi::process::SpawnOptions;
|
||||
type MutexOperation = yggdrasil_abi::process::MutexOperation;
|
||||
type ExecveOptions = yggdrasil_abi::process::ExecveOptions;
|
||||
#[thin]
|
||||
type ExitCode = yggdrasil_abi::process::ExitCode;
|
||||
|
||||
@ -20,12 +19,8 @@ extern {
|
||||
|
||||
type SentMessage = yggdrasil_abi::io::SentMessage;
|
||||
type ReceivedMessageMetadata = yggdrasil_abi::io::ReceivedMessageMetadata;
|
||||
type MountOptions = yggdrasil_abi::io::MountOptions;
|
||||
type UnmountOptions = yggdrasil_abi::io::UnmountOptions;
|
||||
type DeviceRequest = yggdrasil_abi::io::DeviceRequest;
|
||||
type FileMetadataUpdate = yggdrasil_abi::io::FileMetadataUpdate;
|
||||
type DirectoryEntry = yggdrasil_abi::io::DirectoryEntry;
|
||||
type FileAttr = yggdrasil_abi::io::FileAttr;
|
||||
|
||||
#[thin]
|
||||
type SeekFrom = yggdrasil_abi::io::SeekFrom;
|
||||
@ -33,194 +28,6 @@ extern {
|
||||
type MessageDestination = yggdrasil_abi::io::MessageDestination;
|
||||
}
|
||||
|
||||
// abi::error
|
||||
|
||||
enum Error(u32) {
|
||||
OutOfMemory = 1,
|
||||
AlreadyExists = 2,
|
||||
NotImplemented = 3,
|
||||
DoesNotExist = 4,
|
||||
InvalidFile = 5,
|
||||
InvalidArgument = 6,
|
||||
Interrupted = 7,
|
||||
WouldBlock = 8,
|
||||
UnrecognizedExecutable = 9,
|
||||
InvalidOperation = 10,
|
||||
InvalidMemoryOperation = 11,
|
||||
NotADirectory = 12,
|
||||
IsADirectory = 13,
|
||||
ReadOnly = 14,
|
||||
PermissionDenied = 15,
|
||||
AddrInUse = 16,
|
||||
QueueFull = 17,
|
||||
BufferTooSmall = 18,
|
||||
ConnectionReset = 19,
|
||||
MissingData = 20,
|
||||
NetworkUnreachable = 21,
|
||||
TimedOut = 22,
|
||||
ConnectionRefused = 23,
|
||||
HostUnreachable = 24,
|
||||
UndefinedSyscall = 25,
|
||||
DirectoryNotEmpty = 26,
|
||||
}
|
||||
|
||||
// abi::process
|
||||
|
||||
enum Signal(u32) {
|
||||
/// Process has tried to perform an illegal memory operation
|
||||
MemoryAccessViolation = 1,
|
||||
/// Process has hit a breakpoint or was aborted
|
||||
Aborted = 2,
|
||||
/// Process was killed
|
||||
Killed = 3,
|
||||
/// Process was interrupted
|
||||
Interrupted = 4,
|
||||
}
|
||||
|
||||
newtype ProcessId(u32);
|
||||
newtype ProcessGroupId(u32);
|
||||
newtype ThreadId(u32);
|
||||
|
||||
// abi::io
|
||||
|
||||
newtype RawFd(u32);
|
||||
|
||||
newtype UserId(u32);
|
||||
newtype GroupId(u32);
|
||||
|
||||
newtype ChannelPublisherId(u32);
|
||||
|
||||
bitfield FileMode(u32) {
|
||||
/// Other user execution access
|
||||
OTHER_EXEC: 0,
|
||||
/// Other user write access
|
||||
OTHER_WRITE: 1,
|
||||
/// Other user read access
|
||||
OTHER_READ: 2,
|
||||
|
||||
/// Group execution access
|
||||
GROUP_EXEC: 3,
|
||||
/// Group write access
|
||||
GROUP_WRITE: 4,
|
||||
/// Group read access
|
||||
GROUP_READ: 5,
|
||||
|
||||
/// User execution access
|
||||
USER_EXEC: 6,
|
||||
/// User write access
|
||||
USER_WRITE: 7,
|
||||
/// User read access
|
||||
USER_READ: 8,
|
||||
}
|
||||
|
||||
bitfield OpenOptions(u32) {
|
||||
/// The file is to be opened with read capability
|
||||
READ: 0,
|
||||
/// The file is to be opened with write capability
|
||||
WRITE: 1,
|
||||
|
||||
/// Open file at the end
|
||||
APPEND: 2,
|
||||
/// Truncate the file to zero bytes when opening
|
||||
TRUNCATE: 3,
|
||||
|
||||
/// Create the file if it does not exist
|
||||
CREATE: 4,
|
||||
/// When combined with CREATE, will fail if the file already exists
|
||||
CREATE_EXCL: 5,
|
||||
}
|
||||
|
||||
enum FileType(u32) {
|
||||
/// Regular file
|
||||
File = 1,
|
||||
/// Directory
|
||||
Directory = 2,
|
||||
/// Not yet implemented
|
||||
Symlink = 3,
|
||||
/// Block device
|
||||
Block = 4,
|
||||
/// Character device (e.g. terminal)
|
||||
Char = 5,
|
||||
}
|
||||
|
||||
enum PollControl(u32) {
|
||||
AddFd = 1,
|
||||
}
|
||||
|
||||
// abi::io::terminal
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[repr(C)]
|
||||
struct TerminalControlCharacters {
|
||||
/// End-of-file character (0x04, ^D)
|
||||
pub eof: u8,
|
||||
/// Erase character (0x7F, ^?)
|
||||
pub erase: u8,
|
||||
/// Word erase character (0x17, ^W)
|
||||
pub werase: u8,
|
||||
/// Interrupt character (0x03, ^C)
|
||||
pub interrupt: u8,
|
||||
/// Kill character (0x15, ^U)
|
||||
pub kill: u8,
|
||||
}
|
||||
|
||||
/// Controls the line discipline of the terminal
|
||||
#[default(SIGNAL | CANONICAL | ECHO | ECHO_ERASE | ECHO_KILL | ECHO_NL)]
|
||||
bitfield TerminalLineOptions(u32) {
|
||||
/// Enables signal processing for special bytes (INTR, QUIT, etc.)
|
||||
SIGNAL: 0,
|
||||
/// Enables canonical mode
|
||||
CANONICAL: 1,
|
||||
/// Echo input characters back
|
||||
ECHO: 2,
|
||||
/// If CANONICAL is set, ERASE character erases chars, WORD_ERASE erases words
|
||||
ECHO_ERASE: 3,
|
||||
/// If CANONICAL is set, KILL erases lines
|
||||
ECHO_KILL: 4,
|
||||
/// If CANONICAL is set, echo newline even if ECHO is not set
|
||||
ECHO_NL: 5,
|
||||
}
|
||||
|
||||
/// Defines how output to the terminal should be processed
|
||||
#[default(NL_TO_CRNL)]
|
||||
bitfield TerminalOutputOptions(u32) {
|
||||
/// Translate \n to \r\n
|
||||
NL_TO_CRNL: 0,
|
||||
}
|
||||
|
||||
/// Defines how input should be presented to the reader
|
||||
#[default(CR_TO_NL)]
|
||||
bitfield TerminalInputOptions(u32) {
|
||||
/// Translate \n to \r on input
|
||||
NL_TO_CR: 0,
|
||||
/// Translate \r to \n on input
|
||||
CR_TO_NL: 1,
|
||||
}
|
||||
|
||||
/// Terminal I/O transformation and control settings
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[repr(C)]
|
||||
struct TerminalOptions {
|
||||
/// Controls output processing
|
||||
pub output: TerminalOutputOptions,
|
||||
/// Controls input processing
|
||||
pub input: TerminalInputOptions,
|
||||
/// Controls special bytes and line discipline
|
||||
pub line: TerminalLineOptions,
|
||||
/// Specifies control characters of the terminal
|
||||
pub chars: TerminalControlCharacters,
|
||||
}
|
||||
|
||||
/// Describes terminal size in rows and columns
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[repr(C)]
|
||||
struct TerminalSize {
|
||||
/// Number of text rows
|
||||
pub rows: usize,
|
||||
/// Number of text columns
|
||||
pub columns: usize,
|
||||
}
|
||||
|
||||
// abi::net
|
||||
|
||||
enum SocketType(u32) {
|
@ -4,26 +4,6 @@ use crate::generated::ProcessId;
|
||||
|
||||
use super::terminal;
|
||||
|
||||
/// Describes how a mount operation should be performed
|
||||
#[derive(Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub struct MountOptions<'a> {
|
||||
/// Block device to use as a mount source. May be empty when mounting virtual filesystems.
|
||||
pub source: Option<&'a str>,
|
||||
/// Filesystem to use when mounting. Empty means "deduce automatically" and source must be set.
|
||||
pub filesystem: Option<&'a str>,
|
||||
/// Path to a directory to mount the filesystem to
|
||||
pub target: &'a str,
|
||||
}
|
||||
|
||||
/// Describes how an unmount operation should be performed
|
||||
#[derive(Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub struct UnmountOptions {
|
||||
/// Path to the mountpoint to unmount
|
||||
pub mountpoint: &'static str,
|
||||
}
|
||||
|
||||
// TODO make this accept references when "reading" something
|
||||
/// Describes device-specific requests
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -2,7 +2,7 @@ use core::fmt;
|
||||
|
||||
use abi_lib::SyscallRegister;
|
||||
|
||||
use super::{FileMode, FileType, GroupId, UserId};
|
||||
use super::FileMode;
|
||||
|
||||
/// Describes an operation to perform when updating certain file metadata elements
|
||||
#[derive(Debug, Clone)]
|
||||
@ -24,23 +24,6 @@ pub enum FileMetadataUpdate {
|
||||
Permissions(FileMode, FileMetadataUpdateMode),
|
||||
}
|
||||
|
||||
/// Describes metadata associated with a filesystem entry
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub struct FileAttr {
|
||||
/// Data size for files, UNSPECIFIED for the rest
|
||||
pub size: u64,
|
||||
/// Entry type
|
||||
pub ty: FileType,
|
||||
/// Entry access permissions
|
||||
pub mode: FileMode,
|
||||
|
||||
/// Owner user ID
|
||||
pub uid: UserId,
|
||||
/// Owner group ID
|
||||
pub gid: GroupId,
|
||||
}
|
||||
|
||||
/// Describes a seek operation for a regular file
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum SeekFrom {
|
||||
|
@ -1,15 +1,16 @@
|
||||
use crate::util::FixedString;
|
||||
|
||||
mod channel;
|
||||
mod device;
|
||||
mod file;
|
||||
mod input;
|
||||
mod terminal;
|
||||
|
||||
pub use crate::generated::{FileMode, FileType, GroupId, OpenOptions, PollControl, RawFd, UserId};
|
||||
pub use crate::generated::{
|
||||
DirectoryEntry, FileAttr, FileMode, FileType, GroupId, MountOptions, OpenOptions, PollControl,
|
||||
RawFd, UnmountOptions, UserId,
|
||||
};
|
||||
pub use channel::{ChannelPublisherId, MessageDestination, ReceivedMessageMetadata, SentMessage};
|
||||
pub use device::{DeviceRequest, MountOptions, UnmountOptions};
|
||||
pub use file::{FileAttr, FileMetadataUpdate, FileMetadataUpdateMode, SeekFrom};
|
||||
pub use device::DeviceRequest;
|
||||
pub use file::{FileMetadataUpdate, FileMetadataUpdateMode, SeekFrom};
|
||||
pub use input::{KeyboardKey, KeyboardKeyCode, KeyboardKeyEvent};
|
||||
pub use terminal::{
|
||||
TerminalControlCharacters, TerminalInputOptions, TerminalLineOptions, TerminalOptions,
|
||||
@ -52,16 +53,6 @@ impl FileMode {
|
||||
}
|
||||
}
|
||||
|
||||
/// Raw directory entry representation
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub struct DirectoryEntry {
|
||||
/// Name of the entry
|
||||
pub name: FixedString<256>,
|
||||
/// Type of the entry
|
||||
pub ty: FileType,
|
||||
}
|
||||
|
||||
impl RawFd {
|
||||
pub const STDIN: Self = Self(0);
|
||||
pub const STDOUT: Self = Self(1);
|
||||
|
@ -21,6 +21,8 @@ pub mod pass;
|
||||
pub mod util;
|
||||
|
||||
mod generated {
|
||||
use crate::{arch::SavedFrame, process::SpawnOption, util::FixedString};
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/generated_types.rs"));
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@ use core::num::NonZeroI32;
|
||||
|
||||
use abi_lib::SyscallRegister;
|
||||
|
||||
use super::signal::Signal;
|
||||
use super::Signal;
|
||||
|
||||
/// Code signalled by a process when it finishes or is terminated by a signal
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
|
@ -2,16 +2,33 @@
|
||||
|
||||
use core::{fmt, time::Duration};
|
||||
|
||||
use crate::{impl_place_lifetime, io::FileMode};
|
||||
use crate::{
|
||||
impl_place_lifetime,
|
||||
io::{FileMode, RawFd},
|
||||
};
|
||||
|
||||
mod exit;
|
||||
mod signal;
|
||||
mod spawn;
|
||||
|
||||
pub use crate::generated::{ProcessId, ThreadId};
|
||||
pub use crate::generated::{
|
||||
ExecveOptions, ProcessId, Signal, SignalEntryData, SpawnOptions, ThreadId, ThreadSpawnOptions,
|
||||
};
|
||||
pub use exit::ExitCode;
|
||||
pub use signal::{Signal, SignalEntryData};
|
||||
pub use spawn::{ExecveOptions, SpawnOption, SpawnOptions, ThreadSpawnOptions};
|
||||
|
||||
/// Defines an optional argument for controlling process creation
|
||||
#[derive(Debug)]
|
||||
pub enum SpawnOption {
|
||||
/// Indicates a new process should inherit a file descriptor from its creator
|
||||
InheritFile {
|
||||
/// FD on the creator side
|
||||
source: RawFd,
|
||||
/// What FD number should be used in the child
|
||||
child: RawFd,
|
||||
},
|
||||
/// The new process should be placed in the specified group
|
||||
SetProcessGroup(ProcessId),
|
||||
/// Gain terminal control for the given FD
|
||||
GainTerminal(RawFd),
|
||||
}
|
||||
|
||||
/// Describes a single mutex operation
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -1,13 +0,0 @@
|
||||
use crate::arch::SavedFrame;
|
||||
|
||||
pub use crate::generated::Signal;
|
||||
|
||||
/// Data provided by the kernel to signal entry function
|
||||
#[derive(Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub struct SignalEntryData {
|
||||
/// Which signal was issued
|
||||
pub signal: Signal,
|
||||
/// Saved frame of the context that was interrupted
|
||||
pub frame: SavedFrame,
|
||||
}
|
@ -16,7 +16,6 @@ abi-lib = { path = "../abi-lib" }
|
||||
|
||||
[build-dependencies]
|
||||
abi-generator = { path = "../../tool/abi-generator" }
|
||||
yggdrasil-abi-def = { path = "../abi-def" }
|
||||
prettyplease = "0.2.15"
|
||||
cc = "*"
|
||||
|
||||
|
@ -11,6 +11,18 @@ fn add_file<'a>(build: &'a mut cc::Build, name: &'a str) -> &'a mut cc::Build {
|
||||
build.file(name)
|
||||
}
|
||||
|
||||
fn load_abi_definitions<P: AsRef<Path>>(path: P) -> String {
|
||||
let mut content = String::new();
|
||||
for file in fs::read_dir(path).unwrap() {
|
||||
let file = file.unwrap();
|
||||
if file.path().extension().map(|x| x == "abi").unwrap_or(false) {
|
||||
println!("cargo:rerun-if-changed={}", file.path().display());
|
||||
content.extend(fs::read_to_string(file.path()));
|
||||
}
|
||||
}
|
||||
content
|
||||
}
|
||||
|
||||
fn build_libm() {
|
||||
println!("cargo:rerun-if-changed=libm/private.h");
|
||||
|
||||
@ -38,18 +50,19 @@ fn build_libm() {
|
||||
build.compile("m");
|
||||
}
|
||||
|
||||
fn generate_abi() {
|
||||
fn generate_abi<P: AsRef<Path>>(abi_path: P) {
|
||||
let output_dir = std::env::var("OUT_DIR").expect("$OUT_DIR not set");
|
||||
let generated_calls = Path::new(&output_dir).join("generated_calls.rs");
|
||||
|
||||
let abi = load_abi_definitions(abi_path);
|
||||
let abi = AbiBuilder::from_string(
|
||||
yggdrasil_abi_def::ABI_FILE,
|
||||
&abi,
|
||||
TargetEnv {
|
||||
thin_pointer_width: TypeWidth::U64,
|
||||
fat_pointer_width: TypeWidth::U64,
|
||||
},
|
||||
)
|
||||
.unwrap_fancy(yggdrasil_abi_def::ABI_FILE);
|
||||
.unwrap_fancy(&abi);
|
||||
|
||||
let calls = prettyplease::unparse(
|
||||
&abi.emit_file(false, true)
|
||||
@ -61,5 +74,5 @@ fn generate_abi() {
|
||||
|
||||
fn main() {
|
||||
build_libm();
|
||||
generate_abi();
|
||||
generate_abi("../abi/def");
|
||||
}
|
||||
|
@ -13,12 +13,12 @@ mod generated {
|
||||
use abi::{
|
||||
error::Error,
|
||||
io::{
|
||||
ChannelPublisherId, FileMode, OpenOptions, PollControl, RawFd, TerminalOptions,
|
||||
TerminalSize,
|
||||
ChannelPublisherId, DirectoryEntry, FileAttr, FileMode, MountOptions, OpenOptions,
|
||||
PollControl, RawFd, TerminalOptions, TerminalSize, UnmountOptions,
|
||||
},
|
||||
mem::MappingSource,
|
||||
net::SocketType,
|
||||
process::{ProcessId, Signal},
|
||||
process::{ExecveOptions, ProcessId, Signal, SignalEntryData, SpawnOptions},
|
||||
SyscallFunction,
|
||||
};
|
||||
|
||||
|
@ -105,7 +105,9 @@ impl Type for ComplexType {
|
||||
} => {
|
||||
quote!(#alias #arguments)
|
||||
}
|
||||
Self::Struct { name, .. } => quote!(#name),
|
||||
Self::Struct {
|
||||
name, arguments, ..
|
||||
} => quote!(#name #arguments),
|
||||
Self::MaybeUninit(ty) => {
|
||||
let ty = ty.as_rust_type();
|
||||
quote!(core::mem::MaybeUninit<#ty>)
|
||||
|
@ -40,7 +40,7 @@ impl DocumentItemAttributes for BitfieldType {
|
||||
}
|
||||
|
||||
impl syn::parse::Parse for BitfieldDefaultValue {
|
||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||
fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
|
||||
let items = input.parse_terminated(syn::Ident::parse, Token![|])?;
|
||||
Ok(Self { items })
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ impl SpanHelper for Span {
|
||||
pub enum SyntaxError {
|
||||
UnhandledType(syn::Type),
|
||||
UndefinedIdentifier(syn::Ident),
|
||||
|
||||
UnexpectedAttributes(syn::Ident),
|
||||
PrimitiveReprRequired(syn::Ident),
|
||||
}
|
||||
|
||||
@ -59,9 +59,10 @@ impl From<SyntaxError> for ParseError {
|
||||
impl SyntaxError {
|
||||
pub fn span(&self) -> Span {
|
||||
match self {
|
||||
Self::UndefinedIdentifier(id) => id.span(),
|
||||
Self::UnhandledType(ty) => ty.span(),
|
||||
Self::PrimitiveReprRequired(id) => id.span(),
|
||||
Self::PrimitiveReprRequired(id)
|
||||
| Self::UnexpectedAttributes(id)
|
||||
| Self::UndefinedIdentifier(id) => id.span(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,6 +73,9 @@ impl SyntaxError {
|
||||
Self::PrimitiveReprRequired(id) => {
|
||||
format!("Primitive repr required in type definition, got '{}'", id)
|
||||
}
|
||||
Self::UnexpectedAttributes(id) => {
|
||||
format!("Unexpected attributes for type '{}'", id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,17 @@ fn process_type(t: &syn::Type, known_types: &TypeEnv) -> Result<Rc<ComplexType>,
|
||||
let ty = process_type(ty, known_types)?;
|
||||
Ok(Rc::new(ComplexType::MaybeUninit(ty)))
|
||||
}
|
||||
name if let Some((ty, _)) = known_types.lookup_local(name) => Ok(ty.clone()),
|
||||
name if let Some((ty, _)) = known_types.lookup_local(name) => match ty.as_ref() {
|
||||
ComplexType::Struct { name, kind, .. } => Ok(Rc::new(ComplexType::Struct {
|
||||
name: name.clone(),
|
||||
kind: *kind,
|
||||
arguments: segment.arguments.clone(),
|
||||
})),
|
||||
_ if !segment.arguments.is_empty() => Err(ParseError::syntax1(
|
||||
SyntaxError::UnexpectedAttributes(segment.ident.clone()),
|
||||
)),
|
||||
_ => Ok(ty.clone()),
|
||||
},
|
||||
name if let Some((ty, kind)) = known_types.lookup_extern(name) => {
|
||||
Ok(Rc::new(ComplexType::Extern {
|
||||
kind: *kind,
|
||||
|
@ -8,7 +8,7 @@ pub struct StructType {
|
||||
}
|
||||
|
||||
impl syn::parse::Parse for StructType {
|
||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||
fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
|
||||
let mut inner: syn::ItemStruct = input.parse()?;
|
||||
inner.vis = syn::Visibility::Public(syn::token::Pub(input.span()));
|
||||
Ok(Self { inner })
|
||||
|
6
userspace/Cargo.lock
generated
6
userspace/Cargo.lock
generated
@ -1091,13 +1091,8 @@ dependencies = [
|
||||
"bytemuck",
|
||||
"prettyplease",
|
||||
"serde",
|
||||
"yggdrasil-abi-def",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yggdrasil-abi-def"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "yggdrasil-rt"
|
||||
version = "0.1.0"
|
||||
@ -1107,7 +1102,6 @@ dependencies = [
|
||||
"cc",
|
||||
"prettyplease",
|
||||
"yggdrasil-abi",
|
||||
"yggdrasil-abi-def",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
Loading…
x
Reference in New Issue
Block a user