initial implementations for call and call-method
This commit is contained in:
parent
cf89db1b52
commit
2604f47bec
7 changed files with 578 additions and 0 deletions
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
/target
|
||||||
|
/Cargo.lock
|
||||||
|
|
||||||
|
# as its usage is encouraged for testing architecture-specific code, do not include the .cargo directory
|
||||||
|
/.cargo
|
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
name = "ofw"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
16
examples/client_ppc.rs
Normal file
16
examples/client_ppc.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
use ofw::arch::EntryFunction;
|
||||||
|
use ofw::{call, service_result, ntstr, OFW_TRUE};
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
#[link_section = ".text"]
|
||||||
|
extern "C" fn _start(_r3: u32, _r4: u32, entry: EntryFunction) -> isize {
|
||||||
|
let mut results = service_result!(1,1);
|
||||||
|
call!(entry, results, ntstr!("test"), 1, 1, ntstr!("test"));
|
||||||
|
if results.success {
|
||||||
|
let _missing: bool = results.rets[0] == OFW_TRUE;
|
||||||
|
}
|
||||||
|
0
|
||||||
|
}
|
20
src/arch/mod.rs
Normal file
20
src/arch/mod.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// # Note to developers:
|
||||||
|
// architecture-specific code may be tested via the usage of a filein the following
|
||||||
|
// path: `/.cargo/config`. (where `/` is the root of the project)
|
||||||
|
// the file should contain the following:
|
||||||
|
// ```
|
||||||
|
// [build]
|
||||||
|
// # for powerpc
|
||||||
|
// target = "powerpc-unknown-linux-gnu"
|
||||||
|
// ```
|
||||||
|
|
||||||
|
use crate::Args;
|
||||||
|
|
||||||
|
/// # PowerPC
|
||||||
|
#[cfg(target_arch = "powerpc")]
|
||||||
|
pub type EntryFunction = extern "C" fn (*mut Args) -> i32;
|
||||||
|
|
||||||
|
/// # x86_64
|
||||||
|
/// note: x86_64 does not have an OpenFirmware implementation, this is for testing purposes only
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
pub type EntryFunction = extern "C" fn (*mut Args) -> i32;
|
268
src/lib.rs
Normal file
268
src/lib.rs
Normal file
|
@ -0,0 +1,268 @@
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
/// # OFW_TRUE
|
||||||
|
/// a constant representing the OpenFirmware "true" value
|
||||||
|
pub const OFW_TRUE: i32 = -1;
|
||||||
|
|
||||||
|
/// # OFW_FALSE
|
||||||
|
/// a constant representing the OpenFirmware "false" value
|
||||||
|
pub const OFW_FALSE: i32 = 0;
|
||||||
|
|
||||||
|
/// # OFWBoolean
|
||||||
|
/// a type representing the OpenFirmware boolean type
|
||||||
|
/// can be either OFW_TRUE or OFW_FALSE
|
||||||
|
pub type OFWBoolean = i32;
|
||||||
|
|
||||||
|
/// # PHandle
|
||||||
|
/// handle to a "package" in OpenFirmware
|
||||||
|
/// usually used to access properties
|
||||||
|
pub type PHandle = i32;
|
||||||
|
|
||||||
|
/// # IHandle
|
||||||
|
/// handle to a package instance in OpenFirmware
|
||||||
|
/// usually used to call methods from a package
|
||||||
|
pub type IHandle = i32;
|
||||||
|
|
||||||
|
use crate::arch::EntryFunction;
|
||||||
|
use crate::ntstr::NTSTR;
|
||||||
|
|
||||||
|
/// # ntstr
|
||||||
|
/// module for handling null-terminated strings
|
||||||
|
pub mod ntstr;
|
||||||
|
|
||||||
|
/// # arch
|
||||||
|
/// module for architecture-specific code
|
||||||
|
pub mod arch;
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
|
|
||||||
|
/// # Args
|
||||||
|
/// a base structure for all calls to the OpenFirmware entry function,
|
||||||
|
/// shouldn't be used directly but rather used as a base for other "service" structures
|
||||||
|
/// an example "service struct" is as follows
|
||||||
|
/// ```
|
||||||
|
/// use ofw::{Args, OFWBoolean};
|
||||||
|
/// use ofw::ntstr::NTSTR;
|
||||||
|
/// /// # test
|
||||||
|
/// /// nargs: 1
|
||||||
|
/// /// nrets: 1
|
||||||
|
/// /// takes a service name string, and returns OFW_TRUE if the service is missing or OFW_FALSE if it is present
|
||||||
|
/// #[repr(C)]
|
||||||
|
/// pub struct TestService {
|
||||||
|
/// pub args: Args,
|
||||||
|
/// pub service: NTSTR,
|
||||||
|
/// pub missing: OFWBoolean,
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Args {
|
||||||
|
pub service: NTSTR,
|
||||||
|
// ieee 1275, 2.4.1 General conventions: "All numbers on the stack are signed integers, _32 bits[...]"
|
||||||
|
pub nrets: i32,
|
||||||
|
pub nargs: i32,
|
||||||
|
// inheriting structs will continue from here
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # ServiceResult
|
||||||
|
/// a generic structure for accessing the results of a service call
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub struct ServiceResult<'a> {
|
||||||
|
pub success: bool,
|
||||||
|
buf: &'static mut [i32],
|
||||||
|
pub rets: &'a [i32],
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # call!
|
||||||
|
/// a macro for calling OpenFirmware services
|
||||||
|
/// ## example
|
||||||
|
/// ```
|
||||||
|
/// 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);
|
||||||
|
/// // <entry function>, <service name>, <# of args>, <# of rets>, <args...>
|
||||||
|
/// call!(entry_fn, results, ntstr!("test"), 1, 1, ntstr!("test"));
|
||||||
|
/// if results.success {
|
||||||
|
/// let test_result: i32 = results.rets[0];
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! call {
|
||||||
|
($entry_fn:expr, $results:expr, $service:expr, $nargs:expr, $nrets:expr, $($args:expr),*) => {
|
||||||
|
#[allow(unused_assignments)]
|
||||||
|
{
|
||||||
|
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..];
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # call_method!
|
||||||
|
/// a macro for calling package methods
|
||||||
|
/// ## example
|
||||||
|
/// ```
|
||||||
|
/// use ofw::arch::EntryFunction;
|
||||||
|
/// use ofw::{call_method, method_service_result, ServiceResult};
|
||||||
|
///
|
||||||
|
/// let entry_fn: EntryFunction = unimplemented!("get the entry function from somewhere");
|
||||||
|
/// let package_instance: i32 = unimplemented!("get the package instance from somewhere");
|
||||||
|
/// // 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);
|
||||||
|
/// // <entry function>, <package instance>, <method name>, <# of args>, <# of rets>, <args...>
|
||||||
|
/// call_method!(entry_fn, results, package_instance, ntstr!("seek"), 2, 1, 0, 0);
|
||||||
|
/// if results.success {
|
||||||
|
/// let seek_result: i32 = results.rets[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)]
|
||||||
|
{
|
||||||
|
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..];
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # service_result!
|
||||||
|
/// a macro for creating a ServiceResult struct, used with the `call!` macro
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! service_result {
|
||||||
|
($nargs:expr, $nrets:expr) => { unsafe {
|
||||||
|
static mut BUF: [i32; $nargs + $nrets] = [0; $nargs + $nrets];
|
||||||
|
let rets: &[i32] = &[];
|
||||||
|
let results = $crate::ServiceResult {
|
||||||
|
success: false,
|
||||||
|
buf: &mut BUF,
|
||||||
|
rets,
|
||||||
|
};
|
||||||
|
results
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # method_service_result!
|
||||||
|
/// a macro for creating a ServiceResult struct, used with the `call_method!` macro
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! method_service_result {
|
||||||
|
($nargs:expr, $nrets:expr) => { unsafe {
|
||||||
|
static mut BUF: [i32; $nargs + $nrets + 1] = [0; $nargs + $nrets + 1];
|
||||||
|
let rets: &[i32] = &[];
|
||||||
|
let results = $crate::ServiceResult {
|
||||||
|
success: false,
|
||||||
|
buf: &mut BUF,
|
||||||
|
rets,
|
||||||
|
};
|
||||||
|
results
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # ofw_call
|
||||||
|
/// a function to call any OpenFirmware-provided service
|
||||||
|
/// usage of the macro `call!` is preferred, but this function can be used directly
|
||||||
|
/// ## example
|
||||||
|
/// ```
|
||||||
|
/// 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 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 {
|
||||||
|
#[repr(C)]
|
||||||
|
struct GenericArgs {
|
||||||
|
args: Args,
|
||||||
|
buffer: *mut i32,
|
||||||
|
}
|
||||||
|
let mut generic_args = GenericArgs {
|
||||||
|
args: Args {
|
||||||
|
service,
|
||||||
|
nrets: num_rets,
|
||||||
|
nargs: num_args,
|
||||||
|
},
|
||||||
|
buffer: args_and_rets.as_mut_ptr(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let result: bool;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "powerpc")]
|
||||||
|
{
|
||||||
|
result = entry_fn(&mut generic_args as *mut _ as *mut Args) == OFW_TRUE;
|
||||||
|
}
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
{
|
||||||
|
result = entry_fn(&mut generic_args as *mut _ as *mut Args) == OFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # ofw_call_method
|
||||||
|
/// a function to call a method provided by a package instance
|
||||||
|
/// usage of the `call_method!` macro is preferred, but this function can be used directly
|
||||||
|
/// ## example
|
||||||
|
/// ```
|
||||||
|
/// // we will be calling the "seek" method on an imaginary block device
|
||||||
|
/// // the seek method takes 2 arguments, and returns 1 value
|
||||||
|
/// // addr_hi, addr_lo -- okay?
|
||||||
|
/// // however, we must add another cell in order to account for the catch-result
|
||||||
|
/// // (see ieee 1275, 6.3.2.2 Device tree)
|
||||||
|
/// use ofw::{ntstr, ofw_call_method};
|
||||||
|
/// // addr_hi, addr_lo, catch-result, okay?
|
||||||
|
/// let mut 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);
|
||||||
|
/// 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 {
|
||||||
|
#[repr(C)]
|
||||||
|
struct CallMethodArgs {
|
||||||
|
args: Args,
|
||||||
|
method: NTSTR,
|
||||||
|
ihandle: IHandle,
|
||||||
|
buffer: *mut i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut call_method_args = CallMethodArgs {
|
||||||
|
args: Args {
|
||||||
|
service: ntstr!("call-method"),
|
||||||
|
nrets: num_rets + 1,
|
||||||
|
nargs: num_args + 2,
|
||||||
|
},
|
||||||
|
method,
|
||||||
|
ihandle,
|
||||||
|
buffer: args_and_rets.as_mut_ptr(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let result: bool;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "powerpc")]
|
||||||
|
{
|
||||||
|
result = entry_fn(&mut call_method_args as *mut _ as *mut Args) == OFW_TRUE;
|
||||||
|
}
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
{
|
||||||
|
result = entry_fn(&mut call_method_args as *mut _ as *mut Args) == OFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
94
src/ntstr.rs
Normal file
94
src/ntstr.rs
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
use core::fmt::{Debug, Display, Formatter, Write};
|
||||||
|
|
||||||
|
/// # ntstr!
|
||||||
|
/// macro for creating a null-terminated string
|
||||||
|
/// ## example
|
||||||
|
/// ```
|
||||||
|
/// use ofw::ntstr;
|
||||||
|
/// let ntstr = ntstr!("Hello, world!");
|
||||||
|
/// ```
|
||||||
|
/// becomes
|
||||||
|
/// ```
|
||||||
|
/// let ntstr = ofw::ntstr::NTSTR::new(b"Hello, world!\0".as_ptr());
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! ntstr {
|
||||||
|
($str:expr) => {
|
||||||
|
$crate::ntstr::NTSTR::new(concat!($str, "\0").as_ptr())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # NTSTR
|
||||||
|
/// a null-terminated string, defined as a pointer to an array of u8 characters ending with a null byte
|
||||||
|
/// not mutable
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct NTSTR {
|
||||||
|
ptr: *const u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<usize> for NTSTR {
|
||||||
|
fn from(ptr: usize) -> Self {
|
||||||
|
Self { ptr: ptr as *const u8 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<*const u8> for NTSTR {
|
||||||
|
fn from(ptr: *const u8) -> Self {
|
||||||
|
Self { ptr }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::from_over_into)]
|
||||||
|
impl Into<i32> for NTSTR {
|
||||||
|
fn into(self) -> i32 {
|
||||||
|
self.ptr as i32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NTSTR {
|
||||||
|
pub const fn new(ptr: *const u8) -> Self {
|
||||||
|
Self { ptr }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||||
|
let mut i = 0;
|
||||||
|
loop {
|
||||||
|
let a = unsafe { *self.ptr.add(i) };
|
||||||
|
if a == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
f.write_char(a as char)?;
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for NTSTR {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
let mut i = 0;
|
||||||
|
loop {
|
||||||
|
let a = unsafe { *self.ptr.add(i) };
|
||||||
|
let b = unsafe { *other.ptr.add(i) };
|
||||||
|
if a != b {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if a == 0 {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for NTSTR {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||||
|
self.print(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for NTSTR {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||||
|
self.print(f)
|
||||||
|
}
|
||||||
|
}
|
167
src/tests.rs
Normal file
167
src/tests.rs
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
use crate::arch::EntryFunction;
|
||||||
|
use crate::{Args, call, call_method, IHandle, method_service_result, ntstr, OFW_FALSE, OFW_TRUE, service_result};
|
||||||
|
use crate::ntstr::NTSTR;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ntstr_macro() {
|
||||||
|
let a = ntstr!("Hello, world!");
|
||||||
|
let b = NTSTR::new(b"Hello, world!\0".as_ptr());
|
||||||
|
assert_eq!(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn call_ofw() {
|
||||||
|
pub extern "C" fn test_entry_function(args: *mut Args) -> i32 {
|
||||||
|
#[repr(C)]
|
||||||
|
struct GenericArgs {
|
||||||
|
args: Args,
|
||||||
|
buffer: *mut i32,
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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,
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn call_ofw_failure() {
|
||||||
|
pub extern "C" fn test_entry_function(args: *mut Args) -> i32 {
|
||||||
|
#[repr(C)]
|
||||||
|
struct GenericArgs {
|
||||||
|
args: Args,
|
||||||
|
buffer: *mut i32,
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn call_method_ofw() {
|
||||||
|
pub extern "C" fn test_entry_function(args: *mut Args) -> i32 {
|
||||||
|
#[repr(C)]
|
||||||
|
struct CallMethodArgs {
|
||||||
|
args: Args,
|
||||||
|
method: NTSTR,
|
||||||
|
ihandle: IHandle,
|
||||||
|
buffer: *mut i32,
|
||||||
|
}
|
||||||
|
let args = unsafe { &mut *(args as *mut CallMethodArgs) };
|
||||||
|
assert_eq!(args.args.service, ntstr!("call-method"));
|
||||||
|
assert_eq!(args.method, ntstr!("seek"));
|
||||||
|
assert_eq!(args.ihandle, 0);
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn call_method_ofw_seek_failure() {
|
||||||
|
pub extern "C" fn test_entry_function(args: *mut Args) -> i32 {
|
||||||
|
#[repr(C)]
|
||||||
|
struct CallMethodArgs {
|
||||||
|
args: Args,
|
||||||
|
method: NTSTR,
|
||||||
|
ihandle: IHandle,
|
||||||
|
buffer: *mut i32,
|
||||||
|
}
|
||||||
|
let args = unsafe { &mut *(args as *mut CallMethodArgs) };
|
||||||
|
assert_eq!(args.args.service, ntstr!("call-method"));
|
||||||
|
assert_eq!(args.method, ntstr!("seek"));
|
||||||
|
assert_eq!(args.ihandle, 0);
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn call_method_ofw_failure() {
|
||||||
|
pub extern "C" fn test_entry_function(args: *mut Args) -> i32 {
|
||||||
|
#[repr(C)]
|
||||||
|
struct CallMethodArgs {
|
||||||
|
args: Args,
|
||||||
|
method: NTSTR,
|
||||||
|
ihandle: IHandle,
|
||||||
|
buffer: *mut i32,
|
||||||
|
}
|
||||||
|
let args = unsafe { &mut *(args as *mut CallMethodArgs) };
|
||||||
|
assert_eq!(args.args.service, ntstr!("call-method"));
|
||||||
|
assert_eq!(args.method, ntstr!("asiofhawoptgh"));
|
||||||
|
assert_eq!(args.ihandle, 0);
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue