Compare commits

..

83 Commits

Author SHA1 Message Date
Liam
ceda2d280e general: rename CurrentProcess to ApplicationProcess 2023-02-13 19:03:12 -05:00
Liam
4363ca304a kernel: use GetCurrentProcess 2023-02-13 11:05:14 -05:00
bunnei
770a49616d Merge pull request #9784 from m-HD/master
settings: added missing graphical settings to RestoreGlobalState()
2023-02-12 21:49:45 -08:00
bunnei
8b74047b1b Merge pull request #9757 from german77/gyro
core: hid: Use gyro thresholds modes set by the game
2023-02-12 00:19:22 -08:00
bunnei
f70fcdb873 Merge pull request #9746 from ameerj/ogl-msaa-texcache
texture_cache: OpenGL: Implement MSAA uploads and copies
2023-02-12 00:18:52 -08:00
m-HD
9df92bad2a Update settings.cpp
added missing graphical settings to RestoreGlobalState()
2023-02-12 02:58:39 +01:00
liamwhite
fbba6e10bc Merge pull request #9781 from ColinKinloch/info_id_typo
kernel/svc: Fix undefined info_id
2023-02-11 20:13:54 -05:00
ameerj
93cf2b3ca8 texture_cache: OpenGL: Implement MSAA uploads and copies 2023-02-11 15:43:07 -05:00
Colin Kinloch
868ab0d3b4 kernel/svc: Fix undefined info_id 2023-02-11 18:00:34 +00:00
liamwhite
c97b5c9ff9 Merge pull request #9777 from vonchenplus/speed_up_video_copy
video_core: Speed up video frame data copy
2023-02-11 12:35:16 -05:00
liamwhite
709879cfc1 Merge pull request #9773 from bunnei/fix-process-resource
core: kernel: k_process: Use application system resource.
2023-02-11 10:28:50 -05:00
liamwhite
89c09d639a Merge pull request #9768 from merryhime/biquad-rounding
biquad_filter: Fix rounding in ApplyBiquadFilterInt
2023-02-11 10:28:42 -05:00
liamwhite
1040f1f503 Merge pull request #9744 from behunin/quick-release
gpu_thread: Remove OnCommandListEndCommand
2023-02-11 10:28:30 -05:00
FengChen
4adf39edf2 video_core: Speed up video frame data copy 2023-02-11 22:18:54 +08:00
bunnei
abd826ba87 Merge pull request #9742 from liamwhite/svc-wrap-only
kernel/svc: switch to generated wrappers
2023-02-10 21:41:22 -08:00
bunnei
023ac943aa Merge pull request #9759 from german77/pro_controller
input_common: Reintroduce custom pro controller support
2023-02-10 21:14:40 -08:00
bunnei
e79270507b core: kernel: k_process: Use application system resource. 2023-02-10 21:03:39 -08:00
Merry
3c60bc36a1 biquad_filter: Clamp f64 in ApplyBiquadFilterFloat 2023-02-10 20:43:34 +00:00
Merry
9bdcb1070f biquad_filter: Fix rounding in ApplyBiquadFilterInt 2023-02-10 20:34:52 +00:00
liamwhite
b3a8c0dc49 Merge pull request #9761 from Morph1984/oops
main: Re-add QtWebEngine zoom factor
2023-02-10 10:54:10 -05:00
bunnei
84743fd6ce Merge pull request #9765 from liamwhite/ffs-apple
kernel: avoid usage of bit_cast
2023-02-10 07:53:40 -08:00
Liam
36b70dec05 kernel: avoid usage of bit_cast 2023-02-10 09:13:58 -05:00
Morph
3fbb93e5c9 main: Re-add QtWebEngine zoom factor
For some reason, I had removed this in ad6cec71ec

This should fix any improperly scaled web applets.
2023-02-09 22:57:37 -05:00
liamwhite
c5743d5499 Merge pull request #9736 from Kelebek1/dynamic_vertex_attribs
Remove fake vertex bindings when dynamic state is enabled
2023-02-09 22:14:55 -05:00
liamwhite
cbb289fbee Merge pull request #9750 from ameerj/glsl-sample-id-mask
glsl_emit_context: Remove redeclarations of gl_SampleID and gl_SampleMask
2023-02-09 22:14:47 -05:00
liamwhite
c0b36c2d26 Merge pull request #9758 from german77/multi_audio
audio: cubeb: Fix yuzu crashing when it test for latency
2023-02-09 22:14:33 -05:00
Narr the Reg
acba9a6b76 input_common: Reintroduce custom pro controller support 2023-02-09 20:08:54 -06:00
Narr the Reg
7c0dcea96c audio: cubeb: Fix yuzu crashing when it test for latency 2023-02-09 19:38:03 -06:00
Narr the Reg
5e9fa5def5 core: hid: Use gyro thresholds modes set by the game 2023-02-09 19:07:50 -06:00
Matías Locatti
7bad3a7e5e Merge pull request #9749 from ameerj/pr9559-partial-revert
buffer_base: Partially revert changes from #9559
2023-02-09 17:53:45 -03:00
ameerj
eb9f16dce4 buffer_base: Partially revert changes from #9559
This fixes a regression where Yoshi's Crafted World (and potentially other titles) would enter an infinite loop when GPU Accuracy was set to "Normal"
2023-02-08 19:37:23 -05:00
ameerj
04139cb3ed glsl_emit_context: Remove redeclarations of gl_SampleID and gl_SampleMask
These built-ins seem to be available without needing to be declared for fragment shaders, similar i.e. to gl_FragDepth
2023-02-08 19:34:39 -05:00
liamwhite
f6477b91f9 Merge pull request #9747 from german77/SetSupportedNpadIdTypes
service: hid: Return error if arguments of SetSupportedNpadIdType is invalid
2023-02-08 10:09:26 -05:00
Narr the Reg
c27006e99d service: hid: Return error if arguments of SetSupportedNpadIdType is invalid 2023-02-07 21:11:39 -06:00
Mai
f3b532d091 Merge pull request #9739 from liamwhite/old-gcc-fix
kernel: fix compilation with older gcc
2023-02-07 22:10:35 -05:00
Behunin
8551ac6008 Remove OnCommandListEndCommand
Call rasterizer->ReleaseFences() directly
2023-02-07 17:21:17 -07:00
Liam
2415d37ea2 kernel/svc: switch to generated wrappers 2023-02-06 23:57:44 -05:00
liamwhite
1f3e8d633a Merge pull request #4949 from Morph1984/hidpi-temp-fix
main: Enable High DPI fixes for Qt >= 5.14
2023-02-06 23:20:49 -05:00
bunnei
ecbf74b87a Merge pull request #9644 from SaiKai/volume_quicksetting
add volume quicksetting with volume slider
2023-02-06 17:10:44 -08:00
bunnei
01cb49973a Merge pull request #9735 from merryhime/dynarmic-6.4.5
dynarmic: Update to 6.4.5
2023-02-06 17:09:17 -08:00
Liam
82c2a3da9f kernel: fix compilation with older gcc 2023-02-06 13:14:27 -05:00
liamwhite
72f78a48e3 Merge pull request #9737 from goldenx86/yuzu_cmd
Update yuzu_cmd's default_ini.h
2023-02-06 09:08:27 -05:00
Matías Locatti
69eaad18a5 Update yuzu_cmd's default_ini.h
Rename FSR, add missing resolution multipliers, and SMAA
2023-02-06 06:01:51 -03:00
Kelebek1
8ae2a664d2 Remove fake vertex bindings when dynamic state is enabled 2023-02-05 22:28:03 +00:00
Merry
3f852c61d1 dynarmic: Update to 6.4.5 2023-02-05 21:49:32 +00:00
Mai
0373000143 Merge pull request #9731 from liamwhite/svc-move-only
kernel/svc: Split implementations into separate files
2023-02-05 02:26:52 -05:00
Liam
92eb091ddb kernel/svc: Split implementations into separate files 2023-02-04 22:37:43 -05:00
bunnei
a64fc3ee77 Merge pull request #9720 from SoRadGaming/discordPresenceUpdate
Game Image with Discord RPC
2023-02-04 18:37:21 -08:00
Sorab
923c17f1ae Add Game Icon for Discord RPC
Connected to Yuzu Compatibility Page
2023-02-05 12:40:57 +11:00
liamwhite
f5ed51bdf3 Merge pull request #9730 from german77/cmd_arg
yuzu_cmd: Order arguments alphabetically and port arguments from Qt
2023-02-04 15:01:17 -05:00
liamwhite
236b54376d Merge pull request #9729 from german77/sdl_input
yuzu_cmd: Fix touch and controller input
2023-02-04 15:01:07 -05:00
liamwhite
7f56b0c49f Merge pull request #9728 from ameerj/s32-value
shader_recompiler/value.h: Remove lingering references to S32
2023-02-04 15:00:54 -05:00
german77
3cd0b816cc yuzu_cmd: Order arguments alphabetically and port arguments from Qt 2023-02-04 11:33:29 -06:00
german77
ebca59b8e9 yuzu_cmd: Fix mismatching controller input 2023-02-04 11:05:57 -06:00
german77
424643f9af yuzu_cmd: Fix touch input 2023-02-04 10:31:12 -06:00
ameerj
4678f53463 shader_recompiler/value.h: Remove lingering references to S32 2023-02-04 00:13:47 -05:00
bunnei
5aca9386cf Merge pull request #9717 from german77/less_is_better
input_common: Simplify stick from button
2023-02-03 16:09:29 -08:00
bunnei
193b513bf5 Merge pull request #9719 from ameerj/hle-ipc-span-copy
Revert #9718, Copy HLE Read Buffer for OutputAccessLogToSdCard
2023-02-03 15:42:18 -08:00
Jonas Gutenschwager
2a491f7aaa remove disambiguation argument from mute text
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
2023-02-04 00:00:20 +01:00
ameerj
979e4d9950 fsp_srv: Copy HLE Read Buffer for OutputAccessLogToSdCard 2023-02-03 00:12:16 -05:00
ameerj
2d2522693e Revert "Merge pull request #9718 from yuzu-emu/revert-9508-hle-ipc-buffer-span"
This reverts commit 25fc5c0e11, reversing
changes made to af20e25081.
2023-02-03 00:08:45 -05:00
Mai
9083ad816f Merge pull request #9713 from unfamiliarplace/master
Added 'Hide empty rooms' toggle to lobby
2023-02-02 23:54:48 -05:00
bunnei
25fc5c0e11 Merge pull request #9718 from yuzu-emu/revert-9508-hle-ipc-buffer-span
Revert "hle_ipc: Use std::span to avoid heap allocations/copies when calling ReadBuffer"
2023-02-02 19:04:50 -08:00
bunnei
af20e25081 Merge pull request #9704 from liamwhite/das
kernel: add KDeviceAddressSpace
2023-02-02 19:00:23 -08:00
Luke Sawczak
54ab154696 added 'Hide empty rooms' toggle to lobby
fixed typo

fixed typo

fixed typo

clang
2023-02-02 18:46:28 -06:00
liamwhite
b01698775b Revert "hle_ipc: Use std::span to avoid heap allocations/copies when calling ReadBuffer" 2023-02-02 15:53:28 -05:00
Narr the Reg
2f2e88c3fb input_common: Simplify stick from button 2023-02-02 10:13:27 -06:00
liamwhite
8a33f8bd30 Merge pull request #9708 from ameerj/gl-context-flush
gl_shader_cache: Force context flush when loading disk shader cache
2023-02-01 22:38:13 -05:00
liamwhite
a9a860a4f7 Merge pull request #9703 from ameerj/txq-ms
shaders: Fix TXQ with MSAA textures
2023-02-01 22:38:00 -05:00
Liam
7d1c3a3f59 kernel: add KDeviceAddressSpace 2023-02-01 17:18:21 -05:00
bunnei
92c5ab33b7 Merge pull request #9696 from german77/please_forgive_me_for_this_sin
input_common: Implement turbo buttons
2023-02-01 12:08:34 -08:00
german77
ce1895497d yuzu: config: Draw turbo buttons with a different color 2023-02-01 12:42:06 -06:00
german77
75e81885b0 input_common: Implement turbo buttons 2023-02-01 12:42:05 -06:00
Mai
c4aa833d61 Merge pull request #9711 from zhaobot/tx-update-20230201062139
Update translations (2023-02-01)
2023-02-01 01:26:51 -05:00
ameerj
720ff38097 gl_compute_pipeline: Force context flush when loading shader cache 2023-01-29 21:32:12 -05:00
ameerj
01eeda74a6 gl_graphics_pipeline: Force context flush when loading shader cache 2023-01-29 20:26:49 -05:00
ameerj
a63e17566a spirv: Fix TXQ with MSAA textures 2023-01-29 13:47:30 -05:00
ameerj
a1d8306bfd emit_glasm_image: Fix TXQ with MSAA textures 2023-01-29 13:42:34 -05:00
ameerj
08feba2b56 emit_glsl_image: Implement TXQ with MSAA textures
Also fixes for texture buffers, which do not have mips eithers.
2023-01-29 13:31:47 -05:00
Morph
ad6cec71ec main: Convert to device independent coordinates for scaling
devicePixelRatioF() returns the scaling ratio when high dpi scaling is enabled.
When high dpi scaling is enabled, the raw screen coordinate system is scaled to device independent coordinates.
2023-01-25 21:16:05 -05:00
Morph
5be85c556e main: Use passthrough scaling for non-windows OSes
They should be better than windows when handling fractional scaling ratios.
2023-01-25 21:16:04 -05:00
Morph
6a1b089a50 main: Enable High DPI fixes for Qt >= 5.14
This uses Qt's new high DPI application attributes for scaling the current window.
However, these aren't perfect as scaling with non integer scales will cause artifacts in UI, icons and other elements.
Therefore, we use a heuristic to select an appropriate integer scale value depending on the current screen resolution and applies this to the application.
2023-01-25 21:16:04 -05:00
Jonas Gutenschwager
4653effad8 add volume quicksetting with volume slider 2023-01-19 15:13:23 +01:00
171 changed files with 11577 additions and 4297 deletions

View File

@@ -4,6 +4,7 @@
#include "audio_core/renderer/adsp/command_list_processor.h"
#include "audio_core/renderer/command/effect/biquad_filter.h"
#include "audio_core/renderer/voice/voice_state.h"
#include "common/bit_cast.h"
namespace AudioCore::AudioRenderer {
/**
@@ -19,21 +20,21 @@ namespace AudioCore::AudioRenderer {
void ApplyBiquadFilterFloat(std::span<s32> output, std::span<const s32> input,
std::array<s16, 3>& b_, std::array<s16, 2>& a_,
VoiceState::BiquadFilterState& state, const u32 sample_count) {
constexpr s64 min{std::numeric_limits<s32>::min()};
constexpr s64 max{std::numeric_limits<s32>::max()};
constexpr f64 min{std::numeric_limits<s32>::min()};
constexpr f64 max{std::numeric_limits<s32>::max()};
std::array<f64, 3> b{Common::FixedPoint<50, 14>::from_base(b_[0]).to_double(),
Common::FixedPoint<50, 14>::from_base(b_[1]).to_double(),
Common::FixedPoint<50, 14>::from_base(b_[2]).to_double()};
std::array<f64, 2> a{Common::FixedPoint<50, 14>::from_base(a_[0]).to_double(),
Common::FixedPoint<50, 14>::from_base(a_[1]).to_double()};
std::array<f64, 4> s{state.s0.to_double(), state.s1.to_double(), state.s2.to_double(),
state.s3.to_double()};
std::array<f64, 4> s{Common::BitCast<f64>(state.s0), Common::BitCast<f64>(state.s1),
Common::BitCast<f64>(state.s2), Common::BitCast<f64>(state.s3)};
for (u32 i = 0; i < sample_count; i++) {
f64 in_sample{static_cast<f64>(input[i])};
auto sample{in_sample * b[0] + s[0] * b[1] + s[1] * b[2] + s[2] * a[0] + s[3] * a[1]};
output[i] = static_cast<s32>(std::clamp(static_cast<s64>(sample), min, max));
output[i] = static_cast<s32>(std::clamp(sample, min, max));
s[1] = s[0];
s[0] = in_sample;
@@ -41,10 +42,10 @@ void ApplyBiquadFilterFloat(std::span<s32> output, std::span<const s32> input,
s[2] = sample;
}
state.s0 = s[0];
state.s1 = s[1];
state.s2 = s[2];
state.s3 = s[3];
state.s0 = Common::BitCast<s64>(s[0]);
state.s1 = Common::BitCast<s64>(s[1]);
state.s2 = Common::BitCast<s64>(s[2]);
state.s3 = Common::BitCast<s64>(s[3]);
}
/**
@@ -58,29 +59,20 @@ void ApplyBiquadFilterFloat(std::span<s32> output, std::span<const s32> input,
* @param sample_count - Number of samples to process.
*/
static void ApplyBiquadFilterInt(std::span<s32> output, std::span<const s32> input,
std::array<s16, 3>& b_, std::array<s16, 2>& a_,
std::array<s16, 3>& b, std::array<s16, 2>& a,
VoiceState::BiquadFilterState& state, const u32 sample_count) {
constexpr s64 min{std::numeric_limits<s32>::min()};
constexpr s64 max{std::numeric_limits<s32>::max()};
std::array<Common::FixedPoint<50, 14>, 3> b{
Common::FixedPoint<50, 14>::from_base(b_[0]),
Common::FixedPoint<50, 14>::from_base(b_[1]),
Common::FixedPoint<50, 14>::from_base(b_[2]),
};
std::array<Common::FixedPoint<50, 14>, 3> a{
Common::FixedPoint<50, 14>::from_base(a_[0]),
Common::FixedPoint<50, 14>::from_base(a_[1]),
};
for (u32 i = 0; i < sample_count; i++) {
s64 in_sample{input[i]};
auto sample{in_sample * b[0] + state.s0};
const auto out_sample{std::clamp(sample.to_long(), min, max)};
const s64 in_sample{input[i]};
const s64 sample{in_sample * b[0] + state.s0};
const s64 out_sample{std::clamp<s64>((sample + (1 << 13)) >> 14, min, max)};
output[i] = static_cast<s32>(out_sample);
state.s0 = state.s1 + b[1] * in_sample + a[0] * out_sample;
state.s1 = 0 + b[2] * in_sample + a[1] * out_sample;
state.s1 = b[2] * in_sample + a[1] * out_sample;
}
}

View File

@@ -127,7 +127,7 @@ Result System::Initialize(const AudioRendererParameterInternal& params,
render_device = params.rendering_device;
execution_mode = params.execution_mode;
core.Memory().ZeroBlock(*core.Kernel().CurrentProcess(), transfer_memory->GetSourceAddress(),
core.Memory().ZeroBlock(*core.ApplicationProcess(), transfer_memory->GetSourceAddress(),
transfer_memory_size);
// Note: We're not actually using the transfer memory because it's a pain to code for.

View File

@@ -19,10 +19,10 @@ struct VoiceState {
* State of the voice's biquad filter.
*/
struct BiquadFilterState {
Common::FixedPoint<50, 14> s0;
Common::FixedPoint<50, 14> s1;
Common::FixedPoint<50, 14> s2;
Common::FixedPoint<50, 14> s3;
s64 s0;
s64 s1;
s64 s2;
s64 s3;
};
/**

View File

@@ -302,11 +302,21 @@ std::vector<std::string> ListCubebSinkDevices(bool capture) {
std::vector<std::string> device_list;
cubeb* ctx;
#ifdef _WIN32
auto com_init_result = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
#endif
if (cubeb_init(&ctx, "yuzu Device Enumerator", nullptr) != CUBEB_OK) {
LOG_CRITICAL(Audio_Sink, "cubeb_init failed");
return {};
}
#ifdef _WIN32
if (SUCCEEDED(com_init_result)) {
CoUninitialize();
}
#endif
auto type{capture ? CUBEB_DEVICE_TYPE_INPUT : CUBEB_DEVICE_TYPE_OUTPUT};
cubeb_device_collection collection;
if (cubeb_enumerate_devices(ctx, type, &collection) != CUBEB_OK) {
@@ -329,12 +339,22 @@ std::vector<std::string> ListCubebSinkDevices(bool capture) {
u32 GetCubebLatency() {
cubeb* ctx;
#ifdef _WIN32
auto com_init_result = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
#endif
if (cubeb_init(&ctx, "yuzu Latency Getter", nullptr) != CUBEB_OK) {
LOG_CRITICAL(Audio_Sink, "cubeb_init failed");
// Return a large latency so we choose SDL instead.
return 10000u;
}
#ifdef _WIN32
if (SUCCEEDED(com_init_result)) {
CoUninitialize();
}
#endif
cubeb_stream_params params{};
params.rate = TargetSampleRate;
params.channels = 2;

View File

@@ -270,7 +270,7 @@ void SinkStream::Stall() {
if (stalled_lock) {
return;
}
stalled_lock = system.StallProcesses();
stalled_lock = system.StallApplication();
}
void SinkStream::Unstall() {
@@ -278,7 +278,7 @@ void SinkStream::Unstall() {
if (!stalled_lock) {
return;
}
system.UnstallProcesses();
system.UnstallApplication();
stalled_lock.unlock();
}

View File

@@ -130,6 +130,8 @@ struct ButtonStatus {
bool inverted{};
// Press once to activate, press again to release
bool toggle{};
// Spams the button when active
bool turbo{};
// Internal lock for the toggle status
bool locked{};
};

View File

@@ -199,7 +199,11 @@ void RestoreGlobalState(bool is_powered_on) {
values.renderer_backend.SetGlobal(true);
values.renderer_force_max_clock.SetGlobal(true);
values.vulkan_device.SetGlobal(true);
values.fullscreen_mode.SetGlobal(true);
values.aspect_ratio.SetGlobal(true);
values.resolution_setup.SetGlobal(true);
values.scaling_filter.SetGlobal(true);
values.anti_aliasing.SetGlobal(true);
values.max_anisotropy.SetGlobal(true);
values.use_speed_limit.SetGlobal(true);
values.speed_limit.SetGlobal(true);

View File

@@ -488,6 +488,7 @@ struct Values {
Setting<bool> enable_raw_input{false, "enable_raw_input"};
Setting<bool> controller_navigation{true, "controller_navigation"};
Setting<bool> enable_joycon_driver{true, "enable_joycon_driver"};
Setting<bool> enable_procon_driver{false, "enable_procon_driver"};
SwitchableSetting<bool> vibration_enabled{true, "vibration_enabled"};
SwitchableSetting<bool> enable_accurate_vibrations{false, "enable_accurate_vibrations"};

View File

@@ -195,6 +195,8 @@ add_library(core STATIC
hle/kernel/k_condition_variable.cpp
hle/kernel/k_condition_variable.h
hle/kernel/k_debug.h
hle/kernel/k_device_address_space.cpp
hle/kernel/k_device_address_space.h
hle/kernel/k_dynamic_page_manager.h
hle/kernel/k_dynamic_resource_manager.h
hle/kernel/k_dynamic_slab_heap.h
@@ -296,7 +298,43 @@ add_library(core STATIC
hle/kernel/svc.h
hle/kernel/svc_common.h
hle/kernel/svc_types.h
hle/kernel/svc_wrap.h
hle/kernel/svc/svc_activity.cpp
hle/kernel/svc/svc_address_arbiter.cpp
hle/kernel/svc/svc_address_translation.cpp
hle/kernel/svc/svc_cache.cpp
hle/kernel/svc/svc_code_memory.cpp
hle/kernel/svc/svc_condition_variable.cpp
hle/kernel/svc/svc_debug.cpp
hle/kernel/svc/svc_debug_string.cpp
hle/kernel/svc/svc_device_address_space.cpp
hle/kernel/svc/svc_event.cpp
hle/kernel/svc/svc_exception.cpp
hle/kernel/svc/svc_info.cpp
hle/kernel/svc/svc_insecure_memory.cpp
hle/kernel/svc/svc_interrupt_event.cpp
hle/kernel/svc/svc_io_pool.cpp
hle/kernel/svc/svc_ipc.cpp
hle/kernel/svc/svc_kernel_debug.cpp
hle/kernel/svc/svc_light_ipc.cpp
hle/kernel/svc/svc_lock.cpp
hle/kernel/svc/svc_memory.cpp
hle/kernel/svc/svc_physical_memory.cpp
hle/kernel/svc/svc_port.cpp
hle/kernel/svc/svc_power_management.cpp
hle/kernel/svc/svc_process.cpp
hle/kernel/svc/svc_process_memory.cpp
hle/kernel/svc/svc_processor.cpp
hle/kernel/svc/svc_query_memory.cpp
hle/kernel/svc/svc_register.cpp
hle/kernel/svc/svc_resource_limit.cpp
hle/kernel/svc/svc_secure_monitor_call.cpp
hle/kernel/svc/svc_session.cpp
hle/kernel/svc/svc_shared_memory.cpp
hle/kernel/svc/svc_synchronization.cpp
hle/kernel/svc/svc_thread.cpp
hle/kernel/svc/svc_thread_profiler.cpp
hle/kernel/svc/svc_tick.cpp
hle/kernel/svc/svc_transfer_memory.cpp
hle/result.h
hle/service/acc/acc.cpp
hle/service/acc/acc.h

View File

@@ -43,9 +43,9 @@ void ARM_Interface::SymbolicateBacktrace(Core::System& system, std::vector<Backt
std::map<std::string, Symbols::Symbols> symbols;
for (const auto& module : modules) {
symbols.insert_or_assign(module.second,
Symbols::GetSymbols(module.first, system.Memory(),
system.CurrentProcess()->Is64BitProcess()));
symbols.insert_or_assign(
module.second, Symbols::GetSymbols(module.first, system.Memory(),
system.ApplicationProcess()->Is64BitProcess()));
}
for (auto& entry : out) {

View File

@@ -5,6 +5,7 @@
#include <array>
#include <span>
#include <string>
#include <vector>
#include <dynarmic/interface/halt_reason.h>

View File

@@ -186,7 +186,7 @@ struct System::Impl {
void Run() {
std::unique_lock<std::mutex> lk(suspend_guard);
kernel.Suspend(false);
kernel.SuspendApplication(false);
core_timing.SyncPause(false);
is_paused.store(false, std::memory_order_relaxed);
}
@@ -195,7 +195,7 @@ struct System::Impl {
std::unique_lock<std::mutex> lk(suspend_guard);
core_timing.SyncPause(true);
kernel.Suspend(true);
kernel.SuspendApplication(true);
is_paused.store(true, std::memory_order_relaxed);
}
@@ -203,17 +203,17 @@ struct System::Impl {
return is_paused.load(std::memory_order_relaxed);
}
std::unique_lock<std::mutex> StallProcesses() {
std::unique_lock<std::mutex> StallApplication() {
std::unique_lock<std::mutex> lk(suspend_guard);
kernel.Suspend(true);
kernel.SuspendApplication(true);
core_timing.SyncPause(true);
return lk;
}
void UnstallProcesses() {
void UnstallApplication() {
if (!IsPaused()) {
core_timing.SyncPause(false);
kernel.Suspend(false);
kernel.SuspendApplication(false);
}
}
@@ -221,7 +221,7 @@ struct System::Impl {
debugger = std::make_unique<Debugger>(system, port);
}
SystemResultStatus SetupForMainProcess(System& system, Frontend::EmuWindow& emu_window) {
SystemResultStatus SetupForApplicationProcess(System& system, Frontend::EmuWindow& emu_window) {
LOG_DEBUG(Core, "initialized OK");
// Setting changes may require a full system reinitialization (e.g., disabling multicore).
@@ -273,7 +273,7 @@ struct System::Impl {
return SystemResultStatus::ErrorGetLoader;
}
SystemResultStatus init_result{SetupForMainProcess(system, emu_window)};
SystemResultStatus init_result{SetupForApplicationProcess(system, emu_window)};
if (init_result != SystemResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
static_cast<int>(init_result));
@@ -302,7 +302,7 @@ struct System::Impl {
static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result));
}
AddGlueRegistrationForProcess(*app_loader, *main_process);
kernel.MakeCurrentProcess(main_process);
kernel.MakeApplicationProcess(main_process);
kernel.InitializeCores();
// Initialize cheat engine
@@ -585,12 +585,12 @@ void System::DetachDebugger() {
}
}
std::unique_lock<std::mutex> System::StallProcesses() {
return impl->StallProcesses();
std::unique_lock<std::mutex> System::StallApplication() {
return impl->StallApplication();
}
void System::UnstallProcesses() {
impl->UnstallProcesses();
void System::UnstallApplication() {
impl->UnstallApplication();
}
void System::InitializeDebugger() {
@@ -648,8 +648,8 @@ const Kernel::GlobalSchedulerContext& System::GlobalSchedulerContext() const {
return impl->kernel.GlobalSchedulerContext();
}
Kernel::KProcess* System::CurrentProcess() {
return impl->kernel.CurrentProcess();
Kernel::KProcess* System::ApplicationProcess() {
return impl->kernel.ApplicationProcess();
}
Core::DeviceMemory& System::DeviceMemory() {
@@ -660,8 +660,8 @@ const Core::DeviceMemory& System::DeviceMemory() const {
return *impl->device_memory;
}
const Kernel::KProcess* System::CurrentProcess() const {
return impl->kernel.CurrentProcess();
const Kernel::KProcess* System::ApplicationProcess() const {
return impl->kernel.ApplicationProcess();
}
ARM_Interface& System::ArmInterface(std::size_t core_index) {
@@ -760,8 +760,8 @@ const Core::SpeedLimiter& System::SpeedLimiter() const {
return impl->speed_limiter;
}
u64 System::GetCurrentProcessProgramID() const {
return impl->kernel.CurrentProcess()->GetProgramID();
u64 System::GetApplicationProcessProgramID() const {
return impl->kernel.ApplicationProcess()->GetProgramID();
}
Loader::ResultStatus System::GetGameName(std::string& out) const {
@@ -880,11 +880,11 @@ bool System::GetExitLock() const {
return impl->exit_lock;
}
void System::SetCurrentProcessBuildID(const CurrentBuildProcessID& id) {
void System::SetApplicationProcessBuildID(const CurrentBuildProcessID& id) {
impl->build_id = id;
}
const System::CurrentBuildProcessID& System::GetCurrentProcessBuildID() const {
const System::CurrentBuildProcessID& System::GetApplicationProcessBuildID() const {
return impl->build_id;
}

View File

@@ -184,8 +184,8 @@ public:
/// Forcibly detach the debugger if it is running.
void DetachDebugger();
std::unique_lock<std::mutex> StallProcesses();
void UnstallProcesses();
std::unique_lock<std::mutex> StallApplication();
void UnstallApplication();
/**
* Initialize the debugger.
@@ -295,11 +295,11 @@ public:
/// Gets the manager for the guest device memory
[[nodiscard]] const Core::DeviceMemory& DeviceMemory() const;
/// Provides a pointer to the current process
[[nodiscard]] Kernel::KProcess* CurrentProcess();
/// Provides a pointer to the application process
[[nodiscard]] Kernel::KProcess* ApplicationProcess();
/// Provides a constant pointer to the current process.
[[nodiscard]] const Kernel::KProcess* CurrentProcess() const;
/// Provides a constant pointer to the application process.
[[nodiscard]] const Kernel::KProcess* ApplicationProcess() const;
/// Provides a reference to the core timing instance.
[[nodiscard]] Timing::CoreTiming& CoreTiming();
@@ -331,7 +331,7 @@ public:
/// Provides a constant reference to the speed limiter
[[nodiscard]] const Core::SpeedLimiter& SpeedLimiter() const;
[[nodiscard]] u64 GetCurrentProcessProgramID() const;
[[nodiscard]] u64 GetApplicationProcessProgramID() const;
/// Gets the name of the current game
[[nodiscard]] Loader::ResultStatus GetGameName(std::string& out) const;
@@ -396,8 +396,8 @@ public:
void SetExitLock(bool locked);
[[nodiscard]] bool GetExitLock() const;
void SetCurrentProcessBuildID(const CurrentBuildProcessID& id);
[[nodiscard]] const CurrentBuildProcessID& GetCurrentProcessBuildID() const;
void SetApplicationProcessBuildID(const CurrentBuildProcessID& id);
[[nodiscard]] const CurrentBuildProcessID& GetApplicationProcessBuildID() const;
/// Register a host thread as an emulated CPU Core.
void RegisterCoreThread(std::size_t id);

View File

@@ -96,7 +96,7 @@ static std::string EscapeXML(std::string_view data) {
GDBStub::GDBStub(DebuggerBackend& backend_, Core::System& system_)
: DebuggerFrontend(backend_), system{system_} {
if (system.CurrentProcess()->Is64BitProcess()) {
if (system.ApplicationProcess()->Is64BitProcess()) {
arch = std::make_unique<GDBStubA64>();
} else {
arch = std::make_unique<GDBStubA32>();
@@ -340,15 +340,15 @@ void GDBStub::HandleBreakpointInsert(std::string_view command) {
success = true;
break;
case BreakpointType::WriteWatch:
success = system.CurrentProcess()->InsertWatchpoint(system, addr, size,
Kernel::DebugWatchpointType::Write);
success = system.ApplicationProcess()->InsertWatchpoint(system, addr, size,
Kernel::DebugWatchpointType::Write);
break;
case BreakpointType::ReadWatch:
success = system.CurrentProcess()->InsertWatchpoint(system, addr, size,
Kernel::DebugWatchpointType::Read);
success = system.ApplicationProcess()->InsertWatchpoint(system, addr, size,
Kernel::DebugWatchpointType::Read);
break;
case BreakpointType::AccessWatch:
success = system.CurrentProcess()->InsertWatchpoint(
success = system.ApplicationProcess()->InsertWatchpoint(
system, addr, size, Kernel::DebugWatchpointType::ReadOrWrite);
break;
case BreakpointType::Hardware:
@@ -391,15 +391,15 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) {
break;
}
case BreakpointType::WriteWatch:
success = system.CurrentProcess()->RemoveWatchpoint(system, addr, size,
Kernel::DebugWatchpointType::Write);
success = system.ApplicationProcess()->RemoveWatchpoint(system, addr, size,
Kernel::DebugWatchpointType::Write);
break;
case BreakpointType::ReadWatch:
success = system.CurrentProcess()->RemoveWatchpoint(system, addr, size,
Kernel::DebugWatchpointType::Read);
success = system.ApplicationProcess()->RemoveWatchpoint(system, addr, size,
Kernel::DebugWatchpointType::Read);
break;
case BreakpointType::AccessWatch:
success = system.CurrentProcess()->RemoveWatchpoint(
success = system.ApplicationProcess()->RemoveWatchpoint(
system, addr, size, Kernel::DebugWatchpointType::ReadOrWrite);
break;
case BreakpointType::Hardware:
@@ -482,7 +482,7 @@ static std::optional<std::string> GetNameFromThreadType64(Core::Memory::Memory&
static std::optional<std::string> GetThreadName(Core::System& system,
const Kernel::KThread* thread) {
if (system.CurrentProcess()->Is64BitProcess()) {
if (system.ApplicationProcess()->Is64BitProcess()) {
return GetNameFromThreadType64(system.Memory(), thread);
} else {
return GetNameFromThreadType32(system.Memory(), thread);
@@ -555,7 +555,7 @@ void GDBStub::HandleQuery(std::string_view command) {
SendReply(fmt::format("TextSeg={:x}", main->first));
} else {
SendReply(fmt::format("TextSeg={:x}",
system.CurrentProcess()->PageTable().GetCodeRegionStart()));
system.ApplicationProcess()->PageTable().GetCodeRegionStart()));
}
} else if (command.starts_with("Xfer:libraries:read::")) {
Loader::AppLoader::Modules modules;
@@ -729,7 +729,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) {
std::string_view command_str{reinterpret_cast<const char*>(&command[0]), command.size()};
std::string reply;
auto* process = system.CurrentProcess();
auto* process = system.ApplicationProcess();
auto& page_table = process->PageTable();
const char* commands = "Commands:\n"

View File

@@ -172,7 +172,7 @@ std::string SaveDataFactory::GetFullPath(Core::System& system, VirtualDir dir,
// be interpreted as the title id of the current process.
if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) {
if (title_id == 0) {
title_id = system.GetCurrentProcessProgramID();
title_id = system.GetApplicationProcessProgramID();
}
}

View File

@@ -12,6 +12,7 @@
namespace Core::HID {
constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
constexpr s32 HID_TRIGGER_MAX = 0x7fff;
constexpr u32 TURBO_BUTTON_DELAY = 4;
// Use a common UUID for TAS and Virtual Gamepad
constexpr Common::UUID TAS_UUID =
Common::UUID{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xA5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
@@ -447,6 +448,7 @@ void EmulatedController::ReloadInput() {
},
});
}
turbo_button_state = 0;
}
void EmulatedController::UnloadInput() {
@@ -687,6 +689,7 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback
}
current_status.toggle = new_status.toggle;
current_status.turbo = new_status.turbo;
current_status.uuid = uuid;
// Update button status with current
@@ -954,7 +957,7 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
raw_status.gyro.y.value,
raw_status.gyro.z.value,
});
emulated.SetGyroThreshold(raw_status.gyro.x.properties.threshold);
emulated.SetUserGyroThreshold(raw_status.gyro.x.properties.threshold);
emulated.UpdateRotation(raw_status.delta_timestamp);
emulated.UpdateOrientation(raw_status.delta_timestamp);
force_update_motion = raw_status.force_update;
@@ -1281,6 +1284,26 @@ void EmulatedController::SetLedPattern() {
}
}
void EmulatedController::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode mode) {
for (auto& motion : controller.motion_values) {
switch (mode) {
case GyroscopeZeroDriftMode::Loose:
motion_sensitivity = motion.emulated.IsAtRestLoose;
motion.emulated.SetGyroThreshold(motion.emulated.ThresholdLoose);
break;
case GyroscopeZeroDriftMode::Tight:
motion_sensitivity = motion.emulated.IsAtRestThight;
motion.emulated.SetGyroThreshold(motion.emulated.ThresholdThight);
break;
case GyroscopeZeroDriftMode::Standard:
default:
motion_sensitivity = motion.emulated.IsAtRestStandard;
motion.emulated.SetGyroThreshold(motion.emulated.ThresholdStandard);
break;
}
}
}
void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles) {
supported_style_tag = supported_styles;
if (!is_connected) {
@@ -1548,7 +1571,7 @@ NpadButtonState EmulatedController::GetNpadButtons() const {
if (is_configuring) {
return {};
}
return controller.npad_button_state;
return {controller.npad_button_state.raw & GetTurboButtonMask()};
}
DebugPadButton EmulatedController::GetDebugPadButtons() const {
@@ -1656,4 +1679,74 @@ void EmulatedController::DeleteCallback(int key) {
}
callback_list.erase(iterator);
}
void EmulatedController::TurboButtonUpdate() {
turbo_button_state = (turbo_button_state + 1) % (TURBO_BUTTON_DELAY * 2);
}
NpadButton EmulatedController::GetTurboButtonMask() const {
// Apply no mask when disabled
if (turbo_button_state < TURBO_BUTTON_DELAY) {
return {NpadButton::All};
}
NpadButtonState button_mask{};
for (std::size_t index = 0; index < controller.button_values.size(); ++index) {
if (!controller.button_values[index].turbo) {
continue;
}
switch (index) {
case Settings::NativeButton::A:
button_mask.a.Assign(1);
break;
case Settings::NativeButton::B:
button_mask.b.Assign(1);
break;
case Settings::NativeButton::X:
button_mask.x.Assign(1);
break;
case Settings::NativeButton::Y:
button_mask.y.Assign(1);
break;
case Settings::NativeButton::L:
button_mask.l.Assign(1);
break;
case Settings::NativeButton::R:
button_mask.r.Assign(1);
break;
case Settings::NativeButton::ZL:
button_mask.zl.Assign(1);
break;
case Settings::NativeButton::ZR:
button_mask.zr.Assign(1);
break;
case Settings::NativeButton::DLeft:
button_mask.left.Assign(1);
break;
case Settings::NativeButton::DUp:
button_mask.up.Assign(1);
break;
case Settings::NativeButton::DRight:
button_mask.right.Assign(1);
break;
case Settings::NativeButton::DDown:
button_mask.down.Assign(1);
break;
case Settings::NativeButton::SL:
button_mask.left_sl.Assign(1);
button_mask.right_sl.Assign(1);
break;
case Settings::NativeButton::SR:
button_mask.left_sr.Assign(1);
button_mask.right_sr.Assign(1);
break;
default:
break;
}
}
return static_cast<NpadButton>(~button_mask.raw);
}
} // namespace Core::HID

View File

@@ -398,6 +398,9 @@ public:
/// Asks the output device to change the player led pattern
void SetLedPattern();
/// Changes sensitivity of the motion sensor
void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode mode);
/**
* Adds a callback to the list of events
* @param update_callback A ConsoleUpdateCallback that will be triggered
@@ -411,6 +414,9 @@ public:
*/
void DeleteCallback(int key);
/// Swaps the state of the turbo buttons
void TurboButtonUpdate();
private:
/// creates input devices from params
void LoadDevices();
@@ -511,6 +517,8 @@ private:
*/
void TriggerOnChange(ControllerTriggerType type, bool is_service_update);
NpadButton GetTurboButtonMask() const;
const NpadIdType npad_id_type;
NpadStyleIndex npad_type{NpadStyleIndex::None};
NpadStyleIndex original_npad_type{NpadStyleIndex::None};
@@ -518,8 +526,9 @@ private:
bool is_connected{false};
bool is_configuring{false};
bool system_buttons_enabled{true};
f32 motion_sensitivity{0.01f};
f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard};
bool force_update_motion{false};
u32 turbo_button_state{0};
// Temporary values to avoid doing changes while the controller is in configuring mode
NpadStyleIndex tmp_npad_type{NpadStyleIndex::None};

View File

@@ -282,6 +282,13 @@ enum class VibrationGcErmCommand : u64 {
StopHard = 2,
};
// This is nn::hid::GyroscopeZeroDriftMode
enum class GyroscopeZeroDriftMode : u32 {
Loose = 0,
Standard = 1,
Tight = 2,
};
// This is nn::hid::NpadStyleTag
struct NpadStyleTag {
union {

View File

@@ -9,7 +9,7 @@ namespace Core::HID {
MotionInput::MotionInput() {
// Initialize PID constants with default values
SetPID(0.3f, 0.005f, 0.0f);
SetGyroThreshold(0.007f);
SetGyroThreshold(ThresholdStandard);
}
void MotionInput::SetPID(f32 new_kp, f32 new_ki, f32 new_kd) {
@@ -26,11 +26,11 @@ void MotionInput::SetGyroscope(const Common::Vec3f& gyroscope) {
gyro = gyroscope - gyro_bias;
// Auto adjust drift to minimize drift
if (!IsMoving(0.1f)) {
if (!IsMoving(IsAtRestRelaxed)) {
gyro_bias = (gyro_bias * 0.9999f) + (gyroscope * 0.0001f);
}
if (gyro.Length() < gyro_threshold) {
if (gyro.Length() < gyro_threshold * user_gyro_threshold) {
gyro = {};
} else {
only_accelerometer = false;
@@ -49,6 +49,10 @@ void MotionInput::SetGyroThreshold(f32 threshold) {
gyro_threshold = threshold;
}
void MotionInput::SetUserGyroThreshold(f32 threshold) {
user_gyro_threshold = threshold / ThresholdStandard;
}
void MotionInput::EnableReset(bool reset) {
reset_enabled = reset;
}
@@ -208,7 +212,7 @@ void MotionInput::ResetOrientation() {
if (!reset_enabled || only_accelerometer) {
return;
}
if (!IsMoving(0.5f) && accel.z <= -0.9f) {
if (!IsMoving(IsAtRestRelaxed) && accel.z <= -0.9f) {
++reset_counter;
if (reset_counter > 900) {
quat.w = 0;

View File

@@ -11,6 +11,15 @@ namespace Core::HID {
class MotionInput {
public:
static constexpr float ThresholdLoose = 0.01f;
static constexpr float ThresholdStandard = 0.007f;
static constexpr float ThresholdThight = 0.002f;
static constexpr float IsAtRestRelaxed = 0.05f;
static constexpr float IsAtRestLoose = 0.02f;
static constexpr float IsAtRestStandard = 0.01f;
static constexpr float IsAtRestThight = 0.005f;
explicit MotionInput();
MotionInput(const MotionInput&) = default;
@@ -26,6 +35,9 @@ public:
void SetGyroBias(const Common::Vec3f& bias);
void SetGyroThreshold(f32 threshold);
/// Applies a modifier on top of the normal gyro threshold
void SetUserGyroThreshold(f32 threshold);
void EnableReset(bool reset);
void ResetRotations();
@@ -74,6 +86,9 @@ private:
// Minimum gyro amplitude to detect if the device is moving
f32 gyro_threshold = 0.0f;
// Multiplies gyro_threshold by this value
f32 user_gyro_threshold = 0.0f;
// Number of invalid sequential data
u32 reset_counter = 0;

View File

@@ -148,7 +148,7 @@ public:
if (context->GetManager()->IsDomain()) {
context->AddDomainObject(std::move(iface));
} else {
kernel.CurrentProcess()->GetResourceLimit()->Reserve(
kernel.ApplicationProcess()->GetResourceLimit()->Reserve(
Kernel::LimitableResource::SessionCountMax, 1);
auto* session = Kernel::KSession::Create(kernel);

View File

@@ -11,6 +11,7 @@
#include "core/hle/kernel/init/init_slab_setup.h"
#include "core/hle/kernel/k_code_memory.h"
#include "core/hle/kernel/k_debug.h"
#include "core/hle/kernel/k_device_address_space.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_event_info.h"
#include "core/hle/kernel/k_memory_layout.h"
@@ -43,6 +44,7 @@ namespace Kernel::Init {
HANDLER(KSharedMemoryInfo, (SLAB_COUNT(KSharedMemory) * 8), ##__VA_ARGS__) \
HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \
HANDLER(KCodeMemory, (SLAB_COUNT(KCodeMemory)), ##__VA_ARGS__) \
HANDLER(KDeviceAddressSpace, (SLAB_COUNT(KDeviceAddressSpace)), ##__VA_ARGS__) \
HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__) \
HANDLER(KThreadLocalPage, \
(SLAB_COUNT(KProcess) + (SLAB_COUNT(KProcess) + SLAB_COUNT(KThread)) / 8), \

View File

@@ -203,23 +203,23 @@ Result KCapabilities::ProcessMapRegionCapability(const u32 cap, F f) {
Result KCapabilities::MapRegion_(const u32 cap, KPageTable* page_table) {
// Map each region into the process's page table.
R_RETURN(ProcessMapRegionCapability(
return ProcessMapRegionCapability(
cap, [](KMemoryRegionType region_type, KMemoryPermission perm) -> Result {
// R_RETURN(page_table->MapRegion(region_type, perm));
UNIMPLEMENTED();
R_SUCCEED();
}));
});
}
Result KCapabilities::CheckMapRegion(KernelCore& kernel, const u32 cap) {
// Check that each region has a physical backing store.
R_RETURN(ProcessMapRegionCapability(
return ProcessMapRegionCapability(
cap, [&](KMemoryRegionType region_type, KMemoryPermission perm) -> Result {
R_UNLESS(kernel.MemoryLayout().GetPhysicalMemoryRegionTree().FindFirstDerived(
region_type) != nullptr,
ResultOutOfRange);
R_SUCCEED();
}));
});
}
Result KCapabilities::SetInterruptPairCapability(const u32 cap) {

View File

@@ -60,7 +60,8 @@ bool KClientPort::IsSignaled() const {
Result KClientPort::CreateSession(KClientSession** out) {
// Reserve a new session from the resource limit.
KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(),
//! FIXME: we are reserving this from the wrong resource limit!
KScopedResourceReservation session_reservation(kernel.ApplicationProcess()->GetResourceLimit(),
LimitableResource::SessionCountMax);
R_UNLESS(session_reservation.Succeeded(), ResultLimitReached);

View File

@@ -21,7 +21,7 @@ KCodeMemory::KCodeMemory(KernelCore& kernel_)
Result KCodeMemory::Initialize(Core::DeviceMemory& device_memory, VAddr addr, size_t size) {
// Set members.
m_owner = kernel.CurrentProcess();
m_owner = GetCurrentProcessPointer(kernel);
// Get the owner page table.
auto& page_table = m_owner->PageTable();
@@ -74,7 +74,7 @@ Result KCodeMemory::Map(VAddr address, size_t size) {
R_UNLESS(!m_is_mapped, ResultInvalidState);
// Map the memory.
R_TRY(kernel.CurrentProcess()->PageTable().MapPageGroup(
R_TRY(GetCurrentProcess(kernel).PageTable().MapPageGroup(
address, *m_page_group, KMemoryState::CodeOut, KMemoryPermission::UserReadWrite));
// Mark ourselves as mapped.
@@ -91,8 +91,8 @@ Result KCodeMemory::Unmap(VAddr address, size_t size) {
KScopedLightLock lk(m_lock);
// Unmap the memory.
R_TRY(kernel.CurrentProcess()->PageTable().UnmapPageGroup(address, *m_page_group,
KMemoryState::CodeOut));
R_TRY(GetCurrentProcess(kernel).PageTable().UnmapPageGroup(address, *m_page_group,
KMemoryState::CodeOut));
// Mark ourselves as unmapped.
m_is_mapped = false;

View File

@@ -164,8 +164,8 @@ Result KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value)
R_SUCCEED_IF(test_tag != (handle | Svc::HandleWaitMask));
// Get the lock owner thread.
owner_thread = kernel.CurrentProcess()
->GetHandleTable()
owner_thread = GetCurrentProcess(kernel)
.GetHandleTable()
.GetObjectWithoutPseudoHandle<KThread>(handle)
.ReleasePointerUnsafe();
R_UNLESS(owner_thread != nullptr, ResultInvalidHandle);
@@ -213,8 +213,8 @@ void KConditionVariable::SignalImpl(KThread* thread) {
thread->EndWait(ResultSuccess);
} else {
// Get the previous owner.
KThread* owner_thread = kernel.CurrentProcess()
->GetHandleTable()
KThread* owner_thread = GetCurrentProcess(kernel)
.GetHandleTable()
.GetObjectWithoutPseudoHandle<KThread>(
static_cast<Handle>(prev_tag & ~Svc::HandleWaitMask))
.ReleasePointerUnsafe();

View File

@@ -0,0 +1,150 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/assert.h"
#include "core/core.h"
#include "core/hle/kernel/k_device_address_space.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/svc_results.h"
namespace Kernel {
KDeviceAddressSpace::KDeviceAddressSpace(KernelCore& kernel_)
: KAutoObjectWithSlabHeapAndContainer(kernel_), m_lock(kernel_), m_is_initialized(false) {}
KDeviceAddressSpace::~KDeviceAddressSpace() = default;
void KDeviceAddressSpace::Initialize() {
// This just forwards to the device page table manager.
// KDevicePageTable::Initialize();
}
// Member functions.
Result KDeviceAddressSpace::Initialize(u64 address, u64 size) {
// Initialize the device page table.
// R_TRY(m_table.Initialize(address, size));
// Set member variables.
m_space_address = address;
m_space_size = size;
m_is_initialized = true;
R_SUCCEED();
}
void KDeviceAddressSpace::Finalize() {
// Finalize the table.
// m_table.Finalize();
}
Result KDeviceAddressSpace::Attach(Svc::DeviceName device_name) {
// Lock the address space.
KScopedLightLock lk(m_lock);
// Attach.
// R_RETURN(m_table.Attach(device_name, m_space_address, m_space_size));
R_SUCCEED();
}
Result KDeviceAddressSpace::Detach(Svc::DeviceName device_name) {
// Lock the address space.
KScopedLightLock lk(m_lock);
// Detach.
// R_RETURN(m_table.Detach(device_name));
R_SUCCEED();
}
Result KDeviceAddressSpace::Map(KPageTable* page_table, VAddr process_address, size_t size,
u64 device_address, u32 option, bool is_aligned) {
// Check that the address falls within the space.
R_UNLESS((m_space_address <= device_address &&
device_address + size - 1 <= m_space_address + m_space_size - 1),
ResultInvalidCurrentMemory);
// Decode the option.
const Svc::MapDeviceAddressSpaceOption option_pack{option};
const auto device_perm = option_pack.permission.Value();
const auto flags = option_pack.flags.Value();
const auto reserved = option_pack.reserved.Value();
// Validate the option.
// TODO: It is likely that this check for flags == none is only on NX board.
R_UNLESS(flags == Svc::MapDeviceAddressSpaceFlag::None, ResultInvalidEnumValue);
R_UNLESS(reserved == 0, ResultInvalidEnumValue);
// Lock the address space.
KScopedLightLock lk(m_lock);
// Lock the page table to prevent concurrent device mapping operations.
// KScopedLightLock pt_lk = page_table->AcquireDeviceMapLock();
// Lock the pages.
bool is_io{};
R_TRY(page_table->LockForMapDeviceAddressSpace(std::addressof(is_io), process_address, size,
ConvertToKMemoryPermission(device_perm),
is_aligned, true));
// Ensure that if we fail, we don't keep unmapped pages locked.
ON_RESULT_FAILURE {
ASSERT(page_table->UnlockForDeviceAddressSpace(process_address, size) == ResultSuccess);
};
// Check that the io status is allowable.
if (is_io) {
R_UNLESS(static_cast<u32>(flags & Svc::MapDeviceAddressSpaceFlag::NotIoRegister) == 0,
ResultInvalidCombination);
}
// Map the pages.
{
// Perform the mapping.
// R_TRY(m_table.Map(page_table, process_address, size, device_address, device_perm,
// is_aligned, is_io));
// Ensure that we unmap the pages if we fail to update the protections.
// NOTE: Nintendo does not check the result of this unmap call.
// ON_RESULT_FAILURE { m_table.Unmap(device_address, size); };
// Update the protections in accordance with how much we mapped.
// R_TRY(page_table->UnlockForDeviceAddressSpacePartialMap(process_address, size));
}
// We succeeded.
R_SUCCEED();
}
Result KDeviceAddressSpace::Unmap(KPageTable* page_table, VAddr process_address, size_t size,
u64 device_address) {
// Check that the address falls within the space.
R_UNLESS((m_space_address <= device_address &&
device_address + size - 1 <= m_space_address + m_space_size - 1),
ResultInvalidCurrentMemory);
// Lock the address space.
KScopedLightLock lk(m_lock);
// Lock the page table to prevent concurrent device mapping operations.
// KScopedLightLock pt_lk = page_table->AcquireDeviceMapLock();
// Lock the pages.
R_TRY(page_table->LockForUnmapDeviceAddressSpace(process_address, size, true));
// Unmap the pages.
{
// If we fail to unmap, we want to do a partial unlock.
// ON_RESULT_FAILURE {
// ASSERT(page_table->UnlockForDeviceAddressSpacePartialMap(process_address, size) ==
// ResultSuccess);
// };
// Perform the unmap.
// R_TRY(m_table.Unmap(page_table, process_address, size, device_address));
}
// Unlock the pages.
ASSERT(page_table->UnlockForDeviceAddressSpace(process_address, size) == ResultSuccess);
R_SUCCEED();
}
} // namespace Kernel

View File

@@ -0,0 +1,60 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <string>
#include "common/common_types.h"
#include "core/hle/kernel/k_page_table.h"
#include "core/hle/kernel/slab_helpers.h"
#include "core/hle/result.h"
namespace Kernel {
class KDeviceAddressSpace final
: public KAutoObjectWithSlabHeapAndContainer<KDeviceAddressSpace, KAutoObjectWithList> {
KERNEL_AUTOOBJECT_TRAITS(KDeviceAddressSpace, KAutoObject);
public:
explicit KDeviceAddressSpace(KernelCore& kernel);
~KDeviceAddressSpace();
Result Initialize(u64 address, u64 size);
void Finalize();
bool IsInitialized() const {
return m_is_initialized;
}
static void PostDestroy(uintptr_t arg) {}
Result Attach(Svc::DeviceName device_name);
Result Detach(Svc::DeviceName device_name);
Result MapByForce(KPageTable* page_table, VAddr process_address, size_t size,
u64 device_address, u32 option) {
R_RETURN(this->Map(page_table, process_address, size, device_address, option, false));
}
Result MapAligned(KPageTable* page_table, VAddr process_address, size_t size,
u64 device_address, u32 option) {
R_RETURN(this->Map(page_table, process_address, size, device_address, option, true));
}
Result Unmap(KPageTable* page_table, VAddr process_address, size_t size, u64 device_address);
static void Initialize();
private:
Result Map(KPageTable* page_table, VAddr process_address, size_t size, u64 device_address,
u32 option, bool is_aligned);
private:
KLightLock m_lock;
// KDevicePageTable m_table;
u64 m_space_address{};
u64 m_space_size{};
bool m_is_initialized{};
};
} // namespace Kernel

View File

@@ -90,7 +90,8 @@ public:
// Handle pseudo-handles.
if constexpr (std::derived_from<KProcess, T>) {
if (handle == Svc::PseudoHandle::CurrentProcess) {
auto* const cur_process = m_kernel.CurrentProcess();
//! FIXME: this is the wrong process!
auto* const cur_process = m_kernel.ApplicationProcess();
ASSERT(cur_process != nullptr);
return cur_process;
}

View File

@@ -16,7 +16,7 @@ void HandleInterrupt(KernelCore& kernel, s32 core_id) {
auto& current_thread = GetCurrentThread(kernel);
if (auto* process = kernel.CurrentProcess(); process) {
if (auto* process = GetCurrentProcessPointer(kernel); process) {
// If the user disable count is set, we may need to pin the current thread.
if (current_thread.GetUserDisableCount() && !process->GetPinnedThread(core_id)) {
KScopedSchedulerLock sl{kernel};

View File

@@ -370,7 +370,7 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
// Initialize proces address space
if (const Result result{page_table.InitializeForProcess(
metadata.GetAddressSpaceType(), false, false, false, KMemoryManager::Pool::Application,
0x8000000, code_size, &kernel.GetSystemSystemResource(), resource_limit)};
0x8000000, code_size, &kernel.GetAppSystemResource(), resource_limit)};
result.IsError()) {
R_RETURN(result);
}

View File

@@ -328,7 +328,7 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) {
}
void KScheduler::SwitchThread(KThread* next_thread) {
KProcess* const cur_process = kernel.CurrentProcess();
KProcess* const cur_process = GetCurrentProcessPointer(kernel);
KThread* const cur_thread = GetCurrentThreadPointer(kernel);
// We never want to schedule a null thread, so use the idle thread if we don't have a next.
@@ -689,11 +689,11 @@ void KScheduler::RotateScheduledQueue(KernelCore& kernel, s32 core_id, s32 prior
void KScheduler::YieldWithoutCoreMigration(KernelCore& kernel) {
// Validate preconditions.
ASSERT(CanSchedule(kernel));
ASSERT(kernel.CurrentProcess() != nullptr);
ASSERT(GetCurrentProcessPointer(kernel) != nullptr);
// Get the current thread and process.
KThread& cur_thread = GetCurrentThread(kernel);
KProcess& cur_process = *kernel.CurrentProcess();
KProcess& cur_process = GetCurrentProcess(kernel);
// If the thread's yield count matches, there's nothing for us to do.
if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) {
@@ -728,11 +728,11 @@ void KScheduler::YieldWithoutCoreMigration(KernelCore& kernel) {
void KScheduler::YieldWithCoreMigration(KernelCore& kernel) {
// Validate preconditions.
ASSERT(CanSchedule(kernel));
ASSERT(kernel.CurrentProcess() != nullptr);
ASSERT(GetCurrentProcessPointer(kernel) != nullptr);
// Get the current thread and process.
KThread& cur_thread = GetCurrentThread(kernel);
KProcess& cur_process = *kernel.CurrentProcess();
KProcess& cur_process = GetCurrentProcess(kernel);
// If the thread's yield count matches, there's nothing for us to do.
if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) {
@@ -816,11 +816,11 @@ void KScheduler::YieldWithCoreMigration(KernelCore& kernel) {
void KScheduler::YieldToAnyThread(KernelCore& kernel) {
// Validate preconditions.
ASSERT(CanSchedule(kernel));
ASSERT(kernel.CurrentProcess() != nullptr);
ASSERT(GetCurrentProcessPointer(kernel) != nullptr);
// Get the current thread and process.
KThread& cur_thread = GetCurrentThread(kernel);
KProcess& cur_process = *kernel.CurrentProcess();
KProcess& cur_process = GetCurrentProcess(kernel);
// If the thread's yield count matches, there's nothing for us to do.
if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) {

View File

@@ -33,7 +33,8 @@ void KSession::Initialize(KClientPort* port_, const std::string& name_) {
name = name_;
// Set our owner process.
process = kernel.CurrentProcess();
//! FIXME: this is the wrong process!
process = kernel.ApplicationProcess();
process->Open();
// Set our port.

View File

@@ -1266,6 +1266,14 @@ KThread& GetCurrentThread(KernelCore& kernel) {
return *GetCurrentThreadPointer(kernel);
}
KProcess* GetCurrentProcessPointer(KernelCore& kernel) {
return GetCurrentThread(kernel).GetOwnerProcess();
}
KProcess& GetCurrentProcess(KernelCore& kernel) {
return *GetCurrentProcessPointer(kernel);
}
s32 GetCurrentCoreId(KernelCore& kernel) {
return GetCurrentThread(kernel).GetCurrentCore();
}

View File

@@ -110,6 +110,8 @@ enum class StepState : u32 {
void SetCurrentThread(KernelCore& kernel, KThread* thread);
[[nodiscard]] KThread* GetCurrentThreadPointer(KernelCore& kernel);
[[nodiscard]] KThread& GetCurrentThread(KernelCore& kernel);
[[nodiscard]] KProcess* GetCurrentProcessPointer(KernelCore& kernel);
[[nodiscard]] KProcess& GetCurrentProcess(KernelCore& kernel);
[[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel);
class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KWorkerTask>,

View File

@@ -16,7 +16,7 @@ KTransferMemory::~KTransferMemory() = default;
Result KTransferMemory::Initialize(VAddr address_, std::size_t size_,
Svc::MemoryPermission owner_perm_) {
// Set members.
owner = kernel.CurrentProcess();
owner = GetCurrentProcessPointer(kernel);
// TODO(bunnei): Lock for transfer memory

View File

@@ -102,13 +102,13 @@ struct KernelCore::Impl {
void InitializeCores() {
for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
cores[core_id]->Initialize((*current_process).Is64BitProcess());
system.Memory().SetCurrentPageTable(*current_process, core_id);
cores[core_id]->Initialize((*application_process).Is64BitProcess());
system.Memory().SetCurrentPageTable(*application_process, core_id);
}
}
void CloseCurrentProcess() {
KProcess* old_process = current_process.exchange(nullptr);
void CloseApplicationProcess() {
KProcess* old_process = application_process.exchange(nullptr);
if (old_process == nullptr) {
return;
}
@@ -182,7 +182,7 @@ struct KernelCore::Impl {
}
}
CloseCurrentProcess();
CloseApplicationProcess();
// Track kernel objects that were not freed on shutdown
{
@@ -363,8 +363,8 @@ struct KernelCore::Impl {
}
}
void MakeCurrentProcess(KProcess* process) {
current_process = process;
void MakeApplicationProcess(KProcess* process) {
application_process = process;
}
static inline thread_local u32 host_thread_id = UINT32_MAX;
@@ -821,7 +821,7 @@ struct KernelCore::Impl {
// Lists all processes that exist in the current session.
std::vector<KProcess*> process_list;
std::atomic<KProcess*> current_process{};
std::atomic<KProcess*> application_process{};
std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context;
std::unique_ptr<Kernel::KHardwareTimer> hardware_timer;
@@ -941,20 +941,20 @@ void KernelCore::AppendNewProcess(KProcess* process) {
impl->process_list.push_back(process);
}
void KernelCore::MakeCurrentProcess(KProcess* process) {
impl->MakeCurrentProcess(process);
void KernelCore::MakeApplicationProcess(KProcess* process) {
impl->MakeApplicationProcess(process);
}
KProcess* KernelCore::CurrentProcess() {
return impl->current_process;
KProcess* KernelCore::ApplicationProcess() {
return impl->application_process;
}
const KProcess* KernelCore::CurrentProcess() const {
return impl->current_process;
const KProcess* KernelCore::ApplicationProcess() const {
return impl->application_process;
}
void KernelCore::CloseCurrentProcess() {
impl->CloseCurrentProcess();
void KernelCore::CloseApplicationProcess() {
impl->CloseApplicationProcess();
}
const std::vector<KProcess*>& KernelCore::GetProcessList() const {
@@ -1146,6 +1146,14 @@ const KMemoryManager& KernelCore::MemoryManager() const {
return *impl->memory_manager;
}
KSystemResource& KernelCore::GetAppSystemResource() {
return *impl->app_system_resource;
}
const KSystemResource& KernelCore::GetAppSystemResource() const {
return *impl->app_system_resource;
}
KSystemResource& KernelCore::GetSystemSystemResource() {
return *impl->sys_system_resource;
}
@@ -1194,12 +1202,12 @@ const Kernel::KSharedMemory& KernelCore::GetHidBusSharedMem() const {
return *impl->hidbus_shared_mem;
}
void KernelCore::Suspend(bool suspended) {
void KernelCore::SuspendApplication(bool suspended) {
const bool should_suspend{exception_exited || suspended};
const auto activity = should_suspend ? ProcessActivity::Paused : ProcessActivity::Runnable;
//! This refers to the application process, not the current process.
KScopedAutoObject<KProcess> process = CurrentProcess();
// Get the application process.
KScopedAutoObject<KProcess> process = ApplicationProcess();
if (process.IsNull()) {
return;
}
@@ -1210,8 +1218,8 @@ void KernelCore::Suspend(bool suspended) {
// Wait for process execution to stop.
bool must_wait{should_suspend};
// KernelCore::Suspend must be called from locked context, or we
// could race another call to SetActivity, interfering with waiting.
// KernelCore::SuspendApplication must be called from locked context,
// or we could race another call to SetActivity, interfering with waiting.
while (must_wait) {
KScopedSchedulerLock sl{*this};
@@ -1245,9 +1253,9 @@ bool KernelCore::IsShuttingDown() const {
return impl->IsShuttingDown();
}
void KernelCore::ExceptionalExit() {
void KernelCore::ExceptionalExitApplication() {
exception_exited = true;
Suspend(true);
SuspendApplication(true);
}
void KernelCore::EnterSVCProfile() {

View File

@@ -35,6 +35,7 @@ class GlobalSchedulerContext;
class KAutoObjectWithListContainer;
class KClientSession;
class KDebug;
class KDeviceAddressSpace;
class KDynamicPageManager;
class KEvent;
class KEventInfo;
@@ -130,17 +131,17 @@ public:
/// Adds the given shared pointer to an internal list of active processes.
void AppendNewProcess(KProcess* process);
/// Makes the given process the new current process.
void MakeCurrentProcess(KProcess* process);
/// Makes the given process the new application process.
void MakeApplicationProcess(KProcess* process);
/// Retrieves a pointer to the current process.
KProcess* CurrentProcess();
/// Retrieves a pointer to the application process.
KProcess* ApplicationProcess();
/// Retrieves a const pointer to the current process.
const KProcess* CurrentProcess() const;
/// Retrieves a const pointer to the application process.
const KProcess* ApplicationProcess() const;
/// Closes the current process.
void CloseCurrentProcess();
/// Closes the application process.
void CloseApplicationProcess();
/// Retrieves the list of processes.
const std::vector<KProcess*>& GetProcessList() const;
@@ -245,6 +246,12 @@ public:
/// Gets the virtual memory manager for the kernel.
const KMemoryManager& MemoryManager() const;
/// Gets the application resource manager.
KSystemResource& GetAppSystemResource();
/// Gets the application resource manager.
const KSystemResource& GetAppSystemResource() const;
/// Gets the system resource manager.
KSystemResource& GetSystemSystemResource();
@@ -281,11 +288,11 @@ public:
/// Gets the shared memory object for HIDBus services.
const Kernel::KSharedMemory& GetHidBusSharedMem() const;
/// Suspend/unsuspend all processes.
void Suspend(bool suspend);
/// Suspend/unsuspend application process.
void SuspendApplication(bool suspend);
/// Exceptional exit all processes.
void ExceptionalExit();
/// Exceptional exit application process.
void ExceptionalExitApplication();
/// Notify emulated CPU cores to shut down.
void ShutdownCores();
@@ -359,6 +366,8 @@ public:
return slab_heap_container->transfer_memory;
} else if constexpr (std::is_same_v<T, KCodeMemory>) {
return slab_heap_container->code_memory;
} else if constexpr (std::is_same_v<T, KDeviceAddressSpace>) {
return slab_heap_container->device_address_space;
} else if constexpr (std::is_same_v<T, KPageBuffer>) {
return slab_heap_container->page_buffer;
} else if constexpr (std::is_same_v<T, KThreadLocalPage>) {
@@ -431,6 +440,7 @@ private:
KSlabHeap<KThread> thread;
KSlabHeap<KTransferMemory> transfer_memory;
KSlabHeap<KCodeMemory> code_memory;
KSlabHeap<KDeviceAddressSpace> device_address_space;
KSlabHeap<KPageBuffer> page_buffer;
KSlabHeap<KThreadLocalPage> thread_local_page;
KSlabHeap<KSessionRequest> session_request;

View File

@@ -3,6 +3,7 @@
#pragma once
#include <condition_variable>
#include <cstddef>
#include <memory>
#include <mutex>

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +1,536 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
// This file is automatically generated using svc_generator.py.
#include "common/common_types.h"
#pragma once
namespace Core {
class System;
}
#include "common/common_types.h"
#include "core/hle/kernel/svc_types.h"
#include "core/hle/result.h"
namespace Kernel::Svc {
void Call(Core::System& system, u32 immediate);
// clang-format off
Result SetHeapSize(Core::System& system, uintptr_t* out_address, uint64_t size);
Result SetMemoryPermission(Core::System& system, uint64_t address, uint64_t size, MemoryPermission perm);
Result SetMemoryAttribute(Core::System& system, uint64_t address, uint64_t size, uint32_t mask, uint32_t attr);
Result MapMemory(Core::System& system, uint64_t dst_address, uint64_t src_address, uint64_t size);
Result UnmapMemory(Core::System& system, uint64_t dst_address, uint64_t src_address, uint64_t size);
Result QueryMemory(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info, uint64_t address);
void ExitProcess(Core::System& system);
Result CreateThread(Core::System& system, Handle* out_handle, uint64_t func, uint64_t arg, uint64_t stack_bottom, int32_t priority, int32_t core_id);
Result StartThread(Core::System& system, Handle thread_handle);
void ExitThread(Core::System& system);
void SleepThread(Core::System& system, int64_t ns);
Result GetThreadPriority(Core::System& system, int32_t* out_priority, Handle thread_handle);
Result SetThreadPriority(Core::System& system, Handle thread_handle, int32_t priority);
Result GetThreadCoreMask(Core::System& system, int32_t* out_core_id, uint64_t* out_affinity_mask, Handle thread_handle);
Result SetThreadCoreMask(Core::System& system, Handle thread_handle, int32_t core_id, uint64_t affinity_mask);
int32_t GetCurrentProcessorNumber(Core::System& system);
Result SignalEvent(Core::System& system, Handle event_handle);
Result ClearEvent(Core::System& system, Handle event_handle);
Result MapSharedMemory(Core::System& system, Handle shmem_handle, uint64_t address, uint64_t size, MemoryPermission map_perm);
Result UnmapSharedMemory(Core::System& system, Handle shmem_handle, uint64_t address, uint64_t size);
Result CreateTransferMemory(Core::System& system, Handle* out_handle, uint64_t address, uint64_t size, MemoryPermission map_perm);
Result CloseHandle(Core::System& system, Handle handle);
Result ResetSignal(Core::System& system, Handle handle);
Result WaitSynchronization(Core::System& system, int32_t* out_index, uint64_t handles, int32_t num_handles, int64_t timeout_ns);
Result CancelSynchronization(Core::System& system, Handle handle);
Result ArbitrateLock(Core::System& system, Handle thread_handle, uint64_t address, uint32_t tag);
Result ArbitrateUnlock(Core::System& system, uint64_t address);
Result WaitProcessWideKeyAtomic(Core::System& system, uint64_t address, uint64_t cv_key, uint32_t tag, int64_t timeout_ns);
void SignalProcessWideKey(Core::System& system, uint64_t cv_key, int32_t count);
int64_t GetSystemTick(Core::System& system);
Result ConnectToNamedPort(Core::System& system, Handle* out_handle, uint64_t name);
Result SendSyncRequest(Core::System& system, Handle session_handle);
Result SendSyncRequestWithUserBuffer(Core::System& system, uint64_t message_buffer, uint64_t message_buffer_size, Handle session_handle);
Result SendAsyncRequestWithUserBuffer(Core::System& system, Handle* out_event_handle, uint64_t message_buffer, uint64_t message_buffer_size, Handle session_handle);
Result GetProcessId(Core::System& system, uint64_t* out_process_id, Handle process_handle);
Result GetThreadId(Core::System& system, uint64_t* out_thread_id, Handle thread_handle);
void Break(Core::System& system, BreakReason break_reason, uint64_t arg, uint64_t size);
Result OutputDebugString(Core::System& system, uint64_t debug_str, uint64_t len);
void ReturnFromException(Core::System& system, Result result);
Result GetInfo(Core::System& system, uint64_t* out, InfoType info_type, Handle handle, uint64_t info_subtype);
void FlushEntireDataCache(Core::System& system);
Result FlushDataCache(Core::System& system, uint64_t address, uint64_t size);
Result MapPhysicalMemory(Core::System& system, uint64_t address, uint64_t size);
Result UnmapPhysicalMemory(Core::System& system, uint64_t address, uint64_t size);
Result GetDebugFutureThreadInfo(Core::System& system, lp64::LastThreadContext* out_context, uint64_t* out_thread_id, Handle debug_handle, int64_t ns);
Result GetLastThreadInfo(Core::System& system, lp64::LastThreadContext* out_context, uintptr_t* out_tls_address, uint32_t* out_flags);
Result GetResourceLimitLimitValue(Core::System& system, int64_t* out_limit_value, Handle resource_limit_handle, LimitableResource which);
Result GetResourceLimitCurrentValue(Core::System& system, int64_t* out_current_value, Handle resource_limit_handle, LimitableResource which);
Result SetThreadActivity(Core::System& system, Handle thread_handle, ThreadActivity thread_activity);
Result GetThreadContext3(Core::System& system, uint64_t out_context, Handle thread_handle);
Result WaitForAddress(Core::System& system, uint64_t address, ArbitrationType arb_type, int32_t value, int64_t timeout_ns);
Result SignalToAddress(Core::System& system, uint64_t address, SignalType signal_type, int32_t value, int32_t count);
void SynchronizePreemptionState(Core::System& system);
Result GetResourceLimitPeakValue(Core::System& system, int64_t* out_peak_value, Handle resource_limit_handle, LimitableResource which);
Result CreateIoPool(Core::System& system, Handle* out_handle, IoPoolType which);
Result CreateIoRegion(Core::System& system, Handle* out_handle, Handle io_pool, uint64_t physical_address, uint64_t size, MemoryMapping mapping, MemoryPermission perm);
void KernelDebug(Core::System& system, KernelDebugType kern_debug_type, uint64_t arg0, uint64_t arg1, uint64_t arg2);
void ChangeKernelTraceState(Core::System& system, KernelTraceState kern_trace_state);
Result CreateSession(Core::System& system, Handle* out_server_session_handle, Handle* out_client_session_handle, bool is_light, uint64_t name);
Result AcceptSession(Core::System& system, Handle* out_handle, Handle port);
Result ReplyAndReceive(Core::System& system, int32_t* out_index, uint64_t handles, int32_t num_handles, Handle reply_target, int64_t timeout_ns);
Result ReplyAndReceiveWithUserBuffer(Core::System& system, int32_t* out_index, uint64_t message_buffer, uint64_t message_buffer_size, uint64_t handles, int32_t num_handles, Handle reply_target, int64_t timeout_ns);
Result CreateEvent(Core::System& system, Handle* out_write_handle, Handle* out_read_handle);
Result MapIoRegion(Core::System& system, Handle io_region, uint64_t address, uint64_t size, MemoryPermission perm);
Result UnmapIoRegion(Core::System& system, Handle io_region, uint64_t address, uint64_t size);
Result MapPhysicalMemoryUnsafe(Core::System& system, uint64_t address, uint64_t size);
Result UnmapPhysicalMemoryUnsafe(Core::System& system, uint64_t address, uint64_t size);
Result SetUnsafeLimit(Core::System& system, uint64_t limit);
Result CreateCodeMemory(Core::System& system, Handle* out_handle, uint64_t address, uint64_t size);
Result ControlCodeMemory(Core::System& system, Handle code_memory_handle, CodeMemoryOperation operation, uint64_t address, uint64_t size, MemoryPermission perm);
void SleepSystem(Core::System& system);
Result ReadWriteRegister(Core::System& system, uint32_t* out_value, uint64_t address, uint32_t mask, uint32_t value);
Result SetProcessActivity(Core::System& system, Handle process_handle, ProcessActivity process_activity);
Result CreateSharedMemory(Core::System& system, Handle* out_handle, uint64_t size, MemoryPermission owner_perm, MemoryPermission remote_perm);
Result MapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t address, uint64_t size, MemoryPermission owner_perm);
Result UnmapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t address, uint64_t size);
Result CreateInterruptEvent(Core::System& system, Handle* out_read_handle, int32_t interrupt_id, InterruptType interrupt_type);
Result QueryPhysicalAddress(Core::System& system, lp64::PhysicalMemoryInfo* out_info, uint64_t address);
Result QueryIoMapping(Core::System& system, uintptr_t* out_address, uintptr_t* out_size, uint64_t physical_address, uint64_t size);
Result CreateDeviceAddressSpace(Core::System& system, Handle* out_handle, uint64_t das_address, uint64_t das_size);
Result AttachDeviceAddressSpace(Core::System& system, DeviceName device_name, Handle das_handle);
Result DetachDeviceAddressSpace(Core::System& system, DeviceName device_name, Handle das_handle);
Result MapDeviceAddressSpaceByForce(Core::System& system, Handle das_handle, Handle process_handle, uint64_t process_address, uint64_t size, uint64_t device_address, uint32_t option);
Result MapDeviceAddressSpaceAligned(Core::System& system, Handle das_handle, Handle process_handle, uint64_t process_address, uint64_t size, uint64_t device_address, uint32_t option);
Result UnmapDeviceAddressSpace(Core::System& system, Handle das_handle, Handle process_handle, uint64_t process_address, uint64_t size, uint64_t device_address);
Result InvalidateProcessDataCache(Core::System& system, Handle process_handle, uint64_t address, uint64_t size);
Result StoreProcessDataCache(Core::System& system, Handle process_handle, uint64_t address, uint64_t size);
Result FlushProcessDataCache(Core::System& system, Handle process_handle, uint64_t address, uint64_t size);
Result DebugActiveProcess(Core::System& system, Handle* out_handle, uint64_t process_id);
Result BreakDebugProcess(Core::System& system, Handle debug_handle);
Result TerminateDebugProcess(Core::System& system, Handle debug_handle);
Result GetDebugEvent(Core::System& system, uint64_t out_info, Handle debug_handle);
Result ContinueDebugEvent(Core::System& system, Handle debug_handle, uint32_t flags, uint64_t thread_ids, int32_t num_thread_ids);
Result GetProcessList(Core::System& system, int32_t* out_num_processes, uint64_t out_process_ids, int32_t max_out_count);
Result GetThreadList(Core::System& system, int32_t* out_num_threads, uint64_t out_thread_ids, int32_t max_out_count, Handle debug_handle);
Result GetDebugThreadContext(Core::System& system, uint64_t out_context, Handle debug_handle, uint64_t thread_id, uint32_t context_flags);
Result SetDebugThreadContext(Core::System& system, Handle debug_handle, uint64_t thread_id, uint64_t context, uint32_t context_flags);
Result QueryDebugProcessMemory(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info, Handle process_handle, uint64_t address);
Result ReadDebugProcessMemory(Core::System& system, uint64_t buffer, Handle debug_handle, uint64_t address, uint64_t size);
Result WriteDebugProcessMemory(Core::System& system, Handle debug_handle, uint64_t buffer, uint64_t address, uint64_t size);
Result SetHardwareBreakPoint(Core::System& system, HardwareBreakPointRegisterName name, uint64_t flags, uint64_t value);
Result GetDebugThreadParam(Core::System& system, uint64_t* out_64, uint32_t* out_32, Handle debug_handle, uint64_t thread_id, DebugThreadParam param);
Result GetSystemInfo(Core::System& system, uint64_t* out, SystemInfoType info_type, Handle handle, uint64_t info_subtype);
Result CreatePort(Core::System& system, Handle* out_server_handle, Handle* out_client_handle, int32_t max_sessions, bool is_light, uint64_t name);
Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t name, int32_t max_sessions);
Result ConnectToPort(Core::System& system, Handle* out_handle, Handle port);
Result SetProcessMemoryPermission(Core::System& system, Handle process_handle, uint64_t address, uint64_t size, MemoryPermission perm);
Result MapProcessMemory(Core::System& system, uint64_t dst_address, Handle process_handle, uint64_t src_address, uint64_t size);
Result UnmapProcessMemory(Core::System& system, uint64_t dst_address, Handle process_handle, uint64_t src_address, uint64_t size);
Result QueryProcessMemory(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info, Handle process_handle, uint64_t address);
Result MapProcessCodeMemory(Core::System& system, Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size);
Result UnmapProcessCodeMemory(Core::System& system, Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size);
Result CreateProcess(Core::System& system, Handle* out_handle, uint64_t parameters, uint64_t caps, int32_t num_caps);
Result StartProcess(Core::System& system, Handle process_handle, int32_t priority, int32_t core_id, uint64_t main_thread_stack_size);
Result TerminateProcess(Core::System& system, Handle process_handle);
Result GetProcessInfo(Core::System& system, int64_t* out_info, Handle process_handle, ProcessInfoType info_type);
Result CreateResourceLimit(Core::System& system, Handle* out_handle);
Result SetResourceLimitLimitValue(Core::System& system, Handle resource_limit_handle, LimitableResource which, int64_t limit_value);
Result MapInsecureMemory(Core::System& system, uint64_t address, uint64_t size);
Result UnmapInsecureMemory(Core::System& system, uint64_t address, uint64_t size);
Result SetHeapSize64From32(Core::System& system, uintptr_t* out_address, uint32_t size);
Result SetMemoryPermission64From32(Core::System& system, uint32_t address, uint32_t size, MemoryPermission perm);
Result SetMemoryAttribute64From32(Core::System& system, uint32_t address, uint32_t size, uint32_t mask, uint32_t attr);
Result MapMemory64From32(Core::System& system, uint32_t dst_address, uint32_t src_address, uint32_t size);
Result UnmapMemory64From32(Core::System& system, uint32_t dst_address, uint32_t src_address, uint32_t size);
Result QueryMemory64From32(Core::System& system, uint32_t out_memory_info, PageInfo* out_page_info, uint32_t address);
void ExitProcess64From32(Core::System& system);
Result CreateThread64From32(Core::System& system, Handle* out_handle, uint32_t func, uint32_t arg, uint32_t stack_bottom, int32_t priority, int32_t core_id);
Result StartThread64From32(Core::System& system, Handle thread_handle);
void ExitThread64From32(Core::System& system);
void SleepThread64From32(Core::System& system, int64_t ns);
Result GetThreadPriority64From32(Core::System& system, int32_t* out_priority, Handle thread_handle);
Result SetThreadPriority64From32(Core::System& system, Handle thread_handle, int32_t priority);
Result GetThreadCoreMask64From32(Core::System& system, int32_t* out_core_id, uint64_t* out_affinity_mask, Handle thread_handle);
Result SetThreadCoreMask64From32(Core::System& system, Handle thread_handle, int32_t core_id, uint64_t affinity_mask);
int32_t GetCurrentProcessorNumber64From32(Core::System& system);
Result SignalEvent64From32(Core::System& system, Handle event_handle);
Result ClearEvent64From32(Core::System& system, Handle event_handle);
Result MapSharedMemory64From32(Core::System& system, Handle shmem_handle, uint32_t address, uint32_t size, MemoryPermission map_perm);
Result UnmapSharedMemory64From32(Core::System& system, Handle shmem_handle, uint32_t address, uint32_t size);
Result CreateTransferMemory64From32(Core::System& system, Handle* out_handle, uint32_t address, uint32_t size, MemoryPermission map_perm);
Result CloseHandle64From32(Core::System& system, Handle handle);
Result ResetSignal64From32(Core::System& system, Handle handle);
Result WaitSynchronization64From32(Core::System& system, int32_t* out_index, uint32_t handles, int32_t num_handles, int64_t timeout_ns);
Result CancelSynchronization64From32(Core::System& system, Handle handle);
Result ArbitrateLock64From32(Core::System& system, Handle thread_handle, uint32_t address, uint32_t tag);
Result ArbitrateUnlock64From32(Core::System& system, uint32_t address);
Result WaitProcessWideKeyAtomic64From32(Core::System& system, uint32_t address, uint32_t cv_key, uint32_t tag, int64_t timeout_ns);
void SignalProcessWideKey64From32(Core::System& system, uint32_t cv_key, int32_t count);
int64_t GetSystemTick64From32(Core::System& system);
Result ConnectToNamedPort64From32(Core::System& system, Handle* out_handle, uint32_t name);
Result SendSyncRequest64From32(Core::System& system, Handle session_handle);
Result SendSyncRequestWithUserBuffer64From32(Core::System& system, uint32_t message_buffer, uint32_t message_buffer_size, Handle session_handle);
Result SendAsyncRequestWithUserBuffer64From32(Core::System& system, Handle* out_event_handle, uint32_t message_buffer, uint32_t message_buffer_size, Handle session_handle);
Result GetProcessId64From32(Core::System& system, uint64_t* out_process_id, Handle process_handle);
Result GetThreadId64From32(Core::System& system, uint64_t* out_thread_id, Handle thread_handle);
void Break64From32(Core::System& system, BreakReason break_reason, uint32_t arg, uint32_t size);
Result OutputDebugString64From32(Core::System& system, uint32_t debug_str, uint32_t len);
void ReturnFromException64From32(Core::System& system, Result result);
Result GetInfo64From32(Core::System& system, uint64_t* out, InfoType info_type, Handle handle, uint64_t info_subtype);
void FlushEntireDataCache64From32(Core::System& system);
Result FlushDataCache64From32(Core::System& system, uint32_t address, uint32_t size);
Result MapPhysicalMemory64From32(Core::System& system, uint32_t address, uint32_t size);
Result UnmapPhysicalMemory64From32(Core::System& system, uint32_t address, uint32_t size);
Result GetDebugFutureThreadInfo64From32(Core::System& system, ilp32::LastThreadContext* out_context, uint64_t* out_thread_id, Handle debug_handle, int64_t ns);
Result GetLastThreadInfo64From32(Core::System& system, ilp32::LastThreadContext* out_context, uintptr_t* out_tls_address, uint32_t* out_flags);
Result GetResourceLimitLimitValue64From32(Core::System& system, int64_t* out_limit_value, Handle resource_limit_handle, LimitableResource which);
Result GetResourceLimitCurrentValue64From32(Core::System& system, int64_t* out_current_value, Handle resource_limit_handle, LimitableResource which);
Result SetThreadActivity64From32(Core::System& system, Handle thread_handle, ThreadActivity thread_activity);
Result GetThreadContext364From32(Core::System& system, uint32_t out_context, Handle thread_handle);
Result WaitForAddress64From32(Core::System& system, uint32_t address, ArbitrationType arb_type, int32_t value, int64_t timeout_ns);
Result SignalToAddress64From32(Core::System& system, uint32_t address, SignalType signal_type, int32_t value, int32_t count);
void SynchronizePreemptionState64From32(Core::System& system);
Result GetResourceLimitPeakValue64From32(Core::System& system, int64_t* out_peak_value, Handle resource_limit_handle, LimitableResource which);
Result CreateIoPool64From32(Core::System& system, Handle* out_handle, IoPoolType which);
Result CreateIoRegion64From32(Core::System& system, Handle* out_handle, Handle io_pool, uint64_t physical_address, uint32_t size, MemoryMapping mapping, MemoryPermission perm);
void KernelDebug64From32(Core::System& system, KernelDebugType kern_debug_type, uint64_t arg0, uint64_t arg1, uint64_t arg2);
void ChangeKernelTraceState64From32(Core::System& system, KernelTraceState kern_trace_state);
Result CreateSession64From32(Core::System& system, Handle* out_server_session_handle, Handle* out_client_session_handle, bool is_light, uint32_t name);
Result AcceptSession64From32(Core::System& system, Handle* out_handle, Handle port);
Result ReplyAndReceive64From32(Core::System& system, int32_t* out_index, uint32_t handles, int32_t num_handles, Handle reply_target, int64_t timeout_ns);
Result ReplyAndReceiveWithUserBuffer64From32(Core::System& system, int32_t* out_index, uint32_t message_buffer, uint32_t message_buffer_size, uint32_t handles, int32_t num_handles, Handle reply_target, int64_t timeout_ns);
Result CreateEvent64From32(Core::System& system, Handle* out_write_handle, Handle* out_read_handle);
Result MapIoRegion64From32(Core::System& system, Handle io_region, uint32_t address, uint32_t size, MemoryPermission perm);
Result UnmapIoRegion64From32(Core::System& system, Handle io_region, uint32_t address, uint32_t size);
Result MapPhysicalMemoryUnsafe64From32(Core::System& system, uint32_t address, uint32_t size);
Result UnmapPhysicalMemoryUnsafe64From32(Core::System& system, uint32_t address, uint32_t size);
Result SetUnsafeLimit64From32(Core::System& system, uint32_t limit);
Result CreateCodeMemory64From32(Core::System& system, Handle* out_handle, uint32_t address, uint32_t size);
Result ControlCodeMemory64From32(Core::System& system, Handle code_memory_handle, CodeMemoryOperation operation, uint64_t address, uint64_t size, MemoryPermission perm);
void SleepSystem64From32(Core::System& system);
Result ReadWriteRegister64From32(Core::System& system, uint32_t* out_value, uint64_t address, uint32_t mask, uint32_t value);
Result SetProcessActivity64From32(Core::System& system, Handle process_handle, ProcessActivity process_activity);
Result CreateSharedMemory64From32(Core::System& system, Handle* out_handle, uint32_t size, MemoryPermission owner_perm, MemoryPermission remote_perm);
Result MapTransferMemory64From32(Core::System& system, Handle trmem_handle, uint32_t address, uint32_t size, MemoryPermission owner_perm);
Result UnmapTransferMemory64From32(Core::System& system, Handle trmem_handle, uint32_t address, uint32_t size);
Result CreateInterruptEvent64From32(Core::System& system, Handle* out_read_handle, int32_t interrupt_id, InterruptType interrupt_type);
Result QueryPhysicalAddress64From32(Core::System& system, ilp32::PhysicalMemoryInfo* out_info, uint32_t address);
Result QueryIoMapping64From32(Core::System& system, uintptr_t* out_address, uintptr_t* out_size, uint64_t physical_address, uint32_t size);
Result CreateDeviceAddressSpace64From32(Core::System& system, Handle* out_handle, uint64_t das_address, uint64_t das_size);
Result AttachDeviceAddressSpace64From32(Core::System& system, DeviceName device_name, Handle das_handle);
Result DetachDeviceAddressSpace64From32(Core::System& system, DeviceName device_name, Handle das_handle);
Result MapDeviceAddressSpaceByForce64From32(Core::System& system, Handle das_handle, Handle process_handle, uint64_t process_address, uint32_t size, uint64_t device_address, uint32_t option);
Result MapDeviceAddressSpaceAligned64From32(Core::System& system, Handle das_handle, Handle process_handle, uint64_t process_address, uint32_t size, uint64_t device_address, uint32_t option);
Result UnmapDeviceAddressSpace64From32(Core::System& system, Handle das_handle, Handle process_handle, uint64_t process_address, uint32_t size, uint64_t device_address);
Result InvalidateProcessDataCache64From32(Core::System& system, Handle process_handle, uint64_t address, uint64_t size);
Result StoreProcessDataCache64From32(Core::System& system, Handle process_handle, uint64_t address, uint64_t size);
Result FlushProcessDataCache64From32(Core::System& system, Handle process_handle, uint64_t address, uint64_t size);
Result DebugActiveProcess64From32(Core::System& system, Handle* out_handle, uint64_t process_id);
Result BreakDebugProcess64From32(Core::System& system, Handle debug_handle);
Result TerminateDebugProcess64From32(Core::System& system, Handle debug_handle);
Result GetDebugEvent64From32(Core::System& system, uint32_t out_info, Handle debug_handle);
Result ContinueDebugEvent64From32(Core::System& system, Handle debug_handle, uint32_t flags, uint32_t thread_ids, int32_t num_thread_ids);
Result GetProcessList64From32(Core::System& system, int32_t* out_num_processes, uint32_t out_process_ids, int32_t max_out_count);
Result GetThreadList64From32(Core::System& system, int32_t* out_num_threads, uint32_t out_thread_ids, int32_t max_out_count, Handle debug_handle);
Result GetDebugThreadContext64From32(Core::System& system, uint32_t out_context, Handle debug_handle, uint64_t thread_id, uint32_t context_flags);
Result SetDebugThreadContext64From32(Core::System& system, Handle debug_handle, uint64_t thread_id, uint32_t context, uint32_t context_flags);
Result QueryDebugProcessMemory64From32(Core::System& system, uint32_t out_memory_info, PageInfo* out_page_info, Handle process_handle, uint32_t address);
Result ReadDebugProcessMemory64From32(Core::System& system, uint32_t buffer, Handle debug_handle, uint32_t address, uint32_t size);
Result WriteDebugProcessMemory64From32(Core::System& system, Handle debug_handle, uint32_t buffer, uint32_t address, uint32_t size);
Result SetHardwareBreakPoint64From32(Core::System& system, HardwareBreakPointRegisterName name, uint64_t flags, uint64_t value);
Result GetDebugThreadParam64From32(Core::System& system, uint64_t* out_64, uint32_t* out_32, Handle debug_handle, uint64_t thread_id, DebugThreadParam param);
Result GetSystemInfo64From32(Core::System& system, uint64_t* out, SystemInfoType info_type, Handle handle, uint64_t info_subtype);
Result CreatePort64From32(Core::System& system, Handle* out_server_handle, Handle* out_client_handle, int32_t max_sessions, bool is_light, uint32_t name);
Result ManageNamedPort64From32(Core::System& system, Handle* out_server_handle, uint32_t name, int32_t max_sessions);
Result ConnectToPort64From32(Core::System& system, Handle* out_handle, Handle port);
Result SetProcessMemoryPermission64From32(Core::System& system, Handle process_handle, uint64_t address, uint64_t size, MemoryPermission perm);
Result MapProcessMemory64From32(Core::System& system, uint32_t dst_address, Handle process_handle, uint64_t src_address, uint32_t size);
Result UnmapProcessMemory64From32(Core::System& system, uint32_t dst_address, Handle process_handle, uint64_t src_address, uint32_t size);
Result QueryProcessMemory64From32(Core::System& system, uint32_t out_memory_info, PageInfo* out_page_info, Handle process_handle, uint64_t address);
Result MapProcessCodeMemory64From32(Core::System& system, Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size);
Result UnmapProcessCodeMemory64From32(Core::System& system, Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size);
Result CreateProcess64From32(Core::System& system, Handle* out_handle, uint32_t parameters, uint32_t caps, int32_t num_caps);
Result StartProcess64From32(Core::System& system, Handle process_handle, int32_t priority, int32_t core_id, uint64_t main_thread_stack_size);
Result TerminateProcess64From32(Core::System& system, Handle process_handle);
Result GetProcessInfo64From32(Core::System& system, int64_t* out_info, Handle process_handle, ProcessInfoType info_type);
Result CreateResourceLimit64From32(Core::System& system, Handle* out_handle);
Result SetResourceLimitLimitValue64From32(Core::System& system, Handle resource_limit_handle, LimitableResource which, int64_t limit_value);
Result MapInsecureMemory64From32(Core::System& system, uint32_t address, uint32_t size);
Result UnmapInsecureMemory64From32(Core::System& system, uint32_t address, uint32_t size);
Result SetHeapSize64(Core::System& system, uintptr_t* out_address, uint64_t size);
Result SetMemoryPermission64(Core::System& system, uint64_t address, uint64_t size, MemoryPermission perm);
Result SetMemoryAttribute64(Core::System& system, uint64_t address, uint64_t size, uint32_t mask, uint32_t attr);
Result MapMemory64(Core::System& system, uint64_t dst_address, uint64_t src_address, uint64_t size);
Result UnmapMemory64(Core::System& system, uint64_t dst_address, uint64_t src_address, uint64_t size);
Result QueryMemory64(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info, uint64_t address);
void ExitProcess64(Core::System& system);
Result CreateThread64(Core::System& system, Handle* out_handle, uint64_t func, uint64_t arg, uint64_t stack_bottom, int32_t priority, int32_t core_id);
Result StartThread64(Core::System& system, Handle thread_handle);
void ExitThread64(Core::System& system);
void SleepThread64(Core::System& system, int64_t ns);
Result GetThreadPriority64(Core::System& system, int32_t* out_priority, Handle thread_handle);
Result SetThreadPriority64(Core::System& system, Handle thread_handle, int32_t priority);
Result GetThreadCoreMask64(Core::System& system, int32_t* out_core_id, uint64_t* out_affinity_mask, Handle thread_handle);
Result SetThreadCoreMask64(Core::System& system, Handle thread_handle, int32_t core_id, uint64_t affinity_mask);
int32_t GetCurrentProcessorNumber64(Core::System& system);
Result SignalEvent64(Core::System& system, Handle event_handle);
Result ClearEvent64(Core::System& system, Handle event_handle);
Result MapSharedMemory64(Core::System& system, Handle shmem_handle, uint64_t address, uint64_t size, MemoryPermission map_perm);
Result UnmapSharedMemory64(Core::System& system, Handle shmem_handle, uint64_t address, uint64_t size);
Result CreateTransferMemory64(Core::System& system, Handle* out_handle, uint64_t address, uint64_t size, MemoryPermission map_perm);
Result CloseHandle64(Core::System& system, Handle handle);
Result ResetSignal64(Core::System& system, Handle handle);
Result WaitSynchronization64(Core::System& system, int32_t* out_index, uint64_t handles, int32_t num_handles, int64_t timeout_ns);
Result CancelSynchronization64(Core::System& system, Handle handle);
Result ArbitrateLock64(Core::System& system, Handle thread_handle, uint64_t address, uint32_t tag);
Result ArbitrateUnlock64(Core::System& system, uint64_t address);
Result WaitProcessWideKeyAtomic64(Core::System& system, uint64_t address, uint64_t cv_key, uint32_t tag, int64_t timeout_ns);
void SignalProcessWideKey64(Core::System& system, uint64_t cv_key, int32_t count);
int64_t GetSystemTick64(Core::System& system);
Result ConnectToNamedPort64(Core::System& system, Handle* out_handle, uint64_t name);
Result SendSyncRequest64(Core::System& system, Handle session_handle);
Result SendSyncRequestWithUserBuffer64(Core::System& system, uint64_t message_buffer, uint64_t message_buffer_size, Handle session_handle);
Result SendAsyncRequestWithUserBuffer64(Core::System& system, Handle* out_event_handle, uint64_t message_buffer, uint64_t message_buffer_size, Handle session_handle);
Result GetProcessId64(Core::System& system, uint64_t* out_process_id, Handle process_handle);
Result GetThreadId64(Core::System& system, uint64_t* out_thread_id, Handle thread_handle);
void Break64(Core::System& system, BreakReason break_reason, uint64_t arg, uint64_t size);
Result OutputDebugString64(Core::System& system, uint64_t debug_str, uint64_t len);
void ReturnFromException64(Core::System& system, Result result);
Result GetInfo64(Core::System& system, uint64_t* out, InfoType info_type, Handle handle, uint64_t info_subtype);
void FlushEntireDataCache64(Core::System& system);
Result FlushDataCache64(Core::System& system, uint64_t address, uint64_t size);
Result MapPhysicalMemory64(Core::System& system, uint64_t address, uint64_t size);
Result UnmapPhysicalMemory64(Core::System& system, uint64_t address, uint64_t size);
Result GetDebugFutureThreadInfo64(Core::System& system, lp64::LastThreadContext* out_context, uint64_t* out_thread_id, Handle debug_handle, int64_t ns);
Result GetLastThreadInfo64(Core::System& system, lp64::LastThreadContext* out_context, uintptr_t* out_tls_address, uint32_t* out_flags);
Result GetResourceLimitLimitValue64(Core::System& system, int64_t* out_limit_value, Handle resource_limit_handle, LimitableResource which);
Result GetResourceLimitCurrentValue64(Core::System& system, int64_t* out_current_value, Handle resource_limit_handle, LimitableResource which);
Result SetThreadActivity64(Core::System& system, Handle thread_handle, ThreadActivity thread_activity);
Result GetThreadContext364(Core::System& system, uint64_t out_context, Handle thread_handle);
Result WaitForAddress64(Core::System& system, uint64_t address, ArbitrationType arb_type, int32_t value, int64_t timeout_ns);
Result SignalToAddress64(Core::System& system, uint64_t address, SignalType signal_type, int32_t value, int32_t count);
void SynchronizePreemptionState64(Core::System& system);
Result GetResourceLimitPeakValue64(Core::System& system, int64_t* out_peak_value, Handle resource_limit_handle, LimitableResource which);
Result CreateIoPool64(Core::System& system, Handle* out_handle, IoPoolType which);
Result CreateIoRegion64(Core::System& system, Handle* out_handle, Handle io_pool, uint64_t physical_address, uint64_t size, MemoryMapping mapping, MemoryPermission perm);
void KernelDebug64(Core::System& system, KernelDebugType kern_debug_type, uint64_t arg0, uint64_t arg1, uint64_t arg2);
void ChangeKernelTraceState64(Core::System& system, KernelTraceState kern_trace_state);
Result CreateSession64(Core::System& system, Handle* out_server_session_handle, Handle* out_client_session_handle, bool is_light, uint64_t name);
Result AcceptSession64(Core::System& system, Handle* out_handle, Handle port);
Result ReplyAndReceive64(Core::System& system, int32_t* out_index, uint64_t handles, int32_t num_handles, Handle reply_target, int64_t timeout_ns);
Result ReplyAndReceiveWithUserBuffer64(Core::System& system, int32_t* out_index, uint64_t message_buffer, uint64_t message_buffer_size, uint64_t handles, int32_t num_handles, Handle reply_target, int64_t timeout_ns);
Result CreateEvent64(Core::System& system, Handle* out_write_handle, Handle* out_read_handle);
Result MapIoRegion64(Core::System& system, Handle io_region, uint64_t address, uint64_t size, MemoryPermission perm);
Result UnmapIoRegion64(Core::System& system, Handle io_region, uint64_t address, uint64_t size);
Result MapPhysicalMemoryUnsafe64(Core::System& system, uint64_t address, uint64_t size);
Result UnmapPhysicalMemoryUnsafe64(Core::System& system, uint64_t address, uint64_t size);
Result SetUnsafeLimit64(Core::System& system, uint64_t limit);
Result CreateCodeMemory64(Core::System& system, Handle* out_handle, uint64_t address, uint64_t size);
Result ControlCodeMemory64(Core::System& system, Handle code_memory_handle, CodeMemoryOperation operation, uint64_t address, uint64_t size, MemoryPermission perm);
void SleepSystem64(Core::System& system);
Result ReadWriteRegister64(Core::System& system, uint32_t* out_value, uint64_t address, uint32_t mask, uint32_t value);
Result SetProcessActivity64(Core::System& system, Handle process_handle, ProcessActivity process_activity);
Result CreateSharedMemory64(Core::System& system, Handle* out_handle, uint64_t size, MemoryPermission owner_perm, MemoryPermission remote_perm);
Result MapTransferMemory64(Core::System& system, Handle trmem_handle, uint64_t address, uint64_t size, MemoryPermission owner_perm);
Result UnmapTransferMemory64(Core::System& system, Handle trmem_handle, uint64_t address, uint64_t size);
Result CreateInterruptEvent64(Core::System& system, Handle* out_read_handle, int32_t interrupt_id, InterruptType interrupt_type);
Result QueryPhysicalAddress64(Core::System& system, lp64::PhysicalMemoryInfo* out_info, uint64_t address);
Result QueryIoMapping64(Core::System& system, uintptr_t* out_address, uintptr_t* out_size, uint64_t physical_address, uint64_t size);
Result CreateDeviceAddressSpace64(Core::System& system, Handle* out_handle, uint64_t das_address, uint64_t das_size);
Result AttachDeviceAddressSpace64(Core::System& system, DeviceName device_name, Handle das_handle);
Result DetachDeviceAddressSpace64(Core::System& system, DeviceName device_name, Handle das_handle);
Result MapDeviceAddressSpaceByForce64(Core::System& system, Handle das_handle, Handle process_handle, uint64_t process_address, uint64_t size, uint64_t device_address, uint32_t option);
Result MapDeviceAddressSpaceAligned64(Core::System& system, Handle das_handle, Handle process_handle, uint64_t process_address, uint64_t size, uint64_t device_address, uint32_t option);
Result UnmapDeviceAddressSpace64(Core::System& system, Handle das_handle, Handle process_handle, uint64_t process_address, uint64_t size, uint64_t device_address);
Result InvalidateProcessDataCache64(Core::System& system, Handle process_handle, uint64_t address, uint64_t size);
Result StoreProcessDataCache64(Core::System& system, Handle process_handle, uint64_t address, uint64_t size);
Result FlushProcessDataCache64(Core::System& system, Handle process_handle, uint64_t address, uint64_t size);
Result DebugActiveProcess64(Core::System& system, Handle* out_handle, uint64_t process_id);
Result BreakDebugProcess64(Core::System& system, Handle debug_handle);
Result TerminateDebugProcess64(Core::System& system, Handle debug_handle);
Result GetDebugEvent64(Core::System& system, uint64_t out_info, Handle debug_handle);
Result ContinueDebugEvent64(Core::System& system, Handle debug_handle, uint32_t flags, uint64_t thread_ids, int32_t num_thread_ids);
Result GetProcessList64(Core::System& system, int32_t* out_num_processes, uint64_t out_process_ids, int32_t max_out_count);
Result GetThreadList64(Core::System& system, int32_t* out_num_threads, uint64_t out_thread_ids, int32_t max_out_count, Handle debug_handle);
Result GetDebugThreadContext64(Core::System& system, uint64_t out_context, Handle debug_handle, uint64_t thread_id, uint32_t context_flags);
Result SetDebugThreadContext64(Core::System& system, Handle debug_handle, uint64_t thread_id, uint64_t context, uint32_t context_flags);
Result QueryDebugProcessMemory64(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info, Handle process_handle, uint64_t address);
Result ReadDebugProcessMemory64(Core::System& system, uint64_t buffer, Handle debug_handle, uint64_t address, uint64_t size);
Result WriteDebugProcessMemory64(Core::System& system, Handle debug_handle, uint64_t buffer, uint64_t address, uint64_t size);
Result SetHardwareBreakPoint64(Core::System& system, HardwareBreakPointRegisterName name, uint64_t flags, uint64_t value);
Result GetDebugThreadParam64(Core::System& system, uint64_t* out_64, uint32_t* out_32, Handle debug_handle, uint64_t thread_id, DebugThreadParam param);
Result GetSystemInfo64(Core::System& system, uint64_t* out, SystemInfoType info_type, Handle handle, uint64_t info_subtype);
Result CreatePort64(Core::System& system, Handle* out_server_handle, Handle* out_client_handle, int32_t max_sessions, bool is_light, uint64_t name);
Result ManageNamedPort64(Core::System& system, Handle* out_server_handle, uint64_t name, int32_t max_sessions);
Result ConnectToPort64(Core::System& system, Handle* out_handle, Handle port);
Result SetProcessMemoryPermission64(Core::System& system, Handle process_handle, uint64_t address, uint64_t size, MemoryPermission perm);
Result MapProcessMemory64(Core::System& system, uint64_t dst_address, Handle process_handle, uint64_t src_address, uint64_t size);
Result UnmapProcessMemory64(Core::System& system, uint64_t dst_address, Handle process_handle, uint64_t src_address, uint64_t size);
Result QueryProcessMemory64(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info, Handle process_handle, uint64_t address);
Result MapProcessCodeMemory64(Core::System& system, Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size);
Result UnmapProcessCodeMemory64(Core::System& system, Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size);
Result CreateProcess64(Core::System& system, Handle* out_handle, uint64_t parameters, uint64_t caps, int32_t num_caps);
Result StartProcess64(Core::System& system, Handle process_handle, int32_t priority, int32_t core_id, uint64_t main_thread_stack_size);
Result TerminateProcess64(Core::System& system, Handle process_handle);
Result GetProcessInfo64(Core::System& system, int64_t* out_info, Handle process_handle, ProcessInfoType info_type);
Result CreateResourceLimit64(Core::System& system, Handle* out_handle);
Result SetResourceLimitLimitValue64(Core::System& system, Handle resource_limit_handle, LimitableResource which, int64_t limit_value);
Result MapInsecureMemory64(Core::System& system, uint64_t address, uint64_t size);
Result UnmapInsecureMemory64(Core::System& system, uint64_t address, uint64_t size);
enum class SvcId : u32 {
SetHeapSize = 0x1,
SetMemoryPermission = 0x2,
SetMemoryAttribute = 0x3,
MapMemory = 0x4,
UnmapMemory = 0x5,
QueryMemory = 0x6,
ExitProcess = 0x7,
CreateThread = 0x8,
StartThread = 0x9,
ExitThread = 0xa,
SleepThread = 0xb,
GetThreadPriority = 0xc,
SetThreadPriority = 0xd,
GetThreadCoreMask = 0xe,
SetThreadCoreMask = 0xf,
GetCurrentProcessorNumber = 0x10,
SignalEvent = 0x11,
ClearEvent = 0x12,
MapSharedMemory = 0x13,
UnmapSharedMemory = 0x14,
CreateTransferMemory = 0x15,
CloseHandle = 0x16,
ResetSignal = 0x17,
WaitSynchronization = 0x18,
CancelSynchronization = 0x19,
ArbitrateLock = 0x1a,
ArbitrateUnlock = 0x1b,
WaitProcessWideKeyAtomic = 0x1c,
SignalProcessWideKey = 0x1d,
GetSystemTick = 0x1e,
ConnectToNamedPort = 0x1f,
SendSyncRequestLight = 0x20,
SendSyncRequest = 0x21,
SendSyncRequestWithUserBuffer = 0x22,
SendAsyncRequestWithUserBuffer = 0x23,
GetProcessId = 0x24,
GetThreadId = 0x25,
Break = 0x26,
OutputDebugString = 0x27,
ReturnFromException = 0x28,
GetInfo = 0x29,
FlushEntireDataCache = 0x2a,
FlushDataCache = 0x2b,
MapPhysicalMemory = 0x2c,
UnmapPhysicalMemory = 0x2d,
GetDebugFutureThreadInfo = 0x2e,
GetLastThreadInfo = 0x2f,
GetResourceLimitLimitValue = 0x30,
GetResourceLimitCurrentValue = 0x31,
SetThreadActivity = 0x32,
GetThreadContext3 = 0x33,
WaitForAddress = 0x34,
SignalToAddress = 0x35,
SynchronizePreemptionState = 0x36,
GetResourceLimitPeakValue = 0x37,
CreateIoPool = 0x39,
CreateIoRegion = 0x3a,
KernelDebug = 0x3c,
ChangeKernelTraceState = 0x3d,
CreateSession = 0x40,
AcceptSession = 0x41,
ReplyAndReceiveLight = 0x42,
ReplyAndReceive = 0x43,
ReplyAndReceiveWithUserBuffer = 0x44,
CreateEvent = 0x45,
MapIoRegion = 0x46,
UnmapIoRegion = 0x47,
MapPhysicalMemoryUnsafe = 0x48,
UnmapPhysicalMemoryUnsafe = 0x49,
SetUnsafeLimit = 0x4a,
CreateCodeMemory = 0x4b,
ControlCodeMemory = 0x4c,
SleepSystem = 0x4d,
ReadWriteRegister = 0x4e,
SetProcessActivity = 0x4f,
CreateSharedMemory = 0x50,
MapTransferMemory = 0x51,
UnmapTransferMemory = 0x52,
CreateInterruptEvent = 0x53,
QueryPhysicalAddress = 0x54,
QueryIoMapping = 0x55,
CreateDeviceAddressSpace = 0x56,
AttachDeviceAddressSpace = 0x57,
DetachDeviceAddressSpace = 0x58,
MapDeviceAddressSpaceByForce = 0x59,
MapDeviceAddressSpaceAligned = 0x5a,
UnmapDeviceAddressSpace = 0x5c,
InvalidateProcessDataCache = 0x5d,
StoreProcessDataCache = 0x5e,
FlushProcessDataCache = 0x5f,
DebugActiveProcess = 0x60,
BreakDebugProcess = 0x61,
TerminateDebugProcess = 0x62,
GetDebugEvent = 0x63,
ContinueDebugEvent = 0x64,
GetProcessList = 0x65,
GetThreadList = 0x66,
GetDebugThreadContext = 0x67,
SetDebugThreadContext = 0x68,
QueryDebugProcessMemory = 0x69,
ReadDebugProcessMemory = 0x6a,
WriteDebugProcessMemory = 0x6b,
SetHardwareBreakPoint = 0x6c,
GetDebugThreadParam = 0x6d,
GetSystemInfo = 0x6f,
CreatePort = 0x70,
ManageNamedPort = 0x71,
ConnectToPort = 0x72,
SetProcessMemoryPermission = 0x73,
MapProcessMemory = 0x74,
UnmapProcessMemory = 0x75,
QueryProcessMemory = 0x76,
MapProcessCodeMemory = 0x77,
UnmapProcessCodeMemory = 0x78,
CreateProcess = 0x79,
StartProcess = 0x7a,
TerminateProcess = 0x7b,
GetProcessInfo = 0x7c,
CreateResourceLimit = 0x7d,
SetResourceLimitLimitValue = 0x7e,
CallSecureMonitor = 0x7f,
MapInsecureMemory = 0x90,
UnmapInsecureMemory = 0x91,
};
// clang-format on
// Custom ABI.
Result ReplyAndReceiveLight(Core::System& system, Handle handle, uint32_t* args);
Result ReplyAndReceiveLight64From32(Core::System& system, Handle handle, uint32_t* args);
Result ReplyAndReceiveLight64(Core::System& system, Handle handle, uint32_t* args);
Result SendSyncRequestLight(Core::System& system, Handle session_handle, uint32_t* args);
Result SendSyncRequestLight64From32(Core::System& system, Handle session_handle, uint32_t* args);
Result SendSyncRequestLight64(Core::System& system, Handle session_handle, uint32_t* args);
void CallSecureMonitor(Core::System& system, lp64::SecureMonitorArguments* args);
void CallSecureMonitor64From32(Core::System& system, ilp32::SecureMonitorArguments* args);
void CallSecureMonitor64(Core::System& system, lp64::SecureMonitorArguments* args);
// Defined in svc_light_ipc.cpp.
void SvcWrap_ReplyAndReceiveLight64From32(Core::System& system);
void SvcWrap_ReplyAndReceiveLight64(Core::System& system);
void SvcWrap_SendSyncRequestLight64From32(Core::System& system);
void SvcWrap_SendSyncRequestLight64(Core::System& system);
// Defined in svc_secure_monitor_call.cpp.
void SvcWrap_CallSecureMonitor64From32(Core::System& system);
void SvcWrap_CallSecureMonitor64(Core::System& system);
// Perform a supervisor call by index.
void Call(Core::System& system, u32 imm);
} // namespace Kernel::Svc

View File

@@ -0,0 +1,66 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/svc_results.h"
namespace Kernel::Svc {
/// Sets the thread activity
Result SetThreadActivity(Core::System& system, Handle thread_handle,
ThreadActivity thread_activity) {
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", thread_handle,
thread_activity);
// Validate the activity.
constexpr auto IsValidThreadActivity = [](ThreadActivity activity) {
return activity == ThreadActivity::Runnable || activity == ThreadActivity::Paused;
};
R_UNLESS(IsValidThreadActivity(thread_activity), ResultInvalidEnumValue);
// Get the thread from its handle.
KScopedAutoObject thread =
GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KThread>(thread_handle);
R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
// Check that the activity is being set on a non-current thread for the current process.
R_UNLESS(thread->GetOwnerProcess() == GetCurrentProcessPointer(system.Kernel()),
ResultInvalidHandle);
R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(system.Kernel()), ResultBusy);
// Set the activity.
R_TRY(thread->SetActivity(thread_activity));
return ResultSuccess;
}
Result SetProcessActivity(Core::System& system, Handle process_handle,
ProcessActivity process_activity) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result SetThreadActivity64(Core::System& system, Handle thread_handle,
ThreadActivity thread_activity) {
return SetThreadActivity(system, thread_handle, thread_activity);
}
Result SetProcessActivity64(Core::System& system, Handle process_handle,
ProcessActivity process_activity) {
return SetProcessActivity(system, process_handle, process_activity);
}
Result SetThreadActivity64From32(Core::System& system, Handle thread_handle,
ThreadActivity thread_activity) {
return SetThreadActivity(system, thread_handle, thread_activity);
}
Result SetProcessActivity64From32(Core::System& system, Handle process_handle,
ProcessActivity process_activity) {
return SetProcessActivity(system, process_handle, process_activity);
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,122 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/kernel/k_memory_layout.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/svc_results.h"
#include "core/hle/kernel/svc_types.h"
namespace Kernel::Svc {
namespace {
constexpr bool IsValidSignalType(Svc::SignalType type) {
switch (type) {
case Svc::SignalType::Signal:
case Svc::SignalType::SignalAndIncrementIfEqual:
case Svc::SignalType::SignalAndModifyByWaitingCountIfEqual:
return true;
default:
return false;
}
}
constexpr bool IsValidArbitrationType(Svc::ArbitrationType type) {
switch (type) {
case Svc::ArbitrationType::WaitIfLessThan:
case Svc::ArbitrationType::DecrementAndWaitIfLessThan:
case Svc::ArbitrationType::WaitIfEqual:
return true;
default:
return false;
}
}
} // namespace
// Wait for an address (via Address Arbiter)
Result WaitForAddress(Core::System& system, VAddr address, ArbitrationType arb_type, s32 value,
s64 timeout_ns) {
LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, arb_type=0x{:X}, value=0x{:X}, timeout_ns={}",
address, arb_type, value, timeout_ns);
// Validate input.
if (IsKernelAddress(address)) {
LOG_ERROR(Kernel_SVC, "Attempting to wait on kernel address (address={:08X})", address);
return ResultInvalidCurrentMemory;
}
if (!Common::IsAligned(address, sizeof(s32))) {
LOG_ERROR(Kernel_SVC, "Wait address must be 4 byte aligned (address={:08X})", address);
return ResultInvalidAddress;
}
if (!IsValidArbitrationType(arb_type)) {
LOG_ERROR(Kernel_SVC, "Invalid arbitration type specified (type={})", arb_type);
return ResultInvalidEnumValue;
}
// Convert timeout from nanoseconds to ticks.
s64 timeout{};
if (timeout_ns > 0) {
const s64 offset_tick(timeout_ns);
if (offset_tick > 0) {
timeout = offset_tick + 2;
if (timeout <= 0) {
timeout = std::numeric_limits<s64>::max();
}
} else {
timeout = std::numeric_limits<s64>::max();
}
} else {
timeout = timeout_ns;
}
return GetCurrentProcess(system.Kernel()).WaitAddressArbiter(address, arb_type, value, timeout);
}
// Signals to an address (via Address Arbiter)
Result SignalToAddress(Core::System& system, VAddr address, SignalType signal_type, s32 value,
s32 count) {
LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, signal_type=0x{:X}, value=0x{:X}, count=0x{:X}",
address, signal_type, value, count);
// Validate input.
if (IsKernelAddress(address)) {
LOG_ERROR(Kernel_SVC, "Attempting to signal to a kernel address (address={:08X})", address);
return ResultInvalidCurrentMemory;
}
if (!Common::IsAligned(address, sizeof(s32))) {
LOG_ERROR(Kernel_SVC, "Signaled address must be 4 byte aligned (address={:08X})", address);
return ResultInvalidAddress;
}
if (!IsValidSignalType(signal_type)) {
LOG_ERROR(Kernel_SVC, "Invalid signal type specified (type={})", signal_type);
return ResultInvalidEnumValue;
}
return GetCurrentProcess(system.Kernel())
.SignalAddressArbiter(address, signal_type, value, count);
}
Result WaitForAddress64(Core::System& system, VAddr address, ArbitrationType arb_type, s32 value,
s64 timeout_ns) {
return WaitForAddress(system, address, arb_type, value, timeout_ns);
}
Result SignalToAddress64(Core::System& system, VAddr address, SignalType signal_type, s32 value,
s32 count) {
return SignalToAddress(system, address, signal_type, value, count);
}
Result WaitForAddress64From32(Core::System& system, u32 address, ArbitrationType arb_type,
s32 value, s64 timeout_ns) {
return WaitForAddress(system, address, arb_type, value, timeout_ns);
}
Result SignalToAddress64From32(Core::System& system, u32 address, SignalType signal_type, s32 value,
s32 count) {
return SignalToAddress(system, address, signal_type, value, count);
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,50 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/svc_results.h"
namespace Kernel::Svc {
Result QueryPhysicalAddress(Core::System& system, lp64::PhysicalMemoryInfo* out_info,
uint64_t address) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result QueryIoMapping(Core::System& system, uintptr_t* out_address, uintptr_t* out_size,
uint64_t physical_address, uint64_t size) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result QueryPhysicalAddress64(Core::System& system, lp64::PhysicalMemoryInfo* out_info,
uint64_t address) {
R_RETURN(QueryPhysicalAddress(system, out_info, address));
}
Result QueryIoMapping64(Core::System& system, uintptr_t* out_address, uintptr_t* out_size,
uint64_t physical_address, uint64_t size) {
R_RETURN(QueryIoMapping(system, out_address, out_size, physical_address, size));
}
Result QueryPhysicalAddress64From32(Core::System& system, ilp32::PhysicalMemoryInfo* out_info,
uint32_t address) {
lp64::PhysicalMemoryInfo info{};
R_TRY(QueryPhysicalAddress(system, std::addressof(info), address));
*out_info = {
.physical_address = info.physical_address,
.virtual_address = static_cast<u32>(info.virtual_address),
.size = static_cast<u32>(info.size),
};
R_SUCCEED();
}
Result QueryIoMapping64From32(Core::System& system, uintptr_t* out_address, uintptr_t* out_size,
uint64_t physical_address, uint32_t size) {
R_RETURN(QueryIoMapping(system, reinterpret_cast<uintptr_t*>(out_address),
reinterpret_cast<uintptr_t*>(out_size), physical_address, size));
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,98 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/svc_results.h"
#include "core/hle/kernel/svc_types.h"
namespace Kernel::Svc {
void FlushEntireDataCache(Core::System& system) {
UNIMPLEMENTED();
}
Result FlushDataCache(Core::System& system, VAddr address, size_t size) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result InvalidateProcessDataCache(Core::System& system, Handle process_handle, uint64_t address,
uint64_t size) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result StoreProcessDataCache(Core::System& system, Handle process_handle, uint64_t address,
uint64_t size) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result FlushProcessDataCache(Core::System& system, Handle process_handle, u64 address, u64 size) {
// Validate address/size.
R_UNLESS(size > 0, ResultInvalidSize);
R_UNLESS(address == static_cast<uintptr_t>(address), ResultInvalidCurrentMemory);
R_UNLESS(size == static_cast<size_t>(size), ResultInvalidCurrentMemory);
// Get the process from its handle.
KScopedAutoObject process =
GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KProcess>(process_handle);
R_UNLESS(process.IsNotNull(), ResultInvalidHandle);
// Verify the region is within range.
auto& page_table = process->PageTable();
R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
// Perform the operation.
R_RETURN(system.Memory().FlushDataCache(*process, address, size));
}
void FlushEntireDataCache64(Core::System& system) {
FlushEntireDataCache(system);
}
Result FlushDataCache64(Core::System& system, VAddr address, size_t size) {
R_RETURN(FlushDataCache(system, address, size));
}
Result InvalidateProcessDataCache64(Core::System& system, Handle process_handle, uint64_t address,
uint64_t size) {
R_RETURN(InvalidateProcessDataCache(system, process_handle, address, size));
}
Result StoreProcessDataCache64(Core::System& system, Handle process_handle, uint64_t address,
uint64_t size) {
R_RETURN(StoreProcessDataCache(system, process_handle, address, size));
}
Result FlushProcessDataCache64(Core::System& system, Handle process_handle, uint64_t address,
uint64_t size) {
R_RETURN(FlushProcessDataCache(system, process_handle, address, size));
}
void FlushEntireDataCache64From32(Core::System& system) {
return FlushEntireDataCache(system);
}
Result FlushDataCache64From32(Core::System& system, uint32_t address, uint32_t size) {
R_RETURN(FlushDataCache(system, address, size));
}
Result InvalidateProcessDataCache64From32(Core::System& system, Handle process_handle,
uint64_t address, uint64_t size) {
R_RETURN(InvalidateProcessDataCache(system, process_handle, address, size));
}
Result StoreProcessDataCache64From32(Core::System& system, Handle process_handle, uint64_t address,
uint64_t size) {
R_RETURN(StoreProcessDataCache(system, process_handle, address, size));
}
Result FlushProcessDataCache64From32(Core::System& system, Handle process_handle, uint64_t address,
uint64_t size) {
R_RETURN(FlushProcessDataCache(system, process_handle, address, size));
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,171 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/kernel/k_code_memory.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/svc.h"
namespace Kernel::Svc {
namespace {
constexpr bool IsValidMapCodeMemoryPermission(MemoryPermission perm) {
return perm == MemoryPermission::ReadWrite;
}
constexpr bool IsValidMapToOwnerCodeMemoryPermission(MemoryPermission perm) {
return perm == MemoryPermission::Read || perm == MemoryPermission::ReadExecute;
}
constexpr bool IsValidUnmapCodeMemoryPermission(MemoryPermission perm) {
return perm == MemoryPermission::None;
}
constexpr bool IsValidUnmapFromOwnerCodeMemoryPermission(MemoryPermission perm) {
return perm == MemoryPermission::None;
}
} // namespace
Result CreateCodeMemory(Core::System& system, Handle* out, VAddr address, size_t size) {
LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, size=0x{:X}", address, size);
// Get kernel instance.
auto& kernel = system.Kernel();
// Validate address / size.
R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
R_UNLESS(size > 0, ResultInvalidSize);
R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
// Create the code memory.
KCodeMemory* code_mem = KCodeMemory::Create(kernel);
R_UNLESS(code_mem != nullptr, ResultOutOfResource);
// Verify that the region is in range.
R_UNLESS(GetCurrentProcess(system.Kernel()).PageTable().Contains(address, size),
ResultInvalidCurrentMemory);
// Initialize the code memory.
R_TRY(code_mem->Initialize(system.DeviceMemory(), address, size));
// Register the code memory.
KCodeMemory::Register(kernel, code_mem);
// Add the code memory to the handle table.
R_TRY(GetCurrentProcess(system.Kernel()).GetHandleTable().Add(out, code_mem));
code_mem->Close();
return ResultSuccess;
}
Result ControlCodeMemory(Core::System& system, Handle code_memory_handle,
CodeMemoryOperation operation, VAddr address, size_t size,
MemoryPermission perm) {
LOG_TRACE(Kernel_SVC,
"called, code_memory_handle=0x{:X}, operation=0x{:X}, address=0x{:X}, size=0x{:X}, "
"permission=0x{:X}",
code_memory_handle, operation, address, size, perm);
// Validate the address / size.
R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
R_UNLESS(size > 0, ResultInvalidSize);
R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
// Get the code memory from its handle.
KScopedAutoObject code_mem = GetCurrentProcess(system.Kernel())
.GetHandleTable()
.GetObject<KCodeMemory>(code_memory_handle);
R_UNLESS(code_mem.IsNotNull(), ResultInvalidHandle);
// NOTE: Here, Atmosphere extends the SVC to allow code memory operations on one's own process.
// This enables homebrew usage of these SVCs for JIT.
// Perform the operation.
switch (operation) {
case CodeMemoryOperation::Map: {
// Check that the region is in range.
R_UNLESS(GetCurrentProcess(system.Kernel())
.PageTable()
.CanContain(address, size, KMemoryState::CodeOut),
ResultInvalidMemoryRegion);
// Check the memory permission.
R_UNLESS(IsValidMapCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission);
// Map the memory.
R_TRY(code_mem->Map(address, size));
} break;
case CodeMemoryOperation::Unmap: {
// Check that the region is in range.
R_UNLESS(GetCurrentProcess(system.Kernel())
.PageTable()
.CanContain(address, size, KMemoryState::CodeOut),
ResultInvalidMemoryRegion);
// Check the memory permission.
R_UNLESS(IsValidUnmapCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission);
// Unmap the memory.
R_TRY(code_mem->Unmap(address, size));
} break;
case CodeMemoryOperation::MapToOwner: {
// Check that the region is in range.
R_UNLESS(code_mem->GetOwner()->PageTable().CanContain(address, size,
KMemoryState::GeneratedCode),
ResultInvalidMemoryRegion);
// Check the memory permission.
R_UNLESS(IsValidMapToOwnerCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission);
// Map the memory to its owner.
R_TRY(code_mem->MapToOwner(address, size, perm));
} break;
case CodeMemoryOperation::UnmapFromOwner: {
// Check that the region is in range.
R_UNLESS(code_mem->GetOwner()->PageTable().CanContain(address, size,
KMemoryState::GeneratedCode),
ResultInvalidMemoryRegion);
// Check the memory permission.
R_UNLESS(IsValidUnmapFromOwnerCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission);
// Unmap the memory from its owner.
R_TRY(code_mem->UnmapFromOwner(address, size));
} break;
default:
return ResultInvalidEnumValue;
}
return ResultSuccess;
}
Result CreateCodeMemory64(Core::System& system, Handle* out_handle, uint64_t address,
uint64_t size) {
R_RETURN(CreateCodeMemory(system, out_handle, address, size));
}
Result ControlCodeMemory64(Core::System& system, Handle code_memory_handle,
CodeMemoryOperation operation, uint64_t address, uint64_t size,
MemoryPermission perm) {
R_RETURN(ControlCodeMemory(system, code_memory_handle, operation, address, size, perm));
}
Result CreateCodeMemory64From32(Core::System& system, Handle* out_handle, uint32_t address,
uint32_t size) {
R_RETURN(CreateCodeMemory(system, out_handle, address, size));
}
Result ControlCodeMemory64From32(Core::System& system, Handle code_memory_handle,
CodeMemoryOperation operation, uint64_t address, uint64_t size,
MemoryPermission perm) {
R_RETURN(ControlCodeMemory(system, code_memory_handle, operation, address, size, perm));
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,77 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/kernel/k_memory_layout.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/svc_results.h"
namespace Kernel::Svc {
/// Wait process wide key atomic
Result WaitProcessWideKeyAtomic(Core::System& system, VAddr address, VAddr cv_key, u32 tag,
s64 timeout_ns) {
LOG_TRACE(Kernel_SVC, "called address={:X}, cv_key={:X}, tag=0x{:08X}, timeout_ns={}", address,
cv_key, tag, timeout_ns);
// Validate input.
if (IsKernelAddress(address)) {
LOG_ERROR(Kernel_SVC, "Attempted to wait on kernel address (address={:08X})", address);
return ResultInvalidCurrentMemory;
}
if (!Common::IsAligned(address, sizeof(s32))) {
LOG_ERROR(Kernel_SVC, "Address must be 4 byte aligned (address={:08X})", address);
return ResultInvalidAddress;
}
// Convert timeout from nanoseconds to ticks.
s64 timeout{};
if (timeout_ns > 0) {
const s64 offset_tick(timeout_ns);
if (offset_tick > 0) {
timeout = offset_tick + 2;
if (timeout <= 0) {
timeout = std::numeric_limits<s64>::max();
}
} else {
timeout = std::numeric_limits<s64>::max();
}
} else {
timeout = timeout_ns;
}
// Wait on the condition variable.
return GetCurrentProcess(system.Kernel())
.WaitConditionVariable(address, Common::AlignDown(cv_key, sizeof(u32)), tag, timeout);
}
/// Signal process wide key
void SignalProcessWideKey(Core::System& system, VAddr cv_key, s32 count) {
LOG_TRACE(Kernel_SVC, "called, cv_key=0x{:X}, count=0x{:08X}", cv_key, count);
// Signal the condition variable.
return GetCurrentProcess(system.Kernel())
.SignalConditionVariable(Common::AlignDown(cv_key, sizeof(u32)), count);
}
Result WaitProcessWideKeyAtomic64(Core::System& system, uint64_t address, uint64_t cv_key,
uint32_t tag, int64_t timeout_ns) {
R_RETURN(WaitProcessWideKeyAtomic(system, address, cv_key, tag, timeout_ns));
}
void SignalProcessWideKey64(Core::System& system, uint64_t cv_key, int32_t count) {
SignalProcessWideKey(system, cv_key, count);
}
Result WaitProcessWideKeyAtomic64From32(Core::System& system, uint32_t address, uint32_t cv_key,
uint32_t tag, int64_t timeout_ns) {
R_RETURN(WaitProcessWideKeyAtomic(system, address, cv_key, tag, timeout_ns));
}
void SignalProcessWideKey64From32(Core::System& system, uint32_t cv_key, int32_t count) {
SignalProcessWideKey(system, cv_key, count);
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,194 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/svc_results.h"
namespace Kernel::Svc {
Result DebugActiveProcess(Core::System& system, Handle* out_handle, uint64_t process_id) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result BreakDebugProcess(Core::System& system, Handle debug_handle) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result TerminateDebugProcess(Core::System& system, Handle debug_handle) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result GetDebugEvent(Core::System& system, uint64_t out_info, Handle debug_handle) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result ContinueDebugEvent(Core::System& system, Handle debug_handle, uint32_t flags,
uint64_t user_thread_ids, int32_t num_thread_ids) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result GetDebugThreadContext(Core::System& system, uint64_t out_context, Handle debug_handle,
uint64_t thread_id, uint32_t context_flags) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result SetDebugThreadContext(Core::System& system, Handle debug_handle, uint64_t thread_id,
uint64_t user_context, uint32_t context_flags) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result QueryDebugProcessMemory(Core::System& system, uint64_t out_memory_info,
PageInfo* out_page_info, Handle debug_handle, uintptr_t address) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result ReadDebugProcessMemory(Core::System& system, uintptr_t buffer, Handle debug_handle,
uintptr_t address, size_t size) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result WriteDebugProcessMemory(Core::System& system, Handle debug_handle, uintptr_t buffer,
uintptr_t address, size_t size) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result SetHardwareBreakPoint(Core::System& system, HardwareBreakPointRegisterName name,
uint64_t flags, uint64_t value) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result GetDebugThreadParam(Core::System& system, uint64_t* out_64, uint32_t* out_32,
Handle debug_handle, uint64_t thread_id, DebugThreadParam param) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result DebugActiveProcess64(Core::System& system, Handle* out_handle, uint64_t process_id) {
R_RETURN(DebugActiveProcess(system, out_handle, process_id));
}
Result BreakDebugProcess64(Core::System& system, Handle debug_handle) {
R_RETURN(BreakDebugProcess(system, debug_handle));
}
Result TerminateDebugProcess64(Core::System& system, Handle debug_handle) {
R_RETURN(TerminateDebugProcess(system, debug_handle));
}
Result GetDebugEvent64(Core::System& system, uint64_t out_info, Handle debug_handle) {
R_RETURN(GetDebugEvent(system, out_info, debug_handle));
}
Result ContinueDebugEvent64(Core::System& system, Handle debug_handle, uint32_t flags,
uint64_t thread_ids, int32_t num_thread_ids) {
R_RETURN(ContinueDebugEvent(system, debug_handle, flags, thread_ids, num_thread_ids));
}
Result GetDebugThreadContext64(Core::System& system, uint64_t out_context, Handle debug_handle,
uint64_t thread_id, uint32_t context_flags) {
R_RETURN(GetDebugThreadContext(system, out_context, debug_handle, thread_id, context_flags));
}
Result SetDebugThreadContext64(Core::System& system, Handle debug_handle, uint64_t thread_id,
uint64_t context, uint32_t context_flags) {
R_RETURN(SetDebugThreadContext(system, debug_handle, thread_id, context, context_flags));
}
Result QueryDebugProcessMemory64(Core::System& system, uint64_t out_memory_info,
PageInfo* out_page_info, Handle debug_handle, uint64_t address) {
R_RETURN(
QueryDebugProcessMemory(system, out_memory_info, out_page_info, debug_handle, address));
}
Result ReadDebugProcessMemory64(Core::System& system, uint64_t buffer, Handle debug_handle,
uint64_t address, uint64_t size) {
R_RETURN(ReadDebugProcessMemory(system, buffer, debug_handle, address, size));
}
Result WriteDebugProcessMemory64(Core::System& system, Handle debug_handle, uint64_t buffer,
uint64_t address, uint64_t size) {
R_RETURN(WriteDebugProcessMemory(system, debug_handle, buffer, address, size));
}
Result SetHardwareBreakPoint64(Core::System& system, HardwareBreakPointRegisterName name,
uint64_t flags, uint64_t value) {
R_RETURN(SetHardwareBreakPoint(system, name, flags, value));
}
Result GetDebugThreadParam64(Core::System& system, uint64_t* out_64, uint32_t* out_32,
Handle debug_handle, uint64_t thread_id, DebugThreadParam param) {
R_RETURN(GetDebugThreadParam(system, out_64, out_32, debug_handle, thread_id, param));
}
Result DebugActiveProcess64From32(Core::System& system, Handle* out_handle, uint64_t process_id) {
R_RETURN(DebugActiveProcess(system, out_handle, process_id));
}
Result BreakDebugProcess64From32(Core::System& system, Handle debug_handle) {
R_RETURN(BreakDebugProcess(system, debug_handle));
}
Result TerminateDebugProcess64From32(Core::System& system, Handle debug_handle) {
R_RETURN(TerminateDebugProcess(system, debug_handle));
}
Result GetDebugEvent64From32(Core::System& system, uint32_t out_info, Handle debug_handle) {
R_RETURN(GetDebugEvent(system, out_info, debug_handle));
}
Result ContinueDebugEvent64From32(Core::System& system, Handle debug_handle, uint32_t flags,
uint32_t thread_ids, int32_t num_thread_ids) {
R_RETURN(ContinueDebugEvent(system, debug_handle, flags, thread_ids, num_thread_ids));
}
Result GetDebugThreadContext64From32(Core::System& system, uint32_t out_context,
Handle debug_handle, uint64_t thread_id,
uint32_t context_flags) {
R_RETURN(GetDebugThreadContext(system, out_context, debug_handle, thread_id, context_flags));
}
Result SetDebugThreadContext64From32(Core::System& system, Handle debug_handle, uint64_t thread_id,
uint32_t context, uint32_t context_flags) {
R_RETURN(SetDebugThreadContext(system, debug_handle, thread_id, context, context_flags));
}
Result QueryDebugProcessMemory64From32(Core::System& system, uint32_t out_memory_info,
PageInfo* out_page_info, Handle debug_handle,
uint32_t address) {
R_RETURN(
QueryDebugProcessMemory(system, out_memory_info, out_page_info, debug_handle, address));
}
Result ReadDebugProcessMemory64From32(Core::System& system, uint32_t buffer, Handle debug_handle,
uint32_t address, uint32_t size) {
R_RETURN(ReadDebugProcessMemory(system, buffer, debug_handle, address, size));
}
Result WriteDebugProcessMemory64From32(Core::System& system, Handle debug_handle, uint32_t buffer,
uint32_t address, uint32_t size) {
R_RETURN(WriteDebugProcessMemory(system, debug_handle, buffer, address, size));
}
Result SetHardwareBreakPoint64From32(Core::System& system, HardwareBreakPointRegisterName name,
uint64_t flags, uint64_t value) {
R_RETURN(SetHardwareBreakPoint(system, name, flags, value));
}
Result GetDebugThreadParam64From32(Core::System& system, uint64_t* out_64, uint32_t* out_32,
Handle debug_handle, uint64_t thread_id,
DebugThreadParam param) {
R_RETURN(GetDebugThreadParam(system, out_64, out_32, debug_handle, thread_id, param));
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,29 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/kernel/svc.h"
#include "core/memory.h"
namespace Kernel::Svc {
/// Used to output a message on a debug hardware unit - does nothing on a retail unit
Result OutputDebugString(Core::System& system, VAddr address, u64 len) {
R_SUCCEED_IF(len == 0);
std::string str(len, '\0');
system.Memory().ReadBlock(address, str.data(), str.size());
LOG_DEBUG(Debug_Emulated, "{}", str);
R_SUCCEED();
}
Result OutputDebugString64(Core::System& system, uint64_t debug_str, uint64_t len) {
R_RETURN(OutputDebugString(system, debug_str, len));
}
Result OutputDebugString64From32(Core::System& system, uint32_t debug_str, uint32_t len) {
R_RETURN(OutputDebugString(system, debug_str, len));
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,258 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/alignment.h"
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/hle/kernel/k_device_address_space.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/svc.h"
namespace Kernel::Svc {
constexpr inline u64 DeviceAddressSpaceAlignMask = (1ULL << 22) - 1;
constexpr bool IsProcessAndDeviceAligned(uint64_t process_address, uint64_t device_address) {
return (process_address & DeviceAddressSpaceAlignMask) ==
(device_address & DeviceAddressSpaceAlignMask);
}
Result CreateDeviceAddressSpace(Core::System& system, Handle* out, uint64_t das_address,
uint64_t das_size) {
// Validate input.
R_UNLESS(Common::IsAligned(das_address, PageSize), ResultInvalidMemoryRegion);
R_UNLESS(Common::IsAligned(das_size, PageSize), ResultInvalidMemoryRegion);
R_UNLESS(das_size > 0, ResultInvalidMemoryRegion);
R_UNLESS((das_address < das_address + das_size), ResultInvalidMemoryRegion);
// Create the device address space.
KDeviceAddressSpace* das = KDeviceAddressSpace::Create(system.Kernel());
R_UNLESS(das != nullptr, ResultOutOfResource);
SCOPE_EXIT({ das->Close(); });
// Initialize the device address space.
R_TRY(das->Initialize(das_address, das_size));
// Register the device address space.
KDeviceAddressSpace::Register(system.Kernel(), das);
// Add to the handle table.
R_TRY(GetCurrentProcess(system.Kernel()).GetHandleTable().Add(out, das));
R_SUCCEED();
}
Result AttachDeviceAddressSpace(Core::System& system, DeviceName device_name, Handle das_handle) {
// Get the device address space.
KScopedAutoObject das = GetCurrentProcess(system.Kernel())
.GetHandleTable()
.GetObject<KDeviceAddressSpace>(das_handle);
R_UNLESS(das.IsNotNull(), ResultInvalidHandle);
// Attach.
R_RETURN(das->Attach(device_name));
}
Result DetachDeviceAddressSpace(Core::System& system, DeviceName device_name, Handle das_handle) {
// Get the device address space.
KScopedAutoObject das = GetCurrentProcess(system.Kernel())
.GetHandleTable()
.GetObject<KDeviceAddressSpace>(das_handle);
R_UNLESS(das.IsNotNull(), ResultInvalidHandle);
// Detach.
R_RETURN(das->Detach(device_name));
}
constexpr bool IsValidDeviceMemoryPermission(MemoryPermission device_perm) {
switch (device_perm) {
case MemoryPermission::Read:
case MemoryPermission::Write:
case MemoryPermission::ReadWrite:
return true;
default:
return false;
}
}
Result MapDeviceAddressSpaceByForce(Core::System& system, Handle das_handle, Handle process_handle,
uint64_t process_address, size_t size, uint64_t device_address,
u32 option) {
// Decode the option.
const MapDeviceAddressSpaceOption option_pack{option};
const auto device_perm = option_pack.permission;
const auto reserved = option_pack.reserved;
// Validate input.
R_UNLESS(Common::IsAligned(process_address, PageSize), ResultInvalidAddress);
R_UNLESS(Common::IsAligned(device_address, PageSize), ResultInvalidAddress);
R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
R_UNLESS(size > 0, ResultInvalidSize);
R_UNLESS((process_address < process_address + size), ResultInvalidCurrentMemory);
R_UNLESS((device_address < device_address + size), ResultInvalidMemoryRegion);
R_UNLESS((process_address == static_cast<uintptr_t>(process_address)),
ResultInvalidCurrentMemory);
R_UNLESS(IsValidDeviceMemoryPermission(device_perm), ResultInvalidNewMemoryPermission);
R_UNLESS(reserved == 0, ResultInvalidEnumValue);
// Get the device address space.
KScopedAutoObject das = GetCurrentProcess(system.Kernel())
.GetHandleTable()
.GetObject<KDeviceAddressSpace>(das_handle);
R_UNLESS(das.IsNotNull(), ResultInvalidHandle);
// Get the process.
KScopedAutoObject process =
GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KProcess>(process_handle);
R_UNLESS(process.IsNotNull(), ResultInvalidHandle);
// Validate that the process address is within range.
auto& page_table = process->PageTable();
R_UNLESS(page_table.Contains(process_address, size), ResultInvalidCurrentMemory);
// Map.
R_RETURN(
das->MapByForce(std::addressof(page_table), process_address, size, device_address, option));
}
Result MapDeviceAddressSpaceAligned(Core::System& system, Handle das_handle, Handle process_handle,
uint64_t process_address, size_t size, uint64_t device_address,
u32 option) {
// Decode the option.
const MapDeviceAddressSpaceOption option_pack{option};
const auto device_perm = option_pack.permission;
const auto reserved = option_pack.reserved;
// Validate input.
R_UNLESS(Common::IsAligned(process_address, PageSize), ResultInvalidAddress);
R_UNLESS(Common::IsAligned(device_address, PageSize), ResultInvalidAddress);
R_UNLESS(IsProcessAndDeviceAligned(process_address, device_address), ResultInvalidAddress);
R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
R_UNLESS(size > 0, ResultInvalidSize);
R_UNLESS((process_address < process_address + size), ResultInvalidCurrentMemory);
R_UNLESS((device_address < device_address + size), ResultInvalidMemoryRegion);
R_UNLESS((process_address == static_cast<uintptr_t>(process_address)),
ResultInvalidCurrentMemory);
R_UNLESS(IsValidDeviceMemoryPermission(device_perm), ResultInvalidNewMemoryPermission);
R_UNLESS(reserved == 0, ResultInvalidEnumValue);
// Get the device address space.
KScopedAutoObject das = GetCurrentProcess(system.Kernel())
.GetHandleTable()
.GetObject<KDeviceAddressSpace>(das_handle);
R_UNLESS(das.IsNotNull(), ResultInvalidHandle);
// Get the process.
KScopedAutoObject process =
GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KProcess>(process_handle);
R_UNLESS(process.IsNotNull(), ResultInvalidHandle);
// Validate that the process address is within range.
auto& page_table = process->PageTable();
R_UNLESS(page_table.Contains(process_address, size), ResultInvalidCurrentMemory);
// Map.
R_RETURN(
das->MapAligned(std::addressof(page_table), process_address, size, device_address, option));
}
Result UnmapDeviceAddressSpace(Core::System& system, Handle das_handle, Handle process_handle,
uint64_t process_address, size_t size, uint64_t device_address) {
// Validate input.
R_UNLESS(Common::IsAligned(process_address, PageSize), ResultInvalidAddress);
R_UNLESS(Common::IsAligned(device_address, PageSize), ResultInvalidAddress);
R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
R_UNLESS(size > 0, ResultInvalidSize);
R_UNLESS((process_address < process_address + size), ResultInvalidCurrentMemory);
R_UNLESS((device_address < device_address + size), ResultInvalidMemoryRegion);
R_UNLESS((process_address == static_cast<uintptr_t>(process_address)),
ResultInvalidCurrentMemory);
// Get the device address space.
KScopedAutoObject das = GetCurrentProcess(system.Kernel())
.GetHandleTable()
.GetObject<KDeviceAddressSpace>(das_handle);
R_UNLESS(das.IsNotNull(), ResultInvalidHandle);
// Get the process.
KScopedAutoObject process =
GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KProcess>(process_handle);
R_UNLESS(process.IsNotNull(), ResultInvalidHandle);
// Validate that the process address is within range.
auto& page_table = process->PageTable();
R_UNLESS(page_table.Contains(process_address, size), ResultInvalidCurrentMemory);
R_RETURN(das->Unmap(std::addressof(page_table), process_address, size, device_address));
}
Result CreateDeviceAddressSpace64(Core::System& system, Handle* out_handle, uint64_t das_address,
uint64_t das_size) {
R_RETURN(CreateDeviceAddressSpace(system, out_handle, das_address, das_size));
}
Result AttachDeviceAddressSpace64(Core::System& system, DeviceName device_name, Handle das_handle) {
R_RETURN(AttachDeviceAddressSpace(system, device_name, das_handle));
}
Result DetachDeviceAddressSpace64(Core::System& system, DeviceName device_name, Handle das_handle) {
R_RETURN(DetachDeviceAddressSpace(system, device_name, das_handle));
}
Result MapDeviceAddressSpaceByForce64(Core::System& system, Handle das_handle,
Handle process_handle, uint64_t process_address,
uint64_t size, uint64_t device_address, u32 option) {
R_RETURN(MapDeviceAddressSpaceByForce(system, das_handle, process_handle, process_address, size,
device_address, option));
}
Result MapDeviceAddressSpaceAligned64(Core::System& system, Handle das_handle,
Handle process_handle, uint64_t process_address,
uint64_t size, uint64_t device_address, u32 option) {
R_RETURN(MapDeviceAddressSpaceAligned(system, das_handle, process_handle, process_address, size,
device_address, option));
}
Result UnmapDeviceAddressSpace64(Core::System& system, Handle das_handle, Handle process_handle,
uint64_t process_address, uint64_t size, uint64_t device_address) {
R_RETURN(UnmapDeviceAddressSpace(system, das_handle, process_handle, process_address, size,
device_address));
}
Result CreateDeviceAddressSpace64From32(Core::System& system, Handle* out_handle,
uint64_t das_address, uint64_t das_size) {
R_RETURN(CreateDeviceAddressSpace(system, out_handle, das_address, das_size));
}
Result AttachDeviceAddressSpace64From32(Core::System& system, DeviceName device_name,
Handle das_handle) {
R_RETURN(AttachDeviceAddressSpace(system, device_name, das_handle));
}
Result DetachDeviceAddressSpace64From32(Core::System& system, DeviceName device_name,
Handle das_handle) {
R_RETURN(DetachDeviceAddressSpace(system, device_name, das_handle));
}
Result MapDeviceAddressSpaceByForce64From32(Core::System& system, Handle das_handle,
Handle process_handle, uint64_t process_address,
uint32_t size, uint64_t device_address, u32 option) {
R_RETURN(MapDeviceAddressSpaceByForce(system, das_handle, process_handle, process_address, size,
device_address, option));
}
Result MapDeviceAddressSpaceAligned64From32(Core::System& system, Handle das_handle,
Handle process_handle, uint64_t process_address,
uint32_t size, uint64_t device_address, u32 option) {
R_RETURN(MapDeviceAddressSpaceAligned(system, das_handle, process_handle, process_address, size,
device_address, option));
}
Result UnmapDeviceAddressSpace64From32(Core::System& system, Handle das_handle,
Handle process_handle, uint64_t process_address,
uint32_t size, uint64_t device_address) {
R_RETURN(UnmapDeviceAddressSpace(system, das_handle, process_handle, process_address, size,
device_address));
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,124 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_scoped_resource_reservation.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/svc.h"
namespace Kernel::Svc {
Result SignalEvent(Core::System& system, Handle event_handle) {
LOG_DEBUG(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle);
// Get the current handle table.
const KHandleTable& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
// Get the event.
KScopedAutoObject event = handle_table.GetObject<KEvent>(event_handle);
R_UNLESS(event.IsNotNull(), ResultInvalidHandle);
return event->Signal();
}
Result ClearEvent(Core::System& system, Handle event_handle) {
LOG_TRACE(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle);
// Get the current handle table.
const auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
// Try to clear the writable event.
{
KScopedAutoObject event = handle_table.GetObject<KEvent>(event_handle);
if (event.IsNotNull()) {
return event->Clear();
}
}
// Try to clear the readable event.
{
KScopedAutoObject readable_event = handle_table.GetObject<KReadableEvent>(event_handle);
if (readable_event.IsNotNull()) {
return readable_event->Clear();
}
}
LOG_ERROR(Kernel_SVC, "Event handle does not exist, event_handle=0x{:08X}", event_handle);
return ResultInvalidHandle;
}
Result CreateEvent(Core::System& system, Handle* out_write, Handle* out_read) {
LOG_DEBUG(Kernel_SVC, "called");
// Get the kernel reference and handle table.
auto& kernel = system.Kernel();
auto& handle_table = GetCurrentProcess(kernel).GetHandleTable();
// Reserve a new event from the process resource limit
KScopedResourceReservation event_reservation(GetCurrentProcessPointer(kernel),
LimitableResource::EventCountMax);
R_UNLESS(event_reservation.Succeeded(), ResultLimitReached);
// Create a new event.
KEvent* event = KEvent::Create(kernel);
R_UNLESS(event != nullptr, ResultOutOfResource);
// Initialize the event.
event->Initialize(GetCurrentProcessPointer(kernel));
// Commit the thread reservation.
event_reservation.Commit();
// Ensure that we clean up the event (and its only references are handle table) on function end.
SCOPE_EXIT({
event->GetReadableEvent().Close();
event->Close();
});
// Register the event.
KEvent::Register(kernel, event);
// Add the event to the handle table.
R_TRY(handle_table.Add(out_write, event));
// Ensure that we maintaing a clean handle state on exit.
auto handle_guard = SCOPE_GUARD({ handle_table.Remove(*out_write); });
// Add the readable event to the handle table.
R_TRY(handle_table.Add(out_read, std::addressof(event->GetReadableEvent())));
// We succeeded.
handle_guard.Cancel();
return ResultSuccess;
}
Result SignalEvent64(Core::System& system, Handle event_handle) {
R_RETURN(SignalEvent(system, event_handle));
}
Result ClearEvent64(Core::System& system, Handle event_handle) {
R_RETURN(ClearEvent(system, event_handle));
}
Result CreateEvent64(Core::System& system, Handle* out_write_handle, Handle* out_read_handle) {
R_RETURN(CreateEvent(system, out_write_handle, out_read_handle));
}
Result SignalEvent64From32(Core::System& system, Handle event_handle) {
R_RETURN(SignalEvent(system, event_handle));
}
Result ClearEvent64From32(Core::System& system, Handle event_handle) {
R_RETURN(ClearEvent(system, event_handle));
}
Result CreateEvent64From32(Core::System& system, Handle* out_write_handle,
Handle* out_read_handle) {
R_RETURN(CreateEvent(system, out_write_handle, out_read_handle));
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,137 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/debugger/debugger.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/svc_types.h"
#include "core/memory.h"
#include "core/reporter.h"
namespace Kernel::Svc {
/// Break program execution
void Break(Core::System& system, BreakReason reason, u64 info1, u64 info2) {
BreakReason break_reason =
reason & static_cast<BreakReason>(~BreakReason::NotificationOnlyFlag);
bool notification_only = True(reason & BreakReason::NotificationOnlyFlag);
bool has_dumped_buffer{};
std::vector<u8> debug_buffer;
const auto handle_debug_buffer = [&](VAddr addr, u64 sz) {
if (sz == 0 || addr == 0 || has_dumped_buffer) {
return;
}
auto& memory = system.Memory();
// This typically is an error code so we're going to assume this is the case
if (sz == sizeof(u32)) {
LOG_CRITICAL(Debug_Emulated, "debug_buffer_err_code={:X}", memory.Read32(addr));
} else {
// We don't know what's in here so we'll hexdump it
debug_buffer.resize(sz);
memory.ReadBlock(addr, debug_buffer.data(), sz);
std::string hexdump;
for (std::size_t i = 0; i < debug_buffer.size(); i++) {
hexdump += fmt::format("{:02X} ", debug_buffer[i]);
if (i != 0 && i % 16 == 0) {
hexdump += '\n';
}
}
LOG_CRITICAL(Debug_Emulated, "debug_buffer=\n{}", hexdump);
}
has_dumped_buffer = true;
};
switch (break_reason) {
case BreakReason::Panic:
LOG_CRITICAL(Debug_Emulated, "Userspace PANIC! info1=0x{:016X}, info2=0x{:016X}", info1,
info2);
handle_debug_buffer(info1, info2);
break;
case BreakReason::Assert:
LOG_CRITICAL(Debug_Emulated, "Userspace Assertion failed! info1=0x{:016X}, info2=0x{:016X}",
info1, info2);
handle_debug_buffer(info1, info2);
break;
case BreakReason::User:
LOG_WARNING(Debug_Emulated, "Userspace Break! 0x{:016X} with size 0x{:016X}", info1, info2);
handle_debug_buffer(info1, info2);
break;
case BreakReason::PreLoadDll:
LOG_INFO(Debug_Emulated,
"Userspace Attempting to load an NRO at 0x{:016X} with size 0x{:016X}", info1,
info2);
break;
case BreakReason::PostLoadDll:
LOG_INFO(Debug_Emulated, "Userspace Loaded an NRO at 0x{:016X} with size 0x{:016X}", info1,
info2);
break;
case BreakReason::PreUnloadDll:
LOG_INFO(Debug_Emulated,
"Userspace Attempting to unload an NRO at 0x{:016X} with size 0x{:016X}", info1,
info2);
break;
case BreakReason::PostUnloadDll:
LOG_INFO(Debug_Emulated, "Userspace Unloaded an NRO at 0x{:016X} with size 0x{:016X}",
info1, info2);
break;
case BreakReason::CppException:
LOG_CRITICAL(Debug_Emulated, "Signalling debugger. Uncaught C++ exception encountered.");
break;
default:
LOG_WARNING(
Debug_Emulated,
"Signalling debugger, Unknown break reason {:#X}, info1=0x{:016X}, info2=0x{:016X}",
reason, info1, info2);
handle_debug_buffer(info1, info2);
break;
}
system.GetReporter().SaveSvcBreakReport(
static_cast<u32>(reason), notification_only, info1, info2,
has_dumped_buffer ? std::make_optional(debug_buffer) : std::nullopt);
if (!notification_only) {
LOG_CRITICAL(
Debug_Emulated,
"Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}",
reason, info1, info2);
handle_debug_buffer(info1, info2);
auto* const current_thread = GetCurrentThreadPointer(system.Kernel());
const auto thread_processor_id = current_thread->GetActiveCore();
system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace();
}
if (system.DebuggerEnabled()) {
auto* thread = system.Kernel().GetCurrentEmuThread();
system.GetDebugger().NotifyThreadStopped(thread);
thread->RequestSuspend(Kernel::SuspendType::Debug);
}
}
void ReturnFromException(Core::System& system, Result result) {
UNIMPLEMENTED();
}
void Break64(Core::System& system, BreakReason break_reason, uint64_t arg, uint64_t size) {
Break(system, break_reason, arg, size);
}
void Break64From32(Core::System& system, BreakReason break_reason, uint32_t arg, uint32_t size) {
Break(system, break_reason, arg, size);
}
void ReturnFromException64(Core::System& system, Result result) {
ReturnFromException(system, result);
}
void ReturnFromException64From32(Core::System& system, Result result) {
ReturnFromException(system, result);
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,297 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_resource_limit.h"
#include "core/hle/kernel/svc.h"
namespace Kernel::Svc {
/// Gets system/memory information for the current process
Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle handle,
u64 info_sub_id) {
LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}",
info_id_type, info_sub_id, handle);
u32 info_id = static_cast<u32>(info_id_type);
switch (info_id_type) {
case InfoType::CoreMask:
case InfoType::PriorityMask:
case InfoType::AliasRegionAddress:
case InfoType::AliasRegionSize:
case InfoType::HeapRegionAddress:
case InfoType::HeapRegionSize:
case InfoType::AslrRegionAddress:
case InfoType::AslrRegionSize:
case InfoType::StackRegionAddress:
case InfoType::StackRegionSize:
case InfoType::TotalMemorySize:
case InfoType::UsedMemorySize:
case InfoType::SystemResourceSizeTotal:
case InfoType::SystemResourceSizeUsed:
case InfoType::ProgramId:
case InfoType::UserExceptionContextAddress:
case InfoType::TotalNonSystemMemorySize:
case InfoType::UsedNonSystemMemorySize:
case InfoType::IsApplication:
case InfoType::FreeThreadCount: {
if (info_sub_id != 0) {
LOG_ERROR(Kernel_SVC, "Info sub id is non zero! info_id={}, info_sub_id={}", info_id,
info_sub_id);
return ResultInvalidEnumValue;
}
const auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
KScopedAutoObject process = handle_table.GetObject<KProcess>(handle);
if (process.IsNull()) {
LOG_ERROR(Kernel_SVC, "Process is not valid! info_id={}, info_sub_id={}, handle={:08X}",
info_id, info_sub_id, handle);
return ResultInvalidHandle;
}
switch (info_id_type) {
case InfoType::CoreMask:
*result = process->GetCoreMask();
return ResultSuccess;
case InfoType::PriorityMask:
*result = process->GetPriorityMask();
return ResultSuccess;
case InfoType::AliasRegionAddress:
*result = process->PageTable().GetAliasRegionStart();
return ResultSuccess;
case InfoType::AliasRegionSize:
*result = process->PageTable().GetAliasRegionSize();
return ResultSuccess;
case InfoType::HeapRegionAddress:
*result = process->PageTable().GetHeapRegionStart();
return ResultSuccess;
case InfoType::HeapRegionSize:
*result = process->PageTable().GetHeapRegionSize();
return ResultSuccess;
case InfoType::AslrRegionAddress:
*result = process->PageTable().GetAliasCodeRegionStart();
return ResultSuccess;
case InfoType::AslrRegionSize:
*result = process->PageTable().GetAliasCodeRegionSize();
return ResultSuccess;
case InfoType::StackRegionAddress:
*result = process->PageTable().GetStackRegionStart();
return ResultSuccess;
case InfoType::StackRegionSize:
*result = process->PageTable().GetStackRegionSize();
return ResultSuccess;
case InfoType::TotalMemorySize:
*result = process->GetTotalPhysicalMemoryAvailable();
return ResultSuccess;
case InfoType::UsedMemorySize:
*result = process->GetTotalPhysicalMemoryUsed();
return ResultSuccess;
case InfoType::SystemResourceSizeTotal:
*result = process->GetSystemResourceSize();
return ResultSuccess;
case InfoType::SystemResourceSizeUsed:
LOG_WARNING(Kernel_SVC, "(STUBBED) Attempted to query system resource usage");
*result = process->GetSystemResourceUsage();
return ResultSuccess;
case InfoType::ProgramId:
*result = process->GetProgramID();
return ResultSuccess;
case InfoType::UserExceptionContextAddress:
*result = process->GetProcessLocalRegionAddress();
return ResultSuccess;
case InfoType::TotalNonSystemMemorySize:
*result = process->GetTotalPhysicalMemoryAvailableWithoutSystemResource();
return ResultSuccess;
case InfoType::UsedNonSystemMemorySize:
*result = process->GetTotalPhysicalMemoryUsedWithoutSystemResource();
return ResultSuccess;
case InfoType::FreeThreadCount:
*result = process->GetFreeThreadCount();
return ResultSuccess;
default:
break;
}
LOG_ERROR(Kernel_SVC, "Unimplemented svcGetInfo id=0x{:016X}", info_id);
return ResultInvalidEnumValue;
}
case InfoType::DebuggerAttached:
*result = 0;
return ResultSuccess;
case InfoType::ResourceLimit: {
if (handle != 0) {
LOG_ERROR(Kernel, "Handle is non zero! handle={:08X}", handle);
return ResultInvalidHandle;
}
if (info_sub_id != 0) {
LOG_ERROR(Kernel, "Info sub id is non zero! info_id={}, info_sub_id={}", info_id,
info_sub_id);
return ResultInvalidCombination;
}
KProcess* const current_process = GetCurrentProcessPointer(system.Kernel());
KHandleTable& handle_table = current_process->GetHandleTable();
const auto resource_limit = current_process->GetResourceLimit();
if (!resource_limit) {
*result = Svc::InvalidHandle;
// Yes, the kernel considers this a successful operation.
return ResultSuccess;
}
Handle resource_handle{};
R_TRY(handle_table.Add(&resource_handle, resource_limit));
*result = resource_handle;
return ResultSuccess;
}
case InfoType::RandomEntropy:
if (handle != 0) {
LOG_ERROR(Kernel_SVC, "Process Handle is non zero, expected 0 result but got {:016X}",
handle);
return ResultInvalidHandle;
}
if (info_sub_id >= KProcess::RANDOM_ENTROPY_SIZE) {
LOG_ERROR(Kernel_SVC, "Entropy size is out of range, expected {} but got {}",
KProcess::RANDOM_ENTROPY_SIZE, info_sub_id);
return ResultInvalidCombination;
}
*result = GetCurrentProcess(system.Kernel()).GetRandomEntropy(info_sub_id);
return ResultSuccess;
case InfoType::InitialProcessIdRange:
LOG_WARNING(Kernel_SVC,
"(STUBBED) Attempted to query privileged process id bounds, returned 0");
*result = 0;
return ResultSuccess;
case InfoType::ThreadTickCount: {
constexpr u64 num_cpus = 4;
if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) {
LOG_ERROR(Kernel_SVC, "Core count is out of range, expected {} but got {}", num_cpus,
info_sub_id);
return ResultInvalidCombination;
}
KScopedAutoObject thread = GetCurrentProcess(system.Kernel())
.GetHandleTable()
.GetObject<KThread>(static_cast<Handle>(handle));
if (thread.IsNull()) {
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}",
static_cast<Handle>(handle));
return ResultInvalidHandle;
}
const auto& core_timing = system.CoreTiming();
const auto& scheduler = *system.Kernel().CurrentScheduler();
const auto* const current_thread = GetCurrentThreadPointer(system.Kernel());
const bool same_thread = current_thread == thread.GetPointerUnsafe();
const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTime();
u64 out_ticks = 0;
if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) {
const u64 thread_ticks = current_thread->GetCpuTime();
out_ticks = thread_ticks + (core_timing.GetCPUTicks() - prev_ctx_ticks);
} else if (same_thread && info_sub_id == system.Kernel().CurrentPhysicalCoreIndex()) {
out_ticks = core_timing.GetCPUTicks() - prev_ctx_ticks;
}
*result = out_ticks;
return ResultSuccess;
}
case InfoType::IdleTickCount: {
// Verify the input handle is invalid.
R_UNLESS(handle == InvalidHandle, ResultInvalidHandle);
// Verify the requested core is valid.
const bool core_valid =
(info_sub_id == 0xFFFFFFFFFFFFFFFF) ||
(info_sub_id == static_cast<u64>(system.Kernel().CurrentPhysicalCoreIndex()));
R_UNLESS(core_valid, ResultInvalidCombination);
// Get the idle tick count.
*result = system.Kernel().CurrentScheduler()->GetIdleThread()->GetCpuTime();
return ResultSuccess;
}
case InfoType::MesosphereCurrentProcess: {
// Verify the input handle is invalid.
R_UNLESS(handle == InvalidHandle, ResultInvalidHandle);
// Verify the sub-type is valid.
R_UNLESS(info_sub_id == 0, ResultInvalidCombination);
// Get the handle table.
KProcess* current_process = GetCurrentProcessPointer(system.Kernel());
KHandleTable& handle_table = current_process->GetHandleTable();
// Get a new handle for the current process.
Handle tmp;
R_TRY(handle_table.Add(&tmp, current_process));
// Set the output.
*result = tmp;
// We succeeded.
return ResultSuccess;
}
default:
LOG_ERROR(Kernel_SVC, "Unimplemented svcGetInfo id=0x{:016X}", info_id);
return ResultInvalidEnumValue;
}
}
Result GetSystemInfo(Core::System& system, uint64_t* out, SystemInfoType info_type, Handle handle,
uint64_t info_subtype) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result GetInfo64(Core::System& system, uint64_t* out, InfoType info_type, Handle handle,
uint64_t info_subtype) {
R_RETURN(GetInfo(system, out, info_type, handle, info_subtype));
}
Result GetSystemInfo64(Core::System& system, uint64_t* out, SystemInfoType info_type, Handle handle,
uint64_t info_subtype) {
R_RETURN(GetSystemInfo(system, out, info_type, handle, info_subtype));
}
Result GetInfo64From32(Core::System& system, uint64_t* out, InfoType info_type, Handle handle,
uint64_t info_subtype) {
R_RETURN(GetInfo(system, out, info_type, handle, info_subtype));
}
Result GetSystemInfo64From32(Core::System& system, uint64_t* out, SystemInfoType info_type,
Handle handle, uint64_t info_subtype) {
R_RETURN(GetSystemInfo(system, out, info_type, handle, info_subtype));
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,35 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/svc_results.h"
namespace Kernel::Svc {
Result MapInsecureMemory(Core::System& system, uintptr_t address, size_t size) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result UnmapInsecureMemory(Core::System& system, uintptr_t address, size_t size) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result MapInsecureMemory64(Core::System& system, uint64_t address, uint64_t size) {
R_RETURN(MapInsecureMemory(system, address, size));
}
Result UnmapInsecureMemory64(Core::System& system, uint64_t address, uint64_t size) {
R_RETURN(UnmapInsecureMemory(system, address, size));
}
Result MapInsecureMemory64From32(Core::System& system, uint32_t address, uint32_t size) {
R_RETURN(MapInsecureMemory(system, address, size));
}
Result UnmapInsecureMemory64From32(Core::System& system, uint32_t address, uint32_t size) {
R_RETURN(UnmapInsecureMemory(system, address, size));
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,25 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/svc_results.h"
namespace Kernel::Svc {
Result CreateInterruptEvent(Core::System& system, Handle* out, int32_t interrupt_id,
InterruptType type) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result CreateInterruptEvent64(Core::System& system, Handle* out_read_handle, int32_t interrupt_id,
InterruptType interrupt_type) {
R_RETURN(CreateInterruptEvent(system, out_read_handle, interrupt_id, interrupt_type));
}
Result CreateInterruptEvent64From32(Core::System& system, Handle* out_read_handle,
int32_t interrupt_id, InterruptType interrupt_type) {
R_RETURN(CreateInterruptEvent(system, out_read_handle, interrupt_id, interrupt_type));
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,71 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/svc_results.h"
namespace Kernel::Svc {
Result CreateIoPool(Core::System& system, Handle* out, IoPoolType pool_type) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result CreateIoRegion(Core::System& system, Handle* out, Handle io_pool_handle, uint64_t phys_addr,
size_t size, MemoryMapping mapping, MemoryPermission perm) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result MapIoRegion(Core::System& system, Handle io_region_handle, uintptr_t address, size_t size,
MemoryPermission map_perm) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result UnmapIoRegion(Core::System& system, Handle io_region_handle, uintptr_t address,
size_t size) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result CreateIoPool64(Core::System& system, Handle* out_handle, IoPoolType pool_type) {
R_RETURN(CreateIoPool(system, out_handle, pool_type));
}
Result CreateIoRegion64(Core::System& system, Handle* out_handle, Handle io_pool,
uint64_t physical_address, uint64_t size, MemoryMapping mapping,
MemoryPermission perm) {
R_RETURN(CreateIoRegion(system, out_handle, io_pool, physical_address, size, mapping, perm));
}
Result MapIoRegion64(Core::System& system, Handle io_region, uint64_t address, uint64_t size,
MemoryPermission perm) {
R_RETURN(MapIoRegion(system, io_region, address, size, perm));
}
Result UnmapIoRegion64(Core::System& system, Handle io_region, uint64_t address, uint64_t size) {
R_RETURN(UnmapIoRegion(system, io_region, address, size));
}
Result CreateIoPool64From32(Core::System& system, Handle* out_handle, IoPoolType pool_type) {
R_RETURN(CreateIoPool(system, out_handle, pool_type));
}
Result CreateIoRegion64From32(Core::System& system, Handle* out_handle, Handle io_pool,
uint64_t physical_address, uint32_t size, MemoryMapping mapping,
MemoryPermission perm) {
R_RETURN(CreateIoRegion(system, out_handle, io_pool, physical_address, size, mapping, perm));
}
Result MapIoRegion64From32(Core::System& system, Handle io_region, uint32_t address, uint32_t size,
MemoryPermission perm) {
R_RETURN(MapIoRegion(system, io_region, address, size, perm));
}
Result UnmapIoRegion64From32(Core::System& system, Handle io_region, uint32_t address,
uint32_t size) {
R_RETURN(UnmapIoRegion(system, io_region, address, size));
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,172 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/hle/kernel/k_client_session.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_server_session.h"
#include "core/hle/kernel/svc.h"
namespace Kernel::Svc {
/// Makes a blocking IPC call to a service.
Result SendSyncRequest(Core::System& system, Handle handle) {
// Get the client session from its handle.
KScopedAutoObject session =
GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KClientSession>(handle);
R_UNLESS(session.IsNotNull(), ResultInvalidHandle);
LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());
return session->SendSyncRequest();
}
Result SendSyncRequestWithUserBuffer(Core::System& system, uint64_t message_buffer,
uint64_t message_buffer_size, Handle session_handle) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result SendAsyncRequestWithUserBuffer(Core::System& system, Handle* out_event_handle,
uint64_t message_buffer, uint64_t message_buffer_size,
Handle session_handle) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result ReplyAndReceive(Core::System& system, s32* out_index, uint64_t handles_addr, s32 num_handles,
Handle reply_target, s64 timeout_ns) {
auto& kernel = system.Kernel();
auto& handle_table = GetCurrentProcess(kernel).GetHandleTable();
R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange);
R_UNLESS(system.Memory().IsValidVirtualAddressRange(
handles_addr, static_cast<u64>(sizeof(Handle) * num_handles)),
ResultInvalidPointer);
std::vector<Handle> handles(num_handles);
system.Memory().ReadBlock(handles_addr, handles.data(), sizeof(Handle) * num_handles);
// Convert handle list to object table.
std::vector<KSynchronizationObject*> objs(num_handles);
R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles.data(),
num_handles),
ResultInvalidHandle);
// Ensure handles are closed when we're done.
SCOPE_EXIT({
for (auto i = 0; i < num_handles; ++i) {
objs[i]->Close();
}
});
// Reply to the target, if one is specified.
if (reply_target != InvalidHandle) {
KScopedAutoObject session = handle_table.GetObject<KServerSession>(reply_target);
R_UNLESS(session.IsNotNull(), ResultInvalidHandle);
// If we fail to reply, we want to set the output index to -1.
ON_RESULT_FAILURE {
*out_index = -1;
};
// Send the reply.
R_TRY(session->SendReply());
}
// Wait for a message.
while (true) {
// Wait for an object.
s32 index;
Result result = KSynchronizationObject::Wait(kernel, &index, objs.data(),
static_cast<s32>(objs.size()), timeout_ns);
if (result == ResultTimedOut) {
return result;
}
// Receive the request.
if (R_SUCCEEDED(result)) {
KServerSession* session = objs[index]->DynamicCast<KServerSession*>();
if (session != nullptr) {
result = session->ReceiveRequest();
if (result == ResultNotFound) {
continue;
}
}
}
*out_index = index;
return result;
}
}
Result ReplyAndReceiveWithUserBuffer(Core::System& system, int32_t* out_index,
uint64_t message_buffer, uint64_t message_buffer_size,
uint64_t handles, int32_t num_handles, Handle reply_target,
int64_t timeout_ns) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result SendSyncRequest64(Core::System& system, Handle session_handle) {
R_RETURN(SendSyncRequest(system, session_handle));
}
Result SendSyncRequestWithUserBuffer64(Core::System& system, uint64_t message_buffer,
uint64_t message_buffer_size, Handle session_handle) {
R_RETURN(
SendSyncRequestWithUserBuffer(system, message_buffer, message_buffer_size, session_handle));
}
Result SendAsyncRequestWithUserBuffer64(Core::System& system, Handle* out_event_handle,
uint64_t message_buffer, uint64_t message_buffer_size,
Handle session_handle) {
R_RETURN(SendAsyncRequestWithUserBuffer(system, out_event_handle, message_buffer,
message_buffer_size, session_handle));
}
Result ReplyAndReceive64(Core::System& system, int32_t* out_index, uint64_t handles,
int32_t num_handles, Handle reply_target, int64_t timeout_ns) {
R_RETURN(ReplyAndReceive(system, out_index, handles, num_handles, reply_target, timeout_ns));
}
Result ReplyAndReceiveWithUserBuffer64(Core::System& system, int32_t* out_index,
uint64_t message_buffer, uint64_t message_buffer_size,
uint64_t handles, int32_t num_handles, Handle reply_target,
int64_t timeout_ns) {
R_RETURN(ReplyAndReceiveWithUserBuffer(system, out_index, message_buffer, message_buffer_size,
handles, num_handles, reply_target, timeout_ns));
}
Result SendSyncRequest64From32(Core::System& system, Handle session_handle) {
R_RETURN(SendSyncRequest(system, session_handle));
}
Result SendSyncRequestWithUserBuffer64From32(Core::System& system, uint32_t message_buffer,
uint32_t message_buffer_size, Handle session_handle) {
R_RETURN(
SendSyncRequestWithUserBuffer(system, message_buffer, message_buffer_size, session_handle));
}
Result SendAsyncRequestWithUserBuffer64From32(Core::System& system, Handle* out_event_handle,
uint32_t message_buffer, uint32_t message_buffer_size,
Handle session_handle) {
R_RETURN(SendAsyncRequestWithUserBuffer(system, out_event_handle, message_buffer,
message_buffer_size, session_handle));
}
Result ReplyAndReceive64From32(Core::System& system, int32_t* out_index, uint32_t handles,
int32_t num_handles, Handle reply_target, int64_t timeout_ns) {
R_RETURN(ReplyAndReceive(system, out_index, handles, num_handles, reply_target, timeout_ns));
}
Result ReplyAndReceiveWithUserBuffer64From32(Core::System& system, int32_t* out_index,
uint32_t message_buffer, uint32_t message_buffer_size,
uint32_t handles, int32_t num_handles,
Handle reply_target, int64_t timeout_ns) {
R_RETURN(ReplyAndReceiveWithUserBuffer(system, out_index, message_buffer, message_buffer_size,
handles, num_handles, reply_target, timeout_ns));
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,35 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/kernel/svc.h"
namespace Kernel::Svc {
void KernelDebug(Core::System& system, KernelDebugType kernel_debug_type, u64 arg0, u64 arg1,
u64 arg2) {
// Intentionally do nothing, as this does nothing in released kernel binaries.
}
void ChangeKernelTraceState(Core::System& system, KernelTraceState trace_state) {
// Intentionally do nothing, as this does nothing in released kernel binaries.
}
void KernelDebug64(Core::System& system, KernelDebugType kern_debug_type, uint64_t arg0,
uint64_t arg1, uint64_t arg2) {
KernelDebug(system, kern_debug_type, arg0, arg1, arg2);
}
void ChangeKernelTraceState64(Core::System& system, KernelTraceState kern_trace_state) {
ChangeKernelTraceState(system, kern_trace_state);
}
void KernelDebug64From32(Core::System& system, KernelDebugType kern_debug_type, uint64_t arg0,
uint64_t arg1, uint64_t arg2) {
KernelDebug(system, kern_debug_type, arg0, arg1, arg2);
}
void ChangeKernelTraceState64From32(Core::System& system, KernelTraceState kern_trace_state) {
ChangeKernelTraceState(system, kern_trace_state);
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,73 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/arm/arm_interface.h"
#include "core/core.h"
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/svc_results.h"
namespace Kernel::Svc {
Result SendSyncRequestLight(Core::System& system, Handle session_handle, u32* args) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result ReplyAndReceiveLight(Core::System& system, Handle session_handle, u32* args) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result SendSyncRequestLight64(Core::System& system, Handle session_handle, u32* args) {
R_RETURN(SendSyncRequestLight(system, session_handle, args));
}
Result ReplyAndReceiveLight64(Core::System& system, Handle session_handle, u32* args) {
R_RETURN(ReplyAndReceiveLight(system, session_handle, args));
}
Result SendSyncRequestLight64From32(Core::System& system, Handle session_handle, u32* args) {
R_RETURN(SendSyncRequestLight(system, session_handle, args));
}
Result ReplyAndReceiveLight64From32(Core::System& system, Handle session_handle, u32* args) {
R_RETURN(ReplyAndReceiveLight(system, session_handle, args));
}
// Custom ABI implementation for light IPC.
template <typename F>
static void SvcWrap_LightIpc(Core::System& system, F&& cb) {
auto& core = system.CurrentArmInterface();
std::array<u32, 7> arguments{};
Handle session_handle = static_cast<Handle>(core.GetReg(0));
for (int i = 0; i < 7; i++) {
arguments[i] = static_cast<u32>(core.GetReg(i + 1));
}
Result ret = cb(system, session_handle, arguments.data());
core.SetReg(0, ret.raw);
for (int i = 0; i < 7; i++) {
core.SetReg(i + 1, arguments[i]);
}
}
void SvcWrap_SendSyncRequestLight64(Core::System& system) {
SvcWrap_LightIpc(system, SendSyncRequestLight64);
}
void SvcWrap_ReplyAndReceiveLight64(Core::System& system) {
SvcWrap_LightIpc(system, ReplyAndReceiveLight64);
}
void SvcWrap_SendSyncRequestLight64From32(Core::System& system) {
SvcWrap_LightIpc(system, SendSyncRequestLight64From32);
}
void SvcWrap_ReplyAndReceiveLight64From32(Core::System& system) {
SvcWrap_LightIpc(system, ReplyAndReceiveLight64From32);
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,66 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/kernel/k_memory_layout.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/svc.h"
namespace Kernel::Svc {
/// Attempts to locks a mutex
Result ArbitrateLock(Core::System& system, Handle thread_handle, VAddr address, u32 tag) {
LOG_TRACE(Kernel_SVC, "called thread_handle=0x{:08X}, address=0x{:X}, tag=0x{:08X}",
thread_handle, address, tag);
// Validate the input address.
if (IsKernelAddress(address)) {
LOG_ERROR(Kernel_SVC, "Attempting to arbitrate a lock on a kernel address (address={:08X})",
address);
return ResultInvalidCurrentMemory;
}
if (!Common::IsAligned(address, sizeof(u32))) {
LOG_ERROR(Kernel_SVC, "Input address must be 4 byte aligned (address: {:08X})", address);
return ResultInvalidAddress;
}
return GetCurrentProcess(system.Kernel()).WaitForAddress(thread_handle, address, tag);
}
/// Unlock a mutex
Result ArbitrateUnlock(Core::System& system, VAddr address) {
LOG_TRACE(Kernel_SVC, "called address=0x{:X}", address);
// Validate the input address.
if (IsKernelAddress(address)) {
LOG_ERROR(Kernel_SVC,
"Attempting to arbitrate an unlock on a kernel address (address={:08X})",
address);
return ResultInvalidCurrentMemory;
}
if (!Common::IsAligned(address, sizeof(u32))) {
LOG_ERROR(Kernel_SVC, "Input address must be 4 byte aligned (address: {:08X})", address);
return ResultInvalidAddress;
}
return GetCurrentProcess(system.Kernel()).SignalToAddress(address);
}
Result ArbitrateLock64(Core::System& system, Handle thread_handle, uint64_t address, uint32_t tag) {
R_RETURN(ArbitrateLock(system, thread_handle, address, tag));
}
Result ArbitrateUnlock64(Core::System& system, uint64_t address) {
R_RETURN(ArbitrateUnlock(system, address));
}
Result ArbitrateLock64From32(Core::System& system, Handle thread_handle, uint32_t address,
uint32_t tag) {
R_RETURN(ArbitrateLock(system, thread_handle, address, tag));
}
Result ArbitrateUnlock64From32(Core::System& system, uint32_t address) {
R_RETURN(ArbitrateUnlock(system, address));
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,217 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/svc.h"
namespace Kernel::Svc {
namespace {
constexpr bool IsValidSetMemoryPermission(MemoryPermission perm) {
switch (perm) {
case MemoryPermission::None:
case MemoryPermission::Read:
case MemoryPermission::ReadWrite:
return true;
default:
return false;
}
}
// Checks if address + size is greater than the given address
// This can return false if the size causes an overflow of a 64-bit type
// or if the given size is zero.
constexpr bool IsValidAddressRange(VAddr address, u64 size) {
return address + size > address;
}
// Helper function that performs the common sanity checks for svcMapMemory
// and svcUnmapMemory. This is doable, as both functions perform their sanitizing
// in the same order.
Result MapUnmapMemorySanityChecks(const KPageTable& manager, VAddr dst_addr, VAddr src_addr,
u64 size) {
if (!Common::Is4KBAligned(dst_addr)) {
LOG_ERROR(Kernel_SVC, "Destination address is not aligned to 4KB, 0x{:016X}", dst_addr);
return ResultInvalidAddress;
}
if (!Common::Is4KBAligned(src_addr)) {
LOG_ERROR(Kernel_SVC, "Source address is not aligned to 4KB, 0x{:016X}", src_addr);
return ResultInvalidSize;
}
if (size == 0) {
LOG_ERROR(Kernel_SVC, "Size is 0");
return ResultInvalidSize;
}
if (!Common::Is4KBAligned(size)) {
LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:016X}", size);
return ResultInvalidSize;
}
if (!IsValidAddressRange(dst_addr, size)) {
LOG_ERROR(Kernel_SVC,
"Destination is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
dst_addr, size);
return ResultInvalidCurrentMemory;
}
if (!IsValidAddressRange(src_addr, size)) {
LOG_ERROR(Kernel_SVC, "Source is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
src_addr, size);
return ResultInvalidCurrentMemory;
}
if (!manager.IsInsideAddressSpace(src_addr, size)) {
LOG_ERROR(Kernel_SVC,
"Source is not within the address space, addr=0x{:016X}, size=0x{:016X}",
src_addr, size);
return ResultInvalidCurrentMemory;
}
if (manager.IsOutsideStackRegion(dst_addr, size)) {
LOG_ERROR(Kernel_SVC,
"Destination is not within the stack region, addr=0x{:016X}, size=0x{:016X}",
dst_addr, size);
return ResultInvalidMemoryRegion;
}
if (manager.IsInsideHeapRegion(dst_addr, size)) {
LOG_ERROR(Kernel_SVC,
"Destination does not fit within the heap region, addr=0x{:016X}, "
"size=0x{:016X}",
dst_addr, size);
return ResultInvalidMemoryRegion;
}
if (manager.IsInsideAliasRegion(dst_addr, size)) {
LOG_ERROR(Kernel_SVC,
"Destination does not fit within the map region, addr=0x{:016X}, "
"size=0x{:016X}",
dst_addr, size);
return ResultInvalidMemoryRegion;
}
return ResultSuccess;
}
} // namespace
Result SetMemoryPermission(Core::System& system, VAddr address, u64 size, MemoryPermission perm) {
LOG_DEBUG(Kernel_SVC, "called, address=0x{:016X}, size=0x{:X}, perm=0x{:08X", address, size,
perm);
// Validate address / size.
R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
R_UNLESS(size > 0, ResultInvalidSize);
R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
// Validate the permission.
R_UNLESS(IsValidSetMemoryPermission(perm), ResultInvalidNewMemoryPermission);
// Validate that the region is in range for the current process.
auto& page_table = GetCurrentProcess(system.Kernel()).PageTable();
R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
// Set the memory attribute.
return page_table.SetMemoryPermission(address, size, perm);
}
Result SetMemoryAttribute(Core::System& system, VAddr address, u64 size, u32 mask, u32 attr) {
LOG_DEBUG(Kernel_SVC,
"called, address=0x{:016X}, size=0x{:X}, mask=0x{:08X}, attribute=0x{:08X}", address,
size, mask, attr);
// Validate address / size.
R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
R_UNLESS(size > 0, ResultInvalidSize);
R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
// Validate the attribute and mask.
constexpr u32 SupportedMask = static_cast<u32>(MemoryAttribute::Uncached);
R_UNLESS((mask | attr) == mask, ResultInvalidCombination);
R_UNLESS((mask | attr | SupportedMask) == SupportedMask, ResultInvalidCombination);
// Validate that the region is in range for the current process.
auto& page_table{GetCurrentProcess(system.Kernel()).PageTable()};
R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
// Set the memory attribute.
return page_table.SetMemoryAttribute(address, size, mask, attr);
}
/// Maps a memory range into a different range.
Result MapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) {
LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
src_addr, size);
auto& page_table{GetCurrentProcess(system.Kernel()).PageTable()};
if (const Result result{MapUnmapMemorySanityChecks(page_table, dst_addr, src_addr, size)};
result.IsError()) {
return result;
}
return page_table.MapMemory(dst_addr, src_addr, size);
}
/// Unmaps a region that was previously mapped with svcMapMemory
Result UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) {
LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
src_addr, size);
auto& page_table{GetCurrentProcess(system.Kernel()).PageTable()};
if (const Result result{MapUnmapMemorySanityChecks(page_table, dst_addr, src_addr, size)};
result.IsError()) {
return result;
}
return page_table.UnmapMemory(dst_addr, src_addr, size);
}
Result SetMemoryPermission64(Core::System& system, uint64_t address, uint64_t size,
MemoryPermission perm) {
R_RETURN(SetMemoryPermission(system, address, size, perm));
}
Result SetMemoryAttribute64(Core::System& system, uint64_t address, uint64_t size, uint32_t mask,
uint32_t attr) {
R_RETURN(SetMemoryAttribute(system, address, size, mask, attr));
}
Result MapMemory64(Core::System& system, uint64_t dst_address, uint64_t src_address,
uint64_t size) {
R_RETURN(MapMemory(system, dst_address, src_address, size));
}
Result UnmapMemory64(Core::System& system, uint64_t dst_address, uint64_t src_address,
uint64_t size) {
R_RETURN(UnmapMemory(system, dst_address, src_address, size));
}
Result SetMemoryPermission64From32(Core::System& system, uint32_t address, uint32_t size,
MemoryPermission perm) {
R_RETURN(SetMemoryPermission(system, address, size, perm));
}
Result SetMemoryAttribute64From32(Core::System& system, uint32_t address, uint32_t size,
uint32_t mask, uint32_t attr) {
R_RETURN(SetMemoryAttribute(system, address, size, mask, attr));
}
Result MapMemory64From32(Core::System& system, uint32_t dst_address, uint32_t src_address,
uint32_t size) {
R_RETURN(MapMemory(system, dst_address, src_address, size));
}
Result UnmapMemory64From32(Core::System& system, uint32_t dst_address, uint32_t src_address,
uint32_t size) {
R_RETURN(UnmapMemory(system, dst_address, src_address, size));
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,185 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/svc.h"
namespace Kernel::Svc {
/// Set the process heap to a given Size. It can both extend and shrink the heap.
Result SetHeapSize(Core::System& system, VAddr* out_address, u64 size) {
LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", size);
// Validate size.
R_UNLESS(Common::IsAligned(size, HeapSizeAlignment), ResultInvalidSize);
R_UNLESS(size < MainMemorySizeMax, ResultInvalidSize);
// Set the heap size.
R_TRY(GetCurrentProcess(system.Kernel()).PageTable().SetHeapSize(out_address, size));
return ResultSuccess;
}
/// Maps memory at a desired address
Result MapPhysicalMemory(Core::System& system, VAddr addr, u64 size) {
LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size);
if (!Common::Is4KBAligned(addr)) {
LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, 0x{:016X}", addr);
return ResultInvalidAddress;
}
if (!Common::Is4KBAligned(size)) {
LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:X}", size);
return ResultInvalidSize;
}
if (size == 0) {
LOG_ERROR(Kernel_SVC, "Size is zero");
return ResultInvalidSize;
}
if (!(addr < addr + size)) {
LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address");
return ResultInvalidMemoryRegion;
}
KProcess* const current_process{GetCurrentProcessPointer(system.Kernel())};
auto& page_table{current_process->PageTable()};
if (current_process->GetSystemResourceSize() == 0) {
LOG_ERROR(Kernel_SVC, "System Resource Size is zero");
return ResultInvalidState;
}
if (!page_table.IsInsideAddressSpace(addr, size)) {
LOG_ERROR(Kernel_SVC,
"Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr,
size);
return ResultInvalidMemoryRegion;
}
if (page_table.IsOutsideAliasRegion(addr, size)) {
LOG_ERROR(Kernel_SVC,
"Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr,
size);
return ResultInvalidMemoryRegion;
}
return page_table.MapPhysicalMemory(addr, size);
}
/// Unmaps memory previously mapped via MapPhysicalMemory
Result UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size) {
LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size);
if (!Common::Is4KBAligned(addr)) {
LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, 0x{:016X}", addr);
return ResultInvalidAddress;
}
if (!Common::Is4KBAligned(size)) {
LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:X}", size);
return ResultInvalidSize;
}
if (size == 0) {
LOG_ERROR(Kernel_SVC, "Size is zero");
return ResultInvalidSize;
}
if (!(addr < addr + size)) {
LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address");
return ResultInvalidMemoryRegion;
}
KProcess* const current_process{GetCurrentProcessPointer(system.Kernel())};
auto& page_table{current_process->PageTable()};
if (current_process->GetSystemResourceSize() == 0) {
LOG_ERROR(Kernel_SVC, "System Resource Size is zero");
return ResultInvalidState;
}
if (!page_table.IsInsideAddressSpace(addr, size)) {
LOG_ERROR(Kernel_SVC,
"Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr,
size);
return ResultInvalidMemoryRegion;
}
if (page_table.IsOutsideAliasRegion(addr, size)) {
LOG_ERROR(Kernel_SVC,
"Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr,
size);
return ResultInvalidMemoryRegion;
}
return page_table.UnmapPhysicalMemory(addr, size);
}
Result MapPhysicalMemoryUnsafe(Core::System& system, uint64_t address, uint64_t size) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result UnmapPhysicalMemoryUnsafe(Core::System& system, uint64_t address, uint64_t size) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result SetUnsafeLimit(Core::System& system, uint64_t limit) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result SetHeapSize64(Core::System& system, uint64_t* out_address, uint64_t size) {
R_RETURN(SetHeapSize(system, out_address, size));
}
Result MapPhysicalMemory64(Core::System& system, uint64_t address, uint64_t size) {
R_RETURN(MapPhysicalMemory(system, address, size));
}
Result UnmapPhysicalMemory64(Core::System& system, uint64_t address, uint64_t size) {
R_RETURN(UnmapPhysicalMemory(system, address, size));
}
Result MapPhysicalMemoryUnsafe64(Core::System& system, uint64_t address, uint64_t size) {
R_RETURN(MapPhysicalMemoryUnsafe(system, address, size));
}
Result UnmapPhysicalMemoryUnsafe64(Core::System& system, uint64_t address, uint64_t size) {
R_RETURN(UnmapPhysicalMemoryUnsafe(system, address, size));
}
Result SetUnsafeLimit64(Core::System& system, uint64_t limit) {
R_RETURN(SetUnsafeLimit(system, limit));
}
Result SetHeapSize64From32(Core::System& system, uintptr_t* out_address, uint32_t size) {
R_RETURN(SetHeapSize(system, out_address, size));
}
Result MapPhysicalMemory64From32(Core::System& system, uint32_t address, uint32_t size) {
R_RETURN(MapPhysicalMemory(system, address, size));
}
Result UnmapPhysicalMemory64From32(Core::System& system, uint32_t address, uint32_t size) {
R_RETURN(UnmapPhysicalMemory(system, address, size));
}
Result MapPhysicalMemoryUnsafe64From32(Core::System& system, uint32_t address, uint32_t size) {
R_RETURN(MapPhysicalMemoryUnsafe(system, address, size));
}
Result UnmapPhysicalMemoryUnsafe64From32(Core::System& system, uint32_t address, uint32_t size) {
R_RETURN(UnmapPhysicalMemoryUnsafe(system, address, size));
}
Result SetUnsafeLimit64From32(Core::System& system, uint32_t limit) {
R_RETURN(SetUnsafeLimit(system, limit));
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,122 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/hle/kernel/k_client_port.h"
#include "core/hle/kernel/k_client_session.h"
#include "core/hle/kernel/k_port.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/svc.h"
namespace Kernel::Svc {
/// Connect to an OS service given the port name, returns the handle to the port to out
Result ConnectToNamedPort(Core::System& system, Handle* out, VAddr port_name_address) {
auto& memory = system.Memory();
if (!memory.IsValidVirtualAddress(port_name_address)) {
LOG_ERROR(Kernel_SVC,
"Port Name Address is not a valid virtual address, port_name_address=0x{:016X}",
port_name_address);
return ResultNotFound;
}
static constexpr std::size_t PortNameMaxLength = 11;
// Read 1 char beyond the max allowed port name to detect names that are too long.
const std::string port_name = memory.ReadCString(port_name_address, PortNameMaxLength + 1);
if (port_name.size() > PortNameMaxLength) {
LOG_ERROR(Kernel_SVC, "Port name is too long, expected {} but got {}", PortNameMaxLength,
port_name.size());
return ResultOutOfRange;
}
LOG_TRACE(Kernel_SVC, "called port_name={}", port_name);
// Get the current handle table.
auto& kernel = system.Kernel();
auto& handle_table = GetCurrentProcess(kernel).GetHandleTable();
// Find the client port.
auto port = kernel.CreateNamedServicePort(port_name);
if (!port) {
LOG_ERROR(Kernel_SVC, "tried to connect to unknown port: {}", port_name);
return ResultNotFound;
}
// Reserve a handle for the port.
// NOTE: Nintendo really does write directly to the output handle here.
R_TRY(handle_table.Reserve(out));
auto handle_guard = SCOPE_GUARD({ handle_table.Unreserve(*out); });
// Create a session.
KClientSession* session{};
R_TRY(port->CreateSession(std::addressof(session)));
kernel.RegisterNamedServiceHandler(port_name, &port->GetParent()->GetServerPort());
// Register the session in the table, close the extra reference.
handle_table.Register(*out, session);
session->Close();
// We succeeded.
handle_guard.Cancel();
return ResultSuccess;
}
Result CreatePort(Core::System& system, Handle* out_server, Handle* out_client,
int32_t max_sessions, bool is_light, uintptr_t name) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result ConnectToPort(Core::System& system, Handle* out_handle, Handle port) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t name,
int32_t max_sessions) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result ConnectToNamedPort64(Core::System& system, Handle* out_handle, uint64_t name) {
R_RETURN(ConnectToNamedPort(system, out_handle, name));
}
Result CreatePort64(Core::System& system, Handle* out_server_handle, Handle* out_client_handle,
int32_t max_sessions, bool is_light, uint64_t name) {
R_RETURN(
CreatePort(system, out_server_handle, out_client_handle, max_sessions, is_light, name));
}
Result ManageNamedPort64(Core::System& system, Handle* out_server_handle, uint64_t name,
int32_t max_sessions) {
R_RETURN(ManageNamedPort(system, out_server_handle, name, max_sessions));
}
Result ConnectToPort64(Core::System& system, Handle* out_handle, Handle port) {
R_RETURN(ConnectToPort(system, out_handle, port));
}
Result ConnectToNamedPort64From32(Core::System& system, Handle* out_handle, uint32_t name) {
R_RETURN(ConnectToNamedPort(system, out_handle, name));
}
Result CreatePort64From32(Core::System& system, Handle* out_server_handle,
Handle* out_client_handle, int32_t max_sessions, bool is_light,
uint32_t name) {
R_RETURN(
CreatePort(system, out_server_handle, out_client_handle, max_sessions, is_light, name));
}
Result ManageNamedPort64From32(Core::System& system, Handle* out_server_handle, uint32_t name,
int32_t max_sessions) {
R_RETURN(ManageNamedPort(system, out_server_handle, name, max_sessions));
}
Result ConnectToPort64From32(Core::System& system, Handle* out_handle, Handle port) {
R_RETURN(ConnectToPort(system, out_handle, port));
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,21 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/svc_results.h"
namespace Kernel::Svc {
void SleepSystem(Core::System& system) {
UNIMPLEMENTED();
}
void SleepSystem64(Core::System& system) {
return SleepSystem(system);
}
void SleepSystem64From32(Core::System& system) {
return SleepSystem(system);
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,194 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/svc.h"
namespace Kernel::Svc {
/// Exits the current process
void ExitProcess(Core::System& system) {
auto* current_process = GetCurrentProcessPointer(system.Kernel());
LOG_INFO(Kernel_SVC, "Process {} exiting", current_process->GetProcessID());
ASSERT_MSG(current_process->GetState() == KProcess::State::Running,
"Process has already exited");
system.Exit();
}
/// Gets the ID of the specified process or a specified thread's owning process.
Result GetProcessId(Core::System& system, u64* out_process_id, Handle handle) {
LOG_DEBUG(Kernel_SVC, "called handle=0x{:08X}", handle);
// Get the object from the handle table.
KScopedAutoObject obj = GetCurrentProcess(system.Kernel())
.GetHandleTable()
.GetObject<KAutoObject>(static_cast<Handle>(handle));
R_UNLESS(obj.IsNotNull(), ResultInvalidHandle);
// Get the process from the object.
KProcess* process = nullptr;
if (KProcess* p = obj->DynamicCast<KProcess*>(); p != nullptr) {
// The object is a process, so we can use it directly.
process = p;
} else if (KThread* t = obj->DynamicCast<KThread*>(); t != nullptr) {
// The object is a thread, so we want to use its parent.
process = reinterpret_cast<KThread*>(obj.GetPointerUnsafe())->GetOwnerProcess();
} else {
// TODO(bunnei): This should also handle debug objects before returning.
UNIMPLEMENTED_MSG("Debug objects not implemented");
}
// Make sure the target process exists.
R_UNLESS(process != nullptr, ResultInvalidHandle);
// Get the process id.
*out_process_id = process->GetId();
return ResultSuccess;
}
Result GetProcessList(Core::System& system, s32* out_num_processes, VAddr out_process_ids,
int32_t out_process_ids_size) {
LOG_DEBUG(Kernel_SVC, "called. out_process_ids=0x{:016X}, out_process_ids_size={}",
out_process_ids, out_process_ids_size);
// If the supplied size is negative or greater than INT32_MAX / sizeof(u64), bail.
if ((out_process_ids_size & 0xF0000000) != 0) {
LOG_ERROR(Kernel_SVC,
"Supplied size outside [0, 0x0FFFFFFF] range. out_process_ids_size={}",
out_process_ids_size);
return ResultOutOfRange;
}
auto& kernel = system.Kernel();
const auto total_copy_size = out_process_ids_size * sizeof(u64);
if (out_process_ids_size > 0 && !GetCurrentProcess(kernel).PageTable().IsInsideAddressSpace(
out_process_ids, total_copy_size)) {
LOG_ERROR(Kernel_SVC, "Address range outside address space. begin=0x{:016X}, end=0x{:016X}",
out_process_ids, out_process_ids + total_copy_size);
return ResultInvalidCurrentMemory;
}
auto& memory = system.Memory();
const auto& process_list = kernel.GetProcessList();
const auto num_processes = process_list.size();
const auto copy_amount =
std::min(static_cast<std::size_t>(out_process_ids_size), num_processes);
for (std::size_t i = 0; i < copy_amount; ++i) {
memory.Write64(out_process_ids, process_list[i]->GetProcessID());
out_process_ids += sizeof(u64);
}
*out_num_processes = static_cast<u32>(num_processes);
return ResultSuccess;
}
Result GetProcessInfo(Core::System& system, s64* out, Handle process_handle,
ProcessInfoType info_type) {
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, type=0x{:X}", process_handle, info_type);
const auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle);
if (process.IsNull()) {
LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}",
process_handle);
return ResultInvalidHandle;
}
if (info_type != ProcessInfoType::ProcessState) {
LOG_ERROR(Kernel_SVC, "Expected info_type to be ProcessState but got {} instead",
info_type);
return ResultInvalidEnumValue;
}
*out = static_cast<s64>(process->GetState());
return ResultSuccess;
}
Result CreateProcess(Core::System& system, Handle* out_handle, uint64_t parameters, uint64_t caps,
int32_t num_caps) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result StartProcess(Core::System& system, Handle process_handle, int32_t priority, int32_t core_id,
uint64_t main_thread_stack_size) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result TerminateProcess(Core::System& system, Handle process_handle) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
void ExitProcess64(Core::System& system) {
ExitProcess(system);
}
Result GetProcessId64(Core::System& system, uint64_t* out_process_id, Handle process_handle) {
R_RETURN(GetProcessId(system, out_process_id, process_handle));
}
Result GetProcessList64(Core::System& system, int32_t* out_num_processes, uint64_t out_process_ids,
int32_t max_out_count) {
R_RETURN(GetProcessList(system, out_num_processes, out_process_ids, max_out_count));
}
Result CreateProcess64(Core::System& system, Handle* out_handle, uint64_t parameters, uint64_t caps,
int32_t num_caps) {
R_RETURN(CreateProcess(system, out_handle, parameters, caps, num_caps));
}
Result StartProcess64(Core::System& system, Handle process_handle, int32_t priority,
int32_t core_id, uint64_t main_thread_stack_size) {
R_RETURN(StartProcess(system, process_handle, priority, core_id, main_thread_stack_size));
}
Result TerminateProcess64(Core::System& system, Handle process_handle) {
R_RETURN(TerminateProcess(system, process_handle));
}
Result GetProcessInfo64(Core::System& system, int64_t* out_info, Handle process_handle,
ProcessInfoType info_type) {
R_RETURN(GetProcessInfo(system, out_info, process_handle, info_type));
}
void ExitProcess64From32(Core::System& system) {
ExitProcess(system);
}
Result GetProcessId64From32(Core::System& system, uint64_t* out_process_id, Handle process_handle) {
R_RETURN(GetProcessId(system, out_process_id, process_handle));
}
Result GetProcessList64From32(Core::System& system, int32_t* out_num_processes,
uint32_t out_process_ids, int32_t max_out_count) {
R_RETURN(GetProcessList(system, out_num_processes, out_process_ids, max_out_count));
}
Result CreateProcess64From32(Core::System& system, Handle* out_handle, uint32_t parameters,
uint32_t caps, int32_t num_caps) {
R_RETURN(CreateProcess(system, out_handle, parameters, caps, num_caps));
}
Result StartProcess64From32(Core::System& system, Handle process_handle, int32_t priority,
int32_t core_id, uint64_t main_thread_stack_size) {
R_RETURN(StartProcess(system, process_handle, priority, core_id, main_thread_stack_size));
}
Result TerminateProcess64From32(Core::System& system, Handle process_handle) {
R_RETURN(TerminateProcess(system, process_handle));
}
Result GetProcessInfo64From32(Core::System& system, int64_t* out_info, Handle process_handle,
ProcessInfoType info_type) {
R_RETURN(GetProcessInfo(system, out_info, process_handle, info_type));
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,324 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/svc.h"
namespace Kernel::Svc {
namespace {
constexpr bool IsValidAddressRange(VAddr address, u64 size) {
return address + size > address;
}
constexpr bool IsValidProcessMemoryPermission(Svc::MemoryPermission perm) {
switch (perm) {
case Svc::MemoryPermission::None:
case Svc::MemoryPermission::Read:
case Svc::MemoryPermission::ReadWrite:
case Svc::MemoryPermission::ReadExecute:
return true;
default:
return false;
}
}
} // namespace
Result SetProcessMemoryPermission(Core::System& system, Handle process_handle, VAddr address,
u64 size, Svc::MemoryPermission perm) {
LOG_TRACE(Kernel_SVC,
"called, process_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}",
process_handle, address, size, perm);
// Validate the address/size.
R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
R_UNLESS(size > 0, ResultInvalidSize);
R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
R_UNLESS(address == static_cast<uintptr_t>(address), ResultInvalidCurrentMemory);
R_UNLESS(size == static_cast<size_t>(size), ResultInvalidCurrentMemory);
// Validate the memory permission.
R_UNLESS(IsValidProcessMemoryPermission(perm), ResultInvalidNewMemoryPermission);
// Get the process from its handle.
KScopedAutoObject process =
GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KProcess>(process_handle);
R_UNLESS(process.IsNotNull(), ResultInvalidHandle);
// Validate that the address is in range.
auto& page_table = process->PageTable();
R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
// Set the memory permission.
return page_table.SetProcessMemoryPermission(address, size, perm);
}
Result MapProcessMemory(Core::System& system, VAddr dst_address, Handle process_handle,
VAddr src_address, u64 size) {
LOG_TRACE(Kernel_SVC,
"called, dst_address=0x{:X}, process_handle=0x{:X}, src_address=0x{:X}, size=0x{:X}",
dst_address, process_handle, src_address, size);
// Validate the address/size.
R_UNLESS(Common::IsAligned(dst_address, PageSize), ResultInvalidAddress);
R_UNLESS(Common::IsAligned(src_address, PageSize), ResultInvalidAddress);
R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
R_UNLESS(size > 0, ResultInvalidSize);
R_UNLESS((dst_address < dst_address + size), ResultInvalidCurrentMemory);
R_UNLESS((src_address < src_address + size), ResultInvalidCurrentMemory);
// Get the processes.
KProcess* dst_process = GetCurrentProcessPointer(system.Kernel());
KScopedAutoObject src_process =
dst_process->GetHandleTable().GetObjectWithoutPseudoHandle<KProcess>(process_handle);
R_UNLESS(src_process.IsNotNull(), ResultInvalidHandle);
// Get the page tables.
auto& dst_pt = dst_process->PageTable();
auto& src_pt = src_process->PageTable();
// Validate that the mapping is in range.
R_UNLESS(src_pt.Contains(src_address, size), ResultInvalidCurrentMemory);
R_UNLESS(dst_pt.CanContain(dst_address, size, KMemoryState::SharedCode),
ResultInvalidMemoryRegion);
// Create a new page group.
KPageGroup pg{system.Kernel(), dst_pt.GetBlockInfoManager()};
R_TRY(src_pt.MakeAndOpenPageGroup(
std::addressof(pg), src_address, size / PageSize, KMemoryState::FlagCanMapProcess,
KMemoryState::FlagCanMapProcess, KMemoryPermission::None, KMemoryPermission::None,
KMemoryAttribute::All, KMemoryAttribute::None));
// Map the group.
R_TRY(dst_pt.MapPageGroup(dst_address, pg, KMemoryState::SharedCode,
KMemoryPermission::UserReadWrite));
return ResultSuccess;
}
Result UnmapProcessMemory(Core::System& system, VAddr dst_address, Handle process_handle,
VAddr src_address, u64 size) {
LOG_TRACE(Kernel_SVC,
"called, dst_address=0x{:X}, process_handle=0x{:X}, src_address=0x{:X}, size=0x{:X}",
dst_address, process_handle, src_address, size);
// Validate the address/size.
R_UNLESS(Common::IsAligned(dst_address, PageSize), ResultInvalidAddress);
R_UNLESS(Common::IsAligned(src_address, PageSize), ResultInvalidAddress);
R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
R_UNLESS(size > 0, ResultInvalidSize);
R_UNLESS((dst_address < dst_address + size), ResultInvalidCurrentMemory);
R_UNLESS((src_address < src_address + size), ResultInvalidCurrentMemory);
// Get the processes.
KProcess* dst_process = GetCurrentProcessPointer(system.Kernel());
KScopedAutoObject src_process =
dst_process->GetHandleTable().GetObjectWithoutPseudoHandle<KProcess>(process_handle);
R_UNLESS(src_process.IsNotNull(), ResultInvalidHandle);
// Get the page tables.
auto& dst_pt = dst_process->PageTable();
auto& src_pt = src_process->PageTable();
// Validate that the mapping is in range.
R_UNLESS(src_pt.Contains(src_address, size), ResultInvalidCurrentMemory);
R_UNLESS(dst_pt.CanContain(dst_address, size, KMemoryState::SharedCode),
ResultInvalidMemoryRegion);
// Unmap the memory.
R_TRY(dst_pt.UnmapProcessMemory(dst_address, size, src_pt, src_address));
return ResultSuccess;
}
Result MapProcessCodeMemory(Core::System& system, Handle process_handle, u64 dst_address,
u64 src_address, u64 size) {
LOG_DEBUG(Kernel_SVC,
"called. process_handle=0x{:08X}, dst_address=0x{:016X}, "
"src_address=0x{:016X}, size=0x{:016X}",
process_handle, dst_address, src_address, size);
if (!Common::Is4KBAligned(src_address)) {
LOG_ERROR(Kernel_SVC, "src_address is not page-aligned (src_address=0x{:016X}).",
src_address);
return ResultInvalidAddress;
}
if (!Common::Is4KBAligned(dst_address)) {
LOG_ERROR(Kernel_SVC, "dst_address is not page-aligned (dst_address=0x{:016X}).",
dst_address);
return ResultInvalidAddress;
}
if (size == 0 || !Common::Is4KBAligned(size)) {
LOG_ERROR(Kernel_SVC, "Size is zero or not page-aligned (size=0x{:016X})", size);
return ResultInvalidSize;
}
if (!IsValidAddressRange(dst_address, size)) {
LOG_ERROR(Kernel_SVC,
"Destination address range overflows the address space (dst_address=0x{:016X}, "
"size=0x{:016X}).",
dst_address, size);
return ResultInvalidCurrentMemory;
}
if (!IsValidAddressRange(src_address, size)) {
LOG_ERROR(Kernel_SVC,
"Source address range overflows the address space (src_address=0x{:016X}, "
"size=0x{:016X}).",
src_address, size);
return ResultInvalidCurrentMemory;
}
const auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle);
if (process.IsNull()) {
LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).",
process_handle);
return ResultInvalidHandle;
}
auto& page_table = process->PageTable();
if (!page_table.IsInsideAddressSpace(src_address, size)) {
LOG_ERROR(Kernel_SVC,
"Source address range is not within the address space (src_address=0x{:016X}, "
"size=0x{:016X}).",
src_address, size);
return ResultInvalidCurrentMemory;
}
if (!page_table.IsInsideASLRRegion(dst_address, size)) {
LOG_ERROR(Kernel_SVC,
"Destination address range is not within the ASLR region (dst_address=0x{:016X}, "
"size=0x{:016X}).",
dst_address, size);
return ResultInvalidMemoryRegion;
}
return page_table.MapCodeMemory(dst_address, src_address, size);
}
Result UnmapProcessCodeMemory(Core::System& system, Handle process_handle, u64 dst_address,
u64 src_address, u64 size) {
LOG_DEBUG(Kernel_SVC,
"called. process_handle=0x{:08X}, dst_address=0x{:016X}, src_address=0x{:016X}, "
"size=0x{:016X}",
process_handle, dst_address, src_address, size);
if (!Common::Is4KBAligned(dst_address)) {
LOG_ERROR(Kernel_SVC, "dst_address is not page-aligned (dst_address=0x{:016X}).",
dst_address);
return ResultInvalidAddress;
}
if (!Common::Is4KBAligned(src_address)) {
LOG_ERROR(Kernel_SVC, "src_address is not page-aligned (src_address=0x{:016X}).",
src_address);
return ResultInvalidAddress;
}
if (size == 0 || !Common::Is4KBAligned(size)) {
LOG_ERROR(Kernel_SVC, "Size is zero or not page-aligned (size=0x{:016X}).", size);
return ResultInvalidSize;
}
if (!IsValidAddressRange(dst_address, size)) {
LOG_ERROR(Kernel_SVC,
"Destination address range overflows the address space (dst_address=0x{:016X}, "
"size=0x{:016X}).",
dst_address, size);
return ResultInvalidCurrentMemory;
}
if (!IsValidAddressRange(src_address, size)) {
LOG_ERROR(Kernel_SVC,
"Source address range overflows the address space (src_address=0x{:016X}, "
"size=0x{:016X}).",
src_address, size);
return ResultInvalidCurrentMemory;
}
const auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle);
if (process.IsNull()) {
LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).",
process_handle);
return ResultInvalidHandle;
}
auto& page_table = process->PageTable();
if (!page_table.IsInsideAddressSpace(src_address, size)) {
LOG_ERROR(Kernel_SVC,
"Source address range is not within the address space (src_address=0x{:016X}, "
"size=0x{:016X}).",
src_address, size);
return ResultInvalidCurrentMemory;
}
if (!page_table.IsInsideASLRRegion(dst_address, size)) {
LOG_ERROR(Kernel_SVC,
"Destination address range is not within the ASLR region (dst_address=0x{:016X}, "
"size=0x{:016X}).",
dst_address, size);
return ResultInvalidMemoryRegion;
}
return page_table.UnmapCodeMemory(dst_address, src_address, size,
KPageTable::ICacheInvalidationStrategy::InvalidateAll);
}
Result SetProcessMemoryPermission64(Core::System& system, Handle process_handle, uint64_t address,
uint64_t size, MemoryPermission perm) {
R_RETURN(SetProcessMemoryPermission(system, process_handle, address, size, perm));
}
Result MapProcessMemory64(Core::System& system, uint64_t dst_address, Handle process_handle,
uint64_t src_address, uint64_t size) {
R_RETURN(MapProcessMemory(system, dst_address, process_handle, src_address, size));
}
Result UnmapProcessMemory64(Core::System& system, uint64_t dst_address, Handle process_handle,
uint64_t src_address, uint64_t size) {
R_RETURN(UnmapProcessMemory(system, dst_address, process_handle, src_address, size));
}
Result MapProcessCodeMemory64(Core::System& system, Handle process_handle, uint64_t dst_address,
uint64_t src_address, uint64_t size) {
R_RETURN(MapProcessCodeMemory(system, process_handle, dst_address, src_address, size));
}
Result UnmapProcessCodeMemory64(Core::System& system, Handle process_handle, uint64_t dst_address,
uint64_t src_address, uint64_t size) {
R_RETURN(UnmapProcessCodeMemory(system, process_handle, dst_address, src_address, size));
}
Result SetProcessMemoryPermission64From32(Core::System& system, Handle process_handle,
uint64_t address, uint64_t size, MemoryPermission perm) {
R_RETURN(SetProcessMemoryPermission(system, process_handle, address, size, perm));
}
Result MapProcessMemory64From32(Core::System& system, uint32_t dst_address, Handle process_handle,
uint64_t src_address, uint32_t size) {
R_RETURN(MapProcessMemory(system, dst_address, process_handle, src_address, size));
}
Result UnmapProcessMemory64From32(Core::System& system, uint32_t dst_address, Handle process_handle,
uint64_t src_address, uint32_t size) {
R_RETURN(UnmapProcessMemory(system, dst_address, process_handle, src_address, size));
}
Result MapProcessCodeMemory64From32(Core::System& system, Handle process_handle,
uint64_t dst_address, uint64_t src_address, uint64_t size) {
R_RETURN(MapProcessCodeMemory(system, process_handle, dst_address, src_address, size));
}
Result UnmapProcessCodeMemory64From32(Core::System& system, Handle process_handle,
uint64_t dst_address, uint64_t src_address, uint64_t size) {
R_RETURN(UnmapProcessCodeMemory(system, process_handle, dst_address, src_address, size));
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,25 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/kernel/physical_core.h"
#include "core/hle/kernel/svc.h"
namespace Kernel::Svc {
/// Get which CPU core is executing the current thread
int32_t GetCurrentProcessorNumber(Core::System& system) {
LOG_TRACE(Kernel_SVC, "called");
return static_cast<int32_t>(system.CurrentPhysicalCore().CoreIndex());
}
int32_t GetCurrentProcessorNumber64(Core::System& system) {
return GetCurrentProcessorNumber(system);
}
int32_t GetCurrentProcessorNumber64From32(Core::System& system) {
return GetCurrentProcessorNumber(system);
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,65 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/svc.h"
namespace Kernel::Svc {
Result QueryMemory(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info,
VAddr query_address) {
LOG_TRACE(Kernel_SVC,
"called, out_memory_info=0x{:016X}, "
"query_address=0x{:016X}",
out_memory_info, query_address);
// Query memory is just QueryProcessMemory on the current process.
return QueryProcessMemory(system, out_memory_info, out_page_info, CurrentProcess,
query_address);
}
Result QueryProcessMemory(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info,
Handle process_handle, uint64_t address) {
LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address);
const auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle);
if (process.IsNull()) {
LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}",
process_handle);
return ResultInvalidHandle;
}
auto& memory{system.Memory()};
const auto memory_info{process->PageTable().QueryInfo(address).GetSvcMemoryInfo()};
memory.WriteBlock(out_memory_info, &memory_info, sizeof(memory_info));
//! This is supposed to be part of the QueryInfo call.
*out_page_info = {};
R_SUCCEED();
}
Result QueryMemory64(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info,
uint64_t address) {
R_RETURN(QueryMemory(system, out_memory_info, out_page_info, address));
}
Result QueryProcessMemory64(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info,
Handle process_handle, uint64_t address) {
R_RETURN(QueryProcessMemory(system, out_memory_info, out_page_info, process_handle, address));
}
Result QueryMemory64From32(Core::System& system, uint32_t out_memory_info, PageInfo* out_page_info,
uint32_t address) {
R_RETURN(QueryMemory(system, out_memory_info, out_page_info, address));
}
Result QueryProcessMemory64From32(Core::System& system, uint32_t out_memory_info,
PageInfo* out_page_info, Handle process_handle,
uint64_t address) {
R_RETURN(QueryProcessMemory(system, out_memory_info, out_page_info, process_handle, address));
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,27 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/svc_results.h"
namespace Kernel::Svc {
Result ReadWriteRegister(Core::System& system, uint32_t* out, uint64_t address, uint32_t mask,
uint32_t value) {
*out = 0;
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result ReadWriteRegister64(Core::System& system, uint32_t* out_value, uint64_t address,
uint32_t mask, uint32_t value) {
R_RETURN(ReadWriteRegister(system, out_value, address, mask, value));
}
Result ReadWriteRegister64From32(Core::System& system, uint32_t* out_value, uint64_t address,
uint32_t mask, uint32_t value) {
R_RETURN(ReadWriteRegister(system, out_value, address, mask, value));
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,149 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_resource_limit.h"
#include "core/hle/kernel/svc.h"
namespace Kernel::Svc {
Result CreateResourceLimit(Core::System& system, Handle* out_handle) {
LOG_DEBUG(Kernel_SVC, "called");
// Create a new resource limit.
auto& kernel = system.Kernel();
KResourceLimit* resource_limit = KResourceLimit::Create(kernel);
R_UNLESS(resource_limit != nullptr, ResultOutOfResource);
// Ensure we don't leak a reference to the limit.
SCOPE_EXIT({ resource_limit->Close(); });
// Initialize the resource limit.
resource_limit->Initialize(&system.CoreTiming());
// Register the limit.
KResourceLimit::Register(kernel, resource_limit);
// Add the limit to the handle table.
R_TRY(GetCurrentProcess(kernel).GetHandleTable().Add(out_handle, resource_limit));
return ResultSuccess;
}
Result GetResourceLimitLimitValue(Core::System& system, s64* out_limit_value,
Handle resource_limit_handle, LimitableResource which) {
LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}", resource_limit_handle,
which);
// Validate the resource.
R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue);
// Get the resource limit.
KScopedAutoObject resource_limit = GetCurrentProcess(system.Kernel())
.GetHandleTable()
.GetObject<KResourceLimit>(resource_limit_handle);
R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle);
// Get the limit value.
*out_limit_value = resource_limit->GetLimitValue(which);
return ResultSuccess;
}
Result GetResourceLimitCurrentValue(Core::System& system, s64* out_current_value,
Handle resource_limit_handle, LimitableResource which) {
LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}", resource_limit_handle,
which);
// Validate the resource.
R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue);
// Get the resource limit.
KScopedAutoObject resource_limit = GetCurrentProcess(system.Kernel())
.GetHandleTable()
.GetObject<KResourceLimit>(resource_limit_handle);
R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle);
// Get the current value.
*out_current_value = resource_limit->GetCurrentValue(which);
return ResultSuccess;
}
Result SetResourceLimitLimitValue(Core::System& system, Handle resource_limit_handle,
LimitableResource which, s64 limit_value) {
LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}, limit_value={}",
resource_limit_handle, which, limit_value);
// Validate the resource.
R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue);
// Get the resource limit.
KScopedAutoObject resource_limit = GetCurrentProcess(system.Kernel())
.GetHandleTable()
.GetObject<KResourceLimit>(resource_limit_handle);
R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle);
// Set the limit value.
R_TRY(resource_limit->SetLimitValue(which, limit_value));
return ResultSuccess;
}
Result GetResourceLimitPeakValue(Core::System& system, int64_t* out_peak_value,
Handle resource_limit_handle, LimitableResource which) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result GetResourceLimitLimitValue64(Core::System& system, int64_t* out_limit_value,
Handle resource_limit_handle, LimitableResource which) {
R_RETURN(GetResourceLimitLimitValue(system, out_limit_value, resource_limit_handle, which));
}
Result GetResourceLimitCurrentValue64(Core::System& system, int64_t* out_current_value,
Handle resource_limit_handle, LimitableResource which) {
R_RETURN(GetResourceLimitCurrentValue(system, out_current_value, resource_limit_handle, which));
}
Result GetResourceLimitPeakValue64(Core::System& system, int64_t* out_peak_value,
Handle resource_limit_handle, LimitableResource which) {
R_RETURN(GetResourceLimitPeakValue(system, out_peak_value, resource_limit_handle, which));
}
Result CreateResourceLimit64(Core::System& system, Handle* out_handle) {
R_RETURN(CreateResourceLimit(system, out_handle));
}
Result SetResourceLimitLimitValue64(Core::System& system, Handle resource_limit_handle,
LimitableResource which, int64_t limit_value) {
R_RETURN(SetResourceLimitLimitValue(system, resource_limit_handle, which, limit_value));
}
Result GetResourceLimitLimitValue64From32(Core::System& system, int64_t* out_limit_value,
Handle resource_limit_handle, LimitableResource which) {
R_RETURN(GetResourceLimitLimitValue(system, out_limit_value, resource_limit_handle, which));
}
Result GetResourceLimitCurrentValue64From32(Core::System& system, int64_t* out_current_value,
Handle resource_limit_handle, LimitableResource which) {
R_RETURN(GetResourceLimitCurrentValue(system, out_current_value, resource_limit_handle, which));
}
Result GetResourceLimitPeakValue64From32(Core::System& system, int64_t* out_peak_value,
Handle resource_limit_handle, LimitableResource which) {
R_RETURN(GetResourceLimitPeakValue(system, out_peak_value, resource_limit_handle, which));
}
Result CreateResourceLimit64From32(Core::System& system, Handle* out_handle) {
R_RETURN(CreateResourceLimit(system, out_handle));
}
Result SetResourceLimitLimitValue64From32(Core::System& system, Handle resource_limit_handle,
LimitableResource which, int64_t limit_value) {
R_RETURN(SetResourceLimitLimitValue(system, resource_limit_handle, which, limit_value));
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,53 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/kernel/physical_core.h"
#include "core/hle/kernel/svc.h"
namespace Kernel::Svc {
void CallSecureMonitor(Core::System& system, lp64::SecureMonitorArguments* args) {
UNIMPLEMENTED();
}
void CallSecureMonitor64(Core::System& system, lp64::SecureMonitorArguments* args) {
CallSecureMonitor(system, args);
}
void CallSecureMonitor64From32(Core::System& system, ilp32::SecureMonitorArguments* args) {
// CallSecureMonitor64From32 is not supported.
UNIMPLEMENTED_MSG("CallSecureMonitor64From32");
}
// Custom ABI for CallSecureMonitor.
void SvcWrap_CallSecureMonitor64(Core::System& system) {
auto& core = system.CurrentPhysicalCore().ArmInterface();
lp64::SecureMonitorArguments args{};
for (int i = 0; i < 8; i++) {
args.r[i] = core.GetReg(i);
}
CallSecureMonitor64(system, &args);
for (int i = 0; i < 8; i++) {
core.SetReg(i, args.r[i]);
}
}
void SvcWrap_CallSecureMonitor64From32(Core::System& system) {
auto& core = system.CurrentPhysicalCore().ArmInterface();
ilp32::SecureMonitorArguments args{};
for (int i = 0; i < 8; i++) {
args.r[i] = static_cast<u32>(core.GetReg(i));
}
CallSecureMonitor64From32(system, &args);
for (int i = 0; i < 8; i++) {
core.SetReg(i, args.r[i]);
}
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,128 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_scoped_resource_reservation.h"
#include "core/hle/kernel/k_session.h"
#include "core/hle/kernel/svc.h"
namespace Kernel::Svc {
namespace {
template <typename T>
Result CreateSession(Core::System& system, Handle* out_server, Handle* out_client, u64 name) {
auto& process = GetCurrentProcess(system.Kernel());
auto& handle_table = process.GetHandleTable();
// Declare the session we're going to allocate.
T* session;
// Reserve a new session from the process resource limit.
// FIXME: LimitableResource_SessionCountMax
KScopedResourceReservation session_reservation(&process, LimitableResource::SessionCountMax);
if (session_reservation.Succeeded()) {
session = T::Create(system.Kernel());
} else {
return ResultLimitReached;
// // We couldn't reserve a session. Check that we support dynamically expanding the
// // resource limit.
// R_UNLESS(process.GetResourceLimit() ==
// &system.Kernel().GetSystemResourceLimit(), ResultLimitReached);
// R_UNLESS(KTargetSystem::IsDynamicResourceLimitsEnabled(), ResultLimitReached());
// // Try to allocate a session from unused slab memory.
// session = T::CreateFromUnusedSlabMemory();
// R_UNLESS(session != nullptr, ResultLimitReached);
// ON_RESULT_FAILURE { session->Close(); };
// // If we're creating a KSession, we want to add two KSessionRequests to the heap, to
// // prevent request exhaustion.
// // NOTE: Nintendo checks if session->DynamicCast<KSession *>() != nullptr, but there's
// // no reason to not do this statically.
// if constexpr (std::same_as<T, KSession>) {
// for (size_t i = 0; i < 2; i++) {
// KSessionRequest* request = KSessionRequest::CreateFromUnusedSlabMemory();
// R_UNLESS(request != nullptr, ResultLimitReached);
// request->Close();
// }
// }
// We successfully allocated a session, so add the object we allocated to the resource
// limit.
// system.Kernel().GetSystemResourceLimit().Reserve(LimitableResource::SessionCountMax, 1);
}
// Check that we successfully created a session.
R_UNLESS(session != nullptr, ResultOutOfResource);
// Initialize the session.
session->Initialize(nullptr, fmt::format("{}", name));
// Commit the session reservation.
session_reservation.Commit();
// Ensure that we clean up the session (and its only references are handle table) on function
// end.
SCOPE_EXIT({
session->GetClientSession().Close();
session->GetServerSession().Close();
});
// Register the session.
T::Register(system.Kernel(), session);
// Add the server session to the handle table.
R_TRY(handle_table.Add(out_server, &session->GetServerSession()));
// Add the client session to the handle table.
const auto result = handle_table.Add(out_client, &session->GetClientSession());
if (!R_SUCCEEDED(result)) {
// Ensure that we maintaing a clean handle state on exit.
handle_table.Remove(*out_server);
}
return result;
}
} // namespace
Result CreateSession(Core::System& system, Handle* out_server, Handle* out_client, bool is_light,
u64 name) {
if (is_light) {
// return CreateSession<KLightSession>(system, out_server, out_client, name);
return ResultNotImplemented;
} else {
return CreateSession<KSession>(system, out_server, out_client, name);
}
}
Result AcceptSession(Core::System& system, Handle* out_handle, Handle port_handle) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result CreateSession64(Core::System& system, Handle* out_server_session_handle,
Handle* out_client_session_handle, bool is_light, uint64_t name) {
R_RETURN(CreateSession(system, out_server_session_handle, out_client_session_handle, is_light,
name));
}
Result AcceptSession64(Core::System& system, Handle* out_handle, Handle port) {
R_RETURN(AcceptSession(system, out_handle, port));
}
Result CreateSession64From32(Core::System& system, Handle* out_server_session_handle,
Handle* out_client_session_handle, bool is_light, uint32_t name) {
R_RETURN(CreateSession(system, out_server_session_handle, out_client_session_handle, is_light,
name));
}
Result AcceptSession64From32(Core::System& system, Handle* out_handle, Handle port) {
R_RETURN(AcceptSession(system, out_handle, port));
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,133 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/kernel/svc.h"
namespace Kernel::Svc {
namespace {
constexpr bool IsValidSharedMemoryPermission(MemoryPermission perm) {
switch (perm) {
case MemoryPermission::Read:
case MemoryPermission::ReadWrite:
return true;
default:
return false;
}
}
[[maybe_unused]] constexpr bool IsValidRemoteSharedMemoryPermission(MemoryPermission perm) {
return IsValidSharedMemoryPermission(perm) || perm == MemoryPermission::DontCare;
}
} // namespace
Result MapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address, u64 size,
Svc::MemoryPermission map_perm) {
LOG_TRACE(Kernel_SVC,
"called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}",
shmem_handle, address, size, map_perm);
// Validate the address/size.
R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
R_UNLESS(size > 0, ResultInvalidSize);
R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
// Validate the permission.
R_UNLESS(IsValidSharedMemoryPermission(map_perm), ResultInvalidNewMemoryPermission);
// Get the current process.
auto& process = GetCurrentProcess(system.Kernel());
auto& page_table = process.PageTable();
// Get the shared memory.
KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle);
R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle);
// Verify that the mapping is in range.
R_UNLESS(page_table.CanContain(address, size, KMemoryState::Shared), ResultInvalidMemoryRegion);
// Add the shared memory to the process.
R_TRY(process.AddSharedMemory(shmem.GetPointerUnsafe(), address, size));
// Ensure that we clean up the shared memory if we fail to map it.
auto guard =
SCOPE_GUARD({ process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size); });
// Map the shared memory.
R_TRY(shmem->Map(process, address, size, map_perm));
// We succeeded.
guard.Cancel();
return ResultSuccess;
}
Result UnmapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address, u64 size) {
// Validate the address/size.
R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
R_UNLESS(size > 0, ResultInvalidSize);
R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
// Get the current process.
auto& process = GetCurrentProcess(system.Kernel());
auto& page_table = process.PageTable();
// Get the shared memory.
KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle);
R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle);
// Verify that the mapping is in range.
R_UNLESS(page_table.CanContain(address, size, KMemoryState::Shared), ResultInvalidMemoryRegion);
// Unmap the shared memory.
R_TRY(shmem->Unmap(process, address, size));
// Remove the shared memory from the process.
process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size);
return ResultSuccess;
}
Result CreateSharedMemory(Core::System& system, Handle* out_handle, uint64_t size,
MemoryPermission owner_perm, MemoryPermission remote_perm) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result MapSharedMemory64(Core::System& system, Handle shmem_handle, uint64_t address, uint64_t size,
MemoryPermission map_perm) {
R_RETURN(MapSharedMemory(system, shmem_handle, address, size, map_perm));
}
Result UnmapSharedMemory64(Core::System& system, Handle shmem_handle, uint64_t address,
uint64_t size) {
R_RETURN(UnmapSharedMemory(system, shmem_handle, address, size));
}
Result CreateSharedMemory64(Core::System& system, Handle* out_handle, uint64_t size,
MemoryPermission owner_perm, MemoryPermission remote_perm) {
R_RETURN(CreateSharedMemory(system, out_handle, size, owner_perm, remote_perm));
}
Result MapSharedMemory64From32(Core::System& system, Handle shmem_handle, uint32_t address,
uint32_t size, MemoryPermission map_perm) {
R_RETURN(MapSharedMemory(system, shmem_handle, address, size, map_perm));
}
Result UnmapSharedMemory64From32(Core::System& system, Handle shmem_handle, uint32_t address,
uint32_t size) {
R_RETURN(UnmapSharedMemory(system, shmem_handle, address, size));
}
Result CreateSharedMemory64From32(Core::System& system, Handle* out_handle, uint32_t size,
MemoryPermission owner_perm, MemoryPermission remote_perm) {
R_RETURN(CreateSharedMemory(system, out_handle, size, owner_perm, remote_perm));
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,163 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/svc.h"
namespace Kernel::Svc {
/// Close a handle
Result CloseHandle(Core::System& system, Handle handle) {
LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle);
// Remove the handle.
R_UNLESS(GetCurrentProcess(system.Kernel()).GetHandleTable().Remove(handle),
ResultInvalidHandle);
return ResultSuccess;
}
/// Clears the signaled state of an event or process.
Result ResetSignal(Core::System& system, Handle handle) {
LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle);
// Get the current handle table.
const auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
// Try to reset as readable event.
{
KScopedAutoObject readable_event = handle_table.GetObject<KReadableEvent>(handle);
if (readable_event.IsNotNull()) {
return readable_event->Reset();
}
}
// Try to reset as process.
{
KScopedAutoObject process = handle_table.GetObject<KProcess>(handle);
if (process.IsNotNull()) {
return process->Reset();
}
}
LOG_ERROR(Kernel_SVC, "invalid handle (0x{:08X})", handle);
return ResultInvalidHandle;
}
/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
Result WaitSynchronization(Core::System& system, s32* index, VAddr handles_address, s32 num_handles,
s64 nano_seconds) {
LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, num_handles={}, nano_seconds={}",
handles_address, num_handles, nano_seconds);
// Ensure number of handles is valid.
R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange);
auto& kernel = system.Kernel();
std::vector<KSynchronizationObject*> objs(num_handles);
const auto& handle_table = GetCurrentProcess(kernel).GetHandleTable();
Handle* handles = system.Memory().GetPointer<Handle>(handles_address);
// Copy user handles.
if (num_handles > 0) {
// Convert the handles to objects.
R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles,
num_handles),
ResultInvalidHandle);
for (const auto& obj : objs) {
kernel.RegisterInUseObject(obj);
}
}
// Ensure handles are closed when we're done.
SCOPE_EXIT({
for (s32 i = 0; i < num_handles; ++i) {
kernel.UnregisterInUseObject(objs[i]);
objs[i]->Close();
}
});
return KSynchronizationObject::Wait(kernel, index, objs.data(), static_cast<s32>(objs.size()),
nano_seconds);
}
/// Resumes a thread waiting on WaitSynchronization
Result CancelSynchronization(Core::System& system, Handle handle) {
LOG_TRACE(Kernel_SVC, "called handle=0x{:X}", handle);
// Get the thread from its handle.
KScopedAutoObject thread =
GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KThread>(handle);
R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
// Cancel the thread's wait.
thread->WaitCancel();
return ResultSuccess;
}
void SynchronizePreemptionState(Core::System& system) {
auto& kernel = system.Kernel();
// Lock the scheduler.
KScopedSchedulerLock sl{kernel};
// If the current thread is pinned, unpin it.
KProcess* cur_process = GetCurrentProcessPointer(kernel);
const auto core_id = GetCurrentCoreId(kernel);
if (cur_process->GetPinnedThread(core_id) == GetCurrentThreadPointer(kernel)) {
// Clear the current thread's interrupt flag.
GetCurrentThread(kernel).ClearInterruptFlag();
// Unpin the current thread.
cur_process->UnpinCurrentThread(core_id);
}
}
Result CloseHandle64(Core::System& system, Handle handle) {
R_RETURN(CloseHandle(system, handle));
}
Result ResetSignal64(Core::System& system, Handle handle) {
R_RETURN(ResetSignal(system, handle));
}
Result WaitSynchronization64(Core::System& system, int32_t* out_index, uint64_t handles,
int32_t num_handles, int64_t timeout_ns) {
R_RETURN(WaitSynchronization(system, out_index, handles, num_handles, timeout_ns));
}
Result CancelSynchronization64(Core::System& system, Handle handle) {
R_RETURN(CancelSynchronization(system, handle));
}
void SynchronizePreemptionState64(Core::System& system) {
SynchronizePreemptionState(system);
}
Result CloseHandle64From32(Core::System& system, Handle handle) {
R_RETURN(CloseHandle(system, handle));
}
Result ResetSignal64From32(Core::System& system, Handle handle) {
R_RETURN(ResetSignal(system, handle));
}
Result WaitSynchronization64From32(Core::System& system, int32_t* out_index, uint32_t handles,
int32_t num_handles, int64_t timeout_ns) {
R_RETURN(WaitSynchronization(system, out_index, handles, num_handles, timeout_ns));
}
Result CancelSynchronization64From32(Core::System& system, Handle handle) {
R_RETURN(CancelSynchronization(system, handle));
}
void SynchronizePreemptionState64From32(Core::System& system) {
SynchronizePreemptionState(system);
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,437 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_scoped_resource_reservation.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/svc.h"
namespace Kernel::Svc {
namespace {
constexpr bool IsValidVirtualCoreId(int32_t core_id) {
return (0 <= core_id && core_id < static_cast<int32_t>(Core::Hardware::NUM_CPU_CORES));
}
} // Anonymous namespace
/// Creates a new thread
Result CreateThread(Core::System& system, Handle* out_handle, VAddr entry_point, u64 arg,
VAddr stack_bottom, s32 priority, s32 core_id) {
LOG_DEBUG(Kernel_SVC,
"called entry_point=0x{:08X}, arg=0x{:08X}, stack_bottom=0x{:08X}, "
"priority=0x{:08X}, core_id=0x{:08X}",
entry_point, arg, stack_bottom, priority, core_id);
// Adjust core id, if it's the default magic.
auto& kernel = system.Kernel();
auto& process = GetCurrentProcess(kernel);
if (core_id == IdealCoreUseProcessValue) {
core_id = process.GetIdealCoreId();
}
// Validate arguments.
if (!IsValidVirtualCoreId(core_id)) {
LOG_ERROR(Kernel_SVC, "Invalid Core ID specified (id={})", core_id);
return ResultInvalidCoreId;
}
if (((1ULL << core_id) & process.GetCoreMask()) == 0) {
LOG_ERROR(Kernel_SVC, "Core ID doesn't fall within allowable cores (id={})", core_id);
return ResultInvalidCoreId;
}
if (HighestThreadPriority > priority || priority > LowestThreadPriority) {
LOG_ERROR(Kernel_SVC, "Invalid priority specified (priority={})", priority);
return ResultInvalidPriority;
}
if (!process.CheckThreadPriority(priority)) {
LOG_ERROR(Kernel_SVC, "Invalid allowable thread priority (priority={})", priority);
return ResultInvalidPriority;
}
// Reserve a new thread from the process resource limit (waiting up to 100ms).
KScopedResourceReservation thread_reservation(&process, LimitableResource::ThreadCountMax, 1,
system.CoreTiming().GetGlobalTimeNs().count() +
100000000);
if (!thread_reservation.Succeeded()) {
LOG_ERROR(Kernel_SVC, "Could not reserve a new thread");
return ResultLimitReached;
}
// Create the thread.
KThread* thread = KThread::Create(kernel);
if (!thread) {
LOG_ERROR(Kernel_SVC, "Unable to create new threads. Thread creation limit reached.");
return ResultOutOfResource;
}
SCOPE_EXIT({ thread->Close(); });
// Initialize the thread.
{
KScopedLightLock lk{process.GetStateLock()};
R_TRY(KThread::InitializeUserThread(system, thread, entry_point, arg, stack_bottom,
priority, core_id, &process));
}
// Set the thread name for debugging purposes.
thread->SetName(fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *out_handle));
// Commit the thread reservation.
thread_reservation.Commit();
// Register the new thread.
KThread::Register(kernel, thread);
// Add the thread to the handle table.
R_TRY(process.GetHandleTable().Add(out_handle, thread));
return ResultSuccess;
}
/// Starts the thread for the provided handle
Result StartThread(Core::System& system, Handle thread_handle) {
LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
// Get the thread from its handle.
KScopedAutoObject thread =
GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KThread>(thread_handle);
R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
// Try to start the thread.
R_TRY(thread->Run());
// If we succeeded, persist a reference to the thread.
thread->Open();
system.Kernel().RegisterInUseObject(thread.GetPointerUnsafe());
return ResultSuccess;
}
/// Called when a thread exits
void ExitThread(Core::System& system) {
LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC());
auto* const current_thread = GetCurrentThreadPointer(system.Kernel());
system.GlobalSchedulerContext().RemoveThread(current_thread);
current_thread->Exit();
system.Kernel().UnregisterInUseObject(current_thread);
}
/// Sleep the current thread
void SleepThread(Core::System& system, s64 nanoseconds) {
auto& kernel = system.Kernel();
const auto yield_type = static_cast<Svc::YieldType>(nanoseconds);
LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds);
// When the input tick is positive, sleep.
if (nanoseconds > 0) {
// Convert the timeout from nanoseconds to ticks.
// NOTE: Nintendo does not use this conversion logic in WaitSynchronization...
// Sleep.
// NOTE: Nintendo does not check the result of this sleep.
static_cast<void>(GetCurrentThread(kernel).Sleep(nanoseconds));
} else if (yield_type == Svc::YieldType::WithoutCoreMigration) {
KScheduler::YieldWithoutCoreMigration(kernel);
} else if (yield_type == Svc::YieldType::WithCoreMigration) {
KScheduler::YieldWithCoreMigration(kernel);
} else if (yield_type == Svc::YieldType::ToAnyThread) {
KScheduler::YieldToAnyThread(kernel);
} else {
// Nintendo does nothing at all if an otherwise invalid value is passed.
ASSERT_MSG(false, "Unimplemented sleep yield type '{:016X}'!", nanoseconds);
}
}
/// Gets the thread context
Result GetThreadContext3(Core::System& system, VAddr out_context, Handle thread_handle) {
LOG_DEBUG(Kernel_SVC, "called, out_context=0x{:08X}, thread_handle=0x{:X}", out_context,
thread_handle);
auto& kernel = system.Kernel();
// Get the thread from its handle.
KScopedAutoObject thread =
GetCurrentProcess(kernel).GetHandleTable().GetObject<KThread>(thread_handle);
R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
// Require the handle be to a non-current thread in the current process.
const auto* current_process = GetCurrentProcessPointer(kernel);
R_UNLESS(current_process == thread->GetOwnerProcess(), ResultInvalidId);
// Verify that the thread isn't terminated.
R_UNLESS(thread->GetState() != ThreadState::Terminated, ResultTerminationRequested);
/// Check that the thread is not the current one.
/// NOTE: Nintendo does not check this, and thus the following loop will deadlock.
R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(kernel), ResultInvalidId);
// Try to get the thread context until the thread isn't current on any core.
while (true) {
KScopedSchedulerLock sl{kernel};
// TODO(bunnei): Enforce that thread is suspended for debug here.
// If the thread's raw state isn't runnable, check if it's current on some core.
if (thread->GetRawState() != ThreadState::Runnable) {
bool current = false;
for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) {
if (thread.GetPointerUnsafe() == kernel.Scheduler(i).GetSchedulerCurrentThread()) {
current = true;
break;
}
}
// If the thread is current, retry until it isn't.
if (current) {
continue;
}
}
// Get the thread context.
std::vector<u8> context;
R_TRY(thread->GetThreadContext3(context));
// Copy the thread context to user space.
system.Memory().WriteBlock(out_context, context.data(), context.size());
return ResultSuccess;
}
return ResultSuccess;
}
/// Gets the priority for the specified thread
Result GetThreadPriority(Core::System& system, s32* out_priority, Handle handle) {
LOG_TRACE(Kernel_SVC, "called");
// Get the thread from its handle.
KScopedAutoObject thread =
GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KThread>(handle);
R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
// Get the thread's priority.
*out_priority = thread->GetPriority();
return ResultSuccess;
}
/// Sets the priority for the specified thread
Result SetThreadPriority(Core::System& system, Handle thread_handle, s32 priority) {
// Get the current process.
KProcess& process = GetCurrentProcess(system.Kernel());
// Validate the priority.
R_UNLESS(HighestThreadPriority <= priority && priority <= LowestThreadPriority,
ResultInvalidPriority);
R_UNLESS(process.CheckThreadPriority(priority), ResultInvalidPriority);
// Get the thread from its handle.
KScopedAutoObject thread = process.GetHandleTable().GetObject<KThread>(thread_handle);
R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
// Set the thread priority.
thread->SetBasePriority(priority);
return ResultSuccess;
}
Result GetThreadList(Core::System& system, s32* out_num_threads, VAddr out_thread_ids,
s32 out_thread_ids_size, Handle debug_handle) {
// TODO: Handle this case when debug events are supported.
UNIMPLEMENTED_IF(debug_handle != InvalidHandle);
LOG_DEBUG(Kernel_SVC, "called. out_thread_ids=0x{:016X}, out_thread_ids_size={}",
out_thread_ids, out_thread_ids_size);
// If the size is negative or larger than INT32_MAX / sizeof(u64)
if ((out_thread_ids_size & 0xF0000000) != 0) {
LOG_ERROR(Kernel_SVC, "Supplied size outside [0, 0x0FFFFFFF] range. size={}",
out_thread_ids_size);
return ResultOutOfRange;
}
auto* const current_process = GetCurrentProcessPointer(system.Kernel());
const auto total_copy_size = out_thread_ids_size * sizeof(u64);
if (out_thread_ids_size > 0 &&
!current_process->PageTable().IsInsideAddressSpace(out_thread_ids, total_copy_size)) {
LOG_ERROR(Kernel_SVC, "Address range outside address space. begin=0x{:016X}, end=0x{:016X}",
out_thread_ids, out_thread_ids + total_copy_size);
return ResultInvalidCurrentMemory;
}
auto& memory = system.Memory();
const auto& thread_list = current_process->GetThreadList();
const auto num_threads = thread_list.size();
const auto copy_amount = std::min(static_cast<std::size_t>(out_thread_ids_size), num_threads);
auto list_iter = thread_list.cbegin();
for (std::size_t i = 0; i < copy_amount; ++i, ++list_iter) {
memory.Write64(out_thread_ids, (*list_iter)->GetThreadID());
out_thread_ids += sizeof(u64);
}
*out_num_threads = static_cast<u32>(num_threads);
return ResultSuccess;
}
Result GetThreadCoreMask(Core::System& system, s32* out_core_id, u64* out_affinity_mask,
Handle thread_handle) {
LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle);
// Get the thread from its handle.
KScopedAutoObject thread =
GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KThread>(thread_handle);
R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
// Get the core mask.
R_TRY(thread->GetCoreMask(out_core_id, out_affinity_mask));
return ResultSuccess;
}
Result SetThreadCoreMask(Core::System& system, Handle thread_handle, s32 core_id,
u64 affinity_mask) {
// Determine the core id/affinity mask.
if (core_id == IdealCoreUseProcessValue) {
core_id = GetCurrentProcess(system.Kernel()).GetIdealCoreId();
affinity_mask = (1ULL << core_id);
} else {
// Validate the affinity mask.
const u64 process_core_mask = GetCurrentProcess(system.Kernel()).GetCoreMask();
R_UNLESS((affinity_mask | process_core_mask) == process_core_mask, ResultInvalidCoreId);
R_UNLESS(affinity_mask != 0, ResultInvalidCombination);
// Validate the core id.
if (IsValidVirtualCoreId(core_id)) {
R_UNLESS(((1ULL << core_id) & affinity_mask) != 0, ResultInvalidCombination);
} else {
R_UNLESS(core_id == IdealCoreNoUpdate || core_id == IdealCoreDontCare,
ResultInvalidCoreId);
}
}
// Get the thread from its handle.
KScopedAutoObject thread =
GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KThread>(thread_handle);
R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
// Set the core mask.
R_TRY(thread->SetCoreMask(core_id, affinity_mask));
return ResultSuccess;
}
/// Get the ID for the specified thread.
Result GetThreadId(Core::System& system, u64* out_thread_id, Handle thread_handle) {
// Get the thread from its handle.
KScopedAutoObject thread =
GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KThread>(thread_handle);
R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
// Get the thread's id.
*out_thread_id = thread->GetId();
return ResultSuccess;
}
Result CreateThread64(Core::System& system, Handle* out_handle, uint64_t func, uint64_t arg,
uint64_t stack_bottom, int32_t priority, int32_t core_id) {
R_RETURN(CreateThread(system, out_handle, func, arg, stack_bottom, priority, core_id));
}
Result StartThread64(Core::System& system, Handle thread_handle) {
R_RETURN(StartThread(system, thread_handle));
}
void ExitThread64(Core::System& system) {
return ExitThread(system);
}
void SleepThread64(Core::System& system, int64_t ns) {
return SleepThread(system, ns);
}
Result GetThreadPriority64(Core::System& system, int32_t* out_priority, Handle thread_handle) {
R_RETURN(GetThreadPriority(system, out_priority, thread_handle));
}
Result SetThreadPriority64(Core::System& system, Handle thread_handle, int32_t priority) {
R_RETURN(SetThreadPriority(system, thread_handle, priority));
}
Result GetThreadCoreMask64(Core::System& system, int32_t* out_core_id, uint64_t* out_affinity_mask,
Handle thread_handle) {
R_RETURN(GetThreadCoreMask(system, out_core_id, out_affinity_mask, thread_handle));
}
Result SetThreadCoreMask64(Core::System& system, Handle thread_handle, int32_t core_id,
uint64_t affinity_mask) {
R_RETURN(SetThreadCoreMask(system, thread_handle, core_id, affinity_mask));
}
Result GetThreadId64(Core::System& system, uint64_t* out_thread_id, Handle thread_handle) {
R_RETURN(GetThreadId(system, out_thread_id, thread_handle));
}
Result GetThreadContext364(Core::System& system, uint64_t out_context, Handle thread_handle) {
R_RETURN(GetThreadContext3(system, out_context, thread_handle));
}
Result GetThreadList64(Core::System& system, int32_t* out_num_threads, uint64_t out_thread_ids,
int32_t max_out_count, Handle debug_handle) {
R_RETURN(GetThreadList(system, out_num_threads, out_thread_ids, max_out_count, debug_handle));
}
Result CreateThread64From32(Core::System& system, Handle* out_handle, uint32_t func, uint32_t arg,
uint32_t stack_bottom, int32_t priority, int32_t core_id) {
R_RETURN(CreateThread(system, out_handle, func, arg, stack_bottom, priority, core_id));
}
Result StartThread64From32(Core::System& system, Handle thread_handle) {
R_RETURN(StartThread(system, thread_handle));
}
void ExitThread64From32(Core::System& system) {
return ExitThread(system);
}
void SleepThread64From32(Core::System& system, int64_t ns) {
return SleepThread(system, ns);
}
Result GetThreadPriority64From32(Core::System& system, int32_t* out_priority,
Handle thread_handle) {
R_RETURN(GetThreadPriority(system, out_priority, thread_handle));
}
Result SetThreadPriority64From32(Core::System& system, Handle thread_handle, int32_t priority) {
R_RETURN(SetThreadPriority(system, thread_handle, priority));
}
Result GetThreadCoreMask64From32(Core::System& system, int32_t* out_core_id,
uint64_t* out_affinity_mask, Handle thread_handle) {
R_RETURN(GetThreadCoreMask(system, out_core_id, out_affinity_mask, thread_handle));
}
Result SetThreadCoreMask64From32(Core::System& system, Handle thread_handle, int32_t core_id,
uint64_t affinity_mask) {
R_RETURN(SetThreadCoreMask(system, thread_handle, core_id, affinity_mask));
}
Result GetThreadId64From32(Core::System& system, uint64_t* out_thread_id, Handle thread_handle) {
R_RETURN(GetThreadId(system, out_thread_id, thread_handle));
}
Result GetThreadContext364From32(Core::System& system, uint32_t out_context, Handle thread_handle) {
R_RETURN(GetThreadContext3(system, out_context, thread_handle));
}
Result GetThreadList64From32(Core::System& system, int32_t* out_num_threads,
uint32_t out_thread_ids, int32_t max_out_count, Handle debug_handle) {
R_RETURN(GetThreadList(system, out_num_threads, out_thread_ids, max_out_count, debug_handle));
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,60 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/svc_results.h"
namespace Kernel::Svc {
Result GetDebugFutureThreadInfo(Core::System& system, lp64::LastThreadContext* out_context,
uint64_t* out_thread_id, Handle debug_handle, int64_t ns) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result GetLastThreadInfo(Core::System& system, lp64::LastThreadContext* out_context,
uint64_t* out_tls_address, uint32_t* out_flags) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result GetDebugFutureThreadInfo64(Core::System& system, lp64::LastThreadContext* out_context,
uint64_t* out_thread_id, Handle debug_handle, int64_t ns) {
R_RETURN(GetDebugFutureThreadInfo(system, out_context, out_thread_id, debug_handle, ns));
}
Result GetLastThreadInfo64(Core::System& system, lp64::LastThreadContext* out_context,
uint64_t* out_tls_address, uint32_t* out_flags) {
R_RETURN(GetLastThreadInfo(system, out_context, out_tls_address, out_flags));
}
Result GetDebugFutureThreadInfo64From32(Core::System& system, ilp32::LastThreadContext* out_context,
uint64_t* out_thread_id, Handle debug_handle, int64_t ns) {
lp64::LastThreadContext context{};
R_TRY(
GetDebugFutureThreadInfo(system, std::addressof(context), out_thread_id, debug_handle, ns));
*out_context = {
.fp = static_cast<u32>(context.fp),
.sp = static_cast<u32>(context.sp),
.lr = static_cast<u32>(context.lr),
.pc = static_cast<u32>(context.pc),
};
R_SUCCEED();
}
Result GetLastThreadInfo64From32(Core::System& system, ilp32::LastThreadContext* out_context,
uint64_t* out_tls_address, uint32_t* out_flags) {
lp64::LastThreadContext context{};
R_TRY(GetLastThreadInfo(system, std::addressof(context), out_tls_address, out_flags));
*out_context = {
.fp = static_cast<u32>(context.fp),
.sp = static_cast<u32>(context.sp),
.lr = static_cast<u32>(context.lr),
.pc = static_cast<u32>(context.pc),
};
R_SUCCEED();
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,35 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/svc.h"
namespace Kernel::Svc {
/// This returns the total CPU ticks elapsed since the CPU was powered-on
int64_t GetSystemTick(Core::System& system) {
LOG_TRACE(Kernel_SVC, "called");
auto& core_timing = system.CoreTiming();
// Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick)
const u64 result{core_timing.GetClockTicks()};
if (!system.Kernel().IsMulticore()) {
core_timing.AddTicks(400U);
}
return static_cast<int64_t>(result);
}
int64_t GetSystemTick64(Core::System& system) {
return GetSystemTick(system);
}
int64_t GetSystemTick64From32(Core::System& system) {
return GetSystemTick(system);
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,117 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_scoped_resource_reservation.h"
#include "core/hle/kernel/k_transfer_memory.h"
#include "core/hle/kernel/svc.h"
namespace Kernel::Svc {
namespace {
constexpr bool IsValidTransferMemoryPermission(MemoryPermission perm) {
switch (perm) {
case MemoryPermission::None:
case MemoryPermission::Read:
case MemoryPermission::ReadWrite:
return true;
default:
return false;
}
}
} // Anonymous namespace
/// Creates a TransferMemory object
Result CreateTransferMemory(Core::System& system, Handle* out, VAddr address, u64 size,
MemoryPermission map_perm) {
auto& kernel = system.Kernel();
// Validate the size.
R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
R_UNLESS(size > 0, ResultInvalidSize);
R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
// Validate the permissions.
R_UNLESS(IsValidTransferMemoryPermission(map_perm), ResultInvalidNewMemoryPermission);
// Get the current process and handle table.
auto& process = GetCurrentProcess(kernel);
auto& handle_table = process.GetHandleTable();
// Reserve a new transfer memory from the process resource limit.
KScopedResourceReservation trmem_reservation(&process,
LimitableResource::TransferMemoryCountMax);
R_UNLESS(trmem_reservation.Succeeded(), ResultLimitReached);
// Create the transfer memory.
KTransferMemory* trmem = KTransferMemory::Create(kernel);
R_UNLESS(trmem != nullptr, ResultOutOfResource);
// Ensure the only reference is in the handle table when we're done.
SCOPE_EXIT({ trmem->Close(); });
// Ensure that the region is in range.
R_UNLESS(process.PageTable().Contains(address, size), ResultInvalidCurrentMemory);
// Initialize the transfer memory.
R_TRY(trmem->Initialize(address, size, map_perm));
// Commit the reservation.
trmem_reservation.Commit();
// Register the transfer memory.
KTransferMemory::Register(kernel, trmem);
// Add the transfer memory to the handle table.
R_TRY(handle_table.Add(out, trmem));
return ResultSuccess;
}
Result MapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t address, uint64_t size,
MemoryPermission owner_perm) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result UnmapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t address,
uint64_t size) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
}
Result MapTransferMemory64(Core::System& system, Handle trmem_handle, uint64_t address,
uint64_t size, MemoryPermission owner_perm) {
R_RETURN(MapTransferMemory(system, trmem_handle, address, size, owner_perm));
}
Result UnmapTransferMemory64(Core::System& system, Handle trmem_handle, uint64_t address,
uint64_t size) {
R_RETURN(UnmapTransferMemory(system, trmem_handle, address, size));
}
Result CreateTransferMemory64(Core::System& system, Handle* out_handle, uint64_t address,
uint64_t size, MemoryPermission map_perm) {
R_RETURN(CreateTransferMemory(system, out_handle, address, size, map_perm));
}
Result MapTransferMemory64From32(Core::System& system, Handle trmem_handle, uint32_t address,
uint32_t size, MemoryPermission owner_perm) {
R_RETURN(MapTransferMemory(system, trmem_handle, address, size, owner_perm));
}
Result UnmapTransferMemory64From32(Core::System& system, Handle trmem_handle, uint32_t address,
uint32_t size) {
R_RETURN(UnmapTransferMemory(system, trmem_handle, address, size));
}
Result CreateTransferMemory64From32(Core::System& system, Handle* out_handle, uint32_t address,
uint32_t size, MemoryPermission map_perm) {
R_RETURN(CreateTransferMemory(system, out_handle, address, size, map_perm));
}
} // namespace Kernel::Svc

View File

@@ -0,0 +1,716 @@
# SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
# Raw SVC definitions from the kernel.
#
# Avoid modifying the prototypes; see below for how to customize generation
# for a given typename.
SVCS = [
[0x01, "Result SetHeapSize(Address* out_address, Size size);"],
[0x02, "Result SetMemoryPermission(Address address, Size size, MemoryPermission perm);"],
[0x03, "Result SetMemoryAttribute(Address address, Size size, uint32_t mask, uint32_t attr);"],
[0x04, "Result MapMemory(Address dst_address, Address src_address, Size size);"],
[0x05, "Result UnmapMemory(Address dst_address, Address src_address, Size size);"],
[0x06, "Result QueryMemory(Address out_memory_info, PageInfo* out_page_info, Address address);"],
[0x07, "void ExitProcess();"],
[0x08, "Result CreateThread(Handle* out_handle, ThreadFunc func, Address arg, Address stack_bottom, int32_t priority, int32_t core_id);"],
[0x09, "Result StartThread(Handle thread_handle);"],
[0x0A, "void ExitThread();"],
[0x0B, "void SleepThread(int64_t ns);"],
[0x0C, "Result GetThreadPriority(int32_t* out_priority, Handle thread_handle);"],
[0x0D, "Result SetThreadPriority(Handle thread_handle, int32_t priority);"],
[0x0E, "Result GetThreadCoreMask(int32_t* out_core_id, uint64_t* out_affinity_mask, Handle thread_handle);"],
[0x0F, "Result SetThreadCoreMask(Handle thread_handle, int32_t core_id, uint64_t affinity_mask);"],
[0x10, "int32_t GetCurrentProcessorNumber();"],
[0x11, "Result SignalEvent(Handle event_handle);"],
[0x12, "Result ClearEvent(Handle event_handle);"],
[0x13, "Result MapSharedMemory(Handle shmem_handle, Address address, Size size, MemoryPermission map_perm);"],
[0x14, "Result UnmapSharedMemory(Handle shmem_handle, Address address, Size size);"],
[0x15, "Result CreateTransferMemory(Handle* out_handle, Address address, Size size, MemoryPermission map_perm);"],
[0x16, "Result CloseHandle(Handle handle);"],
[0x17, "Result ResetSignal(Handle handle);"],
[0x18, "Result WaitSynchronization(int32_t* out_index, Address handles, int32_t num_handles, int64_t timeout_ns);"],
[0x19, "Result CancelSynchronization(Handle handle);"],
[0x1A, "Result ArbitrateLock(Handle thread_handle, Address address, uint32_t tag);"],
[0x1B, "Result ArbitrateUnlock(Address address);"],
[0x1C, "Result WaitProcessWideKeyAtomic(Address address, Address cv_key, uint32_t tag, int64_t timeout_ns);"],
[0x1D, "void SignalProcessWideKey(Address cv_key, int32_t count);"],
[0x1E, "int64_t GetSystemTick();"],
[0x1F, "Result ConnectToNamedPort(Handle* out_handle, Address name);"],
[0x20, "Result SendSyncRequestLight(Handle session_handle);"],
[0x21, "Result SendSyncRequest(Handle session_handle);"],
[0x22, "Result SendSyncRequestWithUserBuffer(Address message_buffer, Size message_buffer_size, Handle session_handle);"],
[0x23, "Result SendAsyncRequestWithUserBuffer(Handle* out_event_handle, Address message_buffer, Size message_buffer_size, Handle session_handle);"],
[0x24, "Result GetProcessId(uint64_t* out_process_id, Handle process_handle);"],
[0x25, "Result GetThreadId(uint64_t* out_thread_id, Handle thread_handle);"],
[0x26, "void Break(BreakReason break_reason, Address arg, Size size);"],
[0x27, "Result OutputDebugString(Address debug_str, Size len);"],
[0x28, "void ReturnFromException(Result result);"],
[0x29, "Result GetInfo(uint64_t* out, InfoType info_type, Handle handle, uint64_t info_subtype);"],
[0x2A, "void FlushEntireDataCache();"],
[0x2B, "Result FlushDataCache(Address address, Size size);"],
[0x2C, "Result MapPhysicalMemory(Address address, Size size);"],
[0x2D, "Result UnmapPhysicalMemory(Address address, Size size);"],
[0x2E, "Result GetDebugFutureThreadInfo(LastThreadContext* out_context, uint64_t* out_thread_id, Handle debug_handle, int64_t ns);"],
[0x2F, "Result GetLastThreadInfo(LastThreadContext* out_context, Address* out_tls_address, uint32_t* out_flags);"],
[0x30, "Result GetResourceLimitLimitValue(int64_t* out_limit_value, Handle resource_limit_handle, LimitableResource which);"],
[0x31, "Result GetResourceLimitCurrentValue(int64_t* out_current_value, Handle resource_limit_handle, LimitableResource which);"],
[0x32, "Result SetThreadActivity(Handle thread_handle, ThreadActivity thread_activity);"],
[0x33, "Result GetThreadContext3(Address out_context, Handle thread_handle);"],
[0x34, "Result WaitForAddress(Address address, ArbitrationType arb_type, int32_t value, int64_t timeout_ns);"],
[0x35, "Result SignalToAddress(Address address, SignalType signal_type, int32_t value, int32_t count);"],
[0x36, "void SynchronizePreemptionState();"],
[0x37, "Result GetResourceLimitPeakValue(int64_t* out_peak_value, Handle resource_limit_handle, LimitableResource which);"],
[0x39, "Result CreateIoPool(Handle* out_handle, IoPoolType which);"],
[0x3A, "Result CreateIoRegion(Handle* out_handle, Handle io_pool, PhysicalAddress physical_address, Size size, MemoryMapping mapping, MemoryPermission perm);"],
[0x3C, "void KernelDebug(KernelDebugType kern_debug_type, uint64_t arg0, uint64_t arg1, uint64_t arg2);"],
[0x3D, "void ChangeKernelTraceState(KernelTraceState kern_trace_state);"],
[0x40, "Result CreateSession(Handle* out_server_session_handle, Handle* out_client_session_handle, bool is_light, Address name);"],
[0x41, "Result AcceptSession(Handle* out_handle, Handle port);"],
[0x42, "Result ReplyAndReceiveLight(Handle handle);"],
[0x43, "Result ReplyAndReceive(int32_t* out_index, Address handles, int32_t num_handles, Handle reply_target, int64_t timeout_ns);"],
[0x44, "Result ReplyAndReceiveWithUserBuffer(int32_t* out_index, Address message_buffer, Size message_buffer_size, Address handles, int32_t num_handles, Handle reply_target, int64_t timeout_ns);"],
[0x45, "Result CreateEvent(Handle* out_write_handle, Handle* out_read_handle);"],
[0x46, "Result MapIoRegion(Handle io_region, Address address, Size size, MemoryPermission perm);"],
[0x47, "Result UnmapIoRegion(Handle io_region, Address address, Size size);"],
[0x48, "Result MapPhysicalMemoryUnsafe(Address address, Size size);"],
[0x49, "Result UnmapPhysicalMemoryUnsafe(Address address, Size size);"],
[0x4A, "Result SetUnsafeLimit(Size limit);"],
[0x4B, "Result CreateCodeMemory(Handle* out_handle, Address address, Size size);"],
[0x4C, "Result ControlCodeMemory(Handle code_memory_handle, CodeMemoryOperation operation, uint64_t address, uint64_t size, MemoryPermission perm);"],
[0x4D, "void SleepSystem();"],
[0x4E, "Result ReadWriteRegister(uint32_t* out_value, PhysicalAddress address, uint32_t mask, uint32_t value);"],
[0x4F, "Result SetProcessActivity(Handle process_handle, ProcessActivity process_activity);"],
[0x50, "Result CreateSharedMemory(Handle* out_handle, Size size, MemoryPermission owner_perm, MemoryPermission remote_perm);"],
[0x51, "Result MapTransferMemory(Handle trmem_handle, Address address, Size size, MemoryPermission owner_perm);"],
[0x52, "Result UnmapTransferMemory(Handle trmem_handle, Address address, Size size);"],
[0x53, "Result CreateInterruptEvent(Handle* out_read_handle, int32_t interrupt_id, InterruptType interrupt_type);"],
[0x54, "Result QueryPhysicalAddress(PhysicalMemoryInfo* out_info, Address address);"],
[0x55, "Result QueryIoMapping(Address* out_address, Size* out_size, PhysicalAddress physical_address, Size size);"],
[0x56, "Result CreateDeviceAddressSpace(Handle* out_handle, uint64_t das_address, uint64_t das_size);"],
[0x57, "Result AttachDeviceAddressSpace(DeviceName device_name, Handle das_handle);"],
[0x58, "Result DetachDeviceAddressSpace(DeviceName device_name, Handle das_handle);"],
[0x59, "Result MapDeviceAddressSpaceByForce(Handle das_handle, Handle process_handle, uint64_t process_address, Size size, uint64_t device_address, uint32_t option);"],
[0x5A, "Result MapDeviceAddressSpaceAligned(Handle das_handle, Handle process_handle, uint64_t process_address, Size size, uint64_t device_address, uint32_t option);"],
[0x5C, "Result UnmapDeviceAddressSpace(Handle das_handle, Handle process_handle, uint64_t process_address, Size size, uint64_t device_address);"],
[0x5D, "Result InvalidateProcessDataCache(Handle process_handle, uint64_t address, uint64_t size);"],
[0x5E, "Result StoreProcessDataCache(Handle process_handle, uint64_t address, uint64_t size);"],
[0x5F, "Result FlushProcessDataCache(Handle process_handle, uint64_t address, uint64_t size);"],
[0x60, "Result DebugActiveProcess(Handle* out_handle, uint64_t process_id);"],
[0x61, "Result BreakDebugProcess(Handle debug_handle);"],
[0x62, "Result TerminateDebugProcess(Handle debug_handle);"],
[0x63, "Result GetDebugEvent(Address out_info, Handle debug_handle);"],
[0x64, "Result ContinueDebugEvent(Handle debug_handle, uint32_t flags, Address thread_ids, int32_t num_thread_ids);"],
[0x65, "Result GetProcessList(int32_t* out_num_processes, Address out_process_ids, int32_t max_out_count);"],
[0x66, "Result GetThreadList(int32_t* out_num_threads, Address out_thread_ids, int32_t max_out_count, Handle debug_handle);"],
[0x67, "Result GetDebugThreadContext(Address out_context, Handle debug_handle, uint64_t thread_id, uint32_t context_flags);"],
[0x68, "Result SetDebugThreadContext(Handle debug_handle, uint64_t thread_id, Address context, uint32_t context_flags);"],
[0x69, "Result QueryDebugProcessMemory(Address out_memory_info, PageInfo* out_page_info, Handle process_handle, Address address);"],
[0x6A, "Result ReadDebugProcessMemory(Address buffer, Handle debug_handle, Address address, Size size);"],
[0x6B, "Result WriteDebugProcessMemory(Handle debug_handle, Address buffer, Address address, Size size);"],
[0x6C, "Result SetHardwareBreakPoint(HardwareBreakPointRegisterName name, uint64_t flags, uint64_t value);"],
[0x6D, "Result GetDebugThreadParam(uint64_t* out_64, uint32_t* out_32, Handle debug_handle, uint64_t thread_id, DebugThreadParam param);"],
[0x6F, "Result GetSystemInfo(uint64_t* out, SystemInfoType info_type, Handle handle, uint64_t info_subtype);"],
[0x70, "Result CreatePort(Handle* out_server_handle, Handle* out_client_handle, int32_t max_sessions, bool is_light, Address name);"],
[0x71, "Result ManageNamedPort(Handle* out_server_handle, Address name, int32_t max_sessions);"],
[0x72, "Result ConnectToPort(Handle* out_handle, Handle port);"],
[0x73, "Result SetProcessMemoryPermission(Handle process_handle, uint64_t address, uint64_t size, MemoryPermission perm);"],
[0x74, "Result MapProcessMemory(Address dst_address, Handle process_handle, uint64_t src_address, Size size);"],
[0x75, "Result UnmapProcessMemory(Address dst_address, Handle process_handle, uint64_t src_address, Size size);"],
[0x76, "Result QueryProcessMemory(Address out_memory_info, PageInfo* out_page_info, Handle process_handle, uint64_t address);"],
[0x77, "Result MapProcessCodeMemory(Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size);"],
[0x78, "Result UnmapProcessCodeMemory(Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size);"],
[0x79, "Result CreateProcess(Handle* out_handle, Address parameters, Address caps, int32_t num_caps);"],
[0x7A, "Result StartProcess(Handle process_handle, int32_t priority, int32_t core_id, uint64_t main_thread_stack_size);"],
[0x7B, "Result TerminateProcess(Handle process_handle);"],
[0x7C, "Result GetProcessInfo(int64_t* out_info, Handle process_handle, ProcessInfoType info_type);"],
[0x7D, "Result CreateResourceLimit(Handle* out_handle);"],
[0x7E, "Result SetResourceLimitLimitValue(Handle resource_limit_handle, LimitableResource which, int64_t limit_value);"],
[0x7F, "void CallSecureMonitor(SecureMonitorArguments args);"],
[0x90, "Result MapInsecureMemory(Address address, Size size);"],
[0x91, "Result UnmapInsecureMemory(Address address, Size size);"],
]
# These use a custom ABI, and therefore require custom wrappers
SKIP_WRAPPERS = {
0x20: "SendSyncRequestLight",
0x42: "ReplyAndReceiveLight",
0x7F: "CallSecureMonitor",
}
BIT_32 = 0
BIT_64 = 1
REG_SIZES = [4, 8]
SUFFIX_NAMES = ["64From32", "64"]
TYPE_SIZES = {
# SVC types
"ArbitrationType": 4,
"BreakReason": 4,
"CodeMemoryOperation": 4,
"DebugThreadParam": 4,
"DeviceName": 4,
"HardwareBreakPointRegisterName": 4,
"Handle": 4,
"InfoType": 4,
"InterruptType": 4,
"IoPoolType": 4,
"KernelDebugType": 4,
"KernelTraceState": 4,
"LimitableResource": 4,
"MemoryMapping": 4,
"MemoryPermission": 4,
"PageInfo": 4,
"ProcessActivity": 4,
"ProcessInfoType": 4,
"Result": 4,
"SignalType": 4,
"SystemInfoType": 4,
"ThreadActivity": 4,
# Arch-specific types
"ilp32::LastThreadContext": 16,
"ilp32::PhysicalMemoryInfo": 16,
"ilp32::SecureMonitorArguments": 32,
"lp64::LastThreadContext": 32,
"lp64::PhysicalMemoryInfo": 24,
"lp64::SecureMonitorArguments": 64,
# Generic types
"bool": 1,
"int32_t": 4,
"int64_t": 8,
"uint32_t": 4,
"uint64_t": 8,
"void": 0,
}
TYPE_REPLACEMENTS = {
"Address": ["uint32_t", "uint64_t"],
"LastThreadContext": ["ilp32::LastThreadContext", "lp64::LastThreadContext"],
"PhysicalAddress": ["uint64_t", "uint64_t"],
"PhysicalMemoryInfo": ["ilp32::PhysicalMemoryInfo", "lp64::PhysicalMemoryInfo"],
"SecureMonitorArguments": ["ilp32::SecureMonitorArguments", "lp64::SecureMonitorArguments"],
"Size": ["uint32_t", "uint64_t"],
"ThreadFunc": ["uint32_t", "uint64_t"],
}
# Statically verify that the hardcoded sizes match the intended
# sizes in C++.
def emit_size_check():
lines = []
for type, size in TYPE_SIZES.items():
if type != "void":
lines.append(f"static_assert(sizeof({type}) == {size});")
return "\n".join(lines)
# Replaces a type with an arch-specific one, if it exists.
def substitute_type(name, bitness):
if name in TYPE_REPLACEMENTS:
return TYPE_REPLACEMENTS[name][bitness]
else:
return name
class Argument:
def __init__(self, type_name, var_name, is_output, is_outptr, is_address):
self.type_name = type_name
self.var_name = var_name
self.is_output = is_output
self.is_outptr = is_outptr
self.is_address = is_address
# Parses C-style string declarations for SVCs.
def parse_declaration(declaration, bitness):
return_type, rest = declaration.split(" ", 1)
func_name, rest = rest.split("(", 1)
arg_names, rest = rest.split(")", 1)
argument_types = []
return_type = substitute_type(return_type, bitness)
assert return_type in TYPE_SIZES, f"Unknown type '{return_type}'"
if arg_names:
for arg_name in arg_names.split(", "):
type_name, var_name = arg_name.replace("*", "").split(" ", 1)
# All outputs must contain out_ in the name.
is_output = var_name == "out" or var_name.find("out_") != -1
# User-pointer outputs are not written to registers.
is_outptr = is_output and arg_name.find("*") == -1
# Special handling is performed for output addresses to avoid awkwardness
# in conversion for the 32-bit equivalents.
is_address = is_output and not is_outptr and \
type_name in ["Address", "Size"]
type_name = substitute_type(type_name, bitness)
assert type_name in TYPE_SIZES, f"Unknown type '{type_name}'"
argument_types.append(
Argument(type_name, var_name, is_output, is_outptr, is_address))
return (return_type, func_name, argument_types)
class RegisterAllocator:
def __init__(self, num_regs, byte_size, parameter_count):
self.registers = {}
self.num_regs = num_regs
self.byte_size = byte_size
self.parameter_count = parameter_count
# Mark the given register as allocated, for use in layout
# calculation if the NGRN exceeds the ABI parameter count.
def allocate(self, i):
assert i not in self.registers, f"Register R{i} already allocated"
self.registers[i] = True
return i
# Calculate the next available location for a register;
# the NGRN has exceeded the ABI parameter count.
def allocate_first_free(self):
for i in range(0, self.num_regs):
if i in self.registers:
continue
self.allocate(i)
return i
assert False, "No registers available"
# Add a single register at the given NGRN.
# If the index exceeds the ABI parameter count, try to find a
# location to add it. Returns the output location and increment.
def add_single(self, ngrn):
if ngrn >= self.parameter_count:
return (self.allocate_first_free(), 0)
else:
return (self.allocate(ngrn), 1)
# Add registers at the given NGRN for a data type of
# the given size. Returns the output locations and increment.
def add(self, ngrn, data_size, align=True):
if data_size <= self.byte_size:
r, i = self.add_single(ngrn)
return ([r], i)
regs = []
inc = ngrn % 2 if align else 0
remaining_size = data_size
while remaining_size > 0:
r, i = self.add_single(ngrn + inc)
regs.append(r)
inc += i
remaining_size -= self.byte_size
return (regs, inc)
def reg_alloc(bitness):
if bitness == 0:
# aapcs32: 4 4-byte registers
return RegisterAllocator(8, 4, 4)
elif bitness == 1:
# aapcs64: 8 8-byte registers
return RegisterAllocator(8, 8, 8)
# Converts a parsed SVC declaration into register lists for
# the return value, outputs, and inputs.
def get_registers(parse_result, bitness):
output_alloc = reg_alloc(bitness)
input_alloc = reg_alloc(bitness)
return_type, _, arguments = parse_result
return_write = []
output_writes = []
input_reads = []
input_ngrn = 0
output_ngrn = 0
# Run the input calculation.
for arg in arguments:
if arg.is_output and not arg.is_outptr:
input_ngrn += 1
continue
regs, increment = input_alloc.add(
input_ngrn, TYPE_SIZES[arg.type_name], align=True)
input_reads.append([arg.type_name, arg.var_name, regs])
input_ngrn += increment
# Include the return value if this SVC returns a value.
if return_type != "void":
regs, increment = output_alloc.add(
output_ngrn, TYPE_SIZES[return_type], align=False)
return_write.append([return_type, regs])
output_ngrn += increment
# Run the output calculation.
for arg in arguments:
if not arg.is_output or arg.is_outptr:
continue
regs, increment = output_alloc.add(
output_ngrn, TYPE_SIZES[arg.type_name], align=False)
output_writes.append(
[arg.type_name, arg.var_name, regs, arg.is_address])
output_ngrn += increment
return (return_write, output_writes, input_reads)
# Collects possibly multiple source registers into the named C++ value.
def emit_gather(sources, name, type_name, reg_size):
get_fn = f"GetReg{reg_size*8}"
if len(sources) == 1:
s, = sources
line = f"{name} = Convert<{type_name}>({get_fn}(system, {s}));"
return [line]
var_type = f"std::array<uint{reg_size*8}_t, {len(sources)}>"
lines = [
f"{var_type} {name}_gather{{}};"
]
for i in range(0, len(sources)):
lines.append(
f"{name}_gather[{i}] = {get_fn}(system, {sources[i]});")
lines.append(f"{name} = Convert<{type_name}>({name}_gather);")
return lines
# Produces one or more statements which assign the named C++ value
# into possibly multiple registers.
def emit_scatter(destinations, name, reg_size):
set_fn = f"SetReg{reg_size*8}"
reg_type = f"uint{reg_size*8}_t"
if len(destinations) == 1:
d, = destinations
line = f"{set_fn}(system, {d}, Convert<{reg_type}>({name}));"
return [line]
var_type = f"std::array<{reg_type}, {len(destinations)}>"
lines = [
f"auto {name}_scatter = Convert<{var_type}>({name});"
]
for i in range(0, len(destinations)):
lines.append(
f"{set_fn}(system, {destinations[i]}, {name}_scatter[{i}]);")
return lines
def emit_lines(lines, indent=' '):
output_lines = []
first = True
for line in lines:
if line and not first:
output_lines.append(indent + line)
else:
output_lines.append(line)
first = False
return "\n".join(output_lines)
# Emit a C++ function to wrap a guest SVC.
def emit_wrapper(wrapped_fn, suffix, register_info, arguments, byte_size):
return_write, output_writes, input_reads = register_info
lines = [
f"static void SvcWrap_{wrapped_fn}{suffix}(Core::System& system) {{"
]
# Get everything ready.
for return_type, _ in return_write:
lines.append(f"{return_type} ret{{}};")
if return_write:
lines.append("")
for output_type, var_name, _, is_address in output_writes:
output_type = "uintptr_t" if is_address else output_type
lines.append(f"{output_type} {var_name}{{}};")
for input_type, var_name, _ in input_reads:
lines.append(f"{input_type} {var_name}{{}};")
if output_writes or input_reads:
lines.append("")
for input_type, var_name, sources in input_reads:
lines += emit_gather(sources, var_name, input_type, byte_size)
if input_reads:
lines.append("")
# Build the call.
call_arguments = ["system"]
for arg in arguments:
if arg.is_output and not arg.is_outptr:
call_arguments.append(f"&{arg.var_name}")
else:
call_arguments.append(arg.var_name)
line = ""
if return_write:
line += "ret = "
line += f"{wrapped_fn}{suffix}({', '.join(call_arguments)});"
lines.append(line)
if return_write or output_writes:
lines.append("")
# Write back the return value and outputs.
for _, destinations in return_write:
lines += emit_scatter(destinations, "ret", byte_size)
for _, var_name, destinations, _ in output_writes:
lines += emit_scatter(destinations, var_name, byte_size)
# Finish.
return emit_lines(lines) + "\n}"
COPYRIGHT = """\
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// This file is automatically generated using svc_generator.py.
"""
PROLOGUE_H = """
#pragma once
namespace Core {
class System;
}
#include "common/common_types.h"
#include "core/hle/kernel/svc_types.h"
#include "core/hle/result.h"
namespace Kernel::Svc {
// clang-format off
"""
EPILOGUE_H = """
// clang-format on
// Custom ABI.
Result ReplyAndReceiveLight(Core::System& system, Handle handle, uint32_t* args);
Result ReplyAndReceiveLight64From32(Core::System& system, Handle handle, uint32_t* args);
Result ReplyAndReceiveLight64(Core::System& system, Handle handle, uint32_t* args);
Result SendSyncRequestLight(Core::System& system, Handle session_handle, uint32_t* args);
Result SendSyncRequestLight64From32(Core::System& system, Handle session_handle, uint32_t* args);
Result SendSyncRequestLight64(Core::System& system, Handle session_handle, uint32_t* args);
void CallSecureMonitor(Core::System& system, lp64::SecureMonitorArguments* args);
void CallSecureMonitor64From32(Core::System& system, ilp32::SecureMonitorArguments* args);
void CallSecureMonitor64(Core::System& system, lp64::SecureMonitorArguments* args);
// Defined in svc_light_ipc.cpp.
void SvcWrap_ReplyAndReceiveLight64From32(Core::System& system);
void SvcWrap_ReplyAndReceiveLight64(Core::System& system);
void SvcWrap_SendSyncRequestLight64From32(Core::System& system);
void SvcWrap_SendSyncRequestLight64(Core::System& system);
// Defined in svc_secure_monitor_call.cpp.
void SvcWrap_CallSecureMonitor64From32(Core::System& system);
void SvcWrap_CallSecureMonitor64(Core::System& system);
// Perform a supervisor call by index.
void Call(Core::System& system, u32 imm);
} // namespace Kernel::Svc
"""
PROLOGUE_CPP = """
#include <type_traits>
#include "core/arm/arm_interface.h"
#include "core/core.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/svc.h"
namespace Kernel::Svc {
static uint32_t GetReg32(Core::System& system, int n) {
return static_cast<uint32_t>(system.CurrentArmInterface().GetReg(n));
}
static void SetReg32(Core::System& system, int n, uint32_t result) {
system.CurrentArmInterface().SetReg(n, static_cast<uint64_t>(result));
}
static uint64_t GetReg64(Core::System& system, int n) {
return system.CurrentArmInterface().GetReg(n);
}
static void SetReg64(Core::System& system, int n, uint64_t result) {
system.CurrentArmInterface().SetReg(n, result);
}
// Like bit_cast, but handles the case when the source and dest
// are differently-sized.
template <typename To, typename From>
requires(std::is_trivial_v<To> && std::is_trivially_copyable_v<From>)
static To Convert(const From& from) {
To to{};
if constexpr (sizeof(To) >= sizeof(From)) {
std::memcpy(&to, &from, sizeof(From));
} else {
std::memcpy(&to, &from, sizeof(To));
}
return to;
}
// clang-format off
"""
EPILOGUE_CPP = """
// clang-format on
void Call(Core::System& system, u32 imm) {
auto& kernel = system.Kernel();
kernel.EnterSVCProfile();
if (GetCurrentProcess(system.Kernel()).Is64BitProcess()) {
Call64(system, imm);
} else {
Call32(system, imm);
}
kernel.ExitSVCProfile();
}
} // namespace Kernel::Svc
"""
def emit_call(bitness, names, suffix):
bit_size = REG_SIZES[bitness]*8
indent = " "
lines = [
f"static void Call{bit_size}(Core::System& system, u32 imm) {{",
f"{indent}switch (static_cast<SvcId>(imm)) {{"
]
for _, name in names:
lines.append(f"{indent}case SvcId::{name}:")
lines.append(f"{indent*2}return SvcWrap_{name}{suffix}(system);")
lines.append(f"{indent}default:")
lines.append(
f"{indent*2}LOG_CRITICAL(Kernel_SVC, \"Unknown SVC {{:x}}!\", imm);")
lines.append(f"{indent*2}break;")
lines.append(f"{indent}}}")
lines.append("}")
return "\n".join(lines)
def build_fn_declaration(return_type, name, arguments):
arg_list = ["Core::System& system"]
for arg in arguments:
type_name = "uintptr_t" if arg.is_address else arg.type_name
pointer = "*" if arg.is_output and not arg.is_outptr else ""
arg_list.append(f"{type_name}{pointer} {arg.var_name}")
return f"{return_type} {name}({', '.join(arg_list)});"
def build_enum_declarations():
lines = ["enum class SvcId : u32 {"]
indent = " "
for imm, decl in SVCS:
_, name, _ = parse_declaration(decl, BIT_64)
lines.append(f"{indent}{name} = {hex(imm)},")
lines.append("};")
return "\n".join(lines)
def main():
arch_fw_declarations = [[], []]
svc_fw_declarations = []
wrapper_fns = []
names = []
for imm, decl in SVCS:
return_type, name, arguments = parse_declaration(decl, BIT_64)
if imm not in SKIP_WRAPPERS:
svc_fw_declarations.append(
build_fn_declaration(return_type, name, arguments))
names.append([imm, name])
for bitness in range(2):
byte_size = REG_SIZES[bitness]
suffix = SUFFIX_NAMES[bitness]
for imm, decl in SVCS:
if imm in SKIP_WRAPPERS:
continue
parse_result = parse_declaration(decl, bitness)
return_type, name, arguments = parse_result
register_info = get_registers(parse_result, bitness)
wrapper_fns.append(
emit_wrapper(name, suffix, register_info, arguments, byte_size))
arch_fw_declarations[bitness].append(
build_fn_declaration(return_type, name + suffix, arguments))
call_32 = emit_call(BIT_32, names, SUFFIX_NAMES[BIT_32])
call_64 = emit_call(BIT_64, names, SUFFIX_NAMES[BIT_64])
enum_decls = build_enum_declarations()
with open("svc.h", "w") as f:
f.write(COPYRIGHT)
f.write(PROLOGUE_H)
f.write("\n".join(svc_fw_declarations))
f.write("\n\n")
f.write("\n".join(arch_fw_declarations[BIT_32]))
f.write("\n\n")
f.write("\n".join(arch_fw_declarations[BIT_64]))
f.write("\n\n")
f.write(enum_decls)
f.write(EPILOGUE_H)
with open("svc.cpp", "w") as f:
f.write(COPYRIGHT)
f.write(PROLOGUE_CPP)
f.write(emit_size_check())
f.write("\n\n")
f.write("\n\n".join(wrapper_fns))
f.write("\n\n")
f.write(call_32)
f.write("\n\n")
f.write(call_64)
f.write(EPILOGUE_CPP)
print(f"Done (emitted {len(names)} definitions)")
if __name__ == "__main__":
main()

View File

@@ -11,6 +11,7 @@ namespace Kernel {
constexpr Result ResultOutOfSessions{ErrorModule::Kernel, 7};
constexpr Result ResultInvalidArgument{ErrorModule::Kernel, 14};
constexpr Result ResultNotImplemented{ErrorModule::Kernel, 33};
constexpr Result ResultNoSynchronizationObject{ErrorModule::Kernel, 57};
constexpr Result ResultTerminationRequested{ErrorModule::Kernel, 59};
constexpr Result ResultInvalidSize{ErrorModule::Kernel, 101};

View File

@@ -5,6 +5,7 @@
#include <bitset>
#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
@@ -167,6 +168,7 @@ enum class BreakReason : u32 {
NotificationOnlyFlag = 0x80000000,
};
DECLARE_ENUM_FLAG_OPERATORS(BreakReason);
enum class DebugEvent : u32 {
CreateProcess = 0,
@@ -498,6 +500,19 @@ enum class MemoryMapping : u32 {
Memory = 2,
};
enum class MapDeviceAddressSpaceFlag : u32 {
None = (0U << 0),
NotIoRegister = (1U << 0),
};
DECLARE_ENUM_FLAG_OPERATORS(MapDeviceAddressSpaceFlag);
union MapDeviceAddressSpaceOption {
u32 raw;
BitField<0, 16, MemoryPermission> permission;
BitField<16, 1, MapDeviceAddressSpaceFlag> flags;
BitField<17, 15, u32> reserved;
};
enum class KernelDebugType : u32 {
Thread = 0,
ThreadCallStack = 1,
@@ -582,6 +597,11 @@ enum class ProcessInfoType : u32 {
ProcessState = 0,
};
enum class ProcessActivity : u32 {
Runnable,
Paused,
};
struct CreateProcessParameter {
std::array<char, 12> name;
u32 version;
@@ -597,4 +617,9 @@ static_assert(sizeof(CreateProcessParameter) == 0x30);
constexpr size_t NumSupervisorCalls = 0xC0;
using SvcAccessFlagSet = std::bitset<NumSupervisorCalls>;
enum class InitialProcessIdRangeInfo : u64 {
Minimum = 0,
Maximum = 1,
};
} // namespace Kernel::Svc

View File

@@ -35,11 +35,11 @@ constexpr inline u32 EncodeKernelVersion(u32 major, u32 minor) {
}
constexpr inline u32 GetKernelMajorVersion(u32 encoded) {
return std::bit_cast<decltype(KernelVersion::major_version)>(encoded).Value();
return decltype(KernelVersion::major_version)::ExtractValue(encoded);
}
constexpr inline u32 GetKernelMinorVersion(u32 encoded) {
return std::bit_cast<decltype(KernelVersion::minor_version)>(encoded).Value();
return decltype(KernelVersion::minor_version)::ExtractValue(encoded);
}
// Nintendo doesn't support programs targeting SVC versions < 3.0.

View File

@@ -1,733 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/common_types.h"
#include "core/arm/arm_interface.h"
#include "core/core.h"
#include "core/hle/kernel/svc_types.h"
#include "core/hle/result.h"
#include "core/memory.h"
namespace Kernel {
static inline u64 Param(const Core::System& system, int n) {
return system.CurrentArmInterface().GetReg(n);
}
static inline u32 Param32(const Core::System& system, int n) {
return static_cast<u32>(system.CurrentArmInterface().GetReg(n));
}
/**
* HLE a function return from the current ARM userland process
* @param system System context
* @param result Result to return
*/
static inline void FuncReturn(Core::System& system, u64 result) {
system.CurrentArmInterface().SetReg(0, result);
}
static inline void FuncReturn32(Core::System& system, u32 result) {
system.CurrentArmInterface().SetReg(0, (u64)result);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Function wrappers that return type Result
template <Result func(Core::System&, u64)>
void SvcWrap64(Core::System& system) {
FuncReturn(system, func(system, Param(system, 0)).raw);
}
template <Result func(Core::System&, u64, u64)>
void SvcWrap64(Core::System& system) {
FuncReturn(system, func(system, Param(system, 0), Param(system, 1)).raw);
}
template <Result func(Core::System&, u32)>
void SvcWrap64(Core::System& system) {
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0))).raw);
}
template <Result func(Core::System&, u32, u32)>
void SvcWrap64(Core::System& system) {
FuncReturn(
system,
func(system, static_cast<u32>(Param(system, 0)), static_cast<u32>(Param(system, 1))).raw);
}
// Used by SetThreadActivity
template <Result func(Core::System&, Handle, Svc::ThreadActivity)>
void SvcWrap64(Core::System& system) {
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)),
static_cast<Svc::ThreadActivity>(Param(system, 1)))
.raw);
}
template <Result func(Core::System&, u32, u64, u64, u64)>
void SvcWrap64(Core::System& system) {
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1),
Param(system, 2), Param(system, 3))
.raw);
}
// Used by MapProcessMemory and UnmapProcessMemory
template <Result func(Core::System&, u64, u32, u64, u64)>
void SvcWrap64(Core::System& system) {
FuncReturn(system, func(system, Param(system, 0), static_cast<u32>(Param(system, 1)),
Param(system, 2), Param(system, 3))
.raw);
}
// Used by ControlCodeMemory
template <Result func(Core::System&, Handle, u32, VAddr, size_t, Svc::MemoryPermission)>
void SvcWrap64(Core::System& system) {
FuncReturn(system, func(system, static_cast<Handle>(Param(system, 0)),
static_cast<u32>(Param(system, 1)), Param(system, 2), Param(system, 3),
static_cast<Svc::MemoryPermission>(Param(system, 4)))
.raw);
}
template <Result func(Core::System&, u32*)>
void SvcWrap64(Core::System& system) {
u32 param = 0;
const u32 retval = func(system, &param).raw;
system.CurrentArmInterface().SetReg(1, param);
FuncReturn(system, retval);
}
template <Result func(Core::System&, u32*, u32)>
void SvcWrap64(Core::System& system) {
u32 param_1 = 0;
const u32 retval = func(system, &param_1, static_cast<u32>(Param(system, 1))).raw;
system.CurrentArmInterface().SetReg(1, param_1);
FuncReturn(system, retval);
}
template <Result func(Core::System&, u32*, u32*)>
void SvcWrap64(Core::System& system) {
u32 param_1 = 0;
u32 param_2 = 0;
const u32 retval = func(system, &param_1, &param_2).raw;
auto& arm_interface = system.CurrentArmInterface();
arm_interface.SetReg(1, param_1);
arm_interface.SetReg(2, param_2);
FuncReturn(system, retval);
}
template <Result func(Core::System&, u32*, u64)>
void SvcWrap64(Core::System& system) {
u32 param_1 = 0;
const u32 retval = func(system, &param_1, Param(system, 1)).raw;
system.CurrentArmInterface().SetReg(1, param_1);
FuncReturn(system, retval);
}
template <Result func(Core::System&, u32*, u64, u32)>
void SvcWrap64(Core::System& system) {
u32 param_1 = 0;
const u32 retval =
func(system, &param_1, Param(system, 1), static_cast<u32>(Param(system, 2))).raw;
system.CurrentArmInterface().SetReg(1, param_1);
FuncReturn(system, retval);
}
template <Result func(Core::System&, u64*, u32)>
void SvcWrap64(Core::System& system) {
u64 param_1 = 0;
const u32 retval = func(system, &param_1, static_cast<u32>(Param(system, 1))).raw;
system.CurrentArmInterface().SetReg(1, param_1);
FuncReturn(system, retval);
}
template <Result func(Core::System&, u64, u32)>
void SvcWrap64(Core::System& system) {
FuncReturn(system, func(system, Param(system, 0), static_cast<u32>(Param(system, 1))).raw);
}
template <Result func(Core::System&, u64*, u64)>
void SvcWrap64(Core::System& system) {
u64 param_1 = 0;
const u32 retval = func(system, &param_1, Param(system, 1)).raw;
system.CurrentArmInterface().SetReg(1, param_1);
FuncReturn(system, retval);
}
template <Result func(Core::System&, u64*, u32, u32)>
void SvcWrap64(Core::System& system) {
u64 param_1 = 0;
const u32 retval = func(system, &param_1, static_cast<u32>(Param(system, 1)),
static_cast<u32>(Param(system, 2)))
.raw;
system.CurrentArmInterface().SetReg(1, param_1);
FuncReturn(system, retval);
}
// Used by GetResourceLimitLimitValue.
template <Result func(Core::System&, u64*, Handle, LimitableResource)>
void SvcWrap64(Core::System& system) {
u64 param_1 = 0;
const u32 retval = func(system, &param_1, static_cast<Handle>(Param(system, 1)),
static_cast<LimitableResource>(Param(system, 2)))
.raw;
system.CurrentArmInterface().SetReg(1, param_1);
FuncReturn(system, retval);
}
template <Result func(Core::System&, u32, u64)>
void SvcWrap64(Core::System& system) {
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1)).raw);
}
// Used by SetResourceLimitLimitValue
template <Result func(Core::System&, Handle, LimitableResource, u64)>
void SvcWrap64(Core::System& system) {
FuncReturn(system, func(system, static_cast<Handle>(Param(system, 0)),
static_cast<LimitableResource>(Param(system, 1)), Param(system, 2))
.raw);
}
// Used by SetThreadCoreMask
template <Result func(Core::System&, Handle, s32, u64)>
void SvcWrap64(Core::System& system) {
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)),
static_cast<s32>(Param(system, 1)), Param(system, 2))
.raw);
}
// Used by GetThreadCoreMask
template <Result func(Core::System&, Handle, s32*, u64*)>
void SvcWrap64(Core::System& system) {
s32 param_1 = 0;
u64 param_2 = 0;
const Result retval = func(system, static_cast<u32>(Param(system, 2)), &param_1, &param_2);
system.CurrentArmInterface().SetReg(1, param_1);
system.CurrentArmInterface().SetReg(2, param_2);
FuncReturn(system, retval.raw);
}
template <Result func(Core::System&, u64, u64, u32, u32)>
void SvcWrap64(Core::System& system) {
FuncReturn(system, func(system, Param(system, 0), Param(system, 1),
static_cast<u32>(Param(system, 2)), static_cast<u32>(Param(system, 3)))
.raw);
}
template <Result func(Core::System&, u64, u64, u32, u64)>
void SvcWrap64(Core::System& system) {
FuncReturn(system, func(system, Param(system, 0), Param(system, 1),
static_cast<u32>(Param(system, 2)), Param(system, 3))
.raw);
}
template <Result func(Core::System&, u32, u64, u32)>
void SvcWrap64(Core::System& system) {
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1),
static_cast<u32>(Param(system, 2)))
.raw);
}
template <Result func(Core::System&, u64, u64, u64)>
void SvcWrap64(Core::System& system) {
FuncReturn(system, func(system, Param(system, 0), Param(system, 1), Param(system, 2)).raw);
}
template <Result func(Core::System&, u64, u64, u32)>
void SvcWrap64(Core::System& system) {
FuncReturn(
system,
func(system, Param(system, 0), Param(system, 1), static_cast<u32>(Param(system, 2))).raw);
}
// Used by SetMemoryPermission
template <Result func(Core::System&, u64, u64, Svc::MemoryPermission)>
void SvcWrap64(Core::System& system) {
FuncReturn(system, func(system, Param(system, 0), Param(system, 1),
static_cast<Svc::MemoryPermission>(Param(system, 2)))
.raw);
}
// Used by MapSharedMemory
template <Result func(Core::System&, Handle, u64, u64, Svc::MemoryPermission)>
void SvcWrap64(Core::System& system) {
FuncReturn(system, func(system, static_cast<Handle>(Param(system, 0)), Param(system, 1),
Param(system, 2), static_cast<Svc::MemoryPermission>(Param(system, 3)))
.raw);
}
template <Result func(Core::System&, u32, u64, u64)>
void SvcWrap64(Core::System& system) {
FuncReturn(
system,
func(system, static_cast<u32>(Param(system, 0)), Param(system, 1), Param(system, 2)).raw);
}
// Used by WaitSynchronization
template <Result func(Core::System&, s32*, u64, s32, s64)>
void SvcWrap64(Core::System& system) {
s32 param_1 = 0;
const u32 retval = func(system, &param_1, Param(system, 1), static_cast<s32>(Param(system, 2)),
static_cast<s64>(Param(system, 3)))
.raw;
system.CurrentArmInterface().SetReg(1, param_1);
FuncReturn(system, retval);
}
template <Result func(Core::System&, u64, u64, u32, s64)>
void SvcWrap64(Core::System& system) {
FuncReturn(system, func(system, Param(system, 0), Param(system, 1),
static_cast<u32>(Param(system, 2)), static_cast<s64>(Param(system, 3)))
.raw);
}
// Used by GetInfo
template <Result func(Core::System&, u64*, u64, Handle, u64)>
void SvcWrap64(Core::System& system) {
u64 param_1 = 0;
const u32 retval = func(system, &param_1, Param(system, 1),
static_cast<Handle>(Param(system, 2)), Param(system, 3))
.raw;
system.CurrentArmInterface().SetReg(1, param_1);
FuncReturn(system, retval);
}
template <Result func(Core::System&, u32*, u64, u64, u64, u32, s32)>
void SvcWrap64(Core::System& system) {
u32 param_1 = 0;
const u32 retval = func(system, &param_1, Param(system, 1), Param(system, 2), Param(system, 3),
static_cast<u32>(Param(system, 4)), static_cast<s32>(Param(system, 5)))
.raw;
system.CurrentArmInterface().SetReg(1, param_1);
FuncReturn(system, retval);
}
// Used by CreateTransferMemory
template <Result func(Core::System&, Handle*, u64, u64, Svc::MemoryPermission)>
void SvcWrap64(Core::System& system) {
u32 param_1 = 0;
const u32 retval = func(system, &param_1, Param(system, 1), Param(system, 2),
static_cast<Svc::MemoryPermission>(Param(system, 3)))
.raw;
system.CurrentArmInterface().SetReg(1, param_1);
FuncReturn(system, retval);
}
// Used by CreateCodeMemory
template <Result func(Core::System&, Handle*, VAddr, size_t)>
void SvcWrap64(Core::System& system) {
u32 param_1 = 0;
const u32 retval = func(system, &param_1, Param(system, 1), Param(system, 2)).raw;
system.CurrentArmInterface().SetReg(1, param_1);
FuncReturn(system, retval);
}
template <Result func(Core::System&, Handle*, u64, u32, u32)>
void SvcWrap64(Core::System& system) {
u32 param_1 = 0;
const u32 retval = func(system, &param_1, Param(system, 1), static_cast<u32>(Param(system, 2)),
static_cast<u32>(Param(system, 3)))
.raw;
system.CurrentArmInterface().SetReg(1, param_1);
FuncReturn(system, retval);
}
// Used by CreateSession
template <Result func(Core::System&, Handle*, Handle*, u32, u64)>
void SvcWrap64(Core::System& system) {
Handle param_1 = 0;
Handle param_2 = 0;
const u32 retval = func(system, &param_1, &param_2, static_cast<u32>(Param(system, 2)),
static_cast<u32>(Param(system, 3)))
.raw;
system.CurrentArmInterface().SetReg(1, param_1);
system.CurrentArmInterface().SetReg(2, param_2);
FuncReturn(system, retval);
}
// Used by ReplyAndReceive
template <Result func(Core::System&, s32*, Handle*, s32, Handle, s64)>
void SvcWrap64(Core::System& system) {
s32 param_1 = 0;
s32 num_handles = static_cast<s32>(Param(system, 2));
std::vector<Handle> handles(num_handles);
system.Memory().ReadBlock(Param(system, 1), handles.data(), num_handles * sizeof(Handle));
const u32 retval = func(system, &param_1, handles.data(), num_handles,
static_cast<s32>(Param(system, 3)), static_cast<s64>(Param(system, 4)))
.raw;
system.CurrentArmInterface().SetReg(1, param_1);
FuncReturn(system, retval);
}
// Used by WaitForAddress
template <Result func(Core::System&, u64, Svc::ArbitrationType, s32, s64)>
void SvcWrap64(Core::System& system) {
FuncReturn(system,
func(system, Param(system, 0), static_cast<Svc::ArbitrationType>(Param(system, 1)),
static_cast<s32>(Param(system, 2)), static_cast<s64>(Param(system, 3)))
.raw);
}
// Used by SignalToAddress
template <Result func(Core::System&, u64, Svc::SignalType, s32, s32)>
void SvcWrap64(Core::System& system) {
FuncReturn(system,
func(system, Param(system, 0), static_cast<Svc::SignalType>(Param(system, 1)),
static_cast<s32>(Param(system, 2)), static_cast<s32>(Param(system, 3)))
.raw);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Function wrappers that return type u32
template <u32 func(Core::System&)>
void SvcWrap64(Core::System& system) {
FuncReturn(system, func(system));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Function wrappers that return type u64
template <u64 func(Core::System&)>
void SvcWrap64(Core::System& system) {
FuncReturn(system, func(system));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// Function wrappers that return type void
template <void func(Core::System&)>
void SvcWrap64(Core::System& system) {
func(system);
}
template <void func(Core::System&, u32)>
void SvcWrap64(Core::System& system) {
func(system, static_cast<u32>(Param(system, 0)));
}
template <void func(Core::System&, u32, u64, u64, u64)>
void SvcWrap64(Core::System& system) {
func(system, static_cast<u32>(Param(system, 0)), Param(system, 1), Param(system, 2),
Param(system, 3));
}
template <void func(Core::System&, s64)>
void SvcWrap64(Core::System& system) {
func(system, static_cast<s64>(Param(system, 0)));
}
template <void func(Core::System&, u64, s32)>
void SvcWrap64(Core::System& system) {
func(system, Param(system, 0), static_cast<s32>(Param(system, 1)));
}
template <void func(Core::System&, u64, u64)>
void SvcWrap64(Core::System& system) {
func(system, Param(system, 0), Param(system, 1));
}
template <void func(Core::System&, u64, u64, u64)>
void SvcWrap64(Core::System& system) {
func(system, Param(system, 0), Param(system, 1), Param(system, 2));
}
template <void func(Core::System&, u32, u64, u64)>
void SvcWrap64(Core::System& system) {
func(system, static_cast<u32>(Param(system, 0)), Param(system, 1), Param(system, 2));
}
// Used by QueryMemory32, ArbitrateLock32
template <Result func(Core::System&, u32, u32, u32)>
void SvcWrap32(Core::System& system) {
FuncReturn32(system,
func(system, Param32(system, 0), Param32(system, 1), Param32(system, 2)).raw);
}
// Used by Break32
template <void func(Core::System&, u32, u32, u32)>
void SvcWrap32(Core::System& system) {
func(system, Param32(system, 0), Param32(system, 1), Param32(system, 2));
}
// Used by ExitProcess32, ExitThread32
template <void func(Core::System&)>
void SvcWrap32(Core::System& system) {
func(system);
}
// Used by GetCurrentProcessorNumber32
template <u32 func(Core::System&)>
void SvcWrap32(Core::System& system) {
FuncReturn32(system, func(system));
}
// Used by SleepThread32
template <void func(Core::System&, u32, u32)>
void SvcWrap32(Core::System& system) {
func(system, Param32(system, 0), Param32(system, 1));
}
// Used by CreateThread32
template <Result func(Core::System&, Handle*, u32, u32, u32, u32, s32)>
void SvcWrap32(Core::System& system) {
Handle param_1 = 0;
const u32 retval = func(system, &param_1, Param32(system, 0), Param32(system, 1),
Param32(system, 2), Param32(system, 3), Param32(system, 4))
.raw;
system.CurrentArmInterface().SetReg(1, param_1);
FuncReturn(system, retval);
}
// Used by GetInfo32
template <Result func(Core::System&, u32*, u32*, u32, u32, u32, u32)>
void SvcWrap32(Core::System& system) {
u32 param_1 = 0;
u32 param_2 = 0;
const u32 retval = func(system, &param_1, &param_2, Param32(system, 0), Param32(system, 1),
Param32(system, 2), Param32(system, 3))
.raw;
system.CurrentArmInterface().SetReg(1, param_1);
system.CurrentArmInterface().SetReg(2, param_2);
FuncReturn(system, retval);
}
// Used by GetThreadPriority32, ConnectToNamedPort32
template <Result func(Core::System&, u32*, u32)>
void SvcWrap32(Core::System& system) {
u32 param_1 = 0;
const u32 retval = func(system, &param_1, Param32(system, 1)).raw;
system.CurrentArmInterface().SetReg(1, param_1);
FuncReturn(system, retval);
}
// Used by GetThreadId32
template <Result func(Core::System&, u32*, u32*, u32)>
void SvcWrap32(Core::System& system) {
u32 param_1 = 0;
u32 param_2 = 0;
const u32 retval = func(system, &param_1, &param_2, Param32(system, 1)).raw;
system.CurrentArmInterface().SetReg(1, param_1);
system.CurrentArmInterface().SetReg(2, param_2);
FuncReturn(system, retval);
}
// Used by GetSystemTick32
template <void func(Core::System&, u32*, u32*)>
void SvcWrap32(Core::System& system) {
u32 param_1 = 0;
u32 param_2 = 0;
func(system, &param_1, &param_2);
system.CurrentArmInterface().SetReg(0, param_1);
system.CurrentArmInterface().SetReg(1, param_2);
}
// Used by CreateEvent32
template <Result func(Core::System&, Handle*, Handle*)>
void SvcWrap32(Core::System& system) {
Handle param_1 = 0;
Handle param_2 = 0;
const u32 retval = func(system, &param_1, &param_2).raw;
system.CurrentArmInterface().SetReg(1, param_1);
system.CurrentArmInterface().SetReg(2, param_2);
FuncReturn(system, retval);
}
// Used by GetThreadId32
template <Result func(Core::System&, Handle, u32*, u32*, u32*)>
void SvcWrap32(Core::System& system) {
u32 param_1 = 0;
u32 param_2 = 0;
u32 param_3 = 0;
const u32 retval = func(system, Param32(system, 2), &param_1, &param_2, &param_3).raw;
system.CurrentArmInterface().SetReg(1, param_1);
system.CurrentArmInterface().SetReg(2, param_2);
system.CurrentArmInterface().SetReg(3, param_3);
FuncReturn(system, retval);
}
// Used by GetThreadCoreMask32
template <Result func(Core::System&, Handle, s32*, u32*, u32*)>
void SvcWrap32(Core::System& system) {
s32 param_1 = 0;
u32 param_2 = 0;
u32 param_3 = 0;
const u32 retval = func(system, Param32(system, 2), &param_1, &param_2, &param_3).raw;
system.CurrentArmInterface().SetReg(1, param_1);
system.CurrentArmInterface().SetReg(2, param_2);
system.CurrentArmInterface().SetReg(3, param_3);
FuncReturn(system, retval);
}
// Used by SignalProcessWideKey32
template <void func(Core::System&, u32, s32)>
void SvcWrap32(Core::System& system) {
func(system, static_cast<u32>(Param(system, 0)), static_cast<s32>(Param(system, 1)));
}
// Used by SetThreadActivity32
template <Result func(Core::System&, Handle, Svc::ThreadActivity)>
void SvcWrap32(Core::System& system) {
const u32 retval = func(system, static_cast<Handle>(Param(system, 0)),
static_cast<Svc::ThreadActivity>(Param(system, 1)))
.raw;
FuncReturn(system, retval);
}
// Used by SetThreadPriority32
template <Result func(Core::System&, Handle, u32)>
void SvcWrap32(Core::System& system) {
const u32 retval =
func(system, static_cast<Handle>(Param(system, 0)), static_cast<u32>(Param(system, 1))).raw;
FuncReturn(system, retval);
}
// Used by SetMemoryAttribute32
template <Result func(Core::System&, Handle, u32, u32, u32)>
void SvcWrap32(Core::System& system) {
const u32 retval =
func(system, static_cast<Handle>(Param(system, 0)), static_cast<u32>(Param(system, 1)),
static_cast<u32>(Param(system, 2)), static_cast<u32>(Param(system, 3)))
.raw;
FuncReturn(system, retval);
}
// Used by MapSharedMemory32
template <Result func(Core::System&, Handle, u32, u32, Svc::MemoryPermission)>
void SvcWrap32(Core::System& system) {
const u32 retval = func(system, static_cast<Handle>(Param(system, 0)),
static_cast<u32>(Param(system, 1)), static_cast<u32>(Param(system, 2)),
static_cast<Svc::MemoryPermission>(Param(system, 3)))
.raw;
FuncReturn(system, retval);
}
// Used by SetThreadCoreMask32
template <Result func(Core::System&, Handle, s32, u32, u32)>
void SvcWrap32(Core::System& system) {
const u32 retval =
func(system, static_cast<Handle>(Param(system, 0)), static_cast<s32>(Param(system, 1)),
static_cast<u32>(Param(system, 2)), static_cast<u32>(Param(system, 3)))
.raw;
FuncReturn(system, retval);
}
// Used by WaitProcessWideKeyAtomic32
template <Result func(Core::System&, u32, u32, Handle, u32, u32)>
void SvcWrap32(Core::System& system) {
const u32 retval =
func(system, static_cast<u32>(Param(system, 0)), static_cast<u32>(Param(system, 1)),
static_cast<Handle>(Param(system, 2)), static_cast<u32>(Param(system, 3)),
static_cast<u32>(Param(system, 4)))
.raw;
FuncReturn(system, retval);
}
// Used by WaitForAddress32
template <Result func(Core::System&, u32, Svc::ArbitrationType, s32, u32, u32)>
void SvcWrap32(Core::System& system) {
const u32 retval = func(system, static_cast<u32>(Param(system, 0)),
static_cast<Svc::ArbitrationType>(Param(system, 1)),
static_cast<s32>(Param(system, 2)), static_cast<u32>(Param(system, 3)),
static_cast<u32>(Param(system, 4)))
.raw;
FuncReturn(system, retval);
}
// Used by SignalToAddress32
template <Result func(Core::System&, u32, Svc::SignalType, s32, s32)>
void SvcWrap32(Core::System& system) {
const u32 retval = func(system, static_cast<u32>(Param(system, 0)),
static_cast<Svc::SignalType>(Param(system, 1)),
static_cast<s32>(Param(system, 2)), static_cast<s32>(Param(system, 3)))
.raw;
FuncReturn(system, retval);
}
// Used by SendSyncRequest32, ArbitrateUnlock32
template <Result func(Core::System&, u32)>
void SvcWrap32(Core::System& system) {
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0))).raw);
}
// Used by CreateTransferMemory32
template <Result func(Core::System&, Handle*, u32, u32, Svc::MemoryPermission)>
void SvcWrap32(Core::System& system) {
Handle handle = 0;
const u32 retval = func(system, &handle, Param32(system, 1), Param32(system, 2),
static_cast<Svc::MemoryPermission>(Param32(system, 3)))
.raw;
system.CurrentArmInterface().SetReg(1, handle);
FuncReturn(system, retval);
}
// Used by WaitSynchronization32
template <Result func(Core::System&, u32, u32, s32, u32, s32*)>
void SvcWrap32(Core::System& system) {
s32 param_1 = 0;
const u32 retval = func(system, Param32(system, 0), Param32(system, 1), Param32(system, 2),
Param32(system, 3), &param_1)
.raw;
system.CurrentArmInterface().SetReg(1, param_1);
FuncReturn(system, retval);
}
// Used by CreateCodeMemory32
template <Result func(Core::System&, Handle*, u32, u32)>
void SvcWrap32(Core::System& system) {
Handle handle = 0;
const u32 retval = func(system, &handle, Param32(system, 1), Param32(system, 2)).raw;
system.CurrentArmInterface().SetReg(1, handle);
FuncReturn(system, retval);
}
// Used by ControlCodeMemory32
template <Result func(Core::System&, Handle, u32, u64, u64, Svc::MemoryPermission)>
void SvcWrap32(Core::System& system) {
const u32 retval =
func(system, Param32(system, 0), Param32(system, 1), Param(system, 2), Param(system, 4),
static_cast<Svc::MemoryPermission>(Param32(system, 6)))
.raw;
FuncReturn(system, retval);
}
// Used by Invalidate/Store/FlushProcessDataCache32
template <Result func(Core::System&, Handle, u64, u64)>
void SvcWrap32(Core::System& system) {
const u64 address = (Param(system, 3) << 32) | Param(system, 2);
const u64 size = (Param(system, 4) << 32) | Param(system, 1);
FuncReturn32(system, func(system, Param32(system, 0), address, size).raw);
}
} // namespace Kernel

View File

@@ -762,7 +762,7 @@ Result Module::Interface::InitializeApplicationInfoBase() {
// processes emulated. As we don't actually have pid support we should assume we're just using
// our own process
const auto launch_property =
system.GetARPManager().GetLaunchProperty(system.GetCurrentProcessProgramID());
system.GetARPManager().GetLaunchProperty(system.GetApplicationProcessProgramID());
if (launch_property.Failed()) {
LOG_ERROR(Service_ACC, "Failed to get launch property");
@@ -806,7 +806,7 @@ void Module::Interface::IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx
bool is_locked = false;
if (res != Loader::ResultStatus::Success) {
const FileSys::PatchManager pm{system.GetCurrentProcessProgramID(),
const FileSys::PatchManager pm{system.GetApplicationProcessProgramID(),
system.GetFileSystemController(),
system.GetContentProvider()};
const auto nacp_unique = pm.GetControlMetadata().first;

View File

@@ -79,7 +79,7 @@ IWindowController::IWindowController(Core::System& system_)
IWindowController::~IWindowController() = default;
void IWindowController::GetAppletResourceUserId(Kernel::HLERequestContext& ctx) {
const u64 process_id = system.CurrentProcess()->GetProcessID();
const u64 process_id = system.ApplicationProcess()->GetProcessID();
LOG_DEBUG(Service_AM, "called. Process ID=0x{:016X}", process_id);
@@ -1252,7 +1252,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex
}
auto transfer_mem =
system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle);
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle);
if (transfer_mem.IsNull()) {
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
@@ -1286,7 +1286,7 @@ void ILibraryAppletCreator::CreateHandleStorage(Kernel::HLERequestContext& ctx)
}
auto transfer_mem =
system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle);
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle);
if (transfer_mem.IsNull()) {
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
@@ -1465,11 +1465,12 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
const auto backend = BCAT::CreateBackendFromSettings(system, [this](u64 tid) {
return system.GetFileSystemController().GetBCATDirectory(tid);
});
const auto build_id_full = system.GetCurrentProcessBuildID();
const auto build_id_full = system.GetApplicationProcessBuildID();
u64 build_id{};
std::memcpy(&build_id, build_id_full.data(), sizeof(u64));
auto data = backend->GetLaunchParameter({system.GetCurrentProcessProgramID(), build_id});
auto data =
backend->GetLaunchParameter({system.GetApplicationProcessProgramID(), build_id});
if (data.has_value()) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
@@ -1521,7 +1522,7 @@ void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]);
FileSys::SaveDataAttribute attribute{};
attribute.title_id = system.GetCurrentProcessProgramID();
attribute.title_id = system.GetApplicationProcessProgramID();
attribute.user_id = user_id;
attribute.type = FileSys::SaveDataType::SaveData;
const auto res = system.GetFileSystemController().CreateSaveData(
@@ -1551,7 +1552,7 @@ void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) {
std::array<u8, 0x10> version_string{};
const auto res = [this] {
const auto title_id = system.GetCurrentProcessProgramID();
const auto title_id = system.GetApplicationProcessProgramID();
const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
system.GetContentProvider()};
@@ -1588,7 +1589,7 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
u32 supported_languages = 0;
const auto res = [this] {
const auto title_id = system.GetCurrentProcessProgramID();
const auto title_id = system.GetApplicationProcessProgramID();
const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
system.GetContentProvider()};
@@ -1696,7 +1697,8 @@ void IApplicationFunctions::ExtendSaveData(Kernel::HLERequestContext& ctx) {
static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size);
system.GetFileSystemController().WriteSaveDataSize(
type, system.GetCurrentProcessProgramID(), user_id, {new_normal_size, new_journal_size});
type, system.GetApplicationProcessProgramID(), user_id,
{new_normal_size, new_journal_size});
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
@@ -1720,7 +1722,7 @@ void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) {
user_id[0]);
const auto size = system.GetFileSystemController().ReadSaveDataSize(
type, system.GetCurrentProcessProgramID(), user_id);
type, system.GetApplicationProcessProgramID(), user_id);
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);

View File

@@ -166,7 +166,7 @@ void Error::Execute() {
}
const auto callback = [this] { DisplayCompleted(); };
const auto title_id = system.GetCurrentProcessProgramID();
const auto title_id = system.GetApplicationProcessProgramID();
const auto& reporter{system.GetReporter()};
switch (mode) {

View File

@@ -186,7 +186,7 @@ void PhotoViewer::Execute() {
const auto callback = [this] { ViewFinished(); };
switch (mode) {
case PhotoViewerAppletMode::CurrentApp:
frontend.ShowPhotosForApplication(system.GetCurrentProcessProgramID(), callback);
frontend.ShowPhotosForApplication(system.GetApplicationProcessProgramID(), callback);
break;
case PhotoViewerAppletMode::AllApps:
frontend.ShowAllPhotos(callback);

View File

@@ -393,7 +393,7 @@ void WebBrowser::InitializeOffline() {
switch (document_kind) {
case DocumentKind::OfflineHtmlPage:
default:
title_id = system.GetCurrentProcessProgramID();
title_id = system.GetApplicationProcessProgramID();
nca_type = FileSys::ContentRecordType::HtmlDocument;
additional_paths = "html-document";
break;

View File

@@ -155,7 +155,7 @@ void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
const auto current = system.GetCurrentProcessProgramID();
const auto current = system.GetApplicationProcessProgramID();
const auto& disabled = Settings::values.disabled_addons[current];
if (std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end()) {
@@ -182,7 +182,7 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AOC, "called with offset={}, count={}, process_id={}", offset, count,
process_id);
const auto current = system.GetCurrentProcessProgramID();
const auto current = system.GetApplicationProcessProgramID();
std::vector<u32> out;
const auto& disabled = Settings::values.disabled_addons[current];
@@ -228,7 +228,7 @@ void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
const auto title_id = system.GetCurrentProcessProgramID();
const auto title_id = system.GetApplicationProcessProgramID();
const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
system.GetContentProvider()};

View File

@@ -455,7 +455,7 @@ void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
return;
}
const auto& handle_table{system.CurrentProcess()->GetHandleTable()};
const auto& handle_table{system.ApplicationProcess()->GetHandleTable()};
auto process{handle_table.GetObject<Kernel::KProcess>(process_handle)};
auto transfer_memory{
process->GetHandleTable().GetObject<Kernel::KTransferMemory>(transfer_memory_handle)};

View File

@@ -176,8 +176,8 @@ private:
void RequestSyncDeliveryCache(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_BCAT, "called");
backend.Synchronize({system.GetCurrentProcessProgramID(),
GetCurrentBuildID(system.GetCurrentProcessBuildID())},
backend.Synchronize({system.GetApplicationProcessProgramID(),
GetCurrentBuildID(system.GetApplicationProcessBuildID())},
GetProgressBackend(SyncType::Normal));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -193,8 +193,8 @@ private:
LOG_DEBUG(Service_BCAT, "called, name={}", name);
backend.SynchronizeDirectory({system.GetCurrentProcessProgramID(),
GetCurrentBuildID(system.GetCurrentProcessBuildID())},
backend.SynchronizeDirectory({system.GetApplicationProcessProgramID(),
GetCurrentBuildID(system.GetApplicationProcessBuildID())},
name, GetProgressBackend(SyncType::Directory));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -554,7 +554,7 @@ private:
void Module::Interface::CreateDeliveryCacheStorageService(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_BCAT, "called");
const auto title_id = system.GetCurrentProcessProgramID();
const auto title_id = system.GetApplicationProcessProgramID();
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IDeliveryCacheStorageService>(system, fsc.GetBCATDirectory(title_id));

View File

@@ -63,7 +63,7 @@ enum class FatalType : u32 {
};
static void GenerateErrorReport(Core::System& system, Result error_code, const FatalInfo& info) {
const auto title_id = system.GetCurrentProcessProgramID();
const auto title_id = system.GetApplicationProcessProgramID();
std::string crash_report = fmt::format(
"Yuzu {}-{} crash report\n"
"Title ID: {:016x}\n"

View File

@@ -317,7 +317,7 @@ ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFSCurrentProcess()
return ResultUnknown;
}
return romfs_factory->OpenCurrentProcess(system.GetCurrentProcessProgramID());
return romfs_factory->OpenCurrentProcess(system.GetApplicationProcessProgramID());
}
ResultVal<FileSys::VirtualFile> FileSystemController::OpenPatchedRomFS(
@@ -502,7 +502,7 @@ FileSys::SaveDataSize FileSystemController::ReadSaveDataSize(FileSys::SaveDataTy
const auto res = system.GetAppLoader().ReadControlData(nacp);
if (res != Loader::ResultStatus::Success) {
const FileSys::PatchManager pm{system.GetCurrentProcessProgramID(),
const FileSys::PatchManager pm{system.GetApplicationProcessProgramID(),
system.GetFileSystemController(),
system.GetContentProvider()};
const auto metadata = pm.GetControlMetadata();

View File

@@ -1036,8 +1036,9 @@ void FSP_SRV::OpenDataStorageWithProgramIndex(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called, program_index={}", program_index);
auto patched_romfs = fsc.OpenPatchedRomFSWithProgramIndex(
system.GetCurrentProcessProgramID(), program_index, FileSys::ContentRecordType::Program);
auto patched_romfs =
fsc.OpenPatchedRomFSWithProgramIndex(system.GetApplicationProcessProgramID(), program_index,
FileSys::ContentRecordType::Program);
if (patched_romfs.Failed()) {
// TODO: Find the right error code to use here
@@ -1083,7 +1084,7 @@ void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
}
void FSP_SRV::OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx) {
const auto raw = ctx.ReadBuffer();
const auto raw = ctx.ReadBufferCopy();
auto log = Common::StringFromFixedZeroTerminatedBuffer(
reinterpret_cast<const char*>(raw.data()), raw.size());

View File

@@ -428,6 +428,9 @@ void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) {
return;
}
// This function is unique to yuzu for the turbo buttons to work properly
controller.device->TurboButtonUpdate();
auto& pad_entry = controller.npad_pad_state;
auto& trigger_entry = controller.npad_trigger_state;
const auto button_state = controller.device->GetNpadButtons();
@@ -755,12 +758,20 @@ Core::HID::NpadStyleTag Controller_NPad::GetSupportedStyleSet() const {
return hid_core.GetSupportedStyleTag();
}
void Controller_NPad::SetSupportedNpadIdTypes(std::span<const u8> data) {
Result Controller_NPad::SetSupportedNpadIdTypes(std::span<const u8> data) {
constexpr std::size_t max_number_npad_ids = 0xa;
const auto length = data.size();
ASSERT(length > 0 && (length % sizeof(u32)) == 0);
const std::size_t elements = length / sizeof(u32);
if (elements > max_number_npad_ids) {
return InvalidArraySize;
}
supported_npad_id_types.clear();
supported_npad_id_types.resize(length / sizeof(u32));
supported_npad_id_types.resize(elements);
std::memcpy(supported_npad_id_types.data(), data.data(), length);
return ResultSuccess;
}
void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) {
@@ -1121,7 +1132,8 @@ Result Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) {
return ResultSuccess;
}
Result Controller_NPad::SetGyroscopeZeroDriftMode(
const Core::HID::SixAxisSensorHandle& sixaxis_handle, GyroscopeZeroDriftMode drift_mode) {
const Core::HID::SixAxisSensorHandle& sixaxis_handle,
Core::HID::GyroscopeZeroDriftMode drift_mode) {
const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
if (is_valid.IsError()) {
LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
@@ -1129,14 +1141,16 @@ Result Controller_NPad::SetGyroscopeZeroDriftMode(
}
auto& sixaxis = GetSixaxisState(sixaxis_handle);
auto& controller = GetControllerFromHandle(sixaxis_handle);
sixaxis.gyroscope_zero_drift_mode = drift_mode;
controller.device->SetGyroscopeZeroDriftMode(drift_mode);
return ResultSuccess;
}
Result Controller_NPad::GetGyroscopeZeroDriftMode(
const Core::HID::SixAxisSensorHandle& sixaxis_handle,
GyroscopeZeroDriftMode& drift_mode) const {
Core::HID::GyroscopeZeroDriftMode& drift_mode) const {
const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
if (is_valid.IsError()) {
LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);

View File

@@ -52,13 +52,6 @@ public:
// When the controller is requesting a motion update for the shared memory
void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) override;
// This is nn::hid::GyroscopeZeroDriftMode
enum class GyroscopeZeroDriftMode : u32 {
Loose = 0,
Standard = 1,
Tight = 2,
};
// This is nn::hid::NpadJoyHoldType
enum class NpadJoyHoldType : u64 {
Vertical = 0,
@@ -96,7 +89,7 @@ public:
void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set);
Core::HID::NpadStyleTag GetSupportedStyleSet() const;
void SetSupportedNpadIdTypes(std::span<const u8> data);
Result SetSupportedNpadIdTypes(std::span<const u8> data);
void GetSupportedNpadIdTypes(u32* data, std::size_t max_length);
std::size_t GetSupportedNpadIdTypesSize() const;
@@ -146,9 +139,9 @@ public:
Result DisconnectNpad(Core::HID::NpadIdType npad_id);
Result SetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
GyroscopeZeroDriftMode drift_mode);
Core::HID::GyroscopeZeroDriftMode drift_mode);
Result GetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
GyroscopeZeroDriftMode& drift_mode) const;
Core::HID::GyroscopeZeroDriftMode& drift_mode) const;
Result IsSixAxisSensorAtRest(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
bool& is_at_rest) const;
Result IsFirmwareUpdateAvailableForSixAxisSensor(
@@ -489,7 +482,8 @@ private:
Core::HID::SixAxisSensorFusionParameters fusion{};
Core::HID::SixAxisSensorCalibrationParameter calibration{};
Core::HID::SixAxisSensorIcInformation ic_information{};
GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard};
Core::HID::GyroscopeZeroDriftMode gyroscope_zero_drift_mode{
Core::HID::GyroscopeZeroDriftMode::Standard};
};
struct NpadControllerData {

View File

@@ -18,6 +18,7 @@ constexpr Result NpadIsDualJoycon{ErrorModule::HID, 601};
constexpr Result NpadIsSameType{ErrorModule::HID, 602};
constexpr Result InvalidNpadId{ErrorModule::HID, 709};
constexpr Result NpadNotConnected{ErrorModule::HID, 710};
constexpr Result InvalidArraySize{ErrorModule::HID, 715};
constexpr Result InvalidPalmaHandle{ErrorModule::HID, 3302};
} // namespace Service::HID

View File

@@ -712,7 +712,7 @@ void Hid::ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) {
void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto sixaxis_handle{rp.PopRaw<Core::HID::SixAxisSensorHandle>()};
const auto drift_mode{rp.PopEnum<Controller_NPad::GyroscopeZeroDriftMode>()};
const auto drift_mode{rp.PopEnum<Core::HID::GyroscopeZeroDriftMode>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
@@ -739,7 +739,7 @@ void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()};
auto drift_mode{Controller_NPad::GyroscopeZeroDriftMode::Standard};
auto drift_mode{Core::HID::GyroscopeZeroDriftMode::Standard};
auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
const auto result = controller.GetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode);
@@ -764,7 +764,7 @@ void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()};
const auto drift_mode{Controller_NPad::GyroscopeZeroDriftMode::Standard};
const auto drift_mode{Core::HID::GyroscopeZeroDriftMode::Standard};
auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
const auto result = controller.SetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode);
@@ -1025,13 +1025,13 @@ void Hid::SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad)
.SetSupportedNpadIdTypes(ctx.ReadBuffer());
const auto result = applet_resource->GetController<Controller_NPad>(HidController::NPad)
.SetSupportedNpadIdTypes(ctx.ReadBuffer());
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
rb.Push(result);
}
void Hid::ActivateNpad(Kernel::HLERequestContext& ctx) {
@@ -1830,7 +1830,7 @@ void Hid::InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx) {
ASSERT_MSG(t_mem_1_size == 0x1000, "t_mem_1_size is not 0x1000 bytes");
ASSERT_MSG(t_mem_2_size == 0x7F000, "t_mem_2_size is not 0x7F000 bytes");
auto t_mem_1 = system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
auto t_mem_1 = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
t_mem_1_handle);
if (t_mem_1.IsNull()) {
@@ -1840,7 +1840,7 @@ void Hid::InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx) {
return;
}
auto t_mem_2 = system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
auto t_mem_2 = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
t_mem_2_handle);
if (t_mem_2.IsNull()) {
@@ -2127,8 +2127,8 @@ void Hid::WritePalmaWaveEntry(Kernel::HLERequestContext& ctx) {
ASSERT_MSG(t_mem_size == 0x3000, "t_mem_size is not 0x3000 bytes");
auto t_mem =
system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(t_mem_handle);
auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
t_mem_handle);
if (t_mem.IsNull()) {
LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);

View File

@@ -449,8 +449,8 @@ void HidBus::EnableJoyPollingReceiveMode(Kernel::HLERequestContext& ctx) {
ASSERT_MSG(t_mem_size == 0x1000, "t_mem_size is not 0x1000 bytes");
auto t_mem =
system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(t_mem_handle);
auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
t_mem_handle);
if (t_mem.IsNull()) {
LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);

Some files were not shown because too many files have changed in this diff Show More