Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] [POC] Proc macro for handling system call ABI #12

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ documentation = "https://docs.rs/redox_syscall"

[lib]
name = "syscall"

[dependencies]
redox_syscall_derive = { path = "syscall-derive" }
7 changes: 7 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@
#![feature(asm)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(attr_literals)]
#![no_std]

#[macro_use]
extern crate redox_syscall_derive;

pub use self::arch::*;
pub use self::call::*;
pub use self::data::*;
Expand All @@ -12,6 +16,7 @@ pub use self::flag::*;
pub use self::io::*;
pub use self::number::*;
pub use self::scheme::*;
pub use self::syscall::*;

#[cfg(target_arch = "arm")]
#[path="arch/arm.rs"]
Expand Down Expand Up @@ -45,3 +50,5 @@ pub mod number;

/// A trait useful for scheme handlers
pub mod scheme;

mod syscall;
111 changes: 111 additions & 0 deletions src/syscall.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
pub trait SyscallMem {
unsafe fn to_slice<'a, T>(ptr: usize, len: usize) -> &'a [T];
unsafe fn to_slice_mut<'a, T>(ptr: usize, len: usize) -> &'a mut [T];
}

#[derive(Syscall, Debug)]
#[allow(non_camel_case_types)]
pub enum Syscall<'a> {
#[number = 45]
brk(usize),
#[number = 12]
chdir(&'a [u8]),
#[number = 0x1000_000f]
chmod(&'a [u8], usize),
#[number = 120]
clone(usize),
#[number = 0x2000_0006]
close(usize),
//#[number = 265] FIXME
//clock_gettime(usize, &'a mut TimeSpec)
#[number = 0x2010_0029]
dup(usize, &'a [u8]),
#[number = 0x2010_003f]
dup2(usize, usize, &'a [u8]),
#[number = 11]
execve(&'a [u8], &'a [[usize; 2]]),
#[number = 1]
exit(usize),
#[number = 0x2000_0037]
fcntl(usize, usize, usize),
#[number = 0x2000_039f]
fevent(usize, usize),
#[number = 0x2000_005a]
fmap(usize, usize, usize),
#[number = 0x2000_005b]
funmap(usize),
#[number = 0x2200_03a0]
fpath(usize, &'a mut [u8]),
//#[number = 0x2200_001c] FIXME
//fstat(usize, &'a mut Stat),
//#[number = 0x2200_0064] FIXME
//fstatvfs(usize, &'a mut StatVfs),
#[number = 0x2000_0076]
fsync(usize),
#[number = 0x2000_005d]
ftruncate(usize, usize),
#[number = 240]
futex(*mut i32, usize, i32, usize, *mut i32), // XXX Raw pointer?
#[number = 183]
getcwd(&'a mut [u8]),
#[number = 202]
getegid(),
#[number = 951]
getens(),
#[number = 201]
geteuid(),
#[number = 200]
getgid(),
#[number = 950]
getns(),
#[number = 20]
getpid(),
#[number = 64]
getppid(),
#[number = 199]
getuid(),
#[number = 110]
iopl(usize),
#[number = 37]
kill(usize, usize),
#[number = 0x1300_0009]
link(*const u8, *const u8),
#[number = 0x2000_0013]
lseek(usize, isize, usize),
#[number = 984]
mkns(&'a [[usize; 2]]),
//#[number = 162] FIXME
//nanosleep(&'a TimeSpec, &'a mut TimeSpec),
#[number = 0x1010_0005]
open(&'a [u8], usize),
#[number = 945]
physalloc(usize),
#[number = 946]
physfree(usize, usize),
#[number = 947]
physmap(usize, usize, usize),
#[number = 948]
physunmap(usize),
//#[number = 331] FIXME
//pipe2(&'a mut [usize; 2], usize),
#[number = 0x2200_0003]
read(usize, &'a mut [u8]),
#[number = 0x1000_0054]
rmdir(&'a [u8]),
#[number = 204]
setregid(usize, usize),
#[number = 952]
setrens(usize, usize),
#[number = 203]
setreuid(usize, usize),
#[number = 0x1000_000a]
unlink(&'a [u8]),
#[number = 949]
virttophys(usize),
//#[number = 7] FIXME
//waitpid(usize, &'a mut usize, usize),
#[number = 0x2100_0004]
write(usize, &'a [u8]),
#[number = 158]
sched_yield(),
}
10 changes: 10 additions & 0 deletions syscall-derive/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "redox_syscall_derive"
version = "0.1.0"

[lib]
proc-macro = true

[dependencies]
syn = "0.11"
quote = "0.3"
125 changes: 125 additions & 0 deletions syscall-derive/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#![feature(box_patterns)]

extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;

use syn::{Ty, MutTy, Mutability, MetaItem, Ident, Lit};
use proc_macro::TokenStream;

fn num_to_ident(num: usize) -> quote::Ident {
quote::Ident::from((('a' as u8 + num as u8) as char).to_string())
}

fn impl_syscall(ast: &syn::DeriveInput) -> quote::Tokens {
let variants = match ast.body {
syn::Body::Enum(ref v) => v,
_ => panic!("Must be enum")
};

let enum_name = &ast.ident;
let mut name_arms = Vec::new();
let mut to_arms = Vec::new();
let mut from_arms = Vec::new();

let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
for variant in variants {
let mut number = None;
for attr in variant.attrs.iter() {
if let &MetaItem::NameValue(ref ident, ref value) = &attr.value {
if *ident == Ident::from("number") {
number = match *value {
Lit::Int(value, _) => Some(value as usize),
_ => panic!("Type not supported by 'number' attribute")
};
}
}
}
let number = number.expect("number attribute is mandatory");
let name = &variant.ident;
let fields = match variant.data {
syn::VariantData::Tuple(ref fields) => fields,
_ => panic!("Only tuple variants allowed")
};

let mut call = Vec::new();
call.push(quote!(#number));
let mut field_names = Vec::new();
let mut from_names = Vec::new();

let mut from_num = 1;
for (idx, field) in fields.iter().enumerate() {
let name = num_to_ident(idx);
// For slices, push pointer and length
if let Ty::Rptr(_, box MutTy { ty: Ty::Slice(..), mutability }) = field.ty {
call.push(match mutability {
Mutability::Mutable => quote!(#name.as_mut_ptr() as usize),
Mutability::Immutable => quote!(#name.as_ptr() as usize)
});
call.push(quote!(#name.len() as usize));
field_names.push(match mutability {
Mutability::Mutable => quote!(ref mut #name),
Mutability::Immutable => quote!(ref #name)
});
let from1 = num_to_ident(from_num);
let from2 = num_to_ident(from_num + 1);
from_names.push(match mutability {
Mutability::Mutable => quote!(T::to_slice_mut(#from1, #from2)),
Mutability::Immutable => quote!(T::to_slice(#from1, #from2))
});
from_num += 1;
} else {
call.push(quote!(#name as usize));
field_names.push(quote!(#name));
let from = num_to_ident(from_num);
from_names.push(quote!(#from as _));
}
from_num += 1;
}

if call.len() > 6 {
panic!("Variant {} results in more than 6 values", name);
} else {
while call.len() < 6 {
call.push(quote!(0));
}
}

name_arms.push(quote!{ #enum_name::#name(..) => stringify!(#name) });
to_arms.push(quote!{ #enum_name::#name(#(#field_names),*) => (#(#call),*) });
from_arms.push(quote!{ #number => #enum_name::#name(#(#from_names),*) });
}

from_arms.push(quote!{ _ => unreachable!() });

quote! {
impl #impl_generics #enum_name #ty_generics #where_clause {
pub fn name(&self) -> &'static str {
match *self {
#(#name_arms),*
}
}

pub fn to_call(&mut self) -> (usize, usize, usize, usize, usize, usize) {
match *self {
#(#to_arms),*
}
}

pub unsafe fn from_call<T: SyscallMem>(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> Self {
match a {
#(#from_arms),*
}
}
}
}
}

#[proc_macro_derive(Syscall, attributes(number))]
pub fn syscall(input: TokenStream) -> TokenStream {
let s = input.to_string();
let ast = syn::parse_derive_input(&s).unwrap();
let gen = impl_syscall(&ast);
gen.parse().unwrap()
}