2022-04-23 04:59:50 -04:00
|
|
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2014-04-10 19:58:28 -04:00
|
|
|
|
2018-01-11 22:36:56 -05:00
|
|
|
#include <algorithm>
|
2018-02-25 07:40:22 -05:00
|
|
|
#include <cinttypes>
|
2018-04-19 22:36:48 -04:00
|
|
|
#include <iterator>
|
2018-07-31 08:06:09 -04:00
|
|
|
#include <mutex>
|
|
|
|
#include <vector>
|
2018-01-11 22:36:56 -05:00
|
|
|
|
2018-10-18 12:55:27 -04:00
|
|
|
#include "common/alignment.h"
|
2018-07-31 08:06:09 -04:00
|
|
|
#include "common/assert.h"
|
2020-12-30 04:14:02 -05:00
|
|
|
#include "common/common_funcs.h"
|
2020-02-27 18:12:41 -05:00
|
|
|
#include "common/fiber.h"
|
2015-05-06 03:06:12 -04:00
|
|
|
#include "common/logging/log.h"
|
2021-01-31 19:55:11 -05:00
|
|
|
#include "common/scope_exit.h"
|
2018-03-13 17:49:59 -04:00
|
|
|
#include "core/core.h"
|
2016-09-17 20:38:01 -04:00
|
|
|
#include "core/core_timing.h"
|
2022-06-14 21:03:14 -04:00
|
|
|
#include "core/debugger/debugger.h"
|
2021-04-22 00:43:25 -04:00
|
|
|
#include "core/hle/kernel/k_client_port.h"
|
2021-04-13 20:48:37 -04:00
|
|
|
#include "core/hle/kernel/k_client_session.h"
|
2021-12-05 15:04:08 -05:00
|
|
|
#include "core/hle/kernel/k_code_memory.h"
|
2021-01-31 04:38:57 -05:00
|
|
|
#include "core/hle/kernel/k_event.h"
|
2021-04-24 05:40:31 -04:00
|
|
|
#include "core/hle/kernel/k_handle_table.h"
|
2021-02-12 20:02:51 -05:00
|
|
|
#include "core/hle/kernel/k_memory_block.h"
|
2021-02-12 19:02:35 -05:00
|
|
|
#include "core/hle/kernel/k_memory_layout.h"
|
2021-02-12 20:58:31 -05:00
|
|
|
#include "core/hle/kernel/k_page_table.h"
|
2022-10-16 01:53:56 -04:00
|
|
|
#include "core/hle/kernel/k_port.h"
|
2021-04-24 01:04:28 -04:00
|
|
|
#include "core/hle/kernel/k_process.h"
|
2021-01-30 01:48:06 -05:00
|
|
|
#include "core/hle/kernel/k_readable_event.h"
|
2021-01-30 04:40:49 -05:00
|
|
|
#include "core/hle/kernel/k_resource_limit.h"
|
2020-12-02 21:08:35 -05:00
|
|
|
#include "core/hle/kernel/k_scheduler.h"
|
2021-02-04 20:06:54 -05:00
|
|
|
#include "core/hle/kernel/k_scoped_resource_reservation.h"
|
2022-10-03 22:52:52 -04:00
|
|
|
#include "core/hle/kernel/k_session.h"
|
2021-02-06 02:14:31 -05:00
|
|
|
#include "core/hle/kernel/k_shared_memory.h"
|
2020-12-22 01:36:53 -05:00
|
|
|
#include "core/hle/kernel/k_synchronization_object.h"
|
2020-12-31 02:01:08 -05:00
|
|
|
#include "core/hle/kernel/k_thread.h"
|
2021-11-10 00:02:29 -05:00
|
|
|
#include "core/hle/kernel/k_thread_queue.h"
|
2021-04-17 03:52:53 -04:00
|
|
|
#include "core/hle/kernel/k_transfer_memory.h"
|
2018-08-31 12:21:34 -04:00
|
|
|
#include "core/hle/kernel/kernel.h"
|
2020-02-25 12:22:11 -05:00
|
|
|
#include "core/hle/kernel/physical_core.h"
|
2018-01-02 20:40:30 -05:00
|
|
|
#include "core/hle/kernel/svc.h"
|
2020-12-30 04:14:02 -05:00
|
|
|
#include "core/hle/kernel/svc_results.h"
|
2020-03-26 21:13:46 -04:00
|
|
|
#include "core/hle/kernel/svc_types.h"
|
2018-01-02 20:40:30 -05:00
|
|
|
#include "core/hle/kernel/svc_wrap.h"
|
2014-10-22 23:20:01 -04:00
|
|
|
#include "core/hle/result.h"
|
svc: Handle memory writing explicitly within QueryProcessMemory
Moves the memory writes directly into QueryProcessMemory instead of
letting the wrapper function do it. It would be inaccurate to allow the
handler to do it because there's cases where memory shouldn't even be
written to. For example, if the given process handle is invalid.
HOWEVER, if the memory writing is within the wrapper, then we have no
control over if these memory writes occur, meaning in an error case, 68
bytes of memory randomly get trashed with zeroes, 64 of those being
written to wherever the memory info address points to, and the remaining
4 being written wherever the page info address points to.
One solution in this case would be to just conditionally check within
the handler itself, but this is kind of smelly, given the handler
shouldn't be performing conditional behavior itself, it's a behavior of
the managed function. In other words, if you remove the handler from the
equation entirely, does the function still retain its proper behavior?
In this case, no.
Now, we don't potentially trash memory from this function if an invalid
query is performed.
2018-12-12 11:48:06 -05:00
|
|
|
#include "core/memory.h"
|
2019-05-17 21:46:17 -04:00
|
|
|
#include "core/reporter.h"
|
2014-04-10 19:58:28 -04:00
|
|
|
|
2020-03-26 20:00:30 -04:00
|
|
|
namespace Kernel::Svc {
|
2018-09-13 19:14:50 -04:00
|
|
|
namespace {
|
2018-10-10 14:18:27 -04:00
|
|
|
|
|
|
|
// 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.
|
2022-06-25 23:44:19 -04:00
|
|
|
Result MapUnmapMemorySanityChecks(const KPageTable& manager, VAddr dst_addr, VAddr src_addr,
|
|
|
|
u64 size) {
|
2018-11-26 03:47:39 -05:00
|
|
|
if (!Common::Is4KBAligned(dst_addr)) {
|
|
|
|
LOG_ERROR(Kernel_SVC, "Destination address is not aligned to 4KB, 0x{:016X}", dst_addr);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidAddress;
|
2018-10-10 14:18:27 -04:00
|
|
|
}
|
|
|
|
|
2018-11-26 03:47:39 -05:00
|
|
|
if (!Common::Is4KBAligned(src_addr)) {
|
|
|
|
LOG_ERROR(Kernel_SVC, "Source address is not aligned to 4KB, 0x{:016X}", src_addr);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidSize;
|
2018-11-26 03:47:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if (size == 0) {
|
|
|
|
LOG_ERROR(Kernel_SVC, "Size is 0");
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidSize;
|
2018-11-26 03:47:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!Common::Is4KBAligned(size)) {
|
|
|
|
LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:016X}", size);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidSize;
|
2018-10-10 14:18:27 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!IsValidAddressRange(dst_addr, size)) {
|
2018-11-26 03:47:39 -05:00
|
|
|
LOG_ERROR(Kernel_SVC,
|
|
|
|
"Destination is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
|
|
|
|
dst_addr, size);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidCurrentMemory;
|
2018-10-10 14:18:27 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!IsValidAddressRange(src_addr, size)) {
|
2018-11-26 03:47:39 -05:00
|
|
|
LOG_ERROR(Kernel_SVC, "Source is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
|
|
|
|
src_addr, size);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidCurrentMemory;
|
2018-10-10 14:18:27 -04:00
|
|
|
}
|
|
|
|
|
2020-04-08 23:14:18 -04:00
|
|
|
if (!manager.IsInsideAddressSpace(src_addr, size)) {
|
2018-11-26 03:47:39 -05:00
|
|
|
LOG_ERROR(Kernel_SVC,
|
|
|
|
"Source is not within the address space, addr=0x{:016X}, size=0x{:016X}",
|
|
|
|
src_addr, size);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidCurrentMemory;
|
2018-10-10 14:18:27 -04:00
|
|
|
}
|
|
|
|
|
2020-04-08 23:14:18 -04:00
|
|
|
if (manager.IsOutsideStackRegion(dst_addr, size)) {
|
2018-11-26 03:47:39 -05:00
|
|
|
LOG_ERROR(Kernel_SVC,
|
2019-07-06 02:02:01 -04:00
|
|
|
"Destination is not within the stack region, addr=0x{:016X}, size=0x{:016X}",
|
2018-11-26 03:47:39 -05:00
|
|
|
dst_addr, size);
|
2021-04-11 14:41:48 -04:00
|
|
|
return ResultInvalidMemoryRegion;
|
2018-10-10 14:18:27 -04:00
|
|
|
}
|
|
|
|
|
2020-04-08 23:14:18 -04:00
|
|
|
if (manager.IsInsideHeapRegion(dst_addr, size)) {
|
2018-11-26 03:47:39 -05:00
|
|
|
LOG_ERROR(Kernel_SVC,
|
|
|
|
"Destination does not fit within the heap region, addr=0x{:016X}, "
|
2020-04-08 23:14:18 -04:00
|
|
|
"size=0x{:016X}",
|
|
|
|
dst_addr, size);
|
2021-04-11 14:41:48 -04:00
|
|
|
return ResultInvalidMemoryRegion;
|
2018-10-10 14:18:27 -04:00
|
|
|
}
|
|
|
|
|
2020-04-08 23:14:18 -04:00
|
|
|
if (manager.IsInsideAliasRegion(dst_addr, size)) {
|
2018-11-26 03:47:39 -05:00
|
|
|
LOG_ERROR(Kernel_SVC,
|
|
|
|
"Destination does not fit within the map region, addr=0x{:016X}, "
|
2020-04-08 23:14:18 -04:00
|
|
|
"size=0x{:016X}",
|
|
|
|
dst_addr, size);
|
2021-04-11 14:41:48 -04:00
|
|
|
return ResultInvalidMemoryRegion;
|
2018-10-10 14:18:27 -04:00
|
|
|
}
|
|
|
|
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-10-10 14:18:27 -04:00
|
|
|
}
|
2018-11-26 19:14:29 -05:00
|
|
|
|
|
|
|
enum class ResourceLimitValueType {
|
|
|
|
CurrentValue,
|
|
|
|
LimitValue,
|
2021-02-12 19:05:24 -05:00
|
|
|
PeakValue,
|
2018-11-26 19:14:29 -05:00
|
|
|
};
|
|
|
|
|
2018-09-13 19:14:50 -04:00
|
|
|
} // Anonymous namespace
|
2014-04-10 23:26:12 -04:00
|
|
|
|
2017-12-28 15:29:52 -05:00
|
|
|
/// Set the process heap to a given Size. It can both extend and shrink the heap.
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result SetHeapSize(Core::System& system, VAddr* out_address, u64 size) {
|
2021-12-28 03:18:41 -05:00
|
|
|
LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", size);
|
2018-09-13 19:09:04 -04:00
|
|
|
|
2021-12-28 03:18:41 -05:00
|
|
|
// Validate size.
|
|
|
|
R_UNLESS(Common::IsAligned(size, HeapSizeAlignment), ResultInvalidSize);
|
|
|
|
R_UNLESS(size < MainMemorySizeMax, ResultInvalidSize);
|
2020-04-08 23:14:18 -04:00
|
|
|
|
2021-12-28 03:18:41 -05:00
|
|
|
// Set the heap size.
|
|
|
|
R_TRY(system.Kernel().CurrentProcess()->PageTable().SetHeapSize(out_address, size));
|
2018-12-27 18:31:31 -05:00
|
|
|
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2017-12-28 15:29:52 -05:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result SetHeapSize32(Core::System& system, u32* heap_addr, u32 heap_size) {
|
2020-03-02 00:06:41 -05:00
|
|
|
VAddr temp_heap_addr{};
|
2022-06-25 23:44:19 -04:00
|
|
|
const Result result{SetHeapSize(system, &temp_heap_addr, heap_size)};
|
2020-03-02 00:06:41 -05:00
|
|
|
*heap_addr = static_cast<u32>(temp_heap_addr);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-12-23 04:10:36 -05:00
|
|
|
constexpr bool IsValidSetMemoryPermission(MemoryPermission perm) {
|
|
|
|
switch (perm) {
|
|
|
|
case MemoryPermission::None:
|
|
|
|
case MemoryPermission::Read:
|
|
|
|
case MemoryPermission::ReadWrite:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result SetMemoryPermission(Core::System& system, VAddr address, u64 size,
|
|
|
|
MemoryPermission perm) {
|
2022-01-08 06:16:59 -05:00
|
|
|
LOG_DEBUG(Kernel_SVC, "called, address=0x{:016X}, size=0x{:X}, perm=0x{:08X", address, size,
|
|
|
|
perm);
|
|
|
|
|
2021-12-23 04:10:36 -05:00
|
|
|
// 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 = system.Kernel().CurrentProcess()->PageTable();
|
|
|
|
R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
|
|
|
|
|
|
|
|
// Set the memory attribute.
|
|
|
|
return page_table.SetMemoryPermission(address, size, perm);
|
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result SetMemoryAttribute(Core::System& system, VAddr address, u64 size, u32 mask,
|
|
|
|
u32 attr) {
|
2018-12-15 15:21:41 -05:00
|
|
|
LOG_DEBUG(Kernel_SVC,
|
|
|
|
"called, address=0x{:016X}, size=0x{:X}, mask=0x{:08X}, attribute=0x{:08X}", address,
|
2022-01-08 06:16:59 -05:00
|
|
|
size, mask, attr);
|
2018-12-15 15:21:41 -05:00
|
|
|
|
2022-01-08 06:16:59 -05:00
|
|
|
// 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);
|
2018-12-15 15:21:41 -05:00
|
|
|
|
2022-01-08 06:16:59 -05:00
|
|
|
// 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);
|
2018-12-15 15:21:41 -05:00
|
|
|
|
2022-01-08 06:16:59 -05:00
|
|
|
// Validate that the region is in range for the current process.
|
2020-04-08 23:14:18 -04:00
|
|
|
auto& page_table{system.Kernel().CurrentProcess()->PageTable()};
|
2022-01-08 06:16:59 -05:00
|
|
|
R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
|
2018-12-15 15:21:41 -05:00
|
|
|
|
2022-01-08 06:16:59 -05:00
|
|
|
// Set the memory attribute.
|
|
|
|
return page_table.SetMemoryAttribute(address, size, mask, attr);
|
2018-01-07 21:23:42 -05:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result SetMemoryAttribute32(Core::System& system, u32 address, u32 size, u32 mask,
|
|
|
|
u32 attr) {
|
2022-01-08 06:16:59 -05:00
|
|
|
return SetMemoryAttribute(system, address, size, mask, attr);
|
2020-06-18 20:33:04 -04:00
|
|
|
}
|
|
|
|
|
2017-12-28 21:38:38 -05:00
|
|
|
/// Maps a memory range into a different range.
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result MapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) {
|
2018-07-02 12:13:26 -04:00
|
|
|
LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
|
2018-07-02 12:20:50 -04:00
|
|
|
src_addr, size);
|
2018-09-13 19:14:50 -04:00
|
|
|
|
2020-04-08 23:14:18 -04:00
|
|
|
auto& page_table{system.Kernel().CurrentProcess()->PageTable()};
|
2018-12-27 18:31:31 -05:00
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
if (const Result result{MapUnmapMemorySanityChecks(page_table, dst_addr, src_addr, size)};
|
2020-04-08 23:14:18 -04:00
|
|
|
result.IsError()) {
|
2018-10-10 14:18:27 -04:00
|
|
|
return result;
|
2018-09-13 19:14:50 -04:00
|
|
|
}
|
|
|
|
|
2022-01-15 01:55:12 -05:00
|
|
|
return page_table.MapMemory(dst_addr, src_addr, size);
|
2017-12-28 21:38:38 -05:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result MapMemory32(Core::System& system, u32 dst_addr, u32 src_addr, u32 size) {
|
2020-12-08 15:38:28 -05:00
|
|
|
return MapMemory(system, dst_addr, src_addr, size);
|
2020-06-19 19:40:07 -04:00
|
|
|
}
|
|
|
|
|
2017-12-31 15:22:49 -05:00
|
|
|
/// Unmaps a region that was previously mapped with svcMapMemory
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) {
|
2018-07-02 12:13:26 -04:00
|
|
|
LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
|
2018-07-02 12:20:50 -04:00
|
|
|
src_addr, size);
|
2018-09-13 19:14:50 -04:00
|
|
|
|
2020-04-08 23:14:18 -04:00
|
|
|
auto& page_table{system.Kernel().CurrentProcess()->PageTable()};
|
2018-12-27 18:31:31 -05:00
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
if (const Result result{MapUnmapMemorySanityChecks(page_table, dst_addr, src_addr, size)};
|
2020-04-08 23:14:18 -04:00
|
|
|
result.IsError()) {
|
2018-10-10 14:18:27 -04:00
|
|
|
return result;
|
2018-09-13 19:14:50 -04:00
|
|
|
}
|
|
|
|
|
2022-01-15 01:55:12 -05:00
|
|
|
return page_table.UnmapMemory(dst_addr, src_addr, size);
|
2017-12-31 15:22:49 -05:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result UnmapMemory32(Core::System& system, u32 dst_addr, u32 src_addr, u32 size) {
|
2020-12-08 15:38:28 -05:00
|
|
|
return UnmapMemory(system, dst_addr, src_addr, size);
|
2020-06-19 19:40:07 -04:00
|
|
|
}
|
|
|
|
|
2022-10-03 22:52:52 -04:00
|
|
|
template <typename T>
|
|
|
|
Result CreateSession(Core::System& system, Handle* out_server, Handle* out_client, u64 name) {
|
|
|
|
auto& process = *system.CurrentProcess();
|
|
|
|
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
|
2022-11-03 10:22:05 -04:00
|
|
|
KScopedResourceReservation session_reservation(&process, LimitableResource::SessionCountMax);
|
2022-10-03 22:52:52 -04:00
|
|
|
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.
|
2022-11-03 10:22:05 -04:00
|
|
|
// system.Kernel().GetSystemResourceLimit().Reserve(LimitableResource::SessionCountMax, 1);
|
2022-10-03 22:52:52 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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()));
|
|
|
|
|
2022-10-11 18:16:56 -04:00
|
|
|
// Add the client session to the handle table.
|
2022-10-03 22:52:52 -04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Result CreateSession(Core::System& system, Handle* out_server, Handle* out_client,
|
|
|
|
u32 is_light, u64 name) {
|
|
|
|
if (is_light) {
|
|
|
|
// return CreateSession<KLightSession>(system, out_server, out_client, name);
|
|
|
|
return ResultUnknown;
|
|
|
|
} else {
|
|
|
|
return CreateSession<KSession>(system, out_server, out_client, name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-12 21:55:36 -04:00
|
|
|
/// Connect to an OS service given the port name, returns the handle to the port to out
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result ConnectToNamedPort(Core::System& system, Handle* out, VAddr port_name_address) {
|
2019-11-26 15:48:19 -05:00
|
|
|
auto& memory = system.Memory();
|
|
|
|
if (!memory.IsValidVirtualAddress(port_name_address)) {
|
2018-11-26 03:47:39 -05:00
|
|
|
LOG_ERROR(Kernel_SVC,
|
|
|
|
"Port Name Address is not a valid virtual address, port_name_address=0x{:016X}",
|
|
|
|
port_name_address);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultNotFound;
|
2018-09-02 11:58:58 -04:00
|
|
|
}
|
2017-10-14 17:30:07 -04:00
|
|
|
|
|
|
|
static constexpr std::size_t PortNameMaxLength = 11;
|
|
|
|
// Read 1 char beyond the max allowed port name to detect names that are too long.
|
2019-11-26 15:48:19 -05:00
|
|
|
const std::string port_name = memory.ReadCString(port_name_address, PortNameMaxLength + 1);
|
2018-09-02 11:58:58 -04:00
|
|
|
if (port_name.size() > PortNameMaxLength) {
|
2018-11-26 03:47:39 -05:00
|
|
|
LOG_ERROR(Kernel_SVC, "Port name is too long, expected {} but got {}", PortNameMaxLength,
|
|
|
|
port_name.size());
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultOutOfRange;
|
2018-09-02 11:58:58 -04:00
|
|
|
}
|
2014-06-01 20:48:29 -04:00
|
|
|
|
2018-07-02 12:13:26 -04:00
|
|
|
LOG_TRACE(Kernel_SVC, "called port_name={}", port_name);
|
2014-06-01 20:48:29 -04:00
|
|
|
|
2021-04-23 20:00:15 -04:00
|
|
|
// Get the current handle table.
|
2019-04-06 18:46:18 -04:00
|
|
|
auto& kernel = system.Kernel();
|
2021-04-23 20:00:15 -04:00
|
|
|
auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
|
|
|
|
|
|
|
|
// Find the client port.
|
2021-05-10 18:58:33 -04:00
|
|
|
auto port = kernel.CreateNamedServicePort(port_name);
|
|
|
|
if (!port) {
|
|
|
|
LOG_ERROR(Kernel_SVC, "tried to connect to unknown port: {}", port_name);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultNotFound;
|
2015-01-30 13:07:04 -05:00
|
|
|
}
|
2014-06-01 20:48:29 -04:00
|
|
|
|
2021-04-24 05:54:16 -04:00
|
|
|
// 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); });
|
|
|
|
|
2021-04-23 20:00:15 -04:00
|
|
|
// Create a session.
|
|
|
|
KClientSession* session{};
|
2022-10-16 01:53:56 -04:00
|
|
|
R_TRY(port->CreateSession(std::addressof(session)));
|
2016-06-14 19:03:30 -04:00
|
|
|
|
2022-10-16 01:53:56 -04:00
|
|
|
kernel.RegisterNamedServiceHandler(port_name, &port->GetParent()->GetServerPort());
|
|
|
|
|
2021-04-23 20:00:15 -04:00
|
|
|
// Register the session in the table, close the extra reference.
|
2021-04-24 05:54:16 -04:00
|
|
|
handle_table.Register(*out, session);
|
2021-04-23 20:00:15 -04:00
|
|
|
session->Close();
|
2016-06-14 19:03:30 -04:00
|
|
|
|
2021-04-23 20:00:15 -04:00
|
|
|
// We succeeded.
|
2021-04-24 05:54:16 -04:00
|
|
|
handle_guard.Cancel();
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2014-04-12 21:55:36 -04:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result ConnectToNamedPort32(Core::System& system, Handle* out_handle,
|
|
|
|
u32 port_name_address) {
|
2020-03-02 00:06:41 -05:00
|
|
|
|
|
|
|
return ConnectToNamedPort(system, out_handle, port_name_address);
|
|
|
|
}
|
|
|
|
|
2022-10-11 18:16:56 -04:00
|
|
|
/// Makes a blocking IPC call to a service.
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result SendSyncRequest(Core::System& system, Handle handle) {
|
2020-12-02 21:08:35 -05:00
|
|
|
auto& kernel = system.Kernel();
|
2014-05-26 22:12:46 -04:00
|
|
|
|
2021-11-10 00:02:29 -05:00
|
|
|
// Create the wait queue.
|
|
|
|
KThreadQueue wait_queue(kernel);
|
|
|
|
|
2021-11-26 18:35:11 -05:00
|
|
|
// Get the client session from its handle.
|
|
|
|
KScopedAutoObject session =
|
|
|
|
kernel.CurrentProcess()->GetHandleTable().GetObject<KClientSession>(handle);
|
|
|
|
R_UNLESS(session.IsNotNull(), ResultInvalidHandle);
|
|
|
|
|
|
|
|
LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());
|
|
|
|
|
2022-10-11 18:16:56 -04:00
|
|
|
return session->SendSyncRequest();
|
2014-04-10 19:58:28 -04:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result SendSyncRequest32(Core::System& system, Handle handle) {
|
2020-03-02 00:06:41 -05:00
|
|
|
return SendSyncRequest(system, handle);
|
|
|
|
}
|
|
|
|
|
2022-10-11 18:16:56 -04:00
|
|
|
static Result ReplyAndReceive(Core::System& system, s32* out_index, Handle* handles,
|
|
|
|
s32 num_handles, Handle reply_target, s64 timeout_ns) {
|
|
|
|
auto& kernel = system.Kernel();
|
|
|
|
auto& handle_table = GetCurrentThread(kernel).GetOwnerProcess()->GetHandleTable();
|
|
|
|
|
|
|
|
// Convert handle list to object table.
|
|
|
|
std::vector<KSynchronizationObject*> objs(num_handles);
|
|
|
|
R_UNLESS(
|
|
|
|
handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles, 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());
|
|
|
|
|
|
|
|
Result rc = session->SendReply();
|
|
|
|
if (!R_SUCCEEDED(rc)) {
|
|
|
|
*out_index = -1;
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-23 00:15:45 -04:00
|
|
|
/// Get the ID for the specified thread.
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result GetThreadId(Core::System& system, u64* out_thread_id, Handle thread_handle) {
|
2021-01-20 16:42:27 -05:00
|
|
|
// Get the thread from its handle.
|
2021-04-03 22:11:46 -04:00
|
|
|
KScopedAutoObject thread =
|
|
|
|
system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
|
|
|
|
R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
|
2017-10-23 00:15:45 -04:00
|
|
|
|
2021-01-20 16:42:27 -05:00
|
|
|
// Get the thread's id.
|
2021-04-03 22:11:46 -04:00
|
|
|
*out_thread_id = thread->GetId();
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2017-10-23 00:15:45 -04:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result GetThreadId32(Core::System& system, u32* out_thread_id_low, u32* out_thread_id_high,
|
|
|
|
Handle thread_handle) {
|
2021-01-20 16:42:27 -05:00
|
|
|
u64 out_thread_id{};
|
2022-06-25 23:44:19 -04:00
|
|
|
const Result result{GetThreadId(system, &out_thread_id, thread_handle)};
|
2020-03-02 00:06:41 -05:00
|
|
|
|
2021-01-20 16:42:27 -05:00
|
|
|
*out_thread_id_low = static_cast<u32>(out_thread_id >> 32);
|
|
|
|
*out_thread_id_high = static_cast<u32>(out_thread_id & std::numeric_limits<u32>::max());
|
2020-03-02 00:06:41 -05:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-12-18 23:09:08 -05:00
|
|
|
/// Gets the ID of the specified process or a specified thread's owning process.
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result GetProcessId(Core::System& system, u64* out_process_id, Handle handle) {
|
2021-04-11 15:49:18 -04:00
|
|
|
LOG_DEBUG(Kernel_SVC, "called handle=0x{:08X}", handle);
|
|
|
|
|
|
|
|
// Get the object from the handle table.
|
|
|
|
KScopedAutoObject obj =
|
|
|
|
system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KAutoObject>(
|
|
|
|
static_cast<Handle>(handle));
|
|
|
|
R_UNLESS(obj.IsNotNull(), ResultInvalidHandle);
|
|
|
|
|
|
|
|
// Get the process from the object.
|
2021-04-24 01:04:28 -04:00
|
|
|
KProcess* process = nullptr;
|
|
|
|
if (KProcess* p = obj->DynamicCast<KProcess*>(); p != nullptr) {
|
2021-04-11 15:49:18 -04:00
|
|
|
// 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();
|
|
|
|
|
2022-02-03 14:36:13 -05:00
|
|
|
return ResultSuccess;
|
2017-10-23 00:15:45 -04:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result GetProcessId32(Core::System& system, u32* out_process_id_low,
|
|
|
|
u32* out_process_id_high, Handle handle) {
|
2021-04-11 15:49:18 -04:00
|
|
|
u64 out_process_id{};
|
|
|
|
const auto result = GetProcessId(system, &out_process_id, handle);
|
|
|
|
*out_process_id_low = static_cast<u32>(out_process_id);
|
|
|
|
*out_process_id_high = static_cast<u32>(out_process_id >> 32);
|
2020-06-19 19:40:07 -04:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-01-01 14:47:57 -05:00
|
|
|
/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result WaitSynchronization(Core::System& system, s32* index, VAddr handles_address,
|
|
|
|
s32 num_handles, s64 nano_seconds) {
|
2021-04-18 02:38:20 -04:00
|
|
|
LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, num_handles={}, nano_seconds={}",
|
|
|
|
handles_address, num_handles, nano_seconds);
|
2018-01-06 14:34:32 -05:00
|
|
|
|
2021-04-18 02:38:20 -04:00
|
|
|
// Ensure number of handles is valid.
|
|
|
|
R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange);
|
2018-01-06 14:34:32 -05:00
|
|
|
|
2020-02-11 16:36:39 -05:00
|
|
|
auto& kernel = system.Kernel();
|
2021-04-18 02:38:20 -04:00
|
|
|
std::vector<KSynchronizationObject*> objs(num_handles);
|
2020-02-11 16:36:39 -05:00
|
|
|
const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
|
2021-04-18 02:38:20 -04:00
|
|
|
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);
|
2021-10-25 06:55:20 -04:00
|
|
|
for (const auto& obj : objs) {
|
|
|
|
kernel.RegisterInUseObject(obj);
|
|
|
|
}
|
2021-04-18 02:38:20 -04:00
|
|
|
}
|
2018-01-06 14:34:32 -05:00
|
|
|
|
2021-04-18 02:38:20 -04:00
|
|
|
// Ensure handles are closed when we're done.
|
|
|
|
SCOPE_EXIT({
|
2021-11-02 22:04:20 -04:00
|
|
|
for (s32 i = 0; i < num_handles; ++i) {
|
2021-10-25 06:55:20 -04:00
|
|
|
kernel.UnregisterInUseObject(objs[i]);
|
2021-04-18 02:38:20 -04:00
|
|
|
objs[i]->Close();
|
2018-07-24 09:55:15 -04:00
|
|
|
}
|
2021-04-18 02:38:20 -04:00
|
|
|
});
|
2018-07-24 09:55:15 -04:00
|
|
|
|
2021-04-18 02:38:20 -04:00
|
|
|
return KSynchronizationObject::Wait(kernel, index, objs.data(), static_cast<s32>(objs.size()),
|
|
|
|
nano_seconds);
|
2018-01-01 14:47:57 -05:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result WaitSynchronization32(Core::System& system, u32 timeout_low, u32 handles_address,
|
|
|
|
s32 num_handles, u32 timeout_high, s32* index) {
|
2020-03-02 00:06:41 -05:00
|
|
|
const s64 nano_seconds{(static_cast<s64>(timeout_high) << 32) | static_cast<s64>(timeout_low)};
|
2021-04-18 02:38:20 -04:00
|
|
|
return WaitSynchronization(system, index, handles_address, num_handles, nano_seconds);
|
2020-03-02 00:06:41 -05:00
|
|
|
}
|
|
|
|
|
2018-01-09 15:02:04 -05:00
|
|
|
/// Resumes a thread waiting on WaitSynchronization
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result CancelSynchronization(Core::System& system, Handle handle) {
|
2021-04-11 15:49:18 -04:00
|
|
|
LOG_TRACE(Kernel_SVC, "called handle=0x{:X}", handle);
|
|
|
|
|
|
|
|
// Get the thread from its handle.
|
|
|
|
KScopedAutoObject thread =
|
2021-06-09 18:24:46 -04:00
|
|
|
system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(handle);
|
|
|
|
R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
|
2021-04-11 15:49:18 -04:00
|
|
|
|
|
|
|
// Cancel the thread's wait.
|
|
|
|
thread->WaitCancel();
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-01-09 15:02:04 -05:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result CancelSynchronization32(Core::System& system, Handle handle) {
|
2021-04-11 15:49:18 -04:00
|
|
|
return CancelSynchronization(system, handle);
|
2020-06-19 19:40:07 -04:00
|
|
|
}
|
|
|
|
|
2020-12-30 04:14:02 -05:00
|
|
|
/// Attempts to locks a mutex
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result ArbitrateLock(Core::System& system, Handle thread_handle, VAddr address, u32 tag) {
|
2020-12-30 04:14:02 -05:00
|
|
|
LOG_TRACE(Kernel_SVC, "called thread_handle=0x{:08X}, address=0x{:X}, tag=0x{:08X}",
|
|
|
|
thread_handle, address, tag);
|
2018-01-01 14:02:26 -05:00
|
|
|
|
2020-12-30 04:14:02 -05:00
|
|
|
// Validate the input address.
|
2021-02-12 19:02:35 -05:00
|
|
|
if (IsKernelAddress(address)) {
|
2021-02-03 22:33:27 -05:00
|
|
|
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;
|
|
|
|
}
|
2018-09-17 18:49:51 -04:00
|
|
|
|
2020-12-30 04:14:02 -05:00
|
|
|
return system.Kernel().CurrentProcess()->WaitForAddress(thread_handle, address, tag);
|
2018-01-01 14:02:26 -05:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result ArbitrateLock32(Core::System& system, Handle thread_handle, u32 address, u32 tag) {
|
2020-12-30 04:14:02 -05:00
|
|
|
return ArbitrateLock(system, thread_handle, address, tag);
|
2020-06-19 19:40:07 -04:00
|
|
|
}
|
|
|
|
|
2018-01-01 14:04:36 -05:00
|
|
|
/// Unlock a mutex
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result ArbitrateUnlock(Core::System& system, VAddr address) {
|
2020-12-30 04:14:02 -05:00
|
|
|
LOG_TRACE(Kernel_SVC, "called address=0x{:X}", address);
|
2018-01-01 14:04:36 -05:00
|
|
|
|
2020-12-30 04:14:02 -05:00
|
|
|
// Validate the input address.
|
2021-02-12 19:02:35 -05:00
|
|
|
if (IsKernelAddress(address)) {
|
2021-02-03 22:33:27 -05:00
|
|
|
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;
|
|
|
|
}
|
2018-10-18 13:01:26 -04:00
|
|
|
|
2020-12-30 04:14:02 -05:00
|
|
|
return system.Kernel().CurrentProcess()->SignalToAddress(address);
|
2018-01-01 14:04:36 -05:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result ArbitrateUnlock32(Core::System& system, u32 address) {
|
2020-12-30 04:14:02 -05:00
|
|
|
return ArbitrateUnlock(system, address);
|
2020-06-19 19:40:07 -04:00
|
|
|
}
|
|
|
|
|
2017-10-14 17:30:07 -04:00
|
|
|
/// Break program execution
|
2019-04-06 18:46:18 -04:00
|
|
|
static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) {
|
2022-11-03 10:22:05 -04:00
|
|
|
BreakReason break_reason =
|
|
|
|
static_cast<BreakReason>(reason & ~static_cast<u32>(BreakReason::NotificationOnlyFlag));
|
|
|
|
bool notification_only = (reason & static_cast<u32>(BreakReason::NotificationOnlyFlag)) != 0;
|
|
|
|
|
2018-11-07 23:43:54 -05:00
|
|
|
bool has_dumped_buffer{};
|
2019-05-17 21:46:17 -04:00
|
|
|
std::vector<u8> debug_buffer;
|
2018-10-23 00:03:59 -04:00
|
|
|
|
2018-11-07 23:43:54 -05:00
|
|
|
const auto handle_debug_buffer = [&](VAddr addr, u64 sz) {
|
|
|
|
if (sz == 0 || addr == 0 || has_dumped_buffer) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-11-26 16:29:34 -05:00
|
|
|
auto& memory = system.Memory();
|
|
|
|
|
2018-11-07 23:43:54 -05:00
|
|
|
// This typically is an error code so we're going to assume this is the case
|
|
|
|
if (sz == sizeof(u32)) {
|
2019-11-26 16:29:34 -05:00
|
|
|
LOG_CRITICAL(Debug_Emulated, "debug_buffer_err_code={:X}", memory.Read32(addr));
|
2018-11-07 23:43:54 -05:00
|
|
|
} else {
|
|
|
|
// We don't know what's in here so we'll hexdump it
|
2019-05-17 21:46:17 -04:00
|
|
|
debug_buffer.resize(sz);
|
2019-11-26 16:29:34 -05:00
|
|
|
memory.ReadBlock(addr, debug_buffer.data(), sz);
|
2018-11-07 23:43:54 -05:00
|
|
|
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;
|
|
|
|
};
|
2022-11-03 10:22:05 -04:00
|
|
|
switch (break_reason) {
|
|
|
|
case BreakReason::Panic:
|
|
|
|
LOG_CRITICAL(Debug_Emulated, "Userspace PANIC! info1=0x{:016X}, info2=0x{:016X}", info1,
|
|
|
|
info2);
|
2018-11-07 23:43:54 -05:00
|
|
|
handle_debug_buffer(info1, info2);
|
2018-10-23 00:17:13 -04:00
|
|
|
break;
|
2022-11-03 10:22:05 -04:00
|
|
|
case BreakReason::Assert:
|
|
|
|
LOG_CRITICAL(Debug_Emulated, "Userspace Assertion failed! info1=0x{:016X}, info2=0x{:016X}",
|
2018-10-23 00:17:13 -04:00
|
|
|
info1, info2);
|
2018-11-07 23:43:54 -05:00
|
|
|
handle_debug_buffer(info1, info2);
|
2018-10-23 00:03:59 -04:00
|
|
|
break;
|
2022-11-03 10:22:05 -04:00
|
|
|
case BreakReason::User:
|
|
|
|
LOG_WARNING(Debug_Emulated, "Userspace Break! 0x{:016X} with size 0x{:016X}", info1, info2);
|
|
|
|
handle_debug_buffer(info1, info2);
|
2018-10-23 00:03:59 -04:00
|
|
|
break;
|
2022-11-03 10:22:05 -04:00
|
|
|
case BreakReason::PreLoadDll:
|
|
|
|
LOG_INFO(Debug_Emulated,
|
|
|
|
"Userspace Attempting to load an NRO at 0x{:016X} with size 0x{:016X}", info1,
|
|
|
|
info2);
|
2018-10-23 00:03:59 -04:00
|
|
|
break;
|
2022-11-03 10:22:05 -04:00
|
|
|
case BreakReason::PostLoadDll:
|
|
|
|
LOG_INFO(Debug_Emulated, "Userspace Loaded an NRO at 0x{:016X} with size 0x{:016X}", info1,
|
|
|
|
info2);
|
2018-10-23 00:03:59 -04:00
|
|
|
break;
|
2022-11-03 10:22:05 -04:00
|
|
|
case BreakReason::PreUnloadDll:
|
|
|
|
LOG_INFO(Debug_Emulated,
|
|
|
|
"Userspace Attempting to unload an NRO at 0x{:016X} with size 0x{:016X}", info1,
|
|
|
|
info2);
|
2018-10-23 00:03:59 -04:00
|
|
|
break;
|
2022-11-03 10:22:05 -04:00
|
|
|
case BreakReason::PostUnloadDll:
|
|
|
|
LOG_INFO(Debug_Emulated, "Userspace Unloaded an NRO at 0x{:016X} with size 0x{:016X}",
|
|
|
|
info1, info2);
|
|
|
|
break;
|
|
|
|
case BreakReason::CppException:
|
2019-01-26 21:19:04 -05:00
|
|
|
LOG_CRITICAL(Debug_Emulated, "Signalling debugger. Uncaught C++ exception encountered.");
|
|
|
|
break;
|
2018-10-23 00:03:59 -04:00
|
|
|
default:
|
2018-10-23 00:17:13 -04:00
|
|
|
LOG_WARNING(
|
|
|
|
Debug_Emulated,
|
2022-11-03 10:22:05 -04:00
|
|
|
"Signalling debugger, Unknown break reason {:#X}, info1=0x{:016X}, info2=0x{:016X}",
|
|
|
|
reason, info1, info2);
|
2018-11-07 23:43:54 -05:00
|
|
|
handle_debug_buffer(info1, info2);
|
2018-10-23 00:03:59 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-11-03 10:22:05 -04:00
|
|
|
system.GetReporter().SaveSvcBreakReport(reason, notification_only, info1, info2,
|
|
|
|
has_dumped_buffer ? std::make_optional(debug_buffer)
|
|
|
|
: std::nullopt);
|
2019-05-17 21:46:17 -04:00
|
|
|
|
2022-11-03 10:22:05 -04:00
|
|
|
if (!notification_only) {
|
2018-10-08 21:11:14 -04:00
|
|
|
LOG_CRITICAL(
|
2018-10-08 20:10:30 -04:00
|
|
|
Debug_Emulated,
|
|
|
|
"Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}",
|
|
|
|
reason, info1, info2);
|
2019-04-06 18:46:18 -04:00
|
|
|
|
2018-11-07 23:43:54 -05:00
|
|
|
handle_debug_buffer(info1, info2);
|
2019-04-06 18:46:18 -04:00
|
|
|
|
2022-06-16 10:35:52 -04:00
|
|
|
auto* const current_thread = GetCurrentThreadPointer(system.Kernel());
|
2021-01-20 16:42:27 -05:00
|
|
|
const auto thread_processor_id = current_thread->GetActiveCore();
|
2019-04-06 18:46:18 -04:00
|
|
|
system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace();
|
2018-10-08 20:10:30 -04:00
|
|
|
}
|
2022-06-14 21:03:14 -04:00
|
|
|
|
|
|
|
if (system.DebuggerEnabled()) {
|
|
|
|
auto* thread = system.Kernel().GetCurrentEmuThread();
|
|
|
|
system.GetDebugger().NotifyThreadStopped(thread);
|
|
|
|
thread->RequestSuspend(Kernel::SuspendType::Debug);
|
|
|
|
}
|
2014-04-16 20:41:33 -04:00
|
|
|
}
|
|
|
|
|
2020-06-19 19:40:07 -04:00
|
|
|
static void Break32(Core::System& system, u32 reason, u32 info1, u32 info2) {
|
2020-12-08 15:38:28 -05:00
|
|
|
Break(system, reason, info1, info2);
|
2020-06-19 19:40:07 -04:00
|
|
|
}
|
|
|
|
|
2017-10-14 17:30:07 -04:00
|
|
|
/// Used to output a message on a debug hardware unit - does nothing on a retail unit
|
2020-11-23 10:17:18 -05:00
|
|
|
static void OutputDebugString(Core::System& system, VAddr address, u64 len) {
|
2018-09-12 04:51:41 -04:00
|
|
|
if (len == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-04-25 19:11:22 -04:00
|
|
|
std::string str(len, '\0');
|
2019-11-26 16:29:34 -05:00
|
|
|
system.Memory().ReadBlock(address, str.data(), str.size());
|
2018-07-02 12:13:26 -04:00
|
|
|
LOG_DEBUG(Debug_Emulated, "{}", str);
|
2014-05-17 23:37:25 -04:00
|
|
|
}
|
|
|
|
|
2022-02-08 13:46:45 -05:00
|
|
|
static void OutputDebugString32(Core::System& system, u32 address, u32 len) {
|
|
|
|
OutputDebugString(system, address, len);
|
|
|
|
}
|
|
|
|
|
2018-01-01 16:01:06 -05:00
|
|
|
/// Gets system/memory information for the current process
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result GetInfo(Core::System& system, u64* result, u64 info_id, Handle handle,
|
|
|
|
u64 info_sub_id) {
|
2018-07-02 12:13:26 -04:00
|
|
|
LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id,
|
2018-07-02 12:20:50 -04:00
|
|
|
info_sub_id, handle);
|
2018-01-01 16:01:06 -05:00
|
|
|
|
2022-12-15 14:52:25 -05:00
|
|
|
const auto info_id_type = static_cast<InfoType>(info_id);
|
2018-01-10 00:58:25 -05:00
|
|
|
|
2018-12-02 01:37:15 -05:00
|
|
|
switch (info_id_type) {
|
2022-12-15 14:52:25 -05:00
|
|
|
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: {
|
2018-12-02 01:37:15 -05:00
|
|
|
if (info_sub_id != 0) {
|
2020-04-29 00:53:53 -04:00
|
|
|
LOG_ERROR(Kernel_SVC, "Info sub id is non zero! info_id={}, info_sub_id={}", info_id,
|
|
|
|
info_sub_id);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidEnumValue;
|
2018-12-02 01:37:15 -05:00
|
|
|
}
|
|
|
|
|
2021-04-18 01:21:59 -04:00
|
|
|
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
2021-04-24 01:04:28 -04:00
|
|
|
KScopedAutoObject process = handle_table.GetObject<KProcess>(handle);
|
2021-04-18 01:21:59 -04:00
|
|
|
if (process.IsNull()) {
|
2020-04-29 00:53:53 -04:00
|
|
|
LOG_ERROR(Kernel_SVC, "Process is not valid! info_id={}, info_sub_id={}, handle={:08X}",
|
|
|
|
info_id, info_sub_id, handle);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidHandle;
|
2018-12-02 01:37:15 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (info_id_type) {
|
2022-12-15 14:52:25 -05:00
|
|
|
case InfoType::CoreMask:
|
2018-12-30 21:09:00 -05:00
|
|
|
*result = process->GetCoreMask();
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-12-02 01:37:15 -05:00
|
|
|
|
2022-12-15 14:52:25 -05:00
|
|
|
case InfoType::PriorityMask:
|
2018-12-30 21:09:00 -05:00
|
|
|
*result = process->GetPriorityMask();
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-12-02 01:37:15 -05:00
|
|
|
|
2022-12-15 14:52:25 -05:00
|
|
|
case InfoType::AliasRegionAddress:
|
2020-04-08 23:14:18 -04:00
|
|
|
*result = process->PageTable().GetAliasRegionStart();
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-12-02 01:37:15 -05:00
|
|
|
|
2022-12-15 14:52:25 -05:00
|
|
|
case InfoType::AliasRegionSize:
|
2020-04-08 23:14:18 -04:00
|
|
|
*result = process->PageTable().GetAliasRegionSize();
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-12-02 01:37:15 -05:00
|
|
|
|
2022-12-15 14:52:25 -05:00
|
|
|
case InfoType::HeapRegionAddress:
|
2020-04-08 23:14:18 -04:00
|
|
|
*result = process->PageTable().GetHeapRegionStart();
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-12-02 01:37:15 -05:00
|
|
|
|
2022-12-15 14:52:25 -05:00
|
|
|
case InfoType::HeapRegionSize:
|
2020-04-08 23:14:18 -04:00
|
|
|
*result = process->PageTable().GetHeapRegionSize();
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-12-02 01:37:15 -05:00
|
|
|
|
2022-12-15 14:52:25 -05:00
|
|
|
case InfoType::AslrRegionAddress:
|
2020-04-08 23:14:18 -04:00
|
|
|
*result = process->PageTable().GetAliasCodeRegionStart();
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-12-02 01:37:15 -05:00
|
|
|
|
2022-12-15 14:52:25 -05:00
|
|
|
case InfoType::AslrRegionSize:
|
2020-04-08 23:14:18 -04:00
|
|
|
*result = process->PageTable().GetAliasCodeRegionSize();
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-12-02 01:37:15 -05:00
|
|
|
|
2022-12-15 14:52:25 -05:00
|
|
|
case InfoType::StackRegionAddress:
|
2020-04-08 23:14:18 -04:00
|
|
|
*result = process->PageTable().GetStackRegionStart();
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-12-02 01:37:15 -05:00
|
|
|
|
2022-12-15 14:52:25 -05:00
|
|
|
case InfoType::StackRegionSize:
|
2020-04-08 23:14:18 -04:00
|
|
|
*result = process->PageTable().GetStackRegionSize();
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-12-02 01:37:15 -05:00
|
|
|
|
2022-12-15 14:52:25 -05:00
|
|
|
case InfoType::TotalMemorySize:
|
2019-06-09 18:20:20 -04:00
|
|
|
*result = process->GetTotalPhysicalMemoryAvailable();
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-12-02 01:37:15 -05:00
|
|
|
|
2022-12-15 14:52:25 -05:00
|
|
|
case InfoType::UsedMemorySize:
|
2019-03-28 22:59:17 -04:00
|
|
|
*result = process->GetTotalPhysicalMemoryUsed();
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-12-02 01:37:15 -05:00
|
|
|
|
2022-12-15 14:52:25 -05:00
|
|
|
case InfoType::SystemResourceSizeTotal:
|
2019-07-07 12:42:54 -04:00
|
|
|
*result = process->GetSystemResourceSize();
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2019-07-07 12:42:54 -04:00
|
|
|
|
2022-12-15 14:52:25 -05:00
|
|
|
case InfoType::SystemResourceSizeUsed:
|
2019-07-07 15:08:29 -04:00
|
|
|
LOG_WARNING(Kernel_SVC, "(STUBBED) Attempted to query system resource usage");
|
2019-07-07 14:48:11 -04:00
|
|
|
*result = process->GetSystemResourceUsage();
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-12-02 01:37:15 -05:00
|
|
|
|
2022-12-15 14:52:25 -05:00
|
|
|
case InfoType::ProgramId:
|
2021-11-03 14:15:51 -04:00
|
|
|
*result = process->GetProgramID();
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-12-02 01:37:15 -05:00
|
|
|
|
2022-12-15 14:52:25 -05:00
|
|
|
case InfoType::UserExceptionContextAddress:
|
2022-10-02 17:26:30 -04:00
|
|
|
*result = process->GetProcessLocalRegionAddress();
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-12-02 01:37:15 -05:00
|
|
|
|
2022-12-15 14:52:25 -05:00
|
|
|
case InfoType::TotalNonSystemMemorySize:
|
2019-07-07 14:48:11 -04:00
|
|
|
*result = process->GetTotalPhysicalMemoryAvailableWithoutSystemResource();
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2019-06-09 18:20:20 -04:00
|
|
|
|
2022-12-15 14:52:25 -05:00
|
|
|
case InfoType::UsedNonSystemMemorySize:
|
2019-07-07 14:48:11 -04:00
|
|
|
*result = process->GetTotalPhysicalMemoryUsedWithoutSystemResource();
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2019-06-09 18:20:20 -04:00
|
|
|
|
2022-12-15 14:52:25 -05:00
|
|
|
case InfoType::FreeThreadCount:
|
2022-12-15 14:22:07 -05:00
|
|
|
*result = process->GetFreeThreadCount();
|
|
|
|
return ResultSuccess;
|
|
|
|
|
2018-12-02 01:37:15 -05:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-04-28 11:17:59 -04:00
|
|
|
LOG_ERROR(Kernel_SVC, "Unimplemented svcGetInfo id=0x{:016X}", info_id);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidEnumValue;
|
2018-12-02 01:37:15 -05:00
|
|
|
}
|
|
|
|
|
2022-12-15 14:52:25 -05:00
|
|
|
case InfoType::DebuggerAttached:
|
2018-02-04 12:34:45 -05:00
|
|
|
*result = 0;
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-12-02 01:37:15 -05:00
|
|
|
|
2022-12-15 14:52:25 -05:00
|
|
|
case InfoType::ResourceLimit: {
|
2018-12-04 00:29:15 -05:00
|
|
|
if (handle != 0) {
|
2020-04-29 00:53:53 -04:00
|
|
|
LOG_ERROR(Kernel, "Handle is non zero! handle={:08X}", handle);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidHandle;
|
2018-12-04 00:29:15 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if (info_sub_id != 0) {
|
2020-04-29 00:53:53 -04:00
|
|
|
LOG_ERROR(Kernel, "Info sub id is non zero! info_id={}, info_sub_id={}", info_id,
|
|
|
|
info_sub_id);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidCombination;
|
2018-12-04 00:29:15 -05:00
|
|
|
}
|
|
|
|
|
2021-04-24 01:04:28 -04:00
|
|
|
KProcess* const current_process = system.Kernel().CurrentProcess();
|
2021-04-24 05:40:31 -04:00
|
|
|
KHandleTable& handle_table = current_process->GetHandleTable();
|
2018-12-04 00:29:15 -05:00
|
|
|
const auto resource_limit = current_process->GetResourceLimit();
|
|
|
|
if (!resource_limit) {
|
2021-04-24 05:40:31 -04:00
|
|
|
*result = Svc::InvalidHandle;
|
2018-12-04 00:29:15 -05:00
|
|
|
// Yes, the kernel considers this a successful operation.
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-12-04 00:29:15 -05:00
|
|
|
}
|
|
|
|
|
2021-05-16 01:46:30 -04:00
|
|
|
Handle resource_handle{};
|
|
|
|
R_TRY(handle_table.Add(&resource_handle, resource_limit));
|
2018-12-04 00:29:15 -05:00
|
|
|
|
2021-05-16 01:46:30 -04:00
|
|
|
*result = resource_handle;
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-12-04 00:29:15 -05:00
|
|
|
}
|
|
|
|
|
2022-12-15 14:52:25 -05:00
|
|
|
case InfoType::RandomEntropy:
|
2018-11-13 12:25:43 -05:00
|
|
|
if (handle != 0) {
|
2018-11-26 03:47:39 -05:00
|
|
|
LOG_ERROR(Kernel_SVC, "Process Handle is non zero, expected 0 result but got {:016X}",
|
|
|
|
handle);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidHandle;
|
2018-11-13 12:25:43 -05:00
|
|
|
}
|
|
|
|
|
2021-04-24 01:04:28 -04:00
|
|
|
if (info_sub_id >= KProcess::RANDOM_ENTROPY_SIZE) {
|
2018-11-26 03:47:39 -05:00
|
|
|
LOG_ERROR(Kernel_SVC, "Entropy size is out of range, expected {} but got {}",
|
2021-04-24 01:04:28 -04:00
|
|
|
KProcess::RANDOM_ENTROPY_SIZE, info_sub_id);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidCombination;
|
2018-11-13 12:25:43 -05:00
|
|
|
}
|
|
|
|
|
2019-04-06 18:46:18 -04:00
|
|
|
*result = system.Kernel().CurrentProcess()->GetRandomEntropy(info_sub_id);
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-12-02 01:37:15 -05:00
|
|
|
|
2022-12-15 14:52:25 -05:00
|
|
|
case InfoType::InitialProcessIdRange:
|
2018-07-02 12:13:26 -04:00
|
|
|
LOG_WARNING(Kernel_SVC,
|
2018-07-02 12:20:50 -04:00
|
|
|
"(STUBBED) Attempted to query privileged process id bounds, returned 0");
|
2018-01-15 15:42:57 -05:00
|
|
|
*result = 0;
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-12-02 01:37:15 -05:00
|
|
|
|
2022-12-15 14:52:25 -05:00
|
|
|
case InfoType::ThreadTickCount: {
|
2018-10-25 18:42:50 -04:00
|
|
|
constexpr u64 num_cpus = 4;
|
|
|
|
if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) {
|
2018-11-26 03:47:39 -05:00
|
|
|
LOG_ERROR(Kernel_SVC, "Core count is out of range, expected {} but got {}", num_cpus,
|
|
|
|
info_sub_id);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidCombination;
|
2018-10-25 18:42:50 -04:00
|
|
|
}
|
|
|
|
|
2021-04-03 22:11:46 -04:00
|
|
|
KScopedAutoObject thread =
|
|
|
|
system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(
|
|
|
|
static_cast<Handle>(handle));
|
|
|
|
if (thread.IsNull()) {
|
2018-11-26 03:47:39 -05:00
|
|
|
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}",
|
|
|
|
static_cast<Handle>(handle));
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidHandle;
|
2018-10-25 18:42:50 -04:00
|
|
|
}
|
|
|
|
|
2019-02-14 12:42:58 -05:00
|
|
|
const auto& core_timing = system.CoreTiming();
|
2020-12-02 21:08:35 -05:00
|
|
|
const auto& scheduler = *system.Kernel().CurrentScheduler();
|
2022-06-16 10:35:52 -04:00
|
|
|
const auto* const current_thread = GetCurrentThreadPointer(system.Kernel());
|
2021-04-03 22:11:46 -04:00
|
|
|
const bool same_thread = current_thread == thread.GetPointerUnsafe();
|
2018-10-25 18:42:50 -04:00
|
|
|
|
2022-06-26 18:52:16 -04:00
|
|
|
const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTime();
|
2018-10-25 18:42:50 -04:00
|
|
|
u64 out_ticks = 0;
|
|
|
|
if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) {
|
2021-01-20 16:42:27 -05:00
|
|
|
const u64 thread_ticks = current_thread->GetCpuTime();
|
2018-10-25 18:42:50 -04:00
|
|
|
|
2020-02-24 21:04:12 -05:00
|
|
|
out_ticks = thread_ticks + (core_timing.GetCPUTicks() - prev_ctx_ticks);
|
2021-08-07 01:45:18 -04:00
|
|
|
} else if (same_thread && info_sub_id == system.Kernel().CurrentPhysicalCoreIndex()) {
|
2020-02-24 21:04:12 -05:00
|
|
|
out_ticks = core_timing.GetCPUTicks() - prev_ctx_ticks;
|
2018-10-25 18:42:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
*result = out_ticks;
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-10-25 18:42:50 -04:00
|
|
|
}
|
2022-12-15 14:52:25 -05:00
|
|
|
case InfoType::IdleTickCount: {
|
2021-12-22 01:41:23 -05:00
|
|
|
// Verify the input handle is invalid.
|
|
|
|
R_UNLESS(handle == InvalidHandle, ResultInvalidHandle);
|
2018-12-02 01:37:15 -05:00
|
|
|
|
2021-12-22 01:41:23 -05:00
|
|
|
// Verify the requested core is valid.
|
|
|
|
const bool core_valid =
|
2022-04-24 17:40:47 -04:00
|
|
|
(info_sub_id == 0xFFFFFFFFFFFFFFFF) ||
|
2021-12-22 01:41:23 -05:00
|
|
|
(info_sub_id == static_cast<u64>(system.Kernel().CurrentPhysicalCoreIndex()));
|
|
|
|
R_UNLESS(core_valid, ResultInvalidCombination);
|
2021-10-16 05:54:09 -04:00
|
|
|
|
2021-12-22 01:41:23 -05:00
|
|
|
// Get the idle tick count.
|
|
|
|
*result = system.Kernel().CurrentScheduler()->GetIdleThread()->GetCpuTime();
|
2021-10-16 05:54:09 -04:00
|
|
|
return ResultSuccess;
|
|
|
|
}
|
2022-12-15 14:52:25 -05:00
|
|
|
case InfoType::MesosphereCurrentProcess: {
|
2022-06-25 21:00:29 -04:00
|
|
|
// Verify the input handle is invalid.
|
2022-06-20 20:39:10 -04:00
|
|
|
R_UNLESS(handle == InvalidHandle, ResultInvalidHandle);
|
2022-06-25 21:00:29 -04:00
|
|
|
|
|
|
|
// Verify the sub-type is valid.
|
2022-06-20 20:39:10 -04:00
|
|
|
R_UNLESS(info_sub_id == 0, ResultInvalidCombination);
|
|
|
|
|
2022-06-25 21:00:29 -04:00
|
|
|
// Get the handle table.
|
|
|
|
KProcess* current_process = system.Kernel().CurrentProcess();
|
|
|
|
KHandleTable& handle_table = current_process->GetHandleTable();
|
|
|
|
|
|
|
|
// Get a new handle for the current process.
|
|
|
|
Handle tmp;
|
|
|
|
R_TRY(handle_table.Add(&tmp, current_process));
|
2022-06-20 20:39:10 -04:00
|
|
|
|
2022-06-25 21:00:29 -04:00
|
|
|
// Set the output.
|
|
|
|
*result = tmp;
|
2022-06-25 21:01:56 -04:00
|
|
|
|
2022-06-25 21:00:29 -04:00
|
|
|
// We succeeded.
|
2022-06-20 20:39:10 -04:00
|
|
|
return ResultSuccess;
|
2022-06-25 21:01:56 -04:00
|
|
|
}
|
2018-01-01 16:01:06 -05:00
|
|
|
default:
|
2020-04-28 11:17:59 -04:00
|
|
|
LOG_ERROR(Kernel_SVC, "Unimplemented svcGetInfo id=0x{:016X}", info_id);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidEnumValue;
|
2015-05-17 01:06:59 -04:00
|
|
|
}
|
2014-05-01 18:50:36 -04:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result GetInfo32(Core::System& system, u32* result_low, u32* result_high, u32 sub_id_low,
|
|
|
|
u32 info_id, u32 handle, u32 sub_id_high) {
|
2020-12-08 15:38:28 -05:00
|
|
|
const u64 sub_id{u64{sub_id_low} | (u64{sub_id_high} << 32)};
|
2020-03-02 00:06:41 -05:00
|
|
|
u64 res_value{};
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
const Result result{GetInfo(system, &res_value, info_id, handle, sub_id)};
|
2020-03-02 00:06:41 -05:00
|
|
|
*result_high = static_cast<u32>(res_value >> 32);
|
|
|
|
*result_low = static_cast<u32>(res_value & std::numeric_limits<u32>::max());
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-07-07 12:42:54 -04:00
|
|
|
/// Maps memory at a desired address
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result MapPhysicalMemory(Core::System& system, VAddr addr, u64 size) {
|
2019-07-07 12:42:54 -04:00
|
|
|
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);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidAddress;
|
2019-07-07 12:42:54 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!Common::Is4KBAligned(size)) {
|
|
|
|
LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:X}", size);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidSize;
|
2019-07-07 12:42:54 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (size == 0) {
|
|
|
|
LOG_ERROR(Kernel_SVC, "Size is zero");
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidSize;
|
2019-07-07 12:42:54 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!(addr < addr + size)) {
|
|
|
|
LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address");
|
2021-04-11 14:41:48 -04:00
|
|
|
return ResultInvalidMemoryRegion;
|
2019-07-07 12:42:54 -04:00
|
|
|
}
|
|
|
|
|
2021-04-24 01:04:28 -04:00
|
|
|
KProcess* const current_process{system.Kernel().CurrentProcess()};
|
2020-04-08 23:14:18 -04:00
|
|
|
auto& page_table{current_process->PageTable()};
|
2019-07-07 12:42:54 -04:00
|
|
|
|
|
|
|
if (current_process->GetSystemResourceSize() == 0) {
|
|
|
|
LOG_ERROR(Kernel_SVC, "System Resource Size is zero");
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidState;
|
2019-07-07 12:42:54 -04:00
|
|
|
}
|
|
|
|
|
2020-04-08 23:14:18 -04:00
|
|
|
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);
|
2021-04-11 14:41:48 -04:00
|
|
|
return ResultInvalidMemoryRegion;
|
2020-04-08 23:14:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2021-04-11 14:41:48 -04:00
|
|
|
return ResultInvalidMemoryRegion;
|
2019-07-07 12:42:54 -04:00
|
|
|
}
|
|
|
|
|
2020-04-08 23:14:18 -04:00
|
|
|
return page_table.MapPhysicalMemory(addr, size);
|
2019-07-07 12:42:54 -04:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result MapPhysicalMemory32(Core::System& system, u32 addr, u32 size) {
|
2020-12-08 15:38:28 -05:00
|
|
|
return MapPhysicalMemory(system, addr, size);
|
2020-06-19 19:40:07 -04:00
|
|
|
}
|
|
|
|
|
2019-07-07 12:42:54 -04:00
|
|
|
/// Unmaps memory previously mapped via MapPhysicalMemory
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size) {
|
2019-07-07 12:42:54 -04:00
|
|
|
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);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidAddress;
|
2019-07-07 12:42:54 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!Common::Is4KBAligned(size)) {
|
|
|
|
LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:X}", size);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidSize;
|
2019-07-07 12:42:54 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (size == 0) {
|
|
|
|
LOG_ERROR(Kernel_SVC, "Size is zero");
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidSize;
|
2019-07-07 12:42:54 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!(addr < addr + size)) {
|
|
|
|
LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address");
|
2021-04-11 14:41:48 -04:00
|
|
|
return ResultInvalidMemoryRegion;
|
2019-07-07 12:42:54 -04:00
|
|
|
}
|
|
|
|
|
2021-04-24 01:04:28 -04:00
|
|
|
KProcess* const current_process{system.Kernel().CurrentProcess()};
|
2020-04-08 23:14:18 -04:00
|
|
|
auto& page_table{current_process->PageTable()};
|
2019-07-07 12:42:54 -04:00
|
|
|
|
|
|
|
if (current_process->GetSystemResourceSize() == 0) {
|
|
|
|
LOG_ERROR(Kernel_SVC, "System Resource Size is zero");
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidState;
|
2019-07-07 12:42:54 -04:00
|
|
|
}
|
|
|
|
|
2020-04-08 23:14:18 -04:00
|
|
|
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);
|
2021-04-11 14:41:48 -04:00
|
|
|
return ResultInvalidMemoryRegion;
|
2020-04-08 23:14:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2021-04-11 14:41:48 -04:00
|
|
|
return ResultInvalidMemoryRegion;
|
2019-07-07 12:42:54 -04:00
|
|
|
}
|
|
|
|
|
2020-04-08 23:14:18 -04:00
|
|
|
return page_table.UnmapPhysicalMemory(addr, size);
|
2019-07-07 12:42:54 -04:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result UnmapPhysicalMemory32(Core::System& system, u32 addr, u32 size) {
|
2020-12-08 15:38:28 -05:00
|
|
|
return UnmapPhysicalMemory(system, addr, size);
|
2020-06-19 19:40:07 -04:00
|
|
|
}
|
|
|
|
|
2021-01-20 16:42:27 -05:00
|
|
|
/// Sets the thread activity
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result SetThreadActivity(Core::System& system, Handle thread_handle,
|
|
|
|
ThreadActivity thread_activity) {
|
2021-04-11 15:49:18 -04:00
|
|
|
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 =
|
|
|
|
system.Kernel().CurrentProcess()->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() == system.Kernel().CurrentProcess(), ResultInvalidHandle);
|
|
|
|
R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(system.Kernel()), ResultBusy);
|
|
|
|
|
|
|
|
// Set the activity.
|
|
|
|
R_TRY(thread->SetActivity(thread_activity));
|
|
|
|
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-04-02 23:50:17 -04:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result SetThreadActivity32(Core::System& system, Handle thread_handle,
|
|
|
|
Svc::ThreadActivity thread_activity) {
|
2021-01-20 16:42:27 -05:00
|
|
|
return SetThreadActivity(system, thread_handle, thread_activity);
|
2020-06-19 19:40:07 -04:00
|
|
|
}
|
|
|
|
|
2018-04-02 23:50:17 -04:00
|
|
|
/// Gets the thread context
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result GetThreadContext(Core::System& system, VAddr out_context, Handle thread_handle) {
|
2021-01-20 16:42:27 -05:00
|
|
|
LOG_DEBUG(Kernel_SVC, "called, out_context=0x{:08X}, thread_handle=0x{:X}", out_context,
|
|
|
|
thread_handle);
|
2018-09-29 19:58:21 -04:00
|
|
|
|
2021-04-11 15:49:51 -04:00
|
|
|
auto& kernel = system.Kernel();
|
|
|
|
|
|
|
|
// Get the thread from its handle.
|
|
|
|
KScopedAutoObject thread =
|
|
|
|
kernel.CurrentProcess()->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 = kernel.CurrentProcess();
|
|
|
|
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) {
|
2022-06-16 10:35:52 -04:00
|
|
|
if (thread.GetPointerUnsafe() == kernel.Scheduler(i).GetSchedulerCurrentThread()) {
|
2021-04-11 15:49:51 -04:00
|
|
|
current = true;
|
2021-08-19 09:46:30 -04:00
|
|
|
break;
|
2021-04-11 15:49:51 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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());
|
|
|
|
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2021-04-11 15:49:51 -04:00
|
|
|
}
|
2018-09-29 19:58:21 -04:00
|
|
|
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-04-02 23:50:17 -04:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result GetThreadContext32(Core::System& system, u32 out_context, Handle thread_handle) {
|
2021-01-20 16:42:27 -05:00
|
|
|
return GetThreadContext(system, out_context, thread_handle);
|
2020-06-19 19:40:07 -04:00
|
|
|
}
|
|
|
|
|
2014-06-01 22:12:54 -04:00
|
|
|
/// Gets the priority for the specified thread
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result GetThreadPriority(Core::System& system, u32* out_priority, Handle handle) {
|
2018-11-26 01:06:13 -05:00
|
|
|
LOG_TRACE(Kernel_SVC, "called");
|
|
|
|
|
2021-01-20 16:42:27 -05:00
|
|
|
// Get the thread from its handle.
|
2021-04-03 02:53:31 -04:00
|
|
|
KScopedAutoObject thread =
|
|
|
|
system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(handle);
|
|
|
|
R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
|
2017-12-31 16:06:11 -05:00
|
|
|
|
2021-01-20 16:42:27 -05:00
|
|
|
// Get the thread's priority.
|
|
|
|
*out_priority = thread->GetPriority();
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2014-12-03 18:49:51 -05:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result GetThreadPriority32(Core::System& system, u32* out_priority, Handle handle) {
|
2021-01-20 16:42:27 -05:00
|
|
|
return GetThreadPriority(system, out_priority, handle);
|
2020-03-02 00:06:41 -05:00
|
|
|
}
|
|
|
|
|
2017-12-31 15:58:16 -05:00
|
|
|
/// Sets the priority for the specified thread
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result SetThreadPriority(Core::System& system, Handle thread_handle, u32 priority) {
|
2021-04-03 22:11:46 -04:00
|
|
|
// Get the current process.
|
2021-04-24 01:04:28 -04:00
|
|
|
KProcess& process = *system.Kernel().CurrentProcess();
|
2018-11-26 01:06:13 -05:00
|
|
|
|
2021-01-20 16:42:27 -05:00
|
|
|
// Validate the priority.
|
2021-04-03 22:11:46 -04:00
|
|
|
R_UNLESS(HighestThreadPriority <= priority && priority <= LowestThreadPriority,
|
|
|
|
ResultInvalidPriority);
|
|
|
|
R_UNLESS(process.CheckThreadPriority(priority), ResultInvalidPriority);
|
2017-12-31 15:58:16 -05:00
|
|
|
|
2021-01-20 16:42:27 -05:00
|
|
|
// Get the thread from its handle.
|
2021-04-03 22:11:46 -04:00
|
|
|
KScopedAutoObject thread = process.GetHandleTable().GetObject<KThread>(thread_handle);
|
|
|
|
R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
|
2017-12-31 15:58:16 -05:00
|
|
|
|
2021-01-20 16:42:27 -05:00
|
|
|
// Set the thread priority.
|
2020-12-30 04:14:02 -05:00
|
|
|
thread->SetBasePriority(priority);
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2017-12-31 15:58:16 -05:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result SetThreadPriority32(Core::System& system, Handle thread_handle, u32 priority) {
|
2021-04-03 22:11:46 -04:00
|
|
|
return SetThreadPriority(system, thread_handle, priority);
|
2020-06-18 18:15:19 -04:00
|
|
|
}
|
|
|
|
|
2017-12-31 16:01:04 -05:00
|
|
|
/// Get which CPU core is executing the current thread
|
2019-04-06 18:46:18 -04:00
|
|
|
static u32 GetCurrentProcessorNumber(Core::System& system) {
|
2018-07-02 12:13:26 -04:00
|
|
|
LOG_TRACE(Kernel_SVC, "called");
|
2020-02-25 12:22:11 -05:00
|
|
|
return static_cast<u32>(system.CurrentPhysicalCore().CoreIndex());
|
2017-12-31 16:01:04 -05:00
|
|
|
}
|
|
|
|
|
2020-06-18 20:33:04 -04:00
|
|
|
static u32 GetCurrentProcessorNumber32(Core::System& system) {
|
|
|
|
return GetCurrentProcessorNumber(system);
|
|
|
|
}
|
|
|
|
|
2021-11-20 21:54:46 -05:00
|
|
|
namespace {
|
|
|
|
|
2021-04-30 17:53:22 -04:00
|
|
|
constexpr bool IsValidSharedMemoryPermission(Svc::MemoryPermission perm) {
|
|
|
|
switch (perm) {
|
|
|
|
case Svc::MemoryPermission::Read:
|
|
|
|
case Svc::MemoryPermission::ReadWrite:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-20 21:54:46 -05:00
|
|
|
[[maybe_unused]] constexpr bool IsValidRemoteSharedMemoryPermission(Svc::MemoryPermission perm) {
|
2021-04-30 17:53:22 -04:00
|
|
|
return IsValidSharedMemoryPermission(perm) || perm == Svc::MemoryPermission::DontCare;
|
|
|
|
}
|
|
|
|
|
2021-11-20 20:23:59 -05:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-05 15:04:08 -05:00
|
|
|
constexpr bool IsValidMapCodeMemoryPermission(Svc::MemoryPermission perm) {
|
|
|
|
return perm == Svc::MemoryPermission::ReadWrite;
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr bool IsValidMapToOwnerCodeMemoryPermission(Svc::MemoryPermission perm) {
|
|
|
|
return perm == Svc::MemoryPermission::Read || perm == Svc::MemoryPermission::ReadExecute;
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr bool IsValidUnmapCodeMemoryPermission(Svc::MemoryPermission perm) {
|
|
|
|
return perm == Svc::MemoryPermission::None;
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr bool IsValidUnmapFromOwnerCodeMemoryPermission(Svc::MemoryPermission perm) {
|
|
|
|
return perm == Svc::MemoryPermission::None;
|
|
|
|
}
|
|
|
|
|
2021-11-20 21:54:46 -05:00
|
|
|
} // Anonymous namespace
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result MapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address, u64 size,
|
|
|
|
Svc::MemoryPermission map_perm) {
|
2018-07-02 12:20:50 -04:00
|
|
|
LOG_TRACE(Kernel_SVC,
|
|
|
|
"called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}",
|
2021-04-30 17:53:22 -04:00
|
|
|
shmem_handle, address, size, map_perm);
|
2018-01-14 17:15:31 -05:00
|
|
|
|
2021-04-30 17:53:22 -04:00
|
|
|
// 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);
|
2018-09-13 20:16:43 -04:00
|
|
|
|
2021-04-30 17:53:22 -04:00
|
|
|
// Validate the permission.
|
|
|
|
R_UNLESS(IsValidSharedMemoryPermission(map_perm), ResultInvalidNewMemoryPermission);
|
2018-11-26 03:47:39 -05:00
|
|
|
|
2021-04-30 17:53:22 -04:00
|
|
|
// Get the current process.
|
|
|
|
auto& process = *system.Kernel().CurrentProcess();
|
|
|
|
auto& page_table = process.PageTable();
|
2018-09-13 20:16:43 -04:00
|
|
|
|
2021-04-30 17:53:22 -04:00
|
|
|
// Get the shared memory.
|
|
|
|
KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle);
|
|
|
|
R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle);
|
2018-10-17 22:39:21 -04:00
|
|
|
|
2021-04-30 17:53:22 -04:00
|
|
|
// Verify that the mapping is in range.
|
|
|
|
R_UNLESS(page_table.CanContain(address, size, KMemoryState::Shared), ResultInvalidMemoryRegion);
|
2018-09-13 20:16:43 -04:00
|
|
|
|
2021-04-30 17:53:22 -04:00
|
|
|
// Add the shared memory to the process.
|
|
|
|
R_TRY(process.AddSharedMemory(shmem.GetPointerUnsafe(), address, size));
|
2018-01-14 17:15:31 -05:00
|
|
|
|
2021-04-30 17:53:22 -04:00
|
|
|
// Ensure that we clean up the shared memory if we fail to map it.
|
|
|
|
auto guard =
|
|
|
|
SCOPE_GUARD({ process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size); });
|
2018-10-17 22:39:21 -04:00
|
|
|
|
2021-04-30 17:53:22 -04:00
|
|
|
// Map the shared memory.
|
|
|
|
R_TRY(shmem->Map(process, address, size, map_perm));
|
2018-09-13 20:16:43 -04:00
|
|
|
|
2021-04-30 17:53:22 -04:00
|
|
|
// We succeeded.
|
|
|
|
guard.Cancel();
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2021-04-30 17:53:22 -04:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result MapSharedMemory32(Core::System& system, Handle shmem_handle, u32 address, u32 size,
|
|
|
|
Svc::MemoryPermission map_perm) {
|
2021-04-30 17:53:22 -04:00
|
|
|
return MapSharedMemory(system, shmem_handle, address, size, map_perm);
|
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result UnmapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address,
|
|
|
|
u64 size) {
|
2021-04-30 17:53:22 -04:00
|
|
|
// 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 = *system.Kernel().CurrentProcess();
|
|
|
|
auto& page_table = process.PageTable();
|
|
|
|
|
|
|
|
// Get the shared memory.
|
|
|
|
KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle);
|
|
|
|
R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle);
|
2018-10-17 22:39:21 -04:00
|
|
|
|
2021-04-30 17:53:22 -04:00
|
|
|
// Verify that the mapping is in range.
|
|
|
|
R_UNLESS(page_table.CanContain(address, size, KMemoryState::Shared), ResultInvalidMemoryRegion);
|
2018-10-17 22:39:21 -04:00
|
|
|
|
2021-04-30 17:53:22 -04:00
|
|
|
// Unmap the shared memory.
|
|
|
|
R_TRY(shmem->Unmap(process, address, size));
|
|
|
|
|
|
|
|
// Remove the shared memory from the process.
|
|
|
|
process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size);
|
|
|
|
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-02-22 14:16:43 -05:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result UnmapSharedMemory32(Core::System& system, Handle shmem_handle, u32 address,
|
|
|
|
u32 size) {
|
2021-04-30 17:53:22 -04:00
|
|
|
return UnmapSharedMemory(system, shmem_handle, address, size);
|
2020-06-19 19:40:07 -04:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result SetProcessMemoryPermission(Core::System& system, Handle process_handle, VAddr address,
|
|
|
|
u64 size, Svc::MemoryPermission perm) {
|
2021-11-20 20:23:59 -05:00
|
|
|
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);
|
2022-01-09 05:17:17 -05:00
|
|
|
R_UNLESS(address == static_cast<uintptr_t>(address), ResultInvalidCurrentMemory);
|
|
|
|
R_UNLESS(size == static_cast<size_t>(size), ResultInvalidCurrentMemory);
|
2021-11-20 20:23:59 -05:00
|
|
|
|
|
|
|
// Validate the memory permission.
|
|
|
|
R_UNLESS(IsValidProcessMemoryPermission(perm), ResultInvalidNewMemoryPermission);
|
|
|
|
|
|
|
|
// Get the process from its handle.
|
|
|
|
KScopedAutoObject process =
|
|
|
|
system.CurrentProcess()->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.
|
2022-01-09 05:17:17 -05:00
|
|
|
return page_table.SetProcessMemoryPermission(address, size, perm);
|
2021-11-20 20:23:59 -05:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result MapProcessMemory(Core::System& system, VAddr dst_address, Handle process_handle,
|
|
|
|
VAddr src_address, u64 size) {
|
2021-12-05 15:04:08 -05:00
|
|
|
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 = system.CurrentProcess();
|
|
|
|
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.
|
2022-12-29 03:39:42 -05:00
|
|
|
KPageGroup pg;
|
2022-03-26 04:35:37 -04:00
|
|
|
R_TRY(src_pt.MakeAndOpenPageGroup(
|
|
|
|
std::addressof(pg), src_address, size / PageSize, KMemoryState::FlagCanMapProcess,
|
|
|
|
KMemoryState::FlagCanMapProcess, KMemoryPermission::None, KMemoryPermission::None,
|
|
|
|
KMemoryAttribute::All, KMemoryAttribute::None));
|
2021-12-05 15:04:08 -05:00
|
|
|
|
|
|
|
// Map the group.
|
|
|
|
R_TRY(dst_pt.MapPages(dst_address, pg, KMemoryState::SharedCode,
|
|
|
|
KMemoryPermission::UserReadWrite));
|
|
|
|
|
|
|
|
return ResultSuccess;
|
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result UnmapProcessMemory(Core::System& system, VAddr dst_address, Handle process_handle,
|
|
|
|
VAddr src_address, u64 size) {
|
2021-12-05 15:04:08 -05:00
|
|
|
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 = system.CurrentProcess();
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result CreateCodeMemory(Core::System& system, Handle* out, VAddr address, size_t size) {
|
2022-03-26 04:34:29 -04:00
|
|
|
LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, size=0x{:X}", address, size);
|
|
|
|
|
2021-12-05 15:04:08 -05:00
|
|
|
// 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(system.CurrentProcess()->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(system.CurrentProcess()->GetHandleTable().Add(out, code_mem));
|
|
|
|
|
|
|
|
code_mem->Close();
|
|
|
|
|
|
|
|
return ResultSuccess;
|
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result CreateCodeMemory32(Core::System& system, Handle* out, u32 address, u32 size) {
|
2022-02-08 13:46:45 -05:00
|
|
|
return CreateCodeMemory(system, out, address, size);
|
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result ControlCodeMemory(Core::System& system, Handle code_memory_handle, u32 operation,
|
|
|
|
VAddr address, size_t size, Svc::MemoryPermission perm) {
|
2021-12-05 15:04:08 -05:00
|
|
|
|
|
|
|
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 =
|
|
|
|
system.CurrentProcess()->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 (static_cast<CodeMemoryOperation>(operation)) {
|
|
|
|
case CodeMemoryOperation::Map: {
|
|
|
|
// Check that the region is in range.
|
|
|
|
R_UNLESS(
|
|
|
|
system.CurrentProcess()->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(
|
|
|
|
system.CurrentProcess()->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;
|
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result ControlCodeMemory32(Core::System& system, Handle code_memory_handle, u32 operation,
|
|
|
|
u64 address, u64 size, Svc::MemoryPermission perm) {
|
2022-02-08 13:46:45 -05:00
|
|
|
return ControlCodeMemory(system, code_memory_handle, operation, address, size, perm);
|
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result QueryProcessMemory(Core::System& system, VAddr memory_info_address,
|
|
|
|
VAddr page_info_address, Handle process_handle, VAddr address) {
|
2018-12-12 11:34:01 -05:00
|
|
|
LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address);
|
2019-04-06 18:46:18 -04:00
|
|
|
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
2021-04-24 01:04:28 -04:00
|
|
|
KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle);
|
2021-04-18 01:21:59 -04:00
|
|
|
if (process.IsNull()) {
|
2018-11-26 03:47:39 -05:00
|
|
|
LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}",
|
|
|
|
process_handle);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidHandle;
|
2017-10-19 23:00:46 -04:00
|
|
|
}
|
2018-12-06 10:59:22 -05:00
|
|
|
|
2020-04-08 23:14:18 -04:00
|
|
|
auto& memory{system.Memory()};
|
2020-04-17 00:59:08 -04:00
|
|
|
const auto memory_info{process->PageTable().QueryInfo(address).GetSvcMemoryInfo()};
|
2020-04-08 23:14:18 -04:00
|
|
|
|
2022-11-03 10:22:05 -04:00
|
|
|
memory.Write64(memory_info_address + 0x00, memory_info.base_address);
|
2020-04-08 23:14:18 -04:00
|
|
|
memory.Write64(memory_info_address + 0x08, memory_info.size);
|
|
|
|
memory.Write32(memory_info_address + 0x10, static_cast<u32>(memory_info.state) & 0xff);
|
2022-11-03 10:22:05 -04:00
|
|
|
memory.Write32(memory_info_address + 0x14, static_cast<u32>(memory_info.attribute));
|
|
|
|
memory.Write32(memory_info_address + 0x18, static_cast<u32>(memory_info.permission));
|
|
|
|
memory.Write32(memory_info_address + 0x1c, memory_info.ipc_count);
|
|
|
|
memory.Write32(memory_info_address + 0x20, memory_info.device_count);
|
2020-04-08 23:14:18 -04:00
|
|
|
memory.Write32(memory_info_address + 0x24, 0);
|
svc: Handle memory writing explicitly within QueryProcessMemory
Moves the memory writes directly into QueryProcessMemory instead of
letting the wrapper function do it. It would be inaccurate to allow the
handler to do it because there's cases where memory shouldn't even be
written to. For example, if the given process handle is invalid.
HOWEVER, if the memory writing is within the wrapper, then we have no
control over if these memory writes occur, meaning in an error case, 68
bytes of memory randomly get trashed with zeroes, 64 of those being
written to wherever the memory info address points to, and the remaining
4 being written wherever the page info address points to.
One solution in this case would be to just conditionally check within
the handler itself, but this is kind of smelly, given the handler
shouldn't be performing conditional behavior itself, it's a behavior of
the managed function. In other words, if you remove the handler from the
equation entirely, does the function still retain its proper behavior?
In this case, no.
Now, we don't potentially trash memory from this function if an invalid
query is performed.
2018-12-12 11:48:06 -05:00
|
|
|
|
|
|
|
// Page info appears to be currently unused by the kernel and is always set to zero.
|
2019-11-26 17:39:57 -05:00
|
|
|
memory.Write32(page_info_address, 0);
|
2018-12-06 10:59:22 -05:00
|
|
|
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2014-05-15 20:17:30 -04:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result QueryMemory(Core::System& system, VAddr memory_info_address, VAddr page_info_address,
|
|
|
|
VAddr query_address) {
|
svc: Handle memory writing explicitly within QueryProcessMemory
Moves the memory writes directly into QueryProcessMemory instead of
letting the wrapper function do it. It would be inaccurate to allow the
handler to do it because there's cases where memory shouldn't even be
written to. For example, if the given process handle is invalid.
HOWEVER, if the memory writing is within the wrapper, then we have no
control over if these memory writes occur, meaning in an error case, 68
bytes of memory randomly get trashed with zeroes, 64 of those being
written to wherever the memory info address points to, and the remaining
4 being written wherever the page info address points to.
One solution in this case would be to just conditionally check within
the handler itself, but this is kind of smelly, given the handler
shouldn't be performing conditional behavior itself, it's a behavior of
the managed function. In other words, if you remove the handler from the
equation entirely, does the function still retain its proper behavior?
In this case, no.
Now, we don't potentially trash memory from this function if an invalid
query is performed.
2018-12-12 11:48:06 -05:00
|
|
|
LOG_TRACE(Kernel_SVC,
|
|
|
|
"called, memory_info_address=0x{:016X}, page_info_address=0x{:016X}, "
|
|
|
|
"query_address=0x{:016X}",
|
|
|
|
memory_info_address, page_info_address, query_address);
|
|
|
|
|
2019-04-06 18:46:18 -04:00
|
|
|
return QueryProcessMemory(system, memory_info_address, page_info_address, CurrentProcess,
|
svc: Handle memory writing explicitly within QueryProcessMemory
Moves the memory writes directly into QueryProcessMemory instead of
letting the wrapper function do it. It would be inaccurate to allow the
handler to do it because there's cases where memory shouldn't even be
written to. For example, if the given process handle is invalid.
HOWEVER, if the memory writing is within the wrapper, then we have no
control over if these memory writes occur, meaning in an error case, 68
bytes of memory randomly get trashed with zeroes, 64 of those being
written to wherever the memory info address points to, and the remaining
4 being written wherever the page info address points to.
One solution in this case would be to just conditionally check within
the handler itself, but this is kind of smelly, given the handler
shouldn't be performing conditional behavior itself, it's a behavior of
the managed function. In other words, if you remove the handler from the
equation entirely, does the function still retain its proper behavior?
In this case, no.
Now, we don't potentially trash memory from this function if an invalid
query is performed.
2018-12-12 11:48:06 -05:00
|
|
|
query_address);
|
2015-07-17 15:45:12 -04:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result QueryMemory32(Core::System& system, u32 memory_info_address, u32 page_info_address,
|
|
|
|
u32 query_address) {
|
2020-03-02 00:06:41 -05:00
|
|
|
return QueryMemory(system, memory_info_address, page_info_address, query_address);
|
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result MapProcessCodeMemory(Core::System& system, Handle process_handle, u64 dst_address,
|
|
|
|
u64 src_address, u64 size) {
|
2020-04-23 18:05:09 -04:00
|
|
|
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);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidAddress;
|
2020-04-23 18:05:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!Common::Is4KBAligned(dst_address)) {
|
|
|
|
LOG_ERROR(Kernel_SVC, "dst_address is not page-aligned (dst_address=0x{:016X}).",
|
|
|
|
dst_address);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidAddress;
|
2020-04-23 18:05:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (size == 0 || !Common::Is4KBAligned(size)) {
|
|
|
|
LOG_ERROR(Kernel_SVC, "Size is zero or not page-aligned (size=0x{:016X})", size);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidSize;
|
2020-04-23 18:05:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidCurrentMemory;
|
2020-04-23 18:05:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidCurrentMemory;
|
2020-04-23 18:05:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
2021-04-24 01:04:28 -04:00
|
|
|
KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle);
|
2021-04-18 01:21:59 -04:00
|
|
|
if (process.IsNull()) {
|
2020-04-23 18:05:09 -04:00
|
|
|
LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).",
|
|
|
|
process_handle);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidHandle;
|
2020-04-23 18:05:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidCurrentMemory;
|
2020-04-23 18:05:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2021-04-11 14:41:48 -04:00
|
|
|
return ResultInvalidMemoryRegion;
|
2020-04-23 18:05:09 -04:00
|
|
|
}
|
|
|
|
|
2022-01-09 02:07:07 -05:00
|
|
|
return page_table.MapCodeMemory(dst_address, src_address, size);
|
2020-04-23 18:05:09 -04:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result UnmapProcessCodeMemory(Core::System& system, Handle process_handle, u64 dst_address,
|
|
|
|
u64 src_address, u64 size) {
|
2020-04-23 18:05:09 -04:00
|
|
|
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);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidAddress;
|
2020-04-23 18:05:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!Common::Is4KBAligned(src_address)) {
|
|
|
|
LOG_ERROR(Kernel_SVC, "src_address is not page-aligned (src_address=0x{:016X}).",
|
|
|
|
src_address);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidAddress;
|
2020-04-23 18:05:09 -04:00
|
|
|
}
|
|
|
|
|
2022-03-26 04:01:55 -04:00
|
|
|
if (size == 0 || !Common::Is4KBAligned(size)) {
|
2020-04-23 18:05:09 -04:00
|
|
|
LOG_ERROR(Kernel_SVC, "Size is zero or not page-aligned (size=0x{:016X}).", size);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidSize;
|
2020-04-23 18:05:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidCurrentMemory;
|
2020-04-23 18:05:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidCurrentMemory;
|
2020-04-23 18:05:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
2021-04-24 01:04:28 -04:00
|
|
|
KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle);
|
2021-04-18 01:21:59 -04:00
|
|
|
if (process.IsNull()) {
|
2020-04-23 18:05:09 -04:00
|
|
|
LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).",
|
|
|
|
process_handle);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidHandle;
|
2020-04-23 18:05:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidCurrentMemory;
|
2020-04-23 18:05:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2021-04-11 14:41:48 -04:00
|
|
|
return ResultInvalidMemoryRegion;
|
2020-04-23 18:05:09 -04:00
|
|
|
}
|
|
|
|
|
2022-04-08 15:31:56 -04:00
|
|
|
return page_table.UnmapCodeMemory(dst_address, src_address, size,
|
|
|
|
KPageTable::ICacheInvalidationStrategy::InvalidateAll);
|
2020-04-23 18:05:09 -04:00
|
|
|
}
|
|
|
|
|
2018-01-01 14:38:34 -05:00
|
|
|
/// Exits the current process
|
2019-04-06 18:46:18 -04:00
|
|
|
static void ExitProcess(Core::System& system) {
|
|
|
|
auto* current_process = system.Kernel().CurrentProcess();
|
2018-01-01 14:38:34 -05:00
|
|
|
|
2018-09-21 02:06:47 -04:00
|
|
|
LOG_INFO(Kernel_SVC, "Process {} exiting", current_process->GetProcessID());
|
2022-09-05 20:47:00 -04:00
|
|
|
ASSERT_MSG(current_process->GetState() == KProcess::State::Running,
|
2018-03-13 17:49:59 -04:00
|
|
|
"Process has already exited");
|
2022-06-16 14:35:34 -04:00
|
|
|
|
|
|
|
system.Exit();
|
2018-01-01 14:38:34 -05:00
|
|
|
}
|
|
|
|
|
2020-06-19 19:40:07 -04:00
|
|
|
static void ExitProcess32(Core::System& system) {
|
|
|
|
ExitProcess(system);
|
|
|
|
}
|
|
|
|
|
2021-11-20 21:54:46 -05:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
constexpr bool IsValidVirtualCoreId(int32_t core_id) {
|
2021-01-03 04:49:18 -05:00
|
|
|
return (0 <= core_id && core_id < static_cast<int32_t>(Core::Hardware::NUM_CPU_CORES));
|
|
|
|
}
|
|
|
|
|
2021-11-20 21:54:46 -05:00
|
|
|
} // Anonymous namespace
|
|
|
|
|
2017-12-31 16:10:01 -05:00
|
|
|
/// Creates a new thread
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result CreateThread(Core::System& system, Handle* out_handle, VAddr entry_point, u64 arg,
|
|
|
|
VAddr stack_bottom, u32 priority, s32 core_id) {
|
2019-04-15 21:33:07 -04:00
|
|
|
LOG_DEBUG(Kernel_SVC,
|
2021-01-03 04:49:18 -05:00
|
|
|
"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);
|
2018-12-30 21:20:07 -05:00
|
|
|
|
2021-01-03 04:49:18 -05:00
|
|
|
// Adjust core id, if it's the default magic.
|
|
|
|
auto& kernel = system.Kernel();
|
|
|
|
auto& process = *kernel.CurrentProcess();
|
2021-02-03 22:33:27 -05:00
|
|
|
if (core_id == IdealCoreUseProcessValue) {
|
2021-01-03 04:49:18 -05:00
|
|
|
core_id = process.GetIdealCoreId();
|
2018-12-30 21:20:07 -05:00
|
|
|
}
|
|
|
|
|
2021-01-03 04:49:18 -05:00
|
|
|
// Validate arguments.
|
2021-04-03 22:11:46 -04:00
|
|
|
if (!IsValidVirtualCoreId(core_id)) {
|
2021-02-03 22:33:27 -05:00
|
|
|
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;
|
|
|
|
}
|
2018-12-30 21:20:07 -05:00
|
|
|
|
2021-02-03 22:33:27 -05:00
|
|
|
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;
|
|
|
|
}
|
2020-04-08 23:14:18 -04:00
|
|
|
|
2021-04-03 02:50:39 -04:00
|
|
|
// Reserve a new thread from the process resource limit (waiting up to 100ms).
|
2021-02-04 20:06:54 -05:00
|
|
|
KScopedResourceReservation thread_reservation(
|
2022-11-03 10:22:05 -04:00
|
|
|
kernel.CurrentProcess(), LimitableResource::ThreadCountMax, 1,
|
2021-02-04 20:06:54 -05:00
|
|
|
system.CoreTiming().GetGlobalTimeNs().count() + 100000000);
|
|
|
|
if (!thread_reservation.Succeeded()) {
|
|
|
|
LOG_ERROR(Kernel_SVC, "Could not reserve a new thread");
|
2021-04-11 14:41:48 -04:00
|
|
|
return ResultLimitReached;
|
2021-02-04 20:06:54 -05:00
|
|
|
}
|
2020-04-08 23:14:18 -04:00
|
|
|
|
2021-04-03 02:50:39 -04:00
|
|
|
// Create the thread.
|
2021-04-10 01:42:23 -04:00
|
|
|
KThread* thread = KThread::Create(kernel);
|
2021-04-03 02:50:39 -04:00
|
|
|
if (!thread) {
|
|
|
|
LOG_ERROR(Kernel_SVC, "Unable to create new threads. Thread creation limit reached.");
|
|
|
|
return ResultOutOfResource;
|
2021-01-25 01:54:37 -05:00
|
|
|
}
|
2021-04-03 02:50:39 -04:00
|
|
|
SCOPE_EXIT({ thread->Close(); });
|
2018-10-20 14:34:41 -04:00
|
|
|
|
2021-04-03 02:50:39 -04:00
|
|
|
// Initialize the thread.
|
|
|
|
{
|
|
|
|
KScopedLightLock lk{process.GetStateLock()};
|
|
|
|
R_TRY(KThread::InitializeUserThread(system, thread, entry_point, arg, stack_bottom,
|
|
|
|
priority, core_id, &process));
|
2018-10-03 18:47:57 -04:00
|
|
|
}
|
2017-12-31 16:10:01 -05:00
|
|
|
|
2019-04-15 15:54:25 -04:00
|
|
|
// Set the thread name for debugging purposes.
|
2021-04-03 02:50:39 -04:00
|
|
|
thread->SetName(fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *out_handle));
|
|
|
|
|
|
|
|
// Commit the thread reservation.
|
2021-02-04 20:06:54 -05:00
|
|
|
thread_reservation.Commit();
|
2017-12-31 16:10:01 -05:00
|
|
|
|
2021-04-03 02:50:39 -04:00
|
|
|
// Register the new thread.
|
2021-04-03 02:53:31 -04:00
|
|
|
KThread::Register(kernel, thread);
|
2021-04-03 02:50:39 -04:00
|
|
|
|
|
|
|
// Add the thread to the handle table.
|
|
|
|
R_TRY(process.GetHandleTable().Add(out_handle, thread));
|
|
|
|
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2017-12-31 16:10:01 -05:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result CreateThread32(Core::System& system, Handle* out_handle, u32 priority,
|
|
|
|
u32 entry_point, u32 arg, u32 stack_top, s32 processor_id) {
|
2020-12-08 15:38:28 -05:00
|
|
|
return CreateThread(system, out_handle, entry_point, arg, stack_top, priority, processor_id);
|
2020-06-19 19:40:07 -04:00
|
|
|
}
|
|
|
|
|
2017-12-30 13:40:28 -05:00
|
|
|
/// Starts the thread for the provided handle
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result StartThread(Core::System& system, Handle thread_handle) {
|
2019-04-15 21:33:07 -04:00
|
|
|
LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
|
2017-12-30 13:37:07 -05:00
|
|
|
|
2021-01-20 16:42:27 -05:00
|
|
|
// Get the thread from its handle.
|
2021-04-03 02:53:31 -04:00
|
|
|
KScopedAutoObject thread =
|
|
|
|
system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
|
|
|
|
R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
|
2017-12-30 13:37:07 -05:00
|
|
|
|
2021-01-20 16:42:27 -05:00
|
|
|
// Try to start the thread.
|
2021-04-03 02:53:31 -04:00
|
|
|
R_TRY(thread->Run());
|
|
|
|
|
|
|
|
// If we succeeded, persist a reference to the thread.
|
|
|
|
thread->Open();
|
2021-10-25 06:55:20 -04:00
|
|
|
system.Kernel().RegisterInUseObject(thread.GetPointerUnsafe());
|
2018-05-19 17:57:44 -04:00
|
|
|
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2017-12-30 13:37:07 -05:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result StartThread32(Core::System& system, Handle thread_handle) {
|
2020-06-19 19:40:07 -04:00
|
|
|
return StartThread(system, thread_handle);
|
|
|
|
}
|
|
|
|
|
2017-12-31 16:11:27 -05:00
|
|
|
/// Called when a thread exits
|
2019-04-06 18:46:18 -04:00
|
|
|
static void ExitThread(Core::System& system) {
|
2019-04-15 21:33:07 -04:00
|
|
|
LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC());
|
2019-03-15 23:38:51 -04:00
|
|
|
|
2022-06-16 10:35:52 -04:00
|
|
|
auto* const current_thread = GetCurrentThreadPointer(system.Kernel());
|
2021-04-03 02:53:31 -04:00
|
|
|
system.GlobalSchedulerContext().RemoveThread(current_thread);
|
2021-01-20 16:42:27 -05:00
|
|
|
current_thread->Exit();
|
2021-10-25 06:55:20 -04:00
|
|
|
system.Kernel().UnregisterInUseObject(current_thread);
|
2017-12-31 16:11:27 -05:00
|
|
|
}
|
|
|
|
|
2020-06-19 19:40:07 -04:00
|
|
|
static void ExitThread32(Core::System& system) {
|
|
|
|
ExitThread(system);
|
|
|
|
}
|
|
|
|
|
2014-06-01 10:37:19 -04:00
|
|
|
/// Sleep the current thread
|
2019-04-06 18:46:18 -04:00
|
|
|
static void SleepThread(Core::System& system, s64 nanoseconds) {
|
2021-01-20 16:42:27 -05:00
|
|
|
auto& kernel = system.Kernel();
|
|
|
|
const auto yield_type = static_cast<Svc::YieldType>(nanoseconds);
|
2014-11-26 00:34:14 -05:00
|
|
|
|
2021-01-20 16:42:27 -05:00
|
|
|
LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds);
|
2017-01-05 14:14:22 -05:00
|
|
|
|
2021-01-20 16:42:27 -05:00
|
|
|
// 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);
|
2018-12-03 17:29:21 -05:00
|
|
|
} else {
|
2021-01-20 16:42:27 -05:00
|
|
|
// Nintendo does nothing at all if an otherwise invalid value is passed.
|
2022-06-07 17:02:29 -04:00
|
|
|
ASSERT_MSG(false, "Unimplemented sleep yield type '{:016X}'!", nanoseconds);
|
2020-03-10 13:13:39 -04:00
|
|
|
}
|
2014-06-01 10:37:19 -04:00
|
|
|
}
|
|
|
|
|
2020-06-19 19:40:07 -04:00
|
|
|
static void SleepThread32(Core::System& system, u32 nanoseconds_low, u32 nanoseconds_high) {
|
2020-12-08 15:38:28 -05:00
|
|
|
const auto nanoseconds = static_cast<s64>(u64{nanoseconds_low} | (u64{nanoseconds_high} << 32));
|
2020-06-19 19:40:07 -04:00
|
|
|
SleepThread(system, nanoseconds);
|
|
|
|
}
|
|
|
|
|
2018-06-21 02:49:43 -04:00
|
|
|
/// Wait process wide key atomic
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result WaitProcessWideKeyAtomic(Core::System& system, VAddr address, VAddr cv_key, u32 tag,
|
|
|
|
s64 timeout_ns) {
|
2020-12-30 04:14:02 -05:00
|
|
|
LOG_TRACE(Kernel_SVC, "called address={:X}, cv_key={:X}, tag=0x{:08X}, timeout_ns={}", address,
|
|
|
|
cv_key, tag, timeout_ns);
|
|
|
|
|
|
|
|
// Validate input.
|
2021-02-12 19:02:35 -05:00
|
|
|
if (IsKernelAddress(address)) {
|
2021-02-03 22:33:27 -05:00
|
|
|
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;
|
|
|
|
}
|
2020-12-30 04:14:02 -05:00
|
|
|
|
|
|
|
// 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();
|
2020-03-08 12:51:24 -04:00
|
|
|
}
|
2020-12-30 04:14:02 -05:00
|
|
|
} else {
|
|
|
|
timeout = timeout_ns;
|
2020-02-26 21:26:53 -05:00
|
|
|
}
|
2018-01-06 16:14:12 -05:00
|
|
|
|
2020-12-30 04:14:02 -05:00
|
|
|
// Wait on the condition variable.
|
|
|
|
return system.Kernel().CurrentProcess()->WaitConditionVariable(
|
|
|
|
address, Common::AlignDown(cv_key, sizeof(u32)), tag, timeout);
|
2018-01-06 16:14:12 -05:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result WaitProcessWideKeyAtomic32(Core::System& system, u32 address, u32 cv_key, u32 tag,
|
|
|
|
u32 timeout_ns_low, u32 timeout_ns_high) {
|
2020-12-30 04:14:02 -05:00
|
|
|
const auto timeout_ns = static_cast<s64>(timeout_ns_low | (u64{timeout_ns_high} << 32));
|
|
|
|
return WaitProcessWideKeyAtomic(system, address, cv_key, tag, timeout_ns);
|
2020-06-19 19:40:07 -04:00
|
|
|
}
|
|
|
|
|
2017-10-14 17:30:07 -04:00
|
|
|
/// Signal process wide key
|
2020-12-30 04:14:02 -05:00
|
|
|
static 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);
|
2018-01-07 16:55:17 -05:00
|
|
|
|
2020-12-30 04:14:02 -05:00
|
|
|
// Signal the condition variable.
|
|
|
|
return system.Kernel().CurrentProcess()->SignalConditionVariable(
|
|
|
|
Common::AlignDown(cv_key, sizeof(u32)), count);
|
|
|
|
}
|
2019-10-12 07:57:32 -04:00
|
|
|
|
2020-12-30 04:14:02 -05:00
|
|
|
static void SignalProcessWideKey32(Core::System& system, u32 cv_key, s32 count) {
|
|
|
|
SignalProcessWideKey(system, cv_key, count);
|
|
|
|
}
|
2018-05-19 17:58:30 -04:00
|
|
|
|
2020-12-30 04:14:02 -05:00
|
|
|
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;
|
2018-05-19 17:58:30 -04:00
|
|
|
}
|
2014-12-08 23:52:27 -05:00
|
|
|
}
|
|
|
|
|
2020-12-30 04:14:02 -05:00
|
|
|
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;
|
|
|
|
}
|
2020-03-02 00:06:41 -05:00
|
|
|
}
|
|
|
|
|
2020-12-30 04:14:02 -05:00
|
|
|
} // namespace
|
2019-04-06 18:46:18 -04:00
|
|
|
|
2020-12-30 04:14:02 -05:00
|
|
|
// Wait for an address (via Address Arbiter)
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result WaitForAddress(Core::System& system, VAddr address, Svc::ArbitrationType arb_type,
|
|
|
|
s32 value, s64 timeout_ns) {
|
2020-12-30 04:14:02 -05:00
|
|
|
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.
|
2021-02-12 19:02:35 -05:00
|
|
|
if (IsKernelAddress(address)) {
|
2021-02-03 22:33:27 -05:00
|
|
|
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;
|
|
|
|
}
|
2020-12-30 04:14:02 -05:00
|
|
|
|
|
|
|
// 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;
|
2018-06-21 02:49:43 -04:00
|
|
|
}
|
|
|
|
|
2020-12-30 04:14:02 -05:00
|
|
|
return system.Kernel().CurrentProcess()->WaitAddressArbiter(address, arb_type, value, timeout);
|
2018-06-21 02:49:43 -04:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result WaitForAddress32(Core::System& system, u32 address, Svc::ArbitrationType arb_type,
|
|
|
|
s32 value, u32 timeout_ns_low, u32 timeout_ns_high) {
|
2020-12-30 04:14:02 -05:00
|
|
|
const auto timeout = static_cast<s64>(timeout_ns_low | (u64{timeout_ns_high} << 32));
|
|
|
|
return WaitForAddress(system, address, arb_type, value, timeout);
|
2020-06-19 19:40:07 -04:00
|
|
|
}
|
|
|
|
|
2018-06-21 02:49:43 -04:00
|
|
|
// Signals to an address (via Address Arbiter)
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result SignalToAddress(Core::System& system, VAddr address, Svc::SignalType signal_type,
|
|
|
|
s32 value, s32 count) {
|
2020-12-30 04:14:02 -05:00
|
|
|
LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, signal_type=0x{:X}, value=0x{:X}, count=0x{:X}",
|
|
|
|
address, signal_type, value, count);
|
2019-04-06 18:46:18 -04:00
|
|
|
|
2020-12-30 04:14:02 -05:00
|
|
|
// Validate input.
|
2021-02-12 19:02:35 -05:00
|
|
|
if (IsKernelAddress(address)) {
|
2021-02-03 22:33:27 -05:00
|
|
|
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;
|
|
|
|
}
|
2018-06-21 02:49:43 -04:00
|
|
|
|
2020-12-30 04:14:02 -05:00
|
|
|
return system.Kernel().CurrentProcess()->SignalAddressArbiter(address, signal_type, value,
|
|
|
|
count);
|
2018-06-21 02:49:43 -04:00
|
|
|
}
|
|
|
|
|
2021-12-30 00:40:38 -05:00
|
|
|
static 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 = system.Kernel().CurrentProcess();
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result SignalToAddress32(Core::System& system, u32 address, Svc::SignalType signal_type,
|
|
|
|
s32 value, s32 count) {
|
2020-12-30 04:14:02 -05:00
|
|
|
return SignalToAddress(system, address, signal_type, value, count);
|
2020-06-19 19:40:07 -04:00
|
|
|
}
|
|
|
|
|
2019-12-07 21:12:14 -05:00
|
|
|
static void KernelDebug([[maybe_unused]] Core::System& system,
|
|
|
|
[[maybe_unused]] u32 kernel_debug_type, [[maybe_unused]] u64 param1,
|
|
|
|
[[maybe_unused]] u64 param2, [[maybe_unused]] u64 param3) {
|
|
|
|
// Intentionally do nothing, as this does nothing in released kernel binaries.
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ChangeKernelTraceState([[maybe_unused]] Core::System& system,
|
|
|
|
[[maybe_unused]] u32 trace_state) {
|
|
|
|
// Intentionally do nothing, as this does nothing in released kernel binaries.
|
|
|
|
}
|
|
|
|
|
2018-01-11 21:59:31 -05:00
|
|
|
/// This returns the total CPU ticks elapsed since the CPU was powered-on
|
2019-04-06 18:46:18 -04:00
|
|
|
static u64 GetSystemTick(Core::System& system) {
|
2018-11-26 01:06:13 -05:00
|
|
|
LOG_TRACE(Kernel_SVC, "called");
|
|
|
|
|
2019-04-06 18:46:18 -04:00
|
|
|
auto& core_timing = system.CoreTiming();
|
2019-11-22 15:55:42 -05:00
|
|
|
|
|
|
|
// Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick)
|
2022-10-29 16:19:33 -04:00
|
|
|
const u64 result{core_timing.GetClockTicks()};
|
2018-01-11 21:59:31 -05:00
|
|
|
|
2020-03-28 15:23:28 -04:00
|
|
|
if (!system.Kernel().IsMulticore()) {
|
|
|
|
core_timing.AddTicks(400U);
|
|
|
|
}
|
|
|
|
|
2018-01-11 21:59:31 -05:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2020-06-19 19:40:07 -04:00
|
|
|
static void GetSystemTick32(Core::System& system, u32* time_low, u32* time_high) {
|
2020-12-08 15:38:28 -05:00
|
|
|
const auto time = GetSystemTick(system);
|
2020-06-19 19:40:07 -04:00
|
|
|
*time_low = static_cast<u32>(time);
|
|
|
|
*time_high = static_cast<u32>(time >> 32);
|
|
|
|
}
|
|
|
|
|
2017-10-14 17:30:07 -04:00
|
|
|
/// Close a handle
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result CloseHandle(Core::System& system, Handle handle) {
|
2018-07-02 12:13:26 -04:00
|
|
|
LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle);
|
2018-08-28 12:30:33 -04:00
|
|
|
|
2021-04-03 22:11:46 -04:00
|
|
|
// Remove the handle.
|
|
|
|
R_UNLESS(system.Kernel().CurrentProcess()->GetHandleTable().Remove(handle),
|
|
|
|
ResultInvalidHandle);
|
|
|
|
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2015-08-05 20:39:53 -04:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result CloseHandle32(Core::System& system, Handle handle) {
|
2020-03-02 00:06:41 -05:00
|
|
|
return CloseHandle(system, handle);
|
|
|
|
}
|
|
|
|
|
2018-12-04 19:59:29 -05:00
|
|
|
/// Clears the signaled state of an event or process.
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result ResetSignal(Core::System& system, Handle handle) {
|
2018-11-18 15:49:17 -05:00
|
|
|
LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle);
|
2018-08-28 12:30:33 -04:00
|
|
|
|
2021-01-31 19:55:11 -05:00
|
|
|
// Get the current handle table.
|
2019-04-06 18:46:18 -04:00
|
|
|
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
2018-12-04 19:59:29 -05:00
|
|
|
|
2021-01-31 19:55:11 -05:00
|
|
|
// Try to reset as readable event.
|
|
|
|
{
|
2021-04-10 05:34:26 -04:00
|
|
|
KScopedAutoObject readable_event = handle_table.GetObject<KReadableEvent>(handle);
|
|
|
|
if (readable_event.IsNotNull()) {
|
2021-01-31 19:55:11 -05:00
|
|
|
return readable_event->Reset();
|
|
|
|
}
|
2018-12-04 19:59:29 -05:00
|
|
|
}
|
2018-08-28 12:30:33 -04:00
|
|
|
|
2021-01-31 19:55:11 -05:00
|
|
|
// Try to reset as process.
|
|
|
|
{
|
2021-04-24 01:04:28 -04:00
|
|
|
KScopedAutoObject process = handle_table.GetObject<KProcess>(handle);
|
2021-04-10 05:34:26 -04:00
|
|
|
if (process.IsNotNull()) {
|
2021-01-31 19:55:11 -05:00
|
|
|
return process->Reset();
|
|
|
|
}
|
2018-12-04 19:59:29 -05:00
|
|
|
}
|
2018-08-28 12:30:33 -04:00
|
|
|
|
2021-01-31 19:55:11 -05:00
|
|
|
LOG_ERROR(Kernel_SVC, "invalid handle (0x{:08X})", handle);
|
|
|
|
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidHandle;
|
2018-01-07 21:24:19 -05:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result ResetSignal32(Core::System& system, Handle handle) {
|
2020-06-19 19:40:07 -04:00
|
|
|
return ResetSignal(system, handle);
|
|
|
|
}
|
|
|
|
|
2021-11-20 21:54:46 -05:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
constexpr bool IsValidTransferMemoryPermission(MemoryPermission perm) {
|
2021-04-17 03:52:53 -04:00
|
|
|
switch (perm) {
|
|
|
|
case MemoryPermission::None:
|
|
|
|
case MemoryPermission::Read:
|
|
|
|
case MemoryPermission::ReadWrite:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
2018-11-09 17:02:50 -05:00
|
|
|
}
|
2021-04-17 03:52:53 -04:00
|
|
|
}
|
2018-11-09 17:02:50 -05:00
|
|
|
|
2021-11-20 21:54:46 -05:00
|
|
|
} // Anonymous namespace
|
|
|
|
|
2021-04-17 03:52:53 -04:00
|
|
|
/// Creates a TransferMemory object
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result CreateTransferMemory(Core::System& system, Handle* out, VAddr address, u64 size,
|
|
|
|
MemoryPermission map_perm) {
|
2021-04-17 03:52:53 -04:00
|
|
|
auto& kernel = system.Kernel();
|
2018-11-09 17:02:50 -05:00
|
|
|
|
2021-04-17 03:52:53 -04:00
|
|
|
// 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);
|
2018-11-09 17:02:50 -05:00
|
|
|
|
2021-04-17 03:52:53 -04:00
|
|
|
// Validate the permissions.
|
|
|
|
R_UNLESS(IsValidTransferMemoryPermission(map_perm), ResultInvalidNewMemoryPermission);
|
|
|
|
|
|
|
|
// Get the current process and handle table.
|
|
|
|
auto& process = *kernel.CurrentProcess();
|
|
|
|
auto& handle_table = process.GetHandleTable();
|
2018-11-09 17:02:50 -05:00
|
|
|
|
2021-02-04 20:06:54 -05:00
|
|
|
// Reserve a new transfer memory from the process resource limit.
|
|
|
|
KScopedResourceReservation trmem_reservation(kernel.CurrentProcess(),
|
2022-11-03 10:22:05 -04:00
|
|
|
LimitableResource::TransferMemoryCountMax);
|
2021-04-17 03:52:53 -04:00
|
|
|
R_UNLESS(trmem_reservation.Succeeded(), ResultLimitReached);
|
2020-01-30 22:39:07 -05:00
|
|
|
|
2021-04-17 03:52:53 -04:00
|
|
|
// Create the transfer memory.
|
|
|
|
KTransferMemory* trmem = KTransferMemory::Create(kernel);
|
|
|
|
R_UNLESS(trmem != nullptr, ResultOutOfResource);
|
2018-11-09 17:02:50 -05:00
|
|
|
|
2021-04-17 03:52:53 -04:00
|
|
|
// 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.
|
2021-02-04 20:06:54 -05:00
|
|
|
trmem_reservation.Commit();
|
2019-03-13 03:09:27 -04:00
|
|
|
|
2021-04-17 03:52:53 -04:00
|
|
|
// Register the transfer memory.
|
|
|
|
KTransferMemory::Register(kernel, trmem);
|
|
|
|
|
|
|
|
// Add the transfer memory to the handle table.
|
|
|
|
R_TRY(handle_table.Add(out, trmem));
|
|
|
|
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-01-07 21:24:19 -05:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result CreateTransferMemory32(Core::System& system, Handle* out, u32 address, u32 size,
|
|
|
|
MemoryPermission map_perm) {
|
2021-04-17 03:52:53 -04:00
|
|
|
return CreateTransferMemory(system, out, address, size, map_perm);
|
2020-06-18 20:33:04 -04:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result GetThreadCoreMask(Core::System& system, Handle thread_handle, s32* out_core_id,
|
|
|
|
u64* out_affinity_mask) {
|
2021-04-11 15:49:51 -04:00
|
|
|
LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle);
|
|
|
|
|
|
|
|
// Get the thread from its handle.
|
|
|
|
KScopedAutoObject thread =
|
|
|
|
system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
|
|
|
|
R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
|
|
|
|
|
|
|
|
// Get the core mask.
|
|
|
|
R_TRY(thread->GetCoreMask(out_core_id, out_affinity_mask));
|
|
|
|
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-03-29 21:07:49 -04:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result GetThreadCoreMask32(Core::System& system, Handle thread_handle, s32* out_core_id,
|
|
|
|
u32* out_affinity_mask_low, u32* out_affinity_mask_high) {
|
2021-01-20 16:42:27 -05:00
|
|
|
u64 out_affinity_mask{};
|
|
|
|
const auto result = GetThreadCoreMask(system, thread_handle, out_core_id, &out_affinity_mask);
|
|
|
|
*out_affinity_mask_high = static_cast<u32>(out_affinity_mask >> 32);
|
|
|
|
*out_affinity_mask_low = static_cast<u32>(out_affinity_mask);
|
2020-06-19 19:40:07 -04:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result SetThreadCoreMask(Core::System& system, Handle thread_handle, s32 core_id,
|
|
|
|
u64 affinity_mask) {
|
2021-01-20 16:42:27 -05:00
|
|
|
// Determine the core id/affinity mask.
|
2021-04-03 22:11:46 -04:00
|
|
|
if (core_id == IdealCoreUseProcessValue) {
|
|
|
|
core_id = system.Kernel().CurrentProcess()->GetIdealCoreId();
|
2021-01-20 16:42:27 -05:00
|
|
|
affinity_mask = (1ULL << core_id);
|
2019-04-15 20:34:55 -04:00
|
|
|
} else {
|
2021-01-20 16:42:27 -05:00
|
|
|
// Validate the affinity mask.
|
2021-04-03 22:11:46 -04:00
|
|
|
const u64 process_core_mask = system.Kernel().CurrentProcess()->GetCoreMask();
|
|
|
|
R_UNLESS((affinity_mask | process_core_mask) == process_core_mask, ResultInvalidCoreId);
|
|
|
|
R_UNLESS(affinity_mask != 0, ResultInvalidCombination);
|
2021-01-20 16:42:27 -05:00
|
|
|
|
|
|
|
// Validate the core id.
|
2021-04-03 22:11:46 -04:00
|
|
|
if (IsValidVirtualCoreId(core_id)) {
|
|
|
|
R_UNLESS(((1ULL << core_id) & affinity_mask) != 0, ResultInvalidCombination);
|
2021-01-20 16:42:27 -05:00
|
|
|
} else {
|
2021-04-03 22:11:46 -04:00
|
|
|
R_UNLESS(core_id == IdealCoreNoUpdate || core_id == IdealCoreDontCare,
|
|
|
|
ResultInvalidCoreId);
|
2019-04-15 20:34:55 -04:00
|
|
|
}
|
2018-05-30 13:03:19 -04:00
|
|
|
}
|
|
|
|
|
2021-01-20 16:42:27 -05:00
|
|
|
// Get the thread from its handle.
|
2021-04-03 22:11:46 -04:00
|
|
|
KScopedAutoObject thread =
|
|
|
|
system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
|
|
|
|
R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
|
2018-05-30 13:03:19 -04:00
|
|
|
|
2021-01-20 16:42:27 -05:00
|
|
|
// Set the core mask.
|
2021-04-03 22:11:46 -04:00
|
|
|
R_TRY(thread->SetCoreMask(core_id, affinity_mask));
|
|
|
|
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-01-16 17:23:53 -05:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result SetThreadCoreMask32(Core::System& system, Handle thread_handle, s32 core_id,
|
|
|
|
u32 affinity_mask_low, u32 affinity_mask_high) {
|
2020-12-08 15:38:28 -05:00
|
|
|
const auto affinity_mask = u64{affinity_mask_low} | (u64{affinity_mask_high} << 32);
|
2021-01-20 16:42:27 -05:00
|
|
|
return SetThreadCoreMask(system, thread_handle, core_id, affinity_mask);
|
2020-06-18 18:15:19 -04:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result SignalEvent(Core::System& system, Handle event_handle) {
|
2021-01-31 19:55:11 -05:00
|
|
|
LOG_DEBUG(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle);
|
2018-12-04 15:11:18 -05:00
|
|
|
|
2021-01-31 19:55:11 -05:00
|
|
|
// Get the current handle table.
|
2021-04-24 05:40:31 -04:00
|
|
|
const KHandleTable& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
2018-12-04 15:11:18 -05:00
|
|
|
|
2022-10-12 20:26:04 -04:00
|
|
|
// Get the event.
|
|
|
|
KScopedAutoObject event = handle_table.GetObject<KEvent>(event_handle);
|
|
|
|
R_UNLESS(event.IsNotNull(), ResultInvalidHandle);
|
2021-02-04 20:06:54 -05:00
|
|
|
|
2022-10-12 20:26:04 -04:00
|
|
|
return event->Signal();
|
2018-12-04 15:11:18 -05:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result SignalEvent32(Core::System& system, Handle event_handle) {
|
2021-01-31 19:55:11 -05:00
|
|
|
return SignalEvent(system, event_handle);
|
2020-06-19 19:40:07 -04:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result ClearEvent(Core::System& system, Handle event_handle) {
|
2021-01-31 19:55:11 -05:00
|
|
|
LOG_TRACE(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle);
|
2018-02-22 09:28:15 -05:00
|
|
|
|
2021-01-31 19:55:11 -05:00
|
|
|
// Get the current handle table.
|
2019-04-06 18:46:18 -04:00
|
|
|
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
2018-12-03 22:50:16 -05:00
|
|
|
|
2021-01-31 19:55:11 -05:00
|
|
|
// Try to clear the writable event.
|
|
|
|
{
|
2022-10-12 20:26:04 -04:00
|
|
|
KScopedAutoObject event = handle_table.GetObject<KEvent>(event_handle);
|
|
|
|
if (event.IsNotNull()) {
|
|
|
|
return event->Clear();
|
2021-01-31 19:55:11 -05:00
|
|
|
}
|
2018-10-20 14:34:41 -04:00
|
|
|
}
|
|
|
|
|
2021-01-31 19:55:11 -05:00
|
|
|
// Try to clear the readable event.
|
|
|
|
{
|
2021-04-10 05:34:26 -04:00
|
|
|
KScopedAutoObject readable_event = handle_table.GetObject<KReadableEvent>(event_handle);
|
|
|
|
if (readable_event.IsNotNull()) {
|
2021-01-31 19:55:11 -05:00
|
|
|
return readable_event->Clear();
|
|
|
|
}
|
2018-12-03 22:50:16 -05:00
|
|
|
}
|
|
|
|
|
2021-01-31 19:55:11 -05:00
|
|
|
LOG_ERROR(Kernel_SVC, "Event handle does not exist, event_handle=0x{:08X}", event_handle);
|
|
|
|
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidHandle;
|
2018-02-22 09:28:15 -05:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result ClearEvent32(Core::System& system, Handle event_handle) {
|
2021-01-31 19:55:11 -05:00
|
|
|
return ClearEvent(system, event_handle);
|
2020-06-19 19:40:07 -04:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result CreateEvent(Core::System& system, Handle* out_write, Handle* out_read) {
|
2021-01-31 19:55:11 -05:00
|
|
|
LOG_DEBUG(Kernel_SVC, "called");
|
2018-12-04 15:39:49 -05:00
|
|
|
|
2021-01-31 19:55:11 -05:00
|
|
|
// Get the kernel reference and handle table.
|
|
|
|
auto& kernel = system.Kernel();
|
2021-04-10 05:34:26 -04:00
|
|
|
auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
|
|
|
|
|
|
|
|
// Reserve a new event from the process resource limit
|
|
|
|
KScopedResourceReservation event_reservation(kernel.CurrentProcess(),
|
2022-11-03 10:22:05 -04:00
|
|
|
LimitableResource::EventCountMax);
|
2021-04-11 14:41:48 -04:00
|
|
|
R_UNLESS(event_reservation.Succeeded(), ResultLimitReached);
|
2018-12-04 15:39:49 -05:00
|
|
|
|
2021-01-31 19:55:11 -05:00
|
|
|
// Create a new event.
|
2021-04-10 01:42:23 -04:00
|
|
|
KEvent* event = KEvent::Create(kernel);
|
2021-04-04 03:56:09 -04:00
|
|
|
R_UNLESS(event != nullptr, ResultOutOfResource);
|
2021-01-31 19:55:11 -05:00
|
|
|
|
|
|
|
// Initialize the event.
|
2022-10-12 20:26:04 -04:00
|
|
|
event->Initialize(kernel.CurrentProcess());
|
2021-01-31 19:55:11 -05:00
|
|
|
|
2021-04-10 05:34:26 -04:00
|
|
|
// 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();
|
2022-10-12 20:26:04 -04:00
|
|
|
event->Close();
|
2021-04-10 05:34:26 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
// Register the event.
|
|
|
|
KEvent::Register(kernel, event);
|
|
|
|
|
2022-10-12 20:26:04 -04:00
|
|
|
// Add the event to the handle table.
|
|
|
|
R_TRY(handle_table.Add(out_write, event));
|
2021-01-31 19:55:11 -05:00
|
|
|
|
2022-10-12 20:26:04 -04:00
|
|
|
// Ensure that we maintaing a clean handle state on exit.
|
2021-04-10 05:34:26 -04:00
|
|
|
auto handle_guard = SCOPE_GUARD({ handle_table.Remove(*out_write); });
|
2021-01-31 19:55:11 -05:00
|
|
|
|
|
|
|
// Add the readable event to the handle table.
|
2021-04-10 05:34:26 -04:00
|
|
|
R_TRY(handle_table.Add(out_read, std::addressof(event->GetReadableEvent())));
|
2018-12-04 15:39:49 -05:00
|
|
|
|
2021-01-31 19:55:11 -05:00
|
|
|
// We succeeded.
|
|
|
|
handle_guard.Cancel();
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-12-04 15:39:49 -05:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result CreateEvent32(Core::System& system, Handle* out_write, Handle* out_read) {
|
2021-01-31 19:55:11 -05:00
|
|
|
return CreateEvent(system, out_write, out_read);
|
2020-06-19 19:40:07 -04:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result GetProcessInfo(Core::System& system, u64* out, Handle process_handle, u32 type) {
|
2018-10-13 14:31:46 -04:00
|
|
|
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, type=0x{:X}", process_handle, type);
|
|
|
|
|
2019-04-06 18:46:18 -04:00
|
|
|
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
2021-04-24 01:04:28 -04:00
|
|
|
KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle);
|
2021-04-18 01:21:59 -04:00
|
|
|
if (process.IsNull()) {
|
2018-11-26 03:47:39 -05:00
|
|
|
LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}",
|
|
|
|
process_handle);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidHandle;
|
2018-10-13 14:31:46 -04:00
|
|
|
}
|
|
|
|
|
2022-11-03 10:22:05 -04:00
|
|
|
const auto info_type = static_cast<ProcessInfoType>(type);
|
|
|
|
if (info_type != ProcessInfoType::ProcessState) {
|
|
|
|
LOG_ERROR(Kernel_SVC, "Expected info_type to be ProcessState but got {} instead", type);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidEnumValue;
|
2018-10-13 14:31:46 -04:00
|
|
|
}
|
|
|
|
|
2022-09-05 20:47:00 -04:00
|
|
|
*out = static_cast<u64>(process->GetState());
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-10-13 14:31:46 -04:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result CreateResourceLimit(Core::System& system, Handle* out_handle) {
|
2018-11-26 18:23:12 -05:00
|
|
|
LOG_DEBUG(Kernel_SVC, "called");
|
|
|
|
|
2021-04-21 00:28:11 -04:00
|
|
|
// Create a new resource limit.
|
2019-04-06 18:46:18 -04:00
|
|
|
auto& kernel = system.Kernel();
|
2021-04-21 00:28:11 -04:00
|
|
|
KResourceLimit* resource_limit = KResourceLimit::Create(kernel);
|
|
|
|
R_UNLESS(resource_limit != nullptr, ResultOutOfResource);
|
2018-11-26 18:23:12 -05:00
|
|
|
|
2021-04-21 00:28:11 -04:00
|
|
|
// Ensure we don't leak a reference to the limit.
|
|
|
|
SCOPE_EXIT({ resource_limit->Close(); });
|
2018-11-26 18:23:12 -05:00
|
|
|
|
2021-04-21 00:28:11 -04:00
|
|
|
// 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(kernel.CurrentProcess()->GetHandleTable().Add(out_handle, resource_limit));
|
2018-11-26 18:23:12 -05:00
|
|
|
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-11-26 18:23:12 -05:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result GetResourceLimitLimitValue(Core::System& system, u64* out_limit_value,
|
|
|
|
Handle resource_limit_handle, LimitableResource which) {
|
2021-04-21 00:28:11 -04:00
|
|
|
LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}", resource_limit_handle,
|
|
|
|
which);
|
2018-11-26 18:48:07 -05:00
|
|
|
|
2021-04-21 00:28:11 -04:00
|
|
|
// Validate the resource.
|
|
|
|
R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue);
|
|
|
|
|
|
|
|
// Get the resource limit.
|
|
|
|
auto& kernel = system.Kernel();
|
|
|
|
KScopedAutoObject resource_limit =
|
|
|
|
kernel.CurrentProcess()->GetHandleTable().GetObject<KResourceLimit>(resource_limit_handle);
|
|
|
|
R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle);
|
|
|
|
|
|
|
|
// Get the limit value.
|
|
|
|
*out_limit_value = resource_limit->GetLimitValue(which);
|
2018-11-26 18:48:07 -05:00
|
|
|
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-11-26 19:14:29 -05:00
|
|
|
}
|
2018-11-26 18:48:07 -05:00
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result GetResourceLimitCurrentValue(Core::System& system, u64* out_current_value,
|
|
|
|
Handle resource_limit_handle, LimitableResource which) {
|
2021-04-21 00:28:11 -04:00
|
|
|
LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}", resource_limit_handle,
|
|
|
|
which);
|
2018-11-26 19:14:29 -05:00
|
|
|
|
2021-04-21 00:28:11 -04:00
|
|
|
// Validate the resource.
|
|
|
|
R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue);
|
|
|
|
|
|
|
|
// Get the resource limit.
|
|
|
|
auto& kernel = system.Kernel();
|
|
|
|
KScopedAutoObject resource_limit =
|
|
|
|
kernel.CurrentProcess()->GetHandleTable().GetObject<KResourceLimit>(resource_limit_handle);
|
|
|
|
R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle);
|
|
|
|
|
|
|
|
// Get the current value.
|
|
|
|
*out_current_value = resource_limit->GetCurrentValue(which);
|
2018-11-26 18:48:07 -05:00
|
|
|
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-11-26 18:48:07 -05:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result SetResourceLimitLimitValue(Core::System& system, Handle resource_limit_handle,
|
|
|
|
LimitableResource which, u64 limit_value) {
|
2021-04-21 00:28:11 -04:00
|
|
|
LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}, limit_value={}",
|
|
|
|
resource_limit_handle, which, limit_value);
|
2018-11-26 19:51:09 -05:00
|
|
|
|
2021-04-21 00:28:11 -04:00
|
|
|
// Validate the resource.
|
|
|
|
R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue);
|
2018-11-26 19:51:09 -05:00
|
|
|
|
2021-04-21 00:28:11 -04:00
|
|
|
// Get the resource limit.
|
|
|
|
auto& kernel = system.Kernel();
|
|
|
|
KScopedAutoObject resource_limit =
|
|
|
|
kernel.CurrentProcess()->GetHandleTable().GetObject<KResourceLimit>(resource_limit_handle);
|
|
|
|
R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle);
|
2018-11-26 19:51:09 -05:00
|
|
|
|
2021-04-21 00:28:11 -04:00
|
|
|
// Set the limit value.
|
|
|
|
R_TRY(resource_limit->SetLimitValue(which, limit_value));
|
2018-11-26 19:51:09 -05:00
|
|
|
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2018-11-26 19:51:09 -05:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result GetProcessList(Core::System& system, u32* out_num_processes, VAddr out_process_ids,
|
|
|
|
u32 out_process_ids_size) {
|
2019-03-20 15:03:52 -04:00
|
|
|
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);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultOutOfRange;
|
2019-03-20 15:03:52 -04:00
|
|
|
}
|
|
|
|
|
2019-04-06 18:46:18 -04:00
|
|
|
const auto& kernel = system.Kernel();
|
2019-03-20 15:03:52 -04:00
|
|
|
const auto total_copy_size = out_process_ids_size * sizeof(u64);
|
|
|
|
|
2020-04-08 23:14:18 -04:00
|
|
|
if (out_process_ids_size > 0 && !kernel.CurrentProcess()->PageTable().IsInsideAddressSpace(
|
|
|
|
out_process_ids, total_copy_size)) {
|
2019-03-20 15:03:52 -04:00
|
|
|
LOG_ERROR(Kernel_SVC, "Address range outside address space. begin=0x{:016X}, end=0x{:016X}",
|
|
|
|
out_process_ids, out_process_ids + total_copy_size);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidCurrentMemory;
|
2019-03-20 15:03:52 -04:00
|
|
|
}
|
|
|
|
|
2019-11-26 17:39:57 -05:00
|
|
|
auto& memory = system.Memory();
|
2019-03-20 15:03:52 -04:00
|
|
|
const auto& process_list = kernel.GetProcessList();
|
|
|
|
const auto num_processes = process_list.size();
|
|
|
|
const auto copy_amount = std::min(std::size_t{out_process_ids_size}, num_processes);
|
|
|
|
|
|
|
|
for (std::size_t i = 0; i < copy_amount; ++i) {
|
2019-11-26 17:39:57 -05:00
|
|
|
memory.Write64(out_process_ids, process_list[i]->GetProcessID());
|
2019-03-20 15:03:52 -04:00
|
|
|
out_process_ids += sizeof(u64);
|
|
|
|
}
|
|
|
|
|
|
|
|
*out_num_processes = static_cast<u32>(num_processes);
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2019-03-20 15:03:52 -04:00
|
|
|
}
|
|
|
|
|
2022-06-25 23:44:19 -04:00
|
|
|
static Result GetThreadList(Core::System& system, u32* out_num_threads, VAddr out_thread_ids,
|
|
|
|
u32 out_thread_ids_size, Handle debug_handle) {
|
2019-03-20 18:53:48 -04:00
|
|
|
// 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);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultOutOfRange;
|
2019-03-20 18:53:48 -04:00
|
|
|
}
|
|
|
|
|
2022-06-13 18:36:30 -04:00
|
|
|
auto* const current_process = system.Kernel().CurrentProcess();
|
2019-03-20 18:53:48 -04:00
|
|
|
const auto total_copy_size = out_thread_ids_size * sizeof(u64);
|
|
|
|
|
|
|
|
if (out_thread_ids_size > 0 &&
|
2020-04-08 23:14:18 -04:00
|
|
|
!current_process->PageTable().IsInsideAddressSpace(out_thread_ids, total_copy_size)) {
|
2019-03-20 18:53:48 -04:00
|
|
|
LOG_ERROR(Kernel_SVC, "Address range outside address space. begin=0x{:016X}, end=0x{:016X}",
|
|
|
|
out_thread_ids, out_thread_ids + total_copy_size);
|
2021-02-12 18:43:01 -05:00
|
|
|
return ResultInvalidCurrentMemory;
|
2019-03-20 18:53:48 -04:00
|
|
|
}
|
|
|
|
|
2019-11-26 17:39:57 -05:00
|
|
|
auto& memory = system.Memory();
|
2019-03-20 18:53:48 -04:00
|
|
|
const auto& thread_list = current_process->GetThreadList();
|
|
|
|
const auto num_threads = thread_list.size();
|
|
|
|
const auto copy_amount = std::min(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) {
|
2019-11-26 17:39:57 -05:00
|
|
|
memory.Write64(out_thread_ids, (*list_iter)->GetThreadID());
|
2019-03-20 18:53:48 -04:00
|
|
|
out_thread_ids += sizeof(u64);
|
|
|
|
}
|
|
|
|
|
|
|
|
*out_num_threads = static_cast<u32>(num_threads);
|
2021-05-21 01:05:04 -04:00
|
|
|
return ResultSuccess;
|
2019-03-20 18:53:48 -04:00
|
|
|
}
|
|
|
|
|
2022-11-12 11:02:07 -05:00
|
|
|
static Result FlushProcessDataCache32(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 =
|
|
|
|
system.Kernel().CurrentProcess()->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));
|
2020-06-19 19:40:07 -04:00
|
|
|
}
|
|
|
|
|
2015-05-05 23:04:25 -04:00
|
|
|
namespace {
|
2016-09-17 20:38:01 -04:00
|
|
|
struct FunctionDef {
|
2019-04-06 18:46:18 -04:00
|
|
|
using Func = void(Core::System&);
|
2015-05-05 23:04:25 -04:00
|
|
|
|
2016-09-17 20:38:01 -04:00
|
|
|
u32 id;
|
|
|
|
Func* func;
|
|
|
|
const char* name;
|
|
|
|
};
|
2017-10-14 17:30:07 -04:00
|
|
|
} // namespace
|
2015-05-05 23:04:25 -04:00
|
|
|
|
2020-03-02 00:06:41 -05:00
|
|
|
static const FunctionDef SVC_Table_32[] = {
|
2022-02-08 22:02:51 -05:00
|
|
|
{0x00, nullptr, "Unknown0"},
|
2020-03-02 00:06:41 -05:00
|
|
|
{0x01, SvcWrap32<SetHeapSize32>, "SetHeapSize32"},
|
2022-02-08 22:02:51 -05:00
|
|
|
{0x02, nullptr, "SetMemoryPermission32"},
|
2020-06-18 20:33:04 -04:00
|
|
|
{0x03, SvcWrap32<SetMemoryAttribute32>, "SetMemoryAttribute32"},
|
2020-06-19 19:40:07 -04:00
|
|
|
{0x04, SvcWrap32<MapMemory32>, "MapMemory32"},
|
|
|
|
{0x05, SvcWrap32<UnmapMemory32>, "UnmapMemory32"},
|
2020-03-02 00:06:41 -05:00
|
|
|
{0x06, SvcWrap32<QueryMemory32>, "QueryMemory32"},
|
2020-06-19 19:40:07 -04:00
|
|
|
{0x07, SvcWrap32<ExitProcess32>, "ExitProcess32"},
|
|
|
|
{0x08, SvcWrap32<CreateThread32>, "CreateThread32"},
|
|
|
|
{0x09, SvcWrap32<StartThread32>, "StartThread32"},
|
|
|
|
{0x0a, SvcWrap32<ExitThread32>, "ExitThread32"},
|
|
|
|
{0x0b, SvcWrap32<SleepThread32>, "SleepThread32"},
|
2020-03-02 00:06:41 -05:00
|
|
|
{0x0c, SvcWrap32<GetThreadPriority32>, "GetThreadPriority32"},
|
2020-06-18 18:15:19 -04:00
|
|
|
{0x0d, SvcWrap32<SetThreadPriority32>, "SetThreadPriority32"},
|
2020-06-19 19:40:07 -04:00
|
|
|
{0x0e, SvcWrap32<GetThreadCoreMask32>, "GetThreadCoreMask32"},
|
2020-06-18 18:15:19 -04:00
|
|
|
{0x0f, SvcWrap32<SetThreadCoreMask32>, "SetThreadCoreMask32"},
|
2020-06-18 20:33:04 -04:00
|
|
|
{0x10, SvcWrap32<GetCurrentProcessorNumber32>, "GetCurrentProcessorNumber32"},
|
2020-06-19 19:40:07 -04:00
|
|
|
{0x11, SvcWrap32<SignalEvent32>, "SignalEvent32"},
|
|
|
|
{0x12, SvcWrap32<ClearEvent32>, "ClearEvent32"},
|
|
|
|
{0x13, SvcWrap32<MapSharedMemory32>, "MapSharedMemory32"},
|
2021-04-30 17:53:22 -04:00
|
|
|
{0x14, SvcWrap32<UnmapSharedMemory32>, "UnmapSharedMemory32"},
|
2020-06-18 20:33:04 -04:00
|
|
|
{0x15, SvcWrap32<CreateTransferMemory32>, "CreateTransferMemory32"},
|
2020-03-02 00:06:41 -05:00
|
|
|
{0x16, SvcWrap32<CloseHandle32>, "CloseHandle32"},
|
2020-06-19 19:40:07 -04:00
|
|
|
{0x17, SvcWrap32<ResetSignal32>, "ResetSignal32"},
|
2020-03-02 00:06:41 -05:00
|
|
|
{0x18, SvcWrap32<WaitSynchronization32>, "WaitSynchronization32"},
|
2020-06-19 19:40:07 -04:00
|
|
|
{0x19, SvcWrap32<CancelSynchronization32>, "CancelSynchronization32"},
|
|
|
|
{0x1a, SvcWrap32<ArbitrateLock32>, "ArbitrateLock32"},
|
|
|
|
{0x1b, SvcWrap32<ArbitrateUnlock32>, "ArbitrateUnlock32"},
|
|
|
|
{0x1c, SvcWrap32<WaitProcessWideKeyAtomic32>, "WaitProcessWideKeyAtomic32"},
|
2020-03-02 00:06:41 -05:00
|
|
|
{0x1d, SvcWrap32<SignalProcessWideKey32>, "SignalProcessWideKey32"},
|
2020-06-19 19:40:07 -04:00
|
|
|
{0x1e, SvcWrap32<GetSystemTick32>, "GetSystemTick32"},
|
2020-03-02 00:06:41 -05:00
|
|
|
{0x1f, SvcWrap32<ConnectToNamedPort32>, "ConnectToNamedPort32"},
|
2022-02-08 22:02:51 -05:00
|
|
|
{0x20, nullptr, "SendSyncRequestLight32"},
|
2020-03-02 00:06:41 -05:00
|
|
|
{0x21, SvcWrap32<SendSyncRequest32>, "SendSyncRequest32"},
|
|
|
|
{0x22, nullptr, "SendSyncRequestWithUserBuffer32"},
|
2022-02-08 22:02:51 -05:00
|
|
|
{0x23, nullptr, "SendAsyncRequestWithUserBuffer32"},
|
2020-06-19 19:40:07 -04:00
|
|
|
{0x24, SvcWrap32<GetProcessId32>, "GetProcessId32"},
|
2020-03-02 00:06:41 -05:00
|
|
|
{0x25, SvcWrap32<GetThreadId32>, "GetThreadId32"},
|
2020-06-19 19:40:07 -04:00
|
|
|
{0x26, SvcWrap32<Break32>, "Break32"},
|
2022-02-08 13:46:45 -05:00
|
|
|
{0x27, SvcWrap32<OutputDebugString32>, "OutputDebugString32"},
|
2022-02-08 22:02:51 -05:00
|
|
|
{0x28, nullptr, "ReturnFromException32"},
|
2020-03-02 00:06:41 -05:00
|
|
|
{0x29, SvcWrap32<GetInfo32>, "GetInfo32"},
|
2022-02-08 22:02:51 -05:00
|
|
|
{0x2a, nullptr, "FlushEntireDataCache32"},
|
|
|
|
{0x2b, nullptr, "FlushDataCache32"},
|
2020-06-19 19:40:07 -04:00
|
|
|
{0x2c, SvcWrap32<MapPhysicalMemory32>, "MapPhysicalMemory32"},
|
|
|
|
{0x2d, SvcWrap32<UnmapPhysicalMemory32>, "UnmapPhysicalMemory32"},
|
2022-02-08 22:02:51 -05:00
|
|
|
{0x2e, nullptr, "GetDebugFutureThreadInfo32"},
|
|
|
|
{0x2f, nullptr, "GetLastThreadInfo32"},
|
|
|
|
{0x30, nullptr, "GetResourceLimitLimitValue32"},
|
|
|
|
{0x31, nullptr, "GetResourceLimitCurrentValue32"},
|
2020-06-19 19:40:07 -04:00
|
|
|
{0x32, SvcWrap32<SetThreadActivity32>, "SetThreadActivity32"},
|
|
|
|
{0x33, SvcWrap32<GetThreadContext32>, "GetThreadContext32"},
|
|
|
|
{0x34, SvcWrap32<WaitForAddress32>, "WaitForAddress32"},
|
|
|
|
{0x35, SvcWrap32<SignalToAddress32>, "SignalToAddress32"},
|
2022-01-31 20:02:12 -05:00
|
|
|
{0x36, SvcWrap32<SynchronizePreemptionState>, "SynchronizePreemptionState32"},
|
2022-02-08 22:02:51 -05:00
|
|
|
{0x37, nullptr, "GetResourceLimitPeakValue32"},
|
|
|
|
{0x38, nullptr, "Unknown38"},
|
|
|
|
{0x39, nullptr, "CreateIoPool32"},
|
|
|
|
{0x3a, nullptr, "CreateIoRegion32"},
|
|
|
|
{0x3b, nullptr, "Unknown3b"},
|
|
|
|
{0x3c, nullptr, "KernelDebug32"},
|
|
|
|
{0x3d, nullptr, "ChangeKernelTraceState32"},
|
|
|
|
{0x3e, nullptr, "Unknown3e"},
|
|
|
|
{0x3f, nullptr, "Unknown3f"},
|
2020-03-02 00:06:41 -05:00
|
|
|
{0x40, nullptr, "CreateSession32"},
|
|
|
|
{0x41, nullptr, "AcceptSession32"},
|
2022-02-08 22:02:51 -05:00
|
|
|
{0x42, nullptr, "ReplyAndReceiveLight32"},
|
2020-03-02 00:06:41 -05:00
|
|
|
{0x43, nullptr, "ReplyAndReceive32"},
|
2022-02-08 22:02:51 -05:00
|
|
|
{0x44, nullptr, "ReplyAndReceiveWithUserBuffer32"},
|
2020-06-19 19:40:07 -04:00
|
|
|
{0x45, SvcWrap32<CreateEvent32>, "CreateEvent32"},
|
2022-02-08 22:02:51 -05:00
|
|
|
{0x46, nullptr, "MapIoRegion32"},
|
|
|
|
{0x47, nullptr, "UnmapIoRegion32"},
|
|
|
|
{0x48, nullptr, "MapPhysicalMemoryUnsafe32"},
|
|
|
|
{0x49, nullptr, "UnmapPhysicalMemoryUnsafe32"},
|
|
|
|
{0x4a, nullptr, "SetUnsafeLimit32"},
|
2022-02-08 13:46:45 -05:00
|
|
|
{0x4b, SvcWrap32<CreateCodeMemory32>, "CreateCodeMemory32"},
|
|
|
|
{0x4c, SvcWrap32<ControlCodeMemory32>, "ControlCodeMemory32"},
|
2022-02-08 22:02:51 -05:00
|
|
|
{0x4d, nullptr, "SleepSystem32"},
|
|
|
|
{0x4e, nullptr, "ReadWriteRegister32"},
|
|
|
|
{0x4f, nullptr, "SetProcessActivity32"},
|
|
|
|
{0x50, nullptr, "CreateSharedMemory32"},
|
|
|
|
{0x51, nullptr, "MapTransferMemory32"},
|
|
|
|
{0x52, nullptr, "UnmapTransferMemory32"},
|
|
|
|
{0x53, nullptr, "CreateInterruptEvent32"},
|
|
|
|
{0x54, nullptr, "QueryPhysicalAddress32"},
|
|
|
|
{0x55, nullptr, "QueryIoMapping32"},
|
|
|
|
{0x56, nullptr, "CreateDeviceAddressSpace32"},
|
|
|
|
{0x57, nullptr, "AttachDeviceAddressSpace32"},
|
|
|
|
{0x58, nullptr, "DetachDeviceAddressSpace32"},
|
|
|
|
{0x59, nullptr, "MapDeviceAddressSpaceByForce32"},
|
|
|
|
{0x5a, nullptr, "MapDeviceAddressSpaceAligned32"},
|
|
|
|
{0x5b, nullptr, "MapDeviceAddressSpace32"},
|
|
|
|
{0x5c, nullptr, "UnmapDeviceAddressSpace32"},
|
|
|
|
{0x5d, nullptr, "InvalidateProcessDataCache32"},
|
|
|
|
{0x5e, nullptr, "StoreProcessDataCache32"},
|
2020-06-19 19:40:07 -04:00
|
|
|
{0x5F, SvcWrap32<FlushProcessDataCache32>, "FlushProcessDataCache32"},
|
2022-02-08 22:02:51 -05:00
|
|
|
{0x60, nullptr, "StoreProcessDataCache32"},
|
|
|
|
{0x61, nullptr, "BreakDebugProcess32"},
|
|
|
|
{0x62, nullptr, "TerminateDebugProcess32"},
|
|
|
|
{0x63, nullptr, "GetDebugEvent32"},
|
|
|
|
{0x64, nullptr, "ContinueDebugEvent32"},
|
2020-03-02 00:06:41 -05:00
|
|
|
{0x65, nullptr, "GetProcessList32"},
|
2022-02-08 22:02:51 -05:00
|
|
|
{0x66, nullptr, "GetThreadList"},
|
|
|
|
{0x67, nullptr, "GetDebugThreadContext32"},
|
|
|
|
{0x68, nullptr, "SetDebugThreadContext32"},
|
|
|
|
{0x69, nullptr, "QueryDebugProcessMemory32"},
|
|
|
|
{0x6A, nullptr, "ReadDebugProcessMemory32"},
|
|
|
|
{0x6B, nullptr, "WriteDebugProcessMemory32"},
|
|
|
|
{0x6C, nullptr, "SetHardwareBreakPoint32"},
|
|
|
|
{0x6D, nullptr, "GetDebugThreadParam32"},
|
|
|
|
{0x6E, nullptr, "Unknown6E"},
|
2020-03-02 00:06:41 -05:00
|
|
|
{0x6f, nullptr, "GetSystemInfo32"},
|
|
|
|
{0x70, nullptr, "CreatePort32"},
|
|
|
|
{0x71, nullptr, "ManageNamedPort32"},
|
|
|
|
{0x72, nullptr, "ConnectToPort32"},
|
|
|
|
{0x73, nullptr, "SetProcessMemoryPermission32"},
|
2022-02-08 22:02:51 -05:00
|
|
|
{0x74, nullptr, "MapProcessMemory32"},
|
|
|
|
{0x75, nullptr, "UnmapProcessMemory32"},
|
|
|
|
{0x76, nullptr, "QueryProcessMemory32"},
|
2020-03-02 00:06:41 -05:00
|
|
|
{0x77, nullptr, "MapProcessCodeMemory32"},
|
|
|
|
{0x78, nullptr, "UnmapProcessCodeMemory32"},
|
2022-02-08 22:02:51 -05:00
|
|
|
{0x79, nullptr, "CreateProcess32"},
|
|
|
|
{0x7A, nullptr, "StartProcess32"},
|
2020-03-02 00:06:41 -05:00
|
|
|
{0x7B, nullptr, "TerminateProcess32"},
|
2021-04-07 00:55:31 -04:00
|
|
|
{0x7C, nullptr, "GetProcessInfo32"},
|
|
|
|
{0x7D, nullptr, "CreateResourceLimit32"},
|
|
|
|
{0x7E, nullptr, "SetResourceLimitLimitValue32"},
|
|
|
|
{0x7F, nullptr, "CallSecureMonitor32"},
|
|
|
|
{0x80, nullptr, "Unknown"},
|
|
|
|
{0x81, nullptr, "Unknown"},
|
|
|
|
{0x82, nullptr, "Unknown"},
|
|
|
|
{0x83, nullptr, "Unknown"},
|
|
|
|
{0x84, nullptr, "Unknown"},
|
|
|
|
{0x85, nullptr, "Unknown"},
|
|
|
|
{0x86, nullptr, "Unknown"},
|
|
|
|
{0x87, nullptr, "Unknown"},
|
|
|
|
{0x88, nullptr, "Unknown"},
|
|
|
|
{0x89, nullptr, "Unknown"},
|
|
|
|
{0x8A, nullptr, "Unknown"},
|
|
|
|
{0x8B, nullptr, "Unknown"},
|
|
|
|
{0x8C, nullptr, "Unknown"},
|
|
|
|
{0x8D, nullptr, "Unknown"},
|
|
|
|
{0x8E, nullptr, "Unknown"},
|
|
|
|
{0x8F, nullptr, "Unknown"},
|
|
|
|
{0x90, nullptr, "Unknown"},
|
|
|
|
{0x91, nullptr, "Unknown"},
|
|
|
|
{0x92, nullptr, "Unknown"},
|
|
|
|
{0x93, nullptr, "Unknown"},
|
|
|
|
{0x94, nullptr, "Unknown"},
|
|
|
|
{0x95, nullptr, "Unknown"},
|
|
|
|
{0x96, nullptr, "Unknown"},
|
|
|
|
{0x97, nullptr, "Unknown"},
|
|
|
|
{0x98, nullptr, "Unknown"},
|
|
|
|
{0x99, nullptr, "Unknown"},
|
|
|
|
{0x9A, nullptr, "Unknown"},
|
|
|
|
{0x9B, nullptr, "Unknown"},
|
|
|
|
{0x9C, nullptr, "Unknown"},
|
|
|
|
{0x9D, nullptr, "Unknown"},
|
|
|
|
{0x9E, nullptr, "Unknown"},
|
|
|
|
{0x9F, nullptr, "Unknown"},
|
|
|
|
{0xA0, nullptr, "Unknown"},
|
|
|
|
{0xA1, nullptr, "Unknown"},
|
|
|
|
{0xA2, nullptr, "Unknown"},
|
|
|
|
{0xA3, nullptr, "Unknown"},
|
|
|
|
{0xA4, nullptr, "Unknown"},
|
|
|
|
{0xA5, nullptr, "Unknown"},
|
|
|
|
{0xA6, nullptr, "Unknown"},
|
|
|
|
{0xA7, nullptr, "Unknown"},
|
|
|
|
{0xA8, nullptr, "Unknown"},
|
|
|
|
{0xA9, nullptr, "Unknown"},
|
|
|
|
{0xAA, nullptr, "Unknown"},
|
|
|
|
{0xAB, nullptr, "Unknown"},
|
|
|
|
{0xAC, nullptr, "Unknown"},
|
|
|
|
{0xAD, nullptr, "Unknown"},
|
|
|
|
{0xAE, nullptr, "Unknown"},
|
|
|
|
{0xAF, nullptr, "Unknown"},
|
|
|
|
{0xB0, nullptr, "Unknown"},
|
|
|
|
{0xB1, nullptr, "Unknown"},
|
|
|
|
{0xB2, nullptr, "Unknown"},
|
|
|
|
{0xB3, nullptr, "Unknown"},
|
|
|
|
{0xB4, nullptr, "Unknown"},
|
|
|
|
{0xB5, nullptr, "Unknown"},
|
|
|
|
{0xB6, nullptr, "Unknown"},
|
|
|
|
{0xB7, nullptr, "Unknown"},
|
|
|
|
{0xB8, nullptr, "Unknown"},
|
|
|
|
{0xB9, nullptr, "Unknown"},
|
|
|
|
{0xBA, nullptr, "Unknown"},
|
|
|
|
{0xBB, nullptr, "Unknown"},
|
|
|
|
{0xBC, nullptr, "Unknown"},
|
|
|
|
{0xBD, nullptr, "Unknown"},
|
|
|
|
{0xBE, nullptr, "Unknown"},
|
|
|
|
{0xBF, nullptr, "Unknown"},
|
2020-03-02 00:06:41 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
static const FunctionDef SVC_Table_64[] = {
|
2022-02-08 22:02:51 -05:00
|
|
|
{0x00, nullptr, "Unknown0"},
|
2020-03-02 00:06:41 -05:00
|
|
|
{0x01, SvcWrap64<SetHeapSize>, "SetHeapSize"},
|
2021-12-23 04:10:36 -05:00
|
|
|
{0x02, SvcWrap64<SetMemoryPermission>, "SetMemoryPermission"},
|
2020-03-02 00:06:41 -05:00
|
|
|
{0x03, SvcWrap64<SetMemoryAttribute>, "SetMemoryAttribute"},
|
|
|
|
{0x04, SvcWrap64<MapMemory>, "MapMemory"},
|
|
|
|
{0x05, SvcWrap64<UnmapMemory>, "UnmapMemory"},
|
|
|
|
{0x06, SvcWrap64<QueryMemory>, "QueryMemory"},
|
|
|
|
{0x07, SvcWrap64<ExitProcess>, "ExitProcess"},
|
|
|
|
{0x08, SvcWrap64<CreateThread>, "CreateThread"},
|
|
|
|
{0x09, SvcWrap64<StartThread>, "StartThread"},
|
|
|
|
{0x0A, SvcWrap64<ExitThread>, "ExitThread"},
|
|
|
|
{0x0B, SvcWrap64<SleepThread>, "SleepThread"},
|
|
|
|
{0x0C, SvcWrap64<GetThreadPriority>, "GetThreadPriority"},
|
|
|
|
{0x0D, SvcWrap64<SetThreadPriority>, "SetThreadPriority"},
|
|
|
|
{0x0E, SvcWrap64<GetThreadCoreMask>, "GetThreadCoreMask"},
|
|
|
|
{0x0F, SvcWrap64<SetThreadCoreMask>, "SetThreadCoreMask"},
|
|
|
|
{0x10, SvcWrap64<GetCurrentProcessorNumber>, "GetCurrentProcessorNumber"},
|
|
|
|
{0x11, SvcWrap64<SignalEvent>, "SignalEvent"},
|
|
|
|
{0x12, SvcWrap64<ClearEvent>, "ClearEvent"},
|
|
|
|
{0x13, SvcWrap64<MapSharedMemory>, "MapSharedMemory"},
|
2021-04-30 17:53:22 -04:00
|
|
|
{0x14, SvcWrap64<UnmapSharedMemory>, "UnmapSharedMemory"},
|
2020-03-02 00:06:41 -05:00
|
|
|
{0x15, SvcWrap64<CreateTransferMemory>, "CreateTransferMemory"},
|
|
|
|
{0x16, SvcWrap64<CloseHandle>, "CloseHandle"},
|
|
|
|
{0x17, SvcWrap64<ResetSignal>, "ResetSignal"},
|
|
|
|
{0x18, SvcWrap64<WaitSynchronization>, "WaitSynchronization"},
|
|
|
|
{0x19, SvcWrap64<CancelSynchronization>, "CancelSynchronization"},
|
|
|
|
{0x1A, SvcWrap64<ArbitrateLock>, "ArbitrateLock"},
|
|
|
|
{0x1B, SvcWrap64<ArbitrateUnlock>, "ArbitrateUnlock"},
|
|
|
|
{0x1C, SvcWrap64<WaitProcessWideKeyAtomic>, "WaitProcessWideKeyAtomic"},
|
|
|
|
{0x1D, SvcWrap64<SignalProcessWideKey>, "SignalProcessWideKey"},
|
|
|
|
{0x1E, SvcWrap64<GetSystemTick>, "GetSystemTick"},
|
|
|
|
{0x1F, SvcWrap64<ConnectToNamedPort>, "ConnectToNamedPort"},
|
2018-01-02 20:47:26 -05:00
|
|
|
{0x20, nullptr, "SendSyncRequestLight"},
|
2020-03-02 00:06:41 -05:00
|
|
|
{0x21, SvcWrap64<SendSyncRequest>, "SendSyncRequest"},
|
2018-01-02 20:47:26 -05:00
|
|
|
{0x22, nullptr, "SendSyncRequestWithUserBuffer"},
|
|
|
|
{0x23, nullptr, "SendAsyncRequestWithUserBuffer"},
|
2020-03-02 00:06:41 -05:00
|
|
|
{0x24, SvcWrap64<GetProcessId>, "GetProcessId"},
|
|
|
|
{0x25, SvcWrap64<GetThreadId>, "GetThreadId"},
|
|
|
|
{0x26, SvcWrap64<Break>, "Break"},
|
|
|
|
{0x27, SvcWrap64<OutputDebugString>, "OutputDebugString"},
|
2018-01-02 20:47:26 -05:00
|
|
|
{0x28, nullptr, "ReturnFromException"},
|
2020-03-02 00:06:41 -05:00
|
|
|
{0x29, SvcWrap64<GetInfo>, "GetInfo"},
|
2018-01-02 20:47:26 -05:00
|
|
|
{0x2A, nullptr, "FlushEntireDataCache"},
|
|
|
|
{0x2B, nullptr, "FlushDataCache"},
|
2020-03-02 00:06:41 -05:00
|
|
|
{0x2C, SvcWrap64<MapPhysicalMemory>, "MapPhysicalMemory"},
|
|
|
|
{0x2D, SvcWrap64<UnmapPhysicalMemory>, "UnmapPhysicalMemory"},
|
2018-09-23 20:03:38 -04:00
|
|
|
{0x2E, nullptr, "GetFutureThreadInfo"},
|
2018-01-02 20:47:26 -05:00
|
|
|
{0x2F, nullptr, "GetLastThreadInfo"},
|
2020-03-02 00:06:41 -05:00
|
|
|
{0x30, SvcWrap64<GetResourceLimitLimitValue>, "GetResourceLimitLimitValue"},
|
|
|
|
{0x31, SvcWrap64<GetResourceLimitCurrentValue>, "GetResourceLimitCurrentValue"},
|
|
|
|
{0x32, SvcWrap64<SetThreadActivity>, "SetThreadActivity"},
|
|
|
|
{0x33, SvcWrap64<GetThreadContext>, "GetThreadContext"},
|
|
|
|
{0x34, SvcWrap64<WaitForAddress>, "WaitForAddress"},
|
|
|
|
{0x35, SvcWrap64<SignalToAddress>, "SignalToAddress"},
|
2021-12-30 00:40:38 -05:00
|
|
|
{0x36, SvcWrap64<SynchronizePreemptionState>, "SynchronizePreemptionState"},
|
2022-02-08 22:02:51 -05:00
|
|
|
{0x37, nullptr, "GetResourceLimitPeakValue"},
|
|
|
|
{0x38, nullptr, "Unknown38"},
|
|
|
|
{0x39, nullptr, "CreateIoPool"},
|
|
|
|
{0x3A, nullptr, "CreateIoRegion"},
|
|
|
|
{0x3B, nullptr, "Unknown3B"},
|
2020-03-02 00:06:41 -05:00
|
|
|
{0x3C, SvcWrap64<KernelDebug>, "KernelDebug"},
|
|
|
|
{0x3D, SvcWrap64<ChangeKernelTraceState>, "ChangeKernelTraceState"},
|
2022-02-08 22:02:51 -05:00
|
|
|
{0x3E, nullptr, "Unknown3e"},
|
|
|
|
{0x3F, nullptr, "Unknown3f"},
|
2022-10-03 22:52:52 -04:00
|
|
|
{0x40, SvcWrap64<CreateSession>, "CreateSession"},
|
2018-01-02 20:47:26 -05:00
|
|
|
{0x41, nullptr, "AcceptSession"},
|
|
|
|
{0x42, nullptr, "ReplyAndReceiveLight"},
|
2022-10-11 18:16:56 -04:00
|
|
|
{0x43, SvcWrap64<ReplyAndReceive>, "ReplyAndReceive"},
|
2018-01-02 20:47:26 -05:00
|
|
|
{0x44, nullptr, "ReplyAndReceiveWithUserBuffer"},
|
2020-03-02 00:06:41 -05:00
|
|
|
{0x45, SvcWrap64<CreateEvent>, "CreateEvent"},
|
2022-02-08 22:02:51 -05:00
|
|
|
{0x46, nullptr, "MapIoRegion"},
|
|
|
|
{0x47, nullptr, "UnmapIoRegion"},
|
2018-09-23 20:03:38 -04:00
|
|
|
{0x48, nullptr, "MapPhysicalMemoryUnsafe"},
|
|
|
|
{0x49, nullptr, "UnmapPhysicalMemoryUnsafe"},
|
|
|
|
{0x4A, nullptr, "SetUnsafeLimit"},
|
2021-12-05 15:04:08 -05:00
|
|
|
{0x4B, SvcWrap64<CreateCodeMemory>, "CreateCodeMemory"},
|
|
|
|
{0x4C, SvcWrap64<ControlCodeMemory>, "ControlCodeMemory"},
|
2018-01-02 20:47:26 -05:00
|
|
|
{0x4D, nullptr, "SleepSystem"},
|
|
|
|
{0x4E, nullptr, "ReadWriteRegister"},
|
|
|
|
{0x4F, nullptr, "SetProcessActivity"},
|
2020-04-08 23:14:18 -04:00
|
|
|
{0x50, nullptr, "CreateSharedMemory"},
|
|
|
|
{0x51, nullptr, "MapTransferMemory"},
|
|
|
|
{0x52, nullptr, "UnmapTransferMemory"},
|
2018-01-02 20:47:26 -05:00
|
|
|
{0x53, nullptr, "CreateInterruptEvent"},
|
|
|
|
{0x54, nullptr, "QueryPhysicalAddress"},
|
|
|
|
{0x55, nullptr, "QueryIoMapping"},
|
|
|
|
{0x56, nullptr, "CreateDeviceAddressSpace"},
|
|
|
|
{0x57, nullptr, "AttachDeviceAddressSpace"},
|
|
|
|
{0x58, nullptr, "DetachDeviceAddressSpace"},
|
|
|
|
{0x59, nullptr, "MapDeviceAddressSpaceByForce"},
|
|
|
|
{0x5A, nullptr, "MapDeviceAddressSpaceAligned"},
|
|
|
|
{0x5B, nullptr, "MapDeviceAddressSpace"},
|
|
|
|
{0x5C, nullptr, "UnmapDeviceAddressSpace"},
|
|
|
|
{0x5D, nullptr, "InvalidateProcessDataCache"},
|
|
|
|
{0x5E, nullptr, "StoreProcessDataCache"},
|
|
|
|
{0x5F, nullptr, "FlushProcessDataCache"},
|
|
|
|
{0x60, nullptr, "DebugActiveProcess"},
|
|
|
|
{0x61, nullptr, "BreakDebugProcess"},
|
|
|
|
{0x62, nullptr, "TerminateDebugProcess"},
|
|
|
|
{0x63, nullptr, "GetDebugEvent"},
|
|
|
|
{0x64, nullptr, "ContinueDebugEvent"},
|
2020-03-02 00:06:41 -05:00
|
|
|
{0x65, SvcWrap64<GetProcessList>, "GetProcessList"},
|
|
|
|
{0x66, SvcWrap64<GetThreadList>, "GetThreadList"},
|
2018-01-02 20:47:26 -05:00
|
|
|
{0x67, nullptr, "GetDebugThreadContext"},
|
|
|
|
{0x68, nullptr, "SetDebugThreadContext"},
|
|
|
|
{0x69, nullptr, "QueryDebugProcessMemory"},
|
|
|
|
{0x6A, nullptr, "ReadDebugProcessMemory"},
|
|
|
|
{0x6B, nullptr, "WriteDebugProcessMemory"},
|
|
|
|
{0x6C, nullptr, "SetHardwareBreakPoint"},
|
|
|
|
{0x6D, nullptr, "GetDebugThreadParam"},
|
2022-02-08 22:02:51 -05:00
|
|
|
{0x6E, nullptr, "Unknown6E"},
|
2018-09-23 20:03:38 -04:00
|
|
|
{0x6F, nullptr, "GetSystemInfo"},
|
2018-01-02 20:47:26 -05:00
|
|
|
{0x70, nullptr, "CreatePort"},
|
|
|
|
{0x71, nullptr, "ManageNamedPort"},
|
|
|
|
{0x72, nullptr, "ConnectToPort"},
|
2021-11-20 20:23:59 -05:00
|
|
|
{0x73, SvcWrap64<SetProcessMemoryPermission>, "SetProcessMemoryPermission"},
|
2021-12-05 15:04:08 -05:00
|
|
|
{0x74, SvcWrap64<MapProcessMemory>, "MapProcessMemory"},
|
|
|
|
{0x75, SvcWrap64<UnmapProcessMemory>, "UnmapProcessMemory"},
|
2020-03-02 00:06:41 -05:00
|
|
|
{0x76, SvcWrap64<QueryProcessMemory>, "QueryProcessMemory"},
|
2020-04-23 18:05:09 -04:00
|
|
|
{0x77, SvcWrap64<MapProcessCodeMemory>, "MapProcessCodeMemory"},
|
|
|
|
{0x78, SvcWrap64<UnmapProcessCodeMemory>, "UnmapProcessCodeMemory"},
|
2018-01-02 20:47:26 -05:00
|
|
|
{0x79, nullptr, "CreateProcess"},
|
|
|
|
{0x7A, nullptr, "StartProcess"},
|
|
|
|
{0x7B, nullptr, "TerminateProcess"},
|
2020-03-02 00:06:41 -05:00
|
|
|
{0x7C, SvcWrap64<GetProcessInfo>, "GetProcessInfo"},
|
|
|
|
{0x7D, SvcWrap64<CreateResourceLimit>, "CreateResourceLimit"},
|
|
|
|
{0x7E, SvcWrap64<SetResourceLimitLimitValue>, "SetResourceLimitLimitValue"},
|
2018-01-02 20:47:26 -05:00
|
|
|
{0x7F, nullptr, "CallSecureMonitor"},
|
2021-04-07 00:55:31 -04:00
|
|
|
{0x80, nullptr, "Unknown"},
|
|
|
|
{0x81, nullptr, "Unknown"},
|
|
|
|
{0x82, nullptr, "Unknown"},
|
|
|
|
{0x83, nullptr, "Unknown"},
|
|
|
|
{0x84, nullptr, "Unknown"},
|
|
|
|
{0x85, nullptr, "Unknown"},
|
|
|
|
{0x86, nullptr, "Unknown"},
|
|
|
|
{0x87, nullptr, "Unknown"},
|
|
|
|
{0x88, nullptr, "Unknown"},
|
|
|
|
{0x89, nullptr, "Unknown"},
|
|
|
|
{0x8A, nullptr, "Unknown"},
|
|
|
|
{0x8B, nullptr, "Unknown"},
|
|
|
|
{0x8C, nullptr, "Unknown"},
|
|
|
|
{0x8D, nullptr, "Unknown"},
|
|
|
|
{0x8E, nullptr, "Unknown"},
|
|
|
|
{0x8F, nullptr, "Unknown"},
|
|
|
|
{0x90, nullptr, "Unknown"},
|
|
|
|
{0x91, nullptr, "Unknown"},
|
|
|
|
{0x92, nullptr, "Unknown"},
|
|
|
|
{0x93, nullptr, "Unknown"},
|
|
|
|
{0x94, nullptr, "Unknown"},
|
|
|
|
{0x95, nullptr, "Unknown"},
|
|
|
|
{0x96, nullptr, "Unknown"},
|
|
|
|
{0x97, nullptr, "Unknown"},
|
|
|
|
{0x98, nullptr, "Unknown"},
|
|
|
|
{0x99, nullptr, "Unknown"},
|
|
|
|
{0x9A, nullptr, "Unknown"},
|
|
|
|
{0x9B, nullptr, "Unknown"},
|
|
|
|
{0x9C, nullptr, "Unknown"},
|
|
|
|
{0x9D, nullptr, "Unknown"},
|
|
|
|
{0x9E, nullptr, "Unknown"},
|
|
|
|
{0x9F, nullptr, "Unknown"},
|
|
|
|
{0xA0, nullptr, "Unknown"},
|
|
|
|
{0xA1, nullptr, "Unknown"},
|
|
|
|
{0xA2, nullptr, "Unknown"},
|
|
|
|
{0xA3, nullptr, "Unknown"},
|
|
|
|
{0xA4, nullptr, "Unknown"},
|
|
|
|
{0xA5, nullptr, "Unknown"},
|
|
|
|
{0xA6, nullptr, "Unknown"},
|
|
|
|
{0xA7, nullptr, "Unknown"},
|
|
|
|
{0xA8, nullptr, "Unknown"},
|
|
|
|
{0xA9, nullptr, "Unknown"},
|
|
|
|
{0xAA, nullptr, "Unknown"},
|
|
|
|
{0xAB, nullptr, "Unknown"},
|
|
|
|
{0xAC, nullptr, "Unknown"},
|
|
|
|
{0xAD, nullptr, "Unknown"},
|
|
|
|
{0xAE, nullptr, "Unknown"},
|
|
|
|
{0xAF, nullptr, "Unknown"},
|
|
|
|
{0xB0, nullptr, "Unknown"},
|
|
|
|
{0xB1, nullptr, "Unknown"},
|
|
|
|
{0xB2, nullptr, "Unknown"},
|
|
|
|
{0xB3, nullptr, "Unknown"},
|
|
|
|
{0xB4, nullptr, "Unknown"},
|
|
|
|
{0xB5, nullptr, "Unknown"},
|
|
|
|
{0xB6, nullptr, "Unknown"},
|
|
|
|
{0xB7, nullptr, "Unknown"},
|
|
|
|
{0xB8, nullptr, "Unknown"},
|
|
|
|
{0xB9, nullptr, "Unknown"},
|
|
|
|
{0xBA, nullptr, "Unknown"},
|
|
|
|
{0xBB, nullptr, "Unknown"},
|
|
|
|
{0xBC, nullptr, "Unknown"},
|
|
|
|
{0xBD, nullptr, "Unknown"},
|
|
|
|
{0xBE, nullptr, "Unknown"},
|
|
|
|
{0xBF, nullptr, "Unknown"},
|
2014-04-10 19:58:28 -04:00
|
|
|
};
|
|
|
|
|
2020-03-02 00:06:41 -05:00
|
|
|
static const FunctionDef* GetSVCInfo32(u32 func_num) {
|
|
|
|
if (func_num >= std::size(SVC_Table_32)) {
|
|
|
|
LOG_ERROR(Kernel_SVC, "Unknown svc=0x{:02X}", func_num);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return &SVC_Table_32[func_num];
|
|
|
|
}
|
|
|
|
|
|
|
|
static const FunctionDef* GetSVCInfo64(u32 func_num) {
|
|
|
|
if (func_num >= std::size(SVC_Table_64)) {
|
2018-07-02 12:13:26 -04:00
|
|
|
LOG_ERROR(Kernel_SVC, "Unknown svc=0x{:02X}", func_num);
|
2015-05-05 23:04:25 -04:00
|
|
|
return nullptr;
|
|
|
|
}
|
2020-03-02 00:06:41 -05:00
|
|
|
return &SVC_Table_64[func_num];
|
2015-05-05 23:04:25 -04:00
|
|
|
}
|
|
|
|
|
2020-03-26 20:00:30 -04:00
|
|
|
void Call(Core::System& system, u32 immediate) {
|
2020-03-12 16:48:43 -04:00
|
|
|
auto& kernel = system.Kernel();
|
|
|
|
kernel.EnterSVCProfile();
|
2015-05-05 23:04:25 -04:00
|
|
|
|
2022-06-16 10:35:52 -04:00
|
|
|
auto* thread = GetCurrentThreadPointer(kernel);
|
2021-01-20 16:42:27 -05:00
|
|
|
thread->SetIsCallingSvc();
|
2020-11-13 14:11:12 -05:00
|
|
|
|
2020-03-02 00:06:41 -05:00
|
|
|
const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate)
|
|
|
|
: GetSVCInfo32(immediate);
|
2015-05-05 23:04:25 -04:00
|
|
|
if (info) {
|
|
|
|
if (info->func) {
|
2019-04-06 18:46:18 -04:00
|
|
|
info->func(system);
|
2015-05-05 23:04:25 -04:00
|
|
|
} else {
|
2018-07-02 12:13:26 -04:00
|
|
|
LOG_CRITICAL(Kernel_SVC, "Unimplemented SVC function {}(..)", info->name);
|
2015-05-05 23:04:25 -04:00
|
|
|
}
|
2017-10-14 17:30:07 -04:00
|
|
|
} else {
|
2018-07-02 12:13:26 -04:00
|
|
|
LOG_CRITICAL(Kernel_SVC, "Unknown SVC function 0x{:X}", immediate);
|
2015-05-05 23:04:25 -04:00
|
|
|
}
|
2020-03-10 18:41:11 -04:00
|
|
|
|
2020-03-12 16:48:43 -04:00
|
|
|
kernel.ExitSVCProfile();
|
2014-04-10 19:58:28 -04:00
|
|
|
}
|
2014-04-11 18:44:21 -04:00
|
|
|
|
2020-03-26 20:00:30 -04:00
|
|
|
} // namespace Kernel::Svc
|