mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-19 09:07:38 +00:00
Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2d1eb0dab9 | |||
| 9a30172e45 | |||
| 07f40d5cac | |||
| 3c38afad74 | |||
| 0ce29be608 | |||
| 1203082a8f | |||
| 14235dc0d0 | |||
| 6374f7f51f | |||
| 73e004de6e | |||
| f7b8ade40e | |||
| 8c1194474e | |||
| 90aafeedc1 | |||
| 4fe5f62c38 | |||
| c3f1e6562b | |||
| ac35358b3f | |||
| 7bf95be2c2 | |||
| 4ce45b3b37 | |||
| fd34024f0e | |||
| d76f8f91c4 | |||
| a7061eb4c8 | |||
| fa4e7c6992 | |||
| b77308ced6 | |||
| defddec47f | |||
| c5405250d1 | |||
| 10c07d700c | |||
| 505b157647 | |||
| 1575f55abe | |||
| bfba95fd60 | |||
| ee73920d28 | |||
| 42642f8bad | |||
| 1a48de6e55 |
@@ -1,13 +0,0 @@
|
|||||||
diff --git a/libs/cobalt/include/boost/cobalt/concepts.hpp b/libs/cobalt/include/boost/cobalt/concepts.hpp
|
|
||||||
index d49f2ec..a9bdb80 100644
|
|
||||||
--- a/libs/cobalt/include/boost/cobalt/concepts.hpp
|
|
||||||
+++ b/libs/cobalt/include/boost/cobalt/concepts.hpp
|
|
||||||
@@ -62,7 +62,7 @@ struct enable_awaitables
|
|
||||||
template <typename T>
|
|
||||||
concept with_get_executor = requires (T& t)
|
|
||||||
{
|
|
||||||
- {t.get_executor()} -> asio::execution::executor;
|
|
||||||
+ t.get_executor();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
+3
-7
@@ -417,12 +417,9 @@ AddJsonPackage(boost)
|
|||||||
set(BOOST_NO_HEADERS ${Boost_ADDED})
|
set(BOOST_NO_HEADERS ${Boost_ADDED})
|
||||||
|
|
||||||
if (Boost_ADDED)
|
if (Boost_ADDED)
|
||||||
if (MSVC OR ANDROID)
|
add_compile_definitions(YUZU_BOOST_v1)
|
||||||
add_compile_definitions(YUZU_BOOST_v1)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (NOT MSVC OR CXX_CLANG)
|
if (NOT MSVC OR CXX_CLANG)
|
||||||
# boost sucks
|
# solaris sucks
|
||||||
if (SOLARIS)
|
if (SOLARIS)
|
||||||
add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:-pthreads>)
|
add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:-pthreads>)
|
||||||
endif()
|
endif()
|
||||||
@@ -431,8 +428,7 @@ if (Boost_ADDED)
|
|||||||
target_compile_options(boost_icl INTERFACE $<$<COMPILE_LANGUAGE:C,CXX>:-Wno-shadow>)
|
target_compile_options(boost_icl INTERFACE $<$<COMPILE_LANGUAGE:C,CXX>:-Wno-shadow>)
|
||||||
target_compile_options(boost_asio INTERFACE
|
target_compile_options(boost_asio INTERFACE
|
||||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-conversion>
|
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-conversion>
|
||||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-implicit-fallthrough>
|
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-implicit-fallthrough>)
|
||||||
)
|
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|||||||
+6
-9
@@ -6,22 +6,19 @@
|
|||||||
"version": "v0.19.0"
|
"version": "v0.19.0"
|
||||||
},
|
},
|
||||||
"boost": {
|
"boost": {
|
||||||
"artifact": "%VERSION%-cmake.tar.xz",
|
"artifact": "boost-%VERSION%.tar.zst",
|
||||||
"find_args": "CONFIG OPTIONAL_COMPONENTS headers context system fiber filesystem",
|
"find_args": "CONFIG OPTIONAL_COMPONENTS headers context system fiber filesystem",
|
||||||
"hash": "6ae6e94664fe7f2fb01976b59b276ac5df8085c7503fa829d810fbfe495960cfec44fa2c36e2cb23480bc19c956ed199d4952b02639a00a6c07625d4e7130c2d",
|
"hash": "681d97be4386767662e230b2e7c9754d45e709cc5db4e747c23c27d1f5b0e87770bdf19b0bc44dcb0e8349324887bbb8fffb432098f4d0ce74a5043021a90afc",
|
||||||
"min_version": "1.57",
|
"min_version": "1.57",
|
||||||
"package": "Boost",
|
"package": "Boost",
|
||||||
"patches": [
|
"repo": "eden-emulator/ext-boost",
|
||||||
"0001-clang-cl.patch"
|
"version": "1.92.0"
|
||||||
],
|
|
||||||
"repo": "boostorg/boost",
|
|
||||||
"version": "boost-1.90.0"
|
|
||||||
},
|
},
|
||||||
"boost_headers": {
|
"boost_headers": {
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"hash": "4ef845775e2277a8104ded6ddf749aa262ce52cf8438042869a048f9a0156dd772fbbcfa74efa1378fecef339b7286f6fe4b4feb5c45d49966b35d08e3e83507",
|
"hash": "c5fa2cd72f6e6666b7963b97bc359c75284b8fb540c30f3629a028b85270c9bc66c8a051383964f2bd4c1e005a4691593d15696e7ef39ea87cf6cff9e5691fb2",
|
||||||
"repo": "boostorg/headers",
|
"repo": "boostorg/headers",
|
||||||
"version": "boost-1.90.0"
|
"version": "boost-1.91.0"
|
||||||
},
|
},
|
||||||
"catch2": {
|
"catch2": {
|
||||||
"hash": "7eea385d79d88a5690cde131fe7ccda97d5c54ea09d6f515000d7bf07c828809d61c1ac99912c1ee507cf933f61c1c47ecdcc45df7850ffa82714034b0fccf35",
|
"hash": "7eea385d79d88a5690cde131fe7ccda97d5c54ea09d6f515000d7bf07c828809d61c1ac99912c1ee507cf933f61c1c47ecdcc45df7850ffa82714034b0fccf35",
|
||||||
|
|||||||
Vendored
+709
-599
File diff suppressed because it is too large
Load Diff
Vendored
+709
-600
File diff suppressed because it is too large
Load Diff
Vendored
+709
-600
File diff suppressed because it is too large
Load Diff
Vendored
+708
-599
File diff suppressed because it is too large
Load Diff
Vendored
+708
-599
File diff suppressed because it is too large
Load Diff
Vendored
+708
-599
File diff suppressed because it is too large
Load Diff
Vendored
+710
-601
File diff suppressed because it is too large
Load Diff
Vendored
+708
-599
File diff suppressed because it is too large
Load Diff
Vendored
+708
-599
File diff suppressed because it is too large
Load Diff
Vendored
+709
-600
File diff suppressed because it is too large
Load Diff
Vendored
+708
-599
File diff suppressed because it is too large
Load Diff
Vendored
+709
-600
File diff suppressed because it is too large
Load Diff
Vendored
+709
-600
File diff suppressed because it is too large
Load Diff
Vendored
+708
-599
File diff suppressed because it is too large
Load Diff
Vendored
+709
-600
File diff suppressed because it is too large
Load Diff
Vendored
+709
-600
File diff suppressed because it is too large
Load Diff
Vendored
+709
-600
File diff suppressed because it is too large
Load Diff
Vendored
+709
-600
File diff suppressed because it is too large
Load Diff
Vendored
+709
-600
File diff suppressed because it is too large
Load Diff
Vendored
+708
-599
File diff suppressed because it is too large
Load Diff
Vendored
+709
-599
File diff suppressed because it is too large
Load Diff
Vendored
+709
-600
File diff suppressed because it is too large
Load Diff
Vendored
+709
-600
File diff suppressed because it is too large
Load Diff
Vendored
+709
-600
File diff suppressed because it is too large
Load Diff
Vendored
+709
-600
File diff suppressed because it is too large
Load Diff
Vendored
+708
-599
File diff suppressed because it is too large
Load Diff
Vendored
+709
-600
File diff suppressed because it is too large
Load Diff
+21
-33
@@ -1,44 +1,32 @@
|
|||||||
# User Handbook - Command Line
|
# User Handbook - Command Line
|
||||||
|
|
||||||
There are two main applications, an SDL-based app (`eden-cli`) and a Qt based app (`eden`); both accept the same command line arguments.
|
There are two main applications, an SDL-based app (`eden-cli`) and a Qt based app (`eden`); both accept command line arguments.
|
||||||
|
|
||||||
|
## eden
|
||||||
|
|
||||||
- `./eden <path>`: Running with a single argument and nothing else, will make the emulator look for the given file and load it, this behavior is similar to `eden-cli`; allows dragging and dropping games into the application.
|
- `./eden <path>`: Running with a single argument and nothing else, will make the emulator look for the given file and load it, this behavior is similar to `eden-cli`; allows dragging and dropping games into the application.
|
||||||
- `--debug/-d`: Enter debug mode, allow gdb stub at port `1234`
|
- `-g <path>`: Alternate way to specify what to load, overrides. However let it be noted that arguments that use `-` will be treated as options/ignored, if your game, for some reason, starts with `-`, in order to safely handle it you may need to specify it as an argument.
|
||||||
- `--config/-c`: Specify alternate configuration file.
|
- `-f`: Use fullscreen.
|
||||||
- `--fullscreen/-f`: Use fullscreen.
|
- `-u <number>`: Select the index of the user to load as.
|
||||||
- `--help/-h`: Display help.
|
- `-input-profile <name>`: Specifies input profile name to use (for player #0 only).
|
||||||
- `--game/-g <path>`: Alternate way to specify what to load, overrides. However let it be noted that arguments that use `-` will be treated as options/ignored, if your game, for some reason, starts with `-`, in order to safely handle it you may need to specify it as an argument.
|
|
||||||
- `--multiplayer/-m`: Specify multiplayer options.
|
|
||||||
- `--program/-p`: Specify the program arguments to pass (optional).
|
|
||||||
- `--user/-u <number>`: Specify the user index.
|
|
||||||
- `--version/-v`: Display version and quit.
|
|
||||||
- `--input-profile/-i <name>`: Specifies input profile name to use (for player #0 only).
|
|
||||||
- `--null-render/-n`: Forces the usage of the "Null" render backend irrespective of settings.
|
|
||||||
- `--filter/-x`: Sets the debug log filter irrespective of settings.
|
|
||||||
- `--singlecore/-s`: Forces single-core regardless of settings.
|
|
||||||
|
|
||||||
Only the Qt frontend supports the following arguments:
|
|
||||||
|
|
||||||
- `-qlaunch`: Launch QLaunch.
|
- `-qlaunch`: Launch QLaunch.
|
||||||
- `-hlaunch`: Launch homebrew launcher `nx-hbloader`.
|
- `-hlaunch`: Launch homebrew launcher `nx-hbloader`.
|
||||||
- Requires a copy of Atmosphere to be extracted onto `sdmc`.
|
- Requires a copy of Atmosphere to be extracted onto `sdmc`.
|
||||||
- This is a shorthand for `<eden folder>/sdmc/atmosphere/hbl.nsp`.
|
- This is a shorthand for `<eden folder>/sdmc/atmosphere/hbl.nsp`.
|
||||||
- `-setup`: Launch setup applet.
|
- `-setup`: Launch setup applet.
|
||||||
|
|
||||||
`eden` (provided with `--room`), and `eden-room` supports the following options as well:
|
## eden-cli
|
||||||
|
|
||||||
- `-n/--room-name`: The name of the room.
|
- `--debug/-d`: Enter debug mode, allow gdb stub at port `1234`
|
||||||
- `-d/--room-description`: The room description.
|
- `--config/-c`: Specify alternate configuration file.
|
||||||
- `-s/--bind-address`: The bind address for the room.
|
- `--fullscreen/-f`: Set fullscreen.
|
||||||
- `-p/--port`: The port used for the room.
|
- `--help/-h`: Display help.
|
||||||
- `-m/--max-members`: The maximum number of players for this room.
|
- `--game/-g`: Specify the game to run.
|
||||||
- `-w/--password`: The password for the room.
|
- `--multiplayer/-m`: Specify multiplayer options.
|
||||||
- `-g/--preferred-game`: The preferred game for this room.
|
- `--program/-p`: Specify the program arguments to pass (optional).
|
||||||
- `-i/--preferred-game-id`: The preferred game-id for this room.
|
- `--user/-u`: Specify the user index.
|
||||||
- `-u/--username`: The username used for announce.
|
- `--version/-v`: Display version and quit.
|
||||||
- `-t/--token`: The token used for announce.
|
- `--input-profile/-i`: Specifies input profile name to use (for player #0 only).
|
||||||
- `-a/--web-api-url`: yuzu Web API url.
|
- `--null-render/-n`: Forces the usage of the "Null" render backend irrespective of settings.
|
||||||
- `-b/--ban-list-file`: The file for storing the room ban list.
|
- `--filter/-x`: Sets the debug log filter irrespective of settings.
|
||||||
- `-l/--log-file`: The file for storing the room log.
|
- `--singlecore/-s`: Forces single-core regardless of settings.
|
||||||
- `-h/--help`: Display this help and exit.
|
|
||||||
- `-v/--version`: Output version information and exit.
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?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://yuzu-mirror.github.io/help/quickstart\">اعرف المزيد</a>]]></string>
|
<string name="app_disclaimer">سيعمل هذا البرنامج على تشغيل ألعاب منصة ألعاب «نينتندو سويتش». لا يتضمن البرنامج أي ألعاب أو مفاتيح تفعيل.<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,6 +291,25 @@
|
|||||||
<string name="gpu_driver_fetcher">أداة جلب برامج تشغيل وحدة المعالجة الرسومية</string>
|
<string name="gpu_driver_fetcher">أداة جلب برامج تشغيل وحدة المعالجة الرسومية</string>
|
||||||
<string name="gpu_driver_manager">إدارة برامج تشغيل وحدة معالجة الرسومات</string>
|
<string name="gpu_driver_manager">إدارة برامج تشغيل وحدة معالجة الرسومات</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>
|
||||||
@@ -305,6 +324,13 @@
|
|||||||
<string name="frame_gen_target_rate_60">60 إطارًا في الثانية</string>
|
<string name="frame_gen_target_rate_60">60 إطارًا في الثانية</string>
|
||||||
<string name="frame_gen_target_rate_90">90 إطارًا في الثانية</string>
|
<string name="frame_gen_target_rate_90">90 إطارًا في الثانية</string>
|
||||||
<string name="frame_gen_target_rate_120">120 إطارًا في الثانية</string>
|
<string name="frame_gen_target_rate_120">120 إطارًا في الثانية</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>
|
||||||
@@ -315,14 +341,14 @@
|
|||||||
<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، الذي تتطلبه برامج التظليل الخاصة بـ«Lossless Scaling».</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)</string>
|
<string name="frame_generation_unsupported">غير مدعوم (لا يتوفر نموذج ذاكرة Vulkan أو float16)</string>
|
||||||
<string name="lossless_scaling">Lossless Scaling</string>
|
<string name="lossless_scaling">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>
|
||||||
@@ -912,7 +938,7 @@
|
|||||||
<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[اللعبة التي تحاول تشغيلها تتطلب الفيرموير للتمهيد أو لتجاوز القائمة الافتتاحية. يرجى <a href=\"https://yuzu-mirror.github.io/help/quickstart\">نسخ وتثبيت الفيرموير</a>، أو اضغط \"موافق\" للمتابعة على أي حال.]]></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>
|
||||||
|
|||||||
@@ -474,8 +474,6 @@
|
|||||||
<string name="loader_error_file_not_found">فایلی ڕۆم بوونی نییە</string>
|
<string name="loader_error_file_not_found">فایلی ڕۆم بوونی نییە</string>
|
||||||
|
|
||||||
<string name="loader_requires_firmware">یارییەکە فریموێر پێویستە</string>
|
<string name="loader_requires_firmware">یارییەکە فریموێر پێویستە</string>
|
||||||
<string name="loader_requires_firmware_description"><![CDATA[یارییەکە کە تۆ هەوڵ دەدەیت بیخەیتە کار فریموێر پێویستە بۆ کردنەوە یان تێپەڕاندنی مێنیوی کردنەوە. تکایە <a href=\"https://yuzu-mirror.github.io/help/quickstart\"> فریموێر دامپ بکە و دابنێ</a>, یان پەنجە بنێ سەر \"باشە\" بۆ بەردەوامبوون هەرچۆنێک بێت.]]></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">یاری نەدۆزرایەوە بۆ ناسنامەی ناونیشان: %1$s</string>
|
<string name="game_not_found_for_title_id">یاری نەدۆزرایەوە بۆ ناسنامەی ناونیشان: %1$s</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">Tento software umožňuje spouštět hry pro herní konzoli Nintendo Switch. Neobsahuje žádné herní tituly ani klíče.<br /><br /> Nejdříve prosím vyhledejte soubor <![CDATA[<b> prod.keys </b>]]> v úložišti vašeho zařízení.<br /><br /><![CDATA[<a href=\"https://yuzu-mirror.github.io/help/quickstart\">Další informace</a>]]></string>
|
|
||||||
<string name="notice_notification_channel_name">Upozornění a chyby</string>
|
<string name="notice_notification_channel_name">Upozornění a chyby</string>
|
||||||
<string name="notice_notification_channel_description">Zobrazí oznámení v případě chyby.</string>
|
<string name="notice_notification_channel_description">Zobrazí oznámení v případě chyby.</string>
|
||||||
<string name="notification_permission_not_granted">Oprávnění k zobrazení oznámení nebylo uděleno!</string>
|
<string name="notification_permission_not_granted">Oprávnění k zobrazení oznámení nebylo uděleno!</string>
|
||||||
@@ -605,8 +604,6 @@
|
|||||||
<string name="loader_error_file_not_found">ROM neexistuje</string>
|
<string name="loader_error_file_not_found">ROM neexistuje</string>
|
||||||
|
|
||||||
<string name="loader_requires_firmware">Hra vyžaduje firmware</string>
|
<string name="loader_requires_firmware">Hra vyžaduje firmware</string>
|
||||||
<string name="loader_requires_firmware_description"><![CDATA[Hra, kterou se pokoušíte spustit, vyžaduje firmware pro spuštění nebo pro překročení úvodní nabídky. Prosím <a href=\"https://yuzu-mirror.github.io/help/quickstart\"> převezměte a nainstalujte firmware</a>, nebo stiskněte \"OK\" pro pokračování v každém případě.]]></string>
|
|
||||||
|
|
||||||
<!-- Intent Launch strings -->
|
<!-- Intent Launch strings -->
|
||||||
<string name="searching_for_game">Hledání hry...</string>
|
<string name="searching_for_game">Hledání hry...</string>
|
||||||
<string name="game_not_found_for_title_id">Hra nebyla nalezena pro ID titulu: %1$s</string>
|
<string name="game_not_found_for_title_id">Hra nebyla nalezena pro ID titulu: %1$s</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">Diese Software führt Spiele für die Nintendo Switch-Konsole aus. Es sind keine Spiele oder Schlüssel enthalten. Suche, bevor du beginnst, deine <![CDATA[<b> prod.keys </b>]]>-Datei auf deinem Gerät.<br /><br /><![CDATA[<a href=\"https://yuzu-mirror.github.io/help/quickstart\">Mehr Erfahren</a>]]></string>
|
|
||||||
<string name="notice_notification_channel_name">Hinweise und Fehler</string>
|
<string name="notice_notification_channel_name">Hinweise und Fehler</string>
|
||||||
<string name="notice_notification_channel_description">Zeigt Benachrichtigungen an, wenn etwas schief läuft.</string>
|
<string name="notice_notification_channel_description">Zeigt Benachrichtigungen an, wenn etwas schief läuft.</string>
|
||||||
<string name="notification_permission_not_granted">Berechtigung für Benachrichtigungen nicht zugelassen!</string>
|
<string name="notification_permission_not_granted">Berechtigung für Benachrichtigungen nicht zugelassen!</string>
|
||||||
@@ -307,12 +306,10 @@
|
|||||||
<string name="frame_gen_queue_target_1">Ausbalanciert (1 Bild)</string>
|
<string name="frame_gen_queue_target_1">Ausbalanciert (1 Bild)</string>
|
||||||
<string name="frame_gen_queue_target_2">Flüssigste (2 Bilder)</string>
|
<string name="frame_gen_queue_target_2">Flüssigste (2 Bilder)</string>
|
||||||
<string name="frame_gen_unsupported">Frame-Generation nicht verfügbar</string>
|
<string name="frame_gen_unsupported">Frame-Generation nicht verfügbar</string>
|
||||||
<string name="frame_gen_unsupported_description">Dieser GPU-Treiber unterstützt das Vulkan-Memory-Model nicht, welches Lossless Scaling-Shader benötigen.</string>
|
|
||||||
<string name="lossless_scaling_setup_description">Optional. Stelle deine eigene Lossless.dll zur Verfügung, um Frame-Generation später zu aktivieren.</string>
|
<string name="lossless_scaling_setup_description">Optional. Stelle deine eigene Lossless.dll zur Verfügung, um Frame-Generation später zu aktivieren.</string>
|
||||||
<string name="lossless_scaling_install">Installiere Lossless.dll</string>
|
<string name="lossless_scaling_install">Installiere Lossless.dll</string>
|
||||||
<string name="lossless_scaling_replace_description">Wähle eine andere Kopie von Lossless.dll</string>
|
<string name="lossless_scaling_replace_description">Wähle eine andere Kopie von Lossless.dll</string>
|
||||||
<string name="frame_generation_supported">Unterstützt</string>
|
<string name="frame_generation_supported">Unterstützt</string>
|
||||||
<string name="frame_generation_unsupported">Nicht unterstützt (kein Vulkan-Memory-Model)</string>
|
|
||||||
<string name="lossless_scaling">Lossless Scaling</string>
|
<string name="lossless_scaling">Lossless Scaling</string>
|
||||||
<string name="lossless_scaling_installed">Installiert</string>
|
<string name="lossless_scaling_installed">Installiert</string>
|
||||||
<string name="lossless_scaling_not_installed">Nicht installiert</string>
|
<string name="lossless_scaling_not_installed">Nicht installiert</string>
|
||||||
@@ -811,8 +808,6 @@ Wirklich fortfahren?</string>
|
|||||||
<string name="loader_error_file_not_found">ROM-Datei existiert nicht</string>
|
<string name="loader_error_file_not_found">ROM-Datei existiert nicht</string>
|
||||||
|
|
||||||
<string name="loader_requires_firmware">Spiel erfordert Firmware</string>
|
<string name="loader_requires_firmware">Spiel erfordert Firmware</string>
|
||||||
<string name="loader_requires_firmware_description"><![CDATA[Das Spiel, das Sie starten möchten, benötigt Firmware zum Booten oder zum Überspringen des Startmenüs. Bitte <a href=\"https://yuzu-mirror.github.io/help/quickstart\"> dumpen und installieren Sie Firmware</a>, oder drücken Sie \"OK\", um trotzdem zu starten.]]></string>
|
|
||||||
|
|
||||||
<!-- Intent Launch strings -->
|
<!-- Intent Launch strings -->
|
||||||
<string name="searching_for_game">Suche nach Spiel...</string>
|
<string name="searching_for_game">Suche nach Spiel...</string>
|
||||||
<string name="game_not_found_for_title_id">Spiel nicht gefunden für Titel-ID: %1$s</string>
|
<string name="game_not_found_for_title_id">Spiel nicht gefunden für Titel-ID: %1$s</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">Este software arrancará juegos para la consola Nintendo Switch. No se incluyen títulos ni claves de juego.<br /><br />Antes de continuar, por favor localiza tu archivo <![CDATA[prod.keys ]]> en el almacenamiento de tu dispositivo. <br /><br /><![CDATA[<a href=\"https://yuzu-mirror.github.io/help/quickstart\">Aprender más</a>]]><b></string>
|
|
||||||
<string name="notice_notification_channel_name">Avisos y errores</string>
|
<string name="notice_notification_channel_name">Avisos y errores</string>
|
||||||
<string name="notice_notification_channel_description">Mostrar notificaciones cuando algo vaya mal.</string>
|
<string name="notice_notification_channel_description">Mostrar notificaciones cuando algo vaya mal.</string>
|
||||||
<string name="notification_permission_not_granted">¡Permiso de notificación no concedido!</string>
|
<string name="notification_permission_not_granted">¡Permiso de notificación no concedido!</string>
|
||||||
@@ -290,6 +289,9 @@
|
|||||||
<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_open_list">Abrir lista</string>
|
||||||
|
<string name="post_processing_close_list">Cerrar lista</string>
|
||||||
|
<string name="post_processing_reset">Restablecer a predeterminado</string>
|
||||||
<string name="frame_gen">Generación de fotograma</string>
|
<string name="frame_gen">Generación de fotograma</string>
|
||||||
<string name="frame_gen_per_game_description">Configurar la generación de fotogramas para este juego</string>
|
<string name="frame_gen_per_game_description">Configurar la generación de fotogramas para este juego</string>
|
||||||
<string name="frame_gen_multiplier">Multiplicador de fotograma</string>
|
<string name="frame_gen_multiplier">Multiplicador de fotograma</string>
|
||||||
@@ -309,7 +311,6 @@
|
|||||||
<string name="lossless_scaling_replace_description">Seleccionar una copia diferente de Lossless.dll</string>
|
<string name="lossless_scaling_replace_description">Seleccionar una copia diferente de Lossless.dll</string>
|
||||||
<string name="frame_generation_support">Generación de fotograma</string>
|
<string name="frame_generation_support">Generación de fotograma</string>
|
||||||
<string name="frame_generation_supported">Soportado</string>
|
<string name="frame_generation_supported">Soportado</string>
|
||||||
<string name="frame_generation_unsupported">No soportado (sin modelo de memoria de Vulkan)</string>
|
|
||||||
<string name="lossless_scaling">Escalado sin pérdidas</string>
|
<string name="lossless_scaling">Escalado sin pérdidas</string>
|
||||||
<string name="lossless_scaling_installed">Instalado</string>
|
<string name="lossless_scaling_installed">Instalado</string>
|
||||||
<string name="lossless_scaling_not_installed">No instalado</string>
|
<string name="lossless_scaling_not_installed">No instalado</string>
|
||||||
@@ -783,7 +784,7 @@
|
|||||||
<!-- Custom Paths settings -->
|
<!-- Custom Paths settings -->
|
||||||
<string name="custom_save_directory">Directorio de los datos de guardado</string>
|
<string name="custom_save_directory">Directorio de los datos de guardado</string>
|
||||||
<string name="custom_save_directory_description">Establecer una ruta personalizada para el almacenamiento de los datos de guardado</string>
|
<string name="custom_save_directory_description">Establecer una ruta personalizada para el almacenamiento de los datos de guardado</string>
|
||||||
<string name="reset_to_nand">Restaurar valores predeterminados</string>
|
<string name="reset_to_nand">Restaurar los valores predeterminados</string>
|
||||||
<string name="migrate_save_data">Migrar datos de guardado</string>
|
<string name="migrate_save_data">Migrar datos de guardado</string>
|
||||||
<string name="migrate_save_data_question">¿Desea migrar los datos de guardado existentes a la nueva ubicación\?</string>
|
<string name="migrate_save_data_question">¿Desea migrar los datos de guardado existentes a la nueva ubicación\?</string>
|
||||||
<string name="save_migration_complete">Datos de guardado migrados con éxito</string>
|
<string name="save_migration_complete">Datos de guardado migrados con éxito</string>
|
||||||
@@ -877,8 +878,6 @@
|
|||||||
<string name="loader_error_file_not_found">Archivo ROM no existe</string>
|
<string name="loader_error_file_not_found">Archivo ROM no existe</string>
|
||||||
|
|
||||||
<string name="loader_requires_firmware">El juego requiere firmware</string>
|
<string name="loader_requires_firmware">El juego requiere firmware</string>
|
||||||
<string name="loader_requires_firmware_description"><![CDATA[El juego que intenta iniciar requiere el firmware para arrancar o pasar el menú de inicio. Por favor <a href=\"https://yuzu-mirror.github.io/help/quickstart\"> vuelque e instale el firmware</a>, o pulse \"Aceptar\" para continuar de todos modos.]]></string>
|
|
||||||
|
|
||||||
<!-- Intent Launch strings -->
|
<!-- Intent Launch strings -->
|
||||||
<string name="searching_for_game">Buscando juego...</string>
|
<string name="searching_for_game">Buscando juego...</string>
|
||||||
<string name="game_not_found_for_title_id">Juego no encontrado para el ID de título: %1$s</string>
|
<string name="game_not_found_for_title_id">Juego no encontrado para el ID de título: %1$s</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">Ce logiciel permet de jouer à des jeux de la console Nintendo Switch. Aucun titre ni clé de jeu n\'est inclus.<br /><br />Avant de commencer, veuillez localiser votre fichier <![CDATA[<b> prod.keys </b>]]> sur le stockage de votre appareil.<br /><br /><![CDATA[<a href=\"https://yuzu-mirror.github.io/help/quickstart\">En savoir plus</a>]]></string>
|
|
||||||
<string name="notice_notification_channel_name">Avis et erreurs</string>
|
<string name="notice_notification_channel_name">Avis et erreurs</string>
|
||||||
<string name="notice_notification_channel_description">Affiche des notifications en cas de problème.</string>
|
<string name="notice_notification_channel_description">Affiche des notifications en cas de problème.</string>
|
||||||
<string name="notification_permission_not_granted">Permission de notification non accordée !</string>
|
<string name="notification_permission_not_granted">Permission de notification non accordée !</string>
|
||||||
@@ -785,8 +784,6 @@
|
|||||||
<string name="loader_error_file_not_found">Le fichier ROM n\'existe pas</string>
|
<string name="loader_error_file_not_found">Le fichier ROM n\'existe pas</string>
|
||||||
|
|
||||||
<string name="loader_requires_firmware">Jeu nécessite un firmware</string>
|
<string name="loader_requires_firmware">Jeu nécessite un firmware</string>
|
||||||
<string name="loader_requires_firmware_description"><![CDATA[Ce jeu nécessite un firmware pour démarrer ou passer le menu d\'accueil. Veuillez <a href=\"https://yuzu-mirror.github.io/help/quickstart\">dumper et installer le firmware</a> ou appuyez sur \"OK\" pour continuer quand même.]]></string>
|
|
||||||
|
|
||||||
<!-- Intent Launch strings -->
|
<!-- Intent Launch strings -->
|
||||||
<string name="searching_for_game">Recherche du jeu...</string>
|
<string name="searching_for_game">Recherche du jeu...</string>
|
||||||
<string name="game_not_found_for_title_id">Jeu non trouvé pour l\'ID de titre : %1$s</string>
|
<string name="game_not_found_for_title_id">Jeu non trouvé pour l\'ID de titre : %1$s</string>
|
||||||
|
|||||||
@@ -510,8 +510,6 @@
|
|||||||
<string name="loader_error_file_not_found">קובץ המשחק לא קיים</string>
|
<string name="loader_error_file_not_found">קובץ המשחק לא קיים</string>
|
||||||
|
|
||||||
<string name="loader_requires_firmware">המשחק דורש קושחה</string>
|
<string name="loader_requires_firmware">המשחק דורש קושחה</string>
|
||||||
<string name="loader_requires_firmware_description"><![CDATA[המשחק שאתה מנסה להפעיל דורש קושחה לאתחול או למעבר מתפריט הפתיחה. אנא <a href=\"https://yuzu-mirror.github.io/help/quickstart\">שמור והתקן קושחה</a> או לחץ \"אישור\" כדי להמשיך בכל מקרה.]]></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">משחק לא נמצא למזהה כותרת: %1$s</string>
|
<string name="game_not_found_for_title_id">משחק לא נמצא למזהה כותרת: %1$s</string>
|
||||||
|
|||||||
@@ -598,8 +598,6 @@
|
|||||||
<string name="loader_error_file_not_found">ROM fájl nem létezik</string>
|
<string name="loader_error_file_not_found">ROM fájl nem létezik</string>
|
||||||
|
|
||||||
<string name="loader_requires_firmware">A játék firmware-t igényel</string>
|
<string name="loader_requires_firmware">A játék firmware-t igényel</string>
|
||||||
<string name="loader_requires_firmware_description"><![CDATA[A játék, amelyet el szeretne indítani, firmware-t igényel a bootoláshoz vagy a kezdőmenü átlépéséhez. Kérjük, <a href=\"https://yuzu-mirror.github.io/help/quickstart\"> dumpolja és telepítse a firmware-t</a>, vagy nyomja meg az \"OK\" gombot a folytatáshoz.]]></string>
|
|
||||||
|
|
||||||
<!-- Intent Launch strings -->
|
<!-- Intent Launch strings -->
|
||||||
<string name="searching_for_game">Játék keresése...</string>
|
<string name="searching_for_game">Játék keresése...</string>
|
||||||
<string name="game_not_found_for_title_id">A játék nem található a következő címazonosítóhoz: %1$s</string>
|
<string name="game_not_found_for_title_id">A játék nem található a következő címazonosítóhoz: %1$s</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">Perangkat lunak ini akan menjalankan permainan dari konsol Nintendo Switch. Permainan maupun keys tidak disediakan.<br /><br />Sebelum memulai, tolong temukan berkas <![CDATA[<b> prod.keys </b>]]> didalam tempat penyimpanan mu.<br /><br /><![CDATA[<a href=\"https://yuzu-mirror.github.io/help/quickstart\">Pelajari lebih lanjut</a>]]></string>
|
|
||||||
<string name="notice_notification_channel_name">Pemberitahuan dan error</string>
|
<string name="notice_notification_channel_name">Pemberitahuan dan error</string>
|
||||||
<string name="notice_notification_channel_description">Menampilkan pemberitahuan ketika terjadi kesalahan.</string>
|
<string name="notice_notification_channel_description">Menampilkan pemberitahuan ketika terjadi kesalahan.</string>
|
||||||
<string name="notification_permission_not_granted">Izin notifikasi tidak diberikan!</string>
|
<string name="notification_permission_not_granted">Izin notifikasi tidak diberikan!</string>
|
||||||
@@ -638,8 +637,6 @@
|
|||||||
<string name="loader_error_file_not_found">Berkas Tidak Ditemukan</string>
|
<string name="loader_error_file_not_found">Berkas Tidak Ditemukan</string>
|
||||||
|
|
||||||
<string name="loader_requires_firmware">Game memerlukan firmware</string>
|
<string name="loader_requires_firmware">Game memerlukan firmware</string>
|
||||||
<string name="loader_requires_firmware_description"><![CDATA[Game yang ingin Anda jalankan memerlukan firmware untuk boot atau melewati menu pembuka. Silakan <a href=\"https://yuzu-mirror.github.io/help/quickstart\"> dump dan instal firmware</a>, atau tekan \"OK\" untuk melanjutkan.]]></string>
|
|
||||||
|
|
||||||
<!-- Intent Launch strings -->
|
<!-- Intent Launch strings -->
|
||||||
<string name="searching_for_game">Mencari game...</string>
|
<string name="searching_for_game">Mencari game...</string>
|
||||||
<string name="game_not_found_for_title_id">Game tidak ditemukan untuk ID Judul: %1$s</string>
|
<string name="game_not_found_for_title_id">Game tidak ditemukan untuk ID Judul: %1$s</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">Questo software esegue giochi per la console Nintendo Switch. Non sono inclusi titoli di giochi o chiavi.<br /><br /> Prima di iniziare, individua il file <![CDATA[<b>prod.keys</b>]]> nella memoria del tuo dispositivo.<br /><br /> <![CDATA[<a href=\"https://yuzu-mirror.github.io/help/quickstart\">Ulteriori informazioni</a>]]></string>
|
|
||||||
<string name="notice_notification_channel_name">Avvisi ed errori</string>
|
<string name="notice_notification_channel_name">Avvisi ed errori</string>
|
||||||
<string name="notice_notification_channel_description">Mostra le notifiche quando qualcosa va storto.</string>
|
<string name="notice_notification_channel_description">Mostra le notifiche quando qualcosa va storto.</string>
|
||||||
<string name="notification_permission_not_granted">Autorizzazione di notifica non concessa!</string>
|
<string name="notification_permission_not_granted">Autorizzazione di notifica non concessa!</string>
|
||||||
@@ -662,8 +661,6 @@
|
|||||||
<string name="loader_error_file_not_found">Il file della ROM non esiste</string>
|
<string name="loader_error_file_not_found">Il file della ROM non esiste</string>
|
||||||
|
|
||||||
<string name="loader_requires_firmware">Firmware richiesto</string>
|
<string name="loader_requires_firmware">Firmware richiesto</string>
|
||||||
<string name="loader_requires_firmware_description"><![CDATA[Il gioco che stai cercando di avviare richiede il firmware per poter partire o per superare il menù iniziale. <a href=\"https://yuzu-mirror.github.io/help/quickstart\">Esegui il dump del firmware e installalo</a>, o premi \"OK\" per continuare lo stesso.]]></string>
|
|
||||||
|
|
||||||
<!-- Intent Launch strings -->
|
<!-- Intent Launch strings -->
|
||||||
<string name="searching_for_game">Ricerca del gioco in corso...</string>
|
<string name="searching_for_game">Ricerca del gioco in corso...</string>
|
||||||
<string name="game_not_found_for_title_id">Gioco non trovato per l\'ID titolo: %1$s</string>
|
<string name="game_not_found_for_title_id">Gioco non trovato per l\'ID titolo: %1$s</string>
|
||||||
|
|||||||
@@ -508,8 +508,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[起動しようとしているゲームは、起動または開始メニューを通過するためにファームウェアが必要です。<a href=\"https://yuzu-mirror.github.io/help/quickstart\"> ファームウェアをダンプしてインストール</a>するか、\"OK\"を押して続行してください。]]></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>
|
||||||
|
|||||||
@@ -558,8 +558,6 @@
|
|||||||
<string name="loader_error_file_not_found">롬 파일이 존재하지 않음</string>
|
<string name="loader_error_file_not_found">롬 파일이 존재하지 않음</string>
|
||||||
|
|
||||||
<string name="loader_requires_firmware">게임에 펌웨어가 필요합니다</string>
|
<string name="loader_requires_firmware">게임에 펌웨어가 필요합니다</string>
|
||||||
<string name="loader_requires_firmware_description"><![CDATA[실행하려는 게임은 부팅하거나 시작 메뉴를 통과하기 위해 펌웨어가 필요합니다. <a href=\"https://yuzu-mirror.github.io/help/quickstart\">펌웨어를 덤프하여 설치</a>하거나 \"확인\"을 눌러 계속 진행하세요.]]></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>
|
||||||
|
|||||||
@@ -487,8 +487,6 @@
|
|||||||
<string name="loader_error_file_not_found">ROM-filen finnes ikke</string>
|
<string name="loader_error_file_not_found">ROM-filen finnes ikke</string>
|
||||||
|
|
||||||
<string name="loader_requires_firmware">Spillet krever fastvare</string>
|
<string name="loader_requires_firmware">Spillet krever fastvare</string>
|
||||||
<string name="loader_requires_firmware_description"><![CDATA[Spillet du prøver å starte krever fastvare for oppstart eller for å komme forbi startmenyen. Vennligst <a href=\"https://yuzu-mirror.github.io/help/quickstart\"> dump og installer fastvare</a>, eller trykk \"OK\" for å fortsette likevel.]]></string>
|
|
||||||
|
|
||||||
<!-- Intent Launch strings -->
|
<!-- Intent Launch strings -->
|
||||||
<string name="searching_for_game">Søker etter spill...</string>
|
<string name="searching_for_game">Søker etter spill...</string>
|
||||||
<string name="game_not_found_for_title_id">Spill ikke funnet for tittel-ID: %1$s</string>
|
<string name="game_not_found_for_title_id">Spill ikke funnet for tittel-ID: %1$s</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">To oprogramowanie uruchamia gry na konsoli Nintendo Switch. Żadne tytuły gier ani klucze nie są dołączone.<br /><br />Zanim zaczniesz, zlokalizuj plik <![CDATA[<b> prod.keys </b>]]> na swoim urządzeniu.<br /><br /><![CDATA[<a href=\"https://yuzu-mirror.github.io/help/quickstart\">Więcej informacji</a>]]></string>
|
|
||||||
<string name="notice_notification_channel_name">Powiadomienia błędy</string>
|
<string name="notice_notification_channel_name">Powiadomienia błędy</string>
|
||||||
<string name="notice_notification_channel_description">Pokaż powiadomienie gdy coś pójdzie źle</string>
|
<string name="notice_notification_channel_description">Pokaż powiadomienie gdy coś pójdzie źle</string>
|
||||||
<string name="notification_permission_not_granted">Nie zezwolono na powiadomienia!</string>
|
<string name="notification_permission_not_granted">Nie zezwolono na powiadomienia!</string>
|
||||||
@@ -758,8 +757,6 @@
|
|||||||
<string name="loader_error_file_not_found">Plik ROM nie istnieje</string>
|
<string name="loader_error_file_not_found">Plik ROM nie istnieje</string>
|
||||||
|
|
||||||
<string name="loader_requires_firmware">Gra wymaga oprogramowania sprzętowego</string>
|
<string name="loader_requires_firmware">Gra wymaga oprogramowania sprzętowego</string>
|
||||||
<string name="loader_requires_firmware_description"><![CDATA[Gra, którą próbujesz uruchomić, wymaga oprogramowania sprzętowego do uruchomienia lub przejścia przez menu startowe. Proszę <a href=\"https://yuzu-mirror.github.io/help/quickstart\"> zrzuć i zainstaluj oprogramowanie sprzętowe</a>, lub naciśnij \"OK\", aby kontynuować mimo to.]]></string>
|
|
||||||
|
|
||||||
<!-- Intent Launch strings -->
|
<!-- Intent Launch strings -->
|
||||||
<string name="searching_for_game">Wyszukiwanie gry...</string>
|
<string name="searching_for_game">Wyszukiwanie gry...</string>
|
||||||
<string name="game_not_found_for_title_id">Nie znaleziono gry dla ID tytułu: %1$s</string>
|
<string name="game_not_found_for_title_id">Nie znaleziono gry dla ID tytułu: %1$s</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">Este programa serve para rodar jogos do Nintendo Switch. Nenhum jogo ou chaves do sistema são inclusos<br /><br />Antes de começar, localize o seu <![CDATA[<b> prod.keys </b>]]> salvo no seu sistema.<br /><br /><![CDATA[<a href=\"https://yuzu-mirror.github.io/help/quickstart\">Saiba mais</a>]]></string>
|
|
||||||
<string name="notice_notification_channel_name">Notificações e erros</string>
|
<string name="notice_notification_channel_name">Notificações e erros</string>
|
||||||
<string name="notice_notification_channel_description">Mostra notificações quando acontecer um erro.</string>
|
<string name="notice_notification_channel_description">Mostra notificações quando acontecer um erro.</string>
|
||||||
<string name="notification_permission_not_granted">Acesso às notificações não foi permitido!</string>
|
<string name="notification_permission_not_granted">Acesso às notificações não foi permitido!</string>
|
||||||
@@ -717,8 +716,6 @@
|
|||||||
<string name="loader_error_file_not_found">O arquivo ROM não existe</string>
|
<string name="loader_error_file_not_found">O arquivo ROM não existe</string>
|
||||||
|
|
||||||
<string name="loader_requires_firmware">O jogo requer firmware</string>
|
<string name="loader_requires_firmware">O jogo requer firmware</string>
|
||||||
<string name="loader_requires_firmware_description"><![CDATA[O jogo que você está tentando iniciar requer firmware para inicializar ou passar do menu de abertura. Por favor <a href=\"https://yuzu-mirror.github.io/help/quickstart\"> faça dump e instale o firmware</a>, ou pressione \"OK\" para continuar mesmo assim.]]></string>
|
|
||||||
|
|
||||||
<!-- Intent Launch strings -->
|
<!-- Intent Launch strings -->
|
||||||
<string name="searching_for_game">Procurando jogo...</string>
|
<string name="searching_for_game">Procurando jogo...</string>
|
||||||
<string name="game_not_found_for_title_id">Jogo não encontrado para o ID do Título: %1$s</string>
|
<string name="game_not_found_for_title_id">Jogo não encontrado para o ID do Título: %1$s</string>
|
||||||
|
|||||||
@@ -609,8 +609,6 @@ uma tentativa de mapeamento automático</string>
|
|||||||
<string name="loader_error_file_not_found">O ficheiro da ROM não existe</string>
|
<string name="loader_error_file_not_found">O ficheiro da ROM não existe</string>
|
||||||
|
|
||||||
<string name="loader_requires_firmware">O jogo requer firmware</string>
|
<string name="loader_requires_firmware">O jogo requer firmware</string>
|
||||||
<string name="loader_requires_firmware_description"><![CDATA[O jogo que está a tentar iniciar requer firmware para arrancar ou passar o menu inicial. Por favor <a href=\"https://yuzu-mirror.github.io/help/quickstart\"> faça dump e instale o firmware</a>, ou pressione \"OK\" para continuar mesmo assim.]]></string>
|
|
||||||
|
|
||||||
<!-- Intent Launch strings -->
|
<!-- Intent Launch strings -->
|
||||||
<string name="searching_for_game">A procurar jogo...</string>
|
<string name="searching_for_game">A procurar jogo...</string>
|
||||||
<string name="game_not_found_for_title_id">Jogo não encontrado para o ID do Título: %1$s</string>
|
<string name="game_not_found_for_title_id">Jogo não encontrado para o ID do Título: %1$s</string>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?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://yuzu-mirror.github.io/help/quickstart\">Узнать больше</a>]]></string>
|
<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,6 +291,25 @@
|
|||||||
<string name="gpu_driver_fetcher">Получение драйверов ГПУ</string>
|
<string name="gpu_driver_fetcher">Получение драйверов ГПУ</string>
|
||||||
<string name="gpu_driver_manager">Менеджер драйверов ГПУ</string>
|
<string name="gpu_driver_manager">Менеджер драйверов ГПУ</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">Вставляет промежуточные кадры между отрендеренными с помощью Lossless Scaling. При включении принудительно устанавливает режим вывода FIFO.</string>
|
<string name="frame_gen_description">Вставляет промежуточные кадры между отрендеренными с помощью Lossless Scaling. При включении принудительно устанавливает режим вывода FIFO.</string>
|
||||||
@@ -309,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, требуемую шейдерами 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)</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>
|
||||||
@@ -613,6 +630,11 @@
|
|||||||
<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 МБ до 1 ГБ.</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">Ведение журнала ГПУ</string>
|
<string name="gpu_logging_header">Ведение журнала ГПУ</string>
|
||||||
<string name="gpu_log_level">Уровень журналирования</string>
|
<string name="gpu_log_level">Уровень журналирования</string>
|
||||||
@@ -896,7 +918,7 @@
|
|||||||
<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[Для запуска этой игры или прохождения начального меню требуется прошивка. Пожалуйста, <a href=\"https://yuzu-mirror.github.io/help/quickstart\">сохраните и установите прошивку</a> или нажмите \"OK\" для запуска в любом случае.]]></string>
|
<string name="loader_requires_firmware_description"><![CDATA[Для корректной работы этой игры может потребоваться прошивка, а у вас она не установлена. Пожалуйста, установите прошивку перед запуском или нажмите \"OK\", чтобы всё равно запустить.]]></string>
|
||||||
|
|
||||||
<!-- Intent Launch strings -->
|
<!-- Intent Launch strings -->
|
||||||
<string name="searching_for_game">Поиск игры...</string>
|
<string name="searching_for_game">Поиск игры...</string>
|
||||||
|
|||||||
@@ -606,8 +606,6 @@
|
|||||||
<string name="loader_error_file_not_found">РОМ датотека не постоји</string>
|
<string name="loader_error_file_not_found">РОМ датотека не постоји</string>
|
||||||
|
|
||||||
<string name="loader_requires_firmware">Игра захтева firmware</string>
|
<string name="loader_requires_firmware">Игра захтева firmware</string>
|
||||||
<string name="loader_requires_firmware_description"><![CDATA[Игра коју покушавате да покренете захтева firmware за покретање или прелазак почетног менија. Молимо <a href=\"https://yuzu-mirror.github.io/help/quickstart\"> направите дамп и инсталирајте firmware</a>, или притисните \"OK\" да бисте наставили у сваком случају.]]></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>
|
||||||
|
|||||||
@@ -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://yuzu-mirror.github.io/help/quickstart\">Дізнатися більше</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>
|
||||||
@@ -830,8 +829,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[Гра, яку ви намагаєтеся запустити, вимагає прошивки для завантаження або пропуску початкового меню. Будь ласка, <a href=\"https://yuzu-mirror.github.io/help/quickstart\"> зробіть дамп і встановіть прошивку</a>, або натисніть \"OK\", щоб продовжити в будь-якому разі.]]></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>
|
||||||
|
|||||||
@@ -483,8 +483,6 @@
|
|||||||
<string name="loader_error_file_not_found">Tệp ROM không tồn tại</string>
|
<string name="loader_error_file_not_found">Tệp ROM không tồn tại</string>
|
||||||
|
|
||||||
<string name="loader_requires_firmware">Trò chơi yêu cầu firmware</string>
|
<string name="loader_requires_firmware">Trò chơi yêu cầu firmware</string>
|
||||||
<string name="loader_requires_firmware_description"><![CDATA[Trò chơi bạn đang cố khởi chạy yêu cầu firmware để khởi động hoặc vượt qua menu mở đầu. Vui lòng <a href=\"https://yuzu-mirror.github.io/help/quickstart\"> dump và cài đặt firmware</a>, hoặc nhấn \"OK\" để tiếp tục dù sao đi nữa.]]></string>
|
|
||||||
|
|
||||||
<!-- Intent Launch strings -->
|
<!-- Intent Launch strings -->
|
||||||
<string name="searching_for_game">Đang tìm kiếm trò chơi...</string>
|
<string name="searching_for_game">Đang tìm kiếm trò chơi...</string>
|
||||||
<string name="game_not_found_for_title_id">Không tìm thấy trò chơi cho ID Tiêu đề: %1$s</string>
|
<string name="game_not_found_for_title_id">Không tìm thấy trò chơi cho ID Tiêu đề: %1$s</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://yuzu-mirror.github.io/help/quickstart\">了解更多</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>
|
||||||
@@ -315,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 驱动不支持无损缩放着色器所需的 Vulkan 内存模型。</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 内存模型)</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>
|
||||||
@@ -897,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[您尝试启动的游戏需要固件才能引导或通过启动菜单。请<a href=\"https://yuzu-mirror.github.io/help/quickstart\">转储并安装固件</a>,或点击\"确定\"继续。]]></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>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?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://yuzu-mirror.github.io/help/quickstart\">了解更多</a>]]></string>
|
<string name="app_disclaimer">本軟體可執行Nintendo Switch主機的遊戲,軟體不提供遊戲和金鑰檔案。<br /><br />在開始之前,請先安裝您的 <![CDATA[<b> prod.keys </b>]]> 檔案,<![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,6 +291,25 @@
|
|||||||
<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">使用 Lossless Scaling 在已渲染的影格之間插入補間影格。啟用此功能時,會強制採用 FIFO 垂直同步</string>
|
<string name="frame_gen_description">使用 Lossless Scaling 在已渲染的影格之間插入補間影格。啟用此功能時,會強制採用 FIFO 垂直同步</string>
|
||||||
@@ -315,10 +334,37 @@
|
|||||||
<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">Lossless Scaling 的著色器需要 Vulkan 記憶體模型,所選的驅動程式不支援該功能</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_description">您需要擁有從合法管道獲得的 Lossless Scaling 並從該軟體的資料夾中取得 Lossless.dll 檔案才能使用影格生成功能</string>
|
||||||
|
<string name="lossless_scaling_replace_description">安裝不同的 Lossless.dll 檔案</string>
|
||||||
|
<string name="frame_generation_support">影格生成</string>
|
||||||
|
<string name="frame_generation_supported">支援</string>
|
||||||
|
<string name="lossless_scaling">Lossless Scaling</string>
|
||||||
|
<string name="lossless_scaling_description">安裝您擁有的 Lossless.dll 檔案以使用影格生成</string>
|
||||||
|
<string name="lossless_scaling_installed">已安裝</string>
|
||||||
|
<string name="lossless_scaling_not_installed">未安裝</string>
|
||||||
|
<string name="lossless_scaling_replace">替換</string>
|
||||||
|
<string name="lossless_scaling_remove">刪除</string>
|
||||||
|
<string name="lossless_scaling_remove_description">刪除已安裝的 Lossless.dll 及預先編譯的著色器</string>
|
||||||
|
<string name="lossless_scaling_remove_confirmation">影格生成功能會停止運作直到您重新安裝 Lossless.dll 。您的 Lossless.dll 原始檔並不會被 Eden 修改</string>
|
||||||
|
<string name="lossless_scaling_missing">Lossless.dll 未安裝</string>
|
||||||
|
<string name="lossless_scaling_missing_description">前往 設定 -> Lossless Scaling 安裝以使用影格生成功能</string>
|
||||||
|
<string name="lossless_scaling_locked">請先關閉遊戲</string>
|
||||||
|
<string name="lossless_scaling_locked_description">Lossless.dll 無法在遊戲執行時進行更換</string>
|
||||||
|
<string name="lossless_scaling_remove_unavailable">沒有東西可以刪除</string>
|
||||||
|
<string name="lossless_scaling_remove_unavailable_description">尚未安裝 Lossless.dll</string>
|
||||||
|
<string name="lossless_scaling_installing">準備影格生成著色器中...</string>
|
||||||
|
<string name="lossless_scaling_install_success">成功安裝 Lossless.dll</string>
|
||||||
|
<string name="lossless_scaling_install_failed">無法安裝 Lossless.dll</string>
|
||||||
|
<string name="error_lossless_copy_failed">無法複製選取的檔案</string>
|
||||||
|
<string name="error_lossless_unreadable">無法讀取選取的檔案</string>
|
||||||
|
<string name="error_lossless_not_pe">選取的檔案並不是 Windows 程式庫。請在 Lossless Scaling 的安裝位置(資料夾)中選擇 Lossless.dll</string>
|
||||||
|
<string name="error_lossless_missing_shaders">這個 Lossless.dll 的副本並未包含影格生成著色器。請更新 Lossless Scaling 後再試一次</string>
|
||||||
|
<string name="error_lossless_translation_failed">無法轉譯影格生成著色器。尚不支援此 Lossless Scaling 版本</string>
|
||||||
|
<string name="error_lossless_cache_failed">轉譯的著色器無法寫入到儲存空間。請確認手機容量是否充足</string>
|
||||||
<string name="advanced_settings">進階設定</string>
|
<string name="advanced_settings">進階設定</string>
|
||||||
<string name="settings_description">進行模擬器設定</string>
|
<string name="settings_description">調整模擬器設定</string>
|
||||||
<string name="search_recently_played">最近遊玩</string>
|
<string name="search_recently_played">最近遊玩</string>
|
||||||
<string name="search_recently_added">最近新增</string>
|
<string name="search_recently_added">最近新增</string>
|
||||||
<string name="open_user_folder">開啟 Eden 資料夾</string>
|
<string name="open_user_folder">開啟 Eden 資料夾</string>
|
||||||
@@ -512,7 +558,7 @@
|
|||||||
<string name="renderer_async_presentation">非同步呈現</string>
|
<string name="renderer_async_presentation">非同步呈現</string>
|
||||||
<string name="renderer_async_presentation_description">此修改可以透過將渲染移至單獨的 CPU 執行緒來提升性能,但可能會導致圖形問題</string>
|
<string name="renderer_async_presentation_description">此修改可以透過將渲染移至單獨的 CPU 執行緒來提升性能,但可能會導致圖形問題</string>
|
||||||
<string name="renderer_reactive_flushing">使用重新啟用排清</string>
|
<string name="renderer_reactive_flushing">使用重新啟用排清</string>
|
||||||
<string name="renderer_reactive_flushing_description">犧牲效能,以改善部分遊戲的轉譯準確度。</string>
|
<string name="renderer_reactive_flushing_description">犧牲效能,以改善部分遊戲的轉譯準確度</string>
|
||||||
<string name="enable_buffer_history">啟用緩衝區歷史</string>
|
<string name="enable_buffer_history">啟用緩衝區歷史</string>
|
||||||
<string name="enable_buffer_history_description">允許存取先前的緩衝區狀態。此選項可能會改善部分遊戲的渲染品質與效能穩定性</string>
|
<string name="enable_buffer_history_description">允許存取先前的緩衝區狀態。此選項可能會改善部分遊戲的渲染品質與效能穩定性</string>
|
||||||
<string name="enable_gpu_buffer_readback">啟用 GPU 緩衝區讀回</string>
|
<string name="enable_gpu_buffer_readback">啟用 GPU 緩衝區讀回</string>
|
||||||
@@ -525,7 +571,7 @@
|
|||||||
<string name="fast_gpu_time">GPU 時脈</string>
|
<string name="fast_gpu_time">GPU 時脈</string>
|
||||||
<string name="fast_gpu_time_description">讓遊戲誤以為 GPU 工作能更快完成,避免遊戲為了配合 Switch 的時脈而降低解析度與渲染距離</string>
|
<string name="fast_gpu_time_description">讓遊戲誤以為 GPU 工作能更快完成,避免遊戲為了配合 Switch 的時脈而降低解析度與渲染距離</string>
|
||||||
<string name="skip_cpu_inner_invalidation">跳過CPU內部失效處理</string>
|
<string name="skip_cpu_inner_invalidation">跳過CPU內部失效處理</string>
|
||||||
<string name="skip_cpu_inner_invalidation_description">在記憶體更新期間跳過某些CPU端快取的失效處理,減少CPU使用率並提高其性能。可能會導致某些遊戲出現故障或當機。</string>
|
<string name="skip_cpu_inner_invalidation_description">在記憶體更新期間跳過某些CPU端快取的失效處理,減少CPU使用率並提高其性能。可能會導致某些遊戲出現故障或當機</string>
|
||||||
<string name="fix_bloom_effects">修正光暈特效</string>
|
<string name="fix_bloom_effects">修正光暈特效</string>
|
||||||
<string name="fix_bloom_effects_description">在 薩爾達傳說:織夢島 和 薩爾達傳說:智慧的再現 中 減少光暈模糊的問題並移除 橫衝直撞:狂飆樂園重製版 中的光暈效果 (Adreno A6XX - A7XX/ Turnip)。警告:可能會在其它遊戲中導致圖形異常</string>
|
<string name="fix_bloom_effects_description">在 薩爾達傳說:織夢島 和 薩爾達傳說:智慧的再現 中 減少光暈模糊的問題並移除 橫衝直撞:狂飆樂園重製版 中的光暈效果 (Adreno A6XX - A7XX/ Turnip)。警告:可能會在其它遊戲中導致圖形異常</string>
|
||||||
<string name="emulate_bgr565">模擬 BGR565</string>
|
<string name="emulate_bgr565">模擬 BGR565</string>
|
||||||
@@ -585,6 +631,11 @@
|
|||||||
<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">將日誌檔的最大檔案限制從 100MB 提高到 1GB</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>
|
||||||
@@ -709,7 +760,7 @@
|
|||||||
<string name="import_failed">導入失敗</string>
|
<string name="import_failed">導入失敗</string>
|
||||||
<string name="cancelling">正在取消</string>
|
<string name="cancelling">正在取消</string>
|
||||||
<string name="install">安裝</string>
|
<string name="install">安裝</string>
|
||||||
<string name="fetch">獲取</string>
|
<string name="fetch">下載</string>
|
||||||
<string name="delete">刪除</string>
|
<string name="delete">刪除</string>
|
||||||
<string name="edit">編輯</string>
|
<string name="edit">編輯</string>
|
||||||
<string name="import_success">已成功導入</string>
|
<string name="import_success">已成功導入</string>
|
||||||
@@ -734,12 +785,12 @@
|
|||||||
|
|
||||||
<!-- GPU driver fetcher -->
|
<!-- GPU driver fetcher -->
|
||||||
<string name="show_releases">顯示版本</string>
|
<string name="show_releases">顯示版本</string>
|
||||||
<string name="failed_to_fetch">獲取失敗</string>
|
<string name="failed_to_fetch">下載失敗</string>
|
||||||
<string name="error_during_fetch">獲取過程中發生錯誤</string>
|
<string name="error_during_fetch">下載過程中發生錯誤</string>
|
||||||
<string name="show_downloads">顯示下載</string>
|
<string name="show_downloads">顯示下載</string>
|
||||||
<string name="hide_downloads">隱藏下載</string>
|
<string name="hide_downloads">隱藏下載</string>
|
||||||
<string name="failed_cache_dir">快取目錄不可用</string>
|
<string name="failed_cache_dir">快取目錄不可用</string>
|
||||||
<string name="empty_response_body">回應內容為空</string>
|
<string name="empty_response_body">未回傳任何資料</string>
|
||||||
<string name="successfully_installed">%1$s 安裝成功</string>
|
<string name="successfully_installed">%1$s 安裝成功</string>
|
||||||
<string name="driver_failed_title">驅動程式安裝失敗</string>
|
<string name="driver_failed_title">驅動程式安裝失敗</string>
|
||||||
<string name="failed_install_driver">無法安裝 %1$s 驅動程式,您的系統支援此驅動程式嗎?</string>
|
<string name="failed_install_driver">無法安裝 %1$s 驅動程式,您的系統支援此驅動程式嗎?</string>
|
||||||
@@ -780,13 +831,21 @@
|
|||||||
<string name="save_migration_complete">成功遷移儲存資料</string>
|
<string name="save_migration_complete">成功遷移儲存資料</string>
|
||||||
<string name="save_migration_failed">儲存資料遷移失敗</string>
|
<string name="save_migration_failed">儲存資料遷移失敗</string>
|
||||||
<string name="save_directory_set">存檔目錄設定完成</string>
|
<string name="save_directory_set">存檔目錄設定完成</string>
|
||||||
|
<string name="destination_has_saves">所選取的位置已有儲存資料。是否要取代該檔案?</string>
|
||||||
|
<string name="all_files_permission_required">若要自訂路徑必須授予所有檔案的存取權</string>
|
||||||
|
<string name="grant_permission">授予權限</string>
|
||||||
|
<string name="custom_nand_directory">NAND 路徑</string>
|
||||||
|
<string name="custom_nand_directory_description">設定 NAND 資料的自訂路徑</string>
|
||||||
|
<string name="custom_sdmc_directory">虛擬 SD卡 路徑</string>
|
||||||
|
<string name="custom_sdmc_directory_description">設定虛擬 SD卡 儲存空間的自訂路徑</string>
|
||||||
|
<string name="path_set">路徑設定成功</string>
|
||||||
<string name="skip_migration">跳過</string>
|
<string name="skip_migration">跳過</string>
|
||||||
|
|
||||||
<!-- Game properties -->
|
<!-- Game properties -->
|
||||||
<string name="info">資訊</string>
|
<string name="info">軟體資訊</string>
|
||||||
<string name="info_description">程式 ID、開發人員及版本資訊</string>
|
<string name="info_description">程式 ID、開發人員及版本資訊</string>
|
||||||
<string name="per_game_settings">個別遊戲設定</string>
|
<string name="per_game_settings">個別遊戲設定</string>
|
||||||
<string name="per_game_settings_description">編輯此遊戲的特定設定</string>
|
<string name="per_game_settings_description">調整此遊戲的專用設定</string>
|
||||||
<string name="launch_options">啟動設定</string>
|
<string name="launch_options">啟動設定</string>
|
||||||
<string name="path">路徑</string>
|
<string name="path">路徑</string>
|
||||||
<string name="program_id">程式 ID</string>
|
<string name="program_id">程式 ID</string>
|
||||||
@@ -821,17 +880,17 @@
|
|||||||
<string name="save_data_description">管理此遊戲的儲存資料</string>
|
<string name="save_data_description">管理此遊戲的儲存資料</string>
|
||||||
<string name="delete_save_data">刪除儲存資料</string>
|
<string name="delete_save_data">刪除儲存資料</string>
|
||||||
<string name="delete_save_data_description">刪除此遊戲的所有儲存資料</string>
|
<string name="delete_save_data_description">刪除此遊戲的所有儲存資料</string>
|
||||||
<string name="delete_save_data_warning_description">這將會刪除此遊戲的所有儲存資料,且無法復原,您確定要繼續嗎?</string>
|
<string name="delete_save_data_warning_description">這將會刪除此遊戲的所有儲存資料且無法復原,您確定要繼續嗎?</string>
|
||||||
<string name="save_data_deleted_successfully">儲存資料已成功刪除</string>
|
<string name="save_data_deleted_successfully">儲存資料已成功刪除</string>
|
||||||
<string name="select_content_type">內容類型</string>
|
<string name="select_content_type">內容類型</string>
|
||||||
<string name="updates_and_dlc">更新及 DLC</string>
|
<string name="updates_and_dlc">更新及 DLC</string>
|
||||||
<string name="mods_and_cheats">模組及密技</string>
|
<string name="mods_and_cheats">模組及金手指</string>
|
||||||
<string name="addon_notice">重要的˙附加元件通知</string>
|
<string name="addon_notice">重要的˙附加元件通知</string>
|
||||||
<!-- \"cheats/" "romfs/" and \"exefs/ should not be translated -->
|
<!-- \"cheats/" "romfs/" and \"exefs/ should not be translated -->
|
||||||
<string name="addon_notice_description">若要安裝模組及密技,您必須選擇一個包含 cheats/、romfs/ 或 exefs/ 的目錄。我們無法驗證這些內容是否與您的遊戲相容,所以請謹慎安裝!</string>
|
<string name="addon_notice_description">若要安裝模組及金手指,您必須選擇一個包含 cheats/、romfs/ 或 exefs/ 的目錄。我們無法驗證這些內容是否與您的遊戲相容,所以請謹慎安裝!</string>
|
||||||
<string name="invalid_directory">無效的目錄</string>
|
<string name="invalid_directory">無效的目錄</string>
|
||||||
<!-- \"cheats/" "romfs/" and \"exefs/ should not be translated -->
|
<!-- \"cheats/" "romfs/" and \"exefs/ should not be translated -->
|
||||||
<string name="invalid_directory_description">請確保您選取的目錄包含 cheats/、romfs/ 或 exefs/ 資料夾,然後再試一次。</string>
|
<string name="invalid_directory_description">請確保您選取的目錄包含 cheats/、romfs/ 或 exefs/ 資料夾,然後再試一次</string>
|
||||||
<string name="addon_installed_successfully">附加元件已成功安裝</string>
|
<string name="addon_installed_successfully">附加元件已成功安裝</string>
|
||||||
<string name="verifying_content">正在驗證內容…</string>
|
<string name="verifying_content">正在驗證內容…</string>
|
||||||
<string name="content_install_notice">內容安裝通知</string>
|
<string name="content_install_notice">內容安裝通知</string>
|
||||||
@@ -839,11 +898,12 @@
|
|||||||
<string name="confirm_uninstall">確認刪除</string>
|
<string name="confirm_uninstall">確認刪除</string>
|
||||||
<string name="confirm_uninstall_description">您確定要刪除此附加元件嗎?</string>
|
<string name="confirm_uninstall_description">您確定要刪除此附加元件嗎?</string>
|
||||||
<string name="verify_integrity">完整性驗證</string>
|
<string name="verify_integrity">完整性驗證</string>
|
||||||
|
<string name="verifying">驗證中...</string>
|
||||||
<string name="verify_success">完整性驗證成功!</string>
|
<string name="verify_success">完整性驗證成功!</string>
|
||||||
<string name="verify_failure">完整性驗證失敗!</string>
|
<string name="verify_failure">完整性驗證失敗!</string>
|
||||||
<string name="verify_failure_description">文件可能已經損壞</string>
|
<string name="verify_failure_description">文件可能已經損壞</string>
|
||||||
<string name="verify_no_result">無法執行完整性驗證</string>
|
<string name="verify_no_result">無法正常執行完整性驗證</string>
|
||||||
<string name="verify_no_result_description">未檢查文件的完整性</string>
|
<string name="verify_no_result_description">未完成文件完整性檢查</string>
|
||||||
<string name="verification_failed_for">以下文件的完整性驗證失敗:\n %1$s</string>
|
<string name="verification_failed_for">以下文件的完整性驗證失敗:\n %1$s</string>
|
||||||
<string name="share_game_settings">分享設定</string>
|
<string name="share_game_settings">分享設定</string>
|
||||||
<string name="import_config">導入設定</string>
|
<string name="import_config">導入設定</string>
|
||||||
@@ -853,13 +913,13 @@
|
|||||||
<!-- ROM loading errors -->
|
<!-- ROM loading errors -->
|
||||||
<string name="loader_error_encrypted">您的 ROM 已加密</string>
|
<string name="loader_error_encrypted">您的 ROM 已加密</string>
|
||||||
<string name="loader_error_encrypted_roms_description"><![CDATA[請按照指南重新轉儲您的<a href=\"https://yuzu-mirror.github.io/help/quickstart/#dumping-physical-titles-game-cards\">遊戲卡</a>或<a href=\"https://yuzu-mirror.github.io/help/quickstart/#dumping-digital-titles-eshop\">數位版遊戲</a>。]]></string>
|
<string name="loader_error_encrypted_roms_description"><![CDATA[請按照指南重新轉儲您的<a href=\"https://yuzu-mirror.github.io/help/quickstart/#dumping-physical-titles-game-cards\">遊戲卡</a>或<a href=\"https://yuzu-mirror.github.io/help/quickstart/#dumping-digital-titles-eshop\">數位版遊戲</a>。]]></string>
|
||||||
<string name="loader_error_encrypted_keys_description"><![CDATA[請確保您的 <a href=\"https://yuzu-mirror.github.io/help/quickstart/#dumping-prodkeys-and-titlekeys\">prod.keys</a> 檔案已安裝,讓遊戲可以解密。]]></string>
|
<string name="loader_error_encrypted_keys_description"><![CDATA[請確保您的 <a href=\"https://yuzu-mirror.github.io/help/quickstart/#dumping-prodkeys-and-titlekeys\">prod.keys</a> 檔案已安裝,讓遊戲可以正常解密]]></string>
|
||||||
<string name="loader_error_video_core">初始化視訊核心時發生錯誤</string>
|
<string name="loader_error_video_core">初始化視訊核心時發生錯誤</string>
|
||||||
<string name="loader_error_video_core_description">這經常是因為不相容的 GPU 驅動程式造成,安裝自訂 GPU 驅動程式可能會解決此問題。</string>
|
<string name="loader_error_video_core_description">這經常是因為不相容的 GPU 驅動程式造成,安裝自訂 GPU 驅動程式可能會解決此問題。</string>
|
||||||
<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[您嘗試啟動的遊戲需要韌體才能啟動或通過遊戲主選單。請<a href=\"https://yuzu-mirror.github.io/help/quickstart\">轉儲並安裝韌體</a>,或點擊\"確定\"繼續。]]></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>
|
||||||
@@ -881,15 +941,15 @@
|
|||||||
<string name="config_write_failed">設定寫入失敗</string>
|
<string name="config_write_failed">設定寫入失敗</string>
|
||||||
<string name="config_apply_failed">套用設定失敗</string>
|
<string name="config_apply_failed">套用設定失敗</string>
|
||||||
<string name="config_already_exists_title">設定已存在</string>
|
<string name="config_already_exists_title">設定已存在</string>
|
||||||
<string name="config_already_exists_message">%1$s已存在自訂設定\n\n您要覆寫它嗎?\n\n這個動作無法復原</string>
|
<string name="config_already_exists_message">%1$s已存在自訂設定\n\n您要取代它嗎?\n\n這個動作無法復原</string>
|
||||||
<string name="config_exists_prompt">正在檢查現有設定...</string>
|
<string name="config_exists_prompt">正在檢查現有設定...</string>
|
||||||
<string name="overwrite_cancelled">覆寫已取消</string>
|
<string name="overwrite_cancelled">已取消取代該設定</string>
|
||||||
<string name="overwrite">覆寫</string>
|
<string name="overwrite">取代</string>
|
||||||
|
|
||||||
<!-- Driver strings -->
|
<!-- Driver strings -->
|
||||||
<string name="driver_not_found">未安裝所需的驅動程式: %s</string>
|
<string name="driver_not_found">未安裝所需的驅動程式: %s</string>
|
||||||
<string name="invalid_driver_file">無效的驅動程式檔案: %s</string>
|
<string name="invalid_driver_file">無效的驅動程式檔案: %s</string>
|
||||||
<string name="network_unavailable">無可用網路連線。請檢查您的網路連線並重試。</string>
|
<string name="network_unavailable">無可用網路連線。請檢查您的網路連線並重試</string>
|
||||||
<string name="driver_missing_title">需要GPU驅動程式</string>
|
<string name="driver_missing_title">需要GPU驅動程式</string>
|
||||||
<string name="driver_missing_message">這個遊戲的設定需要 \"%s\"驅動程式,而它並沒有安裝在您的裝置上\n\n要下載並安裝此驅動程式嗎?</string>
|
<string name="driver_missing_message">這個遊戲的設定需要 \"%s\"驅動程式,而它並沒有安裝在您的裝置上\n\n要下載並安裝此驅動程式嗎?</string>
|
||||||
<string name="driver_download_cancelled">驅動程式下載已取消。沒有所需的驅動程式無法啟動遊戲。</string>
|
<string name="driver_download_cancelled">驅動程式下載已取消。沒有所需的驅動程式無法啟動遊戲。</string>
|
||||||
@@ -901,7 +961,7 @@
|
|||||||
<string name="emulation_toggle_controls">切換控制</string>
|
<string name="emulation_toggle_controls">切換控制</string>
|
||||||
<string name="emulation_rel_stick_center">相對搖桿中心</string>
|
<string name="emulation_rel_stick_center">相對搖桿中心</string>
|
||||||
<string name="emulation_dpad_slide">方向鍵滑動</string>
|
<string name="emulation_dpad_slide">方向鍵滑動</string>
|
||||||
<string name="emulation_haptics">觸覺回饋技術</string>
|
<string name="emulation_haptics">觸覺回饋</string>
|
||||||
<string name="emulation_show_overlay">顯示虛擬按鍵</string>
|
<string name="emulation_show_overlay">顯示虛擬按鍵</string>
|
||||||
<string name="emulation_hide_overlay">隱藏虛擬按鍵</string>
|
<string name="emulation_hide_overlay">隱藏虛擬按鍵</string>
|
||||||
<string name="emulation_toggle_all">全部切換</string>
|
<string name="emulation_toggle_all">全部切換</string>
|
||||||
@@ -910,8 +970,9 @@
|
|||||||
<string name="emulation_control_opacity">不透明度</string>
|
<string name="emulation_control_opacity">不透明度</string>
|
||||||
<string name="emulation_touch_overlay_reset">重設虛擬按鍵</string>
|
<string name="emulation_touch_overlay_reset">重設虛擬按鍵</string>
|
||||||
<string name="emulation_touch_overlay_edit">編輯虛擬按鍵</string>
|
<string name="emulation_touch_overlay_edit">編輯虛擬按鍵</string>
|
||||||
|
<string name="emulation_snap_to_grid">對齊網格</string>
|
||||||
<string name="emulation_pause">暫停模擬</string>
|
<string name="emulation_pause">暫停模擬</string>
|
||||||
<string name="emulation_unpause">取消暫停模擬</string>
|
<string name="emulation_unpause">繼續模擬</string>
|
||||||
<string name="emulation_input_overlay">疊加層/虛擬按鍵設定</string>
|
<string name="emulation_input_overlay">疊加層/虛擬按鍵設定</string>
|
||||||
<string name="load_amiibo">導入Amiibo</string>
|
<string name="load_amiibo">導入Amiibo</string>
|
||||||
<string name="touchscreen">觸控螢幕</string>
|
<string name="touchscreen">觸控螢幕</string>
|
||||||
|
|||||||
@@ -110,7 +110,6 @@ add_library(
|
|||||||
socket_types.h
|
socket_types.h
|
||||||
sparse_large_vector.cpp
|
sparse_large_vector.cpp
|
||||||
sparse_large_vector.h
|
sparse_large_vector.h
|
||||||
spin_lock.h
|
|
||||||
stb.cpp
|
stb.cpp
|
||||||
stb.h
|
stb.h
|
||||||
steady_clock.cpp
|
steady_clock.cpp
|
||||||
|
|||||||
@@ -244,7 +244,8 @@ WallClock::WallClock(bool invariant_, u64 rdtsc_frequency_) noexcept
|
|||||||
, ns_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(NsRatio::den, rdtsc_frequency_) : 0}
|
, ns_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(NsRatio::den, rdtsc_frequency_) : 0}
|
||||||
, us_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(UsRatio::den, rdtsc_frequency_) : 0}
|
, us_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(UsRatio::den, rdtsc_frequency_) : 0}
|
||||||
, ms_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(MsRatio::den, rdtsc_frequency_) : 0}
|
, ms_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(MsRatio::den, rdtsc_frequency_) : 0}
|
||||||
, rdtsc_ns_factor{invariant_ ? GetFixedPoint64Factor(rdtsc_frequency_, NsRatio::den) : 1}
|
, rdtsc_ns_integer{invariant_ ? rdtsc_frequency_ / NsRatio::den : 1}
|
||||||
|
, rdtsc_ns_factor{invariant_ ? GetFixedPoint64Factor(rdtsc_frequency_ % NsRatio::den, NsRatio::den) : 0}
|
||||||
, cntpct_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(CNTFRQ, rdtsc_frequency_) : 0}
|
, cntpct_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(CNTFRQ, rdtsc_frequency_) : 0}
|
||||||
, gputick_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(GPUTickFreq, rdtsc_frequency_) : 0}
|
, gputick_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(GPUTickFreq, rdtsc_frequency_) : 0}
|
||||||
, invariant{invariant_}
|
, invariant{invariant_}
|
||||||
@@ -291,7 +292,7 @@ bool WallClock::IsNative() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u64 WallClock::NsToTicks(std::chrono::nanoseconds ns) const {
|
u64 WallClock::NsToTicks(std::chrono::nanoseconds ns) const {
|
||||||
return invariant ? MultiplyHigh(ns.count(), rdtsc_ns_factor) : ns.count();
|
return ns.count() * rdtsc_ns_integer + MultiplyHigh(ns.count(), rdtsc_ns_factor);
|
||||||
}
|
}
|
||||||
#elif defined(HAS_NCE)
|
#elif defined(HAS_NCE)
|
||||||
namespace {
|
namespace {
|
||||||
@@ -416,7 +417,7 @@ u64 WallClock::NsToTicks(std::chrono::nanoseconds ns) const {
|
|||||||
const WallClock g_wall_clock = [] {
|
const WallClock g_wall_clock = [] {
|
||||||
#if defined(ARCHITECTURE_x86_64)
|
#if defined(ARCHITECTURE_x86_64)
|
||||||
auto const& caps = Common::g_cpu_caps;
|
auto const& caps = Common::g_cpu_caps;
|
||||||
return WallClock(caps.invariant_tsc && caps.tsc_frequency >= std::nano::den, caps.tsc_frequency);
|
return WallClock(caps.invariant_tsc && caps.tsc_frequency > std::nano::den, caps.tsc_frequency);
|
||||||
#elif defined(HAS_NCE)
|
#elif defined(HAS_NCE)
|
||||||
return WallClock(false, 1);
|
return WallClock(false, 1);
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ public:
|
|||||||
u64 ns_rdtsc_factor;
|
u64 ns_rdtsc_factor;
|
||||||
u64 us_rdtsc_factor;
|
u64 us_rdtsc_factor;
|
||||||
u64 ms_rdtsc_factor;
|
u64 ms_rdtsc_factor;
|
||||||
|
u64 rdtsc_ns_integer;
|
||||||
u64 rdtsc_ns_factor;
|
u64 rdtsc_ns_factor;
|
||||||
u64 cntpct_rdtsc_factor;
|
u64 cntpct_rdtsc_factor;
|
||||||
u64 gputick_rdtsc_factor;
|
u64 gputick_rdtsc_factor;
|
||||||
|
|||||||
+18
-20
@@ -17,35 +17,33 @@
|
|||||||
|
|
||||||
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),
|
||||||
reinterpret_cast<LPSTR>(&err_str), 1, nullptr);
|
LPSTR(&err_str), 1, nullptr);
|
||||||
if (!res) {
|
if (res) {
|
||||||
return "(FormatMessageA failed to format error)";
|
std::string ret(err_str);
|
||||||
|
LocalFree(err_str);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
std::string ret(err_str);
|
return "(FormatMessageA failed to format error)";
|
||||||
LocalFree(err_str);
|
|
||||||
return ret;
|
|
||||||
#else
|
#else
|
||||||
char err_str[255];
|
char err_str[255];
|
||||||
#if defined(__ANDROID__) || \
|
return HandleStrerrorR(strerror_r(e, err_str, sizeof(err_str)), err_str);
|
||||||
(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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+66
-13
@@ -5,6 +5,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include "common/container/unordered_map.h"
|
#include "common/container/unordered_map.h"
|
||||||
@@ -480,28 +481,80 @@ std::string SanitizePath(std::string_view path_, DirectorySeparator directory_se
|
|||||||
[type2](char c1, char c2) { return c1 == type2 && c2 == type2; }),
|
[type2](char c1, char c2) { return c1 == type2 && c2 == type2; }),
|
||||||
path.end());
|
path.end());
|
||||||
|
|
||||||
const bool absolute = !path.empty() && path[0] == type2;
|
std::string root;
|
||||||
std::vector<std::string_view> parts;
|
std::string_view components{path};
|
||||||
|
bool drive_relative = false;
|
||||||
|
|
||||||
for (const auto part : SplitPathComponents(path))
|
#ifdef _WIN32
|
||||||
{
|
const bool network = path.size() > 1 && path[0] == type2 && path[1] == type2;
|
||||||
if (part.empty() || part == ".")
|
const bool drive =
|
||||||
continue;
|
path.size() > 1 && std::isalpha(static_cast<unsigned char>(path[0])) && path[1] == ':';
|
||||||
if (part == ".." && !parts.empty() && parts.back() != "..")
|
|
||||||
parts.pop_back();
|
if (network) {
|
||||||
else if (part != "..") parts.push_back(part);
|
root.assign(2, type2);
|
||||||
|
components.remove_prefix(2);
|
||||||
|
} else if (drive) {
|
||||||
|
root.assign(path.data(), 2);
|
||||||
|
components.remove_prefix(2);
|
||||||
|
if (!components.empty() && components.front() == type2) {
|
||||||
|
root += type2;
|
||||||
|
components.remove_prefix(1);
|
||||||
|
} else {
|
||||||
|
drive_relative = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (root.empty() && !components.empty() && components.front() == type2) {
|
||||||
|
root += type2;
|
||||||
|
components.remove_prefix(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string resolved = absolute ? std::string(1, type2) : std::string{};
|
const auto path_parts = SplitPathComponents(components);
|
||||||
for (std::size_t i = 0; i < parts.size(); ++i)
|
std::size_t root_component_count = 0;
|
||||||
{
|
#ifdef _WIN32
|
||||||
if (i != 0)
|
if (network) {
|
||||||
|
root_component_count = 2;
|
||||||
|
|
||||||
|
const auto is_unc = [](std::string_view part) {
|
||||||
|
return part.size() == 3 && (part[0] == 'U' || part[0] == 'u') &&
|
||||||
|
(part[1] == 'N' || part[1] == 'n') && (part[2] == 'C' || part[2] == 'c');
|
||||||
|
};
|
||||||
|
if (path_parts.size() >= 2 && path_parts[0] == "?" && is_unc(path_parts[1])) {
|
||||||
|
root_component_count = 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::vector<std::string_view> parts;
|
||||||
|
for (std::size_t i = 0; i < path_parts.size(); ++i) {
|
||||||
|
const auto part = path_parts[i];
|
||||||
|
if (i < root_component_count) {
|
||||||
|
parts.push_back(part);
|
||||||
|
} else if (part.empty() || part == ".") {
|
||||||
|
continue;
|
||||||
|
} else if (part == "..") {
|
||||||
|
if (parts.size() > root_component_count) {
|
||||||
|
parts.pop_back();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
parts.push_back(part);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t root_length = root.size();
|
||||||
|
std::string resolved = std::move(root);
|
||||||
|
for (std::size_t i = 0; i < parts.size(); ++i) {
|
||||||
|
if (i != 0 || (!resolved.empty() && resolved.back() != type2 && !drive_relative))
|
||||||
resolved += type2;
|
resolved += type2;
|
||||||
resolved.append(parts[i].data(), parts[i].size());
|
resolved.append(parts[i].data(), parts[i].size());
|
||||||
}
|
}
|
||||||
|
|
||||||
path = std::move(resolved);
|
path = std::move(resolved);
|
||||||
|
|
||||||
|
if (!path.empty() && path.size() == root_length) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
return std::string(RemoveTrailingSlash(path));
|
return std::string(RemoveTrailingSlash(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -347,8 +347,9 @@ enum class DirectorySeparator {
|
|||||||
// i.e. "C:\Users\Yuzu\Documents\save.bin" becomes {"C:", "Users", "Yuzu", "Documents", "save.bin" }
|
// i.e. "C:\Users\Yuzu\Documents\save.bin" becomes {"C:", "Users", "Yuzu", "Documents", "save.bin" }
|
||||||
[[nodiscard]] std::vector<std::string> SplitPathComponentsCopy(std::string_view filename);
|
[[nodiscard]] std::vector<std::string> SplitPathComponentsCopy(std::string_view filename);
|
||||||
|
|
||||||
// Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'. Makes '/' into '\\'
|
// Normalizes directory separators, removes duplicate and non-root trailing separators, and resolves
|
||||||
// depending if directory_separator is BackwardSlash or PlatformDefault and running on windows
|
// '.' and '..' components without traversing above the path root. Windows drive and UNC roots are
|
||||||
|
// preserved.
|
||||||
[[nodiscard]] std::string SanitizePath(
|
[[nodiscard]] std::string SanitizePath(
|
||||||
std::string_view path,
|
std::string_view path,
|
||||||
DirectorySeparator directory_separator = DirectorySeparator::ForwardSlash);
|
DirectorySeparator directory_separator = DirectorySeparator::ForwardSlash);
|
||||||
|
|||||||
@@ -96,15 +96,15 @@ struct PageTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Write page info atomically
|
/// Write page info atomically
|
||||||
constexpr void Store(bool marked, PageType type, u16 block, uintptr_t pointer) noexcept {
|
inline void Store(bool marked, PageType type, u16 block, uintptr_t pointer) noexcept {
|
||||||
data_raw.store(std::bit_cast<u64>(Data{marked, type, block, pointer}));
|
data_raw.store(std::bit_cast<u64>(Data{marked, type, block, pointer}));
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void MarkRasterizerCached() noexcept {
|
inline void MarkRasterizerCached() noexcept {
|
||||||
data_raw.fetch_or(0b111);
|
data_raw.fetch_or(0b111);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void MarkDebug(u64 ptr, u16 block) noexcept {
|
inline void MarkDebug(u64 ptr, u16 block) noexcept {
|
||||||
Store(true, PageType::DebugMemory, block, ptr);
|
Store(true, PageType::DebugMemory, block, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ void FreeMemoryPages(void* base, std::size_t size) noexcept;
|
|||||||
|
|
||||||
/// A large page-aligned buffer that has optimized memory usage for zero-writes.
|
/// A large page-aligned buffer that has optimized memory usage for zero-writes.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
requires std::is_trivially_copyable_v<T>
|
// MSVC doesn't regard structs with atomics as trivially copyable
|
||||||
|
// requires std::is_trivially_copyable_v<T>
|
||||||
class SparseLargeVector final {
|
class SparseLargeVector final {
|
||||||
public:
|
public:
|
||||||
constexpr SparseLargeVector() = default;
|
constexpr SparseLargeVector() = default;
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#include <intrin.h>
|
|
||||||
#elif defined(ARCHITECTURE_x86_64)
|
|
||||||
#include <xmmintrin.h>
|
|
||||||
#endif
|
|
||||||
#include <atomic>
|
|
||||||
|
|
||||||
namespace Common {
|
|
||||||
|
|
||||||
/// @brief A lock similar to mutex that forces a thread to spin wait instead calling the
|
|
||||||
/// supervisor. Should be used on short sequences of code.
|
|
||||||
struct SpinLock {
|
|
||||||
SpinLock() noexcept = default;
|
|
||||||
SpinLock(const SpinLock&) noexcept = delete;
|
|
||||||
SpinLock& operator=(const SpinLock&) noexcept = delete;
|
|
||||||
SpinLock(SpinLock&&) noexcept = delete;
|
|
||||||
SpinLock& operator=(SpinLock&&) noexcept = delete;
|
|
||||||
|
|
||||||
inline void lock() noexcept {
|
|
||||||
while (lck.test_and_set(std::memory_order_acquire)) {
|
|
||||||
#if defined(ARCHITECTURE_x86_64)
|
|
||||||
_mm_pause();
|
|
||||||
#elif defined(ARCHITECTURE_arm64) && defined(_MSC_VER)
|
|
||||||
__yield();
|
|
||||||
#elif defined(ARCHITECTURE_arm64)
|
|
||||||
asm("yield");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void unlock() noexcept {
|
|
||||||
lck.clear(std::memory_order_release);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] inline bool try_lock() noexcept {
|
|
||||||
return !lck.test_and_set(std::memory_order_acquire);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::atomic_flag lck = ATOMIC_FLAG_INIT;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Common
|
|
||||||
+2
-2
@@ -208,9 +208,9 @@ UUID UUID::MakeRandomRFC4122V4() {
|
|||||||
return uuid;
|
return uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
UUID UUID::MakeRFC4122V5(std::span<u8, 20> sha1) {
|
UUID UUID::MakeRFC4122V5(std::span<u8, 16> sha1) {
|
||||||
UUID uuid{};
|
UUID uuid{};
|
||||||
std::memcpy(&uuid.uuid, sha1.data(), sizeof(UUID));
|
std::memcpy(&uuid.uuid, sha1.data(), sha1.size());
|
||||||
uuid.uuid[8] = 0x80 | (uuid.uuid[8] & 0x3F);
|
uuid.uuid[8] = 0x80 | (uuid.uuid[8] & 0x3F);
|
||||||
uuid.uuid[6] = 0x50 | (uuid.uuid[6] & 0xF);
|
uuid.uuid[6] = 0x50 | (uuid.uuid[6] & 0xF);
|
||||||
return uuid;
|
return uuid;
|
||||||
|
|||||||
+1
-1
@@ -104,7 +104,7 @@ struct UUID {
|
|||||||
/// @returns A random UUID that is RFC 4122 Version 4 compliant.
|
/// @returns A random UUID that is RFC 4122 Version 4 compliant.
|
||||||
[[nodiscard]] static UUID MakeRandomRFC4122V4();
|
[[nodiscard]] static UUID MakeRandomRFC4122V4();
|
||||||
|
|
||||||
[[nodiscard]] static UUID MakeRFC4122V5(std::span<u8, 20> sha1);
|
[[nodiscard]] static UUID MakeRFC4122V5(std::span<u8, 16> sha1);
|
||||||
|
|
||||||
friend constexpr bool operator==(const UUID& lhs, const UUID& rhs) = default;
|
friend constexpr bool operator==(const UUID& lhs, const UUID& rhs) = default;
|
||||||
};
|
};
|
||||||
|
|||||||
+8
-23
@@ -23,8 +23,6 @@ add_library(core STATIC
|
|||||||
core_timing.h
|
core_timing.h
|
||||||
cpu_manager.cpp
|
cpu_manager.cpp
|
||||||
cpu_manager.h
|
cpu_manager.h
|
||||||
launch_params.cpp
|
|
||||||
launch_params.h
|
|
||||||
crypto/aes_util.cpp
|
crypto/aes_util.cpp
|
||||||
crypto/aes_util.h
|
crypto/aes_util.h
|
||||||
crypto/ctr_encryption_layer.cpp
|
crypto/ctr_encryption_layer.cpp
|
||||||
@@ -798,6 +796,8 @@ add_library(core STATIC
|
|||||||
hle/service/ns/application_manager_interface.h
|
hle/service/ns/application_manager_interface.h
|
||||||
hle/service/ns/application_version_interface.cpp
|
hle/service/ns/application_version_interface.cpp
|
||||||
hle/service/ns/application_version_interface.h
|
hle/service/ns/application_version_interface.h
|
||||||
|
hle/service/ns/async_result.cpp
|
||||||
|
hle/service/ns/async_result.h
|
||||||
hle/service/ns/content_management_interface.cpp
|
hle/service/ns/content_management_interface.cpp
|
||||||
hle/service/ns/content_management_interface.h
|
hle/service/ns/content_management_interface.h
|
||||||
hle/service/ns/develop_interface.cpp
|
hle/service/ns/develop_interface.cpp
|
||||||
@@ -1203,9 +1203,6 @@ endif()
|
|||||||
|
|
||||||
target_include_directories(core PRIVATE ${OPUS_INCLUDE_DIRS})
|
target_include_directories(core PRIVATE ${OPUS_INCLUDE_DIRS})
|
||||||
target_link_libraries(core PUBLIC common PRIVATE audio_core hid_core network video_core nx_tzdb tz)
|
target_link_libraries(core PUBLIC common PRIVATE audio_core hid_core network video_core nx_tzdb tz)
|
||||||
if (MSVC)
|
|
||||||
target_link_libraries(core PRIVATE getopt)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (BOOST_NO_HEADERS)
|
if (BOOST_NO_HEADERS)
|
||||||
target_link_libraries(core PUBLIC Boost::container Boost::heap Boost::asio Boost::process Boost::crc)
|
target_link_libraries(core PUBLIC Boost::container Boost::heap Boost::asio Boost::process Boost::crc)
|
||||||
@@ -1266,23 +1263,11 @@ if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64 OR ARCHITECTURE_riscv64 OR ARCHITE
|
|||||||
target_link_libraries(core PRIVATE dynarmic::dynarmic)
|
target_link_libraries(core PRIVATE dynarmic::dynarmic)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_sources(core PRIVATE hle/service/ssl/ssl_backend_openssl.cpp)
|
if (TARGET OpenSSL::SSL)
|
||||||
|
target_sources(core PRIVATE hle/service/ssl/ssl_backend_openssl.cpp)
|
||||||
target_link_libraries(core PRIVATE OpenSSL::SSL OpenSSL::Crypto)
|
target_link_libraries(core PRIVATE OpenSSL::SSL OpenSSL::Crypto)
|
||||||
|
else()
|
||||||
# TODO
|
target_sources(core PRIVATE hle/service/ssl/ssl_backend_none.cpp)
|
||||||
|
endif()
|
||||||
# elseif (APPLE)
|
|
||||||
# target_sources(core PRIVATE
|
|
||||||
# hle/service/ssl/ssl_backend_securetransport.cpp)
|
|
||||||
# target_link_libraries(core PRIVATE "-framework Security")
|
|
||||||
# elseif (WIN32)
|
|
||||||
# target_sources(core PRIVATE
|
|
||||||
# hle/service/ssl/ssl_backend_schannel.cpp)
|
|
||||||
# target_link_libraries(core PRIVATE crypt32 secur32)
|
|
||||||
# else()
|
|
||||||
# target_sources(core PRIVATE
|
|
||||||
# hle/service/ssl/ssl_backend_none.cpp)
|
|
||||||
# endif()
|
|
||||||
|
|
||||||
create_target_directory_groups(core)
|
create_target_directory_groups(core)
|
||||||
|
|||||||
@@ -22,21 +22,15 @@ DynarmicCallbacks32::DynarmicCallbacks32(ArmDynarmic32& parent, Kernel::KProcess
|
|||||||
, m_check_memory_access{m_debugger_enabled || !Settings::values.cpuopt_ignore_memory_aborts.GetValue()}
|
, m_check_memory_access{m_debugger_enabled || !Settings::values.cpuopt_ignore_memory_aborts.GetValue()}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
u8 DynarmicCallbacks32::MemoryRead8(u32 vaddr) {
|
u64 DynarmicCallbacks32::MemoryRead(u32 vaddr, size_t size) {
|
||||||
CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read);
|
CheckMemoryAccess(vaddr, size, Kernel::DebugWatchpointType::Read);
|
||||||
return m_memory.Read8(vaddr);
|
switch (size) {
|
||||||
}
|
case sizeof(u64): return m_memory.Read64(vaddr);
|
||||||
u16 DynarmicCallbacks32::MemoryRead16(u32 vaddr) {
|
case sizeof(u32): return m_memory.Read32(vaddr);
|
||||||
CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Read);
|
case sizeof(u16): return m_memory.Read16(vaddr);
|
||||||
return m_memory.Read16(vaddr);
|
case sizeof(u8): return m_memory.Read8(vaddr);
|
||||||
}
|
default: UNREACHABLE();
|
||||||
u32 DynarmicCallbacks32::MemoryRead32(u32 vaddr) {
|
}
|
||||||
CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Read);
|
|
||||||
return m_memory.Read32(vaddr);
|
|
||||||
}
|
|
||||||
u64 DynarmicCallbacks32::MemoryRead64(u32 vaddr) {
|
|
||||||
CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read);
|
|
||||||
return m_memory.Read64(vaddr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<u32> DynarmicCallbacks32::MemoryReadCode(u32 vaddr) {
|
std::optional<u32> DynarmicCallbacks32::MemoryReadCode(u32 vaddr) {
|
||||||
@@ -50,27 +44,17 @@ std::optional<u32> DynarmicCallbacks32::MemoryReadCode(u32 vaddr) {
|
|||||||
return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)];
|
return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void DynarmicCallbacks32::MemoryWrite8(u32 vaddr, u8 value) {
|
void DynarmicCallbacks32::MemoryWrite(Dynarmic::A32::VAddr vaddr, u64 value, size_t size) {
|
||||||
if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) {
|
if (CheckMemoryAccess(vaddr, size, Kernel::DebugWatchpointType::Write)) {
|
||||||
m_memory.Write8(vaddr, value);
|
switch (size) {
|
||||||
|
case sizeof(u64): return m_memory.Write64(vaddr, value);
|
||||||
|
case sizeof(u32): return m_memory.Write32(vaddr, u32(value));
|
||||||
|
case sizeof(u16): return m_memory.Write16(vaddr, u16(value));
|
||||||
|
case sizeof(u8): return m_memory.Write8(vaddr, u8(value));
|
||||||
|
default: UNREACHABLE();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void DynarmicCallbacks32::MemoryWrite16(u32 vaddr, u16 value) {
|
|
||||||
if (CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write)) {
|
|
||||||
m_memory.Write16(vaddr, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void DynarmicCallbacks32::MemoryWrite32(u32 vaddr, u32 value) {
|
|
||||||
if (CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write)) {
|
|
||||||
m_memory.Write32(vaddr, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void DynarmicCallbacks32::MemoryWrite64(u32 vaddr, u64 value) {
|
|
||||||
if (CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write)) {
|
|
||||||
m_memory.Write64(vaddr, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DynarmicCallbacks32::MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) {
|
bool DynarmicCallbacks32::MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) {
|
||||||
return CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write) &&
|
return CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write) &&
|
||||||
m_memory.WriteExclusive8(vaddr, value, expected);
|
m_memory.WriteExclusive8(vaddr, value, expected);
|
||||||
@@ -177,7 +161,7 @@ void ArmDynarmic32::MakeJit(Common::PageTable* page_table) {
|
|||||||
config.page_table = reinterpret_cast<std::array<std::uint8_t*, NumPageTableEntries>*>(
|
config.page_table = reinterpret_cast<std::array<std::uint8_t*, NumPageTableEntries>*>(
|
||||||
const_cast<Common::PageTable::PageEntryData*>(page_table->entries.data()));
|
const_cast<Common::PageTable::PageEntryData*>(page_table->entries.data()));
|
||||||
config.page_table_pointer_mask = Common::PageTable::ATTRIBUTE_MASK;
|
config.page_table_pointer_mask = Common::PageTable::ATTRIBUTE_MASK;
|
||||||
config.page_table_marked_bit = 0;
|
config.page_table_marked_bit = uint8_t(0);
|
||||||
config.absolute_offset_page_table = true;
|
config.absolute_offset_page_table = true;
|
||||||
config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
|
config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
|
||||||
config.only_detect_misalignment_via_page_table_on_page_boundary = true;
|
config.only_detect_misalignment_via_page_table_on_page_boundary = true;
|
||||||
@@ -193,7 +177,7 @@ void ArmDynarmic32::MakeJit(Common::PageTable* page_table) {
|
|||||||
Kernel::Board::Nintendo::Nx::KSystemControl::Init::GetIntendedMemorySize()) < (1ULL << 39)) {
|
Kernel::Board::Nintendo::Nx::KSystemControl::Init::GetIntendedMemorySize()) < (1ULL << 39)) {
|
||||||
// Systems like FreeBSD allocate memory really low by default, and since we pack our page table entries,
|
// Systems like FreeBSD allocate memory really low by default, and since we pack our page table entries,
|
||||||
// we have to manually sign extend when our actual pointer is negative.
|
// we have to manually sign extend when our actual pointer is negative.
|
||||||
config.page_table_sign_extension = Common::PageTable::SIGN_BIT;
|
config.page_table_sign_extension = std::uint8_t(Common::PageTable::SIGN_BIT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,18 +30,12 @@ class System;
|
|||||||
class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
|
class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
|
||||||
public:
|
public:
|
||||||
explicit DynarmicCallbacks32(ArmDynarmic32& parent, Kernel::KProcess* process);
|
explicit DynarmicCallbacks32(ArmDynarmic32& parent, Kernel::KProcess* process);
|
||||||
u8 MemoryRead8(u32 vaddr) override;
|
u64 MemoryRead(u32 vaddr, size_t size) override;
|
||||||
u16 MemoryRead16(u32 vaddr) override;
|
|
||||||
u32 MemoryRead32(u32 vaddr) override;
|
|
||||||
u64 MemoryRead64(u32 vaddr) override;
|
|
||||||
std::optional<u32> MemoryReadCode(u32 vaddr) override;
|
std::optional<u32> MemoryReadCode(u32 vaddr) override;
|
||||||
void InstructionSynchronizationBarrierRaised() override {
|
void InstructionSynchronizationBarrierRaised() override {
|
||||||
last_code_addr = u64(-1); //reset back, force refetch
|
last_code_addr = u64(-1); //reset back, force refetch
|
||||||
}
|
}
|
||||||
void MemoryWrite8(u32 vaddr, u8 value) override;
|
void MemoryWrite(Dynarmic::A32::VAddr vaddr, u64 value, size_t size) override;
|
||||||
void MemoryWrite16(u32 vaddr, u16 value) override;
|
|
||||||
void MemoryWrite32(u32 vaddr, u32 value) override;
|
|
||||||
void MemoryWrite64(u32 vaddr, u64 value) override;
|
|
||||||
bool MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) override;
|
bool MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) override;
|
||||||
bool MemoryWriteExclusive16(u32 vaddr, u16 value, u16 expected) override;
|
bool MemoryWriteExclusive16(u32 vaddr, u16 value, u16 expected) override;
|
||||||
bool MemoryWriteExclusive32(u32 vaddr, u32 value, u32 expected) override;
|
bool MemoryWriteExclusive32(u32 vaddr, u32 value, u32 expected) override;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
|
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/hle/kernel/k_process.h"
|
#include "core/hle/kernel/k_process.h"
|
||||||
|
#include "dynarmic/interface/A64/config.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
@@ -21,21 +22,15 @@ DynarmicCallbacks64::DynarmicCallbacks64(ArmDynarmic64& parent, Kernel::KProcess
|
|||||||
, m_check_memory_access{m_debugger_enabled || !Settings::values.cpuopt_ignore_memory_aborts.GetValue()}
|
, m_check_memory_access{m_debugger_enabled || !Settings::values.cpuopt_ignore_memory_aborts.GetValue()}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
u8 DynarmicCallbacks64::MemoryRead8(u64 vaddr) {
|
u64 DynarmicCallbacks64::MemoryRead(u64 vaddr, size_t size) {
|
||||||
CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read);
|
CheckMemoryAccess(vaddr, size, Kernel::DebugWatchpointType::Read);
|
||||||
return m_memory.Read8(vaddr);
|
switch (size) {
|
||||||
}
|
case sizeof(u64): return m_memory.Read64(vaddr);
|
||||||
u16 DynarmicCallbacks64::MemoryRead16(u64 vaddr) {
|
case sizeof(u32): return m_memory.Read32(vaddr);
|
||||||
CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Read);
|
case sizeof(u16): return m_memory.Read16(vaddr);
|
||||||
return m_memory.Read16(vaddr);
|
case sizeof(u8): return m_memory.Read8(vaddr);
|
||||||
}
|
default: UNREACHABLE();
|
||||||
u32 DynarmicCallbacks64::MemoryRead32(u64 vaddr) {
|
}
|
||||||
CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Read);
|
|
||||||
return m_memory.Read32(vaddr);
|
|
||||||
}
|
|
||||||
u64 DynarmicCallbacks64::MemoryRead64(u64 vaddr) {
|
|
||||||
CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read);
|
|
||||||
return m_memory.Read64(vaddr);
|
|
||||||
}
|
}
|
||||||
Dynarmic::A64::Vector DynarmicCallbacks64::MemoryRead128(u64 vaddr) {
|
Dynarmic::A64::Vector DynarmicCallbacks64::MemoryRead128(u64 vaddr) {
|
||||||
CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Read);
|
CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Read);
|
||||||
@@ -53,24 +48,15 @@ std::optional<u32> DynarmicCallbacks64::MemoryReadCode(u64 vaddr) {
|
|||||||
return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)];
|
return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void DynarmicCallbacks64::MemoryWrite8(u64 vaddr, u8 value) {
|
void DynarmicCallbacks64::MemoryWrite(Dynarmic::A64::VAddr vaddr, u64 value, std::size_t size) {
|
||||||
if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) {
|
if (CheckMemoryAccess(vaddr, size, Kernel::DebugWatchpointType::Write)) {
|
||||||
m_memory.Write8(vaddr, value);
|
switch (size) {
|
||||||
}
|
case sizeof(u64): return m_memory.Write64(vaddr, u64(value));
|
||||||
}
|
case sizeof(u32): return m_memory.Write32(vaddr, u32(value));
|
||||||
void DynarmicCallbacks64::MemoryWrite16(u64 vaddr, u16 value) {
|
case sizeof(u16): return m_memory.Write16(vaddr, u16(value));
|
||||||
if (CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write)) {
|
case sizeof(u8): return m_memory.Write8(vaddr, u8(value));
|
||||||
m_memory.Write16(vaddr, value);
|
default: UNREACHABLE();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
void DynarmicCallbacks64::MemoryWrite32(u64 vaddr, u32 value) {
|
|
||||||
if (CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write)) {
|
|
||||||
m_memory.Write32(vaddr, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void DynarmicCallbacks64::MemoryWrite64(u64 vaddr, u64 value) {
|
|
||||||
if (CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write)) {
|
|
||||||
m_memory.Write64(vaddr, value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void DynarmicCallbacks64::MemoryWrite128(u64 vaddr, Dynarmic::A64::Vector value) {
|
void DynarmicCallbacks64::MemoryWrite128(u64 vaddr, Dynarmic::A64::Vector value) {
|
||||||
@@ -216,7 +202,7 @@ void ArmDynarmic64::MakeJit(Common::PageTable* page_table, std::size_t address_s
|
|||||||
const_cast<Common::PageTable::PageEntryData*>(page_table->entries.data()));
|
const_cast<Common::PageTable::PageEntryData*>(page_table->entries.data()));
|
||||||
config.page_table_address_space_bits = std::uint32_t(address_space_bits);
|
config.page_table_address_space_bits = std::uint32_t(address_space_bits);
|
||||||
config.page_table_pointer_mask = Common::PageTable::ATTRIBUTE_MASK;
|
config.page_table_pointer_mask = Common::PageTable::ATTRIBUTE_MASK;
|
||||||
config.page_table_marked_bit = 0;
|
config.page_table_marked_bit = uint8_t(0);
|
||||||
config.silently_mirror_page_table = false;
|
config.silently_mirror_page_table = false;
|
||||||
config.absolute_offset_page_table = true;
|
config.absolute_offset_page_table = true;
|
||||||
config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
|
config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
|
||||||
@@ -235,7 +221,7 @@ void ArmDynarmic64::MakeJit(Common::PageTable* page_table, std::size_t address_s
|
|||||||
Kernel::Board::Nintendo::Nx::KSystemControl::Init::GetIntendedMemorySize()) < (1ULL << 39)) {
|
Kernel::Board::Nintendo::Nx::KSystemControl::Init::GetIntendedMemorySize()) < (1ULL << 39)) {
|
||||||
// Systems like FreeBSD allocate memory really low by default, and since we pack our page table entries,
|
// Systems like FreeBSD allocate memory really low by default, and since we pack our page table entries,
|
||||||
// we have to manually sign extend when our actual pointer is negative.
|
// we have to manually sign extend when our actual pointer is negative.
|
||||||
config.page_table_sign_extension = Common::PageTable::SIGN_BIT;
|
config.page_table_sign_extension = std::uint8_t(Common::PageTable::SIGN_BIT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include "common/hash.h"
|
#include "common/hash.h"
|
||||||
#include "core/arm/arm_interface.h"
|
#include "core/arm/arm_interface.h"
|
||||||
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
|
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
|
||||||
|
#include "dynarmic/interface/A64/config.h"
|
||||||
|
|
||||||
namespace Core::Memory {
|
namespace Core::Memory {
|
||||||
class Memory;
|
class Memory;
|
||||||
@@ -36,19 +37,13 @@ class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {
|
|||||||
public:
|
public:
|
||||||
explicit DynarmicCallbacks64(ArmDynarmic64& parent, Kernel::KProcess* process);
|
explicit DynarmicCallbacks64(ArmDynarmic64& parent, Kernel::KProcess* process);
|
||||||
|
|
||||||
u8 MemoryRead8(u64 vaddr) override;
|
u64 MemoryRead(u64 vaddr, size_t size) override;
|
||||||
u16 MemoryRead16(u64 vaddr) override;
|
|
||||||
u32 MemoryRead32(u64 vaddr) override;
|
|
||||||
u64 MemoryRead64(u64 vaddr) override;
|
|
||||||
Dynarmic::A64::Vector MemoryRead128(u64 vaddr) override;
|
Dynarmic::A64::Vector MemoryRead128(u64 vaddr) override;
|
||||||
std::optional<u32> MemoryReadCode(u64 vaddr) override;
|
std::optional<u32> MemoryReadCode(u64 vaddr) override;
|
||||||
void InstructionSynchronizationBarrierRaised() override {
|
void InstructionSynchronizationBarrierRaised() override {
|
||||||
last_code_addr = u64(-1); //reset back, force refetch
|
last_code_addr = u64(-1); //reset back, force refetch
|
||||||
}
|
}
|
||||||
void MemoryWrite8(u64 vaddr, u8 value) override;
|
void MemoryWrite(Dynarmic::A64::VAddr vaddr, u64 value, std::size_t size) override;
|
||||||
void MemoryWrite16(u64 vaddr, u16 value) override;
|
|
||||||
void MemoryWrite32(u64 vaddr, u32 value) override;
|
|
||||||
void MemoryWrite64(u64 vaddr, u64 value) override;
|
|
||||||
void MemoryWrite128(u64 vaddr, Dynarmic::A64::Vector value) override;
|
void MemoryWrite128(u64 vaddr, Dynarmic::A64::Vector value) override;
|
||||||
bool MemoryWriteExclusive8(u64 vaddr, std::uint8_t value, std::uint8_t expected) override;
|
bool MemoryWriteExclusive8(u64 vaddr, std::uint8_t value, std::uint8_t expected) override;
|
||||||
bool MemoryWriteExclusive16(u64 vaddr, std::uint16_t value, std::uint16_t expected) override;
|
bool MemoryWriteExclusive16(u64 vaddr, std::uint16_t value, std::uint16_t expected) override;
|
||||||
|
|||||||
@@ -100,8 +100,7 @@ VirtualFile PatchIPS(const VirtualFile& in, const VirtualFile& ips) {
|
|||||||
|
|
||||||
|
|
||||||
struct IPSwitchRecord {
|
struct IPSwitchRecord {
|
||||||
std::array<uint8_t, 256 - sizeof(size_t)> data;
|
std::vector<uint8_t> data;
|
||||||
size_t count;
|
|
||||||
};
|
};
|
||||||
struct IPSwitchCompiler::IPSwitchPatch {
|
struct IPSwitchCompiler::IPSwitchPatch {
|
||||||
::Common::unordered_map<u32, IPSwitchRecord> records;
|
::Common::unordered_map<u32, IPSwitchRecord> records;
|
||||||
@@ -122,22 +121,23 @@ static IPSwitchRecord EscapeStringSequences(std::string_view sv) {
|
|||||||
IPSwitchRecord r{};
|
IPSwitchRecord r{};
|
||||||
for (auto it = sv.cbegin(); it < sv.cend(); ) {
|
for (auto it = sv.cbegin(); it < sv.cend(); ) {
|
||||||
if (*it == '\\' && it + 1 < sv.cend()) {
|
if (*it == '\\' && it + 1 < sv.cend()) {
|
||||||
switch (it[1]) {
|
r.data.push_back([it]() {
|
||||||
case 'a': r.data[r.count] = '\a'; break;
|
switch (it[1]) {
|
||||||
case 'b': r.data[r.count] = '\b'; break;
|
case 'a': return '\a';
|
||||||
case 'e': r.data[r.count] = '\e'; break;
|
case 'b': return '\b';
|
||||||
case 'f': r.data[r.count] = '\f'; break;
|
case 'e': return '\e';
|
||||||
case 'n': r.data[r.count] = '\n'; break;
|
case 'f': return '\f';
|
||||||
case 'r': r.data[r.count] = '\r'; break;
|
case 'n': return '\n';
|
||||||
case 't': r.data[r.count] = '\t'; break;
|
case 'r': return '\r';
|
||||||
case 'v': r.data[r.count] = '\v'; break;
|
case 't': return '\t';
|
||||||
case '?': r.data[r.count] = '\?'; break;
|
case 'v': return '\v';
|
||||||
default: r.data[r.count] = it[1]; break;
|
case '?': return '\?';
|
||||||
}
|
default: return it[1];
|
||||||
++r.count;
|
}
|
||||||
|
}());
|
||||||
it += 2;
|
it += 2;
|
||||||
} else {
|
} else {
|
||||||
++r.count;
|
r.data.push_back(*it);
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -223,8 +223,8 @@ void IPSwitchCompiler::Parse(std::span<u8 const> bytes) {
|
|||||||
if (start <= line.cend() && end <= line.cend()) {
|
if (start <= line.cend() && end <= line.cend()) {
|
||||||
// Actually IPS wants ordering from {lsb, ..., msb} -- so LE and BE are inverted, fun!
|
// Actually IPS wants ordering from {lsb, ..., msb} -- so LE and BE are inverted, fun!
|
||||||
auto const hs = Common::HexStringToVector({start, end}, is_little_endian);
|
auto const hs = Common::HexStringToVector({start, end}, is_little_endian);
|
||||||
|
r.data.resize(hs.size());
|
||||||
std::memcpy(r.data.data(), hs.data(), hs.size());
|
std::memcpy(r.data.data(), hs.data(), hs.size());
|
||||||
r.count = hs.size();
|
|
||||||
LOG_INFO(Loader, "[H] value @ {:#08X}", offset);
|
LOG_INFO(Loader, "[H] value @ {:#08X}", offset);
|
||||||
patches.back().records.insert_or_assign(u32(offset), std::move(r));
|
patches.back().records.insert_or_assign(u32(offset), std::move(r));
|
||||||
} else {
|
} else {
|
||||||
@@ -293,7 +293,7 @@ VirtualFile IPSwitchCompiler::Apply(const VirtualFile& in) const {
|
|||||||
if (patch.enabled) {
|
if (patch.enabled) {
|
||||||
for (const auto& record : patch.records) {
|
for (const auto& record : patch.records) {
|
||||||
if (record.first < in_data.size()) {
|
if (record.first < in_data.size()) {
|
||||||
auto replace_size = record.second.count;
|
auto replace_size = record.second.data.size();
|
||||||
if (record.first + replace_size > in_data.size())
|
if (record.first + replace_size > in_data.size())
|
||||||
replace_size = in_data.size() - record.first;
|
replace_size = in_data.size() - record.first;
|
||||||
std::memcpy(in_data.data() + record.first, record.second.data.data(), replace_size);
|
std::memcpy(in_data.data() + record.first, record.second.data.data(), replace_size);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "common/assert.h"
|
||||||
#include "common/hex_util.h"
|
#include "common/hex_util.h"
|
||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
@@ -156,12 +157,15 @@ std::string GetUpdateVersionStringFromSlot(const ContentProvider* provider, u64
|
|||||||
NACP nacp{nacp_file};
|
NACP nacp{nacp_file};
|
||||||
return nacp.GetVersionString();
|
return nacp.GetVersionString();
|
||||||
}
|
}
|
||||||
|
YUZU_NO_INLINE std::optional<u64> GetParentApplicationId(const ContentProvider* provider, u64 title_id) {
|
||||||
|
return provider == nullptr ? std::nullopt : provider->GetParentApplicationId(title_id);
|
||||||
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
PatchManager::PatchManager(u64 title_id_,
|
PatchManager::PatchManager(u64 title_id_,
|
||||||
const Service::FileSystem::FileSystemController& fs_controller_,
|
const Service::FileSystem::FileSystemController& fs_controller_,
|
||||||
const ContentProvider& content_provider_)
|
const ContentProvider& content_provider_)
|
||||||
: title_id{title_id_}, fs_controller{fs_controller_}, content_provider{content_provider_} {}
|
: title_id{title_id_}, parent_title_id{GetParentApplicationId(std::addressof(content_provider_), title_id_)}, fs_controller{fs_controller_}, content_provider{content_provider_} {}
|
||||||
|
|
||||||
PatchManager::~PatchManager() = default;
|
PatchManager::~PatchManager() = default;
|
||||||
|
|
||||||
@@ -169,13 +173,35 @@ u64 PatchManager::GetTitleID() const {
|
|||||||
return title_id;
|
return title_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VirtualDir PatchManager::GetModificationLoadRoot(bool sdmc) const {
|
||||||
|
const auto get_root = [&](u64 id) {
|
||||||
|
return sdmc ? fs_controller.GetSDMCModificationLoadRoot(id) : fs_controller.GetModificationLoadRoot(id);
|
||||||
|
};
|
||||||
|
auto root = get_root(title_id);
|
||||||
|
if (!parent_title_id) {
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
std::vector<VirtualDir> roots{std::move(root), get_root(*parent_title_id)};
|
||||||
|
std::erase(roots, nullptr);
|
||||||
|
return LayeredVfsDirectory::MakeLayeredDirectory(std::move(roots));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> PatchManager::GetDisabledAddons() const {
|
||||||
|
auto disabled = Settings::values.disabled_addons[title_id];
|
||||||
|
if (parent_title_id) {
|
||||||
|
const auto& shared = Settings::values.disabled_addons[*parent_title_id];
|
||||||
|
disabled.insert(disabled.end(), shared.begin(), shared.end());
|
||||||
|
}
|
||||||
|
return disabled;
|
||||||
|
}
|
||||||
|
|
||||||
VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
|
VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
|
||||||
LOG_INFO(Loader, "Patching ExeFS for title_id={:016X}", title_id);
|
LOG_INFO(Loader, "Patching ExeFS for title_id={:016X}", title_id);
|
||||||
|
|
||||||
if (exefs == nullptr)
|
if (exefs == nullptr)
|
||||||
return exefs;
|
return exefs;
|
||||||
|
|
||||||
const auto& disabled = Settings::values.disabled_addons[title_id];
|
const auto disabled = GetDisabledAddons();
|
||||||
|
|
||||||
bool update_disabled = true;
|
bool update_disabled = true;
|
||||||
std::optional<u32> enabled_version;
|
std::optional<u32> enabled_version;
|
||||||
@@ -303,8 +329,8 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LayeredExeFS
|
// LayeredExeFS
|
||||||
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
|
const auto load_dir = GetModificationLoadRoot();
|
||||||
const auto sdmc_load_dir = fs_controller.GetSDMCModificationLoadRoot(title_id);
|
const auto sdmc_load_dir = GetModificationLoadRoot(true);
|
||||||
|
|
||||||
std::vector<VirtualDir> patch_dirs = {sdmc_load_dir};
|
std::vector<VirtualDir> patch_dirs = {sdmc_load_dir};
|
||||||
if (load_dir != nullptr) {
|
if (load_dir != nullptr) {
|
||||||
@@ -346,7 +372,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<VirtualFile> PatchManager::CollectPatches(const std::vector<VirtualDir>& patch_dirs, const std::string& build_id) const {
|
std::vector<VirtualFile> PatchManager::CollectPatches(const std::vector<VirtualDir>& patch_dirs, const std::string& build_id) const {
|
||||||
const auto& disabled = Settings::values.disabled_addons[title_id];
|
const auto disabled = GetDisabledAddons();
|
||||||
const auto nso_build_id = fmt::format("{:0<64}", build_id);
|
const auto nso_build_id = fmt::format("{:0<64}", build_id);
|
||||||
|
|
||||||
std::vector<VirtualFile> out;
|
std::vector<VirtualFile> out;
|
||||||
@@ -405,7 +431,7 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st
|
|||||||
|
|
||||||
LOG_INFO(Loader, "Patching NSO for name={}, build_id={}", name, build_id);
|
LOG_INFO(Loader, "Patching NSO for name={}, build_id={}", name, build_id);
|
||||||
|
|
||||||
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
|
const auto load_dir = GetModificationLoadRoot();
|
||||||
if (load_dir == nullptr) {
|
if (load_dir == nullptr) {
|
||||||
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
|
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
|
||||||
return nso;
|
return nso;
|
||||||
@@ -448,7 +474,7 @@ bool PatchManager::HasNSOPatch(const BuildID& build_id_, std::string_view name)
|
|||||||
|
|
||||||
LOG_INFO(Loader, "Querying NSO patch existence for build_id={}, name={}", build_id, name);
|
LOG_INFO(Loader, "Querying NSO patch existence for build_id={}, name={}", build_id, name);
|
||||||
|
|
||||||
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
|
const auto load_dir = GetModificationLoadRoot();
|
||||||
if (load_dir == nullptr) {
|
if (load_dir == nullptr) {
|
||||||
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
|
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
|
||||||
return false;
|
return false;
|
||||||
@@ -462,13 +488,13 @@ bool PatchManager::HasNSOPatch(const BuildID& build_id_, std::string_view name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(const BuildID& build_id_) const {
|
std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(const BuildID& build_id_) const {
|
||||||
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
|
const auto load_dir = GetModificationLoadRoot();
|
||||||
if (load_dir == nullptr) {
|
if (load_dir == nullptr) {
|
||||||
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
|
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& disabled = Settings::values.disabled_addons[title_id];
|
const auto disabled = GetDisabledAddons();
|
||||||
auto patch_dirs = load_dir->GetSubdirectories();
|
auto patch_dirs = load_dir->GetSubdirectories();
|
||||||
std::sort(patch_dirs.begin(), patch_dirs.end(), [](auto const& l, auto const& r) { return l->GetName() < r->GetName(); });
|
std::sort(patch_dirs.begin(), patch_dirs.end(), [](auto const& l, auto const& r) { return l->GetName() < r->GetName(); });
|
||||||
|
|
||||||
@@ -502,17 +528,16 @@ std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(const BuildI
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type,
|
void PatchManager::ApplyLayeredFS(VirtualFile& romfs, ContentRecordType type) const {
|
||||||
const Service::FileSystem::FileSystemController& fs_controller) {
|
const auto load_dir = GetModificationLoadRoot();
|
||||||
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
|
const auto sdmc_load_dir = GetModificationLoadRoot(true);
|
||||||
const auto sdmc_load_dir = fs_controller.GetSDMCModificationLoadRoot(title_id);
|
|
||||||
if ((type != ContentRecordType::Program && type != ContentRecordType::Data &&
|
if ((type != ContentRecordType::Program && type != ContentRecordType::Data &&
|
||||||
type != ContentRecordType::HtmlDocument) ||
|
type != ContentRecordType::HtmlDocument) ||
|
||||||
(load_dir == nullptr && sdmc_load_dir == nullptr)) {
|
(load_dir == nullptr && sdmc_load_dir == nullptr)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& disabled = Settings::values.disabled_addons[title_id];
|
const auto disabled = GetDisabledAddons();
|
||||||
std::vector<VirtualDir> patch_dirs = load_dir->GetSubdirectories();
|
std::vector<VirtualDir> patch_dirs = load_dir->GetSubdirectories();
|
||||||
if (std::find(disabled.cbegin(), disabled.cend(), "SDMC") == disabled.cend()) {
|
if (std::find(disabled.cbegin(), disabled.cend(), "SDMC") == disabled.cend()) {
|
||||||
patch_dirs.push_back(sdmc_load_dir);
|
patch_dirs.push_back(sdmc_load_dir);
|
||||||
@@ -591,7 +616,7 @@ VirtualFile PatchManager::PatchRomFS(const NCA* base_nca, VirtualFile base_romfs
|
|||||||
|
|
||||||
// Game Updates
|
// Game Updates
|
||||||
const auto update_tid = GetUpdateTitleID(title_id);
|
const auto update_tid = GetUpdateTitleID(title_id);
|
||||||
const auto& disabled = Settings::values.disabled_addons[title_id];
|
const auto disabled = GetDisabledAddons();
|
||||||
|
|
||||||
bool update_disabled = true;
|
bool update_disabled = true;
|
||||||
std::optional<u32> enabled_version;
|
std::optional<u32> enabled_version;
|
||||||
@@ -698,7 +723,7 @@ VirtualFile PatchManager::PatchRomFS(const NCA* base_nca, VirtualFile base_romfs
|
|||||||
|
|
||||||
// LayeredFS
|
// LayeredFS
|
||||||
if (apply_layeredfs) {
|
if (apply_layeredfs) {
|
||||||
ApplyLayeredFS(romfs, title_id, type, fs_controller);
|
ApplyLayeredFS(romfs, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
return romfs;
|
return romfs;
|
||||||
@@ -1072,15 +1097,22 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
|
|||||||
std::optional<u32> PatchManager::GetGameVersion() const {
|
std::optional<u32> PatchManager::GetGameVersion() const {
|
||||||
const auto update_tid = GetUpdateTitleID(title_id);
|
const auto update_tid = GetUpdateTitleID(title_id);
|
||||||
if (content_provider.HasEntry(update_tid, ContentRecordType::Program)) {
|
if (content_provider.HasEntry(update_tid, ContentRecordType::Program)) {
|
||||||
return content_provider.GetEntryVersion(update_tid);
|
const auto version = content_provider.GetEntryVersion(update_tid);
|
||||||
|
return version || !parent_title_id ? version : content_provider.GetEntryVersion(GetUpdateTitleID(*parent_title_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
return content_provider.GetEntryVersion(title_id);
|
const auto version = content_provider.GetEntryVersion(title_id);
|
||||||
|
return version || !parent_title_id ? version : content_provider.GetEntryVersion(*parent_title_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
PatchManager::Metadata PatchManager::GetControlMetadata() const {
|
PatchManager::Metadata PatchManager::GetControlMetadata() const {
|
||||||
const auto base_control_nca = content_provider.GetEntry(title_id, ContentRecordType::Control);
|
const auto base_control_nca = content_provider.GetEntry(title_id, ContentRecordType::Control);
|
||||||
if (base_control_nca == nullptr) {
|
if (base_control_nca == nullptr) {
|
||||||
|
if (parent_title_id) {
|
||||||
|
const auto control_id = content_provider.HasEntry(*parent_title_id, ContentRecordType::Control) ? *parent_title_id : GetUpdateTitleID(*parent_title_id);
|
||||||
|
const PatchManager parent{control_id, fs_controller, content_provider};
|
||||||
|
return parent.GetControlMetadata();
|
||||||
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -109,10 +109,14 @@ public:
|
|||||||
[[nodiscard]] static PatchManager::Metadata GetMetadataFromBaseOrUpdate(Core::System& system, u64 application_id) noexcept;
|
[[nodiscard]] static PatchManager::Metadata GetMetadataFromBaseOrUpdate(Core::System& system, u64 application_id) noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
[[nodiscard]] VirtualDir GetModificationLoadRoot(bool sdmc = false) const;
|
||||||
|
[[nodiscard]] std::vector<std::string> GetDisabledAddons() const;
|
||||||
|
void ApplyLayeredFS(VirtualFile& romfs, ContentRecordType type) const;
|
||||||
[[nodiscard]] std::vector<VirtualFile> CollectPatches(const std::vector<VirtualDir>& patch_dirs,
|
[[nodiscard]] std::vector<VirtualFile> CollectPatches(const std::vector<VirtualDir>& patch_dirs,
|
||||||
const std::string& build_id) const;
|
const std::string& build_id) const;
|
||||||
|
|
||||||
u64 title_id;
|
u64 title_id;
|
||||||
|
std::optional<u64> parent_title_id;
|
||||||
const Service::FileSystem::FileSystemController& fs_controller;
|
const Service::FileSystem::FileSystemController& fs_controller;
|
||||||
const ContentProvider& content_provider;
|
const ContentProvider& content_provider;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <limits>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
@@ -348,6 +349,22 @@ std::vector<ContentProviderEntry> ContentProvider::ListEntries() const {
|
|||||||
return ListEntriesFilter(std::nullopt, std::nullopt, std::nullopt);
|
return ListEntriesFilter(std::nullopt, std::nullopt, std::nullopt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<u64> ContentProvider::GetParentApplicationId(u64 program_id) const {
|
||||||
|
const auto application_id = GetBaseTitleID(program_id);
|
||||||
|
const auto program_index = program_id - application_id;
|
||||||
|
if (program_index == 0 || program_index > std::numeric_limits<u8>::max()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
if (!ListEntriesFilter(TitleType::Application, ContentRecordType::Meta, program_id).empty()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
if ((!ListEntriesFilter(TitleType::Application, ContentRecordType::Meta, application_id).empty() && HasEntry(program_id, ContentRecordType::Program))
|
||||||
|
|| (!ListEntriesFilter(TitleType::Update, ContentRecordType::Meta, GetUpdateTitleID(application_id)).empty() && HasEntry(GetUpdateTitleID(program_id), ContentRecordType::Program))) {
|
||||||
|
return application_id;
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
PlaceholderCache::PlaceholderCache(VirtualDir dir_) : dir(std::move(dir_)) {}
|
PlaceholderCache::PlaceholderCache(VirtualDir dir_) : dir(std::move(dir_)) {}
|
||||||
|
|
||||||
bool PlaceholderCache::Create(const NcaID& id, u64 size) const {
|
bool PlaceholderCache::Create(const NcaID& id, u64 size) const {
|
||||||
|
|||||||
@@ -100,6 +100,8 @@ public:
|
|||||||
std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {},
|
std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {},
|
||||||
std::optional<u64> title_id = {}) const = 0;
|
std::optional<u64> title_id = {}) const = 0;
|
||||||
|
|
||||||
|
[[nodiscard]] std::optional<u64> GetParentApplicationId(u64 program_id) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// A single instance of KeyManager to be used by GetEntry()
|
// A single instance of KeyManager to be used by GetEntry()
|
||||||
Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance();
|
Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance();
|
||||||
|
|||||||
@@ -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,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -47,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;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "hid_core/frontend/emulated_controller.h"
|
#include "hid_core/frontend/emulated_controller.h"
|
||||||
#include "hid_core/hid_core.h"
|
#include "hid_core/hid_core.h"
|
||||||
#include "hid_core/hid_types.h"
|
#include "hid_core/hid_types.h"
|
||||||
|
#include <array>
|
||||||
|
|
||||||
namespace Core::Frontend {
|
namespace Core::Frontend {
|
||||||
|
|
||||||
@@ -29,23 +30,39 @@ void DefaultControllerApplet::ReconfigureControllers(ReconfigureCallback callbac
|
|||||||
|
|
||||||
const std::size_t min_supported_players =
|
const std::size_t min_supported_players =
|
||||||
parameters.enable_single_mode ? 1 : parameters.min_players;
|
parameters.enable_single_mode ? 1 : parameters.min_players;
|
||||||
|
using Core::HID::NpadStyleIndex;
|
||||||
|
const std::size_t max_supported_players = parameters.enable_single_mode ? 1 : parameters.max_players;
|
||||||
|
std::size_t num_selected_players = 0;
|
||||||
|
std::array<bool, HID::HIDCore::available_controllers> keep_connected{};
|
||||||
|
|
||||||
// Disconnect Handheld first.
|
// reserve existing AND valid players before filling slots. include Handheld, but not other
|
||||||
|
for (std::size_t index = 0; index < hid_core.available_controllers - 1; ++index) {
|
||||||
|
const auto* controller = hid_core.GetEmulatedControllerByIndex(index);
|
||||||
|
if (!parameters.keep_controllers_connected || !controller->IsConnected() || num_selected_players >= max_supported_players) continue;
|
||||||
|
|
||||||
|
const auto style = controller->GetNpadStyleIndex();
|
||||||
|
keep_connected[index] =
|
||||||
|
(style == NpadStyleIndex::Fullkey && parameters.allow_pro_controller) ||
|
||||||
|
(style == NpadStyleIndex::JoyconDual && parameters.allow_dual_joycons) ||
|
||||||
|
(style == NpadStyleIndex::JoyconLeft && parameters.allow_left_joycon) ||
|
||||||
|
(style == NpadStyleIndex::JoyconRight && parameters.allow_right_joycon) ||
|
||||||
|
(style == NpadStyleIndex::Handheld && parameters.enable_single_mode && parameters.allow_handheld && !Settings::IsDockedMode()) ||
|
||||||
|
(style == NpadStyleIndex::GameCube && parameters.allow_gamecube_controller);
|
||||||
|
num_selected_players += keep_connected[index];
|
||||||
|
}
|
||||||
auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
|
auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
|
||||||
handheld->Disconnect();
|
if (!keep_connected[hid_core.available_controllers - 2]) handheld->Disconnect();
|
||||||
|
|
||||||
// Deduce the best configuration based on the input parameters.
|
// Deduce the best configuration based on the input parameters.
|
||||||
for (std::size_t index = 0; index < hid_core.available_controllers - 2; ++index) {
|
for (std::size_t index = 0; index < hid_core.available_controllers - 2; ++index) {
|
||||||
auto* controller = hid_core.GetEmulatedControllerByIndex(index);
|
auto* controller = hid_core.GetEmulatedControllerByIndex(index);
|
||||||
|
|
||||||
// First, disconnect all controllers regardless of the value of keep_controllers_connected.
|
if (keep_connected[index]) continue;
|
||||||
// This makes it easy to connect the desired controllers.
|
|
||||||
controller->Disconnect();
|
controller->Disconnect();
|
||||||
|
|
||||||
// Only connect the minimum number of required players.
|
// only add players still needed to reach the minimum
|
||||||
if (index >= min_supported_players) {
|
if (num_selected_players >= min_supported_players) continue;
|
||||||
continue;
|
++num_selected_players;
|
||||||
}
|
|
||||||
|
|
||||||
// Connect controllers based on the following priority list from highest to lowest priority:
|
// Connect controllers based on the following priority list from highest to lowest priority:
|
||||||
// Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld
|
// Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld
|
||||||
|
|||||||
@@ -465,6 +465,10 @@ void KScheduler::ScheduleImplFiber(KernelCore& kernel) {
|
|||||||
// Check if we need scheduling. If we do, then we can't complete the switch and should
|
// Check if we need scheduling. If we do, then we can't complete the switch and should
|
||||||
// retry.
|
// retry.
|
||||||
if (m_state.needs_scheduling.load(std::memory_order_seq_cst)) {
|
if (m_state.needs_scheduling.load(std::memory_order_seq_cst)) {
|
||||||
|
// Some libc++ lazily init mutex
|
||||||
|
[[maybe_unused]] auto const can_lock = highest_priority_thread->m_context_guard.try_lock();
|
||||||
|
DEBUG_ASSERT(!can_lock);
|
||||||
|
|
||||||
// Our switch failed.
|
// Our switch failed.
|
||||||
// We should unlock the thread context, and then retry.
|
// We should unlock the thread context, and then retry.
|
||||||
highest_priority_thread->m_context_guard.unlock();
|
highest_priority_thread->m_context_guard.unlock();
|
||||||
@@ -496,6 +500,10 @@ void KScheduler::Unload(KernelCore& kernel, KThread* thread) {
|
|||||||
|
|
||||||
// Check if the thread is terminated by checking the DPC flags.
|
// Check if the thread is terminated by checking the DPC flags.
|
||||||
if ((thread->GetStackParameters().dpc_flags & static_cast<u32>(DpcFlag::Terminated)) == 0) {
|
if ((thread->GetStackParameters().dpc_flags & static_cast<u32>(DpcFlag::Terminated)) == 0) {
|
||||||
|
// Some libc++ lazily init mutex
|
||||||
|
[[maybe_unused]] auto const can_lock = thread->m_context_guard.try_lock();
|
||||||
|
DEBUG_ASSERT(!can_lock);
|
||||||
|
|
||||||
// The thread isn't terminated, so we want to unlock it.
|
// The thread isn't terminated, so we want to unlock it.
|
||||||
thread->m_context_guard.unlock();
|
thread->m_context_guard.unlock();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
@@ -12,7 +12,6 @@
|
|||||||
#include "common/atomic_ops.h"
|
#include "common/atomic_ops.h"
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/spin_lock.h"
|
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
@@ -30,7 +29,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr KSlabHeapImpl() = default;
|
KSlabHeapImpl() = default;
|
||||||
|
|
||||||
void Initialize() {
|
void Initialize() {
|
||||||
ASSERT(m_head == nullptr);
|
ASSERT(m_head == nullptr);
|
||||||
@@ -68,7 +67,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::atomic<Node*> m_head{};
|
std::atomic<Node*> m_head{};
|
||||||
Common::SpinLock m_lock;
|
std::mutex m_lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace impl
|
} // namespace impl
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
#include "common/intrusive_red_black_tree.h"
|
#include "common/intrusive_red_black_tree.h"
|
||||||
#include "common/scratch_buffer.h"
|
#include "common/scratch_buffer.h"
|
||||||
#include "common/spin_lock.h"
|
|
||||||
#include "core/arm/arm_interface.h"
|
#include "core/arm/arm_interface.h"
|
||||||
#include "core/hle/kernel/k_affinity_mask.h"
|
#include "core/hle/kernel/k_affinity_mask.h"
|
||||||
#include "core/hle/kernel/k_light_lock.h"
|
#include "core/hle/kernel/k_light_lock.h"
|
||||||
@@ -920,7 +919,7 @@ private:
|
|||||||
bool m_resource_limit_release_hint{};
|
bool m_resource_limit_release_hint{};
|
||||||
bool m_is_kernel_address_key{};
|
bool m_is_kernel_address_key{};
|
||||||
StackParameters m_stack_parameters{};
|
StackParameters m_stack_parameters{};
|
||||||
Common::SpinLock m_context_guard{};
|
std::mutex m_context_guard{};
|
||||||
|
|
||||||
// For emulation
|
// For emulation
|
||||||
std::shared_ptr<Common::Fiber> m_host_context{};
|
std::shared_ptr<Common::Fiber> m_host_context{};
|
||||||
|
|||||||
@@ -23,6 +23,12 @@ constexpr std::size_t profile_username_size{32};
|
|||||||
using ProfileUsername = std::array<u8, profile_username_size>;
|
using ProfileUsername = std::array<u8, profile_username_size>;
|
||||||
using UserIDArray = std::array<Common::UUID, MAX_USERS>;
|
using UserIDArray = std::array<Common::UUID, MAX_USERS>;
|
||||||
|
|
||||||
|
// This is nn::account::Uid
|
||||||
|
struct Uid {
|
||||||
|
std::array<u8, 0x10> unk0;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(Uid) == 0x10);
|
||||||
|
|
||||||
/// Contains extra data related to a user.
|
/// Contains extra data related to a user.
|
||||||
/// TODO: RE this structure
|
/// TODO: RE this structure
|
||||||
struct UserData {
|
struct UserData {
|
||||||
|
|||||||
@@ -92,6 +92,13 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RequestFocusStateChangedNotification(Kernel::KernelCore& kernel) {
|
||||||
|
if (m_focus_state_changed_notification_enabled) {
|
||||||
|
m_has_focus_state_changed = true;
|
||||||
|
this->SignalSystemEventIfNeeded(kernel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void OnOperationAndPerformanceModeChanged(Kernel::KernelCore& kernel);
|
void OnOperationAndPerformanceModeChanged(Kernel::KernelCore& kernel);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -347,21 +347,22 @@ Result IApplicationFunctions::NotifyRunning(Out<bool> out_became_running) {
|
|||||||
|
|
||||||
Result IApplicationFunctions::GetPseudoDeviceId(Out<Common::UUID> out_pseudo_device_id) {
|
Result IApplicationFunctions::GetPseudoDeviceId(Out<Common::UUID> out_pseudo_device_id) {
|
||||||
LOG_WARNING(Service_AM, "(stubbed)");
|
LOG_WARNING(Service_AM, "(stubbed)");
|
||||||
R_UNLESS(out_pseudo_device_id, ResultUnknown);
|
R_UNLESS(out_pseudo_device_id != nullptr, ResultUnknown);
|
||||||
|
|
||||||
// This should be hashed with the device specific hash
|
// This should be hashed with the device specific hash
|
||||||
// for now this will do
|
// for now this will do
|
||||||
const auto res = FileSys::PatchManager::GetMetadataFromBaseOrUpdate(system, m_applet->program_id);
|
const auto res = FileSys::PatchManager::GetMetadataFromBaseOrUpdate(system, m_applet->program_id);
|
||||||
u8 hash[EVP_MAX_MD_SIZE];
|
R_UNLESS(res.first != nullptr, ResultUnknown);
|
||||||
|
std::array<u8, EVP_MAX_MD_SIZE> hash;
|
||||||
unsigned int hash_len = 0;
|
unsigned int hash_len = 0;
|
||||||
auto const seed = res.first->raw.seed_for_pseudo_device_id;
|
auto const seed = res.first->raw.seed_for_pseudo_device_id;
|
||||||
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
|
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
|
||||||
auto const algorithm = EVP_sha1();
|
auto const algorithm = EVP_sha1();
|
||||||
EVP_DigestInit_ex(ctx, algorithm, nullptr);
|
EVP_DigestInit_ex(ctx, algorithm, nullptr);
|
||||||
EVP_DigestUpdate(ctx, &seed, sizeof(seed));
|
EVP_DigestUpdate(ctx, &seed, sizeof(seed));
|
||||||
EVP_DigestFinal_ex(ctx, hash, &hash_len);
|
EVP_DigestFinal_ex(ctx, hash.data(), &hash_len);
|
||||||
EVP_MD_CTX_free(ctx);
|
EVP_MD_CTX_free(ctx);
|
||||||
*out_pseudo_device_id = Common::UUID::MakeRFC4122V5(std::span<u8, 20>{hash, std::size(hash)});
|
*out_pseudo_device_id = Common::UUID::MakeRFC4122V5(std::span<u8, 16>{hash.begin(), hash.begin() + 16});
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -164,14 +164,14 @@ Result ILibraryAppletAccessor::PushInData(SharedPointer<IStorage> storage) {
|
|||||||
Result ILibraryAppletAccessor::PopOutData(Out<SharedPointer<IStorage>> out_storage) {
|
Result ILibraryAppletAccessor::PopOutData(Out<SharedPointer<IStorage>> out_storage) {
|
||||||
LOG_DEBUG(Service_AM, "called");
|
LOG_DEBUG(Service_AM, "called");
|
||||||
|
|
||||||
if (auto caller_applet = m_applet->caller_applet.lock(); caller_applet) {
|
|
||||||
caller_applet->lifecycle_manager.GetSystemEvent().Signal(system.Kernel());
|
|
||||||
caller_applet->lifecycle_manager.RequestResumeNotification();
|
|
||||||
caller_applet->lifecycle_manager.GetSystemEvent().Clear(system.Kernel());
|
|
||||||
caller_applet->lifecycle_manager.UpdateRequestedFocusState();
|
|
||||||
}
|
|
||||||
|
|
||||||
R_TRY(m_broker->GetOutData().Pop(system.Kernel(), out_storage.Get()));
|
R_TRY(m_broker->GetOutData().Pop(system.Kernel(), out_storage.Get()));
|
||||||
|
if (auto caller_applet = m_applet->caller_applet.lock(); caller_applet) {
|
||||||
|
std::scoped_lock lk{caller_applet->lock};
|
||||||
|
const bool focus_state_changed = caller_applet->lifecycle_manager.UpdateRequestedFocusState();
|
||||||
|
const bool is_front_app = m_applet->frontend && caller_applet->lifecycle_manager.IsApplication();
|
||||||
|
if (focus_state_changed) caller_applet->lifecycle_manager.SignalSystemEventIfNeeded(system.Kernel());
|
||||||
|
else if (is_front_app) caller_applet->lifecycle_manager.RequestFocusStateChangedNotification(system.Kernel());
|
||||||
|
}
|
||||||
|
|
||||||
if (m_applet->applet_id == AppletId::ProfileSelect && *out_storage) {
|
if (m_applet->applet_id == AppletId::ProfileSelect && *out_storage) {
|
||||||
auto impl = (*out_storage)->GetImpl();
|
auto impl = (*out_storage)->GetImpl();
|
||||||
|
|||||||
@@ -154,6 +154,9 @@ FSP_SRV::FSP_SRV(Core::System& system_)
|
|||||||
{720, nullptr, "AbandonAccessFailure"},
|
{720, nullptr, "AbandonAccessFailure"},
|
||||||
{800, nullptr, "GetAndClearFileSystemProxyErrorInfo"},
|
{800, nullptr, "GetAndClearFileSystemProxyErrorInfo"},
|
||||||
{810, nullptr, "RegisterProgramIndexMapInfo"},
|
{810, nullptr, "RegisterProgramIndexMapInfo"},
|
||||||
|
{820, nullptr, "GetContentStorageInfoIndex"},
|
||||||
|
{830, nullptr, "EncryptStreamPlaySaveData"},
|
||||||
|
{831, nullptr, "DecryptStreamPlaySaveData"},
|
||||||
{1000, nullptr, "SetBisRootForHost"},
|
{1000, nullptr, "SetBisRootForHost"},
|
||||||
{1001, nullptr, "SetSaveDataSize"},
|
{1001, nullptr, "SetSaveDataSize"},
|
||||||
{1002, nullptr, "SetSaveDataRootPath"},
|
{1002, nullptr, "SetSaveDataRootPath"},
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
|
|||||||
{547, nullptr, "GetAllowedBluetoothLinksCount"},
|
{547, nullptr, "GetAllowedBluetoothLinksCount"},
|
||||||
{548, &IHidSystemServer::GetRegisteredDevices, "GetRegisteredDevices"},
|
{548, &IHidSystemServer::GetRegisteredDevices, "GetRegisteredDevices"},
|
||||||
{549, nullptr, "GetConnectableRegisteredDevices"},
|
{549, nullptr, "GetConnectableRegisteredDevices"},
|
||||||
{551, nullptr, "GetRegisteredDevicesForControllerSupport"}, //20.0.0+
|
{551, &IHidSystemServer::GetRegisteredDevices, "GetRegisteredDevicesForControllerSupport"}, //20.0.0+ //mocked via 548 for Diablo 3 (at least)
|
||||||
{700, nullptr, "ActivateUniquePad"},
|
{700, nullptr, "ActivateUniquePad"},
|
||||||
{702, &IHidSystemServer::AcquireUniquePadConnectionEventHandle, "AcquireUniquePadConnectionEventHandle"},
|
{702, &IHidSystemServer::AcquireUniquePadConnectionEventHandle, "AcquireUniquePadConnectionEventHandle"},
|
||||||
{703, &IHidSystemServer::GetUniquePadIds, "GetUniquePadIds"},
|
{703, &IHidSystemServer::GetUniquePadIds, "GetUniquePadIds"},
|
||||||
@@ -758,7 +758,7 @@ void IHidSystemServer::AcquireDeviceRegisteredEventForControllerSupport(HLEReque
|
|||||||
}
|
}
|
||||||
|
|
||||||
void IHidSystemServer::GetRegisteredDevices(HLERequestContext& ctx) {
|
void IHidSystemServer::GetRegisteredDevices(HLERequestContext& ctx) {
|
||||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
LOG_WARNING(Service_HID, "(STUBBED) called, command={}", ctx.GetCommand()); //548 or 551
|
||||||
|
|
||||||
struct RegisterData {
|
struct RegisterData {
|
||||||
std::array<u8, 0x68> data;
|
std::array<u8, 0x68> data;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
namespace IPC {
|
namespace IPC {
|
||||||
|
|
||||||
|
constexpr Result ResultNotSupported{ErrorModule::HIPC, 1};
|
||||||
constexpr Result ResultSessionClosed{ErrorModule::HIPC, 301};
|
constexpr Result ResultSessionClosed{ErrorModule::HIPC, 301};
|
||||||
|
|
||||||
struct ResponseBuilder {
|
struct ResponseBuilder {
|
||||||
|
|||||||
@@ -71,17 +71,14 @@ public:
|
|||||||
void InstructionSynchronizationBarrierRaised() override {
|
void InstructionSynchronizationBarrierRaised() override {
|
||||||
last_code_addr = u64(-1); //reset back, force refetch
|
last_code_addr = u64(-1); //reset back, force refetch
|
||||||
}
|
}
|
||||||
u8 MemoryRead8(u64 vaddr) override {
|
u64 MemoryRead(u64 vaddr, size_t size) override {
|
||||||
return ReadMemory<u8>(vaddr);
|
switch (size) {
|
||||||
}
|
case sizeof(u64): return ReadMemory<u64>(vaddr);
|
||||||
u16 MemoryRead16(u64 vaddr) override {
|
case sizeof(u32): return ReadMemory<u32>(vaddr);
|
||||||
return ReadMemory<u16>(vaddr);
|
case sizeof(u16): return ReadMemory<u16>(vaddr);
|
||||||
}
|
case sizeof(u8): return ReadMemory<u8>(vaddr);
|
||||||
u32 MemoryRead32(u64 vaddr) override {
|
default: UNREACHABLE();
|
||||||
return ReadMemory<u32>(vaddr);
|
}
|
||||||
}
|
|
||||||
u64 MemoryRead64(u64 vaddr) override {
|
|
||||||
return ReadMemory<u64>(vaddr);
|
|
||||||
}
|
}
|
||||||
u128 MemoryRead128(u64 vaddr) override {
|
u128 MemoryRead128(u64 vaddr) override {
|
||||||
return ReadMemory<u128>(vaddr);
|
return ReadMemory<u128>(vaddr);
|
||||||
@@ -89,22 +86,19 @@ public:
|
|||||||
std::string MemoryReadCString(u64 vaddr) {
|
std::string MemoryReadCString(u64 vaddr) {
|
||||||
std::string result{};
|
std::string result{};
|
||||||
u8 next;
|
u8 next;
|
||||||
while ((next = MemoryRead8(vaddr++)) != 0)
|
while ((next = u8(MemoryRead(vaddr++, sizeof(u8)))) != 0)
|
||||||
result += char(next);
|
result += char(next);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryWrite8(u64 vaddr, u8 value) override {
|
void MemoryWrite(u64 vaddr, u64 value, size_t size) override {
|
||||||
WriteMemory<u8>(vaddr, value);
|
switch (size) {
|
||||||
}
|
case sizeof(u64): WriteMemory<u64>(vaddr, u64(value)); break;
|
||||||
void MemoryWrite16(u64 vaddr, u16 value) override {
|
case sizeof(u32): WriteMemory<u32>(vaddr, u32(value)); break;
|
||||||
WriteMemory<u16>(vaddr, value);
|
case sizeof(u16): WriteMemory<u16>(vaddr, u16(value)); break;
|
||||||
}
|
case sizeof(u8): WriteMemory<u8>(vaddr, u8(value)); break;
|
||||||
void MemoryWrite32(u64 vaddr, u32 value) override {
|
default: UNREACHABLE();
|
||||||
WriteMemory<u32>(vaddr, value);
|
}
|
||||||
}
|
|
||||||
void MemoryWrite64(u64 vaddr, u64 value) override {
|
|
||||||
WriteMemory<u64>(vaddr, value);
|
|
||||||
}
|
}
|
||||||
void MemoryWrite128(u64 vaddr, u128 value) override {
|
void MemoryWrite128(u64 vaddr, u128 value) override {
|
||||||
WriteMemory<u128>(vaddr, value);
|
WriteMemory<u128>(vaddr, value);
|
||||||
@@ -193,14 +187,14 @@ public:
|
|||||||
// The loaded NRO file has ELF relocations that must be processed before it can run.
|
// The loaded NRO file has ELF relocations that must be processed before it can run.
|
||||||
// Normally this would be processed by RTLD, but in HLE context, we don't have
|
// Normally this would be processed by RTLD, but in HLE context, we don't have
|
||||||
// the linker available, so we have to do it ourselves.
|
// the linker available, so we have to do it ourselves.
|
||||||
const VAddr mod_offset{callbacks->MemoryRead32(4)};
|
const VAddr mod_offset{callbacks->MemoryRead(4, sizeof(u32))};
|
||||||
if (callbacks->MemoryRead32(mod_offset) != Common::MakeMagic('M', 'O', 'D', '0'))
|
if (callbacks->MemoryRead(mod_offset, sizeof(u32)) != Common::MakeMagic('M', 'O', 'D', '0'))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// For more info about dynamic entries, see the ELF ABI specification:
|
// For more info about dynamic entries, see the ELF ABI specification:
|
||||||
// https://refspecs.linuxbase.org/elf/gabi4+/ch5.dynamic.html
|
// https://refspecs.linuxbase.org/elf/gabi4+/ch5.dynamic.html
|
||||||
// https://refspecs.linuxbase.org/elf/gabi4+/ch4.reloc.html
|
// https://refspecs.linuxbase.org/elf/gabi4+/ch4.reloc.html
|
||||||
VAddr dynamic_offset{mod_offset + callbacks->MemoryRead32(mod_offset + 4)};
|
VAddr dynamic_offset{mod_offset + callbacks->MemoryRead(mod_offset + 4, sizeof(u32))};
|
||||||
VAddr rela_dyn = 0, relr_dyn = 0;
|
VAddr rela_dyn = 0, relr_dyn = 0;
|
||||||
size_t num_rela = 0, num_relr = 0;
|
size_t num_rela = 0, num_relr = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
@@ -222,8 +216,8 @@ public:
|
|||||||
for (size_t i = 0; i < num_rela; i++) {
|
for (size_t i = 0; i < num_rela; i++) {
|
||||||
const auto rela{callbacks->ReadMemory<Elf64_Rela>(rela_dyn + i * sizeof(Elf64_Rela))};
|
const auto rela{callbacks->ReadMemory<Elf64_Rela>(rela_dyn + i * sizeof(Elf64_Rela))};
|
||||||
if (Elf64RelType(rela.r_info) == ElfAArch64Relative) {
|
if (Elf64RelType(rela.r_info) == ElfAArch64Relative) {
|
||||||
const VAddr contents{callbacks->MemoryRead64(rela.r_offset)};
|
const VAddr contents{callbacks->MemoryRead(rela.r_offset, sizeof(u64))};
|
||||||
callbacks->MemoryWrite64(rela.r_offset, contents + rela.r_addend);
|
callbacks->MemoryWrite(rela.r_offset, contents + rela.r_addend, sizeof(u64));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,7 +225,7 @@ public:
|
|||||||
for (size_t i = 0; i < num_relr; i++) {
|
for (size_t i = 0; i < num_relr; i++) {
|
||||||
const auto relr = callbacks->ReadMemory<Elf64_Relr>(relr_dyn + i * sizeof(Elf64_Relr));
|
const auto relr = callbacks->ReadMemory<Elf64_Relr>(relr_dyn + i * sizeof(Elf64_Relr));
|
||||||
const auto incr = [&](VAddr where) {
|
const auto incr = [&](VAddr where) {
|
||||||
callbacks->MemoryWrite64(where, callbacks->MemoryRead64(where) + relocbase);
|
callbacks->MemoryWrite(where, callbacks->MemoryRead(where, sizeof(u64)) + relocbase, sizeof(u64));
|
||||||
};
|
};
|
||||||
if ((relr & 1) == 0) {
|
if ((relr & 1) == 0) {
|
||||||
// where pointer
|
// where pointer
|
||||||
@@ -294,7 +288,7 @@ public:
|
|||||||
if (argument_stack.size() > 8) {
|
if (argument_stack.size() > 8) {
|
||||||
const VAddr new_sp = Common::AlignDown(top_of_stack - (argument_stack.size() - 8) * sizeof(u64), STACK_ALIGN);
|
const VAddr new_sp = Common::AlignDown(top_of_stack - (argument_stack.size() - 8) * sizeof(u64), STACK_ALIGN);
|
||||||
for (size_t i = 8; i < argument_stack.size(); i++)
|
for (size_t i = 8; i < argument_stack.size(); i++)
|
||||||
callbacks->MemoryWrite64(new_sp + (i - 8) * sizeof(u64), argument_stack[i]);
|
callbacks->MemoryWrite(new_sp + (i - 8) * sizeof(u64), argument_stack[i], sizeof(u64));
|
||||||
jit->SetSP(new_sp);
|
jit->SetSP(new_sp);
|
||||||
}
|
}
|
||||||
// Reset the call state for the next invocation
|
// Reset the call state for the next invocation
|
||||||
@@ -385,17 +379,17 @@ void DynarmicCallbacks64::CallSVC(u32 swi) {
|
|||||||
|
|
||||||
if (dest < src) {
|
if (dest < src) {
|
||||||
for (size_t i = 0; i < n; i++)
|
for (size_t i = 0; i < n; i++)
|
||||||
MemoryWrite8(dest + i, MemoryRead8(src + i));
|
MemoryWrite(dest + i, u8(MemoryRead(src + i, sizeof(u8))), sizeof(u8));
|
||||||
} else {
|
} else {
|
||||||
for (size_t i = n; i > 0; i--)
|
for (size_t i = n; i > 0; i--)
|
||||||
MemoryWrite8(dest + i - 1, MemoryRead8(src + i - 1));
|
MemoryWrite(dest + i - 1, u8(MemoryRead(src + i - 1, sizeof(u8))), sizeof(u8));
|
||||||
}
|
}
|
||||||
} else if (pc == parent.helpers[size_t(HelperFn::Memset)]) {
|
} else if (pc == parent.helpers[size_t(HelperFn::Memset)]) {
|
||||||
const VAddr dest{parent.jit->GetRegister(0)};
|
const VAddr dest{parent.jit->GetRegister(0)};
|
||||||
const u64 c{parent.jit->GetRegister(1)};
|
const u64 c{parent.jit->GetRegister(1)};
|
||||||
const size_t n{parent.jit->GetRegister(2)};
|
const size_t n{parent.jit->GetRegister(2)};
|
||||||
for (size_t i = 0; i < n; i++)
|
for (size_t i = 0; i < n; i++)
|
||||||
MemoryWrite8(dest + i, u8(c));
|
MemoryWrite(dest + i, u8(c), sizeof(u8));
|
||||||
} else if (pc == parent.helpers[size_t(HelperFn::Resolve)]) {
|
} else if (pc == parent.helpers[size_t(HelperFn::Resolve)]) {
|
||||||
// X0 contains a char* for a symbol to resolve
|
// X0 contains a char* for a symbol to resolve
|
||||||
const auto name{MemoryReadCString(parent.jit->GetRegister(0))};
|
const auto name{MemoryReadCString(parent.jit->GetRegister(0))};
|
||||||
@@ -422,7 +416,7 @@ void DynarmicCallbacks64::CallSVC(u32 swi) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DynarmicCallbacks64::ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) {
|
void DynarmicCallbacks64::ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) {
|
||||||
auto const inst = MemoryRead32(pc);
|
auto const inst = MemoryRead(pc, sizeof(u32));
|
||||||
LOG_CRITICAL(Service_JIT, "{} PC @ {:08x}, data = {:08x}", exception, pc, inst);
|
LOG_CRITICAL(Service_JIT, "{} PC @ {:08x}, data = {:08x}", exception, pc, inst);
|
||||||
parent.jit->HaltExecution();
|
parent.jit->HaltExecution();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ public:
|
|||||||
{22, &IUser::GetApplicationAreaSize, "GetApplicationAreaSize"},
|
{22, &IUser::GetApplicationAreaSize, "GetApplicationAreaSize"},
|
||||||
{23, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
|
{23, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
|
||||||
{24, &IUser::RecreateApplicationArea, "RecreateApplicationArea"},
|
{24, &IUser::RecreateApplicationArea, "RecreateApplicationArea"},
|
||||||
|
{25, &IUser::StartDetection, "StartDetectionWithFilter"},
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
@@ -74,6 +75,7 @@ public:
|
|||||||
{20, &ISystem::GetDeviceState, "GetDeviceState"},
|
{20, &ISystem::GetDeviceState, "GetDeviceState"},
|
||||||
{21, &ISystem::GetNpadId, "GetNpadId"},
|
{21, &ISystem::GetNpadId, "GetNpadId"},
|
||||||
{23, &ISystem::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
|
{23, &ISystem::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
|
||||||
|
{25, &ISystem::StartDetection, "StartDetectionWithFilter"},
|
||||||
{100, &ISystem::Format, "Format"},
|
{100, &ISystem::Format, "Format"},
|
||||||
{101, &ISystem::GetAdminInfo, "GetAdminInfo"},
|
{101, &ISystem::GetAdminInfo, "GetAdminInfo"},
|
||||||
{102, &ISystem::GetRegisterInfoPrivate, "GetRegisterInfoPrivate"},
|
{102, &ISystem::GetRegisterInfoPrivate, "GetRegisterInfoPrivate"},
|
||||||
@@ -118,6 +120,7 @@ public:
|
|||||||
{22, &IDebug::GetApplicationAreaSize, "GetApplicationAreaSize"},
|
{22, &IDebug::GetApplicationAreaSize, "GetApplicationAreaSize"},
|
||||||
{23, &IDebug::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
|
{23, &IDebug::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
|
||||||
{24, &IDebug::RecreateApplicationArea, "RecreateApplicationArea"},
|
{24, &IDebug::RecreateApplicationArea, "RecreateApplicationArea"},
|
||||||
|
{25, &IDebug::StartDetection, "StartDetectionWithFilter"},
|
||||||
{100, &IDebug::Format, "Format"},
|
{100, &IDebug::Format, "Format"},
|
||||||
{101, &IDebug::GetAdminInfo, "GetAdminInfo"},
|
{101, &IDebug::GetAdminInfo, "GetAdminInfo"},
|
||||||
{102, &IDebug::GetRegisterInfoPrivate, "GetRegisterInfoPrivate"},
|
{102, &IDebug::GetRegisterInfoPrivate, "GetRegisterInfoPrivate"},
|
||||||
|
|||||||
@@ -6,10 +6,16 @@
|
|||||||
|
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
#include "core/hle/kernel/k_client_session.h"
|
||||||
|
#include "core/hle/result.h"
|
||||||
|
#include "core/hle/service/acc/profile_manager.h"
|
||||||
|
#include "core/hle/service/cmif_types.h"
|
||||||
|
#include "core/hle/service/cmif_serialization.h"
|
||||||
#include "core/hle/service/ipc_helpers.h"
|
#include "core/hle/service/ipc_helpers.h"
|
||||||
#include "core/hle/service/ngc/ngc.h"
|
#include "core/hle/service/ngc/ngc.h"
|
||||||
#include "core/hle/service/server_manager.h"
|
#include "core/hle/service/server_manager.h"
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
|
#include "frontend_common/firmware_manager.h"
|
||||||
|
|
||||||
namespace Service::NGC {
|
namespace Service::NGC {
|
||||||
|
|
||||||
@@ -166,12 +172,123 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SaveDataHandle {
|
||||||
|
u64 unk0;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(SaveDataHandle) == 0x08);
|
||||||
|
|
||||||
|
class IUserShimScopedObject final : public ServiceFramework<IUserShimScopedObject> {
|
||||||
|
public:
|
||||||
|
explicit IUserShimScopedObject(Core::System& system_) : ServiceFramework(system_, "IUserShimScopedObject") {
|
||||||
|
// clang-format off
|
||||||
|
static const FunctionInfo functions[] = {
|
||||||
|
{450, nullptr, "InitializeForSaveData"},
|
||||||
|
{451, nullptr, "FinalizeForSaveData"},
|
||||||
|
{452, D<&IUserShimScopedObject::OpenSaveData>, "OpenSaveData"},
|
||||||
|
{453, nullptr, "CloseSaveData"},
|
||||||
|
{454, D<&IUserShimScopedObject::ReadSaveSlot>, "ReadSaveSlot"},
|
||||||
|
{455, D<&IUserShimScopedObject::WriteSaveSlot>, "WriteSaveSlot"},
|
||||||
|
{456, nullptr, "FlushSaveSlot"},
|
||||||
|
{457, nullptr, "CommitSaveData"},
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
RegisterHandlers(functions);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result OpenSaveData(Account::Uid unk0, Out<SaveDataHandle> unk1) {
|
||||||
|
LOG_WARNING(Service_NGC, "stubbed");
|
||||||
|
R_THROW(IPC::ResultNotSupported);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ReadSaveSlot(s32 offset, SaveDataHandle handle, OutBuffer<BufferAttr_HipcAutoSelect> out_data, Out<u32> out_size) {
|
||||||
|
LOG_WARNING(Service_NGC, "stubbed");
|
||||||
|
R_THROW(IPC::ResultNotSupported);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result WriteSaveSlot(s32 offset, SaveDataHandle handle, InBuffer<BufferAttr_HipcAutoSelect> out_data) {
|
||||||
|
LOG_WARNING(Service_NGC, "stubbed");
|
||||||
|
// to implement
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class IUserService final : public ServiceFramework<IUserService> {
|
||||||
|
public:
|
||||||
|
explicit IUserService(Core::System& system_) : ServiceFramework(system_, "stpl:u") {
|
||||||
|
// clang-format off
|
||||||
|
static const FunctionInfo functions[] = {
|
||||||
|
{0 , D<&IUserService::Cmd0>, "Cmd0"},
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
RegisterHandlers(functions);
|
||||||
|
}
|
||||||
|
Result Cmd0(u32 unk0, OutInterface<IUserShimScopedObject> out_interface) {
|
||||||
|
LOG_WARNING(Service_NGC, "stubbed");
|
||||||
|
*out_interface = std::make_shared<IUserShimScopedObject>(system);
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ISystemShimScopedObject final : public ServiceFramework<ISystemShimScopedObject> {
|
||||||
|
public:
|
||||||
|
explicit ISystemShimScopedObject(Core::System& system_) : ServiceFramework(system_, "ISystemShimScopedObject") {
|
||||||
|
// clang-format off
|
||||||
|
static const FunctionInfo functions[] = {
|
||||||
|
{106, nullptr, "Cmd106"},
|
||||||
|
{107, nullptr, "Cmd107"},
|
||||||
|
{108, D<&ISystemShimScopedObject::Cmd108>, "Cmd108"},
|
||||||
|
{207, nullptr, "Cmd207"},
|
||||||
|
{208, D<&ISystemShimScopedObject::Cmd208>, "Cmd208"},
|
||||||
|
{209, nullptr, "Cmd209"},
|
||||||
|
{210, nullptr, "Cmd210"},
|
||||||
|
{211, nullptr, "Cmd211"},
|
||||||
|
{212, nullptr, "Cmd212"},
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
RegisterHandlers(functions);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Cmd108() {
|
||||||
|
LOG_WARNING(Service_NGC, "stubbed");
|
||||||
|
R_THROW(IPC::ResultNotSupported);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Cmd208(Out<std::array<u8, 0x20>> unk0) {
|
||||||
|
LOG_WARNING(Service_NGC, "stubbed");
|
||||||
|
R_THROW(IPC::ResultNotSupported);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ISystemService final : public ServiceFramework<ISystemService> {
|
||||||
|
public:
|
||||||
|
explicit ISystemService(Core::System& system_) : ServiceFramework(system_, "stpl:sys") {
|
||||||
|
// clang-format off
|
||||||
|
static const FunctionInfo functions[] = {
|
||||||
|
{0 , D<&ISystemService::Cmd0>, "Cmd0"},
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
RegisterHandlers(functions);
|
||||||
|
}
|
||||||
|
Result Cmd0(OutInterface<ISystemShimScopedObject> out_interface) {
|
||||||
|
LOG_WARNING(Service_NGC, "stubbed");
|
||||||
|
*out_interface = std::make_shared<ISystemShimScopedObject>(system);
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void LoopProcess(Core::System& system) {
|
void LoopProcess(Core::System& system) {
|
||||||
auto server_manager = std::make_unique<ServerManager>(system);
|
auto server_manager = std::make_unique<ServerManager>(system);
|
||||||
|
|
||||||
server_manager->RegisterNamedService("ngct:u", std::make_shared<IService>(system), 4);
|
server_manager->RegisterNamedService("ngct:u", std::make_shared<IService>(system), 4);
|
||||||
server_manager->RegisterNamedService("ngct:s", std::make_shared<IServiceWithManagementApi>(system), 4);
|
server_manager->RegisterNamedService("ngct:s", std::make_shared<IServiceWithManagementApi>(system), 4);
|
||||||
server_manager->RegisterNamedService("ngc:u", std::make_shared<NgcServiceImpl>(system), 4);
|
server_manager->RegisterNamedService("ngc:u", std::make_shared<NgcServiceImpl>(system), 4);
|
||||||
|
|
||||||
|
// +23.0.0
|
||||||
|
if (FirmwareManager::GetFirmwareVersion(system).first.major >= 23) {
|
||||||
|
server_manager->RegisterNamedService("stpl:u", std::make_shared<IUserService>(system), 4);
|
||||||
|
server_manager->RegisterNamedService("stpl:sys", std::make_shared<ISystemService>(system), 4);
|
||||||
|
}
|
||||||
|
|
||||||
ServerManager::RunServer(std::move(server_manager));
|
ServerManager::RunServer(std::move(server_manager));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -228,9 +228,9 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
|
|||||||
{930, nullptr, "Unknown930"}, //20.0.0+
|
{930, nullptr, "Unknown930"}, //20.0.0+
|
||||||
{931, nullptr, "Unknown931"}, //20.0.0+
|
{931, nullptr, "Unknown931"}, //20.0.0+
|
||||||
{933, nullptr, "Unknown933"}, //20.0.0+
|
{933, nullptr, "Unknown933"}, //20.0.0+
|
||||||
{934, nullptr, "Unknown934"}, //20.0.0+
|
{934, nullptr, "Unknown934"}, //21.0.0+
|
||||||
{935, nullptr, "Unknown935"}, //20.0.0+
|
{935, nullptr, "Unknown935"}, //21.0.0+
|
||||||
{936, nullptr, "Unknown936"}, //20.0.0+
|
{936, D<&IApplicationManagerInterface::Unknown936>, "Unknown936"}, //21.0.0+
|
||||||
{1000, nullptr, "RequestVerifyApplicationDeprecated"},
|
{1000, nullptr, "RequestVerifyApplicationDeprecated"},
|
||||||
{1001, nullptr, "CorruptApplicationForDebug"},
|
{1001, nullptr, "CorruptApplicationForDebug"},
|
||||||
{1002, nullptr, "RequestVerifyAddOnContentsRights"},
|
{1002, nullptr, "RequestVerifyAddOnContentsRights"},
|
||||||
@@ -422,7 +422,7 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
|
|||||||
{4039, nullptr, "Unknown4039"}, //20.0.0+
|
{4039, nullptr, "Unknown4039"}, //20.0.0+
|
||||||
{4040, nullptr, "Unknown4040"}, //20.0.0+
|
{4040, nullptr, "Unknown4040"}, //20.0.0+
|
||||||
{4041, nullptr, "Unknown4041"}, //20.0.0+
|
{4041, nullptr, "Unknown4041"}, //20.0.0+
|
||||||
{4042, nullptr, "Unknown4042"}, //20.0.0+
|
{4042, D<&IApplicationManagerInterface::Unknown4042>, "Unknown4042"}, //20.0.0+
|
||||||
{4043, nullptr, "Unknown4043"}, //20.0.0+
|
{4043, nullptr, "Unknown4043"}, //20.0.0+
|
||||||
{4044, nullptr, "Unknown4044"}, //20.0.0+
|
{4044, nullptr, "Unknown4044"}, //20.0.0+
|
||||||
{4045, nullptr, "Unknown4045"}, //20.0.0+
|
{4045, nullptr, "Unknown4045"}, //20.0.0+
|
||||||
@@ -476,6 +476,7 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
|
|||||||
{4096, nullptr, "Unknown4096"}, //20.0.0+
|
{4096, nullptr, "Unknown4096"}, //20.0.0+
|
||||||
{4097, nullptr, "Unknown4097"}, //20.0.0+
|
{4097, nullptr, "Unknown4097"}, //20.0.0+
|
||||||
{4099, nullptr, "Unknown4099"}, //21.0.0+
|
{4099, nullptr, "Unknown4099"}, //21.0.0+
|
||||||
|
{4105, D<&IApplicationManagerInterface::Unknown4105>, "Unknown4105"}, //23.0.0+
|
||||||
{5000, nullptr, "Unknown5000"}, //18.0.0+
|
{5000, nullptr, "Unknown5000"}, //18.0.0+
|
||||||
{5001, nullptr, "Unknown5001"}, //18.0.0+
|
{5001, nullptr, "Unknown5001"}, //18.0.0+
|
||||||
{9999, nullptr, "GetApplicationCertificate"}, //10.0.0-10.2.0
|
{9999, nullptr, "GetApplicationCertificate"}, //10.0.0-10.2.0
|
||||||
@@ -638,6 +639,12 @@ Result IApplicationManagerInterface::IsGameCardApplicationRunning(Out<bool> out_
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result IApplicationManagerInterface::Unknown936(Out<u64> out_result) {
|
||||||
|
LOG_WARNING(Service_NS, "(STUBBED) called.");
|
||||||
|
*out_result = 0;
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
Result IApplicationManagerInterface::IsAnyApplicationEntityInstalled(
|
Result IApplicationManagerInterface::IsAnyApplicationEntityInstalled(
|
||||||
Out<bool> out_is_any_application_entity_installed) {
|
Out<bool> out_is_any_application_entity_installed) {
|
||||||
LOG_WARNING(Service_NS, "(STUBBED) called");
|
LOG_WARNING(Service_NS, "(STUBBED) called");
|
||||||
@@ -861,11 +868,25 @@ Result IApplicationManagerInterface::Unknown4023(Out<u64> out_result) {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result IApplicationManagerInterface::Unknown4042(OutInterface<IAsyncResult> out_interface,
|
||||||
|
OutCopyHandle<Kernel::KReadableEvent> out_event,
|
||||||
|
u64 arg1, u64 arg2) {
|
||||||
|
LOG_WARNING(Service_NS, "(STUBBED) called, arg1={:016X}, arg2={:016X}", arg1, arg2);
|
||||||
|
*out_event = unknown_event.GetHandle();
|
||||||
|
*out_interface = std::make_shared<IAsyncResult>(system, &unknown_event);
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
Result IApplicationManagerInterface::Unknown4053() {
|
Result IApplicationManagerInterface::Unknown4053() {
|
||||||
LOG_WARNING(Service_NS, "(STUBBED) called.");
|
LOG_WARNING(Service_NS, "(STUBBED) called.");
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result IApplicationManagerInterface::Unknown4105() {
|
||||||
|
LOG_WARNING(Service_NS, "(STUBBED) called.");
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
void IApplicationManagerInterface::PushApplicationRecord(HLERequestContext& ctx) {
|
void IApplicationManagerInterface::PushApplicationRecord(HLERequestContext& ctx) {
|
||||||
const auto record = ctx.ReadBuffer();
|
const auto record = ctx.ReadBuffer();
|
||||||
u64 application_id{};
|
u64 application_id{};
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "core/hle/service/cmif_types.h"
|
#include "core/hle/service/cmif_types.h"
|
||||||
|
#include "core/hle/service/ns/async_result.h"
|
||||||
#include "core/hle/service/ns/language.h"
|
#include "core/hle/service/ns/language.h"
|
||||||
#include "core/hle/service/ns/ns_types.h"
|
#include "core/hle/service/ns/ns_types.h"
|
||||||
#include "core/hle/service/os/event.h"
|
#include "core/hle/service/os/event.h"
|
||||||
@@ -34,6 +35,7 @@ public:
|
|||||||
Result GetGameCardMountFailureEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
Result GetGameCardMountFailureEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||||
Result GetGameCardWakenReadyEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
Result GetGameCardWakenReadyEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||||
Result IsGameCardApplicationRunning(Out<bool> out_is_running);
|
Result IsGameCardApplicationRunning(Out<bool> out_is_running);
|
||||||
|
Result Unknown936(Out<u64> out_result);
|
||||||
Result IsAnyApplicationEntityInstalled(Out<bool> out_is_any_application_entity_installed);
|
Result IsAnyApplicationEntityInstalled(Out<bool> out_is_any_application_entity_installed);
|
||||||
Result GetApplicationViewDeprecated(
|
Result GetApplicationViewDeprecated(
|
||||||
OutArray<ApplicationViewV19, BufferAttr_HipcMapAlias> out_application_views,
|
OutArray<ApplicationViewV19, BufferAttr_HipcMapAlias> out_application_views,
|
||||||
@@ -71,7 +73,11 @@ public:
|
|||||||
InBuffer<BufferAttr_HipcMapAlias> logo_path_buffer);
|
InBuffer<BufferAttr_HipcMapAlias> logo_path_buffer);
|
||||||
Result Unknown4022(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
Result Unknown4022(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||||
Result Unknown4023(Out<u64> out_result);
|
Result Unknown4023(Out<u64> out_result);
|
||||||
|
Result Unknown4042(OutInterface<IAsyncResult> out_interface,
|
||||||
|
OutCopyHandle<Kernel::KReadableEvent> out_event,
|
||||||
|
u64 arg1, u64 arg2);
|
||||||
Result Unknown4053();
|
Result Unknown4053();
|
||||||
|
Result Unknown4105();
|
||||||
|
|
||||||
Result RequestDownloadApplicationControlDataInBackground(u64 control_source,
|
Result RequestDownloadApplicationControlDataInBackground(u64 control_source,
|
||||||
u64 application_id);
|
u64 application_id);
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "core/hle/service/cmif_serialization.h"
|
||||||
|
#include "core/hle/service/ns/async_result.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
namespace Service::NS {
|
||||||
|
|
||||||
|
IAsyncResult::IAsyncResult(Core::System& system_, Service::Event* event_)
|
||||||
|
: ServiceFramework{system_, "nn::ns::detail::IAsyncResult"}, event{event_} {
|
||||||
|
// clang-format off
|
||||||
|
static const FunctionInfo functions[] = {
|
||||||
|
{0, nullptr, "Get"},
|
||||||
|
{1, D<&IAsyncResult::Cancel>, "Cancel"},
|
||||||
|
{2, nullptr, "GetErrorContext"}, // 4.0.0+
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
RegisterHandlers(functions);
|
||||||
|
}
|
||||||
|
|
||||||
|
IAsyncResult::~IAsyncResult() = default;
|
||||||
|
|
||||||
|
Result IAsyncResult::Cancel() {
|
||||||
|
LOG_DEBUG(Service_NS, "called");
|
||||||
|
if (event != nullptr) {
|
||||||
|
event->Signal(system.Kernel());
|
||||||
|
}
|
||||||
|
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::NS
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
|
namespace Service::NS {
|
||||||
|
|
||||||
|
class IAsyncResult final : public ServiceFramework<IAsyncResult> {
|
||||||
|
public:
|
||||||
|
explicit IAsyncResult(Core::System& system_, Service::Event* event_);
|
||||||
|
~IAsyncResult() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Result Cancel();
|
||||||
|
|
||||||
|
Service::Event* event{};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::NS
|
||||||
@@ -142,7 +142,7 @@ IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterfa
|
|||||||
{10, &IReadOnlyApplicationControlDataInterface::ListApplicationIcon, "ListApplicationIcon"},
|
{10, &IReadOnlyApplicationControlDataInterface::ListApplicationIcon, "ListApplicationIcon"},
|
||||||
{13, &IReadOnlyApplicationControlDataInterface::ListApplicationTitle, "ListApplicationTitle"},
|
{13, &IReadOnlyApplicationControlDataInterface::ListApplicationTitle, "ListApplicationTitle"},
|
||||||
{19, D<&IReadOnlyApplicationControlDataInterface::GetApplicationControlData3>, "GetApplicationControlData"},
|
{19, D<&IReadOnlyApplicationControlDataInterface::GetApplicationControlData3>, "GetApplicationControlData"},
|
||||||
{23, D<&IReadOnlyApplicationControlDataInterface::GetApplicationControlData3>, "GetApplicationControlData"},
|
{23, D<&IReadOnlyApplicationControlDataInterface::GetApplicationControlData3>, "GetApplicationControlData"}, //23.0.0+
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
@@ -311,27 +311,30 @@ void IReadOnlyApplicationControlDataInterface::ListApplicationIcon(HLERequestCon
|
|||||||
// u64 - app count
|
// u64 - app count
|
||||||
memory.WriteBlock(t_mem_address + out_length, &app_count, sizeof(u64));
|
memory.WriteBlock(t_mem_address + out_length, &app_count, sizeof(u64));
|
||||||
out_length += sizeof(u64);
|
out_length += sizeof(u64);
|
||||||
|
ASSERT(out_length <= t_mem->GetSize());
|
||||||
// [list of u64] - size of icons
|
// [list of u64] - size of icons
|
||||||
for (size_t i = 0; i < app_count; ++i) {
|
for (size_t i = 0; i < app_count; ++i) {
|
||||||
const u64 app_id = app_ids_buffer[i];
|
const u64 app_id = app_ids_buffer[i];
|
||||||
const FileSys::PatchManager pm{app_id, system.GetFileSystemController(), system.GetContentProvider()};
|
const FileSys::PatchManager pm{app_id, system.GetFileSystemController(), system.GetContentProvider()};
|
||||||
const auto control = pm.GetControlMetadata();
|
if (const auto control = pm.GetControlMetadata(); control.second) {
|
||||||
u64 full_size = control.second->GetSize();
|
u64 full_size = control.second->GetSize();
|
||||||
memory.WriteBlock(t_mem_address + out_length, &full_size, sizeof(u64));
|
memory.WriteBlock(t_mem_address + out_length, &full_size, sizeof(u64));
|
||||||
|
}
|
||||||
out_length += sizeof(u64);
|
out_length += sizeof(u64);
|
||||||
|
ASSERT(out_length <= t_mem->GetSize());
|
||||||
}
|
}
|
||||||
// [list of raw icon data]
|
// [list of raw icon data]
|
||||||
std::vector<u8> full_icon_data;
|
|
||||||
for (size_t i = 0; i < app_count; ++i) {
|
for (size_t i = 0; i < app_count; ++i) {
|
||||||
const u64 app_id = app_ids_buffer[i];
|
const u64 app_id = app_ids_buffer[i];
|
||||||
const FileSys::PatchManager pm{app_id, system.GetFileSystemController(), system.GetContentProvider()};
|
const FileSys::PatchManager pm{app_id, system.GetFileSystemController(), system.GetContentProvider()};
|
||||||
const auto control = pm.GetControlMetadata();
|
if (const auto control = pm.GetControlMetadata(); control.second) {
|
||||||
auto const full_size = control.second->GetSize();
|
if (auto const full_size = control.second->GetSize(); full_size > 0) {
|
||||||
if (full_size > 0) {
|
std::vector<u8> full_icon_data(full_size);
|
||||||
full_icon_data.resize(full_size);
|
control.second->Read(full_icon_data.data(), full_size, 0);
|
||||||
control.second->Read(full_icon_data.data(), full_size, 0);
|
memory.WriteBlock(t_mem_address + out_length, full_icon_data.data(), full_size);
|
||||||
memory.WriteBlock(t_mem_address + out_length, full_icon_data.data(), full_size);
|
out_length += full_size;
|
||||||
out_length += full_size;
|
ASSERT(out_length <= t_mem->GetSize());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -345,6 +348,12 @@ void IReadOnlyApplicationControlDataInterface::ListApplicationIcon(HLERequestCon
|
|||||||
void IReadOnlyApplicationControlDataInterface::ListApplicationTitle(HLERequestContext& ctx) {
|
void IReadOnlyApplicationControlDataInterface::ListApplicationTitle(HLERequestContext& ctx) {
|
||||||
const auto app_ids_buffer = ctx.ReadBuffer();
|
const auto app_ids_buffer = ctx.ReadBuffer();
|
||||||
const size_t app_count = app_ids_buffer.size() / sizeof(u64);
|
const size_t app_count = app_ids_buffer.size() / sizeof(u64);
|
||||||
|
|
||||||
|
std::vector<u64> application_ids(app_count);
|
||||||
|
if (app_count > 0) {
|
||||||
|
std::memcpy(application_ids.data(), app_ids_buffer.data(), app_count * sizeof(u64));
|
||||||
|
}
|
||||||
|
|
||||||
auto t_mem_obj = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(ctx.GetCopyHandle(0));
|
auto t_mem_obj = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(ctx.GetCopyHandle(0));
|
||||||
auto* t_mem = t_mem_obj.GetPointerUnsafe();
|
auto* t_mem = t_mem_obj.GetPointerUnsafe();
|
||||||
constexpr size_t title_entry_size = sizeof(FileSys::LanguageEntry);
|
constexpr size_t title_entry_size = sizeof(FileSys::LanguageEntry);
|
||||||
@@ -354,8 +363,9 @@ void IReadOnlyApplicationControlDataInterface::ListApplicationTitle(HLERequestCo
|
|||||||
auto& memory = system.ApplicationMemory();
|
auto& memory = system.ApplicationMemory();
|
||||||
const auto t_mem_address = t_mem->GetSourceAddress();
|
const auto t_mem_address = t_mem->GetSourceAddress();
|
||||||
for (size_t i = 0; i < app_count; ++i) {
|
for (size_t i = 0; i < app_count; ++i) {
|
||||||
const u64 app_id = app_ids_buffer[i];
|
const u64 app_id = application_ids[i];
|
||||||
const FileSys::PatchManager pm{app_id, system.GetFileSystemController(), system.GetContentProvider()};
|
const FileSys::PatchManager pm{app_id, system.GetFileSystemController(),
|
||||||
|
system.GetContentProvider()};
|
||||||
const auto control = pm.GetControlMetadata();
|
const auto control = pm.GetControlMetadata();
|
||||||
FileSys::LanguageEntry entry{};
|
FileSys::LanguageEntry entry{};
|
||||||
if (control.first != nullptr) {
|
if (control.first != nullptr) {
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ ITransferTaskListController::ITransferTaskListController(Core::System& system_)
|
|||||||
{18, nullptr, "ListTransferTaskInfo"},
|
{18, nullptr, "ListTransferTaskInfo"},
|
||||||
{19, nullptr, "DeleteTransferTask"},
|
{19, nullptr, "DeleteTransferTask"},
|
||||||
{20, nullptr, "RaiseTransferTaskPriority"},
|
{20, nullptr, "RaiseTransferTaskPriority"},
|
||||||
{21, nullptr, "GetTransferTaskProgress"},
|
{21, D<&ITransferTaskListController::GetTransferTaskProgress>, "GetTransferTaskProgress"}, //10.1.0+
|
||||||
{22, nullptr, "GetTransferTaskLastResult"},
|
{22, nullptr, "GetTransferTaskLastResult"},
|
||||||
{23, nullptr, "SuspendTransferTask"},
|
{23, nullptr, "SuspendTransferTask"},
|
||||||
{24, D<&ITransferTaskListController::GetCurrentTransferTaskInfo>, "GetCurrentTransferTaskInfo"},
|
{24, D<&ITransferTaskListController::GetCurrentTransferTaskInfo>, "GetCurrentTransferTaskInfo"},
|
||||||
@@ -82,6 +82,11 @@ Result ITransferTaskListController::GetCurrentTransferTaskInfo(Out<std::array<u8
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result ITransferTaskListController::GetTransferTaskProgress() {
|
||||||
|
LOG_WARNING(Service_OLSC, "(STUBBED) called.");
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
Result ITransferTaskListController::FindTransferTaskInfo(Out<std::array<u8, 0x30>> out_info,
|
Result ITransferTaskListController::FindTransferTaskInfo(Out<std::array<u8, 0x30>> out_info,
|
||||||
InBuffer<BufferAttr_HipcAutoSelect> in) {
|
InBuffer<BufferAttr_HipcAutoSelect> in) {
|
||||||
LOG_WARNING(Service_OLSC, "(STUBBED) called, in_size={}", in.size());
|
LOG_WARNING(Service_OLSC, "(STUBBED) called, in_size={}", in.size());
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ private:
|
|||||||
Result GetTransferTaskStartEventNativeHandleHolder(Out<SharedPointer<INativeHandleHolder>> out_holder);
|
Result GetTransferTaskStartEventNativeHandleHolder(Out<SharedPointer<INativeHandleHolder>> out_holder);
|
||||||
Result StopNextTransferTaskExecution(Out<SharedPointer<IStopperObject>> out_stopper);
|
Result StopNextTransferTaskExecution(Out<SharedPointer<IStopperObject>> out_stopper);
|
||||||
Result GetTransferTaskCount(Out<u32> out_count, u8 unknown);
|
Result GetTransferTaskCount(Out<u32> out_count, u8 unknown);
|
||||||
|
Result GetTransferTaskProgress();
|
||||||
Result GetCurrentTransferTaskInfo(Out<std::array<u8, 0x30>> out_info, u8 unknown);
|
Result GetCurrentTransferTaskInfo(Out<std::array<u8, 0x30>> out_info, u8 unknown);
|
||||||
Result FindTransferTaskInfo(Out<std::array<u8, 0x30>> out_info, InBuffer<BufferAttr_HipcAutoSelect> in);
|
Result FindTransferTaskInfo(Out<std::array<u8, 0x30>> out_info, InBuffer<BufferAttr_HipcAutoSelect> in);
|
||||||
};
|
};
|
||||||
|
|||||||
+218
-244
@@ -48,6 +48,12 @@ enum class OptionType : u32 {
|
|||||||
EnableAlpn = 3,
|
EnableAlpn = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// This is nn::ssl::sf::RenegotiationMode
|
||||||
|
enum RenegotiationMode : u32 {
|
||||||
|
None = 0, ///< None
|
||||||
|
Secure = 1, ///< Secure
|
||||||
|
};
|
||||||
|
|
||||||
// This is nn::ssl::sf::SslVersion
|
// This is nn::ssl::sf::SslVersion
|
||||||
struct SslVersion {
|
struct SslVersion {
|
||||||
union {
|
union {
|
||||||
@@ -75,34 +81,34 @@ public:
|
|||||||
shared_data{shared_data_in}, backend{std::move(backend_in)} {
|
shared_data{shared_data_in}, backend{std::move(backend_in)} {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &ISslConnection::SetSocketDescriptor, "SetSocketDescriptor"},
|
{0, D<&ISslConnection::SetSocketDescriptor>, "SetSocketDescriptor"},
|
||||||
{1, &ISslConnection::SetHostName, "SetHostName"},
|
{1, D<&ISslConnection::SetHostName>, "SetHostName"},
|
||||||
{2, &ISslConnection::SetVerifyOption, "SetVerifyOption"},
|
{2, D<&ISslConnection::SetVerifyOption>, "SetVerifyOption"},
|
||||||
{3, &ISslConnection::SetIoMode, "SetIoMode"},
|
{3, D<&ISslConnection::SetIoMode>, "SetIoMode"},
|
||||||
{4, nullptr, "GetSocketDescriptor"},
|
{4, D<&ISslConnection::GetSocketDescriptor>, "GetSocketDescriptor"},
|
||||||
{5, nullptr, "GetHostName"},
|
{5, D<&ISslConnection::GetHostName>, "GetHostName"},
|
||||||
{6, nullptr, "GetVerifyOption"},
|
{6, nullptr, "GetVerifyOption"},
|
||||||
{7, nullptr, "GetIoMode"},
|
{7, D<&ISslConnection::GetIoMode>, "GetIoMode"},
|
||||||
{8, &ISslConnection::DoHandshake, "DoHandshake"},
|
{8, D<&ISslConnection::DoHandshake>, "DoHandshake"},
|
||||||
{9, &ISslConnection::DoHandshakeGetServerCert, "DoHandshakeGetServerCert"},
|
{9, &ISslConnection::DoHandshakeGetServerCert, "DoHandshakeGetServerCert"},
|
||||||
{10, &ISslConnection::Read, "Read"},
|
{10, D<&ISslConnection::Read>, "Read"},
|
||||||
{11, &ISslConnection::Write, "Write"},
|
{11, D<&ISslConnection::Write>, "Write"},
|
||||||
{12, &ISslConnection::Pending, "Pending"},
|
{12, D<&ISslConnection::Pending>, "Pending"},
|
||||||
{13, nullptr, "Peek"},
|
{13, D<&ISslConnection::Peek>, "Peek"},
|
||||||
{14, nullptr, "Poll"},
|
{14, D<&ISslConnection::Poll>, "Poll"},
|
||||||
{15, nullptr, "GetVerifyCertError"},
|
{15, D<&ISslConnection::GetVerifyCertError>, "GetVerifyCertError"},
|
||||||
{16, nullptr, "GetNeededServerCertBufferSize"},
|
{16, D<&ISslConnection::GetNeededServerCertBufferSize>, "GetNeededServerCertBufferSize"},
|
||||||
{17, &ISslConnection::SetSessionCacheMode, "SetSessionCacheMode"},
|
{17, D<&ISslConnection::SetSessionCacheMode>, "SetSessionCacheMode"},
|
||||||
{18, nullptr, "GetSessionCacheMode"},
|
{18, D<&ISslConnection::GetSessionCacheMode>, "GetSessionCacheMode"},
|
||||||
{19, nullptr, "FlushSessionCache"},
|
{19, D<&ISslConnection::FlushSessionCache>, "FlushSessionCache"},
|
||||||
{20, nullptr, "SetRenegotiationMode"},
|
{20, D<&ISslConnection::SetRenegotiationMode>, "SetRenegotiationMode"},
|
||||||
{21, nullptr, "GetRenegotiationMode"},
|
{21, D<&ISslConnection::GetRenegotiationMode>, "GetRenegotiationMode"},
|
||||||
{22, &ISslConnection::SetOption, "SetOption"},
|
{22, D<&ISslConnection::SetOption>, "SetOption"},
|
||||||
{23, &ISslConnection::GetOption, "GetOption"},
|
{23, D<&ISslConnection::GetOption>, "GetOption"},
|
||||||
{24, nullptr, "GetVerifyCertErrors"},
|
{24, nullptr, "GetVerifyCertErrors"},
|
||||||
{25, nullptr, "GetCipherInfo"},
|
{25, nullptr, "GetCipherInfo"},
|
||||||
{26, &ISslConnection::SetNextAlpnProto, "SetNextAlpnProto"},
|
{26, D<&ISslConnection::SetNextAlpnProto>, "SetNextAlpnProto"},
|
||||||
{27, &ISslConnection::GetNextAlpnProto, "GetNextAlpnProto"},
|
{27, D<&ISslConnection::GetNextAlpnProto>, "GetNextAlpnProto"},
|
||||||
{28, nullptr, "SetDtlsSocketDescriptor"},
|
{28, nullptr, "SetDtlsSocketDescriptor"},
|
||||||
{29, nullptr, "GetDtlsHandshakeTimeout"},
|
{29, nullptr, "GetDtlsHandshakeTimeout"},
|
||||||
{30, nullptr, "SetPrivateOption"},
|
{30, nullptr, "SetPrivateOption"},
|
||||||
@@ -141,80 +147,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SslVersion ssl_version;
|
|
||||||
std::shared_ptr<SslContextSharedData> shared_data;
|
|
||||||
std::unique_ptr<SSLConnectionBackend> backend;
|
|
||||||
std::optional<int> fd_to_close;
|
|
||||||
bool do_not_close_socket = false;
|
|
||||||
bool get_server_cert_chain = false;
|
|
||||||
bool skip_default_verify = false;
|
|
||||||
bool enable_alpn = false;
|
|
||||||
std::shared_ptr<Network::SocketBase> socket;
|
|
||||||
std::vector<u8> next_alpn_proto;
|
|
||||||
bool did_handshake = false;
|
|
||||||
u32 verify_option = 0;
|
|
||||||
|
|
||||||
Result SetSocketDescriptorImpl(s32* out_fd, s32 fd) {
|
|
||||||
LOG_DEBUG(Service_SSL, "called, fd={}", fd);
|
|
||||||
ASSERT(!did_handshake);
|
|
||||||
auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD_USA>("bsd:u");
|
|
||||||
ASSERT_OR_EXECUTE(bsd, { return ResultInternalError; });
|
|
||||||
|
|
||||||
auto const res_v = bsd->DuplicateSocketImpl(fd);
|
|
||||||
if (auto *res = std::get_if<s32>(&res_v)) {
|
|
||||||
const s32 duplicated_fd = *res;
|
|
||||||
if (do_not_close_socket) {
|
|
||||||
*out_fd = duplicated_fd;
|
|
||||||
} else {
|
|
||||||
*out_fd = -1;
|
|
||||||
fd_to_close = duplicated_fd;
|
|
||||||
}
|
|
||||||
std::optional<std::shared_ptr<Network::SocketBase>> sock = bsd->GetSocket(duplicated_fd);
|
|
||||||
if (!sock.has_value()) {
|
|
||||||
LOG_ERROR(Service_SSL, "invalid socket fd {} after duplication", duplicated_fd);
|
|
||||||
return ResultInvalidSocket;
|
|
||||||
}
|
|
||||||
socket = std::move(*sock);
|
|
||||||
backend->SetSocket(socket);
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
LOG_ERROR(Service_SSL, "Failed to duplicate socket with fd {}", fd);
|
|
||||||
return ResultInvalidSocket;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SetHostNameImpl(const std::string& hostname) {
|
|
||||||
LOG_DEBUG(Service_SSL, "called. hostname={}", hostname);
|
|
||||||
ASSERT(!did_handshake);
|
|
||||||
return backend->SetHostName(hostname);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SetVerifyOptionImpl(u32 option) {
|
|
||||||
ASSERT(!did_handshake);
|
|
||||||
LOG_DEBUG(Service_SSL, "called. option={} (forcing 0)", option);
|
|
||||||
verify_option = 0;
|
|
||||||
backend->SetVerifyOption(0);
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SetIoModeImpl(u32 input_mode) {
|
|
||||||
auto mode = static_cast<IoMode>(input_mode);
|
|
||||||
ASSERT(mode == IoMode::Blocking || mode == IoMode::NonBlocking);
|
|
||||||
ASSERT_OR_EXECUTE(socket, { return ResultNoSocket; });
|
|
||||||
|
|
||||||
const bool non_block = mode == IoMode::NonBlocking;
|
|
||||||
const Network::Errno error = socket->SetNonBlock(non_block);
|
|
||||||
if (error != Network::Errno::SUCCESS) {
|
|
||||||
LOG_ERROR(Service_SSL, "Failed to set native socket non-block flag to {}", non_block);
|
|
||||||
}
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SetSessionCacheModeImpl(u32 mode) {
|
|
||||||
ASSERT(!did_handshake);
|
|
||||||
LOG_WARNING(Service_SSL, "(STUBBED) called. value={}", mode);
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result DoHandshakeImpl() {
|
Result DoHandshakeImpl() {
|
||||||
ASSERT_OR_EXECUTE(!did_handshake && socket, { return ResultNoSocket; });
|
ASSERT_OR_EXECUTE(!did_handshake && socket, { return ResultNoSocket; });
|
||||||
Result res = backend->DoHandshake();
|
Result res = backend->DoHandshake();
|
||||||
@@ -234,19 +166,17 @@ private:
|
|||||||
};
|
};
|
||||||
if (!get_server_cert_chain) {
|
if (!get_server_cert_chain) {
|
||||||
// Just return the first one, unencoded.
|
// Just return the first one, unencoded.
|
||||||
ASSERT_OR_EXECUTE_MSG(
|
ASSERT_OR_EXECUTE_MSG(!certs.empty(), { return {}; }, "Should be at least one server cert");
|
||||||
!certs.empty(), { return {}; }, "Should be at least one server cert");
|
|
||||||
return certs[0];
|
return certs[0];
|
||||||
}
|
}
|
||||||
std::vector<u8> ret;
|
std::vector<u8> ret;
|
||||||
Header header{0x4E4D684374726543, static_cast<u32>(certs.size()), 0};
|
Header header{0x4E4D684374726543, u32(certs.size()), 0};
|
||||||
ret.insert(ret.end(), reinterpret_cast<u8*>(&header), reinterpret_cast<u8*>(&header + 1));
|
ret.insert(ret.end(), reinterpret_cast<u8*>(&header), reinterpret_cast<u8*>(&header + 1));
|
||||||
size_t data_offset = sizeof(Header) + certs.size() * sizeof(EntryHeader);
|
size_t data_offset = sizeof(Header) + certs.size() * sizeof(EntryHeader);
|
||||||
for (auto& cert : certs) {
|
for (auto& cert : certs) {
|
||||||
EntryHeader entry_header{static_cast<u32>(cert.size()), static_cast<u32>(data_offset)};
|
EntryHeader entry_header{u32(cert.size()), u32(data_offset)};
|
||||||
data_offset += cert.size();
|
data_offset += cert.size();
|
||||||
ret.insert(ret.end(), reinterpret_cast<u8*>(&entry_header),
|
ret.insert(ret.end(), reinterpret_cast<u8*>(&entry_header), reinterpret_cast<u8*>(&entry_header + 1));
|
||||||
reinterpret_cast<u8*>(&entry_header + 1));
|
|
||||||
}
|
}
|
||||||
for (auto& cert : certs) {
|
for (auto& cert : certs) {
|
||||||
ret.insert(ret.end(), cert.begin(), cert.end());
|
ret.insert(ret.end(), cert.begin(), cert.end());
|
||||||
@@ -254,65 +184,77 @@ private:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result ReadImpl(std::vector<u8>* out_data) {
|
Result SetSocketDescriptor(s32 in_fd, Out<s32> out_fd) {
|
||||||
ASSERT_OR_EXECUTE(did_handshake, { return ResultInternalError; });
|
LOG_DEBUG(Service_SSL, "called, fd={}", in_fd);
|
||||||
size_t actual_size{};
|
ASSERT(!did_handshake);
|
||||||
Result res = backend->Read(&actual_size, *out_data);
|
auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD_USA>("bsd:u");
|
||||||
if (res != ResultSuccess) {
|
ASSERT_OR_EXECUTE(bsd, { return ResultInternalError; });
|
||||||
return res;
|
|
||||||
|
auto const res_v = bsd->DuplicateSocketImpl(in_fd);
|
||||||
|
if (auto *res = std::get_if<s32>(&res_v)) {
|
||||||
|
const s32 dup_fd = *res;
|
||||||
|
*out_fd = do_not_close_socket ? dup_fd : -1;
|
||||||
|
if (!do_not_close_socket)
|
||||||
|
fd_to_close = dup_fd;
|
||||||
|
auto const sock = bsd->GetSocket(dup_fd);
|
||||||
|
if (!sock.has_value()) {
|
||||||
|
LOG_ERROR(Service_SSL, "invalid socket fd {} after duplication", dup_fd);
|
||||||
|
return ResultInvalidSocket;
|
||||||
|
}
|
||||||
|
socket = std::move(*sock);
|
||||||
|
backend->SetSocket(std::move(socket));
|
||||||
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
out_data->resize(actual_size);
|
LOG_ERROR(Service_SSL, "Failed to duplicate socket with fd {}", in_fd);
|
||||||
return res;
|
return ResultInvalidSocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result WriteImpl(size_t* out_size, std::span<const u8> data) {
|
Result SetHostName(InBuffer<BufferAttr_HipcMapAlias> buf) {
|
||||||
ASSERT_OR_EXECUTE(did_handshake, { return ResultInternalError; });
|
auto const hostname = Common::StringFromBuffer(buf);
|
||||||
return backend->Write(out_size, data);
|
LOG_DEBUG(Service_SSL, "called. hostname={}", hostname);
|
||||||
|
ASSERT(!did_handshake);
|
||||||
|
return backend->SetHostName(hostname.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
Result PendingImpl(s32* out_pending) {
|
Result SetVerifyOption(u32 option) {
|
||||||
LOG_WARNING(Service_SSL, "(STUBBED) called.");
|
LOG_DEBUG(Service_SSL, "called. option={} (forcing 0)", option);
|
||||||
*out_pending = 0;
|
ASSERT(!did_handshake);
|
||||||
return ResultSuccess;
|
verify_option = 0;
|
||||||
|
backend->SetVerifyOption(0);
|
||||||
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetSocketDescriptor(HLERequestContext& ctx) {
|
Result SetIoMode(u32 input_mode) {
|
||||||
IPC::RequestParser rp{ctx};
|
auto mode = IoMode(input_mode);
|
||||||
const s32 in_fd = rp.Pop<s32>();
|
ASSERT(mode == IoMode::Blocking || mode == IoMode::NonBlocking);
|
||||||
s32 out_fd{-1};
|
R_UNLESS(socket, ResultNoSocket);
|
||||||
const Result res = SetSocketDescriptorImpl(&out_fd, in_fd);
|
const bool non_block = mode == IoMode::NonBlocking;
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
const Network::Errno error = socket->SetNonBlock(non_block);
|
||||||
rb.Push(res);
|
if (error != Network::Errno::SUCCESS) {
|
||||||
rb.Push<s32>(out_fd);
|
LOG_ERROR(Service_SSL, "Failed to set native socket non-block flag to {}", non_block);
|
||||||
|
}
|
||||||
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetHostName(HLERequestContext& ctx) {
|
Result GetSocketDescriptor(Out<u32> out_fd) {
|
||||||
const std::string hostname = Common::StringFromBuffer(ctx.ReadBuffer());
|
LOG_WARNING(Service_SSL, "(STUBBED)");
|
||||||
const Result res = SetHostNameImpl(hostname);
|
*out_fd = uint32_t(socket->GetFD());
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
R_SUCCEED();
|
||||||
rb.Push(res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetVerifyOption(HLERequestContext& ctx) {
|
Result GetHostName(OutBuffer<BufferAttr_HipcMapAlias> data, Out<u32> out_size) {
|
||||||
IPC::RequestParser rp{ctx};
|
LOG_WARNING(Service_SSL, "(STUBBED)");
|
||||||
const u32 option = rp.Pop<u32>();
|
ASSERT(!did_handshake);
|
||||||
const Result res = SetVerifyOptionImpl(option);
|
return backend->GetHostName(std::span<u8>{data.begin(), data.end()}, out_size);
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetIoMode(HLERequestContext& ctx) {
|
Result GetIoMode(Out<u32> out_mode) {
|
||||||
IPC::RequestParser rp{ctx};
|
LOG_WARNING(Service_SSL, "(STUBBED)");
|
||||||
const u32 mode = rp.Pop<u32>();
|
R_SUCCEED();
|
||||||
const Result res = SetIoModeImpl(mode);
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoHandshake(HLERequestContext& ctx) {
|
Result DoHandshake() {
|
||||||
const Result res = DoHandshakeImpl();
|
return DoHandshakeImpl();
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoHandshakeGetServerCert(HLERequestContext& ctx) {
|
void DoHandshakeGetServerCert(HLERequestContext& ctx) {
|
||||||
@@ -351,131 +293,158 @@ private:
|
|||||||
rb.PushRaw(out);
|
rb.PushRaw(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Read(HLERequestContext& ctx) {
|
Result Read(OutBuffer<BufferAttr_HipcMapAlias> data, Out<u32> out_size) {
|
||||||
std::vector<u8> output_bytes(ctx.GetWriteBufferSize());
|
R_UNLESS(did_handshake, ResultInternalError);
|
||||||
const Result res = ReadImpl(&output_bytes);
|
size_t tmp{};
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
auto const res = backend->Read(&tmp, data);
|
||||||
rb.Push(res);
|
*out_size = u32(tmp);
|
||||||
if (res == ResultSuccess) {
|
return res;
|
||||||
rb.Push(static_cast<u32>(output_bytes.size()));
|
|
||||||
ctx.WriteBuffer(output_bytes);
|
|
||||||
} else {
|
|
||||||
rb.Push(static_cast<u32>(0));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write(HLERequestContext& ctx) {
|
Result Write(InBuffer<BufferAttr_HipcMapAlias> data, Out<u32> out_size) {
|
||||||
size_t write_size{0};
|
R_UNLESS(did_handshake, ResultInternalError);
|
||||||
const Result res = WriteImpl(&write_size, ctx.ReadBuffer());
|
size_t tmp{};
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
auto const res = backend->Write(&tmp, data);
|
||||||
rb.Push(res);
|
*out_size = u32(tmp);
|
||||||
rb.Push(static_cast<u32>(write_size));
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Pending(HLERequestContext& ctx) {
|
Result Pending(Out<s32> out_pending_size) {
|
||||||
s32 pending_size{0};
|
LOG_WARNING(Service_SSL, "(STUBBED)");
|
||||||
const Result res = PendingImpl(&pending_size);
|
*out_pending_size = s32(backend->Pending());
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
R_SUCCEED();
|
||||||
rb.Push(res);
|
|
||||||
rb.Push<s32>(pending_size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetSessionCacheMode(HLERequestContext& ctx) {
|
Result Peek(OutBuffer<BufferAttr_HipcMapAlias> data, Out<u32> out_size) {
|
||||||
IPC::RequestParser rp{ctx};
|
LOG_WARNING(Service_SSL, "(STUBBED)");
|
||||||
const u32 mode = rp.Pop<u32>();
|
size_t tmp{};
|
||||||
const Result res = SetSessionCacheModeImpl(mode);
|
auto const res = backend->Peek(&tmp, data);
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
*out_size = u32(tmp);
|
||||||
rb.Push(res);
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetOption(HLERequestContext& ctx) {
|
Result Poll(u32 in_pollevent, u32 timer, Out<u32> out_pollevent) {
|
||||||
struct Parameters {
|
LOG_WARNING(Service_SSL, "(STUBBED)");
|
||||||
OptionType option;
|
R_SUCCEED();
|
||||||
s32 value;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(Parameters) == 0x8, "Parameters is an invalid size");
|
|
||||||
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto parameters = rp.PopRaw<Parameters>();
|
|
||||||
|
|
||||||
switch (parameters.option) {
|
|
||||||
case OptionType::DoNotCloseSocket:
|
|
||||||
do_not_close_socket = static_cast<bool>(parameters.value);
|
|
||||||
break;
|
|
||||||
case OptionType::GetServerCertChain:
|
|
||||||
get_server_cert_chain = static_cast<bool>(parameters.value);
|
|
||||||
break;
|
|
||||||
case OptionType::SkipDefaultVerify:
|
|
||||||
skip_default_verify = static_cast<bool>(parameters.value);
|
|
||||||
break;
|
|
||||||
case OptionType::EnableAlpn:
|
|
||||||
enable_alpn = static_cast<bool>(parameters.value);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LOG_WARNING(Service_SSL, "Unknown option={}, value={}", parameters.option,
|
|
||||||
parameters.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetOption(HLERequestContext& ctx) {
|
Result GetVerifyCertError() {
|
||||||
IPC::RequestParser rp{ctx};
|
LOG_WARNING(Service_SSL, "(STUBBED)");
|
||||||
const auto option = rp.PopRaw<OptionType>();
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
u8 value = 0;
|
Result GetNeededServerCertBufferSize(Out<u32> out_needed_buffer_size) {
|
||||||
|
LOG_WARNING(Service_SSL, "(STUBBED)");
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SetSessionCacheMode(u32 mode) {
|
||||||
|
LOG_WARNING(Service_SSL, "(STUBBED) called. value={}", mode);
|
||||||
|
R_UNLESS(!did_handshake, ResultInternalError);
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetSessionCacheMode(Out<u32> mode) {
|
||||||
|
LOG_WARNING(Service_SSL, "(STUBBED)");
|
||||||
|
R_UNLESS(!did_handshake, ResultInternalError);
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result FlushSessionCache() {
|
||||||
|
LOG_WARNING(Service_SSL, "(STUBBED)");
|
||||||
|
R_UNLESS(!did_handshake, ResultInternalError);
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SetRenegotiationMode(RenegotiationMode mode) {
|
||||||
|
LOG_WARNING(Service_SSL, "(STUBBED)");
|
||||||
|
backend->SetRenegotiationMode(u32(mode));
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetRenegotiationMode(Out<RenegotiationMode> mode) {
|
||||||
|
LOG_WARNING(Service_SSL, "(STUBBED)");
|
||||||
|
u32 tmp{};
|
||||||
|
auto const res = backend->GetRenegotiationMode(&tmp);
|
||||||
|
*mode = RenegotiationMode(tmp);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SetOption(OptionType option, s32 value) {
|
||||||
switch (option) {
|
switch (option) {
|
||||||
case OptionType::DoNotCloseSocket:
|
case OptionType::DoNotCloseSocket:
|
||||||
value = static_cast<u8>(do_not_close_socket);
|
do_not_close_socket = bool(value);
|
||||||
break;
|
break;
|
||||||
case OptionType::GetServerCertChain:
|
case OptionType::GetServerCertChain:
|
||||||
value = static_cast<u8>(get_server_cert_chain);
|
get_server_cert_chain = bool(value);
|
||||||
break;
|
break;
|
||||||
case OptionType::SkipDefaultVerify:
|
case OptionType::SkipDefaultVerify:
|
||||||
value = static_cast<u8>(skip_default_verify);
|
skip_default_verify = bool(value);
|
||||||
break;
|
break;
|
||||||
case OptionType::EnableAlpn:
|
case OptionType::EnableAlpn:
|
||||||
value = static_cast<u8>(enable_alpn);
|
enable_alpn = bool(value);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_WARNING(Service_SSL, "Unknown option={}", option);
|
LOG_WARNING(Service_SSL, "Unknown option={}, value={}", option, value);
|
||||||
value = 0;
|
}
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetOption(OptionType option, Out<u8> value) {
|
||||||
|
switch (option) {
|
||||||
|
case OptionType::DoNotCloseSocket:
|
||||||
|
*value = u8(do_not_close_socket);
|
||||||
|
break;
|
||||||
|
case OptionType::GetServerCertChain:
|
||||||
|
*value = u8(get_server_cert_chain);
|
||||||
|
break;
|
||||||
|
case OptionType::SkipDefaultVerify:
|
||||||
|
*value = u8(skip_default_verify);
|
||||||
|
break;
|
||||||
|
case OptionType::EnableAlpn:
|
||||||
|
*value = u8(enable_alpn);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_WARNING(Service_SSL, "Unknown option={}", u32(option));
|
||||||
|
*value = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
LOG_DEBUG(Service_SSL, "GetOption called, option={}, ret value={}", u32(option), *value);
|
||||||
LOG_DEBUG(Service_SSL, "GetOption called, option={}, ret value={}", option, value);
|
R_SUCCEED();
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.Push<u8>(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetNextAlpnProto(HLERequestContext& ctx) {
|
Result SetNextAlpnProto(InBuffer<BufferAttr_HipcMapAlias> data) {
|
||||||
const auto data = ctx.ReadBuffer(0);
|
auto const to_write = u32((std::min)(next_alpn_proto.size(), data.size()));
|
||||||
next_alpn_proto.assign(data.begin(), data.end());
|
next_alpn_proto.assign(data.begin(), data.begin() + to_write);
|
||||||
|
|
||||||
LOG_DEBUG(Service_SSL, "SetNextAlpnProto called, size={}", next_alpn_proto.size());
|
LOG_DEBUG(Service_SSL, "SetNextAlpnProto called, size={}", next_alpn_proto.size());
|
||||||
|
R_SUCCEED();
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetNextAlpnProto(HLERequestContext& ctx) {
|
Result GetNextAlpnProto(OutBuffer<BufferAttr_HipcMapAlias> data, Out<u32> to_write) {
|
||||||
const size_t writable = ctx.GetWriteBufferSize();
|
*to_write = u32((std::min)(next_alpn_proto.size(), data.size()));
|
||||||
const size_t to_write = (std::min)(next_alpn_proto.size(), writable);
|
next_alpn_proto.assign(data.begin(), data.begin() + *to_write);
|
||||||
|
LOG_DEBUG(Service_SSL, "GetNextAlpnProto called, size={}", *to_write);
|
||||||
if (to_write != 0) {
|
R_SUCCEED();
|
||||||
ctx.WriteBuffer(std::span<const u8>(next_alpn_proto.data(), to_write));
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_DEBUG(Service_SSL, "GetNextAlpnProto called, size={}", to_write);
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.Push<u32>(static_cast<u32>(to_write));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result GetVerifyCertErrors(OutBuffer<BufferAttr_HipcMapAlias> unk0, Out<u32> unk1, Out<u32> unk2) {
|
||||||
|
LOG_WARNING(Service_SSL, "(STUBBED)");
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
SslVersion ssl_version;
|
||||||
|
std::shared_ptr<SslContextSharedData> shared_data;
|
||||||
|
std::unique_ptr<SSLConnectionBackend> backend;
|
||||||
|
std::optional<int> fd_to_close;
|
||||||
|
std::shared_ptr<Network::SocketBase> socket;
|
||||||
|
std::vector<u8> next_alpn_proto;
|
||||||
|
u32 verify_option = 0;
|
||||||
|
|
||||||
|
bool do_not_close_socket = false;
|
||||||
|
bool get_server_cert_chain = false;
|
||||||
|
bool skip_default_verify = false;
|
||||||
|
bool enable_alpn = false;
|
||||||
|
bool did_handshake = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ISslContext final : public ServiceFramework<ISslContext> {
|
class ISslContext final : public ServiceFramework<ISslContext> {
|
||||||
@@ -492,7 +461,7 @@ public:
|
|||||||
{5, &ISslContext::ImportClientPki, "ImportClientPki"},
|
{5, &ISslContext::ImportClientPki, "ImportClientPki"},
|
||||||
{6, nullptr, "RemoveServerPki"},
|
{6, nullptr, "RemoveServerPki"},
|
||||||
{7, nullptr, "RemoveClientPki"},
|
{7, nullptr, "RemoveClientPki"},
|
||||||
{8, nullptr, "RegisterInternalPki"},
|
{8, D<&ISslContext::RegisterInternalPki>, "RegisterInternalPki"},
|
||||||
{9, nullptr, "AddPolicyOid"},
|
{9, nullptr, "AddPolicyOid"},
|
||||||
{10, nullptr, "ImportCrl"},
|
{10, nullptr, "ImportCrl"},
|
||||||
{11, nullptr, "RemoveCrl"},
|
{11, nullptr, "RemoveCrl"},
|
||||||
@@ -587,6 +556,11 @@ private:
|
|||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.Push(client_id);
|
rb.Push(client_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result RegisterInternalPki() {
|
||||||
|
LOG_WARNING(Service_SSL, "(STUBBED) called");
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ISslService final : public ServiceFramework<ISslService> {
|
class ISslService final : public ServiceFramework<ISslService> {
|
||||||
|
|||||||
@@ -36,12 +36,17 @@ class SSLConnectionBackend {
|
|||||||
public:
|
public:
|
||||||
virtual ~SSLConnectionBackend() {}
|
virtual ~SSLConnectionBackend() {}
|
||||||
virtual void SetSocket(std::shared_ptr<Network::SocketBase> socket) = 0;
|
virtual void SetSocket(std::shared_ptr<Network::SocketBase> socket) = 0;
|
||||||
virtual Result SetHostName(const std::string& hostname) = 0;
|
|
||||||
virtual void SetVerifyOption(u32 option) = 0;
|
virtual void SetVerifyOption(u32 option) = 0;
|
||||||
virtual Result DoHandshake() = 0;
|
virtual Result DoHandshake() = 0;
|
||||||
virtual Result Read(size_t* out_size, std::span<u8> data) = 0;
|
virtual Result Read(size_t* out_size, std::span<u8> data) = 0;
|
||||||
|
virtual Result Peek(size_t* out_size, std::span<u8> data) = 0;
|
||||||
virtual Result Write(size_t* out_size, std::span<const u8> data) = 0;
|
virtual Result Write(size_t* out_size, std::span<const u8> data) = 0;
|
||||||
virtual Result GetServerCerts(std::vector<std::vector<u8>>* out_certs) = 0;
|
virtual Result GetServerCerts(std::vector<std::vector<u8>>* out_certs) = 0;
|
||||||
|
virtual Result SetHostName(const char* hostname) = 0;
|
||||||
|
virtual Result GetHostName(std::span<u8> hostname, u32* out_size) = 0;
|
||||||
|
virtual int Pending() = 0;
|
||||||
|
virtual Result SetRenegotiationMode(u32 mode) = 0;
|
||||||
|
virtual Result GetRenegotiationMode(u32* mode) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
Result CreateSSLConnectionBackend(std::unique_ptr<SSLConnectionBackend>* out_backend);
|
Result CreateSSLConnectionBackend(std::unique_ptr<SSLConnectionBackend>* out_backend);
|
||||||
|
|||||||
@@ -157,18 +157,30 @@ public:
|
|||||||
socket = std::move(socket_in);
|
socket = std::move(socket_in);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SetHostName(const std::string& hostname) override {
|
Result SetHostName(const char* hostname) override {
|
||||||
if (!skip_cert_verification) {
|
if (!skip_cert_verification) {
|
||||||
if (!SSL_set1_host(ssl, hostname.c_str())) {
|
if (!SSL_set1_host(ssl, hostname)) {
|
||||||
LOG_ERROR(Service_SSL, "SSL_set1_host({}) failed", hostname);
|
LOG_ERROR(Service_SSL, "SSL_set1_host({}) failed", hostname);
|
||||||
return CheckOpenSSLErrors();
|
return CheckOpenSSLErrors();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!SSL_set_tlsext_host_name(ssl, hostname.c_str())) { // hostname for SNI
|
if (!SSL_set_tlsext_host_name(ssl, hostname)) { // hostname for SNI
|
||||||
LOG_ERROR(Service_SSL, "SSL_set_tlsext_host_name({}) failed", hostname);
|
LOG_ERROR(Service_SSL, "SSL_set_tlsext_host_name({}) failed", hostname);
|
||||||
return CheckOpenSSLErrors();
|
return CheckOpenSSLErrors();
|
||||||
}
|
}
|
||||||
return ResultSuccess;
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetHostName(std::span<u8> data, u32* out_size) override {
|
||||||
|
auto const peer_name = SSL_get0_peername(ssl);
|
||||||
|
if (peer_name == nullptr) {
|
||||||
|
LOG_ERROR(Service_SSL, "SSL_get0_peername()");
|
||||||
|
return CheckOpenSSLErrors();
|
||||||
|
}
|
||||||
|
auto const s = std::string{peer_name};
|
||||||
|
*out_size = u32(s.size());
|
||||||
|
std::memcpy(data.data(), s.data(), (std::min)(s.size(), data.size()));
|
||||||
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetVerifyOption(u32 option) override {
|
void SetVerifyOption(u32 option) override {
|
||||||
@@ -213,6 +225,13 @@ public:
|
|||||||
return HandleReturn("SSL_read_ex", out_size, ret);
|
return HandleReturn("SSL_read_ex", out_size, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result Peek(size_t* out_size, std::span<u8> data) override {
|
||||||
|
auto const n = (std::min)(data.size(), *out_size);
|
||||||
|
const int ret = SSL_peek(ssl, data.data(), int(n));
|
||||||
|
*out_size = n;
|
||||||
|
return HandleReturn("SSL_write_ex", out_size, ret);
|
||||||
|
}
|
||||||
|
|
||||||
Result Write(size_t* out_size, std::span<const u8> data) override {
|
Result Write(size_t* out_size, std::span<const u8> data) override {
|
||||||
const int ret = SSL_write_ex(ssl, data.data(), data.size(), out_size);
|
const int ret = SSL_write_ex(ssl, data.data(), data.size(), out_size);
|
||||||
return HandleReturn("SSL_write_ex", out_size, ret);
|
return HandleReturn("SSL_write_ex", out_size, ret);
|
||||||
@@ -263,7 +282,25 @@ public:
|
|||||||
out_certs->emplace_back(buf, buf + len);
|
out_certs->emplace_back(buf, buf + len);
|
||||||
OPENSSL_free(buf);
|
OPENSSL_free(buf);
|
||||||
}
|
}
|
||||||
return ResultSuccess;
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
int Pending() override {
|
||||||
|
return SSL_pending(ssl);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SetRenegotiationMode(u32 mode) override {
|
||||||
|
if (mode == 0) {
|
||||||
|
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_RENEGOTIATION);
|
||||||
|
} else {
|
||||||
|
SSL_CTX_set_options(ssl_ctx, SSL_OP_ALLOW_CLIENT_RENEGOTIATION);
|
||||||
|
}
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetRenegotiationMode(u32* mode) override {
|
||||||
|
*mode = SSL_get_secure_renegotiation_support(ssl) ? 1 : 0;
|
||||||
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
~SSLConnectionBackendOpenSSL() {
|
~SSLConnectionBackendOpenSSL() {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user