[Kernel] nonintrusive guest to host object mapping
This commit is contained in:
parent
d36b1b3830
commit
ee424ae14a
|
@ -17,9 +17,7 @@ struct XAPC;
|
||||||
|
|
||||||
struct X_KPCR;
|
struct X_KPCR;
|
||||||
struct X_KTHREAD;
|
struct X_KTHREAD;
|
||||||
struct X_OBJECT_HEADER;
|
|
||||||
struct X_OBJECT_CREATE_INFORMATION;
|
struct X_OBJECT_CREATE_INFORMATION;
|
||||||
struct X_OBJECT_TYPE;
|
|
||||||
|
|
||||||
} // namespace xe::kernel
|
} // namespace xe::kernel
|
||||||
|
|
||||||
|
|
|
@ -479,6 +479,31 @@ X_STATUS ObjectTable::RestoreHandle(X_HANDLE handle, XObject* object) {
|
||||||
return X_STATUS_SUCCESS;
|
return X_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ObjectTable::MapGuestObjectToHostHandle(uint32_t guest_object,
|
||||||
|
X_HANDLE host_handle) {
|
||||||
|
auto global_lock = global_critical_region_.Acquire();
|
||||||
|
guest_to_host_handle_[guest_object] = host_handle;
|
||||||
|
}
|
||||||
|
bool ObjectTable::HostHandleForGuestObject(uint32_t guest_object, X_HANDLE& out) {
|
||||||
|
auto global_lock = global_critical_region_.Acquire();
|
||||||
|
auto gobj_iter = guest_to_host_handle_.find(guest_object);
|
||||||
|
if (gobj_iter == guest_to_host_handle_.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
out = gobj_iter->second;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjectTable::UnmapGuestObjectHostHandle(uint32_t guest_object) {
|
||||||
|
auto global_lock = global_critical_region_.Acquire();
|
||||||
|
auto iter = guest_to_host_handle_.find(guest_object);
|
||||||
|
if (iter == guest_to_host_handle_.end()) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
guest_to_host_handle_.erase(iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace util
|
} // namespace util
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -80,6 +80,9 @@ class ObjectTable {
|
||||||
std::vector<object_ref<XObject>> GetAllObjects();
|
std::vector<object_ref<XObject>> GetAllObjects();
|
||||||
void PurgeAllObjects(); // Purges the object table of all guest objects
|
void PurgeAllObjects(); // Purges the object table of all guest objects
|
||||||
|
|
||||||
|
void MapGuestObjectToHostHandle(uint32_t guest_object, X_HANDLE host_handle);
|
||||||
|
void UnmapGuestObjectHostHandle(uint32_t guest_object);
|
||||||
|
bool HostHandleForGuestObject(uint32_t guest_object, X_HANDLE& out);
|
||||||
private:
|
private:
|
||||||
struct ObjectTableEntry {
|
struct ObjectTableEntry {
|
||||||
int handle_ref_count = 0;
|
int handle_ref_count = 0;
|
||||||
|
@ -107,6 +110,7 @@ class ObjectTable {
|
||||||
uint32_t last_free_entry_ = 0;
|
uint32_t last_free_entry_ = 0;
|
||||||
uint32_t last_free_host_entry_ = 0;
|
uint32_t last_free_host_entry_ = 0;
|
||||||
std::unordered_map<string_key_case, X_HANDLE> name_table_;
|
std::unordered_map<string_key_case, X_HANDLE> name_table_;
|
||||||
|
std::unordered_map<uint32_t, X_HANDLE> guest_to_host_handle_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Generic lookup
|
// Generic lookup
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "xenia/kernel/xsemaphore.h"
|
#include "xenia/kernel/xsemaphore.h"
|
||||||
#include "xenia/kernel/xsymboliclink.h"
|
#include "xenia/kernel/xsymboliclink.h"
|
||||||
#include "xenia/kernel/xthread.h"
|
#include "xenia/kernel/xthread.h"
|
||||||
|
#include "xenia/xbox.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
|
@ -328,14 +329,11 @@ uint8_t* XObject::CreateNative(uint32_t size) {
|
||||||
SetNativePointer(mem + sizeof(X_OBJECT_HEADER), true);
|
SetNativePointer(mem + sizeof(X_OBJECT_HEADER), true);
|
||||||
|
|
||||||
auto header = memory()->TranslateVirtual<X_OBJECT_HEADER*>(mem);
|
auto header = memory()->TranslateVirtual<X_OBJECT_HEADER*>(mem);
|
||||||
|
// todo: should check whether
|
||||||
auto object_type = memory()->SystemHeapAlloc(sizeof(X_OBJECT_TYPE));
|
header->flags = OBJECT_HEADER_IS_TITLE_OBJECT;
|
||||||
if (object_type) {
|
header->pointer_count = 1;
|
||||||
// Set it up in the header.
|
header->handle_count = 0;
|
||||||
// Some kernel method is accessing this struct and dereferencing a member
|
header->object_type_ptr = 0;
|
||||||
// @ offset 0x14
|
|
||||||
header->object_type_ptr = object_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
return memory()->TranslateVirtual(guest_object_ptr_);
|
return memory()->TranslateVirtual(guest_object_ptr_);
|
||||||
}
|
}
|
||||||
|
@ -346,17 +344,11 @@ void XObject::SetNativePointer(uint32_t native_ptr, bool uninitialized) {
|
||||||
// If hit: We've already setup the native ptr with CreateNative!
|
// If hit: We've already setup the native ptr with CreateNative!
|
||||||
assert_zero(guest_object_ptr_);
|
assert_zero(guest_object_ptr_);
|
||||||
|
|
||||||
auto header =
|
|
||||||
kernel_state_->memory()->TranslateVirtual<X_DISPATCH_HEADER*>(native_ptr);
|
|
||||||
|
|
||||||
// Memory uninitialized, so don't bother with the check.
|
|
||||||
if (!uninitialized) {
|
|
||||||
assert_true(!(header->wait_list_blink & 0x1));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stash pointer in struct.
|
// Stash pointer in struct.
|
||||||
// FIXME: This assumes the object has a dispatch header (some don't!)
|
// FIXME: This assumes the object has a dispatch header (some don't!)
|
||||||
StashHandle(header, handle());
|
//StashHandle(header, handle());
|
||||||
|
kernel_state()->object_table()->MapGuestObjectToHostHandle(native_ptr,
|
||||||
|
handle());
|
||||||
|
|
||||||
guest_object_ptr_ = native_ptr;
|
guest_object_ptr_ = native_ptr;
|
||||||
}
|
}
|
||||||
|
@ -375,22 +367,30 @@ object_ref<XObject> XObject::GetNativeObject(KernelState* kernel_state,
|
||||||
// We identify this by setting wait_list_flink to a magic value. When set,
|
// We identify this by setting wait_list_flink to a magic value. When set,
|
||||||
// wait_list_blink will hold a handle to our object.
|
// wait_list_blink will hold a handle to our object.
|
||||||
|
|
||||||
|
auto guest_ptr = kernel_state->memory()->HostToGuestVirtual(native_ptr);
|
||||||
if (!already_locked) {
|
if (!already_locked) {
|
||||||
global_critical_region::mutex().lock();
|
global_critical_region::mutex().lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto header = reinterpret_cast<X_DISPATCH_HEADER*>(native_ptr);
|
|
||||||
XObject* result;
|
XObject* result;
|
||||||
|
|
||||||
|
auto header = reinterpret_cast<X_DISPATCH_HEADER*>(native_ptr);
|
||||||
if (as_type == -1) {
|
if (as_type == -1) {
|
||||||
as_type = header->type;
|
as_type = header->type;
|
||||||
}
|
}
|
||||||
|
auto true_object_header =
|
||||||
|
kernel_state->memory()->TranslateVirtual<X_OBJECT_HEADER*>(guest_ptr-sizeof(X_OBJECT_HEADER));
|
||||||
|
|
||||||
if (header->wait_list_flink == kXObjSignature) {
|
X_HANDLE host_handle;
|
||||||
|
|
||||||
|
|
||||||
|
if (kernel_state->object_table()->HostHandleForGuestObject(guest_ptr, host_handle)) {
|
||||||
// Already initialized.
|
// Already initialized.
|
||||||
// TODO: assert if the type of the object != as_type
|
// TODO: assert if the type of the object != as_type
|
||||||
uint32_t handle = header->wait_list_blink;
|
|
||||||
|
|
||||||
result = kernel_state->object_table()
|
result = kernel_state->object_table()
|
||||||
->LookupObject<XObject>(handle, true)
|
->LookupObject<XObject>(host_handle, true)
|
||||||
.release();
|
.release();
|
||||||
goto return_result;
|
goto return_result;
|
||||||
// TODO(benvanik): assert nothing has been changed in the struct.
|
// TODO(benvanik): assert nothing has been changed in the struct.
|
||||||
|
@ -444,7 +444,9 @@ object_ref<XObject> XObject::GetNativeObject(KernelState* kernel_state,
|
||||||
|
|
||||||
// Stash pointer in struct.
|
// Stash pointer in struct.
|
||||||
// FIXME: This assumes the object contains a dispatch header (some don't!)
|
// FIXME: This assumes the object contains a dispatch header (some don't!)
|
||||||
StashHandle(header, object->handle());
|
// StashHandle(header, object->handle());
|
||||||
|
kernel_state->object_table()->MapGuestObjectToHostHandle(guest_ptr,
|
||||||
|
object->handle());
|
||||||
result = object;
|
result = object;
|
||||||
|
|
||||||
return_result:
|
return_result:
|
||||||
|
|
|
@ -62,28 +62,6 @@ typedef struct {
|
||||||
} X_DISPATCH_HEADER;
|
} X_DISPATCH_HEADER;
|
||||||
static_assert_size(X_DISPATCH_HEADER, 0x10);
|
static_assert_size(X_DISPATCH_HEADER, 0x10);
|
||||||
|
|
||||||
// https://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;
|
|
||||||
};
|
|
||||||
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> object_type_ptr; // -0x8 POBJECT_TYPE
|
|
||||||
xe::be<uint32_t> unk_04; // -0x4
|
|
||||||
|
|
||||||
// Object lives after this header.
|
|
||||||
// (There's actually a body field here which is the object itself)
|
|
||||||
};
|
|
||||||
|
|
||||||
// https://www.nirsoft.net/kernel_struct/vista/OBJECT_CREATE_INFORMATION.html
|
// https://www.nirsoft.net/kernel_struct/vista/OBJECT_CREATE_INFORMATION.html
|
||||||
struct X_OBJECT_CREATE_INFORMATION {
|
struct X_OBJECT_CREATE_INFORMATION {
|
||||||
xe::be<uint32_t> attributes; // 0x0
|
xe::be<uint32_t> attributes; // 0x0
|
||||||
|
@ -99,16 +77,6 @@ struct X_OBJECT_CREATE_INFORMATION {
|
||||||
// Security QoS here (SECURITY_QUALITY_OF_SERVICE) too!
|
// Security QoS here (SECURITY_QUALITY_OF_SERVICE) too!
|
||||||
};
|
};
|
||||||
|
|
||||||
struct X_OBJECT_TYPE {
|
|
||||||
xe::be<uint32_t> constructor; // 0x0
|
|
||||||
xe::be<uint32_t> destructor; // 0x4
|
|
||||||
xe::be<uint32_t> unk_08; // 0x8
|
|
||||||
xe::be<uint32_t> unk_0C; // 0xC
|
|
||||||
xe::be<uint32_t> unk_10; // 0x10
|
|
||||||
xe::be<uint32_t> unk_14; // 0x14 probably offset from ntobject to keobject
|
|
||||||
xe::be<uint32_t> pool_tag; // 0x18
|
|
||||||
};
|
|
||||||
|
|
||||||
class XObject {
|
class XObject {
|
||||||
public:
|
public:
|
||||||
// 45410806 needs proper handle value for certain calculations
|
// 45410806 needs proper handle value for certain calculations
|
||||||
|
@ -221,11 +189,7 @@ class XObject {
|
||||||
return reinterpret_cast<T*>(CreateNative(sizeof(T)));
|
return reinterpret_cast<T*>(CreateNative(sizeof(T)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stash native pointer into X_DISPATCH_HEADER
|
|
||||||
static void StashHandle(X_DISPATCH_HEADER* header, uint32_t handle) {
|
|
||||||
header->wait_list_flink = kXObjSignature;
|
|
||||||
header->wait_list_blink = handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t TimeoutTicksToMs(int64_t timeout_ticks);
|
static uint32_t TimeoutTicksToMs(int64_t timeout_ticks);
|
||||||
|
|
||||||
|
|
|
@ -250,7 +250,7 @@ void StfsContainerDevice::UpdateCachedHashTable(
|
||||||
xe::filesystem::Seek(file, hash_offset + secondary_table_offset, SEEK_SET);
|
xe::filesystem::Seek(file, hash_offset + secondary_table_offset, SEEK_SET);
|
||||||
StfsHashTable table;
|
StfsHashTable table;
|
||||||
if (fread(&table, sizeof(StfsHashTable), 1, file) != 1) {
|
if (fread(&table, sizeof(StfsHashTable), 1, file) != 1) {
|
||||||
XELOGE("GetBlockHash failed to read level{} hash table at 0x{X}",
|
XELOGE("GetBlockHash failed to read level{} hash table at 0x{:08X}",
|
||||||
hash_level, hash_offset + secondary_table_offset);
|
hash_level, hash_offset + secondary_table_offset);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -312,12 +312,62 @@ struct X_EX_TITLE_TERMINATE_REGISTRATION {
|
||||||
};
|
};
|
||||||
static_assert_size(X_EX_TITLE_TERMINATE_REGISTRATION, 16);
|
static_assert_size(X_EX_TITLE_TERMINATE_REGISTRATION, 16);
|
||||||
|
|
||||||
|
|
||||||
|
enum X_OBJECT_HEADER_FLAGS : uint16_t {
|
||||||
|
OBJECT_HEADER_FLAG_NAMED_OBJECT =
|
||||||
|
1, // if set, has X_OBJECT_HEADER_NAME_INFO prior to X_OBJECT_HEADER
|
||||||
|
OBJECT_HEADER_FLAG_IS_PERMANENT = 2,
|
||||||
|
OBJECT_HEADER_FLAG_CONTAINED_IN_DIRECTORY =
|
||||||
|
4, // this object resides in an X_OBJECT_DIRECTORY
|
||||||
|
OBJECT_HEADER_IS_TITLE_OBJECT = 0x10, // used in obcreateobject
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://www.nirsoft.net/kernel_struct/vista/OBJECT_HEADER.html
|
||||||
|
struct X_OBJECT_HEADER {
|
||||||
|
xe::be<uint32_t> pointer_count;
|
||||||
|
xe::be<uint32_t> handle_count;
|
||||||
|
xe::be<uint32_t> object_type_ptr; // -0x8 POBJECT_TYPE
|
||||||
|
xe::be<uint16_t> flags;
|
||||||
|
uint8_t unknownE;
|
||||||
|
uint8_t unknownF;
|
||||||
|
// Object lives after this header.
|
||||||
|
// (There's actually a body field here which is the object itself)
|
||||||
|
};
|
||||||
|
static_assert_size(X_OBJECT_HEADER, 0x10);
|
||||||
|
|
||||||
|
struct X_OBJECT_DIRECTORY {
|
||||||
|
// each is a pointer to X_OBJECT_HEADER_NAME_INFO
|
||||||
|
// i believe offset 0 = pointer to next in bucket
|
||||||
|
xe::be<uint32_t> name_buckets[13];
|
||||||
|
};
|
||||||
|
static_assert_size(X_OBJECT_DIRECTORY, 0x34);
|
||||||
|
|
||||||
|
// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/ntos/ob/object_header_name_info.htm
|
||||||
|
// quite different, though
|
||||||
|
struct X_OBJECT_HEADER_NAME_INFO {
|
||||||
|
// i think that this is the next link in an X_OBJECT_DIRECTORY's buckets
|
||||||
|
xe::be<uint32_t> next_in_directory;
|
||||||
|
xe::be<uint32_t> object_directory; // pointer to X_OBJECT_DIRECTORY
|
||||||
|
X_ANSI_STRING name;
|
||||||
|
};
|
||||||
struct X_OBJECT_ATTRIBUTES {
|
struct X_OBJECT_ATTRIBUTES {
|
||||||
xe::be<uint32_t> root_directory; // 0x0
|
xe::be<uint32_t> root_directory; // 0x0
|
||||||
xe::be<uint32_t> name_ptr; // 0x4 PANSI_STRING
|
xe::be<uint32_t> name_ptr; // 0x4 PANSI_STRING
|
||||||
xe::be<uint32_t> attributes; // 0xC
|
xe::be<uint32_t> attributes; // 0xC
|
||||||
};
|
};
|
||||||
|
struct X_OBJECT_TYPE {
|
||||||
|
xe::be<uint32_t> allocate_proc; // 0x0
|
||||||
|
xe::be<uint32_t> free_proc; // 0x4
|
||||||
|
xe::be<uint32_t> close_proc; // 0x8
|
||||||
|
xe::be<uint32_t> delete_proc; // 0xC
|
||||||
|
xe::be<uint32_t> unknown_proc; // 0x10
|
||||||
|
xe::be<uint32_t>
|
||||||
|
unknown_size_or_object_; // this seems to be a union, it can be a pointer
|
||||||
|
// or it can be the size of the object
|
||||||
|
xe::be<uint32_t> pool_tag; // 0x18
|
||||||
|
};
|
||||||
|
static_assert_size(X_OBJECT_TYPE, 0x1C);
|
||||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363082.aspx
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363082.aspx
|
||||||
typedef struct {
|
typedef struct {
|
||||||
// Renamed due to a collision with exception_code from Windows excpt.h.
|
// Renamed due to a collision with exception_code from Windows excpt.h.
|
||||||
|
|
Loading…
Reference in New Issue