diff --git a/stratosphere/ams_mitm/source/fs_mitm/fs_dir_utils.cpp b/stratosphere/ams_mitm/source/fs_mitm/fs_dir_utils.cpp index 8d924971b..7ea9c56fd 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fs_dir_utils.cpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fs_dir_utils.cpp @@ -31,10 +31,8 @@ Result FsDirUtils::CopyFile(IFileSystem *dst_fs, IFileSystem *src_fs, const FsPa /* Create and open destination file. */ { FsPath dst_path; - if (static_cast(snprintf(dst_path.str, sizeof(dst_path.str), "%s%s", dst_parent_path.str, dir_ent->name)) >= sizeof(dst_path)) { - /* TODO: Error code? N aborts here. */ - std::abort(); - } + /* TODO: Error code? N aborts here. */ + STS_ASSERT(static_cast(snprintf(dst_path.str, sizeof(dst_path.str), "%s%s", dst_parent_path.str, dir_ent->name)) < sizeof(dst_path)); R_TRY(dst_fs->CreateFile(dst_path, file_size)); R_TRY(dst_fs->OpenFile(dst_file, dst_path, OpenMode_Write)); diff --git a/stratosphere/ams_mitm/source/fs_mitm/fs_directory_redirection_filesystem.cpp b/stratosphere/ams_mitm/source/fs_mitm/fs_directory_redirection_filesystem.cpp index 3268e2b07..564b40a7e 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fs_directory_redirection_filesystem.cpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fs_directory_redirection_filesystem.cpp @@ -30,20 +30,14 @@ static char *GetNormalizedDirectory(const char *dir_prefix) { /* Ensure terminating '/' */ if (normal_path[normal_path_len-1] != '/') { - if (normal_path_len + 2 > sizeof(normal_path)) { - std::abort(); - } - + STS_ASSERT(normal_path_len + 2 <= sizeof(normal_path)); strncat(normal_path, "/", 2); normal_path[sizeof(normal_path)-1] = 0; normal_path_len++; } - char *output = static_cast(malloc(normal_path_len + 1)); - if (output == nullptr) { - std::abort(); - /* TODO: Result error code? */ - } + char *output = static_cast(std::malloc(normal_path_len + 1)); + STS_ASSERT(output != nullptr); std::strncpy(output, normal_path, normal_path_len + 1); output[normal_path_len] = 0; diff --git a/stratosphere/ams_mitm/source/fs_mitm/fs_path_utils.cpp b/stratosphere/ams_mitm/source/fs_mitm/fs_path_utils.cpp index b3d282334..32c587695 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fs_path_utils.cpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fs_path_utils.cpp @@ -261,9 +261,7 @@ Result FsPathUtils::Normalize(char *out, size_t max_out_size, const char *src, s /* Assert normalized. */ bool normalized = false; R_ASSERT(FsPathUtils::IsNormalized(&normalized, out)); - if (!normalized) { - std::abort(); - } + STS_ASSERT(normalized); return ResultSuccess; } diff --git a/stratosphere/ams_mitm/source/fs_mitm/fs_subdirectory_filesystem.cpp b/stratosphere/ams_mitm/source/fs_mitm/fs_subdirectory_filesystem.cpp index 6da23c798..9a7cc9793 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fs_subdirectory_filesystem.cpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fs_subdirectory_filesystem.cpp @@ -34,9 +34,7 @@ Result SubDirectoryFileSystem::Initialize(const char *bp) { /* Ensure terminating '/' */ if (normal_path[normal_path_len-1] != '/') { - if (normal_path_len + 2 > sizeof(normal_path)) { - std::abort(); - } + STS_ASSERT(normal_path_len + 2 <= sizeof(normal_path)); strncat(normal_path, "/", 2); normal_path[sizeof(normal_path)-1] = 0; diff --git a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_layeredrom.cpp b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_layeredrom.cpp index 4558a8ccd..f5abdde40 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_layeredrom.cpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_layeredrom.cpp @@ -93,9 +93,7 @@ Result LayeredRomFS::Read(void *buffer, size_t size, u64 offset) { R_ASSERT(Utils::OpenSdFileForAtmosphere(this->title_id, ROMFS_METADATA_FILE_PATH, FS_OPEN_READ, &file)); size_t out_read; R_ASSERT(fsFileRead(&file, (offset - cur_source->virtual_offset), (void *)((uintptr_t)buffer + read_so_far), cur_read_size, FS_READOPTION_NONE, &out_read)); - if (out_read != cur_read_size) { - std::abort(); - } + STS_ASSERT(out_read == cur_read_size); fsFileClose(&file); } break; @@ -105,9 +103,7 @@ Result LayeredRomFS::Read(void *buffer, size_t size, u64 offset) { R_ASSERT(Utils::OpenRomFSSdFile(this->title_id, cur_source->loose_source_info.path, FS_OPEN_READ, &file)); size_t out_read; R_ASSERT(fsFileRead(&file, (offset - cur_source->virtual_offset), (void *)((uintptr_t)buffer + read_so_far), cur_read_size, FS_READOPTION_NONE, &out_read)); - if (out_read != cur_read_size) { - std::abort(); - } + STS_ASSERT(out_read == cur_read_size); fsFileClose(&file); } break; diff --git a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfsbuild.cpp b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfsbuild.cpp index a7de93965..6fe31b3ac 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfsbuild.cpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfsbuild.cpp @@ -39,6 +39,7 @@ void RomFSBuildContext::VisitDirectory(FsFileSystem *filesys, RomFSBuildDirector break; } + STS_ASSERT(this->dir_entry.type == ENTRYTYPE_DIR || this->dir_entry.type == ENTRYTYPE_FILE); if (this->dir_entry.type == ENTRYTYPE_DIR) { RomFSBuildDirectoryContext *child = new RomFSBuildDirectoryContext({0}); /* Set child's path. */ @@ -58,7 +59,7 @@ void RomFSBuildContext::VisitDirectory(FsFileSystem *filesys, RomFSBuildDirector } else { child_dirs.push_back(child); } - } else if (this->dir_entry.type == ENTRYTYPE_FILE) { + } else /* if (this->dir_entry.type == ENTRYTYPE_FILE) */ { RomFSBuildFileContext *child = new RomFSBuildFileContext({0}); /* Set child's path. */ child->cur_path_ofs = parent->path_len + 1; @@ -79,8 +80,6 @@ void RomFSBuildContext::VisitDirectory(FsFileSystem *filesys, RomFSBuildDirector delete[] child->path; delete child; } - } else { - std::abort(); } } } @@ -180,10 +179,7 @@ void RomFSBuildContext::VisitDirectory(RomFSBuildDirectoryContext *parent, u32 p void RomFSBuildContext::MergeRomStorage(IROStorage *storage, RomFSDataSource source) { RomFSHeader header; R_ASSERT(storage->Read(&header, sizeof(header), 0)); - if (header.header_size != sizeof(header)) { - /* what */ - std::abort(); - } + STS_ASSERT(header.header_size == sizeof(header)); /* Read tables. */ auto dir_table = std::make_unique(header.dir_table_size); diff --git a/stratosphere/ams_mitm/source/set_mitm/setsys_firmware_version.cpp b/stratosphere/ams_mitm/source/set_mitm/setsys_firmware_version.cpp index 88153fd52..43b32d57f 100644 --- a/stratosphere/ams_mitm/source/set_mitm/setsys_firmware_version.cpp +++ b/stratosphere/ams_mitm/source/set_mitm/setsys_firmware_version.cpp @@ -40,16 +40,11 @@ void VersionManager::Initialize() { /* Firmware version file must exist. */ FILE *f = fopen("sysver:/file", "rb"); - if (f == NULL) { - std::abort(); - } + STS_ASSERT(f != NULL); + ON_SCOPE_EXIT { fclose(f); }; /* Must be possible to read firmware version from file. */ - if (fread(&fw_ver, sizeof(fw_ver), 1, f) != 1) { - std::abort(); - } - - fclose(f); + STS_ASSERT(fread(&fw_ver, sizeof(fw_ver), 1, f) == 1); g_fw_version = fw_ver; g_ams_fw_version = fw_ver; diff --git a/stratosphere/boot/source/boot_boot_reason.cpp b/stratosphere/boot/source/boot_boot_reason.cpp index d78ef8a4c..c72e681ec 100644 --- a/stratosphere/boot/source/boot_boot_reason.cpp +++ b/stratosphere/boot/source/boot_boot_reason.cpp @@ -75,26 +75,16 @@ namespace sts::boot { /* Get values from PMIC. */ { PmicDriver pmic_driver; - if (R_FAILED(pmic_driver.GetPowerIntr(&power_intr))) { - std::abort(); - } - if (R_FAILED(pmic_driver.GetNvErc(&nv_erc))) { - std::abort(); - } - if (R_FAILED(pmic_driver.GetAcOk(&ac_ok))) { - std::abort(); - } + R_ASSERT(pmic_driver.GetPowerIntr(&power_intr)); + R_ASSERT(pmic_driver.GetNvErc(&nv_erc)); + R_ASSERT(pmic_driver.GetAcOk(&ac_ok)); } /* Get values from RTC. */ { RtcDriver rtc_driver; - if (R_FAILED(rtc_driver.GetRtcIntr(&rtc_intr))) { - std::abort(); - } - if (R_FAILED(rtc_driver.GetRtcIntrM(&rtc_intr_m))) { - std::abort(); - } + R_ASSERT(rtc_driver.GetRtcIntr(&rtc_intr)); + R_ASSERT(rtc_driver.GetRtcIntrM(&rtc_intr_m)); } /* Set global derived boot reason. */ @@ -107,19 +97,14 @@ namespace sts::boot { boot_reason_value.rtc_intr = rtc_intr & ~rtc_intr_m; boot_reason_value.nv_erc = nv_erc; boot_reason_value.boot_reason = g_boot_reason; - if (R_FAILED(splSetBootReason(boot_reason_value.value))) { - std::abort(); - } + R_ASSERT(splSetBootReason(boot_reason_value.value)); } g_detected_boot_reason = true; } u32 GetBootReason() { - if (!g_detected_boot_reason) { - std::abort(); - } - + STS_ASSERT(g_detected_boot_reason); return g_boot_reason; } diff --git a/stratosphere/boot/source/boot_bq24193_charger.hpp b/stratosphere/boot/source/boot_bq24193_charger.hpp index 4f2f91de6..768bbeb88 100644 --- a/stratosphere/boot/source/boot_bq24193_charger.hpp +++ b/stratosphere/boot/source/boot_bq24193_charger.hpp @@ -38,9 +38,9 @@ namespace sts::boot::bq24193 { constexpr u32 ChargeVoltageLimitMax = 4208; inline u8 EncodeChargeVoltageLimit(u32 voltage) { - if (voltage < ChargeVoltageLimitMin || voltage > ChargeVoltageLimitMax) { - std::abort(); - } + STS_ASSERT(voltage >= ChargeVoltageLimitMin); + STS_ASSERT(voltage <= ChargeVoltageLimitMax); + voltage -= ChargeVoltageLimitMin; voltage >>= 4; return static_cast(voltage << 2); @@ -54,9 +54,9 @@ namespace sts::boot::bq24193 { constexpr u32 FastChargeCurrentLimitMax = 4544; inline u8 EncodeFastChargeCurrentLimit(u32 current) { - if (current < FastChargeCurrentLimitMin || current > FastChargeCurrentLimitMax) { - std::abort(); - } + STS_ASSERT(current >= FastChargeCurrentLimitMin); + STS_ASSERT(current <= FastChargeCurrentLimitMax); + current -= FastChargeCurrentLimitMin; current >>= 6; return static_cast(current << 2); @@ -81,9 +81,9 @@ namespace sts::boot::bq24193 { constexpr u32 PreChargeCurrentLimitMax = 2048; inline u8 EncodePreChargeCurrentLimit(u32 current) { - if (current < PreChargeCurrentLimitMin || current > PreChargeCurrentLimitMax) { - std::abort(); - } + STS_ASSERT(current >= PreChargeCurrentLimitMin); + STS_ASSERT(current <= PreChargeCurrentLimitMax); + current -= PreChargeCurrentLimitMin; current >>= 7; return static_cast(current << 4); @@ -97,9 +97,9 @@ namespace sts::boot::bq24193 { constexpr u32 TerminationCurrentLimitMax = 2048; inline u8 EncodeTerminationCurrentLimit(u32 current) { - if (current < TerminationCurrentLimitMin || current > TerminationCurrentLimitMax) { - std::abort(); - } + STS_ASSERT(current >= TerminationCurrentLimitMin); + STS_ASSERT(current <= TerminationCurrentLimitMax); + current -= TerminationCurrentLimitMin; current >>= 7; return static_cast(current); @@ -113,9 +113,9 @@ namespace sts::boot::bq24193 { constexpr u32 MinimumSystemVoltageLimitMax = 3700; inline u8 EncodeMinimumSystemVoltageLimit(u32 voltage) { - if (voltage < MinimumSystemVoltageLimitMin || voltage > MinimumSystemVoltageLimitMax) { - std::abort(); - } + STS_ASSERT(voltage >= MinimumSystemVoltageLimitMin); + STS_ASSERT(voltage <= MinimumSystemVoltageLimitMax); + voltage -= MinimumSystemVoltageLimitMin; voltage /= 100; return static_cast(voltage << 1); diff --git a/stratosphere/boot/source/boot_calibration.cpp b/stratosphere/boot/source/boot_calibration.cpp index a732c283c..06d2105c2 100644 --- a/stratosphere/boot/source/boot_calibration.cpp +++ b/stratosphere/boot/source/boot_calibration.cpp @@ -38,9 +38,7 @@ namespace sts::boot { 0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400 }; - if (data == nullptr) { - std::abort(); - } + STS_ASSERT(data != nullptr); u16 crc16 = 0x55AA; const u8 *data_u8 = reinterpret_cast(data); diff --git a/stratosphere/boot/source/boot_display.cpp b/stratosphere/boot/source/boot_display.cpp index d158bc5b5..bb4cdb354 100644 --- a/stratosphere/boot/source/boot_display.cpp +++ b/stratosphere/boot/source/boot_display.cpp @@ -103,12 +103,15 @@ namespace sts::boot { inline void DoDsiSleepOrRegisterWrites(const DsiSleepOrRegisterWrite *reg_writes, size_t num_writes) { for (size_t i = 0; i < num_writes; i++) { - if (reg_writes[i].kind == DsiSleepOrRegisterWriteKind_Write) { - reg::Write(g_dsi_regs + sizeof(u32) * reg_writes[i].offset, reg_writes[i].value); - } else if (reg_writes[i].kind == DsiSleepOrRegisterWriteKind_Sleep) { - svcSleepThread(1'000'000ul * u64(reg_writes[i].offset)); - } else { - std::abort(); + switch (reg_writes[i].kind) { + case DsiSleepOrRegisterWriteKind_Write: + reg::Write(g_dsi_regs + sizeof(u32) * reg_writes[i].offset, reg_writes[i].value); + break; + case DsiSleepOrRegisterWriteKind_Sleep: + svcSleepThread(1'000'000ul * u64(reg_writes[i].offset)); + break; + default: + std::abort(); } } } @@ -130,18 +133,12 @@ namespace sts::boot { constexpr u64 DeviceName_DC = 2; /* Create Address Space. */ - if (R_FAILED(svcCreateDeviceAddressSpace(&g_dc_das_hnd, 0, (1ul << 32)))) { - std::abort(); - } + R_ASSERT(svcCreateDeviceAddressSpace(&g_dc_das_hnd, 0, (1ul << 32))); /* Attach it to the DC. */ - if (R_FAILED(svcAttachDeviceAddressSpace(DeviceName_DC, g_dc_das_hnd))) { - std::abort(); - } + R_ASSERT(svcAttachDeviceAddressSpace(DeviceName_DC, g_dc_das_hnd)); /* Map the framebuffer for the DC as read-only. */ - if (R_FAILED(svcMapDeviceAddressSpaceAligned(g_dc_das_hnd, CUR_PROCESS_HANDLE, frame_buffer_aligned, FrameBufferSize, FrameBufferPaddr, 1))) { - std::abort(); - } + R_ASSERT(svcMapDeviceAddressSpaceAligned(g_dc_das_hnd, CUR_PROCESS_HANDLE, frame_buffer_aligned, FrameBufferSize, FrameBufferPaddr, 1)); } } @@ -151,17 +148,11 @@ namespace sts::boot { constexpr u64 DeviceName_DC = 2; /* Unmap the framebuffer from the DC. */ - if (R_FAILED(svcUnmapDeviceAddressSpace(g_dc_das_hnd, CUR_PROCESS_HANDLE, frame_buffer_aligned, FrameBufferSize, FrameBufferPaddr))) { - std::abort(); - } + R_ASSERT(svcUnmapDeviceAddressSpace(g_dc_das_hnd, CUR_PROCESS_HANDLE, frame_buffer_aligned, FrameBufferSize, FrameBufferPaddr)); /* Detach address space from the DC. */ - if (R_FAILED(svcDetachDeviceAddressSpace(DeviceName_DC, g_dc_das_hnd))) { - std::abort(); - } + R_ASSERT(svcDetachDeviceAddressSpace(DeviceName_DC, g_dc_das_hnd)); /* Close the address space. */ - if (R_FAILED(svcCloseHandle(g_dc_das_hnd))) { - std::abort(); - } + R_ASSERT(svcCloseHandle(g_dc_das_hnd)); g_dc_das_hnd = INVALID_HANDLE; g_frame_buffer = nullptr; } @@ -300,8 +291,8 @@ namespace sts::boot { for (size_t i = 0; i < util::size(host_response); i++) { host_response[i] = reg::Read(g_dsi_regs + sizeof(u32) * DSI_RD_DATA); } - - /* The last word from host response is: + + /* The last word from host response is: Bits 0-7: FAB Bits 8-15: REV Bits 16-23: Minor REV diff --git a/stratosphere/boot/source/boot_i2c_utils.cpp b/stratosphere/boot/source/boot_i2c_utils.cpp index 13aa2b5f5..86138ad1f 100644 --- a/stratosphere/boot/source/boot_i2c_utils.cpp +++ b/stratosphere/boot/source/boot_i2c_utils.cpp @@ -41,9 +41,8 @@ namespace sts::boot { } Result ReadI2cRegister(i2c::driver::Session &session, u8 *dst, size_t dst_size, const u8 *cmd, size_t cmd_size) { - if (dst == nullptr || dst_size == 0 || cmd == nullptr || cmd_size == 0) { - std::abort(); - } + STS_ASSERT(dst != nullptr && dst_size > 0); + STS_ASSERT(cmd != nullptr && cmd_size > 0); u8 cmd_list[i2c::CommandListFormatter::MaxCommandListSize]; @@ -55,9 +54,8 @@ namespace sts::boot { } Result WriteI2cRegister(i2c::driver::Session &session, const u8 *src, size_t src_size, const u8 *cmd, size_t cmd_size) { - if (src == nullptr || src_size == 0 || cmd == nullptr || cmd_size == 0) { - std::abort(); - } + STS_ASSERT(src != nullptr && src_size > 0); + STS_ASSERT(cmd != nullptr && cmd_size > 0); u8 cmd_list[0x20]; diff --git a/stratosphere/boot/source/boot_pmc_wrapper.cpp b/stratosphere/boot/source/boot_pmc_wrapper.cpp index 1719d5430..2cdb2a467 100644 --- a/stratosphere/boot/source/boot_pmc_wrapper.cpp +++ b/stratosphere/boot/source/boot_pmc_wrapper.cpp @@ -39,9 +39,7 @@ namespace sts::boot { args.X[2] = mask; args.X[3] = value; R_ASSERT(svcCallSecureMonitor(&args)); - if (args.X[0] != 0) { - std::abort(); - } + STS_ASSERT(args.X[0] == 0); return static_cast(args.X[1]); } @@ -49,18 +47,12 @@ namespace sts::boot { } u32 ReadPmcRegister(u32 phys_addr) { - if (!IsValidPmcAddress(phys_addr)) { - std::abort(); - } - + STS_ASSERT(IsValidPmcAddress(phys_addr)); return SmcAtmosphereReadWriteRegister(phys_addr, 0, 0); } void WritePmcRegister(u32 phys_addr, u32 value, u32 mask) { - if (!IsValidPmcAddress(phys_addr)) { - std::abort(); - } - + STS_ASSERT(IsValidPmcAddress(phys_addr)); SmcAtmosphereReadWriteRegister(phys_addr, value, mask); } diff --git a/stratosphere/boot/source/gpio/gpio_initial_configuration.cpp b/stratosphere/boot/source/gpio/gpio_initial_configuration.cpp index d16e5802d..efccbf28c 100644 --- a/stratosphere/boot/source/gpio/gpio_initial_configuration.cpp +++ b/stratosphere/boot/source/gpio/gpio_initial_configuration.cpp @@ -80,9 +80,7 @@ namespace sts::gpio { } /* Ensure we found an appropriate config. */ - if (configs == nullptr) { - std::abort(); - } + STS_ASSERT(configs != nullptr); for (size_t i = 0; i < num_configs; i++) { /* Configure the GPIO. */ diff --git a/stratosphere/boot/source/gpio/gpio_utils.cpp b/stratosphere/boot/source/gpio/gpio_utils.cpp index 778f3a98d..f0ff57750 100644 --- a/stratosphere/boot/source/gpio/gpio_utils.cpp +++ b/stratosphere/boot/source/gpio/gpio_utils.cpp @@ -33,10 +33,7 @@ namespace sts::gpio { /* Helpers. */ inline u32 GetPadDescriptor(u32 gpio_pad_name) { - if (gpio_pad_name >= PadNameMax) { - std::abort(); - } - + STS_ASSERT(gpio_pad_name < PadNameMax); return Map[gpio_pad_name]; } diff --git a/stratosphere/boot/source/i2c/driver/i2c_api.cpp b/stratosphere/boot/source/i2c/driver/i2c_api.cpp index 37f866226..47824ebf8 100644 --- a/stratosphere/boot/source/i2c/driver/i2c_api.cpp +++ b/stratosphere/boot/source/i2c/driver/i2c_api.cpp @@ -88,9 +88,7 @@ namespace sts::i2c::driver { } inline void CheckInitialized() { - if (!GetResourceManager().IsInitialized()) { - std::abort(); - } + STS_ASSERT(GetResourceManager().IsInitialized()); } } @@ -107,9 +105,7 @@ namespace sts::i2c::driver { /* Session management. */ void OpenSession(Session *out_session, I2cDevice device) { CheckInitialized(); - if (!impl::IsDeviceSupported(device)) { - std::abort(); - } + STS_ASSERT(impl::IsDeviceSupported(device)); const auto bus = impl::GetDeviceBus(device); const auto slave_address = impl::GetDeviceSlaveAddress(device); @@ -128,9 +124,8 @@ namespace sts::i2c::driver { /* Communication. */ Result Send(Session &session, const void *src, size_t size, I2cTransactionOption option) { CheckInitialized(); - if (src == nullptr || size == 0) { - std::abort(); - } + STS_ASSERT(src != nullptr); + STS_ASSERT(size > 0); std::scoped_lock lk(GetResourceManager().GetTransactionMutex(impl::ConvertFromIndex(session.bus_idx))); return GetResourceManager().GetSession(session.session_id).DoTransactionWithRetry(nullptr, src, size, option, impl::Command::Send); @@ -138,9 +133,8 @@ namespace sts::i2c::driver { Result Receive(Session &session, void *dst, size_t size, I2cTransactionOption option) { CheckInitialized(); - if (dst == nullptr || size == 0) { - std::abort(); - } + STS_ASSERT(dst != nullptr); + STS_ASSERT(size > 0); std::scoped_lock lk(GetResourceManager().GetTransactionMutex(impl::ConvertFromIndex(session.bus_idx))); return GetResourceManager().GetSession(session.session_id).DoTransactionWithRetry(dst, nullptr, size, option, impl::Command::Receive); @@ -148,9 +142,8 @@ namespace sts::i2c::driver { Result ExecuteCommandList(Session &session, void *dst, size_t size, const void *cmd_list, size_t cmd_list_size) { CheckInitialized(); - if (dst == nullptr || size == 0 || cmd_list == nullptr || cmd_list_size == 0) { - std::abort(); - } + STS_ASSERT(dst != nullptr && size > 0); + STS_ASSERT(cmd_list != nullptr && cmd_list_size > 0); u8 *cur_dst = static_cast(dst); const u8 *cur_cmd = static_cast(cmd_list); @@ -158,9 +151,7 @@ namespace sts::i2c::driver { while (cur_cmd < cmd_list_end) { Command cmd = static_cast((*cur_cmd) & 3); - if (cmd >= Command::Count) { - std::abort(); - } + STS_ASSERT(cmd < Command::Count); R_TRY(g_cmd_handlers[static_cast(cmd)](&cur_cmd, &cur_dst, session)); } diff --git a/stratosphere/boot/source/i2c/driver/impl/i2c_bus_accessor.cpp b/stratosphere/boot/source/i2c/driver/impl/i2c_bus_accessor.cpp index f248127f3..cedc570a8 100644 --- a/stratosphere/boot/source/i2c/driver/impl/i2c_bus_accessor.cpp +++ b/stratosphere/boot/source/i2c/driver/impl/i2c_bus_accessor.cpp @@ -29,9 +29,7 @@ namespace sts::i2c::driver::impl { /* Ensure we're good if this isn't our first session. */ if (this->open_sessions > 1) { - if (this->speed_mode != speed_mode) { - std::abort(); - } + STS_ASSERT(this->speed_mode == speed_mode); return; } @@ -58,7 +56,7 @@ namespace sts::i2c::driver::impl { } /* Close interrupt event. */ - eventClose(&this->interrupt_event); + this->interrupt_event.Finalize(); /* Close PCV. */ pcv::Finalize(); @@ -158,10 +156,10 @@ namespace sts::i2c::driver::impl { break; } - eventClear(&this->interrupt_event); - if (R_FAILED(eventWait(&this->interrupt_event, InterruptTimeout))) { + this->interrupt_event.Reset(); + if (!this->interrupt_event.TimedWait(InterruptTimeout)) { this->HandleTransactionResult(ResultI2cBusBusy); - eventClear(&this->interrupt_event); + this->interrupt_event.Reset(); return ResultI2cTimedOut; } @@ -181,10 +179,10 @@ namespace sts::i2c::driver::impl { break; } - eventClear(&this->interrupt_event); - if (R_FAILED(eventWait(&this->interrupt_event, InterruptTimeout))) { + this->interrupt_event.Reset(); + if (!this->interrupt_event.TimedWait(InterruptTimeout)) { this->HandleTransactionResult(ResultI2cBusBusy); - eventClear(&this->interrupt_event); + this->interrupt_event.Reset(); return ResultI2cTimedOut; } } @@ -206,11 +204,11 @@ namespace sts::i2c::driver::impl { /* Receive bytes. */ while (remaining > 0) { - eventClear(&this->interrupt_event); - if (R_FAILED(eventWait(&this->interrupt_event, InterruptTimeout))) { + this->interrupt_event.Reset(); + if (!this->interrupt_event.TimedWait(InterruptTimeout)) { this->HandleTransactionResult(ResultI2cBusBusy); this->ClearInterruptMask(); - eventClear(&this->interrupt_event); + this->interrupt_event.Reset(); return ResultI2cTimedOut; } @@ -245,16 +243,9 @@ namespace sts::i2c::driver::impl { static constexpr u64 s_interrupts[] = { 0x46, 0x74, 0x7C, 0x98, 0x55, 0x5F }; - if (ConvertToIndex(bus) >= util::size(s_interrupts)) { - std::abort(); - } - - Handle evt_h; - if (R_FAILED(svcCreateInterruptEvent(&evt_h, s_interrupts[ConvertToIndex(bus)], 1))) { - std::abort(); - } - - eventLoadRemote(&this->interrupt_event, evt_h, false); + const auto index = ConvertToIndex(bus); + STS_ASSERT(index < util::size(s_interrupts)); + R_ASSERT(this->interrupt_event.Initialize(s_interrupts[index], false)); } void BusAccessor::SetClock(SpeedMode speed_mode) { @@ -307,29 +298,17 @@ namespace sts::i2c::driver::impl { reg::Read(&this->i2c_registers->I2C_I2C_CNFG_0); if (this->pcv_module != PcvModule_I2C5) { - if (R_FAILED(pcv::SetReset(this->pcv_module, true))) { - std::abort(); - } - if (R_FAILED(pcv::SetClockRate(this->pcv_module, (408'000'000) / (src_div + 1)))) { - std::abort(); - } - if (R_FAILED(pcv::SetReset(this->pcv_module, false))) { - std::abort(); - } + R_ASSERT(pcv::SetReset(this->pcv_module, true)); + R_ASSERT(pcv::SetClockRate(this->pcv_module, (408'000'000) / (src_div + 1))); + R_ASSERT(pcv::SetReset(this->pcv_module, false)); } } void BusAccessor::ResetController() const { if (this->pcv_module != PcvModule_I2C5) { - if (R_FAILED(pcv::SetReset(this->pcv_module, true))) { - std::abort(); - } - if (R_FAILED(pcv::SetClockRate(this->pcv_module, 81'600'000))) { - std::abort(); - } - if (R_FAILED(pcv::SetReset(this->pcv_module, false))) { - std::abort(); - } + R_ASSERT(pcv::SetReset(this->pcv_module, true)); + R_ASSERT(pcv::SetClockRate(this->pcv_module, 81'600'000)); + R_ASSERT(pcv::SetReset(this->pcv_module, false)); } } @@ -388,9 +367,7 @@ namespace sts::i2c::driver::impl { } void BusAccessor::DisableClock() { - if (R_FAILED(pcv::SetClockEnabled(this->pcv_module, false))) { - std::abort(); - } + R_ASSERT(pcv::SetClockEnabled(this->pcv_module, false)); } void BusAccessor::SetPacketMode() { @@ -435,24 +412,21 @@ namespace sts::i2c::driver::impl { } void BusAccessor::HandleTransactionResult(Result result) { - if (R_FAILED(result)) { - if (result == ResultI2cNoAck || result == ResultI2cBusBusy) { + R_TRY_CATCH(result) { + R_CATCH_MANY(ResultI2cNoAck, ResultI2cBusBusy) { this->ResetController(); this->SetClock(this->speed_mode); this->SetPacketMode(); this->FlushFifos(); - } else { - std::abort(); } - } + } R_END_TRY_CATCH_WITH_ASSERT; } Result BusAccessor::GetAndHandleTransactionResult() { - const Result transaction_res = this->GetTransactionResult(); - R_TRY_CLEANUP(transaction_res, { - this->HandleTransactionResult(transaction_res); + R_TRY_CLEANUP(this->GetTransactionResult(), { + this->HandleTransactionResult(R_CLEANUP_RESULT); this->ClearInterruptMask(); - eventClear(&this->interrupt_event); + this->interrupt_event.Reset(); }); return ResultSuccess; } diff --git a/stratosphere/boot/source/i2c/driver/impl/i2c_bus_accessor.hpp b/stratosphere/boot/source/i2c/driver/impl/i2c_bus_accessor.hpp index a039434fb..c7f75ccea 100644 --- a/stratosphere/boot/source/i2c/driver/impl/i2c_bus_accessor.hpp +++ b/stratosphere/boot/source/i2c/driver/impl/i2c_bus_accessor.hpp @@ -31,7 +31,7 @@ namespace sts::i2c::driver::impl { }; static constexpr u64 InterruptTimeout = 100'000'000ul; private: - Event interrupt_event; + os::InterruptEvent interrupt_event; os::Mutex open_mutex; os::Mutex register_mutex; Registers *i2c_registers = nullptr; diff --git a/stratosphere/boot/source/i2c/driver/impl/i2c_device_config.cpp b/stratosphere/boot/source/i2c/driver/impl/i2c_device_config.cpp index 870131362..a80f6c017 100644 --- a/stratosphere/boot/source/i2c/driver/impl/i2c_device_config.cpp +++ b/stratosphere/boot/source/i2c/driver/impl/i2c_device_config.cpp @@ -88,37 +88,37 @@ namespace sts::i2c::driver::impl { Bus GetDeviceBus(I2cDevice dev) { const size_t dev_idx = GetDeviceIndex(dev); - if (dev_idx == DeviceInvalidIndex) { std::abort(); } + STS_ASSERT(dev_idx != DeviceInvalidIndex); return g_device_configs[dev_idx].bus; } u32 GetDeviceSlaveAddress(I2cDevice dev) { const size_t dev_idx = GetDeviceIndex(dev); - if (dev_idx == DeviceInvalidIndex) { std::abort(); } + STS_ASSERT(dev_idx != DeviceInvalidIndex); return g_device_configs[dev_idx].slave_address; } AddressingMode GetDeviceAddressingMode(I2cDevice dev) { const size_t dev_idx = GetDeviceIndex(dev); - if (dev_idx == DeviceInvalidIndex) { std::abort(); } + STS_ASSERT(dev_idx != DeviceInvalidIndex); return g_device_configs[dev_idx].addressing_mode; } SpeedMode GetDeviceSpeedMode(I2cDevice dev) { const size_t dev_idx = GetDeviceIndex(dev); - if (dev_idx == DeviceInvalidIndex) { std::abort(); } + STS_ASSERT(dev_idx != DeviceInvalidIndex); return g_device_configs[dev_idx].speed_mode; } u32 GetDeviceMaxRetries(I2cDevice dev) { const size_t dev_idx = GetDeviceIndex(dev); - if (dev_idx == DeviceInvalidIndex) { std::abort(); } + STS_ASSERT(dev_idx != DeviceInvalidIndex); return g_device_configs[dev_idx].max_retries; } u64 GetDeviceRetryWaitTime(I2cDevice dev) { const size_t dev_idx = GetDeviceIndex(dev); - if (dev_idx == DeviceInvalidIndex) { std::abort(); } + STS_ASSERT(dev_idx != DeviceInvalidIndex); return g_device_configs[dev_idx].retry_wait_time; } diff --git a/stratosphere/boot/source/i2c/driver/impl/i2c_driver_types.hpp b/stratosphere/boot/source/i2c/driver/impl/i2c_driver_types.hpp index 5fb2ec0e1..d6d014870 100644 --- a/stratosphere/boot/source/i2c/driver/impl/i2c_driver_types.hpp +++ b/stratosphere/boot/source/i2c/driver/impl/i2c_driver_types.hpp @@ -43,9 +43,7 @@ namespace sts::i2c::driver::impl { } constexpr inline Bus ConvertFromIndex(size_t idx) { - if (idx >= static_cast(Bus::Count)) { - std::abort(); - } + STS_ASSERT(idx < static_cast(Bus::Count)); return static_cast(idx); } diff --git a/stratosphere/boot/source/i2c/driver/impl/i2c_resource_manager.cpp b/stratosphere/boot/source/i2c/driver/impl/i2c_resource_manager.cpp index 1e0d3b920..b35d5e875 100644 --- a/stratosphere/boot/source/i2c/driver/impl/i2c_resource_manager.cpp +++ b/stratosphere/boot/source/i2c/driver/impl/i2c_resource_manager.cpp @@ -29,9 +29,7 @@ namespace sts::i2c::driver::impl { void ResourceManager::Finalize() { std::scoped_lock lk(this->initialize_mutex); - if (this->ref_cnt == 0) { - std::abort(); - } + STS_ASSERT(this->ref_cnt > 0); this->ref_cnt--; if (this->ref_cnt > 0) { return; @@ -61,14 +59,11 @@ namespace sts::i2c::driver::impl { /* Get, open session. */ { std::scoped_lock lk(this->session_open_mutex); - if (out_session == nullptr || bus >= Bus::Count) { - std::abort(); - } + STS_ASSERT(out_session != nullptr); + STS_ASSERT(bus < Bus::Count); session_id = GetFreeSessionId(); - if (session_id == InvalidSessionId) { - std::abort(); - } + STS_ASSERT(session_id != InvalidSessionId); if ((bus == Bus::I2C2 || bus == Bus::I2C3) && (this->bus_accessors[ConvertToIndex(Bus::I2C2)].GetOpenSessions() == 0 && this->bus_accessors[ConvertToIndex(Bus::I2C3)].GetOpenSessions() == 0)) { @@ -83,12 +78,8 @@ namespace sts::i2c::driver::impl { this->sessions[session_id].Start(); if (need_enable_ldo6) { pcv::Initialize(); - if (R_FAILED(pcv::SetVoltageValue(10, 2'900'000))) { - std::abort(); - } - if (R_FAILED(pcv::SetVoltageEnabled(10, true))) { - std::abort(); - } + R_ASSERT(pcv::SetVoltageValue(10, 2'900'000)); + R_ASSERT(pcv::SetVoltageEnabled(10, true)); pcv::Finalize(); svcSleepThread(560'000ul); } @@ -99,9 +90,7 @@ namespace sts::i2c::driver::impl { /* Get, open session. */ { std::scoped_lock lk(this->session_open_mutex); - if (!this->sessions[session.session_id].IsOpen()) { - std::abort(); - } + STS_ASSERT(this->sessions[session.session_id].IsOpen()); this->sessions[session.session_id].Close(); @@ -113,18 +102,14 @@ namespace sts::i2c::driver::impl { if (need_disable_ldo6) { pcv::Initialize(); - if (R_FAILED(pcv::SetVoltageEnabled(10, false))) { - std::abort(); - } + R_ASSERT(pcv::SetVoltageEnabled(10, false)); pcv::Finalize(); } } void ResourceManager::SuspendBuses() { - if (this->ref_cnt == 0) { - std::abort(); - } + STS_ASSERT(this->ref_cnt > 0); if (!this->suspended) { { @@ -137,27 +122,19 @@ namespace sts::i2c::driver::impl { } } pcv::Initialize(); - if (R_FAILED(pcv::SetVoltageEnabled(10, false))) { - std::abort(); - } + R_ASSERT(pcv::SetVoltageEnabled(10, false)); pcv::Finalize(); } } void ResourceManager::ResumeBuses() { - if (this->ref_cnt == 0) { - std::abort(); - } + STS_ASSERT(this->ref_cnt > 0); if (this->suspended) { if (this->bus_accessors[ConvertToIndex(Bus::I2C2)].GetOpenSessions() > 0 || this->bus_accessors[ConvertToIndex(Bus::I2C3)].GetOpenSessions() > 0) { pcv::Initialize(); - if (R_FAILED(pcv::SetVoltageValue(10, 2'900'000))) { - std::abort(); - } - if (R_FAILED(pcv::SetVoltageEnabled(10, true))) { - std::abort(); - } + R_ASSERT(pcv::SetVoltageValue(10, 2'900'000)); + R_ASSERT(pcv::SetVoltageEnabled(10, true)); pcv::Finalize(); svcSleepThread(1'560'000ul); } @@ -174,9 +151,7 @@ namespace sts::i2c::driver::impl { } void ResourceManager::SuspendPowerBus() { - if (this->ref_cnt == 0) { - std::abort(); - } + STS_ASSERT(this->ref_cnt > 0); std::scoped_lock lk(this->session_open_mutex); if (!this->power_bus_suspended) { @@ -188,9 +163,7 @@ namespace sts::i2c::driver::impl { } void ResourceManager::ResumePowerBus() { - if (this->ref_cnt == 0) { - std::abort(); - } + STS_ASSERT(this->ref_cnt > 0); std::scoped_lock lk(this->session_open_mutex); if (this->power_bus_suspended) { diff --git a/stratosphere/boot/source/i2c/i2c_command_list.hpp b/stratosphere/boot/source/i2c/i2c_command_list.hpp index 4ca94c881..6689f4885 100644 --- a/stratosphere/boot/source/i2c/i2c_command_list.hpp +++ b/stratosphere/boot/source/i2c/i2c_command_list.hpp @@ -43,9 +43,7 @@ namespace sts::i2c { size_t cur_index = 0; public: CommandListFormatter(void *cmd_list, size_t cmd_list_size) : cmd_list(static_cast(cmd_list)), cmd_list_size(cmd_list_size) { - if (cmd_list_size > MaxCommandListSize) { - std::abort(); - } + STS_ASSERT(cmd_list_size <= MaxCommandListSize); } ~CommandListFormatter() { this->cmd_list = nullptr; diff --git a/stratosphere/boot/source/pinmux/pinmux_initial_configuration.cpp b/stratosphere/boot/source/pinmux/pinmux_initial_configuration.cpp index d0537a065..03a70eb62 100644 --- a/stratosphere/boot/source/pinmux/pinmux_initial_configuration.cpp +++ b/stratosphere/boot/source/pinmux/pinmux_initial_configuration.cpp @@ -66,9 +66,7 @@ namespace sts::pinmux { } /* Ensure we found an appropriate config. */ - if (configs == nullptr) { - std::abort(); - } + STS_ASSERT(configs != nullptr); for (size_t i = 0; i < num_configs; i++) { UpdatePad(configs[i].name, configs[i].val, configs[i].mask); diff --git a/stratosphere/boot/source/pinmux/pinmux_utils.cpp b/stratosphere/boot/source/pinmux/pinmux_utils.cpp index 404086a56..2b2e17380 100644 --- a/stratosphere/boot/source/pinmux/pinmux_utils.cpp +++ b/stratosphere/boot/source/pinmux/pinmux_utils.cpp @@ -33,19 +33,13 @@ namespace sts::pinmux { /* Helpers. */ inline const Definition *GetDefinition(u32 pinmux_name) { - if (pinmux_name >= PadNameMax) { - std::abort(); - } - + STS_ASSERT(pinmux_name < PadNameMax); return &Map[pinmux_name]; } - inline const DrivePadDefinition *GetDrivePadDefinition(u32 pinmux_name) { - if (pinmux_name >= DrivePadNameMax) { - std::abort(); - } - - return &DrivePadMap[pinmux_name]; + inline const DrivePadDefinition *GetDrivePadDefinition(u32 drivepad_name) { + STS_ASSERT(drivepad_name < DrivePadNameMax); + return &DrivePadMap[drivepad_name]; } uintptr_t GetBaseAddress() { @@ -110,9 +104,7 @@ namespace sts::pinmux { u32 pinmux_val = reg::Read(pinmux_reg); /* This PINMUX register is locked */ - if (pinmux_val & 0x80) { - std::abort(); - } + STS_ASSERT((pinmux_val & 0x80) == 0); u32 pm_val = (pinmux_config_val & 0x07); diff --git a/stratosphere/dmnt/source/cheat/impl/dmnt_cheat_api.cpp b/stratosphere/dmnt/source/cheat/impl/dmnt_cheat_api.cpp index cba90bcfc..0468c3f43 100644 --- a/stratosphere/dmnt/source/cheat/impl/dmnt_cheat_api.cpp +++ b/stratosphere/dmnt/source/cheat/impl/dmnt_cheat_api.cpp @@ -34,7 +34,7 @@ namespace sts::dmnt::cheat::impl { os::Mutex cheat_lock; os::Event debug_events_event; /* Autoclear. */ os::Thread detect_thread, debug_events_thread; - IEvent *cheat_process_event; + os::SystemEvent cheat_process_event; Handle cheat_process_debug_handle = INVALID_HANDLE; CheatProcessMetadata cheat_process_metadata = {}; @@ -140,7 +140,7 @@ namespace sts::dmnt::cheat::impl { this->frozen_addresses_map.clear(); /* Signal to our fans. */ - this->cheat_process_event->Signal(); + this->cheat_process_event.Signal(); } } @@ -183,7 +183,7 @@ namespace sts::dmnt::cheat::impl { public: CheatProcessManager() { /* Create cheat process detection event. */ - this->cheat_process_event = CreateWriteOnlySystemEvent(); + R_ASSERT(this->cheat_process_event.InitializeAsInterProcessEvent()); /* Learn whether we should enable cheats by default. */ { @@ -214,8 +214,8 @@ namespace sts::dmnt::cheat::impl { return this->HasActiveCheatProcess(); } - Handle GetCheatProcessEventHandle() { - return this->cheat_process_event->GetHandle(); + Handle GetCheatProcessEventHandle() const { + return this->cheat_process_event.GetReadableHandle(); } Result GetCheatProcessMetadata(CheatProcessMetadata *out) { @@ -710,7 +710,7 @@ namespace sts::dmnt::cheat::impl { this->debug_events_event.Signal(); /* Signal to our fans. */ - this->cheat_process_event->Signal(); + this->cheat_process_event.Signal(); return ResultSuccess; } diff --git a/stratosphere/fatal/source/fatal_config.cpp b/stratosphere/fatal/source/fatal_config.cpp index eaf0ec8f3..8cfd922b5 100644 --- a/stratosphere/fatal/source/fatal_config.cpp +++ b/stratosphere/fatal/source/fatal_config.cpp @@ -24,20 +24,29 @@ namespace sts::fatal::srv { FatalConfig g_config; /* Event creator. */ - IEvent *CreateFatalDirtyEvent() { + Handle GetFatalDirtyEventReadableHandle() { Event evt; R_ASSERT(setsysBindFatalDirtyFlagEvent(&evt)); - return LoadReadOnlySystemEvent(evt.revent, [](u64 timeout) { - u64 flags_0, flags_1; - if (R_SUCCEEDED(setsysGetFatalDirtyFlags(&flags_0, &flags_1)) && (flags_0 & 1)) { - g_config.UpdateLanguageCode(); - } - return ResultSuccess; - }, true); + return evt.revent; } /* Global event. */ - IEvent *g_fatal_dirty_event = CreateFatalDirtyEvent(); + os::SystemEvent g_fatal_dirty_event(GetFatalDirtyEventReadableHandle(), true, false); + os::WaitableHolder g_fatal_dirty_waitable_holder(&g_fatal_dirty_event); + + } + + os::WaitableHolder *GetFatalDirtyWaitableHolder() { + return &g_fatal_dirty_waitable_holder; + } + + void OnFatalDirtyEvent() { + g_fatal_dirty_event.Reset(); + + u64 flags_0, flags_1; + if (R_SUCCEEDED(setsysGetFatalDirtyFlags(&flags_0, &flags_1)) && (flags_0 & 1)) { + g_config.UpdateLanguageCode(); + } } FatalConfig::FatalConfig() { @@ -84,10 +93,6 @@ namespace sts::fatal::srv { } } - IEvent *GetFatalDirtyEvent() { - return g_fatal_dirty_event; - } - const FatalConfig &GetFatalConfig() { return g_config; } diff --git a/stratosphere/fatal/source/fatal_config.hpp b/stratosphere/fatal/source/fatal_config.hpp index 5f805a088..aa039f76f 100644 --- a/stratosphere/fatal/source/fatal_config.hpp +++ b/stratosphere/fatal/source/fatal_config.hpp @@ -90,7 +90,8 @@ namespace sts::fatal::srv { } }; - IEvent *GetFatalDirtyEvent(); + os::WaitableHolder *GetFatalDirtyWaitableHolder(); + void OnFatalDirtyEvent(); const FatalConfig &GetFatalConfig(); } diff --git a/stratosphere/fatal/source/fatal_debug.cpp b/stratosphere/fatal/source/fatal_debug.cpp index fc008b963..ee5f03e98 100644 --- a/stratosphere/fatal/source/fatal_debug.cpp +++ b/stratosphere/fatal/source/fatal_debug.cpp @@ -156,7 +156,7 @@ namespace sts::fatal::srv { void TryCollectDebugInformation(ThrowContext *ctx, u64 process_id) { /* Try to debug the process. This may fail, if we called into ourself. */ - AutoHandle debug_handle; + os::ManagedHandle debug_handle; if (R_FAILED(svcDebugActiveProcess(debug_handle.GetPointer(), process_id))) { return; } diff --git a/stratosphere/fatal/source/fatal_main.cpp b/stratosphere/fatal/source/fatal_main.cpp index 8d05a0967..cc80c4599 100644 --- a/stratosphere/fatal/source/fatal_main.cpp +++ b/stratosphere/fatal/source/fatal_main.cpp @@ -133,7 +133,9 @@ int main(int argc, char **argv) /* Create services. */ s_server_manager.AddWaitable(new ServiceServer("fatal:p", 4)); s_server_manager.AddWaitable(new ServiceServer("fatal:u", 4)); - s_server_manager.AddWaitable(sts::fatal::srv::GetFatalDirtyEvent()); + /* TODO: s_server_manager.AddWaitable(sts::fatal::srv::GetFatalDirtyEvent()); */ + auto dirty_event_holder = sts::fatal::srv::GetFatalDirtyWaitableHolder(); + (void)dirty_event_holder; /* Loop forever, servicing our services. */ s_server_manager.Process(); diff --git a/stratosphere/fatal/source/fatal_task.cpp b/stratosphere/fatal/source/fatal_task.cpp index 79c584923..d412d4684 100644 --- a/stratosphere/fatal/source/fatal_task.cpp +++ b/stratosphere/fatal/source/fatal_task.cpp @@ -60,10 +60,7 @@ namespace sts::fatal::srv { public: TaskManager() { /* ... */ } void StartTask(ITask *task) { - if (this->task_count >= MaxTasks) { - std::abort(); - } - + STS_ASSERT(this->task_count < MaxTasks); this->task_threads[this->task_count++].StartTask(task); } }; diff --git a/stratosphere/libstratosphere/Makefile b/stratosphere/libstratosphere/Makefile index c3f1c90d5..5a8943afd 100644 --- a/stratosphere/libstratosphere/Makefile +++ b/stratosphere/libstratosphere/Makefile @@ -16,7 +16,7 @@ include $(DEVKITPRO)/libnx/switch_rules # INCLUDES is a list of directories containing header files #--------------------------------------------------------------------------------- TARGET := $(notdir $(CURDIR)) -SOURCES := source source/os source/spl source/spl/smc source/updater source/patcher source/map source/rnd source/util source/sm source/cfg source/pm source/hid source/ldr source/kvdb +SOURCES := source source/os source/os/impl source/spl source/spl/smc source/updater source/patcher source/map source/rnd source/util source/sm source/cfg source/pm source/hid source/ldr source/kvdb DATA := data INCLUDES := include diff --git a/stratosphere/libstratosphere/include/stratosphere.hpp b/stratosphere/libstratosphere/include/stratosphere.hpp index 2192ff1dc..5c3d899e9 100644 --- a/stratosphere/libstratosphere/include/stratosphere.hpp +++ b/stratosphere/libstratosphere/include/stratosphere.hpp @@ -21,13 +21,9 @@ #include "stratosphere/utilities.hpp" #include "stratosphere/emummc_utilities.hpp" -#include "stratosphere/scope_guard.hpp" - #include "stratosphere/version_check.hpp" -#include "stratosphere/auto_handle.hpp" #include "stratosphere/iwaitable.hpp" -#include "stratosphere/event.hpp" #include "stratosphere/waitable_manager.hpp" diff --git a/stratosphere/libstratosphere/include/stratosphere/auto_handle.hpp b/stratosphere/libstratosphere/include/stratosphere/auto_handle.hpp deleted file mode 100644 index 778465476..000000000 --- a/stratosphere/libstratosphere/include/stratosphere/auto_handle.hpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2018-2019 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include -#include "defines.hpp" - -class AutoHandle { - NON_COPYABLE(AutoHandle); - private: - Handle hnd; - public: - AutoHandle() : hnd(INVALID_HANDLE) { /* ... */ } - AutoHandle(Handle h) : hnd(h) { /* ... */ } - ~AutoHandle() { - if (this->hnd != INVALID_HANDLE) { - svcCloseHandle(this->hnd); - this->hnd = INVALID_HANDLE; - } - } - - AutoHandle(AutoHandle&& rhs) { - this->hnd = rhs.hnd; - rhs.hnd = INVALID_HANDLE; - } - - AutoHandle& operator=(AutoHandle&& rhs) { - rhs.Swap(*this); - return *this; - } - - explicit operator bool() const { - return this->hnd != INVALID_HANDLE; - } - - void Swap(AutoHandle& rhs) { - std::swap(this->hnd, rhs.hnd); - } - - Handle Get() const { - return this->hnd; - } - - Handle *GetPointer() { - return &this->hnd; - } - - Handle *GetPointerAndClear() { - this->Clear(); - return this->GetPointer(); - } - - Handle Move() { - const Handle h = this->hnd; - this->hnd = INVALID_HANDLE; - return h; - } - - void Reset(Handle h) { - AutoHandle(h).Swap(*this); - } - - void Clear() { - this->Reset(INVALID_HANDLE); - } -}; diff --git a/stratosphere/libstratosphere/include/stratosphere/defines.hpp b/stratosphere/libstratosphere/include/stratosphere/defines.hpp index 5df9d6769..aecf6aa7e 100644 --- a/stratosphere/libstratosphere/include/stratosphere/defines.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/defines.hpp @@ -19,6 +19,8 @@ /* Any broadly useful language defines should go here. */ +#define STS_ASSERT(expr) do { if (!(expr)) { std::abort(); } } while (0) + #define NON_COPYABLE(cls) \ cls(const cls&) = delete; \ cls& operator=(const cls&) = delete @@ -30,21 +32,12 @@ #define ALIGNED(algn) __attribute__((aligned(algn))) #define WEAK __attribute__((weak)) -namespace sts::util { - /* std::size() does not support zero-size C arrays. We're fixing that. */ - template - constexpr auto size(const C& c) -> decltype(c.size()) { - return std::size(c); - } +#define CONCATENATE_IMPL(S1, s2) s1##s2 +#define CONCATENATE(s1, s2) CONCATENATE_IMPL(s1, s2) - template - constexpr std::size_t size(const C& c) { - if constexpr (sizeof(C) == 0) { - return 0; - } else { - return std::size(c); - } - } - -} \ No newline at end of file +#ifdef __COUNTER__ +#define ANONYMOUS_VARIABLE(pref) CONCATENATE(pref, __COUNTER__) +#else +#define ANONYMOUS_VARIABLE(pref) CONCATENATE(pref, __LINE__) +#endif \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/stratosphere/event.hpp b/stratosphere/libstratosphere/include/stratosphere/event.hpp deleted file mode 100644 index 326bf9354..000000000 --- a/stratosphere/libstratosphere/include/stratosphere/event.hpp +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2018-2019 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once -#include -#include -#include - -#include "iwaitable.hpp" -#include "results.hpp" - -class IEvent : public IWaitable { - public: - /* Information members. */ - Handle r_h; - Handle w_h; - bool autoclear; - public: - IEvent(bool a = false) : r_h(INVALID_HANDLE), w_h(INVALID_HANDLE), autoclear(a) { } - IEvent(Handle r, bool a = false) : r_h(r), w_h(INVALID_HANDLE), autoclear(a) { } - IEvent(Handle r, Handle w, bool a = false) : r_h(r), w_h(w), autoclear(a) { } - - ~IEvent() { - if (r_h != INVALID_HANDLE) { - svcCloseHandle(r_h); - } - if (w_h != INVALID_HANDLE) { - svcCloseHandle(w_h); - } - } - - /* Make it non-copyable */ - IEvent() = delete; - IEvent(const IEvent &) = delete; - IEvent& operator=(const IEvent&) = delete; - - - bool IsAutoClear() { - return this->autoclear; - } - - void Clear() { - std::scoped_lock lock(this->sig_lock); - this->is_signaled = false; - if (this->w_h != INVALID_HANDLE) { - svcClearEvent(this->w_h); - } else if (this->r_h != INVALID_HANDLE) { - svcResetSignal(this->r_h); - } - } - - void Signal() { - std::scoped_lock lock(this->sig_lock); - - if (this->w_h == INVALID_HANDLE && this->r_h != INVALID_HANDLE) { - /* We can't signal an event if we only have a read handle. */ - std::abort(); - } - - if (this->w_h == INVALID_HANDLE && this->is_signaled) { - return; - } - - this->is_signaled = true; - - if (this->w_h != INVALID_HANDLE) { - svcSignalEvent(this->w_h); - } else { - this->NotifyManagerSignaled(); - } - } - - virtual Result HandleSignaled(u64 timeout) = 0; - - /* IWaitable */ - virtual Handle GetHandle() override { - return this->r_h; - } -}; - -template -class HosEvent : public IEvent { - private: - F callback; - public: - HosEvent(F f, bool a = false) : IEvent(a), callback(std::move(f)) { } - HosEvent(Handle r, F f, bool a = false) : IEvent(r, a), callback(std::move(f)) { } - HosEvent(Handle r, Handle w, F f, bool a = false) : IEvent(r, w, a), callback(std::move(f)) { } - - virtual Result HandleSignaled(u64 timeout) override { - if (this->IsAutoClear()) { - this->Clear(); - } - return this->callback(timeout); - } -}; - -template -static IEvent *CreateHosEvent(F f, bool autoclear = false) { - return new HosEvent(INVALID_HANDLE, INVALID_HANDLE, std::move(f), autoclear); -} - -template -static IEvent *CreateSystemEvent(F f, bool autoclear = false) { - Handle w_h, r_h; - R_ASSERT(svcCreateEvent(&w_h, &r_h)); - return new HosEvent(r_h, w_h, std::move(f), autoclear); -} - -template -static IEvent *CreateInterruptEvent(F f, u64 irq, bool autoclear = false) { - Handle r_h; - /* flag is "rising edge vs level". */ - R_ASSERT(svcCreateInterruptEvent(&r_h, irq, autoclear ? 0 : 1)); - return new HosEvent(r_h, INVALID_HANDLE, std::move(f), autoclear); -} - -template -static IEvent *CreateWriteOnlySystemEvent() { - return CreateSystemEvent([](u64 timeout) -> Result { std::abort(); }, a); -} - -template -static IEvent *LoadReadOnlySystemEvent(Handle r_h, F f, bool autoclear = false) { - return new HosEvent(r_h, f, autoclear); -} diff --git a/stratosphere/libstratosphere/include/stratosphere/kvdb/kvdb_auto_buffer.hpp b/stratosphere/libstratosphere/include/stratosphere/kvdb/kvdb_auto_buffer.hpp index 269abccef..f731f8f76 100644 --- a/stratosphere/libstratosphere/include/stratosphere/kvdb/kvdb_auto_buffer.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/kvdb/kvdb_auto_buffer.hpp @@ -68,9 +68,7 @@ namespace sts::kvdb { Result Initialize(size_t size) { /* Check that we're not already initialized. */ - if (this->buffer != nullptr) { - std::abort(); - } + STS_ASSERT(this->buffer == nullptr); /* Allocate a buffer. */ this->buffer = static_cast(std::malloc(size)); diff --git a/stratosphere/libstratosphere/include/stratosphere/kvdb/kvdb_bounded_string.hpp b/stratosphere/libstratosphere/include/stratosphere/kvdb/kvdb_bounded_string.hpp index 89272dfb8..8ab11dc89 100644 --- a/stratosphere/libstratosphere/include/stratosphere/kvdb/kvdb_bounded_string.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/kvdb/kvdb_bounded_string.hpp @@ -32,9 +32,7 @@ namespace sts::kvdb { private: /* Utility. */ static inline void CheckLength(size_t len) { - if (len >= N) { - std::abort(); - } + STS_ASSERT(len < N); } public: /* Constructors. */ @@ -115,9 +113,8 @@ namespace sts::kvdb { /* Substring utilities. */ void GetSubstring(char *dst, size_t dst_size, size_t offset, size_t length) const { /* Make sure output buffer can hold the substring. */ - if (offset + length > GetLength() || dst_size <= length) { - std::abort(); - } + STS_ASSERT(offset + length <= GetLength()); + STS_ASSERT(dst_size > length); /* Copy substring to dst. */ std::strncpy(dst, this->buffer + offset, length); dst[length] = 0; diff --git a/stratosphere/libstratosphere/include/stratosphere/kvdb/kvdb_file_key_value_cache.hpp b/stratosphere/libstratosphere/include/stratosphere/kvdb/kvdb_file_key_value_cache.hpp index 64a6037ba..920bddb8b 100644 --- a/stratosphere/libstratosphere/include/stratosphere/kvdb/kvdb_file_key_value_cache.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/kvdb/kvdb_file_key_value_cache.hpp @@ -60,9 +60,7 @@ namespace sts::kvdb { } private: void RemoveIndex(size_t i) { - if (i >= this->GetCount()) { - std::abort(); - } + STS_ASSERT(i < this->GetCount()); std::memmove(this->keys + i, this->keys + i + 1, sizeof(*this->keys) * (this->GetCount() - (i + 1))); this->DecrementCount(); } @@ -79,9 +77,8 @@ namespace sts::kvdb { Result Initialize(const char *path, void *buf, size_t size) { /* Only initialize once, and ensure we have sufficient memory. */ - if (this->keys != nullptr || size < BufferSize) { - std::abort(); - } + STS_ASSERT(this->keys == nullptr); + SSS_ASSERT(size >= BufferSize); /* Setup member variables. */ this->keys = static_cast(buf); @@ -148,31 +145,23 @@ namespace sts::kvdb { } Key Get(size_t i) const { - if (i >= this->GetCount()) { - std::abort(); - } + STS_ASSERT(i < this->GetCount()); return this->keys[i]; } Key Peek() const { - if (this->IsEmpty()) { - std::abort(); - } + STS_ASSERT(!this->IsEmpty()); return this->Get(0); } void Push(const Key &key) { - if (this->IsFull()) { - std::abort(); - } + STS_ASSERT(!this->IsFull()); this->keys[this->GetCount()] = key; this->IncrementCount(); } Key Pop() { - if (this->IsEmpty()) { - std::abort(); - } + STS_ASSERT(!this->IsEmpty()); this->RemoveIndex(0); } diff --git a/stratosphere/libstratosphere/include/stratosphere/kvdb/kvdb_file_key_value_store.hpp b/stratosphere/libstratosphere/include/stratosphere/kvdb/kvdb_file_key_value_store.hpp index ea06860b3..745bcdb41 100644 --- a/stratosphere/libstratosphere/include/stratosphere/kvdb/kvdb_file_key_value_store.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/kvdb/kvdb_file_key_value_store.hpp @@ -96,9 +96,7 @@ namespace sts::kvdb { static_assert(std::is_pod::value && !std::is_pointer::value, "Invalid FileKeyValueStore Value!"); size_t size = 0; R_TRY(this->Get(&size, out_value, sizeof(Value), key)); - if (size < sizeof(Value)) { - std::abort(); - } + STS_ASSERT(size >= sizeof(Value)); return ResultSuccess; } diff --git a/stratosphere/libstratosphere/include/stratosphere/kvdb/kvdb_memory_key_value_store.hpp b/stratosphere/libstratosphere/include/stratosphere/kvdb/kvdb_memory_key_value_store.hpp index d44dd8b92..926a2d1ea 100644 --- a/stratosphere/libstratosphere/include/stratosphere/kvdb/kvdb_memory_key_value_store.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/kvdb/kvdb_memory_key_value_store.hpp @@ -18,6 +18,9 @@ #include #include #include +#include "../defines.hpp" +#include "../results.hpp" +#include "../util.hpp" #include "kvdb_auto_buffer.hpp" #include "kvdb_archive.hpp" #include "kvdb_bounded_string.hpp" @@ -47,9 +50,7 @@ namespace sts::kvdb { Value *GetValuePointer() { /* Size check. Note: Nintendo does not size check. */ if constexpr (!std::is_same::value) { - if (sizeof(Value) > this->value_size) { - std::abort(); - } + STS_ASSERT(sizeof(Value) <= this->value_size); /* Ensure we only get pod. */ static_assert(std::is_pod::value, "KeyValueStore Values must be pod"); } @@ -60,9 +61,7 @@ namespace sts::kvdb { const Value *GetValuePointer() const { /* Size check. Note: Nintendo does not size check. */ if constexpr (!std::is_same::value) { - if (sizeof(Value) > this->value_size) { - std::abort(); - } + STS_ASSERT(sizeof(Value) <= this->value_size); /* Ensure we only get pod. */ static_assert(std::is_pod::value, "KeyValueStore Values must be pod"); } diff --git a/stratosphere/libstratosphere/include/stratosphere/os.hpp b/stratosphere/libstratosphere/include/stratosphere/os.hpp index b3a53469d..6d009ee05 100644 --- a/stratosphere/libstratosphere/include/stratosphere/os.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/os.hpp @@ -17,10 +17,16 @@ #pragma once #include +#include "os/os_common_types.hpp" +#include "os/os_managed_handle.hpp" #include "os/os_mutex.hpp" #include "os/os_condvar.hpp" #include "os/os_semaphore.hpp" #include "os/os_timeout_helper.hpp" #include "os/os_event.hpp" +#include "os/os_system_event.hpp" +#include "os/os_interrupt_event.hpp" #include "os/os_thread.hpp" -#include "os/os_message_queue.hpp" \ No newline at end of file +#include "os/os_message_queue.hpp" +#include "os/os_waitable_holder.hpp" +#include "os/os_waitable_manager.hpp" diff --git a/stratosphere/libstratosphere/include/stratosphere/os/os_common_types.hpp b/stratosphere/libstratosphere/include/stratosphere/os/os_common_types.hpp new file mode 100644 index 000000000..b6d36df93 --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/os/os_common_types.hpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace sts::os { + + enum class TriBool { + False = 0, + True = 1, + Undefined = 2, + }; + + enum class MessageQueueWaitKind { + ForNotEmpty, + ForNotFull, + }; + +} diff --git a/stratosphere/libstratosphere/include/stratosphere/os/os_event.hpp b/stratosphere/libstratosphere/include/stratosphere/os/os_event.hpp index e287db6c9..461e0a239 100644 --- a/stratosphere/libstratosphere/include/stratosphere/os/os_event.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/os/os_event.hpp @@ -21,93 +21,33 @@ namespace sts::os { + namespace impl { + + class WaitableObjectList; + class WaitableHolderOfEvent; + + } + class Event { + friend class impl::WaitableHolderOfEvent; NON_COPYABLE(Event); NON_MOVEABLE(Event); private: - Mutex m; + util::TypedStorage waitable_object_list_storage; + Mutex lock; ConditionVariable cv; + u64 counter = 0; bool auto_clear; bool signaled; - u64 counter = 0; public: - Event(bool a = true, bool s = false) : auto_clear(a), signaled(s) {} + Event(bool a = true, bool s = false); + ~Event(); - void Signal() { - std::scoped_lock lk(this->m); - - /* If we're already signaled, nothing more to do. */ - if (this->signaled) { - return; - } - - this->signaled = true; - - /* Signal! */ - if (this->auto_clear) { - /* If we're auto clear, signal one thread, which will clear. */ - this->cv.Signal(); - } else { - /* If we're manual clear, increment counter and wake all. */ - this->counter++; - this->cv.Broadcast(); - } - - /* TODO: Waitable auto-wakeup. */ - } - - void Reset() { - std::scoped_lock lk(this->m); - this->signaled = false; - } - - void Wait() { - std::scoped_lock lk(this->m); - - u64 cur_counter = this->counter; - while (!this->signaled) { - if (this->counter != cur_counter) { - break; - } - this->cv.Wait(&this->m); - } - - if (this->auto_clear) { - this->signaled = false; - } - } - - bool TryWait() { - std::scoped_lock lk(this->m); - - const bool success = this->signaled; - if (this->auto_clear) { - this->signaled = false; - } - - return success; - } - - bool TimedWait(u64 ns) { - TimeoutHelper timeout_helper(ns); - std::scoped_lock lk(this->m); - - u64 cur_counter = this->counter; - while (!this->signaled) { - if (this->counter != cur_counter) { - break; - } - if (R_FAILED(this->cv.TimedWait(&this->m, timeout_helper.NsUntilTimeout()))) { - return false; - } - } - - if (this->auto_clear) { - this->signaled = false; - } - - return true; - } + void Signal(); + void Reset(); + void Wait(); + bool TryWait(); + bool TimedWait(u64 ns); }; } diff --git a/stratosphere/libstratosphere/include/stratosphere/os/os_interrupt_event.hpp b/stratosphere/libstratosphere/include/stratosphere/os/os_interrupt_event.hpp new file mode 100644 index 000000000..d1fd15925 --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/os/os_interrupt_event.hpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "os_common_types.hpp" +#include "os_managed_handle.hpp" + +namespace sts::os { + + namespace impl { + + class WaitableHolderOfInterruptEvent; + + } + + class InterruptEvent { + friend class impl::WaitableHolderOfInterruptEvent; + NON_COPYABLE(InterruptEvent); + NON_MOVEABLE(InterruptEvent); + private: + ManagedHandle handle; + bool auto_clear; + bool is_initialized; + public: + InterruptEvent() : auto_clear(true), is_initialized(false) { } + InterruptEvent(u32 interrupt_id, bool autoclear = true); + + Result Initialize(u32 interrupt_id, bool autoclear = true); + void Finalize(); + + void Reset(); + void Wait(); + bool TryWait(); + bool TimedWait(u64 ns); + }; + +} diff --git a/stratosphere/libstratosphere/include/stratosphere/os/os_managed_handle.hpp b/stratosphere/libstratosphere/include/stratosphere/os/os_managed_handle.hpp new file mode 100644 index 000000000..0d2d91ffe --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/os/os_managed_handle.hpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include "../defines.hpp" +#include "../results.hpp" + +namespace sts::os { + + class ManagedHandle { + NON_COPYABLE(ManagedHandle); + private: + Handle hnd; + public: + ManagedHandle() : hnd(INVALID_HANDLE) { /* ... */ } + ManagedHandle(Handle h) : hnd(h) { /* ... */ } + ~ManagedHandle() { + if (this->hnd != INVALID_HANDLE) { + R_ASSERT(svcCloseHandle(this->hnd)); + this->hnd = INVALID_HANDLE; + } + } + + ManagedHandle(ManagedHandle&& rhs) { + this->hnd = rhs.hnd; + rhs.hnd = INVALID_HANDLE; + } + + ManagedHandle& operator=(ManagedHandle&& rhs) { + rhs.Swap(*this); + return *this; + } + + explicit operator bool() const { + return this->hnd != INVALID_HANDLE; + } + + void Swap(ManagedHandle& rhs) { + std::swap(this->hnd, rhs.hnd); + } + + Handle Get() const { + return this->hnd; + } + + Handle *GetPointer() { + return &this->hnd; + } + + Handle *GetPointerAndClear() { + this->Clear(); + return this->GetPointer(); + } + + Handle Move() { + const Handle h = this->hnd; + this->hnd = INVALID_HANDLE; + return h; + } + + void Reset(Handle h) { + ManagedHandle(h).Swap(*this); + } + + void Clear() { + this->Reset(INVALID_HANDLE); + } + }; + +} diff --git a/stratosphere/libstratosphere/include/stratosphere/os/os_message_queue.hpp b/stratosphere/libstratosphere/include/stratosphere/os/os_message_queue.hpp index 7c9f8bad6..a320e29cc 100644 --- a/stratosphere/libstratosphere/include/stratosphere/os/os_message_queue.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/os/os_message_queue.hpp @@ -16,15 +16,28 @@ #pragma once #include +#include "os_common_types.hpp" #include "os_mutex.hpp" #include "os_condvar.hpp" namespace sts::os { + namespace impl { + + class WaitableObjectList; + + template + class WaitableHolderOfMessageQueue; + + } + class MessageQueue { + template + friend class impl::WaitableHolderOfMessageQueue; NON_COPYABLE(MessageQueue); NON_MOVEABLE(MessageQueue); private: + util::TypedStorage waitable_object_list_storage; Mutex queue_lock; ConditionVariable cv_not_full; ConditionVariable cv_not_empty; @@ -47,11 +60,11 @@ namespace sts::os { uintptr_t ReceiveInternal(); uintptr_t PeekInternal(); public: - MessageQueue(size_t c) : capacity(c) { - this->buffer = std::make_unique(this->capacity); - } + MessageQueue(std::unique_ptr buf, size_t c); + ~MessageQueue(); - MessageQueue(std::unique_ptr buf, size_t c) : buffer(std::move(buf)), capacity(c) { } + /* For convenience. */ + MessageQueue(size_t c) : MessageQueue(std::make_unique(c), c) { /* ... */ } /* Sending (FIFO functionality) */ void Send(uintptr_t data); diff --git a/stratosphere/libstratosphere/include/stratosphere/os/os_system_event.hpp b/stratosphere/libstratosphere/include/stratosphere/os/os_system_event.hpp new file mode 100644 index 000000000..506544553 --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/os/os_system_event.hpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "os_common_types.hpp" +#include "os_event.hpp" + +namespace sts::os { + + class WaitableHolder; + + namespace impl { + + class InterProcessEvent; + + } + + enum class SystemEventState { + Uninitialized, + Event, + InterProcessEvent, + }; + + class SystemEvent { + friend class WaitableHolder; + NON_COPYABLE(SystemEvent); + NON_MOVEABLE(SystemEvent); + private: + union { + util::TypedStorage storage_for_event; + util::TypedStorage storage_for_inter_process_event; + }; + SystemEventState state; + private: + Event &GetEvent(); + const Event &GetEvent() const; + impl::InterProcessEvent &GetInterProcessEvent(); + const impl::InterProcessEvent &GetInterProcessEvent() const; + public: + SystemEvent() : state(SystemEventState::Uninitialized) { /* ... */ } + SystemEvent(bool inter_process, bool autoclear = true); + SystemEvent(Handle read_handle, bool manage_read_handle, Handle write_handle, bool manage_write_handle, bool autoclear = true); + SystemEvent(Handle read_handle, bool manage_read_handle, bool autoclear = true) : SystemEvent(read_handle, manage_read_handle, INVALID_HANDLE, false, autoclear) { /* ... */ } + ~SystemEvent(); + + Result InitializeAsEvent(bool autoclear = true); + Result InitializeAsInterProcessEvent(bool autoclear = true); + void AttachHandles(Handle read_handle, bool manage_read_handle, Handle write_handle, bool manage_write_handle, bool autoclear = true); + void AttachReadableHandle(Handle read_handle, bool manage_read_handle, bool autoclear = true); + void AttachWritableHandle(Handle write_handle, bool manage_write_handle, bool autoclear = true); + Handle DetachReadableHandle(); + Handle DetachWritableHandle(); + Handle GetReadableHandle() const; + Handle GetWritableHandle() const; + void Finalize(); + + SystemEventState GetState() const { + return this->state; + } + + void Signal(); + void Reset(); + void Wait(); + bool TryWait(); + bool TimedWait(u64 ns); + }; + +} diff --git a/stratosphere/libstratosphere/include/stratosphere/os/os_thread.hpp b/stratosphere/libstratosphere/include/stratosphere/os/os_thread.hpp index e659ac3c7..b0ab77f4f 100644 --- a/stratosphere/libstratosphere/include/stratosphere/os/os_thread.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/os/os_thread.hpp @@ -37,6 +37,10 @@ namespace sts::os { return threadStart(&this->thr); } + Result Wait() { + return threadWaitForExit(&this->thr); + } + Result Join() { R_TRY(threadWaitForExit(&this->thr)); R_TRY(threadClose(&this->thr)); diff --git a/stratosphere/libstratosphere/include/stratosphere/os/os_waitable_holder.hpp b/stratosphere/libstratosphere/include/stratosphere/os/os_waitable_holder.hpp new file mode 100644 index 000000000..6118a3a2c --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/os/os_waitable_holder.hpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "../util.hpp" +#include "os_common_types.hpp" + +namespace sts::os { + + class WaitableManager; + + class Event; + class SystemEvent; + class InterruptEvent; + class Thread; + class MessageQueue; + + namespace impl { + + class WaitableHolderImpl; + + } + + class WaitableHolder { + friend class WaitableManager; + NON_COPYABLE(WaitableHolder); + NON_MOVEABLE(WaitableHolder); + private: + util::TypedStorage impl_storage; + uintptr_t user_data; + public: + static constexpr size_t ImplStorageSize = sizeof(impl_storage); + public: + WaitableHolder(Handle handle); + WaitableHolder(Event *event); + WaitableHolder(SystemEvent *event); + WaitableHolder(InterruptEvent *event); + WaitableHolder(Thread *thread); + WaitableHolder(MessageQueue *message_queue, MessageQueueWaitKind wait_kind); + + ~WaitableHolder(); + + void SetUserData(uintptr_t data) { + this->user_data = data; + } + + uintptr_t GetUserData() const { + return this->user_data; + } + + void UnlinkFromWaitableManager(); + }; + +} diff --git a/stratosphere/libstratosphere/include/stratosphere/os/os_waitable_manager.hpp b/stratosphere/libstratosphere/include/stratosphere/os/os_waitable_manager.hpp new file mode 100644 index 000000000..c4eaf721a --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/os/os_waitable_manager.hpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "../util.hpp" +#include "os_common_types.hpp" +#include "os_mutex.hpp" + +namespace sts::os { + + class WaitableHolder; + + namespace impl { + + class WaitableManagerImpl; + + } + + class WaitableManager { + NON_COPYABLE(WaitableManager); + NON_MOVEABLE(WaitableManager); + private: + util::TypedStorage impl_storage; + public: + static constexpr size_t ImplStorageSize = sizeof(impl_storage); + public: + WaitableManager(); + ~WaitableManager(); + + /* Wait. */ + WaitableHolder *WaitAny(); + WaitableHolder *TryWaitAny(); + WaitableHolder *TimedWaitAny(u64 timeout); + + /* Link. */ + void LinkWaitableHolder(WaitableHolder *holder); + void UnlinkAll(); + void MoveAllFrom(WaitableManager *other); + }; + +} diff --git a/stratosphere/libstratosphere/include/stratosphere/results.hpp b/stratosphere/libstratosphere/include/stratosphere/results.hpp index 5eddf72fc..ef1a7c116 100644 --- a/stratosphere/libstratosphere/include/stratosphere/results.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/results.hpp @@ -32,6 +32,7 @@ #include "results/kvdb_results.hpp" #include "results/loader_results.hpp" #include "results/lr_results.hpp" +#include "results/os_results.hpp" #include "results/ncm_results.hpp" #include "results/pm_results.hpp" #include "results/ro_results.hpp" diff --git a/stratosphere/libstratosphere/include/stratosphere/results/os_results.hpp b/stratosphere/libstratosphere/include/stratosphere/results/os_results.hpp new file mode 100644 index 000000000..81acaf05e --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/results/os_results.hpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include + +static constexpr u32 Module_Os = 3; + +static constexpr Result ResultOsOutOfMemory = MAKERESULT(Module_Os, 8); +static constexpr Result ResultOsResourceExhausted = MAKERESULT(Module_Os, 9); diff --git a/stratosphere/libstratosphere/include/stratosphere/results/utilities.h b/stratosphere/libstratosphere/include/stratosphere/results/utilities.h index da499496c..7768d4860 100644 --- a/stratosphere/libstratosphere/include/stratosphere/results/utilities.h +++ b/stratosphere/libstratosphere/include/stratosphere/results/utilities.h @@ -28,6 +28,14 @@ extern "C" { #define R_ASSERT_IMPL(res) fatalSimple(res) #endif +/// Evaluates a boolean expression, and returns a result unless that expression is true. +#define R_UNLESS(expr, res) \ + ({ \ + if (!(expr)) { \ + return static_cast(res); \ + } \ + }) + #define R_ASSERT(res_expr) \ ({ \ const Result _tmp_r_assert_rc = res_expr; \ @@ -83,6 +91,14 @@ extern "C" { } \ }) +#define R_END_TRY_CATCH_WITH_ASSERT \ + else { \ + R_ASSERT(R_TRY_CATCH_RESULT); \ + } \ + } \ + }) + + /// Evaluates an expression that returns a result, and returns the result (after evaluating a cleanup expression) if it would fail. #define R_CLEANUP_RESULT _tmp_r_try_cleanup_rc diff --git a/stratosphere/libstratosphere/include/stratosphere/ro/ro_types.hpp b/stratosphere/libstratosphere/include/stratosphere/ro/ro_types.hpp index 0a6a01893..7c092159a 100644 --- a/stratosphere/libstratosphere/include/stratosphere/ro/ro_types.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/ro/ro_types.hpp @@ -17,6 +17,7 @@ #pragma once #include #include +#include "../defines.hpp" namespace sts::ro { @@ -61,9 +62,7 @@ namespace sts::ro { ModuleType GetType() const { const ModuleType type = static_cast(this->type); - if (type >= ModuleType::Count) { - std::abort(); - } + STS_ASSERT(type < ModuleType::Count); return type; } diff --git a/stratosphere/libstratosphere/include/stratosphere/scope_guard.hpp b/stratosphere/libstratosphere/include/stratosphere/scope_guard.hpp deleted file mode 100644 index 9ff4be701..000000000 --- a/stratosphere/libstratosphere/include/stratosphere/scope_guard.hpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2018-2019 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - /* Scope guard logic lovingly taken from Andrei Alexandrescu's "Systemic Error Handling in C++" */ -#pragma once - -#include - -template -class ScopeGuard { -private: - F f; - bool active; -public: - ScopeGuard(F f) : f(std::move(f)), active(true) { } - ~ScopeGuard() { if (active) { f(); } } - void Cancel() { active = false; } - - ScopeGuard() = delete; - ScopeGuard(const ScopeGuard &) = delete; - ScopeGuard& operator=(const ScopeGuard&) = delete; - ScopeGuard(ScopeGuard&& rhs) : f(std::move(rhs.f)), active(rhs.active) { - rhs.Cancel(); - } -}; - -template -ScopeGuard MakeScopeGuard(F f) { - return ScopeGuard(std::move(f)); -} - -enum class ScopeGuardOnExit {}; - -template -ScopeGuard operator+(ScopeGuardOnExit, F&& f) { - return ScopeGuard(std::forward(f)); -} - -#define CONCATENATE_IMPL(S1, s2) s1##s2 -#define CONCATENATE(s1, s2) CONCATENATE_IMPL(s1, s2) - -#ifdef __COUNTER__ -#define ANONYMOUS_VARIABLE(pref) CONCATENATE(pref, __COUNTER__) -#else -#define ANONYMOUS_VARIABLE(pref) CONCATENATE(pref, __LINE__) -#endif - -#define SCOPE_GUARD ScopeGuardOnExit() + [&]() -#define ON_SCOPE_EXIT auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE_) = SCOPE_GUARD diff --git a/stratosphere/libstratosphere/include/stratosphere/sm/sm_types.hpp b/stratosphere/libstratosphere/include/stratosphere/sm/sm_types.hpp index c831d9136..68a9091a5 100644 --- a/stratosphere/libstratosphere/include/stratosphere/sm/sm_types.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/sm/sm_types.hpp @@ -114,9 +114,7 @@ namespace sts::sm { } Result Initialize() { - if (this->has_initialized) { - std::abort(); - } + STS_ASSERT(!this->has_initialized); DoWithSmSession([&]() { this->result = Initializer(); @@ -127,9 +125,7 @@ namespace sts::sm { } void Finalize() { - if (!this->has_initialized) { - std::abort(); - } + STS_ASSERT(this->has_initialized); Finalizer(); this->has_initialized = false; } diff --git a/stratosphere/libstratosphere/include/stratosphere/svc/svc_types.hpp b/stratosphere/libstratosphere/include/stratosphere/svc/svc_types.hpp index 98855abdb..74612d49c 100644 --- a/stratosphere/libstratosphere/include/stratosphere/svc/svc_types.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/svc/svc_types.hpp @@ -202,4 +202,10 @@ namespace sts::svc { CreateProcessFlag_OptimizeMemoryAllocation = (1 << 11), }; + /* Type for svcCreateInterruptEvent. */ + enum InterruptType : u32 { + InterruptType_Edge = 0, + InterruptType_Level = 1, + }; + } diff --git a/stratosphere/libstratosphere/include/stratosphere/util.hpp b/stratosphere/libstratosphere/include/stratosphere/util.hpp index d33453d60..a8b21abed 100644 --- a/stratosphere/libstratosphere/include/stratosphere/util.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/util.hpp @@ -17,7 +17,11 @@ #pragma once #include -#include "util/util_compression.hpp" -#include "util/util_ini.hpp" +#include "util/util_alignment.hpp" +#include "util/util_size.hpp" +#include "util/util_scope_guard.hpp" +#include "util/util_typed_storage.hpp" #include "util/util_intrusive_list.hpp" #include "util/util_intrusive_red_black_tree.hpp" +#include "util/util_compression.hpp" +#include "util/util_ini.hpp" diff --git a/stratosphere/libstratosphere/include/stratosphere/util/util_alignment.hpp b/stratosphere/libstratosphere/include/stratosphere/util/util_alignment.hpp new file mode 100644 index 000000000..c7d9b4c0a --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/util/util_alignment.hpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include "../defines.hpp" +#include + +namespace sts::util { + + /* Utilities for alignment to power of two. */ + + template + static constexpr inline T AlignUp(T value, size_t alignment) { + using U = typename std::make_unsigned::type; + const U invmask = static_cast(alignment - 1); + return static_cast((value + invmask) & ~invmask); + } + + template + static constexpr inline T AlignDown(T value, size_t alignment) { + using U = typename std::make_unsigned::type; + const U invmask = static_cast(alignment - 1); + return static_cast(value & ~invmask); + } + + template + static constexpr inline bool IsAligned(T value, size_t alignment) { + using U = typename std::make_unsigned::type; + const U invmask = static_cast(alignment - 1); + return (value & invmask) == 0; + } + +} \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/stratosphere/util/util_intrusive_list.hpp b/stratosphere/libstratosphere/include/stratosphere/util/util_intrusive_list.hpp index 708dfbfc6..017625846 100644 --- a/stratosphere/libstratosphere/include/stratosphere/util/util_intrusive_list.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/util/util_intrusive_list.hpp @@ -49,10 +49,8 @@ namespace sts::util { private: void LinkPrev(IntrusiveListNode *node) { /* We can't link an already linked node. */ - if (node->IsLinked()) { - std::abort(); - } - return this->SplicePrev(node, node); + STS_ASSERT(!node->IsLinked()); + this->SplicePrev(node, node); } void SplicePrev(IntrusiveListNode *first, IntrusiveListNode *last) { @@ -66,9 +64,7 @@ namespace sts::util { void LinkNext(IntrusiveListNode *node) { /* We can't link an already linked node. */ - if (node->IsLinked()) { - std::abort(); - } + STS_ASSERT(!node->IsLinked()); return this->SpliceNext(node, node); } @@ -214,17 +210,13 @@ namespace sts::util { iterator iterator_to(reference v) { /* Only allow iterator_to for values in lists. */ - if (!v.IsLinked()) { - std::abort(); - } + STS_ASSERT(v.IsLinked()); return iterator(&v); } const_iterator iterator_to(const_reference v) const { /* Only allow iterator_to for values in lists. */ - if (!v.IsLinked()) { - std::abort(); - } + STS_ASSERT(v.IsLinked()); return const_iterator(&v); } @@ -488,23 +480,23 @@ namespace sts::util { } reference back() { - if (this->impl.empty()) { std::abort(); } - return this->impl.back(); + STS_ASSERT(!this->impl.empty()); + return GetParent(this->impl.back()); } const_reference back() const { - if (this->impl.empty()) { std::abort(); } - return this->impl.back(); + STS_ASSERT(!this->impl.empty()); + return GetParent(this->impl.back()); } reference front() { - if (this->impl.empty()) { std::abort(); } - return this->impl.front(); + STS_ASSERT(!this->impl.empty()); + return GetParent(this->impl.front()); } const_reference front() const { - if (this->impl.empty()) { std::abort(); } - return this->impl.front(); + STS_ASSERT(!this->impl.empty()); + return GetParent(this->impl.front()); } void push_back(reference ref) { @@ -516,13 +508,13 @@ namespace sts::util { } void pop_back() { - if (this->impl.empty()) { std::abort(); } - return this->impl.pop_back(); + STS_ASSERT(!this->impl.empty()); + this->impl.pop_back(); } void pop_front() { - if (this->impl.empty()) { std::abort(); } - return this->impl.pop_front(); + STS_ASSERT(!this->impl.empty()); + this->impl.pop_front(); } iterator insert(const_iterator pos, reference ref) { diff --git a/stratosphere/libstratosphere/include/stratosphere/util/util_scope_guard.hpp b/stratosphere/libstratosphere/include/stratosphere/util/util_scope_guard.hpp new file mode 100644 index 000000000..275c1368d --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/util/util_scope_guard.hpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + /* Scope guard logic lovingly taken from Andrei Alexandrescu's "Systemic Error Handling in C++" */ +#pragma once +#include +#include "../defines.hpp" + +namespace sts::util { + + namespace impl { + + template + class ScopeGuard { + NON_COPYABLE(ScopeGuard); + private: + F f; + bool active; + public: + constexpr ScopeGuard(F f) : f(std::move(f)), active(true) { } + ~ScopeGuard() { if (active) { f(); } } + void Cancel() { active = false; } + + ScopeGuard(ScopeGuard&& rhs) : f(std::move(rhs.f)), active(rhs.active) { + rhs.Cancel(); + } + }; + + template + constexpr ScopeGuard MakeScopeGuard(F f) { + return ScopeGuard(std::move(f)); + } + + enum class ScopeGuardOnExit {}; + + template + constexpr ScopeGuard operator+(ScopeGuardOnExit, F&& f) { + return ScopeGuard(std::forward(f)); + } + + } + +} + +#define SCOPE_GUARD ::sts::util::impl::ScopeGuardOnExit() + [&]() +#define ON_SCOPE_EXIT auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE_) = SCOPE_GUARD diff --git a/stratosphere/libstratosphere/include/stratosphere/util/util_size.hpp b/stratosphere/libstratosphere/include/stratosphere/util/util_size.hpp new file mode 100644 index 000000000..8f1785c5e --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/util/util_size.hpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include + +namespace sts::util { + + /* std::size() does not support zero-size C arrays. We're fixing that. */ + template + constexpr auto size(const C& c) -> decltype(c.size()) { + return std::size(c); + } + + template + constexpr std::size_t size(const C& c) { + if constexpr (sizeof(C) == 0) { + return 0; + } else { + return std::size(c); + } + } + +} \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/stratosphere/util/util_typed_storage.hpp b/stratosphere/libstratosphere/include/stratosphere/util/util_typed_storage.hpp new file mode 100644 index 000000000..54999a87e --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/util/util_typed_storage.hpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include "../defines.hpp" +#include + +namespace sts::util { + + template + struct TypedStorage { + typename std::aligned_storage::type _storage; + }; + + #define TYPED_STORAGE(T) ::sts::util::TypedStorage + + template + static constexpr inline __attribute__((always_inline)) T *GetPointer(TYPED_STORAGE(T) &ts) { + return reinterpret_cast(&ts._storage); + } + + template + static constexpr inline __attribute__((always_inline)) const T *GetPointer(const TYPED_STORAGE(T) &ts) { + return reinterpret_cast(&ts._storage); + } + + template + static constexpr inline __attribute__((always_inline)) T &GetReference(TYPED_STORAGE(T) &ts) { + return *GetPointer(ts); + } + + template + static constexpr inline __attribute__((always_inline)) const T &GetReference(const TYPED_STORAGE(T) &ts) { + return *GetPointer(ts); + } + +} \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/stratosphere/waitable_manager.hpp b/stratosphere/libstratosphere/include/stratosphere/waitable_manager.hpp index 7edc4b52e..e27bac9f6 100644 --- a/stratosphere/libstratosphere/include/stratosphere/waitable_manager.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/waitable_manager.hpp @@ -23,11 +23,10 @@ #include "results.hpp" #include "os.hpp" #include "waitable_manager_base.hpp" -#include "event.hpp" #include "ipc.hpp" #include "servers.hpp" -#include "scope_guard.hpp" +#include "util.hpp" static inline Handle GetCurrentThreadHandle() { return threadGetCurHandle(); diff --git a/stratosphere/libstratosphere/source/emummc_utilities.cpp b/stratosphere/libstratosphere/source/emummc_utilities.cpp index ba73ae138..59c4267cd 100644 --- a/stratosphere/libstratosphere/source/emummc_utilities.cpp +++ b/stratosphere/libstratosphere/source/emummc_utilities.cpp @@ -81,9 +81,7 @@ static void _CacheValues(void) args.X[1] = 0; /* NAND */ args.X[2] = reinterpret_cast(&paths); /* path output */ R_ASSERT(svcCallSecureMonitor(&args)); - if (args.X[0] != 0) { - std::abort(); - } + STS_ASSERT(args.X[0] == 0); std::memcpy(&g_exo_emummc_config, &args.X[1], sizeof(args) - sizeof(args.X[0])); } diff --git a/stratosphere/libstratosphere/source/firmware_version.cpp b/stratosphere/libstratosphere/source/firmware_version.cpp index 4723872cf..c444ad496 100644 --- a/stratosphere/libstratosphere/source/firmware_version.cpp +++ b/stratosphere/libstratosphere/source/firmware_version.cpp @@ -40,9 +40,7 @@ static void _CacheValues(void) args.X[0] = 0xC3000002; /* smcGetConfig */ args.X[1] = 65000; /* ConfigItem_ExosphereVersion */ R_ASSERT(svcCallSecureMonitor(&args)); - if (args.X[0] != 0) { - std::abort(); - } + STS_ASSERT(args.X[0] == 0); target_fw = (args.X[1] >> 0x08) & 0xFF; } diff --git a/stratosphere/libstratosphere/source/kvdb/kvdb_archive.cpp b/stratosphere/libstratosphere/source/kvdb/kvdb_archive.cpp index 503f155fb..be3cd6e2d 100644 --- a/stratosphere/libstratosphere/source/kvdb/kvdb_archive.cpp +++ b/stratosphere/libstratosphere/source/kvdb/kvdb_archive.cpp @@ -90,9 +90,7 @@ namespace sts::kvdb { Result ArchiveReader::ReadEntryCount(size_t *out) { /* This should only be called at the start of reading stream. */ - if (this->offset != 0) { - std::abort(); - } + STS_ASSERT(this->offset == 0); /* Read and validate header. */ ArchiveHeader header; @@ -105,9 +103,7 @@ namespace sts::kvdb { Result ArchiveReader::GetEntrySize(size_t *out_key_size, size_t *out_value_size) { /* This should only be called after ReadEntryCount. */ - if (this->offset == 0) { - std::abort(); - } + STS_ASSERT(this->offset != 0); /* Peek the next entry header. */ ArchiveEntryHeader header; @@ -121,9 +117,7 @@ namespace sts::kvdb { Result ArchiveReader::ReadEntry(void *out_key, size_t key_size, void *out_value, size_t value_size) { /* This should only be called after ReadEntryCount. */ - if (this->offset == 0) { - std::abort(); - } + STS_ASSERT(this->offset != 0); /* Read the next entry header. */ ArchiveEntryHeader header; @@ -131,9 +125,8 @@ namespace sts::kvdb { R_TRY(header.Validate()); /* Key size and Value size must be correct. */ - if (key_size != header.key_size || value_size != header.value_size) { - std::abort(); - } + STS_ASSERT(key_size == header.key_size); + STS_ASSERT(value_size == header.value_size); R_ASSERT(this->Read(out_key, key_size)); R_ASSERT(this->Read(out_value, value_size)); @@ -154,9 +147,7 @@ namespace sts::kvdb { void ArchiveWriter::WriteHeader(size_t entry_count) { /* This should only be called at start of write. */ - if (this->offset != 0) { - std::abort(); - } + STS_ASSERT(this->offset == 0); ArchiveHeader header = ArchiveHeader::Make(entry_count); R_ASSERT(this->Write(&header, sizeof(header))); @@ -164,9 +155,7 @@ namespace sts::kvdb { void ArchiveWriter::WriteEntry(const void *key, size_t key_size, const void *value, size_t value_size) { /* This should only be called after writing header. */ - if (this->offset == 0) { - std::abort(); - } + STS_ASSERT(this->offset != 0); ArchiveEntryHeader header = ArchiveEntryHeader::Make(key_size, value_size); R_ASSERT(this->Write(&header, sizeof(header))); diff --git a/stratosphere/libstratosphere/source/kvdb/kvdb_file_key_value_store.cpp b/stratosphere/libstratosphere/source/kvdb/kvdb_file_key_value_store.cpp index e1f770688..3853c2f68 100644 --- a/stratosphere/libstratosphere/source/kvdb/kvdb_file_key_value_store.cpp +++ b/stratosphere/libstratosphere/source/kvdb/kvdb_file_key_value_store.cpp @@ -57,9 +57,7 @@ namespace sts::kvdb { this->backing_buffer_free_offset = 0; this->count = 0; this->entries = static_castentries)>(this->Allocate(sizeof(*this->entries) * this->capacity)); - if (this->entries == nullptr) { - std::abort(); - } + STS_ASSERT(this->entries != nullptr); } std::optional FileKeyValueStore::Cache::TryGet(void *out_value, size_t max_out_size, const void *key, size_t key_size) { @@ -106,9 +104,7 @@ namespace sts::kvdb { } /* Ensure key size is small enough. */ - if (key_size > MaxKeySize) { - std::abort(); - } + STS_ASSERT(key_size <= MaxKeySize); /* If we're at capacity, invalidate the cache. */ if (this->count == this->capacity) { diff --git a/stratosphere/libstratosphere/source/os/impl/os_inter_process_event.cpp b/stratosphere/libstratosphere/source/os/impl/os_inter_process_event.cpp new file mode 100644 index 000000000..2b7377f62 --- /dev/null +++ b/stratosphere/libstratosphere/source/os/impl/os_inter_process_event.cpp @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "os_inter_process_event.hpp" + +namespace sts::os::impl { + + namespace { + + Result CreateEventHandles(Handle *out_readable, Handle *out_writable) { + /* Create the event handles. */ + R_TRY_CATCH(svcCreateEvent(out_writable, out_readable)) { + R_CATCH(ResultKernelResourceExhausted) { + return ResultOsResourceExhausted; + } + } R_END_TRY_CATCH_WITH_ASSERT; + + return ResultSuccess; + } + + } + + InterProcessEvent::InterProcessEvent(bool autoclear) : is_initialized(false) { + R_ASSERT(this->Initialize(autoclear)); + } + + InterProcessEvent::~InterProcessEvent() { + this->Finalize(); + } + + Result InterProcessEvent::Initialize(bool autoclear) { + STS_ASSERT(!this->is_initialized); + Handle rh, wh; + R_TRY(CreateEventHandles(&rh, &wh)); + this->Initialize(rh, true, wh, true, autoclear); + return ResultSuccess; + } + + void InterProcessEvent::Initialize(Handle read_handle, bool manage_read_handle, Handle write_handle, bool manage_write_handle, bool autoclear) { + STS_ASSERT(!this->is_initialized); + STS_ASSERT(read_handle != INVALID_HANDLE || write_handle != INVALID_HANDLE); + this->read_handle = read_handle; + this->manage_read_handle = manage_read_handle; + this->write_handle = write_handle; + this->manage_write_handle = manage_write_handle; + this->auto_clear = autoclear; + this->is_initialized = true; + } + + Handle InterProcessEvent::DetachReadableHandle() { + STS_ASSERT(this->is_initialized); + const Handle handle = this->read_handle; + STS_ASSERT(handle != INVALID_HANDLE); + this->read_handle = INVALID_HANDLE; + this->manage_read_handle = false; + return handle; + } + + Handle InterProcessEvent::DetachWritableHandle() { + STS_ASSERT(this->is_initialized); + const Handle handle = this->write_handle; + STS_ASSERT(handle != INVALID_HANDLE); + this->write_handle = INVALID_HANDLE; + this->manage_write_handle = false; + return handle; + } + + Handle InterProcessEvent::GetReadableHandle() const { + STS_ASSERT(this->is_initialized); + return this->read_handle; + } + + Handle InterProcessEvent::GetWritableHandle() const { + STS_ASSERT(this->is_initialized); + return this->write_handle; + } + + void InterProcessEvent::Finalize() { + if (this->is_initialized) { + if (this->manage_read_handle && this->read_handle != INVALID_HANDLE) { + R_ASSERT(svcCloseHandle(this->read_handle)); + } + if (this->manage_write_handle && this->write_handle != INVALID_HANDLE) { + R_ASSERT(svcCloseHandle(this->write_handle)); + } + } + this->read_handle = INVALID_HANDLE; + this->manage_read_handle = false; + this->write_handle = INVALID_HANDLE; + this->manage_write_handle = false; + this->is_initialized = false; + } + + void InterProcessEvent::Signal() { + R_ASSERT(svcSignalEvent(this->GetWritableHandle())); + } + + void InterProcessEvent::Reset() { + Handle handle = this->GetReadableHandle(); + if (handle == INVALID_HANDLE) { + handle = this->GetWritableHandle(); + } + R_ASSERT(svcClearEvent(handle)); + } + + void InterProcessEvent::Wait() { + const Handle handle = this->GetReadableHandle(); + + while (true) { + /* Continuously wait, until success. */ + R_TRY_CATCH(svcWaitSynchronizationSingle(handle, U64_MAX)) { + R_CATCH(ResultKernelCancelled) { continue; } + } R_END_TRY_CATCH_WITH_ASSERT; + + /* Clear, if we must. */ + if (this->auto_clear) { + R_TRY_CATCH(svcResetSignal(handle)) { + /* Some other thread might have caught this before we did. */ + R_CATCH(ResultKernelInvalidState) { continue; } + } R_END_TRY_CATCH_WITH_ASSERT; + } + return; + } + } + + bool InterProcessEvent::TryWait() { + const Handle handle = this->GetReadableHandle(); + + if (this->auto_clear) { + /* Auto-clear. Just try to reset. */ + return R_SUCCEEDED(svcResetSignal(handle)); + } else { + /* Not auto-clear. */ + while (true) { + /* Continuously wait, until success or timeout. */ + R_TRY_CATCH(svcWaitSynchronizationSingle(handle, 0)) { + R_CATCH(ResultKernelTimedOut) { return false; } + R_CATCH(ResultKernelCancelled) { continue; } + } R_END_TRY_CATCH_WITH_ASSERT; + + /* We succeeded, so we're signaled. */ + return true; + } + } + } + + bool InterProcessEvent::TimedWait(u64 ns) { + const Handle handle = this->GetReadableHandle(); + + TimeoutHelper timeout_helper(ns); + while (true) { + /* Continuously wait, until success or timeout. */ + R_TRY_CATCH(svcWaitSynchronizationSingle(handle, timeout_helper.NsUntilTimeout())) { + R_CATCH(ResultKernelTimedOut) { return false; } + R_CATCH(ResultKernelCancelled) { continue; } + } R_END_TRY_CATCH_WITH_ASSERT; + + /* Clear, if we must. */ + if (this->auto_clear) { + R_TRY_CATCH(svcResetSignal(handle)) { + /* Some other thread might have caught this before we did. */ + R_CATCH(ResultKernelInvalidState) { continue; } + } R_END_TRY_CATCH_WITH_ASSERT; + } + + return true; + } + } +} diff --git a/stratosphere/libstratosphere/source/os/impl/os_inter_process_event.hpp b/stratosphere/libstratosphere/source/os/impl/os_inter_process_event.hpp new file mode 100644 index 000000000..98f5d9748 --- /dev/null +++ b/stratosphere/libstratosphere/source/os/impl/os_inter_process_event.hpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include + +namespace sts::os::impl { + + class WaitableHolderOfInterProcessEvent; + + class InterProcessEvent { + friend class WaitableHolderOfInterProcessEvent; + NON_COPYABLE(InterProcessEvent); + NON_MOVEABLE(InterProcessEvent); + private: + Handle read_handle; + Handle write_handle; + bool manage_read_handle; + bool manage_write_handle; + bool auto_clear; + bool is_initialized; + public: + InterProcessEvent() : is_initialized(false) { /* ... */ } + InterProcessEvent(bool autoclear); + ~InterProcessEvent(); + + Result Initialize(bool autoclear = true); + void Initialize(Handle read_handle, bool manage_read_handle, Handle write_handle, bool manage_write_handle, bool autoclear = true); + Handle DetachReadableHandle(); + Handle DetachWritableHandle(); + Handle GetReadableHandle() const; + Handle GetWritableHandle() const; + void Finalize(); + + void Signal(); + void Reset(); + void Wait(); + bool TryWait(); + bool TimedWait(u64 ns); + }; + +} diff --git a/stratosphere/libstratosphere/source/os/impl/os_waitable_holder_base.hpp b/stratosphere/libstratosphere/source/os/impl/os_waitable_holder_base.hpp new file mode 100644 index 000000000..dbe229bda --- /dev/null +++ b/stratosphere/libstratosphere/source/os/impl/os_waitable_holder_base.hpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace sts::os::impl { + + class WaitableObjectList; + class WaitableManagerImpl; + + class WaitableHolderBase { + public: + util::IntrusiveListNode manager_node; + util::IntrusiveListNode object_list_node; + private: + WaitableManagerImpl *manager = nullptr; + public: + /* Gets whether the held waitable is currently signaled. */ + virtual TriBool IsSignaled() const = 0; + /* Adds to manager's object list, returns is signaled. */ + virtual TriBool LinkToObjectList() = 0; + /* Removes from the manager's object list. */ + virtual void UnlinkFromObjectList() = 0; + /* Gets handle to output, returns INVALID_HANDLE on failure. */ + virtual Handle GetHandle() const = 0; + /* Gets the amount of time remaining until this wakes up. */ + virtual u64 GetWakeupTime() const { + return U64_MAX; + } + + /* Interface with manager. */ + void SetManager(WaitableManagerImpl *m) { + this->manager = m; + } + + WaitableManagerImpl *GetManager() const { + return this->manager; + } + + bool IsLinkedToManager() const { + return this->manager != nullptr; + } + }; + + class WaitableHolderOfUserObject : public WaitableHolderBase { + public: + /* All user objects have no handle to wait on. */ + virtual Handle GetHandle() const override { + return INVALID_HANDLE; + } + }; + + class WaitableHolderOfKernelObject : public WaitableHolderBase { + public: + /* All kernel objects have native handles, and thus don't have object list semantics. */ + virtual TriBool LinkToObjectList() override { + return TriBool::Undefined; + } + virtual void UnlinkFromObjectList() override { + /* ... */ + } + }; + +} diff --git a/stratosphere/libstratosphere/source/os/impl/os_waitable_holder_impl.hpp b/stratosphere/libstratosphere/source/os/impl/os_waitable_holder_impl.hpp new file mode 100644 index 000000000..59fe202b9 --- /dev/null +++ b/stratosphere/libstratosphere/source/os/impl/os_waitable_holder_impl.hpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "os_waitable_holder_of_handle.hpp" +#include "os_waitable_holder_of_event.hpp" +#include "os_waitable_holder_of_inter_process_event.hpp" +#include "os_waitable_holder_of_interrupt_event.hpp" +#include "os_waitable_holder_of_thread.hpp" +#include "os_waitable_holder_of_message_queue.hpp" + +namespace sts::os::impl { + + struct WaitableHolderImpl { + union { + TYPED_STORAGE(WaitableHolderOfHandle) holder_of_handle_storage; + TYPED_STORAGE(WaitableHolderOfEvent) holder_of_event_storage; + TYPED_STORAGE(WaitableHolderOfInterProcessEvent) holder_of_inter_process_event_storage; + TYPED_STORAGE(WaitableHolderOfInterruptEvent) holder_of_interrupt_event_storage; + TYPED_STORAGE(WaitableHolderOfThread) holder_of_thread_storage; + TYPED_STORAGE(WaitableHolderOfMessageQueueForNotFull) holder_of_mq_for_not_full_storage; + TYPED_STORAGE(WaitableHolderOfMessageQueueForNotEmpty) holder_of_mq_for_not_empty_storage; + }; + }; + + #define CHECK_HOLDER(T) \ + static_assert(std::is_base_of<::sts::os::impl::WaitableHolderBase, T>::value && std::is_trivially_destructible::value, #T) + + CHECK_HOLDER(WaitableHolderOfHandle); + CHECK_HOLDER(WaitableHolderOfEvent); + CHECK_HOLDER(WaitableHolderOfInterProcessEvent); + CHECK_HOLDER(WaitableHolderOfInterruptEvent); + CHECK_HOLDER(WaitableHolderOfThread); + CHECK_HOLDER(WaitableHolderOfMessageQueueForNotFull); + CHECK_HOLDER(WaitableHolderOfMessageQueueForNotEmpty); + + #undef CHECK_HOLDER + + static_assert(std::is_trivial::value && std::is_trivially_destructible::value, "WaitableHolderImpl"); + static_assert(sizeof(WaitableHolderImpl) == WaitableHolder::ImplStorageSize, "WaitableHolderImpl size"); +} diff --git a/stratosphere/libstratosphere/source/os/impl/os_waitable_holder_of_event.hpp b/stratosphere/libstratosphere/source/os/impl/os_waitable_holder_of_event.hpp new file mode 100644 index 000000000..fc440fac7 --- /dev/null +++ b/stratosphere/libstratosphere/source/os/impl/os_waitable_holder_of_event.hpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "os_waitable_holder_base.hpp" +#include "os_waitable_object_list.hpp" + +namespace sts::os::impl { + + class WaitableHolderOfEvent : public WaitableHolderOfUserObject { + private: + Event *event; + private: + TriBool IsSignaledImpl() const { + return this->event->signaled ? TriBool::True : TriBool::False; + } + public: + explicit WaitableHolderOfEvent(Event *e) : event(e) { /* ... */ } + + /* IsSignaled, Link, Unlink implemented. */ + virtual TriBool IsSignaled() const override { + std::scoped_lock lk(this->event->lock); + return this->IsSignaledImpl(); + } + + virtual TriBool LinkToObjectList() override { + std::scoped_lock lk(this->event->lock); + + GetReference(this->event->waitable_object_list_storage).LinkWaitableHolder(*this); + return this->IsSignaledImpl(); + } + + virtual void UnlinkFromObjectList() override { + std::scoped_lock lk(this->event->lock); + + GetReference(this->event->waitable_object_list_storage).UnlinkWaitableHolder(*this); + } + }; + +} diff --git a/stratosphere/libstratosphere/source/os/impl/os_waitable_holder_of_handle.hpp b/stratosphere/libstratosphere/source/os/impl/os_waitable_holder_of_handle.hpp new file mode 100644 index 000000000..f11acf704 --- /dev/null +++ b/stratosphere/libstratosphere/source/os/impl/os_waitable_holder_of_handle.hpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "os_waitable_holder_base.hpp" + +namespace sts::os::impl { + + class WaitableHolderOfHandle : public WaitableHolderOfKernelObject { + private: + Handle handle; + public: + explicit WaitableHolderOfHandle(Handle h) : handle(h) { /* ... */ } + + /* IsSignaled, GetHandle both implemented. */ + virtual TriBool IsSignaled() const override { + return TriBool::Undefined; + } + + virtual Handle GetHandle() const override { + return this->handle; + } + }; + +} diff --git a/stratosphere/libstratosphere/source/os/impl/os_waitable_holder_of_inter_process_event.hpp b/stratosphere/libstratosphere/source/os/impl/os_waitable_holder_of_inter_process_event.hpp new file mode 100644 index 000000000..8439a7b67 --- /dev/null +++ b/stratosphere/libstratosphere/source/os/impl/os_waitable_holder_of_inter_process_event.hpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "os_waitable_holder_base.hpp" +#include "os_inter_process_event.hpp" + +namespace sts::os::impl { + + class WaitableHolderOfInterProcessEvent : public WaitableHolderOfKernelObject { + private: + InterProcessEvent *event; + public: + explicit WaitableHolderOfInterProcessEvent(InterProcessEvent *e) : event(e) { /* ... */ } + + /* IsSignaled, GetHandle both implemented. */ + virtual TriBool IsSignaled() const override { + return TriBool::Undefined; + } + + virtual Handle GetHandle() const override { + STS_ASSERT(this->event->is_initialized); + return this->event->GetReadableHandle(); + } + }; + +} diff --git a/stratosphere/libstratosphere/source/os/impl/os_waitable_holder_of_interrupt_event.hpp b/stratosphere/libstratosphere/source/os/impl/os_waitable_holder_of_interrupt_event.hpp new file mode 100644 index 000000000..f54952c37 --- /dev/null +++ b/stratosphere/libstratosphere/source/os/impl/os_waitable_holder_of_interrupt_event.hpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "os_waitable_holder_base.hpp" + +namespace sts::os::impl { + + class WaitableHolderOfInterruptEvent : public WaitableHolderOfKernelObject { + private: + InterruptEvent *event; + public: + explicit WaitableHolderOfInterruptEvent(InterruptEvent *e) : event(e) { /* ... */ } + + /* IsSignaled, GetHandle both implemented. */ + virtual TriBool IsSignaled() const override { + return TriBool::Undefined; + } + + virtual Handle GetHandle() const override { + STS_ASSERT(this->event->is_initialized); + return this->event->handle.Get(); + } + }; + +} diff --git a/stratosphere/libstratosphere/source/os/impl/os_waitable_holder_of_message_queue.hpp b/stratosphere/libstratosphere/source/os/impl/os_waitable_holder_of_message_queue.hpp new file mode 100644 index 000000000..d85c6123e --- /dev/null +++ b/stratosphere/libstratosphere/source/os/impl/os_waitable_holder_of_message_queue.hpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "os_waitable_holder_base.hpp" +#include "os_waitable_object_list.hpp" + +namespace sts::os::impl { + + template + class WaitableHolderOfMessageQueue : public WaitableHolderOfUserObject { + static_assert(WaitKind == MessageQueueWaitKind::ForNotEmpty || WaitKind == MessageQueueWaitKind::ForNotFull, "MessageQueueHolder WaitKind!"); + private: + MessageQueue *message_queue; + private: + TriBool IsSignaledImpl() const { + if constexpr (WaitKind == MessageQueueWaitKind::ForNotEmpty) { + /* ForNotEmpty. */ + return this->message_queue->IsEmpty() ? TriBool::False : TriBool::True; + } else /* if constexpr (WaitKind == MessageQueueWaitKind::ForNotFull) */ { + /* ForNotFull */ + return this->message_queue->IsFull() ? TriBool::False : TriBool::True; + } + } + public: + explicit WaitableHolderOfMessageQueue(MessageQueue *mq) : message_queue(mq) { /* ... */ } + + /* IsSignaled, Link, Unlink implemented. */ + virtual TriBool IsSignaled() const override { + std::scoped_lock lk(this->message_queue->queue_lock); + return this->IsSignaledImpl(); + } + + virtual TriBool LinkToObjectList() override { + std::scoped_lock lk(this->message_queue->queue_lock); + + GetReference(this->message_queue->waitable_object_list_storage).LinkWaitableHolder(*this); + return this->IsSignaledImpl(); + } + + virtual void UnlinkFromObjectList() override { + std::scoped_lock lk(this->message_queue->queue_lock); + + GetReference(this->message_queue->waitable_object_list_storage).UnlinkWaitableHolder(*this); + } + }; + + using WaitableHolderOfMessageQueueForNotEmpty = WaitableHolderOfMessageQueue; + using WaitableHolderOfMessageQueueForNotFull = WaitableHolderOfMessageQueue; + +} diff --git a/stratosphere/libstratosphere/source/os/impl/os_waitable_holder_of_thread.hpp b/stratosphere/libstratosphere/source/os/impl/os_waitable_holder_of_thread.hpp new file mode 100644 index 000000000..844eaf8b4 --- /dev/null +++ b/stratosphere/libstratosphere/source/os/impl/os_waitable_holder_of_thread.hpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "os_waitable_holder_base.hpp" + +namespace sts::os::impl { + + /* Nintendo implements this as a user wait object, operating on Thread state. */ + /* Libnx doesn't have an equivalent, so we'll use the thread's handle for kernel semantics. */ + class WaitableHolderOfThread : public WaitableHolderOfKernelObject { + private: + Thread *thread; + public: + explicit WaitableHolderOfThread(Thread *t) : thread(t) { /* ... */ } + + /* IsSignaled, GetHandle both implemented. */ + virtual TriBool IsSignaled() const override { + return TriBool::Undefined; + } + + virtual Handle GetHandle() const override { + return this->thread->GetHandle(); + } + }; + +} diff --git a/stratosphere/libstratosphere/source/os/impl/os_waitable_manager_impl.cpp b/stratosphere/libstratosphere/source/os/impl/os_waitable_manager_impl.cpp new file mode 100644 index 000000000..85b89e2c8 --- /dev/null +++ b/stratosphere/libstratosphere/source/os/impl/os_waitable_manager_impl.cpp @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "os_waitable_manager_impl.hpp" +#include "os_waitable_object_list.hpp" + +namespace sts::os::impl{ + + WaitableHolderBase *WaitableManagerImpl::WaitAnyImpl(bool infinite, u64 timeout) { + /* Set processing thread handle while in scope. */ + this->waiting_thread_handle = threadGetCurHandle(); + ON_SCOPE_EXIT { this->waiting_thread_handle = INVALID_HANDLE; }; + + /* Prepare for processing. */ + this->signaled_holder = nullptr; + WaitableHolderBase *result = this->LinkHoldersToObjectList(); + + /* Check if we've been signaled. */ + { + std::scoped_lock lk(this->lock); + if (this->signaled_holder != nullptr) { + result = this->signaled_holder; + } + } + + /* Process object array. */ + if (result == nullptr) { + result = this->WaitAnyHandleImpl(infinite, timeout); + } + + /* Unlink holders from the current object list. */ + this->UnlinkHoldersFromObjectList(); + + return result; + } + + WaitableHolderBase *WaitableManagerImpl::WaitAnyHandleImpl(bool infinite, u64 timeout) { + Handle object_handles[MaximumHandleCount]; + WaitableHolderBase *objects[MaximumHandleCount]; + + const size_t count = this->BuildHandleArray(object_handles, objects); + const u64 end_time = infinite ? U64_MAX : armTicksToNs(armGetSystemTick()); + + while (true) { + this->current_time = armTicksToNs(armGetSystemTick()); + + u64 min_timeout = 0; + WaitableHolderBase *min_timeout_object = this->RecalculateNextTimeout(&min_timeout, end_time); + + s32 index; + if (count == 0 && min_timeout == 0) { + index = WaitTimedOut; + } else { + index = this->WaitSynchronization(object_handles, count, min_timeout); + STS_ASSERT(index != WaitInvalid); + } + + switch (index) { + case WaitTimedOut: + if (min_timeout_object) { + this->current_time = armTicksToNs(armGetSystemTick()); + if (min_timeout_object->IsSignaled() == TriBool::True) { + std::scoped_lock lk(this->lock); + this->signaled_holder = min_timeout_object; + return this->signaled_holder; + } + continue; + } + return nullptr; + case WaitCancelled: + if (this->signaled_holder) { + return this->signaled_holder; + } + continue; + default: /* 0 - 0x3F, valid. */ + { + std::scoped_lock lk(this->lock); + this->signaled_holder = objects[index]; + return this->signaled_holder; + } + } + } + } + + s32 WaitableManagerImpl::WaitSynchronization(Handle *handles, size_t count, u64 timeout) { + s32 index = WaitInvalid; + + R_TRY_CATCH(svcWaitSynchronization(&index, handles, count, timeout)) { + R_CATCH(ResultKernelTimedOut) { return WaitTimedOut; } + R_CATCH(ResultKernelCancelled) { return WaitCancelled; } + /* All other results are critical errors. */ + /* 7601: Thread termination requested. */ + /* E401: Handle is dead. */ + /* E601: Handle list address invalid. */ + /* EE01: Too many handles. */ + } R_END_TRY_CATCH_WITH_ASSERT; + + return index; + } + + size_t WaitableManagerImpl::BuildHandleArray(Handle *out_handles, WaitableHolderBase **out_objects) { + size_t count = 0; + + for (WaitableHolderBase &holder_base : this->waitable_list) { + if (Handle handle = holder_base.GetHandle(); handle != INVALID_HANDLE) { + STS_ASSERT(count < MaximumHandleCount); + + out_handles[count] = handle; + out_objects[count] = &holder_base; + count++; + } + } + + return count; + } + + WaitableHolderBase *WaitableManagerImpl::LinkHoldersToObjectList() { + WaitableHolderBase *signaled_holder = nullptr; + + for (WaitableHolderBase &holder_base : this->waitable_list) { + TriBool is_signaled = holder_base.LinkToObjectList(); + + if (signaled_holder == nullptr && is_signaled == TriBool::True) { + signaled_holder = &holder_base; + } + } + + return signaled_holder; + } + + void WaitableManagerImpl::UnlinkHoldersFromObjectList() { + for (WaitableHolderBase &holder_base : this->waitable_list) { + holder_base.UnlinkFromObjectList(); + } + } + + WaitableHolderBase *WaitableManagerImpl::RecalculateNextTimeout(u64 *out_min_timeout, u64 end_time) { + WaitableHolderBase *min_timeout_holder = nullptr; + u64 min_time = end_time; + + for (WaitableHolderBase &holder_base : this->waitable_list) { + if (const u64 cur_time = holder_base.GetWakeupTime(); cur_time < min_time) { + min_timeout_holder = &holder_base; + min_time = cur_time; + } + } + + if (min_time < this->current_time) { + *out_min_timeout = 0; + } else { + *out_min_timeout = min_time - this->current_time; + } + return min_timeout_holder; + } + + void WaitableManagerImpl::SignalAndWakeupThread(WaitableHolderBase *holder_base) { + std::scoped_lock lk(this->lock); + + if (this->signaled_holder == nullptr) { + this->signaled_holder = holder_base; + R_ASSERT(svcCancelSynchronization(this->waiting_thread_handle)); + } + } + +} diff --git a/stratosphere/libstratosphere/source/os/impl/os_waitable_manager_impl.hpp b/stratosphere/libstratosphere/source/os/impl/os_waitable_manager_impl.hpp new file mode 100644 index 000000000..bea1a0f29 --- /dev/null +++ b/stratosphere/libstratosphere/source/os/impl/os_waitable_manager_impl.hpp @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "os_waitable_holder_base.hpp" + +namespace sts::os::impl { + + class WaitableManagerImpl { + public: + static constexpr size_t MaximumHandleCount = 0x40; + static constexpr s32 WaitInvalid = -3; + static constexpr s32 WaitCancelled = -2; + static constexpr s32 WaitTimedOut = -1; + using ListType = util::IntrusiveListMemberTraits<&WaitableHolderBase::manager_node>::ListType; + private: + ListType waitable_list; + WaitableHolderBase *signaled_holder; + u64 current_time; + Mutex lock; + Handle waiting_thread_handle; + private: + WaitableHolderBase *WaitAnyImpl(bool infinite, u64 timeout); + WaitableHolderBase *WaitAnyHandleImpl(bool infinite, u64 timeout); + s32 WaitSynchronization(Handle *handles, size_t count, u64 timeout); + size_t BuildHandleArray(Handle *out_handles, WaitableHolderBase **out_objects); + + WaitableHolderBase *LinkHoldersToObjectList(); + void UnlinkHoldersFromObjectList(); + + WaitableHolderBase *RecalculateNextTimeout(u64 *out_min_timeout, u64 end_time); + public: + /* Wait. */ + WaitableHolderBase *WaitAny() { + return this->WaitAnyImpl(true, U64_MAX); + } + + WaitableHolderBase *TryWaitAny() { + return this->WaitAnyImpl(false, 0); + } + + WaitableHolderBase *TimedWaitAny(u64 timeout) { + return this->WaitAnyImpl(false, timeout); + } + + /* List management. */ + bool IsEmpty() const { + return this->waitable_list.empty(); + } + + void LinkWaitableHolder(WaitableHolderBase &holder_base) { + this->waitable_list.push_back(holder_base); + } + + void UnlinkWaitableHolder(WaitableHolderBase &holder_base) { + this->waitable_list.erase(this->waitable_list.iterator_to(holder_base)); + } + + void UnlinkAll() { + while (!this->IsEmpty()) { + this->waitable_list.front().SetManager(nullptr); + this->waitable_list.pop_front(); + } + } + + void MoveAllFrom(WaitableManagerImpl &other) { + /* Set manager for all of the other's waitables. */ + for (auto &w : other.waitable_list) { + w.SetManager(this); + } + this->waitable_list.splice(this->waitable_list.end(), other.waitable_list); + } + + /* Other. */ + u64 GetCurrentTime() const { + return this->current_time; + } + + void SignalAndWakeupThread(WaitableHolderBase *holder_base); + }; + +} diff --git a/stratosphere/libstratosphere/source/os/impl/os_waitable_object_list.hpp b/stratosphere/libstratosphere/source/os/impl/os_waitable_object_list.hpp new file mode 100644 index 000000000..7129b6613 --- /dev/null +++ b/stratosphere/libstratosphere/source/os/impl/os_waitable_object_list.hpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "os_waitable_holder_base.hpp" +#include "os_waitable_manager_impl.hpp" + +namespace sts::os::impl { + + class WaitableObjectList { + public: + using ListType = util::IntrusiveListMemberTraits<&WaitableHolderBase::object_list_node>::ListType; + private: + ListType object_list; + public: + void SignalAllThreads() { + for (WaitableHolderBase &holder_base : this->object_list) { + holder_base.GetManager()->SignalAndWakeupThread(&holder_base); + } + } + + void WakeupAllThreads() { + for (WaitableHolderBase &holder_base : this->object_list) { + holder_base.GetManager()->SignalAndWakeupThread(nullptr); + } + } + + bool IsEmpty() const { + return this->object_list.empty(); + } + + void LinkWaitableHolder(WaitableHolderBase &holder_base) { + this->object_list.push_back(holder_base); + } + + void UnlinkWaitableHolder(WaitableHolderBase &holder_base) { + this->object_list.erase(this->object_list.iterator_to(holder_base)); + } + }; + +} diff --git a/stratosphere/libstratosphere/source/os/os_event.cpp b/stratosphere/libstratosphere/source/os/os_event.cpp new file mode 100644 index 000000000..51b5ebe10 --- /dev/null +++ b/stratosphere/libstratosphere/source/os/os_event.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "impl/os_waitable_object_list.hpp" + +namespace sts::os { + + Event::Event(bool a, bool s) : auto_clear(a), signaled(s) { + new (GetPointer(this->waitable_object_list_storage)) impl::WaitableObjectList(); + } + + Event::~Event() { + GetReference(this->waitable_object_list_storage).~WaitableObjectList(); + } + + void Event::Signal() { + std::scoped_lock lk(this->lock); + + /* If we're already signaled, nothing more to do. */ + if (this->signaled) { + return; + } + + this->signaled = true; + + /* Signal! */ + if (this->auto_clear) { + /* If we're auto clear, signal one thread, which will clear. */ + this->cv.Signal(); + } else { + /* If we're manual clear, increment counter and wake all. */ + this->counter++; + this->cv.Broadcast(); + } + + /* Wake up whatever manager, if any. */ + GetReference(this->waitable_object_list_storage).SignalAllThreads(); + } + + void Event::Reset() { + std::scoped_lock lk(this->lock); + this->signaled = false; + } + + void Event::Wait() { + std::scoped_lock lk(this->lock); + + u64 cur_counter = this->counter; + while (!this->signaled) { + if (this->counter != cur_counter) { + break; + } + this->cv.Wait(&this->lock); + } + + if (this->auto_clear) { + this->signaled = false; + } + } + + bool Event::TryWait() { + std::scoped_lock lk(this->lock); + + const bool success = this->signaled; + if (this->auto_clear) { + this->signaled = false; + } + + return success; + } + + bool Event::TimedWait(u64 ns) { + TimeoutHelper timeout_helper(ns); + std::scoped_lock lk(this->lock); + + u64 cur_counter = this->counter; + while (!this->signaled) { + if (this->counter != cur_counter) { + break; + } + if (R_FAILED(this->cv.TimedWait(&this->lock, timeout_helper.NsUntilTimeout()))) { + return false; + } + } + + if (this->auto_clear) { + this->signaled = false; + } + + return true; + } + +} diff --git a/stratosphere/libstratosphere/source/os/os_interrupt_event.cpp b/stratosphere/libstratosphere/source/os/os_interrupt_event.cpp new file mode 100644 index 000000000..96201ff92 --- /dev/null +++ b/stratosphere/libstratosphere/source/os/os_interrupt_event.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "impl/os_waitable_object_list.hpp" + +namespace sts::os { + + Result InterruptEvent::Initialize(u32 interrupt_id, bool autoclear) { + STS_ASSERT(!this->is_initialized); + this->auto_clear = autoclear; + + const auto type = this->auto_clear ? svc::InterruptType_Edge : svc::InterruptType_Level; + R_TRY(svcCreateInterruptEvent(this->handle.GetPointer(), interrupt_id, type)); + + this->is_initialized = true; + return ResultSuccess; + } + + void InterruptEvent::Finalize() { + STS_ASSERT(this->is_initialized); + R_ASSERT(svcCloseHandle(this->handle.Move())); + this->auto_clear = true; + this->is_initialized = false; + } + + InterruptEvent::InterruptEvent(u32 interrupt_id, bool autoclear) { + this->is_initialized = false; + R_ASSERT(this->Initialize(interrupt_id, autoclear)); + } + + void InterruptEvent::Reset() { + R_ASSERT(svcClearEvent(this->handle.Get())); + } + + void InterruptEvent::Wait() { + STS_ASSERT(this->is_initialized); + + while (true) { + /* Continuously wait, until success. */ + R_TRY_CATCH(svcWaitSynchronizationSingle(this->handle.Get(), U64_MAX)) { + R_CATCH(ResultKernelCancelled) { continue; } + } R_END_TRY_CATCH_WITH_ASSERT; + + /* Clear, if we must. */ + if (this->auto_clear) { + R_TRY_CATCH(svcResetSignal(this->handle.Get())) { + /* Some other thread might have caught this before we did. */ + R_CATCH(ResultKernelInvalidState) { continue; } + } R_END_TRY_CATCH_WITH_ASSERT; + } + return; + } + } + + bool InterruptEvent::TryWait() { + STS_ASSERT(this->is_initialized); + + if (this->auto_clear) { + /* Auto-clear. Just try to reset. */ + return R_SUCCEEDED(svcResetSignal(this->handle.Get())); + } else { + /* Not auto-clear. */ + while (true) { + /* Continuously wait, until success or timeout. */ + R_TRY_CATCH(svcWaitSynchronizationSingle(this->handle.Get(), 0)) { + R_CATCH(ResultKernelTimedOut) { return false; } + R_CATCH(ResultKernelCancelled) { continue; } + } R_END_TRY_CATCH_WITH_ASSERT; + + /* We succeeded, so we're signaled. */ + return true; + } + } + } + + bool InterruptEvent::TimedWait(u64 ns) { + STS_ASSERT(this->is_initialized); + + TimeoutHelper timeout_helper(ns); + while (true) { + /* Continuously wait, until success or timeout. */ + R_TRY_CATCH(svcWaitSynchronizationSingle(this->handle.Get(), timeout_helper.NsUntilTimeout())) { + R_CATCH(ResultKernelTimedOut) { return false; } + R_CATCH(ResultKernelCancelled) { continue; } + } R_END_TRY_CATCH_WITH_ASSERT; + + /* Clear, if we must. */ + if (this->auto_clear) { + R_TRY_CATCH(svcResetSignal(this->handle.Get())) { + /* Some other thread might have caught this before we did. */ + R_CATCH(ResultKernelInvalidState) { continue; } + } R_END_TRY_CATCH_WITH_ASSERT; + } + + return true; + } + } + +} diff --git a/stratosphere/libstratosphere/source/os/os_message_queue.cpp b/stratosphere/libstratosphere/source/os/os_message_queue.cpp index 2008ed7b3..26b1ae6d4 100644 --- a/stratosphere/libstratosphere/source/os/os_message_queue.cpp +++ b/stratosphere/libstratosphere/source/os/os_message_queue.cpp @@ -14,14 +14,21 @@ * along with this program. If not, see . */ #include +#include "impl/os_waitable_object_list.hpp" namespace sts::os { + MessageQueue::MessageQueue(std::unique_ptr buf, size_t c): buffer(std::move(buf)), capacity(c) { + new (GetPointer(this->waitable_object_list_storage)) impl::WaitableObjectList(); + } + + MessageQueue::~MessageQueue() { + GetReference(this->waitable_object_list_storage).~WaitableObjectList(); + } + void MessageQueue::SendInternal(uintptr_t data) { /* Ensure we don't corrupt the queue, but this should never happen. */ - if (this->count >= this->capacity) { - std::abort(); - } + STS_ASSERT(this->count < this->capacity); /* Write data to tail of queue. */ this->buffer[(this->count++ + this->offset) % this->capacity] = data; @@ -29,9 +36,7 @@ namespace sts::os { void MessageQueue::SendNextInternal(uintptr_t data) { /* Ensure we don't corrupt the queue, but this should never happen. */ - if (this->count >= this->capacity) { - std::abort(); - } + STS_ASSERT(this->count < this->capacity); /* Write data to head of queue. */ this->offset = (this->offset + this->capacity - 1) % this->capacity; @@ -41,9 +46,7 @@ namespace sts::os { uintptr_t MessageQueue::ReceiveInternal() { /* Ensure we don't corrupt the queue, but this should never happen. */ - if (this->count == 0) { - std::abort(); - } + STS_ASSERT(this->count > 0); uintptr_t data = this->buffer[this->offset]; this->offset = (this->offset + 1) % this->capacity; @@ -53,9 +56,7 @@ namespace sts::os { uintptr_t MessageQueue::PeekInternal() { /* Ensure we don't corrupt the queue, but this should never happen. */ - if (this->count == 0) { - std::abort(); - } + STS_ASSERT(this->count > 0); return this->buffer[this->offset]; } diff --git a/stratosphere/libstratosphere/source/os/os_system_event.cpp b/stratosphere/libstratosphere/source/os/os_system_event.cpp new file mode 100644 index 000000000..1e64fa031 --- /dev/null +++ b/stratosphere/libstratosphere/source/os/os_system_event.cpp @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "impl/os_waitable_holder_impl.hpp" + +namespace sts::os { + + SystemEvent::SystemEvent(bool inter_process, bool autoclear) : state(SystemEventState::Uninitialized) { + if (inter_process) { + R_ASSERT(this->InitializeAsInterProcessEvent(autoclear)); + } else { + R_ASSERT(this->InitializeAsEvent(autoclear)); + } + } + + SystemEvent::SystemEvent(Handle read_handle, bool manage_read_handle, Handle write_handle, bool manage_write_handle, bool autoclear) : state(SystemEventState::Uninitialized) { + this->AttachHandles(read_handle, manage_read_handle, write_handle, manage_write_handle, autoclear); + } + + SystemEvent::~SystemEvent() { + this->Finalize(); + } + + Event &SystemEvent::GetEvent() { + STS_ASSERT(this->state == SystemEventState::Event); + return GetReference(this->storage_for_event); + } + + const Event &SystemEvent::GetEvent() const { + STS_ASSERT(this->state == SystemEventState::Event); + return GetReference(this->storage_for_event); + } + + impl::InterProcessEvent &SystemEvent::GetInterProcessEvent() { + STS_ASSERT(this->state == SystemEventState::InterProcessEvent); + return GetReference(this->storage_for_inter_process_event); + } + + const impl::InterProcessEvent &SystemEvent::GetInterProcessEvent() const { + STS_ASSERT(this->state == SystemEventState::InterProcessEvent); + return GetReference(this->storage_for_inter_process_event); + } + + Result SystemEvent::InitializeAsEvent(bool autoclear) { + STS_ASSERT(this->state == SystemEventState::Uninitialized); + new (GetPointer(this->storage_for_event)) Event(autoclear); + this->state = SystemEventState::Event; + return ResultSuccess; + } + + Result SystemEvent::InitializeAsInterProcessEvent(bool autoclear) { + STS_ASSERT(this->state == SystemEventState::Uninitialized); + new (GetPointer(this->storage_for_inter_process_event)) impl::InterProcessEvent(); + this->state = SystemEventState::InterProcessEvent; + R_TRY_CLEANUP(this->GetInterProcessEvent().Initialize(autoclear), { + this->Finalize(); + }); + return ResultSuccess; + } + + void SystemEvent::AttachHandles(Handle read_handle, bool manage_read_handle, Handle write_handle, bool manage_write_handle, bool autoclear) { + STS_ASSERT(this->state == SystemEventState::Uninitialized); + new (GetPointer(this->storage_for_inter_process_event)) impl::InterProcessEvent(); + this->state = SystemEventState::InterProcessEvent; + this->GetInterProcessEvent().Initialize(read_handle, manage_read_handle, write_handle, manage_write_handle, autoclear); + } + + void SystemEvent::AttachReadableHandle(Handle read_handle, bool manage_read_handle, bool autoclear) { + this->AttachHandles(read_handle, manage_read_handle, INVALID_HANDLE, false, autoclear); + } + + void SystemEvent::AttachWritableHandle(Handle write_handle, bool manage_write_handle, bool autoclear) { + this->AttachHandles(INVALID_HANDLE, false, write_handle, manage_write_handle, autoclear); + } + + Handle SystemEvent::DetachReadableHandle() { + STS_ASSERT(this->state == SystemEventState::InterProcessEvent); + return this->GetInterProcessEvent().DetachReadableHandle(); + } + + Handle SystemEvent::DetachWritableHandle() { + STS_ASSERT(this->state == SystemEventState::InterProcessEvent); + return this->GetInterProcessEvent().DetachWritableHandle(); + } + + Handle SystemEvent::GetReadableHandle() const { + STS_ASSERT(this->state == SystemEventState::InterProcessEvent); + return this->GetInterProcessEvent().GetReadableHandle(); + } + + Handle SystemEvent::GetWritableHandle() const { + STS_ASSERT(this->state == SystemEventState::InterProcessEvent); + return this->GetInterProcessEvent().GetWritableHandle(); + } + + void SystemEvent::Finalize() { + switch (this->state) { + case SystemEventState::Uninitialized: + break; + case SystemEventState::Event: + this->GetEvent().~Event(); + break; + case SystemEventState::InterProcessEvent: + this->GetInterProcessEvent().~InterProcessEvent(); + break; + default: + std::abort(); + } + this->state = SystemEventState::Uninitialized; + } + + void SystemEvent::Signal() { + switch (this->state) { + case SystemEventState::Event: + this->GetEvent().Signal(); + break; + case SystemEventState::InterProcessEvent: + this->GetInterProcessEvent().Signal(); + break; + case SystemEventState::Uninitialized: + default: + std::abort(); + } + } + + void SystemEvent::Reset() { + switch (this->state) { + case SystemEventState::Event: + this->GetEvent().Reset(); + break; + case SystemEventState::InterProcessEvent: + this->GetInterProcessEvent().Reset(); + break; + case SystemEventState::Uninitialized: + default: + std::abort(); + } + } + void SystemEvent::Wait() { + switch (this->state) { + case SystemEventState::Event: + this->GetEvent().Wait(); + break; + case SystemEventState::InterProcessEvent: + this->GetInterProcessEvent().Wait(); + break; + case SystemEventState::Uninitialized: + default: + std::abort(); + } + } + + bool SystemEvent::TryWait() { + switch (this->state) { + case SystemEventState::Event: + return this->GetEvent().TryWait(); + case SystemEventState::InterProcessEvent: + return this->GetInterProcessEvent().TryWait(); + case SystemEventState::Uninitialized: + default: + std::abort(); + } + } + + bool SystemEvent::TimedWait(u64 ns) { + switch (this->state) { + case SystemEventState::Event: + return this->GetEvent().TimedWait(ns); + case SystemEventState::InterProcessEvent: + return this->GetInterProcessEvent().TimedWait(ns); + case SystemEventState::Uninitialized: + default: + std::abort(); + } + } +} diff --git a/stratosphere/libstratosphere/source/os/os_waitable_holder.cpp b/stratosphere/libstratosphere/source/os/os_waitable_holder.cpp new file mode 100644 index 000000000..c44b65f51 --- /dev/null +++ b/stratosphere/libstratosphere/source/os/os_waitable_holder.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "impl/os_waitable_holder_impl.hpp" +#include "impl/os_waitable_manager_impl.hpp" + +namespace sts::os { + + WaitableHolder::WaitableHolder(Handle handle) { + /* Don't allow invalid handles. */ + STS_ASSERT(handle != INVALID_HANDLE); + + /* Initialize appropriate holder. */ + new (GetPointer(this->impl_storage)) impl::WaitableHolderOfHandle(handle); + + /* Set user-data. */ + this->user_data = 0; + } + + WaitableHolder::WaitableHolder(Event *event) { + /* Initialize appropriate holder. */ + new (GetPointer(this->impl_storage)) impl::WaitableHolderOfEvent(event); + + /* Set user-data. */ + this->user_data = 0; + } + + WaitableHolder::WaitableHolder(SystemEvent *event) { + /* Initialize appropriate holder. */ + switch (event->GetState()) { + case SystemEventState::Event: + new (GetPointer(this->impl_storage)) impl::WaitableHolderOfEvent(&event->GetEvent()); + break; + case SystemEventState::InterProcessEvent: + new (GetPointer(this->impl_storage)) impl::WaitableHolderOfInterProcessEvent(&event->GetInterProcessEvent()); + break; + case SystemEventState::Uninitialized: + default: + std::abort(); + } + + /* Set user-data. */ + this->user_data = 0; + } + + WaitableHolder::WaitableHolder(InterruptEvent *event) { + /* Initialize appropriate holder. */ + new (GetPointer(this->impl_storage)) impl::WaitableHolderOfInterruptEvent(event); + + /* Set user-data. */ + this->user_data = 0; + } + + WaitableHolder::WaitableHolder(Thread *thread) { + /* Initialize appropriate holder. */ + new (GetPointer(this->impl_storage)) impl::WaitableHolderOfThread(thread); + + /* Set user-data. */ + this->user_data = 0; + } + + WaitableHolder::WaitableHolder(MessageQueue *message_queue, MessageQueueWaitKind wait_kind) { + /* Initialize appropriate holder. */ + switch (wait_kind) { + case MessageQueueWaitKind::ForNotFull: + new (GetPointer(this->impl_storage)) impl::WaitableHolderOfMessageQueueForNotFull(message_queue); + break; + case MessageQueueWaitKind::ForNotEmpty: + new (GetPointer(this->impl_storage)) impl::WaitableHolderOfMessageQueueForNotEmpty(message_queue); + break; + default: + std::abort(); + } + + /* Set user-data. */ + this->user_data = 0; + } + + WaitableHolder::~WaitableHolder() { + auto holder_base = reinterpret_cast(GetPointer(this->impl_storage)); + + /* Don't allow destruction of a linked waitable holder. */ + STS_ASSERT(!holder_base->IsLinkedToManager()); + + holder_base->~WaitableHolderBase(); + } + + void WaitableHolder::UnlinkFromWaitableManager() { + auto holder_base = reinterpret_cast(GetPointer(this->impl_storage)); + + /* Don't allow unlinking of an unlinked holder. */ + STS_ASSERT(holder_base->IsLinkedToManager()); + + holder_base->GetManager()->UnlinkWaitableHolder(*holder_base); + holder_base->SetManager(nullptr); + } + +} diff --git a/stratosphere/libstratosphere/source/os/os_waitable_manager.cpp b/stratosphere/libstratosphere/source/os/os_waitable_manager.cpp new file mode 100644 index 000000000..bfec7eda7 --- /dev/null +++ b/stratosphere/libstratosphere/source/os/os_waitable_manager.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "impl/os_waitable_holder_impl.hpp" +#include "impl/os_waitable_manager_impl.hpp" + +namespace sts::os { + + WaitableManager::WaitableManager() { + /* Initialize storage. */ + new (GetPointer(this->impl_storage)) impl::WaitableManagerImpl(); + } + + WaitableManager::~WaitableManager() { + auto &impl = GetReference(this->impl_storage); + + /* Don't allow destruction of a non-empty waitable holder. */ + STS_ASSERT(impl.IsEmpty()); + + impl.~WaitableManagerImpl(); + } + + + /* Wait. */ + WaitableHolder *WaitableManager::WaitAny() { + auto &impl = GetReference(this->impl_storage); + + /* Don't allow waiting on empty list. */ + STS_ASSERT(!impl.IsEmpty()); + + return reinterpret_cast(impl.WaitAny()); + } + + WaitableHolder *WaitableManager::TryWaitAny() { + auto &impl = GetReference(this->impl_storage); + + /* Don't allow waiting on empty list. */ + STS_ASSERT(!impl.IsEmpty()); + + return reinterpret_cast(impl.TryWaitAny()); + } + + WaitableHolder *WaitableManager::TimedWaitAny(u64 timeout) { + auto &impl = GetReference(this->impl_storage); + + /* Don't allow waiting on empty list. */ + STS_ASSERT(!impl.IsEmpty()); + + return reinterpret_cast(impl.TimedWaitAny(timeout)); + } + + /* Link. */ + void WaitableManager::LinkWaitableHolder(WaitableHolder *holder) { + auto &impl = GetReference(this->impl_storage); + auto holder_base = reinterpret_cast(GetPointer(holder->impl_storage)); + + /* Don't allow double-linking a holder. */ + STS_ASSERT(!holder_base->IsLinkedToManager()); + + impl.LinkWaitableHolder(*holder_base); + holder_base->SetManager(&impl); + } + + void WaitableManager::UnlinkAll() { + auto &impl = GetReference(this->impl_storage); + impl.UnlinkAll(); + } + + void WaitableManager::MoveAllFrom(WaitableManager *other) { + auto &dst_impl = GetReference(this->impl_storage); + auto &src_impl = GetReference(other->impl_storage); + + dst_impl.MoveAllFrom(src_impl); + } + +} diff --git a/stratosphere/libstratosphere/source/patcher/patcher_api.cpp b/stratosphere/libstratosphere/source/patcher/patcher_api.cpp index 8834a93a5..63257d7a9 100644 --- a/stratosphere/libstratosphere/source/patcher/patcher_api.cpp +++ b/stratosphere/libstratosphere/source/patcher/patcher_api.cpp @@ -101,15 +101,11 @@ namespace sts::patcher { void ApplyIpsPatch(u8 *mapped_module, size_t mapped_size, size_t protected_size, size_t offset, bool is_ips32, FILE *f_ips) { /* Validate offset/protected size. */ - if (offset > protected_size) { - std::abort(); - } + STS_ASSERT(offset <= protected_size); u8 buffer[sizeof(Ips32TailMagic)]; while (true) { - if (fread(buffer, is_ips32 ? sizeof(Ips32TailMagic) : sizeof(IpsTailMagic), 1, f_ips) != 1) { - std::abort(); - } + STS_ASSERT(fread(buffer, is_ips32 ? sizeof(Ips32TailMagic) : sizeof(IpsTailMagic), 1, f_ips) == 1); if (IsIpsTail(is_ips32, buffer)) { break; @@ -119,24 +115,18 @@ namespace sts::patcher { u32 patch_offset = GetIpsPatchOffset(is_ips32, buffer); /* Size of patch. */ - if (fread(buffer, 2, 1, f_ips) != 1) { - std::abort(); - } + STS_ASSERT(fread(buffer, 2, 1, f_ips) == 1); u32 patch_size = GetIpsPatchSize(is_ips32, buffer); /* Check for RLE encoding. */ if (patch_size == 0) { /* Size of RLE. */ - if (fread(buffer, 2, 1, f_ips) != 1) { - std::abort(); - } + STS_ASSERT(fread(buffer, 2, 1, f_ips) == 1); u32 rle_size = (buffer[0] << 8) | (buffer[1]); /* Value for RLE. */ - if (fread(buffer, 1, 1, f_ips) != 1) { - std::abort(); - } + STS_ASSERT(fread(buffer, 1, 1, f_ips) == 1); /* Ensure we don't write to protected region. */ if (patch_offset < protected_size) { @@ -179,9 +169,7 @@ namespace sts::patcher { if (patch_offset + read_size > mapped_size) { read_size = mapped_size - patch_offset; } - if (fread(mapped_module + patch_offset, read_size, 1, f_ips) != 1) { - std::abort(); - } + STS_ASSERT(fread(mapped_module + patch_offset, read_size, 1, f_ips) == 1); if (patch_size > read_size) { fseek(f_ips, patch_size - read_size, SEEK_CUR); } diff --git a/stratosphere/libstratosphere/source/updater/updater_api.cpp b/stratosphere/libstratosphere/source/updater/updater_api.cpp index 2e6afd254..d078b9650 100644 --- a/stratosphere/libstratosphere/source/updater/updater_api.cpp +++ b/stratosphere/libstratosphere/source/updater/updater_api.cpp @@ -142,9 +142,7 @@ namespace sts::updater { Result GetBootImagePackageDataId(u64 *out_data_id, BootModeType mode, void *work_buffer, size_t work_buffer_size) { /* Ensure we can read content metas. */ constexpr size_t MaxContentMetas = 0x40; - if (work_buffer_size < sizeof(NcmMetaRecord) * MaxContentMetas) { - std::abort(); - } + STS_ASSERT(work_buffer_size >= sizeof(NcmMetaRecord) * MaxContentMetas); /* Open NAND System meta database, list contents. */ NcmContentMetaDatabase meta_db; @@ -161,9 +159,7 @@ namespace sts::updater { return ResultUpdaterBootImagePackageNotFound; } - if (total_entries != written_entries) { - std::abort(); - } + STS_ASSERT(total_entries == written_entries); /* Output is sorted, return the lowest valid exfat entry. */ if (total_entries > 1) { @@ -203,7 +199,7 @@ namespace sts::updater { return ResultUpdaterBootImagePackageNotFound; } } R_END_TRY_CATCH; - ON_SCOPE_EXIT { if (R_FAILED(romfsUnmount(GetBootImagePackageMountPath()))) { std::abort(); } }; + ON_SCOPE_EXIT { R_ASSERT(romfsUnmount(GetBootImagePackageMountPath())); }; /* Read and validate hashes of boot images. */ { @@ -258,7 +254,7 @@ namespace sts::updater { return ResultUpdaterBootImagePackageNotFound; } } R_END_TRY_CATCH; - ON_SCOPE_EXIT { if (R_FAILED(romfsUnmount(GetBootImagePackageMountPath()))) { std::abort(); } }; + ON_SCOPE_EXIT { R_ASSERT(romfsUnmount(GetBootImagePackageMountPath())); }; /* Read and validate hashes of boot images. */ { @@ -329,7 +325,7 @@ namespace sts::updater { return ResultUpdaterBootImagePackageNotFound; } } R_END_TRY_CATCH; - ON_SCOPE_EXIT { if (R_FAILED(romfsUnmount(GetBootImagePackageMountPath()))) { std::abort(); } }; + ON_SCOPE_EXIT { R_ASSERT(romfsUnmount(GetBootImagePackageMountPath())); }; { Boot0Accessor boot0_accessor; @@ -386,7 +382,7 @@ namespace sts::updater { return ResultUpdaterBootImagePackageNotFound; } } R_END_TRY_CATCH; - ON_SCOPE_EXIT { if (R_FAILED(romfsUnmount(GetBootImagePackageMountPath()))) { std::abort(); } }; + ON_SCOPE_EXIT { R_ASSERT(romfsUnmount(GetBootImagePackageMountPath())); }; { Boot0Accessor boot0_accessor; @@ -533,9 +529,7 @@ namespace sts::updater { /* Get a session to ncm. */ DoWithSmSession([&]() { - if (R_FAILED(ncmInitialize())) { - std::abort(); - } + R_ASSERT(ncmInitialize()); }); ON_SCOPE_EXIT { ncmExit(); }; diff --git a/stratosphere/libstratosphere/source/updater/updater_bis_management.cpp b/stratosphere/libstratosphere/source/updater/updater_bis_management.cpp index 27912c0e0..364365fab 100644 --- a/stratosphere/libstratosphere/source/updater/updater_bis_management.cpp +++ b/stratosphere/libstratosphere/source/updater/updater_bis_management.cpp @@ -35,23 +35,18 @@ namespace sts::updater { } Result BisAccessor::Read(void *dst, size_t size, u64 offset) { - if (offset % SectorAlignment) { - std::abort(); - } + STS_ASSERT((offset % SectorAlignment) == 0); return fsStorageRead(&this->storage, offset, dst, size); } Result BisAccessor::Write(u64 offset, const void *src, size_t size) { - if (offset % SectorAlignment) { - std::abort(); - } + STS_ASSERT((offset % SectorAlignment) == 0); return fsStorageWrite(&this->storage, offset, src, size); } Result BisAccessor::Write(u64 offset, size_t size, const char *bip_path, void *work_buffer, size_t work_buffer_size) { - if (offset % SectorAlignment != 0 || work_buffer_size % SectorAlignment != 0) { - std::abort(); - } + STS_ASSERT((offset % SectorAlignment) == 0); + STS_ASSERT((work_buffer_size % SectorAlignment) == 0); FILE *bip_fp = fopen(bip_path, "rb"); if (bip_fp == NULL) { @@ -68,9 +63,7 @@ namespace sts::updater { return fsdevGetLastResult(); } } - if (written + read_size > size) { - std::abort(); - } + STS_ASSERT(written + read_size <= size); size_t aligned_size = ((read_size + SectorAlignment - 1) / SectorAlignment) * SectorAlignment; R_TRY(this->Write(offset + written, work_buffer, aligned_size)); @@ -84,9 +77,8 @@ namespace sts::updater { } Result BisAccessor::Clear(u64 offset, u64 size, void *work_buffer, size_t work_buffer_size) { - if (offset % SectorAlignment != 0 || work_buffer_size % SectorAlignment != 0) { - std::abort(); - } + STS_ASSERT((offset % SectorAlignment) == 0); + STS_ASSERT((work_buffer_size % SectorAlignment) == 0); std::memset(work_buffer, 0, work_buffer_size); @@ -100,9 +92,8 @@ namespace sts::updater { } Result BisAccessor::GetHash(void *dst, u64 offset, u64 size, u64 hash_size, void *work_buffer, size_t work_buffer_size) { - if (offset % SectorAlignment != 0 || work_buffer_size % SectorAlignment != 0) { - std::abort(); - } + STS_ASSERT((offset % SectorAlignment) == 0); + STS_ASSERT((work_buffer_size % SectorAlignment) == 0); Sha256Context sha_ctx; sha256ContextCreate(&sha_ctx); @@ -122,18 +113,12 @@ namespace sts::updater { size_t Boot0Accessor::GetBootloaderVersion(void *bct) { u32 version = *reinterpret_cast(reinterpret_cast(bct) + BctVersionOffset); - if (version > BctVersionMax) { - std::abort(); - } - + STS_ASSERT(version <= BctVersionMax); return static_cast(version); } size_t Boot0Accessor::GetEksIndex(size_t bootloader_version) { - if (bootloader_version > BctVersionMax) { - std::abort(); - } - + STS_ASSERT(bootloader_version <= BctVersionMax); return (bootloader_version > 0) ? bootloader_version - 1 : 0; } diff --git a/stratosphere/libstratosphere/source/updater/updater_bis_management.hpp b/stratosphere/libstratosphere/source/updater/updater_bis_management.hpp index 913e09f72..83078e21e 100644 --- a/stratosphere/libstratosphere/source/updater/updater_bis_management.hpp +++ b/stratosphere/libstratosphere/source/updater/updater_bis_management.hpp @@ -140,9 +140,7 @@ namespace sts::updater { public: Result Read(size_t *out_size, void *dst, size_t size, EnumType which) { const auto entry = FindEntry(which); - if (size < entry->size) { - std::abort(); - } + STS_ASSERT(size >= entry->size); R_TRY(BisAccessor::Read(dst, entry->size, entry->offset)); @@ -152,10 +150,8 @@ namespace sts::updater { Result Write(const void *src, size_t size, EnumType which) { const auto entry = FindEntry(which); - if (size > entry->size || size % BisAccessor::SectorAlignment != 0) { - std::abort(); - } - + STS_ASSERT(size <= entry->size); + STS_ASSERT((size % BisAccessor::SectorAlignment) == 0); return BisAccessor::Write(entry->offset, src, size); } diff --git a/stratosphere/libstratosphere/source/updater/updater_bis_save.cpp b/stratosphere/libstratosphere/source/updater/updater_bis_save.cpp index a06158763..07a5f5689 100644 --- a/stratosphere/libstratosphere/source/updater/updater_bis_save.cpp +++ b/stratosphere/libstratosphere/source/updater/updater_bis_save.cpp @@ -33,9 +33,9 @@ namespace sts::updater { } Result BisSave::Initialize(void *work_buffer, size_t work_buffer_size) { - if (work_buffer_size < SaveSize || reinterpret_cast(work_buffer) & 0xFFF || work_buffer_size & 0x1FF) { - std::abort(); - } + STS_ASSERT(work_buffer_size >= SaveSize); + STS_ASSERT(util::IsAligned(reinterpret_cast(work_buffer), 0x1000)); + STS_ASSERT(util::IsAligned(work_buffer_size, 0x200)); R_TRY(this->accessor.Initialize()); this->save_buffer = work_buffer; diff --git a/stratosphere/libstratosphere/source/updater/updater_paths.cpp b/stratosphere/libstratosphere/source/updater/updater_paths.cpp index 794297b50..228d89c4b 100644 --- a/stratosphere/libstratosphere/source/updater/updater_paths.cpp +++ b/stratosphere/libstratosphere/source/updater/updater_paths.cpp @@ -34,9 +34,7 @@ namespace sts::updater { constexpr const char *Package2PathA = "bip:/a/package2"; const char *ChooseCandidatePath(const char * const *candidates, size_t num_candidates) { - if (num_candidates == 0) { - std::abort(); - } + STS_ASSERT(num_candidates > 0); for (size_t i = 0; i < num_candidates; i++) { struct stat buf; diff --git a/stratosphere/libstratosphere/source/util/util_compression.cpp b/stratosphere/libstratosphere/source/util/util_compression.cpp index 5cc8b836f..ba33163b8 100644 --- a/stratosphere/libstratosphere/source/util/util_compression.cpp +++ b/stratosphere/libstratosphere/source/util/util_compression.cpp @@ -25,9 +25,8 @@ namespace sts::util { /* Compression utilities. */ int CompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size) { /* Size checks. */ - if (dst_size > std::numeric_limits::max() || src_size > std::numeric_limits::max()) { - std::abort(); - } + STS_ASSERT(dst_size <= std::numeric_limits::max()); + STS_ASSERT(src_size <= std::numeric_limits::max()); /* This is just a thin wrapper around LZ4. */ return LZ4_compress_default(reinterpret_cast(src), reinterpret_cast(dst), static_cast(src_size), static_cast(dst_size)); @@ -36,9 +35,8 @@ namespace sts::util { /* Decompression utilities. */ int DecompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size) { /* Size checks. */ - if (dst_size > std::numeric_limits::max() || src_size > std::numeric_limits::max()) { - std::abort(); - } + STS_ASSERT(dst_size <= std::numeric_limits::max()); + STS_ASSERT(src_size <= std::numeric_limits::max()); /* This is just a thin wrapper around LZ4. */ return LZ4_decompress_safe(reinterpret_cast(src), reinterpret_cast(dst), static_cast(src_size), static_cast(dst_size)); diff --git a/stratosphere/libstratosphere/source/util/util_ini.cpp b/stratosphere/libstratosphere/source/util/util_ini.cpp index a552b5946..0bf4214c1 100644 --- a/stratosphere/libstratosphere/source/util/util_ini.cpp +++ b/stratosphere/libstratosphere/source/util/util_ini.cpp @@ -50,9 +50,7 @@ namespace sts::util::ini { size_t try_read = std::min(size_t(num - 1), ctx->num_left); size_t actually_read; R_ASSERT(fsFileRead(ctx->f, ctx->offset, str, try_read, FS_READOPTION_NONE, &actually_read)); - if (actually_read != try_read) { - std::abort(); - } + STS_ASSERT(actually_read == try_read); /* Only "read" up to the first \n. */ size_t offset = actually_read; diff --git a/stratosphere/loader/source/ldr_content_management.cpp b/stratosphere/loader/source/ldr_content_management.cpp index 734b60bb3..c65eabfe9 100644 --- a/stratosphere/loader/source/ldr_content_management.cpp +++ b/stratosphere/loader/source/ldr_content_management.cpp @@ -83,9 +83,7 @@ namespace sts::ldr { Result MountNspFileSystem(const char *device_name, const char *path) { FsFileSystem fs; R_TRY(fsOpenFileSystemWithId(&fs, 0, FsFileSystemType_ApplicationPackage, path)); - if(fsdevMountDevice(device_name, fs) < 0) { - std::abort(); - } + STS_ASSERT(fsdevMountDevice(device_name, fs) >= 0); return ResultSuccess; } @@ -178,9 +176,7 @@ namespace sts::ldr { /* Try to mount the content path. */ FsFileSystem fs; R_TRY(fsldrOpenCodeFileSystem(static_cast(loc.title_id), path, &fs)); - if(fsdevMountDevice(CodeFileSystemDeviceName, fs) == -1) { - std::abort(); - } + STS_ASSERT(fsdevMountDevice(CodeFileSystemDeviceName, fs) != -1); /* Note that we mounted code. */ this->is_code_mounted = true; diff --git a/stratosphere/loader/source/ldr_ecs.cpp b/stratosphere/loader/source/ldr_ecs.cpp index c3c896ddd..69dc9afda 100644 --- a/stratosphere/loader/source/ldr_ecs.cpp +++ b/stratosphere/loader/source/ldr_ecs.cpp @@ -73,7 +73,7 @@ namespace sts::ldr::ecs { std::snprintf(device_name, DeviceNameSizeMax, "ecs-%016lx", static_cast(title_id)); /* Create session. */ - AutoHandle server, client; + os::ManagedHandle server, client; R_TRY(svcCreateSession(server.GetPointer(), client.GetPointer(), 0, 0)); /* Create service. */ diff --git a/stratosphere/loader/source/ldr_loader_service.cpp b/stratosphere/loader/source/ldr_loader_service.cpp index 0142e7ac5..38d7af60f 100644 --- a/stratosphere/loader/source/ldr_loader_service.cpp +++ b/stratosphere/loader/source/ldr_loader_service.cpp @@ -27,7 +27,7 @@ namespace sts::ldr { /* Official commands. */ Result LoaderService::CreateProcess(Out proc_h, PinId id, u32 flags, CopiedHandle reslimit) { - AutoHandle reslimit_holder(reslimit.GetValue()); + os::ManagedHandle reslimit_holder(reslimit.GetValue()); ncm::TitleLocation loc; char path[FS_MAX_PATH]; diff --git a/stratosphere/loader/source/ldr_process_creation.cpp b/stratosphere/loader/source/ldr_process_creation.cpp index 1014bffd1..148060652 100644 --- a/stratosphere/loader/source/ldr_process_creation.cpp +++ b/stratosphere/loader/source/ldr_process_creation.cpp @@ -56,9 +56,7 @@ namespace sts::ldr { }; constexpr const char *GetNsoName(size_t idx) { - if (idx >= Nso_Count) { - std::abort(); - } + STS_ASSERT(idx < Nso_Count); constexpr const char *NsoNames[Nso_Count] = { "rtld", @@ -91,7 +89,7 @@ namespace sts::ldr { static_assert(sizeof(CreateProcessInfo) == 0x30, "CreateProcessInfo definition!"); struct ProcessInfo { - AutoHandle process_handle; + os::ManagedHandle process_handle; uintptr_t args_address; size_t args_size; uintptr_t nso_address[Nso_Count]; diff --git a/stratosphere/pm/source/boot2/boot2_api.cpp b/stratosphere/pm/source/boot2/boot2_api.cpp index c5c146422..524776d49 100644 --- a/stratosphere/pm/source/boot2/boot2_api.cpp +++ b/stratosphere/pm/source/boot2/boot2_api.cpp @@ -284,9 +284,7 @@ namespace sts::boot2 { } /* Don't allow invalid lines. */ - if (name_len > sizeof(sm::ServiceName)) { - std::abort(); - } + STS_ASSERT(name_len <= sizeof(sm::ServiceName)); /* Declare the service. */ R_ASSERT(sm::mitm::DeclareFutureMitm(sm::ServiceName::Encode(mitm_list + offset, name_len))); diff --git a/stratosphere/pm/source/impl/pm_process_info.cpp b/stratosphere/pm/source/impl/pm_process_info.cpp index 4e53c0924..01ed87bbc 100644 --- a/stratosphere/pm/source/impl/pm_process_info.cpp +++ b/stratosphere/pm/source/impl/pm_process_info.cpp @@ -21,8 +21,8 @@ namespace sts::pm::impl { - ProcessInfo::ProcessInfo(Handle h, u64 pid, ldr::PinId pin, const ncm::TitleLocation &l) : process_id(pid), pin_id(pin), loc(l), handle(h), state(ProcessState_Created), flags(0) { - /* ... */ + ProcessInfo::ProcessInfo(Handle h, u64 pid, ldr::PinId pin, const ncm::TitleLocation &l) : process_id(pid), pin_id(pin), loc(l), handle(h), state(ProcessState_Created), flags(0), waitable_holder(h) { + this->waitable_holder.SetUserData(reinterpret_cast(this)); } ProcessInfo::~ProcessInfo() { @@ -39,6 +39,9 @@ namespace sts::pm::impl { /* Close the process's handle. */ svcCloseHandle(this->handle); this->handle = INVALID_HANDLE; + + /* Unlink the process from its waitable manager. */ + this->waitable_holder.UnlinkFromWaitableManager(); } } diff --git a/stratosphere/pm/source/impl/pm_process_info.hpp b/stratosphere/pm/source/impl/pm_process_info.hpp index 10d060944..1b40c557e 100644 --- a/stratosphere/pm/source/impl/pm_process_info.hpp +++ b/stratosphere/pm/source/impl/pm_process_info.hpp @@ -24,8 +24,12 @@ namespace sts::pm::impl { + class ProcessList; + class ProcessInfo { + friend class ProcessList; NON_COPYABLE(ProcessInfo); + NON_MOVEABLE(ProcessInfo); private: enum Flag : u32 { Flag_SignalOnExit = (1 << 0), @@ -39,12 +43,14 @@ namespace sts::pm::impl { Flag_StartedStateChanged = (1 << 8), }; private: + util::IntrusiveListNode list_node; const u64 process_id; const ldr::PinId pin_id; const ncm::TitleLocation loc; Handle handle; ProcessState state; u32 flags; + os::WaitableHolder waitable_holder; private: void SetFlag(Flag flag) { this->flags |= flag; @@ -62,6 +68,10 @@ namespace sts::pm::impl { ~ProcessInfo(); void Cleanup(); + void LinkToWaitableManager(os::WaitableManager &manager) { + manager.LinkWaitableHolder(&this->waitable_holder); + } + Handle GetHandle() const { return this->handle; } @@ -148,31 +158,11 @@ namespace sts::pm::impl { #undef DEFINE_FLAG_SET #undef DEFINE_FLAG_GET #undef DEFINE_FLAG_CLEAR - }; - Result OnProcessSignaled(std::shared_ptr process_info); - - class ProcessInfoWaiter final : public IWaitable { - private: - std::shared_ptr process_info; - public: - ProcessInfoWaiter(std::shared_ptr p) : process_info(std::move(p)) { /* ... */ } - - /* IWaitable */ - Handle GetHandle() override { - return this->process_info->GetHandle(); - } - - Result HandleSignaled(u64 timeout) override { - return OnProcessSignaled(this->process_info); - } - }; - - class ProcessList final { + class ProcessList final : public util::IntrusiveListMemberTraits<&ProcessInfo::list_node>::ListType { private: os::Mutex lock; - std::vector> processes; public: void Lock() { this->lock.Lock(); @@ -182,54 +172,28 @@ namespace sts::pm::impl { this->lock.Unlock(); } - size_t GetSize() const { - return this->processes.size(); + void Remove(ProcessInfo *process_info) { + this->erase(this->iterator_to(*process_info)); } - std::shared_ptr Pop() { - auto front = this->processes[0]; - this->processes.erase(this->processes.begin()); - return front; - } - - void Add(std::shared_ptr process_info) { - this->processes.push_back(process_info); - } - - void Remove(u64 process_id) { - for (auto it = this->processes.begin(); it != this->processes.end(); it++) { - if ((*it)->GetProcessId() == process_id) { - this->processes.erase(it); - break; - } - } - } - - std::shared_ptr Find(u64 process_id) { - for (auto it = this->processes.begin(); it != this->processes.end(); it++) { - if ((*it)->GetProcessId() == process_id) { - return *it; + ProcessInfo *Find(u64 process_id) { + for (auto it = this->begin(); it != this->end(); it++) { + if ((*it).GetProcessId() == process_id) { + return &*it; } } return nullptr; } - std::shared_ptr Find(ncm::TitleId title_id) { - for (auto it = this->processes.begin(); it != this->processes.end(); it++) { - if ((*it)->GetTitleLocation().title_id == title_id) { - return *it; + ProcessInfo *Find(ncm::TitleId title_id) { + for (auto it = this->begin(); it != this->end(); it++) { + if ((*it).GetTitleLocation().title_id == title_id) { + return &*it; } } return nullptr; } - std::shared_ptr operator[](int i) { - return this->processes[i]; - } - - const std::shared_ptr operator[](int i) const { - return this->processes[i]; - } }; class ProcessListAccessor final { @@ -259,14 +223,6 @@ namespace sts::pm::impl { const ProcessList &operator*() const { return this->list; } - - std::shared_ptr operator[](int i) { - return this->list[i]; - } - - const std::shared_ptr operator[](int i) const { - return this->list[i]; - } }; } diff --git a/stratosphere/pm/source/impl/pm_process_manager.cpp b/stratosphere/pm/source/impl/pm_process_manager.cpp index 048fcb7c5..271af34fe 100644 --- a/stratosphere/pm/source/impl/pm_process_manager.cpp +++ b/stratosphere/pm/source/impl/pm_process_manager.cpp @@ -141,20 +141,19 @@ namespace sts::pm::impl { /* Process Tracking globals. */ os::Thread g_process_track_thread; - auto g_process_waitable_manager = WaitableManager(1); /* Process lists. */ ProcessList g_process_list; ProcessList g_dead_process_list; /* Global events. */ - IEvent *g_process_event = CreateWriteOnlySystemEvent(); - IEvent *g_hook_to_create_process_event = CreateWriteOnlySystemEvent(); - IEvent *g_hook_to_create_application_process_event = CreateWriteOnlySystemEvent(); - IEvent *g_boot_finished_event = CreateWriteOnlySystemEvent(); + 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; /* Process Launch synchronization globals. */ - IEvent *g_process_launch_start_event = CreateWriteOnlySystemEvent(); + os::Event g_process_launch_start_event; os::Event g_process_launch_finish_event; Result g_process_launch_result = ResultSuccess; LaunchProcessArgs g_process_launch_args = {}; @@ -163,13 +162,34 @@ namespace sts::pm::impl { std::atomic g_title_id_hook; std::atomic g_application_hook; + /* Forward declarations. */ + Result LaunchProcess(os::WaitableManager &waitable_manager, const LaunchProcessArgs &args); + Result OnProcessSignaled(ProcessListAccessor &list, ProcessInfo *process_info); + /* Helpers. */ void ProcessTrackingMain(void *arg) { /* This is the main loop of the process tracking thread. */ - /* Service processes. */ - g_process_waitable_manager.AddWaitable(g_process_launch_start_event); - g_process_waitable_manager.Process(); + /* 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); + + while (true) { + auto signaled_holder = process_waitable_manager.WaitAny(); + if (signaled_holder == &start_event_holder) { + /* Launch start event signaled. */ + /* TryWait will clear signaled, preventing duplicate notifications. */ + if (g_process_launch_start_event.TryWait()) { + g_process_launch_result = LaunchProcess(process_waitable_manager, g_process_launch_args); + g_process_launch_finish_event.Signal(); + } + } else { + /* Some process was signaled. */ + ProcessListAccessor list(g_process_list); + OnProcessSignaled(list, reinterpret_cast(signaled_holder->GetUserData())); + } + } } inline u32 GetLoaderCreateProcessFlags(u32 launch_flags) { @@ -188,8 +208,8 @@ namespace sts::pm::impl { bool HasApplicationProcess() { ProcessListAccessor list(g_process_list); - for (size_t i = 0; i < list->GetSize(); i++) { - if (list[i]->IsApplication()) { + for (auto &process : *list) { + if (process.IsApplication()) { return true; } } @@ -197,16 +217,24 @@ namespace sts::pm::impl { return false; } - Result StartProcess(std::shared_ptr process_info, const ldr::ProgramInfo *program_info) { + Result StartProcess(ProcessInfo *process_info, const ldr::ProgramInfo *program_info) { R_TRY(svcStartProcess(process_info->GetHandle(), program_info->main_thread_priority, program_info->default_cpu_id, program_info->main_thread_stack_size)); process_info->SetState(ProcessState_Running); return ResultSuccess; } - Result LaunchProcess(const LaunchProcessArgs *args) { + void CleanupProcessInfo(ProcessListAccessor &list, ProcessInfo *process_info) { + /* Remove the process from the list. */ + list->Remove(process_info); + + /* Delete the process. */ + delete process_info; + } + + Result LaunchProcess(os::WaitableManager &waitable_manager, const LaunchProcessArgs &args) { /* Get Program Info. */ ldr::ProgramInfo program_info; - R_TRY(ldr::pm::GetProgramInfo(&program_info, args->location)); + R_TRY(ldr::pm::GetProgramInfo(&program_info, args.location)); const bool is_application = (program_info.flags & ldr::ProgramInfoFlag_ApplicationTypeMask) == ldr::ProgramInfoFlag_Application; const bool allow_debug = (program_info.flags & ldr::ProgramInfoFlag_AllowDebug) || GetRuntimeFirmwareVersion() < FirmwareVersion_200; @@ -216,7 +244,7 @@ namespace sts::pm::impl { } /* Fix the title location to use the right title id. */ - const ncm::TitleLocation location = ncm::TitleLocation::Make(program_info.title_id, static_cast(args->location.storage_id)); + const ncm::TitleLocation location = ncm::TitleLocation::Make(program_info.title_id, static_cast(args.location.storage_id)); /* Pin the program with loader. */ ldr::PinId pin_id; @@ -227,7 +255,7 @@ namespace sts::pm::impl { /* Actually create the process. */ Handle process_handle; - R_TRY_CLEANUP(ldr::pm::CreateProcess(&process_handle, pin_id, GetLoaderCreateProcessFlags(args->flags), resource::GetResourceLimitHandle(&program_info)), { + R_TRY_CLEANUP(ldr::pm::CreateProcess(&process_handle, pin_id, GetLoaderCreateProcessFlags(args.flags), resource::GetResourceLimitHandle(&program_info)), { ldr::pm::UnpinTitle(pin_id); }); @@ -236,7 +264,21 @@ namespace sts::pm::impl { R_ASSERT(svcGetProcessId(&process_id, process_handle)); /* Make new process info. */ - auto process_info = std::make_shared(process_handle, process_id, pin_id, location); + ProcessInfo *process_info = new ProcessInfo(process_handle, process_id, pin_id, location); + + /* Link new process info. */ + { + ProcessListAccessor list(g_process_list); + list->push_back(*process_info); + process_info->LinkToWaitableManager(waitable_manager); + } + + /* Prevent resource leakage if register fails. */ + auto cleanup_guard = SCOPE_GUARD { + ProcessListAccessor list(g_process_list); + process_info->Cleanup(); + CleanupProcessInfo(list, process_info); + }; const u8 *acid_sac = program_info.ac_buffer; const u8 *aci_sac = acid_sac + program_info.acid_sac_size; @@ -251,62 +293,116 @@ namespace sts::pm::impl { if (is_application) { process_info->SetApplication(); } - if (ShouldSignalOnStart(args->flags) && allow_debug) { + if (ShouldSignalOnStart(args.flags) && allow_debug) { process_info->SetSignalOnStart(); } - if (ShouldSignalOnExit(args->flags)) { + if (ShouldSignalOnExit(args.flags)) { process_info->SetSignalOnExit(); } - if (ShouldSignalOnDebugEvent(args->flags) && allow_debug) { + if (ShouldSignalOnDebugEvent(args.flags) && allow_debug) { process_info->SetSignalOnDebugEvent(); } /* Process hooks/signaling. */ if (location.title_id == g_title_id_hook) { - g_hook_to_create_process_event->Signal(); + g_hook_to_create_process_event.Signal(); g_title_id_hook = ncm::TitleId::Invalid; } else if (is_application && g_application_hook) { - g_hook_to_create_application_process_event->Signal(); + g_hook_to_create_application_process_event.Signal(); g_application_hook = false; - } else if (!ShouldStartSuspended(args->flags)) { + } else if (!ShouldStartSuspended(args.flags)) { R_TRY(StartProcess(process_info, &program_info)); } - /* Add process to list. */ + /* We succeeded, so we can cancel our cleanup. */ + cleanup_guard.Cancel(); + + *args.out_process_id = process_id; + return ResultSuccess; + } + + Result OnProcessSignaled(ProcessListAccessor &list, ProcessInfo *process_info) { + /* Resest the process's signal. */ + svcResetSignal(process_info->GetHandle()); + + /* Update the process's state. */ + const ProcessState old_state = process_info->GetState(); { - ProcessListAccessor list(g_process_list); - list->Add(process_info); - g_process_waitable_manager.AddWaitable(new ProcessInfoWaiter(process_info)); + u64 tmp = 0; + R_ASSERT(svcGetProcessInfo(&tmp, process_info->GetHandle(), ProcessInfoType_ProcessState)); + process_info->SetState(static_cast(tmp)); + } + const ProcessState new_state = process_info->GetState(); + + /* If we're transitioning away from crashed, clear waiting attached. */ + if (old_state == ProcessState_Crashed && new_state != ProcessState_Crashed) { + process_info->ClearExceptionWaitingAttach(); } - *args->out_process_id = process_id; - return ResultSuccess; - } + switch (new_state) { + case ProcessState_Created: + case ProcessState_CreatedAttached: + case ProcessState_Exiting: + break; + case ProcessState_Running: + if (process_info->ShouldSignalOnDebugEvent()) { + process_info->ClearSuspended(); + process_info->SetSuspendedStateChanged(); + g_process_event.Signal(); + } else if (GetRuntimeFirmwareVersion() >= FirmwareVersion_200 && process_info->ShouldSignalOnStart()) { + process_info->SetStartedStateChanged(); + process_info->ClearSignalOnStart(); + g_process_event.Signal(); + } + break; + case ProcessState_Crashed: + process_info->SetExceptionOccurred(); + g_process_event.Signal(); + break; + case ProcessState_RunningAttached: + if (process_info->ShouldSignalOnDebugEvent()) { + process_info->ClearSuspended(); + process_info->SetSuspendedStateChanged(); + g_process_event.Signal(); + } + break; + case ProcessState_Exited: + if (GetRuntimeFirmwareVersion() < FirmwareVersion_500 && process_info->ShouldSignalOnExit()) { + g_process_event.Signal(); + } else { + /* Free process resources, unlink from waitable manager. */ + process_info->Cleanup(); - Result LaunchProcessEventCallback(u64 timeout) { - g_process_launch_start_event->Clear(); - g_process_launch_result = LaunchProcess(&g_process_launch_args); - g_process_launch_finish_event.Signal(); - return ResultSuccess; - } + /* Handle the case where we need to keep the process alive some time longer. */ + if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500 && process_info->ShouldSignalOnExit()) { + /* Remove from the living list. */ + list->Remove(process_info); - void CleanupProcess(ProcessListAccessor &list, std::shared_ptr process_info) { - /* Remove the process from the list. */ - list->Remove(process_info->GetProcessId()); + /* Add the process to the list of dead processes. */ + { + ProcessListAccessor dead_list(g_dead_process_list); + dead_list->push_back(*process_info); + } - /* Close process resources. */ - process_info->Cleanup(); - - /* Handle the case where we need to keep the process alive some time longer. */ - if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500 && process_info->ShouldSignalOnExit()) { - /* Add the process to the list of dead processes. */ - { - ProcessListAccessor dead_list(g_dead_process_list); - dead_list->Add(process_info); - } - /* Signal. */ - g_process_event->Signal(); + /* Signal. */ + g_process_event.Signal(); + } else { + /* Actually delete process. */ + CleanupProcessInfo(list, process_info); + } + } + /* Return ConnectionClosed to cause libstratosphere to stop waiting on the process. */ + return ResultKernelConnectionClosed; + case ProcessState_DebugSuspended: + if (process_info->ShouldSignalOnDebugEvent()) { + process_info->SetSuspended(); + process_info->SetSuspendedStateChanged(); + g_process_event.Signal(); + } + break; } + + return ResultSuccess; } } @@ -314,13 +410,10 @@ namespace sts::pm::impl { /* Initialization. */ Result InitializeProcessManager() { /* Create events. */ - g_process_event = CreateWriteOnlySystemEvent(); - g_hook_to_create_process_event = CreateWriteOnlySystemEvent(); - g_hook_to_create_application_process_event = CreateWriteOnlySystemEvent(); - g_boot_finished_event = CreateWriteOnlySystemEvent(); - - /* Process launch is signaled via non-system event. */ - g_process_launch_start_event = CreateHosEvent(&LaunchProcessEventCallback); + R_ASSERT(g_process_event.InitializeAsInterProcessEvent()); + R_ASSERT(g_hook_to_create_process_event.InitializeAsInterProcessEvent()); + R_ASSERT(g_hook_to_create_application_process_event.InitializeAsInterProcessEvent()); + R_ASSERT(g_boot_finished_event.InitializeAsInterProcessEvent()); /* Initialize resource limits. */ R_TRY(resource::InitializeResourceManager()); @@ -332,73 +425,6 @@ namespace sts::pm::impl { return ResultSuccess; } - /* Process Info API. */ - Result OnProcessSignaled(std::shared_ptr process_info) { - /* Resest the process's signal. */ - svcResetSignal(process_info->GetHandle()); - - /* Update the process's state. */ - const ProcessState old_state = process_info->GetState(); - { - u64 tmp = 0; - R_ASSERT(svcGetProcessInfo(&tmp, process_info->GetHandle(), ProcessInfoType_ProcessState)); - process_info->SetState(static_cast(tmp)); - } - const ProcessState new_state = process_info->GetState(); - - /* If we're transitioning away from crashed, clear waiting attached. */ - if (old_state == ProcessState_Crashed && new_state != ProcessState_Crashed) { - process_info->ClearExceptionWaitingAttach(); - } - - switch (new_state) { - case ProcessState_Created: - case ProcessState_CreatedAttached: - case ProcessState_Exiting: - break; - case ProcessState_Running: - if (process_info->ShouldSignalOnDebugEvent()) { - process_info->ClearSuspended(); - process_info->SetSuspendedStateChanged(); - g_process_event->Signal(); - } else if (GetRuntimeFirmwareVersion() >= FirmwareVersion_200 && process_info->ShouldSignalOnStart()) { - process_info->SetStartedStateChanged(); - process_info->ClearSignalOnStart(); - g_process_event->Signal(); - } - break; - case ProcessState_Crashed: - process_info->SetExceptionOccurred(); - g_process_event->Signal(); - break; - case ProcessState_RunningAttached: - if (process_info->ShouldSignalOnDebugEvent()) { - process_info->ClearSuspended(); - process_info->SetSuspendedStateChanged(); - g_process_event->Signal(); - } - break; - case ProcessState_Exited: - if (GetRuntimeFirmwareVersion() < FirmwareVersion_500 && process_info->ShouldSignalOnExit()) { - g_process_event->Signal(); - } else { - ProcessListAccessor list(g_process_list); - CleanupProcess(list, process_info); - } - /* Return ConnectionClosed to cause libstratosphere to stop waiting on the process. */ - return ResultKernelConnectionClosed; - case ProcessState_DebugSuspended: - if (process_info->ShouldSignalOnDebugEvent()) { - process_info->SetSuspended(); - process_info->SetSuspendedStateChanged(); - g_process_event->Signal(); - } - break; - } - - return ResultSuccess; - } - /* Process Management. */ Result LaunchTitle(u64 *out_process_id, const ncm::TitleLocation &loc, u32 flags) { /* Ensure we only try to launch one title at a time. */ @@ -411,7 +437,7 @@ namespace sts::pm::impl { .location = loc, .flags = flags, }; - g_process_launch_start_event->Signal(); + g_process_launch_start_event.Signal(); g_process_launch_finish_event.Wait(); return g_process_launch_result; @@ -457,7 +483,7 @@ namespace sts::pm::impl { } Result GetProcessEventHandle(Handle *out) { - *out = g_process_event->GetHandle(); + *out = g_process_event.GetReadableHandle(); return ResultSuccess; } @@ -466,33 +492,33 @@ namespace sts::pm::impl { { ProcessListAccessor list(g_process_list); - for (size_t i = 0; i < list->GetSize(); i++) { - auto process_info = list[i]; - if (process_info->HasStarted() && process_info->HasStartedStateChanged()) { - process_info->ClearStartedStateChanged(); + + for (auto &process : *list) { + if (process.HasStarted() && process.HasStartedStateChanged()) { + process.ClearStartedStateChanged(); out->event = GetProcessEventValue(ProcessEvent::Started); - out->process_id = process_info->GetProcessId(); + out->process_id = process.GetProcessId(); return ResultSuccess; } - if (process_info->HasSuspendedStateChanged()) { - process_info->ClearSuspendedStateChanged(); - if (process_info->IsSuspended()) { + if (process.HasSuspendedStateChanged()) { + process.ClearSuspendedStateChanged(); + if (process.IsSuspended()) { out->event = GetProcessEventValue(ProcessEvent::DebugSuspended); } else { out->event = GetProcessEventValue(ProcessEvent::DebugRunning); } - out->process_id = process_info->GetProcessId(); + out->process_id = process.GetProcessId(); return ResultSuccess; } - if (process_info->HasExceptionOccurred()) { - process_info->ClearExceptionOccurred(); + if (process.HasExceptionOccurred()) { + process.ClearExceptionOccurred(); out->event = GetProcessEventValue(ProcessEvent::Exception); - out->process_id = process_info->GetProcessId(); + out->process_id = process.GetProcessId(); return ResultSuccess; } - if (GetRuntimeFirmwareVersion() < FirmwareVersion_500 && process_info->ShouldSignalOnExit() && process_info->HasExited()) { + if (GetRuntimeFirmwareVersion() < FirmwareVersion_500 && process.ShouldSignalOnExit() && process.HasExited()) { out->event = GetProcessEventValue(ProcessEvent::Exited); - out->process_id = process_info->GetProcessId(); + out->process_id = process.GetProcessId(); return ResultSuccess; } } @@ -502,10 +528,12 @@ namespace sts::pm::impl { if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) { ProcessListAccessor dead_list(g_dead_process_list); - if (dead_list->GetSize() > 0) { - auto process_info = dead_list->Pop(); + if (!dead_list->empty()) { + auto &process_info = dead_list->front(); out->event = GetProcessEventValue(ProcessEvent::Exited); - out->process_id = process_info->GetProcessId(); + out->process_id = process_info.GetProcessId(); + + CleanupProcessInfo(dead_list, &process_info); return ResultSuccess; } } @@ -527,7 +555,7 @@ namespace sts::pm::impl { return ResultPmNotExited; } - CleanupProcess(list, process_info); + CleanupProcessInfo(list, process_info); return ResultSuccess; } @@ -554,13 +582,11 @@ namespace sts::pm::impl { ProcessListAccessor list(g_process_list); size_t count = 0; - for (size_t i = 0; i < list->GetSize() && count < max_out_count; i++) { - auto process_info = list[i]; - if (process_info->HasExceptionWaitingAttach()) { - out_process_ids[count++] = process_info->GetProcessId(); + for (auto &process : *list) { + if (process.HasExceptionWaitingAttach()) { + out_process_ids[count++] = process.GetProcessId(); } } - *out_count = static_cast(count); return ResultSuccess; } @@ -592,10 +618,9 @@ namespace sts::pm::impl { Result GetApplicationProcessId(u64 *out_process_id) { ProcessListAccessor list(g_process_list); - for (size_t i = 0; i < list->GetSize(); i++) { - auto process_info = list[i]; - if (process_info->IsApplication()) { - *out_process_id = process_info->GetProcessId(); + for (auto &process : *list) { + if (process.IsApplication()) { + *out_process_id = process.GetProcessId(); return ResultSuccess; } } @@ -625,7 +650,7 @@ namespace sts::pm::impl { return ResultPmDebugHookInUse; } - *out_hook = g_hook_to_create_process_event->GetHandle(); + *out_hook = g_hook_to_create_process_event.GetReadableHandle(); return ResultSuccess; } @@ -637,7 +662,7 @@ namespace sts::pm::impl { return ResultPmDebugHookInUse; } - *out_hook = g_hook_to_create_application_process_event->GetHandle(); + *out_hook = g_hook_to_create_application_process_event.GetReadableHandle(); return ResultSuccess; } @@ -657,7 +682,7 @@ namespace sts::pm::impl { if (!g_has_boot_finished) { boot2::LaunchBootPrograms(); g_has_boot_finished = true; - g_boot_finished_event->Signal(); + g_boot_finished_event.Signal(); } return ResultSuccess; } @@ -666,10 +691,8 @@ namespace sts::pm::impl { /* In 8.0.0, Nintendo added this command, which signals that the boot sysmodule has finished. */ /* 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. */ - if (!spl::IsRecoveryBoot()) { - std::abort(); - } - *out = g_boot_finished_event->GetHandle(); + STS_ASSERT(spl::IsRecoveryBoot()); + *out = g_boot_finished_event.GetReadableHandle(); return ResultSuccess; } diff --git a/stratosphere/pm/source/impl/pm_resource_manager.cpp b/stratosphere/pm/source/impl/pm_resource_manager.cpp index 50798750a..f83529080 100644 --- a/stratosphere/pm/source/impl/pm_resource_manager.cpp +++ b/stratosphere/pm/source/impl/pm_resource_manager.cpp @@ -218,9 +218,7 @@ namespace sts::pm::resource { g_resource_limits[ResourceLimitGroup_Applet][LimitableResource_Threads]; /* Ensure we don't over-commit threads. */ - if (total_threads_available < total_threads_allocated) { - std::abort(); - } + STS_ASSERT(total_threads_allocated <= total_threads_available); /* Set number of extra threads. */ g_extra_application_threads_available = total_threads_available - total_threads_allocated; @@ -244,9 +242,7 @@ namespace sts::pm::resource { const u64 reserved_non_system_size = (application_size + applet_size + ReservedMemorySize600); /* Ensure there's enough memory for the system region. */ - if (reserved_non_system_size >= total_memory) { - std::abort(); - } + STS_ASSERT(reserved_non_system_size < total_memory); g_memory_resource_limits[spl::MemoryArrangement_Dynamic][ResourceLimitGroup_System] = total_memory - reserved_non_system_size; } else { @@ -344,9 +340,8 @@ namespace sts::pm::resource { Result GetResourceLimitValues(u64 *out_cur, u64 *out_lim, ResourceLimitGroup group, LimitableResource resource) { /* Do not allow out of bounds access. */ - if (group >= ResourceLimitGroup_Count || resource >= LimitableResource_Count) { - std::abort(); - } + STS_ASSERT(group < ResourceLimitGroup_Count); + STS_ASSERT(resource < LimitableResource_Count); const Handle reslimit_hnd = GetResourceLimitHandle(group); R_TRY(svcGetResourceLimitCurrentValue(out_cur, reslimit_hnd, resource)); diff --git a/stratosphere/pm/source/pm_main.cpp b/stratosphere/pm/source/pm_main.cpp index b87bad0a2..7a35aec8c 100644 --- a/stratosphere/pm/source/pm_main.cpp +++ b/stratosphere/pm/source/pm_main.cpp @@ -77,37 +77,6 @@ namespace { constexpr u8 PrivilegedServiceAccessControl[] = {0x80, '*', 0x00, '*'}; constexpr size_t ProcessCountMax = 0x40; - /* TODO: Libstratosphere this stuff during fatal/creport rewrite. */ - enum class DebugEventType : u32 { - AttachProcess = 0, - AttachThread = 1, - ExitProcess = 2, - ExitThread = 3, - Exception = 4 - }; - - struct AttachProcessInfo { - sts::ncm::TitleId title_id; - u64 process_id; - char name[0xC]; - u32 flags; - u64 user_exception_context_address; /* 5.0.0+ */ - }; - - union DebugInfo { - AttachProcessInfo attach_process; - }; - - struct DebugEventInfo { - DebugEventType type; - u32 flags; - u64 thread_id; - union { - DebugInfo info; - u64 _[0x40/sizeof(u64)]; - }; - }; - /* This uses debugging SVCs to retrieve a process's title id. */ sts::ncm::TitleId GetProcessTitleId(u64 process_id) { /* Check if we should return our title id. */ @@ -118,24 +87,19 @@ namespace { if (current_process_id == process_id) { return __stratosphere_title_id; } - + /* Get a debug handle. */ - AutoHandle debug_handle; - if (R_FAILED(svcDebugActiveProcess(debug_handle.GetPointer(), process_id))) { - /* If we fail to debug a process other than our own, abort. */ - std::abort(); - } + sts::os::ManagedHandle debug_handle; + R_ASSERT(svcDebugActiveProcess(debug_handle.GetPointer(), process_id)); /* Loop until we get the event that tells us about the process. */ - DebugEventInfo d; - while (R_SUCCEEDED(svcGetDebugEvent(reinterpret_cast(&d), debug_handle.Get()))) { - if (d.type == DebugEventType::AttachProcess) { - return d.info.attach_process.title_id; + sts::svc::DebugEventInfo d; + while (true) { + R_ASSERT(svcGetDebugEvent(reinterpret_cast(&d), debug_handle.Get())); + if (d.type == sts::svc::DebugEventType::AttachProcess) { + return sts::ncm::TitleId{d.info.attach_process.title_id}; } } - - /* If we somehow didn't get the event, abort. */ - std::abort(); } /* This works around a bug fixed by FS in 4.0.0. */ diff --git a/stratosphere/ro/source/impl/ro_service_impl.cpp b/stratosphere/ro/source/impl/ro_service_impl.cpp index b023abd76..048b26c1f 100644 --- a/stratosphere/ro/source/impl/ro_service_impl.cpp +++ b/stratosphere/ro/source/impl/ro_service_impl.cpp @@ -248,11 +248,10 @@ namespace sts::ro::impl { ProcessContext *GetContextById(size_t context_id) { if (context_id == InvalidContextId) { return nullptr; - } else if (context_id < MaxSessions) { - return &g_process_contexts[context_id]; - } else { - std::abort(); } + + STS_ASSERT(context_id < MaxSessions); + return &g_process_contexts[context_id]; } ProcessContext *GetContextByProcessId(u64 process_id) { @@ -268,6 +267,7 @@ namespace sts::ro::impl { /* Find a free process context. */ for (size_t i = 0; i < MaxSessions; i++) { ProcessContext *context = &g_process_contexts[i]; + if (!context->in_use) { std::memset(context, 0, sizeof(*context)); context->process_id = process_id; @@ -276,9 +276,8 @@ namespace sts::ro::impl { return i; } } - /* Failure to find a free context is actually an abort condition. */ - std::abort(); + STS_ASSERT(false); } void FreeContext(size_t context_id) { @@ -370,9 +369,7 @@ namespace sts::ro::impl { Result LoadNrr(size_t context_id, Handle process_h, u64 nrr_address, u64 nrr_size, ModuleType expected_type, bool enforce_type) { /* Get context. */ ProcessContext *context = GetContextById(context_id); - if (context == nullptr) { - std::abort(); - } + STS_ASSERT(context != nullptr); /* Get title id. */ const u64 title_id = context->GetTitleId(process_h); @@ -407,9 +404,7 @@ namespace sts::ro::impl { Result UnloadNrr(size_t context_id, u64 nrr_address) { /* Get context. */ ProcessContext *context = GetContextById(context_id); - if (context == nullptr) { - std::abort(); - } + STS_ASSERT(context != nullptr); /* Validate address. */ if (nrr_address & 0xFFF) { @@ -433,9 +428,7 @@ namespace sts::ro::impl { Result LoadNro(u64 *out_address, size_t context_id, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size) { /* Get context. */ ProcessContext *context = GetContextById(context_id); - if (context == nullptr) { - std::abort(); - } + STS_ASSERT(context != nullptr); /* Validate address/size. */ if (nro_address & 0xFFF) { @@ -488,9 +481,7 @@ namespace sts::ro::impl { Result UnloadNro(size_t context_id, u64 nro_address) { /* Get context. */ ProcessContext *context = GetContextById(context_id); - if (context == nullptr) { - std::abort(); - } + STS_ASSERT(context != nullptr); /* Validate address. */ if (nro_address & 0xFFF) { diff --git a/stratosphere/sm/source/impl/sm_service_manager.cpp b/stratosphere/sm/source/impl/sm_service_manager.cpp index 76fdd234a..26928f51d 100644 --- a/stratosphere/sm/source/impl/sm_service_manager.cpp +++ b/stratosphere/sm/source/impl/sm_service_manager.cpp @@ -57,7 +57,7 @@ namespace sts::sm::impl { struct ServiceInfo { ServiceName name; u64 owner_pid; - AutoHandle port_h; + os::ManagedHandle port_h; /* Debug. */ u64 max_sessions; @@ -65,13 +65,13 @@ namespace sts::sm::impl { /* Mitm Extension. */ u64 mitm_pid; - AutoHandle mitm_port_h; - AutoHandle mitm_query_h; + os::ManagedHandle mitm_port_h; + os::ManagedHandle mitm_query_h; /* Acknowledgement members. */ bool mitm_waiting_ack; u64 mitm_waiting_ack_pid; - AutoHandle mitm_fwd_sess_h; + os::ManagedHandle mitm_fwd_sess_h; ServiceInfo() { this->Free(); @@ -167,15 +167,11 @@ namespace sts::sm::impl { cfg::GetInitialProcessRange(&this->min, &this->max); /* Ensure range is sane. */ - if (this->min > this->max) { - std::abort(); - } + STS_ASSERT(this->min <= this->max); } bool IsInitialProcess(u64 pid) const { - if (pid == InvalidProcessId) { - std::abort(); - } + STS_ASSERT(pid != InvalidProcessId); return this->min <= pid && pid <= this->max; } }; @@ -238,9 +234,7 @@ namespace sts::sm::impl { ncm::TitleId GetTitleIdForMitm(u64 pid) { /* Anything that can request a mitm session must have a process info. */ const auto process_info = GetProcessInfo(pid); - if (process_info == nullptr) { - std::abort(); - } + STS_ASSERT(process_info != nullptr); return process_info->tid; } @@ -398,7 +392,7 @@ namespace sts::sm::impl { /* Create both handles. */ { - AutoHandle fwd_hnd, hnd; + os::ManagedHandle fwd_hnd, hnd; R_TRY(svcConnectToPort(fwd_hnd.GetPointer(), service_info->port_h.Get())); R_TRY(svcConnectToPort(hnd.GetPointer(), service_info->mitm_port_h.Get())); service_info->mitm_fwd_sess_h = std::move(fwd_hnd); @@ -672,7 +666,7 @@ namespace sts::sm::impl { /* Create mitm handles. */ { - AutoHandle hnd, port_hnd, qry_hnd, mitm_qry_hnd; + os::ManagedHandle hnd, port_hnd, qry_hnd, mitm_qry_hnd; u64 x = 0; R_TRY(svcCreatePort(hnd.GetPointer(), port_hnd.GetPointer(), service_info->max_sessions, service_info->is_light, reinterpret_cast(&x))); R_TRY(svcCreateSession(qry_hnd.GetPointer(), mitm_qry_hnd.GetPointer(), 0, 0)); diff --git a/stratosphere/spl/source/spl_api_impl.cpp b/stratosphere/spl/source/spl_api_impl.cpp index 9ecf65f1a..9bd2b5938 100644 --- a/stratosphere/spl/source/spl_api_impl.cpp +++ b/stratosphere/spl/source/spl_api_impl.cpp @@ -103,8 +103,8 @@ namespace sts::spl::impl { /* Global variables. */ CtrDrbg g_drbg; - Event g_se_event; - IEvent *g_se_keyslot_available_event; + os::InterruptEvent g_se_event; + os::SystemEvent g_se_keyslot_available_event; Handle g_se_das_hnd; u32 g_se_mapped_work_buffer_addr; @@ -128,23 +128,18 @@ namespace sts::spl::impl { /* Initialization functionality. */ void InitializeCtrDrbg() { u8 seed[CtrDrbg::SeedSize]; - - if (smc::GenerateRandomBytes(seed, sizeof(seed)) != smc::Result::Success) { - std::abort(); - } + STS_ASSERT(smc::GenerateRandomBytes(seed, sizeof(seed)) == smc::Result::Success); g_drbg.Initialize(seed); } void InitializeSeEvents() { u64 irq_num; - smc::GetConfig(&irq_num, 1, SplConfigItem_SecurityEngineIrqNumber); - Handle hnd; - R_ASSERT(svcCreateInterruptEvent(&hnd, irq_num, 1)); - eventLoadRemote(&g_se_event, hnd, true); + STS_ASSERT(smc::GetConfig(&irq_num, 1, SplConfigItem_SecurityEngineIrqNumber) == smc::Result::Success); + R_ASSERT(g_se_event.Initialize(irq_num)); - g_se_keyslot_available_event = CreateWriteOnlySystemEvent(); - g_se_keyslot_available_event->Signal(); + R_ASSERT(g_se_keyslot_available_event.InitializeAsInterProcessEvent()); + g_se_keyslot_available_event.Signal(); } void InitializeDeviceAddressSpace() { @@ -262,7 +257,7 @@ namespace sts::spl::impl { /* Internal async implementation functionality. */ void WaitSeOperationComplete() { - eventWait(&g_se_event, U64_MAX); + g_se_event.Wait(); } smc::Result WaitCheckStatus(smc::AsyncOperationKey op_key) { @@ -722,7 +717,7 @@ namespace sts::spl::impl { } } - g_se_keyslot_available_event->Clear(); + g_se_keyslot_available_event.Reset(); return ResultSplOutOfKeyslots; } @@ -742,7 +737,7 @@ namespace sts::spl::impl { smc::LoadAesKey(keyslot, access_key, key_source); } g_keyslot_owners[keyslot] = nullptr; - g_se_keyslot_available_event->Signal(); + g_se_keyslot_available_event.Signal(); return ResultSuccess; } @@ -931,7 +926,7 @@ namespace sts::spl::impl { } Handle GetAesKeyslotAvailableEventHandle() { - return g_se_keyslot_available_event->GetHandle(); + return g_se_keyslot_available_event.GetReadableHandle(); } }