mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-06-02 23:59:49 -04:00
os: refactor/rewrite entire namespace.
This commit is contained in:
parent
6193283f03
commit
065485b971
181 changed files with 5353 additions and 1929 deletions
|
@ -20,7 +20,7 @@ namespace ams::mitm {
|
|||
|
||||
namespace {
|
||||
|
||||
os::Mutex g_throw_lock;
|
||||
os::Mutex g_throw_lock(false);
|
||||
bool g_threw;
|
||||
Result g_throw_result;
|
||||
|
||||
|
@ -28,12 +28,14 @@ namespace ams::mitm {
|
|||
void DebugThrowThreadFunc(void *arg);
|
||||
|
||||
constexpr size_t DebugThrowThreadStackSize = 0x4000;
|
||||
constexpr int DebugThrowThreadPriority = 49;
|
||||
os::StaticThread<DebugThrowThreadStackSize> g_debug_throw_thread(&DebugThrowThreadFunc, nullptr, DebugThrowThreadPriority);
|
||||
constexpr int DebugThrowThreadPriority = 21;
|
||||
os::ThreadType g_debug_throw_thread;
|
||||
|
||||
alignas(os::ThreadStackAlignment) u8 g_debug_throw_thread_stack[DebugThrowThreadStackSize];
|
||||
|
||||
void DebugThrowThreadFunc(void *arg) {
|
||||
/* TODO: Better heuristic for fatal startup than sleep. */
|
||||
svcSleepThread(10'000'000'000ul);
|
||||
os::SleepThread(TimeSpan::FromSeconds(10));
|
||||
fatalThrow(g_throw_result.GetValue());
|
||||
}
|
||||
|
||||
|
@ -48,7 +50,8 @@ namespace ams::mitm {
|
|||
|
||||
g_throw_result = res;
|
||||
g_threw = true;
|
||||
R_ABORT_UNLESS(g_debug_throw_thread.Start());
|
||||
R_ABORT_UNLESS(os::CreateThread(std::addressof(g_debug_throw_thread), DebugThrowThreadFunc, nullptr, g_debug_throw_thread_stack, sizeof(g_debug_throw_thread_stack), DebugThrowThreadPriority));
|
||||
os::StartThread(std::addressof(g_debug_throw_thread));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -50,11 +50,13 @@ namespace ams::mitm {
|
|||
void InitializeThreadFunc(void *arg);
|
||||
|
||||
constexpr size_t InitializeThreadStackSize = 0x4000;
|
||||
constexpr int InitializeThreadPriority = 0x15;
|
||||
os::StaticThread<InitializeThreadStackSize> g_initialize_thread(&InitializeThreadFunc, nullptr, InitializeThreadPriority);
|
||||
constexpr int InitializeThreadPriority = -7;
|
||||
|
||||
/* Globals. */
|
||||
os::Event g_init_event(false);
|
||||
os::Event g_init_event(os::EventClearMode_ManualClear);
|
||||
|
||||
os::ThreadType g_initialize_thread;
|
||||
alignas(os::ThreadStackAlignment) u8 g_initialize_thread_stack[InitializeThreadStackSize];
|
||||
|
||||
/* Console-unique data backup and protection. */
|
||||
constexpr size_t CalibrationBinarySize = 0x8000;
|
||||
|
@ -221,7 +223,8 @@ namespace ams::mitm {
|
|||
}
|
||||
|
||||
void StartInitialize() {
|
||||
R_ABORT_UNLESS(g_initialize_thread.Start());
|
||||
R_ABORT_UNLESS(os::CreateThread(std::addressof(g_initialize_thread), InitializeThreadFunc, nullptr, g_initialize_thread_stack, sizeof(g_initialize_thread_stack), InitializeThreadPriority));
|
||||
os::StartThread(std::addressof(g_initialize_thread));
|
||||
}
|
||||
|
||||
bool IsInitialized() {
|
||||
|
|
|
@ -22,12 +22,12 @@ namespace ams::mitm {
|
|||
class ModuleBase {};
|
||||
|
||||
#define DEFINE_MITM_MODULE_CLASS(ss, prio) class MitmModule : public ::ams::mitm::ModuleBase { \
|
||||
public: \
|
||||
static constexpr size_t ThreadPriority = prio; \
|
||||
static constexpr size_t StackSize = ss; \
|
||||
alignas(os::MemoryPageSize) static inline u8 Stack[StackSize]; \
|
||||
public: \
|
||||
static void ThreadFunction(void *); \
|
||||
public: \
|
||||
static constexpr s32 ThreadPriority = prio; \
|
||||
static constexpr size_t StackSize = ss; \
|
||||
alignas(os::ThreadStackAlignment) static inline u8 Stack[StackSize]; \
|
||||
public: \
|
||||
static void ThreadFunction(void *); \
|
||||
}
|
||||
|
||||
template<class M>
|
||||
|
@ -37,7 +37,7 @@ namespace ams::mitm {
|
|||
static constexpr void *Stack = &M::Stack[0];
|
||||
static constexpr size_t StackSize = M::StackSize;
|
||||
|
||||
static constexpr size_t ThreadPriority = M::ThreadPriority;
|
||||
static constexpr s32 ThreadPriority = M::ThreadPriority;
|
||||
|
||||
static constexpr ::ThreadFunc ThreadFunction = &M::ThreadFunction;
|
||||
};
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace ams::mitm {
|
|||
struct ModuleDefinition {
|
||||
ThreadFunc main;
|
||||
void *stack_mem;
|
||||
u32 priority;
|
||||
s32 priority;
|
||||
u32 stack_size;
|
||||
};
|
||||
|
||||
|
@ -56,7 +56,7 @@ namespace ams::mitm {
|
|||
};
|
||||
}
|
||||
|
||||
ams::os::Thread g_module_threads[ModuleId_Count];
|
||||
ams::os::ThreadType g_module_threads[ModuleId_Count];
|
||||
|
||||
constexpr ModuleDefinition g_module_definitions[ModuleId_Count] = {
|
||||
GetModuleDefinition<fs::MitmModule>(),
|
||||
|
@ -72,19 +72,19 @@ namespace ams::mitm {
|
|||
/* Create thread for each module. */
|
||||
for (u32 i = 0; i < static_cast<u32>(ModuleId_Count); i++) {
|
||||
const ModuleDefinition &cur_module = g_module_definitions[i];
|
||||
R_ABORT_UNLESS(g_module_threads[i].Initialize(cur_module.main, nullptr, cur_module.stack_mem, cur_module.stack_size, cur_module.priority));
|
||||
R_ABORT_UNLESS(os::CreateThread(g_module_threads + i, cur_module.main, nullptr, cur_module.stack_mem, cur_module.stack_size, cur_module.priority));
|
||||
}
|
||||
|
||||
/* Start thread for each module. */
|
||||
for (u32 i = 0; i < static_cast<u32>(ModuleId_Count); i++) {
|
||||
R_ABORT_UNLESS(g_module_threads[i].Start());
|
||||
os::StartThread(g_module_threads + i);
|
||||
}
|
||||
}
|
||||
|
||||
void WaitAllModules() {
|
||||
/* Wait on thread for each module. */
|
||||
for (u32 i = 0; i < static_cast<u32>(ModuleId_Count); i++) {
|
||||
g_module_threads[i].Join();
|
||||
os::WaitThread(g_module_threads + i);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,6 @@
|
|||
|
||||
namespace ams::mitm::bpc {
|
||||
|
||||
DEFINE_MITM_MODULE_CLASS(0x8000, 32);
|
||||
DEFINE_MITM_MODULE_CLASS(0x8000, 4);
|
||||
|
||||
}
|
||||
|
|
|
@ -30,8 +30,8 @@ namespace ams::mitm::fs {
|
|||
constexpr const char AtmosphereHblWebContentDir[] = "/atmosphere/hbl_html/";
|
||||
constexpr const char ProgramWebContentDir[] = "/manual_html/";
|
||||
|
||||
os::Mutex g_data_storage_lock;
|
||||
os::Mutex g_storage_cache_lock;
|
||||
os::Mutex g_data_storage_lock(false);
|
||||
os::Mutex g_storage_cache_lock(false);
|
||||
std::unordered_map<u64, std::weak_ptr<IStorageInterface>> g_storage_cache;
|
||||
|
||||
std::shared_ptr<IStorageInterface> GetStorageCacheEntry(ncm::ProgramId program_id) {
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace ams::mitm::fs {
|
|||
|
||||
namespace {
|
||||
|
||||
os::Mutex g_boot0_access_mutex;
|
||||
os::Mutex g_boot0_access_mutex(false);
|
||||
u8 g_boot0_bct_buffer[Boot0Storage::BctEndOffset];
|
||||
|
||||
}
|
||||
|
|
|
@ -22,10 +22,11 @@ namespace ams::mitm::fs {
|
|||
|
||||
namespace {
|
||||
|
||||
os::Mutex g_mq_lock;
|
||||
os::Mutex g_mq_lock(false);
|
||||
bool g_started_req_thread;
|
||||
os::MessageQueue g_req_mq(1);
|
||||
os::MessageQueue g_ack_mq(1);
|
||||
uintptr_t g_mq_storage[2];
|
||||
os::MessageQueue g_req_mq(g_mq_storage + 0, 1);
|
||||
os::MessageQueue g_ack_mq(g_mq_storage + 1, 1);
|
||||
|
||||
void RomfsInitializerThreadFunction(void *arg) {
|
||||
while (true) {
|
||||
|
@ -38,14 +39,16 @@ namespace ams::mitm::fs {
|
|||
}
|
||||
|
||||
constexpr size_t RomfsInitializerThreadStackSize = 0x8000;
|
||||
constexpr int RomfsInitializerThreadPriority = 44;
|
||||
os::StaticThread<RomfsInitializerThreadStackSize> g_romfs_initializer_thread(&RomfsInitializerThreadFunction, nullptr, RomfsInitializerThreadPriority);
|
||||
constexpr int RomfsInitializerThreadPriority = 16;
|
||||
os::ThreadType g_romfs_initializer_thread;
|
||||
alignas(os::ThreadStackAlignment) u8 g_romfs_initializer_thread_stack[RomfsInitializerThreadStackSize];
|
||||
|
||||
void RequestInitializeStorage(uintptr_t storage_uptr) {
|
||||
std::scoped_lock lk(g_mq_lock);
|
||||
|
||||
if (!g_started_req_thread) {
|
||||
R_ABORT_UNLESS(g_romfs_initializer_thread.Start());
|
||||
if (AMS_UNLIKELY(!g_started_req_thread)) {
|
||||
R_ABORT_UNLESS(os::CreateThread(std::addressof(g_romfs_initializer_thread), RomfsInitializerThreadFunction, nullptr, g_romfs_initializer_thread_stack, sizeof(g_romfs_initializer_thread_stack), RomfsInitializerThreadPriority));
|
||||
os::StartThread(std::addressof(g_romfs_initializer_thread));
|
||||
g_started_req_thread = true;
|
||||
}
|
||||
|
||||
|
@ -59,7 +62,7 @@ namespace ams::mitm::fs {
|
|||
|
||||
using namespace ams::fs;
|
||||
|
||||
LayeredRomfsStorage::LayeredRomfsStorage(std::unique_ptr<IStorage> s_r, std::unique_ptr<IStorage> f_r, ncm::ProgramId pr_id) : storage_romfs(std::move(s_r)), file_romfs(std::move(f_r)), initialize_event(false, false), program_id(std::move(pr_id)), is_initialized(false), started_initialize(false) {
|
||||
LayeredRomfsStorage::LayeredRomfsStorage(std::unique_ptr<IStorage> s_r, std::unique_ptr<IStorage> f_r, ncm::ProgramId pr_id) : storage_romfs(std::move(s_r)), file_romfs(std::move(f_r)), initialize_event(os::EventClearMode_ManualClear), program_id(std::move(pr_id)), is_initialized(false), started_initialize(false) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace ams::mitm::fs {
|
|||
constexpr size_t ThreadStackSize = mitm::ModuleTraits<fs::MitmModule>::StackSize;
|
||||
alignas(os::MemoryPageSize) u8 g_extra_thread_stacks[NumExtraThreads][ThreadStackSize];
|
||||
|
||||
os::Thread g_extra_threads[NumExtraThreads];
|
||||
os::ThreadType g_extra_threads[NumExtraThreads];
|
||||
|
||||
void LoopServerThread(void *arg) {
|
||||
/* Loop forever, servicing our services. */
|
||||
|
@ -49,16 +49,16 @@ namespace ams::mitm::fs {
|
|||
void ProcessForServerOnAllThreads() {
|
||||
/* Initialize threads. */
|
||||
if constexpr (NumExtraThreads > 0) {
|
||||
const s32 priority = os::GetCurrentThreadPriority();
|
||||
const s32 priority = os::GetThreadCurrentPriority(os::GetCurrentThread());
|
||||
for (size_t i = 0; i < NumExtraThreads; i++) {
|
||||
R_ABORT_UNLESS(g_extra_threads[i].Initialize(LoopServerThread, nullptr, g_extra_thread_stacks[i], ThreadStackSize, priority));
|
||||
R_ABORT_UNLESS(os::CreateThread(g_extra_threads + i, LoopServerThread, nullptr, g_extra_thread_stacks[i], ThreadStackSize, priority));
|
||||
}
|
||||
}
|
||||
|
||||
/* Start extra threads. */
|
||||
if constexpr (NumExtraThreads > 0) {
|
||||
for (size_t i = 0; i < NumExtraThreads; i++) {
|
||||
R_ABORT_UNLESS(g_extra_threads[i].Start());
|
||||
os::StartThread(g_extra_threads + i);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@ namespace ams::mitm::fs {
|
|||
/* Wait for extra threads to finish. */
|
||||
if constexpr (NumExtraThreads > 0) {
|
||||
for (size_t i = 0; i < NumExtraThreads; i++) {
|
||||
R_ABORT_UNLESS(g_extra_threads[i].Join());
|
||||
os::WaitThread(g_extra_threads + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,6 @@
|
|||
|
||||
namespace ams::mitm::fs {
|
||||
|
||||
DEFINE_MITM_MODULE_CLASS(0x8000, 43);
|
||||
DEFINE_MITM_MODULE_CLASS(0x8000, 15);
|
||||
|
||||
}
|
||||
|
|
|
@ -257,7 +257,7 @@ namespace ams::mitm::fs {
|
|||
}
|
||||
}
|
||||
|
||||
os::Mutex g_fs_romfs_path_lock;
|
||||
os::Mutex g_fs_romfs_path_lock(false);
|
||||
char g_fs_romfs_path_buffer[fs::EntryNameLengthMax + 1];
|
||||
|
||||
NOINLINE void OpenFileSystemRomfsDirectory(FsDir *out, ncm::ProgramId program_id, BuildDirectoryContext *parent, fs::OpenDirectoryMode mode, FsFileSystem *fs) {
|
||||
|
|
|
@ -19,6 +19,6 @@
|
|||
|
||||
namespace ams::mitm::hid {
|
||||
|
||||
DEFINE_MITM_MODULE_CLASS(0x8000, 47);
|
||||
DEFINE_MITM_MODULE_CLASS(0x8000, 19);
|
||||
|
||||
}
|
||||
|
|
|
@ -19,6 +19,6 @@
|
|||
|
||||
namespace ams::mitm::ns {
|
||||
|
||||
DEFINE_MITM_MODULE_CLASS(0x4000, 48);
|
||||
DEFINE_MITM_MODULE_CLASS(0x4000, 20);
|
||||
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace ams::mitm::settings {
|
|||
GetRegionCode = 4,
|
||||
};
|
||||
private:
|
||||
os::Mutex lock;
|
||||
os::Mutex lock{false};
|
||||
cfg::OverrideLocale locale;
|
||||
bool got_locale;
|
||||
public:
|
||||
|
|
|
@ -19,6 +19,6 @@
|
|||
|
||||
namespace ams::mitm::settings {
|
||||
|
||||
DEFINE_MITM_MODULE_CLASS(0x8000, 43);
|
||||
DEFINE_MITM_MODULE_CLASS(0x8000, 20);
|
||||
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace ams::mitm::settings {
|
|||
|
||||
namespace {
|
||||
|
||||
os::Mutex g_firmware_version_lock;
|
||||
os::Mutex g_firmware_version_lock(false);
|
||||
bool g_cached_firmware_version;
|
||||
settings::FirmwareVersion g_firmware_version;
|
||||
settings::FirmwareVersion g_ams_firmware_version;
|
||||
|
@ -30,7 +30,7 @@ namespace ams::mitm::settings {
|
|||
void CacheFirmwareVersion() {
|
||||
std::scoped_lock lk(g_firmware_version_lock);
|
||||
|
||||
if (g_cached_firmware_version) {
|
||||
if (AMS_LIKELY(g_cached_firmware_version)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -56,6 +56,10 @@ namespace ams::boot {
|
|||
constexpr size_t ApbMiscSize = os::MemoryPageSize;
|
||||
constexpr size_t MipiCalSize = os::MemoryPageSize;
|
||||
|
||||
constexpr s32 DsiWaitForCommandMilliSecondsMax = 250;
|
||||
constexpr s32 DsiWaitForCommandCompletionMilliSeconds = 5;
|
||||
constexpr s32 DsiWaitForHostControlMilliSecondsMax = 150;
|
||||
|
||||
/* Types. */
|
||||
|
||||
/* Globals. */
|
||||
|
@ -151,10 +155,10 @@ namespace ams::boot {
|
|||
}
|
||||
|
||||
void WaitDsiTrigger() {
|
||||
os::TimeoutHelper timeout_helper(250'000'000ul);
|
||||
os::Tick timeout = os::GetSystemTick() + os::ConvertToTick(TimeSpan::FromMilliSeconds(DsiWaitForCommandMilliSecondsMax));
|
||||
|
||||
while (true) {
|
||||
if (timeout_helper.TimedOut()) {
|
||||
if (os::GetSystemTick() >= timeout) {
|
||||
break;
|
||||
}
|
||||
if (reg::Read(g_dsi_regs + sizeof(u32) * DSI_TRIGGER) == 0) {
|
||||
|
@ -162,14 +166,14 @@ namespace ams::boot {
|
|||
}
|
||||
}
|
||||
|
||||
svcSleepThread(5'000'000ul);
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(DsiWaitForCommandCompletionMilliSeconds));
|
||||
}
|
||||
|
||||
void WaitDsiHostControl() {
|
||||
os::TimeoutHelper timeout_helper(150'000'000ul);
|
||||
os::Tick timeout = os::GetSystemTick() + os::ConvertToTick(TimeSpan::FromMilliSeconds(DsiWaitForHostControlMilliSecondsMax));
|
||||
|
||||
while (true) {
|
||||
if (timeout_helper.TimedOut()) {
|
||||
if (os::GetSystemTick() >= timeout) {
|
||||
break;
|
||||
}
|
||||
if ((reg::Read(g_dsi_regs + sizeof(u32) * DSI_HOST_CONTROL) & DSI_HOST_CONTROL_IMM_BTA) == 0) {
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace ams::i2c::driver::impl {
|
|||
}
|
||||
|
||||
/* Close interrupt event. */
|
||||
this->interrupt_event.Finalize();
|
||||
os::FinalizeInterruptEvent(std::addressof(this->interrupt_event));
|
||||
|
||||
/* Close PCV. */
|
||||
pcv::Finalize();
|
||||
|
@ -152,10 +152,10 @@ namespace ams::i2c::driver::impl {
|
|||
break;
|
||||
}
|
||||
|
||||
this->interrupt_event.Reset();
|
||||
if (!this->interrupt_event.TimedWait(InterruptTimeout)) {
|
||||
os::ClearInterruptEvent(std::addressof(this->interrupt_event));
|
||||
if (!os::TimedWaitInterruptEvent(std::addressof(this->interrupt_event), InterruptTimeout)) {
|
||||
this->HandleTransactionResult(i2c::ResultBusBusy());
|
||||
this->interrupt_event.Reset();
|
||||
os::ClearInterruptEvent(std::addressof(this->interrupt_event));
|
||||
return i2c::ResultTimedOut();
|
||||
}
|
||||
|
||||
|
@ -175,10 +175,10 @@ namespace ams::i2c::driver::impl {
|
|||
break;
|
||||
}
|
||||
|
||||
this->interrupt_event.Reset();
|
||||
if (!this->interrupt_event.TimedWait(InterruptTimeout)) {
|
||||
os::ClearInterruptEvent(std::addressof(this->interrupt_event));
|
||||
if (!os::TimedWaitInterruptEvent(std::addressof(this->interrupt_event), InterruptTimeout)) {
|
||||
this->HandleTransactionResult(i2c::ResultBusBusy());
|
||||
this->interrupt_event.Reset();
|
||||
os::ClearInterruptEvent(std::addressof(this->interrupt_event));
|
||||
return i2c::ResultTimedOut();
|
||||
}
|
||||
}
|
||||
|
@ -200,11 +200,11 @@ namespace ams::i2c::driver::impl {
|
|||
|
||||
/* Receive bytes. */
|
||||
while (remaining > 0) {
|
||||
this->interrupt_event.Reset();
|
||||
if (!this->interrupt_event.TimedWait(InterruptTimeout)) {
|
||||
os::ClearInterruptEvent(std::addressof(this->interrupt_event));
|
||||
if (!os::TimedWaitInterruptEvent(std::addressof(this->interrupt_event), InterruptTimeout)) {
|
||||
this->HandleTransactionResult(i2c::ResultBusBusy());
|
||||
this->ClearInterruptMask();
|
||||
this->interrupt_event.Reset();
|
||||
os::ClearInterruptEvent(std::addressof(this->interrupt_event));
|
||||
return i2c::ResultTimedOut();
|
||||
}
|
||||
|
||||
|
@ -241,7 +241,8 @@ namespace ams::i2c::driver::impl {
|
|||
};
|
||||
const auto index = ConvertToIndex(bus);
|
||||
AMS_ABORT_UNLESS(index < util::size(s_interrupts));
|
||||
R_ABORT_UNLESS(this->interrupt_event.Initialize(s_interrupts[index], false));
|
||||
os::InitializeInterruptEvent(std::addressof(this->interrupt_event), s_interrupts[index], os::EventClearMode_ManualClear);
|
||||
os::ClearInterruptEvent(std::addressof(this->interrupt_event));
|
||||
}
|
||||
|
||||
void BusAccessor::SetClock(SpeedMode speed_mode) {
|
||||
|
@ -423,7 +424,7 @@ namespace ams::i2c::driver::impl {
|
|||
|
||||
this->HandleTransactionResult(transaction_result);
|
||||
this->ClearInterruptMask();
|
||||
this->interrupt_event.Reset();
|
||||
os::ClearInterruptEvent(std::addressof(this->interrupt_event));
|
||||
return transaction_result;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,9 +25,9 @@ namespace ams::i2c::driver::impl {
|
|||
Send = 0,
|
||||
Receive = 1,
|
||||
};
|
||||
static constexpr u64 InterruptTimeout = 100'000'000ul;
|
||||
static constexpr TimeSpan InterruptTimeout = TimeSpan::FromMilliSeconds(100);
|
||||
private:
|
||||
os::InterruptEvent interrupt_event;
|
||||
os::InterruptEventType interrupt_event;
|
||||
os::Mutex open_mutex;
|
||||
os::Mutex register_mutex;
|
||||
Registers *i2c_registers = nullptr;
|
||||
|
@ -38,7 +38,7 @@ namespace ams::i2c::driver::impl {
|
|||
PcvModule pcv_module = PcvModule_I2C1;
|
||||
bool suspended = false;
|
||||
public:
|
||||
BusAccessor() { /* ... */ }
|
||||
BusAccessor() : open_mutex(false), register_mutex(false) { /* ... */ }
|
||||
private:
|
||||
inline void ClearInterruptMask() const {
|
||||
reg::Write(&i2c_registers->I2C_INTERRUPT_MASK_REGISTER_0, 0);
|
||||
|
|
|
@ -34,10 +34,18 @@ namespace ams::i2c::driver::impl {
|
|||
bool power_bus_suspended = false;
|
||||
Session sessions[MaxDriverSessions];
|
||||
BusAccessor bus_accessors[ConvertToIndex(Bus::Count)];
|
||||
os::Mutex transaction_mutexes[ConvertToIndex(Bus::Count)];
|
||||
TYPED_STORAGE(os::Mutex) transaction_mutexes[ConvertToIndex(Bus::Count)];
|
||||
public:
|
||||
ResourceManager() {
|
||||
/* ... */
|
||||
ResourceManager() : initialize_mutex(false), session_open_mutex(false) {
|
||||
for (size_t i = 0; i < util::size(this->transaction_mutexes); i++) {
|
||||
new (GetPointer(this->transaction_mutexes[i])) os::Mutex(false);
|
||||
}
|
||||
}
|
||||
|
||||
~ResourceManager() {
|
||||
for (size_t i = 0; i < util::size(this->transaction_mutexes); i++) {
|
||||
GetReference(this->transaction_mutexes[i]).~Mutex();
|
||||
}
|
||||
}
|
||||
private:
|
||||
size_t GetFreeSessionId() const;
|
||||
|
@ -57,7 +65,7 @@ namespace ams::i2c::driver::impl {
|
|||
}
|
||||
|
||||
os::Mutex& GetTransactionMutex(Bus bus) {
|
||||
return this->transaction_mutexes[ConvertToIndex(bus)];
|
||||
return GetReference(this->transaction_mutexes[ConvertToIndex(bus)]);
|
||||
}
|
||||
|
||||
void Initialize();
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace ams::i2c::driver::impl {
|
|||
u64 retry_wait_time = 0;
|
||||
bool open = false;
|
||||
public:
|
||||
Session() { /* ... */ }
|
||||
Session() : bus_accessor_mutex(false) { /* ... */ }
|
||||
public:
|
||||
void Open(Bus bus, u32 slave_address, AddressingMode addr_mode, SpeedMode speed_mode, BusAccessor *bus_accessor, u32 max_retries, u64 retry_wait_time);
|
||||
void Start();
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace ams::creport {
|
|||
/* Convenience definitions. */
|
||||
constexpr size_t MaximumLineLength = 0x20;
|
||||
|
||||
os::Mutex g_format_lock;
|
||||
os::Mutex g_format_lock(false);
|
||||
char g_format_buffer[2 * os::MemoryPageSize];
|
||||
|
||||
}
|
||||
|
|
|
@ -29,18 +29,18 @@ namespace ams::dmnt::cheat::impl {
|
|||
class CheatProcessManager {
|
||||
private:
|
||||
static constexpr size_t ThreadStackSize = 0x4000;
|
||||
static constexpr int DetectThreadPriority = 39;
|
||||
static constexpr int VirtualMachineThreadPriority = 48;
|
||||
static constexpr int DebugEventsThreadPriority = 24;
|
||||
static constexpr s32 DetectThreadPriority = 11;
|
||||
static constexpr s32 VirtualMachineThreadPriority = 20;
|
||||
static constexpr s32 DebugEventsThreadPriority = -1;
|
||||
private:
|
||||
os::Mutex cheat_lock;
|
||||
os::Event debug_events_event; /* Autoclear. */
|
||||
os::Thread detect_thread, debug_events_thread;
|
||||
os::ThreadType detect_thread, debug_events_thread;
|
||||
os::SystemEvent cheat_process_event;
|
||||
Handle cheat_process_debug_handle = INVALID_HANDLE;
|
||||
Handle cheat_process_debug_handle = svc::InvalidHandle;
|
||||
CheatProcessMetadata cheat_process_metadata = {};
|
||||
|
||||
os::Thread vm_thread;
|
||||
os::ThreadType vm_thread;
|
||||
bool needs_reload_vm = false;
|
||||
CheatVirtualMachine cheat_vm;
|
||||
|
||||
|
@ -121,13 +121,13 @@ namespace ams::dmnt::cheat::impl {
|
|||
}
|
||||
|
||||
void CloseActiveCheatProcess() {
|
||||
if (this->cheat_process_debug_handle != INVALID_HANDLE) {
|
||||
if (this->cheat_process_debug_handle != svc::InvalidHandle) {
|
||||
/* Knock out the debug events thread. */
|
||||
R_ABORT_UNLESS(this->debug_events_thread.CancelSynchronization());
|
||||
os::CancelThreadSynchronization(std::addressof(this->debug_events_thread));
|
||||
|
||||
/* Close resources. */
|
||||
R_ABORT_UNLESS(svcCloseHandle(this->cheat_process_debug_handle));
|
||||
this->cheat_process_debug_handle = INVALID_HANDLE;
|
||||
R_ABORT_UNLESS(svc::CloseHandle(this->cheat_process_debug_handle));
|
||||
this->cheat_process_debug_handle = svc::InvalidHandle;
|
||||
|
||||
/* Save cheat toggles. */
|
||||
if (this->always_save_cheat_toggles || this->should_save_cheat_toggles) {
|
||||
|
@ -153,7 +153,7 @@ namespace ams::dmnt::cheat::impl {
|
|||
bool HasActiveCheatProcess() {
|
||||
/* Note: This function *MUST* be called only with the cheat lock held. */
|
||||
os::ProcessId pid;
|
||||
bool has_cheat_process = this->cheat_process_debug_handle != INVALID_HANDLE;
|
||||
bool has_cheat_process = this->cheat_process_debug_handle != svc::InvalidHandle;
|
||||
has_cheat_process &= R_SUCCEEDED(os::TryGetProcessId(&pid, this->cheat_process_debug_handle));
|
||||
has_cheat_process &= R_SUCCEEDED(pm::dmnt::GetApplicationProcessId(&pid));
|
||||
has_cheat_process &= (pid == this->cheat_process_metadata.process_id);
|
||||
|
@ -175,7 +175,7 @@ namespace ams::dmnt::cheat::impl {
|
|||
}
|
||||
|
||||
Handle HookToCreateApplicationProcess() const {
|
||||
Handle h = INVALID_HANDLE;
|
||||
Handle h = svc::InvalidHandle;
|
||||
R_ABORT_UNLESS(pm::dmnt::HookToCreateApplicationProcess(&h));
|
||||
return h;
|
||||
}
|
||||
|
@ -185,10 +185,7 @@ namespace ams::dmnt::cheat::impl {
|
|||
}
|
||||
|
||||
public:
|
||||
CheatProcessManager() {
|
||||
/* Create cheat process detection event. */
|
||||
R_ABORT_UNLESS(this->cheat_process_event.InitializeAsInterProcessEvent());
|
||||
|
||||
CheatProcessManager() : cheat_lock(false), debug_events_event(os::EventClearMode_AutoClear), cheat_process_event(os::EventClearMode_AutoClear, true) {
|
||||
/* Learn whether we should enable cheats by default. */
|
||||
{
|
||||
u8 en = 0;
|
||||
|
@ -203,14 +200,14 @@ namespace ams::dmnt::cheat::impl {
|
|||
}
|
||||
|
||||
/* Spawn application detection thread, spawn cheat vm thread. */
|
||||
R_ABORT_UNLESS(this->detect_thread.Initialize(&CheatProcessManager::DetectLaunchThread, this, this->detect_thread_stack, ThreadStackSize, DetectThreadPriority));
|
||||
R_ABORT_UNLESS(this->vm_thread.Initialize(&CheatProcessManager::VirtualMachineThread, this, this->vm_thread_stack, ThreadStackSize, VirtualMachineThreadPriority));
|
||||
R_ABORT_UNLESS(this->debug_events_thread.Initialize(&CheatProcessManager::DebugEventsThread, this, this->debug_events_thread_stack, ThreadStackSize, DebugEventsThreadPriority));
|
||||
R_ABORT_UNLESS(os::CreateThread(std::addressof(this->detect_thread), DetectLaunchThread, this, this->detect_thread_stack, ThreadStackSize, DetectThreadPriority));
|
||||
R_ABORT_UNLESS(os::CreateThread(std::addressof(this->vm_thread), VirtualMachineThread, this, this->vm_thread_stack, ThreadStackSize, VirtualMachineThreadPriority));
|
||||
R_ABORT_UNLESS(os::CreateThread(std::addressof(this->debug_events_thread), DebugEventsThread, this, this->debug_events_thread_stack, ThreadStackSize, DebugEventsThreadPriority));
|
||||
|
||||
/* Start threads. */
|
||||
R_ABORT_UNLESS(this->detect_thread.Start());
|
||||
R_ABORT_UNLESS(this->vm_thread.Start());
|
||||
R_ABORT_UNLESS(this->debug_events_thread.Start());
|
||||
os::StartThread(std::addressof(this->detect_thread));
|
||||
os::StartThread(std::addressof(this->vm_thread));
|
||||
os::StartThread(std::addressof(this->debug_events_thread));
|
||||
}
|
||||
|
||||
bool GetHasActiveCheatProcess() {
|
||||
|
@ -620,10 +617,10 @@ namespace ams::dmnt::cheat::impl {
|
|||
|
||||
/* Get process handle, use it to learn memory extents. */
|
||||
{
|
||||
Handle proc_h = INVALID_HANDLE;
|
||||
Handle proc_h = svc::InvalidHandle;
|
||||
ncm::ProgramLocation loc = {};
|
||||
cfg::OverrideStatus status = {};
|
||||
ON_SCOPE_EXIT { if (proc_h != INVALID_HANDLE) { R_ABORT_UNLESS(svcCloseHandle(proc_h)); } };
|
||||
ON_SCOPE_EXIT { if (proc_h != svc::InvalidHandle) { R_ABORT_UNLESS(svcCloseHandle(proc_h)); } };
|
||||
|
||||
R_ABORT_UNLESS_IF_NEW_PROCESS(pm::dmnt::AtmosphereGetProcessInfo(&proc_h, &loc, &status, this->cheat_process_metadata.process_id));
|
||||
this->cheat_process_metadata.program_id = loc.program_id;
|
||||
|
@ -988,96 +985,104 @@ namespace ams::dmnt::cheat::impl {
|
|||
|
||||
|
||||
/* Manager global. */
|
||||
CheatProcessManager g_cheat_process_manager;
|
||||
TYPED_STORAGE(CheatProcessManager) g_cheat_process_manager;
|
||||
|
||||
}
|
||||
|
||||
void InitializeCheatManager() {
|
||||
/* Initialize the debug events manager (spawning its threads). */
|
||||
InitializeDebugEventsManager();
|
||||
|
||||
/* Create the cheat process manager (spawning its threads). */
|
||||
new (GetPointer(g_cheat_process_manager)) CheatProcessManager;
|
||||
}
|
||||
|
||||
bool GetHasActiveCheatProcess() {
|
||||
return g_cheat_process_manager.GetHasActiveCheatProcess();
|
||||
return GetReference(g_cheat_process_manager).GetHasActiveCheatProcess();
|
||||
}
|
||||
|
||||
Handle GetCheatProcessEventHandle() {
|
||||
return g_cheat_process_manager.GetCheatProcessEventHandle();
|
||||
return GetReference(g_cheat_process_manager).GetCheatProcessEventHandle();
|
||||
}
|
||||
|
||||
Result GetCheatProcessMetadata(CheatProcessMetadata *out) {
|
||||
return g_cheat_process_manager.GetCheatProcessMetadata(out);
|
||||
return GetReference(g_cheat_process_manager).GetCheatProcessMetadata(out);
|
||||
}
|
||||
|
||||
Result ForceOpenCheatProcess() {
|
||||
return g_cheat_process_manager.ForceOpenCheatProcess();
|
||||
return GetReference(g_cheat_process_manager).ForceOpenCheatProcess();
|
||||
}
|
||||
|
||||
Result ReadCheatProcessMemoryUnsafe(u64 process_addr, void *out_data, size_t size) {
|
||||
return g_cheat_process_manager.ReadCheatProcessMemoryUnsafe(process_addr, out_data, size);
|
||||
return GetReference(g_cheat_process_manager).ReadCheatProcessMemoryUnsafe(process_addr, out_data, size);
|
||||
}
|
||||
|
||||
Result WriteCheatProcessMemoryUnsafe(u64 process_addr, void *data, size_t size) {
|
||||
return g_cheat_process_manager.WriteCheatProcessMemoryUnsafe(process_addr, data, size);
|
||||
return GetReference(g_cheat_process_manager).WriteCheatProcessMemoryUnsafe(process_addr, data, size);
|
||||
}
|
||||
|
||||
Result GetCheatProcessMappingCount(u64 *out_count) {
|
||||
return g_cheat_process_manager.GetCheatProcessMappingCount(out_count);
|
||||
return GetReference(g_cheat_process_manager).GetCheatProcessMappingCount(out_count);
|
||||
}
|
||||
|
||||
Result GetCheatProcessMappings(MemoryInfo *mappings, size_t max_count, u64 *out_count, u64 offset) {
|
||||
return g_cheat_process_manager.GetCheatProcessMappings(mappings, max_count, out_count, offset);
|
||||
return GetReference(g_cheat_process_manager).GetCheatProcessMappings(mappings, max_count, out_count, offset);
|
||||
}
|
||||
|
||||
Result ReadCheatProcessMemory(u64 proc_addr, void *out_data, size_t size) {
|
||||
return g_cheat_process_manager.ReadCheatProcessMemory(proc_addr, out_data, size);
|
||||
return GetReference(g_cheat_process_manager).ReadCheatProcessMemory(proc_addr, out_data, size);
|
||||
}
|
||||
|
||||
Result WriteCheatProcessMemory(u64 proc_addr, const void *data, size_t size) {
|
||||
return g_cheat_process_manager.WriteCheatProcessMemory(proc_addr, data, size);
|
||||
return GetReference(g_cheat_process_manager).WriteCheatProcessMemory(proc_addr, data, size);
|
||||
}
|
||||
|
||||
Result QueryCheatProcessMemory(MemoryInfo *mapping, u64 address) {
|
||||
return g_cheat_process_manager.QueryCheatProcessMemory(mapping, address);
|
||||
return GetReference(g_cheat_process_manager).QueryCheatProcessMemory(mapping, address);
|
||||
}
|
||||
|
||||
Result GetCheatCount(u64 *out_count) {
|
||||
return g_cheat_process_manager.GetCheatCount(out_count);
|
||||
return GetReference(g_cheat_process_manager).GetCheatCount(out_count);
|
||||
}
|
||||
|
||||
Result GetCheats(CheatEntry *cheats, size_t max_count, u64 *out_count, u64 offset) {
|
||||
return g_cheat_process_manager.GetCheats(cheats, max_count, out_count, offset);
|
||||
return GetReference(g_cheat_process_manager).GetCheats(cheats, max_count, out_count, offset);
|
||||
}
|
||||
|
||||
Result GetCheatById(CheatEntry *out_cheat, u32 cheat_id) {
|
||||
return g_cheat_process_manager.GetCheatById(out_cheat, cheat_id);
|
||||
return GetReference(g_cheat_process_manager).GetCheatById(out_cheat, cheat_id);
|
||||
}
|
||||
|
||||
Result ToggleCheat(u32 cheat_id) {
|
||||
return g_cheat_process_manager.ToggleCheat(cheat_id);
|
||||
return GetReference(g_cheat_process_manager).ToggleCheat(cheat_id);
|
||||
}
|
||||
|
||||
Result AddCheat(u32 *out_id, const CheatDefinition &def, bool enabled) {
|
||||
return g_cheat_process_manager.AddCheat(out_id, def, enabled);
|
||||
return GetReference(g_cheat_process_manager).AddCheat(out_id, def, enabled);
|
||||
}
|
||||
|
||||
Result RemoveCheat(u32 cheat_id) {
|
||||
return g_cheat_process_manager.RemoveCheat(cheat_id);
|
||||
return GetReference(g_cheat_process_manager).RemoveCheat(cheat_id);
|
||||
}
|
||||
|
||||
Result GetFrozenAddressCount(u64 *out_count) {
|
||||
return g_cheat_process_manager.GetFrozenAddressCount(out_count);
|
||||
return GetReference(g_cheat_process_manager).GetFrozenAddressCount(out_count);
|
||||
}
|
||||
|
||||
Result GetFrozenAddresses(FrozenAddressEntry *frz_addrs, size_t max_count, u64 *out_count, u64 offset) {
|
||||
return g_cheat_process_manager.GetFrozenAddresses(frz_addrs, max_count, out_count, offset);
|
||||
return GetReference(g_cheat_process_manager).GetFrozenAddresses(frz_addrs, max_count, out_count, offset);
|
||||
}
|
||||
|
||||
Result GetFrozenAddress(FrozenAddressEntry *frz_addr, u64 address) {
|
||||
return g_cheat_process_manager.GetFrozenAddress(frz_addr, address);
|
||||
return GetReference(g_cheat_process_manager).GetFrozenAddress(frz_addr, address);
|
||||
}
|
||||
|
||||
Result EnableFrozenAddress(u64 *out_value, u64 address, u64 width) {
|
||||
return g_cheat_process_manager.EnableFrozenAddress(out_value, address, width);
|
||||
return GetReference(g_cheat_process_manager).EnableFrozenAddress(out_value, address, width);
|
||||
}
|
||||
|
||||
Result DisableFrozenAddress(u64 address) {
|
||||
return g_cheat_process_manager.DisableFrozenAddress(address);
|
||||
return GetReference(g_cheat_process_manager).DisableFrozenAddress(address);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
namespace ams::dmnt::cheat::impl {
|
||||
|
||||
void InitializeCheatManager();
|
||||
|
||||
bool GetHasActiveCheatProcess();
|
||||
Handle GetCheatProcessEventHandle();
|
||||
Result GetCheatProcessMetadata(CheatProcessMetadata *out);
|
||||
|
|
|
@ -25,10 +25,11 @@ namespace ams::dmnt::cheat::impl {
|
|||
public:
|
||||
static constexpr size_t NumCores = 4;
|
||||
static constexpr size_t ThreadStackSize = os::MemoryPageSize;
|
||||
static constexpr size_t ThreadPriority = 24;
|
||||
static constexpr s32 ThreadPriority = -3;
|
||||
private:
|
||||
std::array<uintptr_t, NumCores> message_queue_buffers;
|
||||
std::array<os::MessageQueue, NumCores> message_queues;
|
||||
std::array<os::Thread, NumCores> threads;
|
||||
std::array<os::ThreadType, NumCores> threads;
|
||||
os::Event continued_event;
|
||||
|
||||
alignas(os::MemoryPageSize) u8 thread_stacks[NumCores][ThreadStackSize];
|
||||
|
@ -91,16 +92,24 @@ namespace ams::dmnt::cheat::impl {
|
|||
}
|
||||
|
||||
public:
|
||||
DebugEventsManager() : message_queues{os::MessageQueue(1), os::MessageQueue(1), os::MessageQueue(1), os::MessageQueue(1)}, thread_stacks{} {
|
||||
DebugEventsManager()
|
||||
: message_queues{
|
||||
os::MessageQueue(std::addressof(message_queue_buffers[0]), 1),
|
||||
os::MessageQueue(std::addressof(message_queue_buffers[1]), 1),
|
||||
os::MessageQueue(std::addressof(message_queue_buffers[2]), 1),
|
||||
os::MessageQueue(std::addressof(message_queue_buffers[3]), 1)},
|
||||
continued_event(os::EventClearMode_AutoClear),
|
||||
thread_stacks{}
|
||||
{
|
||||
for (size_t i = 0; i < NumCores; i++) {
|
||||
/* Create thread. */
|
||||
R_ABORT_UNLESS(this->threads[i].Initialize(&DebugEventsManager::PerCoreThreadFunction, reinterpret_cast<void *>(this), this->thread_stacks[i], ThreadStackSize, ThreadPriority, i));
|
||||
R_ABORT_UNLESS(os::CreateThread(std::addressof(this->threads[i]), PerCoreThreadFunction, this, this->thread_stacks[i], ThreadStackSize, ThreadPriority, i));
|
||||
|
||||
/* Set core mask. */
|
||||
R_ABORT_UNLESS(svcSetThreadCoreMask(this->threads[i].GetHandle(), i, (1u << i)));
|
||||
os::SetThreadCoreMask(std::addressof(this->threads[i]), i, (1u << i));
|
||||
|
||||
/* Start thread. */
|
||||
R_ABORT_UNLESS(this->threads[i].Start());
|
||||
os::StartThread(std::addressof(this->threads[i]));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,7 +117,7 @@ namespace ams::dmnt::cheat::impl {
|
|||
/* Loop getting all debug events. */
|
||||
svc::DebugEventInfo d;
|
||||
size_t target_core = NumCores - 1;
|
||||
while (R_SUCCEEDED(svcGetDebugEvent(reinterpret_cast<u8 *>(&d), cheat_dbg_hnd))) {
|
||||
while (R_SUCCEEDED(svc::GetDebugEvent(std::addressof(d), cheat_dbg_hnd))) {
|
||||
if (d.type == svc::DebugEvent_AttachThread) {
|
||||
target_core = GetTargetCore(d, cheat_dbg_hnd);
|
||||
}
|
||||
|
@ -121,12 +130,16 @@ namespace ams::dmnt::cheat::impl {
|
|||
};
|
||||
|
||||
/* Manager global. */
|
||||
DebugEventsManager g_events_manager;
|
||||
TYPED_STORAGE(DebugEventsManager) g_events_manager;
|
||||
|
||||
}
|
||||
|
||||
void InitializeDebugEventsManager() {
|
||||
new (GetPointer(g_events_manager)) DebugEventsManager;
|
||||
}
|
||||
|
||||
void ContinueCheatProcess(Handle cheat_dbg_hnd) {
|
||||
g_events_manager.ContinueCheatProcess(cheat_dbg_hnd);
|
||||
GetReference(g_events_manager).ContinueCheatProcess(cheat_dbg_hnd);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
namespace ams::dmnt::cheat::impl {
|
||||
|
||||
void InitializeDebugEventsManager();
|
||||
|
||||
void ContinueCheatProcess(Handle cheat_dbg_hnd);
|
||||
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
#include "dmnt_service.hpp"
|
||||
#include "cheat/dmnt_cheat_service.hpp"
|
||||
#include "cheat/impl/dmnt_cheat_api.hpp"
|
||||
|
||||
extern "C" {
|
||||
extern u32 __start__;
|
||||
|
@ -122,12 +123,15 @@ namespace {
|
|||
constexpr size_t ThreadStackSize = 0x4000;
|
||||
alignas(os::MemoryPageSize) u8 g_extra_thread_stacks[NumExtraThreads][ThreadStackSize];
|
||||
|
||||
os::Thread g_extra_threads[NumExtraThreads];
|
||||
os::ThreadType g_extra_threads[NumExtraThreads];
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
/* Initialize the cheat manager. */
|
||||
ams::dmnt::cheat::impl::InitializeCheatManager();
|
||||
|
||||
/* Create services. */
|
||||
/* TODO: Implement rest of dmnt:- in ams.tma development branch. */
|
||||
/* R_ABORT_UNLESS((g_server_manager.RegisterServer<dmnt::cheat::CheatService>(DebugMonitorServiceName, DebugMonitorMaxSessions))); */
|
||||
|
@ -139,16 +143,16 @@ int main(int argc, char **argv)
|
|||
|
||||
/* Initialize threads. */
|
||||
if constexpr (NumExtraThreads > 0) {
|
||||
const s32 priority = os::GetCurrentThreadPriority();
|
||||
const s32 priority = os::GetThreadCurrentPriority(os::GetCurrentThread());
|
||||
for (size_t i = 0; i < NumExtraThreads; i++) {
|
||||
R_ABORT_UNLESS(g_extra_threads[i].Initialize(LoopServerThread, nullptr, g_extra_thread_stacks[i], ThreadStackSize, priority));
|
||||
R_ABORT_UNLESS(os::CreateThread(std::addressof(g_extra_threads[i]), LoopServerThread, nullptr, g_extra_thread_stacks[i], ThreadStackSize, priority));
|
||||
}
|
||||
}
|
||||
|
||||
/* Start extra threads. */
|
||||
if constexpr (NumExtraThreads > 0) {
|
||||
for (size_t i = 0; i < NumExtraThreads; i++) {
|
||||
R_ABORT_UNLESS(g_extra_threads[i].Start());
|
||||
os::StartThread(std::addressof(g_extra_threads[i]));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -158,7 +162,7 @@ int main(int argc, char **argv)
|
|||
/* Wait for extra threads to finish. */
|
||||
if constexpr (NumExtraThreads > 0) {
|
||||
for (size_t i = 0; i < NumExtraThreads; i++) {
|
||||
R_ABORT_UNLESS(g_extra_threads[i].Join());
|
||||
os::WaitThread(std::addressof(g_extra_threads[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,10 +40,10 @@ namespace ams::dmnt {
|
|||
|
||||
/* Nintendo uses actual pointers as file handles. We'll add a layer of indirection... */
|
||||
bool g_sd_initialized = false;
|
||||
os::Mutex g_sd_lock;
|
||||
os::Mutex g_sd_lock(false);
|
||||
FsFileSystem g_sd_fs;
|
||||
|
||||
os::Mutex g_file_handle_lock;
|
||||
os::Mutex g_file_handle_lock(false);
|
||||
u64 g_cur_fd;
|
||||
std::unordered_map<TargetIOFileHandle, FsFile> g_file_handles;
|
||||
|
||||
|
|
|
@ -30,17 +30,24 @@ namespace ams::fatal::srv {
|
|||
}
|
||||
|
||||
/* Global event. */
|
||||
os::SystemEvent g_fatal_dirty_event(GetFatalDirtyEventReadableHandle(), true, false);
|
||||
os::WaitableHolder g_fatal_dirty_waitable_holder(&g_fatal_dirty_event);
|
||||
os::SystemEventType g_fatal_dirty_event;
|
||||
os::WaitableHolderType g_fatal_dirty_waitable_holder;
|
||||
bool g_initialized;
|
||||
|
||||
}
|
||||
|
||||
os::WaitableHolder *GetFatalDirtyWaitableHolder() {
|
||||
return &g_fatal_dirty_waitable_holder;
|
||||
os::WaitableHolderType *GetFatalDirtyWaitableHolder() {
|
||||
if (AMS_UNLIKELY(!g_initialized)) {
|
||||
os::AttachReadableHandleToSystemEvent(std::addressof(g_fatal_dirty_event), GetFatalDirtyEventReadableHandle(), true, os::EventClearMode_ManualClear);
|
||||
os::InitializeWaitableHolder(std::addressof(g_fatal_dirty_waitable_holder), std::addressof(g_fatal_dirty_event));
|
||||
os::SetWaitableHolderUserData(std::addressof(g_fatal_dirty_waitable_holder), reinterpret_cast<uintptr_t>(std::addressof(g_fatal_dirty_waitable_holder)));
|
||||
g_initialized = true;
|
||||
}
|
||||
return std::addressof(g_fatal_dirty_waitable_holder);
|
||||
}
|
||||
|
||||
void OnFatalDirtyEvent() {
|
||||
g_fatal_dirty_event.Reset();
|
||||
os::ClearSystemEvent(std::addressof(g_fatal_dirty_event));
|
||||
|
||||
u64 flags_0, flags_1;
|
||||
if (R_SUCCEEDED(setsysGetFatalDirtyFlags(&flags_0, &flags_1)) && (flags_0 & 1)) {
|
||||
|
|
|
@ -88,7 +88,7 @@ namespace ams::fatal::srv {
|
|||
}
|
||||
};
|
||||
|
||||
os::WaitableHolder *GetFatalDirtyWaitableHolder();
|
||||
os::WaitableHolderType *GetFatalDirtyWaitableHolder();
|
||||
void OnFatalDirtyEvent();
|
||||
const FatalConfig &GetFatalConfig();
|
||||
|
||||
|
|
|
@ -17,26 +17,26 @@
|
|||
|
||||
namespace ams::fatal::srv {
|
||||
|
||||
FatalEventManager::FatalEventManager() {
|
||||
FatalEventManager::FatalEventManager() : lock(false) {
|
||||
/* Just create all the events. */
|
||||
for (size_t i = 0; i < FatalEventManager::NumFatalEvents; i++) {
|
||||
R_ABORT_UNLESS(eventCreate(&this->events[i], true));
|
||||
R_ABORT_UNLESS(os::CreateSystemEvent(std::addressof(this->events[i]), os::EventClearMode_AutoClear, true));
|
||||
}
|
||||
}
|
||||
|
||||
Result FatalEventManager::GetEvent(Handle *out) {
|
||||
Result FatalEventManager::GetEvent(const os::SystemEventType **out) {
|
||||
std::scoped_lock lk{this->lock};
|
||||
|
||||
/* Only allow GetEvent to succeed NumFatalEvents times. */
|
||||
R_UNLESS(this->num_events_gotten < FatalEventManager::NumFatalEvents, ResultTooManyEvents());
|
||||
|
||||
*out = this->events[this->num_events_gotten++].revent;
|
||||
*out = std::addressof(this->events[this->num_events_gotten++]);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void FatalEventManager::SignalEvents() {
|
||||
for (size_t i = 0; i < FatalEventManager::NumFatalEvents; i++) {
|
||||
eventFire(&this->events[i]);
|
||||
os::SignalSystemEvent(std::addressof(this->events[i]));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,15 +19,17 @@
|
|||
namespace ams::fatal::srv {
|
||||
|
||||
class FatalEventManager {
|
||||
private:
|
||||
NON_COPYABLE(FatalEventManager);
|
||||
NON_MOVEABLE(FatalEventManager);
|
||||
public:
|
||||
static constexpr size_t NumFatalEvents = 3;
|
||||
|
||||
private:
|
||||
os::Mutex lock;
|
||||
size_t num_events_gotten = 0;
|
||||
Event events[NumFatalEvents];
|
||||
os::SystemEventType events[NumFatalEvents];
|
||||
public:
|
||||
FatalEventManager();
|
||||
Result GetEvent(Handle *out);
|
||||
Result GetEvent(const os::SystemEventType **out);
|
||||
void SignalEvents();
|
||||
};
|
||||
|
||||
|
|
|
@ -44,16 +44,16 @@ namespace ams::fatal::srv {
|
|||
gpioPadSetDirection(&vol_btn, GpioDirection_Input);
|
||||
|
||||
/* Ensure that we're holding the volume button for a full second. */
|
||||
os::TimeoutHelper timeout_helper(1'000'000'000ul);
|
||||
while (!timeout_helper.TimedOut()) {
|
||||
auto start = os::GetSystemTick();
|
||||
do {
|
||||
GpioValue val;
|
||||
if (R_FAILED(gpioPadGetValue(&vol_btn, &val)) || val != GpioValue_Low) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Sleep for 100 ms. */
|
||||
svcSleepThread(100'000'000ul);
|
||||
}
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(100));
|
||||
} while (os::ConvertToTimeSpan(os::GetSystemTick() - start) < TimeSpan::FromSeconds(1));
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace ams::fatal::srv {
|
|||
/* Convenience definitions. */
|
||||
constexpr size_t MaximumLineLength = 0x20;
|
||||
|
||||
os::Mutex g_format_lock;
|
||||
os::Mutex g_format_lock(false);
|
||||
char g_format_buffer[2 * os::MemoryPageSize];
|
||||
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@ namespace ams::fatal::srv {
|
|||
/* Service Context. */
|
||||
class ServiceContext {
|
||||
private:
|
||||
os::Event erpt_event;
|
||||
os::Event battery_event;
|
||||
ThrowContext context;
|
||||
FatalEventManager event_manager;
|
||||
bool has_thrown;
|
||||
|
@ -37,14 +39,14 @@ namespace ams::fatal::srv {
|
|||
return ResultSuccess();
|
||||
}
|
||||
public:
|
||||
ServiceContext() {
|
||||
this->context.ClearState();
|
||||
R_ABORT_UNLESS(eventCreate(&this->context.erpt_event, false));
|
||||
R_ABORT_UNLESS(eventCreate(&this->context.battery_event, false));
|
||||
this->has_thrown = false;
|
||||
ServiceContext()
|
||||
: erpt_event(os::EventClearMode_ManualClear), battery_event(os::EventClearMode_ManualClear),
|
||||
context(std::addressof(erpt_event), std::addressof(battery_event)), has_thrown(false)
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
||||
Result GetEvent(Handle *out) {
|
||||
Result GetEvent(const os::SystemEventType **out) {
|
||||
return this->event_manager.GetEvent(out);
|
||||
}
|
||||
|
||||
|
@ -143,7 +145,10 @@ namespace ams::fatal::srv {
|
|||
}
|
||||
|
||||
Result PrivateService::GetFatalEvent(sf::OutCopyHandle out_h) {
|
||||
return g_context.GetEvent(out_h.GetHandlePointer());
|
||||
const os::SystemEventType *event;
|
||||
R_TRY(g_context.GetEvent(std::addressof(event)));
|
||||
out_h.SetValue(os::GetReadableHandleOfSystemEvent(event));
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
|
@ -28,9 +28,9 @@ namespace ams::fatal::srv {
|
|||
class TaskThread {
|
||||
NON_COPYABLE(TaskThread);
|
||||
private:
|
||||
static constexpr int TaskThreadPriority = 15;
|
||||
static constexpr s32 TaskThreadPriority = -13;
|
||||
private:
|
||||
os::Thread thread;
|
||||
os::ThreadType thread;
|
||||
private:
|
||||
static void RunTaskImpl(void *arg) {
|
||||
ITask *task = reinterpret_cast<ITask *>(arg);
|
||||
|
@ -42,8 +42,8 @@ namespace ams::fatal::srv {
|
|||
public:
|
||||
TaskThread() { /* ... */ }
|
||||
void StartTask(ITask *task) {
|
||||
R_ABORT_UNLESS(this->thread.Initialize(&RunTaskImpl, task, task->GetStack(), task->GetStackSize(), TaskThreadPriority));
|
||||
R_ABORT_UNLESS(this->thread.Start());
|
||||
R_ABORT_UNLESS(os::CreateThread(std::addressof(this->thread), RunTaskImpl, task, task->GetStack(), task->GetStackSize(), TaskThreadPriority, 3));
|
||||
os::StartThread(std::addressof(this->thread));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -160,7 +160,7 @@ namespace ams::fatal::srv {
|
|||
}
|
||||
|
||||
/* Signal we're done with our job. */
|
||||
eventFire(const_cast<Event *>(&this->context->erpt_event));
|
||||
this->context->erpt_event->Signal();
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
|
|
@ -50,6 +50,22 @@ namespace ams::fatal::srv {
|
|||
}
|
||||
};
|
||||
|
||||
class RebootTimingObserver {
|
||||
private:
|
||||
os::Tick start_tick;
|
||||
bool flag;
|
||||
s32 interval;
|
||||
public:
|
||||
RebootTimingObserver(bool flag, s32 interval) : start_tick(os::GetSystemTick()), flag(flag), interval(interval) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
bool IsRebootTiming() const {
|
||||
auto current_tick = os::GetSystemTick();
|
||||
return this->flag && (current_tick - this->start_tick).ToTimeSpan().GetSeconds() >= this->interval;
|
||||
}
|
||||
};
|
||||
|
||||
/* Task globals. */
|
||||
PowerControlTask g_power_control_task;
|
||||
PowerButtonObserveTask g_power_button_observe_task;
|
||||
|
@ -58,13 +74,16 @@ namespace ams::fatal::srv {
|
|||
/* Task Implementations. */
|
||||
bool PowerControlTask::TryShutdown() {
|
||||
/* Set a timeout of 30 seconds. */
|
||||
os::TimeoutHelper timeout_helper(30'000'000'000ul);
|
||||
constexpr s32 MaxShutdownWaitSeconds = 30;
|
||||
|
||||
auto start_tick = os::GetSystemTick();
|
||||
|
||||
bool perform_shutdown = true;
|
||||
PsmBatteryVoltageState bv_state = PsmBatteryVoltageState_Normal;
|
||||
|
||||
while (true) {
|
||||
if (timeout_helper.TimedOut()) {
|
||||
auto cur_tick = os::GetSystemTick();
|
||||
if ((cur_tick - start_tick).ToTimeSpan().GetSeconds() > MaxShutdownWaitSeconds) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -77,8 +96,8 @@ namespace ams::fatal::srv {
|
|||
break;
|
||||
}
|
||||
|
||||
/* Query voltage state every 5 seconds, for 30 seconds. */
|
||||
svcSleepThread(5'000'000'000ul);
|
||||
/* Query voltage state every 1 seconds, for 30 seconds. */
|
||||
os::SleepThread(TimeSpan::FromSeconds(1));
|
||||
}
|
||||
|
||||
if (perform_shutdown) {
|
||||
|
@ -94,13 +113,13 @@ namespace ams::fatal::srv {
|
|||
/* Check the battery state, and shutdown on low voltage. */
|
||||
if (R_FAILED(psmGetBatteryVoltageState(&bv_state)) || bv_state == PsmBatteryVoltageState_NeedsShutdown) {
|
||||
/* Wait a second for the error report task to finish. */
|
||||
eventWait(const_cast<Event *>(&this->context->erpt_event), os::TimeoutHelper::NsToTick(1'000'000'000ul));
|
||||
this->context->erpt_event->TimedWait(TimeSpan::FromSeconds(1));
|
||||
this->TryShutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Signal we've checked the battery at least once. */
|
||||
eventFire(const_cast<Event *>(&this->context->battery_event));
|
||||
this->context->battery_event->Signal();
|
||||
|
||||
/* Loop querying voltage state every 5 seconds. */
|
||||
while (true) {
|
||||
|
@ -122,18 +141,18 @@ namespace ams::fatal::srv {
|
|||
break;
|
||||
}
|
||||
|
||||
svcSleepThread(5'000'000'000ul);
|
||||
os::SleepThread(TimeSpan::FromSeconds(5));
|
||||
}
|
||||
}
|
||||
|
||||
void PowerButtonObserveTask::WaitForPowerButton() {
|
||||
/* Wait up to a second for error report generation to finish. */
|
||||
eventWait(const_cast<Event *>(&this->context->erpt_event), os::TimeoutHelper::NsToTick(1'000'000'000ul));
|
||||
this->context->erpt_event->TimedWait(TimeSpan::FromSeconds(1));
|
||||
|
||||
/* Force a reboot after some time if kiosk unit. */
|
||||
const auto &config = GetFatalConfig();
|
||||
os::TimeoutHelper quest_reboot_helper(config.GetQuestRebootTimeoutInterval());
|
||||
os::TimeoutHelper fatal_reboot_helper(config.GetFatalRebootTimeoutInterval());
|
||||
RebootTimingObserver quest_reboot_helper(config.IsQuest(), config.GetQuestRebootTimeoutInterval());
|
||||
RebootTimingObserver fatal_reboot_helper(config.IsFatalRebootEnabled(), config.GetFatalRebootTimeoutInterval());
|
||||
|
||||
bool check_vol_up = true, check_vol_down = true;
|
||||
GpioPadSession vol_up_btn, vol_down_btn;
|
||||
|
@ -159,11 +178,10 @@ namespace ams::fatal::srv {
|
|||
BpcSleepButtonState state;
|
||||
GpioValue val;
|
||||
while (true) {
|
||||
if ((config.IsFatalRebootEnabled() && fatal_reboot_helper.TimedOut()) ||
|
||||
if (fatal_reboot_helper.IsRebootTiming() || (quest_reboot_helper.IsRebootTiming()) ||
|
||||
(check_vol_up && R_SUCCEEDED(gpioPadGetValue(&vol_up_btn, &val)) && val == GpioValue_Low) ||
|
||||
(check_vol_down && R_SUCCEEDED(gpioPadGetValue(&vol_down_btn, &val)) && val == GpioValue_Low) ||
|
||||
(R_SUCCEEDED(bpcGetSleepButtonState(&state)) && state == BpcSleepButtonState_Held) ||
|
||||
(config.IsQuest() && quest_reboot_helper.TimedOut())) {
|
||||
(R_SUCCEEDED(bpcGetSleepButtonState(&state)) && state == BpcSleepButtonState_Held)) {
|
||||
/* If any of the above conditions succeeded, we should reboot. */
|
||||
bpcRebootSystem();
|
||||
return;
|
||||
|
@ -171,7 +189,7 @@ namespace ams::fatal::srv {
|
|||
|
||||
|
||||
/* Wait 100 ms between button checks. */
|
||||
svcSleepThread(100'000'000ul);
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(100));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -418,7 +418,7 @@ namespace ams::fatal::srv {
|
|||
|
||||
Result ShowFatalTask::Run() {
|
||||
/* Don't show the fatal error screen until we've verified the battery is okay. */
|
||||
eventWait(const_cast<Event *>(&this->context->battery_event), std::numeric_limits<u64>::max());
|
||||
this->context->battery_event->Wait();
|
||||
|
||||
return ShowFatal();
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace ams::ldr {
|
|||
|
||||
namespace {
|
||||
|
||||
os::Mutex g_scoped_code_mount_lock;
|
||||
os::Mutex g_scoped_code_mount_lock(false);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace ams::ldr {
|
|||
constexpr const char * const LoaderSdMountName = "#amsldr-sdpatch";
|
||||
static_assert(sizeof(LoaderSdMountName) <= fs::MountNameLengthMax);
|
||||
|
||||
os::Mutex g_ldr_sd_lock;
|
||||
os::Mutex g_ldr_sd_lock(false);
|
||||
bool g_mounted_sd;
|
||||
|
||||
bool EnsureSdCardMounted() {
|
||||
|
|
|
@ -144,14 +144,14 @@ namespace {
|
|||
|
||||
constexpr inline sm::ServiceName ContentManagerServiceName = sm::ServiceName::Encode("ncm");
|
||||
|
||||
alignas(os::ThreadStackAlignment) u8 g_content_manager_thread_stack[16_KB];
|
||||
alignas(os::ThreadStackAlignment) u8 g_location_resolver_thread_stack[16_KB];
|
||||
|
||||
class ContentManagerServerManager : public sf::hipc::ServerManager<ContentManagerNumServers, ContentManagerServerOptions, ContentManagerMaxSessions> {
|
||||
private:
|
||||
static constexpr size_t ThreadStackSize = 0x4000;
|
||||
static constexpr int ThreadPriority = 0x15;
|
||||
|
||||
using ServiceType = ncm::ContentManagerImpl;
|
||||
private:
|
||||
os::StaticThread<ThreadStackSize> thread;
|
||||
os::ThreadType thread;
|
||||
std::shared_ptr<ServiceType> ncm_manager;
|
||||
private:
|
||||
static void ThreadFunction(void *_this) {
|
||||
|
@ -159,7 +159,7 @@ namespace {
|
|||
}
|
||||
public:
|
||||
ContentManagerServerManager(ServiceType *m)
|
||||
: thread(ThreadFunction, this, ThreadPriority), ncm_manager()
|
||||
: ncm_manager()
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
@ -170,11 +170,13 @@ namespace {
|
|||
}
|
||||
|
||||
ams::Result StartThreads() {
|
||||
return this->thread.Start();
|
||||
R_TRY(os::CreateThread(std::addressof(this->thread), ThreadFunction, this, g_content_manager_thread_stack, sizeof(g_content_manager_thread_stack), 21));
|
||||
os::StartThread(std::addressof(this->thread));
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void Wait() {
|
||||
this->thread.Join();
|
||||
os::WaitThread(std::addressof(this->thread));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -193,12 +195,9 @@ namespace {
|
|||
|
||||
class LocationResolverServerManager : public sf::hipc::ServerManager<LocationResolverNumServers, LocationResolverServerOptions, LocationResolverMaxSessions> {
|
||||
private:
|
||||
static constexpr size_t ThreadStackSize = 0x4000;
|
||||
static constexpr int ThreadPriority = 0x15;
|
||||
|
||||
using ServiceType = lr::LocationResolverManagerImpl;
|
||||
private:
|
||||
os::StaticThread<ThreadStackSize> thread;
|
||||
os::ThreadType thread;
|
||||
std::shared_ptr<ServiceType> lr_manager;
|
||||
private:
|
||||
static void ThreadFunction(void *_this) {
|
||||
|
@ -206,7 +205,7 @@ namespace {
|
|||
}
|
||||
public:
|
||||
LocationResolverServerManager(ServiceType *m)
|
||||
: thread(ThreadFunction, this, ThreadPriority), lr_manager(sf::ServiceObjectTraits<ServiceType>::SharedPointerHelper::GetEmptyDeleteSharedPointer(m))
|
||||
: lr_manager(sf::ServiceObjectTraits<ServiceType>::SharedPointerHelper::GetEmptyDeleteSharedPointer(m))
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
@ -216,11 +215,13 @@ namespace {
|
|||
}
|
||||
|
||||
ams::Result StartThreads() {
|
||||
return this->thread.Start();
|
||||
R_TRY(os::CreateThread(std::addressof(this->thread), ThreadFunction, this, g_location_resolver_thread_stack, sizeof(g_location_resolver_thread_stack), 21));
|
||||
os::StartThread(std::addressof(this->thread));
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void Wait() {
|
||||
this->thread.Join();
|
||||
os::WaitThread(std::addressof(this->thread));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -17,8 +17,9 @@
|
|||
|
||||
namespace ams::pm::impl {
|
||||
|
||||
ProcessInfo::ProcessInfo(Handle h, os::ProcessId pid, ldr::PinId pin, const ncm::ProgramLocation &l, const cfg::OverrideStatus &s) : process_id(pid), pin_id(pin), loc(l), status(s), handle(h), state(svc::ProcessState_Created), flags(0), waitable_holder(h) {
|
||||
this->waitable_holder.SetUserData(reinterpret_cast<uintptr_t>(this));
|
||||
ProcessInfo::ProcessInfo(Handle h, os::ProcessId pid, ldr::PinId pin, const ncm::ProgramLocation &l, const cfg::OverrideStatus &s) : process_id(pid), pin_id(pin), loc(l), status(s), handle(h), state(svc::ProcessState_Created), flags(0) {
|
||||
os::InitializeWaitableHolder(std::addressof(this->waitable_holder), this->handle);
|
||||
os::SetWaitableHolderUserData(std::addressof(this->waitable_holder), reinterpret_cast<uintptr_t>(this));
|
||||
}
|
||||
|
||||
ProcessInfo::~ProcessInfo() {
|
||||
|
@ -37,7 +38,7 @@ namespace ams::pm::impl {
|
|||
this->handle = INVALID_HANDLE;
|
||||
|
||||
/* Unlink the process from its waitable manager. */
|
||||
this->waitable_holder.UnlinkFromWaitableManager();
|
||||
os::UnlinkWaitableHolder(std::addressof(this->waitable_holder));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace ams::pm::impl {
|
|||
Handle handle;
|
||||
svc::ProcessState state;
|
||||
u32 flags;
|
||||
os::WaitableHolder waitable_holder;
|
||||
os::WaitableHolderType waitable_holder;
|
||||
private:
|
||||
void SetFlag(Flag flag) {
|
||||
this->flags |= flag;
|
||||
|
@ -63,8 +63,8 @@ namespace ams::pm::impl {
|
|||
~ProcessInfo();
|
||||
void Cleanup();
|
||||
|
||||
void LinkToWaitableManager(os::WaitableManager &manager) {
|
||||
manager.LinkWaitableHolder(&this->waitable_holder);
|
||||
void LinkToWaitableManager(os::WaitableManagerType &manager) {
|
||||
os::LinkWaitableHolder(std::addressof(manager), std::addressof(this->waitable_holder));
|
||||
}
|
||||
|
||||
Handle GetHandle() const {
|
||||
|
@ -163,6 +163,8 @@ namespace ams::pm::impl {
|
|||
private:
|
||||
os::Mutex lock;
|
||||
public:
|
||||
constexpr ProcessList() : lock(false) { /* ... */ }
|
||||
|
||||
void Lock() {
|
||||
this->lock.Lock();
|
||||
}
|
||||
|
|
|
@ -144,7 +144,7 @@ namespace ams::pm::impl {
|
|||
return process_info - GetPointer(this->process_info_storages[0]);
|
||||
}
|
||||
public:
|
||||
constexpr ProcessInfoAllocator() {
|
||||
constexpr ProcessInfoAllocator() : lock(false) {
|
||||
std::memset(this->process_info_storages, 0, sizeof(this->process_info_storages));
|
||||
std::memset(this->process_info_allocated, 0, sizeof(this->process_info_allocated));
|
||||
}
|
||||
|
@ -176,9 +176,9 @@ namespace ams::pm::impl {
|
|||
/* Process Tracking globals. */
|
||||
void ProcessTrackingMain(void *arg);
|
||||
|
||||
constexpr size_t ProcessTrackThreadStackSize = 0x4000;
|
||||
constexpr int ProcessTrackThreadPriority = 0x15;
|
||||
os::StaticThread<ProcessTrackThreadStackSize> g_process_track_thread(&ProcessTrackingMain, nullptr, ProcessTrackThreadPriority);
|
||||
constexpr int ProcessTrackThreadPriority = 21;
|
||||
os::ThreadType g_process_track_thread;
|
||||
alignas(os::ThreadStackAlignment) u8 g_process_track_thread_stack[16_KB];
|
||||
|
||||
/* Process lists. */
|
||||
ProcessList g_process_list;
|
||||
|
@ -190,15 +190,15 @@ namespace ams::pm::impl {
|
|||
ProcessInfoAllocator<MaxProcessCount> g_process_info_allocator;
|
||||
|
||||
/* Global events. */
|
||||
os::SystemEvent g_process_event;
|
||||
os::SystemEvent g_hook_to_create_process_event;
|
||||
os::SystemEvent g_hook_to_create_application_process_event;
|
||||
os::SystemEvent g_boot_finished_event;
|
||||
os::SystemEventType g_process_event;
|
||||
os::SystemEventType g_hook_to_create_process_event;
|
||||
os::SystemEventType g_hook_to_create_application_process_event;
|
||||
os::SystemEventType g_boot_finished_event;
|
||||
|
||||
/* Process Launch synchronization globals. */
|
||||
os::Mutex g_launch_program_lock;
|
||||
os::Event g_process_launch_start_event;
|
||||
os::Event g_process_launch_finish_event;
|
||||
os::Mutex g_launch_program_lock(false);
|
||||
os::Event g_process_launch_start_event(os::EventClearMode_AutoClear);
|
||||
os::Event g_process_launch_finish_event(os::EventClearMode_AutoClear);
|
||||
Result g_process_launch_result = ResultSuccess();
|
||||
LaunchProcessArgs g_process_launch_args = {};
|
||||
|
||||
|
@ -207,7 +207,7 @@ namespace ams::pm::impl {
|
|||
std::atomic<bool> g_application_hook;
|
||||
|
||||
/* Forward declarations. */
|
||||
Result LaunchProcess(os::WaitableManager &waitable_manager, const LaunchProcessArgs &args);
|
||||
Result LaunchProcess(os::WaitableManagerType &waitable_manager, const LaunchProcessArgs &args);
|
||||
void OnProcessSignaled(ProcessListAccessor &list, ProcessInfo *process_info);
|
||||
|
||||
/* Helpers. */
|
||||
|
@ -215,12 +215,14 @@ namespace ams::pm::impl {
|
|||
/* This is the main loop of the process tracking thread. */
|
||||
|
||||
/* Setup waitable manager. */
|
||||
os::WaitableManager process_waitable_manager;
|
||||
os::WaitableHolder start_event_holder(&g_process_launch_start_event);
|
||||
process_waitable_manager.LinkWaitableHolder(&start_event_holder);
|
||||
os::WaitableManagerType process_waitable_manager;
|
||||
os::WaitableHolderType start_event_holder;
|
||||
os::InitializeWaitableManager(std::addressof(process_waitable_manager));
|
||||
os::InitializeWaitableHolder(std::addressof(start_event_holder), g_process_launch_start_event.GetBase());
|
||||
os::LinkWaitableHolder(std::addressof(process_waitable_manager), std::addressof(start_event_holder));
|
||||
|
||||
while (true) {
|
||||
auto signaled_holder = process_waitable_manager.WaitAny();
|
||||
auto signaled_holder = os::WaitAny(std::addressof(process_waitable_manager));
|
||||
if (signaled_holder == &start_event_holder) {
|
||||
/* Launch start event signaled. */
|
||||
/* TryWait will clear signaled, preventing duplicate notifications. */
|
||||
|
@ -231,7 +233,7 @@ namespace ams::pm::impl {
|
|||
} else {
|
||||
/* Some process was signaled. */
|
||||
ProcessListAccessor list(g_process_list);
|
||||
OnProcessSignaled(list, reinterpret_cast<ProcessInfo *>(signaled_holder->GetUserData()));
|
||||
OnProcessSignaled(list, reinterpret_cast<ProcessInfo *>(os::GetWaitableHolderUserData(signaled_holder)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -275,7 +277,7 @@ namespace ams::pm::impl {
|
|||
g_process_info_allocator.FreeProcessInfo(process_info);
|
||||
}
|
||||
|
||||
Result LaunchProcess(os::WaitableManager &waitable_manager, const LaunchProcessArgs &args) {
|
||||
Result LaunchProcess(os::WaitableManagerType &waitable_manager, const LaunchProcessArgs &args) {
|
||||
/* Get Program Info. */
|
||||
ldr::ProgramInfo program_info;
|
||||
cfg::OverrideStatus override_status;
|
||||
|
@ -351,10 +353,10 @@ namespace ams::pm::impl {
|
|||
|
||||
/* Process hooks/signaling. */
|
||||
if (location.program_id == g_program_id_hook) {
|
||||
g_hook_to_create_process_event.Signal();
|
||||
os::SignalSystemEvent(std::addressof(g_hook_to_create_process_event));
|
||||
g_program_id_hook = ncm::InvalidProgramId;
|
||||
} else if (is_application && g_application_hook) {
|
||||
g_hook_to_create_application_process_event.Signal();
|
||||
os::SignalSystemEvent(std::addressof(g_hook_to_create_application_process_event));
|
||||
g_application_hook = false;
|
||||
} else if (!ShouldStartSuspended(args.flags)) {
|
||||
R_TRY(StartProcess(process_info, &program_info));
|
||||
|
@ -394,22 +396,22 @@ namespace ams::pm::impl {
|
|||
if (process_info->ShouldSignalOnDebugEvent()) {
|
||||
process_info->ClearSuspended();
|
||||
process_info->SetSuspendedStateChanged();
|
||||
g_process_event.Signal();
|
||||
os::SignalSystemEvent(std::addressof(g_process_event));
|
||||
} else if (hos::GetVersion() >= hos::Version_200 && process_info->ShouldSignalOnStart()) {
|
||||
process_info->SetStartedStateChanged();
|
||||
process_info->ClearSignalOnStart();
|
||||
g_process_event.Signal();
|
||||
os::SignalSystemEvent(std::addressof(g_process_event));
|
||||
}
|
||||
break;
|
||||
case svc::ProcessState_Crashed:
|
||||
process_info->SetExceptionOccurred();
|
||||
g_process_event.Signal();
|
||||
os::SignalSystemEvent(std::addressof(g_process_event));
|
||||
break;
|
||||
case svc::ProcessState_RunningAttached:
|
||||
if (process_info->ShouldSignalOnDebugEvent()) {
|
||||
process_info->ClearSuspended();
|
||||
process_info->SetSuspendedStateChanged();
|
||||
g_process_event.Signal();
|
||||
os::SignalSystemEvent(std::addressof(g_process_event));
|
||||
}
|
||||
break;
|
||||
case svc::ProcessState_Terminated:
|
||||
|
@ -417,7 +419,7 @@ namespace ams::pm::impl {
|
|||
process_info->Cleanup();
|
||||
|
||||
if (hos::GetVersion() < hos::Version_500 && process_info->ShouldSignalOnExit()) {
|
||||
g_process_event.Signal();
|
||||
os::SignalSystemEvent(std::addressof(g_process_event));
|
||||
} else {
|
||||
/* Handle the case where we need to keep the process alive some time longer. */
|
||||
if (hos::GetVersion() >= hos::Version_500 && process_info->ShouldSignalOnExit()) {
|
||||
|
@ -431,7 +433,7 @@ namespace ams::pm::impl {
|
|||
}
|
||||
|
||||
/* Signal. */
|
||||
g_process_event.Signal();
|
||||
os::SignalSystemEvent(std::addressof(g_process_event));
|
||||
} else {
|
||||
/* Actually delete process. */
|
||||
CleanupProcessInfo(list, process_info);
|
||||
|
@ -442,7 +444,7 @@ namespace ams::pm::impl {
|
|||
if (process_info->ShouldSignalOnDebugEvent()) {
|
||||
process_info->SetSuspended();
|
||||
process_info->SetSuspendedStateChanged();
|
||||
g_process_event.Signal();
|
||||
os::SignalSystemEvent(std::addressof(g_process_event));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -453,16 +455,19 @@ namespace ams::pm::impl {
|
|||
/* Initialization. */
|
||||
Result InitializeProcessManager() {
|
||||
/* Create events. */
|
||||
R_ABORT_UNLESS(g_process_event.InitializeAsInterProcessEvent());
|
||||
R_ABORT_UNLESS(g_hook_to_create_process_event.InitializeAsInterProcessEvent());
|
||||
R_ABORT_UNLESS(g_hook_to_create_application_process_event.InitializeAsInterProcessEvent());
|
||||
R_ABORT_UNLESS(g_boot_finished_event.InitializeAsInterProcessEvent());
|
||||
R_ABORT_UNLESS(os::CreateSystemEvent(std::addressof(g_process_event), os::EventClearMode_AutoClear, true));
|
||||
R_ABORT_UNLESS(os::CreateSystemEvent(std::addressof(g_hook_to_create_process_event), os::EventClearMode_AutoClear, true));
|
||||
R_ABORT_UNLESS(os::CreateSystemEvent(std::addressof(g_hook_to_create_application_process_event), os::EventClearMode_AutoClear, true));
|
||||
R_ABORT_UNLESS(os::CreateSystemEvent(std::addressof(g_boot_finished_event), os::EventClearMode_AutoClear, true));
|
||||
|
||||
/* Initialize resource limits. */
|
||||
R_TRY(resource::InitializeResourceManager());
|
||||
|
||||
/* Create thread. */
|
||||
R_ABORT_UNLESS(os::CreateThread(std::addressof(g_process_track_thread), ProcessTrackingMain, nullptr, g_process_track_thread_stack, sizeof(g_process_track_thread_stack), ProcessTrackThreadPriority));
|
||||
|
||||
/* Start thread. */
|
||||
R_ABORT_UNLESS(g_process_track_thread.Start());
|
||||
os::StartThread(std::addressof(g_process_track_thread));
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
@ -515,7 +520,7 @@ namespace ams::pm::impl {
|
|||
}
|
||||
|
||||
Result GetProcessEventHandle(Handle *out) {
|
||||
*out = g_process_event.GetReadableHandle();
|
||||
*out = os::GetReadableHandleOfSystemEvent(std::addressof(g_process_event));
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
|
@ -670,7 +675,7 @@ namespace ams::pm::impl {
|
|||
R_UNLESS(g_program_id_hook.compare_exchange_strong(old_value, program_id), pm::ResultDebugHookInUse());
|
||||
}
|
||||
|
||||
*out_hook = g_hook_to_create_process_event.GetReadableHandle();
|
||||
*out_hook = os::GetReadableHandleOfSystemEvent(std::addressof(g_hook_to_create_process_event));
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
|
@ -682,7 +687,7 @@ namespace ams::pm::impl {
|
|||
R_UNLESS(g_application_hook.compare_exchange_strong(old_value, true), pm::ResultDebugHookInUse());
|
||||
}
|
||||
|
||||
*out_hook = g_hook_to_create_application_process_event.GetReadableHandle();
|
||||
*out_hook = os::GetReadableHandleOfSystemEvent(std::addressof(g_hook_to_create_application_process_event));
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
|
@ -702,7 +707,7 @@ namespace ams::pm::impl {
|
|||
if (!g_has_boot_finished) {
|
||||
boot2::LaunchPreSdCardBootProgramsAndBoot2();
|
||||
g_has_boot_finished = true;
|
||||
g_boot_finished_event.Signal();
|
||||
os::SignalSystemEvent(std::addressof(g_boot_finished_event));
|
||||
}
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
@ -712,7 +717,7 @@ namespace ams::pm::impl {
|
|||
/* Nintendo only signals it in safe mode FIRM, and this function aborts on normal FIRM. */
|
||||
/* We will signal it always, but only allow this function to succeed on safe mode. */
|
||||
AMS_ABORT_UNLESS(spl::IsRecoveryBoot());
|
||||
*out = g_boot_finished_event.GetReadableHandle();
|
||||
*out = os::GetReadableHandleOfSystemEvent(std::addressof(g_boot_finished_event));
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace ams::pm::resource {
|
|||
constexpr size_t ExtraSystemMemorySizeAtmosphere500 = 33_MB; /* Applet pool is 0x20100000 */
|
||||
|
||||
/* Globals. */
|
||||
os::Mutex g_resource_limit_lock;
|
||||
os::Mutex g_resource_limit_lock(false);
|
||||
Handle g_resource_limit_handles[ResourceLimitGroup_Count];
|
||||
spl::MemoryArrangement g_memory_arrangement = spl::MemoryArrangement_Standard;
|
||||
u64 g_system_memory_boost_size = 0;
|
||||
|
|
|
@ -97,14 +97,14 @@ namespace ams::spl::impl {
|
|||
|
||||
/* Global variables. */
|
||||
CtrDrbg g_drbg;
|
||||
os::InterruptEvent g_se_event;
|
||||
os::SystemEvent g_se_keyslot_available_event;
|
||||
os::InterruptEventType g_se_event;
|
||||
os::SystemEventType g_se_keyslot_available_event;
|
||||
|
||||
Handle g_se_das_hnd;
|
||||
u32 g_se_mapped_work_buffer_addr;
|
||||
alignas(os::MemoryPageSize) u8 g_work_buffer[2 * WorkBufferSizeMax];
|
||||
|
||||
os::Mutex g_async_op_lock;
|
||||
os::Mutex g_async_op_lock(false);
|
||||
|
||||
const void *g_keyslot_owners[MaxAesKeyslots];
|
||||
BootReasonValue g_boot_reason;
|
||||
|
@ -130,10 +130,10 @@ namespace ams::spl::impl {
|
|||
void InitializeSeEvents() {
|
||||
u64 irq_num;
|
||||
AMS_ABORT_UNLESS(smc::GetConfig(&irq_num, 1, SplConfigItem_SecurityEngineIrqNumber) == smc::Result::Success);
|
||||
R_ABORT_UNLESS(g_se_event.Initialize(irq_num));
|
||||
os::InitializeInterruptEvent(std::addressof(g_se_event), irq_num, os::EventClearMode_AutoClear);
|
||||
|
||||
R_ABORT_UNLESS(g_se_keyslot_available_event.InitializeAsInterProcessEvent());
|
||||
g_se_keyslot_available_event.Signal();
|
||||
R_ABORT_UNLESS(os::CreateSystemEvent(std::addressof(g_se_keyslot_available_event), os::EventClearMode_AutoClear, true));
|
||||
os::SignalSystemEvent(std::addressof(g_se_keyslot_available_event));
|
||||
}
|
||||
|
||||
void InitializeDeviceAddressSpace() {
|
||||
|
@ -173,7 +173,7 @@ namespace ams::spl::impl {
|
|||
|
||||
/* Internal async implementation functionality. */
|
||||
void WaitSeOperationComplete() {
|
||||
g_se_event.Wait();
|
||||
os::WaitInterruptEvent(std::addressof(g_se_event));
|
||||
}
|
||||
|
||||
smc::Result WaitCheckStatus(smc::AsyncOperationKey op_key) {
|
||||
|
@ -596,7 +596,7 @@ namespace ams::spl::impl {
|
|||
}
|
||||
}
|
||||
|
||||
g_se_keyslot_available_event.Reset();
|
||||
os::ClearSystemEvent(std::addressof(g_se_keyslot_available_event));
|
||||
return spl::ResultOutOfKeyslots();
|
||||
}
|
||||
|
||||
|
@ -616,7 +616,7 @@ namespace ams::spl::impl {
|
|||
smc::LoadAesKey(keyslot, access_key, key_source);
|
||||
}
|
||||
g_keyslot_owners[keyslot] = nullptr;
|
||||
g_se_keyslot_available_event.Signal();
|
||||
os::SignalSystemEvent(std::addressof(g_se_keyslot_available_event));
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
|
@ -792,7 +792,7 @@ namespace ams::spl::impl {
|
|||
}
|
||||
|
||||
Handle GetAesKeyslotAvailableEventHandle() {
|
||||
return g_se_keyslot_available_event.GetReadableHandle();
|
||||
return os::GetReadableHandleOfSystemEvent(std::addressof(g_se_keyslot_available_event));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue