Merge pull request #253 from DrChat/krnl_obj_fix
Misc. Kernel Object Fixes
This commit is contained in:
commit
3a43eef4fe
|
@ -28,11 +28,11 @@ void XEvent::Initialize(bool manual_reset, bool initial_state) {
|
|||
native_handle_ = CreateEvent(NULL, manual_reset, initial_state, NULL);
|
||||
}
|
||||
|
||||
void XEvent::InitializeNative(void* native_ptr, DISPATCH_HEADER& header) {
|
||||
void XEvent::InitializeNative(void* native_ptr, X_DISPATCH_HEADER& header) {
|
||||
assert_null(native_handle_);
|
||||
|
||||
bool manual_reset;
|
||||
switch ((header.type_flags >> 24) & 0xFF) {
|
||||
switch (header.type) {
|
||||
case 0x00: // EventNotificationObject (manual reset)
|
||||
manual_reset = true;
|
||||
break;
|
||||
|
|
|
@ -22,7 +22,7 @@ class XEvent : public XObject {
|
|||
virtual ~XEvent();
|
||||
|
||||
void Initialize(bool manual_reset, bool initial_state);
|
||||
void InitializeNative(void* native_ptr, DISPATCH_HEADER& header);
|
||||
void InitializeNative(void* native_ptr, X_DISPATCH_HEADER& header);
|
||||
|
||||
int32_t Set(uint32_t priority_increment, bool wait);
|
||||
int32_t Pulse(uint32_t priority_increment, bool wait);
|
||||
|
|
|
@ -27,7 +27,7 @@ void XMutant::Initialize(bool initial_owner) {
|
|||
native_handle_ = CreateMutex(NULL, initial_owner ? TRUE : FALSE, NULL);
|
||||
}
|
||||
|
||||
void XMutant::InitializeNative(void* native_ptr, DISPATCH_HEADER& header) {
|
||||
void XMutant::InitializeNative(void* native_ptr, X_DISPATCH_HEADER& header) {
|
||||
assert_null(native_handle_);
|
||||
|
||||
// Haven't seen this yet, but it's possible.
|
||||
|
|
|
@ -22,7 +22,7 @@ class XMutant : public XObject {
|
|||
virtual ~XMutant();
|
||||
|
||||
void Initialize(bool initial_owner);
|
||||
void InitializeNative(void* native_ptr, DISPATCH_HEADER& header);
|
||||
void InitializeNative(void* native_ptr, X_DISPATCH_HEADER& header);
|
||||
|
||||
X_STATUS ReleaseMutant(uint32_t priority_increment, bool abandon, bool wait);
|
||||
|
||||
|
|
|
@ -24,10 +24,12 @@ XSemaphore::~XSemaphore() {
|
|||
void XSemaphore::Initialize(int32_t initial_count, int32_t maximum_count) {
|
||||
assert_null(native_handle_);
|
||||
|
||||
CreateNative(sizeof(X_SEMAPHORE));
|
||||
|
||||
native_handle_ = CreateSemaphore(NULL, initial_count, maximum_count, NULL);
|
||||
}
|
||||
|
||||
void XSemaphore::InitializeNative(void* native_ptr, DISPATCH_HEADER& header) {
|
||||
void XSemaphore::InitializeNative(void* native_ptr, X_DISPATCH_HEADER& header) {
|
||||
assert_null(native_handle_);
|
||||
|
||||
// NOT IMPLEMENTED
|
||||
|
|
|
@ -16,13 +16,18 @@
|
|||
namespace xe {
|
||||
namespace kernel {
|
||||
|
||||
struct X_SEMAPHORE {
|
||||
X_DISPATCH_HEADER header;
|
||||
// TODO: Make this not empty!
|
||||
};
|
||||
|
||||
class XSemaphore : public XObject {
|
||||
public:
|
||||
XSemaphore(KernelState* kernel_state);
|
||||
virtual ~XSemaphore();
|
||||
|
||||
void Initialize(int32_t initial_count, int32_t maximum_count);
|
||||
void InitializeNative(void* native_ptr, DISPATCH_HEADER& header);
|
||||
void InitializeNative(void* native_ptr, X_DISPATCH_HEADER& header);
|
||||
|
||||
int32_t ReleaseSemaphore(int32_t release_count);
|
||||
|
||||
|
|
|
@ -143,6 +143,14 @@ uint8_t GetFakeCpuNumber(uint8_t proc_mask) {
|
|||
}
|
||||
|
||||
X_STATUS XThread::Create() {
|
||||
// Thread kernel object
|
||||
// This call will also setup the native pointer for us.
|
||||
uint8_t* guest_object = CreateNative(sizeof(X_THREAD));
|
||||
if (!guest_object) {
|
||||
XELOGW("Unable to allocate thread object");
|
||||
return X_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
// Allocate thread state block from heap.
|
||||
// This is set as r13 for user code and some special inlined Win32 calls
|
||||
// (like GetLastError/etc) will poke it directly.
|
||||
|
@ -162,9 +170,6 @@ X_STATUS XThread::Create() {
|
|||
return X_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
// Set native info.
|
||||
SetNativePointer(thread_state_address_, true);
|
||||
|
||||
auto module = kernel_state()->GetExecutableModule();
|
||||
|
||||
// Allocate thread scratch.
|
||||
|
@ -276,8 +281,6 @@ X_STATUS XThread::Create() {
|
|||
xe::store_and_swap<uint32_t>(p + 0x16C, creation_params_.creation_flags);
|
||||
xe::store_and_swap<uint32_t>(p + 0x17C, 1);
|
||||
|
||||
SetNativePointer(thread_state_address_);
|
||||
|
||||
X_STATUS return_code = PlatformCreate();
|
||||
if (XFAILED(return_code)) {
|
||||
XELOGW("Unable to create platform thread (%.8X)", return_code);
|
||||
|
|
|
@ -60,6 +60,19 @@ struct XAPC {
|
|||
}
|
||||
};
|
||||
|
||||
// http://www.nirsoft.net/kernel_struct/vista/KTHREAD.html
|
||||
struct X_THREAD {
|
||||
X_DISPATCH_HEADER header;
|
||||
xe::be<uint64_t> cycle_time;
|
||||
xe::be<uint32_t> high_cycle_time; // FIXME: Needed?
|
||||
xe::be<uint64_t> quantum_target;
|
||||
xe::be<uint32_t> initial_stack_ptr;
|
||||
xe::be<uint32_t> stack_limit_ptr;
|
||||
xe::be<uint32_t> kernel_stack_ptr;
|
||||
|
||||
// This struct is actually quite long... so uh, not filling this out!
|
||||
};
|
||||
|
||||
class XThread : public XObject {
|
||||
public:
|
||||
XThread(KernelState* kernel_state, uint32_t stack_size,
|
||||
|
@ -74,6 +87,7 @@ class XThread : public XObject {
|
|||
|
||||
uint32_t pcr_ptr() const { return pcr_address_; }
|
||||
uint32_t thread_state_ptr() const { return thread_state_address_; }
|
||||
|
||||
cpu::ThreadState* thread_state() const { return thread_state_; }
|
||||
uint32_t thread_id() const { return thread_id_; }
|
||||
uint32_t last_error();
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "xenia/base/logging.h"
|
||||
#include "xenia/kernel/kernel_state.h"
|
||||
#include "xenia/kernel/objects/xthread.h"
|
||||
#include "xenia/kernel/objects/xsemaphore.h"
|
||||
#include "xenia/kernel/util/shim_utils.h"
|
||||
#include "xenia/kernel/xboxkrnl_private.h"
|
||||
#include "xenia/kernel/xobject.h"
|
||||
|
@ -76,7 +77,7 @@ SHIM_CALL ObReferenceObjectByHandle_shim(PPCContext* ppc_context,
|
|||
} break;*/
|
||||
case XObject::kTypeThread: {
|
||||
auto thread = object.get<XThread>();
|
||||
native_ptr = thread->thread_state_ptr();
|
||||
native_ptr = thread->guest_object();
|
||||
} break;
|
||||
default: {
|
||||
assert_unhandled_case(object->type());
|
||||
|
@ -85,13 +86,16 @@ SHIM_CALL ObReferenceObjectByHandle_shim(PPCContext* ppc_context,
|
|||
}
|
||||
} break;
|
||||
case 0xD017BEEF: { // ExSemaphoreObjectType
|
||||
// TODO(benvanik): implement.
|
||||
assert_unhandled_case(object_type_ptr);
|
||||
native_ptr = 0xDEADF00D;
|
||||
assert(object->type() == XObject::kTypeSemaphore);
|
||||
auto sem = object.get<XSemaphore>();
|
||||
|
||||
native_ptr = sem->guest_object();
|
||||
} break;
|
||||
case 0xD01BBEEF: { // ExThreadObjectType
|
||||
assert(object->type() == XObject::kTypeThread);
|
||||
auto thread = object.get<XThread>();
|
||||
native_ptr = thread->thread_state_ptr();
|
||||
|
||||
native_ptr = thread->guest_object();
|
||||
} break;
|
||||
default: {
|
||||
assert_unhandled_case(object_type_ptr);
|
||||
|
|
|
@ -24,7 +24,9 @@ XObject::XObject(KernelState* kernel_state, Type type)
|
|||
handle_ref_count_(0),
|
||||
pointer_ref_count_(1),
|
||||
type_(type),
|
||||
handle_(X_INVALID_HANDLE_VALUE) {
|
||||
handle_(X_INVALID_HANDLE_VALUE),
|
||||
guest_object_ptr_(0),
|
||||
allocated_guest_object_(false) {
|
||||
// Added pointer check to support usage without a kernel_state
|
||||
if (kernel_state != nullptr) {
|
||||
kernel_state->object_table()->AddHandle(this, &handle_);
|
||||
|
@ -34,6 +36,18 @@ XObject::XObject(KernelState* kernel_state, Type type)
|
|||
XObject::~XObject() {
|
||||
assert_zero(handle_ref_count_);
|
||||
assert_zero(pointer_ref_count_);
|
||||
|
||||
if (allocated_guest_object_) {
|
||||
uint32_t ptr = guest_object_ptr_ - sizeof(X_OBJECT_HEADER);
|
||||
auto header = memory()->TranslateVirtual<X_OBJECT_HEADER*>(ptr);
|
||||
|
||||
// Free the object creation info
|
||||
if (header->object_create_info) {
|
||||
memory()->SystemHeapFree(header->object_create_info);
|
||||
}
|
||||
|
||||
memory()->SystemHeapFree(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
Emulator* XObject::emulator() const { return kernel_state_->emulator_; }
|
||||
|
@ -161,11 +175,45 @@ X_STATUS XObject::WaitMultiple(uint32_t count, XObject** objects,
|
|||
return result;
|
||||
}
|
||||
|
||||
uint8_t* XObject::CreateNative(uint32_t size) {
|
||||
std::lock_guard<xe::recursive_mutex> lock(kernel_state_->object_mutex());
|
||||
|
||||
uint32_t total_size = size + sizeof(X_OBJECT_HEADER);
|
||||
|
||||
auto mem = memory()->SystemHeapAlloc(total_size);
|
||||
if (!mem) {
|
||||
// Out of memory!
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
allocated_guest_object_ = true;
|
||||
memory()->Zero(mem, total_size);
|
||||
SetNativePointer(mem + sizeof(X_OBJECT_HEADER), true);
|
||||
|
||||
auto header = memory()->TranslateVirtual<X_OBJECT_HEADER*>(mem);
|
||||
|
||||
auto creation_info =
|
||||
memory()->SystemHeapAlloc(sizeof(X_OBJECT_CREATE_INFORMATION));
|
||||
if (creation_info) {
|
||||
memory()->Zero(creation_info, sizeof(X_OBJECT_CREATE_INFORMATION));
|
||||
|
||||
// Set it up in the header.
|
||||
// Some kernel method is accessing this struct and dereferencing a member.
|
||||
// With our current definition that member is non_paged_pool_charge.
|
||||
header->object_create_info = creation_info;
|
||||
}
|
||||
|
||||
return memory()->TranslateVirtual(guest_object_ptr_);
|
||||
}
|
||||
|
||||
void XObject::SetNativePointer(uint32_t native_ptr, bool uninitialized) {
|
||||
std::lock_guard<xe::recursive_mutex> lock(kernel_state_->object_mutex());
|
||||
|
||||
// If hit: We've already setup the native ptr with CreateNative!
|
||||
assert_zero(guest_object_ptr_);
|
||||
|
||||
auto header =
|
||||
kernel_state_->memory()->TranslateVirtual<DISPATCH_HEADER*>(native_ptr);
|
||||
kernel_state_->memory()->TranslateVirtual<X_DISPATCH_HEADER*>(native_ptr);
|
||||
|
||||
// Memory uninitialized, so don't bother with the check.
|
||||
if (!uninitialized) {
|
||||
|
@ -173,10 +221,13 @@ void XObject::SetNativePointer(uint32_t native_ptr, bool uninitialized) {
|
|||
}
|
||||
|
||||
// Stash pointer in struct.
|
||||
// FIXME: This assumes the object has a dispatch header (some don't!)
|
||||
uint64_t object_ptr = reinterpret_cast<uint64_t>(this);
|
||||
object_ptr |= 0x1;
|
||||
header->wait_list_flink = (uint32_t)(object_ptr >> 32);
|
||||
header->wait_list_blink = (uint32_t)(object_ptr & 0xFFFFFFFF);
|
||||
|
||||
guest_object_ptr_ = native_ptr;
|
||||
}
|
||||
|
||||
object_ref<XObject> XObject::GetNativeObject(KernelState* kernel_state,
|
||||
|
@ -195,10 +246,10 @@ object_ref<XObject> XObject::GetNativeObject(KernelState* kernel_state,
|
|||
|
||||
std::lock_guard<xe::recursive_mutex> lock(kernel_state->object_mutex());
|
||||
|
||||
auto header = reinterpret_cast<DISPATCH_HEADER*>(native_ptr);
|
||||
auto header = reinterpret_cast<X_DISPATCH_HEADER*>(native_ptr);
|
||||
|
||||
if (as_type == -1) {
|
||||
as_type = (header->type_flags >> 24) & 0xFF;
|
||||
as_type = header->type;
|
||||
}
|
||||
|
||||
if (header->wait_list_blink & 0x1) {
|
||||
|
@ -251,6 +302,7 @@ object_ref<XObject> XObject::GetNativeObject(KernelState* kernel_state,
|
|||
}
|
||||
|
||||
// Stash pointer in struct.
|
||||
// FIXME: This assumes the object contains a dispatch header (some don't!)
|
||||
uint64_t object_ptr = reinterpret_cast<uint64_t>(object);
|
||||
object_ptr |= 0x1;
|
||||
header->wait_list_flink = (uint32_t)(object_ptr >> 32);
|
||||
|
|
|
@ -29,11 +29,67 @@ class object_ref;
|
|||
|
||||
// http://www.nirsoft.net/kernel_struct/vista/DISPATCHER_HEADER.html
|
||||
typedef struct {
|
||||
xe::be<uint32_t> type_flags;
|
||||
struct {
|
||||
uint8_t type;
|
||||
|
||||
union {
|
||||
uint8_t abandoned;
|
||||
uint8_t absolute;
|
||||
uint8_t npx_irql;
|
||||
uint8_t signalling;
|
||||
};
|
||||
union {
|
||||
uint8_t size;
|
||||
uint8_t hand;
|
||||
};
|
||||
union {
|
||||
uint8_t inserted;
|
||||
uint8_t debug_active;
|
||||
uint8_t dpc_active;
|
||||
};
|
||||
};
|
||||
|
||||
xe::be<uint32_t> signal_state;
|
||||
xe::be<uint32_t> wait_list_flink;
|
||||
xe::be<uint32_t> wait_list_blink;
|
||||
} DISPATCH_HEADER;
|
||||
} X_DISPATCH_HEADER;
|
||||
|
||||
// http://www.nirsoft.net/kernel_struct/vista/OBJECT_HEADER.html
|
||||
struct X_OBJECT_HEADER {
|
||||
xe::be<uint32_t> pointer_count;
|
||||
union {
|
||||
xe::be<uint32_t> handle_count;
|
||||
xe::be<uint32_t> next_to_free;
|
||||
};
|
||||
xe::be<uint32_t> object_type_ptr;
|
||||
uint8_t name_info_offset;
|
||||
uint8_t handle_info_offset;
|
||||
uint8_t quota_info_offset;
|
||||
uint8_t flags;
|
||||
union {
|
||||
xe::be<uint32_t> object_create_info; // X_OBJECT_CREATE_INFORMATION
|
||||
xe::be<uint32_t> quota_block_charged;
|
||||
};
|
||||
xe::be<uint32_t> security_descriptor;
|
||||
|
||||
// Object lives after this header.
|
||||
// (There's actually a body field here which is the object itself)
|
||||
};
|
||||
|
||||
// http://www.nirsoft.net/kernel_struct/vista/OBJECT_CREATE_INFORMATION.html
|
||||
struct X_OBJECT_CREATE_INFORMATION {
|
||||
xe::be<uint32_t> attributes;
|
||||
xe::be<uint32_t> root_directory_ptr;
|
||||
xe::be<uint32_t> parse_context_ptr;
|
||||
xe::be<uint32_t> probe_mode;
|
||||
xe::be<uint32_t> paged_pool_charge;
|
||||
xe::be<uint32_t> non_paged_pool_charge;
|
||||
xe::be<uint32_t> security_descriptor_charge;
|
||||
xe::be<uint32_t> security_descriptor;
|
||||
xe::be<uint32_t> security_qos_ptr;
|
||||
|
||||
// Security QoS here (SECURITY_QUALITY_OF_SERVICE) too!
|
||||
};
|
||||
|
||||
class XObject {
|
||||
public:
|
||||
|
@ -59,6 +115,7 @@ class XObject {
|
|||
Type type();
|
||||
X_HANDLE handle() const;
|
||||
const std::string& name() const { return name_; }
|
||||
uint32_t guest_object() const { return guest_object_ptr_; }
|
||||
|
||||
void RetainHandle();
|
||||
bool ReleaseHandle();
|
||||
|
@ -94,6 +151,8 @@ class XObject {
|
|||
virtual void* GetWaitHandle() { return 0; }
|
||||
|
||||
protected:
|
||||
// Creates the kernel object for guest code to use. Typically not needed.
|
||||
uint8_t* CreateNative(uint32_t size);
|
||||
void SetNativePointer(uint32_t native_ptr, bool uninitialized = false);
|
||||
|
||||
static uint32_t TimeoutTicksToMs(int64_t timeout_ticks);
|
||||
|
@ -107,6 +166,11 @@ class XObject {
|
|||
Type type_;
|
||||
X_HANDLE handle_;
|
||||
std::string name_; // May be zero length.
|
||||
|
||||
// Guest pointer for kernel object. Remember: X_OBJECT_HEADER precedes this
|
||||
// if we allocated it!
|
||||
uint32_t guest_object_ptr_;
|
||||
bool allocated_guest_object_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
|
Loading…
Reference in New Issue