Merge pull request #253 from DrChat/krnl_obj_fix

Misc. Kernel Object Fixes
This commit is contained in:
Ben Vanik 2015-06-12 22:36:07 -07:00
commit 3a43eef4fe
11 changed files with 167 additions and 23 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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.

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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();

View File

@ -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);

View File

@ -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);

View File

@ -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>