kernel: Switch to atmosphere style macros

This commit is contained in:
GPUCode
2023-12-11 22:08:24 +02:00
parent 5bcdcffd96
commit 0fd8892892
23 changed files with 308 additions and 453 deletions

View File

@ -178,7 +178,6 @@ ResultCode AddressArbiter::ArbitrateAddress(std::shared_ptr<Thread> thread, Arbi
// the thread to sleep // the thread to sleep
if (type == ArbitrationType::WaitIfLessThanWithTimeout || if (type == ArbitrationType::WaitIfLessThanWithTimeout ||
type == ArbitrationType::DecrementAndWaitIfLessThanWithTimeout) { type == ArbitrationType::DecrementAndWaitIfLessThanWithTimeout) {
return RESULT_TIMEOUT; return RESULT_TIMEOUT;
} }
return RESULT_SUCCESS; return RESULT_SUCCESS;

View File

@ -20,32 +20,31 @@ namespace Kernel {
ClientPort::ClientPort(KernelSystem& kernel) : Object(kernel), kernel(kernel) {} ClientPort::ClientPort(KernelSystem& kernel) : Object(kernel), kernel(kernel) {}
ClientPort::~ClientPort() = default; ClientPort::~ClientPort() = default;
ResultVal<std::shared_ptr<ClientSession>> ClientPort::Connect() { ResultCode ClientPort::Connect(std::shared_ptr<ClientSession>& client_session) {
// Note: Threads do not wait for the server endpoint to call // Note: Threads do not wait for the server endpoint to call
// AcceptSession before returning from this call. // AcceptSession before returning from this call.
if (active_sessions >= max_sessions) { R_UNLESS(active_sessions < max_sessions, ERR_MAX_CONNECTIONS_REACHED);
return ERR_MAX_CONNECTIONS_REACHED;
}
active_sessions++; active_sessions++;
// Create a new session pair, let the created sessions inherit the parent port's HLE handler. // Create a new session pair, let the created sessions inherit the parent port's HLE handler.
auto [server, client] = kernel.CreateSessionPair(server_port->GetName(), SharedFrom(this)); auto [server, client] = kernel.CreateSessionPair(server_port->GetName(), SharedFrom(this));
if (server_port->hle_handler) if (server_port->hle_handler) {
server_port->hle_handler->ClientConnected(server); server_port->hle_handler->ClientConnected(server);
else } else {
server_port->pending_sessions.push_back(server); server_port->pending_sessions.push_back(server);
}
// Wake the threads waiting on the ServerPort // Wake the threads waiting on the ServerPort
server_port->WakeupAllWaitingThreads(); server_port->WakeupAllWaitingThreads();
return client; client_session = client;
return RESULT_SUCCESS;
} }
void ClientPort::ConnectionClosed() { void ClientPort::ConnectionClosed() {
ASSERT(active_sessions > 0); ASSERT(active_sessions > 0);
--active_sessions; --active_sessions;
} }

View File

@ -46,7 +46,7 @@ public:
* waiting on it to awake. * waiting on it to awake.
* @returns ClientSession The client endpoint of the created Session pair, or error code. * @returns ClientSession The client endpoint of the created Session pair, or error code.
*/ */
ResultVal<std::shared_ptr<ClientSession>> Connect(); ResultCode Connect(std::shared_ptr<ClientSession>& client_session);
/** /**
* Signifies that a previously active connection has been closed, * Signifies that a previously active connection has been closed,

View File

@ -47,8 +47,7 @@ ClientSession::~ClientSession() {
ResultCode ClientSession::SendSyncRequest(std::shared_ptr<Thread> thread) { ResultCode ClientSession::SendSyncRequest(std::shared_ptr<Thread> thread) {
// Keep ServerSession alive until we're done working with it. // Keep ServerSession alive until we're done working with it.
std::shared_ptr<ServerSession> server = SharedFrom(parent->server); std::shared_ptr<ServerSession> server = SharedFrom(parent->server);
if (server == nullptr) R_UNLESS(server, ERR_SESSION_CLOSED_BY_REMOTE);
return ERR_SESSION_CLOSED_BY_REMOTE;
// Signal the server session that new data is available // Signal the server session that new data is available
return server->HandleSyncRequest(std::move(thread)); return server->HandleSyncRequest(std::move(thread));

View File

@ -36,8 +36,9 @@ bool Event::ShouldWait(const Thread* thread) const {
void Event::Acquire(Thread* thread) { void Event::Acquire(Thread* thread) {
ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
if (reset_type == ResetType::OneShot) if (reset_type == ResetType::OneShot) {
signaled = false; signaled = false;
}
} }
void Event::Signal() { void Event::Signal() {
@ -52,8 +53,9 @@ void Event::Clear() {
void Event::WakeupAllWaitingThreads() { void Event::WakeupAllWaitingThreads() {
WaitObject::WakeupAllWaitingThreads(); WaitObject::WakeupAllWaitingThreads();
if (reset_type == ResetType::Pulse) if (reset_type == ResetType::Pulse) {
signaled = false; signaled = false;
}
} }
} // namespace Kernel } // namespace Kernel

View File

@ -28,45 +28,38 @@ HandleTable::HandleTable(KernelSystem& kernel) : kernel(kernel) {
HandleTable::~HandleTable() = default; HandleTable::~HandleTable() = default;
ResultVal<Handle> HandleTable::Create(std::shared_ptr<Object> obj) { ResultCode HandleTable::Create(Handle* out_handle, std::shared_ptr<Object> obj) {
DEBUG_ASSERT(obj != nullptr); DEBUG_ASSERT(obj != nullptr);
u16 slot = next_free_slot; u16 slot = next_free_slot;
if (slot >= generations.size()) { R_UNLESS(slot < generations.size(), ERR_OUT_OF_HANDLES);
LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use.");
return ERR_OUT_OF_HANDLES;
}
next_free_slot = generations[slot]; next_free_slot = generations[slot];
u16 generation = next_generation++; u16 generation = next_generation++;
// Overflow count so it fits in the 15 bits dedicated to the generation in the handle. // Overflow count so it fits in the 15 bits dedicated to the generation in the handle.
// CTR-OS doesn't use generation 0, so skip straight to 1. // CTR-OS doesn't use generation 0, so skip straight to 1.
if (next_generation >= (1 << 15)) if (next_generation >= (1 << 15)) {
next_generation = 1; next_generation = 1;
}
generations[slot] = generation; generations[slot] = generation;
objects[slot] = std::move(obj); objects[slot] = std::move(obj);
Handle handle = generation | (slot << 15); *out_handle = generation | (slot << 15);
return handle; return RESULT_SUCCESS;
} }
ResultVal<Handle> HandleTable::Duplicate(Handle handle) { ResultCode HandleTable::Duplicate(Handle* out, Handle handle) {
std::shared_ptr<Object> object = GetGeneric(handle); std::shared_ptr<Object> object = GetGeneric(handle);
if (object == nullptr) { R_UNLESS(object, ERR_INVALID_HANDLE);
LOG_ERROR(Kernel, "Tried to duplicate invalid handle: {:08X}", handle); return Create(out, std::move(object));
return ERR_INVALID_HANDLE;
}
return Create(std::move(object));
} }
ResultCode HandleTable::Close(Handle handle) { ResultCode HandleTable::Close(Handle handle) {
if (!IsValid(handle)) R_UNLESS(IsValid(handle), ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
u16 slot = GetSlot(handle);
const u16 slot = GetSlot(handle);
objects[slot] = nullptr; objects[slot] = nullptr;
generations[slot] = next_free_slot; generations[slot] = next_free_slot;
@ -75,9 +68,8 @@ ResultCode HandleTable::Close(Handle handle) {
} }
bool HandleTable::IsValid(Handle handle) const { bool HandleTable::IsValid(Handle handle) const {
std::size_t slot = GetSlot(handle); const u16 slot = GetSlot(handle);
u16 generation = GetGeneration(handle); const u16 generation = GetGeneration(handle);
return slot < MAX_COUNT && objects[slot] != nullptr && generations[slot] == generation; return slot < MAX_COUNT && objects[slot] != nullptr && generations[slot] == generation;
} }

View File

@ -53,7 +53,7 @@ public:
* @return The created Handle or one of the following errors: * @return The created Handle or one of the following errors:
* - `ERR_OUT_OF_HANDLES`: the maximum number of handles has been exceeded. * - `ERR_OUT_OF_HANDLES`: the maximum number of handles has been exceeded.
*/ */
ResultVal<Handle> Create(std::shared_ptr<Object> obj); ResultCode Create(Handle* out_handle, std::shared_ptr<Object> obj);
/** /**
* Returns a new handle that points to the same object as the passed in handle. * Returns a new handle that points to the same object as the passed in handle.
@ -61,7 +61,7 @@ public:
* - `ERR_INVALID_HANDLE`: an invalid handle was passed in. * - `ERR_INVALID_HANDLE`: an invalid handle was passed in.
* - Any errors returned by `Create()`. * - Any errors returned by `Create()`.
*/ */
ResultVal<Handle> Duplicate(Handle handle); ResultCode Duplicate(Handle* out, Handle handle);
/** /**
* Closes a handle, removing it from the table and decreasing the object's ref-count. * Closes a handle, removing it from the table and decreasing the object's ref-count.

View File

@ -239,7 +239,7 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf,
Handle handle = 0; Handle handle = 0;
if (object != nullptr) { if (object != nullptr) {
// TODO(yuriks): Figure out the proper error handling for if this fails // TODO(yuriks): Figure out the proper error handling for if this fails
handle = dst_process.handle_table.Create(object).Unwrap(); R_ASSERT(dst_process.handle_table.Create(std::addressof(handle), object));
} }
dst_cmdbuf[i++] = handle; dst_cmdbuf[i++] = handle;
} }

View File

@ -88,8 +88,8 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy
continue; continue;
} }
auto result = dst_process->handle_table.Create(std::move(object)); R_ASSERT(dst_process->handle_table.Create(std::addressof(cmd_buf[i++]),
cmd_buf[i++] = result.ValueOr(0); std::move(object)));
} }
break; break;
} }

View File

@ -192,9 +192,12 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) {
return; return;
} }
VAddr out_addr{};
auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions, auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions,
MemoryState memory_state) { MemoryState memory_state) {
HeapAllocate(segment.addr, segment.size, permissions, memory_state, true); HeapAllocate(std::addressof(out_addr), segment.addr, segment.size, permissions,
memory_state, true);
kernel.memory.WriteBlock(*this, segment.addr, codeset->memory.data() + segment.offset, kernel.memory.WriteBlock(*this, segment.addr, codeset->memory.data() + segment.offset,
segment.size); segment.size);
}; };
@ -205,8 +208,8 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) {
MapSegment(codeset->DataSegment(), VMAPermission::ReadWrite, MemoryState::Private); MapSegment(codeset->DataSegment(), VMAPermission::ReadWrite, MemoryState::Private);
// Allocate and map stack // Allocate and map stack
HeapAllocate(Memory::HEAP_VADDR_END - stack_size, stack_size, VMAPermission::ReadWrite, HeapAllocate(std::addressof(out_addr), Memory::HEAP_VADDR_END - stack_size, stack_size,
MemoryState::Locked, true); VMAPermission::ReadWrite, MemoryState::Locked, true);
// Map special address mappings // Map special address mappings
kernel.MapSharedPages(vm_manager); kernel.MapSharedPages(vm_manager);
@ -246,8 +249,8 @@ VAddr Process::GetLinearHeapLimit() const {
return GetLinearHeapBase() + memory_region->size; return GetLinearHeapBase() + memory_region->size;
} }
ResultVal<VAddr> Process::HeapAllocate(VAddr target, u32 size, VMAPermission perms, ResultCode Process::HeapAllocate(VAddr* out_addr, VAddr target, u32 size, VMAPermission perms,
MemoryState memory_state, bool skip_range_check) { MemoryState memory_state, bool skip_range_check) {
LOG_DEBUG(Kernel, "Allocate heap target={:08X}, size={:08X}", target, size); LOG_DEBUG(Kernel, "Allocate heap target={:08X}, size={:08X}", target, size);
if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END || if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END ||
target + size < target) { target + size < target) {
@ -290,7 +293,8 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u32 size, VMAPermission per
memory_used += size; memory_used += size;
resource_limit->Reserve(ResourceLimitType::Commit, size); resource_limit->Reserve(ResourceLimitType::Commit, size);
return target; *out_addr = target;
return RESULT_SUCCESS;
} }
ResultCode Process::HeapFree(VAddr target, u32 size) { ResultCode Process::HeapFree(VAddr target, u32 size) {
@ -301,9 +305,7 @@ ResultCode Process::HeapFree(VAddr target, u32 size) {
return ERR_INVALID_ADDRESS; return ERR_INVALID_ADDRESS;
} }
if (size == 0) { R_SUCCEED_IF(size == 0);
return RESULT_SUCCESS;
}
// Free heaps block by block // Free heaps block by block
CASCADE_RESULT(auto backing_blocks, vm_manager.GetBackingBlocksForRange(target, size)); CASCADE_RESULT(auto backing_blocks, vm_manager.GetBackingBlocksForRange(target, size));
@ -322,7 +324,7 @@ ResultCode Process::HeapFree(VAddr target, u32 size) {
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
ResultVal<VAddr> Process::LinearAllocate(VAddr target, u32 size, VMAPermission perms) { ResultCode Process::LinearAllocate(VAddr* out_addr, VAddr target, u32 size, VMAPermission perms) {
LOG_DEBUG(Kernel, "Allocate linear heap target={:08X}, size={:08X}", target, size); LOG_DEBUG(Kernel, "Allocate linear heap target={:08X}, size={:08X}", target, size);
u32 physical_offset; u32 physical_offset;
if (target == 0) { if (target == 0) {
@ -366,7 +368,8 @@ ResultVal<VAddr> Process::LinearAllocate(VAddr target, u32 size, VMAPermission p
resource_limit->Reserve(ResourceLimitType::Commit, size); resource_limit->Reserve(ResourceLimitType::Commit, size);
LOG_DEBUG(Kernel, "Allocated at target={:08X}", target); LOG_DEBUG(Kernel, "Allocated at target={:08X}", target);
return target; *out_addr = target;
return RESULT_SUCCESS;
} }
ResultCode Process::LinearFree(VAddr target, u32 size) { ResultCode Process::LinearFree(VAddr target, u32 size) {
@ -377,15 +380,8 @@ ResultCode Process::LinearFree(VAddr target, u32 size) {
return ERR_INVALID_ADDRESS; return ERR_INVALID_ADDRESS;
} }
if (size == 0) { R_SUCCEED_IF(size == 0);
return RESULT_SUCCESS; R_TRY(vm_manager.UnmapRange(target, size));
}
ResultCode result = vm_manager.UnmapRange(target, size);
if (result.IsError()) {
LOG_ERROR(Kernel, "Trying to free already freed memory");
return result;
}
u32 physical_offset = target - GetLinearHeapAreaAddress(); // relative to FCRAM u32 physical_offset = target - GetLinearHeapAreaAddress(); // relative to FCRAM
memory_region->Free(physical_offset, size); memory_region->Free(physical_offset, size);

View File

@ -231,12 +231,12 @@ public:
VAddr GetLinearHeapBase() const; VAddr GetLinearHeapBase() const;
VAddr GetLinearHeapLimit() const; VAddr GetLinearHeapLimit() const;
ResultVal<VAddr> HeapAllocate(VAddr target, u32 size, VMAPermission perms, ResultCode HeapAllocate(VAddr* out_addr, VAddr target, u32 size, VMAPermission perms,
MemoryState memory_state = MemoryState::Private, MemoryState memory_state = MemoryState::Private,
bool skip_range_check = false); bool skip_range_check = false);
ResultCode HeapFree(VAddr target, u32 size); ResultCode HeapFree(VAddr target, u32 size);
ResultVal<VAddr> LinearAllocate(VAddr target, u32 size, VMAPermission perms); ResultCode LinearAllocate(VAddr* out_addr, VAddr target, u32 size, VMAPermission perms);
ResultCode LinearFree(VAddr target, u32 size); ResultCode LinearFree(VAddr target, u32 size);
ResultVal<VAddr> AllocateThreadLocalStorage(); ResultVal<VAddr> AllocateThreadLocalStorage();

View File

@ -26,9 +26,7 @@ ResultVal<std::shared_ptr<Semaphore>> KernelSystem::CreateSemaphore(s32 initial_
s32 max_count, s32 max_count,
std::string name) { std::string name) {
if (initial_count > max_count) { R_UNLESS(initial_count <= max_count, ERR_INVALID_COMBINATION_KERNEL);
return ERR_INVALID_COMBINATION_KERNEL;
}
// When the semaphore is created, some slots are reserved for other threads, // When the semaphore is created, some slots are reserved for other threads,
// and the rest is reserved for the caller thread // and the rest is reserved for the caller thread
@ -44,21 +42,20 @@ bool Semaphore::ShouldWait(const Thread* thread) const {
} }
void Semaphore::Acquire(Thread* thread) { void Semaphore::Acquire(Thread* thread) {
if (available_count <= 0) if (available_count <= 0) {
return; return;
}
--available_count; --available_count;
} }
ResultVal<s32> Semaphore::Release(s32 release_count) { ResultCode Semaphore::Release(s32* count, s32 release_count) {
if (max_count - available_count < release_count) R_UNLESS(max_count >= release_count + available_count, ERR_OUT_OF_RANGE_KERNEL);
return ERR_OUT_OF_RANGE_KERNEL;
s32 previous_count = available_count; *count = available_count;
available_count += release_count; available_count += release_count;
WakeupAllWaitingThreads(); WakeupAllWaitingThreads();
return previous_count; return RESULT_SUCCESS;
} }
} // namespace Kernel } // namespace Kernel

View File

@ -47,7 +47,7 @@ public:
* @param release_count The number of slots to release * @param release_count The number of slots to release
* @return The number of free slots the semaphore had before this call * @return The number of free slots the semaphore had before this call
*/ */
ResultVal<s32> Release(s32 release_count); ResultCode Release(s32* count, s32 release_count);
private: private:
friend class boost::serialization::access; friend class boost::serialization::access;

View File

@ -24,14 +24,12 @@ namespace Kernel {
ServerPort::ServerPort(KernelSystem& kernel) : WaitObject(kernel) {} ServerPort::ServerPort(KernelSystem& kernel) : WaitObject(kernel) {}
ServerPort::~ServerPort() {} ServerPort::~ServerPort() {}
ResultVal<std::shared_ptr<ServerSession>> ServerPort::Accept() { ResultCode ServerPort::Accept(std::shared_ptr<ServerSession>& session) {
if (pending_sessions.empty()) { R_UNLESS(!pending_sessions.empty(), ERR_NO_PENDING_SESSIONS);
return ERR_NO_PENDING_SESSIONS;
}
auto session = std::move(pending_sessions.back()); session = std::move(pending_sessions.back());
pending_sessions.pop_back(); pending_sessions.pop_back();
return session; return RESULT_SUCCESS;
} }
bool ServerPort::ShouldWait(const Thread* thread) const { bool ServerPort::ShouldWait(const Thread* thread) const {

View File

@ -41,7 +41,7 @@ public:
* Accepts a pending incoming connection on this port. If there are no pending sessions, will * Accepts a pending incoming connection on this port. If there are no pending sessions, will
* return ERR_NO_PENDING_SESSIONS. * return ERR_NO_PENDING_SESSIONS.
*/ */
ResultVal<std::shared_ptr<ServerSession>> Accept(); ResultCode Accept(std::shared_ptr<ServerSession>& session);
/** /**
* Sets the HLE handler template for the port. ServerSessions crated by connecting to this port * Sets the HLE handler template for the port. ServerSessions crated by connecting to this port

View File

@ -460,14 +460,11 @@ ResultCode SVC::ControlMemory(u32* out_addr, u32 addr0, u32 addr1, u32 size, u32
"size=0x{:X}, permissions=0x{:08X}", "size=0x{:X}, permissions=0x{:08X}",
operation, addr0, addr1, size, permissions); operation, addr0, addr1, size, permissions);
if ((addr0 & Memory::CITRA_PAGE_MASK) != 0 || (addr1 & Memory::CITRA_PAGE_MASK) != 0) { R_UNLESS((addr0 & Memory::CITRA_PAGE_MASK) == 0, ERR_MISALIGNED_ADDRESS);
return ERR_MISALIGNED_ADDRESS; R_UNLESS((addr1 & Memory::CITRA_PAGE_MASK) == 0, ERR_MISALIGNED_ADDRESS);
} R_UNLESS((size & Memory::CITRA_PAGE_MASK) == 0, ERR_MISALIGNED_SIZE);
if ((size & Memory::CITRA_PAGE_MASK) != 0) {
return ERR_MISALIGNED_SIZE;
}
u32 region = operation & MEMOP_REGION_MASK; const u32 region = operation & MEMOP_REGION_MASK;
operation &= ~MEMOP_REGION_MASK; operation &= ~MEMOP_REGION_MASK;
if (region != 0) { if (region != 0) {
@ -487,53 +484,37 @@ ResultCode SVC::ControlMemory(u32* out_addr, u32 addr0, u32 addr1, u32 size, u32
// TODO(Subv): What happens if an application tries to FREE a block of memory that has a // TODO(Subv): What happens if an application tries to FREE a block of memory that has a
// SharedMemory pointing to it? // SharedMemory pointing to it?
if (addr0 >= Memory::HEAP_VADDR && addr0 < Memory::HEAP_VADDR_END) { if (addr0 >= Memory::HEAP_VADDR && addr0 < Memory::HEAP_VADDR_END) {
ResultCode result = process.HeapFree(addr0, size); R_TRY(process.HeapFree(addr0, size));
if (result.IsError())
return result;
} else if (addr0 >= process.GetLinearHeapBase() && addr0 < process.GetLinearHeapLimit()) { } else if (addr0 >= process.GetLinearHeapBase() && addr0 < process.GetLinearHeapLimit()) {
ResultCode result = process.LinearFree(addr0, size); R_TRY(process.LinearFree(addr0, size));
if (result.IsError())
return result;
} else { } else {
return ERR_INVALID_ADDRESS; return ERR_INVALID_ADDRESS;
} }
*out_addr = addr0; *out_addr = addr0;
break; break;
} }
case MEMOP_COMMIT: { case MEMOP_COMMIT: {
if (operation & MEMOP_LINEAR) { if (operation & MEMOP_LINEAR) {
CASCADE_RESULT(*out_addr, process.LinearAllocate(addr0, size, vma_permissions)); return process.LinearAllocate(out_addr, addr0, size, vma_permissions);
} else { } else {
CASCADE_RESULT(*out_addr, process.HeapAllocate(addr0, size, vma_permissions)); return process.HeapAllocate(out_addr, addr0, size, vma_permissions);
} }
break; break;
} }
case MEMOP_MAP: { case MEMOP_MAP: {
CASCADE_CODE(process.Map(addr0, addr1, size, vma_permissions)); return process.Map(addr0, addr1, size, vma_permissions);
break;
} }
case MEMOP_UNMAP: { case MEMOP_UNMAP: {
CASCADE_CODE(process.Unmap(addr0, addr1, size, vma_permissions)); return process.Unmap(addr0, addr1, size, vma_permissions);
break;
} }
case MEMOP_PROTECT: { case MEMOP_PROTECT: {
ResultCode result = process.vm_manager.ReprotectRange(addr0, size, vma_permissions); return process.vm_manager.ReprotectRange(addr0, size, vma_permissions);
if (result.IsError())
return result;
break;
} }
default: default:
LOG_ERROR(Kernel_SVC, "unknown operation=0x{:08X}", operation); LOG_ERROR(Kernel_SVC, "unknown operation=0x{:08X}", operation);
return ERR_INVALID_COMBINATION; return ERR_INVALID_COMBINATION;
} }
process.vm_manager.LogLayout(Common::Log::Level::Trace);
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
@ -544,9 +525,7 @@ void SVC::ExitProcess() {
ResultCode SVC::TerminateProcess(Handle handle) { ResultCode SVC::TerminateProcess(Handle handle) {
std::shared_ptr<Process> process = std::shared_ptr<Process> process =
kernel.GetCurrentProcess()->handle_table.Get<Process>(handle); kernel.GetCurrentProcess()->handle_table.Get<Process>(handle);
if (process == nullptr) { R_UNLESS(process, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
}
kernel.TerminateProcess(process); kernel.TerminateProcess(process);
return RESULT_SUCCESS; return RESULT_SUCCESS;
@ -561,8 +540,7 @@ ResultCode SVC::MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 oth
std::shared_ptr<SharedMemory> shared_memory = std::shared_ptr<SharedMemory> shared_memory =
kernel.GetCurrentProcess()->handle_table.Get<SharedMemory>(handle); kernel.GetCurrentProcess()->handle_table.Get<SharedMemory>(handle);
if (shared_memory == nullptr) R_UNLESS(shared_memory, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
MemoryPermission permissions_type = static_cast<MemoryPermission>(permissions); MemoryPermission permissions_type = static_cast<MemoryPermission>(permissions);
switch (permissions_type) { switch (permissions_type) {
@ -591,50 +569,39 @@ ResultCode SVC::UnmapMemoryBlock(Handle handle, u32 addr) {
std::shared_ptr<Process> current_process = kernel.GetCurrentProcess(); std::shared_ptr<Process> current_process = kernel.GetCurrentProcess();
std::shared_ptr<SharedMemory> shared_memory = std::shared_ptr<SharedMemory> shared_memory =
current_process->handle_table.Get<SharedMemory>(handle); current_process->handle_table.Get<SharedMemory>(handle);
if (shared_memory == nullptr) R_UNLESS(shared_memory, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
return shared_memory->Unmap(*current_process, addr); return shared_memory->Unmap(*current_process, addr);
} }
/// Connect to an OS service given the port name, returns the handle to the port to out /// Connect to an OS service given the port name, returns the handle to the port to out
ResultCode SVC::ConnectToPort(Handle* out_handle, VAddr port_name_address) { ResultCode SVC::ConnectToPort(Handle* out_handle, VAddr port_name_address) {
if (!memory.IsValidVirtualAddress(*kernel.GetCurrentProcess(), port_name_address)) { R_UNLESS(memory.IsValidVirtualAddress(*kernel.GetCurrentProcess(), port_name_address),
return ERR_NOT_FOUND; ERR_NOT_FOUND);
}
static constexpr std::size_t PortNameMaxLength = 11; static constexpr std::size_t PortNameMaxLength = 11;
// Read 1 char beyond the max allowed port name to detect names that are too long. // Read 1 char beyond the max allowed port name to detect names that are too long.
std::string port_name = memory.ReadCString(port_name_address, PortNameMaxLength + 1); std::string port_name = memory.ReadCString(port_name_address, PortNameMaxLength + 1);
if (port_name.size() > PortNameMaxLength) { R_UNLESS(port_name.size() <= PortNameMaxLength, ERR_PORT_NAME_TOO_LONG);
return ERR_PORT_NAME_TOO_LONG;
}
LOG_TRACE(Kernel_SVC, "called port_name={}", port_name); LOG_TRACE(Kernel_SVC, "called port_name={}", port_name);
auto it = kernel.named_ports.find(port_name); auto it = kernel.named_ports.find(port_name);
if (it == kernel.named_ports.end()) { R_UNLESS(it != kernel.named_ports.end(), ERR_NOT_FOUND);
LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: {}", port_name);
return ERR_NOT_FOUND;
}
auto client_port = it->second; auto client_port = it->second;
std::shared_ptr<ClientSession> client_session; std::shared_ptr<ClientSession> client_session;
CASCADE_RESULT(client_session, client_port->Connect()); R_TRY(client_port->Connect(client_session));
// Return the client session // Return the client session
CASCADE_RESULT(*out_handle, kernel.GetCurrentProcess()->handle_table.Create(client_session)); return kernel.GetCurrentProcess()->handle_table.Create(out_handle, client_session);
return RESULT_SUCCESS;
} }
/// Makes a blocking IPC call to an OS service. /// Makes a blocking IPC call to an OS service.
ResultCode SVC::SendSyncRequest(Handle handle) { ResultCode SVC::SendSyncRequest(Handle handle) {
std::shared_ptr<ClientSession> session = std::shared_ptr<ClientSession> session =
kernel.GetCurrentProcess()->handle_table.Get<ClientSession>(handle); kernel.GetCurrentProcess()->handle_table.Get<ClientSession>(handle);
if (session == nullptr) { R_UNLESS(session, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
}
LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());
@ -655,42 +622,32 @@ ResultCode SVC::OpenProcess(Handle* out_handle, u32 process_id) {
// Result 0xd9001818 (process not found?) // Result 0xd9001818 (process not found?)
return ResultCode(24, ErrorModule::OS, ErrorSummary::WrongArgument, ErrorLevel::Permanent); return ResultCode(24, ErrorModule::OS, ErrorSummary::WrongArgument, ErrorLevel::Permanent);
} }
auto result_handle = kernel.GetCurrentProcess()->handle_table.Create(process); return kernel.GetCurrentProcess()->handle_table.Create(out_handle, process);
if (!result_handle) {
return result_handle.Code();
}
*out_handle = result_handle.Unwrap();
return RESULT_SUCCESS;
} }
ResultCode SVC::OpenThread(Handle* out_handle, Handle process_handle, u32 thread_id) { ResultCode SVC::OpenThread(Handle* out_handle, Handle process_handle, u32 thread_id) {
// Result 0xd9001819 (thread not found?)
constexpr static ResultCode ResultThreadNotFound(
25, ErrorModule::OS, ErrorSummary::WrongArgument, ErrorLevel::Permanent);
if (process_handle == 0) { if (process_handle == 0) {
LOG_ERROR(Kernel_SVC, "Uninplemented svcOpenThread process_handle=0"); LOG_ERROR(Kernel_SVC, "Uninplemented svcOpenThread process_handle=0");
// Result 0xd9001819 (thread not found?) return ResultThreadNotFound;
return ResultCode(25, ErrorModule::OS, ErrorSummary::WrongArgument, ErrorLevel::Permanent);
} }
std::shared_ptr<Process> process = std::shared_ptr<Process> process =
kernel.GetCurrentProcess()->handle_table.Get<Process>(process_handle); kernel.GetCurrentProcess()->handle_table.Get<Process>(process_handle);
if (!process) { R_UNLESS(process, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
}
for (u32 core_id = 0; core_id < system.GetNumCores(); core_id++) { for (u32 core_id = 0; core_id < system.GetNumCores(); core_id++) {
const auto thread_list = kernel.GetThreadManager(core_id).GetThreadList(); const auto thread_list = kernel.GetThreadManager(core_id).GetThreadList();
for (auto& thread : thread_list) { for (auto& thread : thread_list) {
if (thread->owner_process.lock() == process && thread.get()->thread_id == thread_id) { if (thread->owner_process.lock() == process && thread.get()->thread_id == thread_id) {
auto result_handle = kernel.GetCurrentProcess()->handle_table.Create(thread); return kernel.GetCurrentProcess()->handle_table.Create(out_handle, thread);
if (!result_handle) {
return result_handle.Code();
}
*out_handle = result_handle.Unwrap();
return RESULT_SUCCESS;
} }
} }
} }
// Result 0xd9001819 (thread not found?) return ResultThreadNotFound;
return ResultCode(25, ErrorModule::OS, ErrorSummary::WrongArgument, ErrorLevel::Permanent);
} }
/// Close a handle /// Close a handle
@ -773,17 +730,13 @@ private:
ResultCode SVC::WaitSynchronization1(Handle handle, s64 nano_seconds) { ResultCode SVC::WaitSynchronization1(Handle handle, s64 nano_seconds) {
auto object = kernel.GetCurrentProcess()->handle_table.Get<WaitObject>(handle); auto object = kernel.GetCurrentProcess()->handle_table.Get<WaitObject>(handle);
Thread* thread = kernel.GetCurrentThreadManager().GetCurrentThread(); Thread* thread = kernel.GetCurrentThreadManager().GetCurrentThread();
R_UNLESS(object, ERR_INVALID_HANDLE);
if (object == nullptr)
return ERR_INVALID_HANDLE;
LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({}:{}), nanoseconds={}", handle, LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({}:{}), nanoseconds={}", handle,
object->GetTypeName(), object->GetName(), nano_seconds); object->GetTypeName(), object->GetName(), nano_seconds);
if (object->ShouldWait(thread)) { if (object->ShouldWait(thread)) {
R_UNLESS(nano_seconds != 0, RESULT_TIMEOUT);
if (nano_seconds == 0)
return RESULT_TIMEOUT;
thread->wait_objects = {object}; thread->wait_objects = {object};
object->AddWaitingThread(SharedFrom(thread)); object->AddWaitingThread(SharedFrom(thread));
@ -803,7 +756,6 @@ ResultCode SVC::WaitSynchronization1(Handle handle, s64 nano_seconds) {
} }
object->Acquire(thread); object->Acquire(thread);
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
@ -811,19 +763,15 @@ ResultCode SVC::WaitSynchronization1(Handle handle, s64 nano_seconds) {
ResultCode SVC::WaitSynchronizationN(s32* out, VAddr handles_address, s32 handle_count, ResultCode SVC::WaitSynchronizationN(s32* out, VAddr handles_address, s32 handle_count,
bool wait_all, s64 nano_seconds) { bool wait_all, s64 nano_seconds) {
Thread* thread = kernel.GetCurrentThreadManager().GetCurrentThread(); Thread* thread = kernel.GetCurrentThreadManager().GetCurrentThread();
R_UNLESS(memory.IsValidVirtualAddress(*kernel.GetCurrentProcess(), handles_address),
if (!memory.IsValidVirtualAddress(*kernel.GetCurrentProcess(), handles_address)) { ERR_INVALID_POINTER);
return ERR_INVALID_POINTER;
}
// NOTE: on real hardware, there is no nullptr check for 'out' (tested with firmware 4.4). If // NOTE: on real hardware, there is no nullptr check for 'out' (tested with firmware 4.4). If
// this happens, the running application will crash. // this happens, the running application will crash.
ASSERT_MSG(out != nullptr, "invalid output pointer specified!"); ASSERT_MSG(out != nullptr, "invalid output pointer specified!");
// Check if 'handle_count' is invalid // Check if 'handle_count' is invalid
if (handle_count < 0) { R_UNLESS(handle_count >= 0, ERR_OUT_OF_RANGE);
return ERR_OUT_OF_RANGE;
}
using ObjectPtr = std::shared_ptr<WaitObject>; using ObjectPtr = std::shared_ptr<WaitObject>;
std::vector<ObjectPtr> objects(handle_count); std::vector<ObjectPtr> objects(handle_count);
@ -831,8 +779,7 @@ ResultCode SVC::WaitSynchronizationN(s32* out, VAddr handles_address, s32 handle
for (int i = 0; i < handle_count; ++i) { for (int i = 0; i < handle_count; ++i) {
Handle handle = memory.Read32(handles_address + i * sizeof(Handle)); Handle handle = memory.Read32(handles_address + i * sizeof(Handle));
auto object = kernel.GetCurrentProcess()->handle_table.Get<WaitObject>(handle); auto object = kernel.GetCurrentProcess()->handle_table.Get<WaitObject>(handle);
if (object == nullptr) R_UNLESS(object, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
objects[i] = object; objects[i] = object;
} }
@ -853,8 +800,7 @@ ResultCode SVC::WaitSynchronizationN(s32* out, VAddr handles_address, s32 handle
// If a timeout value of 0 was provided, just return the Timeout error code instead of // If a timeout value of 0 was provided, just return the Timeout error code instead of
// suspending the thread. // suspending the thread.
if (nano_seconds == 0) R_UNLESS(nano_seconds != 0, RESULT_TIMEOUT);
return RESULT_TIMEOUT;
// Put the thread to sleep // Put the thread to sleep
thread->status = ThreadStatus::WaitSynchAll; thread->status = ThreadStatus::WaitSynchAll;
@ -896,8 +842,7 @@ ResultCode SVC::WaitSynchronizationN(s32* out, VAddr handles_address, s32 handle
// If a timeout value of 0 was provided, just return the Timeout error code instead of // If a timeout value of 0 was provided, just return the Timeout error code instead of
// suspending the thread. // suspending the thread.
if (nano_seconds == 0) R_UNLESS(nano_seconds != 0, RESULT_TIMEOUT);
return RESULT_TIMEOUT;
// Put the thread to sleep // Put the thread to sleep
thread->status = ThreadStatus::WaitSynchAny; thread->status = ThreadStatus::WaitSynchAny;
@ -931,9 +876,7 @@ ResultCode SVC::WaitSynchronizationN(s32* out, VAddr handles_address, s32 handle
static ResultCode ReceiveIPCRequest(Kernel::KernelSystem& kernel, Memory::MemorySystem& memory, static ResultCode ReceiveIPCRequest(Kernel::KernelSystem& kernel, Memory::MemorySystem& memory,
std::shared_ptr<ServerSession> server_session, std::shared_ptr<ServerSession> server_session,
std::shared_ptr<Thread> thread) { std::shared_ptr<Thread> thread) {
if (server_session->parent->client == nullptr) { R_UNLESS(server_session->parent->client, ERR_SESSION_CLOSED_BY_REMOTE);
return ERR_SESSION_CLOSED_BY_REMOTE;
}
VAddr target_address = thread->GetCommandBufferAddress(); VAddr target_address = thread->GetCommandBufferAddress();
VAddr source_address = server_session->currently_handling->GetCommandBufferAddress(); VAddr source_address = server_session->currently_handling->GetCommandBufferAddress();
@ -960,14 +903,11 @@ static ResultCode ReceiveIPCRequest(Kernel::KernelSystem& kernel, Memory::Memory
/// In a single operation, sends a IPC reply and waits for a new request. /// In a single operation, sends a IPC reply and waits for a new request.
ResultCode SVC::ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_count, ResultCode SVC::ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_count,
Handle reply_target) { Handle reply_target) {
if (!memory.IsValidVirtualAddress(*kernel.GetCurrentProcess(), handles_address)) { R_UNLESS(memory.IsValidVirtualAddress(*kernel.GetCurrentProcess(), handles_address),
return ERR_INVALID_POINTER; ERR_INVALID_POINTER);
}
// Check if 'handle_count' is invalid // Check if 'handle_count' is invalid
if (handle_count < 0) { R_UNLESS(handle_count >= 0, ERR_OUT_OF_RANGE);
return ERR_OUT_OF_RANGE;
}
using ObjectPtr = std::shared_ptr<WaitObject>; using ObjectPtr = std::shared_ptr<WaitObject>;
std::vector<ObjectPtr> objects(handle_count); std::vector<ObjectPtr> objects(handle_count);
@ -977,8 +917,7 @@ ResultCode SVC::ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_co
for (int i = 0; i < handle_count; ++i) { for (int i = 0; i < handle_count; ++i) {
Handle handle = memory.Read32(handles_address + i * sizeof(Handle)); Handle handle = memory.Read32(handles_address + i * sizeof(Handle));
auto object = current_process->handle_table.Get<WaitObject>(handle); auto object = current_process->handle_table.Get<WaitObject>(handle);
if (object == nullptr) R_UNLESS(object, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
objects[i] = object; objects[i] = object;
} }
@ -989,8 +928,7 @@ ResultCode SVC::ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_co
IPC::Header header{cmd_buff_header}; IPC::Header header{cmd_buff_header};
if (reply_target != 0 && header.command_id != 0xFFFF) { if (reply_target != 0 && header.command_id != 0xFFFF) {
auto session = current_process->handle_table.Get<ServerSession>(reply_target); auto session = current_process->handle_table.Get<ServerSession>(reply_target);
if (session == nullptr) R_UNLESS(session, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
auto request_thread = std::move(session->currently_handling); auto request_thread = std::move(session->currently_handling);
@ -1021,12 +959,10 @@ ResultCode SVC::ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_co
if (handle_count == 0) { if (handle_count == 0) {
*index = 0; *index = 0;
R_SUCCEED_IF(reply_target != 0 && header.command_id != 0xFFFF);
// The kernel uses this value as a placeholder for the real error, and returns it when we // The kernel uses this value as a placeholder for the real error, and returns it when we
// pass no handles and do not perform any reply. // pass no handles and do not perform any reply.
if (reply_target == 0 || header.command_id == 0xFFFF) return ResultCode(0xE7E3FFFF);
return ResultCode(0xE7E3FFFF);
return RESULT_SUCCESS;
} }
// Find the first object that is acquirable in the provided list of objects // Find the first object that is acquirable in the provided list of objects
@ -1040,8 +976,7 @@ ResultCode SVC::ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_co
object->Acquire(thread); object->Acquire(thread);
*index = static_cast<s32>(std::distance(objects.begin(), itr)); *index = static_cast<s32>(std::distance(objects.begin(), itr));
if (object->GetHandleType() != HandleType::ServerSession) R_SUCCEED_IF(object->GetHandleType() != HandleType::ServerSession);
return RESULT_SUCCESS;
auto server_session = static_cast<ServerSession*>(object); auto server_session = static_cast<ServerSession*>(object);
return ReceiveIPCRequest(kernel, memory, SharedFrom(server_session), SharedFrom(thread)); return ReceiveIPCRequest(kernel, memory, SharedFrom(server_session), SharedFrom(thread));
@ -1084,9 +1019,7 @@ ResultCode SVC::CreateAddressArbiter(Handle* out_handle) {
// Create address arbiter. // Create address arbiter.
const auto arbiter = kernel.CreateAddressArbiter(); const auto arbiter = kernel.CreateAddressArbiter();
arbiter->resource_limit = resource_limit; arbiter->resource_limit = resource_limit;
CASCADE_RESULT(*out_handle, current_process->handle_table.Create(std::move(arbiter))); return current_process->handle_table.Create(out_handle, std::move(arbiter));
LOG_TRACE(Kernel_SVC, "returned handle=0x{:08X}", *out_handle);
return RESULT_SUCCESS;
} }
/// Arbitrate address /// Arbitrate address
@ -1096,8 +1029,7 @@ ResultCode SVC::ArbitrateAddress(Handle handle, u32 address, u32 type, u32 value
std::shared_ptr<AddressArbiter> arbiter = std::shared_ptr<AddressArbiter> arbiter =
kernel.GetCurrentProcess()->handle_table.Get<AddressArbiter>(handle); kernel.GetCurrentProcess()->handle_table.Get<AddressArbiter>(handle);
if (arbiter == nullptr) R_UNLESS(arbiter, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
auto res = auto res =
arbiter->ArbitrateAddress(SharedFrom(kernel.GetCurrentThreadManager().GetCurrentThread()), arbiter->ArbitrateAddress(SharedFrom(kernel.GetCurrentThreadManager().GetCurrentThread()),
@ -1105,7 +1037,6 @@ ResultCode SVC::ArbitrateAddress(Handle handle, u32 address, u32 type, u32 value
// TODO(Subv): Identify in which specific cases this call should cause a reschedule. // TODO(Subv): Identify in which specific cases this call should cause a reschedule.
system.PrepareReschedule(); system.PrepareReschedule();
return res; return res;
} }
@ -1159,12 +1090,9 @@ ResultCode SVC::GetResourceLimit(Handle* resource_limit, Handle process_handle)
std::shared_ptr<Process> current_process = kernel.GetCurrentProcess(); std::shared_ptr<Process> current_process = kernel.GetCurrentProcess();
std::shared_ptr<Process> process = current_process->handle_table.Get<Process>(process_handle); std::shared_ptr<Process> process = current_process->handle_table.Get<Process>(process_handle);
if (process == nullptr) R_UNLESS(process, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
CASCADE_RESULT(*resource_limit, current_process->handle_table.Create(process->resource_limit)); return current_process->handle_table.Create(resource_limit, process->resource_limit);
return RESULT_SUCCESS;
} }
/// Get resource limit current values /// Get resource limit current values
@ -1175,9 +1103,7 @@ ResultCode SVC::GetResourceLimitCurrentValues(VAddr values, Handle resource_limi
const auto resource_limit = const auto resource_limit =
kernel.GetCurrentProcess()->handle_table.Get<ResourceLimit>(resource_limit_handle); kernel.GetCurrentProcess()->handle_table.Get<ResourceLimit>(resource_limit_handle);
if (!resource_limit) { R_UNLESS(resource_limit, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
}
for (u32 i = 0; i < name_count; ++i) { for (u32 i = 0; i < name_count; ++i) {
const u32 name = memory.Read32(names + i * sizeof(u32)); const u32 name = memory.Read32(names + i * sizeof(u32));
@ -1196,15 +1122,11 @@ ResultCode SVC::GetResourceLimitLimitValues(VAddr values, Handle resource_limit_
const auto resource_limit = const auto resource_limit =
kernel.GetCurrentProcess()->handle_table.Get<ResourceLimit>(resource_limit_handle); kernel.GetCurrentProcess()->handle_table.Get<ResourceLimit>(resource_limit_handle);
if (!resource_limit) { R_UNLESS(resource_limit, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
}
for (u32 i = 0; i < name_count; ++i) { for (u32 i = 0; i < name_count; ++i) {
const auto name = static_cast<ResourceLimitType>(memory.Read32(names + i * sizeof(u32))); const auto name = static_cast<ResourceLimitType>(memory.Read32(names + i * sizeof(u32)));
if (name >= ResourceLimitType::Max) { R_UNLESS(name < ResourceLimitType::Max, ERR_INVALID_ENUM_VALUE);
return ERR_INVALID_ENUM_VALUE;
}
const s64 value = resource_limit->GetLimitValue(name); const s64 value = resource_limit->GetLimitValue(name);
memory.Write64(values + i * sizeof(u64), value); memory.Write64(values + i * sizeof(u64), value);
} }
@ -1219,20 +1141,16 @@ ResultCode SVC::SetResourceLimitLimitValues(Handle res_limit, VAddr names, VAddr
const auto resource_limit = const auto resource_limit =
kernel.GetCurrentProcess()->handle_table.Get<ResourceLimit>(res_limit); kernel.GetCurrentProcess()->handle_table.Get<ResourceLimit>(res_limit);
if (!resource_limit) { R_UNLESS(resource_limit, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
}
for (u32 i = 0; i < name_count; ++i) { for (u32 i = 0; i < name_count; ++i) {
const auto name = static_cast<ResourceLimitType>(memory.Read32(names + i * sizeof(u32))); const auto name = static_cast<ResourceLimitType>(memory.Read32(names + i * sizeof(u32)));
if (name >= ResourceLimitType::Max) { R_UNLESS(name < ResourceLimitType::Max, ERR_INVALID_ENUM_VALUE);
return ERR_INVALID_ENUM_VALUE;
}
const s64 value = memory.Read64(resource_list + i * sizeof(u64)); const s64 value = memory.Read64(resource_list + i * sizeof(u64));
const s32 value_high = value >> 32; const s32 value_high = value >> 32;
if (value_high < 0) { R_UNLESS(value_high >= 0, ERR_OUT_OF_RANGE_KERNEL);
return ERR_OUT_OF_RANGE_KERNEL;
}
if (name == ResourceLimitType::Commit && value_high != 0) { if (name == ResourceLimitType::Commit && value_high != 0) {
auto& config_mem = kernel.GetConfigMemHandler().GetConfigMem(); auto& config_mem = kernel.GetConfigMemHandler().GetConfigMem();
config_mem.app_mem_alloc = value_high; config_mem.app_mem_alloc = value_high;
@ -1246,18 +1164,13 @@ ResultCode SVC::SetResourceLimitLimitValues(Handle res_limit, VAddr names, VAddr
/// Creates a new thread /// Creates a new thread
ResultCode SVC::CreateThread(Handle* out_handle, u32 entry_point, u32 arg, VAddr stack_top, ResultCode SVC::CreateThread(Handle* out_handle, u32 entry_point, u32 arg, VAddr stack_top,
u32 priority, s32 processor_id) { u32 priority, s32 processor_id) {
std::string name = fmt::format("thread-{:08X}", entry_point); R_UNLESS(priority <= ThreadPrioLowest, ERR_OUT_OF_RANGE);
if (priority > ThreadPrioLowest) {
return ERR_OUT_OF_RANGE;
}
const auto current_process = kernel.GetCurrentProcess(); const auto current_process = kernel.GetCurrentProcess();
const auto& resource_limit = current_process->resource_limit; const auto& resource_limit = current_process->resource_limit;
const u32 max_priority = resource_limit->GetLimitValue(ResourceLimitType::Priority); const u32 max_priority = resource_limit->GetLimitValue(ResourceLimitType::Priority);
if (max_priority > priority && !current_process->no_thread_restrictions) { R_UNLESS(max_priority <= priority || current_process->no_thread_restrictions,
return ERR_NOT_AUTHORIZED; ERR_NOT_AUTHORIZED);
}
if (processor_id == ThreadProcessorIdDefault) { if (processor_id == ThreadProcessorIdDefault) {
// Set the target CPU to the one specified in the process' exheader. // Set the target CPU to the one specified in the process' exheader.
@ -1294,6 +1207,7 @@ ResultCode SVC::CreateThread(Handle* out_handle, u32 entry_point, u32 arg, VAddr
} }
// Create thread. // Create thread.
const std::string name = fmt::format("thread-{:08X}", entry_point);
CASCADE_RESULT(std::shared_ptr<Thread> thread, CASCADE_RESULT(std::shared_ptr<Thread> thread,
kernel.CreateThread(name, entry_point, priority, arg, processor_id, stack_top, kernel.CreateThread(name, entry_point, priority, arg, processor_id, stack_top,
current_process)); current_process));
@ -1301,16 +1215,14 @@ ResultCode SVC::CreateThread(Handle* out_handle, u32 entry_point, u32 arg, VAddr
thread->context.fpscr = thread->context.fpscr =
FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO; // 0x03C00000 FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO; // 0x03C00000
CASCADE_RESULT(*out_handle, current_process->handle_table.Create(std::move(thread)));
system.PrepareReschedule(); system.PrepareReschedule();
LOG_TRACE(Kernel_SVC, LOG_TRACE(Kernel_SVC,
"called entrypoint=0x{:08X} ({}), arg=0x{:08X}, stacktop=0x{:08X}, " "called entrypoint=0x{:08X} ({}), arg=0x{:08X}, stacktop=0x{:08X}, "
"threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}", "threadpriority=0x{:08X}, processorid=0x{:08X}",
entry_point, name, arg, stack_top, priority, processor_id, *out_handle); entry_point, name, arg, stack_top, priority, processor_id);
return RESULT_SUCCESS; return current_process->handle_table.Create(out_handle, std::move(thread));
} }
/// Called when a thread exits /// Called when a thread exits
@ -1325,8 +1237,7 @@ void SVC::ExitThread() {
ResultCode SVC::GetThreadPriority(u32* priority, Handle handle) { ResultCode SVC::GetThreadPriority(u32* priority, Handle handle) {
const std::shared_ptr<Thread> thread = const std::shared_ptr<Thread> thread =
kernel.GetCurrentProcess()->handle_table.Get<Thread>(handle); kernel.GetCurrentProcess()->handle_table.Get<Thread>(handle);
if (thread == nullptr) R_UNLESS(thread, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
*priority = thread->GetPriority(); *priority = thread->GetPriority();
return RESULT_SUCCESS; return RESULT_SUCCESS;
@ -1334,22 +1245,16 @@ ResultCode SVC::GetThreadPriority(u32* priority, Handle handle) {
/// Sets the priority for the specified thread /// Sets the priority for the specified thread
ResultCode SVC::SetThreadPriority(Handle handle, u32 priority) { ResultCode SVC::SetThreadPriority(Handle handle, u32 priority) {
if (priority > ThreadPrioLowest) { R_UNLESS(priority <= ThreadPrioLowest, ERR_OUT_OF_RANGE);
return ERR_OUT_OF_RANGE;
}
const auto thread = kernel.GetCurrentProcess()->handle_table.Get<Thread>(handle); const auto thread = kernel.GetCurrentProcess()->handle_table.Get<Thread>(handle);
if (!thread) { R_UNLESS(thread, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
}
// Note: The kernel uses the current process's resource limit instead of // Note: The kernel uses the current process's resource limit instead of
// the one from the thread owner's resource limit. // the one from the thread owner's resource limit.
const auto& resource_limit = kernel.GetCurrentProcess()->resource_limit; const auto& resource_limit = kernel.GetCurrentProcess()->resource_limit;
const u32 max_priority = resource_limit->GetLimitValue(ResourceLimitType::Priority); const u32 max_priority = resource_limit->GetLimitValue(ResourceLimitType::Priority);
if (max_priority > priority) { R_UNLESS(max_priority <= priority, ERR_NOT_AUTHORIZED);
return ERR_NOT_AUTHORIZED;
}
thread->SetPriority(priority); thread->SetPriority(priority);
thread->UpdatePriority(); thread->UpdatePriority();
@ -1377,12 +1282,7 @@ ResultCode SVC::CreateMutex(Handle* out_handle, u32 initial_locked) {
const auto mutex = kernel.CreateMutex(initial_locked != 0); const auto mutex = kernel.CreateMutex(initial_locked != 0);
mutex->name = fmt::format("mutex-{:08x}", system.GetRunningCore().GetReg(14)); mutex->name = fmt::format("mutex-{:08x}", system.GetRunningCore().GetReg(14));
mutex->resource_limit = resource_limit; mutex->resource_limit = resource_limit;
CASCADE_RESULT(*out_handle, current_process->handle_table.Create(std::move(mutex))); return current_process->handle_table.Create(out_handle, std::move(mutex));
LOG_TRACE(Kernel_SVC, "called initial_locked={} : created handle=0x{:08X}",
initial_locked ? "true" : "false", *out_handle);
return RESULT_SUCCESS;
} }
/// Release a mutex /// Release a mutex
@ -1390,8 +1290,7 @@ ResultCode SVC::ReleaseMutex(Handle handle) {
LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}", handle); LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}", handle);
std::shared_ptr<Mutex> mutex = kernel.GetCurrentProcess()->handle_table.Get<Mutex>(handle); std::shared_ptr<Mutex> mutex = kernel.GetCurrentProcess()->handle_table.Get<Mutex>(handle);
if (mutex == nullptr) R_UNLESS(mutex, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
return mutex->Release(kernel.GetCurrentThreadManager().GetCurrentThread()); return mutex->Release(kernel.GetCurrentThreadManager().GetCurrentThread());
} }
@ -1402,8 +1301,7 @@ ResultCode SVC::GetProcessId(u32* process_id, Handle process_handle) {
const std::shared_ptr<Process> process = const std::shared_ptr<Process> process =
kernel.GetCurrentProcess()->handle_table.Get<Process>(process_handle); kernel.GetCurrentProcess()->handle_table.Get<Process>(process_handle);
if (process == nullptr) R_UNLESS(process, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
*process_id = process->process_id; *process_id = process->process_id;
return RESULT_SUCCESS; return RESULT_SUCCESS;
@ -1415,8 +1313,7 @@ ResultCode SVC::GetProcessIdOfThread(u32* process_id, Handle thread_handle) {
const std::shared_ptr<Thread> thread = const std::shared_ptr<Thread> thread =
kernel.GetCurrentProcess()->handle_table.Get<Thread>(thread_handle); kernel.GetCurrentProcess()->handle_table.Get<Thread>(thread_handle);
if (thread == nullptr) R_UNLESS(thread, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
const std::shared_ptr<Process> process = thread->owner_process.lock(); const std::shared_ptr<Process> process = thread->owner_process.lock();
ASSERT_MSG(process != nullptr, "Invalid parent process for thread={:#010X}", thread_handle); ASSERT_MSG(process != nullptr, "Invalid parent process for thread={:#010X}", thread_handle);
@ -1431,8 +1328,7 @@ ResultCode SVC::GetThreadId(u32* thread_id, Handle handle) {
const std::shared_ptr<Thread> thread = const std::shared_ptr<Thread> thread =
kernel.GetCurrentProcess()->handle_table.Get<Thread>(handle); kernel.GetCurrentProcess()->handle_table.Get<Thread>(handle);
if (thread == nullptr) R_UNLESS(thread, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
*thread_id = thread->GetThreadId(); *thread_id = thread->GetThreadId();
return RESULT_SUCCESS; return RESULT_SUCCESS;
@ -1453,11 +1349,7 @@ ResultCode SVC::CreateSemaphore(Handle* out_handle, s32 initial_count, s32 max_c
kernel.CreateSemaphore(initial_count, max_count)); kernel.CreateSemaphore(initial_count, max_count));
semaphore->name = fmt::format("semaphore-{:08x}", system.GetRunningCore().GetReg(14)); semaphore->name = fmt::format("semaphore-{:08x}", system.GetRunningCore().GetReg(14));
semaphore->resource_limit = resource_limit; semaphore->resource_limit = resource_limit;
CASCADE_RESULT(*out_handle, current_process->handle_table.Create(std::move(semaphore))); return current_process->handle_table.Create(out_handle, std::move(semaphore));
LOG_TRACE(Kernel_SVC, "called initial_count={}, max_count={}, created handle=0x{:08X}",
initial_count, max_count, *out_handle);
return RESULT_SUCCESS;
} }
/// Releases a certain number of slots in a semaphore /// Releases a certain number of slots in a semaphore
@ -1466,18 +1358,14 @@ ResultCode SVC::ReleaseSemaphore(s32* count, Handle handle, s32 release_count) {
std::shared_ptr<Semaphore> semaphore = std::shared_ptr<Semaphore> semaphore =
kernel.GetCurrentProcess()->handle_table.Get<Semaphore>(handle); kernel.GetCurrentProcess()->handle_table.Get<Semaphore>(handle);
if (semaphore == nullptr) R_UNLESS(semaphore, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
CASCADE_RESULT(*count, semaphore->Release(release_count)); return semaphore->Release(count, release_count);
return RESULT_SUCCESS;
} }
/// Sets the kernel state /// Sets the kernel state
ResultCode SVC::KernelSetState(u32 kernel_state, u32 varg1, u32 varg2) { ResultCode SVC::KernelSetState(u32 kernel_state, u32 varg1, u32 varg2) {
switch (static_cast<KernelState>(kernel_state)) { switch (static_cast<KernelState>(kernel_state)) {
// This triggers a hardware reboot on real console, since this doesn't make sense // This triggers a hardware reboot on real console, since this doesn't make sense
// on emulator, we shutdown instead. // on emulator, we shutdown instead.
case KernelState::KERNEL_STATE_REBOOT: case KernelState::KERNEL_STATE_REBOOT:
@ -1495,13 +1383,10 @@ ResultCode SVC::QueryProcessMemory(MemoryInfo* memory_info, PageInfo* page_info,
Handle process_handle, u32 addr) { Handle process_handle, u32 addr) {
std::shared_ptr<Process> process = std::shared_ptr<Process> process =
kernel.GetCurrentProcess()->handle_table.Get<Process>(process_handle); kernel.GetCurrentProcess()->handle_table.Get<Process>(process_handle);
if (process == nullptr) R_UNLESS(process, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
auto vma = process->vm_manager.FindVMA(addr); auto vma = process->vm_manager.FindVMA(addr);
R_UNLESS(vma != process->vm_manager.vma_map.end(), ERR_INVALID_ADDRESS);
if (vma == process->vm_manager.vma_map.end())
return ERR_INVALID_ADDRESS;
auto permissions = vma->second.permissions; auto permissions = vma->second.permissions;
auto state = vma->second.meminfo_state; auto state = vma->second.meminfo_state;
@ -1549,18 +1434,12 @@ ResultCode SVC::CreateEvent(Handle* out_handle, u32 reset_type) {
const auto name = fmt::format("event-{:08x}", system.GetRunningCore().GetReg(14)); const auto name = fmt::format("event-{:08x}", system.GetRunningCore().GetReg(14));
const auto event = kernel.CreateEvent(static_cast<ResetType>(reset_type), name); const auto event = kernel.CreateEvent(static_cast<ResetType>(reset_type), name);
event->resource_limit = resource_limit; event->resource_limit = resource_limit;
CASCADE_RESULT(*out_handle, current_process->handle_table.Create(std::move(event))); return current_process->handle_table.Create(out_handle, std::move(event));
LOG_TRACE(Kernel_SVC, "called reset_type=0x{:08X} : created handle=0x{:08X}", reset_type,
*out_handle);
return RESULT_SUCCESS;
} }
/// Duplicates a kernel handle /// Duplicates a kernel handle
ResultCode SVC::DuplicateHandle(Handle* out, Handle handle) { ResultCode SVC::DuplicateHandle(Handle* out, Handle handle) {
CASCADE_RESULT(*out, kernel.GetCurrentProcess()->handle_table.Duplicate(handle)); return kernel.GetCurrentProcess()->handle_table.Duplicate(out, handle);
LOG_TRACE(Kernel_SVC, "duplicated 0x{:08X} to 0x{:08X}", handle, *out);
return RESULT_SUCCESS;
} }
/// Signals an event /// Signals an event
@ -1568,11 +1447,9 @@ ResultCode SVC::SignalEvent(Handle handle) {
LOG_TRACE(Kernel_SVC, "called event=0x{:08X}", handle); LOG_TRACE(Kernel_SVC, "called event=0x{:08X}", handle);
std::shared_ptr<Event> evt = kernel.GetCurrentProcess()->handle_table.Get<Event>(handle); std::shared_ptr<Event> evt = kernel.GetCurrentProcess()->handle_table.Get<Event>(handle);
if (evt == nullptr) R_UNLESS(evt, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
evt->Signal(); evt->Signal();
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
@ -1581,8 +1458,7 @@ ResultCode SVC::ClearEvent(Handle handle) {
LOG_TRACE(Kernel_SVC, "called event=0x{:08X}", handle); LOG_TRACE(Kernel_SVC, "called event=0x{:08X}", handle);
std::shared_ptr<Event> evt = kernel.GetCurrentProcess()->handle_table.Get<Event>(handle); std::shared_ptr<Event> evt = kernel.GetCurrentProcess()->handle_table.Get<Event>(handle);
if (evt == nullptr) R_UNLESS(evt, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
evt->Clear(); evt->Clear();
return RESULT_SUCCESS; return RESULT_SUCCESS;
@ -1602,11 +1478,7 @@ ResultCode SVC::CreateTimer(Handle* out_handle, u32 reset_type) {
const auto name = fmt::format("timer-{:08x}", system.GetRunningCore().GetReg(14)); const auto name = fmt::format("timer-{:08x}", system.GetRunningCore().GetReg(14));
const auto timer = kernel.CreateTimer(static_cast<ResetType>(reset_type), name); const auto timer = kernel.CreateTimer(static_cast<ResetType>(reset_type), name);
timer->resource_limit = resource_limit; timer->resource_limit = resource_limit;
CASCADE_RESULT(*out_handle, current_process->handle_table.Create(std::move(timer))); return current_process->handle_table.Create(out_handle, std::move(timer));
LOG_TRACE(Kernel_SVC, "called reset_type=0x{:08X} : created handle=0x{:08X}", reset_type,
*out_handle);
return RESULT_SUCCESS;
} }
/// Clears a timer /// Clears a timer
@ -1614,8 +1486,7 @@ ResultCode SVC::ClearTimer(Handle handle) {
LOG_TRACE(Kernel_SVC, "called timer=0x{:08X}", handle); LOG_TRACE(Kernel_SVC, "called timer=0x{:08X}", handle);
std::shared_ptr<Timer> timer = kernel.GetCurrentProcess()->handle_table.Get<Timer>(handle); std::shared_ptr<Timer> timer = kernel.GetCurrentProcess()->handle_table.Get<Timer>(handle);
if (timer == nullptr) R_UNLESS(timer, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
timer->Clear(); timer->Clear();
return RESULT_SUCCESS; return RESULT_SUCCESS;
@ -1625,13 +1496,10 @@ ResultCode SVC::ClearTimer(Handle handle) {
ResultCode SVC::SetTimer(Handle handle, s64 initial, s64 interval) { ResultCode SVC::SetTimer(Handle handle, s64 initial, s64 interval) {
LOG_TRACE(Kernel_SVC, "called timer=0x{:08X}", handle); LOG_TRACE(Kernel_SVC, "called timer=0x{:08X}", handle);
if (initial < 0 || interval < 0) { R_UNLESS(initial >= 0 && interval >= 0, ERR_OUT_OF_RANGE_KERNEL);
return ERR_OUT_OF_RANGE_KERNEL;
}
std::shared_ptr<Timer> timer = kernel.GetCurrentProcess()->handle_table.Get<Timer>(handle); std::shared_ptr<Timer> timer = kernel.GetCurrentProcess()->handle_table.Get<Timer>(handle);
if (timer == nullptr) R_UNLESS(timer, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
timer->Set(initial, interval); timer->Set(initial, interval);
@ -1643,11 +1511,9 @@ ResultCode SVC::CancelTimer(Handle handle) {
LOG_TRACE(Kernel_SVC, "called timer=0x{:08X}", handle); LOG_TRACE(Kernel_SVC, "called timer=0x{:08X}", handle);
std::shared_ptr<Timer> timer = kernel.GetCurrentProcess()->handle_table.Get<Timer>(handle); std::shared_ptr<Timer> timer = kernel.GetCurrentProcess()->handle_table.Get<Timer>(handle);
if (timer == nullptr) R_UNLESS(timer, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
timer->Cancel(); timer->Cancel();
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
@ -1659,8 +1525,9 @@ void SVC::SleepThread(s64 nanoseconds) {
// Don't attempt to yield execution if there are no available threads to run, // Don't attempt to yield execution if there are no available threads to run,
// this way we avoid a useless reschedule to the idle thread. // this way we avoid a useless reschedule to the idle thread.
if (nanoseconds == 0 && !thread_manager.HaveReadyThreads()) if (nanoseconds == 0 && !thread_manager.HaveReadyThreads()) {
return; return;
}
// Sleep current thread and check for next thread to schedule // Sleep current thread and check for next thread to schedule
thread_manager.WaitCurrentThread_Sleep(); thread_manager.WaitCurrentThread_Sleep();
@ -1683,10 +1550,8 @@ s64 SVC::GetSystemTick() {
// Returns information of the specified handle // Returns information of the specified handle
ResultCode SVC::GetHandleInfo(s64* out, Handle handle, u32 type) { ResultCode SVC::GetHandleInfo(s64* out, Handle handle, u32 type) {
std::shared_ptr<Object> KObject = kernel.GetCurrentProcess()->handle_table.GetGeneric(handle); std::shared_ptr<Object> object = kernel.GetCurrentProcess()->handle_table.GetGeneric(handle);
if (!KObject) { R_UNLESS(object, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
}
// Not initialized in real kernel, but we don't want to leak memory. // Not initialized in real kernel, but we don't want to leak memory.
s64 value = 0; s64 value = 0;
@ -1694,14 +1559,14 @@ ResultCode SVC::GetHandleInfo(s64* out, Handle handle, u32 type) {
switch (static_cast<HandleInfoType>(type)) { switch (static_cast<HandleInfoType>(type)) {
case HandleInfoType::KPROCESS_ELAPSED_TICKS: case HandleInfoType::KPROCESS_ELAPSED_TICKS:
process = DynamicObjectCast<Process>(KObject); process = DynamicObjectCast<Process>(object);
if (process) { if (process) {
value = process->creation_time_ticks; value = process->creation_time_ticks;
} }
break; break;
case HandleInfoType::REFERENCE_COUNT: case HandleInfoType::REFERENCE_COUNT:
// This is the closest approximation we can get without a full KObject impl. // This is the closest approximation we can get without a full KObject impl.
value = KObject.use_count() - 1; value = object.use_count() - 1;
break; break;
// These values are stubbed in real kernel, they do nothing. // These values are stubbed in real kernel, they do nothing.
@ -1718,8 +1583,7 @@ ResultCode SVC::GetHandleInfo(s64* out, Handle handle, u32 type) {
/// Creates a memory block at the specified address with the specified permissions and size /// Creates a memory block at the specified address with the specified permissions and size
ResultCode SVC::CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 my_permission, ResultCode SVC::CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 my_permission,
u32 other_permission) { u32 other_permission) {
if (size % Memory::CITRA_PAGE_SIZE != 0) R_UNLESS(size % Memory::CITRA_PAGE_SIZE == 0, ERR_MISALIGNED_SIZE);
return ERR_MISALIGNED_SIZE;
std::shared_ptr<SharedMemory> shared_memory = nullptr; std::shared_ptr<SharedMemory> shared_memory = nullptr;
@ -1737,9 +1601,10 @@ ResultCode SVC::CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 my
} }
}; };
if (!VerifyPermissions(static_cast<MemoryPermission>(my_permission)) || R_UNLESS(VerifyPermissions(static_cast<MemoryPermission>(my_permission)),
!VerifyPermissions(static_cast<MemoryPermission>(other_permission))) ERR_INVALID_COMBINATION);
return ERR_INVALID_COMBINATION; R_UNLESS(VerifyPermissions(static_cast<MemoryPermission>(other_permission)),
ERR_INVALID_COMBINATION);
// TODO(Subv): Processes with memory type APPLICATION are not allowed // TODO(Subv): Processes with memory type APPLICATION are not allowed
// to create memory blocks with addr = 0, any attempts to do so // to create memory blocks with addr = 0, any attempts to do so
@ -1770,64 +1635,56 @@ ResultCode SVC::CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 my
kernel.CreateSharedMemory( kernel.CreateSharedMemory(
current_process, size, static_cast<MemoryPermission>(my_permission), current_process, size, static_cast<MemoryPermission>(my_permission),
static_cast<MemoryPermission>(other_permission), addr, region)); static_cast<MemoryPermission>(other_permission), addr, region));
CASCADE_RESULT(*out_handle, current_process->handle_table.Create(std::move(shared_memory))); return current_process->handle_table.Create(out_handle, std::move(shared_memory));
LOG_WARNING(Kernel_SVC, "called addr=0x{:08X}", addr);
return RESULT_SUCCESS;
} }
ResultCode SVC::CreatePort(Handle* server_port, Handle* client_port, VAddr name_address, ResultCode SVC::CreatePort(Handle* server_port, Handle* client_port, VAddr name_address,
u32 max_sessions) { u32 max_sessions) {
// TODO(Subv): Implement named ports. // TODO(Subv): Implement named ports.
ASSERT_MSG(name_address == 0, "Named ports are currently unimplemented"); ASSERT_MSG(name_address == 0, "Named ports are currently unimplemented");
LOG_TRACE(Kernel_SVC, "called max_sessions={}", max_sessions);
std::shared_ptr<Process> current_process = kernel.GetCurrentProcess(); std::shared_ptr<Process> current_process = kernel.GetCurrentProcess();
auto [server, client] = kernel.CreatePortPair(max_sessions); auto [server, client] = kernel.CreatePortPair(max_sessions);
CASCADE_RESULT(*client_port, current_process->handle_table.Create(std::move(client))); R_TRY(current_process->handle_table.Create(client_port, std::move(client)));
// Note: The 3DS kernel also leaks the client port handle if the server port handle fails to be // Note: The 3DS kernel also leaks the client port handle if the server port handle fails to be
// created. // created.
CASCADE_RESULT(*server_port, current_process->handle_table.Create(std::move(server))); return current_process->handle_table.Create(server_port, std::move(server));
LOG_TRACE(Kernel_SVC, "called max_sessions={}", max_sessions);
return RESULT_SUCCESS;
} }
ResultCode SVC::CreateSessionToPort(Handle* out_client_session, Handle client_port_handle) { ResultCode SVC::CreateSessionToPort(Handle* out_client_session, Handle client_port_handle) {
std::shared_ptr<Process> current_process = kernel.GetCurrentProcess(); std::shared_ptr<Process> current_process = kernel.GetCurrentProcess();
std::shared_ptr<ClientPort> client_port = std::shared_ptr<ClientPort> client_port =
current_process->handle_table.Get<ClientPort>(client_port_handle); current_process->handle_table.Get<ClientPort>(client_port_handle);
if (client_port == nullptr) R_UNLESS(client_port, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
CASCADE_RESULT(auto session, client_port->Connect()); std::shared_ptr<ClientSession> session;
CASCADE_RESULT(*out_client_session, current_process->handle_table.Create(std::move(session))); R_TRY(client_port->Connect(session));
return RESULT_SUCCESS;
return current_process->handle_table.Create(out_client_session, std::move(session));
} }
ResultCode SVC::CreateSession(Handle* server_session, Handle* client_session) { ResultCode SVC::CreateSession(Handle* server_session, Handle* client_session) {
auto [server, client] = kernel.CreateSessionPair(); auto [server, client] = kernel.CreateSessionPair();
LOG_TRACE(Kernel_SVC, "called");
std::shared_ptr<Process> current_process = kernel.GetCurrentProcess(); std::shared_ptr<Process> current_process = kernel.GetCurrentProcess();
R_TRY(current_process->handle_table.Create(server_session, std::move(server)));
CASCADE_RESULT(*server_session, current_process->handle_table.Create(std::move(server))); return current_process->handle_table.Create(client_session, std::move(client));
CASCADE_RESULT(*client_session, current_process->handle_table.Create(std::move(client)));
LOG_TRACE(Kernel_SVC, "called");
return RESULT_SUCCESS;
} }
ResultCode SVC::AcceptSession(Handle* out_server_session, Handle server_port_handle) { ResultCode SVC::AcceptSession(Handle* out_server_session, Handle server_port_handle) {
std::shared_ptr<Process> current_process = kernel.GetCurrentProcess(); std::shared_ptr<Process> current_process = kernel.GetCurrentProcess();
std::shared_ptr<ServerPort> server_port = std::shared_ptr<ServerPort> server_port =
current_process->handle_table.Get<ServerPort>(server_port_handle); current_process->handle_table.Get<ServerPort>(server_port_handle);
if (server_port == nullptr) R_UNLESS(server_port, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
CASCADE_RESULT(auto session, server_port->Accept()); std::shared_ptr<ServerSession> session;
CASCADE_RESULT(*out_server_session, current_process->handle_table.Create(std::move(session))); R_TRY(server_port->Accept(session));
return RESULT_SUCCESS;
return current_process->handle_table.Create(out_server_session, std::move(session));
} }
static void CopyStringPart(char* out, const char* in, size_t offset, size_t max_length) { static void CopyStringPart(char* out, const char* in, size_t offset, size_t max_length) {
@ -1943,8 +1800,7 @@ ResultCode SVC::GetProcessInfo(s64* out, Handle process_handle, u32 type) {
std::shared_ptr<Process> process = std::shared_ptr<Process> process =
kernel.GetCurrentProcess()->handle_table.Get<Process>(process_handle); kernel.GetCurrentProcess()->handle_table.Get<Process>(process_handle);
if (process == nullptr) R_UNLESS(process, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
switch (static_cast<ProcessInfoType>(type)) { switch (static_cast<ProcessInfoType>(type)) {
case ProcessInfoType::PRIVATE_AND_SHARED_USED_MEMORY: case ProcessInfoType::PRIVATE_AND_SHARED_USED_MEMORY:
@ -1979,7 +1835,7 @@ ResultCode SVC::GetProcessInfo(s64* out, Handle process_handle, u32 type) {
// Here start the custom ones, taken from Luma3DS for 3GX support // Here start the custom ones, taken from Luma3DS for 3GX support
case ProcessInfoType::LUMA_CUSTOM_PROCESS_NAME: case ProcessInfoType::LUMA_CUSTOM_PROCESS_NAME:
// Get process name // Get process name
strncpy(reinterpret_cast<char*>(out), process->codeset->GetName().c_str(), 8); std::strncpy(reinterpret_cast<char*>(out), process->codeset->GetName().c_str(), 8);
break; break;
case ProcessInfoType::LUMA_CUSTOM_PROCESS_TITLE_ID: case ProcessInfoType::LUMA_CUSTOM_PROCESS_TITLE_ID:
// Get process TID // Get process TID
@ -2017,9 +1873,7 @@ ResultCode SVC::GetThreadInfo(s64* out, Handle thread_handle, u32 type) {
std::shared_ptr<Thread> thread = std::shared_ptr<Thread> thread =
kernel.GetCurrentProcess()->handle_table.Get<Thread>(thread_handle); kernel.GetCurrentProcess()->handle_table.Get<Thread>(thread_handle);
if (thread == nullptr) { R_UNLESS(thread, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
}
switch (type) { switch (type) {
case 0x10000: case 0x10000:
@ -2035,9 +1889,8 @@ ResultCode SVC::GetThreadInfo(s64* out, Handle thread_handle, u32 type) {
ResultCode SVC::GetProcessList(s32* process_count, VAddr out_process_array, ResultCode SVC::GetProcessList(s32* process_count, VAddr out_process_array,
s32 out_process_array_count) { s32 out_process_array_count) {
if (!memory.IsValidVirtualAddress(*kernel.GetCurrentProcess(), out_process_array)) { R_UNLESS(memory.IsValidVirtualAddress(*kernel.GetCurrentProcess(), out_process_array),
return ERR_INVALID_POINTER; ERR_INVALID_POINTER);
}
s32 written = 0; s32 written = 0;
for (const auto& process : kernel.GetProcessList()) { for (const auto& process : kernel.GetProcessList()) {
@ -2080,9 +1933,7 @@ ResultCode SVC::MapProcessMemoryEx(Handle dst_process_handle, u32 dst_address,
std::shared_ptr<Process> src_process = std::shared_ptr<Process> src_process =
kernel.GetCurrentProcess()->handle_table.Get<Process>(src_process_handle); kernel.GetCurrentProcess()->handle_table.Get<Process>(src_process_handle);
if (dst_process == nullptr || src_process == nullptr) { R_UNLESS(dst_process && src_process, ERR_INVALID_HANDLE);
return ERR_INVALID_HANDLE;
}
if (size & 0xFFF) { if (size & 0xFFF) {
size = (size & ~0xFFF) + Memory::CITRA_PAGE_SIZE; size = (size & ~0xFFF) + Memory::CITRA_PAGE_SIZE;
@ -2090,16 +1941,13 @@ ResultCode SVC::MapProcessMemoryEx(Handle dst_process_handle, u32 dst_address,
// Only linear memory supported // Only linear memory supported
auto vma = src_process->vm_manager.FindVMA(src_address); auto vma = src_process->vm_manager.FindVMA(src_address);
if (vma == src_process->vm_manager.vma_map.end() || R_UNLESS(vma != src_process->vm_manager.vma_map.end() &&
vma->second.type != VMAType::BackingMemory || vma->second.type == VMAType::BackingMemory &&
vma->second.meminfo_state != MemoryState::Continuous) { vma->second.meminfo_state == MemoryState::Continuous,
return ERR_INVALID_ADDRESS; ERR_INVALID_ADDRESS);
}
u32 offset = src_address - vma->second.base; const u32 offset = src_address - vma->second.base;
if (offset + size > vma->second.size) { R_UNLESS(offset + size <= vma->second.size, ERR_INVALID_ADDRESS);
return ERR_INVALID_ADDRESS;
}
auto vma_res = dst_process->vm_manager.MapBackingMemory( auto vma_res = dst_process->vm_manager.MapBackingMemory(
dst_address, dst_address,
@ -2110,18 +1958,15 @@ ResultCode SVC::MapProcessMemoryEx(Handle dst_process_handle, u32 dst_address,
if (!vma_res.Succeeded()) { if (!vma_res.Succeeded()) {
return ERR_INVALID_ADDRESS_STATE; return ERR_INVALID_ADDRESS_STATE;
} }
dst_process->vm_manager.Reprotect(vma_res.Unwrap(), Kernel::VMAPermission::ReadWriteExecute);
dst_process->vm_manager.Reprotect(vma_res.Unwrap(), Kernel::VMAPermission::ReadWriteExecute);
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
ResultCode SVC::UnmapProcessMemoryEx(Handle process, u32 dst_address, u32 size) { ResultCode SVC::UnmapProcessMemoryEx(Handle process, u32 dst_address, u32 size) {
std::shared_ptr<Process> dst_process = std::shared_ptr<Process> dst_process =
kernel.GetCurrentProcess()->handle_table.Get<Process>(process); kernel.GetCurrentProcess()->handle_table.Get<Process>(process);
R_UNLESS(dst_process, ERR_INVALID_HANDLE);
if (dst_process == nullptr) {
return ERR_INVALID_HANDLE;
}
if (size & 0xFFF) { if (size & 0xFFF) {
size = (size & ~0xFFF) + Memory::CITRA_PAGE_SIZE; size = (size & ~0xFFF) + Memory::CITRA_PAGE_SIZE;
@ -2129,11 +1974,10 @@ ResultCode SVC::UnmapProcessMemoryEx(Handle process, u32 dst_address, u32 size)
// Only linear memory supported // Only linear memory supported
auto vma = dst_process->vm_manager.FindVMA(dst_address); auto vma = dst_process->vm_manager.FindVMA(dst_address);
if (vma == dst_process->vm_manager.vma_map.end() || R_UNLESS(vma != dst_process->vm_manager.vma_map.end() &&
vma->second.type != VMAType::BackingMemory || vma->second.type == VMAType::BackingMemory &&
vma->second.meminfo_state != MemoryState::Continuous) { vma->second.meminfo_state == MemoryState::Continuous,
return ERR_INVALID_ADDRESS; ERR_INVALID_ADDRESS);
}
dst_process->vm_manager.UnmapRange(dst_address, size); dst_process->vm_manager.UnmapRange(dst_address, size);
return RESULT_SUCCESS; return RESULT_SUCCESS;
@ -2142,10 +1986,7 @@ ResultCode SVC::UnmapProcessMemoryEx(Handle process, u32 dst_address, u32 size)
ResultCode SVC::ControlProcess(Handle process_handle, u32 process_OP, u32 varg2, u32 varg3) { ResultCode SVC::ControlProcess(Handle process_handle, u32 process_OP, u32 varg2, u32 varg3) {
std::shared_ptr<Process> process = std::shared_ptr<Process> process =
kernel.GetCurrentProcess()->handle_table.Get<Process>(process_handle); kernel.GetCurrentProcess()->handle_table.Get<Process>(process_handle);
R_UNLESS(process, ERR_INVALID_HANDLE);
if (process == nullptr) {
return ERR_INVALID_HANDLE;
}
switch (static_cast<ControlProcessOP>(process_OP)) { switch (static_cast<ControlProcessOP>(process_OP)) {
case ControlProcessOP::PROCESSOP_SET_MMU_TO_RWX: { case ControlProcessOP::PROCESSOP_SET_MMU_TO_RWX: {
@ -2158,9 +1999,7 @@ ResultCode SVC::ControlProcess(Handle process_handle, u32 process_OP, u32 varg2,
} }
case ControlProcessOP::PROCESSOP_GET_ON_MEMORY_CHANGE_EVENT: { case ControlProcessOP::PROCESSOP_GET_ON_MEMORY_CHANGE_EVENT: {
auto plgldr = Service::PLGLDR::GetService(system); auto plgldr = Service::PLGLDR::GetService(system);
if (!plgldr) { R_UNLESS(plgldr, ERR_NOT_FOUND);
return ERR_NOT_FOUND;
}
ResultVal<Handle> out = plgldr->GetMemoryChangedHandle(kernel); ResultVal<Handle> out = plgldr->GetMemoryChangedHandle(kernel);
if (out.Failed()) { if (out.Failed()) {

View File

@ -408,3 +408,29 @@ private:
auto CONCAT2(check_result_L, __LINE__) = source; \ auto CONCAT2(check_result_L, __LINE__) = source; \
if (CONCAT2(check_result_L, __LINE__).IsError()) \ if (CONCAT2(check_result_L, __LINE__).IsError()) \
return CONCAT2(check_result_L, __LINE__); return CONCAT2(check_result_L, __LINE__);
#define R_SUCCEEDED(res) (static_cast<ResultCode>(res).IsSuccess())
#define R_FAILED(res) (static_cast<ResultCode>(res).IsError())
/// Evaluates a boolean expression, and returns a result unless that expression is true.
#define R_UNLESS(expr, res) \
{ \
if (!(expr)) { \
return (res); \
} \
}
/// Evaluates an expression that returns a result, and returns the result if it would fail.
#define R_TRY(res_expr) \
{ \
const auto _tmp_r_try_rc = (res_expr); \
if (R_FAILED(_tmp_r_try_rc)) { \
return (_tmp_r_try_rc); \
} \
}
/// Evaluates a boolean expression, and succeeds if that expression is true.
#define R_SUCCEED_IF(expr) R_UNLESS(!(expr), RESULT_SUCCESS)
/// Evaluates a boolean expression, and asserts if that expression is false.
#define R_ASSERT(expr) ASSERT(R_SUCCEEDED(expr))

View File

@ -130,21 +130,22 @@ void PLG_LDR::OnProcessExit(Kernel::Process& process, Kernel::KernelSystem& kern
} }
ResultVal<Kernel::Handle> PLG_LDR::GetMemoryChangedHandle(Kernel::KernelSystem& kernel) { ResultVal<Kernel::Handle> PLG_LDR::GetMemoryChangedHandle(Kernel::KernelSystem& kernel) {
if (plgldr_context.memory_changed_handle) if (plgldr_context.memory_changed_handle) {
return plgldr_context.memory_changed_handle; return plgldr_context.memory_changed_handle;
}
std::shared_ptr<Kernel::Event> evt = kernel.CreateEvent( std::shared_ptr<Kernel::Event> evt = kernel.CreateEvent(
Kernel::ResetType::OneShot, Kernel::ResetType::OneShot,
fmt::format("event-{:08x}", Core::System::GetInstance().GetRunningCore().GetReg(14))); fmt::format("event-{:08x}", Core::System::GetInstance().GetRunningCore().GetReg(14)));
CASCADE_RESULT(plgldr_context.memory_changed_handle, R_TRY(kernel.GetCurrentProcess()->handle_table.Create(
kernel.GetCurrentProcess()->handle_table.Create(std::move(evt))); std::addressof(plgldr_context.memory_changed_handle), std::move(evt)));
return plgldr_context.memory_changed_handle; return plgldr_context.memory_changed_handle;
} }
void PLG_LDR::OnMemoryChanged(Kernel::Process& process, Kernel::KernelSystem& kernel) { void PLG_LDR::OnMemoryChanged(Kernel::Process& process, Kernel::KernelSystem& kernel) {
if (!plgldr_context.plugin_loaded || !plgldr_context.memory_changed_handle) if (!plgldr_context.plugin_loaded || !plgldr_context.memory_changed_handle) {
return; return;
}
std::shared_ptr<Kernel::Event> evt = std::shared_ptr<Kernel::Event> evt =
kernel.GetCurrentProcess()->handle_table.Get<Kernel::Event>( kernel.GetCurrentProcess()->handle_table.Get<Kernel::Event>(

View File

@ -130,7 +130,8 @@ ServiceFrameworkBase::ServiceFrameworkBase(const char* service_name, u32 max_ses
ServiceFrameworkBase::~ServiceFrameworkBase() = default; ServiceFrameworkBase::~ServiceFrameworkBase() = default;
void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) { void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) {
auto port = service_manager.RegisterService(service_name, max_sessions).Unwrap(); std::shared_ptr<Kernel::ServerPort> port;
R_ASSERT(service_manager.RegisterService(port, service_name, max_sessions));
port->SetHleHandler(shared_from_this()); port->SetHleHandler(shared_from_this());
} }

View File

@ -13,12 +13,8 @@
namespace Service::SM { namespace Service::SM {
static ResultCode ValidateServiceName(const std::string& name) { static ResultCode ValidateServiceName(const std::string& name) {
if (name.size() <= 0 || name.size() > 8) { R_UNLESS(name.size() > 0 && name.size() <= 8, ERR_INVALID_NAME_SIZE);
return ERR_INVALID_NAME_SIZE; R_UNLESS(name.find('\0') == std::string::npos, ERR_NAME_CONTAINS_NUL);
}
if (name.find('\0') != std::string::npos) {
return ERR_NAME_CONTAINS_NUL;
}
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
@ -32,38 +28,35 @@ void ServiceManager::InstallInterfaces(Core::System& system) {
system.ServiceManager().srv_interface = srv; system.ServiceManager().srv_interface = srv;
} }
ResultVal<std::shared_ptr<Kernel::ServerPort>> ServiceManager::RegisterService( ResultCode ServiceManager::RegisterService(std::shared_ptr<Kernel::ServerPort>& server_port,
std::string name, unsigned int max_sessions) { std::string name, u32 max_sessions) {
R_TRY(ValidateServiceName(name));
CASCADE_CODE(ValidateServiceName(name)); R_UNLESS(registered_services.find(name) == registered_services.end(), ERR_ALREADY_REGISTERED);
if (registered_services.find(name) != registered_services.end())
return ERR_ALREADY_REGISTERED;
auto [server_port, client_port] = system.Kernel().CreatePortPair(max_sessions, name);
std::shared_ptr<Kernel::ClientPort> client_port;
std::tie(server_port, client_port) = system.Kernel().CreatePortPair(max_sessions, name);
registered_services_inverse.emplace(client_port->GetObjectId(), name); registered_services_inverse.emplace(client_port->GetObjectId(), name);
registered_services.emplace(std::move(name), std::move(client_port)); registered_services.emplace(std::move(name), std::move(client_port));
return server_port;
return RESULT_SUCCESS;
} }
ResultVal<std::shared_ptr<Kernel::ClientPort>> ServiceManager::GetServicePort( ResultCode ServiceManager::GetServicePort(std::shared_ptr<Kernel::ClientPort>& out_port,
const std::string& name) { const std::string& name) {
R_TRY(ValidateServiceName(name));
CASCADE_CODE(ValidateServiceName(name));
auto it = registered_services.find(name); auto it = registered_services.find(name);
if (it == registered_services.end()) { R_UNLESS(it != registered_services.end(), ERR_SERVICE_NOT_REGISTERED);
return ERR_SERVICE_NOT_REGISTERED;
}
return it->second; out_port = it->second;
return RESULT_SUCCESS;
} }
ResultVal<std::shared_ptr<Kernel::ClientSession>> ServiceManager::ConnectToService( ResultCode ServiceManager::ConnectToService(std::shared_ptr<Kernel::ClientSession>& session,
const std::string& name) { const std::string& name) {
std::shared_ptr<Kernel::ClientPort> client_port;
CASCADE_RESULT(auto client_port, GetServicePort(name)); R_TRY(GetServicePort(client_port, name));
return client_port->Connect(); return client_port->Connect(session);
} }
std::string ServiceManager::GetServiceNameByPortId(u32 port) const { std::string ServiceManager::GetServiceNameByPortId(u32 port) const {

View File

@ -51,10 +51,12 @@ public:
explicit ServiceManager(Core::System& system); explicit ServiceManager(Core::System& system);
ResultVal<std::shared_ptr<Kernel::ServerPort>> RegisterService(std::string name, ResultCode RegisterService(std::shared_ptr<Kernel::ServerPort>& out_port, std::string name,
unsigned int max_sessions); u32 max_sessions);
ResultVal<std::shared_ptr<Kernel::ClientPort>> GetServicePort(const std::string& name); ResultCode GetServicePort(std::shared_ptr<Kernel::ClientPort>& out_port,
ResultVal<std::shared_ptr<Kernel::ClientSession>> ConnectToService(const std::string& name); const std::string& name);
ResultCode ConnectToService(std::shared_ptr<Kernel::ClientSession>& out_session,
const std::string& name);
// For IPC Recorder // For IPC Recorder
std::string GetServiceNameByPortId(u32 port) const; std::string GetServiceNameByPortId(u32 port) const;

View File

@ -94,22 +94,23 @@ public:
void WakeUp(std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx, void WakeUp(std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx,
Kernel::ThreadWakeupReason reason) { Kernel::ThreadWakeupReason reason) {
LOG_ERROR(Service_SRV, "called service={} wakeup", name); LOG_ERROR(Service_SRV, "called service={} wakeup", name);
auto client_port = system.ServiceManager().GetServicePort(name); std::shared_ptr<Kernel::ClientPort> client_port;
R_ASSERT(system.ServiceManager().GetServicePort(client_port, name));
auto session = client_port.Unwrap()->Connect(); std::shared_ptr<Kernel::ClientSession> session;
if (session.Succeeded()) { auto result = client_port->Connect(session);
LOG_DEBUG(Service_SRV, "called service={} -> session={}", name, if (result.IsSuccess()) {
(*session)->GetObjectId()); LOG_DEBUG(Service_SRV, "called service={} -> session={}", name, session->GetObjectId());
IPC::RequestBuilder rb(ctx, 0x5, 1, 2); IPC::RequestBuilder rb(ctx, 0x5, 1, 2);
rb.Push(session.Code()); rb.Push(result);
rb.PushMoveObjects(std::move(session).Unwrap()); rb.PushMoveObjects(std::move(session));
} else if (session.Code() == Kernel::ERR_MAX_CONNECTIONS_REACHED) { } else if (result == Kernel::ERR_MAX_CONNECTIONS_REACHED) {
LOG_ERROR(Service_SRV, "called service={} -> ERR_MAX_CONNECTIONS_REACHED", name); LOG_ERROR(Service_SRV, "called service={} -> ERR_MAX_CONNECTIONS_REACHED", name);
UNREACHABLE(); UNREACHABLE();
} else { } else {
LOG_ERROR(Service_SRV, "called service={} -> error 0x{:08X}", name, session.Code().raw); LOG_ERROR(Service_SRV, "called service={} -> error 0x{:08X}", name, result.raw);
IPC::RequestBuilder rb(ctx, 0x5, 1, 0); IPC::RequestBuilder rb(ctx, 0x5, 1, 0);
rb.Push(session.Code()); rb.Push(result);
} }
} }
@ -158,9 +159,10 @@ void SRV::GetServiceHandle(Kernel::HLERequestContext& ctx) {
auto get_handle = std::make_shared<ThreadCallback>(system, name); auto get_handle = std::make_shared<ThreadCallback>(system, name);
auto client_port = system.ServiceManager().GetServicePort(name); std::shared_ptr<Kernel::ClientPort> client_port;
if (client_port.Failed()) { auto result = system.ServiceManager().GetServicePort(client_port, name);
if (wait_until_available && client_port.Code() == ERR_SERVICE_NOT_REGISTERED) { if (result.IsError()) {
if (wait_until_available && result == ERR_SERVICE_NOT_REGISTERED) {
LOG_INFO(Service_SRV, "called service={} delayed", name); LOG_INFO(Service_SRV, "called service={} delayed", name);
std::shared_ptr<Kernel::Event> get_service_handle_event = std::shared_ptr<Kernel::Event> get_service_handle_event =
ctx.SleepClientThread("GetServiceHandle", std::chrono::nanoseconds(-1), get_handle); ctx.SleepClientThread("GetServiceHandle", std::chrono::nanoseconds(-1), get_handle);
@ -168,27 +170,27 @@ void SRV::GetServiceHandle(Kernel::HLERequestContext& ctx) {
return; return;
} else { } else {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(client_port.Code()); rb.Push(result);
LOG_ERROR(Service_SRV, "called service={} -> error 0x{:08X}", name, LOG_ERROR(Service_SRV, "called service={} -> error 0x{:08X}", name, result.raw);
client_port.Code().raw);
return; return;
} }
} }
auto session = client_port.Unwrap()->Connect(); std::shared_ptr<Kernel::ClientSession> session;
if (session.Succeeded()) { result = client_port->Connect(session);
LOG_DEBUG(Service_SRV, "called service={} -> session={}", name, (*session)->GetObjectId()); if (result.IsSuccess()) {
LOG_DEBUG(Service_SRV, "called service={} -> session={}", name, session->GetObjectId());
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
rb.Push(session.Code()); rb.Push(result);
rb.PushMoveObjects(std::move(session).Unwrap()); rb.PushMoveObjects(std::move(session));
} else if (session.Code() == Kernel::ERR_MAX_CONNECTIONS_REACHED && wait_until_available) { } else if (result == Kernel::ERR_MAX_CONNECTIONS_REACHED && wait_until_available) {
LOG_WARNING(Service_SRV, "called service={} -> ERR_MAX_CONNECTIONS_REACHED", name); LOG_WARNING(Service_SRV, "called service={} -> ERR_MAX_CONNECTIONS_REACHED", name);
// TODO(Subv): Put the caller guest thread to sleep until this port becomes available again. // TODO(Subv): Put the caller guest thread to sleep until this port becomes available again.
UNIMPLEMENTED_MSG("Unimplemented wait until port {} is available.", name); UNIMPLEMENTED_MSG("Unimplemented wait until port {} is available.", name);
} else { } else {
LOG_ERROR(Service_SRV, "called service={} -> error 0x{:08X}", name, session.Code().raw); LOG_ERROR(Service_SRV, "called service={} -> error 0x{:08X}", name, result.raw);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(session.Code()); rb.Push(result);
} }
} }
@ -266,12 +268,13 @@ void SRV::RegisterService(Kernel::HLERequestContext& ctx) {
std::string name(name_buf.data(), std::min(name_len, name_buf.size())); std::string name(name_buf.data(), std::min(name_len, name_buf.size()));
auto port = system.ServiceManager().RegisterService(name, max_sessions); std::shared_ptr<Kernel::ServerPort> port;
auto result = system.ServiceManager().RegisterService(port, name, max_sessions);
if (port.Failed()) { if (result.IsError()) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(port.Code()); rb.Push(result);
LOG_ERROR(Service_SRV, "called service={} -> error 0x{:08X}", name, port.Code().raw); LOG_ERROR(Service_SRV, "called service={} -> error 0x{:08X}", name, result.raw);
return; return;
} }
@ -283,7 +286,7 @@ void SRV::RegisterService(Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.PushMoveObjects(port.Unwrap()); rb.PushMoveObjects(std::move(port));
} }
SRV::SRV(Core::System& system) : ServiceFramework("srv:", 64), system(system) { SRV::SRV(Core::System& system) : ServiceFramework("srv:", 64), system(system) {

View File

@ -59,7 +59,8 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
SECTION("translates move handles") { SECTION("translates move handles") {
auto a = MakeObject(kernel); auto a = MakeObject(kernel);
Handle a_handle = process->handle_table.Create(a).Unwrap(); Handle a_handle;
process->handle_table.Create(std::addressof(a_handle), a);
const u32_le input[]{ const u32_le input[]{
IPC::MakeHeader(0, 0, 2), IPC::MakeHeader(0, 0, 2),
IPC::MoveHandleDesc(1), IPC::MoveHandleDesc(1),
@ -75,7 +76,8 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
SECTION("translates copy handles") { SECTION("translates copy handles") {
auto a = MakeObject(kernel); auto a = MakeObject(kernel);
Handle a_handle = process->handle_table.Create(a).Unwrap(); Handle a_handle;
process->handle_table.Create(std::addressof(a_handle), a);
const u32_le input[]{ const u32_le input[]{
IPC::MakeHeader(0, 0, 2), IPC::MakeHeader(0, 0, 2),
IPC::CopyHandleDesc(1), IPC::CopyHandleDesc(1),
@ -93,13 +95,17 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
auto a = MakeObject(kernel); auto a = MakeObject(kernel);
auto b = MakeObject(kernel); auto b = MakeObject(kernel);
auto c = MakeObject(kernel); auto c = MakeObject(kernel);
Handle a_handle, b_handle, c_handle;
process->handle_table.Create(std::addressof(a_handle), a);
process->handle_table.Create(std::addressof(b_handle), b);
process->handle_table.Create(std::addressof(c_handle), c);
const u32_le input[]{ const u32_le input[]{
IPC::MakeHeader(0, 0, 5), IPC::MakeHeader(0, 0, 5),
IPC::MoveHandleDesc(2), IPC::MoveHandleDesc(2),
process->handle_table.Create(a).Unwrap(), a_handle,
process->handle_table.Create(b).Unwrap(), b_handle,
IPC::MoveHandleDesc(1), IPC::MoveHandleDesc(1),
process->handle_table.Create(c).Unwrap(), c_handle,
}; };
context.PopulateFromIncomingCommandBuffer(input, process); context.PopulateFromIncomingCommandBuffer(input, process);
@ -209,12 +215,14 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
REQUIRE(result.Code() == RESULT_SUCCESS); REQUIRE(result.Code() == RESULT_SUCCESS);
auto a = MakeObject(kernel); auto a = MakeObject(kernel);
Handle a_handle;
process->handle_table.Create(std::addressof(a_handle), a);
const u32_le input[]{ const u32_le input[]{
IPC::MakeHeader(0, 2, 8), IPC::MakeHeader(0, 2, 8),
0x12345678, 0x12345678,
0xABCDEF00, 0xABCDEF00,
IPC::MoveHandleDesc(1), IPC::MoveHandleDesc(1),
process->handle_table.Create(a).Unwrap(), a_handle,
IPC::CallingPidDesc(), IPC::CallingPidDesc(),
0, 0,
IPC::StaticBufferDesc(buffer_static.GetSize(), 0), IPC::StaticBufferDesc(buffer_static.GetSize(), 0),