Merge pull request #180 from chrisps/iodevices_and_deterrents
Misc kernel changes, deterrents
This commit is contained in:
commit
e54262b710
|
@ -850,7 +850,11 @@ void EmulatorWindow::OnKeyDown(ui::KeyEvent& e) {
|
|||
} break;
|
||||
|
||||
case ui::VirtualKey::kF2: {
|
||||
if (e.is_ctrl_pressed()) {
|
||||
emulator()->ClearStickyPersistentFlags();
|
||||
} else {
|
||||
ShowBuildCommit();
|
||||
}
|
||||
} break;
|
||||
|
||||
case ui::VirtualKey::kF9: {
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "xenia/base/mapped_memory.h"
|
||||
#include "xenia/base/platform.h"
|
||||
#include "xenia/base/string.h"
|
||||
#include "xenia/base/system.h"
|
||||
#include "xenia/cpu/backend/code_cache.h"
|
||||
#include "xenia/cpu/backend/null_backend.h"
|
||||
#include "xenia/cpu/cpu_flags.h"
|
||||
|
@ -109,7 +110,15 @@ Emulator::Emulator(const std::filesystem::path& command_line,
|
|||
title_id_(std::nullopt),
|
||||
paused_(false),
|
||||
restoring_(false),
|
||||
restore_fence_() {}
|
||||
restore_fence_() {
|
||||
// show the quickstart guide the first time they ever open the emulator
|
||||
uint64_t persistent_flags = GetPersistentEmulatorFlags();
|
||||
if (!(persistent_flags & EmulatorFlagQuickstartShown)) {
|
||||
LaunchWebBrowser(
|
||||
"https://github.com/xenia-canary/xenia-canary/wiki/Quickstart");
|
||||
SetPersistentEmulatorFlags(persistent_flags | EmulatorFlagQuickstartShown);
|
||||
}
|
||||
}
|
||||
|
||||
Emulator::~Emulator() {
|
||||
// Note that we delete things in the reverse order they were initialized.
|
||||
|
@ -280,30 +289,161 @@ X_STATUS Emulator::TerminateTitle() {
|
|||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
std::string Emulator::CanonicalizeFileExtension(
|
||||
const std::filesystem::path& path) {
|
||||
return xe::utf8::lower_ascii(xe::path_to_utf8(path.extension()));
|
||||
}
|
||||
|
||||
const std::unique_ptr<vfs::Device> Emulator::CreateVfsDeviceBasedOnPath(
|
||||
const std::filesystem::path& path, const std::string_view mount_path) {
|
||||
if (!path.has_extension()) {
|
||||
return std::make_unique<vfs::StfsContainerDevice>(mount_path, path);
|
||||
}
|
||||
auto extension = xe::utf8::lower_ascii(xe::path_to_utf8(path.extension()));
|
||||
auto extension = CanonicalizeFileExtension(path);
|
||||
if (extension == ".xex" || extension == ".elf" || extension == ".exe") {
|
||||
auto parent_path = path.parent_path();
|
||||
return std::make_unique<vfs::HostPathDevice>(
|
||||
mount_path, parent_path, !cvars::allow_game_relative_writes);
|
||||
} else {
|
||||
} else if (extension == ".7z" || extension == ".zip" || extension == ".rar") {
|
||||
xe::ShowSimpleMessageBox(
|
||||
xe::SimpleMessageBoxType::Error,
|
||||
fmt::format("Xenia does not support running {} files, the file you "
|
||||
"actually want to run is inside of this {} file.",
|
||||
extension, extension));
|
||||
// user likely compressed the file themselves, then suffered a traumatic
|
||||
// brain injury that caused them to forget how archives work
|
||||
|
||||
LaunchWebBrowser(fmt::format(
|
||||
"https://www.google.com/search?q=how+to+extract+{}+file", extension));
|
||||
|
||||
xe::FatalError("Terminating due to user's lack of basic computer skills.");
|
||||
}
|
||||
return std::make_unique<vfs::DiscImageDevice>(mount_path, path);
|
||||
}
|
||||
|
||||
uint64_t Emulator::GetPersistentEmulatorFlags() {
|
||||
#if XE_PLATFORM_WIN32 == 1
|
||||
uint64_t value = 0;
|
||||
DWORD value_size = sizeof(value);
|
||||
HKEY xenia_hkey = nullptr;
|
||||
LSTATUS lstat =
|
||||
RegOpenKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Xenia", &xenia_hkey);
|
||||
if (!xenia_hkey) {
|
||||
// let the Set function create the key and initialize it to 0
|
||||
SetPersistentEmulatorFlags(0ULL);
|
||||
return 0ULL;
|
||||
}
|
||||
|
||||
lstat = RegQueryValueExA(xenia_hkey, "XEFLAGS", 0, NULL,
|
||||
reinterpret_cast<LPBYTE>(&value), &value_size);
|
||||
RegCloseKey(xenia_hkey);
|
||||
if (lstat) {
|
||||
return 0ULL;
|
||||
}
|
||||
return value;
|
||||
#else
|
||||
return EmulatorFlagQuickstartShown | EmulatorFlagIsoWarningAcknowledged;
|
||||
#endif
|
||||
}
|
||||
void Emulator::SetPersistentEmulatorFlags(uint64_t new_flags) {
|
||||
#if XE_PLATFORM_WIN32 == 1
|
||||
uint64_t value = new_flags;
|
||||
DWORD value_size = sizeof(value);
|
||||
HKEY xenia_hkey = nullptr;
|
||||
LSTATUS lstat =
|
||||
RegOpenKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Xenia", &xenia_hkey);
|
||||
if (!xenia_hkey) {
|
||||
lstat = RegCreateKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Xenia", &xenia_hkey);
|
||||
}
|
||||
|
||||
lstat = RegSetValueExA(xenia_hkey, "XEFLAGS", 0, REG_QWORD,
|
||||
reinterpret_cast<const BYTE*>(&value), 8);
|
||||
RegFlushKey(xenia_hkey);
|
||||
RegCloseKey(xenia_hkey);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Emulator::ClearStickyPersistentFlags() {
|
||||
SetPersistentEmulatorFlags(GetPersistentEmulatorFlags() &
|
||||
~EmulatorFlagIsoWarningSticky);
|
||||
}
|
||||
|
||||
void Emulator::CheckMountWarning(const std::filesystem::path& path) {
|
||||
auto extension = CanonicalizeFileExtension(path);
|
||||
|
||||
uint64_t emu_flags = GetPersistentEmulatorFlags();
|
||||
|
||||
bool moron_flag_set = (emu_flags & EmulatorFlagIsoWarningSticky) != 0ULL;
|
||||
|
||||
if (!(emu_flags & EmulatorFlagIsoWarningAcknowledged) &&
|
||||
extension == ".iso") {
|
||||
// get their attention, they're more likely to read the message if they're
|
||||
// worried something is wrong with their computer
|
||||
|
||||
// beep blocks for duration, so run it on another thread
|
||||
// beep is better than MessageBeep; if the user has disabled all windows
|
||||
// sounds, MessageBeep doesnt play, but beep does play
|
||||
|
||||
std::thread beep_thread{[]() {
|
||||
for (uint32_t i = 0; i < 4; ++i) {
|
||||
#if XE_PLATFORM_WIN32 == 1
|
||||
Beep(4096, 500);
|
||||
Sleep(50);
|
||||
#endif
|
||||
}
|
||||
}};
|
||||
|
||||
uint64_t time_started_reading = Clock::QueryHostUptimeMillis();
|
||||
// this isn't true really, they just won't be able to speak in discussion
|
||||
// channels, and they can prove they have a physical copy
|
||||
ShowSimpleMessageBox(
|
||||
xe::SimpleMessageBoxType::Warning,
|
||||
"PIRACY IS ILLEGAL, STAY OUT OF OUR DISCORD: ISO files are commonly "
|
||||
"associated with piracy, which the "
|
||||
"Xenia team "
|
||||
"does not support or condone. Any users who come to the Xenia discord "
|
||||
"for support who are found to be using pirated games will be banned "
|
||||
"immediately, regardless of whether they own a physical copy.");
|
||||
uint64_t time_finished_reading = Clock::QueryHostUptimeMillis();
|
||||
// join AFTER getting the end time, otherwise the beep duration will knock
|
||||
// us out of idiot range
|
||||
beep_thread.join();
|
||||
/*
|
||||
we only show them this warning once.
|
||||
if they immediately skipped it, assume they're an idiot and force
|
||||
the warning every time they open the file don't do the check though if
|
||||
we've already given them the moron flag
|
||||
*/
|
||||
if (!moron_flag_set &&
|
||||
(time_finished_reading - time_started_reading) < 2000) {
|
||||
ShowSimpleMessageBox(xe::SimpleMessageBoxType::Warning,
|
||||
"You clearly didn't read the warning. It will now "
|
||||
"show every time you open an ISO file.");
|
||||
SetPersistentEmulatorFlags(emu_flags | EmulatorFlagIsoWarningSticky);
|
||||
} else {
|
||||
// dont set the warning acknowledged bit, ever, if they skipped the first
|
||||
// warning without reading it
|
||||
if (!moron_flag_set) {
|
||||
SetPersistentEmulatorFlags(emu_flags |
|
||||
EmulatorFlagIsoWarningAcknowledged);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
X_STATUS Emulator::MountPath(const std::filesystem::path& path,
|
||||
const std::string_view mount_path) {
|
||||
CheckMountWarning(path);
|
||||
auto device = CreateVfsDeviceBasedOnPath(path, mount_path);
|
||||
if (!device->Initialize()) {
|
||||
xe::FatalError(fmt::format("Unable to mount {}; file corrupt or not found.", xe::path_to_utf8(path)));
|
||||
xe::FatalError(
|
||||
"Unable to mount the selected file, it is an unsupported format or "
|
||||
"corrupted.");
|
||||
return X_STATUS_NO_SUCH_FILE;
|
||||
}
|
||||
if (!file_system_->RegisterDevice(std::move(device))) {
|
||||
xe::FatalError(fmt::format("Unable to register {} to {}.", xe::path_to_utf8(path), xe::path_to_utf8(mount_path)));
|
||||
xe::FatalError(fmt::format("Unable to register the input file to {}.",
|
||||
xe::path_to_utf8(mount_path)));
|
||||
return X_STATUS_NO_SUCH_FILE;
|
||||
}
|
||||
|
||||
|
@ -640,25 +780,28 @@ bool Emulator::ExceptionCallback(Exception* ex) {
|
|||
crash_msg.append(fmt::format(" r{:<3} = {:016X}\n", i, context->r[i]));
|
||||
}
|
||||
for (int i = 0; i < 32; i++) {
|
||||
crash_msg.append(fmt::format(" f{:<3} = {:016X} = (double){} = (float){}\n", i,
|
||||
*reinterpret_cast<uint64_t*>(&context->f[i]), context->f[i],
|
||||
*(float*)&context->f[i]));
|
||||
crash_msg.append(fmt::format(" f{:<3} = {:016X} = (double){} = (float){}\n",
|
||||
i,
|
||||
*reinterpret_cast<uint64_t*>(&context->f[i]),
|
||||
context->f[i], *(float*)&context->f[i]));
|
||||
}
|
||||
for (int i = 0; i < 128; i++) {
|
||||
crash_msg.append(fmt::format(" v{:<3} = [0x{:08X}, 0x{:08X}, 0x{:08X}, 0x{:08X}]\n", i,
|
||||
context->v[i].u32[0], context->v[i].u32[1], context->v[i].u32[2],
|
||||
context->v[i].u32[3]));
|
||||
crash_msg.append(
|
||||
fmt::format(" v{:<3} = [0x{:08X}, 0x{:08X}, 0x{:08X}, 0x{:08X}]\n", i,
|
||||
context->v[i].u32[0], context->v[i].u32[1],
|
||||
context->v[i].u32[2], context->v[i].u32[3]));
|
||||
}
|
||||
XELOGE("{}", crash_msg);
|
||||
std::string crash_dlg = fmt::format(
|
||||
"The guest has crashed.\n\n"
|
||||
"Xenia has now paused itself.\n\n"
|
||||
"{}", crash_msg);
|
||||
"{}",
|
||||
crash_msg);
|
||||
// Display a dialog telling the user the guest has crashed.
|
||||
if (display_window_ && imgui_drawer_) {
|
||||
display_window_->app_context().CallInUIThreadSynchronous([this, &crash_dlg]() {
|
||||
xe::ui::ImGuiDialog::ShowMessageBox(
|
||||
imgui_drawer_, "Uh-oh!", crash_dlg);
|
||||
display_window_->app_context().CallInUIThreadSynchronous([this,
|
||||
&crash_dlg]() {
|
||||
xe::ui::ImGuiDialog::ShowMessageBox(imgui_drawer_, "Uh-oh!", crash_dlg);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -202,7 +202,7 @@ const std::unique_ptr<vfs::Device> CreateVfsDeviceBasedOnPath(
|
|||
void Pause();
|
||||
void Resume();
|
||||
bool is_paused() const { return paused_; }
|
||||
|
||||
void ClearStickyPersistentFlags();
|
||||
bool SaveToFile(const std::filesystem::path& path);
|
||||
bool RestoreFromFile(const std::filesystem::path& path);
|
||||
|
||||
|
@ -221,6 +221,17 @@ const std::unique_ptr<vfs::Device> CreateVfsDeviceBasedOnPath(
|
|||
xe::Delegate<> on_exit;
|
||||
|
||||
private:
|
||||
enum : uint64_t {
|
||||
EmulatorFlagQuickstartShown = 1ULL << 0,
|
||||
EmulatorFlagIsoWarningAcknowledged = 1ULL << 1,
|
||||
EmulatorFlagIsoWarningSticky = 1ULL<<2,
|
||||
|
||||
};
|
||||
static uint64_t GetPersistentEmulatorFlags();
|
||||
static void SetPersistentEmulatorFlags(uint64_t new_flags);
|
||||
static std::string CanonicalizeFileExtension(
|
||||
const std::filesystem::path& path);
|
||||
void CheckMountWarning(const std::filesystem::path& path);
|
||||
static bool ExceptionCallbackThunk(Exception* ex, void* data);
|
||||
bool ExceptionCallback(Exception* ex);
|
||||
|
||||
|
|
|
@ -616,6 +616,55 @@ dword_result_t XamIsCurrentTitleDash_entry(const ppc_context_t& ctx) {
|
|||
}
|
||||
DECLARE_XAM_EXPORT1(XamIsCurrentTitleDash, kNone, kImplemented);
|
||||
|
||||
dword_result_t XGetAudioFlags_entry() { return 65537; }
|
||||
DECLARE_XAM_EXPORT1(XGetAudioFlags, kNone, kStub);
|
||||
|
||||
/*
|
||||
todo: this table should instead be pointed to by a member of kernel state and initialized along with the process
|
||||
*/
|
||||
static int32_t XamRtlRandomTable[128] = {
|
||||
1284227242, 1275210071, 573735546, 790525478, 2139871995, 1547161642,
|
||||
179605362, 789336058, 688789844, 1801674531, 1563985344, 1957994488,
|
||||
1364589140, 1645522239, 287218729, 606747145, 1972579041, 1085031214,
|
||||
1425521274, 1482476501, 1844823847, 57989841, 1897051121, 1935655697,
|
||||
1078145449, 1960408961, 1682526488, 842925246, 1500820517, 1214440339,
|
||||
1647877149, 682003330, 261478967, 2052111302, 162531612, 583907252,
|
||||
1336601894, 1715567821, 413027322, 484763869, 1383384898, 1004336348,
|
||||
764733703, 854245398, 651377827, 1614895754, 838170752, 1757981266,
|
||||
602609370, 1644491937, 926492609, 220523388, 115176313, 725345543,
|
||||
261903793, 746137067, 920026266, 1123561945, 1580818891, 1708537768,
|
||||
616249376, 1292428093, 562591055, 343818398, 1788223648, 1659004503,
|
||||
2077806209, 299502267, 1604221776, 602162358, 630328440, 1606980848,
|
||||
1580436667, 1078081533, 492894223, 839522115, 1979792683, 117609710,
|
||||
1767777339, 1454471165, 1965331169, 1844237615, 308236825, 329068152,
|
||||
412668190, 796845957, 1303643608, 436374069, 1677128483, 527237240,
|
||||
813497703, 1060284298, 1770027372, 1177238915, 884357618, 1409082233,
|
||||
1958367476, 448539723, 1592454029, 861567501, 963894560, 73586283,
|
||||
362288127, 507921405, 113007714, 823518204, 152049171, 1202660629,
|
||||
1326574676, 2025429265, 1035525444, 515967899, 1532298954, 2000478354,
|
||||
1450960922, 1417001333, 2049760794, 1229272821, 879983540, 1993962763,
|
||||
706699826, 776561741, 2111687655, 1343024091, 1637723038, 1220945662,
|
||||
484061587, 1390067357};
|
||||
|
||||
/*
|
||||
Follows xam exactly, the updates to the random table are probably racy.
|
||||
*/
|
||||
dword_result_t RtlRandom_entry(lpdword_t seed_out) {
|
||||
int32_t table_seed_new = (0x7FFFFFED * *seed_out + 0x7FFFFFC3) % 0x7FFFFFFF;
|
||||
*seed_out = table_seed_new;
|
||||
uint32_t param_seed_new =
|
||||
(0x7FFFFFED * table_seed_new + 0x7FFFFFC3) % 0x7FFFFFFFu;
|
||||
*seed_out = param_seed_new;
|
||||
|
||||
int32_t* update_table_position = &XamRtlRandomTable[param_seed_new & 0x7F];
|
||||
|
||||
int32_t result = *update_table_position;
|
||||
*update_table_position = table_seed_new;
|
||||
return result;
|
||||
}
|
||||
|
||||
DECLARE_XAM_EXPORT1(RtlRandom, kNone, kImplemented);
|
||||
|
||||
} // namespace xam
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
|
|
@ -38,6 +38,13 @@ DECLARE_XAM_EXPORT1(XamVoiceClose, kNone, kStub);
|
|||
dword_result_t XamVoiceHeadsetPresent_entry(lpunknown_t voice_ptr) { return 0; }
|
||||
DECLARE_XAM_EXPORT1(XamVoiceHeadsetPresent, kNone, kStub);
|
||||
|
||||
dword_result_t XamVoiceSubmitPacket_entry(lpdword_t unk1, dword_t unk2,
|
||||
lpdword_t unk3) {
|
||||
// also may return 0xD000009D
|
||||
return 0x800700AA;
|
||||
}
|
||||
DECLARE_XAM_EXPORT1(XamVoiceSubmitPacket, kNone, kStub);
|
||||
|
||||
} // namespace xam
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
|
|
@ -119,6 +119,22 @@ dword_result_t DmGetConsoleDebugMemoryStatus_entry() {
|
|||
}
|
||||
DECLARE_XBDM_EXPORT1(DmGetConsoleDebugMemoryStatus, kDebug, kStub);
|
||||
|
||||
void __CAP_Start_Profiling_entry(dword_t a1, dword_t a2) {}
|
||||
|
||||
DECLARE_XBDM_EXPORT1(__CAP_Start_Profiling, kDebug, kStub);
|
||||
|
||||
void __CAP_End_Profiling_entry() {}
|
||||
|
||||
DECLARE_XBDM_EXPORT1(__CAP_End_Profiling, kDebug, kStub);
|
||||
|
||||
void __CAP_Enter_Function_entry() {}
|
||||
|
||||
DECLARE_XBDM_EXPORT1(__CAP_Enter_Function, kDebug, kStub);
|
||||
|
||||
void __CAP_Exit_Function_entry() {}
|
||||
|
||||
DECLARE_XBDM_EXPORT1(__CAP_Exit_Function, kDebug, kStub);
|
||||
|
||||
} // namespace xbdm
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
|
|
@ -672,20 +672,17 @@ dword_result_t FscSetCacheElementCount_entry(dword_t unk_0, dword_t unk_1) {
|
|||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
DECLARE_XBOXKRNL_EXPORT1(FscSetCacheElementCount, kFileSystem, kStub);
|
||||
|
||||
// todo: this should fill in the io status block and queue the apc
|
||||
dword_result_t NtDeviceIoControlFile_entry(
|
||||
dword_t handle, dword_t event_handle, dword_t apc_routine,
|
||||
dword_t apc_context, dword_t io_status_block, dword_t io_control_code,
|
||||
lpvoid_t input_buffer, dword_t input_buffer_len, lpvoid_t output_buffer,
|
||||
dword_t output_buffer_len) {
|
||||
dword_t apc_context, pointer_t<X_IO_STATUS_BLOCK> io_status_block,
|
||||
dword_t io_control_code, lpvoid_t input_buffer, dword_t input_buffer_len,
|
||||
lpvoid_t output_buffer, dword_t output_buffer_len) {
|
||||
// Called by XMountUtilityDrive cache-mounting code
|
||||
// (checks if the returned values look valid, values below seem to pass the
|
||||
// checks)
|
||||
const uint32_t cache_size = 0xFF000;
|
||||
|
||||
const uint32_t X_IOCTL_DISK_GET_DRIVE_GEOMETRY = 0x70000;
|
||||
const uint32_t X_IOCTL_DISK_GET_PARTITION_INFO = 0x74004;
|
||||
|
||||
if (io_control_code == X_IOCTL_DISK_GET_DRIVE_GEOMETRY) {
|
||||
if (output_buffer_len < 0x8) {
|
||||
assert_always();
|
||||
|
@ -710,30 +707,89 @@ dword_result_t NtDeviceIoControlFile_entry(
|
|||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
DECLARE_XBOXKRNL_EXPORT1(NtDeviceIoControlFile, kFileSystem, kStub);
|
||||
// device_extension_size = additional bytes of data (aligned up to 8 byte
|
||||
// granularity) that will be allocated at the tail of the resulting device
|
||||
// object. although it is allocated at the tail, it is accessed through a
|
||||
// pointer at offset 0x18 so in theory a guest could be unaware that its a
|
||||
// single allocation device_name is optional, extra_device_object_attributes
|
||||
// gets assigned to the attributes field of the OBJECT_ATTRIBUTES used for
|
||||
// ObCreateObject
|
||||
|
||||
dword_result_t IoCreateDevice_entry(dword_t device_struct, dword_t r4,
|
||||
dword_t r5, dword_t r6, dword_t r7,
|
||||
lpdword_t out_struct) {
|
||||
// todo: need device guest object struct + host object for device
|
||||
dword_result_t IoCreateDevice_entry(dword_t driver_object,
|
||||
dword_t device_extension_size,
|
||||
pointer_t<X_ANSI_STRING> device_name,
|
||||
dword_t device_type,
|
||||
dword_t extra_device_object_attributes,
|
||||
lpdword_t device_object,
|
||||
const ppc_context_t& ctx) {
|
||||
// Called from XMountUtilityDrive XAM-task code
|
||||
// That code tries writing things to a pointer at out_struct+0x18
|
||||
// We'll alloc some scratch space for it so it doesn't cause any exceptions
|
||||
|
||||
// 0x24 is guessed size from accesses to out_struct - likely incorrect
|
||||
auto out_guest = kernel_memory()->SystemHeapAlloc(0x24);
|
||||
auto current_kernel = ctx->kernel_state;
|
||||
|
||||
auto out = kernel_memory()->TranslateVirtual<uint8_t*>(out_guest);
|
||||
memset(out, 0, 0x24);
|
||||
uint32_t required_size = 80 + xe::align<uint32_t>(device_extension_size, 8);
|
||||
|
||||
auto kernel_mem = current_kernel->memory();
|
||||
|
||||
auto out_guest = kernel_mem->SystemHeapAlloc(required_size);
|
||||
|
||||
auto out = kernel_mem->TranslateVirtual<uint8_t*>(out_guest);
|
||||
|
||||
memset(out, 0, required_size);
|
||||
|
||||
xe::store<unsigned char>(out, 3); // maybe device object's Ob type?
|
||||
|
||||
// this stores the total object size, without alignment!
|
||||
|
||||
xe::store_and_swap<uint16_t>(out + 2, device_extension_size + 80);
|
||||
|
||||
// from 17559
|
||||
if (device_type == 7 || device_type == 58 || device_type == 62 ||
|
||||
device_type == 45 || device_type == 2 || device_type == 60 ||
|
||||
device_type == 61 || device_type == 36 || device_type == 64 ||
|
||||
device_type == 65 || device_type == 66 || device_type == 67 ||
|
||||
device_type == 68 || device_type == 69 || device_type == 70 ||
|
||||
device_type == 72 || device_type == 73) {
|
||||
xe::store_and_swap<uint32_t>(out + 0xC, 0);
|
||||
} else {
|
||||
// pointer to itself?
|
||||
xe::store_and_swap<uint32_t>(out + 0xC, out_guest);
|
||||
}
|
||||
xe::store<uint8_t>(out + 0x1C, static_cast<uint8_t>(device_type));
|
||||
|
||||
uint32_t flags_field_value = 16;
|
||||
if (device_name) {
|
||||
flags_field_value |= 8;
|
||||
}
|
||||
xe::store<unsigned char>(out + 0x1e, 1);
|
||||
xe::store_and_swap<uint32_t>(out + 0x14, flags_field_value);
|
||||
if (device_extension_size != 0) {
|
||||
// pointer to device specific data
|
||||
// XMountUtilityDrive writes some kind of header here
|
||||
// 0x1000 bytes should be enough to store it
|
||||
auto out_guest2 = kernel_memory()->SystemHeapAlloc(0x1000);
|
||||
xe::store_and_swap(out + 0x18, out_guest2);
|
||||
xe::store_and_swap<uint32_t>(out + 0x18, out_guest + 80);
|
||||
}
|
||||
|
||||
*out_struct = out_guest;
|
||||
xe::store_and_swap<uint32_t>(out + 8, driver_object);
|
||||
|
||||
*device_object = out_guest;
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
DECLARE_XBOXKRNL_EXPORT1(IoCreateDevice, kFileSystem, kStub);
|
||||
|
||||
//supposed to invoke a callback on the driver object! its some sort of destructor function
|
||||
//intended to be called for all devices created from the driver
|
||||
void IoDeleteDevice_entry(dword_t device_ptr, const ppc_context_t& ctx) {
|
||||
if (device_ptr) {
|
||||
auto kernel_mem = ctx->kernel_state->memory();
|
||||
kernel_mem->SystemHeapFree(device_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_XBOXKRNL_EXPORT1(IoDeleteDevice, kFileSystem, kStub);
|
||||
|
||||
} // namespace xboxkrnl
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "xenia/kernel/kernel_state.h"
|
||||
#include "xenia/kernel/user_module.h"
|
||||
#include "xenia/kernel/util/shim_utils.h"
|
||||
#include "xenia/kernel/util/xex2_info.h"
|
||||
#include "xenia/kernel/xboxkrnl/xboxkrnl_private.h"
|
||||
#include "xenia/xbox.h"
|
||||
|
||||
|
@ -215,6 +216,65 @@ void ExRegisterTitleTerminateNotification_entry(
|
|||
}
|
||||
DECLARE_XBOXKRNL_EXPORT1(ExRegisterTitleTerminateNotification, kModules,
|
||||
kImplemented);
|
||||
// todo: replace magic numbers
|
||||
dword_result_t XexLoadImageHeaders_entry(pointer_t<X_ANSI_STRING> path,
|
||||
pointer_t<xex2_header> header,
|
||||
dword_t buffer_size,
|
||||
const ppc_context_t& ctx) {
|
||||
if (buffer_size < 0x800) {
|
||||
return X_STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
auto current_kernel = ctx->kernel_state;
|
||||
auto target_path = util::TranslateAnsiString(current_kernel->memory(), path);
|
||||
|
||||
vfs::File* vfs_file = nullptr;
|
||||
vfs::FileAction file_action;
|
||||
X_STATUS result = current_kernel->file_system()->OpenFile(
|
||||
nullptr, target_path, vfs::FileDisposition::kOpen,
|
||||
vfs::FileAccess::kGenericRead, false, true, &vfs_file, &file_action);
|
||||
|
||||
if (!vfs_file) {
|
||||
return result;
|
||||
}
|
||||
size_t bytes_read = 0;
|
||||
|
||||
X_STATUS result_status = vfs_file->ReadSync(
|
||||
reinterpret_cast<void*>(header.host_address()), 2048, 0, &bytes_read);
|
||||
|
||||
if (result_status < 0) {
|
||||
vfs_file->Destroy();
|
||||
return result_status;
|
||||
}
|
||||
|
||||
if (header->magic != 'XEX2') {
|
||||
vfs_file->Destroy();
|
||||
return X_STATUS_INVALID_IMAGE_FORMAT;
|
||||
}
|
||||
unsigned int header_size = header->header_size;
|
||||
|
||||
if (header_size < 0x800 || header_size > 0x10000 ||
|
||||
(header_size & 0x7FF) != 0) {
|
||||
result_status = X_STATUS_INVALID_IMAGE_FORMAT;
|
||||
} else if (header_size <= buffer_size) {
|
||||
if (header_size <= 0x800) {
|
||||
result_status = X_STATUS_SUCCESS;
|
||||
} else {
|
||||
result_status = vfs_file->ReadSync(
|
||||
reinterpret_cast<void*>(header.host_address() + 2048),
|
||||
header_size - 2048, 2048, &bytes_read);
|
||||
if (result_status >= X_STATUS_SUCCESS) {
|
||||
result_status = X_STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
result_status = X_STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
vfs_file->Destroy();
|
||||
return result_status;
|
||||
}
|
||||
DECLARE_XBOXKRNL_EXPORT1(XexLoadImageHeaders, kModules, kImplemented);
|
||||
|
||||
} // namespace xboxkrnl
|
||||
} // namespace kernel
|
||||
|
|
|
@ -30,10 +30,10 @@ DiscImageDevice::~DiscImageDevice() = default;
|
|||
bool DiscImageDevice::Initialize() {
|
||||
mmap_ = MappedMemory::Open(host_path_, MappedMemory::Mode::kRead);
|
||||
if (!mmap_) {
|
||||
XELOGE("Disc image {} could not be mapped", xe::path_to_utf8(host_path_));
|
||||
XELOGE("Disc image could not be mapped");
|
||||
return false;
|
||||
} else {
|
||||
XELOGFS("DiscImageDevice::Initialize({})", xe::path_to_utf8(host_path_));
|
||||
XELOGFS("DiscImageDevice::Initialize");
|
||||
}
|
||||
|
||||
ParseState state = {0};
|
||||
|
|
|
@ -63,6 +63,7 @@ typedef uint32_t X_STATUS;
|
|||
#define X_STATUS_MUTANT_NOT_OWNED ((X_STATUS)0xC0000046L)
|
||||
#define X_STATUS_THREAD_IS_TERMINATING ((X_STATUS)0xC000004BL)
|
||||
#define X_STATUS_PROCEDURE_NOT_FOUND ((X_STATUS)0xC000007AL)
|
||||
#define X_STATUS_INVALID_IMAGE_FORMAT ((X_STATUS)0xC000007BL)
|
||||
#define X_STATUS_INSUFFICIENT_RESOURCES ((X_STATUS)0xC000009AL)
|
||||
#define X_STATUS_MEMORY_NOT_ALLOCATED ((X_STATUS)0xC00000A0L)
|
||||
#define X_STATUS_FILE_IS_A_DIRECTORY ((X_STATUS)0xC00000BAL)
|
||||
|
@ -123,6 +124,10 @@ typedef uint32_t X_HRESULT;
|
|||
#define X_E_NOTFOUND X_HRESULT_FROM_WIN32(X_ERROR_NOT_FOUND)
|
||||
#define X_E_NO_SUCH_USER X_HRESULT_FROM_WIN32(X_ERROR_NO_SUCH_USER)
|
||||
|
||||
//IOCTL_, used by NtDeviceIoControlFile
|
||||
constexpr uint32_t X_IOCTL_DISK_GET_DRIVE_GEOMETRY = 0x70000;
|
||||
constexpr uint32_t X_IOCTL_DISK_GET_PARTITION_INFO = 0x74004;
|
||||
|
||||
// MEM_*, used by NtAllocateVirtualMemory
|
||||
enum X_MEM : uint32_t {
|
||||
X_MEM_COMMIT = 0x00001000,
|
||||
|
|
Loading…
Reference in New Issue