abi: fix incorrect u64 ABI in 32-bit archs
This commit is contained in:
parent
e8e2705384
commit
019e4ae43f
@ -78,6 +78,10 @@ impl Architecture for ArchitectureImpl {
|
||||
fn wait_for_interrupt() {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn halt() -> ! {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl KernelTableManager for KernelTableManagerImpl {
|
||||
|
@ -621,6 +621,7 @@ mod tests {
|
||||
};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use yggdrasil_abi::{
|
||||
error::Error,
|
||||
io::{DirectoryEntry, FileType, OpenOptions, SeekFrom},
|
||||
@ -859,49 +860,4 @@ mod tests {
|
||||
assert_eq!(file.tell().unwrap(), 9);
|
||||
assert_eq!(&buf[..7], b"l123456");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn char_device() {
|
||||
struct C;
|
||||
|
||||
impl FileReadiness for C {
|
||||
fn poll_read(&self, _cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl CharDevice for C {
|
||||
fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||
buf.fill(b'@');
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn is_writable(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
static DEV: C = C;
|
||||
|
||||
let node = Node::char(&DEV, NodeFlags::empty());
|
||||
let mut buf = [0; 512];
|
||||
|
||||
let err = node
|
||||
.open(OpenOptions::WRITE, AccessToken::test_authorized())
|
||||
.unwrap_err();
|
||||
assert_eq!(err, Error::ReadOnly);
|
||||
|
||||
let file = node
|
||||
.open(OpenOptions::READ, AccessToken::test_authorized())
|
||||
.unwrap();
|
||||
assert_eq!(file.tell().unwrap_err(), Error::InvalidOperation);
|
||||
assert_eq!(
|
||||
file.seek(SeekFrom::Start(10)).unwrap_err(),
|
||||
Error::InvalidOperation
|
||||
);
|
||||
assert_eq!(file.read(&mut buf).unwrap(), 512);
|
||||
assert_eq!(buf, [b'@'; 512]);
|
||||
|
||||
assert_eq!(file.write(b"1234").unwrap_err(), Error::ReadOnly);
|
||||
}
|
||||
}
|
||||
|
@ -566,7 +566,7 @@ mod tests {
|
||||
let l1 = fixed_symlink(f1.clone());
|
||||
let root = mdir([("l1", l1.clone())]);
|
||||
|
||||
let mut ioctx = IoContext::new(root.clone());
|
||||
let ioctx = IoContext::new(root.clone());
|
||||
|
||||
// No follow
|
||||
let node = ioctx.find(None, "/l1", false, true).unwrap();
|
||||
@ -626,7 +626,7 @@ mod tests {
|
||||
let root_d1 = mdir([("f1", root_d1_f1.clone())]);
|
||||
let root = mdir([("f1", root_f1.clone()), ("d1", root_d1.clone())]);
|
||||
|
||||
let mut ioctx = IoContext::new(root.clone());
|
||||
let ioctx = IoContext::new(root.clone());
|
||||
|
||||
// Ok paths
|
||||
let node = ioctx.find(None, Path::empty(), false, false).unwrap();
|
||||
|
@ -75,11 +75,14 @@ pub(crate) fn read(fd: RawFd, buffer: &mut [u8]) -> Result<usize, Error> {
|
||||
run_with_io(&process, |io| io.files.file(fd)?.read(buffer))
|
||||
}
|
||||
|
||||
pub(crate) fn seek(fd: RawFd, pos: SeekFrom) -> Result<u64, Error> {
|
||||
pub(crate) fn seek(fd: RawFd, pos: SeekFrom, output: &mut u64) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |io| io.files.file(fd)?.seek(pos))
|
||||
run_with_io(&process, |io| {
|
||||
*output = io.files.file(fd)?.seek(pos)?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn open_directory(at: Option<RawFd>, path: &str) -> Result<RawFd, Error> {
|
||||
|
@ -13,3 +13,6 @@ rustc-dep-of-std = [
|
||||
"core",
|
||||
"compiler_builtins/rustc-dep-of-std",
|
||||
]
|
||||
|
||||
[lints.rust]
|
||||
unexpected_cfgs = { level = "allow", check-cfg = ['cfg(rust_analyzer)'] }
|
||||
|
@ -20,8 +20,41 @@ macro_rules! numeric_impl {
|
||||
};
|
||||
}
|
||||
|
||||
numeric_impl!(u8, u16, u32, u64);
|
||||
numeric_impl!(i8, i16, i32, i64);
|
||||
numeric_impl!(u8, u16, u32);
|
||||
numeric_impl!(i8, i16, i32);
|
||||
|
||||
#[cfg(any(target_pointer_width = "64", rust_analyzer))]
|
||||
numeric_impl!(u64, i64);
|
||||
|
||||
#[cfg(any(target_pointer_width = "32", rust_analyzer))]
|
||||
impl crate::SyscallFatRegister for u64 {
|
||||
fn as_syscall_meta(&self) -> usize {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn as_syscall_data(&self) -> usize {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn from_syscall_registers(_meta: usize, _data: usize) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_pointer_width = "32", rust_analyzer))]
|
||||
impl crate::SyscallFatRegister for u32 {
|
||||
fn as_syscall_meta(&self) -> usize {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn as_syscall_data(&self) -> usize {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn from_syscall_registers(_meta: usize, _data: usize) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl ThinWrapped for () {}
|
||||
|
||||
|
@ -83,7 +83,7 @@ syscall open(at: Option<RawFd>, path: &str, opts: OpenOptions, mode: FileMode) -
|
||||
syscall close(fd: RawFd) -> Result<()>;
|
||||
syscall write(fd: RawFd, data: &[u8]) -> Result<usize>;
|
||||
syscall read(fd: RawFd, data: &mut [u8]) -> Result<usize>;
|
||||
syscall seek(fd: RawFd, pos: SeekFrom) -> Result<u64>;
|
||||
syscall seek(fd: RawFd, pos: SeekFrom, output: &mut u64) -> Result<()>;
|
||||
|
||||
syscall open_directory(at: Option<RawFd>, path: &str) -> Result<RawFd>;
|
||||
syscall read_directory_entries(fd: RawFd, entries: &mut [MaybeUninit<DirectoryEntry>]) -> Result<usize>;
|
||||
|
@ -2,7 +2,7 @@ use std::{collections::HashMap, path::Path, rc::Rc};
|
||||
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{quote, TokenStreamExt};
|
||||
use syn::{punctuated::Punctuated, spanned::Spanned, token, Ident, Token};
|
||||
use syn::{punctuated::Punctuated, spanned::Spanned, token, Token};
|
||||
|
||||
pub mod ty;
|
||||
|
||||
@ -367,15 +367,11 @@ impl GenerateTypeDefinition for EnumType {
|
||||
fn generate_transparent_struct(
|
||||
attributes: &Attributes,
|
||||
name: &syn::Ident,
|
||||
repr: &TypeRepr,
|
||||
is_thin: bool,
|
||||
env: &TargetEnv,
|
||||
abi_type: AbiPrimitive,
|
||||
) -> TokenStream {
|
||||
let TypeRepr(repr) = &repr;
|
||||
let real_repr = match repr.to_string().as_str() {
|
||||
"u31" => Ident::new("u32", repr.span()),
|
||||
"u63" => Ident::new("u64", repr.span()),
|
||||
_ => repr.clone(),
|
||||
};
|
||||
let is_thin = abi_type.width(env) <= env.thin_pointer_width;
|
||||
let real_repr = abi_type.as_rust_type();
|
||||
|
||||
let attributes = attributes.filtered(|attr| !attr.path().is_ident("default"));
|
||||
|
||||
@ -433,17 +429,11 @@ fn generate_transparent_struct(
|
||||
impl GenerateTypeDefinition for NewType {
|
||||
fn generate_type_definition(&self, abi_type: &ComplexType, env: &TargetEnv) -> TokenStream {
|
||||
let Self {
|
||||
attributes,
|
||||
name,
|
||||
repr,
|
||||
attributes, name, ..
|
||||
} = self;
|
||||
let abi_type = abi_type.as_primitive().unwrap();
|
||||
|
||||
generate_transparent_struct(
|
||||
attributes,
|
||||
name,
|
||||
repr,
|
||||
abi_type.width(env) < env.fat_pointer_width,
|
||||
)
|
||||
generate_transparent_struct(attributes, name, env, abi_type)
|
||||
}
|
||||
}
|
||||
|
||||
@ -452,21 +442,17 @@ impl GenerateTypeDefinition for BitfieldType {
|
||||
let Self {
|
||||
attributes,
|
||||
name,
|
||||
repr,
|
||||
fields,
|
||||
..
|
||||
} = self;
|
||||
let abi_type = abi_type.as_primitive().unwrap();
|
||||
|
||||
// Find default attribute, if any
|
||||
let default_attr: Option<Result<BitfieldDefaultValue, _>> = attributes
|
||||
.iter()
|
||||
.find_map(|attr| attr.path().is_ident("default").then_some(attr.parse_args()));
|
||||
|
||||
let base = generate_transparent_struct(
|
||||
attributes,
|
||||
name,
|
||||
repr,
|
||||
abi_type.width(env) < env.fat_pointer_width,
|
||||
);
|
||||
let base = generate_transparent_struct(attributes, name, env, abi_type);
|
||||
|
||||
let mut field_impls = TokenStream::new();
|
||||
for BitfieldTypeField {
|
||||
|
@ -46,6 +46,8 @@ impl ComplexType {
|
||||
pub fn as_primitive(&self) -> Option<AbiPrimitive> {
|
||||
if let Self::Simple(SimpleType::Primitive(ty)) = self {
|
||||
Some(*ty)
|
||||
} else if let Self::Simple(SimpleType::Transparent { inner, .. }) = self {
|
||||
Some(*inner)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -56,14 +58,17 @@ impl Type for ComplexType {
|
||||
fn width(&self, env: &TargetEnv) -> TypeWidth {
|
||||
match self {
|
||||
Self::Simple(ty) => ty.width(env),
|
||||
Self::Option(ty) | Self::Result(ty) => match ty.kind() {
|
||||
TypeKind::Other => ty.width(env).double(),
|
||||
Self::Option(ty) | Self::Result(ty) => match (ty.kind(), ty.width(env)) {
|
||||
// Some(val) -> val
|
||||
// None -> usize::MAX
|
||||
(_, TypeWidth::U31) => TypeWidth::U32,
|
||||
(TypeKind::Other, _) => ty.width(env).double(),
|
||||
// Some(&[1, 2, 3]) -> (ptr, len), where ptr and len are non-zero
|
||||
// None -> (null, 0)
|
||||
TypeKind::FatPointer => env.fat_pointer_width,
|
||||
(TypeKind::FatPointer, _) => env.fat_pointer_width,
|
||||
// Some(&x) -> ptr, where ptr is non-zero
|
||||
// None -> null
|
||||
TypeKind::ThinPointer => env.thin_pointer_width,
|
||||
(TypeKind::ThinPointer, _) => env.thin_pointer_width,
|
||||
},
|
||||
Self::Tuple(_) => TypeWidth::Unknown,
|
||||
Self::Extern { .. } => TypeWidth::Unknown,
|
||||
|
@ -100,6 +100,10 @@ mod tests {
|
||||
thin_pointer_width: TypeWidth::U64,
|
||||
fat_pointer_width: TypeWidth::U128,
|
||||
};
|
||||
const TARGET_32: TargetEnv = TargetEnv {
|
||||
thin_pointer_width: TypeWidth::U32,
|
||||
fat_pointer_width: TypeWidth::U64,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn type_width() {
|
||||
@ -152,6 +156,30 @@ mod tests {
|
||||
assert_eq!(quote!(&[u8]).to_string(), ty.as_rust_type().to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn u31_type() {
|
||||
let ty = SimpleType::Primitive(AbiPrimitive::U31);
|
||||
let option_ty = ComplexType::Option(Rc::new(ComplexType::Simple(ty.clone())));
|
||||
|
||||
assert_eq!(ty.width(&TARGET_32), TypeWidth::U31);
|
||||
assert_eq!(ty.width(&TARGET_64), TypeWidth::U31);
|
||||
assert_eq!(ty.width(&TARGET_32).double(), TypeWidth::U64);
|
||||
assert_eq!(ty.width(&TARGET_64).double(), TypeWidth::U64);
|
||||
|
||||
assert_eq!(option_ty.width(&TARGET_32), TypeWidth::U32);
|
||||
assert_eq!(option_ty.width(&TARGET_64), TypeWidth::U32);
|
||||
|
||||
let val = Ident::new("val0", Span::call_site());
|
||||
assert_eq!(
|
||||
ty.emit_to_syscall_arguments(&TARGET_64, &val).to_string(),
|
||||
quote!(val0 as usize).to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
ty.emit_to_syscall_arguments(&TARGET_32, &val).to_string(),
|
||||
quote!(val0 as usize).to_string()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn emit_to_syscall_arguments() {
|
||||
let ty = SimpleType::Reference {
|
||||
@ -160,10 +188,31 @@ mod tests {
|
||||
AbiPrimitive::U64,
|
||||
))),
|
||||
};
|
||||
|
||||
let val = Ident::new("val0", Span::call_site());
|
||||
assert_eq!(
|
||||
ty.emit_to_syscall_arguments(&TARGET_64, &val).to_string(),
|
||||
quote!((val0 as *const _).expose_addr()).to_string()
|
||||
quote!((val0 as *const u64).addr()).to_string()
|
||||
);
|
||||
|
||||
let val = Ident::new("val0", Span::call_site());
|
||||
assert_eq!(
|
||||
ty.emit_to_syscall_arguments(&TARGET_32, &val).to_string(),
|
||||
quote!((val0 as *const u64).addr()).to_string()
|
||||
);
|
||||
|
||||
let ty = SimpleType::Primitive(AbiPrimitive::U64);
|
||||
|
||||
let val = Ident::new("val0", Span::call_site());
|
||||
assert_eq!(
|
||||
ty.emit_to_syscall_arguments(&TARGET_64, &val).to_string(),
|
||||
quote!(val0 as usize).to_string()
|
||||
);
|
||||
|
||||
let val = Ident::new("val0", Span::call_site());
|
||||
assert_eq!(
|
||||
ty.emit_to_syscall_arguments(&TARGET_32, &val).to_string(),
|
||||
quote!(val0 as usize, (val0 >> 32) as usize).to_string()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ impl Type for AbiPrimitive {
|
||||
Self::USize => quote!(usize),
|
||||
Self::Bool => quote!(bool),
|
||||
|
||||
Self::U31 => todo!(),
|
||||
Self::U31 => quote!(u32),
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,7 +68,9 @@ impl Type for AbiPrimitive {
|
||||
match self {
|
||||
Self::USize => quote!(#value),
|
||||
Self::U128 => todo!("Emit to syscall for u128"),
|
||||
Self::U64 if env.thin_pointer_width == TypeWidth::U32 => todo!(),
|
||||
Self::U64 if env.thin_pointer_width == TypeWidth::U32 => {
|
||||
quote!(#value as usize, (#value >> 32) as usize)
|
||||
}
|
||||
_ => quote!(#value as usize),
|
||||
}
|
||||
}
|
||||
@ -82,7 +84,9 @@ impl Type for AbiPrimitive {
|
||||
match self {
|
||||
Self::Bool => (quote!(#args[#index] != 0), 1),
|
||||
Self::U128 => todo!("Emit from syscall for u128"),
|
||||
Self::U64 if env.thin_pointer_width == TypeWidth::U32 => todo!(),
|
||||
Self::U64 if env.thin_pointer_width == TypeWidth::U32 => {
|
||||
todo!();
|
||||
}
|
||||
_ => {
|
||||
let ty = self.as_rust_type();
|
||||
(quote!(#args[#index] as #ty), 1)
|
||||
|
@ -129,8 +129,10 @@ pub fn test_all(env: BuildEnv) -> Result<(), Error> {
|
||||
"kernel/driver/fs/memfs",
|
||||
"lib/abi",
|
||||
"kernel/libk",
|
||||
"kernel/libk-util",
|
||||
"kernel/libk/libk-util",
|
||||
"tool/abi-generator",
|
||||
] {
|
||||
log::info!("Run tests: {:?}", path);
|
||||
CargoBuilder::Host(env.verbose).run(env.workspace_root.join(path), "test")?;
|
||||
}
|
||||
Ok(())
|
||||
|
Loading…
x
Reference in New Issue
Block a user