Merge pull request #159 from chrisps/info_stubs_and_misc_kernel

[Kernel] Implement misc functions, bandaids for 415608D8
This commit is contained in:
chrisps 2023-05-01 10:13:49 -04:00 committed by GitHub
commit 1319ff6ead
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 249 additions and 30 deletions

View File

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

View File

@ -54,6 +54,16 @@ struct X_FILE_FS_ATTRIBUTE_INFORMATION {
};
static_assert_size(X_FILE_FS_ATTRIBUTE_INFORMATION, 16);
enum X_FILE_DEVICE_TYPE : uint32_t {
FILE_DEVICE_UNKNOWN = 0x22
};
struct X_FILE_FS_DEVICE_INFORMATION {
be<X_FILE_DEVICE_TYPE> device_type;
be<uint32_t> characteristics;
};
static_assert_size(X_FILE_FS_DEVICE_INFORMATION, 8);
#pragma pack(pop)
} // namespace kernel

View File

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

View File

@ -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,44 @@ 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] = {
X_PAGE_READONLY,
X_PAGE_READWRITE | X_PAGE_NOCACHE,
X_PAGE_READWRITE,
X_PAGE_WRITECOMBINE | X_PAGE_READWRITE
};
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) {
// setting default alignment
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 +464,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

View File

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

View File

@ -92,10 +92,14 @@ 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*>();
size_t fname_hash = xe::memory::hash_combine(82589933LL, file->path());
*info = static_cast<uint32_t>(fname_hash ^ (fname_hash >> 32));
out_length = sizeof(uint32_t);
break;
}
case XFileXctdCompressionInformation: {
@ -338,9 +342,16 @@ 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!");
info->device_type = FILE_DEVICE_UNKNOWN; // 415608D8 checks for 0x46;
info->characteristics = 0;
out_length = sizeof(X_FILE_FS_DEVICE_INFORMATION);
break;
}
default: {
// Unsupported, for now.
assert_always();
out_length = 0;
break;

View File

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

View File

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

View File

@ -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 != IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
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) {

View File

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