abi: fix incorrect u64 ABI in 32-bit archs

This commit is contained in:
Mark Poliakov 2024-10-11 17:24:20 +03:00
parent e8e2705384
commit 019e4ae43f
12 changed files with 131 additions and 86 deletions

View File

@ -78,6 +78,10 @@ impl Architecture for ArchitectureImpl {
fn wait_for_interrupt() {
unimplemented!()
}
fn halt() -> ! {
unimplemented!()
}
}
impl KernelTableManager for KernelTableManagerImpl {

View File

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

View File

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

View File

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

View File

@ -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)'] }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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