mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-09 13:26:48 +00:00
add derive procedural macro for pod
This commit is contained in:
parent
895e5c340b
commit
6e56458e52
10
src/Cargo.lock
generated
10
src/Cargo.lock
generated
@ -97,6 +97,15 @@ dependencies = [
|
||||
"x86_64",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kxos-frame-pod-derive"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kxos-pci"
|
||||
version = "0.1.0"
|
||||
@ -114,6 +123,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"kxos-frame",
|
||||
"kxos-frame-pod-derive",
|
||||
"kxos-pci",
|
||||
"kxos-virtio",
|
||||
"lazy_static",
|
||||
|
@ -17,6 +17,7 @@ members = [
|
||||
"kxos-pci",
|
||||
"kxos-virtio",
|
||||
"kxos-util",
|
||||
"kxos-frame-pod-derive",
|
||||
]
|
||||
|
||||
[package.metadata.bootloader]
|
||||
|
14
src/kxos-frame-pod-derive/Cargo.toml
Normal file
14
src/kxos-frame-pod-derive/Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "kxos-frame-pod-derive"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = "1.0"
|
||||
quote = "1.0"
|
||||
syn = "1.0.90"
|
49
src/kxos-frame-pod-derive/src/lib.rs
Normal file
49
src/kxos-frame-pod-derive/src/lib.rs
Normal file
@ -0,0 +1,49 @@
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Fields};
|
||||
|
||||
#[proc_macro_derive(Pod)]
|
||||
pub fn derive_pod(input_token: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let input = parse_macro_input!(input_token as DeriveInput);
|
||||
expand_derive_pod(input).into()
|
||||
}
|
||||
|
||||
fn expand_derive_pod(input: DeriveInput) -> TokenStream {
|
||||
let ident = input.ident;
|
||||
let fields = match input.data {
|
||||
Data::Struct(DataStruct { fields, .. }) => match fields {
|
||||
Fields::Named(fields_named) => fields_named.named,
|
||||
Fields::Unnamed(fields_unnamed) => fields_unnamed.unnamed,
|
||||
Fields::Unit => panic!("derive pod does not work for struct with unit field"),
|
||||
},
|
||||
// Panic on compilation time if one tries to derive pod for enum or union.
|
||||
// It may not be a good idea, but works now.
|
||||
_ => panic!("derive pod only works for struct now."),
|
||||
};
|
||||
|
||||
// deal with generics
|
||||
let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl();
|
||||
|
||||
let pod_where_predicates = fields
|
||||
.into_iter()
|
||||
.map(|field| {
|
||||
let field_ty = field.ty;
|
||||
quote! {
|
||||
#field_ty: ::kxos_frame::Pod
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// if where_clause is none, we should add a `where` word manually.
|
||||
if where_clause.is_none() {
|
||||
quote! {
|
||||
#[automatically_derived]
|
||||
unsafe impl #impl_generics ::kxos_frame::Pod #type_generics for #ident where #(#pod_where_predicates),* {}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
#[automatically_derived]
|
||||
unsafe impl #impl_generics ::kxos_frame::Pod #type_generics for #ident #where_clause, #(#pod_where_predicates),* {}
|
||||
}
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
kxos-frame = {path = "../kxos-frame"}
|
||||
kxos-frame-pod-derive = {path = "../kxos-frame-pod-derive"}
|
||||
kxos-pci = {path="../kxos-pci"}
|
||||
kxos-virtio = {path="../kxos-virtio"}
|
||||
|
||||
|
@ -20,6 +20,8 @@ mod memory;
|
||||
mod process;
|
||||
pub mod syscall;
|
||||
mod util;
|
||||
#[macro_use]
|
||||
extern crate kxos_frame_pod_derive;
|
||||
|
||||
pub fn init() {
|
||||
driver::init();
|
||||
|
@ -33,7 +33,7 @@ pub fn load_elf_to_vm_space<'a>(
|
||||
}
|
||||
|
||||
/// copy bytes from user space of current process. The bytes len is the len of dest.
|
||||
pub fn copy_bytes_from_user(src: Vaddr, dest: &mut [u8]) {
|
||||
pub fn read_bytes_from_user(src: Vaddr, dest: &mut [u8]) {
|
||||
let current = Process::current();
|
||||
let vm_space = current
|
||||
.vm_space()
|
||||
@ -42,7 +42,7 @@ pub fn copy_bytes_from_user(src: Vaddr, dest: &mut [u8]) {
|
||||
}
|
||||
|
||||
/// copy val (Plain of Data type) from user space of current process.
|
||||
pub fn copy_val_from_user<T: Pod>(src: Vaddr) -> T {
|
||||
pub fn read_val_from_user<T: Pod>(src: Vaddr) -> T {
|
||||
let current = Process::current();
|
||||
let vm_space = current
|
||||
.vm_space()
|
||||
@ -60,10 +60,10 @@ pub fn write_bytes_to_user(dest: Vaddr, src: &[u8]) {
|
||||
}
|
||||
|
||||
/// write val (Plain of Data type) to user space of current process.
|
||||
pub fn write_val_to_user<T: Pod>(dest: Vaddr, val: T) {
|
||||
pub fn write_val_to_user<T: Pod>(dest: Vaddr, val: &T) {
|
||||
let current = Process::current();
|
||||
let vm_space = current
|
||||
.vm_space()
|
||||
.expect("[Internal error]Current should have vm space to write val to user");
|
||||
vm_space.write_val(dest, &val).expect("write val failed");
|
||||
vm_space.write_val(dest, val).expect("write val failed");
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::{memory::copy_val_from_user, syscall::SYS_FUTEX};
|
||||
use crate::{memory::read_val_from_user, syscall::SYS_FUTEX};
|
||||
|
||||
use super::SyscallResult;
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
@ -340,7 +340,7 @@ impl FutexKey {
|
||||
pub fn load_val(&self) -> i32 {
|
||||
// FIXME: how to implement a atomic load?
|
||||
warn!("implement an atomic load");
|
||||
copy_val_from_user(self.0)
|
||||
read_val_from_user(self.0)
|
||||
}
|
||||
|
||||
pub fn addr(&self) -> Vaddr {
|
||||
|
@ -4,7 +4,7 @@ use alloc::ffi::CString;
|
||||
use kxos_frame::{debug, vm::Vaddr};
|
||||
|
||||
use crate::{
|
||||
memory::{copy_bytes_from_user, write_bytes_to_user},
|
||||
memory::{read_bytes_from_user, write_bytes_to_user},
|
||||
process::Process,
|
||||
syscall::SYS_READLINK,
|
||||
};
|
||||
@ -32,7 +32,7 @@ pub fn do_sys_readlink(filename_ptr: Vaddr, user_buf_ptr: Vaddr, user_buf_len: u
|
||||
|
||||
let mut filename_buffer = [0u8; MAX_FILENAME_LEN];
|
||||
let current = Process::current();
|
||||
copy_bytes_from_user(filename_ptr, &mut filename_buffer);
|
||||
read_bytes_from_user(filename_ptr, &mut filename_buffer);
|
||||
let filename = CStr::from_bytes_until_nul(&filename_buffer).expect("Invalid filename");
|
||||
debug!("filename = {:?}", filename);
|
||||
if filename == CString::new("/proc/self/exe").unwrap().as_c_str() {
|
||||
|
@ -5,10 +5,13 @@ use kxos_frame::{debug, vm::Vaddr};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use crate::{
|
||||
memory::write_bytes_to_user,
|
||||
memory::write_val_to_user,
|
||||
syscall::{SyscallResult, SYS_UNAME},
|
||||
};
|
||||
|
||||
// The values are used to fool glibc. Since glibc will check the version and os name
|
||||
// We don't use lazy static to generate a static UTS_NAME is because lazy static will create a new struct, which does not inherent the trait.å
|
||||
|
||||
lazy_static! {
|
||||
/// used to fool glibc
|
||||
static ref SYS_NAME: CString = CString::new("Linux").unwrap();
|
||||
@ -31,6 +34,7 @@ lazy_static! {
|
||||
|
||||
const UTS_FIELD_LEN: usize = 65;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Pod)]
|
||||
#[repr(C)]
|
||||
struct UtsName {
|
||||
sysname: [u8; UTS_FIELD_LEN],
|
||||
@ -71,11 +75,6 @@ pub fn do_sys_uname(old_uname_addr: Vaddr) -> usize {
|
||||
debug!("uts name size: {}", core::mem::size_of::<UtsName>());
|
||||
debug!("uts name align: {}", core::mem::align_of::<UtsName>());
|
||||
|
||||
write_bytes_to_user(old_uname_addr, &UTS_NAME.sysname);
|
||||
write_bytes_to_user(old_uname_addr + UTS_FIELD_LEN, &UTS_NAME.nodename);
|
||||
write_bytes_to_user(old_uname_addr + UTS_FIELD_LEN * 2, &UTS_NAME.release);
|
||||
write_bytes_to_user(old_uname_addr + UTS_FIELD_LEN * 3, &UTS_NAME.version);
|
||||
write_bytes_to_user(old_uname_addr + UTS_FIELD_LEN * 4, &UTS_NAME.machine);
|
||||
write_bytes_to_user(old_uname_addr + UTS_FIELD_LEN * 5, &UTS_NAME.domainname);
|
||||
write_val_to_user(old_uname_addr, &*UTS_NAME);
|
||||
0
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ pub fn sys_wait4(wait_pid: u64, exit_status_ptr: u64, wait_options: u64) -> Sysc
|
||||
let process_filter = ProcessFilter::from_wait_pid(wait_pid as _);
|
||||
let (return_pid, exit_code) = wait_child_exit(process_filter, wait_options);
|
||||
if return_pid != 0 && exit_status_ptr != 0 {
|
||||
write_val_to_user(exit_status_ptr as _, exit_code);
|
||||
write_val_to_user(exit_status_ptr as _, &exit_code);
|
||||
}
|
||||
|
||||
SyscallResult::Return(return_pid as _)
|
||||
|
@ -1,7 +1,7 @@
|
||||
use alloc::vec;
|
||||
use kxos_frame::{debug, info};
|
||||
|
||||
use crate::{memory::copy_bytes_from_user, syscall::SYS_WRITE};
|
||||
use crate::{memory::read_bytes_from_user, syscall::SYS_WRITE};
|
||||
|
||||
use super::SyscallResult;
|
||||
|
||||
@ -14,7 +14,7 @@ pub fn sys_write(fd: u64, user_buf_ptr: u64, user_buf_len: u64) -> SyscallResult
|
||||
|
||||
if fd == STDOUT || fd == STDERR {
|
||||
let mut buffer = vec![0u8; user_buf_len as usize];
|
||||
copy_bytes_from_user(user_buf_ptr as usize, &mut buffer);
|
||||
read_bytes_from_user(user_buf_ptr as usize, &mut buffer);
|
||||
let content = alloc::str::from_utf8(buffer.as_slice()).expect("Invalid content"); // TODO: print content
|
||||
if fd == STDOUT {
|
||||
info!("Message from user mode: {:?}", content);
|
||||
|
@ -2,7 +2,7 @@ use alloc::vec;
|
||||
use kxos_frame::{debug, info, vm::Vaddr};
|
||||
|
||||
use crate::{
|
||||
memory::{copy_bytes_from_user, copy_val_from_user},
|
||||
memory::{read_bytes_from_user, read_val_from_user},
|
||||
syscall::SYS_WRITEV,
|
||||
};
|
||||
|
||||
@ -10,6 +10,8 @@ use super::SyscallResult;
|
||||
|
||||
const IOVEC_MAX: usize = 256;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, Pod)]
|
||||
pub struct IoVec {
|
||||
base: Vaddr,
|
||||
len: usize,
|
||||
@ -27,12 +29,13 @@ pub fn do_sys_writev(fd: u64, io_vec_addr: Vaddr, io_vec_count: usize) -> usize
|
||||
debug!("io_vec_counter = 0x{:x}", io_vec_count);
|
||||
let mut write_len = 0;
|
||||
for i in 0..io_vec_count {
|
||||
let base = copy_val_from_user::<usize>(io_vec_addr + i * 8);
|
||||
let len = copy_val_from_user::<usize>(io_vec_addr + i * 8 + 8);
|
||||
let io_vec = read_val_from_user::<IoVec>(io_vec_addr + i * 8);
|
||||
let base = io_vec.base;
|
||||
let len = io_vec.len;
|
||||
debug!("base = 0x{:x}", base);
|
||||
debug!("len = {}", len);
|
||||
let mut buffer = vec![0u8; len];
|
||||
copy_bytes_from_user(base, &mut buffer);
|
||||
read_bytes_from_user(base, &mut buffer);
|
||||
let content = alloc::str::from_utf8(&buffer).unwrap();
|
||||
write_len += len;
|
||||
if fd == 1 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user