Compare commits

..

1 Commits

Author SHA1 Message Date
lizzie c52a6371a4 2026-09-18 06:06:10
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-18 19:11:31 +00:00
45 changed files with 13819 additions and 15211 deletions
+579 -624
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+503 -548
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+508 -550
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+527 -573
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -788,7 +788,7 @@ int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jobject
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* env, jobject jobj, jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* env, jobject jobj,
jstring jprogramId, jstring jprogramId,
jstring jupdatePath) { jstring jupdatePath) {
const u64 program_id = FileSys::GetBaseTitleID(EmulationSession::GetProgramId(env, jprogramId)); u64 program_id = EmulationSession::GetProgramId(env, jprogramId);
std::string updatePath = Common::Android::GetJString(env, jupdatePath); std::string updatePath = Common::Android::GetJString(env, jupdatePath);
std::shared_ptr<FileSys::NSP> nsp = std::make_shared<FileSys::NSP>( std::shared_ptr<FileSys::NSP> nsp = std::make_shared<FileSys::NSP>(
EmulationSession::GetInstance().System().GetFilesystem()->OpenFile( EmulationSession::GetInstance().System().GetFilesystem()->OpenFile(
@@ -796,7 +796,7 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* en
for (const auto& item : nsp->GetNCAs()) { for (const auto& item : nsp->GetNCAs()) {
for (const auto& nca_details : item.second) { for (const auto& nca_details : item.second) {
if (nca_details.second->GetName().ends_with(".cnmt.nca")) { if (nca_details.second->GetName().ends_with(".cnmt.nca")) {
const auto update_id = FileSys::GetBaseTitleID(nca_details.second->GetTitleId()); auto update_id = nca_details.second->GetTitleId() & ~0xFFFULL;
if (update_id == program_id) { if (update_id == program_id) {
return true; return true;
} }
@@ -289,7 +289,6 @@
<string name="gpu_driver_fetcher">Obtenedor de controladores de la GPU</string> <string name="gpu_driver_fetcher">Obtenedor de controladores de la GPU</string>
<string name="gpu_driver_manager">Gestor de controladores de la GPU</string> <string name="gpu_driver_manager">Gestor de controladores de la GPU</string>
<string name="install_gpu_driver_description">Instale los controladores alternativos para obtener un posible mejor rendimiento o precisión</string> <string name="install_gpu_driver_description">Instale los controladores alternativos para obtener un posible mejor rendimiento o precisión</string>
<string name="post_processing_add">Añadir efecto</string>
<string name="post_processing_open_list">Abrir lista</string> <string name="post_processing_open_list">Abrir lista</string>
<string name="post_processing_close_list">Cerrar lista</string> <string name="post_processing_close_list">Cerrar lista</string>
<string name="post_processing_reset">Restablecer a predeterminado</string> <string name="post_processing_reset">Restablecer a predeterminado</string>
@@ -318,13 +318,6 @@
<string name="frame_gen_target_rate">Целевая частота кадров</string> <string name="frame_gen_target_rate">Целевая частота кадров</string>
<string name="frame_gen_target_rate_description">Выберите значение под ваш дисплей. Множитель подстроится сам, чтобы его держать, и откатит изменения, если игра начнёт тормозить.</string> <string name="frame_gen_target_rate_description">Выберите значение под ваш дисплей. Множитель подстроится сам, чтобы его держать, и откатит изменения, если игра начнёт тормозить.</string>
<string name="frame_gen_target_rate_off">Использовать фиксированный множитель</string> <string name="frame_gen_target_rate_off">Использовать фиксированный множитель</string>
<string name="frame_gen_on">Вкл.</string>
<string name="frame_gen_off">Выкл.</string>
<string name="frame_gen_fixed">Фикс.</string>
<string name="frame_gen_flow_auto">Авто</string>
<string name="frame_gen_quick_description">Включите или выключите генерацию кадров и выберите множитель кадров.</string>
<string name="frame_gen_target_rate_quick_description">Генерация кадров с заданной частотой кадров. Множитель регулируется автоматически.</string>
<string name="frame_gen_flow_scale_quick_description">Разрешение, используемое для оценки движения между кадрами. Меньшие значения экономят время ГПУ.</string>
<string name="frame_gen_queue_target">Целевой размер очереди кадров</string> <string name="frame_gen_queue_target">Целевой размер очереди кадров</string>
<string name="frame_gen_queue_target_description">Сколько готовых кадров может ожидать перед выводом на экран. Более длинные очереди сглаживают скачки ГПУ ценой задержки ввода.</string> <string name="frame_gen_queue_target_description">Сколько готовых кадров может ожидать перед выводом на экран. Более длинные очереди сглаживают скачки ГПУ ценой задержки ввода.</string>
<string name="frame_gen_queue_target_0">Минимальная задержка (Без буферизации)</string> <string name="frame_gen_queue_target_0">Минимальная задержка (Без буферизации)</string>
@@ -335,14 +328,12 @@
<string name="frame_gen_flow_scale">Разрешение оценки движения</string> <string name="frame_gen_flow_scale">Разрешение оценки движения</string>
<string name="frame_gen_flow_scale_description">Разрешение прохода оптического потока в долях от выходного разрешения. Его понижение — самый дешёвый способ вернуть производительность.</string> <string name="frame_gen_flow_scale_description">Разрешение прохода оптического потока в долях от выходного разрешения. Его понижение — самый дешёвый способ вернуть производительность.</string>
<string name="frame_gen_unsupported">Генерация кадров недоступна</string> <string name="frame_gen_unsupported">Генерация кадров недоступна</string>
<string name="frame_gen_unsupported_description">В этом ГПУ драйвере отсутствует поддержка модели памяти Vulkan или половинной точности (float16), которая требуется шейдерам Lossless Scaling.</string>
<string name="lossless_scaling_setup_description">Опционально. Укажите свой Lossless.dll для включения генерации кадров позже.</string> <string name="lossless_scaling_setup_description">Опционально. Укажите свой Lossless.dll для включения генерации кадров позже.</string>
<string name="lossless_scaling_install">Установить Lossless.dll</string> <string name="lossless_scaling_install">Установить Lossless.dll</string>
<string name="lossless_scaling_install_description">Для генерации кадров требуется ваша собственная легальная копия Lossless.dll из Lossless Scaling</string> <string name="lossless_scaling_install_description">Для генерации кадров требуется ваша собственная легальная копия Lossless.dll из Lossless Scaling</string>
<string name="lossless_scaling_replace_description">Выбрать другой файл Lossless.dll</string> <string name="lossless_scaling_replace_description">Выбрать другой файл Lossless.dll</string>
<string name="frame_generation_support">Генерация кадров</string> <string name="frame_generation_support">Генерация кадров</string>
<string name="frame_generation_supported">Поддерживается</string> <string name="frame_generation_supported">Поддерживается</string>
<string name="frame_generation_unsupported">Не поддерживается (нет модели памяти Vulkan или float16)</string>
<string name="lossless_scaling_description">Предоставьте свою копию Lossless.dll для включения генерации кадров</string> <string name="lossless_scaling_description">Предоставьте свою копию Lossless.dll для включения генерации кадров</string>
<string name="lossless_scaling_installed">Установлена</string> <string name="lossless_scaling_installed">Установлена</string>
<string name="lossless_scaling_not_installed">Не установлена</string> <string name="lossless_scaling_not_installed">Не установлена</string>
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"> <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="app_disclaimer">本软件可以运行用于 Nintendo Switch 游戏机的游戏。不包含任何游戏或密钥。<br /><br />在您开始之前, 请定位您设备存储上的 <![CDATA[<b> prod.keys </b>]]> 文件。<br /><br /><![CDATA[<a href=\"https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/QuickStart.md\">了解更多</a>]]></string>
<string name="notice_notification_channel_name">错误与注意事项</string> <string name="notice_notification_channel_name">错误与注意事项</string>
<string name="notice_notification_channel_description">当发生错误时显示通知。</string> <string name="notice_notification_channel_description">当发生错误时显示通知。</string>
<string name="notification_permission_not_granted">未授予通知权限!</string> <string name="notification_permission_not_granted">未授予通知权限!</string>
@@ -291,25 +290,6 @@
<string name="gpu_driver_fetcher">GPU驱动获取器</string> <string name="gpu_driver_fetcher">GPU驱动获取器</string>
<string name="gpu_driver_manager">GPU 驱动管理器</string> <string name="gpu_driver_manager">GPU 驱动管理器</string>
<string name="install_gpu_driver_description">安装替代的驱动程序以获得更好的性能和精度</string> <string name="install_gpu_driver_description">安装替代的驱动程序以获得更好的性能和精度</string>
<string name="post_processing">后处理效果</string>
<string name="post_processing_description">在渲染完成后应用 ReShade FX 效果</string>
<string name="post_processing_per_game_description">配置此游戏的效果链</string>
<string name="post_processing_add">添加效果</string>
<string name="post_processing_remove">移除</string>
<string name="post_processing_open_list">打开列表</string>
<string name="post_processing_close_list">关闭列表</string>
<string name="post_processing_remove_all">移除效果</string>
<string name="post_processing_preset_locked">预设已激活。在开始游戏前可以在后处理效果中编辑它。</string>
<string name="post_processing_preset_modified">数值已从原始预设被更改。</string>
<string name="post_processing_presets">预设</string>
<string name="post_processing_preset_new">新建预设</string>
<string name="post_processing_preset_new_description">把您加载的效果及当前数值保存为一个预设,以便今后选用。</string>
<string name="post_processing_preset_name_invalid">请给预设起一个不含等号的名称。</string>
<string name="post_processing_preset_none">无预设</string>
<string name="post_processing_preset_delete">删除预设</string>
<string name="post_processing_preset_reset">重置预设值</string>
<string name="post_processing_reset">重置为默认值</string>
<string name="post_processing_empty">找不到效果。请在此文件中放置 .fx 文件:</string>
<string name="frame_gen">帧生成</string> <string name="frame_gen">帧生成</string>
<string name="frame_gen_per_game_description">配置针对此游戏的帧生成设定</string> <string name="frame_gen_per_game_description">配置针对此游戏的帧生成设定</string>
<string name="frame_gen_description">设定要在使用无损缩放渲染的帧之间应用的插帧。启用后强制采用FIFO呈现模式 。</string> <string name="frame_gen_description">设定要在使用无损缩放渲染的帧之间应用的插帧。启用后强制采用FIFO呈现模式 。</string>
@@ -324,13 +304,6 @@
<string name="frame_gen_target_rate_60">60 FPS</string> <string name="frame_gen_target_rate_60">60 FPS</string>
<string name="frame_gen_target_rate_90">90 FPS</string> <string name="frame_gen_target_rate_90">90 FPS</string>
<string name="frame_gen_target_rate_120">120 FPS</string> <string name="frame_gen_target_rate_120">120 FPS</string>
<string name="frame_gen_on"></string>
<string name="frame_gen_off"></string>
<string name="frame_gen_fixed">固定</string>
<string name="frame_gen_flow_auto">自动</string>
<string name="frame_gen_quick_description">打开或关闭帧生成并选择帧生成倍数。</string>
<string name="frame_gen_target_rate_quick_description">生成帧到目标帧率。倍率会自动调整。</string>
<string name="frame_gen_flow_scale_quick_description">用来估算帧间运动的分辨率。较低的值可以节省 GPU 时间。</string>
<string name="frame_gen_queue_target">帧队列目标</string> <string name="frame_gen_queue_target">帧队列目标</string>
<string name="frame_gen_queue_target_description">在显示之前有多少已完成渲染的帧正在等待。较大的队列可以缓解 GPU 突发的压力,但会增加输入延迟。</string> <string name="frame_gen_queue_target_description">在显示之前有多少已完成渲染的帧正在等待。较大的队列可以缓解 GPU 突发的压力,但会增加输入延迟。</string>
<string name="frame_gen_queue_target_0">最低延迟 (无缓冲)</string> <string name="frame_gen_queue_target_0">最低延迟 (无缓冲)</string>
@@ -341,14 +314,12 @@
<string name="frame_gen_flow_scale">运动预估分辨率</string> <string name="frame_gen_flow_scale">运动预估分辨率</string>
<string name="frame_gen_flow_scale_description">光流通道的分辨率,以输出的比例表示。降低它是提升性能最经济的做法。</string> <string name="frame_gen_flow_scale_description">光流通道的分辨率,以输出的比例表示。降低它是提升性能最经济的做法。</string>
<string name="frame_gen_unsupported">帧生成不可用</string> <string name="frame_gen_unsupported">帧生成不可用</string>
<string name="frame_gen_unsupported_description">这个 GPU 驱动缺少 Lossless Scaling 着色器所需的 Vulkan 内存模型或半精度 (float16) 支持。</string>
<string name="lossless_scaling_setup_description">作为可选项。请提供您自己的 Lossless.dll 以便在之后可以启用帧生成。</string> <string name="lossless_scaling_setup_description">作为可选项。请提供您自己的 Lossless.dll 以便在之后可以启用帧生成。</string>
<string name="lossless_scaling_install">安装 Lossless.dll</string> <string name="lossless_scaling_install">安装 Lossless.dll</string>
<string name="lossless_scaling_install_description">帧生成需要您自己从 Lossless Scaling 获得合法的 Lossless.dll 副本</string> <string name="lossless_scaling_install_description">帧生成需要您自己从 Lossless Scaling 获得合法的 Lossless.dll 副本</string>
<string name="lossless_scaling_replace_description">选择其它 Lossless.dll 副本</string> <string name="lossless_scaling_replace_description">选择其它 Lossless.dll 副本</string>
<string name="frame_generation_support">帧生成</string> <string name="frame_generation_support">帧生成</string>
<string name="frame_generation_supported">支持</string> <string name="frame_generation_supported">支持</string>
<string name="frame_generation_unsupported">不支持 (无 Vulkan 内存模型或 float16)</string>
<string name="lossless_scaling">无损缩放</string> <string name="lossless_scaling">无损缩放</string>
<string name="lossless_scaling_description">提供您自己的 Lossless.dll 文件以启用帧生成</string> <string name="lossless_scaling_description">提供您自己的 Lossless.dll 文件以启用帧生成</string>
<string name="lossless_scaling_installed">已安装</string> <string name="lossless_scaling_installed">已安装</string>
@@ -640,11 +611,6 @@
<string name="log">日志记录</string> <string name="log">日志记录</string>
<string name="flush_by_line">按行刷新调试日志</string> <string name="flush_by_line">按行刷新调试日志</string>
<string name="flush_by_line_description">在每行写入时刷新调试日志,使在崩溃或冻结时调试更容易。</string> <string name="flush_by_line_description">在每行写入时刷新调试日志,使在崩溃或冻结时调试更容易。</string>
<string name="extended_logging">开启扩展日志</string>
<string name="extended_logging_description">将最大日志文件大小从 100 MiB 提升至 1GiB。</string>
<string name="log_filter">日志筛选器</string>
<string name="log_filter_description">控制 Eden 的日志类别。例如: *:Info Service.LM:Debug</string>
<!-- GPU Logging strings --> <!-- GPU Logging strings -->
<string name="gpu_logging_header">GPU 日志</string> <string name="gpu_logging_header">GPU 日志</string>
<string name="gpu_log_level">日志等级</string> <string name="gpu_log_level">日志等级</string>
@@ -928,8 +894,6 @@
<string name="loader_error_file_not_found">ROM 文件不存在</string> <string name="loader_error_file_not_found">ROM 文件不存在</string>
<string name="loader_requires_firmware">游戏需要固件</string> <string name="loader_requires_firmware">游戏需要固件</string>
<string name="loader_requires_firmware_description"><![CDATA[这个游戏可能需要固件才能正常运行,但您还没有安装任何固件。请在启动前安装固件,或者按 “确定” 继续启动。]]></string>
<!-- Intent Launch strings --> <!-- Intent Launch strings -->
<string name="searching_for_game">正在搜索游戏...</string> <string name="searching_for_game">正在搜索游戏...</string>
<string name="game_not_found_for_title_id">未找到标题ID的游戏: %1$s</string> <string name="game_not_found_for_title_id">未找到标题ID的游戏: %1$s</string>
@@ -229,7 +229,7 @@
<string name="add_directory_success">遊戲目錄新增成功</string> <string name="add_directory_success">遊戲目錄新增成功</string>
<string name="enable_update_checks">檢查更新</string> <string name="enable_update_checks">檢查更新</string>
<string name="enable_update_checks_description">在Eden啟動時檢查有無新版本並選擇是否要下載與安裝更新</string> <string name="enable_update_checks_description">在Eden啟動時檢查有無新版本並選擇是否要下載與安裝更新</string>
<string name="update_available">發現新版本</string> <string name="update_available">偵測到新版本</string>
<string name="update_available_description">有更新可供安裝:%1$s\n\n您要進行更新嗎?</string> <string name="update_available_description">有更新可供安裝:%1$s\n\n您要進行更新嗎?</string>
<string name="downloading_update">下載更新中</string> <string name="downloading_update">下載更新中</string>
<string name="update_download_failed">更新下載失敗</string> <string name="update_download_failed">更新下載失敗</string>
@@ -1020,40 +1020,9 @@
<string name="memory_6gb">6GB (不穩定)</string> <string name="memory_6gb">6GB (不穩定)</string>
<string name="memory_8gb">8GB (不穩定)</string> <string name="memory_8gb">8GB (不穩定)</string>
<!-- CPU clock levels -->
<string name="clock_normal">正常</string>
<string name="clock_boost">加速</string>
<string name="clock_fast">超頻</string>
<!-- GPU clock levels -->
<string name="fast_gpu_normal">正常</string>
<string name="fast_gpu_medium">加速</string>
<string name="fast_gpu_high">超頻</string>
<!-- GPU swizzle texture size -->
<string name="gpu_texturesizeswizzle_verysmall">極小 16MB</string>
<string name="gpu_texturesizeswizzle_small">小(32MB</string>
<string name="gpu_texturesizeswizzle_normal">正常(128MB</string>
<string name="gpu_texturesizeswizzle_large">大(256MB</string>
<string name="gpu_texturesizeswizzle_verylarge">極大(512MB</string>
<!-- GPU swizzle streams -->
<string name="gpu_swizzle_verylow">極小(4MB</string>
<string name="gpu_swizzle_low">小(8MB</string>
<string name="gpu_swizzle_normal">正常(16MB</string>
<string name="gpu_swizzle_medium">中(32MB</string>
<string name="gpu_swizzle_high">大(64MB</string>
<!-- GPU swizzle chunks -->
<string name="gpu_swizzlechunk_verylow">極小(32</string>
<string name="gpu_swizzlechunk_low">小(64</string>
<string name="gpu_swizzlechunk_normal">正常(128</string>
<string name="gpu_swizzlechunk_medium">中(256</string>
<string name="gpu_swizzlechunk_high">大(512</string>
<!-- Temperature Units --> <!-- Temperature Units -->
<string name="temperature_celsius">攝氏</string> <string name="temperature_celsius">攝氏</string>
<string name="temperature_fahrenheit">華氏</string> <string name="temperature_fahrenheit">華氏</string>
<!-- Memory Sizes --> <!-- Memory Sizes -->
<string name="memory_byte_shorthand">B</string> <string name="memory_byte_shorthand">B</string>
@@ -1066,8 +1035,6 @@
<string name="renderer_none"></string> <string name="renderer_none"></string>
<!-- Renderer Accuracy -->
<string name="renderer_accuracy_low">效能</string>
<string name="renderer_accuracy_high">準確</string> <string name="renderer_accuracy_high">準確</string>
<!-- DMA Accuracy --> <!-- DMA Accuracy -->
+20 -18
View File
@@ -17,33 +17,35 @@
namespace Common { namespace Common {
// glibc, mlibc, musl, and newlib all define their own variants of strerror_r
// We don't need to use the preprocessor, we can just select depending on return type
template<typename T> std::string HandleStrerrorR(T r, char *err_str);
template<> std::string HandleStrerrorR(char* r, char *) { return std::string{r}; }
template<> std::string HandleStrerrorR(const char* r, char *) { return std::string{r}; }
template<> std::string HandleStrerrorR(int r, char *err_str) {
return std::string{r != 0
? "(strerror_r failed to format error)"
: err_str};
}
std::string NativeErrorToString(int e) { std::string NativeErrorToString(int e) {
#ifdef _WIN32 #ifdef _WIN32
LPSTR err_str; LPSTR err_str;
DWORD res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | DWORD res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS, FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, e, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), nullptr, e, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
LPSTR(&err_str), 1, nullptr); reinterpret_cast<LPSTR>(&err_str), 1, nullptr);
if (res) { if (!res) {
std::string ret(err_str); return "(FormatMessageA failed to format error)";
LocalFree(err_str);
return ret;
} }
return "(FormatMessageA failed to format error)"; std::string ret(err_str);
LocalFree(err_str);
return ret;
#else #else
char err_str[255]; char err_str[255];
return HandleStrerrorR(strerror_r(e, err_str, sizeof(err_str)), err_str); #if defined(__ANDROID__) || \
(defined(__GLIBC__) && (_GNU_SOURCE || (_POSIX_C_SOURCE < 200112L && _XOPEN_SOURCE < 600)))
// Thread safe (GNU-specific)
const char* str = strerror_r(e, err_str, sizeof(err_str));
return std::string(str);
#else
// Thread safe (XSI-compliant)
int second_err = strerror_r(e, err_str, sizeof(err_str));
if (second_err != 0) {
return "(strerror_r failed to format error)";
}
return std::string(err_str);
#endif // GLIBC etc.
#endif // _WIN32 #endif // _WIN32
} }
+14 -8
View File
@@ -9,6 +9,7 @@
#include "common/logging.h" #include "common/logging.h"
#include "common/uuid.h" #include "common/uuid.h"
#include "core/core.h" #include "core/core.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/savedata_factory.h" #include "core/file_sys/savedata_factory.h"
#include "core/file_sys/vfs/vfs.h" #include "core/file_sys/vfs/vfs.h"
@@ -61,17 +62,24 @@ SaveDataFactory::SaveDataFactory(Core::System& system_, ProgramId program_id_,
SaveDataFactory::~SaveDataFactory() = default; SaveDataFactory::~SaveDataFactory() = default;
std::string SaveDataFactory::GetSaveDataPath(SaveDataSpaceId space, SaveDataType type, u64 title_id, u128 user_id, u64 save_id) const {
if (type == SaveDataType::Account || type == SaveDataType::Device) {
const auto requested_id = title_id != 0 ? title_id : program_id;
const auto parent_id = system.GetContentProvider().GetParentApplicationId(requested_id);
title_id = parent_id.value_or(requested_id);
}
return GetFullPath(program_id, dir, space, type, title_id, user_id, save_id);
}
VirtualDir SaveDataFactory::Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const { VirtualDir SaveDataFactory::Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
const auto save_directory = GetFullPath(program_id, dir, space, meta.type, meta.program_id, const auto save_directory = GetSaveDataPath(space, meta.type, meta.program_id, meta.user_id, meta.system_save_data_id);
meta.user_id, meta.system_save_data_id);
return dir->CreateDirectoryRelative(save_directory); return dir->CreateDirectoryRelative(save_directory);
} }
VirtualDir SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const { VirtualDir SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
const auto save_directory = GetFullPath(program_id, dir, space, meta.type, meta.program_id, const auto save_directory = GetSaveDataPath(space, meta.type, meta.program_id, meta.user_id, meta.system_save_data_id);
meta.user_id, meta.system_save_data_id);
auto out = dir->GetDirectoryRelative(save_directory); auto out = dir->GetDirectoryRelative(save_directory);
@@ -154,8 +162,7 @@ std::string SaveDataFactory::GetUserGameSaveDataRoot(u128 user_id, bool future)
SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id, SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
u128 user_id) const { u128 user_id) const {
const auto path = const auto path = GetSaveDataPath(SaveDataSpaceId::User, type, title_id, user_id, 0);
GetFullPath(program_id, dir, SaveDataSpaceId::User, type, title_id, user_id, 0);
const auto relative_dir = GetOrCreateDirectoryRelative(dir, path); const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
const auto size_file = relative_dir->GetFile(GetSaveDataSizeFileName()); const auto size_file = relative_dir->GetFile(GetSaveDataSizeFileName());
@@ -173,8 +180,7 @@ SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
SaveDataSize new_value) const { SaveDataSize new_value) const {
const auto path = const auto path = GetSaveDataPath(SaveDataSpaceId::User, type, title_id, user_id, 0);
GetFullPath(program_id, dir, SaveDataSpaceId::User, type, title_id, user_id, 0);
const auto relative_dir = GetOrCreateDirectoryRelative(dir, path); const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
const auto size_file = relative_dir->CreateFile(GetSaveDataSizeFileName()); const auto size_file = relative_dir->CreateFile(GetSaveDataSizeFileName());
+1
View File
@@ -50,6 +50,7 @@ public:
void SetAutoCreate(bool state); void SetAutoCreate(bool state);
private: private:
std::string GetSaveDataPath(SaveDataSpaceId space, SaveDataType type, u64 title_id, u128 user_id, u64 save_id) const;
Core::System& system; Core::System& system;
ProgramId program_id; ProgramId program_id;
VirtualDir dir; VirtualDir dir;
+4 -11
View File
@@ -29,7 +29,6 @@
#include "core/hle/service/am/frontend/applet_web_browser.h" #include "core/hle/service/am/frontend/applet_web_browser.h"
#include "core/hle/service/am/frontend/applets.h" #include "core/hle/service/am/frontend/applets.h"
#include "core/hle/service/am/service/storage.h" #include "core/hle/service/am/service/storage.h"
#include "core/hle/service/am/window_system.h"
#include "core/hle/service/sm/sm.h" #include "core/hle/service/sm/sm.h"
namespace Service::AM::Frontend { namespace Service::AM::Frontend {
@@ -73,16 +72,10 @@ void FrontendApplet::PushInteractiveOutData(std::shared_ptr<IStorage> storage) {
void FrontendApplet::Exit() { void FrontendApplet::Exit() {
auto applet_ = applet.lock(); auto applet_ = applet.lock();
{
std::scoped_lock lk{applet_->lock}; std::scoped_lock lk{applet_->lock};
applet_->is_completed = true; applet_->is_completed = true;
applet_->state_changed_event.Signal(system.Kernel()); applet_->state_changed_event.Signal(system.Kernel());
}
if (auto caller_applet = applet_->caller_applet.lock()) {
std::scoped_lock lk{caller_applet->lock};
std::erase(caller_applet->child_applets, applet_);
}
if (auto* window_system = system.GetAppletManager().GetWindowSystem()) window_system->RequestUpdate();
} }
FrontendAppletSet::FrontendAppletSet() = default; FrontendAppletSet::FrontendAppletSet() = default;
@@ -122,10 +122,7 @@ std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system,
auto broker = std::make_shared<AppletDataBroker>(system); auto broker = std::make_shared<AppletDataBroker>(system);
applet->caller_applet = caller_applet; applet->caller_applet = caller_applet;
applet->caller_applet_broker = broker; applet->caller_applet_broker = broker;
{ caller_applet->child_applets.push_back(applet);
std::scoped_lock lk{caller_applet->lock};
caller_applet->child_applets.push_back(applet);
}
window_system.TrackApplet(applet, false); window_system.TrackApplet(applet, false);
return std::make_shared<ILibraryAppletAccessor>(system, broker, applet); return std::make_shared<ILibraryAppletAccessor>(system, broker, applet);
} }
@@ -151,10 +148,10 @@ std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet(Core::System& syste
applet->caller_applet = caller_applet; applet->caller_applet = caller_applet;
applet->caller_applet_broker = storage; applet->caller_applet_broker = storage;
applet->frontend = system.GetFrontendAppletHolder().GetApplet(applet, applet_id, mode); applet->frontend = system.GetFrontendAppletHolder().GetApplet(applet, applet_id, mode);
{ caller_applet->child_applets.push_back(applet);
std::scoped_lock lk{caller_applet->lock};
caller_applet->child_applets.push_back(applet); window_system.TrackApplet(applet, false);
}
return std::make_shared<ILibraryAppletAccessor>(system, storage, applet); return std::make_shared<ILibraryAppletAccessor>(system, storage, applet);
} }
@@ -23,66 +23,30 @@
namespace Dynarmic::Backend::Arm64 { namespace Dynarmic::Backend::Arm64 {
template<auto mfp, typename T>
static void* EmitCallReadTrampoline(oaknut::CodeGenerator& code, T* this_, size_t bitsize) {
using namespace oaknut::util;
const auto info = Devirtualize<mfp>(this_);
oaknut::Label l_addr, l_this;
void* target = code.xptr<void*>();
// params = { this, vaddr, bitsize }
code.LDR(X0, l_this);
// X1 = vaddr
code.MOV(X2, bitsize);
code.LDR(Xscratch0, l_addr);
code.BR(Xscratch0);
code.align(8);
code.l(l_this);
code.dx(info.this_ptr);
code.l(l_addr);
code.dx(info.fn_ptr);
return target;
}
template<auto mfp, typename T>
static void* EmitCallWriteTrampoline(oaknut::CodeGenerator& code, T* this_, size_t bitsize) {
using namespace oaknut::util;
const auto info = Devirtualize<mfp>(this_);
oaknut::Label l_addr, l_this;
void* target = code.xptr<void*>();
// params = { this, vaddr, value, bitsize }
code.LDR(X0, l_this);
// X1 = vaddr
// X2 = value
code.MOV(X3, bitsize);
code.LDR(Xscratch0, l_addr);
code.BR(Xscratch0);
code.align(8);
code.l(l_this);
code.dx(info.this_ptr);
code.l(l_addr);
code.dx(info.fn_ptr);
return target;
}
template<auto mfp, typename T> template<auto mfp, typename T>
static void* EmitCallTrampoline(oaknut::CodeGenerator& code, T* this_) { static void* EmitCallTrampoline(oaknut::CodeGenerator& code, T* this_) {
using namespace oaknut::util; using namespace oaknut::util;
const auto info = Devirtualize<mfp>(this_); const auto info = Devirtualize<mfp>(this_);
oaknut::Label l_addr, l_this; oaknut::Label l_addr, l_this;
void* target = code.xptr<void*>(); void* target = code.xptr<void*>();
code.LDR(X0, l_this); code.LDR(X0, l_this);
code.LDR(Xscratch0, l_addr); code.LDR(Xscratch0, l_addr);
code.BR(Xscratch0); code.BR(Xscratch0);
code.align(8); code.align(8);
code.l(l_this); code.l(l_this);
code.dx(info.this_ptr); code.dx(info.this_ptr);
code.l(l_addr); code.l(l_addr);
code.dx(info.fn_ptr); code.dx(info.fn_ptr);
return target; return target;
} }
template<auto mfp, typename T> template<auto mfp, typename T>
static void* EmitWrappedReadCallTrampoline(oaknut::CodeGenerator& code, T* this_, size_t bitsize) { static void* EmitWrappedReadCallTrampoline(oaknut::CodeGenerator& code, T* this_) {
using namespace oaknut::util; using namespace oaknut::util;
const auto info = Devirtualize<mfp>(this_); const auto info = Devirtualize<mfp>(this_);
@@ -95,7 +59,6 @@ static void* EmitWrappedReadCallTrampoline(oaknut::CodeGenerator& code, T* this_
ABI_PushRegisters(code, save_regs, 0); ABI_PushRegisters(code, save_regs, 0);
code.LDR(X0, l_this); code.LDR(X0, l_this);
code.MOV(X1, Xscratch0); code.MOV(X1, Xscratch0);
code.MOV(X2, bitsize);
code.LDR(Xscratch0, l_addr); code.LDR(Xscratch0, l_addr);
code.BLR(Xscratch0); code.BLR(Xscratch0);
code.MOV(Xscratch0, X0); code.MOV(Xscratch0, X0);
@@ -138,7 +101,7 @@ static void* EmitExclusiveReadCallTrampoline(oaknut::CodeGenerator& code, const
} }
template<auto mfp, typename T> template<auto mfp, typename T>
static void* EmitWrappedWriteCallTrampoline(oaknut::CodeGenerator& code, T* this_, size_t bitsize) { static void* EmitWrappedWriteCallTrampoline(oaknut::CodeGenerator& code, T* this_) {
using namespace oaknut::util; using namespace oaknut::util;
const auto info = Devirtualize<mfp>(this_); const auto info = Devirtualize<mfp>(this_);
@@ -152,7 +115,6 @@ static void* EmitWrappedWriteCallTrampoline(oaknut::CodeGenerator& code, T* this
code.LDR(X0, l_this); code.LDR(X0, l_this);
code.MOV(X1, Xscratch0); code.MOV(X1, Xscratch0);
code.MOV(X2, Xscratch1); code.MOV(X2, Xscratch1);
code.MOV(X3, bitsize);
code.LDR(Xscratch0, l_addr); code.LDR(Xscratch0, l_addr);
code.BLR(Xscratch0); code.BLR(Xscratch0);
ABI_PopRegisters(code, save_regs, 0); ABI_PopRegisters(code, save_regs, 0);
@@ -214,27 +176,14 @@ void A32AddressSpace::EmitPrelude() {
UnprotectCodeMemory(); UnprotectCodeMemory();
prelude_info.read_memory = EmitCallTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks);
prelude_info.read_memory_8 = EmitCallReadTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u8)); prelude_info.wrapped_read_memory = EmitWrappedReadCallTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks);
prelude_info.read_memory_16 = EmitCallReadTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u16));
prelude_info.read_memory_32 = EmitCallReadTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u32));
prelude_info.read_memory_64 = EmitCallReadTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u64));
prelude_info.wrapped_read_memory_8 = EmitWrappedReadCallTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u8));
prelude_info.wrapped_read_memory_16 = EmitWrappedReadCallTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u16));
prelude_info.wrapped_read_memory_32 = EmitWrappedReadCallTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u32));
prelude_info.wrapped_read_memory_64 = EmitWrappedReadCallTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u64));
prelude_info.exclusive_read_memory_8 = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead, u8>(code, conf); prelude_info.exclusive_read_memory_8 = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead, u8>(code, conf);
prelude_info.exclusive_read_memory_16 = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead, u16>(code, conf); prelude_info.exclusive_read_memory_16 = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead, u16>(code, conf);
prelude_info.exclusive_read_memory_32 = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead, u32>(code, conf); prelude_info.exclusive_read_memory_32 = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead, u32>(code, conf);
prelude_info.exclusive_read_memory_64 = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead, u64>(code, conf); prelude_info.exclusive_read_memory_64 = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead, u64>(code, conf);
prelude_info.write_memory_8 = EmitCallWriteTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u8)); prelude_info.write_memory = EmitCallTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks);
prelude_info.write_memory_16 = EmitCallWriteTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u16)); prelude_info.wrapped_write_memory = EmitWrappedWriteCallTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks);
prelude_info.write_memory_32 = EmitCallWriteTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u32));
prelude_info.write_memory_64 = EmitCallWriteTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u64));
prelude_info.wrapped_write_memory_8 = EmitWrappedWriteCallTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u8));
prelude_info.wrapped_write_memory_16 = EmitWrappedWriteCallTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u16));
prelude_info.wrapped_write_memory_32 = EmitWrappedWriteCallTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u32));
prelude_info.wrapped_write_memory_64 = EmitWrappedWriteCallTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u64));
prelude_info.exclusive_write_memory_8 = EmitExclusiveWriteCallTrampoline<&A32::UserCallbacks::MemoryWriteExclusive8, u8>(code, conf); prelude_info.exclusive_write_memory_8 = EmitExclusiveWriteCallTrampoline<&A32::UserCallbacks::MemoryWriteExclusive8, u8>(code, conf);
prelude_info.exclusive_write_memory_16 = EmitExclusiveWriteCallTrampoline<&A32::UserCallbacks::MemoryWriteExclusive16, u16>(code, conf); prelude_info.exclusive_write_memory_16 = EmitExclusiveWriteCallTrampoline<&A32::UserCallbacks::MemoryWriteExclusive16, u16>(code, conf);
prelude_info.exclusive_write_memory_32 = EmitExclusiveWriteCallTrampoline<&A32::UserCallbacks::MemoryWriteExclusive32, u32>(code, conf); prelude_info.exclusive_write_memory_32 = EmitExclusiveWriteCallTrampoline<&A32::UserCallbacks::MemoryWriteExclusive32, u32>(code, conf);
@@ -22,66 +22,30 @@
namespace Dynarmic::Backend::Arm64 { namespace Dynarmic::Backend::Arm64 {
template<auto mfp, typename T>
static void* EmitCallReadTrampoline(oaknut::CodeGenerator& code, T* this_, size_t bitsize) {
using namespace oaknut::util;
const auto info = Devirtualize<mfp>(this_);
oaknut::Label l_addr, l_this;
void* target = code.xptr<void*>();
// params = { this, vaddr, bitsize }
code.LDR(X0, l_this);
// X1 = vaddr
code.MOV(X2, bitsize);
code.LDR(Xscratch0, l_addr);
code.BR(Xscratch0);
code.align(8);
code.l(l_this);
code.dx(info.this_ptr);
code.l(l_addr);
code.dx(info.fn_ptr);
return target;
}
template<auto mfp, typename T>
static void* EmitCallWriteTrampoline(oaknut::CodeGenerator& code, T* this_, size_t bitsize) {
using namespace oaknut::util;
const auto info = Devirtualize<mfp>(this_);
oaknut::Label l_addr, l_this;
void* target = code.xptr<void*>();
// params = { this, vaddr, value, bitsize }
code.LDR(X0, l_this);
// X1 = vaddr
// X2 = value
code.MOV(X3, bitsize);
code.LDR(Xscratch0, l_addr);
code.BR(Xscratch0);
code.align(8);
code.l(l_this);
code.dx(info.this_ptr);
code.l(l_addr);
code.dx(info.fn_ptr);
return target;
}
template<auto mfp, typename T> template<auto mfp, typename T>
static void* EmitCallTrampoline(oaknut::CodeGenerator& code, T* this_) { static void* EmitCallTrampoline(oaknut::CodeGenerator& code, T* this_) {
using namespace oaknut::util; using namespace oaknut::util;
const auto info = Devirtualize<mfp>(this_); const auto info = Devirtualize<mfp>(this_);
oaknut::Label l_addr, l_this; oaknut::Label l_addr, l_this;
void* target = code.xptr<void*>(); void* target = code.xptr<void*>();
code.LDR(X0, l_this); code.LDR(X0, l_this);
code.LDR(Xscratch0, l_addr); code.LDR(Xscratch0, l_addr);
code.BR(Xscratch0); code.BR(Xscratch0);
code.align(8); code.align(8);
code.l(l_this); code.l(l_this);
code.dx(info.this_ptr); code.dx(info.this_ptr);
code.l(l_addr); code.l(l_addr);
code.dx(info.fn_ptr); code.dx(info.fn_ptr);
return target; return target;
} }
template<auto mfp, typename T> template<auto mfp, typename T>
static void* EmitWrappedReadCallTrampoline(oaknut::CodeGenerator& code, T* this_, size_t bitsize) { static void* EmitWrappedReadCallTrampoline(oaknut::CodeGenerator& code, T* this_) {
using namespace oaknut::util; using namespace oaknut::util;
const auto info = Devirtualize<mfp>(this_); const auto info = Devirtualize<mfp>(this_);
@@ -94,7 +58,6 @@ static void* EmitWrappedReadCallTrampoline(oaknut::CodeGenerator& code, T* this_
ABI_PushRegisters(code, save_regs, 0); ABI_PushRegisters(code, save_regs, 0);
code.LDR(X0, l_this); code.LDR(X0, l_this);
code.MOV(X1, Xscratch0); code.MOV(X1, Xscratch0);
code.MOV(X2, bitsize);
code.LDR(Xscratch0, l_addr); code.LDR(Xscratch0, l_addr);
code.BLR(Xscratch0); code.BLR(Xscratch0);
code.MOV(Xscratch0, X0); code.MOV(Xscratch0, X0);
@@ -137,7 +100,7 @@ static void* EmitExclusiveReadCallTrampoline(oaknut::CodeGenerator& code, const
} }
template<auto mfp, typename T> template<auto mfp, typename T>
static void* EmitWrappedWriteCallTrampoline(oaknut::CodeGenerator& code, T* this_, size_t bitsize) { static void* EmitWrappedWriteCallTrampoline(oaknut::CodeGenerator& code, T* this_) {
using namespace oaknut::util; using namespace oaknut::util;
const auto info = Devirtualize<mfp>(this_); const auto info = Devirtualize<mfp>(this_);
@@ -151,7 +114,6 @@ static void* EmitWrappedWriteCallTrampoline(oaknut::CodeGenerator& code, T* this
code.LDR(X0, l_this); code.LDR(X0, l_this);
code.MOV(X1, Xscratch0); code.MOV(X1, Xscratch0);
code.MOV(X2, Xscratch1); code.MOV(X2, Xscratch1);
code.MOV(X3, bitsize);
code.LDR(Xscratch0, l_addr); code.LDR(Xscratch0, l_addr);
code.BLR(Xscratch0); code.BLR(Xscratch0);
ABI_PopRegisters(code, save_regs, 0); ABI_PopRegisters(code, save_regs, 0);
@@ -380,30 +342,18 @@ void A64AddressSpace::EmitPrelude() {
UnprotectCodeMemory(); UnprotectCodeMemory();
prelude_info.read_memory_8 = EmitCallReadTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u8)); prelude_info.read_memory = EmitCallTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks);
prelude_info.read_memory_16 = EmitCallReadTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u16));
prelude_info.read_memory_32 = EmitCallReadTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u32));
prelude_info.read_memory_64 = EmitCallReadTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u64));
prelude_info.read_memory_128 = EmitRead128CallTrampoline(code, conf.callbacks); prelude_info.read_memory_128 = EmitRead128CallTrampoline(code, conf.callbacks);
prelude_info.wrapped_read_memory_8 = EmitWrappedReadCallTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u8)); prelude_info.wrapped_read_memory = EmitWrappedReadCallTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks);
prelude_info.wrapped_read_memory_16 = EmitWrappedReadCallTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u16));
prelude_info.wrapped_read_memory_32 = EmitWrappedReadCallTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u32));
prelude_info.wrapped_read_memory_64 = EmitWrappedReadCallTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u64));
prelude_info.wrapped_read_memory_128 = EmitWrappedRead128CallTrampoline(code, conf.callbacks); prelude_info.wrapped_read_memory_128 = EmitWrappedRead128CallTrampoline(code, conf.callbacks);
prelude_info.exclusive_read_memory_8 = EmitExclusiveReadCallTrampoline<&A64::UserCallbacks::MemoryRead, u8>(code, conf); prelude_info.exclusive_read_memory_8 = EmitExclusiveReadCallTrampoline<&A64::UserCallbacks::MemoryRead, u8>(code, conf);
prelude_info.exclusive_read_memory_16 = EmitExclusiveReadCallTrampoline<&A64::UserCallbacks::MemoryRead, u16>(code, conf); prelude_info.exclusive_read_memory_16 = EmitExclusiveReadCallTrampoline<&A64::UserCallbacks::MemoryRead, u16>(code, conf);
prelude_info.exclusive_read_memory_32 = EmitExclusiveReadCallTrampoline<&A64::UserCallbacks::MemoryRead, u32>(code, conf); prelude_info.exclusive_read_memory_32 = EmitExclusiveReadCallTrampoline<&A64::UserCallbacks::MemoryRead, u32>(code, conf);
prelude_info.exclusive_read_memory_64 = EmitExclusiveReadCallTrampoline<&A64::UserCallbacks::MemoryRead, u64>(code, conf); prelude_info.exclusive_read_memory_64 = EmitExclusiveReadCallTrampoline<&A64::UserCallbacks::MemoryRead, u64>(code, conf);
prelude_info.exclusive_read_memory_128 = EmitExclusiveRead128CallTrampoline(code, conf); prelude_info.exclusive_read_memory_128 = EmitExclusiveRead128CallTrampoline(code, conf);
prelude_info.write_memory_8 = EmitCallWriteTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u8)); prelude_info.write_memory = EmitCallTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks);
prelude_info.write_memory_16 = EmitCallWriteTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u16));
prelude_info.write_memory_32 = EmitCallWriteTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u32));
prelude_info.write_memory_64 = EmitCallWriteTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u64));
prelude_info.write_memory_128 = EmitWrite128CallTrampoline(code, conf.callbacks); prelude_info.write_memory_128 = EmitWrite128CallTrampoline(code, conf.callbacks);
prelude_info.wrapped_write_memory_8 = EmitWrappedWriteCallTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u8)); prelude_info.wrapped_write_memory = EmitWrappedWriteCallTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks);
prelude_info.wrapped_write_memory_16 = EmitWrappedWriteCallTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u16));
prelude_info.wrapped_write_memory_32 = EmitWrappedWriteCallTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u32));
prelude_info.wrapped_write_memory_64 = EmitWrappedWriteCallTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u64));
prelude_info.wrapped_write_memory_128 = EmitWrappedWrite128CallTrampoline(code, conf.callbacks); prelude_info.wrapped_write_memory_128 = EmitWrappedWrite128CallTrampoline(code, conf.callbacks);
prelude_info.exclusive_write_memory_8 = EmitExclusiveWriteCallTrampoline<&A64::UserCallbacks::MemoryWriteExclusive8, u8>(code, conf); prelude_info.exclusive_write_memory_8 = EmitExclusiveWriteCallTrampoline<&A64::UserCallbacks::MemoryWriteExclusive8, u8>(code, conf);
prelude_info.exclusive_write_memory_16 = EmitExclusiveWriteCallTrampoline<&A64::UserCallbacks::MemoryWriteExclusive16, u16>(code, conf); prelude_info.exclusive_write_memory_16 = EmitExclusiveWriteCallTrampoline<&A64::UserCallbacks::MemoryWriteExclusive16, u16>(code, conf);
@@ -147,37 +147,44 @@ void AddressSpace::Link(EmittedBlockInfo& block_info) {
break; break;
// { this, vaddr, size } // { this, vaddr, size }
case LinkTarget::ReadMemory8: case LinkTarget::ReadMemory8:
c.BL(prelude_info.read_memory_8); c.LDR(X2, 1);
c.BL(prelude_info.read_memory);
break; break;
case LinkTarget::ReadMemory16: case LinkTarget::ReadMemory16:
c.BL(prelude_info.read_memory_16); c.LDR(X2, 2);
c.BL(prelude_info.read_memory);
break; break;
case LinkTarget::ReadMemory32: case LinkTarget::ReadMemory32:
c.BL(prelude_info.read_memory_32); c.LDR(X2, 4);
c.BL(prelude_info.read_memory);
break; break;
case LinkTarget::ReadMemory64: case LinkTarget::ReadMemory64:
c.BL(prelude_info.read_memory_64); c.LDR(X2, 8);
c.BL(prelude_info.read_memory);
break; break;
case LinkTarget::ReadMemory128: case LinkTarget::ReadMemory128:
c.BL(prelude_info.read_memory_128); c.BL(prelude_info.read_memory_128);
break; break;
// { this, vaddr, size } // { this, vaddr, size }
case LinkTarget::WrappedReadMemory8: case LinkTarget::WrappedReadMemory8:
c.BL(prelude_info.wrapped_read_memory_8); c.LDR(X2, 1);
c.BL(prelude_info.wrapped_read_memory);
break; break;
case LinkTarget::WrappedReadMemory16: case LinkTarget::WrappedReadMemory16:
c.BL(prelude_info.wrapped_read_memory_16); c.LDR(X2, 2);
c.BL(prelude_info.wrapped_read_memory);
break; break;
case LinkTarget::WrappedReadMemory32: case LinkTarget::WrappedReadMemory32:
c.BL(prelude_info.wrapped_read_memory_32); c.LDR(X2, 4);
c.BL(prelude_info.wrapped_read_memory);
break; break;
case LinkTarget::WrappedReadMemory64: case LinkTarget::WrappedReadMemory64:
c.BL(prelude_info.wrapped_read_memory_64); c.LDR(X2, 8);
c.BL(prelude_info.wrapped_read_memory);
break; break;
case LinkTarget::WrappedReadMemory128: case LinkTarget::WrappedReadMemory128:
c.BL(prelude_info.wrapped_read_memory_128); c.BL(prelude_info.wrapped_read_memory_128);
break; break;
//
case LinkTarget::ExclusiveReadMemory8: case LinkTarget::ExclusiveReadMemory8:
c.BL(prelude_info.exclusive_read_memory_8); c.BL(prelude_info.exclusive_read_memory_8);
break; break;
@@ -195,37 +202,43 @@ void AddressSpace::Link(EmittedBlockInfo& block_info) {
break; break;
// { this, vaddr, value, size } // { this, vaddr, value, size }
case LinkTarget::WriteMemory8: case LinkTarget::WriteMemory8:
c.BL(prelude_info.write_memory_8); c.LDR(X3, 1);
c.BL(prelude_info.write_memory);
break; break;
case LinkTarget::WriteMemory16: case LinkTarget::WriteMemory16:
c.BL(prelude_info.write_memory_16); c.LDR(X3, 2);
c.BL(prelude_info.write_memory);
break; break;
case LinkTarget::WriteMemory32: case LinkTarget::WriteMemory32:
c.BL(prelude_info.write_memory_32); c.LDR(X3, 4);
c.BL(prelude_info.write_memory);
break; break;
case LinkTarget::WriteMemory64: case LinkTarget::WriteMemory64:
c.BL(prelude_info.write_memory_64); c.LDR(X3, 8);
c.BL(prelude_info.write_memory);
break; break;
case LinkTarget::WriteMemory128: case LinkTarget::WriteMemory128:
c.BL(prelude_info.write_memory_128); c.BL(prelude_info.write_memory_128);
break; break;
//
case LinkTarget::WrappedWriteMemory8: case LinkTarget::WrappedWriteMemory8:
c.BL(prelude_info.wrapped_write_memory_8); c.LDR(X3, 1);
c.BL(prelude_info.wrapped_write_memory);
break; break;
case LinkTarget::WrappedWriteMemory16: case LinkTarget::WrappedWriteMemory16:
c.BL(prelude_info.wrapped_write_memory_16); c.LDR(X3, 2);
c.BL(prelude_info.wrapped_write_memory);
break; break;
case LinkTarget::WrappedWriteMemory32: case LinkTarget::WrappedWriteMemory32:
c.BL(prelude_info.wrapped_write_memory_32); c.LDR(X3, 4);
c.BL(prelude_info.wrapped_write_memory);
break; break;
case LinkTarget::WrappedWriteMemory64: case LinkTarget::WrappedWriteMemory64:
c.BL(prelude_info.wrapped_write_memory_64); c.LDR(X3, 8);
c.BL(prelude_info.wrapped_write_memory);
break; break;
case LinkTarget::WrappedWriteMemory128: case LinkTarget::WrappedWriteMemory128:
c.BL(prelude_info.wrapped_write_memory_128); c.BL(prelude_info.wrapped_write_memory_128);
break; break;
//
case LinkTarget::ExclusiveWriteMemory8: case LinkTarget::ExclusiveWriteMemory8:
c.BL(prelude_info.exclusive_write_memory_8); c.BL(prelude_info.exclusive_write_memory_8);
break; break;
@@ -93,30 +93,18 @@ protected:
void* return_to_dispatcher; void* return_to_dispatcher;
void* return_from_run_code; void* return_from_run_code;
void* read_memory_8; void* read_memory;
void* read_memory_16;
void* read_memory_32;
void* read_memory_64;
void* read_memory_128; void* read_memory_128;
void* wrapped_read_memory_8; void* wrapped_read_memory;
void* wrapped_read_memory_16;
void* wrapped_read_memory_32;
void* wrapped_read_memory_64;
void* wrapped_read_memory_128; void* wrapped_read_memory_128;
void* exclusive_read_memory_8; void* exclusive_read_memory_8;
void* exclusive_read_memory_16; void* exclusive_read_memory_16;
void* exclusive_read_memory_32; void* exclusive_read_memory_32;
void* exclusive_read_memory_64; void* exclusive_read_memory_64;
void* exclusive_read_memory_128; void* exclusive_read_memory_128;
void* write_memory_8; void* write_memory;
void* write_memory_16;
void* write_memory_32;
void* write_memory_64;
void* write_memory_128; void* write_memory_128;
void* wrapped_write_memory_8; void* wrapped_write_memory;
void* wrapped_write_memory_16;
void* wrapped_write_memory_32;
void* wrapped_write_memory_64;
void* wrapped_write_memory_128; void* wrapped_write_memory_128;
void* exclusive_write_memory_8; void* exclusive_write_memory_8;
void* exclusive_write_memory_16; void* exclusive_write_memory_16;
@@ -11,8 +11,7 @@
#include <tuple> #include <tuple>
#include <utility> #include <utility>
#include <fmt/format.h> #include "common/logging.h"
#include <fmt/ostream.h>
#include "dynarmic/mcl/integer_of_size.hpp" #include "dynarmic/mcl/integer_of_size.hpp"
#include "dynarmic/backend/x64/xbyak.h" #include "dynarmic/backend/x64/xbyak.h"
@@ -11,8 +11,7 @@
#include <tuple> #include <tuple>
#include <utility> #include <utility>
#include <fmt/format.h> #include "common/logging.h"
#include <fmt/ostream.h>
#include "dynarmic/mcl/integer_of_size.hpp" #include "dynarmic/mcl/integer_of_size.hpp"
#include "dynarmic/backend/x64/xbyak.h" #include "dynarmic/backend/x64/xbyak.h"
@@ -14,10 +14,6 @@
#define AxxJitState CONCATENATE_TOKENS(Axx, JitState) #define AxxJitState CONCATENATE_TOKENS(Axx, JitState)
#define AxxUserConfig Axx::UserConfig #define AxxUserConfig Axx::UserConfig
namespace {
using Vector = std::array<u64, 2>;
}
std::optional<AxxEmitX64::DoNotFastmemMarker> AxxEmitX64::ShouldFastmem(AxxEmitContext& ctx, IR::Inst* inst) const { std::optional<AxxEmitX64::DoNotFastmemMarker> AxxEmitX64::ShouldFastmem(AxxEmitContext& ctx, IR::Inst* inst) const {
if (!conf.fastmem_pointer || !exception_handler.SupportsFastmem()) { if (!conf.fastmem_pointer || !exception_handler.SupportsFastmem()) {
return std::nullopt; return std::nullopt;
@@ -31,22 +27,19 @@ std::optional<AxxEmitX64::DoNotFastmemMarker> AxxEmitX64::ShouldFastmem(AxxEmitC
} }
FakeCall AxxEmitX64::FastmemCallback(u64 rip_) { FakeCall AxxEmitX64::FastmemCallback(u64 rip_) {
const auto iter = fastmem_patch_info.find(rip_); if (auto const it = fastmem_patch_info.find(rip_); it != fastmem_patch_info.end()) {
if (iter != fastmem_patch_info.end()) {
FakeCall result{ FakeCall result{
.call_rip = iter->second.callback, .call_rip = it->second.callback,
.ret_rip = iter->second.resume_rip, .ret_rip = it->second.resume_rip,
}; };
if (iter->second.recompile) { if (it->second.recompile) {
const auto marker = iter->second.marker; const auto marker = it->second.marker;
do_not_fastmem.insert(marker); do_not_fastmem.insert(marker);
InvalidateBasicBlocks({std::get<0>(marker)}); InvalidateBasicBlocks({std::get<0>(marker)});
} }
return result; return result;
} }
fmt::print("dynarmic: Segfault happened within JITted code at rip = {:016x}\n" UNREACHABLE_MSG("SIGSEGV @ JIT, rip={:#016x}", rip_); //("iter != fastmem_patch_info.end()");
"Segfault wasn't at a fastmem patch location!\n", rip_);
UNREACHABLE(); //("iter != fastmem_patch_info.end()");
} }
template<std::size_t bitsize, auto callback> template<std::size_t bitsize, auto callback>
@@ -83,22 +76,17 @@ void AxxEmitX64::EmitMemoryRead(AxxEmitContext& ctx, IR::Inst* inst) {
const Xbyak::Reg64 vaddr = ctx.reg_alloc.UseGpr(code, args[1]); const Xbyak::Reg64 vaddr = ctx.reg_alloc.UseGpr(code, args[1]);
const int value_idx = bitsize == 128 ? ctx.reg_alloc.ScratchXmm(code).getIdx() : ctx.reg_alloc.ScratchGpr(code).getIdx(); const int value_idx = bitsize == 128 ? ctx.reg_alloc.ScratchXmm(code).getIdx() : ctx.reg_alloc.ScratchGpr(code).getIdx();
const auto wrapped_fn = read_fallbacks[std::make_tuple(ordered, bitsize, vaddr.getIdx(), value_idx)]; const auto wrapped_fn = read_fallbacks[std::make_tuple(ordered, bitsize, vaddr.getIdx(), value_idx)];
SharedLabel abort = ctx.GenSharedLabel(), end = ctx.GenSharedLabel(); SharedLabel abort = ctx.GenSharedLabel(), end = ctx.GenSharedLabel();
if (fastmem_marker) { if (fastmem_marker) {
// Use fastmem // Use fastmem
bool require_abort_handling = false; bool require_abort_handling = false;
const auto src_ptr = EmitFastmemVAddr(code, ctx, *abort, vaddr, require_abort_handling); const auto src_ptr = EmitFastmemVAddr(code, ctx, *abort, vaddr, require_abort_handling);
const auto location = EmitReadMemoryMov<bitsize>(code, value_idx, src_ptr, ordered); const auto location = EmitReadMemoryMov<bitsize>(code, value_idx, src_ptr, ordered);
ctx.deferred_emits.emplace_back([=, this, &ctx] { ctx.deferred_emits.emplace_back([=, this, &ctx] {
code.L(*abort); code.L(*abort);
code.call(wrapped_fn); code.call(wrapped_fn);
fastmem_patch_info.emplace( fastmem_patch_info.emplace(
std::bit_cast<u64>(location), std::bit_cast<u64>(location),
FastmemPatchInfo{ FastmemPatchInfo{
@@ -107,25 +95,23 @@ void AxxEmitX64::EmitMemoryRead(AxxEmitContext& ctx, IR::Inst* inst) {
*fastmem_marker, *fastmem_marker,
conf.recompile_on_fastmem_failure, conf.recompile_on_fastmem_failure,
}); });
EmitCheckMemoryAbort(ctx, inst, end); EmitCheckMemoryAbort(ctx, inst, end);
code.jmp(*end, code.T_NEAR); code.jmp(*end, code.T_NEAR);
}); });
} else { } else if (conf.page_table) {
// Use page table // Use page table
ASSERT(conf.page_table);
const auto src_ptr = EmitVAddrLookup(code, ctx, bitsize, *abort, vaddr); const auto src_ptr = EmitVAddrLookup(code, ctx, bitsize, *abort, vaddr);
EmitReadMemoryMov<bitsize>(code, value_idx, src_ptr, ordered); EmitReadMemoryMov<bitsize>(code, value_idx, src_ptr, ordered);
ctx.deferred_emits.emplace_back([=, this, &ctx] { ctx.deferred_emits.emplace_back([=, this, &ctx] {
code.L(*abort); code.L(*abort);
code.call(wrapped_fn); code.call(wrapped_fn);
EmitCheckMemoryAbort(ctx, inst, end); EmitCheckMemoryAbort(ctx, inst, end);
code.jmp(*end, code.T_NEAR); code.jmp(*end, code.T_NEAR);
}); });
} else {
UNREACHABLE();
} }
code.L(*end); code.L(*end);
if constexpr (bitsize == 128) { if constexpr (bitsize == 128) {
ctx.reg_alloc.DefineValue(code, inst, Xbyak::Xmm{value_idx}); ctx.reg_alloc.DefineValue(code, inst, Xbyak::Xmm{value_idx});
} else { } else {
@@ -168,18 +154,16 @@ void AxxEmitX64::EmitMemoryWrite(AxxEmitContext& ctx, IR::Inst* inst) {
const Xbyak::Reg64 vaddr = ctx.reg_alloc.UseGpr(code, args[1]); const Xbyak::Reg64 vaddr = ctx.reg_alloc.UseGpr(code, args[1]);
const int value_idx = bitsize == 128 const int value_idx = bitsize == 128
? ctx.reg_alloc.UseXmm(code, args[2]).getIdx() ? ctx.reg_alloc.UseXmm(code, args[2]).getIdx()
: (ordered ? ctx.reg_alloc.UseScratchGpr(code, args[2]).getIdx() : ctx.reg_alloc.UseGpr(code, args[2]).getIdx()); : (ordered ? ctx.reg_alloc.UseScratchGpr(code, args[2]).getIdx() : ctx.reg_alloc.UseGpr(code, args[2]).getIdx());
const auto wrapped_fn = write_fallbacks[std::make_tuple(ordered, bitsize, vaddr.getIdx(), value_idx)]; const auto wrapped_fn = write_fallbacks[std::make_tuple(ordered, bitsize, vaddr.getIdx(), value_idx)];
SharedLabel abort = ctx.GenSharedLabel(), end = ctx.GenSharedLabel(); SharedLabel abort = ctx.GenSharedLabel(), end = ctx.GenSharedLabel();
if (fastmem_marker) { if (fastmem_marker) {
// Use fastmem // Use fastmem
bool require_abort_handling = false; bool require_abort_handling = false;
const auto dest_ptr = EmitFastmemVAddr(code, ctx, *abort, vaddr, require_abort_handling); const auto dest_ptr = EmitFastmemVAddr(code, ctx, *abort, vaddr, require_abort_handling);
const auto location = EmitWriteMemoryMov<bitsize>(code, dest_ptr, value_idx, ordered); const auto location = EmitWriteMemoryMov<bitsize>(code, dest_ptr, value_idx, ordered);
ctx.deferred_emits.emplace_back([=, this, &ctx] { ctx.deferred_emits.emplace_back([=, this, &ctx] {
@@ -198,9 +182,8 @@ void AxxEmitX64::EmitMemoryWrite(AxxEmitContext& ctx, IR::Inst* inst) {
EmitCheckMemoryAbort(ctx, inst, end); EmitCheckMemoryAbort(ctx, inst, end);
code.jmp(*end, code.T_NEAR); code.jmp(*end, code.T_NEAR);
}); });
} else { } else if (conf.page_table) {
// Use page table // Use page table
ASSERT(conf.page_table);
const auto dest_ptr = EmitVAddrLookup(code, ctx, bitsize, *abort, vaddr); const auto dest_ptr = EmitVAddrLookup(code, ctx, bitsize, *abort, vaddr);
EmitWriteMemoryMov<bitsize>(code, dest_ptr, value_idx, ordered); EmitWriteMemoryMov<bitsize>(code, dest_ptr, value_idx, ordered);
@@ -210,6 +193,8 @@ void AxxEmitX64::EmitMemoryWrite(AxxEmitContext& ctx, IR::Inst* inst) {
EmitCheckMemoryAbort(ctx, inst, end); EmitCheckMemoryAbort(ctx, inst, end);
code.jmp(*end, code.T_NEAR); code.jmp(*end, code.T_NEAR);
}); });
} else {
UNREACHABLE();
} }
code.L(*end); code.L(*end);
} }
@@ -249,8 +234,8 @@ void AxxEmitX64::EmitExclusiveReadMemory(AxxEmitContext& ctx, IR::Inst* inst) {
if (ordered) { if (ordered) {
code.mfence(); code.mfence();
} }
code.CallLambda([](AxxUserConfig& conf, Axx::VAddr vaddr, Vector& ret) { code.CallLambda([](AxxUserConfig& conf, Axx::VAddr vaddr, u128& ret) {
ret = conf.global_monitor->ReadAndMark<Vector>(conf.processor_id, vaddr, [&]() -> Vector { ret = conf.global_monitor->ReadAndMark<u128>(conf.processor_id, vaddr, [&]() -> u128 {
return (conf.callbacks->*callback)(vaddr); return (conf.callbacks->*callback)(vaddr);
}); });
}); });
@@ -301,8 +286,8 @@ void AxxEmitX64::EmitExclusiveWriteMemory(AxxEmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.AllocStackSpace(code, 16 + ABI_SHADOW_SPACE); ctx.reg_alloc.AllocStackSpace(code, 16 + ABI_SHADOW_SPACE);
code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE]); code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE]);
code.movaps(xword[code.ABI_PARAM3], xmm1); code.movaps(xword[code.ABI_PARAM3], xmm1);
code.CallLambda([](AxxUserConfig& conf, Axx::VAddr vaddr, Vector& value) -> u32 { code.CallLambda([](AxxUserConfig& conf, Axx::VAddr vaddr, u128& value) -> u32 {
return conf.global_monitor->DoExclusiveOperation<Vector>(conf.processor_id, vaddr, [&](Vector expected) -> bool { return conf.global_monitor->DoExclusiveOperation<u128>(conf.processor_id, vaddr, [&](u128 expected) -> bool {
return (conf.callbacks->*callback)(vaddr, value, expected); return (conf.callbacks->*callback)(vaddr, value, expected);
}) ? 0 : 1; }) ? 0 : 1;
}); });
@@ -135,10 +135,16 @@ template<>
if (unused_top_bits == 0) { if (unused_top_bits == 0) {
code.mov(tmp, vaddr); code.mov(tmp, vaddr);
code.shr(tmp, int(page_table_const_bits)); code.shr(tmp, int(page_table_const_bits));
if (ctx.conf.page_table_log2_stride > 3) {
code.shl(tmp, int(ctx.conf.page_table_log2_stride));
code.mov(page, qword[r14 + tmp.cvt64()]);
} else {
code.mov(page, qword[r14 + tmp.cvt64() * int(1 << ctx.conf.page_table_log2_stride)]);
}
} else if (ctx.conf.silently_mirror_page_table) { } else if (ctx.conf.silently_mirror_page_table) {
if (valid_page_index_bits >= 32) { if (valid_page_index_bits >= 32) {
if (code.HasHostFeature(HostFeature::BMI2)) { if (code.HasHostFeature(HostFeature::BMI2)) {
const Xbyak::Reg64 bit_count = ctx.reg_alloc.ScratchGpr(code); auto const bit_count = ctx.reg_alloc.ScratchGpr(code);
code.mov(bit_count, unused_top_bits); code.mov(bit_count, unused_top_bits);
code.bzhi(tmp, vaddr, bit_count); code.bzhi(tmp, vaddr, bit_count);
code.shr(tmp, int(page_table_const_bits)); code.shr(tmp, int(page_table_const_bits));
@@ -153,19 +159,31 @@ template<>
code.shr(tmp, int(page_table_const_bits)); code.shr(tmp, int(page_table_const_bits));
code.and_(tmp, u32((1 << valid_page_index_bits) - 1)); code.and_(tmp, u32((1 << valid_page_index_bits) - 1));
} }
if (ctx.conf.page_table_log2_stride > 3) {
code.shl(tmp, int(ctx.conf.page_table_log2_stride));
code.mov(page, qword[r14 + tmp.cvt64()]);
} else {
code.mov(page, qword[r14 + tmp.cvt64() * int(1 << ctx.conf.page_table_log2_stride)]);
}
} else { } else {
// Common VA sizes: 39 - 12 => 27, 42 - 12 => 30
// Check if bits outside of VA space are non-zero
ASSERT(valid_page_index_bits < 32); ASSERT(valid_page_index_bits < 32);
code.mov(tmp, vaddr); code.mov(tmp, vaddr);
if (ctx.conf.check_halt_on_memory_access) {
auto const tmp2 = ctx.reg_alloc.ScratchGpr(code);
code.mov(tmp2, u64(-(1ull << valid_page_index_bits) << page_table_const_bits));
code.test(tmp, tmp2);
code.jnz(abort, code.T_NEAR);
ctx.reg_alloc.Release(tmp2);
}
code.shr(tmp, int(page_table_const_bits)); code.shr(tmp, int(page_table_const_bits));
code.test(tmp, u32(-(1 << valid_page_index_bits))); if (ctx.conf.page_table_log2_stride > 3) {
code.jnz(abort, code.T_NEAR); code.shl(tmp, int(ctx.conf.page_table_log2_stride));
} code.mov(page, qword[r14 + tmp.cvt64()]);
} else {
if (ctx.conf.page_table_log2_stride > 3) { code.mov(page, qword[r14 + tmp.cvt64() * int(1 << ctx.conf.page_table_log2_stride)]);
code.shl(tmp, int(ctx.conf.page_table_log2_stride)); }
code.mov(page, qword[r14 + tmp.cvt64()]);
} else {
code.mov(page, qword[r14 + tmp.cvt64() * int(1 << ctx.conf.page_table_log2_stride)]);
} }
// check for marked bit, use as unmapped if marked // check for marked bit, use as unmapped if marked
@@ -193,7 +211,7 @@ template<>
return page + vaddr; return page + vaddr;
} }
code.mov(tmp, vaddr); code.mov(tmp, vaddr);
code.and_(tmp, static_cast<u32>(page_table_const_mask)); code.and_(tmp, u32(page_table_const_mask));
return page + tmp; return page + tmp;
} }