xenia-kernel: HLE expansion, scheduler integration, audit + UI bridge
Major HLE buildout in exports.rs: KeInitializeSemaphore now seeds
count/limit, XexGet{Module,Procedure}Address use distinct
HMODULE_XBOXKRNL/HMODULE_XAM pseudo-handles with a reverse
(ModuleId,ordinal)→thunk_addr map, plus sweeping additions across
sync primitives, file I/O, semaphores, events, threads, and
allocator paths needed to advance Sylpheed past VdSwap=2.
New modules:
- thread.rs — ThreadRef + per-thread suspension/wake plumbing
- interrupts.rs — IRQ delivery, pending-IRQ slots, IPI helpers
- path.rs — guest path normalization (D:\\, game:\\, etc.)
- audit.rs — --trace-handles harness backing the handle audit
- ui_bridge.rs — kernel-side endpoint of the xenia-ui bridge
(input snapshots, framebuffer publish handles)
state.rs grows to own the HW-slot scheduler state, the new audit /
UI bridge handles, and the per-handle reverse maps. xam.rs and
objects.rs follow suit for the HLE additions.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,12 +1,94 @@
|
||||
//! Kernel object tracking for HLE.
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use xenia_cpu::ThreadRef;
|
||||
|
||||
/// Kernel object types tracked by handle.
|
||||
///
|
||||
/// Sync variants (`Event`, `Semaphore`, `Mutex`, `Thread`) carry an in-place
|
||||
/// waiter list so wait/set/release sites keep invariants local — dropping the
|
||||
/// object implicitly drops its waiters. Waiters are stored as `ThreadRef`
|
||||
/// (post-Axis-1) — a bare `hw_id: u8` would have been ambiguous under per-slot
|
||||
/// runqueues where multiple guest threads share one HW slot.
|
||||
#[derive(Debug)]
|
||||
pub enum KernelObject {
|
||||
Event { manual_reset: bool, signaled: bool },
|
||||
Semaphore { count: i32, max: i32 },
|
||||
File { path: String },
|
||||
Thread { id: u32 },
|
||||
Timer,
|
||||
Mutex,
|
||||
Event {
|
||||
manual_reset: bool,
|
||||
signaled: bool,
|
||||
/// Guest threads parked on this event.
|
||||
waiters: Vec<ThreadRef>,
|
||||
},
|
||||
Semaphore {
|
||||
count: i32,
|
||||
max: i32,
|
||||
waiters: Vec<ThreadRef>,
|
||||
},
|
||||
File {
|
||||
/// Normalized VFS path (e.g. "default.xex", "media/shared/foo.pkg").
|
||||
path: String,
|
||||
/// Full file size in bytes.
|
||||
size: u64,
|
||||
/// Current read/write cursor.
|
||||
position: u64,
|
||||
/// Whole-file buffer — VFS reads the entire file up front so
|
||||
/// subsequent NtReadFile calls are O(1) slice copies.
|
||||
/// `Arc<Vec<u8>>` so duplicate handles could share backing storage.
|
||||
data: Arc<Vec<u8>>,
|
||||
/// Directory-enumeration cursor consumed by `NtQueryDirectoryFile`.
|
||||
/// `None` before the first call; `Some(N)` = next VFS entry index
|
||||
/// to emit. Reset to `Some(0)` when the guest passes
|
||||
/// `restart_scan=1`. Unused on non-directory files.
|
||||
dir_enum_pos: Option<usize>,
|
||||
},
|
||||
Thread {
|
||||
id: u32,
|
||||
/// HW thread slot currently running this guest thread (None once exited
|
||||
/// — `exit_code` becomes Some).
|
||||
hw_id: Option<u8>,
|
||||
/// None while the thread is running; populated on ExTerminateThread
|
||||
/// or halt-sentinel return.
|
||||
exit_code: Option<u32>,
|
||||
/// Guest threads parked in KeWaitForSingleObject on this thread handle.
|
||||
waiters: Vec<ThreadRef>,
|
||||
},
|
||||
Timer {
|
||||
/// Xbox 360 timer_type 0 = NotificationTimer (manual-reset),
|
||||
/// 1 = SynchronizationTimer (auto-reset). Same shape as Event.
|
||||
manual_reset: bool,
|
||||
signaled: bool,
|
||||
/// Absolute tick-space deadline; None when disarmed.
|
||||
deadline: Option<u64>,
|
||||
/// Period in ticks (same units as `deadline`); 0 = one-shot.
|
||||
period_ticks: u64,
|
||||
/// Original ms value (canary's SetTimer keeps it for diagnostics).
|
||||
period_ms: u32,
|
||||
/// APC routine (deferred — see `timer_apc` warn in nt_set_timer_ex).
|
||||
callback_routine: u32,
|
||||
callback_arg: u32,
|
||||
waiters: Vec<ThreadRef>,
|
||||
},
|
||||
Mutex {
|
||||
/// HW thread id currently holding the mutex; None when free.
|
||||
owner: Option<u8>,
|
||||
recursion: u32,
|
||||
waiters: Vec<ThreadRef>,
|
||||
},
|
||||
}
|
||||
|
||||
impl KernelObject {
|
||||
/// Returns the per-object waiter list for the 5 sync variants (Event,
|
||||
/// Semaphore, Thread, Timer, Mutex) and `None` for `File`. Used by
|
||||
/// deadline-expiry scrub in `KernelState::handle_timeout_wake` so a
|
||||
/// timed-out waiter isn't left stranded in a handle's waiters list.
|
||||
pub fn waiters_mut(&mut self) -> Option<&mut Vec<ThreadRef>> {
|
||||
match self {
|
||||
KernelObject::Event { waiters, .. }
|
||||
| KernelObject::Semaphore { waiters, .. }
|
||||
| KernelObject::Thread { waiters, .. }
|
||||
| KernelObject::Timer { waiters, .. }
|
||||
| KernelObject::Mutex { waiters, .. } => Some(waiters),
|
||||
KernelObject::File { .. } => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user