diff --git a/Cargo.toml b/Cargo.toml index 52b72a2..8c16eab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "ofw" description = "basic interfacing with OpenFirmware (former IEEE standard 1275)" -version = "0.2.1" +version = "0.3.0" edition = "2021" authors = ["Niko Chow-Stuart "] repository = "https://git.gaycatgirl.sex/voremicrocomputers/vap_os/ofw" diff --git a/src/lib.rs b/src/lib.rs index c03024e..63f37f7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -88,28 +88,33 @@ pub struct ServiceResult<'a> { /// use ofw::{call, service_result, ServiceResult}; /// use ofw::arch::EntryFunction; /// let entry_fn: EntryFunction = unimplemented!("get the entry function from somewhere"); -/// // <# of args>, <# of rets> -/// let mut results: ServiceResult = service_result!(1, 1); /// // , , <# of args>, <# of rets>, -/// call!(entry_fn, results, ntstr!("test"), 1, 1, ntstr!("test")); -/// if results.success { -/// let test_result: i32 = results.rets[0]; +/// let (success, returns): (bool, [i32; 1]) = call!(entry_fn, ntstr!("test"), 1, 1, ntstr!("test")); +/// if success { +/// let test_result: i32 = returns[0]; /// } /// ``` #[macro_export] macro_rules! call { - ($entry_fn:expr, $results:expr, $service:expr, $nargs:expr, $nrets:expr, $($args:expr),*) => { - #[allow(unused_assignments)] + ($entry_fn:expr, $service:expr, $nargs:expr, $nrets:expr, $($args:expr),*) => { { - let mut i = 0; - $( - $results.buf[i] = $args.into(); - i += 1; - )* - let success: bool = $crate::ofw_call($entry_fn, $service, $nargs, $nrets, $results.buf); - $results.success = success; - $results.rets = &$results.buf[$nargs as usize..]; - }}; + let mut args_and_rets: [i32; $nargs as usize + $nrets as usize] = [0; $nargs as usize + $nrets as usize]; + let mut rets: [i32; $nrets as usize] = [0; $nrets as usize]; + let mut i = 0; + #[allow(unused_assignments)] + { + $( + args_and_rets[i] = $args.into(); + i += 1; + )* + } + let success: (bool, [i32; $nargs as usize + $nrets as usize]) = $crate::ofw_call($entry_fn, $service, $nargs, $nrets, args_and_rets); + for i in 0..$nrets as usize { + rets[i] = success.1[i + $nargs as usize]; + } + (success.0, rets) + } + }; } /// # call_method! @@ -124,28 +129,33 @@ macro_rules! call { /// // note the usage of the `method_service_result!` macro instead of `service_result!` /// // this is required as the `call_method!` macro requires a /// // slightly different ServiceResult struct configuration -/// // <# of args>, <# of rets> -/// let mut results: ServiceResult = method_service_result!(1, 1); /// // , , , <# of args>, <# of rets>, -/// call_method!(entry_fn, results, package_instance, ntstr!("seek"), 2, 1, 0, 0); -/// if results.success { -/// let seek_result: i32 = results.rets[0]; +/// let (success, returns): (bool, [i32; 1]) = call_method!(entry_fn, package_instance, ntstr!("seek"), 2, 1, 0, 0); +/// if success { +/// let seek_result: i32 = returns[0]; /// } /// ``` #[macro_export] macro_rules! call_method { - ($entry_fn:expr, $package_instance:expr, $results:expr, $service:expr, $nargs:expr, $nrets:expr, $($args:expr),*) => { - #[allow(unused_assignments)] + ($entry_fn:expr, $package_instance:expr, $service:expr, $nargs:expr, $nrets:expr, $($args:expr),*) => { { - let mut i = 0; - $( - $results.buf[i] = $args.into(); - i += 1; - )* - let success: bool = $crate::ofw_call_method($entry_fn, $package_instance, $service, $nargs, $nrets, $results.buf); - $results.success = success && $results.buf[$nargs as usize] != 0; - $results.rets = &$results.buf[$nargs as usize + 1..]; - }}; + let mut args_and_rets: [i32; $nargs as usize + $nrets as usize + 1] = [0; $nargs as usize + $nrets as usize + 1]; + let mut rets: [i32; $nrets as usize] = [0; $nrets as usize]; + let mut i = 0; + #[allow(unused_assignments)] + { + $( + args_and_rets[i] = $args.into(); + i += 1; + )* + } + let success: (bool, [i32; $nargs as usize + $nrets as usize + 1]) = $crate::ofw_call_method($entry_fn, $package_instance, $service, $nargs, $nrets, args_and_rets); + for i in 0..$nrets as usize { + rets[i] = success.1[i + $nargs as usize + 1]; + } + (success.0 && success.1[$nargs as usize] != 0, rets) + } + }; } /// # service_result! @@ -180,15 +190,15 @@ macro_rules! method_service_result { /// use ofw::arch::EntryFunction; /// use ofw::{ntstr, ofw_call}; /// let entry_fn: EntryFunction = unimplemented!("get the entry function from somewhere"); -/// let mut args: [i32; 2] = [ntstr!("test") as i32, 0]; -/// let was_service_successfully_called: bool = ofw_call(entry_fn, ntstr!("test"), 1, 1, &mut args); +/// let args: [i32; 2] = [ntstr!("test") as i32, 0]; +/// let (was_service_successfully_called, args): (bool, [i32; 2]) = ofw_call(entry_fn, ntstr!("test"), 1, 1, args); /// let test_result: i32 = args[1]; /// ``` -pub fn ofw_call(entry_fn: EntryFunction, service: NTSTR, num_args: i32, num_rets: i32, args_and_rets: &mut [i32]) -> bool { +pub fn ofw_call(entry_fn: EntryFunction, service: NTSTR, num_args: i32, num_rets: i32, args_and_rets: T) -> (bool, T) { #[repr(C)] - struct GenericArgs { + struct GenericArgs { args: Args, - buffer: *mut i32, + buffer: U, } let mut generic_args = GenericArgs { args: Args { @@ -196,24 +206,21 @@ pub fn ofw_call(entry_fn: EntryFunction, service: NTSTR, num_args: i32, num_rets nrets: num_rets, nargs: num_args, }, - buffer: args_and_rets.as_mut_ptr(), + buffer: args_and_rets, }; let result: bool; - // note: i cannot figure out why we must match against !OFW_TRUE instead of OFW_TRUE, - // i haven't found anything in either the ieee 1275 doc or the ppc extension saying that - // this is the case, but it is #[cfg(target_arch = "powerpc")] { - result = entry_fn(&mut generic_args as *mut _ as *mut Args) != OFW_TRUE; + result = entry_fn(&mut generic_args as *mut _ as *mut Args) != -1; } #[cfg(target_arch = "x86_64")] { - result = entry_fn(&mut generic_args as *mut _ as *mut Args) != OFW_TRUE; + result = entry_fn(&mut generic_args as *mut _ as *mut Args) != -1; } - result + (result, generic_args.buffer) } /// # ofw_call_method @@ -231,20 +238,20 @@ pub fn ofw_call(entry_fn: EntryFunction, service: NTSTR, num_args: i32, num_rets /// let entry_fn: EntryFunction = unimplemented!("get the entry function from somewhere"); /// let instance: IHandle = unimplemented!("get the package instance from somewhere"); /// // addr_hi, addr_lo, catch-result, okay? -/// let mut args: [i32; 4] = [0, 0, 0, 0]; +/// let args: [i32; 4] = [0, 0, 0, 0]; /// // note that num_args and num_rets are not the same as the length of args, this is intentional -/// let was_service_successfully_called: bool = ofw_call_method(entry_fn, instance, ntstr!("seek"), 2, 1, &mut args); +/// let (was_service_successfully_called, args): (bool, [i32; 4]) = ofw_call_method(entry_fn, instance, ntstr!("seek"), 2, 1, args); /// if was_service_successfully_called && args[2] != 0 { /// let seek_result: i32 = args[3]; /// } /// ``` -pub fn ofw_call_method(entry_fn: EntryFunction, ihandle: IHandle, method: NTSTR, num_args: i32, num_rets: i32, args_and_rets: &mut [i32]) -> bool { +pub fn ofw_call_method(entry_fn: EntryFunction, ihandle: IHandle, method: NTSTR, num_args: i32, num_rets: i32, args_and_rets: T) -> (bool, T) { #[repr(C)] - struct CallMethodArgs { + struct CallMethodArgs { args: Args, method: NTSTR, ihandle: IHandle, - buffer: *mut i32, + buffer: U, } let mut call_method_args = CallMethodArgs { @@ -255,7 +262,7 @@ pub fn ofw_call_method(entry_fn: EntryFunction, ihandle: IHandle, method: NTSTR, }, method, ihandle, - buffer: args_and_rets.as_mut_ptr(), + buffer: args_and_rets, }; let result: bool; @@ -269,5 +276,5 @@ pub fn ofw_call_method(entry_fn: EntryFunction, ihandle: IHandle, method: NTSTR, result = entry_fn(&mut call_method_args as *mut _ as *mut Args) != OFW_TRUE; } - result + (result, call_method_args.buffer) } \ No newline at end of file diff --git a/src/tests.rs b/src/tests.rs index 7185696..4fcddab 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,5 +1,5 @@ use crate::arch::EntryFunction; -use crate::{Args, call, call_method, IHandle, method_service_result, ntstr, OFW_FALSE, OFW_TRUE, service_result}; +use crate::{Args, call, call_method, IHandle, ntstr, ofw_call, OFW_FALSE, OFW_TRUE}; use crate::cell_conv::DoubleWord; use crate::ntstr::NTSTR; @@ -26,46 +26,43 @@ fn call_ofw() { #[repr(C)] struct GenericArgs { args: Args, - buffer: *mut i32, + buffer: [i32; 2], } let args = unsafe { &mut *(args as *mut GenericArgs) }; assert_eq!(args.args.service, ntstr!("test")); assert_eq!(args.args.nargs, 1); assert_eq!(args.args.nrets, 1); - // 1 offset from args in buffer - unsafe { *(args.buffer.offset(1)) = OFW_FALSE }; // set "missing" to false - OFW_TRUE + args.buffer[1] = OFW_FALSE; // not missing + 0 } let entry_fn: EntryFunction = test_entry_function; - let mut results = service_result!(1,1); - call!(entry_fn, results, ntstr!("test"), 1, 1, ntstr!("test")); - assert!(results.success); - assert_eq!(results.rets[0], OFW_FALSE); + let (success, results) = call!(entry_fn, ntstr!("test"), 1, 1, ntstr!("test")); + assert!(success); + assert_eq!(results[0], 0); } + #[test] fn call_ofw_missing() { pub extern "C" fn test_entry_function(args: *mut Args) -> i32 { #[repr(C)] struct GenericArgs { args: Args, - buffer: *mut i32, + buffer: [i32; 2], } let args = unsafe { &mut *(args as *mut GenericArgs) }; assert_eq!(args.args.service, ntstr!("test")); assert_eq!(args.args.nargs, 1); assert_eq!(args.args.nrets, 1); - // 1 offset from args in buffer - unsafe { *(args.buffer.offset(1)) = OFW_TRUE }; // set "missing" to true - OFW_TRUE + args.buffer[1] = OFW_TRUE; // missing + 0 } let entry_fn: EntryFunction = test_entry_function; - let mut results = service_result!(1,1); - call!(entry_fn, results, ntstr!("test"), 1, 1, ntstr!("aioshjfoahwfi")); - assert!(results.success); - assert_eq!(results.rets[0], OFW_TRUE); + let (success, results) = call!(entry_fn, ntstr!("test"), 1, 1, ntstr!("aioshjfoahwfi")); + assert!(success); + assert_eq!(results[0], OFW_TRUE); } #[test] @@ -73,20 +70,18 @@ fn call_ofw_failure() { pub extern "C" fn test_entry_function(args: *mut Args) -> i32 { #[repr(C)] struct GenericArgs { - args: Args, - buffer: *mut i32, + args: Args } let args = unsafe { &mut *(args as *mut GenericArgs) }; assert_eq!(args.args.service, ntstr!("this-method-does-not-exist")); assert_eq!(args.args.nargs, 1); assert_eq!(args.args.nrets, 1); - OFW_FALSE + -1 } let entry_fn: EntryFunction = test_entry_function; - let mut results = service_result!(1,1); - call!(entry_fn, results, ntstr!("this-method-does-not-exist"), 1, 1, ntstr!("aioshjfoahwfi")); - assert!(!results.success); + let (success, _) = call!(entry_fn, ntstr!("this-method-does-not-exist"), 1, 1, ntstr!("aioshjfoahwfi")); + assert!(!success); } #[test] @@ -97,7 +92,7 @@ fn call_method_ofw() { args: Args, method: NTSTR, ihandle: IHandle, - buffer: *mut i32, + buffer: [i32; 4], } let args = unsafe { &mut *(args as *mut CallMethodArgs) }; assert_eq!(args.args.service, ntstr!("call-method")); @@ -106,17 +101,16 @@ fn call_method_ofw() { assert_eq!(args.args.nargs, 2 + 2); assert_eq!(args.args.nrets, 1 + 1); // 2 offset from args in buffer - unsafe { *(args.buffer.offset(2)) = 1 }; // set catch-result to non-zero - unsafe { *(args.buffer.offset(2 + 1)) = OFW_TRUE }; // set okay? to true - OFW_TRUE + args.buffer[2] = 1; // set catch-result to non-zero + args.buffer[2 + 1] = OFW_TRUE; // set okay? to true + 0 } let entry_fn: EntryFunction = test_entry_function; let ih: IHandle = 0; - let mut results = method_service_result!(2,1); - call_method!(entry_fn, ih, results, ntstr!("seek"), 2, 1, 0, 0); - assert!(results.success); - assert_eq!(results.rets[0], OFW_TRUE); + let (success, returns) = call_method!(entry_fn, ih, ntstr!("seek"), 2, 1, 0, 0); + assert!(success); + assert_eq!(returns[0], OFW_TRUE); } #[test] @@ -127,7 +121,7 @@ fn call_method_ofw_seek_failure() { args: Args, method: NTSTR, ihandle: IHandle, - buffer: *mut i32, + buffer: [i32; 4], } let args = unsafe { &mut *(args as *mut CallMethodArgs) }; assert_eq!(args.args.service, ntstr!("call-method")); @@ -136,17 +130,16 @@ fn call_method_ofw_seek_failure() { assert_eq!(args.args.nargs, 2 + 2); assert_eq!(args.args.nrets, 1 + 1); // 2 offset from args in buffer - unsafe { *(args.buffer.offset(2)) = 1 }; // set catch-result to non-zero - unsafe { *(args.buffer.offset(2 + 1)) = OFW_FALSE }; // set okay? to false - OFW_TRUE + args.buffer[2] = 1; // set catch-result to non-zero + args.buffer[2 + 1] = OFW_FALSE; // set okay? to false + 0 } let entry_fn: EntryFunction = test_entry_function; let ih: IHandle = 0; - let mut results = method_service_result!(2,1); - call_method!(entry_fn, ih, results, ntstr!("seek"), 2, 1, 0, 0); - assert!(results.success); - assert_eq!(results.rets[0], OFW_FALSE); + let (success, returns) = call_method!(entry_fn, ih, ntstr!("seek"), 2, 1, 0, 0); + assert!(success); + assert_eq!(returns[0], OFW_FALSE); } #[test] @@ -157,7 +150,7 @@ fn call_method_ofw_failure() { args: Args, method: NTSTR, ihandle: IHandle, - buffer: *mut i32, + buffer: [i32; 4], } let args = unsafe { &mut *(args as *mut CallMethodArgs) }; assert_eq!(args.args.service, ntstr!("call-method")); @@ -166,13 +159,12 @@ fn call_method_ofw_failure() { assert_eq!(args.args.nargs, 2 + 2); assert_eq!(args.args.nrets, 1 + 1); // 2 offset from args in buffer - unsafe { *(args.buffer.offset(2)) = 0 }; // set catch-result to 0 (caught error, package doesn't have this method) - OFW_TRUE + args.buffer[2] = 0; // set catch-result to 0 (caught error, package doesn't have this method) + 0 } let entry_fn: EntryFunction = test_entry_function; let ih: IHandle = 0; - let mut results = method_service_result!(2,1); - call_method!(entry_fn, ih, results, ntstr!("asiofhawoptgh"), 2, 1, 0, 0); - assert!(!results.success); + let (success, _) = call_method!(entry_fn, ih, ntstr!("asiofhawoptgh"), 2, 1, 0, 0); + assert!(!success); } \ No newline at end of file