[Kernel] Revert Guest->Host Object Mapping

This commit is contained in:
Gliniak 2024-01-19 21:03:57 +01:00 committed by Radosław Gliński
parent be689457cb
commit 18b5a6706a
7 changed files with 60 additions and 80 deletions

View File

@ -109,6 +109,7 @@ struct X_UNKNOWN_TYPE_REFED {
points_to_prior; // points to the previous field, which points to itself points_to_prior; // points to the previous field, which points to itself
}; };
static_assert_size(X_UNKNOWN_TYPE_REFED, 16); static_assert_size(X_UNKNOWN_TYPE_REFED, 16);
struct KernelGuestGlobals { struct KernelGuestGlobals {
X_OBJECT_TYPE ExThreadObjectType; X_OBJECT_TYPE ExThreadObjectType;
X_OBJECT_TYPE ExEventObjectType; X_OBJECT_TYPE ExEventObjectType;

View File

@ -17,6 +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;
} // namespace xe::kernel } // namespace xe::kernel

View File

@ -479,44 +479,6 @@ 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);
}
}
void ObjectTable::FlushGuestToHostMapping(uint32_t base_address,
uint32_t length) {
auto global_lock = global_critical_region_.Acquire();
auto iterator = guest_to_host_handle_.lower_bound(base_address);
while (iterator !=guest_to_host_handle_.end() && iterator->first >= base_address && iterator->first < (base_address + length)) {
auto old_mapping = iterator;
iterator++;
auto node_handle = guest_to_host_handle_.extract(old_mapping);
}
}
} // namespace util } // namespace util
} // namespace kernel } // namespace kernel
} // namespace xe } // namespace xe

View File

@ -80,10 +80,6 @@ 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);
void FlushGuestToHostMapping(uint32_t base_address, uint32_t length);
private: private:
struct ObjectTableEntry { struct ObjectTableEntry {
int handle_ref_count = 0; int handle_ref_count = 0;
@ -111,7 +107,6 @@ 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::map<uint32_t, X_HANDLE> guest_to_host_handle_;
}; };
// Generic lookup // Generic lookup

View File

@ -55,10 +55,14 @@ XObject::~XObject() {
assert_zero(pointer_ref_count_); assert_zero(pointer_ref_count_);
if (allocated_guest_object_) { if (allocated_guest_object_) {
kernel_state()->object_table()->UnmapGuestObjectHostHandle( uint32_t ptr = guest_object_ptr_ - sizeof(X_OBJECT_HEADER);
guest_object_ptr_); auto header = memory()->TranslateVirtual<X_OBJECT_HEADER*>(ptr);
// Free the object creation info
if (header->object_type_ptr) {
memory()->SystemHeapFree(header->object_type_ptr);
}
const uint32_t ptr = guest_object_ptr_ - sizeof(X_OBJECT_HEADER);
memory()->SystemHeapFree(ptr); memory()->SystemHeapFree(ptr);
} }
} }
@ -323,14 +327,12 @@ 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);
header->flags = OBJECT_HEADER_IS_TITLE_OBJECT;
header->pointer_count = 1;
header->handle_count = 0;
// Added to prevent having nullptr crashes on semaphore.
// This should probably work differently, but for now it is good enough (hopefully).
auto object_type = memory()->SystemHeapAlloc(sizeof(X_OBJECT_TYPE)); auto object_type = memory()->SystemHeapAlloc(sizeof(X_OBJECT_TYPE));
if (object_type) { if (object_type) {
// Set it up in the header.
// Some kernel method is accessing this struct and dereferencing a member
// @ offset 0x14
header->object_type_ptr = object_type; header->object_type_ptr = object_type;
} }
@ -343,8 +345,17 @@ 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_);
kernel_state()->object_table()->MapGuestObjectToHostHandle(native_ptr, auto header =
handle()); 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.
// FIXME: This assumes the object has a dispatch header (some don't!)
StashHandle(header, handle());
guest_object_ptr_ = native_ptr; guest_object_ptr_ = native_ptr;
} }
@ -362,8 +373,6 @@ object_ref<XObject> XObject::GetNativeObject(KernelState* kernel_state,
// each time. // each time.
// 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();
} }
@ -375,14 +384,11 @@ object_ref<XObject> XObject::GetNativeObject(KernelState* kernel_state,
as_type = header->type; as_type = header->type;
} }
X_HANDLE host_handle; if (header->wait_list_flink == kXObjSignature) {
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
result = kernel_state->object_table() uint32_t handle = header->wait_list_blink;
->LookupObject<XObject>(host_handle, true) result = kernel_state->object_table()->LookupObject<XObject>(handle, true).release();
.release();
} else { } else {
// First use, create new. // First use, create new.
// https://www.nirsoft.net/kernel_struct/vista/KOBJECTS.html // https://www.nirsoft.net/kernel_struct/vista/KOBJECTS.html
@ -426,12 +432,10 @@ object_ref<XObject> XObject::GetNativeObject(KernelState* kernel_state,
assert_always(); assert_always();
result = nullptr; result = nullptr;
} }
// Stash pointer in struct.
if (object) { // FIXME: This assumes the object contains a dispatch header (some don't!)
kernel_state->object_table()->MapGuestObjectToHostHandle( StashHandle(header, object->handle());
guest_ptr, object->handle()); result = object;
result = object;
}
} }
if (!already_locked) { if (!already_locked) {

View File

@ -62,6 +62,28 @@ 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
@ -219,6 +241,12 @@ 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);
KernelState* kernel_state_; KernelState* kernel_state_;

View File

@ -323,19 +323,6 @@ enum X_OBJECT_HEADER_FLAGS : uint16_t {
}; };
// 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 { struct X_OBJECT_DIRECTORY {
// each is a pointer to X_OBJECT_HEADER_NAME_INFO // each is a pointer to X_OBJECT_HEADER_NAME_INFO
// i believe offset 0 = pointer to next in bucket // i believe offset 0 = pointer to next in bucket
@ -351,11 +338,13 @@ struct X_OBJECT_HEADER_NAME_INFO {
xe::be<uint32_t> object_directory; // pointer to X_OBJECT_DIRECTORY xe::be<uint32_t> object_directory; // pointer to X_OBJECT_DIRECTORY
X_ANSI_STRING name; 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 { struct X_OBJECT_TYPE {
xe::be<uint32_t> allocate_proc; // 0x0 xe::be<uint32_t> allocate_proc; // 0x0
xe::be<uint32_t> free_proc; // 0x4 xe::be<uint32_t> free_proc; // 0x4