pm: fix critical bugs where 1.0(?) titles not in the list have scheduling mode misconfigured

Also fix the comments.
Thanks @fincs
This commit is contained in:
TuxSH 2020-06-26 00:58:29 +01:00
parent 3a0418e279
commit 4e12453fff

View File

@ -4,6 +4,9 @@
#include "manager.h" #include "manager.h"
#include "luma.h" #include "luma.h"
#define CPUTIME_MULTI_MASK BIT(7)
#define CPUTIME_SINGLE_MASK 0
typedef s64 ReslimitValues[10]; typedef s64 ReslimitValues[10];
static const ResourceLimitType g_reslimitInitOrder[10] = { static const ResourceLimitType g_reslimitInitOrder[10] = {
@ -189,20 +192,23 @@ static ReslimitValues g_n3dsReslimitValues[4] = {
Both modes pause threads they don't want to run in thread selection, and unpause them when needed. Both modes pause threads they don't want to run in thread selection, and unpause them when needed.
If the threads that are intended to be paused is running an SVC, the pause will happen *after* SVC return. If the threads that are intended to be paused is running an SVC, the pause will happen *after* SVC return.
Mode0 (unsure) Mode0 "multi"
Starting by "sysmodule" threads, alternatively allow (if preemptible) only sysmodule threads, Starting by "sysmodule" threads, alternatively allow (if preemptible) only sysmodule threads,
and then only application threads to run. and then only application threads to run.
The latter has an exception; if "sysmodule" threads have run for less than 2usec, they The latter has an exception; if "sysmodule" threads have run for less than 8usec (value is a kernel bug), they
are unpaused an allowed to run instead. are unpaused an allowed to run instead.
This happens at a rate of 1ms * (cpuTime/100). This happens at a rate of 2ms * (cpuTime/100).
Mode1
Mode1 "single"
This mode is half-broken due to a kernel bug (when "current thread" is the priority 0 kernel thread).
When this mode is enabled, only one application thread is allowed to be created on core1. When this mode is enabled, only one application thread is allowed to be created on core1.
This divides the core1 time into slices of 12.5ms. This divides the core1 time into slices of 25ms.
The "application" thread is given cpuTime% of the slice. The "application" thread is given cpuTime% of the slice.
The "sysmodules" threads are given a total of (90 - cpuTime)% of the slice. The "sysmodules" threads are given a total of (90 - cpuTime)% of the slice.
@ -318,22 +324,23 @@ void setAppCpuTimeLimitAndSchedModeFromDescriptor(u64 titleId, u16 descriptor)
- app has a non-0 cputime descriptor in exhdr: maximum core1 cputime reslimit and scheduling - app has a non-0 cputime descriptor in exhdr: maximum core1 cputime reslimit and scheduling
mode are set according to it. Current reslimit is set to 0. SetAppResourceLimit *is* needed mode are set according to it. Current reslimit is set to 0. SetAppResourceLimit *is* needed
to use core1. to use core1.
- app has a 0 cputime descriptor: maximum is set to 80. - app has a 0 cputime descriptor: maximum is set to 80, scheduling mode to "single" (broken).
Current reslimit is set to 0, and SetAppResourceLimit *is* needed Current reslimit is set to 0, and SetAppResourceLimit *is* also needed
to use core1, **EXCEPT** for an hardcoded set of titles. to use core1, **EXCEPT** for an hardcoded set of titles.
*/ */
u8 cpuTime = (u8)descriptor; u8 cpuTime = (u8)descriptor;
assertSuccess(setAppCpuTimeLimit(0)); // remove preemption first. assertSuccess(setAppCpuTimeLimit(0)); // remove preemption first.
g_manager.cpuTimeBase = 0; g_manager.cpuTimeBase = 0;
u32 currentValueToSet = g_manager.cpuTimeBase; // 0
if (cpuTime != 0) { if (cpuTime == 0) {
// Set core1 scheduling mode // 2.0 apps have this exheader field correctly filled, very often to 0x9E (1.0 titles don't).
g_manager.maxAppCpuTime = cpuTime & 0x7F;
assertSuccess(svcKernelSetState(6, 3, (cpuTime & 0x80) ? 0LL : 1LL));
} else {
u32 titleUid = ((u32)titleId >> 8) & 0xFFFFF; u32 titleUid = ((u32)titleId >> 8) & 0xFFFFF;
g_manager.maxAppCpuTime = 80;
// Default setting is 80% max "single", with a current value of 0
cpuTime = CPUTIME_SINGLE_MASK | 80;
static const u32 numOverrides = sizeof(g_startCpuTimeOverrides) / sizeof(g_startCpuTimeOverrides[0]); static const u32 numOverrides = sizeof(g_startCpuTimeOverrides) / sizeof(g_startCpuTimeOverrides[0]);
if (titleUid >= g_startCpuTimeOverrides[0].titleUid && titleUid <= g_startCpuTimeOverrides[numOverrides - 1].titleUid) { if (titleUid >= g_startCpuTimeOverrides[0].titleUid && titleUid <= g_startCpuTimeOverrides[numOverrides - 1].titleUid) {
@ -341,15 +348,26 @@ void setAppCpuTimeLimitAndSchedModeFromDescriptor(u64 titleId, u16 descriptor)
for (u32 i = 0; i < numOverrides && titleUid < g_startCpuTimeOverrides[i].titleUid; i++); for (u32 i = 0; i < numOverrides && titleUid < g_startCpuTimeOverrides[i].titleUid; i++);
if (i < numOverrides) { if (i < numOverrides) {
if (g_startCpuTimeOverrides[i].value > 100 && g_startCpuTimeOverrides[i].value < 200) { if (g_startCpuTimeOverrides[i].value > 100 && g_startCpuTimeOverrides[i].value < 200) {
assertSuccess(svcKernelSetState(6, 3, 0LL)); cpuTime = CPUTIME_MULTI_MASK | 80; // "multi", max 80%
assertSuccess(setAppCpuTimeLimit(g_startCpuTimeOverrides[i].value - 100)); currentValueToSet = g_startCpuTimeOverrides[i].value - 100;
} else { } else {
assertSuccess(svcKernelSetState(6, 3, 1LL)); cpuTime = CPUTIME_SINGLE_MASK | 80; // "single", max 80%
assertSuccess(setAppCpuTimeLimit(g_startCpuTimeOverrides[i].value)); currentValueToSet = g_startCpuTimeOverrides[i].value;
} }
} }
} }
} }
// Set core1 scheduling mode
assertSuccess(svcKernelSetState(6, 3, (cpuTime & CPUTIME_MULTI_MASK) ? 0LL : 1LL));
// Set max value (limit)
g_manager.maxAppCpuTime = cpuTime & 0x7F;
// Set current value (for 1.0 apps)
if (currentValueToSet != 0) {
assertSuccess(setAppCpuTimeLimit(currentValueToSet));
}
} }
Result SetAppResourceLimit(u32 mbz, ResourceLimitType category, u32 value, u64 mbz2) Result SetAppResourceLimit(u32 mbz, ResourceLimitType category, u32 value, u64 mbz2)