kernel: Switch to atmosphere style macros
This commit is contained in:
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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));
|
||||||
|
@ -36,9 +36,10 @@ 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() {
|
||||||
signaled = true;
|
signaled = true;
|
||||||
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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,7 +249,7 @@ 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 ||
|
||||||
@ -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);
|
||||||
|
@ -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();
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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()) {
|
||||||
|
@ -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))
|
||||||
|
@ -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>(
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
|
||||||
|
out_port = it->second;
|
||||||
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
return it->second;
|
ResultCode ServiceManager::ConnectToService(std::shared_ptr<Kernel::ClientSession>& session,
|
||||||
}
|
|
||||||
|
|
||||||
ResultVal<std::shared_ptr<Kernel::ClientSession>> ServiceManager::ConnectToService(
|
|
||||||
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 {
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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),
|
||||||
|
Reference in New Issue
Block a user