add derive procedural macro for pod

This commit is contained in:
Jianfeng Jiang 2022-10-09 17:51:25 +08:00
parent 895e5c340b
commit 6e56458e52
13 changed files with 101 additions and 22 deletions

10
src/Cargo.lock generated
View File

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

View File

@ -17,6 +17,7 @@ members = [
"kxos-pci",
"kxos-virtio",
"kxos-util",
"kxos-frame-pod-derive",
]
[package.metadata.bootloader]

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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