minor cleanup
This commit is contained in:
parent
a67fa70632
commit
b0e6174467
|
@ -14,10 +14,10 @@ get going:
|
||||||
`wbx_activate_host()`
|
`wbx_activate_host()`
|
||||||
2. Connect exports from the guest executable to your host system
|
2. Connect exports from the guest executable to your host system
|
||||||
`wbx_get_proc_addr()`
|
`wbx_get_proc_addr()`
|
||||||
3. Run the guest system's init, using function pointers it exposed through wbx_get_proc_addr()
|
3. Run the guest system's init, using function pointers it exposed through `wbx_get_proc_addr()`
|
||||||
4. Get ready to take savestates
|
4. Get ready to take savestates
|
||||||
`wbx_seal()`
|
`wbx_seal()`
|
||||||
5. Run emulation, using frameadvance or other advance functions exposed by the guest through wbx_get_proc_addr()
|
5. Run emulation, using frameadvance or other advance functions exposed by the guest through `wbx_get_proc_addr()`
|
||||||
6. Save and load states as needed
|
6. Save and load states as needed
|
||||||
`wbx_save_state()`
|
`wbx_save_state()`
|
||||||
`wbx_load_state()`
|
`wbx_load_state()`
|
||||||
|
@ -25,8 +25,13 @@ get going:
|
||||||
`wbx_deactivate_host()`
|
`wbx_deactivate_host()`
|
||||||
`wbx_destroy_host()`
|
`wbx_destroy_host()`
|
||||||
|
|
||||||
If you're keeping around multiple hosts that may compete for the same address space, use `wbx_activate_host` and `wbx_deactivate_host`
|
Some more advanced features:
|
||||||
to switch between them. If you'd like to expose files to the virtual filesystem, see `wbx_mount_file` and `wbx_unmount_file`
|
|
||||||
|
* If you're keeping around multiple hosts that may compete for the same address space,
|
||||||
|
use `wbx_activate_host()` and `wbx_deactivate_host()` to switch between them.
|
||||||
|
* If you'd like to expose files to the virtual filesystem, see `wbx_mount_file()` and `wbx_unmount_file()`.
|
||||||
|
* If you need to call dynamically exposed functions that are not part of the static exports, see `wbx_get_callin_addr()`.
|
||||||
|
* If you'd like the guest code to be able to call callbacks that you pass to it, see `wbx_get_callback_addr()`.
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ const CALL_GUEST_SIMPLE_ADDR: usize = ORG + 64;
|
||||||
|
|
||||||
pub const CALLBACK_SLOTS: usize = 64;
|
pub const CALLBACK_SLOTS: usize = 64;
|
||||||
/// Retrieves a function pointer suitable for sending to the guest that will cause
|
/// Retrieves a function pointer suitable for sending to the guest that will cause
|
||||||
/// the host to callback to `slot` when called
|
/// the host to callback to `slot` when called. Slot must be less than CALLBACK_SLOTS
|
||||||
pub fn get_callback_ptr(slot: usize) -> usize{
|
pub fn get_callback_ptr(slot: usize) -> usize{
|
||||||
assert!(slot < CALLBACK_SLOTS);
|
assert!(slot < CALLBACK_SLOTS);
|
||||||
ORG + 0x100 + slot * 16
|
ORG + 0x100 + slot * 16
|
||||||
|
@ -52,27 +52,44 @@ pub fn call_guest_simple(entry_point: usize, context: &mut Context) -> usize{
|
||||||
unsafe { (CALL_GUEST_SIMPLE.f)(entry_point, context) }
|
unsafe { (CALL_GUEST_SIMPLE.f)(entry_point, context) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Allowed type for callback functions that Waterbox cores can make back into the real world.
|
||||||
pub type ExternalCallback = extern "sysv64" fn(
|
pub type ExternalCallback = extern "sysv64" fn(
|
||||||
a1: usize, a2: usize, a3: usize, a4: usize, a5: usize, a6: usize) -> usize;
|
a1: usize, a2: usize, a3: usize, a4: usize, a5: usize, a6: usize) -> usize;
|
||||||
|
/// Allowed type of the syscall service function
|
||||||
pub type SyscallCallback = extern "sysv64" fn(
|
pub type SyscallCallback = extern "sysv64" fn(
|
||||||
a1: usize, a2: usize, a3: usize, a4: usize, a5: usize, a6: usize, nr: SyscallNumber, h: &mut ActivatedWaterboxHost) -> SyscallReturn;
|
a1: usize, a2: usize, a3: usize, a4: usize, a5: usize, a6: usize, nr: SyscallNumber, h: &mut ActivatedWaterboxHost) -> SyscallReturn;
|
||||||
|
|
||||||
|
/// Structure used to track information for calls into waterbox code
|
||||||
/// Layout must be synced with interop.s
|
/// Layout must be synced with interop.s
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
|
/// Used internally to track the host's most recent rsp when transitioned to Waterbox code.
|
||||||
pub host_rsp: usize,
|
pub host_rsp: usize,
|
||||||
|
/// Sets the guest's starting rsp, and used internally to track the guest's most recent rsp when transitioned to extcall or syscall
|
||||||
pub guest_rsp: usize,
|
pub guest_rsp: usize,
|
||||||
|
/// syscall service function
|
||||||
pub dispatch_syscall: SyscallCallback,
|
pub dispatch_syscall: SyscallCallback,
|
||||||
|
/// This will be passed as the final parameter to dispatch_syscall, and is not otherwise used by the context tracking code
|
||||||
pub host_ptr: usize,
|
pub host_ptr: usize,
|
||||||
|
/// Host function pointers that will be called when the guest calls an extcall slot thunk (returned from `get_callback_ptr`)
|
||||||
pub extcall_slots: [Option<ExternalCallback>; 64],
|
pub extcall_slots: [Option<ExternalCallback>; 64],
|
||||||
}
|
}
|
||||||
|
impl Context {
|
||||||
|
/// Returns a suitably initialized context. It's almost ready to use, but host_ptr must be set before each usage
|
||||||
|
pub fn new(initial_guest_rsp: usize, dispatch_syscall: SyscallCallback) -> Context {
|
||||||
|
Context {
|
||||||
|
host_rsp: 0,
|
||||||
|
guest_rsp: initial_guest_rsp,
|
||||||
|
dispatch_syscall,
|
||||||
|
host_ptr: 0,
|
||||||
|
extcall_slots: [None; 64]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
thread_local!(static TIB: Box<[usize; 4]> = Box::new([0usize; 4]));
|
thread_local!(static TIB: Box<[usize; 4]> = Box::new([0usize; 4]));
|
||||||
|
|
||||||
|
|
||||||
/// Prepares this host thread to be allowed to call guest code. Noop if already called.
|
/// Prepares this host thread to be allowed to call guest code. Noop if already called.
|
||||||
/// Only needs to happen once per host thread
|
/// Only needs to happen once per host thread
|
||||||
pub fn prepare_thread() {
|
pub fn prepare_thread() {
|
||||||
|
|
|
@ -11,6 +11,7 @@ use std::collections::HashMap;
|
||||||
|
|
||||||
const THUNK_SIZE: usize = 32;
|
const THUNK_SIZE: usize = 32;
|
||||||
|
|
||||||
|
/// tracks thunks for calling into waterbox code
|
||||||
pub struct ThunkManager {
|
pub struct ThunkManager {
|
||||||
memory: AddressRange,
|
memory: AddressRange,
|
||||||
lookup: HashMap<usize, usize>,
|
lookup: HashMap<usize, usize>,
|
||||||
|
@ -25,6 +26,8 @@ impl ThunkManager {
|
||||||
}
|
}
|
||||||
/// Generates a thunk for calling into waterbox.
|
/// Generates a thunk for calling into waterbox.
|
||||||
/// Only valid so long as this ThunkManager is alive and set_context_ptr is kept up to date
|
/// Only valid so long as this ThunkManager is alive and set_context_ptr is kept up to date
|
||||||
|
/// See also `call_guest_simple`, which directly performs a call of the sort that these thunks do, but requires
|
||||||
|
/// Context to be passed at the time of call and cannot pass arguments to the guest
|
||||||
pub fn get_thunk_for_proc(&mut self, guest_entry_point: usize, context: *mut Context) -> anyhow::Result<usize> {
|
pub fn get_thunk_for_proc(&mut self, guest_entry_point: usize, context: *mut Context) -> anyhow::Result<usize> {
|
||||||
match self.lookup.get(&guest_entry_point) {
|
match self.lookup.get(&guest_entry_point) {
|
||||||
Some(p) => return Ok(*p),
|
Some(p) => return Ok(*p),
|
||||||
|
|
|
@ -41,13 +41,7 @@ impl WaterboxHost {
|
||||||
active: false,
|
active: false,
|
||||||
sealed: false,
|
sealed: false,
|
||||||
image_file,
|
image_file,
|
||||||
context: Context {
|
context: Context::new(layout.main_thread.end(), syscall),
|
||||||
host_rsp: 0,
|
|
||||||
guest_rsp: layout.main_thread.end(),
|
|
||||||
dispatch_syscall: syscall,
|
|
||||||
host_ptr: 0,
|
|
||||||
extcall_slots: [None; 64],
|
|
||||||
},
|
|
||||||
thunks,
|
thunks,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue