[hle, kernel] Add support for FW21 and kernel changes (#3004)

- Adapts kernel changes from atmosphere for firmware 21.0.0.
- Fixes launch error of firmware 21.0.0 applets.
- Adds new commands for `prepo` (New `SaveSystemReport` & `SaveSystemReportWithUser`).
- Adds new commands for `IReadOnlyApplicationControlDataInterface` (cmd 19; incomplete!)
- Adds `{12010, nullptr, "SetButtonConfigLeft"},` undocumented IHidServer.
- Adds new commands for `ngc:u` (`Mask2` and `Check2`)
- Adds new commands for system settings server (GetHttpAuthConfig) for webapplet
- Removes incompatible firmware popup warning.

Signed-off-by: lizzie lizzie@eden-emu.dev
Co-authored by: maufeat sahyno1996@gmail.com

Co-authored-by: crueter <crueter@eden-emu.dev>
Co-authored-by: JPikachu <jpikachu.eden@gmail.com>
Co-authored-by: Maufeat <sahyno1996@gmail.com>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3004
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
This commit is contained in:
lizzie 2025-11-16 22:15:09 +01:00 committed by crueter
parent b690813196
commit 7d239df065
No known key found for this signature in database
GPG key ID: 425ACD2D4830EBC6
35 changed files with 1624 additions and 1363 deletions

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -8,6 +11,7 @@ namespace Kernel {
KAutoObject* KAutoObject::Create(KAutoObject* obj) {
obj->m_ref_count = 1;
obj->m_class_token = obj->GetTypeObj().GetClassToken();
return obj;
}

View file

@ -74,6 +74,10 @@ protected:
return (this->GetClassToken() | rhs.GetClassToken()) == this->GetClassToken();
}
static constexpr bool IsClassTokenDerivedFrom(ClassTokenType self, ClassTokenType base) {
return (self | base) == self;
}
private:
const char* m_name;
ClassTokenType m_class_token;
@ -84,6 +88,7 @@ private:
public:
explicit KAutoObject(KernelCore& kernel) : m_kernel(kernel) {
m_class_token = GetStaticTypeObj().GetClassToken();
RegisterWithKernel();
}
virtual ~KAutoObject() = default;
@ -107,11 +112,11 @@ public:
}
bool IsDerivedFrom(const TypeObj& rhs) const {
return this->GetTypeObj().IsDerivedFrom(rhs);
return TypeObj::IsClassTokenDerivedFrom(m_class_token, rhs.GetClassToken());
}
bool IsDerivedFrom(const KAutoObject& rhs) const {
return this->IsDerivedFrom(rhs.GetTypeObj());
return TypeObj::IsClassTokenDerivedFrom(m_class_token, rhs.m_class_token);
}
template <typename Derived>
@ -180,6 +185,7 @@ protected:
private:
std::atomic<u32> m_ref_count{};
ClassTokenType m_class_token{};
};
class KAutoObjectWithListContainer;

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -23,8 +26,8 @@ bool ReadFromUser(KernelCore& kernel, u32* out, KProcessAddress address) {
return true;
}
bool WriteToUser(KernelCore& kernel, KProcessAddress address, const u32* p) {
GetCurrentMemory(kernel).Write32(GetInteger(address), *p);
bool WriteToUser(KernelCore& kernel, KProcessAddress address, u32 val) {
GetCurrentMemory(kernel).Write32(GetInteger(address), val);
return true;
}
@ -133,7 +136,7 @@ Result KConditionVariable::SignalToAddress(KernelCore& kernel, KProcessAddress a
// Write the value to userspace.
Result result{ResultSuccess};
if (WriteToUser(kernel, addr, std::addressof(next_value))) [[likely]] {
if (WriteToUser(kernel, addr, next_value)) {
result = ResultSuccess;
} else {
result = ResultInvalidCurrentMemory;
@ -207,13 +210,13 @@ void KConditionVariable::SignalImpl(KThread* thread) {
// TODO(bunnei): We should call CanAccessAtomic(..) here.
can_access = true;
if (can_access) [[likely]] {
if (can_access) {
UpdateLockAtomic(m_kernel, std::addressof(prev_tag), address, own_tag,
Svc::HandleWaitMask);
}
}
if (can_access) [[likely]] {
if (can_access) {
if (prev_tag == Svc::InvalidHandle) {
// If nobody held the lock previously, we're all good.
thread->EndWait(ResultSuccess);
@ -225,7 +228,7 @@ void KConditionVariable::SignalImpl(KThread* thread) {
static_cast<Handle>(prev_tag & ~Svc::HandleWaitMask))
.ReleasePointerUnsafe();
if (owner_thread) [[likely]] {
if (owner_thread) {
// Add the thread as a waiter on the owner.
owner_thread->AddWaiter(thread);
owner_thread->Close();
@ -261,8 +264,8 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) {
// If we have no waiters, clear the has waiter flag.
if (it == m_tree.end() || it->GetConditionVariableKey() != cv_key) {
const u32 has_waiter_flag{};
WriteToUser(m_kernel, cv_key, std::addressof(has_waiter_flag));
constexpr u32 HasNoWaiterFlag = 0;
WriteToUser(m_kernel, cv_key, HasNoWaiterFlag);
}
}
}
@ -305,13 +308,13 @@ Result KConditionVariable::Wait(KProcessAddress addr, u64 key, u32 value, s64 ti
// Write to the cv key.
{
const u32 has_waiter_flag = 1;
WriteToUser(m_kernel, key, std::addressof(has_waiter_flag));
constexpr u32 HasWaiterFlag = 1;
WriteToUser(m_kernel, key, HasWaiterFlag);
std::atomic_thread_fence(std::memory_order_seq_cst);
}
// Write the value to userspace.
if (!WriteToUser(m_kernel, addr, std::addressof(next_value))) {
if (!WriteToUser(m_kernel, addr, next_value)) {
slp.CancelSleep();
R_THROW(ResultInvalidCurrentMemory);
}

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -6,7 +9,7 @@
namespace Kernel {
Result KHandleTable::Finalize() {
void KHandleTable::Finalize() {
// Get the table and clear our record of it.
u16 saved_table_size = 0;
{
@ -22,8 +25,6 @@ Result KHandleTable::Finalize() {
obj->Close();
}
}
R_SUCCEED();
}
bool KHandleTable::Remove(Handle handle) {

View file

@ -68,7 +68,7 @@ public:
return m_max_count;
}
Result Finalize();
void Finalize();
bool Remove(Handle handle);
template <typename T = KAutoObject>

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -381,6 +384,9 @@ void KScheduler::SwitchThread(KThread* next_thread) {
// Set the new Thread Local region.
// cpu::SwitchThreadLocalRegion(GetInteger(next_thread->GetThreadLocalRegionAddress()));
// Update the thread's cpu time differential in TLS, if relevant.
next_thread->UpdateTlsThreadCpuTime(cur_tick);
}
void KScheduler::ScheduleImpl() {

File diff suppressed because it is too large Load diff

View file

@ -99,6 +99,12 @@ enum class DpcFlag : u32 {
Terminated = (1 << 1),
};
enum class ExceptionFlag : u8 {
IsCallingSvc = 1 << 0,
InExceptionHandler = 1 << 1,
};
DECLARE_ENUM_FLAG_OPERATORS(ExceptionFlag);
enum class ThreadWaitReasonForDebugging : u32 {
None, ///< Thread is not waiting
Sleep, ///< Thread is waiting due to a SleepThread SVC
@ -153,7 +159,7 @@ public:
/**
* Sets the thread's current priority.
* @param priority The new priority.
* @param value The new priority.
*/
void SetPriority(s32 value) {
m_priority = value;
@ -340,6 +346,8 @@ public:
void SetInterruptFlag();
void ClearInterruptFlag();
void UpdateTlsThreadCpuTime(s64 switch_tick);
KThread* GetLockOwner() const;
const KAffinityMask& GetAffinityMask() const {
@ -446,6 +454,7 @@ public:
bool is_pinned;
s32 disable_count;
KThread* cur_thread;
std::atomic<u8> exception_flags{0};
};
StackParameters& GetStackParameters() {
@ -456,6 +465,16 @@ public:
return m_stack_parameters;
}
void SetExceptionFlag(ExceptionFlag flag) {
GetStackParameters().exception_flags.fetch_or(static_cast<u8>(flag), std::memory_order_relaxed);
}
void ClearExceptionFlag(ExceptionFlag flag) {
GetStackParameters().exception_flags.fetch_and(static_cast<u8>(~static_cast<u8>(flag)), std::memory_order_relaxed);
}
bool IsExceptionFlagSet(ExceptionFlag flag) const {
return (GetStackParameters().exception_flags.load(std::memory_order_relaxed) & static_cast<u8>(flag)) != 0;
}
class QueueEntry {
public:
constexpr QueueEntry() = default;
@ -511,10 +530,12 @@ public:
void SetInExceptionHandler() {
this->GetStackParameters().is_in_exception_handler = true;
SetExceptionFlag(ExceptionFlag::InExceptionHandler);
}
void ClearInExceptionHandler() {
this->GetStackParameters().is_in_exception_handler = false;
ClearExceptionFlag(ExceptionFlag::InExceptionHandler);
}
bool IsInExceptionHandler() const {
@ -523,10 +544,12 @@ public:
void SetIsCallingSvc() {
this->GetStackParameters().is_calling_svc = true;
SetExceptionFlag(ExceptionFlag::IsCallingSvc);
}
void ClearIsCallingSvc() {
this->GetStackParameters().is_calling_svc = false;
ClearExceptionFlag(ExceptionFlag::IsCallingSvc);
}
bool IsCallingSvc() const {

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -34,7 +37,8 @@ Result ClearEvent(Core::System& system, Handle event_handle) {
{
KScopedAutoObject event = handle_table.GetObject<KEvent>(event_handle);
if (event.IsNotNull()) {
R_RETURN(event->Clear());
event->Clear();
R_SUCCEED();
}
}
@ -42,7 +46,8 @@ Result ClearEvent(Core::System& system, Handle event_handle) {
{
KScopedAutoObject readable_event = handle_table.GetObject<KReadableEvent>(event_handle);
if (readable_event.IsNotNull()) {
R_RETURN(readable_event->Clear());
readable_event->Clear();
R_SUCCEED();
}
}