From 6da28f4a2765213894a203b892a7f49815d3d987 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 3 Dec 2020 11:13:35 -0800 Subject: [PATCH] erpt: update for 11.0.0 (closes #1218) --- .../erpt/sf/erpt_sf_i_context.hpp | 22 +- .../stratosphere/err/err_error_context.hpp | 48 ++++ .../svc/svc_stratosphere_shims.hpp | 4 + .../source/erpt/srv/erpt_srv_attachment.cpp | 6 +- .../source/erpt/srv/erpt_srv_attachment.hpp | 6 +- .../source/erpt/srv/erpt_srv_context.cpp | 38 ++- .../source/erpt/srv/erpt_srv_context.hpp | 4 +- .../source/erpt/srv/erpt_srv_context_impl.cpp | 16 +- .../source/erpt/srv/erpt_srv_context_impl.hpp | 4 +- .../erpt/srv/erpt_srv_context_record.cpp | 28 ++- .../erpt/srv/erpt_srv_context_record.hpp | 5 +- .../source/erpt/srv/erpt_srv_formatter.hpp | 50 ++-- .../source/erpt/srv/erpt_srv_main.cpp | 8 +- .../source/erpt/srv/erpt_srv_report.cpp | 6 +- .../source/erpt/srv/erpt_srv_report.hpp | 6 +- .../source/erpt/srv/erpt_srv_reporter.cpp | 222 +++++++++++++++--- .../source/erpt/srv/erpt_srv_reporter.hpp | 3 +- .../source/erpt/srv/erpt_srv_stream.cpp | 2 +- .../source/erpt/srv/erpt_srv_stream.hpp | 2 +- .../vapours/results/results_common.hpp | 38 ++- libraries/libvapours/include/vapours/span.hpp | 15 ++ libraries/libvapours/include/vapours/util.hpp | 1 + .../include/vapours/util/util_range.hpp | 47 ++++ stratosphere/erpt/source/erpt_main.cpp | 3 + 24 files changed, 438 insertions(+), 146 deletions(-) create mode 100644 libraries/libvapours/include/vapours/util/util_range.hpp diff --git a/libraries/libstratosphere/include/stratosphere/erpt/sf/erpt_sf_i_context.hpp b/libraries/libstratosphere/include/stratosphere/erpt/sf/erpt_sf_i_context.hpp index 2c39208dd..8c71b06ef 100644 --- a/libraries/libstratosphere/include/stratosphere/erpt/sf/erpt_sf_i_context.hpp +++ b/libraries/libstratosphere/include/stratosphere/erpt/sf/erpt_sf_i_context.hpp @@ -25,17 +25,17 @@ namespace ams::erpt::sf { #define AMS_ERPT_I_CONTEXT_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, SubmitContext, (const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, CreateReportV0, (ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer, const ams::sf::InBuffer &meta_buffer)) \ - AMS_SF_METHOD_INFO(C, H, 2, Result, SetInitialLaunchSettingsCompletionTime, (const time::SteadyClockTimePoint &time_point), hos::Version_3_0_0) \ - AMS_SF_METHOD_INFO(C, H, 3, Result, ClearInitialLaunchSettingsCompletionTime, (), hos::Version_3_0_0) \ - AMS_SF_METHOD_INFO(C, H, 4, Result, UpdatePowerOnTime, (), hos::Version_3_0_0) \ - AMS_SF_METHOD_INFO(C, H, 5, Result, UpdateAwakeTime, (), hos::Version_3_0_0) \ - AMS_SF_METHOD_INFO(C, H, 6, Result, SubmitMultipleCategoryContext, (const MultipleCategoryContextEntry &ctx_entry, const ams::sf::InBuffer &str_buffer), hos::Version_5_0_0) \ - AMS_SF_METHOD_INFO(C, H, 7, Result, UpdateApplicationLaunchTime, (), hos::Version_6_0_0) \ - AMS_SF_METHOD_INFO(C, H, 8, Result, ClearApplicationLaunchTime, (), hos::Version_6_0_0) \ - AMS_SF_METHOD_INFO(C, H, 9, Result, SubmitAttachment, (ams::sf::Out out, const ams::sf::InBuffer &attachment_name, const ams::sf::InBuffer &attachment_data), hos::Version_8_0_0) \ - AMS_SF_METHOD_INFO(C, H, 10, Result, CreateReportWithAttachmentsDeprecated, (ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer, const ams::sf::InBuffer &attachment_ids_buffer), hos::Version_8_0_0, hos::Version_10_2_0) \ - AMS_SF_METHOD_INFO(C, H, 10, Result, CreateReportWithAttachments, (ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer, const ams::sf::InBuffer &attachment_ids_buffer, u32 context), hos::Version_11_0_0) \ - AMS_SF_METHOD_INFO(C, H, 11, Result, CreateReport, (ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer, const ams::sf::InBuffer &meta_buffer, u32 context), hos::Version_11_0_0) + AMS_SF_METHOD_INFO(C, H, 2, Result, SetInitialLaunchSettingsCompletionTime, (const time::SteadyClockTimePoint &time_point), hos::Version_3_0_0) \ + AMS_SF_METHOD_INFO(C, H, 3, Result, ClearInitialLaunchSettingsCompletionTime, (), hos::Version_3_0_0) \ + AMS_SF_METHOD_INFO(C, H, 4, Result, UpdatePowerOnTime, (), hos::Version_3_0_0) \ + AMS_SF_METHOD_INFO(C, H, 5, Result, UpdateAwakeTime, (), hos::Version_3_0_0) \ + AMS_SF_METHOD_INFO(C, H, 6, Result, SubmitMultipleCategoryContext, (const MultipleCategoryContextEntry &ctx_entry, const ams::sf::InBuffer &str_buffer), hos::Version_5_0_0) \ + AMS_SF_METHOD_INFO(C, H, 7, Result, UpdateApplicationLaunchTime, (), hos::Version_6_0_0) \ + AMS_SF_METHOD_INFO(C, H, 8, Result, ClearApplicationLaunchTime, (), hos::Version_6_0_0) \ + AMS_SF_METHOD_INFO(C, H, 9, Result, SubmitAttachment, (ams::sf::Out out, const ams::sf::InBuffer &attachment_name, const ams::sf::InBuffer &attachment_data), hos::Version_8_0_0) \ + AMS_SF_METHOD_INFO(C, H, 10, Result, CreateReportWithAttachmentsDeprecated, (ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer, const ams::sf::InBuffer &attachment_ids_buffer), hos::Version_8_0_0, hos::Version_10_2_0) \ + AMS_SF_METHOD_INFO(C, H, 10, Result, CreateReportWithAttachments, (ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer, const ams::sf::InBuffer &attachment_ids_buffer, Result result), hos::Version_11_0_0) \ + AMS_SF_METHOD_INFO(C, H, 11, Result, CreateReport, (ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer, const ams::sf::InBuffer &meta_buffer, Result result), hos::Version_11_0_0) AMS_SF_DEFINE_INTERFACE(IContext, AMS_ERPT_I_CONTEXT_INTERFACE_INFO) diff --git a/libraries/libstratosphere/include/stratosphere/err/err_error_context.hpp b/libraries/libstratosphere/include/stratosphere/err/err_error_context.hpp index df40e82b6..2ad719c27 100644 --- a/libraries/libstratosphere/include/stratosphere/err/err_error_context.hpp +++ b/libraries/libstratosphere/include/stratosphere/err/err_error_context.hpp @@ -42,4 +42,52 @@ namespace ams::err { static_assert(sizeof(ErrorContext) == 0x200); static_assert(util::is_pod::value); + struct ContextDescriptor { + int value; + + constexpr ALWAYS_INLINE bool operator==(const ContextDescriptor &rhs) const { return this->value == rhs.value; } + constexpr ALWAYS_INLINE bool operator!=(const ContextDescriptor &rhs) const { return this->value != rhs.value; } + constexpr ALWAYS_INLINE bool operator< (const ContextDescriptor &rhs) const { return this->value < rhs.value; } + constexpr ALWAYS_INLINE bool operator<=(const ContextDescriptor &rhs) const { return this->value <= rhs.value; } + constexpr ALWAYS_INLINE bool operator> (const ContextDescriptor &rhs) const { return this->value > rhs.value; } + constexpr ALWAYS_INLINE bool operator>=(const ContextDescriptor &rhs) const { return this->value >= rhs.value; } + }; + + constexpr inline const ContextDescriptor InvalidContextDescriptor{ -1 }; + + namespace impl { + + constexpr inline const ContextDescriptor ContextDescriptorMin{ 0x001 }; + constexpr inline const ContextDescriptor ContextDescriptorMax{ 0x1FF }; + + } + + constexpr Result MakeResultWithContextDescriptor(Result result, ContextDescriptor descriptor) { + /* Check pre-conditions. */ + AMS_ASSERT(R_FAILED(result)); + AMS_ASSERT(descriptor != InvalidContextDescriptor); + AMS_ASSERT(impl::ContextDescriptorMin <= descriptor && descriptor <= impl::ContextDescriptorMax); + + return result::impl::ResultInternalAccessor::MergeReserved(result, descriptor.value | 0x200); + } + + constexpr ContextDescriptor GetContextDescriptorFromResult(Result result) { + /* Check pre-conditions. */ + AMS_ASSERT(R_FAILED(result)); + + /* Get reserved bits. */ + const auto reserved = result::impl::ResultInternalAccessor::GetReserved(result); + if ((reserved & 0x200) != 0x200) { + return InvalidContextDescriptor; + } + + /* Check the descriptor value. */ + const ContextDescriptor descriptor{reserved & ~0x200}; + if (!(impl::ContextDescriptorMin <= descriptor && descriptor <= impl::ContextDescriptorMax)) { + return InvalidContextDescriptor; + } + + return descriptor; + } + } diff --git a/libraries/libstratosphere/include/stratosphere/svc/svc_stratosphere_shims.hpp b/libraries/libstratosphere/include/stratosphere/svc/svc_stratosphere_shims.hpp index 58be481ee..49d894692 100644 --- a/libraries/libstratosphere/include/stratosphere/svc/svc_stratosphere_shims.hpp +++ b/libraries/libstratosphere/include/stratosphere/svc/svc_stratosphere_shims.hpp @@ -238,6 +238,10 @@ return ::svcSynchronizePreemptionState(); } + ALWAYS_INLINE Result GetResourceLimitPeakValue(int64_t *out_peak_value, ::ams::svc::Handle resource_limit_handle, ::ams::svc::LimitableResource which) { + return ::svcGetResourceLimitPeakValue(out_peak_value, resource_limit_handle, static_cast<::LimitableResource>(which)); + } + ALWAYS_INLINE void KernelDebug(::ams::svc::KernelDebugType kern_debug_type, uint64_t arg0, uint64_t arg1, uint64_t arg2) { return ::svcKernelDebug(kern_debug_type, arg0, arg1, arg2); } diff --git a/libraries/libstratosphere/source/erpt/srv/erpt_srv_attachment.cpp b/libraries/libstratosphere/source/erpt/srv/erpt_srv_attachment.cpp index 67d585ecd..37f44d482 100644 --- a/libraries/libstratosphere/source/erpt/srv/erpt_srv_attachment.cpp +++ b/libraries/libstratosphere/source/erpt/srv/erpt_srv_attachment.cpp @@ -40,7 +40,7 @@ namespace ams::erpt::srv { } } - AttachmentFileName Attachment::FileName() { + AttachmentFileName Attachment::FileName() const { return FileName(this->record->info.attachment_id); } @@ -64,7 +64,7 @@ namespace ams::erpt::srv { return this->CloseStream(); } - Result Attachment::GetFlags(AttachmentFlagSet *out) { + Result Attachment::GetFlags(AttachmentFlagSet *out) const { *out = this->record->info.flags; return ResultSuccess(); } @@ -77,7 +77,7 @@ namespace ams::erpt::srv { return ResultSuccess(); } - Result Attachment::GetSize(s64 *out) { + Result Attachment::GetSize(s64 *out) const { return this->GetStreamSize(out); } diff --git a/libraries/libstratosphere/source/erpt/srv/erpt_srv_attachment.hpp b/libraries/libstratosphere/source/erpt/srv/erpt_srv_attachment.hpp index 7692cdbe4..415d4c289 100644 --- a/libraries/libstratosphere/source/erpt/srv/erpt_srv_attachment.hpp +++ b/libraries/libstratosphere/source/erpt/srv/erpt_srv_attachment.hpp @@ -32,7 +32,7 @@ namespace ams::erpt::srv { private: JournalRecord *record; private: - AttachmentFileName FileName(); + AttachmentFileName FileName() const; public: static AttachmentFileName FileName(AttachmentId attachment_id); public: @@ -44,9 +44,9 @@ namespace ams::erpt::srv { Result Delete(); void Close(); - Result GetFlags(AttachmentFlagSet *out); + Result GetFlags(AttachmentFlagSet *out) const; Result SetFlags(AttachmentFlagSet flags); - Result GetSize(s64 *out); + Result GetSize(s64 *out) const; template Result Write(T val) { diff --git a/libraries/libstratosphere/source/erpt/srv/erpt_srv_context.cpp b/libraries/libstratosphere/source/erpt/srv/erpt_srv_context.cpp index 1057b25cb..99372c2f8 100644 --- a/libraries/libstratosphere/source/erpt/srv/erpt_srv_context.cpp +++ b/libraries/libstratosphere/source/erpt/srv/erpt_srv_context.cpp @@ -71,25 +71,23 @@ namespace ams::erpt::srv { } Result Context::AddContextToCategory(const ContextEntry *entry, const u8 *data, u32 data_size) { - ContextRecord *record = new ContextRecord(); + auto record = std::make_unique(); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); - auto guard = SCOPE_GUARD { delete record; }; R_TRY(record->Initialize(entry, data, data_size)); - guard.Cancel(); - this->AddContextRecordToCategory(record); + this->AddContextRecordToCategory(std::move(record)); return ResultSuccess(); } - Result Context::AddContextRecordToCategory(ContextRecord *record) { + Result Context::AddContextRecordToCategory(std::unique_ptr record) { if (this->record_count < this->max_record_count) { - this->record_list.push_front(*record); + this->record_list.push_front(*record.release()); this->record_count++; } else { ContextRecord *back = std::addressof(this->record_list.back()); this->record_list.pop_back(); - this->record_list.push_front(*record); + this->record_list.push_front(*record.release()); delete back; } @@ -97,21 +95,21 @@ namespace ams::erpt::srv { } Result Context::SubmitContext(const ContextEntry *entry, const u8 *data, u32 data_size) { - for (auto it = g_category_list.begin(); it != g_category_list.end(); it++) { - if (it->category == entry->category) { - return it->AddContextToCategory(entry, data, data_size); - } - } - return erpt::ResultCategoryNotFound(); + auto it = util::range::find_if(g_category_list, [&](const Context &cur) { + return cur.category == entry->category; + }); + R_UNLESS(it != g_category_list.end(), erpt::ResultCategoryNotFound()); + + return it->AddContextToCategory(entry, data, data_size); } - Result Context::SubmitContextRecord(ContextRecord *record) { - for (auto it = g_category_list.begin(); it != g_category_list.end(); it++) { - if (it->category == record->ctx.category) { - return it->AddContextRecordToCategory(record); - } - } - return erpt::ResultCategoryNotFound(); + Result Context::SubmitContextRecord(std::unique_ptr record) { + auto it = util::range::find_if(g_category_list, [&](const Context &cur) { + return cur.category == record->ctx.category; + }); + R_UNLESS(it != g_category_list.end(), erpt::ResultCategoryNotFound()); + + return it->AddContextRecordToCategory(std::move(record)); } Result Context::WriteContextsToReport(Report *report) { diff --git a/libraries/libstratosphere/source/erpt/srv/erpt_srv_context.hpp b/libraries/libstratosphere/source/erpt/srv/erpt_srv_context.hpp index f6430ab63..dba7128b7 100644 --- a/libraries/libstratosphere/source/erpt/srv/erpt_srv_context.hpp +++ b/libraries/libstratosphere/source/erpt/srv/erpt_srv_context.hpp @@ -35,10 +35,10 @@ namespace ams::erpt::srv { Result AddCategoryToReport(Report *report); Result AddContextToCategory(const ContextEntry *entry, const u8 *data, u32 data_size); - Result AddContextRecordToCategory(ContextRecord *record); + Result AddContextRecordToCategory(std::unique_ptr record); public: static Result SubmitContext(const ContextEntry *entry, const u8 *data, u32 data_size); - static Result SubmitContextRecord(ContextRecord *record); + static Result SubmitContextRecord(std::unique_ptr record); static Result WriteContextsToReport(Report *report); }; diff --git a/libraries/libstratosphere/source/erpt/srv/erpt_srv_context_impl.cpp b/libraries/libstratosphere/source/erpt/srv/erpt_srv_context_impl.cpp index 0fbb0cce1..03fc8f85b 100644 --- a/libraries/libstratosphere/source/erpt/srv/erpt_srv_context_impl.cpp +++ b/libraries/libstratosphere/source/erpt/srv/erpt_srv_context_impl.cpp @@ -35,7 +35,7 @@ namespace ams::erpt::srv { return Context::SubmitContext(ctx, data, data_size); } - Result ContextImpl::CreateReport(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &meta_buffer, u32 context) { + Result ContextImpl::CreateReport(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &meta_buffer, Result result) { const ContextEntry *ctx = reinterpret_cast( ctx_buffer.GetPointer()); const u8 *data = reinterpret_cast(data_buffer.GetPointer()); const ReportMetaData *meta = reinterpret_cast(meta_buffer.GetPointer()); @@ -47,9 +47,7 @@ namespace ams::erpt::srv { R_UNLESS(ctx_size == sizeof(ContextEntry), erpt::ResultInvalidArgument()); R_UNLESS(meta_size == 0 || meta_size == sizeof(ReportMetaData), erpt::ResultInvalidArgument()); - /* TODO: use context */ - - Reporter reporter(report_type, ctx, data, data_size, meta_size != 0 ? meta : nullptr, nullptr, 0); + Reporter reporter(report_type, ctx, data, data_size, meta_size != 0 ? meta : nullptr, nullptr, 0, result); R_TRY(reporter.CreateReport()); ManagerImpl::NotifyAll(); @@ -58,7 +56,7 @@ namespace ams::erpt::srv { } Result ContextImpl::CreateReportV0(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &meta_buffer) { - return this->CreateReport(report_type, ctx_buffer, data_buffer, meta_buffer, {}); + return this->CreateReport(report_type, ctx_buffer, data_buffer, meta_buffer, ResultSuccess()); } Result ContextImpl::SetInitialLaunchSettingsCompletionTime(const time::SteadyClockTimePoint &time_point) { @@ -138,7 +136,7 @@ namespace ams::erpt::srv { return JournalForAttachments::SubmitAttachment(out.GetPointer(), name_safe, data, data_size); } - Result ContextImpl::CreateReportWithAttachments(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &attachment_ids_buffer, u32 context) { + Result ContextImpl::CreateReportWithAttachments(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &attachment_ids_buffer, Result result) { const ContextEntry *ctx = reinterpret_cast( ctx_buffer.GetPointer()); const u8 *data = reinterpret_cast(data_buffer.GetPointer()); const u32 ctx_size = static_cast(ctx_buffer.GetSize()); @@ -150,9 +148,7 @@ namespace ams::erpt::srv { R_UNLESS(ctx_size == sizeof(ContextEntry), erpt::ResultInvalidArgument()); R_UNLESS(num_attachments <= AttachmentsPerReportMax, erpt::ResultInvalidArgument()); - /* TODO: use context */ - - Reporter reporter(report_type, ctx, data, data_size, nullptr, attachments, num_attachments); + Reporter reporter(report_type, ctx, data, data_size, nullptr, attachments, num_attachments, result); R_TRY(reporter.CreateReport()); ManagerImpl::NotifyAll(); @@ -161,7 +157,7 @@ namespace ams::erpt::srv { } Result ContextImpl::CreateReportWithAttachmentsDeprecated(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &attachment_ids_buffer) { - return this->CreateReportWithAttachments(report_type, ctx_buffer, data_buffer, attachment_ids_buffer, {}); + return this->CreateReportWithAttachments(report_type, ctx_buffer, data_buffer, attachment_ids_buffer, ResultSuccess()); } } diff --git a/libraries/libstratosphere/source/erpt/srv/erpt_srv_context_impl.hpp b/libraries/libstratosphere/source/erpt/srv/erpt_srv_context_impl.hpp index 28f5e801c..205d5d71b 100644 --- a/libraries/libstratosphere/source/erpt/srv/erpt_srv_context_impl.hpp +++ b/libraries/libstratosphere/source/erpt/srv/erpt_srv_context_impl.hpp @@ -31,8 +31,8 @@ namespace ams::erpt::srv { Result ClearApplicationLaunchTime(); Result SubmitAttachment(ams::sf::Out out, const ams::sf::InBuffer &attachment_name, const ams::sf::InBuffer &attachment_data); Result CreateReportWithAttachmentsDeprecated(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &attachment_ids_buffer); - Result CreateReportWithAttachments(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &attachment_ids_buffer, u32 context); - Result CreateReport(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &meta_buffer, u32 context); + Result CreateReportWithAttachments(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &attachment_ids_buffer, Result result); + Result CreateReport(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &meta_buffer, Result result); }; static_assert(erpt::sf::IsIContext); diff --git a/libraries/libstratosphere/source/erpt/srv/erpt_srv_context_record.cpp b/libraries/libstratosphere/source/erpt/srv/erpt_srv_context_record.cpp index ace1c0fc0..7019b7e63 100644 --- a/libraries/libstratosphere/source/erpt/srv/erpt_srv_context_record.cpp +++ b/libraries/libstratosphere/source/erpt/srv/erpt_srv_context_record.cpp @@ -37,14 +37,14 @@ namespace ams::erpt::srv { this->ctx = {}; } - ContextRecord::ContextRecord(CategoryId category) { + ContextRecord::ContextRecord(CategoryId category, u32 array_buf_size) { this->ctx = { .category = category, - .array_buffer = static_cast(Allocate(ArrayBufferSizeDefault)), + .array_buffer = static_cast(Allocate(array_buf_size)), }; if (this->ctx.array_buffer != nullptr) { - this->ctx.array_buffer_size = ArrayBufferSizeDefault; - this->ctx.array_free_count = ArrayBufferSizeDefault; + this->ctx.array_buffer_size = array_buf_size; + this->ctx.array_free_count = array_buf_size; } } @@ -176,26 +176,34 @@ namespace ams::erpt::srv { return ResultSuccess(); } - Result ContextRecord::Add(FieldId field_id, const char *str, u32 str_size) { + Result ContextRecord::Add(FieldId field_id, const void *arr, u32 size, FieldType type) { R_UNLESS(this->ctx.field_count < FieldsPerContext, erpt::ResultOutOfFieldSpace()); - R_UNLESS(str_size <= this->ctx.array_free_count, erpt::ResultOutOfArraySpace()); + R_UNLESS(size <= this->ctx.array_free_count, erpt::ResultOutOfArraySpace()); const u32 start_idx = this->ctx.array_buffer_size - this->ctx.array_free_count; - this->ctx.array_free_count -= str_size; + this->ctx.array_free_count -= size; s_record_count++; auto &field = this->ctx.fields[this->ctx.field_count++]; field.id = field_id; - field.type = FieldType_String; + field.type = type; field.value_array = { .start_idx = start_idx, - .size = str_size, + .size = size, }; - std::memcpy(this->ctx.array_buffer + start_idx, str, str_size); + std::memcpy(this->ctx.array_buffer + start_idx, arr, size); return ResultSuccess(); } + Result ContextRecord::Add(FieldId field_id, const char *str, u32 str_size) { + return this->Add(field_id, str, str_size, FieldType_String); + } + + Result ContextRecord::Add(FieldId field_id, const u8 *data, u32 size) { + return this->Add(field_id, data, size, FieldType_U8Array); + } + } diff --git a/libraries/libstratosphere/source/erpt/srv/erpt_srv_context_record.hpp b/libraries/libstratosphere/source/erpt/srv/erpt_srv_context_record.hpp index f199acca1..6996c2b12 100644 --- a/libraries/libstratosphere/source/erpt/srv/erpt_srv_context_record.hpp +++ b/libraries/libstratosphere/source/erpt/srv/erpt_srv_context_record.hpp @@ -31,9 +31,11 @@ namespace ams::erpt::srv { } private: ContextEntry ctx; + private: + Result Add(FieldId field_id, const void *arr, u32 size, FieldType type); public: ContextRecord(); - explicit ContextRecord(CategoryId category); + explicit ContextRecord(CategoryId category, u32 array_buf_size = ArrayBufferSizeDefault); ~ContextRecord(); Result Initialize(const ContextEntry *ctx_ptr, const u8 *data, u32 data_size); @@ -44,6 +46,7 @@ namespace ams::erpt::srv { Result Add(FieldId field_id, s32 value_i32); Result Add(FieldId field_id, s64 value_i64); Result Add(FieldId field_id, const char *str, u32 str_size); + Result Add(FieldId field_id, const u8 *data, u32 size); }; } diff --git a/libraries/libstratosphere/source/erpt/srv/erpt_srv_formatter.hpp b/libraries/libstratosphere/source/erpt/srv/erpt_srv_formatter.hpp index c6a369243..052661460 100644 --- a/libraries/libstratosphere/source/erpt/srv/erpt_srv_formatter.hpp +++ b/libraries/libstratosphere/source/erpt/srv/erpt_srv_formatter.hpp @@ -37,18 +37,32 @@ namespace ams::erpt::srv { static ValueTypeTag GetTag(u32) { return ValueTypeTag::U32; } static ValueTypeTag GetTag(u64) { return ValueTypeTag::U64; } + static Result AddStringValue(Report *report, const char *str, u32 len) { + const u32 str_len = str != nullptr ? static_cast(strnlen(str, len)) : 0; + + if (str_len < ElementSize_32) { + R_TRY(report->Write(static_cast(static_cast(ValueTypeTag::FixStr) | str_len))); + } else if (str_len < ElementSize_256) { + R_TRY(report->Write(static_cast(ValueTypeTag::Str8))); + R_TRY(report->Write(static_cast(str_len))); + } else { + R_UNLESS(str_len < ElementSize_16384, erpt::ResultFormatterError()); + R_TRY(report->Write(static_cast(ValueTypeTag::Str16))); + + u16 be_str_len; + util::StoreBigEndian(std::addressof(be_str_len), static_cast(str_len)); + R_TRY(report->Write(be_str_len)); + } + + R_TRY(report->Write(str, str_len)); + + return ResultSuccess(); + } + static Result AddId(Report *report, FieldId field_id) { static_assert(MaxFieldStringSize < ElementSize_256); - const u32 field_len = static_cast(strnlen(FieldString[field_id], MaxFieldStringSize)); - if (field_len < ElementSize_32) { - R_TRY(report->Write(static_cast(static_cast(ValueTypeTag::FixStr) | field_len))); - } else { - R_TRY(report->Write(static_cast(ValueTypeTag::Str8))); - R_TRY(report->Write(static_cast(field_len))); - } - - R_TRY(report->Write(FieldString[field_id], field_len)); + R_TRY(AddStringValue(report, FieldString[field_id], strnlen(FieldString[field_id], MaxFieldStringSize))); return ResultSuccess(); } @@ -140,23 +154,7 @@ namespace ams::erpt::srv { static Result AddField(Report *report, FieldId field_id, char *str, u32 len) { R_TRY(AddId(report, field_id)); - const u32 str_len = str != nullptr ? static_cast(strnlen(str, len)) : 0; - - if (str_len < ElementSize_32) { - R_TRY(report->Write(static_cast(static_cast(ValueTypeTag::FixStr) | str_len))); - } else if (str_len < ElementSize_256) { - R_TRY(report->Write(static_cast(ValueTypeTag::Str8))); - R_TRY(report->Write(static_cast(str_len))); - } else { - R_UNLESS(str_len < ElementSize_16384, erpt::ResultFormatterError()); - R_TRY(report->Write(static_cast(ValueTypeTag::Str16))); - - u16 be_str_len; - util::StoreBigEndian(std::addressof(be_str_len), static_cast(str_len)); - R_TRY(report->Write(be_str_len)); - } - - R_TRY(report->Write(str, str_len)); + R_TRY(AddStringValue(report, str, len)); return ResultSuccess(); } diff --git a/libraries/libstratosphere/source/erpt/srv/erpt_srv_main.cpp b/libraries/libstratosphere/source/erpt/srv/erpt_srv_main.cpp index 87bf4f780..b79ce2fa4 100644 --- a/libraries/libstratosphere/source/erpt/srv/erpt_srv_main.cpp +++ b/libraries/libstratosphere/source/erpt/srv/erpt_srv_main.cpp @@ -99,22 +99,22 @@ namespace ams::erpt::srv { Result SetProductModel(const char *model, u32 model_len) { /* NOTE: Nintendo does not check that this allocation succeeds. */ - auto *record = new ContextRecord(CategoryId_ProductModelInfo); + auto record = std::make_unique(CategoryId_ProductModelInfo); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); R_TRY(record->Add(FieldId_ProductModel, model, model_len)); - R_TRY(Context::SubmitContextRecord(record)); + R_TRY(Context::SubmitContextRecord(std::move(record))); return ResultSuccess(); } Result SetRegionSetting(const char *region, u32 region_len) { /* NOTE: Nintendo does not check that this allocation succeeds. */ - auto *record = new ContextRecord(CategoryId_RegionSettingInfo); + auto record = std::make_unique(CategoryId_RegionSettingInfo); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); R_TRY(record->Add(FieldId_RegionSetting, region, region_len)); - R_TRY(Context::SubmitContextRecord(record)); + R_TRY(Context::SubmitContextRecord(std::move(record))); return ResultSuccess(); } diff --git a/libraries/libstratosphere/source/erpt/srv/erpt_srv_report.cpp b/libraries/libstratosphere/source/erpt/srv/erpt_srv_report.cpp index 8ec7b7b1e..290621fd8 100644 --- a/libraries/libstratosphere/source/erpt/srv/erpt_srv_report.cpp +++ b/libraries/libstratosphere/source/erpt/srv/erpt_srv_report.cpp @@ -46,7 +46,7 @@ namespace ams::erpt::srv { } } - ReportFileName Report::FileName() { + ReportFileName Report::FileName() const { return FileName(this->record->info.id, this->redirect_to_sd_card); } @@ -70,7 +70,7 @@ namespace ams::erpt::srv { return this->CloseStream(); } - Result Report::GetFlags(ReportFlagSet *out) { + Result Report::GetFlags(ReportFlagSet *out) const { *out = this->record->info.flags; return ResultSuccess(); } @@ -83,7 +83,7 @@ namespace ams::erpt::srv { return ResultSuccess(); } - Result Report::GetSize(s64 *out) { + Result Report::GetSize(s64 *out) const { return this->GetStreamSize(out); } diff --git a/libraries/libstratosphere/source/erpt/srv/erpt_srv_report.hpp b/libraries/libstratosphere/source/erpt/srv/erpt_srv_report.hpp index 115983560..dbd34a65d 100644 --- a/libraries/libstratosphere/source/erpt/srv/erpt_srv_report.hpp +++ b/libraries/libstratosphere/source/erpt/srv/erpt_srv_report.hpp @@ -33,7 +33,7 @@ namespace ams::erpt::srv { JournalRecord *record; bool redirect_to_sd_card; private: - ReportFileName FileName(); + ReportFileName FileName() const; public: static ReportFileName FileName(ReportId report_id, bool redirect_to_sd); public: @@ -45,9 +45,9 @@ namespace ams::erpt::srv { Result Delete(); void Close(); - Result GetFlags(ReportFlagSet *out); + Result GetFlags(ReportFlagSet *out) const; Result SetFlags(ReportFlagSet flags); - Result GetSize(s64 *out); + Result GetSize(s64 *out) const; template Result Write(T val) { diff --git a/libraries/libstratosphere/source/erpt/srv/erpt_srv_reporter.cpp b/libraries/libstratosphere/source/erpt/srv/erpt_srv_reporter.cpp index 3bee29d18..0ff873e47 100644 --- a/libraries/libstratosphere/source/erpt/srv/erpt_srv_reporter.cpp +++ b/libraries/libstratosphere/source/erpt/srv/erpt_srv_reporter.cpp @@ -22,17 +22,158 @@ namespace ams::erpt::srv { - bool Reporter::s_redirect_new_reports = true; - char Reporter::s_serial_number[24] = "Unknown"; - char Reporter::s_os_version[24] = "Unknown"; - char Reporter::s_private_os_version[96] = "Unknown"; - std::optional Reporter::s_application_launch_time; - std::optional Reporter::s_awake_time; - std::optional Reporter::s_power_on_time; - std::optional Reporter::s_initial_launch_settings_completion_time; + constinit bool Reporter::s_redirect_new_reports = true; + constinit char Reporter::s_serial_number[24] = "Unknown"; + constinit char Reporter::s_os_version[24] = "Unknown"; + constinit char Reporter::s_private_os_version[96] = "Unknown"; + constinit std::optional Reporter::s_application_launch_time; + constinit std::optional Reporter::s_awake_time; + constinit std::optional Reporter::s_power_on_time; + constinit std::optional Reporter::s_initial_launch_settings_completion_time; - Reporter::Reporter(ReportType type, const ContextEntry *ctx, const u8 *data, u32 data_size, const ReportMetaData *meta, const AttachmentId *attachments, u32 num_attachments) - : type(type), ctx(ctx), data(data), data_size(data_size), meta(meta), attachments(attachments), num_attachments(num_attachments), occurrence_tick() + namespace { + + constinit os::SdkMutex g_limit_mutex; + constinit bool g_submitted_limit = false; + + Result PullErrorContext(size_t *out_total_size, size_t *out_size, void *dst, size_t dst_size, const err::ContextDescriptor &descriptor, Result result) { + s32 unk0; + u32 total_size, size; + R_TRY(::ectxrPullContext(std::addressof(unk0), std::addressof(total_size), std::addressof(size), dst, dst_size, descriptor.value, result.GetValue())); + + *out_total_size = total_size; + *out_size = size; + return ResultSuccess(); + } + + void SubmitErrorContext(ContextRecord *record, Result result) { + /* Only support submitting context on 11.x. */ + if (hos::GetVersion() < hos::Version_11_0_0) { + return; + } + + /* Get the context descriptor. */ + const auto descriptor = err::GetContextDescriptorFromResult(result); + if (descriptor == err::InvalidContextDescriptor) { + return; + } + + /* Pull the error context. */ + u8 error_context[0x200]; + size_t error_context_total_size; + size_t error_context_size; + if (R_FAILED(PullErrorContext(std::addressof(error_context_total_size), std::addressof(error_context_size), error_context, util::size(error_context), descriptor, result))) { + return; + } + + /* Set the total size. */ + if (error_context_total_size == 0) { + return; + } + record->Add(FieldId_ErrorContextTotalSize, error_context_total_size); + + /* Set the context. */ + if (error_context_size == 0) { + return; + } + record->Add(FieldId_ErrorContextSize, error_context_size); + record->Add(FieldId_ErrorContext, error_context, error_context_size); + } + + void SubmitResourceLimitLimitContext() { + std::scoped_lock lk(g_limit_mutex); + if (g_submitted_limit) { + return; + } + + ON_SCOPE_EXIT { g_submitted_limit = true; }; + + /* Create and populate the record. */ + auto record = std::make_unique(CategoryId_ResourceLimitLimitInfo); + if (record == nullptr) { + return; + } + + u64 reslimit_handle_value; + if (R_FAILED(svc::GetInfo(std::addressof(reslimit_handle_value), svc::InfoType_ResourceLimit, svc::InvalidHandle, 0))) { + return; + } + + const auto handle = static_cast(reslimit_handle_value); + ON_SCOPE_EXIT { R_ABORT_UNLESS(svc::CloseHandle(handle)); }; + + #define ADD_RESOURCE(__RESOURCE__) \ + do { \ + s64 limit_value; \ + if (R_FAILED(svc::GetResourceLimitLimitValue(std::addressof(limit_value), handle, svc::LimitableResource_##__RESOURCE__##Max))) { \ + return; \ + } \ + if (R_FAILED(record->Add(FieldId_System##__RESOURCE__##Limit, limit_value))) { \ + return; \ + } \ + } while (0) + + ADD_RESOURCE(PhysicalMemory); + ADD_RESOURCE(ThreadCount); + ADD_RESOURCE(EventCount); + ADD_RESOURCE(TransferMemoryCount); + ADD_RESOURCE(SessionCount); + + #undef ADD_RESOURCE + + Context::SubmitContextRecord(std::move(record)); + + g_submitted_limit = true; + } + + void SubmitResourceLimitPeakContext() { + /* Create and populate the record. */ + auto record = std::make_unique(CategoryId_ResourceLimitPeakInfo); + if (record == nullptr) { + return; + } + + u64 reslimit_handle_value; + if (R_FAILED(svc::GetInfo(std::addressof(reslimit_handle_value), svc::InfoType_ResourceLimit, svc::InvalidHandle, 0))) { + return; + } + + const auto handle = static_cast(reslimit_handle_value); + ON_SCOPE_EXIT { R_ABORT_UNLESS(svc::CloseHandle(handle)); }; + + #define ADD_RESOURCE(__RESOURCE__) \ + do { \ + s64 peak_value; \ + if (R_FAILED(svc::GetResourceLimitPeakValue(std::addressof(peak_value), handle, svc::LimitableResource_##__RESOURCE__##Max))) { \ + return; \ + } \ + if (R_FAILED(record->Add(FieldId_System##__RESOURCE__##Peak, peak_value))) { \ + return; \ + } \ + } while (0) + + ADD_RESOURCE(PhysicalMemory); + ADD_RESOURCE(ThreadCount); + ADD_RESOURCE(EventCount); + ADD_RESOURCE(TransferMemoryCount); + ADD_RESOURCE(SessionCount); + + #undef ADD_RESOURCE + + Context::SubmitContextRecord(std::move(record)); + } + + void SubmitResourceLimitContexts() { + if (hos::GetVersion() >= hos::Version_11_0_0 || svc::IsKernelMesosphere()) { + SubmitResourceLimitLimitContext(); + SubmitResourceLimitPeakContext(); + } + } + + } + + Reporter::Reporter(ReportType type, const ContextEntry *ctx, const u8 *data, u32 data_size, const ReportMetaData *meta, const AttachmentId *attachments, u32 num_attachments, Result ctx_r) + : type(type), ctx(ctx), data(data), data_size(data_size), meta(meta), attachments(attachments), num_attachments(num_attachments), occurrence_tick(), ctx_result(ctx_r) { /* ... */ } @@ -53,13 +194,9 @@ namespace ams::erpt::srv { R_UNLESS(this->ctx->category == CategoryId_ErrorInfo, erpt::ResultRequiredContextMissing()); R_UNLESS(this->ctx->field_count <= FieldsPerContext, erpt::ResultInvalidArgument()); - bool found_error_code = false; - for (u32 i = 0; i < this->ctx->field_count; i++) { - if (this->ctx->fields[i].id == FieldId_ErrorCode) { - found_error_code = true; - break; - } - } + const bool found_error_code = util::range::any_of(MakeSpan(this->ctx->fields, this->ctx->field_count), [] (const FieldEntry &entry) { + return entry.id == FieldId_ErrorCode; + }); R_UNLESS(found_error_code, erpt::ResultRequiredFieldMissing()); return ResultSuccess(); @@ -83,6 +220,9 @@ namespace ams::erpt::srv { } Result Reporter::SubmitReportDefaults() { + auto record = std::make_unique(CategoryId_ErrorInfoDefaults); + R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); + bool found_abort_flag = false, found_syslog_flag = false; for (u32 i = 0; i < this->ctx->field_count; i++) { if (this->ctx->fields[i].id == FieldId_AbortFlag) { @@ -96,10 +236,6 @@ namespace ams::erpt::srv { } } - ContextRecord *record = new ContextRecord(CategoryId_ErrorInfoDefaults); - R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); - auto record_guard = SCOPE_GUARD { delete record; }; - if (!found_abort_flag) { record->Add(FieldId_AbortFlag, false); } @@ -108,16 +244,19 @@ namespace ams::erpt::srv { record->Add(FieldId_HasSyslogFlag, true); } - R_TRY(Context::SubmitContextRecord(record)); + R_TRY(Context::SubmitContextRecord(std::move(record))); - record_guard.Cancel(); return ResultSuccess(); } Result Reporter::SubmitReportContexts() { - ContextRecord *record = new ContextRecord(CategoryId_ErrorInfoAuto); + auto record = std::make_unique(CategoryId_ErrorInfoAuto); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); - auto record_guard = SCOPE_GUARD { delete record; }; + + /* Handle error context. */ + if (R_FAILED(this->ctx_result)) { + SubmitErrorContext(record.get(), this->ctx_result); + } record->Add(FieldId_OsVersion, s_os_version, strnlen(s_os_version, sizeof(s_os_version))); record->Add(FieldId_PrivateOsVersion, s_private_os_version, strnlen(s_private_os_version, sizeof(s_private_os_version))); @@ -149,11 +288,13 @@ namespace ams::erpt::srv { record->Add(FieldId_ApplicationAliveTime, (this->occurrence_tick - *s_application_launch_time).ToTimeSpan().GetSeconds()); } - R_TRY(Context::SubmitContextRecord(record)); - record_guard.Cancel(); + R_TRY(Context::SubmitContextRecord(std::move(record))); R_TRY(Context::SubmitContext(this->ctx, this->data, this->data_size)); + /* Submit context for resource limits. */ + SubmitResourceLimitContexts(); + return ResultSuccess(); } @@ -165,17 +306,22 @@ namespace ams::erpt::srv { } Result Reporter::CreateReportFile() { - /* Make a journal record. */ - auto *record = new JournalRecord; - R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); - - record->AddReference(); - ON_SCOPE_EXIT { - if (record->RemoveReference()) { - delete record; + /* Define journal record deleter. */ + struct JournalRecordDeleter { + void operator()(JournalRecord *record) { + if (record != nullptr) { + if (record->RemoveReference()) { + delete record; + } + } } }; + /* Make a journal record. */ + auto record = std::unique_ptr, JournalRecordDeleter>{new JournalRecord, JournalRecordDeleter{}}; + R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); + record->AddReference(); + record->info.type = this->type; record->info.id = this->report_id; record->info.flags = erpt::srv::MakeNoReportFlags(); @@ -188,15 +334,16 @@ namespace ams::erpt::srv { record->info.flags.Set(); } - auto report = std::make_unique(record, s_redirect_new_reports); + auto report = std::make_unique(record.get(), s_redirect_new_reports); R_UNLESS(report != nullptr, erpt::ResultOutOfMemory()); + auto report_guard = SCOPE_GUARD { report->Delete(); }; R_TRY(Context::WriteContextsToReport(report.get())); R_TRY(report->GetSize(std::addressof(record->info.report_size))); if (!s_redirect_new_reports) { /* If we're not redirecting new reports, then we want to store the report in the journal. */ - R_TRY(Journal::Store(record)); + R_TRY(Journal::Store(record.get())); } else { /* If we are redirecting new reports, we don't want to store the report in the journal. */ /* We should take this opportunity to delete any attachments associated with the report. */ @@ -205,6 +352,7 @@ namespace ams::erpt::srv { R_TRY(Journal::Commit()); + report_guard.Cancel(); return ResultSuccess(); } diff --git a/libraries/libstratosphere/source/erpt/srv/erpt_srv_reporter.hpp b/libraries/libstratosphere/source/erpt/srv/erpt_srv_reporter.hpp index 1a0e02db3..9a4adca89 100644 --- a/libraries/libstratosphere/source/erpt/srv/erpt_srv_reporter.hpp +++ b/libraries/libstratosphere/source/erpt/srv/erpt_srv_reporter.hpp @@ -42,6 +42,7 @@ namespace ams::erpt::srv { os::Tick occurrence_tick; s64 steady_clock_internal_offset_seconds; ReportId report_id; + Result ctx_result; time::SteadyClockTimePoint steady_clock_current_timepoint; public: static void ClearApplicationLaunchTime() { s_application_launch_time = std::nullopt; } @@ -75,7 +76,7 @@ namespace ams::erpt::srv { void SaveSyslogReportIfRequired(); void SaveSyslogReport(); public: - Reporter(ReportType type, const ContextEntry *ctx, const u8 *data, u32 data_size, const ReportMetaData *meta, const AttachmentId *attachments, u32 num_attachments); + Reporter(ReportType type, const ContextEntry *ctx, const u8 *data, u32 data_size, const ReportMetaData *meta, const AttachmentId *attachments, u32 num_attachments, Result ctx_result); Result CreateReport(); }; diff --git a/libraries/libstratosphere/source/erpt/srv/erpt_srv_stream.cpp b/libraries/libstratosphere/source/erpt/srv/erpt_srv_stream.cpp index 83c6879d5..117bf3a53 100644 --- a/libraries/libstratosphere/source/erpt/srv/erpt_srv_stream.cpp +++ b/libraries/libstratosphere/source/erpt/srv/erpt_srv_stream.cpp @@ -173,7 +173,7 @@ namespace ams::erpt::srv { } } - Result Stream::GetStreamSize(s64 *out) { + Result Stream::GetStreamSize(s64 *out) const { return GetStreamSize(out, this->file_name); } diff --git a/libraries/libstratosphere/source/erpt/srv/erpt_srv_stream.hpp b/libraries/libstratosphere/source/erpt/srv/erpt_srv_stream.hpp index b6671f692..3a5aaab1f 100644 --- a/libraries/libstratosphere/source/erpt/srv/erpt_srv_stream.hpp +++ b/libraries/libstratosphere/source/erpt/srv/erpt_srv_stream.hpp @@ -46,7 +46,7 @@ namespace ams::erpt::srv { Result WriteStream(const u8 *src, u32 src_size); void CloseStream(); - Result GetStreamSize(s64 *out); + Result GetStreamSize(s64 *out) const; private: Result Flush(); public: diff --git a/libraries/libvapours/include/vapours/results/results_common.hpp b/libraries/libvapours/include/vapours/results/results_common.hpp index 23610caee..43b7450e5 100644 --- a/libraries/libvapours/include/vapours/results/results_common.hpp +++ b/libraries/libvapours/include/vapours/results/results_common.hpp @@ -31,6 +31,10 @@ namespace ams { static constexpr BaseType DescriptionBits = 13; static constexpr BaseType ReservedBits = 10; static_assert(ModuleBits + DescriptionBits + ReservedBits == sizeof(BaseType) * CHAR_BIT, "ModuleBits + DescriptionBits + ReservedBits == sizeof(BaseType) * CHAR_BIT"); + private: + static constexpr ALWAYS_INLINE BaseType GetBitsValue(BaseType v, int ofs, int num) { + return (v >> ofs) & ~(~BaseType() << num); + } public: static constexpr ALWAYS_INLINE BaseType MakeValue(BaseType module, BaseType description) { return (module) | (description << ModuleBits); @@ -43,11 +47,23 @@ namespace ams { }; static constexpr ALWAYS_INLINE BaseType GetModuleFromValue(BaseType value) { - return value & ~(~BaseType() << ModuleBits); + return GetBitsValue(value, 0, ModuleBits); } static constexpr ALWAYS_INLINE BaseType GetDescriptionFromValue(BaseType value) { - return ((value >> ModuleBits) & ~(~BaseType() << DescriptionBits)); + return GetBitsValue(value, ModuleBits, DescriptionBits); + } + + static constexpr ALWAYS_INLINE BaseType GetReservedFromValue(BaseType value) { + return GetBitsValue(value, ModuleBits + DescriptionBits, ReservedBits); + } + + static constexpr ALWAYS_INLINE BaseType MaskReservedFromValue(BaseType value) { + return value & ~(~(~BaseType() << ReservedBits) << (ModuleBits + DescriptionBits)); + } + + static constexpr ALWAYS_INLINE BaseType MergeValueWithReserved(BaseType value, BaseType reserved) { + return (value << 0) | (reserved << (ModuleBits + DescriptionBits)); } }; @@ -62,14 +78,14 @@ namespace ams { constexpr ALWAYS_INLINE BaseType GetDescription() const { return ResultTraits::GetDescriptionFromValue(static_cast(this)->GetValue()); } }; - class ResultConstructor; + class ResultInternalAccessor; } class ResultSuccess; class Result final : public result::impl::ResultBase { - friend class ResultConstructor; + friend class result::impl::ResultInternalAccessor; public: using Base = typename result::impl::ResultBase; private: @@ -97,15 +113,23 @@ namespace ams { namespace result::impl { - class ResultConstructor { + class ResultInternalAccessor { public: static constexpr ALWAYS_INLINE Result MakeResult(ResultTraits::BaseType value) { return Result(value); } + + static constexpr ALWAYS_INLINE ResultTraits::BaseType GetReserved(Result result) { + return ResultTraits::GetReservedFromValue(result.value); + } + + static constexpr ALWAYS_INLINE Result MergeReserved(Result result, ResultTraits::BaseType reserved) { + return Result(ResultTraits::MergeValueWithReserved(ResultTraits::MaskReservedFromValue(result.value), reserved)); + } }; constexpr ALWAYS_INLINE Result MakeResult(ResultTraits::BaseType value) { - return ResultConstructor::MakeResult(value); + return ResultInternalAccessor::MakeResult(value); } } @@ -119,8 +143,6 @@ namespace ams { constexpr ALWAYS_INLINE bool IsSuccess() const { return true; } constexpr ALWAYS_INLINE bool IsFailure() const { return !this->IsSuccess(); } - constexpr ALWAYS_INLINE typename Base::BaseType GetModule() const { return Base::GetModule(); } - constexpr ALWAYS_INLINE typename Base::BaseType GetDescription() const { return Base::GetDescription(); } constexpr ALWAYS_INLINE typename Base::BaseType GetValue() const { return Base::SuccessValue; } }; diff --git a/libraries/libvapours/include/vapours/span.hpp b/libraries/libvapours/include/vapours/span.hpp index dc94f5f31..76cdd3517 100644 --- a/libraries/libvapours/include/vapours/span.hpp +++ b/libraries/libvapours/include/vapours/span.hpp @@ -22,4 +22,19 @@ namespace ams { template using Span = std::span; + template + constexpr Span MakeSpan(T *ptr, size_t size) { return { ptr, size }; } + + template + constexpr Span MakeSpan(T *begin, T *end) { return { begin, end }; } + + template + constexpr Span MakeSpan(T (&arr)[Size]) { return Span(arr); } + + template + constexpr Span MakeSpan(std::array &arr) { return Span(arr); } + + template + constexpr Span MakeSpan(const std::array &arr) { return Span(arr); } + } diff --git a/libraries/libvapours/include/vapours/util.hpp b/libraries/libvapours/include/vapours/util.hpp index d55f5db64..2fae1e4fe 100644 --- a/libraries/libvapours/include/vapours/util.hpp +++ b/libraries/libvapours/include/vapours/util.hpp @@ -41,3 +41,4 @@ #include #include #include +#include diff --git a/libraries/libvapours/include/vapours/util/util_range.hpp b/libraries/libvapours/include/vapours/util/util_range.hpp new file mode 100644 index 000000000..6a370f347 --- /dev/null +++ b/libraries/libvapours/include/vapours/util/util_range.hpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2018-2020 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 + +namespace ams::util::range { + + template + constexpr bool any_of(T &&t, F &&f) { + return std::any_of(std::begin(t), std::end(t), std::forward(f)); + } + + template + constexpr bool all_of(T &&t, F &&f) { + return std::all_of(std::begin(t), std::end(t), std::forward(f)); + } + + template + constexpr bool none_of(T &&t, F &&f) { + return std::none_of(std::begin(t), std::end(t), std::forward(f)); + } + + template + constexpr auto find_if(T &&t, F &&f) { + return std::find_if(std::begin(t), std::end(t), std::forward(f)); + } + + template + constexpr auto for_each(T &&t, F &&f) { + return std::for_each(std::begin(t), std::end(t), std::forward(f)); + } + +} diff --git a/stratosphere/erpt/source/erpt_main.cpp b/stratosphere/erpt/source/erpt_main.cpp index 52823bb36..1e7193ebc 100644 --- a/stratosphere/erpt/source/erpt_main.cpp +++ b/stratosphere/erpt/source/erpt_main.cpp @@ -73,6 +73,9 @@ void __appInit(void) { R_ABORT_UNLESS(setsysInitialize()); R_ABORT_UNLESS(pscmInitialize()); R_ABORT_UNLESS(time::Initialize()); + if (hos::GetVersion() >= hos::Version_11_0_0) { + R_ABORT_UNLESS(ectxrInitialize()); + } R_ABORT_UNLESS(fsInitialize()); });