Check for null string passed to Win32Thread::set_name
Move impl of XamAlloc into XamAllocImpl Implement XamAllocEx Implement XamIsCurrentTitleDash Implement XamGetLocaleDateFormat Implement "stub" of XFileFsDeviceInformation, XFileSectorInformation (log warnings when they're executed so this doesnt get mistaken for an actual implementation) Added xboxkrnl_memory file Moved meat of MmAllocatePhysicalMemoryEx into xeMmAllocatePhysicalMemoryEx, exposed its definition via xboxkrnl_memory. Moved impl of RtlImageHeaderNt into a helper function Implement RtlImageDirectoryEntryToData Implement KeSuspendThread Check for bad handles passed in XOVERLAPPED, fixes crash in 415608D8
This commit is contained in:
parent
37051afcaf
commit
b270c59d0c
|
@ -149,10 +149,11 @@ void MaybeYield() {
|
|||
// MemoryBarrier();
|
||||
}
|
||||
void NanoSleep(int64_t ns) {
|
||||
//nanosleep is done in 100 nanosecond increments
|
||||
// nanosleep is done in 100 nanosecond increments
|
||||
int64_t in_nt_increments = ns / 100LL;
|
||||
if (in_nt_increments == 0 && ns != 0) {
|
||||
//if we're explicitly requesting a delay of 0 ns, let it go through, otherwise if it was less than a 100ns increment we round up to 100ns
|
||||
// if we're explicitly requesting a delay of 0 ns, let it go through,
|
||||
// otherwise if it was less than a 100ns increment we round up to 100ns
|
||||
in_nt_increments = 1;
|
||||
}
|
||||
in_nt_increments = -in_nt_increments;
|
||||
|
@ -514,6 +515,10 @@ class Win32Thread : public Win32Handle<Thread> {
|
|||
~Win32Thread() = default;
|
||||
|
||||
void set_name(std::string name) override {
|
||||
// this can actually happen in some debug builds
|
||||
if (&name == nullptr) {
|
||||
return;
|
||||
}
|
||||
xe::threading::set_name(handle_, name);
|
||||
Thread::set_name(name);
|
||||
}
|
||||
|
|
|
@ -54,6 +54,12 @@ struct X_FILE_FS_ATTRIBUTE_INFORMATION {
|
|||
};
|
||||
static_assert_size(X_FILE_FS_ATTRIBUTE_INFORMATION, 16);
|
||||
|
||||
struct X_FILE_FS_DEVICE_INFORMATION {
|
||||
be<uint32_t> device_type;
|
||||
be<uint32_t> characteristics;
|
||||
};
|
||||
static_assert_size(X_FILE_FS_DEVICE_INFORMATION, 8);
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
} // namespace kernel
|
||||
|
|
|
@ -854,10 +854,11 @@ void KernelState::CompleteOverlappedDeferredEx(
|
|||
XOverlappedSetContext(ptr, XThread::GetCurrentThreadHandle());
|
||||
X_HANDLE event_handle = XOverlappedGetEvent(ptr);
|
||||
if (event_handle) {
|
||||
auto ev = object_table()->LookupObject<XEvent>(event_handle);
|
||||
auto ev = object_table()->LookupObject<XObject>(event_handle);
|
||||
|
||||
assert_not_null(ev);
|
||||
if (ev) {
|
||||
ev->Reset();
|
||||
if (ev && ev->type() == XObject::Type::Event) {
|
||||
ev.get<XEvent>()->Reset();
|
||||
}
|
||||
}
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "xenia/kernel/util/shim_utils.h"
|
||||
#include "xenia/kernel/xam/xam_module.h"
|
||||
#include "xenia/kernel/xam/xam_private.h"
|
||||
#include "xenia/kernel/xboxkrnl/xboxkrnl_memory.h"
|
||||
#include "xenia/kernel/xboxkrnl/xboxkrnl_threading.h"
|
||||
#include "xenia/kernel/xenumerator.h"
|
||||
#include "xenia/kernel/xthread.h"
|
||||
|
@ -261,10 +262,8 @@ dword_result_t RtlSleep_entry(dword_t dwMilliseconds, dword_t bAlertable) {
|
|||
? LLONG_MAX
|
||||
: static_cast<LONGLONG>(-10000) * dwMilliseconds;
|
||||
|
||||
X_STATUS result = xboxkrnl::KeDelayExecutionThread(
|
||||
MODE::UserMode,
|
||||
bAlertable,
|
||||
(uint64_t*)&delay);
|
||||
X_STATUS result = xboxkrnl::KeDelayExecutionThread(MODE::UserMode, bAlertable,
|
||||
(uint64_t*)&delay);
|
||||
|
||||
// If the delay was interrupted by an APC, keep delaying the thread
|
||||
while (bAlertable && result == X_STATUS_ALERTED) {
|
||||
|
@ -396,7 +395,8 @@ void XamLoaderTerminateTitle_entry() {
|
|||
}
|
||||
DECLARE_XAM_EXPORT1(XamLoaderTerminateTitle, kNone, kSketchy);
|
||||
|
||||
dword_result_t XamAlloc_entry(dword_t flags, dword_t size, lpdword_t out_ptr) {
|
||||
uint32_t XamAllocImpl(uint32_t flags, uint32_t size,
|
||||
xe::be<uint32_t>* out_ptr) {
|
||||
if (flags & 0x00100000) { // HEAP_ZERO_memory used unless this flag
|
||||
// do nothing!
|
||||
// maybe we ought to fill it with nonzero garbage, but otherwise this is a
|
||||
|
@ -412,8 +412,38 @@ dword_result_t XamAlloc_entry(dword_t flags, dword_t size, lpdword_t out_ptr) {
|
|||
|
||||
return X_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
dword_result_t XamAlloc_entry(dword_t flags, dword_t size, lpdword_t out_ptr) {
|
||||
return XamAllocImpl(flags, size, out_ptr);
|
||||
}
|
||||
DECLARE_XAM_EXPORT1(XamAlloc, kMemory, kImplemented);
|
||||
|
||||
static const unsigned short XamPhysicalProtTable[4] = {2, 516, 4, 1028};
|
||||
|
||||
dword_result_t XamAllocEx_entry(dword_t phys_flags, dword_t flags, dword_t size,
|
||||
lpdword_t out_ptr, const ppc_context_t& ctx) {
|
||||
if ((flags & 0x40000000) == 0) {
|
||||
return XamAllocImpl(flags, size, out_ptr);
|
||||
}
|
||||
|
||||
uint32_t flags_remapped = phys_flags;
|
||||
if ((phys_flags & 0xF000000) == 0) {
|
||||
flags_remapped = 0xC000000 | phys_flags & 0xF0FFFFFF;
|
||||
}
|
||||
|
||||
uint32_t result = xboxkrnl::xeMmAllocatePhysicalMemoryEx(
|
||||
2, size, XamPhysicalProtTable[(flags_remapped >> 28) & 0b11], 0,
|
||||
0xFFFFFFFF, 1 << ((flags_remapped >> 24) & 0xF));
|
||||
|
||||
if (result && (flags_remapped & 0x40000000) != 0) {
|
||||
memset(ctx->TranslateVirtual<uint8_t*>(result), 0, size);
|
||||
}
|
||||
|
||||
*out_ptr = result;
|
||||
return result ? 0 : 0x8007000E;
|
||||
}
|
||||
DECLARE_XAM_EXPORT1(XamAllocEx, kMemory, kImplemented);
|
||||
|
||||
dword_result_t XamFree_entry(lpdword_t ptr) {
|
||||
kernel_state()->memory()->SystemHeapFree(ptr.guest_address());
|
||||
|
||||
|
@ -428,6 +458,11 @@ dword_result_t XamQueryLiveHiveW_entry(lpu16string_t name, lpvoid_t out_buf,
|
|||
}
|
||||
DECLARE_XAM_EXPORT1(XamQueryLiveHiveW, kNone, kStub);
|
||||
|
||||
dword_result_t XamIsCurrentTitleDash_entry(const ppc_context_t& ctx) {
|
||||
return ctx->kernel_state->title_id() == 0xFFFE07D1;
|
||||
}
|
||||
DECLARE_XAM_EXPORT1(XamIsCurrentTitleDash, kNone, kImplemented);
|
||||
|
||||
} // namespace xam
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
|
|
@ -431,6 +431,26 @@ dword_result_t XamGetLocaleEx_entry(dword_t max_country_id,
|
|||
static_cast<uint8_t>(max_locale_id));
|
||||
}
|
||||
DECLARE_XAM_EXPORT1(XamGetLocaleEx, kLocale, kImplemented);
|
||||
//originally a switch table, wrote a script to extract the values for all possible cases
|
||||
|
||||
static constexpr uint8_t XamLocaleDateFmtTable[] = {
|
||||
2, 1, 3, 1, 3, 3, 3, 3, 3, 3, 3, 2, 3, 2, 1, 4, 2, 3, 1, 2, 2, 3,
|
||||
3, 3, 3, 3, 2, 1, 3, 2, 2, 3, 0, 3, 0, 3, 3, 5, 3, 1, 3, 2, 3, 3,
|
||||
3, 2, 3, 3, 5, 3, 3, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
2, 3, 3, 0, 2, 1, 3, 3, 3, 3, 3, 5, 3, 2, 3, 3, 3, 2, 3, 5, 0, 3,
|
||||
1, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 5, 1, 1, 1, 1};
|
||||
|
||||
dword_result_t XamGetLocaleDateFormat_entry(dword_t locale) {
|
||||
uint32_t biased_locale = locale - 5;
|
||||
int result = 3;
|
||||
if (biased_locale > 0x68) {
|
||||
return result;
|
||||
} else {
|
||||
return XamLocaleDateFmtTable[biased_locale];
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_XAM_EXPORT1(XamGetLocaleDateFormat, kLocale, kImplemented);
|
||||
|
||||
} // namespace xam
|
||||
} // namespace kernel
|
||||
|
|
|
@ -92,10 +92,15 @@ dword_result_t NtQueryInformationFile_entry(
|
|||
break;
|
||||
}
|
||||
case XFileSectorInformation: {
|
||||
// TODO(benvanik): return sector this file's on.
|
||||
XELOGE("NtQueryInformationFile(XFileSectorInformation) unimplemented");
|
||||
status = X_STATUS_INVALID_PARAMETER;
|
||||
out_length = 0;
|
||||
// SW that uses this seems to use the output as a way of uniquely
|
||||
// identifying a file for sorting/lookup so we can just give it an
|
||||
// arbitrary 4 byte integer most of the time
|
||||
XELOGW("Stub XFileSectorInformation!");
|
||||
auto info = info_ptr.as<uint32_t*>();
|
||||
//low 32 bits of ptr. todo: maybe hash name?
|
||||
*info = static_cast<uint32_t>(
|
||||
reinterpret_cast<uintptr_t>(file->file()->entry()));
|
||||
out_length = 4;
|
||||
break;
|
||||
}
|
||||
case XFileXctdCompressionInformation: {
|
||||
|
@ -338,9 +343,17 @@ dword_result_t NtQueryVolumeInformationFile_entry(
|
|||
}
|
||||
break;
|
||||
}
|
||||
case XFileFsDeviceInformation:
|
||||
case XFileFsDeviceInformation: {
|
||||
auto info = info_ptr.as<X_FILE_FS_DEVICE_INFORMATION*>();
|
||||
auto file_device = file->device();
|
||||
XELOGW("Stub XFileFsDeviceInformation!");
|
||||
//FILE_DEVICE_UNKNOWN
|
||||
info->device_type = 0x22; // 415608D8 checks for 0x46;
|
||||
info->characteristics = 0;
|
||||
out_length = 8;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// Unsupported, for now.
|
||||
assert_always();
|
||||
out_length = 0;
|
||||
break;
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "xenia/kernel/util/shim_utils.h"
|
||||
#include "xenia/kernel/xboxkrnl/xboxkrnl_private.h"
|
||||
#include "xenia/xbox.h"
|
||||
|
||||
#include "xenia/kernel/xboxkrnl/xboxkrnl_memory.h"
|
||||
DEFINE_bool(
|
||||
ignore_offset_for_ranged_allocations, false,
|
||||
"Allows to ignore 4k offset for physical allocations with provided range. "
|
||||
|
@ -379,9 +379,11 @@ dword_result_t NtAllocateEncryptedMemory_entry(dword_t unk, dword_t region_size,
|
|||
}
|
||||
DECLARE_XBOXKRNL_EXPORT1(NtAllocateEncryptedMemory, kMemory, kImplemented);
|
||||
|
||||
dword_result_t MmAllocatePhysicalMemoryEx_entry(
|
||||
dword_t flags, dword_t region_size, dword_t protect_bits,
|
||||
dword_t min_addr_range, dword_t max_addr_range, dword_t alignment) {
|
||||
uint32_t xeMmAllocatePhysicalMemoryEx(uint32_t flags, uint32_t region_size,
|
||||
uint32_t protect_bits,
|
||||
uint32_t min_addr_range,
|
||||
uint32_t max_addr_range,
|
||||
uint32_t alignment) {
|
||||
// Type will usually be 0 (user request?), where 1 and 2 are sometimes made
|
||||
// by D3D/etc.
|
||||
|
||||
|
@ -430,9 +432,9 @@ dword_result_t MmAllocatePhysicalMemoryEx_entry(
|
|||
}
|
||||
|
||||
uint32_t heap_min_addr =
|
||||
xe::sat_sub(min_addr_range.value(), heap_physical_address_offset);
|
||||
xe::sat_sub(min_addr_range, heap_physical_address_offset);
|
||||
uint32_t heap_max_addr =
|
||||
xe::sat_sub(max_addr_range.value(), heap_physical_address_offset);
|
||||
xe::sat_sub(max_addr_range, heap_physical_address_offset);
|
||||
uint32_t heap_size = heap->heap_size();
|
||||
heap_min_addr = heap_base + std::min(heap_min_addr, heap_size - 1);
|
||||
heap_max_addr = heap_base + std::min(heap_max_addr, heap_size - 1);
|
||||
|
@ -447,12 +449,20 @@ dword_result_t MmAllocatePhysicalMemoryEx_entry(
|
|||
|
||||
return base_address;
|
||||
}
|
||||
|
||||
dword_result_t MmAllocatePhysicalMemoryEx_entry(
|
||||
dword_t flags, dword_t region_size, dword_t protect_bits,
|
||||
dword_t min_addr_range, dword_t max_addr_range, dword_t alignment) {
|
||||
return xeMmAllocatePhysicalMemoryEx(flags, region_size, protect_bits,
|
||||
min_addr_range, max_addr_range,
|
||||
alignment);
|
||||
}
|
||||
DECLARE_XBOXKRNL_EXPORT1(MmAllocatePhysicalMemoryEx, kMemory, kImplemented);
|
||||
|
||||
dword_result_t MmAllocatePhysicalMemory_entry(dword_t flags,
|
||||
dword_t region_size,
|
||||
dword_t protect_bits) {
|
||||
return MmAllocatePhysicalMemoryEx_entry(flags, region_size, protect_bits, 0,
|
||||
return xeMmAllocatePhysicalMemoryEx(flags, region_size, protect_bits, 0,
|
||||
0xFFFFFFFFu, 0);
|
||||
}
|
||||
DECLARE_XBOXKRNL_EXPORT1(MmAllocatePhysicalMemory, kMemory, kImplemented);
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_XBOXKRNL_XBOXKRNL_MEMORY_H_
|
||||
#define XENIA_KERNEL_XBOXKRNL_XBOXKRNL_MEMORY_H_
|
||||
|
||||
#include "xenia/kernel/util/shim_utils.h"
|
||||
#include "xenia/xbox.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
|
||||
|
||||
namespace xboxkrnl {
|
||||
|
||||
uint32_t xeMmAllocatePhysicalMemoryEx(uint32_t flags, uint32_t region_size,
|
||||
uint32_t protect_bits,
|
||||
uint32_t min_addr_range,
|
||||
uint32_t max_addr_range,
|
||||
uint32_t alignment);
|
||||
|
||||
} // namespace xboxkrnl
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_KERNEL_XBOXKRNL_XBOXKRNL_MEMORY_H_
|
|
@ -12,6 +12,7 @@
|
|||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include "third_party/pe/pe_image.h"
|
||||
#include "xenia/base/atomic.h"
|
||||
#include "xenia/base/chrono.h"
|
||||
#include "xenia/base/logging.h"
|
||||
|
@ -24,7 +25,6 @@
|
|||
#include "xenia/kernel/xboxkrnl/xboxkrnl_threading.h"
|
||||
#include "xenia/kernel/xevent.h"
|
||||
#include "xenia/kernel/xthread.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace xboxkrnl {
|
||||
|
@ -402,14 +402,14 @@ DECLARE_XBOXKRNL_EXPORT3(RtlUnicodeToMultiByteN, kNone, kImplemented,
|
|||
kHighFrequency, kSketchy);
|
||||
|
||||
// https://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Executable%20Images/RtlImageNtHeader.html
|
||||
pointer_result_t RtlImageNtHeader_entry(lpvoid_t module) {
|
||||
static IMAGE_NT_HEADERS32* ImageNtHeader(uint8_t* module) {
|
||||
if (!module) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Little-endian! no swapping!
|
||||
|
||||
auto dos_header = module.as<const uint8_t*>();
|
||||
auto dos_header = module;
|
||||
auto dos_magic = *reinterpret_cast<const uint16_t*>(&dos_header[0x00]);
|
||||
if (dos_magic != 0x5A4D) { // 'MZ'
|
||||
return 0;
|
||||
|
@ -421,9 +421,82 @@ pointer_result_t RtlImageNtHeader_entry(lpvoid_t module) {
|
|||
if (nt_magic != 0x4550) { // 'PE'
|
||||
return 0;
|
||||
}
|
||||
return kernel_memory()->HostToGuestVirtual(nt_header);
|
||||
return reinterpret_cast<IMAGE_NT_HEADERS32*>(nt_header);
|
||||
}
|
||||
|
||||
pointer_result_t RtlImageNtHeader_entry(lpvoid_t module) {
|
||||
auto result = ImageNtHeader(module.as<uint8_t*>());
|
||||
if (!result) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return kernel_memory()->HostToGuestVirtual(result);
|
||||
}
|
||||
DECLARE_XBOXKRNL_EXPORT1(RtlImageNtHeader, kNone, kImplemented);
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-imagedirectoryentrytodata
|
||||
dword_result_t RtlImageDirectoryEntryToData_entry(dword_t Base, dword_t MappedAsImage_,
|
||||
word_t DirectoryEntry, dword_t Size,
|
||||
const ppc_context_t& ctx) {
|
||||
bool MappedAsImage = static_cast<unsigned char>(MappedAsImage_);
|
||||
uint32_t aligned_base = Base;
|
||||
if ((Base & 1) != 0) {
|
||||
aligned_base = Base & 0xFFFFFFFE;
|
||||
MappedAsImage = false;
|
||||
}
|
||||
IMAGE_NT_HEADERS32* nt_header =
|
||||
ImageNtHeader(ctx->TranslateVirtual<uint8_t*>(aligned_base));
|
||||
|
||||
if (!nt_header) {
|
||||
return 0;
|
||||
}
|
||||
if (nt_header->OptionalHeader.Magic != 0x10B) {
|
||||
return 0;
|
||||
}
|
||||
if (DirectoryEntry >= nt_header->OptionalHeader.NumberOfRvaAndSizes) {
|
||||
return 0;
|
||||
}
|
||||
uint32_t Address =
|
||||
nt_header->OptionalHeader.DataDirectory[DirectoryEntry].VirtualAddress;
|
||||
if (!Address) {
|
||||
return 0;
|
||||
}
|
||||
xe::store_and_swap<uint32_t>(
|
||||
ctx->TranslateVirtual(Size),
|
||||
nt_header->OptionalHeader.DataDirectory[DirectoryEntry].Size);
|
||||
if (MappedAsImage || Address < nt_header->OptionalHeader.SizeOfHeaders) {
|
||||
return aligned_base + Address;
|
||||
}
|
||||
|
||||
uint32_t n_sections = nt_header->FileHeader.NumberOfSections;
|
||||
IMAGE_SECTION_HEADER* v8 = reinterpret_cast<IMAGE_SECTION_HEADER*>(
|
||||
reinterpret_cast<char*>(&nt_header->OptionalHeader) +
|
||||
nt_header->FileHeader.SizeOfOptionalHeader);
|
||||
if (!n_sections) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t i = 0;
|
||||
while (true) {
|
||||
uint32_t section_virtual_address = v8->VirtualAddress;
|
||||
uint32_t sizeof_section = v8->SizeOfRawData;
|
||||
if (Address >= section_virtual_address &&
|
||||
Address < sizeof_section + section_virtual_address) {
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
++v8;
|
||||
if (i >= n_sections) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (v8) {
|
||||
return aligned_base + Address - v8->VirtualAddress;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DECLARE_XBOXKRNL_EXPORT1(RtlImageDirectoryEntryToData, kNone, kImplemented);
|
||||
|
||||
pointer_result_t RtlImageXexHeaderField_entry(pointer_t<xex2_header> xex_header,
|
||||
dword_t field_dword) {
|
||||
|
|
|
@ -185,7 +185,7 @@ dword_result_t NtResumeThread_entry(dword_t handle,
|
|||
}
|
||||
DECLARE_XBOXKRNL_EXPORT1(NtResumeThread, kThreading, kImplemented);
|
||||
|
||||
dword_result_t KeResumeThread_entry(lpvoid_t thread_ptr) {
|
||||
dword_result_t KeResumeThread_entry(pointer_t<X_KTHREAD> thread_ptr) {
|
||||
X_STATUS result = X_STATUS_SUCCESS;
|
||||
auto thread = XObject::GetNativeObject<XThread>(kernel_state(), thread_ptr);
|
||||
if (thread) {
|
||||
|
@ -230,11 +230,27 @@ dword_result_t NtSuspendThread_entry(dword_t handle,
|
|||
}
|
||||
DECLARE_XBOXKRNL_EXPORT1(NtSuspendThread, kThreading, kImplemented);
|
||||
|
||||
dword_result_t KeSuspendThread_entry(pointer_t<X_KTHREAD> kthread,
|
||||
const ppc_context_t& context) {
|
||||
auto thread = XObject::GetNativeObject<XThread>(context->kernel_state, kthread);
|
||||
uint32_t suspend_count_out = 0;
|
||||
|
||||
if (thread) {
|
||||
suspend_count_out = thread->suspend_count();
|
||||
|
||||
uint32_t discarded_new_suspend_count = 0;
|
||||
thread->Suspend(&discarded_new_suspend_count);
|
||||
}
|
||||
|
||||
return suspend_count_out;
|
||||
}
|
||||
DECLARE_XBOXKRNL_EXPORT1(KeSuspendThread, kThreading, kImplemented);
|
||||
|
||||
void KeSetCurrentStackPointers_entry(lpvoid_t stack_ptr,
|
||||
pointer_t<X_KTHREAD> thread,
|
||||
lpvoid_t stack_alloc_base,
|
||||
lpvoid_t stack_base,
|
||||
lpvoid_t stack_limit, const ppc_context_t& context) {
|
||||
lpvoid_t stack_base, lpvoid_t stack_limit,
|
||||
const ppc_context_t& context) {
|
||||
auto current_thread = XThread::GetCurrentThread();
|
||||
|
||||
auto pcr = context->TranslateVirtualGPR<X_KPCR*>(context->r[13]);
|
||||
|
|
Loading…
Reference in New Issue