erpt: update for 11.0.0 (closes #1218)

This commit is contained in:
Michael Scire 2020-12-03 11:13:35 -08:00
parent bba99d49da
commit 6da28f4a27
24 changed files with 438 additions and 146 deletions

View file

@ -25,17 +25,17 @@ namespace ams::erpt::sf {
#define AMS_ERPT_I_CONTEXT_INTERFACE_INFO(C, H) \ #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, 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, 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, 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, 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, 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, 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, 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, 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, 8, Result, ClearApplicationLaunchTime, (), hos::Version_6_0_0) \
AMS_SF_METHOD_INFO(C, H, 9, Result, SubmitAttachment, (ams::sf::Out<AttachmentId> out, const ams::sf::InBuffer &attachment_name, const ams::sf::InBuffer &attachment_data), hos::Version_8_0_0) \ AMS_SF_METHOD_INFO(C, H, 9, Result, SubmitAttachment, (ams::sf::Out<AttachmentId> 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, 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, 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, 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, Result result), hos::Version_11_0_0)
AMS_SF_DEFINE_INTERFACE(IContext, AMS_ERPT_I_CONTEXT_INTERFACE_INFO) AMS_SF_DEFINE_INTERFACE(IContext, AMS_ERPT_I_CONTEXT_INTERFACE_INFO)

View file

@ -42,4 +42,52 @@ namespace ams::err {
static_assert(sizeof(ErrorContext) == 0x200); static_assert(sizeof(ErrorContext) == 0x200);
static_assert(util::is_pod<ErrorContext>::value); static_assert(util::is_pod<ErrorContext>::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;
}
} }

View file

@ -238,6 +238,10 @@
return ::svcSynchronizePreemptionState(); 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) { 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); return ::svcKernelDebug(kern_debug_type, arg0, arg1, arg2);
} }

View file

@ -40,7 +40,7 @@ namespace ams::erpt::srv {
} }
} }
AttachmentFileName Attachment::FileName() { AttachmentFileName Attachment::FileName() const {
return FileName(this->record->info.attachment_id); return FileName(this->record->info.attachment_id);
} }
@ -64,7 +64,7 @@ namespace ams::erpt::srv {
return this->CloseStream(); return this->CloseStream();
} }
Result Attachment::GetFlags(AttachmentFlagSet *out) { Result Attachment::GetFlags(AttachmentFlagSet *out) const {
*out = this->record->info.flags; *out = this->record->info.flags;
return ResultSuccess(); return ResultSuccess();
} }
@ -77,7 +77,7 @@ namespace ams::erpt::srv {
return ResultSuccess(); return ResultSuccess();
} }
Result Attachment::GetSize(s64 *out) { Result Attachment::GetSize(s64 *out) const {
return this->GetStreamSize(out); return this->GetStreamSize(out);
} }

View file

@ -32,7 +32,7 @@ namespace ams::erpt::srv {
private: private:
JournalRecord<AttachmentInfo> *record; JournalRecord<AttachmentInfo> *record;
private: private:
AttachmentFileName FileName(); AttachmentFileName FileName() const;
public: public:
static AttachmentFileName FileName(AttachmentId attachment_id); static AttachmentFileName FileName(AttachmentId attachment_id);
public: public:
@ -44,9 +44,9 @@ namespace ams::erpt::srv {
Result Delete(); Result Delete();
void Close(); void Close();
Result GetFlags(AttachmentFlagSet *out); Result GetFlags(AttachmentFlagSet *out) const;
Result SetFlags(AttachmentFlagSet flags); Result SetFlags(AttachmentFlagSet flags);
Result GetSize(s64 *out); Result GetSize(s64 *out) const;
template<typename T> template<typename T>
Result Write(T val) { Result Write(T val) {

View file

@ -71,25 +71,23 @@ namespace ams::erpt::srv {
} }
Result Context::AddContextToCategory(const ContextEntry *entry, const u8 *data, u32 data_size) { Result Context::AddContextToCategory(const ContextEntry *entry, const u8 *data, u32 data_size) {
ContextRecord *record = new ContextRecord(); auto record = std::make_unique<ContextRecord>();
R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory());
auto guard = SCOPE_GUARD { delete record; };
R_TRY(record->Initialize(entry, data, data_size)); R_TRY(record->Initialize(entry, data, data_size));
guard.Cancel(); this->AddContextRecordToCategory(std::move(record));
this->AddContextRecordToCategory(record);
return ResultSuccess(); return ResultSuccess();
} }
Result Context::AddContextRecordToCategory(ContextRecord *record) { Result Context::AddContextRecordToCategory(std::unique_ptr<ContextRecord> record) {
if (this->record_count < this->max_record_count) { if (this->record_count < this->max_record_count) {
this->record_list.push_front(*record); this->record_list.push_front(*record.release());
this->record_count++; this->record_count++;
} else { } else {
ContextRecord *back = std::addressof(this->record_list.back()); ContextRecord *back = std::addressof(this->record_list.back());
this->record_list.pop_back(); this->record_list.pop_back();
this->record_list.push_front(*record); this->record_list.push_front(*record.release());
delete back; delete back;
} }
@ -97,21 +95,21 @@ namespace ams::erpt::srv {
} }
Result Context::SubmitContext(const ContextEntry *entry, const u8 *data, u32 data_size) { 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++) { auto it = util::range::find_if(g_category_list, [&](const Context &cur) {
if (it->category == entry->category) { return cur.category == entry->category;
return it->AddContextToCategory(entry, data, data_size); });
} R_UNLESS(it != g_category_list.end(), erpt::ResultCategoryNotFound());
}
return erpt::ResultCategoryNotFound(); return it->AddContextToCategory(entry, data, data_size);
} }
Result Context::SubmitContextRecord(ContextRecord *record) { Result Context::SubmitContextRecord(std::unique_ptr<ContextRecord> record) {
for (auto it = g_category_list.begin(); it != g_category_list.end(); it++) { auto it = util::range::find_if(g_category_list, [&](const Context &cur) {
if (it->category == record->ctx.category) { return cur.category == record->ctx.category;
return it->AddContextRecordToCategory(record); });
} R_UNLESS(it != g_category_list.end(), erpt::ResultCategoryNotFound());
}
return erpt::ResultCategoryNotFound(); return it->AddContextRecordToCategory(std::move(record));
} }
Result Context::WriteContextsToReport(Report *report) { Result Context::WriteContextsToReport(Report *report) {

View file

@ -35,10 +35,10 @@ namespace ams::erpt::srv {
Result AddCategoryToReport(Report *report); Result AddCategoryToReport(Report *report);
Result AddContextToCategory(const ContextEntry *entry, const u8 *data, u32 data_size); Result AddContextToCategory(const ContextEntry *entry, const u8 *data, u32 data_size);
Result AddContextRecordToCategory(ContextRecord *record); Result AddContextRecordToCategory(std::unique_ptr<ContextRecord> record);
public: public:
static Result SubmitContext(const ContextEntry *entry, const u8 *data, u32 data_size); static Result SubmitContext(const ContextEntry *entry, const u8 *data, u32 data_size);
static Result SubmitContextRecord(ContextRecord *record); static Result SubmitContextRecord(std::unique_ptr<ContextRecord> record);
static Result WriteContextsToReport(Report *report); static Result WriteContextsToReport(Report *report);
}; };

View file

@ -35,7 +35,7 @@ namespace ams::erpt::srv {
return Context::SubmitContext(ctx, data, data_size); 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<const ContextEntry *>( ctx_buffer.GetPointer()); const ContextEntry *ctx = reinterpret_cast<const ContextEntry *>( ctx_buffer.GetPointer());
const u8 *data = reinterpret_cast<const u8 *>(data_buffer.GetPointer()); const u8 *data = reinterpret_cast<const u8 *>(data_buffer.GetPointer());
const ReportMetaData *meta = reinterpret_cast<const ReportMetaData *>(meta_buffer.GetPointer()); const ReportMetaData *meta = reinterpret_cast<const ReportMetaData *>(meta_buffer.GetPointer());
@ -47,9 +47,7 @@ namespace ams::erpt::srv {
R_UNLESS(ctx_size == sizeof(ContextEntry), erpt::ResultInvalidArgument()); R_UNLESS(ctx_size == sizeof(ContextEntry), erpt::ResultInvalidArgument());
R_UNLESS(meta_size == 0 || meta_size == sizeof(ReportMetaData), 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, result);
Reporter reporter(report_type, ctx, data, data_size, meta_size != 0 ? meta : nullptr, nullptr, 0);
R_TRY(reporter.CreateReport()); R_TRY(reporter.CreateReport());
ManagerImpl::NotifyAll(); 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) { 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) { 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); 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<const ContextEntry *>( ctx_buffer.GetPointer()); const ContextEntry *ctx = reinterpret_cast<const ContextEntry *>( ctx_buffer.GetPointer());
const u8 *data = reinterpret_cast<const u8 *>(data_buffer.GetPointer()); const u8 *data = reinterpret_cast<const u8 *>(data_buffer.GetPointer());
const u32 ctx_size = static_cast<u32>(ctx_buffer.GetSize()); const u32 ctx_size = static_cast<u32>(ctx_buffer.GetSize());
@ -150,9 +148,7 @@ namespace ams::erpt::srv {
R_UNLESS(ctx_size == sizeof(ContextEntry), erpt::ResultInvalidArgument()); R_UNLESS(ctx_size == sizeof(ContextEntry), erpt::ResultInvalidArgument());
R_UNLESS(num_attachments <= AttachmentsPerReportMax, erpt::ResultInvalidArgument()); R_UNLESS(num_attachments <= AttachmentsPerReportMax, erpt::ResultInvalidArgument());
/* TODO: use context */ Reporter reporter(report_type, ctx, data, data_size, nullptr, attachments, num_attachments, result);
Reporter reporter(report_type, ctx, data, data_size, nullptr, attachments, num_attachments);
R_TRY(reporter.CreateReport()); R_TRY(reporter.CreateReport());
ManagerImpl::NotifyAll(); 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) { 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());
} }
} }

View file

@ -31,8 +31,8 @@ namespace ams::erpt::srv {
Result ClearApplicationLaunchTime(); Result ClearApplicationLaunchTime();
Result SubmitAttachment(ams::sf::Out<AttachmentId> out, const ams::sf::InBuffer &attachment_name, const ams::sf::InBuffer &attachment_data); Result SubmitAttachment(ams::sf::Out<AttachmentId> 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 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 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, 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, Result result);
}; };
static_assert(erpt::sf::IsIContext<ContextImpl>); static_assert(erpt::sf::IsIContext<ContextImpl>);

View file

@ -37,14 +37,14 @@ namespace ams::erpt::srv {
this->ctx = {}; this->ctx = {};
} }
ContextRecord::ContextRecord(CategoryId category) { ContextRecord::ContextRecord(CategoryId category, u32 array_buf_size) {
this->ctx = { this->ctx = {
.category = category, .category = category,
.array_buffer = static_cast<u8 *>(Allocate(ArrayBufferSizeDefault)), .array_buffer = static_cast<u8 *>(Allocate(array_buf_size)),
}; };
if (this->ctx.array_buffer != nullptr) { if (this->ctx.array_buffer != nullptr) {
this->ctx.array_buffer_size = ArrayBufferSizeDefault; this->ctx.array_buffer_size = array_buf_size;
this->ctx.array_free_count = ArrayBufferSizeDefault; this->ctx.array_free_count = array_buf_size;
} }
} }
@ -176,26 +176,34 @@ namespace ams::erpt::srv {
return ResultSuccess(); 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(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; 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++; s_record_count++;
auto &field = this->ctx.fields[this->ctx.field_count++]; auto &field = this->ctx.fields[this->ctx.field_count++];
field.id = field_id; field.id = field_id;
field.type = FieldType_String; field.type = type;
field.value_array = { field.value_array = {
.start_idx = start_idx, .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(); 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);
}
} }

View file

@ -31,9 +31,11 @@ namespace ams::erpt::srv {
} }
private: private:
ContextEntry ctx; ContextEntry ctx;
private:
Result Add(FieldId field_id, const void *arr, u32 size, FieldType type);
public: public:
ContextRecord(); ContextRecord();
explicit ContextRecord(CategoryId category); explicit ContextRecord(CategoryId category, u32 array_buf_size = ArrayBufferSizeDefault);
~ContextRecord(); ~ContextRecord();
Result Initialize(const ContextEntry *ctx_ptr, const u8 *data, u32 data_size); 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, s32 value_i32);
Result Add(FieldId field_id, s64 value_i64); 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 char *str, u32 str_size);
Result Add(FieldId field_id, const u8 *data, u32 size);
}; };
} }

View file

@ -37,18 +37,32 @@ namespace ams::erpt::srv {
static ValueTypeTag GetTag(u32) { return ValueTypeTag::U32; } static ValueTypeTag GetTag(u32) { return ValueTypeTag::U32; }
static ValueTypeTag GetTag(u64) { return ValueTypeTag::U64; } 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<u32>(strnlen(str, len)) : 0;
if (str_len < ElementSize_32) {
R_TRY(report->Write(static_cast<u8>(static_cast<u8>(ValueTypeTag::FixStr) | str_len)));
} else if (str_len < ElementSize_256) {
R_TRY(report->Write(static_cast<u8>(ValueTypeTag::Str8)));
R_TRY(report->Write(static_cast<u8>(str_len)));
} else {
R_UNLESS(str_len < ElementSize_16384, erpt::ResultFormatterError());
R_TRY(report->Write(static_cast<u8>(ValueTypeTag::Str16)));
u16 be_str_len;
util::StoreBigEndian(std::addressof(be_str_len), static_cast<u16>(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 Result AddId(Report *report, FieldId field_id) {
static_assert(MaxFieldStringSize < ElementSize_256); static_assert(MaxFieldStringSize < ElementSize_256);
const u32 field_len = static_cast<u32>(strnlen(FieldString[field_id], MaxFieldStringSize)); R_TRY(AddStringValue(report, FieldString[field_id], strnlen(FieldString[field_id], MaxFieldStringSize)));
if (field_len < ElementSize_32) {
R_TRY(report->Write(static_cast<u8>(static_cast<u8>(ValueTypeTag::FixStr) | field_len)));
} else {
R_TRY(report->Write(static_cast<u8>(ValueTypeTag::Str8)));
R_TRY(report->Write(static_cast<u8>(field_len)));
}
R_TRY(report->Write(FieldString[field_id], field_len));
return ResultSuccess(); return ResultSuccess();
} }
@ -140,23 +154,7 @@ namespace ams::erpt::srv {
static Result AddField(Report *report, FieldId field_id, char *str, u32 len) { static Result AddField(Report *report, FieldId field_id, char *str, u32 len) {
R_TRY(AddId(report, field_id)); R_TRY(AddId(report, field_id));
const u32 str_len = str != nullptr ? static_cast<u32>(strnlen(str, len)) : 0; R_TRY(AddStringValue(report, str, len));
if (str_len < ElementSize_32) {
R_TRY(report->Write(static_cast<u8>(static_cast<u8>(ValueTypeTag::FixStr) | str_len)));
} else if (str_len < ElementSize_256) {
R_TRY(report->Write(static_cast<u8>(ValueTypeTag::Str8)));
R_TRY(report->Write(static_cast<u8>(str_len)));
} else {
R_UNLESS(str_len < ElementSize_16384, erpt::ResultFormatterError());
R_TRY(report->Write(static_cast<u8>(ValueTypeTag::Str16)));
u16 be_str_len;
util::StoreBigEndian(std::addressof(be_str_len), static_cast<u16>(str_len));
R_TRY(report->Write(be_str_len));
}
R_TRY(report->Write(str, str_len));
return ResultSuccess(); return ResultSuccess();
} }

View file

@ -99,22 +99,22 @@ namespace ams::erpt::srv {
Result SetProductModel(const char *model, u32 model_len) { Result SetProductModel(const char *model, u32 model_len) {
/* NOTE: Nintendo does not check that this allocation succeeds. */ /* NOTE: Nintendo does not check that this allocation succeeds. */
auto *record = new ContextRecord(CategoryId_ProductModelInfo); auto record = std::make_unique<ContextRecord>(CategoryId_ProductModelInfo);
R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory());
R_TRY(record->Add(FieldId_ProductModel, model, model_len)); R_TRY(record->Add(FieldId_ProductModel, model, model_len));
R_TRY(Context::SubmitContextRecord(record)); R_TRY(Context::SubmitContextRecord(std::move(record)));
return ResultSuccess(); return ResultSuccess();
} }
Result SetRegionSetting(const char *region, u32 region_len) { Result SetRegionSetting(const char *region, u32 region_len) {
/* NOTE: Nintendo does not check that this allocation succeeds. */ /* NOTE: Nintendo does not check that this allocation succeeds. */
auto *record = new ContextRecord(CategoryId_RegionSettingInfo); auto record = std::make_unique<ContextRecord>(CategoryId_RegionSettingInfo);
R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory());
R_TRY(record->Add(FieldId_RegionSetting, region, region_len)); R_TRY(record->Add(FieldId_RegionSetting, region, region_len));
R_TRY(Context::SubmitContextRecord(record)); R_TRY(Context::SubmitContextRecord(std::move(record)));
return ResultSuccess(); return ResultSuccess();
} }

View file

@ -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); return FileName(this->record->info.id, this->redirect_to_sd_card);
} }
@ -70,7 +70,7 @@ namespace ams::erpt::srv {
return this->CloseStream(); return this->CloseStream();
} }
Result Report::GetFlags(ReportFlagSet *out) { Result Report::GetFlags(ReportFlagSet *out) const {
*out = this->record->info.flags; *out = this->record->info.flags;
return ResultSuccess(); return ResultSuccess();
} }
@ -83,7 +83,7 @@ namespace ams::erpt::srv {
return ResultSuccess(); return ResultSuccess();
} }
Result Report::GetSize(s64 *out) { Result Report::GetSize(s64 *out) const {
return this->GetStreamSize(out); return this->GetStreamSize(out);
} }

View file

@ -33,7 +33,7 @@ namespace ams::erpt::srv {
JournalRecord<ReportInfo> *record; JournalRecord<ReportInfo> *record;
bool redirect_to_sd_card; bool redirect_to_sd_card;
private: private:
ReportFileName FileName(); ReportFileName FileName() const;
public: public:
static ReportFileName FileName(ReportId report_id, bool redirect_to_sd); static ReportFileName FileName(ReportId report_id, bool redirect_to_sd);
public: public:
@ -45,9 +45,9 @@ namespace ams::erpt::srv {
Result Delete(); Result Delete();
void Close(); void Close();
Result GetFlags(ReportFlagSet *out); Result GetFlags(ReportFlagSet *out) const;
Result SetFlags(ReportFlagSet flags); Result SetFlags(ReportFlagSet flags);
Result GetSize(s64 *out); Result GetSize(s64 *out) const;
template<typename T> template<typename T>
Result Write(T val) { Result Write(T val) {

View file

@ -22,17 +22,158 @@
namespace ams::erpt::srv { namespace ams::erpt::srv {
bool Reporter::s_redirect_new_reports = true; constinit bool Reporter::s_redirect_new_reports = true;
char Reporter::s_serial_number[24] = "Unknown"; constinit char Reporter::s_serial_number[24] = "Unknown";
char Reporter::s_os_version[24] = "Unknown"; constinit char Reporter::s_os_version[24] = "Unknown";
char Reporter::s_private_os_version[96] = "Unknown"; constinit char Reporter::s_private_os_version[96] = "Unknown";
std::optional<os::Tick> Reporter::s_application_launch_time; constinit std::optional<os::Tick> Reporter::s_application_launch_time;
std::optional<os::Tick> Reporter::s_awake_time; constinit std::optional<os::Tick> Reporter::s_awake_time;
std::optional<os::Tick> Reporter::s_power_on_time; constinit std::optional<os::Tick> Reporter::s_power_on_time;
std::optional<time::SteadyClockTimePoint> Reporter::s_initial_launch_settings_completion_time; constinit std::optional<time::SteadyClockTimePoint> 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) namespace {
: type(type), ctx(ctx), data(data), data_size(data_size), meta(meta), attachments(attachments), num_attachments(num_attachments), occurrence_tick()
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<ContextRecord>(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<svc::Handle>(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<ContextRecord>(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<svc::Handle>(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->category == CategoryId_ErrorInfo, erpt::ResultRequiredContextMissing());
R_UNLESS(this->ctx->field_count <= FieldsPerContext, erpt::ResultInvalidArgument()); R_UNLESS(this->ctx->field_count <= FieldsPerContext, erpt::ResultInvalidArgument());
bool found_error_code = false; const bool found_error_code = util::range::any_of(MakeSpan(this->ctx->fields, this->ctx->field_count), [] (const FieldEntry &entry) {
for (u32 i = 0; i < this->ctx->field_count; i++) { return entry.id == FieldId_ErrorCode;
if (this->ctx->fields[i].id == FieldId_ErrorCode) { });
found_error_code = true;
break;
}
}
R_UNLESS(found_error_code, erpt::ResultRequiredFieldMissing()); R_UNLESS(found_error_code, erpt::ResultRequiredFieldMissing());
return ResultSuccess(); return ResultSuccess();
@ -83,6 +220,9 @@ namespace ams::erpt::srv {
} }
Result Reporter::SubmitReportDefaults() { Result Reporter::SubmitReportDefaults() {
auto record = std::make_unique<ContextRecord>(CategoryId_ErrorInfoDefaults);
R_UNLESS(record != nullptr, erpt::ResultOutOfMemory());
bool found_abort_flag = false, found_syslog_flag = false; bool found_abort_flag = false, found_syslog_flag = false;
for (u32 i = 0; i < this->ctx->field_count; i++) { for (u32 i = 0; i < this->ctx->field_count; i++) {
if (this->ctx->fields[i].id == FieldId_AbortFlag) { 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) { if (!found_abort_flag) {
record->Add(FieldId_AbortFlag, false); record->Add(FieldId_AbortFlag, false);
} }
@ -108,16 +244,19 @@ namespace ams::erpt::srv {
record->Add(FieldId_HasSyslogFlag, true); record->Add(FieldId_HasSyslogFlag, true);
} }
R_TRY(Context::SubmitContextRecord(record)); R_TRY(Context::SubmitContextRecord(std::move(record)));
record_guard.Cancel();
return ResultSuccess(); return ResultSuccess();
} }
Result Reporter::SubmitReportContexts() { Result Reporter::SubmitReportContexts() {
ContextRecord *record = new ContextRecord(CategoryId_ErrorInfoAuto); auto record = std::make_unique<ContextRecord>(CategoryId_ErrorInfoAuto);
R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); 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_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))); 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()); record->Add(FieldId_ApplicationAliveTime, (this->occurrence_tick - *s_application_launch_time).ToTimeSpan().GetSeconds());
} }
R_TRY(Context::SubmitContextRecord(record)); R_TRY(Context::SubmitContextRecord(std::move(record)));
record_guard.Cancel();
R_TRY(Context::SubmitContext(this->ctx, this->data, this->data_size)); R_TRY(Context::SubmitContext(this->ctx, this->data, this->data_size));
/* Submit context for resource limits. */
SubmitResourceLimitContexts();
return ResultSuccess(); return ResultSuccess();
} }
@ -165,17 +306,22 @@ namespace ams::erpt::srv {
} }
Result Reporter::CreateReportFile() { Result Reporter::CreateReportFile() {
/* Make a journal record. */ /* Define journal record deleter. */
auto *record = new JournalRecord<ReportInfo>; struct JournalRecordDeleter {
R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); void operator()(JournalRecord<ReportInfo> *record) {
if (record != nullptr) {
record->AddReference(); if (record->RemoveReference()) {
ON_SCOPE_EXIT { delete record;
if (record->RemoveReference()) { }
delete record; }
} }
}; };
/* Make a journal record. */
auto record = std::unique_ptr<JournalRecord<ReportInfo>, JournalRecordDeleter>{new JournalRecord<ReportInfo>, JournalRecordDeleter{}};
R_UNLESS(record != nullptr, erpt::ResultOutOfMemory());
record->AddReference();
record->info.type = this->type; record->info.type = this->type;
record->info.id = this->report_id; record->info.id = this->report_id;
record->info.flags = erpt::srv::MakeNoReportFlags(); record->info.flags = erpt::srv::MakeNoReportFlags();
@ -188,15 +334,16 @@ namespace ams::erpt::srv {
record->info.flags.Set<ReportFlag::HasAttachment>(); record->info.flags.Set<ReportFlag::HasAttachment>();
} }
auto report = std::make_unique<Report>(record, s_redirect_new_reports); auto report = std::make_unique<Report>(record.get(), s_redirect_new_reports);
R_UNLESS(report != nullptr, erpt::ResultOutOfMemory()); R_UNLESS(report != nullptr, erpt::ResultOutOfMemory());
auto report_guard = SCOPE_GUARD { report->Delete(); };
R_TRY(Context::WriteContextsToReport(report.get())); R_TRY(Context::WriteContextsToReport(report.get()));
R_TRY(report->GetSize(std::addressof(record->info.report_size))); R_TRY(report->GetSize(std::addressof(record->info.report_size)));
if (!s_redirect_new_reports) { if (!s_redirect_new_reports) {
/* If we're not redirecting new reports, then we want to store the report in the journal. */ /* 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 { } else {
/* If we are redirecting new reports, we don't want to store the report in the journal. */ /* 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. */ /* 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()); R_TRY(Journal::Commit());
report_guard.Cancel();
return ResultSuccess(); return ResultSuccess();
} }

View file

@ -42,6 +42,7 @@ namespace ams::erpt::srv {
os::Tick occurrence_tick; os::Tick occurrence_tick;
s64 steady_clock_internal_offset_seconds; s64 steady_clock_internal_offset_seconds;
ReportId report_id; ReportId report_id;
Result ctx_result;
time::SteadyClockTimePoint steady_clock_current_timepoint; time::SteadyClockTimePoint steady_clock_current_timepoint;
public: public:
static void ClearApplicationLaunchTime() { s_application_launch_time = std::nullopt; } static void ClearApplicationLaunchTime() { s_application_launch_time = std::nullopt; }
@ -75,7 +76,7 @@ namespace ams::erpt::srv {
void SaveSyslogReportIfRequired(); void SaveSyslogReportIfRequired();
void SaveSyslogReport(); void SaveSyslogReport();
public: 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(); Result CreateReport();
}; };

View file

@ -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); return GetStreamSize(out, this->file_name);
} }

View file

@ -46,7 +46,7 @@ namespace ams::erpt::srv {
Result WriteStream(const u8 *src, u32 src_size); Result WriteStream(const u8 *src, u32 src_size);
void CloseStream(); void CloseStream();
Result GetStreamSize(s64 *out); Result GetStreamSize(s64 *out) const;
private: private:
Result Flush(); Result Flush();
public: public:

View file

@ -31,6 +31,10 @@ namespace ams {
static constexpr BaseType DescriptionBits = 13; static constexpr BaseType DescriptionBits = 13;
static constexpr BaseType ReservedBits = 10; static constexpr BaseType ReservedBits = 10;
static_assert(ModuleBits + DescriptionBits + ReservedBits == sizeof(BaseType) * CHAR_BIT, "ModuleBits + DescriptionBits + ReservedBits == sizeof(BaseType) * CHAR_BIT"); 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: public:
static constexpr ALWAYS_INLINE BaseType MakeValue(BaseType module, BaseType description) { static constexpr ALWAYS_INLINE BaseType MakeValue(BaseType module, BaseType description) {
return (module) | (description << ModuleBits); return (module) | (description << ModuleBits);
@ -43,11 +47,23 @@ namespace ams {
}; };
static constexpr ALWAYS_INLINE BaseType GetModuleFromValue(BaseType value) { 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) { 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<const Self *>(this)->GetValue()); } constexpr ALWAYS_INLINE BaseType GetDescription() const { return ResultTraits::GetDescriptionFromValue(static_cast<const Self *>(this)->GetValue()); }
}; };
class ResultConstructor; class ResultInternalAccessor;
} }
class ResultSuccess; class ResultSuccess;
class Result final : public result::impl::ResultBase<Result> { class Result final : public result::impl::ResultBase<Result> {
friend class ResultConstructor; friend class result::impl::ResultInternalAccessor;
public: public:
using Base = typename result::impl::ResultBase<Result>; using Base = typename result::impl::ResultBase<Result>;
private: private:
@ -97,15 +113,23 @@ namespace ams {
namespace result::impl { namespace result::impl {
class ResultConstructor { class ResultInternalAccessor {
public: public:
static constexpr ALWAYS_INLINE Result MakeResult(ResultTraits::BaseType value) { static constexpr ALWAYS_INLINE Result MakeResult(ResultTraits::BaseType value) {
return Result(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) { 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 IsSuccess() const { return true; }
constexpr ALWAYS_INLINE bool IsFailure() const { return !this->IsSuccess(); } 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; } constexpr ALWAYS_INLINE typename Base::BaseType GetValue() const { return Base::SuccessValue; }
}; };

View file

@ -22,4 +22,19 @@ namespace ams {
template<typename T> template<typename T>
using Span = std::span<T>; using Span = std::span<T>;
template<typename T>
constexpr Span<T> MakeSpan(T *ptr, size_t size) { return { ptr, size }; }
template <typename T>
constexpr Span<T> MakeSpan(T *begin, T *end) { return { begin, end }; }
template<typename T, size_t Size>
constexpr Span<T> MakeSpan(T (&arr)[Size]) { return Span<T>(arr); }
template<typename T, size_t Size>
constexpr Span<T> MakeSpan(std::array<T, Size> &arr) { return Span<T>(arr); }
template<typename T, size_t Size>
constexpr Span<T> MakeSpan(const std::array<T, Size> &arr) { return Span<const T>(arr); }
} }

View file

@ -41,3 +41,4 @@
#include <vapours/util/util_string_util.hpp> #include <vapours/util/util_string_util.hpp>
#include <vapours/util/util_variadic.hpp> #include <vapours/util/util_variadic.hpp>
#include <vapours/util/util_format_string.hpp> #include <vapours/util/util_format_string.hpp>
#include <vapours/util/util_range.hpp>

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours/common.hpp>
#include <vapours/assert.hpp>
namespace ams::util::range {
template<typename T, typename F>
constexpr bool any_of(T &&t, F &&f) {
return std::any_of(std::begin(t), std::end(t), std::forward<F>(f));
}
template<typename T, typename F>
constexpr bool all_of(T &&t, F &&f) {
return std::all_of(std::begin(t), std::end(t), std::forward<F>(f));
}
template<typename T, typename F>
constexpr bool none_of(T &&t, F &&f) {
return std::none_of(std::begin(t), std::end(t), std::forward<F>(f));
}
template<typename T, typename F>
constexpr auto find_if(T &&t, F &&f) {
return std::find_if(std::begin(t), std::end(t), std::forward<F>(f));
}
template<typename T, typename F>
constexpr auto for_each(T &&t, F &&f) {
return std::for_each(std::begin(t), std::end(t), std::forward<F>(f));
}
}

View file

@ -73,6 +73,9 @@ void __appInit(void) {
R_ABORT_UNLESS(setsysInitialize()); R_ABORT_UNLESS(setsysInitialize());
R_ABORT_UNLESS(pscmInitialize()); R_ABORT_UNLESS(pscmInitialize());
R_ABORT_UNLESS(time::Initialize()); R_ABORT_UNLESS(time::Initialize());
if (hos::GetVersion() >= hos::Version_11_0_0) {
R_ABORT_UNLESS(ectxrInitialize());
}
R_ABORT_UNLESS(fsInitialize()); R_ABORT_UNLESS(fsInitialize());
}); });