mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-01-31 01:15:24 +01:00
Compare commits
1 Commits
v2.6.2
...
mach-excep
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eee71d54ef |
15
.github/workflows/cron_publish_flatpak.yml
vendored
15
.github/workflows/cron_publish_flatpak.yml
vendored
@@ -4,17 +4,6 @@ on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *" # Every day at 12am UTC.
|
||||
workflow_dispatch: # As well as manually.
|
||||
inputs:
|
||||
stableBuild:
|
||||
description: 'Build stable version'
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
publish:
|
||||
description: 'Publish to Flathub'
|
||||
required: false
|
||||
type: boolean
|
||||
default: true
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -63,8 +52,8 @@ jobs:
|
||||
artifactPrefixName: "PCSX2-linux-Qt-x64-flatpak"
|
||||
compiler: clang
|
||||
cmakeflags: ""
|
||||
publish: ${{ inputs.publish || true }}
|
||||
publish: true
|
||||
fetchTags: true
|
||||
stableBuild: ${{ inputs.stableBuild || false }}
|
||||
stableBuild: false
|
||||
secrets: inherit
|
||||
|
||||
|
||||
14
.github/workflows/release_cut_new.yml
vendored
14
.github/workflows/release_cut_new.yml
vendored
@@ -12,7 +12,7 @@ on:
|
||||
- master
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
is_prerelease:
|
||||
is_prelease:
|
||||
description: 'Should be a pre-release?'
|
||||
required: true
|
||||
default: 'true'
|
||||
@@ -73,7 +73,7 @@ jobs:
|
||||
with:
|
||||
body_path: ./release-notes.md
|
||||
draft: true
|
||||
prerelease: ${{ github.event_name != 'workflow_dispatch' || inputs.is_prerelease == 'true' }}
|
||||
prerelease: ${{ github.event_name != 'workflow_dispatch' || inputs.is_prelease == 'true' }}
|
||||
tag_name: ${{ steps.tag_version.outputs.new_tag }}
|
||||
|
||||
- name: Create a GitHub Release (Push)
|
||||
@@ -100,7 +100,7 @@ jobs:
|
||||
cmakeflags: ""
|
||||
buildAppImage: true
|
||||
fetchTags: true
|
||||
stableBuild: ${{ github.event_name == 'workflow_dispatch' && inputs.is_prerelease == 'false' }}
|
||||
stableBuild: ${{ github.event_name == 'workflow_dispatch' && inputs.is_prelease == 'false' }}
|
||||
secrets: inherit
|
||||
|
||||
build_linux_flatpak:
|
||||
@@ -114,9 +114,9 @@ jobs:
|
||||
artifactPrefixName: "PCSX2-linux-Qt-x64-flatpak"
|
||||
compiler: clang
|
||||
cmakeflags: ""
|
||||
publish: ${{ github.event_name == 'workflow_dispatch' && inputs.is_prerelease == 'false' }} # prerelease builds are published by the cron job
|
||||
publish: false
|
||||
fetchTags: true
|
||||
stableBuild: ${{ inputs.is_prerelease == 'false' }}
|
||||
stableBuild: ${{ github.event_name == 'workflow_dispatch' && inputs.is_prelease == 'false' }}
|
||||
secrets: inherit
|
||||
|
||||
# Windows
|
||||
@@ -133,7 +133,7 @@ jobs:
|
||||
buildSystem: cmake
|
||||
cmakeFlags: -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl
|
||||
fetchTags: true
|
||||
stableBuild: ${{ github.event_name == 'workflow_dispatch' && inputs.is_prerelease == 'false' }}
|
||||
stableBuild: ${{ github.event_name == 'workflow_dispatch' && inputs.is_prelease == 'false' }}
|
||||
secrets: inherit
|
||||
|
||||
# MacOS
|
||||
@@ -147,7 +147,7 @@ jobs:
|
||||
jobName: "MacOS Build"
|
||||
artifactPrefixName: "PCSX2-macos-Qt"
|
||||
fetchTags: true
|
||||
stableBuild: ${{ github.event_name == 'workflow_dispatch' && inputs.is_prerelease == 'false' }}
|
||||
stableBuild: ${{ github.event_name == 'workflow_dispatch' && inputs.is_prelease == 'false' }}
|
||||
sign_and_notarize: true
|
||||
secrets: inherit
|
||||
|
||||
|
||||
@@ -20894,8 +20894,10 @@ SLES-52636:
|
||||
gameFixes:
|
||||
- FullVU0SyncHack # Fixes in-game timer.
|
||||
gsHWFixes:
|
||||
minimumBlendingLevel: 3 # Fixes missing lighting and car reflections.
|
||||
halfPixelOffset: 4 # Fixes lines in game and FMVs.
|
||||
recommendedBlendingLevel: 3 # Fixes missing lighting and car reflections.
|
||||
halfPixelOffset: 1 # Fixes 4 split lines in stage intros.
|
||||
autoFlush: 1 # Fixes incorrect colors.
|
||||
alignSprite: 1 # Fixes vertical lines such as in FMVs.
|
||||
SLES-52637:
|
||||
name: "TOCA Race Driver 2"
|
||||
region: "PAL-M5"
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "common/Threading.h"
|
||||
#include "common/WindowInfo.h"
|
||||
#include "common/HostSys.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
#include <csignal>
|
||||
#include <cstring>
|
||||
@@ -19,12 +20,15 @@
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <thread>
|
||||
#include <time.h>
|
||||
#include <mach/mach_init.h>
|
||||
#include <mach/mach_port.h>
|
||||
#include <mach/mach_time.h>
|
||||
#include <mach/mach_vm.h>
|
||||
#include <mach/message.h>
|
||||
#include <mach/task.h>
|
||||
#include <mach/thread_state.h>
|
||||
#include <mach/vm_map.h>
|
||||
#include <mutex>
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
@@ -294,7 +298,7 @@ static CPUInfo CalcCPUInfo()
|
||||
std::vector<DarwinMisc::CPUClass> classes = DarwinMisc::GetCPUClasses();
|
||||
out.num_clusters = static_cast<u32>(classes.size());
|
||||
out.num_big_cores = classes.empty() ? 0 : classes[0].num_physical;
|
||||
out.num_threads = classes.empty() ? 0 : classes[0].num_logical;
|
||||
out.num_threads = classes.empty() ? 0 : classes[0].num_logical;
|
||||
out.num_small_cores = 0;
|
||||
for (std::size_t i = 1; i < classes.size(); i++)
|
||||
{
|
||||
@@ -568,15 +572,206 @@ void HostSys::EndCodeWrite()
|
||||
|
||||
#endif // _M_ARM64
|
||||
|
||||
#define USE_MACH_EXCEPTION_PORTS
|
||||
|
||||
namespace PageFaultHandler
|
||||
{
|
||||
#ifdef USE_MACH_EXCEPTION_PORTS
|
||||
static void SignalHandler(mach_port_t port);
|
||||
#else
|
||||
static void SignalHandler(int sig, siginfo_t* info, void* ctx);
|
||||
#endif
|
||||
|
||||
static std::recursive_mutex s_exception_handler_mutex;
|
||||
static bool s_in_exception_handler = false;
|
||||
static bool s_installed = false;
|
||||
} // namespace PageFaultHandler
|
||||
|
||||
#ifdef USE_MACH_EXCEPTION_PORTS
|
||||
|
||||
#if defined(_M_X86)
|
||||
#define THREAD_STATE64_COUNT x86_THREAD_STATE64_COUNT
|
||||
#define THREAD_STATE64 x86_THREAD_STATE64
|
||||
#define thread_state64_t x86_thread_state64_t
|
||||
#elif defined(_M_ARM64)
|
||||
#define THREAD_STATE64_COUNT ARM_THREAD_STATE64_COUNT
|
||||
#define THREAD_STATE64 ARM_THREAD_STATE64
|
||||
#define thread_state64_t arm_thread_state64_t
|
||||
#else
|
||||
#error Unknown Darwin Platform
|
||||
#endif
|
||||
|
||||
void PageFaultHandler::SignalHandler(mach_port_t port)
|
||||
{
|
||||
Threading::SetNameOfCurrentThread("Mach Exception Thread");
|
||||
|
||||
#pragma pack(4)
|
||||
struct
|
||||
{
|
||||
mach_msg_header_t Head;
|
||||
NDR_record_t NDR;
|
||||
exception_type_t exception;
|
||||
mach_msg_type_number_t codeCnt;
|
||||
int64_t code[2];
|
||||
int flavor;
|
||||
mach_msg_type_number_t old_stateCnt;
|
||||
natural_t old_state[THREAD_STATE64_COUNT];
|
||||
mach_msg_trailer_t trailer;
|
||||
} msg_in;
|
||||
|
||||
struct
|
||||
{
|
||||
mach_msg_header_t Head;
|
||||
NDR_record_t NDR;
|
||||
kern_return_t RetCode;
|
||||
int flavor;
|
||||
mach_msg_type_number_t new_stateCnt;
|
||||
natural_t new_state[THREAD_STATE64_COUNT];
|
||||
} msg_out;
|
||||
#pragma pack()
|
||||
memset(&msg_in, 0xee, sizeof(msg_in));
|
||||
memset(&msg_out, 0xee, sizeof(msg_out));
|
||||
mach_msg_size_t send_size = 0;
|
||||
mach_msg_option_t option = MACH_RCV_MSG;
|
||||
while (true)
|
||||
{
|
||||
kern_return_t r;
|
||||
if ((r = mach_msg_overwrite(&msg_out.Head, option, send_size, sizeof(msg_in), port,
|
||||
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL, &msg_in.Head, 0)))
|
||||
{
|
||||
pxFail(fmt::format("CRITICAL: mach_msg_overwrite: {:x}", r).c_str());
|
||||
}
|
||||
|
||||
if (msg_in.Head.msgh_id == MACH_NOTIFY_NO_SENDERS)
|
||||
{
|
||||
// the other thread exited
|
||||
mach_port_deallocate(mach_task_self(), port);
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg_in.Head.msgh_id != 2406)
|
||||
{
|
||||
pxFailRel("unknown message received");
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg_in.flavor != THREAD_STATE64)
|
||||
{
|
||||
pxFailRel(fmt::format("unknown flavour {}, expected {}", msg_in.flavor, THREAD_STATE64).c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
s_exception_handler_mutex.lock();
|
||||
thread_state64_t* state = (thread_state64_t*)msg_in.old_state;
|
||||
|
||||
HandlerResult result = HandlerResult::ExecuteNextHandler;
|
||||
if (!s_in_exception_handler)
|
||||
{
|
||||
s_in_exception_handler = true;
|
||||
|
||||
#ifdef _M_ARM64
|
||||
result = HandlePageFault(reinterpret_cast<void*>(state->__pc), reinterpret_cast<void*>(msg_in.code[1]), (msg_in.code[0] & 2) != 0);
|
||||
#else
|
||||
result = HandlePageFault(reinterpret_cast<void*>(state->__rip), reinterpret_cast<void*>(msg_in.code[1]), (msg_in.code[0] & 2) != 0);
|
||||
#endif
|
||||
s_in_exception_handler = false;
|
||||
}
|
||||
|
||||
// Set up the reply.
|
||||
msg_out.Head.msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(msg_in.Head.msgh_bits), 0);
|
||||
msg_out.Head.msgh_remote_port = msg_in.Head.msgh_remote_port;
|
||||
msg_out.Head.msgh_local_port = MACH_PORT_NULL;
|
||||
msg_out.Head.msgh_id = msg_in.Head.msgh_id + 100;
|
||||
msg_out.NDR = msg_in.NDR;
|
||||
|
||||
if (result != HandlerResult::ContinueExecution) // cooked
|
||||
{
|
||||
msg_out.RetCode = KERN_FAILURE;
|
||||
msg_out.flavor = 0;
|
||||
msg_out.new_stateCnt = 0;
|
||||
|
||||
// The crash handler on macOS or Linux doesn't use context passed to it
|
||||
// Stubbing it here is fine
|
||||
CrashHandler::CrashSignalHandler(-1, nullptr, nullptr);
|
||||
|
||||
pxFailRel("CrashSignalHandler returned when it should have terminated us!");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Resumes execution right where we left off (re-executes instruction that caused the SIGSEGV)
|
||||
msg_out.RetCode = KERN_SUCCESS;
|
||||
msg_out.flavor = THREAD_STATE64;
|
||||
msg_out.new_stateCnt = THREAD_STATE64_COUNT;
|
||||
memcpy(msg_out.new_state, msg_in.old_state, THREAD_STATE64_COUNT * sizeof(natural_t));
|
||||
}
|
||||
|
||||
msg_out.Head.msgh_size =
|
||||
offsetof(__typeof__(msg_out), new_state) + msg_out.new_stateCnt * sizeof(natural_t);
|
||||
send_size = msg_out.Head.msgh_size;
|
||||
option |= MACH_SEND_MSG;
|
||||
|
||||
s_exception_handler_mutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
bool PageFaultHandler::Install(Error* error)
|
||||
{
|
||||
exception_mask_t masks[EXC_TYPES_COUNT];
|
||||
mach_port_t ports[EXC_TYPES_COUNT];
|
||||
exception_behavior_t behaviors[EXC_TYPES_COUNT];
|
||||
thread_state_flavor_t flavors[EXC_TYPES_COUNT];
|
||||
mach_msg_type_number_t count = EXC_TYPES_COUNT;
|
||||
|
||||
kern_return_t r = task_get_exception_ports(mach_task_self(), EXC_MASK_ALL,
|
||||
masks, &count, ports, behaviors, flavors);
|
||||
|
||||
mach_port_t port;
|
||||
if ((r = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port)))
|
||||
{
|
||||
pxFailRel(fmt::format("mach_port_allocate: {:x}", r).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
std::thread sig_thread(PageFaultHandler::SignalHandler, port);
|
||||
sig_thread.detach();
|
||||
|
||||
if ((r = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND)))
|
||||
{
|
||||
mach_port_deallocate(mach_task_self(), port);
|
||||
pxFailRel(fmt::format("mach_port_insert_right: {:x}", r).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
task_set_exception_ports(mach_task_self(), EXC_MASK_BAD_ACCESS, MACH_PORT_NULL, EXCEPTION_DEFAULT, THREAD_STATE_NONE);
|
||||
|
||||
if ((r = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, port, EXCEPTION_STATE | MACH_EXCEPTION_CODES, THREAD_STATE64)))
|
||||
{
|
||||
mach_port_deallocate(mach_task_self(), port);
|
||||
pxFailRel(fmt::format("thread_set_exception_ports: {:x}", r).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((r = mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, -1)))
|
||||
{
|
||||
mach_port_deallocate(mach_task_self(), port);
|
||||
pxFailRel(fmt::format("mach_port_mod_refs: {:x}", r).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
mach_port_t previous;
|
||||
if ((r = mach_port_request_notification(mach_task_self(), port, MACH_NOTIFY_NO_SENDERS, 0, port, MACH_MSG_TYPE_MAKE_SEND_ONCE, &previous)))
|
||||
{
|
||||
mach_port_deallocate(mach_task_self(), port);
|
||||
pxFailRel(fmt::format("mach_port_mod_refs: {:x}", r).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
s_installed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void PageFaultHandler::SignalHandler(int sig, siginfo_t* info, void* ctx)
|
||||
{
|
||||
#if defined(_M_X86)
|
||||
@@ -644,3 +839,4 @@ bool PageFaultHandler::Install(Error* error)
|
||||
s_installed = true;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -86,7 +86,6 @@ namespace QtHost
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
static QTimer* s_settings_save_timer = nullptr;
|
||||
static std::unique_ptr<INISettingsInterface> s_base_settings_interface;
|
||||
static std::unique_ptr<INISettingsInterface> s_secrets_settings_interface;
|
||||
static bool s_batch_mode = false;
|
||||
static bool s_nogui_mode = false;
|
||||
static bool s_start_big_picture_mode = false;
|
||||
@@ -1308,7 +1307,6 @@ bool QtHost::InitializeConfig()
|
||||
// Write crash dumps to the data directory, since that'll be accessible for certain.
|
||||
CrashHandler::SetWriteDirectory(EmuFolders::DataRoot);
|
||||
|
||||
// Load main settings ini
|
||||
const std::string path = Path::Combine(EmuFolders::Settings, "PCSX2.ini");
|
||||
const bool settings_exists = FileSystem::FileExists(path.c_str());
|
||||
Console.WriteLnFmt("Loading config from {}.", path);
|
||||
@@ -1349,29 +1347,6 @@ bool QtHost::InitializeConfig()
|
||||
SaveSettings();
|
||||
}
|
||||
|
||||
// Layer secrets ini on top
|
||||
const std::string secrets_path = Path::Combine(EmuFolders::Settings, "secrets.ini");
|
||||
const bool secrets_settings_exists = FileSystem::FileExists(secrets_path.c_str());
|
||||
Console.WriteLnFmt("Loading secrets from {}.", secrets_path);
|
||||
|
||||
s_secrets_settings_interface = std::make_unique<INISettingsInterface>(std::move(secrets_path));
|
||||
Host::Internal::SetSecretsSettingsLayer(s_secrets_settings_interface.get());
|
||||
if (!secrets_settings_exists || !s_secrets_settings_interface->Load())
|
||||
{
|
||||
if (!s_base_settings_interface->Save(&error))
|
||||
{
|
||||
QMessageBox::critical(
|
||||
nullptr, QStringLiteral("PCSX2"),
|
||||
QStringLiteral(
|
||||
"Failed to save secrets to\n\n%1\n\nThe error was: %2\n\nPlease ensure this directory is writable. You "
|
||||
"can also try portable mode by creating portable.txt in the same directory you installed PCSX2 into.")
|
||||
.arg(QString::fromStdString(s_secrets_settings_interface->GetFileName()))
|
||||
.arg(QString::fromStdString(error.GetDescription())));
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Setup wizard was incomplete last time?
|
||||
s_run_setup_wizard =
|
||||
s_run_setup_wizard || s_base_settings_interface->GetBoolValue("UI", "SetupWizardIncomplete", false);
|
||||
|
||||
@@ -202,11 +202,7 @@ void ControllerBindingWidget::onAutomaticBindingClicked()
|
||||
for (const QPair<QString, QString>& dev : m_dialog->getDeviceList())
|
||||
{
|
||||
// we set it as data, because the device list could get invalidated while the menu is up
|
||||
QAction* action;
|
||||
if(dev.first.compare(dev.second, Qt::CaseInsensitive) == 0)
|
||||
action = menu.addAction(dev.first);
|
||||
else
|
||||
action = menu.addAction(QStringLiteral("%1: %2").arg(dev.first).arg(dev.second));
|
||||
QAction* action = menu.addAction(QStringLiteral("%1 (%2)").arg(dev.first).arg(dev.second));
|
||||
action->setData(dev.first);
|
||||
connect(action, &QAction::triggered, this, [this, action]() { doDeviceAutomaticBinding(action->data().toString()); });
|
||||
added = true;
|
||||
@@ -1156,11 +1152,7 @@ void USBDeviceWidget::onAutomaticBindingClicked()
|
||||
for (const QPair<QString, QString>& dev : m_dialog->getDeviceList())
|
||||
{
|
||||
// we set it as data, because the device list could get invalidated while the menu is up
|
||||
QAction* action;
|
||||
if(dev.first.compare(dev.second, Qt::CaseInsensitive) == 0)
|
||||
action = menu.addAction(dev.first);
|
||||
else
|
||||
action = menu.addAction(QStringLiteral("%1: %2").arg(dev.first).arg(dev.second));
|
||||
QAction* action = menu.addAction(QStringLiteral("%1 (%2)").arg(dev.first).arg(dev.second));
|
||||
action->setData(dev.first);
|
||||
connect(action, &QAction::triggered, this, [this, action]() { doDeviceAutomaticBinding(action->data().toString()); });
|
||||
added = true;
|
||||
|
||||
@@ -88,11 +88,7 @@ ControllerGlobalSettingsWidget::~ControllerGlobalSettingsWidget() = default;
|
||||
void ControllerGlobalSettingsWidget::addDeviceToList(const QString& identifier, const QString& name)
|
||||
{
|
||||
QListWidgetItem* item = new QListWidgetItem();
|
||||
if(identifier.compare(name,Qt::CaseInsensitive) == 0)
|
||||
item->setText(identifier);
|
||||
else
|
||||
item->setText(QStringLiteral("%1: %2").arg(identifier).arg(name));
|
||||
|
||||
item->setText(QStringLiteral("%1: %2").arg(identifier).arg(name));
|
||||
item->setData(Qt::UserRole, identifier);
|
||||
m_ui.deviceList->addItem(item);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -26,7 +26,6 @@
|
||||
#include "common/MD5Digest.h"
|
||||
#include "common/Path.h"
|
||||
#include "common/ScopedGuard.h"
|
||||
#include "common/SettingsInterface.h"
|
||||
#include "common/SmallString.h"
|
||||
#include "common/StringUtil.h"
|
||||
#include "common/Timer.h"
|
||||
@@ -440,25 +439,7 @@ bool Achievements::Initialize()
|
||||
IdentifyGame(VMManager::GetDiscCRC(), VMManager::GetCurrentCRC());
|
||||
|
||||
const std::string username = Host::GetBaseStringSettingValue("Achievements", "Username");
|
||||
|
||||
// Check the base settings file to see if the token is defined inside. Move if found.
|
||||
std::string oldToken = Host::GetBaseStringSettingValue("Achievements", "Token");
|
||||
if (!oldToken.empty())
|
||||
{
|
||||
auto secretsLock = Host::GetSecretsSettingsLock();
|
||||
SettingsInterface* secretsInterface = Host::Internal::GetSecretsSettingsLayer();
|
||||
secretsInterface->SetStringValue("Achievements", "Token", oldToken.c_str());
|
||||
secretsInterface->Save();
|
||||
|
||||
oldToken.clear();
|
||||
|
||||
auto baseLock = Host::GetSettingsLock();
|
||||
SettingsInterface* baseInterface = Host::Internal::GetBaseSettingsLayer();
|
||||
baseInterface->DeleteValue("Achievements", "Token");
|
||||
baseInterface->Save();
|
||||
}
|
||||
|
||||
const std::string api_token = Host::GetStringSettingValue("Achievements", "Token");
|
||||
const std::string api_token = Host::GetBaseStringSettingValue("Achievements", "Token");
|
||||
if (!username.empty() && !api_token.empty())
|
||||
{
|
||||
Console.WriteLn("Achievements: Attempting login with user '%s'...", username.c_str());
|
||||
@@ -1804,12 +1785,9 @@ void Achievements::ClientLoginWithPasswordCallback(int result, const char* error
|
||||
|
||||
// Store configuration.
|
||||
Host::SetBaseStringSettingValue("Achievements", "Username", params->username);
|
||||
Host::SetBaseStringSettingValue("Achievements", "Token", user->token);
|
||||
Host::SetBaseStringSettingValue("Achievements", "LoginTimestamp", fmt::format("{}", std::time(nullptr)).c_str());
|
||||
Host::CommitBaseSettingChanges();
|
||||
|
||||
SettingsInterface* secretsInterface = Host::Internal::GetSecretsSettingsLayer();
|
||||
secretsInterface->SetStringValue("Achievements", "Token", user->token);
|
||||
secretsInterface->Save();
|
||||
|
||||
ShowLoginSuccess(client);
|
||||
}
|
||||
@@ -1909,13 +1887,9 @@ void Achievements::Logout()
|
||||
|
||||
Console.WriteLn("Achievements: Clearing credentials...");
|
||||
Host::RemoveBaseSettingValue("Achievements", "Username");
|
||||
Host::RemoveBaseSettingValue("Achievements", "Token");
|
||||
Host::RemoveBaseSettingValue("Achievements", "LoginTimestamp");
|
||||
Host::CommitBaseSettingChanges();
|
||||
|
||||
auto secretsLock = Host::GetSecretsSettingsLock();
|
||||
SettingsInterface* secretsInterface = Host::Internal::GetSecretsSettingsLayer();
|
||||
secretsInterface->DeleteValue("Achievements", "Token");
|
||||
secretsInterface->Save();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
|
||||
std::vector<BreakPoint> CBreakPoints::breakPoints_;
|
||||
u32 CBreakPoints::breakSkipFirstAtEE_ = 0;
|
||||
u64 CBreakPoints::breakSkipFirstTicksEE_ = 0;
|
||||
u32 CBreakPoints::breakSkipFirstAtIop_ = 0;
|
||||
bool CBreakPoints::pendingClearSkipFirstAtEE_ = false;
|
||||
bool CBreakPoints::pendingClearSkipFirstAtIop_ = false;
|
||||
u64 CBreakPoints::breakSkipFirstTicksIop_ = 0;
|
||||
std::vector<MemCheck> CBreakPoints::memChecks_;
|
||||
std::vector<MemCheck*> CBreakPoints::cleanupMemChecks_;
|
||||
bool CBreakPoints::breakpointTriggered_ = false;
|
||||
@@ -393,47 +393,30 @@ void CBreakPoints::SetSkipFirst(BreakPointCpu cpu, u32 pc)
|
||||
if (cpu == BREAKPOINT_EE)
|
||||
{
|
||||
breakSkipFirstAtEE_ = standardizeBreakpointAddress(pc);
|
||||
pendingClearSkipFirstAtEE_ = false;
|
||||
breakSkipFirstTicksEE_ = r5900Debug.getCycles();
|
||||
}
|
||||
else if (cpu == BREAKPOINT_IOP)
|
||||
{
|
||||
breakSkipFirstAtIop_ = pc;
|
||||
pendingClearSkipFirstAtIop_ = false;
|
||||
breakSkipFirstTicksIop_ = r3000Debug.getCycles();
|
||||
}
|
||||
}
|
||||
|
||||
u32 CBreakPoints::CheckSkipFirst(BreakPointCpu cpu, u32 cmpPc)
|
||||
{
|
||||
if (cpu == BREAKPOINT_EE && breakSkipFirstAtEE_ == r5900Debug.getPC())
|
||||
if (cpu == BREAKPOINT_EE && breakSkipFirstTicksEE_ == r5900Debug.getCycles())
|
||||
return breakSkipFirstAtEE_;
|
||||
else if (cpu == BREAKPOINT_IOP && breakSkipFirstAtIop_ == r3000Debug.getPC())
|
||||
else if (cpu == BREAKPOINT_IOP && breakSkipFirstTicksIop_ == r3000Debug.getCycles())
|
||||
return breakSkipFirstAtIop_;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CBreakPoints::ClearSkipFirst(BreakPointCpu cpu)
|
||||
void CBreakPoints::ClearSkipFirst()
|
||||
{
|
||||
if((cpu & BREAKPOINT_EE) != 0)
|
||||
pendingClearSkipFirstAtEE_ = true;
|
||||
else if ((cpu & BREAKPOINT_IOP) != 0)
|
||||
pendingClearSkipFirstAtIop_ = true;
|
||||
|
||||
if(cpu == BREAKPOINT_IOP_AND_EE)
|
||||
CommitClearSkipFirst(BREAKPOINT_IOP_AND_EE);
|
||||
}
|
||||
|
||||
void CBreakPoints::CommitClearSkipFirst(BreakPointCpu cpu)
|
||||
{
|
||||
if((cpu & BREAKPOINT_EE) != 0 && pendingClearSkipFirstAtEE_)
|
||||
{
|
||||
pendingClearSkipFirstAtEE_ = false;
|
||||
breakSkipFirstAtEE_ = 0;
|
||||
}
|
||||
else if ((cpu & BREAKPOINT_IOP) != 0 && pendingClearSkipFirstAtIop_)
|
||||
{
|
||||
pendingClearSkipFirstAtIop_ = true;
|
||||
breakSkipFirstAtIop_ = 0;
|
||||
}
|
||||
breakSkipFirstAtEE_ = 0;
|
||||
breakSkipFirstTicksEE_ = 0;
|
||||
breakSkipFirstAtIop_ = 0;
|
||||
breakSkipFirstTicksIop_ = 0;
|
||||
}
|
||||
|
||||
const std::vector<MemCheck> CBreakPoints::GetMemCheckRanges()
|
||||
|
||||
@@ -135,8 +135,7 @@ public:
|
||||
|
||||
static void SetSkipFirst(BreakPointCpu cpu, u32 pc);
|
||||
static u32 CheckSkipFirst(BreakPointCpu cpu, u32 pc);
|
||||
static void ClearSkipFirst(BreakPointCpu cpu = BREAKPOINT_IOP_AND_EE);
|
||||
static void CommitClearSkipFirst(BreakPointCpu cpu);
|
||||
static void ClearSkipFirst();
|
||||
|
||||
// Includes uncached addresses.
|
||||
static const std::vector<MemCheck> GetMemCheckRanges();
|
||||
@@ -170,9 +169,9 @@ private:
|
||||
|
||||
static std::vector<BreakPoint> breakPoints_;
|
||||
static u32 breakSkipFirstAtEE_;
|
||||
static bool pendingClearSkipFirstAtEE_;
|
||||
static u64 breakSkipFirstTicksEE_;
|
||||
static u32 breakSkipFirstAtIop_;
|
||||
static bool pendingClearSkipFirstAtIop_;
|
||||
static u64 breakSkipFirstTicksIop_;
|
||||
|
||||
static bool breakpointTriggered_;
|
||||
static BreakPointCpu breakpointTriggeredCpu_;
|
||||
|
||||
@@ -26,7 +26,6 @@ namespace Host
|
||||
const std::string_view context, const std::string_view msg);
|
||||
|
||||
static std::mutex s_settings_mutex;
|
||||
static std::mutex s_secrets_settings_mutex;
|
||||
static LayeredSettingsInterface s_layered_settings_interface;
|
||||
|
||||
static constexpr u32 TRANSLATION_STRING_CACHE_SIZE = 4 * 1024 * 1024;
|
||||
@@ -165,11 +164,6 @@ std::unique_lock<std::mutex> Host::GetSettingsLock()
|
||||
return std::unique_lock<std::mutex>(s_settings_mutex);
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> Host::GetSecretsSettingsLock()
|
||||
{
|
||||
return std::unique_lock<std::mutex>(s_secrets_settings_mutex);
|
||||
}
|
||||
|
||||
SettingsInterface* Host::GetSettingsInterface()
|
||||
{
|
||||
return &s_layered_settings_interface;
|
||||
@@ -358,11 +352,6 @@ SettingsInterface* Host::Internal::GetBaseSettingsLayer()
|
||||
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE);
|
||||
}
|
||||
|
||||
SettingsInterface* Host::Internal::GetSecretsSettingsLayer()
|
||||
{
|
||||
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_SECRETS);
|
||||
}
|
||||
|
||||
SettingsInterface* Host::Internal::GetGameSettingsLayer()
|
||||
{
|
||||
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_GAME);
|
||||
@@ -376,17 +365,10 @@ SettingsInterface* Host::Internal::GetInputSettingsLayer()
|
||||
void Host::Internal::SetBaseSettingsLayer(SettingsInterface* sif)
|
||||
{
|
||||
pxAssertRel(s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE) == nullptr,
|
||||
"Base layer has already been set");
|
||||
"Base layer has not been set");
|
||||
s_layered_settings_interface.SetLayer(LayeredSettingsInterface::LAYER_BASE, sif);
|
||||
}
|
||||
|
||||
void Host::Internal::SetSecretsSettingsLayer(SettingsInterface* sif)
|
||||
{
|
||||
pxAssertRel(s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_SECRETS) == nullptr,
|
||||
"Secrets layer has already been set");
|
||||
s_layered_settings_interface.SetLayer(LayeredSettingsInterface::LAYER_SECRETS, sif);
|
||||
}
|
||||
|
||||
void Host::Internal::SetGameSettingsLayer(SettingsInterface* sif, std::unique_lock<std::mutex>& settings_lock)
|
||||
{
|
||||
s_layered_settings_interface.SetLayer(LayeredSettingsInterface::LAYER_GAME, sif);
|
||||
|
||||
@@ -134,8 +134,6 @@ namespace Host
|
||||
|
||||
/// Direct access to settings interface. Must hold the lock when calling GetSettingsInterface() and while using it.
|
||||
std::unique_lock<std::mutex> GetSettingsLock();
|
||||
/// Ditto for secrets file.
|
||||
std::unique_lock<std::mutex> GetSecretsSettingsLock();
|
||||
SettingsInterface* GetSettingsInterface();
|
||||
|
||||
/// Sets host-specific default settings.
|
||||
@@ -149,9 +147,6 @@ namespace Host
|
||||
/// Retrieves the base settings layer. Must call with lock held.
|
||||
SettingsInterface* GetBaseSettingsLayer();
|
||||
|
||||
/// Retrieves the base settings layer. Must call with lock held.
|
||||
SettingsInterface* GetSecretsSettingsLayer();
|
||||
|
||||
/// Retrieves the game settings layer, if present. Must call with lock held.
|
||||
SettingsInterface* GetGameSettingsLayer();
|
||||
|
||||
@@ -161,9 +156,6 @@ namespace Host
|
||||
/// Sets the base settings layer. Should be called by the host at initialization time.
|
||||
void SetBaseSettingsLayer(SettingsInterface* sif);
|
||||
|
||||
/// Sets the secrets settings layer. Should follow call to SetBaseSettingsLayer.
|
||||
void SetSecretsSettingsLayer(SettingsInterface* sif);
|
||||
|
||||
/// Sets the game settings layer. Called by VMManager when the game changes.
|
||||
void SetGameSettingsLayer(SettingsInterface* sif, std::unique_lock<std::mutex>& settings_lock);
|
||||
|
||||
|
||||
@@ -3458,11 +3458,8 @@ void FullscreenUI::StartAutomaticBinding(u32 port)
|
||||
names.reserve(devices.size());
|
||||
for (auto& [name, display_name] : devices)
|
||||
{
|
||||
if(!StringUtil::compareNoCase(name, display_name))
|
||||
options.emplace_back(fmt::format("{}: {}", name, display_name), false);
|
||||
else
|
||||
options.emplace_back(std::move(display_name), false);
|
||||
names.push_back(std::move(name));
|
||||
options.emplace_back(std::move(display_name), false);
|
||||
}
|
||||
OpenChoiceDialog(FSUI_CSTR("Select Device"), false, std::move(options),
|
||||
[port, names = std::move(names)](s32 index, const std::string& title, bool checked) {
|
||||
|
||||
@@ -67,10 +67,7 @@ void intBreakpoint(bool memcheck)
|
||||
{
|
||||
const u32 pc = cpuRegs.pc;
|
||||
if (CBreakPoints::CheckSkipFirst(BREAKPOINT_EE, pc) != 0)
|
||||
{
|
||||
CBreakPoints::ClearSkipFirst(BREAKPOINT_EE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!memcheck)
|
||||
{
|
||||
@@ -164,8 +161,6 @@ static void execI()
|
||||
intBreakpoint(false);
|
||||
|
||||
intCheckMemcheck();
|
||||
|
||||
CBreakPoints::CommitClearSkipFirst(BREAKPOINT_EE);
|
||||
#endif
|
||||
|
||||
const u32 pc = cpuRegs.pc;
|
||||
|
||||
@@ -15,7 +15,6 @@ public:
|
||||
LAYER_CMDLINE,
|
||||
LAYER_GAME,
|
||||
LAYER_INPUT,
|
||||
LAYER_SECRETS,
|
||||
LAYER_BASE,
|
||||
NUM_LAYERS
|
||||
};
|
||||
|
||||
@@ -120,10 +120,7 @@ void psxBreakpoint(bool memcheck)
|
||||
{
|
||||
u32 pc = psxRegs.pc;
|
||||
if (CBreakPoints::CheckSkipFirst(BREAKPOINT_IOP, pc) != 0)
|
||||
{
|
||||
CBreakPoints::ClearSkipFirst(BREAKPOINT_IOP);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!memcheck)
|
||||
{
|
||||
@@ -211,8 +208,6 @@ static __fi void execI()
|
||||
psxBreakpoint(false);
|
||||
|
||||
psxCheckMemcheck();
|
||||
|
||||
CBreakPoints::CommitClearSkipFirst(BREAKPOINT_IOP);
|
||||
#endif
|
||||
|
||||
// Inject IRX hack
|
||||
|
||||
@@ -1259,10 +1259,7 @@ static bool psxDynarecCheckBreakpoint()
|
||||
{
|
||||
u32 pc = psxRegs.pc;
|
||||
if (CBreakPoints::CheckSkipFirst(BREAKPOINT_IOP, pc) == pc)
|
||||
{
|
||||
CBreakPoints::ClearSkipFirst(BREAKPOINT_IOP);
|
||||
return false;
|
||||
}
|
||||
|
||||
int bpFlags = psxIsBreakpointNeeded(pc);
|
||||
bool hit = false;
|
||||
@@ -1302,10 +1299,8 @@ static bool psxDynarecMemcheck(size_t i)
|
||||
auto mc = CBreakPoints::GetMemChecks(BREAKPOINT_IOP)[i];
|
||||
|
||||
if (CBreakPoints::CheckSkipFirst(BREAKPOINT_IOP, pc) == pc)
|
||||
{
|
||||
CBreakPoints::ClearSkipFirst(BREAKPOINT_IOP);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mc.hasCond)
|
||||
{
|
||||
if (!mc.cond.Evaluate())
|
||||
@@ -1378,7 +1373,7 @@ static void psxRecMemcheck(u32 op, u32 bits, bool store)
|
||||
}
|
||||
}
|
||||
|
||||
static bool psxEncodeBreakpoint()
|
||||
static void psxEncodeBreakpoint()
|
||||
{
|
||||
if (psxIsBreakpointNeeded(psxpc) != 0)
|
||||
{
|
||||
@@ -1386,17 +1381,14 @@ static bool psxEncodeBreakpoint()
|
||||
xFastCall((void*)psxDynarecCheckBreakpoint);
|
||||
xTEST(al, al);
|
||||
xJNZ(iopExitRecompiledCode);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool psxEncodeMemcheck()
|
||||
static void psxEncodeMemcheck()
|
||||
{
|
||||
int needed = psxIsMemcheckNeeded(psxpc);
|
||||
if (needed == 0)
|
||||
return false;
|
||||
return;
|
||||
|
||||
u32 op = iopMemRead32(needed == 2 ? psxpc + 4 : psxpc);
|
||||
const R5900::OPCODE& opcode = R5900::GetInstruction(op);
|
||||
@@ -1417,7 +1409,6 @@ static bool psxEncodeMemcheck()
|
||||
psxRecMemcheck(op, 64, store);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void psxRecompileNextInstruction(bool delayslot, bool swapped_delayslot)
|
||||
@@ -1446,10 +1437,12 @@ void psxRecompileNextInstruction(bool delayslot, bool swapped_delayslot)
|
||||
EEINST* old_inst_info = g_pCurInstInfo;
|
||||
s_recompilingDelaySlot = delayslot;
|
||||
|
||||
// add breakpoint
|
||||
if (!delayslot)
|
||||
{
|
||||
if(psxEncodeBreakpoint() || psxEncodeMemcheck())
|
||||
xFastCall((void*)CBreakPoints::CommitClearSkipFirst, BREAKPOINT_IOP);
|
||||
// Broken on x64
|
||||
psxEncodeBreakpoint();
|
||||
psxEncodeMemcheck();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1498,10 +1498,7 @@ void dynarecCheckBreakpoint()
|
||||
{
|
||||
u32 pc = cpuRegs.pc;
|
||||
if (CBreakPoints::CheckSkipFirst(BREAKPOINT_EE, pc) != 0)
|
||||
{
|
||||
CBreakPoints::ClearSkipFirst(BREAKPOINT_EE);
|
||||
return;
|
||||
}
|
||||
|
||||
const int bpFlags = isBreakpointNeeded(pc);
|
||||
bool hit = false;
|
||||
@@ -1535,10 +1532,7 @@ void dynarecMemcheck(size_t i)
|
||||
const u32 op = memRead32(cpuRegs.pc);
|
||||
const OPCODE& opcode = GetInstruction(op);
|
||||
if (CBreakPoints::CheckSkipFirst(BREAKPOINT_EE, pc) != 0)
|
||||
{
|
||||
CBreakPoints::ClearSkipFirst(BREAKPOINT_EE);
|
||||
return;
|
||||
}
|
||||
|
||||
auto mc = CBreakPoints::GetMemChecks(BREAKPOINT_EE)[i];
|
||||
|
||||
@@ -1612,22 +1606,20 @@ void recMemcheck(u32 op, u32 bits, bool store)
|
||||
}
|
||||
}
|
||||
|
||||
bool encodeBreakpoint()
|
||||
void encodeBreakpoint()
|
||||
{
|
||||
if (isBreakpointNeeded(pc) != 0)
|
||||
{
|
||||
iFlushCall(FLUSH_EVERYTHING | FLUSH_PC);
|
||||
xFastCall((void*)dynarecCheckBreakpoint);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool encodeMemcheck()
|
||||
void encodeMemcheck()
|
||||
{
|
||||
const int needed = isMemcheckNeeded(pc);
|
||||
if (needed == 0)
|
||||
return false;
|
||||
return;
|
||||
|
||||
const u32 op = memRead32(needed == 2 ? pc + 4 : pc);
|
||||
const OPCODE& opcode = GetInstruction(op);
|
||||
@@ -1651,7 +1643,6 @@ bool encodeMemcheck()
|
||||
recMemcheck(op, 128, store);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void recompileNextInstruction(bool delayslot, bool swapped_delay_slot)
|
||||
@@ -1662,8 +1653,8 @@ void recompileNextInstruction(bool delayslot, bool swapped_delay_slot)
|
||||
// add breakpoint
|
||||
if (!delayslot)
|
||||
{
|
||||
if(encodeBreakpoint() || encodeMemcheck())
|
||||
xFastCall((void*)CBreakPoints::CommitClearSkipFirst, BREAKPOINT_EE);
|
||||
encodeBreakpoint();
|
||||
encodeMemcheck();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user