mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-27 19:33:23 +00:00
add safe wrapper to read union fields
This commit is contained in:
@ -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];
|
||||
|
@ -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
|
||||
});
|
||||
}
|
||||
|
@ -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<u64> for VmPerm {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: u64) -> Result<Self> {
|
||||
VmPerm::from_bits(value as u8).ok_or_else(|| Error::InvalidVmpermBits)
|
||||
VmPerm::from_bits(value as u8).ok_or(Error::InvalidVmpermBits)
|
||||
}
|
||||
}
|
||||
|
@ -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<Attribute>,
|
||||
) -> 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::<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 ::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<Attribute>,
|
||||
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! {
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user