diff --git a/src/Cargo.lock b/src/Cargo.lock index 3329c62a9..c98842a7f 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -144,6 +144,7 @@ dependencies = [ "jinux-frame", "jinux-pci", "jinux-rights-proc", + "jinux-util", "jinux-virtio", "lazy_static", "pod", diff --git a/src/framework/jinux-frame/src/trap/mod.rs b/src/framework/jinux-frame/src/trap/mod.rs index a1a803311..6643b4ea0 100644 --- a/src/framework/jinux-frame/src/trap/mod.rs +++ b/src/framework/jinux-frame/src/trap/mod.rs @@ -176,9 +176,7 @@ pub(crate) fn init() { // set gate type to 1110: 64 bit Interrupt Gate, Present bit to 1, DPL to Ring 0 let p_low = (((p >> 16) & 0xFFFF) << 48) | (p & 0xFFFF); let trap_entry_option: usize = 0b1000_1110_0000_0000; - let low = (trap_entry_option << 32) - | ((kcs.0 as usize) << 16) - | p_low; + let low = (trap_entry_option << 32) | ((kcs.0 as usize) << 16) | p_low; let high = p >> 32; unsafe { IDT.entries[i] = [low, high]; diff --git a/src/framework/jinux-frame/src/vm/offset.rs b/src/framework/jinux-frame/src/vm/offset.rs index 634716037..d89f970e9 100644 --- a/src/framework/jinux-frame/src/vm/offset.rs +++ b/src/framework/jinux-frame/src/vm/offset.rs @@ -33,3 +33,34 @@ macro_rules! offset_of { field_offset }); } + +/// Get the offset of a field within an object as a pointer. +/// +/// ```rust +/// #[repr(C)] +/// pub struct Foo { +/// first: u8, +/// second: u32, +/// } +/// let foo = &Foo {first: 0, second: 0}; +/// assert!(value_offset!(foo) == (0 as *const Foo)); +/// assert!(value_offset!(foo.first) == (0 as *const u8)); +/// assert!(value_offset!(foo.second) == (4 as *const u32)); +/// ``` +#[macro_export] +macro_rules! value_offset { + ($container:ident) => ({ + let container_addr = &*$container as *const _; + let offset = 0 as *const _; + let _: bool = offset == container_addr; + offset + }); + ($container:ident.$($field:ident).*) => ({ + let container_addr = &*$container as *const _; + // SAFETY: This is safe since we never access the field + let field_addr = unsafe {&($container.$($field).*)} as *const _; + let field_offset = (field_addr as usize- container_addr as usize) as *const _; + let _: bool = field_offset == field_addr; + field_offset + }); +} diff --git a/src/framework/jinux-frame/src/vm/space.rs b/src/framework/jinux-frame/src/vm/space.rs index f7bf77ce2..ff874bfa8 100644 --- a/src/framework/jinux-frame/src/vm/space.rs +++ b/src/framework/jinux-frame/src/vm/space.rs @@ -81,10 +81,7 @@ impl VmSpace { let page_size = (range.end - range.start) / PAGE_SIZE; let mut inner = self.memory_set.lock(); for i in 0..page_size { - let res = inner.unmap(start_va); - if res.is_err() { - return res; - } + inner.unmap(start_va)?; start_va += PAGE_SIZE; } Ok(()) @@ -224,6 +221,6 @@ impl TryFrom for VmPerm { type Error = Error; fn try_from(value: u64) -> Result { - VmPerm::from_bits(value as u8).ok_or_else(|| Error::InvalidVmpermBits) + VmPerm::from_bits(value as u8).ok_or(Error::InvalidVmpermBits) } } diff --git a/src/framework/pod-derive/src/lib.rs b/src/framework/pod-derive/src/lib.rs index 095d38232..a01bdbfa5 100644 --- a/src/framework/pod-derive/src/lib.rs +++ b/src/framework/pod-derive/src/lib.rs @@ -7,7 +7,10 @@ use proc_macro2::{Ident, TokenStream}; use quote::quote; -use syn::{parse_macro_input, Attribute, Data, DataStruct, DeriveInput, Fields, Generics}; +use syn::{ + parse_macro_input, Attribute, Data, DataEnum, DataStruct, DataUnion, DeriveInput, Fields, + Generics, +}; #[proc_macro_derive(Pod)] pub fn derive_pod(input_token: proc_macro::TokenStream) -> proc_macro::TokenStream { @@ -15,8 +18,8 @@ pub fn derive_pod(input_token: proc_macro::TokenStream) -> proc_macro::TokenStre expand_derive_pod(input).into() } -const ALLOWED_REPRS: [&'static str; 13] = [ - "C", "u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "usize", "isize", "u128", "i128", +const ALLOWED_REPRS: [&'static str; 11] = [ + "C", "u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "usize", "isize", ]; fn expand_derive_pod(input: DeriveInput) -> TokenStream { @@ -25,7 +28,8 @@ fn expand_derive_pod(input: DeriveInput) -> TokenStream { let generics = input.generics; match input.data { Data::Struct(data_struct) => impl_pod_for_struct(data_struct, generics, ident, attrs), - Data::Enum(..) | Data::Union(..) => impl_pod_for_enum_or_union(attrs, generics, ident), + Data::Union(data_union) => impl_pod_for_union(data_union, generics, ident, attrs), + Data::Enum(data_enum) => impl_pod_for_enum(data_enum, attrs, generics, ident), } } @@ -72,7 +76,45 @@ fn impl_pod_for_struct( } } -fn impl_pod_for_enum_or_union( +fn impl_pod_for_union( + data_union: DataUnion, + generics: Generics, + ident: Ident, + attrs: Vec, +) -> TokenStream { + if !has_valid_repr(attrs) { + panic!("{} has invalid repr to implement Pod", ident.to_string()); + } + let fields = data_union.fields.named; + // deal with generics + let (impl_generics, type_generics, where_clause) = generics.split_for_impl(); + + let pod_where_predicates = fields + .into_iter() + .map(|field| { + let field_ty = field.ty; + quote! { + #field_ty: ::pod::Pod + } + }) + .collect::>(); + + // if where_clause is none, we should add a `where` word manually. + if where_clause.is_none() { + quote! { + #[automatically_derived] + unsafe impl #impl_generics ::pod::Pod #type_generics for #ident where #(#pod_where_predicates),* {} + } + } else { + quote! { + #[automatically_derived] + unsafe impl #impl_generics ::pod::Pod #type_generics for #ident #where_clause, #(#pod_where_predicates),* {} + } + } +} + +fn impl_pod_for_enum( + data_enum: DataEnum, attrs: Vec, generics: Generics, ident: Ident, @@ -84,6 +126,13 @@ fn impl_pod_for_enum_or_union( ); } + // check variant + for variant in data_enum.variants { + if None == variant.discriminant { + panic!("Enum can only have fields like Variant=1"); + } + } + // deal with generics let (impl_generics, type_generics, where_clause) = generics.split_for_impl(); quote! { diff --git a/src/framework/pod/src/lib.rs b/src/framework/pod/src/lib.rs index 6c03a19c5..9d47df5d5 100644 --- a/src/framework/pod/src/lib.rs +++ b/src/framework/pod/src/lib.rs @@ -1,6 +1,6 @@ #![no_std] -use core::{fmt::Debug, mem::MaybeUninit}; +use core::mem::MaybeUninit; /// A marker trait for plain old data (POD). /// @@ -16,7 +16,7 @@ use core::{fmt::Debug, mem::MaybeUninit}; /// # Safety /// /// Marking a non-POD type as POD may cause undefined behaviors. -pub unsafe trait Pod: Copy + Sized + Debug { +pub unsafe trait Pod: Copy + Sized { /// Creates a new instance of Pod type that is filled with zeroes. fn new_zeroed() -> Self { // SAFETY. An all-zero value of `T: Pod` is always valid. @@ -35,7 +35,8 @@ pub unsafe trait Pod: Copy + Sized + Debug { /// Creates a new instance from the given bytes. fn from_bytes(bytes: &[u8]) -> Self { let mut new_self = Self::new_uninit(); - new_self.as_bytes_mut().copy_from_slice(bytes); + let copy_len = new_self.as_bytes().len(); + new_self.as_bytes_mut().copy_from_slice(&bytes[..copy_len]); new_self } diff --git a/src/services/libs/jinux-std/Cargo.toml b/src/services/libs/jinux-std/Cargo.toml index 138d83c33..236264732 100644 --- a/src/services/libs/jinux-std/Cargo.toml +++ b/src/services/libs/jinux-std/Cargo.toml @@ -14,6 +14,7 @@ jinux-virtio = {path="../../comps/jinux-virtio"} typeflags = {path="../typeflags"} typeflags-util = {path="../typeflags-util"} jinux-rights-proc = {path="../jinux-rights-proc"} +jinux-util = {path="../jinux-util"} # parse elf file xmas-elf = "0.8.0" diff --git a/src/services/libs/jinux-std/src/lib.rs b/src/services/libs/jinux-std/src/lib.rs index af17bb177..69cbc04f7 100644 --- a/src/services/libs/jinux-std/src/lib.rs +++ b/src/services/libs/jinux-std/src/lib.rs @@ -11,7 +11,10 @@ #![feature(const_option)] #![feature(extend_one)] -use crate::{prelude::*, user_apps::UserApp}; +use crate::{ + prelude::*, + user_apps::{get_busybox_app, UserApp}, +}; use jinux_frame::{info, println}; use process::Process; @@ -61,7 +64,12 @@ pub fn init_process() { process.pid() ); - for app in get_all_apps().into_iter().last() { + // FIXME: should be running this apps before we running shell? + println!(""); + println!("[kernel] Running test programs"); + println!(""); + // Run test apps + for app in get_all_apps().into_iter() { let UserApp { app_name, app_content, @@ -69,11 +77,20 @@ pub fn init_process() { envp, } = app; info!("[jinux-std/lib.rs] spwan {:?} process", app_name); - print!("\n"); - print!("BusyBox v1.35.0 built-in shell (ash)\n\n"); Process::spawn_user_process(app_name.clone(), app_content, argv, Vec::new()); } + // Run busybox ash + let UserApp { + app_name, + app_content, + argv, + envp, + } = get_busybox_app(); + println!(""); + println!("BusyBox v1.35.0 built-in shell (ash)\n"); + Process::spawn_user_process(app_name.clone(), app_content, argv, Vec::new()); + loop { // We don't have preemptive scheduler now. // The long running init process should yield its own execution to allow other tasks to go on. @@ -84,7 +101,6 @@ pub fn init_process() { /// first process never return pub fn run_first_process() -> ! { - // let elf_file_content = read_hello_world_content(); Process::spawn_kernel_process(init_process); unreachable!() } diff --git a/src/services/libs/jinux-std/src/process/signal/c_types.rs b/src/services/libs/jinux-std/src/process/signal/c_types.rs index 88fdadafe..91beecc37 100644 --- a/src/services/libs/jinux-std/src/process/signal/c_types.rs +++ b/src/services/libs/jinux-std/src/process/signal/c_types.rs @@ -1,13 +1,16 @@ #![allow(non_camel_case_types)] use core::mem; -use jinux_frame::cpu::GpRegs; +use jinux_frame::{cpu::GpRegs, offset_of}; +use jinux_util::{read_union_fields, union_read_ptr::UnionReadPtr}; -use crate::prelude::*; +use crate::{prelude::*, process::Pid}; -use super::sig_num::SigNum; +use super::{sig_num::SigNum, signals::user::Uid}; pub type sigset_t = u64; +// FIXME: this type should be put at suitable place +pub type clock_t = i64; #[derive(Debug, Clone, Copy, Pod)] #[repr(C)] @@ -18,7 +21,7 @@ pub struct sigaction_t { pub mask: sigset_t, } -#[derive(Debug, Clone, Copy, Pod)] +#[derive(Clone, Copy, Pod)] #[repr(C)] pub struct siginfo_t { pub si_signo: i32, @@ -27,20 +30,116 @@ pub struct siginfo_t { _padding: i32, /// siginfo_fields should be a union type ( See occlum definition ). But union type have unsafe interfaces. /// Here we use a simple byte array. - pub siginfo_fields: [u8; 128 - mem::size_of::() * 4], + siginfo_fields: siginfo_fields_t, } impl siginfo_t { pub fn new(num: SigNum, code: i32) -> Self { - let zero_fields = [0u8; 128 - mem::size_of::() * 4]; siginfo_t { si_signo: num.as_u8() as i32, si_errno: 0, si_code: code, _padding: 0, - siginfo_fields: zero_fields, + siginfo_fields: siginfo_fields_t::zero_fields(), } } + + pub fn set_si_addr(&mut self, si_addr: Vaddr) { + self.siginfo_fields.sigfault.addr = si_addr; + } + + pub fn si_addr(&self) -> Vaddr { + // let siginfo = *self; + read_union_fields!(self.siginfo_fields.sigfault.addr) + } +} + +#[derive(Clone, Copy, Pod)] +#[repr(C)] +union siginfo_fields_t { + bytes: [u8; 128 - mem::size_of::() * 4], + common: siginfo_common_t, + sigfault: siginfo_sigfault_t, +} + +impl siginfo_fields_t { + fn zero_fields() -> Self { + Self { + bytes: [0; 128 - mem::size_of::() * 4], + } + } +} + +#[derive(Clone, Copy, Pod)] +#[repr(C)] +union siginfo_common_t { + first: siginfo_common_first_t, + second: siginfo_common_second_t, +} + +#[derive(Clone, Copy, Pod)] +#[repr(C)] +union siginfo_common_first_t { + piduid: siginfo_piduid_t, + timer: siginfo_timer_t, +} + +#[derive(Clone, Copy, Pod)] +#[repr(C)] +struct siginfo_piduid_t { + pid: Pid, + uid: Uid, +} + +#[derive(Clone, Copy, Pod)] +#[repr(C)] +struct siginfo_timer_t { + timerid: i32, + overrun: i32, +} + +#[derive(Clone, Copy, Pod)] +#[repr(C)] +union siginfo_common_second_t { + value: sigval_t, + sigchild: siginfo_sigchild_t, +} + +#[derive(Clone, Copy, Pod)] +#[repr(C)] +pub union sigval_t { + sigval_int: i32, + sigval_ptr: Vaddr, //*mut c_void +} + +#[derive(Clone, Copy, Pod)] +#[repr(C)] +union siginfo_sigchild_t { + status: i32, + utime: clock_t, + stime: clock_t, +} + +#[derive(Clone, Copy, Pod)] +#[repr(C)] +struct siginfo_sigfault_t { + addr: Vaddr, //*const c_void + addr_lsb: i16, + first: siginfo_sigfault_first_t, +} + +#[derive(Clone, Copy, Pod)] +#[repr(C)] +union siginfo_sigfault_first_t { + addr_bnd: siginfo_addr_bnd_t, + pkey: u32, +} + +#[derive(Clone, Copy, Pod)] +#[repr(C)] +union siginfo_addr_bnd_t { + lower: Vaddr, // *const c_void + upper: Vaddr, // *const c_void, } #[derive(Clone, Copy, Debug, Pod)] diff --git a/src/services/libs/jinux-std/src/user_apps.rs b/src/services/libs/jinux-std/src/user_apps.rs index 5f0ac1bcb..b33c43f9b 100644 --- a/src/services/libs/jinux-std/src/user_apps.rs +++ b/src/services/libs/jinux-std/src/user_apps.rs @@ -56,6 +56,10 @@ pub fn get_all_apps() -> Vec { let signal_test = UserApp::new("/signal_test", read_signal_test_content()); res.push(signal_test); + res +} + +pub fn get_busybox_app() -> UserApp { // busybox let mut busybox = UserApp::new("/busybox", read_busybox_content()); // -l option means the busybox is running as logging shell @@ -74,9 +78,7 @@ pub fn get_all_apps() -> Vec { let envp = to_vec_cstring(&envp).unwrap(); busybox.set_argv(argv); busybox.set_envp(envp); - res.push(busybox); - - res + busybox } fn read_hello_world_content() -> &'static [u8] { diff --git a/src/services/libs/jinux-std/src/vm/vmo/options.rs b/src/services/libs/jinux-std/src/vm/vmo/options.rs index 2a2b567f3..17ccaed0b 100644 --- a/src/services/libs/jinux-std/src/vm/vmo/options.rs +++ b/src/services/libs/jinux-std/src/vm/vmo/options.rs @@ -18,7 +18,7 @@ use super::{Pager, Vmo, VmoFlags}; /// /// Creating a VMO as a _dynamic_ capability with full access rights: /// ``` -/// use kxo_std::vm::{PAGE_SIZE, VmoOptions}; +/// use jinux_std::vm::{PAGE_SIZE, VmoOptions}; /// /// let vmo = VmoOptions::new(PAGE_SIZE) /// .alloc() @@ -28,7 +28,7 @@ use super::{Pager, Vmo, VmoFlags}; /// Creating a VMO as a _static_ capability with all access rights: /// ``` /// use jinux_std::prelude::*; -/// use kxo_std::vm::{PAGE_SIZE, VmoOptions}; +/// use jinux_std::vm::{PAGE_SIZE, VmoOptions}; /// /// let vmo = VmoOptions::::new(PAGE_SIZE) /// .alloc() @@ -118,7 +118,7 @@ impl VmoOptions { /// A child VMO created from a parent VMO of _dynamic_ capability is also a /// _dynamic_ capability. /// ``` -/// use kxo_std::vm::{PAGE_SIZE, VmoOptions}; +/// use jinux_std::vm::{PAGE_SIZE, VmoOptions}; /// /// let parent_vmo = VmoOptions::new(PAGE_SIZE) /// .alloc() @@ -150,7 +150,7 @@ impl VmoOptions { /// right regardless of whether the parent is writable or not. /// /// ``` -/// use kxo_std::vm::{PAGE_SIZE, VmoOptions, VmoChildOptions}; +/// use jinux_std::vm::{PAGE_SIZE, VmoOptions, VmoChildOptions}; /// /// let parent_vmo = VmoOptions::new(PAGE_SIZE) /// .alloc() @@ -181,7 +181,7 @@ impl VmoOptions { /// Note that a slice VMO child and its parent cannot not be resizable. /// /// ```rust -/// use kxo_std::vm::{PAGE_SIZE, VmoOptions}; +/// use _std::vm::{PAGE_SIZE, VmoOptions}; /// /// let parent_vmo = VmoOptions::new(PAGE_SIZE) /// .alloc() diff --git a/src/services/libs/jinux-util/src/lib.rs b/src/services/libs/jinux-util/src/lib.rs index ccbcb5541..92e184141 100644 --- a/src/services/libs/jinux-util/src/lib.rs +++ b/src/services/libs/jinux-util/src/lib.rs @@ -3,3 +3,4 @@ #![forbid(unsafe_code)] pub mod frame_ptr; +pub mod union_read_ptr; diff --git a/src/services/libs/jinux-util/src/union_read_ptr.rs b/src/services/libs/jinux-util/src/union_read_ptr.rs new file mode 100644 index 000000000..2cf404a1b --- /dev/null +++ b/src/services/libs/jinux-util/src/union_read_ptr.rs @@ -0,0 +1,42 @@ +use core::marker::PhantomData; + +use pod::Pod; + +/// This ptr is designed to read union field safely. +/// Write to union field is safe operation. While reading union field is UB. +/// However, if this field is Pod, we can safely read that field. +pub struct UnionReadPtr<'a, T: Pod> { + bytes: &'a [u8], + marker: PhantomData<&'a mut T>, +} + +impl<'a, T: Pod> UnionReadPtr<'a, T> { + pub fn new(object: &'a T) -> Self { + let bytes = object.as_bytes(); + Self { + bytes, + marker: PhantomData, + } + } + + pub fn read_at(&self, offset: *const F) -> F { + let offset = offset as usize; + F::from_bytes(&self.bytes[offset..]) + } +} + +/// FIXME: This macro requires the first argument to be a `reference` of a Pod type. +/// This is because the value_offset macro requires +#[macro_export] +macro_rules! read_union_fields { + ($container:ident) => ({ + let offset = value_offset!($container); + let union_read_ptr = UnionReadPtr::new(&*$container); + union_read_ptr.read_at(offset) + }); + ($container:ident.$($field:ident).*) => ({ + let field_offset = jinux_frame::value_offset!($container.$($field).*); + let union_read_ptr = UnionReadPtr::new(&*$container); + union_read_ptr.read_at(field_offset) + }); +}