aboutsummaryrefslogtreecommitdiff
path: root/src/core/hle
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle')
-rw-r--r--src/core/hle/ipc_helpers.h19
-rw-r--r--src/core/hle/kernel/scheduler.cpp3
-rw-r--r--src/core/hle/kernel/thread.cpp1
-rw-r--r--src/core/hle/kernel/thread.h9
-rw-r--r--src/core/hle/service/apm/interface.cpp17
5 files changed, 48 insertions, 1 deletions
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h
index 24605a273..8b5b06f31 100644
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/ipc_helpers.h
@@ -175,6 +175,25 @@ public:
void Push(const First& first_value, const Other&... other_values);
/**
+ * Helper function for pushing strongly-typed enumeration values.
+ *
+ * @tparam Enum The enumeration type to be pushed
+ *
+ * @param value The value to push.
+ *
+ * @note The underlying size of the enumeration type is the size of the
+ * data that gets pushed. e.g. "enum class SomeEnum : u16" will
+ * push a u16-sized amount of data.
+ */
+ template <typename Enum>
+ void PushEnum(Enum value) {
+ static_assert(std::is_enum_v<Enum>, "T must be an enum type within a PushEnum call.");
+ static_assert(!std::is_convertible_v<Enum, int>,
+ "enum type in PushEnum must be a strongly typed enum.");
+ Push(static_cast<std::underlying_type_t<Enum>>(value));
+ }
+
+ /**
* @brief Copies the content of the given trivially copyable class to the buffer as a normal
* param
* @note: The input class must be correctly packed/padded to fit hardware layout.
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index f7e25cbf5..e307eec98 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -56,6 +56,8 @@ void Scheduler::SwitchContext(Thread* new_thread) {
if (previous_thread) {
previous_thread->last_running_ticks = CoreTiming::GetTicks();
cpu_core->SaveContext(previous_thread->context);
+ // Save the TPIDR_EL0 system register in case it was modified.
+ previous_thread->tpidr_el0 = cpu_core->GetTPIDR_EL0();
if (previous_thread->status == ThreadStatus::Running) {
// This is only the case when a reschedule is triggered without the current thread
@@ -87,6 +89,7 @@ void Scheduler::SwitchContext(Thread* new_thread) {
cpu_core->LoadContext(new_thread->context);
cpu_core->SetTlsAddress(new_thread->GetTLSAddress());
+ cpu_core->SetTPIDR_EL0(new_thread->GetTPIDR_EL0());
cpu_core->ClearExclusiveState();
} else {
current_thread = nullptr;
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 53f2e861e..cd85c4b7c 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -312,6 +312,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
thread->status = ThreadStatus::Dormant;
thread->entry_point = entry_point;
thread->stack_top = stack_top;
+ thread->tpidr_el0 = 0;
thread->nominal_priority = thread->current_priority = priority;
thread->last_running_ticks = CoreTiming::GetTicks();
thread->processor_id = processor_id;
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 47881ec20..6218960d2 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -183,6 +183,14 @@ public:
}
/*
+ * Returns the value of the TPIDR_EL0 Read/Write system register for this thread.
+ * @returns The value of the TPIDR_EL0 register.
+ */
+ u64 GetTPIDR_EL0() const {
+ return tpidr_el0;
+ }
+
+ /*
* Returns the address of the current thread's command buffer, located in the TLS.
* @returns VAddr of the thread's command buffer.
*/
@@ -213,6 +221,7 @@ public:
s32 processor_id;
VAddr tls_address; ///< Virtual address of the Thread Local Storage of the thread
+ u64 tpidr_el0; ///< TPIDR_EL0 read/write system register.
SharedPtr<Process> owner_process; ///< Process that owns this thread
diff --git a/src/core/hle/service/apm/interface.cpp b/src/core/hle/service/apm/interface.cpp
index 751d73f8d..ce943d829 100644
--- a/src/core/hle/service/apm/interface.cpp
+++ b/src/core/hle/service/apm/interface.cpp
@@ -20,6 +20,21 @@ public:
}
private:
+ enum class PerformanceConfiguration : u32 {
+ Config1 = 0x00010000,
+ Config2 = 0x00010001,
+ Config3 = 0x00010002,
+ Config4 = 0x00020000,
+ Config5 = 0x00020001,
+ Config6 = 0x00020002,
+ Config7 = 0x00020003,
+ Config8 = 0x00020004,
+ Config9 = 0x00020005,
+ Config10 = 0x00020006,
+ Config11 = 0x92220007,
+ Config12 = 0x92220008,
+ };
+
void SetPerformanceConfiguration(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
@@ -40,7 +55,7 @@ private:
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
- rb.Push<u32>(0); // Performance configuration
+ rb.Push<u32>(static_cast<u32>(PerformanceConfiguration::Config1));
LOG_WARNING(Service_APM, "(STUBBED) called mode={}", static_cast<u32>(mode));
}