os: refactor/rewrite entire namespace.

This commit is contained in:
Michael Scire 2020-04-08 02:21:35 -07:00
parent 6193283f03
commit 065485b971
181 changed files with 5353 additions and 1929 deletions

View file

@ -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));
}
}

View file

@ -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() {

View file

@ -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;
};

View file

@ -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);
}
}

View file

@ -19,6 +19,6 @@
namespace ams::mitm::bpc {
DEFINE_MITM_MODULE_CLASS(0x8000, 32);
DEFINE_MITM_MODULE_CLASS(0x8000, 4);
}

View file

@ -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) {

View file

@ -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];
}

View file

@ -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) {
/* ... */
}

View file

@ -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);
}
}
}

View file

@ -19,6 +19,6 @@
namespace ams::mitm::fs {
DEFINE_MITM_MODULE_CLASS(0x8000, 43);
DEFINE_MITM_MODULE_CLASS(0x8000, 15);
}

View file

@ -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) {

View file

@ -19,6 +19,6 @@
namespace ams::mitm::hid {
DEFINE_MITM_MODULE_CLASS(0x8000, 47);
DEFINE_MITM_MODULE_CLASS(0x8000, 19);
}

View file

@ -19,6 +19,6 @@
namespace ams::mitm::ns {
DEFINE_MITM_MODULE_CLASS(0x4000, 48);
DEFINE_MITM_MODULE_CLASS(0x4000, 20);
}

View file

@ -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:

View file

@ -19,6 +19,6 @@
namespace ams::mitm::settings {
DEFINE_MITM_MODULE_CLASS(0x8000, 43);
DEFINE_MITM_MODULE_CLASS(0x8000, 20);
}

View file

@ -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;
}

View file

@ -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) {

View file

@ -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;
}

View file

@ -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);

View file

@ -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();

View file

@ -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();

View file

@ -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];
}

View file

@ -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);
}
}

View file

@ -18,6 +18,8 @@
namespace ams::dmnt::cheat::impl {
void InitializeCheatManager();
bool GetHasActiveCheatProcess();
Handle GetCheatProcessEventHandle();
Result GetCheatProcessMetadata(CheatProcessMetadata *out);

View file

@ -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);
}
}

View file

@ -18,6 +18,8 @@
namespace ams::dmnt::cheat::impl {
void InitializeDebugEventsManager();
void ContinueCheatProcess(Handle cheat_dbg_hnd);
}

View file

@ -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]));
}
}
}

View file

@ -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;

View file

@ -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)) {

View file

@ -88,7 +88,7 @@ namespace ams::fatal::srv {
}
};
os::WaitableHolder *GetFatalDirtyWaitableHolder();
os::WaitableHolderType *GetFatalDirtyWaitableHolder();
void OnFatalDirtyEvent();
const FatalConfig &GetFatalConfig();

View file

@ -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]));
}
}

View file

@ -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();
};

View file

@ -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;

View file

@ -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];
}

View file

@ -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();
}
}

View file

@ -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));
}
};

View file

@ -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();
}

View file

@ -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));
}
}

View file

@ -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();
}

View file

@ -19,7 +19,7 @@ namespace ams::ldr {
namespace {
os::Mutex g_scoped_code_mount_lock;
os::Mutex g_scoped_code_mount_lock(false);
}

View file

@ -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() {

View file

@ -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));
}
};

View file

@ -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));
}
}

View file

@ -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();
}

View file

@ -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();
}

View file

@ -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;

View file

@ -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));
}
}