summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt4
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp2
-rw-r--r--src/core/arm/unicorn/arm_unicorn.cpp2
-rw-r--r--src/core/file_sys/patch_manager.cpp16
-rw-r--r--src/core/file_sys/patch_manager.h6
-rw-r--r--src/core/file_sys/romfs_factory.cpp7
-rw-r--r--src/core/file_sys/romfs_factory.h2
-rw-r--r--src/core/file_sys/submission_package.cpp5
-rw-r--r--src/core/gdbstub/gdbstub.cpp44
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp20
-rw-r--r--src/core/hle/kernel/client_port.cpp4
-rw-r--r--src/core/hle/kernel/client_port.h2
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp14
-rw-r--r--src/core/hle/kernel/kernel.cpp36
-rw-r--r--src/core/hle/kernel/mutex.cpp34
-rw-r--r--src/core/hle/kernel/process.cpp6
-rw-r--r--src/core/hle/kernel/scheduler.cpp36
-rw-r--r--src/core/hle/kernel/server_port.h1
-rw-r--r--src/core/hle/kernel/server_session.cpp4
-rw-r--r--src/core/hle/kernel/svc.cpp121
-rw-r--r--src/core/hle/kernel/thread.cpp38
-rw-r--r--src/core/hle/kernel/thread.h218
-rw-r--r--src/core/hle/kernel/wait_object.cpp31
-rw-r--r--src/core/hle/service/aoc/aoc_u.cpp10
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp9
-rw-r--r--src/core/hle/service/filesystem/filesystem.h1
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp7
-rw-r--r--src/core/hle/service/sm/sm.h19
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp4
-rw-r--r--src/core/loader/loader.cpp3
-rw-r--r--src/core/loader/loader.h14
-rw-r--r--src/core/loader/nax.cpp4
-rw-r--r--src/core/loader/nax.h1
-rw-r--r--src/core/loader/nro.cpp15
-rw-r--r--src/core/loader/nso.cpp17
-rw-r--r--src/core/loader/nso.h11
-rw-r--r--src/core/loader/nsp.cpp32
-rw-r--r--src/core/loader/nsp.h4
-rw-r--r--src/core/loader/xci.cpp36
-rw-r--r--src/core/loader/xci.h4
-rw-r--r--src/core/settings.h7
-rw-r--r--src/core/telemetry_session.cpp52
-rw-r--r--src/core/telemetry_session.h5
43 files changed, 659 insertions, 249 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index a98dbb9ab..e4a676e91 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -396,6 +396,10 @@ create_target_directory_groups(core)
target_link_libraries(core PUBLIC common PRIVATE audio_core video_core)
target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt lz4_static mbedtls opus unicorn open_source_archives)
+if (ENABLE_WEB_SERVICE)
+ add_definitions(-DENABLE_WEB_SERVICE)
+ target_link_libraries(core PUBLIC json-headers web_service)
+endif()
if (ARCHITECTURE_x86_64)
target_sources(core PRIVATE
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index 05cc84458..7e978cf7a 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -86,7 +86,7 @@ public:
parent.jit->HaltExecution();
parent.SetPC(pc);
Kernel::Thread* thread = Kernel::GetCurrentThread();
- parent.SaveContext(thread->context);
+ parent.SaveContext(thread->GetContext());
GDBStub::Break();
GDBStub::SendTrap(thread, 5);
return;
diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp
index e218a0b15..ded4dd359 100644
--- a/src/core/arm/unicorn/arm_unicorn.cpp
+++ b/src/core/arm/unicorn/arm_unicorn.cpp
@@ -195,7 +195,7 @@ void ARM_Unicorn::ExecuteInstructions(int num_instructions) {
uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address);
}
Kernel::Thread* thread = Kernel::GetCurrentThread();
- SaveContext(thread->context);
+ SaveContext(thread->GetContext());
if (last_bkpt_hit || GDBStub::GetCpuStepFlag()) {
last_bkpt_hit = false;
GDBStub::Break();
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index ab2e5e43d..7b31a57a4 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -204,8 +204,8 @@ static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType t
romfs = std::move(packed);
}
-VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset,
- ContentRecordType type) const {
+VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, ContentRecordType type,
+ VirtualFile update_raw) const {
LOG_INFO(Loader, "Patching RomFS for title_id={:016X}, type={:02X}", title_id,
static_cast<u8>(type));
@@ -225,6 +225,13 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset,
FormatTitleVersion(installed->GetEntryVersion(update_tid).get_value_or(0)));
romfs = new_nca->GetRomFS();
}
+ } else if (update_raw != nullptr) {
+ const auto new_nca = std::make_shared<NCA>(update_raw, romfs, ivfc_offset);
+ if (new_nca->GetStatus() == Loader::ResultStatus::Success &&
+ new_nca->GetRomFS() != nullptr) {
+ LOG_INFO(Loader, " RomFS: Update (PACKED) applied successfully");
+ romfs = new_nca->GetRomFS();
+ }
}
// LayeredFS
@@ -244,7 +251,8 @@ static bool IsDirValidAndNonEmpty(const VirtualDir& dir) {
return dir != nullptr && (!dir->GetFiles().empty() || !dir->GetSubdirectories().empty());
}
-std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNames() const {
+std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNames(
+ VirtualFile update_raw) const {
std::map<std::string, std::string, std::less<>> out;
const auto installed = Service::FileSystem::GetUnionContents();
@@ -265,6 +273,8 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
"Update",
FormatTitleVersion(meta_ver.get(), TitleVersionFormat::ThreeElements));
}
+ } else if (update_raw != nullptr) {
+ out.insert_or_assign("Update", "PACKED");
}
}
diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h
index 66fdba148..eb6fc4607 100644
--- a/src/core/file_sys/patch_manager.h
+++ b/src/core/file_sys/patch_manager.h
@@ -47,11 +47,13 @@ public:
// - Game Updates
// - LayeredFS
VirtualFile PatchRomFS(VirtualFile base, u64 ivfc_offset,
- ContentRecordType type = ContentRecordType::Program) const;
+ ContentRecordType type = ContentRecordType::Program,
+ VirtualFile update_raw = nullptr) const;
// Returns a vector of pairs between patch names and patch versions.
// i.e. Update 3.2.2 will return {"Update", "3.2.2"}
- std::map<std::string, std::string, std::less<>> GetPatchVersionNames() const;
+ std::map<std::string, std::string, std::less<>> GetPatchVersionNames(
+ VirtualFile update_raw = nullptr) const;
// Given title_id of the program, attempts to get the control data of the update and parse it,
// falling back to the base control data.
diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp
index 4994c2532..0b645b106 100644
--- a/src/core/file_sys/romfs_factory.cpp
+++ b/src/core/file_sys/romfs_factory.cpp
@@ -30,12 +30,17 @@ RomFSFactory::RomFSFactory(Loader::AppLoader& app_loader) {
RomFSFactory::~RomFSFactory() = default;
+void RomFSFactory::SetPackedUpdate(VirtualFile update_raw) {
+ this->update_raw = std::move(update_raw);
+}
+
ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() {
if (!updatable)
return MakeResult<VirtualFile>(file);
const PatchManager patch_manager(Core::CurrentProcess()->GetTitleID());
- return MakeResult<VirtualFile>(patch_manager.PatchRomFS(file, ivfc_offset));
+ return MakeResult<VirtualFile>(
+ patch_manager.PatchRomFS(file, ivfc_offset, ContentRecordType::Program, update_raw));
}
ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, ContentRecordType type) {
diff --git a/src/core/file_sys/romfs_factory.h b/src/core/file_sys/romfs_factory.h
index 2cace8180..7724c0b23 100644
--- a/src/core/file_sys/romfs_factory.h
+++ b/src/core/file_sys/romfs_factory.h
@@ -32,11 +32,13 @@ public:
explicit RomFSFactory(Loader::AppLoader& app_loader);
~RomFSFactory();
+ void SetPackedUpdate(VirtualFile update_raw);
ResultVal<VirtualFile> OpenCurrentProcess();
ResultVal<VirtualFile> Open(u64 title_id, StorageId storage, ContentRecordType type);
private:
VirtualFile file;
+ VirtualFile update_raw;
bool updatable;
u64 ivfc_offset;
};
diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp
index 09bf077cd..ab5dc900c 100644
--- a/src/core/file_sys/submission_package.cpp
+++ b/src/core/file_sys/submission_package.cpp
@@ -259,8 +259,11 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
auto next_nca = std::make_shared<NCA>(next_file);
if (next_nca->GetType() == NCAContentType::Program)
program_status[cnmt.GetTitleID()] = next_nca->GetStatus();
- if (next_nca->GetStatus() == Loader::ResultStatus::Success)
+ if (next_nca->GetStatus() == Loader::ResultStatus::Success ||
+ (next_nca->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS &&
+ (cnmt.GetTitleID() & 0x800) != 0)) {
ncas_title[rec.type] = std::move(next_nca);
+ }
}
break;
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index 5bc947010..e961ef121 100644
--- a/src/core/gdbstub/gdbstub.cpp
+++ b/src/core/gdbstub/gdbstub.cpp
@@ -209,7 +209,7 @@ static Kernel::Thread* FindThreadById(int id) {
for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) {
const auto& threads = Core::System::GetInstance().Scheduler(core)->GetThreadList();
for (auto& thread : threads) {
- if (thread->GetThreadId() == static_cast<u32>(id)) {
+ if (thread->GetThreadID() == static_cast<u32>(id)) {
current_core = core;
return thread.get();
}
@@ -223,16 +223,18 @@ static u64 RegRead(std::size_t id, Kernel::Thread* thread = nullptr) {
return 0;
}
+ const auto& thread_context = thread->GetContext();
+
if (id < SP_REGISTER) {
- return thread->context.cpu_registers[id];
+ return thread_context.cpu_registers[id];
} else if (id == SP_REGISTER) {
- return thread->context.sp;
+ return thread_context.sp;
} else if (id == PC_REGISTER) {
- return thread->context.pc;
+ return thread_context.pc;
} else if (id == PSTATE_REGISTER) {
- return thread->context.pstate;
+ return thread_context.pstate;
} else if (id > PSTATE_REGISTER && id < FPCR_REGISTER) {
- return thread->context.vector_registers[id - UC_ARM64_REG_Q0][0];
+ return thread_context.vector_registers[id - UC_ARM64_REG_Q0][0];
} else {
return 0;
}
@@ -243,16 +245,18 @@ static void RegWrite(std::size_t id, u64 val, Kernel::Thread* thread = nullptr)
return;
}
+ auto& thread_context = thread->GetContext();
+
if (id < SP_REGISTER) {
- thread->context.cpu_registers[id] = val;
+ thread_context.cpu_registers[id] = val;
} else if (id == SP_REGISTER) {
- thread->context.sp = val;
+ thread_context.sp = val;
} else if (id == PC_REGISTER) {
- thread->context.pc = val;
+ thread_context.pc = val;
} else if (id == PSTATE_REGISTER) {
- thread->context.pstate = static_cast<u32>(val);
+ thread_context.pstate = static_cast<u32>(val);
} else if (id > PSTATE_REGISTER && id < FPCR_REGISTER) {
- thread->context.vector_registers[id - (PSTATE_REGISTER + 1)][0] = val;
+ thread_context.vector_registers[id - (PSTATE_REGISTER + 1)][0] = val;
}
}
@@ -595,7 +599,7 @@ static void HandleQuery() {
for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) {
const auto& threads = Core::System::GetInstance().Scheduler(core)->GetThreadList();
for (const auto& thread : threads) {
- val += fmt::format("{:x}", thread->GetThreadId());
+ val += fmt::format("{:x}", thread->GetThreadID());
val += ",";
}
}
@@ -612,7 +616,7 @@ static void HandleQuery() {
for (const auto& thread : threads) {
buffer +=
fmt::format(R"*(<thread id="{:x}" core="{:d}" name="Thread {:x}"></thread>)*",
- thread->GetThreadId(), core, thread->GetThreadId());
+ thread->GetThreadID(), core, thread->GetThreadID());
}
}
buffer += "</threads>";
@@ -693,7 +697,7 @@ static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) {
}
if (thread) {
- buffer += fmt::format(";thread:{:x};", thread->GetThreadId());
+ buffer += fmt::format(";thread:{:x};", thread->GetThreadID());
}
SendReply(buffer.c_str());
@@ -857,7 +861,9 @@ static void WriteRegister() {
}
// Update Unicorn context skipping scheduler, no running threads at this point
- Core::System::GetInstance().ArmInterface(current_core).LoadContext(current_thread->context);
+ Core::System::GetInstance()
+ .ArmInterface(current_core)
+ .LoadContext(current_thread->GetContext());
SendReply("OK");
}
@@ -886,7 +892,9 @@ static void WriteRegisters() {
}
// Update Unicorn context skipping scheduler, no running threads at this point
- Core::System::GetInstance().ArmInterface(current_core).LoadContext(current_thread->context);
+ Core::System::GetInstance()
+ .ArmInterface(current_core)
+ .LoadContext(current_thread->GetContext());
SendReply("OK");
}
@@ -960,7 +968,9 @@ static void Step() {
if (command_length > 1) {
RegWrite(PC_REGISTER, GdbHexToLong(command_buffer + 1), current_thread);
// Update Unicorn context skipping scheduler, no running threads at this point
- Core::System::GetInstance().ArmInterface(current_core).LoadContext(current_thread->context);
+ Core::System::GetInstance()
+ .ArmInterface(current_core)
+ .LoadContext(current_thread->GetContext());
}
step_loop = true;
halt_loop = true;
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index 93577591f..ebf193930 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -23,13 +23,13 @@ namespace AddressArbiter {
// Performs actual address waiting logic.
static ResultCode WaitForAddress(VAddr address, s64 timeout) {
SharedPtr<Thread> current_thread = GetCurrentThread();
- current_thread->arb_wait_address = address;
- current_thread->status = ThreadStatus::WaitArb;
- current_thread->wakeup_callback = nullptr;
+ current_thread->SetArbiterWaitAddress(address);
+ current_thread->SetStatus(ThreadStatus::WaitArb);
+ current_thread->InvalidateWakeupCallback();
current_thread->WakeAfterDelay(timeout);
- Core::System::GetInstance().CpuCore(current_thread->processor_id).PrepareReschedule();
+ Core::System::GetInstance().CpuCore(current_thread->GetProcessorID()).PrepareReschedule();
return RESULT_TIMEOUT;
}
@@ -39,10 +39,10 @@ static std::vector<SharedPtr<Thread>> GetThreadsWaitingOnAddress(VAddr address)
std::vector<SharedPtr<Thread>>& waiting_threads,
VAddr arb_addr) {
const auto& scheduler = Core::System::GetInstance().Scheduler(core_index);
- auto& thread_list = scheduler->GetThreadList();
+ const auto& thread_list = scheduler->GetThreadList();
- for (auto& thread : thread_list) {
- if (thread->arb_wait_address == arb_addr)
+ for (const auto& thread : thread_list) {
+ if (thread->GetArbiterWaitAddress() == arb_addr)
waiting_threads.push_back(thread);
}
};
@@ -57,7 +57,7 @@ static std::vector<SharedPtr<Thread>> GetThreadsWaitingOnAddress(VAddr address)
// Sort them by priority, such that the highest priority ones come first.
std::sort(threads.begin(), threads.end(),
[](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) {
- return lhs->current_priority < rhs->current_priority;
+ return lhs->GetPriority() < rhs->GetPriority();
});
return threads;
@@ -73,9 +73,9 @@ static void WakeThreads(std::vector<SharedPtr<Thread>>& waiting_threads, s32 num
// Signal the waiting threads.
for (std::size_t i = 0; i < last; i++) {
- ASSERT(waiting_threads[i]->status == ThreadStatus::WaitArb);
+ ASSERT(waiting_threads[i]->GetStatus() == ThreadStatus::WaitArb);
waiting_threads[i]->SetWaitSynchronizationResult(RESULT_SUCCESS);
- waiting_threads[i]->arb_wait_address = 0;
+ waiting_threads[i]->SetArbiterWaitAddress(0);
waiting_threads[i]->ResumeFromWait();
}
}
diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp
index 873d6c516..d4c91d529 100644
--- a/src/core/hle/kernel/client_port.cpp
+++ b/src/core/hle/kernel/client_port.cpp
@@ -17,6 +17,10 @@ namespace Kernel {
ClientPort::ClientPort(KernelCore& kernel) : Object{kernel} {}
ClientPort::~ClientPort() = default;
+SharedPtr<ServerPort> ClientPort::GetServerPort() const {
+ return server_port;
+}
+
ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() {
// Note: Threads do not wait for the server endpoint to call
// AcceptSession before returning from this call.
diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h
index f3dfebbb1..6cd607206 100644
--- a/src/core/hle/kernel/client_port.h
+++ b/src/core/hle/kernel/client_port.h
@@ -30,6 +30,8 @@ public:
return HANDLE_TYPE;
}
+ SharedPtr<ServerPort> GetServerPort() const;
+
/**
* Creates a new Session pair, adds the created ServerSession to the associated ServerPort's
* list of pending sessions, and signals the ServerPort, causing any threads
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 72fb9d250..edad5f1b1 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -42,14 +42,14 @@ SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread,
Kernel::SharedPtr<Kernel::Event> event) {
// Put the client thread to sleep until the wait event is signaled or the timeout expires.
- thread->wakeup_callback = [context = *this, callback](
+ thread->SetWakeupCallback([context = *this, callback](
ThreadWakeupReason reason, SharedPtr<Thread> thread,
SharedPtr<WaitObject> object, std::size_t index) mutable -> bool {
- ASSERT(thread->status == ThreadStatus::WaitHLEEvent);
+ ASSERT(thread->GetStatus() == ThreadStatus::WaitHLEEvent);
callback(thread, context, reason);
context.WriteToOutgoingCommandBuffer(*thread);
return true;
- };
+ });
if (!event) {
// Create event if not provided
@@ -59,8 +59,8 @@ SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread,
}
event->Clear();
- thread->status = ThreadStatus::WaitHLEEvent;
- thread->wait_objects = {event};
+ thread->SetStatus(ThreadStatus::WaitHLEEvent);
+ thread->SetWaitObjects({event});
event->AddWaitingThread(thread);
if (timeout > 0) {
@@ -209,7 +209,7 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(u32_le* src_cmdb
ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(const Thread& thread) {
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> dst_cmdbuf;
- Memory::ReadBlock(*thread.owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(),
+ Memory::ReadBlock(*thread.GetOwnerProcess(), thread.GetTLSAddress(), dst_cmdbuf.data(),
dst_cmdbuf.size() * sizeof(u32));
// The header was already built in the internal command buffer. Attempt to parse it to verify
@@ -268,7 +268,7 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(const Thread& thread)
}
// Copy the translated command buffer back into the thread's command buffer area.
- Memory::WriteBlock(*thread.owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(),
+ Memory::WriteBlock(*thread.GetOwnerProcess(), thread.GetTLSAddress(), dst_cmdbuf.data(),
dst_cmdbuf.size() * sizeof(u32));
return RESULT_SUCCESS;
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 3e0800a71..98eb74298 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -46,40 +46,40 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] int cycles_
bool resume = true;
- if (thread->status == ThreadStatus::WaitSynchAny ||
- thread->status == ThreadStatus::WaitSynchAll ||
- thread->status == ThreadStatus::WaitHLEEvent) {
+ if (thread->GetStatus() == ThreadStatus::WaitSynchAny ||
+ thread->GetStatus() == ThreadStatus::WaitSynchAll ||
+ thread->GetStatus() == ThreadStatus::WaitHLEEvent) {
// Remove the thread from each of its waiting objects' waitlists
- for (auto& object : thread->wait_objects) {
+ for (const auto& object : thread->GetWaitObjects()) {
object->RemoveWaitingThread(thread.get());
}
- thread->wait_objects.clear();
+ thread->ClearWaitObjects();
// Invoke the wakeup callback before clearing the wait objects
- if (thread->wakeup_callback) {
- resume = thread->wakeup_callback(ThreadWakeupReason::Timeout, thread, nullptr, 0);
+ if (thread->HasWakeupCallback()) {
+ resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Timeout, thread, nullptr, 0);
}
}
- if (thread->mutex_wait_address != 0 || thread->condvar_wait_address != 0 ||
- thread->wait_handle) {
- ASSERT(thread->status == ThreadStatus::WaitMutex);
- thread->mutex_wait_address = 0;
- thread->condvar_wait_address = 0;
- thread->wait_handle = 0;
+ if (thread->GetMutexWaitAddress() != 0 || thread->GetCondVarWaitAddress() != 0 ||
+ thread->GetWaitHandle() != 0) {
+ ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex);
+ thread->SetMutexWaitAddress(0);
+ thread->SetCondVarWaitAddress(0);
+ thread->SetWaitHandle(0);
- auto lock_owner = thread->lock_owner;
+ auto* const lock_owner = thread->GetLockOwner();
// Threads waking up by timeout from WaitProcessWideKey do not perform priority inheritance
// and don't have a lock owner unless SignalProcessWideKey was called first and the thread
// wasn't awakened due to the mutex already being acquired.
- if (lock_owner) {
+ if (lock_owner != nullptr) {
lock_owner->RemoveMutexWaiter(thread);
}
}
- if (thread->arb_wait_address != 0) {
- ASSERT(thread->status == ThreadStatus::WaitArb);
- thread->arb_wait_address = 0;
+ if (thread->GetArbiterWaitAddress() != 0) {
+ ASSERT(thread->GetStatus() == ThreadStatus::WaitArb);
+ thread->SetArbiterWaitAddress(0);
}
if (resume) {
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 81675eac5..dd541ffcc 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -28,11 +28,11 @@ static std::pair<SharedPtr<Thread>, u32> GetHighestPriorityMutexWaitingThread(
SharedPtr<Thread> highest_priority_thread;
u32 num_waiters = 0;
- for (auto& thread : current_thread->wait_mutex_threads) {
- if (thread->mutex_wait_address != mutex_addr)
+ for (const auto& thread : current_thread->GetMutexWaitingThreads()) {
+ if (thread->GetMutexWaitAddress() != mutex_addr)
continue;
- ASSERT(thread->status == ThreadStatus::WaitMutex);
+ ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex);
++num_waiters;
if (highest_priority_thread == nullptr ||
@@ -47,12 +47,12 @@ static std::pair<SharedPtr<Thread>, u32> GetHighestPriorityMutexWaitingThread(
/// Update the mutex owner field of all threads waiting on the mutex to point to the new owner.
static void TransferMutexOwnership(VAddr mutex_addr, SharedPtr<Thread> current_thread,
SharedPtr<Thread> new_owner) {
- auto threads = current_thread->wait_mutex_threads;
- for (auto& thread : threads) {
- if (thread->mutex_wait_address != mutex_addr)
+ const auto threads = current_thread->GetMutexWaitingThreads();
+ for (const auto& thread : threads) {
+ if (thread->GetMutexWaitAddress() != mutex_addr)
continue;
- ASSERT(thread->lock_owner == current_thread);
+ ASSERT(thread->GetLockOwner() == current_thread);
current_thread->RemoveMutexWaiter(thread);
if (new_owner != thread)
new_owner->AddMutexWaiter(thread);
@@ -84,11 +84,11 @@ ResultCode Mutex::TryAcquire(HandleTable& handle_table, VAddr address, Handle ho
return ERR_INVALID_HANDLE;
// Wait until the mutex is released
- GetCurrentThread()->mutex_wait_address = address;
- GetCurrentThread()->wait_handle = requesting_thread_handle;
+ GetCurrentThread()->SetMutexWaitAddress(address);
+ GetCurrentThread()->SetWaitHandle(requesting_thread_handle);
- GetCurrentThread()->status = ThreadStatus::WaitMutex;
- GetCurrentThread()->wakeup_callback = nullptr;
+ GetCurrentThread()->SetStatus(ThreadStatus::WaitMutex);
+ GetCurrentThread()->InvalidateWakeupCallback();
// Update the lock holder thread's priority to prevent priority inversion.
holding_thread->AddMutexWaiter(GetCurrentThread());
@@ -115,7 +115,7 @@ ResultCode Mutex::Release(VAddr address) {
// Transfer the ownership of the mutex from the previous owner to the new one.
TransferMutexOwnership(address, GetCurrentThread(), thread);
- u32 mutex_value = thread->wait_handle;
+ u32 mutex_value = thread->GetWaitHandle();
if (num_waiters >= 2) {
// Notify the guest that there are still some threads waiting for the mutex
@@ -125,13 +125,13 @@ ResultCode Mutex::Release(VAddr address) {
// Grant the mutex to the next waiting thread and resume it.
Memory::Write32(address, mutex_value);
- ASSERT(thread->status == ThreadStatus::WaitMutex);
+ ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex);
thread->ResumeFromWait();
- thread->lock_owner = nullptr;
- thread->condvar_wait_address = 0;
- thread->mutex_wait_address = 0;
- thread->wait_handle = 0;
+ thread->SetLockOwner(nullptr);
+ thread->SetCondVarWaitAddress(0);
+ thread->SetMutexWaitAddress(0);
+ thread->SetWaitHandle(0);
return RESULT_SUCCESS;
}
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index dc9fc8470..fb0027a71 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -144,15 +144,15 @@ void Process::PrepareForTermination() {
const auto stop_threads = [this](const std::vector<SharedPtr<Thread>>& thread_list) {
for (auto& thread : thread_list) {
- if (thread->owner_process != this)
+ if (thread->GetOwnerProcess() != this)
continue;
if (thread == GetCurrentThread())
continue;
// TODO(Subv): When are the other running/ready threads terminated?
- ASSERT_MSG(thread->status == ThreadStatus::WaitSynchAny ||
- thread->status == ThreadStatus::WaitSynchAll,
+ ASSERT_MSG(thread->GetStatus() == ThreadStatus::WaitSynchAny ||
+ thread->GetStatus() == ThreadStatus::WaitSynchAll,
"Exiting processes with non-waiting threads is currently unimplemented");
thread->Stop();
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index 1e82cfffb..cfd6e1bad 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -38,10 +38,10 @@ Thread* Scheduler::PopNextReadyThread() {
Thread* next = nullptr;
Thread* thread = GetCurrentThread();
- if (thread && thread->status == ThreadStatus::Running) {
+ if (thread && thread->GetStatus() == ThreadStatus::Running) {
// We have to do better than the current thread.
// This call returns null when that's not possible.
- next = ready_queue.pop_first_better(thread->current_priority);
+ next = ready_queue.pop_first_better(thread->GetPriority());
if (!next) {
// Otherwise just keep going with the current thread
next = thread;
@@ -58,22 +58,21 @@ void Scheduler::SwitchContext(Thread* new_thread) {
// Save context for previous thread
if (previous_thread) {
- previous_thread->last_running_ticks = CoreTiming::GetTicks();
- cpu_core.SaveContext(previous_thread->context);
+ cpu_core.SaveContext(previous_thread->GetContext());
// Save the TPIDR_EL0 system register in case it was modified.
- previous_thread->tpidr_el0 = cpu_core.GetTPIDR_EL0();
+ previous_thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0());
- if (previous_thread->status == ThreadStatus::Running) {
+ if (previous_thread->GetStatus() == ThreadStatus::Running) {
// This is only the case when a reschedule is triggered without the current thread
// yielding execution (i.e. an event triggered, system core time-sliced, etc)
- ready_queue.push_front(previous_thread->current_priority, previous_thread);
- previous_thread->status = ThreadStatus::Ready;
+ ready_queue.push_front(previous_thread->GetPriority(), previous_thread);
+ previous_thread->SetStatus(ThreadStatus::Ready);
}
}
// Load context of new thread
if (new_thread) {
- ASSERT_MSG(new_thread->status == ThreadStatus::Ready,
+ ASSERT_MSG(new_thread->GetStatus() == ThreadStatus::Ready,
"Thread must be ready to become running.");
// Cancel any outstanding wakeup events for this thread
@@ -83,15 +82,16 @@ void Scheduler::SwitchContext(Thread* new_thread) {
current_thread = new_thread;
- ready_queue.remove(new_thread->current_priority, new_thread);
- new_thread->status = ThreadStatus::Running;
+ ready_queue.remove(new_thread->GetPriority(), new_thread);
+ new_thread->SetStatus(ThreadStatus::Running);
- if (previous_process != current_thread->owner_process) {
- Core::CurrentProcess() = current_thread->owner_process;
+ const auto thread_owner_process = current_thread->GetOwnerProcess();
+ if (previous_process != thread_owner_process) {
+ Core::CurrentProcess() = thread_owner_process;
SetCurrentPageTable(&Core::CurrentProcess()->VMManager().page_table);
}
- cpu_core.LoadContext(new_thread->context);
+ cpu_core.LoadContext(new_thread->GetContext());
cpu_core.SetTlsAddress(new_thread->GetTLSAddress());
cpu_core.SetTPIDR_EL0(new_thread->GetTPIDR_EL0());
cpu_core.ClearExclusiveState();
@@ -136,14 +136,14 @@ void Scheduler::RemoveThread(Thread* thread) {
void Scheduler::ScheduleThread(Thread* thread, u32 priority) {
std::lock_guard<std::mutex> lock(scheduler_mutex);
- ASSERT(thread->status == ThreadStatus::Ready);
+ ASSERT(thread->GetStatus() == ThreadStatus::Ready);
ready_queue.push_back(priority, thread);
}
void Scheduler::UnscheduleThread(Thread* thread, u32 priority) {
std::lock_guard<std::mutex> lock(scheduler_mutex);
- ASSERT(thread->status == ThreadStatus::Ready);
+ ASSERT(thread->GetStatus() == ThreadStatus::Ready);
ready_queue.remove(priority, thread);
}
@@ -151,8 +151,8 @@ void Scheduler::SetThreadPriority(Thread* thread, u32 priority) {
std::lock_guard<std::mutex> lock(scheduler_mutex);
// If thread was ready, adjust queues
- if (thread->status == ThreadStatus::Ready)
- ready_queue.move(thread, thread->current_priority, priority);
+ if (thread->GetStatus() == ThreadStatus::Ready)
+ ready_queue.move(thread, thread->GetPriority(), priority);
else
ready_queue.prepare(priority);
}
diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h
index 62fb51349..e52f8245f 100644
--- a/src/core/hle/kernel/server_port.h
+++ b/src/core/hle/kernel/server_port.h
@@ -11,6 +11,7 @@
#include "common/common_types.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/wait_object.h"
+#include "core/hle/result.h"
namespace Kernel {
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index aba0cab96..1ece691c7 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -120,10 +120,10 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
result = hle_handler->HandleSyncRequest(context);
}
- if (thread->status == ThreadStatus::Running) {
+ if (thread->GetStatus() == ThreadStatus::Running) {
// Put the thread to sleep until the server replies, it will be awoken in
// svcReplyAndReceive for LLE servers.
- thread->status = ThreadStatus::WaitIPC;
+ thread->SetStatus(ThreadStatus::WaitIPC);
if (hle_handler != nullptr) {
// For HLE services, we put the request threads to sleep for a short duration to
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 1cdaa740a..6c4af7e47 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -156,7 +156,7 @@ static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) {
return ERR_INVALID_HANDLE;
}
- *thread_id = thread->GetThreadId();
+ *thread_id = thread->GetThreadID();
return RESULT_SUCCESS;
}
@@ -177,7 +177,7 @@ static ResultCode GetProcessId(u32* process_id, Handle process_handle) {
/// Default thread wakeup callback for WaitSynchronization
static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thread> thread,
SharedPtr<WaitObject> object, std::size_t index) {
- ASSERT(thread->status == ThreadStatus::WaitSynchAny);
+ ASSERT(thread->GetStatus() == ThreadStatus::WaitSynchAny);
if (reason == ThreadWakeupReason::Timeout) {
thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
@@ -204,10 +204,10 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64
if (handle_count > MaxHandles)
return ResultCode(ErrorModule::Kernel, ErrCodes::TooLarge);
- auto thread = GetCurrentThread();
+ auto* const thread = GetCurrentThread();
- using ObjectPtr = SharedPtr<WaitObject>;
- std::vector<ObjectPtr> objects(handle_count);
+ using ObjectPtr = Thread::ThreadWaitObjects::value_type;
+ Thread::ThreadWaitObjects objects(handle_count);
auto& kernel = Core::System::GetInstance().Kernel();
for (u64 i = 0; i < handle_count; ++i) {
@@ -244,14 +244,14 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64
for (auto& object : objects)
object->AddWaitingThread(thread);
- thread->wait_objects = std::move(objects);
- thread->status = ThreadStatus::WaitSynchAny;
+ thread->SetWaitObjects(std::move(objects));
+ thread->SetStatus(ThreadStatus::WaitSynchAny);
// Create an event to wake the thread up after the specified nanosecond delay has passed
thread->WakeAfterDelay(nano_seconds);
- thread->wakeup_callback = DefaultThreadWakeupCallback;
+ thread->SetWakeupCallback(DefaultThreadWakeupCallback);
- Core::System::GetInstance().CpuCore(thread->processor_id).PrepareReschedule();
+ Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule();
return RESULT_TIMEOUT;
}
@@ -266,7 +266,7 @@ static ResultCode CancelSynchronization(Handle thread_handle) {
return ERR_INVALID_HANDLE;
}
- ASSERT(thread->status == ThreadStatus::WaitSynchAny);
+ ASSERT(thread->GetStatus() == ThreadStatus::WaitSynchAny);
thread->SetWaitSynchronizationResult(
ResultCode(ErrorModule::Kernel, ErrCodes::SynchronizationCanceled));
thread->ResumeFromWait();
@@ -425,7 +425,7 @@ static ResultCode GetThreadContext(VAddr thread_context, Handle handle) {
}
const auto current_process = Core::CurrentProcess();
- if (thread->owner_process != current_process) {
+ if (thread->GetOwnerProcess() != current_process) {
return ERR_INVALID_HANDLE;
}
@@ -433,7 +433,7 @@ static ResultCode GetThreadContext(VAddr thread_context, Handle handle) {
return ERR_ALREADY_REGISTERED;
}
- Core::ARM_Interface::ThreadContext ctx = thread->context;
+ Core::ARM_Interface::ThreadContext ctx = thread->GetContext();
// Mask away mode bits, interrupt bits, IL bit, and other reserved bits.
ctx.pstate &= 0xFF0FFE20;
@@ -479,14 +479,14 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) {
thread->SetPriority(priority);
- Core::System::GetInstance().CpuCore(thread->processor_id).PrepareReschedule();
+ Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule();
return RESULT_SUCCESS;
}
/// Get which CPU core is executing the current thread
static u32 GetCurrentProcessorNumber() {
LOG_TRACE(Kernel_SVC, "called");
- return GetCurrentThread()->processor_id;
+ return GetCurrentThread()->GetProcessorID();
}
static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size,
@@ -622,10 +622,14 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
CASCADE_RESULT(SharedPtr<Thread> thread,
Thread::Create(kernel, name, entry_point, priority, arg, processor_id, stack_top,
Core::CurrentProcess()));
- CASCADE_RESULT(thread->guest_handle, kernel.HandleTable().Create(thread));
- *out_handle = thread->guest_handle;
+ const auto new_guest_handle = kernel.HandleTable().Create(thread);
+ if (new_guest_handle.Failed()) {
+ return new_guest_handle.Code();
+ }
+ thread->SetGuestHandle(*new_guest_handle);
+ *out_handle = *new_guest_handle;
- Core::System::GetInstance().CpuCore(thread->processor_id).PrepareReschedule();
+ Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule();
LOG_TRACE(Kernel_SVC,
"called entrypoint=0x{:08X} ({}), arg=0x{:08X}, stacktop=0x{:08X}, "
@@ -645,10 +649,10 @@ static ResultCode StartThread(Handle thread_handle) {
return ERR_INVALID_HANDLE;
}
- ASSERT(thread->status == ThreadStatus::Dormant);
+ ASSERT(thread->GetStatus() == ThreadStatus::Dormant);
thread->ResumeFromWait();
- Core::System::GetInstance().CpuCore(thread->processor_id).PrepareReschedule();
+ Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule();
return RESULT_SUCCESS;
}
@@ -694,17 +698,17 @@ static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_var
CASCADE_CODE(Mutex::Release(mutex_addr));
SharedPtr<Thread> current_thread = GetCurrentThread();
- current_thread->condvar_wait_address = condition_variable_addr;
- current_thread->mutex_wait_address = mutex_addr;
- current_thread->wait_handle = thread_handle;
- current_thread->status = ThreadStatus::WaitMutex;
- current_thread->wakeup_callback = nullptr;
+ current_thread->SetCondVarWaitAddress(condition_variable_addr);
+ current_thread->SetMutexWaitAddress(mutex_addr);
+ current_thread->SetWaitHandle(thread_handle);
+ current_thread->SetStatus(ThreadStatus::WaitMutex);
+ current_thread->InvalidateWakeupCallback();
current_thread->WakeAfterDelay(nano_seconds);
// Note: Deliberately don't attempt to inherit the lock owner's priority.
- Core::System::GetInstance().CpuCore(current_thread->processor_id).PrepareReschedule();
+ Core::System::GetInstance().CpuCore(current_thread->GetProcessorID()).PrepareReschedule();
return RESULT_SUCCESS;
}
@@ -713,14 +717,14 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
LOG_TRACE(Kernel_SVC, "called, condition_variable_addr=0x{:X}, target=0x{:08X}",
condition_variable_addr, target);
- auto RetrieveWaitingThreads = [](std::size_t core_index,
- std::vector<SharedPtr<Thread>>& waiting_threads,
- VAddr condvar_addr) {
+ const auto RetrieveWaitingThreads = [](std::size_t core_index,
+ std::vector<SharedPtr<Thread>>& waiting_threads,
+ VAddr condvar_addr) {
const auto& scheduler = Core::System::GetInstance().Scheduler(core_index);
- auto& thread_list = scheduler->GetThreadList();
+ const auto& thread_list = scheduler->GetThreadList();
- for (auto& thread : thread_list) {
- if (thread->condvar_wait_address == condvar_addr)
+ for (const auto& thread : thread_list) {
+ if (thread->GetCondVarWaitAddress() == condvar_addr)
waiting_threads.push_back(thread);
}
};
@@ -734,7 +738,7 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
// Sort them by priority, such that the highest priority ones come first.
std::sort(waiting_threads.begin(), waiting_threads.end(),
[](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) {
- return lhs->current_priority < rhs->current_priority;
+ return lhs->GetPriority() < rhs->GetPriority();
});
// Only process up to 'target' threads, unless 'target' is -1, in which case process
@@ -750,7 +754,7 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
for (std::size_t index = 0; index < last; ++index) {
auto& thread = waiting_threads[index];
- ASSERT(thread->condvar_wait_address == condition_variable_addr);
+ ASSERT(thread->GetCondVarWaitAddress() == condition_variable_addr);
std::size_t current_core = Core::System::GetInstance().CurrentCoreIndex();
@@ -759,42 +763,43 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
// Atomically read the value of the mutex.
u32 mutex_val = 0;
do {
- monitor.SetExclusive(current_core, thread->mutex_wait_address);
+ monitor.SetExclusive(current_core, thread->GetMutexWaitAddress());
// If the mutex is not yet acquired, acquire it.
- mutex_val = Memory::Read32(thread->mutex_wait_address);
+ mutex_val = Memory::Read32(thread->GetMutexWaitAddress());
if (mutex_val != 0) {
monitor.ClearExclusive();
break;
}
- } while (!monitor.ExclusiveWrite32(current_core, thread->mutex_wait_address,
- thread->wait_handle));
+ } while (!monitor.ExclusiveWrite32(current_core, thread->GetMutexWaitAddress(),
+ thread->GetWaitHandle()));
if (mutex_val == 0) {
// We were able to acquire the mutex, resume this thread.
- ASSERT(thread->status == ThreadStatus::WaitMutex);
+ ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex);
thread->ResumeFromWait();
- auto lock_owner = thread->lock_owner;
- if (lock_owner)
+ auto* const lock_owner = thread->GetLockOwner();
+ if (lock_owner != nullptr) {
lock_owner->RemoveMutexWaiter(thread);
+ }
- thread->lock_owner = nullptr;
- thread->mutex_wait_address = 0;
- thread->condvar_wait_address = 0;
- thread->wait_handle = 0;
+ thread->SetLockOwner(nullptr);
+ thread->SetMutexWaitAddress(0);
+ thread->SetCondVarWaitAddress(0);
+ thread->SetWaitHandle(0);
} else {
// Atomically signal that the mutex now has a waiting thread.
do {
- monitor.SetExclusive(current_core, thread->mutex_wait_address);
+ monitor.SetExclusive(current_core, thread->GetMutexWaitAddress());
// Ensure that the mutex value is still what we expect.
- u32 value = Memory::Read32(thread->mutex_wait_address);
+ u32 value = Memory::Read32(thread->GetMutexWaitAddress());
// TODO(Subv): When this happens, the kernel just clears the exclusive state and
// retries the initial read for this thread.
ASSERT_MSG(mutex_val == value, "Unhandled synchronization primitive case");
- } while (!monitor.ExclusiveWrite32(current_core, thread->mutex_wait_address,
+ } while (!monitor.ExclusiveWrite32(current_core, thread->GetMutexWaitAddress(),
mutex_val | Mutex::MutexHasWaitersFlag));
// The mutex is already owned by some other thread, make this thread wait on it.
@@ -802,12 +807,12 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask);
auto owner = kernel.HandleTable().Get<Thread>(owner_handle);
ASSERT(owner);
- ASSERT(thread->status == ThreadStatus::WaitMutex);
- thread->wakeup_callback = nullptr;
+ ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex);
+ thread->InvalidateWakeupCallback();
owner->AddMutexWaiter(thread);
- Core::System::GetInstance().CpuCore(thread->processor_id).PrepareReschedule();
+ Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule();
}
}
@@ -913,8 +918,8 @@ static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask)
return ERR_INVALID_HANDLE;
}
- *core = thread->ideal_core;
- *mask = thread->affinity_mask;
+ *core = thread->GetIdealCore();
+ *mask = thread->GetAffinityMask();
return RESULT_SUCCESS;
}
@@ -930,11 +935,13 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
}
if (core == static_cast<u32>(THREADPROCESSORID_DEFAULT)) {
- ASSERT(thread->owner_process->GetDefaultProcessorID() !=
- static_cast<u8>(THREADPROCESSORID_DEFAULT));
+ const u8 default_processor_id = thread->GetOwnerProcess()->GetDefaultProcessorID();
+
+ ASSERT(default_processor_id != static_cast<u8>(THREADPROCESSORID_DEFAULT));
+
// Set the target CPU to the one specified in the process' exheader.
- core = thread->owner_process->GetDefaultProcessorID();
- mask = 1ull << core;
+ core = default_processor_id;
+ mask = 1ULL << core;
}
if (mask == 0) {
@@ -945,7 +952,7 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
static constexpr u32 OnlyChangeMask = static_cast<u32>(-3);
if (core == OnlyChangeMask) {
- core = thread->ideal_core;
+ core = thread->GetIdealCore();
} else if (core >= Core::NUM_CPU_CORES && core != static_cast<u32>(-1)) {
return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidProcessorId);
}
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index b5c16cfbb..8e514cf9a 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -70,7 +70,7 @@ void Thread::Stop() {
void WaitCurrentThread_Sleep() {
Thread* thread = GetCurrentThread();
- thread->status = ThreadStatus::WaitSleep;
+ thread->SetStatus(ThreadStatus::WaitSleep);
}
void ExitCurrentThread() {
@@ -169,7 +169,7 @@ void Thread::ResumeFromWait() {
next_scheduler->ScheduleThread(this, current_priority);
// Change thread's scheduler
- scheduler = next_scheduler;
+ scheduler = next_scheduler.get();
Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule();
}
@@ -233,7 +233,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name
thread->name = std::move(name);
thread->callback_handle = kernel.ThreadWakeupCallbackHandleTable().Create(thread).Unwrap();
thread->owner_process = owner_process;
- thread->scheduler = Core::System::GetInstance().Scheduler(processor_id);
+ thread->scheduler = Core::System::GetInstance().Scheduler(processor_id).get();
thread->scheduler->AddThread(thread, priority);
thread->tls_address = thread->owner_process->MarkNextAvailableTLSSlotAsUsed(*thread);
@@ -269,9 +269,9 @@ SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 pri
SharedPtr<Thread> thread = std::move(thread_res).Unwrap();
// Register 1 must be a handle to the main thread
- thread->guest_handle = kernel.HandleTable().Create(thread).Unwrap();
-
- thread->context.cpu_registers[1] = thread->guest_handle;
+ const Handle guest_handle = kernel.HandleTable().Create(thread).Unwrap();
+ thread->SetGuestHandle(guest_handle);
+ thread->GetContext().cpu_registers[1] = guest_handle;
// Threads by default are dormant, wake up the main thread so it runs when the scheduler fires
thread->ResumeFromWait();
@@ -299,6 +299,18 @@ VAddr Thread::GetCommandBufferAddress() const {
return GetTLSAddress() + CommandHeaderOffset;
}
+void Thread::SetStatus(ThreadStatus new_status) {
+ if (new_status == status) {
+ return;
+ }
+
+ if (status == ThreadStatus::Running) {
+ last_running_ticks = CoreTiming::GetTicks();
+ }
+
+ status = new_status;
+}
+
void Thread::AddMutexWaiter(SharedPtr<Thread> thread) {
if (thread->lock_owner == this) {
// If the thread is already waiting for this thread to release the mutex, ensure that the
@@ -388,11 +400,23 @@ void Thread::ChangeCore(u32 core, u64 mask) {
next_scheduler->ScheduleThread(this, current_priority);
// Change thread's scheduler
- scheduler = next_scheduler;
+ scheduler = next_scheduler.get();
Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule();
}
+bool Thread::AllWaitObjectsReady() {
+ return std::none_of(
+ wait_objects.begin(), wait_objects.end(),
+ [this](const SharedPtr<WaitObject>& object) { return object->ShouldWait(this); });
+}
+
+bool Thread::InvokeWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thread> thread,
+ SharedPtr<WaitObject> object, std::size_t index) {
+ ASSERT(wakeup_callback);
+ return wakeup_callback(reason, std::move(thread), std::move(object), index);
+}
+
////////////////////////////////////////////////////////////////////////////////////////////////////
/**
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 4250144c3..c6ffbd28c 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -65,6 +65,15 @@ public:
using TLSMemory = std::vector<u8>;
using TLSMemoryPtr = std::shared_ptr<TLSMemory>;
+ using MutexWaitingThreads = std::vector<SharedPtr<Thread>>;
+
+ using ThreadContext = Core::ARM_Interface::ThreadContext;
+
+ using ThreadWaitObjects = std::vector<SharedPtr<WaitObject>>;
+
+ using WakeupCallback = std::function<bool(ThreadWakeupReason reason, SharedPtr<Thread> thread,
+ SharedPtr<WaitObject> object, std::size_t index)>;
+
/**
* Creates and returns a new thread. The new thread is immediately scheduled
* @param kernel The kernel instance this thread will be created under.
@@ -106,6 +115,14 @@ public:
}
/**
+ * Gets the thread's nominal priority.
+ * @return The current thread's nominal priority.
+ */
+ u32 GetNominalPriority() const {
+ return nominal_priority;
+ }
+
+ /**
* Sets the thread's current priority
* @param priority The new priority
*/
@@ -133,7 +150,7 @@ public:
* Gets the thread's thread ID
* @return The thread's ID
*/
- u32 GetThreadId() const {
+ u32 GetThreadID() const {
return thread_id;
}
@@ -203,6 +220,11 @@ public:
return tpidr_el0;
}
+ /// Sets the value of the TPIDR_EL0 Read/Write system register for this thread.
+ void SetTPIDR_EL0(u64 value) {
+ tpidr_el0 = value;
+ }
+
/*
* Returns the address of the current thread's command buffer, located in the TLS.
* @returns VAddr of the thread's command buffer.
@@ -218,69 +240,193 @@ public:
return status == ThreadStatus::WaitSynchAll;
}
- Core::ARM_Interface::ThreadContext context;
+ ThreadContext& GetContext() {
+ return context;
+ }
+
+ const ThreadContext& GetContext() const {
+ return context;
+ }
+
+ ThreadStatus GetStatus() const {
+ return status;
+ }
+
+ void SetStatus(ThreadStatus new_status);
+
+ u64 GetLastRunningTicks() const {
+ return last_running_ticks;
+ }
+
+ s32 GetProcessorID() const {
+ return processor_id;
+ }
+
+ SharedPtr<Process>& GetOwnerProcess() {
+ return owner_process;
+ }
+
+ const SharedPtr<Process>& GetOwnerProcess() const {
+ return owner_process;
+ }
+
+ const ThreadWaitObjects& GetWaitObjects() const {
+ return wait_objects;
+ }
+
+ void SetWaitObjects(ThreadWaitObjects objects) {
+ wait_objects = std::move(objects);
+ }
+
+ void ClearWaitObjects() {
+ wait_objects.clear();
+ }
+
+ /// Determines whether all the objects this thread is waiting on are ready.
+ bool AllWaitObjectsReady();
+
+ const MutexWaitingThreads& GetMutexWaitingThreads() const {
+ return wait_mutex_threads;
+ }
+
+ Thread* GetLockOwner() const {
+ return lock_owner.get();
+ }
+
+ void SetLockOwner(SharedPtr<Thread> owner) {
+ lock_owner = std::move(owner);
+ }
+
+ VAddr GetCondVarWaitAddress() const {
+ return condvar_wait_address;
+ }
+
+ void SetCondVarWaitAddress(VAddr address) {
+ condvar_wait_address = address;
+ }
+
+ VAddr GetMutexWaitAddress() const {
+ return mutex_wait_address;
+ }
- u32 thread_id;
+ void SetMutexWaitAddress(VAddr address) {
+ mutex_wait_address = address;
+ }
- ThreadStatus status;
- VAddr entry_point;
- VAddr stack_top;
+ Handle GetWaitHandle() const {
+ return wait_handle;
+ }
- u32 nominal_priority; ///< Nominal thread priority, as set by the emulated application
- u32 current_priority; ///< Current thread priority, can be temporarily changed
+ void SetWaitHandle(Handle handle) {
+ wait_handle = handle;
+ }
- u64 last_running_ticks; ///< CPU tick when thread was last running
+ VAddr GetArbiterWaitAddress() const {
+ return arb_wait_address;
+ }
- s32 processor_id;
+ void SetArbiterWaitAddress(VAddr address) {
+ arb_wait_address = address;
+ }
- VAddr tls_address; ///< Virtual address of the Thread Local Storage of the thread
- u64 tpidr_el0; ///< TPIDR_EL0 read/write system register.
+ void SetGuestHandle(Handle handle) {
+ guest_handle = handle;
+ }
- SharedPtr<Process> owner_process; ///< Process that owns this thread
+ bool HasWakeupCallback() const {
+ return wakeup_callback != nullptr;
+ }
+
+ void SetWakeupCallback(WakeupCallback callback) {
+ wakeup_callback = std::move(callback);
+ }
+
+ void InvalidateWakeupCallback() {
+ SetWakeupCallback(nullptr);
+ }
+
+ /**
+ * Invokes the thread's wakeup callback.
+ *
+ * @pre A valid wakeup callback has been set. Violating this precondition
+ * will cause an assertion to trigger.
+ */
+ bool InvokeWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thread> thread,
+ SharedPtr<WaitObject> object, std::size_t index);
+
+ u32 GetIdealCore() const {
+ return ideal_core;
+ }
+
+ u64 GetAffinityMask() const {
+ return affinity_mask;
+ }
+
+private:
+ explicit Thread(KernelCore& kernel);
+ ~Thread() override;
+
+ Core::ARM_Interface::ThreadContext context{};
+
+ u32 thread_id = 0;
+
+ ThreadStatus status = ThreadStatus::Dormant;
+
+ VAddr entry_point = 0;
+ VAddr stack_top = 0;
+
+ u32 nominal_priority = 0; ///< Nominal thread priority, as set by the emulated application
+ u32 current_priority = 0; ///< Current thread priority, can be temporarily changed
+
+ u64 last_running_ticks = 0; ///< CPU tick when thread was last running
+
+ s32 processor_id = 0;
+
+ VAddr tls_address = 0; ///< Virtual address of the Thread Local Storage of the thread
+ u64 tpidr_el0 = 0; ///< TPIDR_EL0 read/write system register.
+
+ /// Process that owns this thread
+ SharedPtr<Process> owner_process;
/// Objects that the thread is waiting on, in the same order as they were
- // passed to WaitSynchronization1/N.
- std::vector<SharedPtr<WaitObject>> wait_objects;
+ /// passed to WaitSynchronization1/N.
+ ThreadWaitObjects wait_objects;
/// List of threads that are waiting for a mutex that is held by this thread.
- std::vector<SharedPtr<Thread>> wait_mutex_threads;
+ MutexWaitingThreads wait_mutex_threads;
/// Thread that owns the lock that this thread is waiting for.
SharedPtr<Thread> lock_owner;
- // If waiting on a ConditionVariable, this is the ConditionVariable address
- VAddr condvar_wait_address;
- VAddr mutex_wait_address; ///< If waiting on a Mutex, this is the mutex address
- Handle wait_handle; ///< The handle used to wait for the mutex.
+ /// If waiting on a ConditionVariable, this is the ConditionVariable address
+ VAddr condvar_wait_address = 0;
+ /// If waiting on a Mutex, this is the mutex address
+ VAddr mutex_wait_address = 0;
+ /// The handle used to wait for the mutex.
+ Handle wait_handle = 0;
- // If waiting for an AddressArbiter, this is the address being waited on.
+ /// If waiting for an AddressArbiter, this is the address being waited on.
VAddr arb_wait_address{0};
- std::string name;
-
/// Handle used by guest emulated application to access this thread
- Handle guest_handle;
+ Handle guest_handle = 0;
/// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
- Handle callback_handle;
+ Handle callback_handle = 0;
- using WakeupCallback = bool(ThreadWakeupReason reason, SharedPtr<Thread> thread,
- SharedPtr<WaitObject> object, std::size_t index);
- // Callback that will be invoked when the thread is resumed from a waiting state. If the thread
- // was waiting via WaitSynchronizationN then the object will be the last object that became
- // available. In case of a timeout, the object will be nullptr.
- std::function<WakeupCallback> wakeup_callback;
+ /// Callback that will be invoked when the thread is resumed from a waiting state. If the thread
+ /// was waiting via WaitSynchronizationN then the object will be the last object that became
+ /// available. In case of a timeout, the object will be nullptr.
+ WakeupCallback wakeup_callback;
- std::shared_ptr<Scheduler> scheduler;
+ Scheduler* scheduler = nullptr;
u32 ideal_core{0xFFFFFFFF};
u64 affinity_mask{0x1};
-private:
- explicit Thread(KernelCore& kernel);
- ~Thread() override;
-
TLSMemoryPtr tls_memory = std::make_shared<TLSMemory>();
+
+ std::string name;
};
/**
diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp
index b190ceb98..530ee6af7 100644
--- a/src/core/hle/kernel/wait_object.cpp
+++ b/src/core/hle/kernel/wait_object.cpp
@@ -35,13 +35,15 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
u32 candidate_priority = THREADPRIO_LOWEST + 1;
for (const auto& thread : waiting_threads) {
+ const ThreadStatus thread_status = thread->GetStatus();
+
// The list of waiting threads must not contain threads that are not waiting to be awakened.
- ASSERT_MSG(thread->status == ThreadStatus::WaitSynchAny ||
- thread->status == ThreadStatus::WaitSynchAll ||
- thread->status == ThreadStatus::WaitHLEEvent,
+ ASSERT_MSG(thread_status == ThreadStatus::WaitSynchAny ||
+ thread_status == ThreadStatus::WaitSynchAll ||
+ thread_status == ThreadStatus::WaitHLEEvent,
"Inconsistent thread statuses in waiting_threads");
- if (thread->current_priority >= candidate_priority)
+ if (thread->GetPriority() >= candidate_priority)
continue;
if (ShouldWait(thread.get()))
@@ -50,16 +52,13 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
// A thread is ready to run if it's either in ThreadStatus::WaitSynchAny or
// in ThreadStatus::WaitSynchAll and the rest of the objects it is waiting on are ready.
bool ready_to_run = true;
- if (thread->status == ThreadStatus::WaitSynchAll) {
- ready_to_run = std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(),
- [&thread](const SharedPtr<WaitObject>& object) {
- return object->ShouldWait(thread.get());
- });
+ if (thread_status == ThreadStatus::WaitSynchAll) {
+ ready_to_run = thread->AllWaitObjectsReady();
}
if (ready_to_run) {
candidate = thread.get();
- candidate_priority = thread->current_priority;
+ candidate_priority = thread->GetPriority();
}
}
@@ -75,24 +74,24 @@ void WaitObject::WakeupWaitingThread(SharedPtr<Thread> thread) {
if (!thread->IsSleepingOnWaitAll()) {
Acquire(thread.get());
} else {
- for (auto& object : thread->wait_objects) {
+ for (const auto& object : thread->GetWaitObjects()) {
ASSERT(!object->ShouldWait(thread.get()));
object->Acquire(thread.get());
}
}
- std::size_t index = thread->GetWaitObjectIndex(this);
+ const std::size_t index = thread->GetWaitObjectIndex(this);
- for (auto& object : thread->wait_objects)
+ for (const auto& object : thread->GetWaitObjects())
object->RemoveWaitingThread(thread.get());
- thread->wait_objects.clear();
+ thread->ClearWaitObjects();
thread->CancelWakeupTimer();
bool resume = true;
- if (thread->wakeup_callback)
- resume = thread->wakeup_callback(ThreadWakeupReason::Signal, thread, this, index);
+ if (thread->HasWakeupCallback())
+ resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Signal, thread, this, index);
if (resume)
thread->ResumeFromWait();
diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp
index 79580bcd9..0ecfb5af1 100644
--- a/src/core/hle/service/aoc/aoc_u.cpp
+++ b/src/core/hle/service/aoc/aoc_u.cpp
@@ -61,13 +61,13 @@ AOC_U::AOC_U() : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs
AOC_U::~AOC_U() = default;
void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) {
- IPC::ResponseBuilder rb{ctx, 4};
+ IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
const auto current = Core::System::GetInstance().CurrentProcess()->GetTitleID();
- rb.Push<u32>(std::count_if(add_on_content.begin(), add_on_content.end(), [&current](u64 tid) {
- return (tid & DLC_BASE_TITLE_ID_MASK) == current;
- }));
+ rb.Push<u32>(static_cast<u32>(
+ std::count_if(add_on_content.begin(), add_on_content.end(),
+ [&current](u64 tid) { return (tid & DLC_BASE_TITLE_ID_MASK) == current; })));
}
void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) {
@@ -91,7 +91,7 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) {
return;
}
- count = std::min<size_t>(out.size() - offset, count);
+ count = static_cast<u32>(std::min<size_t>(out.size() - offset, count));
std::rotate(out.begin(), out.begin() + offset, out.end());
out.resize(count);
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index aed2abb71..439e62d27 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -264,6 +264,15 @@ ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory) {
return RESULT_SUCCESS;
}
+void SetPackedUpdate(FileSys::VirtualFile update_raw) {
+ LOG_TRACE(Service_FS, "Setting packed update for romfs");
+
+ if (romfs_factory == nullptr)
+ return;
+
+ romfs_factory->SetPackedUpdate(std::move(update_raw));
+}
+
ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess() {
LOG_TRACE(Service_FS, "Opening RomFS for current process");
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index 7039a2247..53b01bb01 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -39,6 +39,7 @@ ResultCode RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory)
ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory);
ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory);
+void SetPackedUpdate(FileSys::VirtualFile update_raw);
ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess();
ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
FileSys::ContentRecordType type);
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
index d8b8037a8..7555bbe7d 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -157,7 +157,12 @@ u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& ou
LOG_DEBUG(Service_NVDRV, "called, offset=0x{:X}", params.offset);
const auto itr = buffer_mappings.find(params.offset);
- ASSERT_MSG(itr != buffer_mappings.end(), "Tried to unmap invalid mapping");
+ if (itr == buffer_mappings.end()) {
+ LOG_WARNING(Service_NVDRV, "Tried to unmap an invalid offset 0x{:X}", params.offset);
+ // Hardware tests shows that unmapping an already unmapped buffer always returns successful
+ // and doesn't fail.
+ return 0;
+ }
auto& system_instance = Core::System::GetInstance();
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index da2c51082..4f8145dda 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -6,9 +6,12 @@
#include <memory>
#include <string>
+#include <type_traits>
#include <unordered_map>
+#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/object.h"
+#include "core/hle/kernel/server_port.h"
#include "core/hle/result.h"
#include "core/hle/service/service.h"
@@ -48,6 +51,22 @@ public:
ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> GetServicePort(const std::string& name);
ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ConnectToService(const std::string& name);
+ template <typename T>
+ std::shared_ptr<T> GetService(const std::string& service_name) const {
+ static_assert(std::is_base_of_v<Kernel::SessionRequestHandler, T>,
+ "Not a base of ServiceFrameworkBase");
+ auto service = registered_services.find(service_name);
+ if (service == registered_services.end()) {
+ LOG_DEBUG(Service, "Can't find service: {}", service_name);
+ return nullptr;
+ }
+ auto port = service->second->GetServerPort();
+ if (port == nullptr) {
+ return nullptr;
+ }
+ return std::static_pointer_cast<T>(port->hle_handler);
+ }
+
void InvokeControlRequest(Kernel::HLERequestContext& context);
private:
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index 9a86e5824..951fd8257 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <cinttypes>
+#include <cstring>
#include "common/common_funcs.h"
#include "common/file_util.h"
#include "common/logging/log.h"
@@ -140,7 +141,8 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(Kernel::Process& process)
const FileSys::VirtualFile module_file = dir->GetFile(module);
if (module_file != nullptr) {
const VAddr load_addr = next_load_addr;
- next_load_addr = AppLoader_NSO::LoadModule(module_file, load_addr, pm);
+ next_load_addr = AppLoader_NSO::LoadModule(module_file, load_addr,
+ std::strcmp(module, "rtld") == 0, pm);
LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr);
// Register module with GDBStub
GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false);
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index f2a183ba1..91659ec17 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -93,7 +93,7 @@ std::string GetFileTypeString(FileType type) {
return "unknown";
}
-constexpr std::array<const char*, 58> RESULT_MESSAGES{
+constexpr std::array<const char*, 59> RESULT_MESSAGES{
"The operation completed successfully.",
"The loader requested to load is already loaded.",
"The operation is not implemented.",
@@ -152,6 +152,7 @@ constexpr std::array<const char*, 58> RESULT_MESSAGES{
"The BKTR-type NCA has a bad Relocation bucket.",
"The BKTR-type NCA has a bad Subsection bucket.",
"The BKTR-type NCA is missing the base RomFS.",
+ "The NSP or XCI does not contain an update in addition to the base game.",
};
std::ostream& operator<<(std::ostream& os, ResultStatus status) {
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 20e66109b..0e0333db5 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -114,6 +114,7 @@ enum class ResultStatus : u16 {
ErrorBadRelocationBuckets,
ErrorBadSubsectionBuckets,
ErrorMissingBKTRBaseRomFS,
+ ErrorNoPackedUpdate,
};
std::ostream& operator<<(std::ostream& os, ResultStatus status);
@@ -196,10 +197,19 @@ public:
/**
* Get the RomFS of the application
* Since the RomFS can be huge, we return a file reference instead of copying to a buffer
- * @param dir The directory containing the RomFS
+ * @param file The directory containing the RomFS
* @return ResultStatus result of function
*/
- virtual ResultStatus ReadRomFS(FileSys::VirtualFile& dir) {
+ virtual ResultStatus ReadRomFS(FileSys::VirtualFile& file) {
+ return ResultStatus::ErrorNotImplemented;
+ }
+
+ /**
+ * Get the raw update of the application, should it come packed with one
+ * @param file The raw update NCA file (Program-type
+ * @return ResultStatus result of function
+ */
+ virtual ResultStatus ReadUpdateRaw(FileSys::VirtualFile& file) {
return ResultStatus::ErrorNotImplemented;
}
diff --git a/src/core/loader/nax.cpp b/src/core/loader/nax.cpp
index 073fb9d2f..42f4a777b 100644
--- a/src/core/loader/nax.cpp
+++ b/src/core/loader/nax.cpp
@@ -72,6 +72,10 @@ ResultStatus AppLoader_NAX::ReadRomFS(FileSys::VirtualFile& dir) {
return nca_loader->ReadRomFS(dir);
}
+u64 AppLoader_NAX::ReadRomFSIVFCOffset() const {
+ return nca_loader->ReadRomFSIVFCOffset();
+}
+
ResultStatus AppLoader_NAX::ReadProgramId(u64& out_program_id) {
return nca_loader->ReadProgramId(out_program_id);
}
diff --git a/src/core/loader/nax.h b/src/core/loader/nax.h
index fc3c01876..b4d93bd01 100644
--- a/src/core/loader/nax.h
+++ b/src/core/loader/nax.h
@@ -36,6 +36,7 @@ public:
ResultStatus Load(Kernel::Process& process) override;
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
+ u64 ReadRomFSIVFCOffset() const override;
ResultStatus ReadProgramId(u64& out_program_id) override;
private:
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index c10f826a4..25dd3f04e 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -18,7 +18,9 @@
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/vm_manager.h"
#include "core/loader/nro.h"
+#include "core/loader/nso.h"
#include "core/memory.h"
+#include "core/settings.h"
namespace Loader {
@@ -150,6 +152,19 @@ bool AppLoader_NRO::LoadNro(FileSys::VirtualFile file, VAddr load_base) {
codeset->segments[i].size = PageAlignSize(nro_header.segments[i].size);
}
+ if (!Settings::values.program_args.empty()) {
+ const auto arg_data = Settings::values.program_args;
+ codeset->DataSegment().size += NSO_ARGUMENT_DATA_ALLOCATION_SIZE;
+ NSOArgumentHeader args_header{
+ NSO_ARGUMENT_DATA_ALLOCATION_SIZE, static_cast<u32_le>(arg_data.size()), {}};
+ const auto end_offset = program_image.size();
+ program_image.resize(static_cast<u32>(program_image.size()) +
+ NSO_ARGUMENT_DATA_ALLOCATION_SIZE);
+ std::memcpy(program_image.data() + end_offset, &args_header, sizeof(NSOArgumentHeader));
+ std::memcpy(program_image.data() + end_offset + sizeof(NSOArgumentHeader), arg_data.data(),
+ arg_data.size());
+ }
+
// Read MOD header
ModHeader mod_header{};
// Default .bss to NRO header bss size if MOD0 section doesn't exist
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 2186b02af..28c6dd9b7 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -17,6 +17,7 @@
#include "core/hle/kernel/vm_manager.h"
#include "core/loader/nso.h"
#include "core/memory.h"
+#include "core/settings.h"
namespace Loader {
@@ -94,6 +95,7 @@ static constexpr u32 PageAlignSize(u32 size) {
}
VAddr AppLoader_NSO::LoadModule(FileSys::VirtualFile file, VAddr load_base,
+ bool should_pass_arguments,
boost::optional<FileSys::PatchManager> pm) {
if (file == nullptr)
return {};
@@ -125,6 +127,19 @@ VAddr AppLoader_NSO::LoadModule(FileSys::VirtualFile file, VAddr load_base,
codeset->segments[i].size = PageAlignSize(static_cast<u32>(data.size()));
}
+ if (should_pass_arguments && !Settings::values.program_args.empty()) {
+ const auto arg_data = Settings::values.program_args;
+ codeset->DataSegment().size += NSO_ARGUMENT_DATA_ALLOCATION_SIZE;
+ NSOArgumentHeader args_header{
+ NSO_ARGUMENT_DATA_ALLOCATION_SIZE, static_cast<u32_le>(arg_data.size()), {}};
+ const auto end_offset = program_image.size();
+ program_image.resize(static_cast<u32>(program_image.size()) +
+ NSO_ARGUMENT_DATA_ALLOCATION_SIZE);
+ std::memcpy(program_image.data() + end_offset, &args_header, sizeof(NSOArgumentHeader));
+ std::memcpy(program_image.data() + end_offset + sizeof(NSOArgumentHeader), arg_data.data(),
+ arg_data.size());
+ }
+
// MOD header pointer is at .text offset + 4
u32 module_offset;
std::memcpy(&module_offset, program_image.data() + 4, sizeof(u32));
@@ -172,7 +187,7 @@ ResultStatus AppLoader_NSO::Load(Kernel::Process& process) {
// Load module
const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
- LoadModule(file, base_address);
+ LoadModule(file, base_address, true);
LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address);
process.Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h
index 05353d4d9..70ab3b718 100644
--- a/src/core/loader/nso.h
+++ b/src/core/loader/nso.h
@@ -11,6 +11,15 @@
namespace Loader {
+constexpr u64 NSO_ARGUMENT_DATA_ALLOCATION_SIZE = 0x9000;
+
+struct NSOArgumentHeader {
+ u32_le allocated_size;
+ u32_le actual_size;
+ INSERT_PADDING_BYTES(0x18);
+};
+static_assert(sizeof(NSOArgumentHeader) == 0x20, "NSOArgumentHeader has incorrect size.");
+
/// Loads an NSO file
class AppLoader_NSO final : public AppLoader, Linker {
public:
@@ -27,7 +36,7 @@ public:
return IdentifyType(file);
}
- static VAddr LoadModule(FileSys::VirtualFile file, VAddr load_base,
+ static VAddr LoadModule(FileSys::VirtualFile file, VAddr load_base, bool should_pass_arguments,
boost::optional<FileSys::PatchManager> pm = boost::none);
ResultStatus Load(Kernel::Process& process) override;
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp
index b7ba77ef4..5534ce01c 100644
--- a/src/core/loader/nsp.cpp
+++ b/src/core/loader/nsp.cpp
@@ -10,8 +10,10 @@
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/patch_manager.h"
+#include "core/file_sys/registered_cache.h"
#include "core/file_sys/submission_package.h"
#include "core/hle/kernel/process.h"
+#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/deconstructed_rom_directory.h"
#include "core/loader/nca.h"
#include "core/loader/nsp.h"
@@ -91,13 +93,39 @@ ResultStatus AppLoader_NSP::Load(Kernel::Process& process) {
if (result != ResultStatus::Success)
return result;
+ FileSys::VirtualFile update_raw;
+ if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr)
+ Service::FileSystem::SetPackedUpdate(std::move(update_raw));
+
is_loaded = true;
return ResultStatus::Success;
}
-ResultStatus AppLoader_NSP::ReadRomFS(FileSys::VirtualFile& dir) {
- return secondary_loader->ReadRomFS(dir);
+ResultStatus AppLoader_NSP::ReadRomFS(FileSys::VirtualFile& file) {
+ return secondary_loader->ReadRomFS(file);
+}
+
+u64 AppLoader_NSP::ReadRomFSIVFCOffset() const {
+ return secondary_loader->ReadRomFSIVFCOffset();
+}
+
+ResultStatus AppLoader_NSP::ReadUpdateRaw(FileSys::VirtualFile& file) {
+ if (nsp->IsExtractedType())
+ return ResultStatus::ErrorNoPackedUpdate;
+
+ const auto read =
+ nsp->GetNCAFile(FileSys::GetUpdateTitleID(title_id), FileSys::ContentRecordType::Program);
+
+ if (read == nullptr)
+ return ResultStatus::ErrorNoPackedUpdate;
+ const auto nca_test = std::make_shared<FileSys::NCA>(read);
+
+ if (nca_test->GetStatus() != ResultStatus::ErrorMissingBKTRBaseRomFS)
+ return nca_test->GetStatus();
+
+ file = read;
+ return ResultStatus::Success;
}
ResultStatus AppLoader_NSP::ReadProgramId(u64& out_program_id) {
diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h
index eac9b819a..b006594a6 100644
--- a/src/core/loader/nsp.h
+++ b/src/core/loader/nsp.h
@@ -37,7 +37,9 @@ public:
ResultStatus Load(Kernel::Process& process) override;
- ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
+ ResultStatus ReadRomFS(FileSys::VirtualFile& file) override;
+ u64 ReadRomFSIVFCOffset() const override;
+ ResultStatus ReadUpdateRaw(FileSys::VirtualFile& file) override;
ResultStatus ReadProgramId(u64& out_program_id) override;
ResultStatus ReadIcon(std::vector<u8>& buffer) override;
ResultStatus ReadTitle(std::string& title) override;
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp
index eda67a8c8..ee5452eb9 100644
--- a/src/core/loader/xci.cpp
+++ b/src/core/loader/xci.cpp
@@ -9,7 +9,11 @@
#include "core/file_sys/content_archive.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
+#include "core/file_sys/registered_cache.h"
+#include "core/file_sys/romfs.h"
+#include "core/file_sys/submission_package.h"
#include "core/hle/kernel/process.h"
+#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/nca.h"
#include "core/loader/xci.h"
@@ -63,13 +67,41 @@ ResultStatus AppLoader_XCI::Load(Kernel::Process& process) {
if (result != ResultStatus::Success)
return result;
+ FileSys::VirtualFile update_raw;
+ if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr)
+ Service::FileSystem::SetPackedUpdate(std::move(update_raw));
+
is_loaded = true;
return ResultStatus::Success;
}
-ResultStatus AppLoader_XCI::ReadRomFS(FileSys::VirtualFile& dir) {
- return nca_loader->ReadRomFS(dir);
+ResultStatus AppLoader_XCI::ReadRomFS(FileSys::VirtualFile& file) {
+ return nca_loader->ReadRomFS(file);
+}
+
+u64 AppLoader_XCI::ReadRomFSIVFCOffset() const {
+ return nca_loader->ReadRomFSIVFCOffset();
+}
+
+ResultStatus AppLoader_XCI::ReadUpdateRaw(FileSys::VirtualFile& file) {
+ u64 program_id{};
+ nca_loader->ReadProgramId(program_id);
+ if (program_id == 0)
+ return ResultStatus::ErrorXCIMissingProgramNCA;
+
+ const auto read = xci->GetSecurePartitionNSP()->GetNCAFile(
+ FileSys::GetUpdateTitleID(program_id), FileSys::ContentRecordType::Program);
+
+ if (read == nullptr)
+ return ResultStatus::ErrorNoPackedUpdate;
+ const auto nca_test = std::make_shared<FileSys::NCA>(read);
+
+ if (nca_test->GetStatus() != ResultStatus::ErrorMissingBKTRBaseRomFS)
+ return nca_test->GetStatus();
+
+ file = read;
+ return ResultStatus::Success;
}
ResultStatus AppLoader_XCI::ReadProgramId(u64& out_program_id) {
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h
index 17e47b658..770ed1437 100644
--- a/src/core/loader/xci.h
+++ b/src/core/loader/xci.h
@@ -37,7 +37,9 @@ public:
ResultStatus Load(Kernel::Process& process) override;
- ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
+ ResultStatus ReadRomFS(FileSys::VirtualFile& file) override;
+ u64 ReadRomFSIVFCOffset() const override;
+ ResultStatus ReadUpdateRaw(FileSys::VirtualFile& file) override;
ResultStatus ReadProgramId(u64& out_program_id) override;
ResultStatus ReadIcon(std::vector<u8>& buffer) override;
ResultStatus ReadTitle(std::string& title) override;
diff --git a/src/core/settings.h b/src/core/settings.h
index 0318d019c..83b9a04c8 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -155,6 +155,13 @@ struct Values {
// Debugging
bool use_gdbstub;
u16 gdbstub_port;
+ std::string program_args;
+
+ // WebService
+ bool enable_telemetry;
+ std::string web_api_url;
+ std::string yuzu_username;
+ std::string yuzu_token;
} extern values;
void Apply();
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index b0df154ca..f29fff1e7 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -6,6 +6,8 @@
#include "common/common_types.h"
#include "common/file_util.h"
+#include <mbedtls/ctr_drbg.h>
+#include <mbedtls/entropy.h>
#include "core/core.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
@@ -13,10 +15,31 @@
#include "core/settings.h"
#include "core/telemetry_session.h"
+#ifdef ENABLE_WEB_SERVICE
+#include "web_service/telemetry_json.h"
+#include "web_service/verify_login.h"
+#endif
+
namespace Core {
static u64 GenerateTelemetryId() {
u64 telemetry_id{};
+
+ mbedtls_entropy_context entropy;
+ mbedtls_entropy_init(&entropy);
+ mbedtls_ctr_drbg_context ctr_drbg;
+ std::string personalization = "yuzu Telemetry ID";
+
+ mbedtls_ctr_drbg_init(&ctr_drbg);
+ ASSERT(mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
+ reinterpret_cast<const unsigned char*>(personalization.c_str()),
+ personalization.size()) == 0);
+ ASSERT(mbedtls_ctr_drbg_random(&ctr_drbg, reinterpret_cast<unsigned char*>(&telemetry_id),
+ sizeof(u64)) == 0);
+
+ mbedtls_ctr_drbg_free(&ctr_drbg);
+ mbedtls_entropy_free(&entropy);
+
return telemetry_id;
}
@@ -25,14 +48,21 @@ u64 GetTelemetryId() {
const std::string filename{FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) +
"telemetry_id"};
- if (FileUtil::Exists(filename)) {
+ bool generate_new_id = !FileUtil::Exists(filename);
+ if (!generate_new_id) {
FileUtil::IOFile file(filename, "rb");
if (!file.IsOpen()) {
LOG_ERROR(Core, "failed to open telemetry_id: {}", filename);
return {};
}
file.ReadBytes(&telemetry_id, sizeof(u64));
- } else {
+ if (telemetry_id == 0) {
+ LOG_ERROR(Frontend, "telemetry_id is 0. Generating a new one.", telemetry_id);
+ generate_new_id = true;
+ }
+ }
+
+ if (generate_new_id) {
FileUtil::IOFile file(filename, "wb");
if (!file.IsOpen()) {
LOG_ERROR(Core, "failed to open telemetry_id: {}", filename);
@@ -59,23 +89,20 @@ u64 RegenerateTelemetryId() {
return new_telemetry_id;
}
-std::future<bool> VerifyLogin(std::string username, std::string token, std::function<void()> func) {
+bool VerifyLogin(const std::string& username, const std::string& token) {
#ifdef ENABLE_WEB_SERVICE
- return WebService::VerifyLogin(username, token, Settings::values.verify_endpoint_url, func);
+ return WebService::VerifyLogin(Settings::values.web_api_url, username, token);
#else
- return std::async(std::launch::async, [func{std::move(func)}]() {
- func();
- return false;
- });
+ return false;
#endif
}
TelemetrySession::TelemetrySession() {
#ifdef ENABLE_WEB_SERVICE
if (Settings::values.enable_telemetry) {
- backend = std::make_unique<WebService::TelemetryJson>(
- Settings::values.telemetry_endpoint_url, Settings::values.yuzu_username,
- Settings::values.yuzu_token);
+ backend = std::make_unique<WebService::TelemetryJson>(Settings::values.web_api_url,
+ Settings::values.yuzu_username,
+ Settings::values.yuzu_token);
} else {
backend = std::make_unique<Telemetry::NullVisitor>();
}
@@ -94,7 +121,8 @@ TelemetrySession::TelemetrySession() {
u64 program_id{};
const Loader::ResultStatus res{System::GetInstance().GetAppLoader().ReadProgramId(program_id)};
if (res == Loader::ResultStatus::Success) {
- AddField(Telemetry::FieldType::Session, "ProgramId", program_id);
+ const std::string formatted_program_id{fmt::format("{:016X}", program_id)};
+ AddField(Telemetry::FieldType::Session, "ProgramId", formatted_program_id);
std::string name;
System::GetInstance().GetAppLoader().ReadTitle(name);
diff --git a/src/core/telemetry_session.h b/src/core/telemetry_session.h
index dbc4f8bd4..cec271df0 100644
--- a/src/core/telemetry_session.h
+++ b/src/core/telemetry_session.h
@@ -4,7 +4,6 @@
#pragma once
-#include <future>
#include <memory>
#include "common/telemetry.h"
@@ -31,6 +30,8 @@ public:
field_collection.AddField(type, name, std::move(value));
}
+ static void FinalizeAsyncJob();
+
private:
Telemetry::FieldCollection field_collection; ///< Tracks all added fields for the session
std::unique_ptr<Telemetry::VisitorInterface> backend; ///< Backend interface that logs fields
@@ -55,6 +56,6 @@ u64 RegenerateTelemetryId();
* @param func A function that gets exectued when the verification is finished
* @returns Future with bool indicating whether the verification succeeded
*/
-std::future<bool> VerifyLogin(std::string username, std::string token, std::function<void()> func);
+bool VerifyLogin(const std::string& username, const std::string& token);
} // namespace Core