Implement RtlRandom (which despite its name is located in Xam, not xboxkrnl, which is why its not in xboxkrnl_rtl)
Stub XamVoiceSubmitPacket Stubs for __CAP_Start_Profiling/End_Profiling/Enter_Function/Exit_Function add a note about io_status_block in NtDeviceIoControlFile, change the param's type move the X_IOCTL_ constants from NtDeviceIoControlFile's body into xbox.h add X_STATUS_INVALID_IMAGE_FORMAT to xbox.h Implement XexLoadImageHeaders Much more correct version of IoCreateDevice, properly initializes/allocates device extension data Stub version of IoDeleteDevice Open the quickstart guide in the browser the first time a user opens the emulator Add some persistent flags that are stored in the registry on windows, not in the config. These are just used to indicate whether one-time tasks have run, like showing the quickstart guide. On non-windows platforms a default value is returned that skips any of these tasks so they don't run every single time. If the user opens a .iso file, show a warning telling them that we do not condone or support piracy. If the user closes the messagebox within two seconds set a sticky flag that will show them the warning every time instead. Otherwise the warning is never shown again. The Beep function is used to spook them a bit, to hopefully make them less likely to skip the message If a user opens an archive file, which we do not support, explain to them that they're dumb. Removed messages intended to "catch" pirates. If they're out there, we don't want to know about them. A huge chunk of the discourse on our discord is now about piracy. Hopefully these changes will deter them from coming to us for now, but some of these messages may backfire
This commit is contained in:
parent
ba936e8038
commit
afef35c1c0
|
@ -850,7 +850,11 @@ void EmulatorWindow::OnKeyDown(ui::KeyEvent& e) {
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case ui::VirtualKey::kF2: {
|
case ui::VirtualKey::kF2: {
|
||||||
ShowBuildCommit();
|
if (e.is_ctrl_pressed()) {
|
||||||
|
emulator()->ClearStickyPersistentFlags();
|
||||||
|
} else {
|
||||||
|
ShowBuildCommit();
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case ui::VirtualKey::kF9: {
|
case ui::VirtualKey::kF9: {
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "xenia/base/mapped_memory.h"
|
#include "xenia/base/mapped_memory.h"
|
||||||
#include "xenia/base/platform.h"
|
#include "xenia/base/platform.h"
|
||||||
#include "xenia/base/string.h"
|
#include "xenia/base/string.h"
|
||||||
|
#include "xenia/base/system.h"
|
||||||
#include "xenia/cpu/backend/code_cache.h"
|
#include "xenia/cpu/backend/code_cache.h"
|
||||||
#include "xenia/cpu/backend/null_backend.h"
|
#include "xenia/cpu/backend/null_backend.h"
|
||||||
#include "xenia/cpu/cpu_flags.h"
|
#include "xenia/cpu/cpu_flags.h"
|
||||||
|
@ -109,7 +110,15 @@ Emulator::Emulator(const std::filesystem::path& command_line,
|
||||||
title_id_(std::nullopt),
|
title_id_(std::nullopt),
|
||||||
paused_(false),
|
paused_(false),
|
||||||
restoring_(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() {
|
Emulator::~Emulator() {
|
||||||
// Note that we delete things in the reverse order they were initialized.
|
// Note that we delete things in the reverse order they were initialized.
|
||||||
|
@ -280,30 +289,161 @@ X_STATUS Emulator::TerminateTitle() {
|
||||||
return X_STATUS_SUCCESS;
|
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::unique_ptr<vfs::Device> Emulator::CreateVfsDeviceBasedOnPath(
|
||||||
const std::filesystem::path& path, const std::string_view mount_path) {
|
const std::filesystem::path& path, const std::string_view mount_path) {
|
||||||
if (!path.has_extension()) {
|
if (!path.has_extension()) {
|
||||||
return std::make_unique<vfs::StfsContainerDevice>(mount_path, path);
|
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") {
|
if (extension == ".xex" || extension == ".elf" || extension == ".exe") {
|
||||||
auto parent_path = path.parent_path();
|
auto parent_path = path.parent_path();
|
||||||
return std::make_unique<vfs::HostPathDevice>(
|
return std::make_unique<vfs::HostPathDevice>(
|
||||||
mount_path, parent_path, !cvars::allow_game_relative_writes);
|
mount_path, parent_path, !cvars::allow_game_relative_writes);
|
||||||
} else {
|
} else if (extension == ".7z" || extension == ".zip" || extension == ".rar") {
|
||||||
return std::make_unique<vfs::DiscImageDevice>(mount_path, path);
|
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,
|
X_STATUS Emulator::MountPath(const std::filesystem::path& path,
|
||||||
const std::string_view mount_path) {
|
const std::string_view mount_path) {
|
||||||
|
CheckMountWarning(path);
|
||||||
auto device = CreateVfsDeviceBasedOnPath(path, mount_path);
|
auto device = CreateVfsDeviceBasedOnPath(path, mount_path);
|
||||||
if (!device->Initialize()) {
|
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;
|
return X_STATUS_NO_SUCH_FILE;
|
||||||
}
|
}
|
||||||
if (!file_system_->RegisterDevice(std::move(device))) {
|
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;
|
return X_STATUS_NO_SUCH_FILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -634,31 +774,34 @@ bool Emulator::ExceptionCallback(Exception* ex) {
|
||||||
current_thread->thread()->system_id(), current_thread->thread_id()));
|
current_thread->thread()->system_id(), current_thread->thread_id()));
|
||||||
crash_msg.append(fmt::format("Thread Handle: 0x{:08X}\n", current_thread->handle()));
|
crash_msg.append(fmt::format("Thread Handle: 0x{:08X}\n", current_thread->handle()));
|
||||||
crash_msg.append(fmt::format("PC: 0x{:08X}\n",
|
crash_msg.append(fmt::format("PC: 0x{:08X}\n",
|
||||||
guest_function->MapMachineCodeToGuestAddress(ex->pc())));
|
guest_function->MapMachineCodeToGuestAddress(ex->pc())));
|
||||||
crash_msg.append("Registers:\n");
|
crash_msg.append("Registers:\n");
|
||||||
for (int i = 0; i < 32; i++) {
|
for (int i = 0; i < 32; i++) {
|
||||||
crash_msg.append(fmt::format(" r{:<3} = {:016X}\n", i, context->r[i]));
|
crash_msg.append(fmt::format(" r{:<3} = {:016X}\n", i, context->r[i]));
|
||||||
}
|
}
|
||||||
for (int i = 0; i < 32; i++) {
|
for (int i = 0; i < 32; i++) {
|
||||||
crash_msg.append(fmt::format(" f{:<3} = {:016X} = (double){} = (float){}\n", i,
|
crash_msg.append(fmt::format(" f{:<3} = {:016X} = (double){} = (float){}\n",
|
||||||
*reinterpret_cast<uint64_t*>(&context->f[i]), context->f[i],
|
i,
|
||||||
*(float*)&context->f[i]));
|
*reinterpret_cast<uint64_t*>(&context->f[i]),
|
||||||
|
context->f[i], *(float*)&context->f[i]));
|
||||||
}
|
}
|
||||||
for (int i = 0; i < 128; 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,
|
crash_msg.append(
|
||||||
context->v[i].u32[0], context->v[i].u32[1], context->v[i].u32[2],
|
fmt::format(" v{:<3} = [0x{:08X}, 0x{:08X}, 0x{:08X}, 0x{:08X}]\n", i,
|
||||||
context->v[i].u32[3]));
|
context->v[i].u32[0], context->v[i].u32[1],
|
||||||
|
context->v[i].u32[2], context->v[i].u32[3]));
|
||||||
}
|
}
|
||||||
XELOGE("{}", crash_msg);
|
XELOGE("{}", crash_msg);
|
||||||
std::string crash_dlg = fmt::format(
|
std::string crash_dlg = fmt::format(
|
||||||
"The guest has crashed.\n\n"
|
"The guest has crashed.\n\n"
|
||||||
"Xenia has now paused itself.\n\n"
|
"Xenia has now paused itself.\n\n"
|
||||||
"{}", crash_msg);
|
"{}",
|
||||||
|
crash_msg);
|
||||||
// Display a dialog telling the user the guest has crashed.
|
// Display a dialog telling the user the guest has crashed.
|
||||||
if (display_window_ && imgui_drawer_) {
|
if (display_window_ && imgui_drawer_) {
|
||||||
display_window_->app_context().CallInUIThreadSynchronous([this, &crash_dlg]() {
|
display_window_->app_context().CallInUIThreadSynchronous([this,
|
||||||
xe::ui::ImGuiDialog::ShowMessageBox(
|
&crash_dlg]() {
|
||||||
imgui_drawer_, "Uh-oh!", crash_dlg);
|
xe::ui::ImGuiDialog::ShowMessageBox(imgui_drawer_, "Uh-oh!", crash_dlg);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -176,7 +176,7 @@ class Emulator {
|
||||||
// Terminates the currently running title.
|
// Terminates the currently running title.
|
||||||
X_STATUS TerminateTitle();
|
X_STATUS TerminateTitle();
|
||||||
|
|
||||||
const std::unique_ptr<vfs::Device> CreateVfsDeviceBasedOnPath(
|
const std::unique_ptr<vfs::Device> CreateVfsDeviceBasedOnPath(
|
||||||
const std::filesystem::path& path, const std::string_view mount_path);
|
const std::filesystem::path& path, const std::string_view mount_path);
|
||||||
|
|
||||||
X_STATUS MountPath(const std::filesystem::path& path,
|
X_STATUS MountPath(const std::filesystem::path& path,
|
||||||
|
@ -202,7 +202,7 @@ const std::unique_ptr<vfs::Device> CreateVfsDeviceBasedOnPath(
|
||||||
void Pause();
|
void Pause();
|
||||||
void Resume();
|
void Resume();
|
||||||
bool is_paused() const { return paused_; }
|
bool is_paused() const { return paused_; }
|
||||||
|
void ClearStickyPersistentFlags();
|
||||||
bool SaveToFile(const std::filesystem::path& path);
|
bool SaveToFile(const std::filesystem::path& path);
|
||||||
bool RestoreFromFile(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;
|
xe::Delegate<> on_exit;
|
||||||
|
|
||||||
private:
|
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);
|
static bool ExceptionCallbackThunk(Exception* ex, void* data);
|
||||||
bool ExceptionCallback(Exception* ex);
|
bool ExceptionCallback(Exception* ex);
|
||||||
|
|
||||||
|
|
|
@ -616,6 +616,55 @@ dword_result_t XamIsCurrentTitleDash_entry(const ppc_context_t& ctx) {
|
||||||
}
|
}
|
||||||
DECLARE_XAM_EXPORT1(XamIsCurrentTitleDash, kNone, kImplemented);
|
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 xam
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -38,6 +38,13 @@ DECLARE_XAM_EXPORT1(XamVoiceClose, kNone, kStub);
|
||||||
dword_result_t XamVoiceHeadsetPresent_entry(lpunknown_t voice_ptr) { return 0; }
|
dword_result_t XamVoiceHeadsetPresent_entry(lpunknown_t voice_ptr) { return 0; }
|
||||||
DECLARE_XAM_EXPORT1(XamVoiceHeadsetPresent, kNone, kStub);
|
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 xam
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -119,6 +119,22 @@ dword_result_t DmGetConsoleDebugMemoryStatus_entry() {
|
||||||
}
|
}
|
||||||
DECLARE_XBDM_EXPORT1(DmGetConsoleDebugMemoryStatus, kDebug, kStub);
|
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 xbdm
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -672,20 +672,17 @@ dword_result_t FscSetCacheElementCount_entry(dword_t unk_0, dword_t unk_1) {
|
||||||
return X_STATUS_SUCCESS;
|
return X_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT1(FscSetCacheElementCount, kFileSystem, kStub);
|
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_result_t NtDeviceIoControlFile_entry(
|
||||||
dword_t handle, dword_t event_handle, dword_t apc_routine,
|
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,
|
dword_t apc_context, pointer_t<X_IO_STATUS_BLOCK> io_status_block,
|
||||||
lpvoid_t input_buffer, dword_t input_buffer_len, lpvoid_t output_buffer,
|
dword_t io_control_code, lpvoid_t input_buffer, dword_t input_buffer_len,
|
||||||
dword_t output_buffer_len) {
|
lpvoid_t output_buffer, dword_t output_buffer_len) {
|
||||||
// Called by XMountUtilityDrive cache-mounting code
|
// Called by XMountUtilityDrive cache-mounting code
|
||||||
// (checks if the returned values look valid, values below seem to pass the
|
// (checks if the returned values look valid, values below seem to pass the
|
||||||
// checks)
|
// checks)
|
||||||
const uint32_t cache_size = 0xFF000;
|
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 (io_control_code == X_IOCTL_DISK_GET_DRIVE_GEOMETRY) {
|
||||||
if (output_buffer_len < 0x8) {
|
if (output_buffer_len < 0x8) {
|
||||||
assert_always();
|
assert_always();
|
||||||
|
@ -710,30 +707,89 @@ dword_result_t NtDeviceIoControlFile_entry(
|
||||||
return X_STATUS_SUCCESS;
|
return X_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT1(NtDeviceIoControlFile, kFileSystem, kStub);
|
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,
|
// todo: need device guest object struct + host object for device
|
||||||
dword_t r5, dword_t r6, dword_t r7,
|
dword_result_t IoCreateDevice_entry(dword_t driver_object,
|
||||||
lpdword_t out_struct) {
|
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
|
// Called from XMountUtilityDrive XAM-task code
|
||||||
// That code tries writing things to a pointer at out_struct+0x18
|
// 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
|
// 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
|
// 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);
|
uint32_t required_size = 80 + xe::align<uint32_t>(device_extension_size, 8);
|
||||||
memset(out, 0, 0x24);
|
|
||||||
|
|
||||||
// XMountUtilityDrive writes some kind of header here
|
auto kernel_mem = current_kernel->memory();
|
||||||
// 0x1000 bytes should be enough to store it
|
|
||||||
auto out_guest2 = kernel_memory()->SystemHeapAlloc(0x1000);
|
|
||||||
xe::store_and_swap(out + 0x18, out_guest2);
|
|
||||||
|
|
||||||
*out_struct = out_guest;
|
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
|
||||||
|
xe::store_and_swap<uint32_t>(out + 0x18, out_guest + 80);
|
||||||
|
}
|
||||||
|
|
||||||
|
xe::store_and_swap<uint32_t>(out + 8, driver_object);
|
||||||
|
|
||||||
|
*device_object = out_guest;
|
||||||
return X_STATUS_SUCCESS;
|
return X_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT1(IoCreateDevice, kFileSystem, kStub);
|
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 xboxkrnl
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "xenia/kernel/kernel_state.h"
|
#include "xenia/kernel/kernel_state.h"
|
||||||
#include "xenia/kernel/user_module.h"
|
#include "xenia/kernel/user_module.h"
|
||||||
#include "xenia/kernel/util/shim_utils.h"
|
#include "xenia/kernel/util/shim_utils.h"
|
||||||
|
#include "xenia/kernel/util/xex2_info.h"
|
||||||
#include "xenia/kernel/xboxkrnl/xboxkrnl_private.h"
|
#include "xenia/kernel/xboxkrnl/xboxkrnl_private.h"
|
||||||
#include "xenia/xbox.h"
|
#include "xenia/xbox.h"
|
||||||
|
|
||||||
|
@ -215,6 +216,65 @@ void ExRegisterTitleTerminateNotification_entry(
|
||||||
}
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT1(ExRegisterTitleTerminateNotification, kModules,
|
DECLARE_XBOXKRNL_EXPORT1(ExRegisterTitleTerminateNotification, kModules,
|
||||||
kImplemented);
|
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 xboxkrnl
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
|
|
|
@ -30,10 +30,10 @@ DiscImageDevice::~DiscImageDevice() = default;
|
||||||
bool DiscImageDevice::Initialize() {
|
bool DiscImageDevice::Initialize() {
|
||||||
mmap_ = MappedMemory::Open(host_path_, MappedMemory::Mode::kRead);
|
mmap_ = MappedMemory::Open(host_path_, MappedMemory::Mode::kRead);
|
||||||
if (!mmap_) {
|
if (!mmap_) {
|
||||||
XELOGE("Disc image {} could not be mapped", xe::path_to_utf8(host_path_));
|
XELOGE("Disc image could not be mapped");
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
XELOGFS("DiscImageDevice::Initialize({})", xe::path_to_utf8(host_path_));
|
XELOGFS("DiscImageDevice::Initialize");
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseState state = {0};
|
ParseState state = {0};
|
||||||
|
|
|
@ -63,6 +63,7 @@ typedef uint32_t X_STATUS;
|
||||||
#define X_STATUS_MUTANT_NOT_OWNED ((X_STATUS)0xC0000046L)
|
#define X_STATUS_MUTANT_NOT_OWNED ((X_STATUS)0xC0000046L)
|
||||||
#define X_STATUS_THREAD_IS_TERMINATING ((X_STATUS)0xC000004BL)
|
#define X_STATUS_THREAD_IS_TERMINATING ((X_STATUS)0xC000004BL)
|
||||||
#define X_STATUS_PROCEDURE_NOT_FOUND ((X_STATUS)0xC000007AL)
|
#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_INSUFFICIENT_RESOURCES ((X_STATUS)0xC000009AL)
|
||||||
#define X_STATUS_MEMORY_NOT_ALLOCATED ((X_STATUS)0xC00000A0L)
|
#define X_STATUS_MEMORY_NOT_ALLOCATED ((X_STATUS)0xC00000A0L)
|
||||||
#define X_STATUS_FILE_IS_A_DIRECTORY ((X_STATUS)0xC00000BAL)
|
#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_NOTFOUND X_HRESULT_FROM_WIN32(X_ERROR_NOT_FOUND)
|
||||||
#define X_E_NO_SUCH_USER X_HRESULT_FROM_WIN32(X_ERROR_NO_SUCH_USER)
|
#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
|
// MEM_*, used by NtAllocateVirtualMemory
|
||||||
enum X_MEM : uint32_t {
|
enum X_MEM : uint32_t {
|
||||||
X_MEM_COMMIT = 0x00001000,
|
X_MEM_COMMIT = 0x00001000,
|
||||||
|
|
Loading…
Reference in New Issue