Compare commits

..

25 Commits
nim ... erpt

Author SHA1 Message Date
Michael Scire
8e1cf7a7e0 erpt: amend logic for culling orphan attachments 2020-04-12 18:39:03 -07:00
Michael Scire
6b3bf10e46 fatal: update for latest bindings 2020-04-12 18:30:15 -07:00
Michael Scire
16a25309d2 erpt: reimplement the sysmodule 2020-04-11 21:40:14 -07:00
Michael Scire
eca5ac01b8 erpt: include all known types/categories in autogen 2020-04-10 03:33:30 -07:00
Michael Scire
50ea19e7a2 erpt: identify flags in autogen 2020-04-08 10:32:53 -07:00
Michael Scire
823a1f3ea3 erpt: tweak autogen 2020-04-08 10:09:56 -07:00
Michael Scire
b73895df0a util: add bitflagset 2020-04-08 08:39:36 -07:00
Michael Scire
5062329979 erpt: add ids (and autogeneration tool) 2020-04-08 07:17:42 -07:00
Michael Scire
065485b971 os: refactor/rewrite entire namespace. 2020-04-08 02:21:35 -07:00
Michael Scire
6193283f03 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "da6eac98"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "da6eac98"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2020-04-06 17:45:00 -07:00
Michael Scire
eb48e7cc59 buildsystem: fix building 2020-04-06 17:44:14 -07:00
Michael Scire
d98490d339 fs: Implement AesXtsStorage 2020-04-06 05:44:33 -07:00
Michael Scire
b2e86f5a1b fs: correct error result in AesCtrStorage 2020-04-06 04:56:49 -07:00
Michael Scire
0e9974e7b3 fs: add AesCtrStorage 2020-04-06 03:58:52 -07:00
Michael Scire
496be5ecd4 fs: implement PooledBuffer 2020-04-06 03:15:38 -07:00
Michael Scire
50a91b1d6e fs: implement system heap 2020-04-06 03:15:33 -07:00
Michael Scire
f872be67eb git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "18396d1a"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "18396d1a"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2020-04-05 23:26:06 -07:00
Michael Scire
e04679f05a crypto: add aes (ecb, ctr, xts) 2020-04-05 23:25:28 -07:00
Michael Scire
8d1ada2a1b fssystem: add RomFsFileSystem 2020-04-04 02:37:21 -07:00
Adubbz
a50d6a2696 NCM client implementation (#858)
* ncm: Implement InstallTaskDataBase and FileInstallTaskData

* ncm: minor bugfixes

* ncm: Implemented MemoryInstallTaskData

* ncm: more std

* ncm: begin implementing install task base

* ncm: move protected funcs

* ncm: fix recursive include

* ncm: more install task progress

* ncm install task: implement IncrementProgress and update UpdateThroughputMeasurement

* ncm: more work

* ncm client: more progress

* ncm client: more progress

* ncm client: finish implementing GetContentMetaInfoList

* ncm client: more progress

* ncm client: finished InstallTaskBase

* ncm client: implement PackageInstallTaskBase

* ncm client: fixes

* ncm: improve accuracy

* ncm client: implement PackageInstallTask

* ncm client: implement PackageSystemUpdateTask

* ncm client: minor name tweaks

* ncm client: implement SubmissionPackageInstallTask

* ncm client: add missing this to SubmissionPackageInstallTask

* ncm client: add missing nullptr check to SubmissionPackageInstallTask destructor

* ncm client: SubmissionPackageInstallTask fixes

* ncm: fix forward declarations

* ncm client: added simplified funcs

* ncm: cleanup client code

* ncm: fix bug introduced by cleanup

* ncm: fix typo

* ncm: implement correct ReadVariationContentMetaInfoList behavior

* ncm: correct InstallContentMetaWriter ctor

* ncm: correct conversion of content meta header types

Co-authored-by: Michael Scire <SciresM@gmail.com>
2020-04-03 22:40:46 -07:00
Michael Scire
76d72fa946 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "62f5667b"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "62f5667b"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2020-04-02 00:29:14 -07:00
Michael Scire
8b19fdfd51 sf: fix OutArray/InArray constructors to behave as expected 2020-04-02 00:28:39 -07:00
Michael Scire
612d846132 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "0f46474d"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "0f46474d"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2020-03-31 22:43:12 -07:00
Michael Scire
816ce605d3 fs: add an extension common name generator for sd card 2020-03-31 22:42:02 -07:00
SciresM
07c95662b1 nim: add DestroySystemUpdateTask/ListSystemUpdateTask (#863) 2020-03-31 12:50:55 -07:00
394 changed files with 25283 additions and 2077 deletions

View File

@@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/Atmosphere-NX/Atmosphere-libs
branch = master
commit = a40d4593d7e46ea296802e5c50fd0da2d9f92a76
parent = 6de1361c8be886eda16faf87c73b9e4d01187bca
commit = da6eac986d7f67ca3dcc3a8df0c191ffbea4686f
parent = eb48e7cc5943bd594b3166cb888d3dadb0474107
method = merge
cmdver = 0.4.1

View File

@@ -5,7 +5,7 @@ endif
include $(DEVKITPRO)/devkitA64/base_rules
export ATMOSPHERE_DEFINES += -DATMOSPHERE_ARCH_ARM64
export ATMOSPHERE_SETTINGS += -march=armv8-a -mtp=soft
export ATMOSPHERE_SETTINGS += -march=armv8-a+crc+crypto -mtp=soft
export ATMOSPHERE_CFLAGS +=
export ATMOSPHERE_CXXFLAGS +=
export ATMOSPHERE_ASFLAGS +=

View File

@@ -6,7 +6,8 @@ include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../config/common.mk
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
PRECOMPILED_HEADERS := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/include/mesosphere.hpp
#PRECOMPILED_HEADERS := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/include/mesosphere.hpp
PRECOMPILED_HEADERS :=
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_MESOSPHERE
SETTINGS := $(ATMOSPHERE_SETTINGS) -O2 -mgeneral-regs-only -ffixed-x18 -Werror -fno-non-call-exceptions

View File

@@ -20,46 +20,49 @@
#include <vapours.hpp>
/* Libstratosphere-only utility. */
#include "stratosphere/util.hpp"
#include <stratosphere/util.hpp>
/* Sadly required shims. */
#include "stratosphere/svc/svc_stratosphere_shims.hpp"
#include <stratosphere/svc/svc_stratosphere_shims.hpp>
/* Critical modules with no dependencies. */
#include "stratosphere/ams.hpp"
#include "stratosphere/os.hpp"
#include "stratosphere/dd.hpp"
#include "stratosphere/lmem.hpp"
#include "stratosphere/mem.hpp"
#include <stratosphere/ams.hpp>
#include <stratosphere/os.hpp>
#include <stratosphere/dd.hpp>
#include <stratosphere/lmem.hpp>
#include <stratosphere/mem.hpp>
/* Pull in all ID definitions from NCM. */
#include "stratosphere/ncm/ncm_ids.hpp"
#include <stratosphere/ncm/ncm_ids.hpp>
/* At this point, just include the rest alphabetically. */
/* TODO: Figure out optimal order. */
#include "stratosphere/boot2.hpp"
#include "stratosphere/cfg.hpp"
#include "stratosphere/dmnt.hpp"
#include "stratosphere/fatal.hpp"
#include "stratosphere/hid.hpp"
#include "stratosphere/hos.hpp"
#include "stratosphere/kvdb.hpp"
#include "stratosphere/ldr.hpp"
#include "stratosphere/lr.hpp"
#include "stratosphere/map.hpp"
#include "stratosphere/ncm.hpp"
#include "stratosphere/nim.hpp"
#include "stratosphere/patcher.hpp"
#include "stratosphere/pm.hpp"
#include "stratosphere/reg.hpp"
#include "stratosphere/ro.hpp"
#include "stratosphere/settings.hpp"
#include "stratosphere/sf.hpp"
#include "stratosphere/sm.hpp"
#include "stratosphere/spl.hpp"
#include "stratosphere/updater.hpp"
#include <stratosphere/boot2.hpp>
#include <stratosphere/cfg.hpp>
#include <stratosphere/dmnt.hpp>
#include <stratosphere/erpt.hpp>
#include <stratosphere/fatal.hpp>
#include <stratosphere/hid.hpp>
#include <stratosphere/hos.hpp>
#include <stratosphere/kvdb.hpp>
#include <stratosphere/ldr.hpp>
#include <stratosphere/lr.hpp>
#include <stratosphere/map.hpp>
#include <stratosphere/ncm.hpp>
#include <stratosphere/nim.hpp>
#include <stratosphere/patcher.hpp>
#include <stratosphere/psc.hpp>
#include <stratosphere/pm.hpp>
#include <stratosphere/reg.hpp>
#include <stratosphere/ro.hpp>
#include <stratosphere/settings.hpp>
#include <stratosphere/sf.hpp>
#include <stratosphere/sm.hpp>
#include <stratosphere/spl.hpp>
#include <stratosphere/time.hpp>
#include <stratosphere/updater.hpp>
/* Include FS last. */
#include "stratosphere/fs.hpp"
#include "stratosphere/fssrv.hpp"
#include "stratosphere/fssystem.hpp"
#include <stratosphere/fs.hpp>
#include <stratosphere/fssrv.hpp>
#include <stratosphere/fssystem.hpp>

View File

@@ -0,0 +1,25 @@
/*
* 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 <stratosphere/erpt/erpt_ids.autogen.hpp>
#include <stratosphere/erpt/erpt_types.hpp>
#include <stratosphere/erpt/erpt_multiple_category_context.hpp>
#include <stratosphere/erpt/sf/erpt_sf_i_context.hpp>
#include <stratosphere/erpt/sf/erpt_sf_i_session.hpp>
#include <stratosphere/erpt/srv/erpt_srv_types.hpp>
#include <stratosphere/erpt/srv/erpt_srv_api.hpp>

View File

@@ -0,0 +1,780 @@
/*
* 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.hpp>
/* NOTE: This file is auto-generated. */
/* Do not make edits to this file by hand. */
#define AMS_ERPT_FOREACH_FIELD_TYPE(HANDLER) \
HANDLER(FieldType_NumericU64, 0 ) \
HANDLER(FieldType_NumericU32, 1 ) \
HANDLER(FieldType_NumericI64, 2 ) \
HANDLER(FieldType_NumericI32, 3 ) \
HANDLER(FieldType_String, 4 ) \
HANDLER(FieldType_U8Array, 5 ) \
HANDLER(FieldType_U32Array, 6 ) \
HANDLER(FieldType_U64Array, 7 ) \
HANDLER(FieldType_I32Array, 8 ) \
HANDLER(FieldType_I64Array, 9 ) \
HANDLER(FieldType_Bool, 10) \
HANDLER(FieldType_NumericU16, 11) \
HANDLER(FieldType_NumericU8, 12) \
HANDLER(FieldType_NumericI16, 13) \
HANDLER(FieldType_NumericI8, 14) \
HANDLER(FieldType_I8Array, 15) \
#define AMS_ERPT_FOREACH_CATEGORY(HANDLER) \
HANDLER(Test, 0 ) \
HANDLER(ErrorInfo, 1 ) \
HANDLER(ConnectionStatusInfo, 2 ) \
HANDLER(NetworkInfo, 3 ) \
HANDLER(NXMacAddressInfo, 4 ) \
HANDLER(StealthNetworkInfo, 5 ) \
HANDLER(LimitHighCapacityInfo, 6 ) \
HANDLER(NATTypeInfo, 7 ) \
HANDLER(WirelessAPMacAddressInfo, 8 ) \
HANDLER(GlobalIPAddressInfo, 9 ) \
HANDLER(EnableWirelessInterfaceInfo, 10 ) \
HANDLER(EnableWifiInfo, 11 ) \
HANDLER(EnableBluetoothInfo, 12 ) \
HANDLER(EnableNFCInfo, 13 ) \
HANDLER(NintendoZoneSSIDListVersionInfo, 14 ) \
HANDLER(LANAdapterMacAddressInfo, 15 ) \
HANDLER(ApplicationInfo, 16 ) \
HANDLER(OccurrenceInfo, 17 ) \
HANDLER(ProductModelInfo, 18 ) \
HANDLER(CurrentLanguageInfo, 19 ) \
HANDLER(UseNetworkTimeProtocolInfo, 20 ) \
HANDLER(TimeZoneInfo, 21 ) \
HANDLER(ControllerFirmwareInfo, 22 ) \
HANDLER(VideoOutputInfo, 23 ) \
HANDLER(NANDFreeSpaceInfo, 24 ) \
HANDLER(SDCardFreeSpaceInfo, 25 ) \
HANDLER(ScreenBrightnessInfo, 26 ) \
HANDLER(AudioFormatInfo, 27 ) \
HANDLER(MuteOnHeadsetUnpluggedInfo, 28 ) \
HANDLER(NumUserRegisteredInfo, 29 ) \
HANDLER(DataDeletionInfo, 30 ) \
HANDLER(ControllerVibrationInfo, 31 ) \
HANDLER(LockScreenInfo, 32 ) \
HANDLER(InternalBatteryLotNumberInfo, 33 ) \
HANDLER(LeftControllerSerialNumberInfo, 34 ) \
HANDLER(RightControllerSerialNumberInfo, 35 ) \
HANDLER(NotificationInfo, 36 ) \
HANDLER(TVInfo, 37 ) \
HANDLER(SleepInfo, 38 ) \
HANDLER(ConnectionInfo, 39 ) \
HANDLER(NetworkErrorInfo, 40 ) \
HANDLER(FileAccessPathInfo, 41 ) \
HANDLER(GameCardCIDInfo, 42 ) \
HANDLER(NANDCIDInfo, 43 ) \
HANDLER(MicroSDCIDInfo, 44 ) \
HANDLER(NANDSpeedModeInfo, 45 ) \
HANDLER(MicroSDSpeedModeInfo, 46 ) \
HANDLER(GameCardSpeedModeInfo, 47 ) \
HANDLER(UserAccountInternalIDInfo, 48 ) \
HANDLER(NetworkServiceAccountInternalIDInfo, 49 ) \
HANDLER(NintendoAccountInternalIDInfo, 50 ) \
HANDLER(USB3AvailableInfo, 51 ) \
HANDLER(CallStackInfo, 52 ) \
HANDLER(SystemStartupLogInfo, 53 ) \
HANDLER(RegionSettingInfo, 54 ) \
HANDLER(NintendoZoneConnectedInfo, 55 ) \
HANDLER(ForceSleepInfo, 56 ) \
HANDLER(ChargerInfo, 57 ) \
HANDLER(RadioStrengthInfo, 58 ) \
HANDLER(ErrorInfoAuto, 59 ) \
HANDLER(AccessPointInfo, 60 ) \
HANDLER(ErrorInfoDefaults, 61 ) \
HANDLER(SystemPowerStateInfo, 62 ) \
HANDLER(PerformanceInfo, 63 ) \
HANDLER(ThrottlingInfo, 64 ) \
HANDLER(GameCardErrorInfo, 65 ) \
HANDLER(EdidInfo, 66 ) \
HANDLER(ThermalInfo, 67 ) \
HANDLER(CradleFirmwareInfo, 68 ) \
HANDLER(RunningApplicationInfo, 69 ) \
HANDLER(RunningAppletInfo, 70 ) \
HANDLER(FocusedAppletHistoryInfo, 71 ) \
HANDLER(CompositorInfo, 72 ) \
HANDLER(BatteryChargeInfo, 73 ) \
HANDLER(NANDExtendedCsd, 74 ) \
HANDLER(NANDPatrolInfo, 75 ) \
HANDLER(NANDErrorInfo, 76 ) \
HANDLER(NANDDriverLog, 77 ) \
HANDLER(SdCardSizeSpec, 78 ) \
HANDLER(SdCardErrorInfo, 79 ) \
HANDLER(SdCardDriverLog , 80 ) \
HANDLER(FsProxyErrorInfo, 81 ) \
HANDLER(SystemAppletSceneInfo, 82 ) \
HANDLER(VideoInfo, 83 ) \
HANDLER(GpuErrorInfo, 84 ) \
HANDLER(PowerClockInfo, 85 ) \
HANDLER(AdspErrorInfo, 86 ) \
HANDLER(NvDispDeviceInfo, 87 ) \
HANDLER(NvDispDcWindowInfo, 88 ) \
HANDLER(NvDispDpModeInfo, 89 ) \
HANDLER(NvDispDpLinkSpec, 90 ) \
HANDLER(NvDispDpLinkStatus, 91 ) \
HANDLER(NvDispDpHdcpInfo, 92 ) \
HANDLER(NvDispDpAuxCecInfo, 93 ) \
HANDLER(NvDispDcInfo, 94 ) \
HANDLER(NvDispDsiInfo, 95 ) \
HANDLER(NvDispErrIDInfo, 96 ) \
HANDLER(SdCardMountInfo, 97 ) \
HANDLER(RetailInteractiveDisplayInfo, 98 ) \
HANDLER(CompositorStateInfo, 99 ) \
HANDLER(CompositorLayerInfo, 100) \
HANDLER(CompositorDisplayInfo, 101) \
HANDLER(CompositorHWCInfo, 102) \
HANDLER(MonitorCapability, 103) \
HANDLER(ErrorReportSharePermissionInfo, 104) \
HANDLER(MultimediaInfo, 105) \
HANDLER(ConnectedControllerInfo, 106) \
HANDLER(FsMemoryInfo, 107) \
HANDLER(UserClockContextInfo, 108) \
HANDLER(NetworkClockContextInfo, 109) \
HANDLER(AcpGeneralSettingsInfo, 110) \
HANDLER(AcpPlayLogSettingsInfo, 111) \
HANDLER(AcpAocSettingsInfo, 112) \
HANDLER(AcpBcatSettingsInfo, 113) \
HANDLER(AcpStorageSettingsInfo, 114) \
HANDLER(AcpRatingSettingsInfo, 115) \
HANDLER(MonitorSettings, 116) \
HANDLER(RebootlessSystemUpdateVersionInfo, 117) \
HANDLER(NifmConnectionTestInfo, 118) \
HANDLER(PcieLoggedStateInfo, 119) \
HANDLER(NetworkSecurityCertificateInfo, 120) \
HANDLER(AcpNeighborDetectionInfo, 121) \
HANDLER(GpuCrashInfo, 122) \
HANDLER(UsbStateInfo, 123) \
HANDLER(NvHostErrInfo, 124) \
HANDLER(RunningUlaInfo, 125) \
#define AMS_ERPT_FOREACH_FIELD(HANDLER) \
HANDLER(TestU64, 0, Test, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(TestU32, 1, Test, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(TestI64, 2, Test, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(TestI32, 3, Test, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(TestString, 4, Test, FieldType_String, FieldFlag_None ) \
HANDLER(TestU8Array, 5, Test, FieldType_U8Array, FieldFlag_None ) \
HANDLER(TestU32Array, 6, Test, FieldType_U32Array, FieldFlag_None ) \
HANDLER(TestU64Array, 7, Test, FieldType_U64Array, FieldFlag_None ) \
HANDLER(TestI32Array, 8, Test, FieldType_I32Array, FieldFlag_None ) \
HANDLER(TestI64Array, 9, Test, FieldType_I64Array, FieldFlag_None ) \
HANDLER(ErrorCode, 10, ErrorInfo, FieldType_String, FieldFlag_None ) \
HANDLER(ErrorDescription, 11, ErrorInfo, FieldType_String, FieldFlag_None ) \
HANDLER(OccurrenceTimestamp, 12, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(ReportIdentifier, 13, ErrorInfoAuto, FieldType_String, FieldFlag_None ) \
HANDLER(ConnectionStatus, 14, ConnectionStatusInfo, FieldType_String, FieldFlag_None ) \
HANDLER(AccessPointSSID, 15, AccessPointInfo, FieldType_String, FieldFlag_None ) \
HANDLER(AccessPointSecurityType, 16, AccessPointInfo, FieldType_String, FieldFlag_None ) \
HANDLER(RadioStrength, 17, RadioStrengthInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NXMacAddress, 18, NXMacAddressInfo, FieldType_String, FieldFlag_None ) \
HANDLER(IPAddressAcquisitionMethod, 19, NetworkInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(CurrentIPAddress, 20, NetworkInfo, FieldType_String, FieldFlag_None ) \
HANDLER(SubnetMask, 21, NetworkInfo, FieldType_String, FieldFlag_None ) \
HANDLER(GatewayIPAddress, 22, NetworkInfo, FieldType_String, FieldFlag_None ) \
HANDLER(DNSType, 23, NetworkInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(PriorityDNSIPAddress, 24, NetworkInfo, FieldType_String, FieldFlag_None ) \
HANDLER(AlternateDNSIPAddress, 25, NetworkInfo, FieldType_String, FieldFlag_None ) \
HANDLER(UseProxyFlag, 26, NetworkInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(ProxyIPAddress, 27, NetworkInfo, FieldType_String, FieldFlag_None ) \
HANDLER(ProxyPort, 28, NetworkInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(ProxyAutoAuthenticateFlag, 29, NetworkInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(MTU, 30, NetworkInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(ConnectAutomaticallyFlag, 31, NetworkInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(UseStealthNetworkFlag, 32, StealthNetworkInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(LimitHighCapacityFlag, 33, LimitHighCapacityInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NATType, 34, NATTypeInfo, FieldType_String, FieldFlag_None ) \
HANDLER(WirelessAPMacAddress, 35, WirelessAPMacAddressInfo, FieldType_String, FieldFlag_None ) \
HANDLER(GlobalIPAddress, 36, GlobalIPAddressInfo, FieldType_String, FieldFlag_None ) \
HANDLER(EnableWirelessInterfaceFlag, 37, EnableWirelessInterfaceInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(EnableWifiFlag, 38, EnableWifiInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(EnableBluetoothFlag, 39, EnableBluetoothInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(EnableNFCFlag, 40, EnableNFCInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NintendoZoneSSIDListVersion, 41, NintendoZoneSSIDListVersionInfo, FieldType_String, FieldFlag_None ) \
HANDLER(LANAdapterMacAddress, 42, LANAdapterMacAddressInfo, FieldType_String, FieldFlag_None ) \
HANDLER(ApplicationID, 43, ApplicationInfo, FieldType_String, FieldFlag_None ) \
HANDLER(ApplicationTitle, 44, ApplicationInfo, FieldType_String, FieldFlag_None ) \
HANDLER(ApplicationVersion, 45, ApplicationInfo, FieldType_String, FieldFlag_None ) \
HANDLER(ApplicationStorageLocation, 46, ApplicationInfo, FieldType_String, FieldFlag_None ) \
HANDLER(DownloadContentType, 47, OccurrenceInfo, FieldType_String, FieldFlag_None ) \
HANDLER(InstallContentType, 48, OccurrenceInfo, FieldType_String, FieldFlag_None ) \
HANDLER(ConsoleStartingUpFlag, 49, OccurrenceInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(SystemStartingUpFlag, 50, OccurrenceInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(ConsoleFirstInitFlag, 51, OccurrenceInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(HomeMenuScreenDisplayedFlag, 52, OccurrenceInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(DataManagementScreenDisplayedFlag, 53, OccurrenceInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(ConnectionTestingFlag, 54, OccurrenceInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(ApplicationRunningFlag, 55, OccurrenceInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(DataCorruptionDetectedFlag, 56, OccurrenceInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(ProductModel, 57, ProductModelInfo, FieldType_String, FieldFlag_None ) \
HANDLER(CurrentLanguage, 58, CurrentLanguageInfo, FieldType_String, FieldFlag_None ) \
HANDLER(UseNetworkTimeProtocolFlag, 59, UseNetworkTimeProtocolInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(TimeZone, 60, TimeZoneInfo, FieldType_String, FieldFlag_None ) \
HANDLER(ControllerFirmware, 61, ControllerFirmwareInfo, FieldType_String, FieldFlag_None ) \
HANDLER(VideoOutputSetting, 62, VideoOutputInfo, FieldType_String, FieldFlag_None ) \
HANDLER(NANDFreeSpace, 63, NANDFreeSpaceInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(SDCardFreeSpace, 64, SDCardFreeSpaceInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(SerialNumber, 65, ErrorInfoAuto, FieldType_String, FieldFlag_None ) \
HANDLER(OsVersion, 66, ErrorInfoAuto, FieldType_String, FieldFlag_None ) \
HANDLER(ScreenBrightnessAutoAdjustFlag, 67, ScreenBrightnessInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(HdmiAudioOutputMode, 68, AudioFormatInfo, FieldType_String, FieldFlag_None ) \
HANDLER(SpeakerAudioOutputMode, 69, AudioFormatInfo, FieldType_String, FieldFlag_None ) \
HANDLER(HeadphoneAudioOutputMode, 70, AudioFormatInfo, FieldType_String, FieldFlag_None ) \
HANDLER(MuteOnHeadsetUnpluggedFlag, 71, MuteOnHeadsetUnpluggedInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NumUserRegistered, 72, NumUserRegisteredInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(StorageAutoOrganizeFlag, 73, DataDeletionInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(ControllerVibrationVolume, 74, ControllerVibrationInfo, FieldType_String, FieldFlag_None ) \
HANDLER(LockScreenFlag, 75, LockScreenInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(InternalBatteryLotNumber, 76, InternalBatteryLotNumberInfo, FieldType_String, FieldFlag_None ) \
HANDLER(LeftControllerSerialNumber, 77, LeftControllerSerialNumberInfo, FieldType_String, FieldFlag_None ) \
HANDLER(RightControllerSerialNumber, 78, RightControllerSerialNumberInfo, FieldType_String, FieldFlag_None ) \
HANDLER(NotifyInGameDownloadCompletionFlag, 79, NotificationInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NotificationSoundFlag, 80, NotificationInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(TVResolutionSetting, 81, TVInfo, FieldType_String, FieldFlag_None ) \
HANDLER(RGBRangeSetting, 82, TVInfo, FieldType_String, FieldFlag_None ) \
HANDLER(ReduceScreenBurnFlag, 83, TVInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(TVAllowsCecFlag, 84, TVInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(HandheldModeTimeToScreenSleep, 85, SleepInfo, FieldType_String, FieldFlag_None ) \
HANDLER(ConsoleModeTimeToScreenSleep, 86, SleepInfo, FieldType_String, FieldFlag_None ) \
HANDLER(StopAutoSleepDuringContentPlayFlag, 87, SleepInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(LastConnectionTestDownloadSpeed, 88, ConnectionInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(LastConnectionTestUploadSpeed, 89, ConnectionInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(DEPRECATED_ServerFQDN, 90, NetworkErrorInfo, FieldType_String, FieldFlag_None ) \
HANDLER(HTTPRequestContents, 91, NetworkErrorInfo, FieldType_String, FieldFlag_None ) \
HANDLER(HTTPRequestResponseContents, 92, NetworkErrorInfo, FieldType_String, FieldFlag_None ) \
HANDLER(EdgeServerIPAddress, 93, NetworkErrorInfo, FieldType_String, FieldFlag_None ) \
HANDLER(CDNContentPath, 94, NetworkErrorInfo, FieldType_String, FieldFlag_None ) \
HANDLER(FileAccessPath, 95, FileAccessPathInfo, FieldType_String, FieldFlag_None ) \
HANDLER(GameCardCID, 96, GameCardCIDInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(NANDCID, 97, NANDCIDInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(MicroSDCID, 98, MicroSDCIDInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(NANDSpeedMode, 99, NANDSpeedModeInfo, FieldType_String, FieldFlag_None ) \
HANDLER(MicroSDSpeedMode, 100, MicroSDSpeedModeInfo, FieldType_String, FieldFlag_None ) \
HANDLER(GameCardSpeedMode, 101, GameCardSpeedModeInfo, FieldType_String, FieldFlag_None ) \
HANDLER(UserAccountInternalID, 102, UserAccountInternalIDInfo, FieldType_String, FieldFlag_None ) \
HANDLER(NetworkServiceAccountInternalID, 103, NetworkServiceAccountInternalIDInfo, FieldType_String, FieldFlag_None ) \
HANDLER(NintendoAccountInternalID, 104, NintendoAccountInternalIDInfo, FieldType_String, FieldFlag_None ) \
HANDLER(USB3AvailableFlag, 105, USB3AvailableInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(CallStack, 106, CallStackInfo, FieldType_String, FieldFlag_None ) \
HANDLER(SystemStartupLog, 107, SystemStartupLogInfo, FieldType_String, FieldFlag_None ) \
HANDLER(RegionSetting, 108, RegionSettingInfo, FieldType_String, FieldFlag_None ) \
HANDLER(NintendoZoneConnectedFlag, 109, NintendoZoneConnectedInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(ForcedSleepHighTemperatureReading, 110, ForceSleepInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(ForcedSleepFanSpeedReading, 111, ForceSleepInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(ForcedSleepHWInfo, 112, ForceSleepInfo, FieldType_String, FieldFlag_None ) \
HANDLER(AbnormalPowerStateInfo, 113, ChargerInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(ScreenBrightnessLevel, 114, ScreenBrightnessInfo, FieldType_String, FieldFlag_None ) \
HANDLER(ProgramId, 115, ErrorInfo, FieldType_String, FieldFlag_None ) \
HANDLER(AbortFlag, 116, ErrorInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(ReportVisibilityFlag, 117, ErrorInfoAuto, FieldType_Bool, FieldFlag_None ) \
HANDLER(FatalFlag, 118, ErrorInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(OccurrenceTimestampNet, 119, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(ResultBacktrace, 120, ErrorInfo, FieldType_U32Array, FieldFlag_None ) \
HANDLER(GeneralRegisterAarch32, 121, ErrorInfo, FieldType_U32Array, FieldFlag_None ) \
HANDLER(StackBacktrace32, 122, ErrorInfo, FieldType_U32Array, FieldFlag_None ) \
HANDLER(ExceptionInfoAarch32, 123, ErrorInfo, FieldType_U32Array, FieldFlag_None ) \
HANDLER(GeneralRegisterAarch64, 124, ErrorInfo, FieldType_U64Array, FieldFlag_None ) \
HANDLER(ExceptionInfoAarch64, 125, ErrorInfo, FieldType_U64Array, FieldFlag_None ) \
HANDLER(StackBacktrace64, 126, ErrorInfo, FieldType_U64Array, FieldFlag_None ) \
HANDLER(RegisterSetFlag32, 127, ErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(RegisterSetFlag64, 128, ErrorInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(ProgramMappedAddr32, 129, ErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(ProgramMappedAddr64, 130, ErrorInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(AbortType, 131, ErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(PrivateOsVersion, 132, ErrorInfoAuto, FieldType_String, FieldFlag_None ) \
HANDLER(CurrentSystemPowerState, 133, SystemPowerStateInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(PreviousSystemPowerState, 134, SystemPowerStateInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(DestinationSystemPowerState, 135, SystemPowerStateInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(PscTransitionCurrentState, 136, ErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(PscTransitionPreviousState, 137, ErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(PscInitializedList, 138, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(PscCurrentPmStateList, 139, ErrorInfo, FieldType_U32Array, FieldFlag_None ) \
HANDLER(PscNextPmStateList, 140, ErrorInfo, FieldType_U32Array, FieldFlag_None ) \
HANDLER(PerformanceMode, 141, PerformanceInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(PerformanceConfiguration, 142, PerformanceInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(Throttled, 143, ThrottlingInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(ThrottlingDuration, 144, ThrottlingInfo, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(ThrottlingTimestamp, 145, ThrottlingInfo, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(GameCardCrcErrorCount, 146, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(GameCardAsicCrcErrorCount, 147, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(GameCardRefreshCount, 148, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(GameCardReadRetryCount, 149, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(EdidBlock, 150, EdidInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(EdidExtensionBlock, 151, EdidInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(CreateProcessFailureFlag, 152, ErrorInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(TemperaturePcb, 153, ThermalInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(TemperatureSoc, 154, ThermalInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(CurrentFanDuty, 155, ThermalInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(LastDvfsThresholdTripped, 156, ThermalInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(CradlePdcHFwVersion, 157, CradleFirmwareInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(CradlePdcAFwVersion, 158, CradleFirmwareInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(CradleMcuFwVersion, 159, CradleFirmwareInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(CradleDp2HdmiFwVersion, 160, CradleFirmwareInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(RunningApplicationId, 161, RunningApplicationInfo, FieldType_String, FieldFlag_None ) \
HANDLER(RunningApplicationTitle, 162, RunningApplicationInfo, FieldType_String, FieldFlag_None ) \
HANDLER(RunningApplicationVersion, 163, RunningApplicationInfo, FieldType_String, FieldFlag_None ) \
HANDLER(RunningApplicationStorageLocation, 164, RunningApplicationInfo, FieldType_String, FieldFlag_None ) \
HANDLER(RunningAppletList, 165, RunningAppletInfo, FieldType_U64Array, FieldFlag_None ) \
HANDLER(FocusedAppletHistory, 166, FocusedAppletHistoryInfo, FieldType_U64Array, FieldFlag_None ) \
HANDLER(CompositorState, 167, CompositorStateInfo, FieldType_String, FieldFlag_None ) \
HANDLER(CompositorLayerState, 168, CompositorLayerInfo, FieldType_String, FieldFlag_None ) \
HANDLER(CompositorDisplayState, 169, CompositorDisplayInfo, FieldType_String, FieldFlag_None ) \
HANDLER(CompositorHWCState, 170, CompositorHWCInfo, FieldType_String, FieldFlag_None ) \
HANDLER(InputCurrentLimit, 171, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(BoostModeCurrentLimit, 172, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(FastChargeCurrentLimit, 173, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(ChargeVoltageLimit, 174, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(ChargeConfiguration, 175, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(HizMode, 176, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(ChargeEnabled, 177, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(PowerSupplyPath, 178, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(BatteryTemperature, 179, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(BatteryChargePercent, 180, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(BatteryChargeVoltage, 181, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(BatteryAge, 182, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(PowerRole, 183, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(PowerSupplyType, 184, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(PowerSupplyVoltage, 185, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(PowerSupplyCurrent, 186, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(FastBatteryChargingEnabled, 187, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(ControllerPowerSupplyAcquired, 188, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(OtgRequested, 189, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NANDPreEolInfo, 190, NANDExtendedCsd, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NANDDeviceLifeTimeEstTypA, 191, NANDExtendedCsd, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NANDDeviceLifeTimeEstTypB, 192, NANDExtendedCsd, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NANDPatrolCount, 193, NANDPatrolInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NANDNumActivationFailures, 194, NANDErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NANDNumActivationErrorCorrections, 195, NANDErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NANDNumReadWriteFailures, 196, NANDErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NANDNumReadWriteErrorCorrections, 197, NANDErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NANDErrorLog, 198, NANDDriverLog, FieldType_String, FieldFlag_None ) \
HANDLER(SdCardUserAreaSize, 199, SdCardSizeSpec, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(SdCardProtectedAreaSize, 200, SdCardSizeSpec, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(SdCardNumActivationFailures, 201, SdCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(SdCardNumActivationErrorCorrections, 202, SdCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(SdCardNumReadWriteFailures, 203, SdCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(SdCardNumReadWriteErrorCorrections, 204, SdCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(SdCardErrorLog, 205, SdCardDriverLog , FieldType_String, FieldFlag_None ) \
HANDLER(EncryptionKey, 206, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(EncryptedExceptionInfo, 207, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(GameCardTimeoutRetryErrorCount, 208, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(FsRemountForDataCorruptCount, 209, FsProxyErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(FsRemountForDataCorruptRetryOutCount, 210, FsProxyErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(GameCardInsertionCount, 211, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(GameCardRemovalCount, 212, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(GameCardAsicInitializeCount, 213, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(TestU16, 214, Test, FieldType_NumericU16, FieldFlag_None ) \
HANDLER(TestU8, 215, Test, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(TestI16, 216, Test, FieldType_NumericI16, FieldFlag_None ) \
HANDLER(TestI8, 217, Test, FieldType_NumericI8, FieldFlag_None ) \
HANDLER(SystemAppletScene, 218, SystemAppletSceneInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(CodecType, 219, VideoInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(DecodeBuffers, 220, VideoInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(FrameWidth, 221, VideoInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(FrameHeight, 222, VideoInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(ColorPrimaries, 223, VideoInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(TransferCharacteristics, 224, VideoInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(MatrixCoefficients, 225, VideoInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(DisplayWidth, 226, VideoInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(DisplayHeight, 227, VideoInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(DARWidth, 228, VideoInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(DARHeight, 229, VideoInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(ColorFormat, 230, VideoInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(ColorSpace, 231, VideoInfo, FieldType_String, FieldFlag_None ) \
HANDLER(SurfaceLayout, 232, VideoInfo, FieldType_String, FieldFlag_None ) \
HANDLER(BitStream, 233, VideoInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(VideoDecState, 234, VideoInfo, FieldType_String, FieldFlag_None ) \
HANDLER(GpuErrorChannelId, 235, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(GpuErrorAruId, 236, GpuErrorInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(GpuErrorType, 237, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(GpuErrorFaultInfo, 238, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(GpuErrorWriteAccess, 239, GpuErrorInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(GpuErrorFaultAddress, 240, GpuErrorInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(GpuErrorFaultUnit, 241, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(GpuErrorFaultType, 242, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(GpuErrorHwContextPointer, 243, GpuErrorInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(GpuErrorContextStatus, 244, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(GpuErrorPbdmaIntr, 245, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(GpuErrorPbdmaErrorType, 246, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(GpuErrorPbdmaHeaderShadow, 247, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(GpuErrorPbdmaHeader, 248, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(GpuErrorPbdmaGpShadow0, 249, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(GpuErrorPbdmaGpShadow1, 250, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(AccessPointChannel, 251, AccessPointInfo, FieldType_NumericU16, FieldFlag_None ) \
HANDLER(ThreadName, 252, ErrorInfo, FieldType_String, FieldFlag_None ) \
HANDLER(AdspExceptionRegisters, 253, AdspErrorInfo, FieldType_U32Array, FieldFlag_None ) \
HANDLER(AdspExceptionSpsr, 254, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(AdspExceptionProgramCounter, 255, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(AdspExceptionLinkRegister, 256, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(AdspExceptionStackPointer, 257, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(AdspExceptionArmModeRegisters, 258, AdspErrorInfo, FieldType_U32Array, FieldFlag_None ) \
HANDLER(AdspExceptionStackAddress, 259, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(AdspExceptionStackDump, 260, AdspErrorInfo, FieldType_U32Array, FieldFlag_None ) \
HANDLER(AdspExceptionReason, 261, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(OscillatorClock, 262, PowerClockInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(CpuDvfsTableClocks, 263, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \
HANDLER(CpuDvfsTableVoltages, 264, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \
HANDLER(GpuDvfsTableClocks, 265, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \
HANDLER(GpuDvfsTableVoltages, 266, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \
HANDLER(EmcDvfsTableClocks, 267, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \
HANDLER(EmcDvfsTableVoltages, 268, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \
HANDLER(ModuleClockFrequencies, 269, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \
HANDLER(ModuleClockEnableFlags, 270, PowerClockInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(ModulePowerEnableFlags, 271, PowerClockInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(ModuleResetAssertFlags, 272, PowerClockInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(ModuleMinimumVoltageClockRates, 273, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \
HANDLER(PowerDomainEnableFlags, 274, PowerClockInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(PowerDomainVoltages, 275, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \
HANDLER(AccessPointRssi, 276, RadioStrengthInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(FuseInfo, 277, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \
HANDLER(VideoLog, 278, VideoInfo, FieldType_String, FieldFlag_None ) \
HANDLER(GameCardDeviceId, 279, GameCardCIDInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(GameCardAsicReinitializeCount, 280, GameCardErrorInfo, FieldType_NumericU16, FieldFlag_None ) \
HANDLER(GameCardAsicReinitializeFailureCount, 281, GameCardErrorInfo, FieldType_NumericU16, FieldFlag_None ) \
HANDLER(GameCardAsicReinitializeFailureDetail, 282, GameCardErrorInfo, FieldType_NumericU16, FieldFlag_None ) \
HANDLER(GameCardRefreshSuccessCount, 283, GameCardErrorInfo, FieldType_NumericU16, FieldFlag_None ) \
HANDLER(GameCardAwakenCount, 284, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(GameCardAwakenFailureCount, 285, GameCardErrorInfo, FieldType_NumericU16, FieldFlag_None ) \
HANDLER(GameCardReadCountFromInsert, 286, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(GameCardReadCountFromAwaken, 287, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(GameCardLastReadErrorPageAddress, 288, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(GameCardLastReadErrorPageCount, 289, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(AppletManagerContextTrace, 290, ErrorInfo, FieldType_I32Array, FieldFlag_None ) \
HANDLER(NvDispIsRegistered, 291, NvDispDeviceInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispIsSuspend, 292, NvDispDeviceInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispDC0SurfaceNum, 293, NvDispDeviceInfo, FieldType_I32Array, FieldFlag_None ) \
HANDLER(NvDispDC1SurfaceNum, 294, NvDispDeviceInfo, FieldType_I32Array, FieldFlag_None ) \
HANDLER(NvDispWindowSrcRectX, 295, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispWindowSrcRectY, 296, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispWindowSrcRectWidth, 297, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispWindowSrcRectHeight, 298, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispWindowDstRectX, 299, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispWindowDstRectY, 300, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispWindowDstRectWidth, 301, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispWindowDstRectHeight, 302, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispWindowIndex, 303, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispWindowBlendOperation, 304, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispWindowAlphaOperation, 305, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispWindowDepth, 306, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispWindowAlpha, 307, NvDispDcWindowInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(NvDispWindowHFilter, 308, NvDispDcWindowInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispWindowVFilter, 309, NvDispDcWindowInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispWindowOptions, 310, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispWindowSyncPointId, 311, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDPSorPower, 312, NvDispDpModeInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispDPClkType, 313, NvDispDpModeInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(NvDispDPEnable, 314, NvDispDpModeInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDPState, 315, NvDispDpModeInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDPEdid, 316, NvDispDpModeInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(NvDispDPEdidSize, 317, NvDispDpModeInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDPEdidExtSize, 318, NvDispDpModeInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDPFakeMode, 319, NvDispDpModeInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispDPModeNumber, 320, NvDispDpModeInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDPPlugInOut, 321, NvDispDpModeInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispDPAuxIntHandler, 322, NvDispDpModeInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispDPForceMaxLinkBW, 323, NvDispDpModeInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispDPIsConnected, 324, NvDispDpModeInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispDPLinkValid, 325, NvDispDpLinkSpec, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispDPLinkMaxBW, 326, NvDispDpLinkSpec, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(NvDispDPLinkMaxLaneCount, 327, NvDispDpLinkSpec, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(NvDispDPLinkDownSpread, 328, NvDispDpLinkSpec, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispDPLinkSupportEnhancedFraming, 329, NvDispDpLinkSpec, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispDPLinkBpp, 330, NvDispDpLinkSpec, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDPLinkScaramberCap, 331, NvDispDpLinkSpec, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispDPLinkBW, 332, NvDispDpLinkStatus, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(NvDispDPLinkLaneCount, 333, NvDispDpLinkStatus, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(NvDispDPLinkEnhancedFraming, 334, NvDispDpLinkStatus, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispDPLinkScrambleEnable, 335, NvDispDpLinkStatus, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispDPLinkActivePolarity, 336, NvDispDpLinkStatus, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDPLinkActiveCount, 337, NvDispDpLinkStatus, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDPLinkTUSize, 338, NvDispDpLinkStatus, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDPLinkActiveFrac, 339, NvDispDpLinkStatus, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDPLinkWatermark, 340, NvDispDpLinkStatus, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDPLinkHBlank, 341, NvDispDpLinkStatus, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDPLinkVBlank, 342, NvDispDpLinkStatus, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDPLinkOnlyEnhancedFraming, 343, NvDispDpLinkStatus, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispDPLinkOnlyEdpCap, 344, NvDispDpLinkStatus, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispDPLinkSupportFastLT, 345, NvDispDpLinkStatus, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispDPLinkLTDataValid, 346, NvDispDpLinkStatus, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispDPLinkTsp3Support, 347, NvDispDpLinkStatus, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispDPLinkAuxInterval, 348, NvDispDpLinkStatus, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(NvDispHdcpCreated, 349, NvDispDpHdcpInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispHdcpUserRequest, 350, NvDispDpHdcpInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispHdcpPlugged, 351, NvDispDpHdcpInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispHdcpState, 352, NvDispDpHdcpInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispHdcpFailCount, 353, NvDispDpHdcpInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(NvDispHdcpHdcp22, 354, NvDispDpHdcpInfo, FieldType_NumericI8, FieldFlag_None ) \
HANDLER(NvDispHdcpMaxRetry, 355, NvDispDpHdcpInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(NvDispHdcpHpd, 356, NvDispDpHdcpInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(NvDispHdcpRepeater, 357, NvDispDpHdcpInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(NvDispCecRxBuf, 358, NvDispDpAuxCecInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(NvDispCecRxLength, 359, NvDispDpAuxCecInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(NvDispCecTxBuf, 360, NvDispDpAuxCecInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(NvDispCecTxLength, 361, NvDispDpAuxCecInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(NvDispCecTxRet, 362, NvDispDpAuxCecInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(NvDispCecState, 363, NvDispDpAuxCecInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispCecTxInfo, 364, NvDispDpAuxCecInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(NvDispCecRxInfo, 365, NvDispDpAuxCecInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(NvDispDCIndex, 366, NvDispDcInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDCInitialize, 367, NvDispDcInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispDCClock, 368, NvDispDcInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispDCFrequency, 369, NvDispDcInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDCFailed, 370, NvDispDcInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispDCModeWidth, 371, NvDispDcInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(NvDispDCModeHeight, 372, NvDispDcInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(NvDispDCModeBpp, 373, NvDispDcInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDCPanelFrequency, 374, NvDispDcInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDCWinDirty, 375, NvDispDcInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDCWinEnable, 376, NvDispDcInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDCVrr, 377, NvDispDcInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispDCPanelInitialize, 378, NvDispDcInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispDsiDataFormat, 379, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDsiVideoMode, 380, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDsiRefreshRate, 381, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDsiLpCmdModeFrequency, 382, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDsiHsCmdModeFrequency, 383, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDsiPanelResetTimeout, 384, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDsiPhyFrequency, 385, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDsiFrequency, 386, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDsiInstance, 387, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDcDsiHostCtrlEnable, 388, NvDispDsiInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispDcDsiInit, 389, NvDispDsiInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispDcDsiEnable, 390, NvDispDsiInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispDcDsiHsMode, 391, NvDispDsiInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispDcDsiVendorId, 392, NvDispDsiInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(NvDispDcDsiLcdVendorNum, 393, NvDispDsiInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(NvDispDcDsiHsClockControl, 394, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDcDsiEnableHsClockInLpMode, 395, NvDispDsiInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispDcDsiTeFrameUpdate, 396, NvDispDsiInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispDcDsiGangedType, 397, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispDcDsiHbpInPktSeq, 398, NvDispDsiInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NvDispErrID, 399, NvDispErrIDInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispErrData0, 400, NvDispErrIDInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvDispErrData1, 401, NvDispErrIDInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(SdCardMountStatus, 402, SdCardMountInfo, FieldType_String, FieldFlag_None ) \
HANDLER(SdCardMountUnexpectedResult, 403, SdCardMountInfo, FieldType_String, FieldFlag_None ) \
HANDLER(NANDTotalSize, 404, NANDFreeSpaceInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(SdCardTotalSize, 405, SDCardFreeSpaceInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(ElapsedTimeSinceInitialLaunch, 406, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(ElapsedTimeSincePowerOn, 407, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(ElapsedTimeSinceLastAwake, 408, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(OccurrenceTick, 409, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(RetailInteractiveDisplayFlag, 410, RetailInteractiveDisplayInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(FatFsError, 411, FsProxyErrorInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(FatFsExtraError, 412, FsProxyErrorInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(FatFsErrorDrive, 413, FsProxyErrorInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(FatFsErrorName, 414, FsProxyErrorInfo, FieldType_String, FieldFlag_None ) \
HANDLER(MonitorManufactureCode, 415, MonitorCapability, FieldType_String, FieldFlag_None ) \
HANDLER(MonitorProductCode, 416, MonitorCapability, FieldType_NumericU16, FieldFlag_None ) \
HANDLER(MonitorSerialNumber, 417, MonitorCapability, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(MonitorManufactureYear, 418, MonitorCapability, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(PhysicalAddress, 419, MonitorCapability, FieldType_NumericU16, FieldFlag_None ) \
HANDLER(Is4k60Hz, 420, MonitorCapability, FieldType_Bool, FieldFlag_None ) \
HANDLER(Is4k30Hz, 421, MonitorCapability, FieldType_Bool, FieldFlag_None ) \
HANDLER(Is1080P60Hz, 422, MonitorCapability, FieldType_Bool, FieldFlag_None ) \
HANDLER(Is720P60Hz, 423, MonitorCapability, FieldType_Bool, FieldFlag_None ) \
HANDLER(PcmChannelMax, 424, MonitorCapability, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(CrashReportHash, 425, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(ErrorReportSharePermission, 426, ErrorReportSharePermissionInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(VideoCodecTypeEnum, 427, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(VideoBitRate, 428, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(VideoFrameRate, 429, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(VideoWidth, 430, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(VideoHeight, 431, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(AudioCodecTypeEnum, 432, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(AudioSampleRate, 433, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(AudioChannelCount, 434, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(AudioBitRate, 435, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(MultimediaContainerType, 436, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(MultimediaProfileType, 437, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(MultimediaLevelType, 438, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(MultimediaCacheSizeEnum, 439, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(MultimediaErrorStatusEnum, 440, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(MultimediaErrorLog, 441, MultimediaInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(ServerFqdn, 442, ErrorInfo, FieldType_String, FieldFlag_None ) \
HANDLER(ServerIpAddress, 443, ErrorInfo, FieldType_String, FieldFlag_None ) \
HANDLER(TestStringEncrypt, 444, Test, FieldType_String, FieldFlag_Encrypt) \
HANDLER(TestU8ArrayEncrypt, 445, Test, FieldType_U8Array, FieldFlag_Encrypt) \
HANDLER(TestU32ArrayEncrypt, 446, Test, FieldType_U32Array, FieldFlag_Encrypt) \
HANDLER(TestU64ArrayEncrypt, 447, Test, FieldType_U64Array, FieldFlag_Encrypt) \
HANDLER(TestI32ArrayEncrypt, 448, Test, FieldType_I32Array, FieldFlag_Encrypt) \
HANDLER(TestI64ArrayEncrypt, 449, Test, FieldType_I64Array, FieldFlag_Encrypt) \
HANDLER(CipherKey, 450, ErrorInfoAuto, FieldType_U8Array, FieldFlag_None ) \
HANDLER(FileSystemPath, 451, ErrorInfo, FieldType_String, FieldFlag_Encrypt) \
HANDLER(WebMediaPlayerOpenUrl, 452, ErrorInfo, FieldType_String, FieldFlag_Encrypt) \
HANDLER(WebMediaPlayerLastSocketErrors, 453, ErrorInfo, FieldType_I32Array, FieldFlag_None ) \
HANDLER(UnknownControllerCount, 454, ConnectedControllerInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(AttachedControllerCount, 455, ConnectedControllerInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(BluetoothControllerCount, 456, ConnectedControllerInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(UsbControllerCount, 457, ConnectedControllerInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(ControllerTypeList, 458, ConnectedControllerInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(ControllerInterfaceList, 459, ConnectedControllerInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(ControllerStyleList, 460, ConnectedControllerInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(FsPooledBufferPeakFreeSize, 461, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(FsPooledBufferRetriedCount, 462, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(FsPooledBufferReduceAllocationCount, 463, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(FsBufferManagerPeakFreeSize, 464, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(FsBufferManagerRetriedCount, 465, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(FsExpHeapPeakFreeSize, 466, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(FsBufferPoolPeakFreeSize, 467, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(FsPatrolReadAllocateBufferSuccessCount, 468, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(FsPatrolReadAllocateBufferFailureCount, 469, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(SteadyClockInternalOffset, 470, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(SteadyClockCurrentTimePointValue, 471, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(UserClockContextOffset, 472, UserClockContextInfo, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(UserClockContextTimeStampValue, 473, UserClockContextInfo, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(NetworkClockContextOffset, 474, NetworkClockContextInfo, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(NetworkClockContextTimeStampValue, 475, NetworkClockContextInfo, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(SystemAbortFlag, 476, ErrorInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(ApplicationAbortFlag, 477, ErrorInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(NifmErrorCode, 478, ConnectionStatusInfo, FieldType_String, FieldFlag_None ) \
HANDLER(LcsApplicationId, 479, ErrorInfo, FieldType_String, FieldFlag_None ) \
HANDLER(LcsContentMetaKeyIdList, 480, ErrorInfo, FieldType_U64Array, FieldFlag_None ) \
HANDLER(LcsContentMetaKeyVersionList, 481, ErrorInfo, FieldType_U32Array, FieldFlag_None ) \
HANDLER(LcsContentMetaKeyTypeList, 482, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(LcsContentMetaKeyInstallTypeList, 483, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(LcsSenderFlag, 484, ErrorInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(LcsApplicationRequestFlag, 485, ErrorInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(LcsHasExFatDriverFlag, 486, ErrorInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(LcsIpAddress, 487, ErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(AcpStartupUserAccount, 488, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(AcpAocRegistrationType, 489, AcpAocSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(AcpAttributeFlag, 490, AcpGeneralSettingsInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(AcpSupportedLanguageFlag, 491, AcpGeneralSettingsInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(AcpParentalControlFlag, 492, AcpGeneralSettingsInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(AcpScreenShot, 493, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(AcpVideoCapture, 494, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(AcpDataLossConfirmation, 495, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(AcpPlayLogPolicy, 496, AcpPlayLogSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(AcpPresenceGroupId, 497, AcpGeneralSettingsInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(AcpRatingAge, 498, AcpRatingSettingsInfo, FieldType_I8Array, FieldFlag_None ) \
HANDLER(AcpAocBaseId, 499, AcpAocSettingsInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(AcpSaveDataOwnerId, 500, AcpStorageSettingsInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(AcpUserAccountSaveDataSize, 501, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(AcpUserAccountSaveDataJournalSize, 502, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(AcpDeviceSaveDataSize, 503, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(AcpDeviceSaveDataJournalSize, 504, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(AcpBcatDeliveryCacheStorageSize, 505, AcpBcatSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(AcpApplicationErrorCodeCategory, 506, AcpGeneralSettingsInfo, FieldType_String, FieldFlag_None ) \
HANDLER(AcpLocalCommunicationId, 507, AcpGeneralSettingsInfo, FieldType_U64Array, FieldFlag_None ) \
HANDLER(AcpLogoType, 508, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(AcpLogoHandling, 509, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(AcpRuntimeAocInstall, 510, AcpAocSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(AcpCrashReport, 511, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(AcpHdcp, 512, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(AcpSeedForPseudoDeviceId, 513, AcpGeneralSettingsInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(AcpBcatPassphrase, 514, AcpBcatSettingsInfo, FieldType_String, FieldFlag_None ) \
HANDLER(AcpUserAccountSaveDataSizeMax, 515, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(AcpUserAccountSaveDataJournalSizeMax, 516, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(AcpDeviceSaveDataSizeMax, 517, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(AcpDeviceSaveDataJournalSizeMax, 518, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(AcpTemporaryStorageSize, 519, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(AcpCacheStorageSize, 520, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(AcpCacheStorageJournalSize, 521, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(AcpCacheStorageDataAndJournalSizeMax, 522, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(AcpCacheStorageIndexMax, 523, AcpStorageSettingsInfo, FieldType_NumericI16, FieldFlag_None ) \
HANDLER(AcpPlayLogQueryableApplicationId, 524, AcpPlayLogSettingsInfo, FieldType_U64Array, FieldFlag_None ) \
HANDLER(AcpPlayLogQueryCapability, 525, AcpPlayLogSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(AcpRepairFlag, 526, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(RunningApplicationPatchStorageLocation, 527, RunningApplicationInfo, FieldType_String, FieldFlag_None ) \
HANDLER(RunningApplicationVersionNumber, 528, RunningApplicationInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(FsRecoveredByInvalidateCacheCount, 529, FsProxyErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(FsSaveDataIndexCount, 530, FsProxyErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(FsBufferManagerPeakTotalAllocatableSize, 531, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(MonitorCurrentWidth, 532, MonitorSettings, FieldType_NumericU16, FieldFlag_None ) \
HANDLER(MonitorCurrentHeight, 533, MonitorSettings, FieldType_NumericU16, FieldFlag_None ) \
HANDLER(MonitorCurrentRefreshRate, 534, MonitorSettings, FieldType_String, FieldFlag_None ) \
HANDLER(RebootlessSystemUpdateVersion, 535, RebootlessSystemUpdateVersionInfo, FieldType_String, FieldFlag_None ) \
HANDLER(EncryptedExceptionInfo1, 536, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(EncryptedExceptionInfo2, 537, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(EncryptedExceptionInfo3, 538, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(EncryptedDyingMessage, 539, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(DramId, 540, PowerClockInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NifmConnectionTestRedirectUrl, 541, NifmConnectionTestInfo, FieldType_String, FieldFlag_None ) \
HANDLER(AcpRequiredNetworkServiceLicenseOnLaunchFlag, 542, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(PciePort0Flags, 543, PcieLoggedStateInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(PciePort0Speed, 544, PcieLoggedStateInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(PciePort0ResetTimeInUs, 545, PcieLoggedStateInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(PciePort0IrqCount, 546, PcieLoggedStateInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(PciePort0Statistics, 547, PcieLoggedStateInfo, FieldType_U32Array, FieldFlag_None ) \
HANDLER(PciePort1Flags, 548, PcieLoggedStateInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(PciePort1Speed, 549, PcieLoggedStateInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(PciePort1ResetTimeInUs, 550, PcieLoggedStateInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(PciePort1IrqCount, 551, PcieLoggedStateInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(PciePort1Statistics, 552, PcieLoggedStateInfo, FieldType_U32Array, FieldFlag_None ) \
HANDLER(PcieFunction0VendorId, 553, PcieLoggedStateInfo, FieldType_NumericU16, FieldFlag_None ) \
HANDLER(PcieFunction0DeviceId, 554, PcieLoggedStateInfo, FieldType_NumericU16, FieldFlag_None ) \
HANDLER(PcieFunction0PmState, 555, PcieLoggedStateInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(PcieFunction0IsAcquired, 556, PcieLoggedStateInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(PcieFunction1VendorId, 557, PcieLoggedStateInfo, FieldType_NumericU16, FieldFlag_None ) \
HANDLER(PcieFunction1DeviceId, 558, PcieLoggedStateInfo, FieldType_NumericU16, FieldFlag_None ) \
HANDLER(PcieFunction1PmState, 559, PcieLoggedStateInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(PcieFunction1IsAcquired, 560, PcieLoggedStateInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(PcieGlobalRootComplexStatistics, 561, PcieLoggedStateInfo, FieldType_U32Array, FieldFlag_None ) \
HANDLER(PciePllResistorCalibrationValue, 562, PcieLoggedStateInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(CertificateRequestedHostName, 563, NetworkSecurityCertificateInfo, FieldType_String, FieldFlag_None ) \
HANDLER(CertificateCommonName, 564, NetworkSecurityCertificateInfo, FieldType_String, FieldFlag_None ) \
HANDLER(CertificateSANCount, 565, NetworkSecurityCertificateInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(CertificateSANs, 566, NetworkSecurityCertificateInfo, FieldType_String, FieldFlag_None ) \
HANDLER(FsBufferPoolMaxAllocateSize, 567, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(CertificateIssuerName, 568, NetworkSecurityCertificateInfo, FieldType_String, FieldFlag_None ) \
HANDLER(ApplicationAliveTime, 569, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(ApplicationInFocusTime, 570, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(ApplicationOutOfFocusTime, 571, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(ApplicationBackgroundFocusTime, 572, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \
HANDLER(AcpUserAccountSwitchLock, 573, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(USB3HostAvailableFlag, 574, USB3AvailableInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(USB3DeviceAvailableFlag, 575, USB3AvailableInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(AcpNeighborDetectionClientConfigurationSendDataId, 576, AcpNeighborDetectionInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(AcpNeighborDetectionClientConfigurationReceivableDataIds, 577, AcpNeighborDetectionInfo, FieldType_U64Array, FieldFlag_None ) \
HANDLER(AcpStartupUserAccountOptionFlag, 578, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(ServerErrorCode, 579, ErrorInfo, FieldType_String, FieldFlag_None ) \
HANDLER(AppletManagerMetaLogTrace, 580, ErrorInfo, FieldType_U64Array, FieldFlag_None ) \
HANDLER(ServerCertificateSerialNumber, 581, NetworkSecurityCertificateInfo, FieldType_String, FieldFlag_None ) \
HANDLER(ServerCertificatePublicKeyAlgorithm, 582, NetworkSecurityCertificateInfo, FieldType_String, FieldFlag_None ) \
HANDLER(ServerCertificateSignatureAlgorithm, 583, NetworkSecurityCertificateInfo, FieldType_String, FieldFlag_None ) \
HANDLER(ServerCertificateNotBefore, 584, NetworkSecurityCertificateInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(ServerCertificateNotAfter, 585, NetworkSecurityCertificateInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(CertificateAlgorithmInfoBits, 586, NetworkSecurityCertificateInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(TlsConnectionPeerIpAddress, 587, NetworkSecurityCertificateInfo, FieldType_String, FieldFlag_None ) \
HANDLER(TlsConnectionLastHandshakeState, 588, NetworkSecurityCertificateInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(TlsConnectionInfoBits, 589, NetworkSecurityCertificateInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(SslStateBits, 590, NetworkSecurityCertificateInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(SslProcessInfoBits, 591, NetworkSecurityCertificateInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(SslProcessHeapSize, 592, NetworkSecurityCertificateInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(SslBaseErrorCode, 593, NetworkSecurityCertificateInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(GpuCrashDumpSize, 594, GpuCrashInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(GpuCrashDump, 595, GpuCrashInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(RunningApplicationProgramIndex, 596, RunningApplicationInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(UsbTopology, 597, UsbStateInfo, FieldType_U8Array, FieldFlag_None ) \
HANDLER(AkamaiReferenceId, 598, ErrorInfo, FieldType_String, FieldFlag_None ) \
HANDLER(NvHostErrID, 599, NvHostErrInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(NvHostErrDataArrayU32, 600, NvHostErrInfo, FieldType_U32Array, FieldFlag_None ) \
HANDLER(HasSyslogFlag, 601, ErrorInfo, FieldType_Bool, FieldFlag_None ) \
HANDLER(AcpRuntimeParameterDelivery, 602, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(PlatformRegion, 603, RegionSettingInfo, FieldType_String, FieldFlag_None ) \
HANDLER(RunningUlaApplicationId, 604, RunningUlaInfo, FieldType_String, FieldFlag_None ) \
HANDLER(RunningUlaAppletId, 605, RunningUlaInfo, FieldType_NumericU8, FieldFlag_None ) \
HANDLER(RunningUlaVersion, 606, RunningUlaInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(RunningUlaApplicationStorageLocation, 607, RunningUlaInfo, FieldType_String, FieldFlag_None ) \
HANDLER(RunningUlaPatchStorageLocation, 608, RunningUlaInfo, FieldType_String, FieldFlag_None ) \
HANDLER(NANDTotalSizeOfSystem, 609, NANDFreeSpaceInfo, FieldType_NumericU64, FieldFlag_None ) \
HANDLER(NANDFreeSpaceOfSystem, 610, NANDFreeSpaceInfo, FieldType_NumericU64, FieldFlag_None ) \

View File

@@ -0,0 +1,35 @@
/*
* 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.hpp>
#include <stratosphere/erpt/erpt_types.hpp>
#include <stratosphere/sf/sf_buffer_tags.hpp>
namespace ams::erpt {
constexpr inline u32 CategoriesPerMultipleCategoryContext = 0x10;
constexpr inline u32 FieldsPerMultipleCategoryContext = CategoriesPerMultipleCategoryContext * 4;
struct MultipleCategoryContextEntry : public sf::LargeData, public sf::PrefersMapAliasTransferMode {
u32 version;
u32 category_count;
CategoryId categories[CategoriesPerMultipleCategoryContext];
u32 field_counts[CategoriesPerMultipleCategoryContext];
u32 array_buf_counts[CategoriesPerMultipleCategoryContext];
FieldEntry fields[FieldsPerMultipleCategoryContext];
};
}

View File

@@ -0,0 +1,234 @@
/*
* 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.hpp>
#include <stratosphere/os.hpp>
#include <stratosphere/time/time_posix_time.hpp>
#include <stratosphere/erpt/erpt_ids.autogen.hpp>
namespace ams::erpt {
#define GENERATE_ENUM(NAME, ID, ...) NAME = ID,
enum FieldType {
AMS_ERPT_FOREACH_FIELD_TYPE(GENERATE_ENUM)
FieldType_Count,
};
#undef GENERATE_ENUM
#define GENERATE_ENUM(NAME, ID, ...) CategoryId_##NAME = ID,
enum CategoryId {
AMS_ERPT_FOREACH_CATEGORY(GENERATE_ENUM)
CategoryId_Count,
};
#undef GENERATE_ENUM
#define GENERATE_ENUM(NAME, ID, ...) FieldId_##NAME = ID,
enum FieldId {
AMS_ERPT_FOREACH_FIELD(GENERATE_ENUM)
FieldId_Count,
};
#undef GENERATE_ENUM
constexpr inline u32 ArrayBufferSizeDefault = 0x100;
constexpr inline u32 ArrayBufferSizeMax = 96_KB;
constexpr inline u32 ArrayFieldSizeMax = 16_KB - 1;
enum ReportType {
ReportType_Start = 0,
ReportType_Visible = ReportType_Start,
ReportType_Invisible = 1,
ReportType_End = 2,
ReportType_Count = ReportType_End,
ReportType_Any = ReportType_Count,
};
constexpr inline u32 ReportCountMax = 50;
constexpr inline u32 AttachmentsPerReportMax = 5;
constexpr inline u32 AttachmentCountMax = ReportCountMax * AttachmentsPerReportMax;
constexpr inline u32 ReportMetaDataSize = 0x20;
struct ReportMetaData {
u8 user_data[ReportMetaDataSize];
};
constexpr inline u32 ReportIdSize = 20;
struct ReportId {
union {
u8 id[ReportIdSize];
util::Uuid uuid;
#pragma pack(push, 1)
struct {
u32 time_low;
u16 time_mid;
u16 time_high_and_version;
u8 clock_high;
u8 clock_low;
u64 node;
} uuid_data;
#pragma pack(pop)
};
};
static_assert(sizeof(ReportId) == ReportIdSize);
inline bool operator==(const ReportId &lhs, const ReportId &rhs) {
return std::memcmp(lhs.id, rhs.id, sizeof(lhs.uuid)) == 0;
}
inline bool operator!=(const ReportId &lhs, const ReportId &rhs) {
return !(lhs == rhs);
}
struct ReportFlag {
using Transmitted = util::BitFlagSet<BITSIZEOF(u32), ReportFlag>::Flag<0>;
using HasAttachment = util::BitFlagSet<BITSIZEOF(u32), ReportFlag>::Flag<1>;
};
using ReportFlagSet = util::BitFlagSet<BITSIZEOF(u32), ReportFlag>;
static_assert(std::is_pod<ReportFlagSet>::value);
static_assert(sizeof(ReportFlagSet) == sizeof(u32));
struct ReportInfo {
ReportType type;
ReportId id;
ReportMetaData meta_data;
ReportFlagSet flags;
time::PosixTime timestamp_user;
time::PosixTime timestamp_network;
s64 report_size;
u64 reserved[3];
};
struct ReportList {
u32 report_count;
ReportInfo reports[ReportCountMax];
};
constexpr inline u32 AttachmentIdSize = 20;
struct AttachmentId {
union {
u8 id[AttachmentIdSize];
util::Uuid uuid;
};
};
static_assert(sizeof(AttachmentId) == AttachmentIdSize);
inline bool operator==(const AttachmentId &lhs, const AttachmentId &rhs) {
return std::memcmp(lhs.id, rhs.id, sizeof(lhs.uuid)) == 0;
}
inline bool operator!=(const AttachmentId &lhs, const AttachmentId &rhs) {
return !(lhs == rhs);
}
struct AttachmentFlag {
using HasOwner = util::BitFlagSet<BITSIZEOF(u32), AttachmentFlag>::Flag<1>;
};
using AttachmentFlagSet = util::BitFlagSet<BITSIZEOF(u32), AttachmentFlag>;
static_assert(std::is_pod<AttachmentFlagSet>::value);
static_assert(sizeof(AttachmentFlagSet) == sizeof(u32));
constexpr inline u32 AttachmentNameSizeMax = 0x20;
struct AttachmentInfo {
ReportId owner_report_id;
AttachmentId attachment_id;
AttachmentFlagSet flags;
s64 attachment_size;
char attachment_name[AttachmentNameSizeMax];
};
struct AttachmentList {
u32 attachment_count;
AttachmentInfo attachments[AttachmentsPerReportMax];
};
constexpr inline u32 AttachmentSizeMax = 512_KB;
struct FieldEntry {
FieldId id;
FieldType type;
union {
u64 value_u64;
u32 value_u32;
u16 value_u16;
u8 value_u8;
s64 value_i64;
s32 value_i32;
s16 value_i16;
s8 value_i8;
bool value_bool;
struct {
u32 start_idx;
u32 size;
} value_array;
};
};
constexpr inline u32 FieldsPerContext = 20;
struct ContextEntry {
u32 version;
u32 field_count;
CategoryId category;
FieldEntry fields[FieldsPerContext];
u8 *array_buffer;
u32 array_free_count;
u32 array_buffer_size;
};
struct StorageUsageStatistics {
util::Uuid journal_uuid;
u32 used_storage_size;
s64 max_report_size;
u32 report_count[ReportType_Count];
u32 transmitted_count[ReportType_Count];
u32 untransmitted_count[ReportType_Count];
};
/* https://github.com/msgpack/msgpack/blob/master/spec.md#overview */
enum class ValueTypeTag {
FixMap = 0x80,
FixArray = 0x90,
FixStr = 0xA0,
False = 0xC2,
True = 0xC3,
Bin8 = 0xC4,
Bin16 = 0xC5,
U8 = 0xCC,
U16 = 0xCD,
U32 = 0xCE,
U64 = 0xCF,
I8 = 0xD0,
I16 = 0xD1,
I32 = 0xD2,
I64 = 0xD3,
Str8 = 0xD9,
Str16 = 0xDA,
Array16 = 0xDC,
Map16 = 0xDE,
};
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (c) 2019-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.hpp>
#include <stratosphere/erpt/erpt_types.hpp>
namespace ams::erpt::sf {
class IAttachment : public ams::sf::IServiceObject {
protected:
enum class CommandId {
Open = 0,
Read = 1,
SetFlags = 2,
GetFlags = 3,
Close = 4,
GetSize = 5,
};
public:
/* Actual commands. */
virtual Result Open(const AttachmentId &attachment_id) = 0;
virtual Result Read(ams::sf::Out<u32> out_count, const ams::sf::OutBuffer &out_buffer) = 0;
virtual Result SetFlags(AttachmentFlagSet flags) = 0;
virtual Result GetFlags(ams::sf::Out<AttachmentFlagSet> out) = 0;
virtual Result Close() = 0;
virtual Result GetSize(ams::sf::Out<s64> out) = 0;
public:
DEFINE_SERVICE_DISPATCH_TABLE {
MAKE_SERVICE_COMMAND_META(Open),
MAKE_SERVICE_COMMAND_META(Read),
MAKE_SERVICE_COMMAND_META(SetFlags),
MAKE_SERVICE_COMMAND_META(GetFlags),
MAKE_SERVICE_COMMAND_META(Close),
MAKE_SERVICE_COMMAND_META(GetSize),
};
};
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright (c) 2019-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.hpp>
#include <stratosphere/sf.hpp>
#include <stratosphere/erpt/erpt_types.hpp>
#include <stratosphere/erpt/erpt_multiple_category_context.hpp>
#include <stratosphere/time/time_steady_clock_time_point.hpp>
namespace ams::erpt::sf {
class IContext : public ams::sf::IServiceObject {
protected:
enum class CommandId {
SubmitContext = 0,
CreateReport = 1,
SetInitialLaunchSettingsCompletionTime = 2,
ClearInitialLaunchSettingsCompletionTime = 3,
UpdatePowerOnTime = 4,
UpdateAwakeTime = 5,
SubmitMultipleCategoryContext = 6,
UpdateApplicationLaunchTime = 7,
ClearApplicationLaunchTime = 8,
SubmitAttachment = 9,
CreateReportWithAttachments = 10,
};
public:
/* Actual commands. */
virtual Result SubmitContext(const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer) = 0;
virtual Result CreateReport(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer, const ams::sf::InBuffer &meta_buffer) = 0;
virtual Result SetInitialLaunchSettingsCompletionTime(const time::SteadyClockTimePoint &time_point) = 0;
virtual Result ClearInitialLaunchSettingsCompletionTime() = 0;
virtual Result UpdatePowerOnTime() = 0;
virtual Result UpdateAwakeTime() = 0;
virtual Result SubmitMultipleCategoryContext(const MultipleCategoryContextEntry &ctx_entry, const ams::sf::InBuffer &str_buffer) = 0;
virtual Result UpdateApplicationLaunchTime() = 0;
virtual Result ClearApplicationLaunchTime() = 0;
virtual Result SubmitAttachment(ams::sf::Out<AttachmentId> out, const ams::sf::InBuffer &attachment_name, const ams::sf::InBuffer &attachment_data) = 0;
virtual Result CreateReportWithAttachments(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer, const ams::sf::InBuffer &attachment_ids_buffer) = 0;
public:
DEFINE_SERVICE_DISPATCH_TABLE {
MAKE_SERVICE_COMMAND_META(SubmitContext),
MAKE_SERVICE_COMMAND_META(CreateReport),
MAKE_SERVICE_COMMAND_META(SetInitialLaunchSettingsCompletionTime, hos::Version_300),
MAKE_SERVICE_COMMAND_META(ClearInitialLaunchSettingsCompletionTime, hos::Version_300),
MAKE_SERVICE_COMMAND_META(UpdatePowerOnTime, hos::Version_300),
MAKE_SERVICE_COMMAND_META(UpdateAwakeTime, hos::Version_300),
MAKE_SERVICE_COMMAND_META(SubmitMultipleCategoryContext, hos::Version_500),
MAKE_SERVICE_COMMAND_META(UpdateApplicationLaunchTime, hos::Version_600),
MAKE_SERVICE_COMMAND_META(ClearApplicationLaunchTime, hos::Version_600),
MAKE_SERVICE_COMMAND_META(SubmitAttachment, hos::Version_800),
MAKE_SERVICE_COMMAND_META(CreateReportWithAttachments, hos::Version_800),
};
};
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (c) 2019-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.hpp>
#include <stratosphere/erpt/erpt_types.hpp>
namespace ams::erpt::sf {
class IManager : public ams::sf::IServiceObject {
protected:
enum class CommandId {
GetReportList = 0,
GetEvent = 1,
CleanupReports = 2,
DeleteReport = 3,
GetStorageUsageStatistics = 4,
GetAttachmentList = 5,
};
public:
/* Actual commands. */
virtual Result GetReportList(const ams::sf::OutBuffer &out_list, ReportType type_filter) = 0;
virtual Result GetEvent(ams::sf::OutCopyHandle out) = 0;
virtual Result CleanupReports() = 0;
virtual Result DeleteReport(const ReportId &report_id) = 0;
virtual Result GetStorageUsageStatistics(ams::sf::Out<StorageUsageStatistics> out) = 0;
virtual Result GetAttachmentList(const ams::sf::OutBuffer &out_buf, const ReportId &report_id) = 0;
public:
DEFINE_SERVICE_DISPATCH_TABLE {
MAKE_SERVICE_COMMAND_META(GetReportList),
MAKE_SERVICE_COMMAND_META(GetEvent),
MAKE_SERVICE_COMMAND_META(CleanupReports, hos::Version_400),
MAKE_SERVICE_COMMAND_META(DeleteReport, hos::Version_500),
MAKE_SERVICE_COMMAND_META(GetStorageUsageStatistics, hos::Version_500),
MAKE_SERVICE_COMMAND_META(GetAttachmentList, hos::Version_800),
};
};
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (c) 2019-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.hpp>
#include <stratosphere/erpt/erpt_types.hpp>
namespace ams::erpt::sf {
class IReport : public ams::sf::IServiceObject {
protected:
enum class CommandId {
Open = 0,
Read = 1,
SetFlags = 2,
GetFlags = 3,
Close = 4,
GetSize = 5,
};
public:
/* Actual commands. */
virtual Result Open(const ReportId &report_id) = 0;
virtual Result Read(ams::sf::Out<u32> out_count, const ams::sf::OutBuffer &out_buffer) = 0;
virtual Result SetFlags(ReportFlagSet flags) = 0;
virtual Result GetFlags(ams::sf::Out<ReportFlagSet> out) = 0;
virtual Result Close() = 0;
virtual Result GetSize(ams::sf::Out<s64> out) = 0;
public:
DEFINE_SERVICE_DISPATCH_TABLE {
MAKE_SERVICE_COMMAND_META(Open),
MAKE_SERVICE_COMMAND_META(Read),
MAKE_SERVICE_COMMAND_META(SetFlags),
MAKE_SERVICE_COMMAND_META(GetFlags),
MAKE_SERVICE_COMMAND_META(Close),
MAKE_SERVICE_COMMAND_META(GetSize),
};
};
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2019-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.hpp>
#include <stratosphere/erpt/erpt_types.hpp>
#include <stratosphere/erpt/sf/erpt_sf_i_report.hpp>
#include <stratosphere/erpt/sf/erpt_sf_i_manager.hpp>
#include <stratosphere/erpt/sf/erpt_sf_i_attachment.hpp>
namespace ams::erpt::sf {
class ISession : public ams::sf::IServiceObject {
protected:
enum class CommandId {
OpenReport = 0,
OpenManager = 1,
OpenAttachment = 2,
};
public:
/* Actual commands. */
virtual Result OpenReport(ams::sf::Out<std::shared_ptr<erpt::sf::IReport>> out) = 0;
virtual Result OpenManager(ams::sf::Out<std::shared_ptr<erpt::sf::IManager>> out) = 0;
virtual Result OpenAttachment(ams::sf::Out<std::shared_ptr<erpt::sf::IAttachment>> out) = 0;
public:
DEFINE_SERVICE_DISPATCH_TABLE {
MAKE_SERVICE_COMMAND_META(OpenReport),
MAKE_SERVICE_COMMAND_META(OpenManager),
MAKE_SERVICE_COMMAND_META(OpenAttachment, hos::Version_800),
};
};
}

View File

@@ -0,0 +1,33 @@
/*
* 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.hpp>
namespace ams::erpt::srv {
Result Initialize(u8 *mem, size_t mem_size);
Result InitializeAndStartService();
Result SetSerialNumberAndOsVersion(const char *sn, u32 sn_len, const char *os, u32 os_len, const char *os_priv, u32 os_priv_len);
Result SetProductModel(const char *model, u32 model_len);
Result SetRegionSetting(const char *region, u32 region_len);
/* Atmosphere extension. */
Result SetRedirectNewReportsToSdCard(bool redirect);
void Wait();
}

View File

@@ -0,0 +1,86 @@
/*
* 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.hpp>
#include <stratosphere/os.hpp>
#include <stratosphere/erpt/erpt_ids.autogen.hpp>
namespace ams::erpt::srv {
constexpr inline const char ReportOnSdStoragePath[] = "ersd";
constexpr inline const char ReportStoragePath[] = "save";
constexpr inline const char JournalFileName[] = "save:/journal";
constexpr size_t ReportFileNameLength = 64;
constexpr size_t AttachmentFileNameLength = 64;
constexpr size_t MaxFieldStringSize = 64;
struct ReportFileName {
char name[ReportFileNameLength];
};
struct AttachmentFileName {
char name[AttachmentFileNameLength];
};
enum FieldFlag : u8 {
FieldFlag_None = 0,
FieldFlag_Encrypt = 1,
};
#define STRINGIZE_HANDLER(NAME, ...) #NAME,
constexpr inline const char * const FieldString[] = {
AMS_ERPT_FOREACH_FIELD(STRINGIZE_HANDLER)
};
constexpr inline const char * const CategoryString[] = {
AMS_ERPT_FOREACH_CATEGORY(STRINGIZE_HANDLER)
};
constexpr inline const char * const TypeString[] = {
AMS_ERPT_FOREACH_FIELD_TYPE(STRINGIZE_HANDLER)
};
#undef STRINGIZE_HANDLER
#define GET_FIELD_CATEGORY(FIELD, ID, CATEGORY, TYPE, FLAG) [FieldId_##FIELD] = CategoryId_##CATEGORY,
constexpr inline const CategoryId FieldToCategoryMap[] = {
AMS_ERPT_FOREACH_FIELD(GET_FIELD_CATEGORY)
};
#undef GET_FIELD_CATEGORY
#define GET_FIELD_TYPE(FIELD, ID, CATEGORY, TYPE, FLAG) [FieldId_##FIELD] = TYPE,
constexpr inline const FieldType FieldToTypeMap[] = {
AMS_ERPT_FOREACH_FIELD(GET_FIELD_TYPE)
};
#undef GET_FIELD_TYPE
#define GET_FIELD_FLAG(FIELD, ID, CATEGORY, TYPE, FLAG) [FieldId_##FIELD] = FLAG,
constexpr inline const FieldFlag FieldToFlagMap[] = {
AMS_ERPT_FOREACH_FIELD(GET_FIELD_FLAG)
};
#undef GET_FIELD_FLAG
constexpr inline ReportFlagSet MakeNoReportFlags() {
return util::MakeBitFlagSet<32, ReportFlag>();
}
constexpr inline AttachmentFlagSet MakeNoAttachmentFlags() {
return util::MakeBitFlagSet<32, AttachmentFlag>();
}
}

View File

@@ -324,28 +324,20 @@ namespace ams::fatal {
bool is_creport;
CpuContext cpu_ctx;
bool generate_error_report;
Event erpt_event;
Event battery_event;
os::Event *erpt_event;
os::Event *battery_event;
size_t stack_dump_size;
u64 stack_dump_base;
u8 stack_dump[0x100];
u64 tls_address;
u8 tls_dump[0x100];
void ClearState() {
this->result = ResultSuccess();
this->program_id = ncm::ProgramId::Invalid;
std::memset(this->proc_name, 0, sizeof(this->proc_name));
this->is_creport = false;
std::memset(&this->cpu_ctx, 0, sizeof(this->cpu_ctx));
this->generate_error_report = false;
std::memset(&this->erpt_event, 0, sizeof(this->erpt_event));
std::memset(&this->battery_event, 0, sizeof(this->battery_event));
this->stack_dump_size = 0;
this->stack_dump_base = 0;
std::memset(this->stack_dump, 0, sizeof(this->stack_dump));
this->tls_address = 0;
std::memset(this->tls_dump, 0, sizeof(this->tls_dump));
ThrowContext(os::Event *erpt, os::Event *bat)
: result(ResultSuccess()), program_id(), proc_name(), is_creport(), cpu_ctx(), generate_error_report(),
erpt_event(erpt), battery_event(bat),
stack_dump_size(), stack_dump_base(), stack_dump(), tls_address(), tls_dump()
{
/* ... */
}
};

View File

@@ -115,12 +115,11 @@ namespace ams::fs {
return this->GetImpl(std::addressof(pos), out, key, hash_key, aux, aux_size);
}
Result FindOpen(FindIndex *out) const {
void FindOpen(FindIndex *out) const {
AMS_ASSERT(out != nullptr);
out->ind = static_cast<BucketIndex>(-1);
out->pos = InvalidPosition;
return ResultSuccess();
}
Result FindNext(Key *out_key, Value *out_val, FindIndex *find) {

View File

@@ -63,7 +63,7 @@ namespace ams::fs {
s64 size;
os::Mutex mutex;
public:
constexpr explicit FileHandleStorage(FileHandle handle, bool close_file) : handle(handle), close_file(close_file), size(InvalidSize), mutex() { /* ... */ }
constexpr explicit FileHandleStorage(FileHandle handle, bool close_file) : handle(handle), close_file(close_file), size(InvalidSize), mutex(false) { /* ... */ }
constexpr explicit FileHandleStorage(FileHandle handle) : FileHandleStorage(handle, false) { /* ... */ }
virtual ~FileHandleStorage() override {

View File

@@ -20,9 +20,9 @@
namespace ams::fs {
struct QueryRangeInfo {
u32 aes_ctr_key_type;
u32 speed_emulation_type;
u32 reserved[0x38 / sizeof(u32)];
s32 aes_ctr_key_type;
s32 speed_emulation_type;
u8 reserved[0x38];
void Clear() {
this->aes_ctr_key_type = 0;
@@ -45,4 +45,8 @@ namespace ams::fs {
Result QueryRange(QueryRangeInfo *out, FileHandle handle, s64 offset, s64 size);
enum class AesCtrKeyTypeFlag : s32 {
InternalKeyForSoftwareAes = (1 << 0),
};
}

View File

@@ -82,7 +82,7 @@ namespace ams::fs {
private:
virtual Result OpenFileImpl(std::unique_ptr<fsa::IFile> *out_file, const char *path, OpenMode mode) override final {
/* Only allow opening files with mode = read. */
R_UNLESS((mode & fs::OpenMode_All) == fs::OpenMode_Read, fs::ResultInvalidArgument());
R_UNLESS((mode & fs::OpenMode_All) == fs::OpenMode_Read, fs::ResultInvalidOpenMode());
std::unique_ptr<fsa::IFile> base_file;
R_TRY(this->base_fs->OpenFile(std::addressof(base_file), path, mode));

View File

@@ -19,12 +19,26 @@
namespace ams::fs {
union RightsId {
u8 data[0x10];
u64 data64[2];
u8 data[0x10];
u64 data64[2];
};
static_assert(sizeof(RightsId) == 0x10);
static_assert(std::is_pod<RightsId>::value);
inline bool operator==(const RightsId &lhs, const RightsId &rhs) {
return std::memcmp(std::addressof(lhs), std::addressof(rhs), sizeof(RightsId)) == 0;
}
inline bool operator!=(const RightsId &lhs, const RightsId &rhs) {
return !(lhs == rhs);
}
inline bool operator<(const RightsId &lhs, const RightsId &rhs) {
return std::memcmp(std::addressof(lhs), std::addressof(rhs), sizeof(RightsId)) < 0;
}
constexpr inline RightsId InvalidRightsId = {};
/* Rights ID API */
Result GetRightsId(RightsId *out, const char *path);
Result GetRightsId(RightsId *out, u8 *out_key_generation, const char *path);

View File

@@ -26,4 +26,9 @@ namespace ams::fs {
Result GetSaveDataFlags(u32 *out, SaveDataSpaceId space_id, SaveDataId id);
Result SetSaveDataFlags(SaveDataId id, SaveDataSpaceId space_id, u32 flags);
Result GetSaveDataAvailableSize(s64 *out, SaveDataId id);
Result GetSaveDataJournalSize(s64 *out, SaveDataId id);
Result ExtendSaveData(SaveDataSpaceId space_id, SaveDataId id, s64 available_size, s64 journal_size);
}

View File

@@ -20,4 +20,6 @@ namespace ams::fs {
Result MountSdCard(const char *name);
Result MountSdCardErrorReportDirectoryForAtmosphere(const char *name);
}

View File

@@ -83,16 +83,16 @@ namespace ams::fs::fsa {
Result OpenFile(std::unique_ptr<IFile> *out_file, const char *path, OpenMode mode) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
R_UNLESS(out_file != nullptr, fs::ResultNullptrArgument());
R_UNLESS((mode & OpenMode_ReadWrite) != 0, fs::ResultInvalidArgument());
R_UNLESS((mode & ~OpenMode_All) == 0, fs::ResultInvalidArgument());
R_UNLESS((mode & OpenMode_ReadWrite) != 0, fs::ResultInvalidOpenMode());
R_UNLESS((mode & ~OpenMode_All) == 0, fs::ResultInvalidOpenMode());
return this->OpenFileImpl(out_file, path, mode);
}
Result OpenDirectory(std::unique_ptr<IDirectory> *out_dir, const char *path, OpenDirectoryMode mode) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
R_UNLESS(out_dir != nullptr, fs::ResultNullptrArgument());
R_UNLESS((mode & OpenDirectoryMode_All) != 0, fs::ResultInvalidArgument());
R_UNLESS((mode & ~(OpenDirectoryMode_All | OpenDirectoryMode_NotRequireFileSize)) == 0, fs::ResultInvalidArgument());
R_UNLESS((mode & OpenDirectoryMode_All) != 0, fs::ResultInvalidOpenMode());
R_UNLESS((mode & ~(OpenDirectoryMode_All | OpenDirectoryMode_NotRequireFileSize)) == 0, fs::ResultInvalidOpenMode());
return this->OpenDirectoryImpl(out_dir, path, mode);
}

View File

@@ -15,11 +15,18 @@
*/
#pragma once
#include "fssystem/fssystem_utility.hpp"
#include "fssystem/fssystem_external_code.hpp"
#include "fssystem/fssystem_partition_file_system.hpp"
#include "fssystem/fssystem_partition_file_system_meta.hpp"
#include "fssystem/fssystem_path_tool.hpp"
#include "fssystem/fssystem_subdirectory_filesystem.hpp"
#include "fssystem/fssystem_directory_redirection_filesystem.hpp"
#include "fssystem/fssystem_directory_savedata_filesystem.hpp"
#include <stratosphere/fssystem/fssystem_utility.hpp>
#include <stratosphere/fssystem/fssystem_external_code.hpp>
#include <stratosphere/fssystem/fssystem_partition_file_system.hpp>
#include <stratosphere/fssystem/fssystem_partition_file_system_meta.hpp>
#include <stratosphere/fssystem/fssystem_path_tool.hpp>
#include <stratosphere/fssystem/fssystem_thread_priority_changer.hpp>
#include <stratosphere/fssystem/fssystem_aes_ctr_storage.hpp>
#include <stratosphere/fssystem/fssystem_aes_xts_storage.hpp>
#include <stratosphere/fssystem/fssystem_subdirectory_filesystem.hpp>
#include <stratosphere/fssystem/fssystem_directory_redirection_filesystem.hpp>
#include <stratosphere/fssystem/fssystem_directory_savedata_filesystem.hpp>
#include <stratosphere/fssystem/fssystem_romfs_file_system.hpp>
#include <stratosphere/fssystem/buffers/fssystem_buffer_manager_utils.hpp>
#include <stratosphere/fssystem/buffers/fssystem_file_system_buddy_heap.hpp>
#include <stratosphere/fssystem/fssystem_pooled_buffer.hpp>

View File

@@ -0,0 +1,90 @@
/*
* 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.hpp>
#include <stratosphere/os.hpp>
namespace ams::fssystem::buffers {
namespace impl {
constexpr inline auto RetryWait = TimeSpan::FromMilliSeconds(10);
}
template<typename F, typename OnFailure>
Result DoContinuouslyUntilBufferIsAllocated(F f, OnFailure on_failure, const char *function_name) {
constexpr auto BufferAllocationRetryLogCountMax = 10;
constexpr auto BufferAllocationRetryLogInterval = 100;
for (auto count = 1; true; count++) {
R_TRY_CATCH(f()) {
R_CATCH(fs::ResultBufferAllocationFailed) {
if ((1 <= count && count <= BufferAllocationRetryLogCountMax) || ((count % BufferAllocationRetryLogInterval) == 0)) {
/* TODO: Log */
}
R_TRY(on_failure());
/* TODO: os::SleepThread */
svc::SleepThread(impl::RetryWait.GetNanoSeconds());
continue;
}
} R_END_TRY_CATCH;
return ResultSuccess();
}
}
template<typename F>
Result DoContinuouslyUntilBufferIsAllocated(F f, const char *function_name) {
R_TRY(DoContinuouslyUntilBufferIsAllocated(f, []() ALWAYS_INLINE_LAMBDA { return ResultSuccess(); }, function_name));
return ResultSuccess();
}
class BufferManagerContext {
private:
bool needs_blocking;
public:
constexpr BufferManagerContext() : needs_blocking(false) { /* ... */ }
public:
bool IsNeedBlocking() const { return this->needs_blocking; }
void SetNeedBlocking(bool need) { this->needs_blocking = need; }
};
void RegisterBufferManagerContext(const BufferManagerContext *context);
BufferManagerContext *GetBufferManagerContext();
void EnableBlockingBufferManagerAllocation();
class ScopedBufferManagerContextRegistration {
private:
BufferManagerContext cur_context;
const BufferManagerContext *old_context;
public:
ALWAYS_INLINE explicit ScopedBufferManagerContextRegistration() {
this->old_context = GetBufferManagerContext();
if (this->old_context != nullptr) {
this->cur_context = *this->old_context;
}
RegisterBufferManagerContext(std::addressof(this->cur_context));
}
ALWAYS_INLINE ~ScopedBufferManagerContextRegistration() {
RegisterBufferManagerContext(this->old_context);
}
};
}

View File

@@ -0,0 +1,189 @@
/*
* 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.hpp>
#include <stratosphere/fs/impl/fs_newable.hpp>
namespace ams::fssystem {
class FileSystemBuddyHeap {
NON_COPYABLE(FileSystemBuddyHeap);
NON_MOVEABLE(FileSystemBuddyHeap);
public:
static constexpr size_t BufferAlignment = sizeof(void *);
static constexpr size_t BlockSizeMin = 2 * sizeof(void *);
static constexpr s32 OrderUpperLimit = BITSIZEOF(s32) - 1;
private:
class PageList;
struct PageEntry { PageEntry *next; };
static_assert(std::is_pod<PageEntry>::value);
static_assert(sizeof(PageEntry) <= BlockSizeMin);
class PageList : public ::ams::fs::impl::Newable {
NON_COPYABLE(PageList);
NON_MOVEABLE(PageList);
private:
PageEntry *first_page_entry;
PageEntry *last_page_entry;
s32 entry_count;
public:
constexpr PageList() : first_page_entry(), last_page_entry(), entry_count() { /* ... */ }
constexpr bool IsEmpty() const { return this->entry_count == 0; }
constexpr s32 GetSize() const { return this->entry_count; }
constexpr const PageEntry *GetFront() const { return this->first_page_entry; }
public:
PageEntry *PopFront();
void PushBack(PageEntry *page_entry);
bool Remove(PageEntry *page_entry);
};
private:
size_t block_size;
s32 order_max;
uintptr_t heap_start;
size_t heap_size;
PageList *free_lists;
size_t total_free_size;
PageList *external_free_lists;
std::unique_ptr<PageList[]> internal_free_lists;
public:
static constexpr s32 GetBlockCountFromOrder(s32 order) {
AMS_ASSERT(0 <= order);
AMS_ASSERT(order < OrderUpperLimit);
return (1 << order);
}
static constexpr size_t QueryWorkBufferSize(s32 order_max) {
AMS_ASSERT(0 < order_max && order_max < OrderUpperLimit);
return util::AlignUp(sizeof(PageList) * (order_max + 1) + alignof(PageList), alignof(u64));
}
static constexpr s32 QueryOrderMax(size_t size, size_t block_size) {
AMS_ASSERT(size >= block_size);
AMS_ASSERT(block_size >= BlockSizeMin);
AMS_ASSERT(util::IsPowerOfTwo(block_size));
const auto block_count = static_cast<s32>(util::AlignUp(size, block_size) / block_size);
for (auto order = 1; true; order++) {
if (block_count <= GetBlockCountFromOrder(order)) {
return order;
}
}
}
public:
constexpr FileSystemBuddyHeap() : block_size(), order_max(), heap_start(), heap_size(), free_lists(), total_free_size(), external_free_lists(), internal_free_lists() { /* ... */ }
Result Initialize(uintptr_t address, size_t size, size_t block_size, s32 order_max);
Result Initialize(uintptr_t address, size_t size, size_t block_size) {
return this->Initialize(address, size, block_size, QueryOrderMax(size, block_size));
}
Result Initialize(uintptr_t address, size_t size, size_t block_size, s32 order_max, void *work, size_t work_size) {
AMS_ASSERT(work_size >= QueryWorkBufferSize(order_max));
const auto aligned_work = util::AlignUp(reinterpret_cast<uintptr_t>(work), alignof(PageList));
this->external_free_lists = reinterpret_cast<PageList *>(aligned_work);
return this->Initialize(address, size, block_size, order_max);
}
Result Initialize(uintptr_t address, size_t size, size_t block_size, void *work, size_t work_size) {
return this->Initialize(address, size, block_size, QueryOrderMax(size, block_size), work, work_size);
}
void Finalize();
void *AllocateByOrder(s32 order);
void Free(void *ptr, s32 order);
size_t GetTotalFreeSize() const;
size_t GetAllocatableSizeMax() const;
void Dump() const;
s32 GetOrderFromBytes(size_t size) const {
AMS_ASSERT(this->free_lists != nullptr);
return this->GetOrderFromBlockCount(this->GetBlockCountFromSize(size));
}
size_t GetBytesFromOrder(s32 order) const {
AMS_ASSERT(this->free_lists != nullptr);
AMS_ASSERT(0 <= order);
AMS_ASSERT(order < this->GetOrderMax());
return (this->GetBlockSize() << order);
}
s32 GetOrderMax() const {
AMS_ASSERT(this->free_lists != nullptr);
return this->order_max;
}
size_t GetBlockSize() const {
AMS_ASSERT(this->free_lists != nullptr);
return this->block_size;
}
s32 GetPageBlockCountMax() const {
AMS_ASSERT(this->free_lists != nullptr);
return 1 << this->GetOrderMax();
}
size_t GetPageSizeMax() const {
AMS_ASSERT(this->free_lists != nullptr);
return this->GetPageBlockCountMax() * this->GetBlockSize();
}
private:
void DivideBuddies(PageEntry *page_entry, s32 required_order, s32 chosen_order);
void JoinBuddies(PageEntry *page_entry, s32 order);
PageEntry *GetBuddy(PageEntry *page_entry, s32 order);
PageEntry *GetFreePageEntry(s32 order);
s32 GetOrderFromBlockCount(s32 block_count) const;
s32 GetBlockCountFromSize(size_t size) const {
const size_t bsize = this->GetBlockSize();
return static_cast<s32>(util::AlignUp(size, bsize) / bsize);
}
uintptr_t GetAddressFromPageEntry(const PageEntry &page_entry) const {
const uintptr_t address = reinterpret_cast<uintptr_t>(std::addressof(page_entry));
AMS_ASSERT(this->heap_start <= address);
AMS_ASSERT(address < this->heap_start + this->heap_size);
AMS_ASSERT(util::IsAligned(address - this->heap_start, this->GetBlockSize()));
return address;
}
PageEntry *GetPageEntryFromAddress(uintptr_t address) const {
AMS_ASSERT(this->heap_start <= address);
AMS_ASSERT(address < this->heap_start + this->heap_size);
return reinterpret_cast<PageEntry *>(this->heap_start + util::AlignDown(address - this->heap_start, this->GetBlockSize()));
}
s32 GetIndexFromPageEntry(const PageEntry &page_entry) const {
const uintptr_t address = reinterpret_cast<uintptr_t>(std::addressof(page_entry));
AMS_ASSERT(this->heap_start <= address);
AMS_ASSERT(address < this->heap_start + this->heap_size);
AMS_ASSERT(util::IsAligned(address - this->heap_start, this->GetBlockSize()));
return static_cast<s32>((address - this->heap_start) / this->GetBlockSize());
}
bool IsAlignedToOrder(const PageEntry *page_entry, s32 order) const {
return util::IsAligned(GetIndexFromPageEntry(*page_entry), GetBlockCountFromOrder(order));
}
};
}

View File

@@ -0,0 +1,50 @@
/*
* 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.hpp>
#include <stratosphere/fs/fs_istorage.hpp>
#include <stratosphere/fs/impl/fs_newable.hpp>
namespace ams::fssystem {
class AesCtrStorage : public ::ams::fs::IStorage, public ::ams::fs::impl::Newable {
NON_COPYABLE(AesCtrStorage);
NON_MOVEABLE(AesCtrStorage);
public:
static constexpr size_t BlockSize = crypto::Aes128CtrEncryptor::BlockSize;
static constexpr size_t KeySize = crypto::Aes128CtrEncryptor::KeySize;
static constexpr size_t IvSize = crypto::Aes128CtrEncryptor::IvSize;
private:
IStorage * const base_storage;
char key[KeySize];
char iv[IvSize];
public:
static void MakeIv(void *dst, size_t dst_size, u64 upper, s64 offset);
public:
AesCtrStorage(IStorage *base, const void *key, size_t key_size, const void *iv, size_t iv_size);
virtual Result Read(s64 offset, void *buffer, size_t size) override;
virtual Result Write(s64 offset, const void *buffer, size_t size) override;
virtual Result Flush() override;
virtual Result SetSize(s64 size) override;
virtual Result GetSize(s64 *out) override;
virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override;
};
}

View File

@@ -0,0 +1,51 @@
/*
* 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.hpp>
#include <stratosphere/fs/fs_istorage.hpp>
#include <stratosphere/fs/impl/fs_newable.hpp>
#include <stratosphere/os.hpp>
namespace ams::fssystem {
class AesXtsStorage : public ::ams::fs::IStorage, public ::ams::fs::impl::Newable {
NON_COPYABLE(AesXtsStorage);
NON_MOVEABLE(AesXtsStorage);
public:
static constexpr size_t AesBlockSize = crypto::Aes128XtsEncryptor::BlockSize;
static constexpr size_t KeySize = crypto::Aes128XtsEncryptor::KeySize;
static constexpr size_t IvSize = crypto::Aes128XtsEncryptor::IvSize;
private:
IStorage * const base_storage;
char key[2][KeySize];
char iv[IvSize];
const size_t block_size;
os::Mutex mutex;
public:
AesXtsStorage(IStorage *base, const void *key1, const void *key2, size_t key_size, const void *iv, size_t iv_size, size_t block_size);
virtual Result Read(s64 offset, void *buffer, size_t size) override;
virtual Result Write(s64 offset, const void *buffer, size_t size) override;
virtual Result Flush() override;
virtual Result SetSize(s64 size) override;
virtual Result GetSize(s64 *out) override;
virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override;
};
}

View File

@@ -0,0 +1,684 @@
/*
* 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.hpp>
#include <stratosphere/fssystem/fssystem_dbm_rom_types.hpp>
#include <stratosphere/fssystem/fssystem_dbm_rom_path_tool.hpp>
#include <stratosphere/fssystem/fssystem_dbm_rom_key_value_storage.hpp>
namespace ams::fssystem {
template<typename DBS, typename DES, typename FBS, typename FES>
class HierarchicalRomFileTable {
private:
using DirectoryBucketStorage = DBS;
using DirectoryEntryStorage = DES;
using FileBucketStorage = FBS;
using FileEntryStorage = FES;
public:
using Position = u32;
struct FindPosition {
Position next_dir;
Position next_file;
};
static_assert(std::is_pod<FindPosition>::value);
using DirectoryInfo = RomDirectoryInfo;
using FileInfo = RomFileInfo;
static constexpr RomFileId ConvertToFileId(Position pos) {
return static_cast<RomFileId>(pos);
}
private:
static constexpr inline Position InvalidPosition = ~Position();
static constexpr inline Position RootPosition = 0;
static constexpr inline size_t ReservedDirectoryCount = 1;
static constexpr RomDirectoryId ConvertToDirectoryId(Position pos) {
return static_cast<RomDirectoryId>(pos);
}
static constexpr Position ConvertToPosition(RomDirectoryId id) {
return static_cast<Position>(id);
}
static_assert(std::is_same<RomDirectoryId, RomFileId>::value);
struct RomDirectoryEntry {
Position next;
Position dir;
Position file;
};
static_assert(std::is_pod<RomDirectoryEntry>::value);
struct RomFileEntry {
Position next;
FileInfo info;
};
static_assert(std::is_pod<RomFileEntry>::value);
static constexpr inline u32 MaxKeyLength = RomPathTool::MaxPathLength;
template<typename BucketStorageType, typename EntryStorageType, typename ImplKeyType, typename ClientKeyType, typename ValueType>
class EntryMapTable : public RomKeyValueStorage<BucketStorageType, EntryStorageType, ImplKeyType, ValueType, MaxKeyLength> {
private:
using BucketStorage = BucketStorageType;
using EntryStorage = EntryStorageType;
public:
using ImplKey = ImplKeyType;
using ClientKey = ClientKeyType;
using Value = ValueType;
using Position = HierarchicalRomFileTable::Position;
using Base = RomKeyValueStorage<BucketStorageType, EntryStorageType, ImplKeyType, ValueType, MaxKeyLength>;
public:
Result Add(Position *out, const ClientKeyType &key, const Value &value) {
return Base::AddImpl(out, key.key, key.Hash(), key.name.path, key.name.length * sizeof(RomPathChar), value);
}
Result Get(Position *out_pos, Value *out_val, const ClientKeyType &key) const {
return Base::GetImpl(out_pos, out_val, key.key, key.Hash(), key.name.path, key.name.length * sizeof(RomPathChar));
}
Result GetByPosition(ImplKey *out_key, Value *out_val, void *out_aux, size_t *out_aux_size, Position pos) const {
return Base::GetByPosition(out_key, out_val, out_aux, out_aux_size, pos);
}
Result SetByPosition(Position pos, const Value &value, fs::WriteOption option) const {
return Base::SetByPosition(pos, value, option);
}
};
struct RomEntryKey {
Position parent;
bool IsEqual(const RomEntryKey &rhs, const void *aux_lhs, size_t aux_lhs_size, const void *aux_rhs, size_t aux_rhs_size) const {
if (this->parent != rhs.parent) {
return false;
}
if (aux_lhs_size != aux_rhs_size) {
return false;
}
return RomPathTool::IsEqualPath(reinterpret_cast<const RomPathChar *>(aux_lhs), reinterpret_cast<const RomPathChar *>(aux_rhs), aux_lhs_size / sizeof(RomPathChar));
}
};
static_assert(std::is_pod<RomEntryKey>::value);
struct EntryKey {
RomEntryKey key;
RomPathTool::RomEntryName name;
constexpr u32 Hash() const {
u32 hash = this->key.parent ^ 123456789;
const RomPathChar *name = this->name.path;
const RomPathChar *end = name + this->name.length;
while (name < end) {
const u32 cur = static_cast<u32>(static_cast<std::make_unsigned<RomPathChar>::type>(*(name++)));
hash = ((hash >> 5) | (hash << 27)) ^ cur;
}
return hash;
}
};
static_assert(std::is_pod<EntryKey>::value);
using DirectoryEntryMapTable = EntryMapTable<DirectoryBucketStorage, DirectoryEntryStorage, RomEntryKey, EntryKey, RomDirectoryEntry>;
using FileEntryMapTable = EntryMapTable<FileBucketStorage, FileEntryStorage, RomEntryKey, EntryKey, RomFileEntry>;
private:
DirectoryEntryMapTable dir_table;
FileEntryMapTable file_table;
public:
static u32 QueryDirectoryEntrySize(u32 name_len) {
AMS_ABORT_UNLESS(name_len <= RomPathTool::MaxPathLength);
return DirectoryEntryMapTable::QueryEntrySize(name_len * sizeof(RomPathChar));
}
static u32 QueryFileEntrySize(u32 name_len) {
AMS_ABORT_UNLESS(name_len <= RomPathTool::MaxPathLength);
return FileEntryMapTable::QueryEntrySize(name_len * sizeof(RomPathChar));
}
static u32 QueryDirectoryEntryBucketStorageSize(u32 count) { return DirectoryEntryMapTable::QueryBucketStorageSize(count); }
static u32 QueryFileEntryBucketStorageSize(u32 count) { return FileEntryMapTable::QueryBucketStorageSize(count); }
static Result Format(DirectoryBucketStorage *dir_bucket, s64 dir_bucket_ofs, u32 dir_bucket_size, DirectoryEntryStorage *dir_entry, s64 dir_entry_ofs, u32 dir_entry_size, FileBucketStorage *file_bucket, s64 file_bucket_ofs, u32 file_bucket_size, FileEntryStorage *file_entry, s64 file_entry_ofs, u32 file_entry_size) {
R_TRY(DirectoryEntryMapTable::Format(dir_bucket, dir_bucket_ofs, DirectoryEntryMapTable::QueryBucketCount(dir_bucket_size), dir_entry, dir_entry_ofs, dir_entry_size));
R_TRY(FileEntryMapTable::Format(file_bucket, file_bucket_ofs, FileEntryMapTable::QueryBucketCount(file_bucket_size), file_entry, file_entry_ofs, file_entry_size));
return ResultSuccess();
}
public:
HierarchicalRomFileTable() { /* ... */ }
constexpr u32 GetDirectoryEntryCount() const {
return this->dir_table.GetEntryCount();
}
constexpr u32 GetFileEntryCount() const {
return this->file_table.GetEntryCount();
}
Result Initialize(DirectoryBucketStorage *dir_bucket, s64 dir_bucket_ofs, u32 dir_bucket_size, DirectoryEntryStorage *dir_entry, s64 dir_entry_ofs, u32 dir_entry_size, FileBucketStorage *file_bucket, s64 file_bucket_ofs, u32 file_bucket_size, FileEntryStorage *file_entry, s64 file_entry_ofs, u32 file_entry_size) {
AMS_ASSERT(dir_bucket != nullptr);
AMS_ASSERT(dir_entry != nullptr);
AMS_ASSERT(file_bucket != nullptr);
AMS_ASSERT(file_entry != nullptr);
R_TRY(this->dir_table.Initialize(dir_bucket, dir_bucket_ofs, DirectoryEntryMapTable::QueryBucketCount(dir_bucket_size), dir_entry, dir_entry_ofs, dir_entry_size));
R_TRY(this->file_table.Initialize(file_bucket, file_bucket_ofs, FileEntryMapTable::QueryBucketCount(file_bucket_size), file_entry, file_entry_ofs, file_entry_size));
return ResultSuccess();
}
void Finalize() {
this->dir_table.Finalize();
this->file_table.Finalize();
}
Result CreateRootDirectory() {
Position root_pos = RootPosition;
EntryKey root_key = {};
root_key.key.parent = root_pos;
RomPathTool::InitializeRomEntryName(std::addressof(root_key.name));
RomDirectoryEntry root_entry = {
.next = InvalidPosition,
.dir = InvalidPosition,
.file = InvalidPosition,
};
return this->dir_table.Add(std::addressof(root_pos), root_key, root_entry);
}
Result CreateDirectory(RomDirectoryId *out, const RomPathChar *path, const DirectoryInfo &info) {
AMS_ASSERT(out != nullptr);
AMS_ASSERT(path != nullptr);
EntryKey parent_key = {};
RomDirectoryEntry parent_entry = {};
EntryKey new_key = {};
R_TRY(this->FindDirectoryRecursive(std::addressof(parent_key), std::addressof(parent_entry), std::addressof(new_key), path));
R_TRY(this->CheckSameEntryExists(new_key, fs::ResultDbmAlreadyExists()));
RomDirectoryEntry new_entry = {
.next = InvalidPosition,
.dir = InvalidPosition,
.file = InvalidPosition,
};
Position new_pos = 0;
R_TRY_CATCH(this->dir_table.Add(std::addressof(new_pos), new_key, new_entry)) {
R_CONVERT(fs::ResultDbmKeyFull, fs::ResultDbmDirectoryEntryFull())
} R_END_TRY_CATCH;
*out = ConvertToDirectoryId(new_pos);
if (parent_entry.dir == InvalidPosition) {
parent_entry.dir = new_pos;
R_TRY(this->dir_table.SetByPosition(new_key.key.parent, parent_entry, fs::WriteOption::None));
} else {
Position cur_pos = parent_entry.dir;
while (true) {
RomEntryKey cur_key = {};
RomDirectoryEntry cur_entry = {};
R_TRY(this->dir_table.GetByPosition(std::addressof(cur_key), std::addressof(cur_entry), nullptr, nullptr, cur_pos));
if (cur_entry.next == InvalidPosition) {
cur_entry.next = new_pos;
R_TRY(this->dir_table.SetByPosition(cur_pos, cur_entry, fs::WriteOption::None));
break;
}
cur_pos = cur_entry.next;
}
}
return ResultSuccess();
}
Result CreateFile(RomFileId *out, const RomPathChar *path, const FileInfo &info) {
AMS_ASSERT(out != nullptr);
AMS_ASSERT(path != nullptr);
EntryKey parent_key = {};
RomDirectoryEntry parent_entry = {};
EntryKey new_key = {};
R_TRY(this->FindFileRecursive(std::addressof(parent_key), std::addressof(parent_entry), std::addressof(new_key), path));
R_TRY(this->CheckSameEntryExists(new_key, fs::ResultDbmAlreadyExists()));
RomFileEntry new_entry = {
.next = InvalidPosition,
.info = info,
};
Position new_pos = 0;
R_TRY_CATCH(this->file_table.Add(std::addressof(new_pos), new_key, new_entry)) {
R_CONVERT(fs::ResultDbmKeyFull, fs::ResultDbmFileEntryFull())
} R_END_TRY_CATCH;
*out = ConvertToFileId(new_pos);
if (parent_entry.file == InvalidPosition) {
parent_entry.file = new_pos;
R_TRY(this->dir_table.SetByPosition(new_key.key.parent, parent_entry, fs::WriteOption::None));
} else {
Position cur_pos = parent_entry.file;
while (true) {
RomEntryKey cur_key = {};
RomFileEntry cur_entry = {};
R_TRY(this->file_table.GetByPosition(std::addressof(cur_key), std::addressof(cur_entry), nullptr, nullptr, cur_pos));
if (cur_entry.next == InvalidPosition) {
cur_entry.next = new_pos;
R_TRY(this->file_table.SetByPosition(cur_pos, cur_entry, fs::WriteOption::None));
break;
}
cur_pos = cur_entry.next;
}
}
return ResultSuccess();
}
Result ConvertPathToDirectoryId(RomDirectoryId *out, const RomPathChar *path) const {
AMS_ASSERT(out != nullptr);
AMS_ASSERT(path != nullptr);
EntryKey parent_key = {};
RomDirectoryEntry parent_entry = {};
EntryKey key = {};
R_TRY(this->FindDirectoryRecursive(std::addressof(parent_key), std::addressof(parent_entry), std::addressof(key), path));
Position pos = 0;
RomDirectoryEntry entry = {};
R_TRY(this->GetDirectoryEntry(std::addressof(pos), std::addressof(entry), key));
*out = ConvertToDirectoryId(pos);
return ResultSuccess();
}
Result ConvertPathToFileId(RomFileId *out, const RomPathChar *path) const {
AMS_ASSERT(out != nullptr);
AMS_ASSERT(path != nullptr);
EntryKey parent_key = {};
RomDirectoryEntry parent_entry = {};
EntryKey key = {};
R_TRY(this->FindDirectoryRecursive(std::addressof(parent_key), std::addressof(parent_entry), std::addressof(key), path));
Position pos = 0;
RomFileEntry entry = {};
R_TRY(this->GetFileEntry(std::addressof(pos), std::addressof(entry), key));
*out = ConvertToFileId(pos);
return ResultSuccess();
}
Result GetDirectoryInformation(DirectoryInfo *out, const RomPathChar *path) const {
AMS_ASSERT(out != nullptr);
AMS_ASSERT(path != nullptr);
EntryKey parent_key = {};
RomDirectoryEntry parent_entry = {};
EntryKey key = {};
R_TRY(this->FindDirectoryRecursive(std::addressof(parent_key), std::addressof(parent_entry), std::addressof(key), path));
return this->GetDirectoryInformation(out, key);
}
Result GetDirectoryInformation(DirectoryInfo *out, RomDirectoryId id) const {
AMS_ASSERT(out != nullptr);
RomDirectoryEntry entry = {};
R_TRY(this->GetDirectoryEntry(std::addressof(entry), id));
return ResultSuccess();
}
Result OpenFile(FileInfo *out, const RomPathChar *path) const {
AMS_ASSERT(out != nullptr);
AMS_ASSERT(path != nullptr);
EntryKey parent_key = {};
RomDirectoryEntry parent_entry = {};
EntryKey key = {};
R_TRY(this->FindFileRecursive(std::addressof(parent_key), std::addressof(parent_entry), std::addressof(key), path));
return this->OpenFile(out, key);
}
Result OpenFile(FileInfo *out, RomFileId id) const {
AMS_ASSERT(out != nullptr);
RomFileEntry entry = {};
R_TRY(this->GetFileEntry(std::addressof(entry), id));
*out = entry.info;
return ResultSuccess();
}
Result FindOpen(FindPosition *out, const RomPathChar *path) const {
AMS_ASSERT(out != nullptr);
AMS_ASSERT(path != nullptr);
EntryKey parent_key = {};
RomDirectoryEntry parent_entry = {};
EntryKey key = {};
R_TRY(this->FindDirectoryRecursive(std::addressof(parent_key), std::addressof(parent_entry), std::addressof(key), path));
return this->FindOpen(out, key);
}
Result FindOpen(FindPosition *out, RomDirectoryId id) const {
AMS_ASSERT(out != nullptr);
out->next_dir = InvalidPosition;
out->next_file = InvalidPosition;
RomDirectoryEntry entry = {};
R_TRY(this->GetDirectoryEntry(std::addressof(entry), id));
out->next_dir = entry.dir;
out->next_file = entry.file;
return ResultSuccess();
}
Result FindNextDirectory(RomPathChar *out, FindPosition *find) const {
AMS_ASSERT(out != nullptr);
AMS_ASSERT(find != nullptr);
R_UNLESS(find->next_dir != InvalidPosition, fs::ResultDbmFindFinished());
RomEntryKey key = {};
RomDirectoryEntry entry = {};
size_t aux_size = 0;
R_TRY(this->dir_table.GetByPosition(std::addressof(key), std::addressof(entry), out, std::addressof(aux_size), find->next_dir));
out[aux_size / sizeof(RomPathChar)] = RomStringTraits::NullTerminator;
find->next_dir = entry.next;
return ResultSuccess();
}
Result FindNextFile(RomPathChar *out, FindPosition *find) const {
AMS_ASSERT(out != nullptr);
AMS_ASSERT(find != nullptr);
R_UNLESS(find->next_file != InvalidPosition, fs::ResultDbmFindFinished());
RomEntryKey key = {};
RomFileEntry entry = {};
size_t aux_size = 0;
R_TRY(this->file_table.GetByPosition(std::addressof(key), std::addressof(entry), out, std::addressof(aux_size), find->next_file));
out[aux_size / sizeof(RomPathChar)] = RomStringTraits::NullTerminator;
find->next_file = entry.next;
return ResultSuccess();
}
Result QueryRomFileSystemSize(u32 *out_dir_entry_size, u32 *out_file_entry_size) {
AMS_ASSERT(out_dir_entry_size != nullptr);
AMS_ASSERT(out_file_entry_size != nullptr);
*out_dir_entry_size = this->dir_table.GetTotalEntrySize();
*out_file_entry_size = this->file_table.GetTotalEntrySize();
return ResultSuccess();
}
private:
Result GetGrandParent(Position *out_pos, EntryKey *out_dir_key, RomDirectoryEntry *out_dir_entry, Position pos, RomPathTool::RomEntryName name, const RomPathChar *path) const {
AMS_ASSERT(out_pos != nullptr);
AMS_ASSERT(out_dir_key != nullptr);
AMS_ASSERT(out_dir_entry != nullptr);
RomEntryKey gp_key = {};
RomDirectoryEntry gp_entry = {};
R_TRY(this->dir_table.GetByPosition(std::addressof(gp_key), std::addressof(gp_entry), nullptr, nullptr, pos));
out_dir_key->key.parent = gp_key.parent;
R_TRY(RomPathTool::GetParentDirectoryName(std::addressof(out_dir_key->name), name, path));
R_TRY(this->GetDirectoryEntry(out_pos, out_dir_entry, *out_dir_key));
return ResultSuccess();
}
Result FindParentDirectoryRecursive(Position *out_pos, EntryKey *out_dir_key, RomDirectoryEntry *out_dir_entry, RomPathTool::PathParser &parser, const RomPathChar *path) const {
AMS_ASSERT(out_pos != nullptr);
AMS_ASSERT(out_dir_key != nullptr);
AMS_ASSERT(out_dir_entry != nullptr);
Position dir_pos = RootPosition;
EntryKey dir_key = {};
RomDirectoryEntry dir_entry = {};
dir_key.key.parent = RootPosition;
R_TRY(parser.GetNextDirectoryName(std::addressof(dir_key.name)));
R_TRY(this->GetDirectoryEntry(std::addressof(dir_pos), std::addressof(dir_entry), dir_key));
Position parent_pos = dir_pos;
while (!parser.IsFinished()) {
EntryKey old_key = dir_key;
R_TRY(parser.GetNextDirectoryName(std::addressof(dir_key.name)));
if (RomPathTool::IsCurrentDirectory(dir_key.name)) {
dir_key = old_key;
continue;
} else if (RomPathTool::IsParentDirectory(dir_key.name)) {
R_UNLESS(parent_pos != RootPosition, fs::ResultDbmInvalidOperation());
R_TRY(this->GetGrandParent(std::addressof(parent_pos), std::addressof(dir_key), std::addressof(dir_entry), dir_key.key.parent, dir_key.name, path));
} else {
dir_key.key.parent = parent_pos;
R_TRY(this->GetDirectoryEntry(std::addressof(dir_pos), std::addressof(dir_entry), dir_key));
parent_pos = dir_pos;
}
}
*out_pos = parent_pos;
*out_dir_key = dir_key;
*out_dir_entry = dir_entry;
return ResultSuccess();
}
Result FindPathRecursive(EntryKey *out_parent_key, RomDirectoryEntry *out_parent_dir_entry, EntryKey *out_key, bool is_dir, const RomPathChar *path) const {
AMS_ASSERT(out_parent_key != nullptr);
AMS_ASSERT(out_parent_dir_entry != nullptr);
AMS_ASSERT(out_key != nullptr);
AMS_ASSERT(path != nullptr);
RomPathTool::PathParser parser;
R_TRY(parser.Initialize(path));
Position parent_pos = 0;
R_TRY(this->FindParentDirectoryRecursive(std::addressof(parent_pos), out_parent_key, out_parent_dir_entry, parser, path));
if (is_dir) {
RomPathTool::RomEntryName name = {};
R_TRY(parser.GetAsDirectoryName(std::addressof(name)));
if (RomPathTool::IsCurrentDirectory(name)) {
*out_key = *out_parent_key;
if (out_key->key.parent != RootPosition) {
Position pos = 0;
R_TRY(this->GetGrandParent(std::addressof(pos), out_parent_key, out_parent_dir_entry, out_key->key.parent, out_key->name, path));
}
} else if (RomPathTool::IsParentDirectory(name)) {
R_UNLESS(parent_pos != RootPosition, fs::ResultDbmInvalidOperation());
Position pos = 0;
RomDirectoryEntry cur_entry = {};
R_TRY(this->GetGrandParent(std::addressof(pos), out_key, std::addressof(cur_entry), out_parent_key->key.parent, out_parent_key->name, path));
if (out_key->key.parent != RootPosition) {
R_TRY(this->GetGrandParent(std::addressof(pos), out_parent_key, out_parent_dir_entry, out_key->key.parent, out_key->name, path));
}
} else {
out_key->name = name;
out_key->key.parent = (out_key->name.length > 0) ? parent_pos : RootPosition;
}
} else {
R_UNLESS(!parser.IsDirectoryPath(), fs::ResultDbmInvalidOperation());
out_key->key.parent = parent_pos;
R_TRY(parser.GetAsFileName(std::addressof(out_key->name)));
}
return ResultSuccess();
}
Result FindDirectoryRecursive(EntryKey *out_parent_key, RomDirectoryEntry *out_parent_dir_entry, EntryKey *out_key, const RomPathChar *path) const {
return this->FindPathRecursive(out_parent_key, out_parent_dir_entry, out_key, true, path);
}
Result FindFileRecursive(EntryKey *out_parent_key, RomDirectoryEntry *out_parent_dir_entry, EntryKey *out_key, const RomPathChar *path) const {
return this->FindPathRecursive(out_parent_key, out_parent_dir_entry, out_key, false, path);
}
Result CheckSameEntryExists(const EntryKey &key, Result if_exists) const {
/* Check dir */
{
Position pos = InvalidPosition;
RomDirectoryEntry entry = {};
const Result get_res = this->dir_table.Get(std::addressof(pos), std::addressof(entry), key);
if (!fs::ResultDbmKeyNotFound::Includes(get_res)) {
R_TRY(get_res);
return if_exists;
}
}
/* Check file */
{
Position pos = InvalidPosition;
RomFileEntry entry = {};
const Result get_res = this->file_table.Get(std::addressof(pos), std::addressof(entry), key);
if (!fs::ResultDbmKeyNotFound::Includes(get_res)) {
R_TRY(get_res);
return if_exists;
}
}
return ResultSuccess();
}
Result GetDirectoryEntry(Position *out_pos, RomDirectoryEntry *out_entry, const EntryKey &key) const {
AMS_ASSERT(out_pos != nullptr);
AMS_ASSERT(out_entry != nullptr);
const Result dir_res = this->dir_table.Get(out_pos, out_entry, key);
R_UNLESS(R_FAILED(dir_res), dir_res);
R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(dir_res), dir_res);
Position pos = 0;
RomFileEntry entry = {};
const Result file_res = this->file_table.Get(std::addressof(pos), std::addressof(entry), key);
R_UNLESS(R_FAILED(file_res), fs::ResultDbmInvalidOperation());
R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(file_res), fs::ResultDbmDirectoryNotFound());
return file_res;
}
Result GetDirectoryEntry(RomDirectoryEntry *out_entry, RomDirectoryId id) const {
AMS_ASSERT(out_entry != nullptr);
Position pos = ConvertToPosition(id);
RomEntryKey key = {};
const Result dir_res = this->dir_table.GetByPosition(std::addressof(key), out_entry, nullptr, nullptr, pos);
R_UNLESS(R_FAILED(dir_res), dir_res);
R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(dir_res), dir_res);
RomFileEntry entry = {};
const Result file_res = this->file_table.GetByPosition(std::addressof(key), std::addressof(entry), nullptr, nullptr, pos);
R_UNLESS(R_FAILED(file_res), fs::ResultDbmInvalidOperation());
R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(file_res), fs::ResultDbmDirectoryNotFound());
return file_res;
}
Result GetFileEntry(Position *out_pos, RomFileEntry *out_entry, const EntryKey &key) const {
AMS_ASSERT(out_pos != nullptr);
AMS_ASSERT(out_entry != nullptr);
const Result file_res = this->file_table.Get(out_pos, out_entry, key);
R_UNLESS(R_FAILED(file_res), file_res);
R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(file_res), file_res);
Position pos = 0;
RomDirectoryEntry entry = {};
const Result dir_res = this->dir_table.Get(std::addressof(pos), std::addressof(entry), key);
R_UNLESS(R_FAILED(dir_res), fs::ResultDbmInvalidOperation());
R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(dir_res), fs::ResultDbmFileNotFound());
return dir_res;
}
Result GetFileEntry(RomFileEntry *out_entry, RomFileId id) const {
AMS_ASSERT(out_entry != nullptr);
Position pos = ConvertToPosition(id);
RomEntryKey key = {};
const Result file_res = this->file_table.GetByPosition(std::addressof(key), out_entry, nullptr, nullptr, pos);
R_UNLESS(R_FAILED(file_res), file_res);
R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(file_res), file_res);
RomDirectoryEntry entry = {};
const Result dir_res = this->dir_table.GetByPosition(std::addressof(key), std::addressof(entry), nullptr, nullptr, pos);
R_UNLESS(R_FAILED(dir_res), fs::ResultDbmInvalidOperation());
R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(dir_res), fs::ResultDbmFileNotFound());
return dir_res;
}
Result GetDirectoryInformation(DirectoryInfo *out, const EntryKey &key) const {
AMS_ASSERT(out != nullptr);
Position pos = 0;
RomDirectoryEntry entry = {};
R_TRY(this->GetDirectoryEntry(std::addressof(pos), std::addressof(entry), key));
return ResultSuccess();
}
Result OpenFile(FileInfo *out, const EntryKey &key) const {
AMS_ASSERT(out != nullptr);
Position pos = 0;
RomFileEntry entry = {};
R_TRY(this->GetFileEntry(std::addressof(pos), std::addressof(entry), key));
*out = entry.info;
return ResultSuccess();
}
Result FindOpen(FindPosition *out, const EntryKey &key) const {
AMS_ASSERT(out != nullptr);
out->next_dir = InvalidPosition;
out->next_file = InvalidPosition;
Position pos = 0;
RomDirectoryEntry entry = {};
R_TRY(this->GetDirectoryEntry(std::addressof(pos), std::addressof(entry), key));
out->next_dir = entry.dir;
out->next_file = entry.file;
return ResultSuccess();
}
};
}

View File

@@ -0,0 +1,367 @@
/*
* 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.hpp>
#include <stratosphere/fssystem/fssystem_dbm_rom_types.hpp>
namespace ams::fssystem {
constexpr ALWAYS_INLINE u32 AlignRomAddress(u32 addr) {
return util::AlignUp(addr, sizeof(addr));
}
template<typename BucketStorageType, typename EntryStorageType, typename KeyType, typename ValueType, size_t MaxAuxiliarySize>
class RomKeyValueStorage {
public:
using BucketStorage = BucketStorageType;
using EntryStorage = EntryStorageType;
using Key = KeyType;
using Value = ValueType;
using Position = u32;
using BucketIndex = u32;
struct FindIndex {
BucketIndex ind;
Position pos;
};
static_assert(std::is_pod<FindIndex>::value);
private:
static constexpr inline Position InvalidPosition = ~Position();
struct Element {
Key key;
Value value;
Position next;
u32 size;
};
static_assert(std::is_pod<Element>::value);
private:
s64 bucket_offset;
u32 bucket_count;
BucketStorage *bucket_storage;
s64 kv_offset;
u32 kv_size;
EntryStorage *kv_storage;
u32 total_entry_size;
u32 entry_count;
public:
static constexpr u32 QueryEntrySize(u32 aux_size) {
return AlignRomAddress(sizeof(Element) + aux_size);
}
static constexpr u32 QueryBucketStorageSize(u32 num) {
return num * sizeof(Position);
}
static constexpr u32 QueryBucketCount(u32 size) {
return size / sizeof(Position);
}
static constexpr u32 QueryKeyValueStorageSize(u32 num) {
return num * sizeof(Element);
}
static Result Format(BucketStorage *bucket, s64 bucket_ofs, u32 bucket_count, EntryStorage *kv, s64 kv_ofs, u32 kv_size) {
AMS_ASSERT(bucket != nullptr);
AMS_ASSERT(kv != nullptr);
AMS_ASSERT(kv_size >= 0);
const Position pos = InvalidPosition;
for (s64 i = 0; i < bucket_count; i++) {
R_TRY(bucket->Write(bucket_ofs + i * sizeof(pos), std::addressof(pos), sizeof(pos)));
}
return ResultSuccess();
}
public:
RomKeyValueStorage() : bucket_offset(), bucket_count(), bucket_storage(), kv_offset(), kv_size(), kv_storage(), total_entry_size(), entry_count() { /* ... */ }
Result Initialize(BucketStorage *bucket, s64 bucket_ofs, u32 bucket_count, EntryStorage *kv, s64 kv_ofs, u32 kv_size) {
AMS_ASSERT(bucket != nullptr);
AMS_ASSERT(kv != nullptr);
AMS_ASSERT(bucket_count > 0);
this->bucket_storage = bucket;
this->bucket_offset = bucket_ofs;
this->bucket_count = bucket_count;
this->kv_storage = kv;
this->kv_offset = kv_ofs;
this->kv_size = kv_size;
return ResultSuccess();
}
void Finalize() {
this->bucket_storage = nullptr;
this->bucket_offset = 0;
this->bucket_count = 0;
this->kv_storage = nullptr;
this->kv_offset = 0;
this->kv_size = 0;
}
constexpr u32 GetTotalEntrySize() const {
return this->total_entry_size;
}
constexpr u32 GetFreeSize() const {
return (this->kv_size - this->total_entry_size);
}
constexpr u32 GetEntryCount() const {
return this->entry_count;
}
Result Add(const Key &key, u32 hash_key, const void *aux, size_t aux_size, const Value &value) {
AMS_ASSERT(aux != nullptr);
AMS_ASSERT(aux_size <= MaxAuxiliarySize);
Position pos;
return this->AddImpl(std::addressof(pos), key, hash_key, aux, aux_size, value);
}
Result Get(Value *out, const Key &key, u32 hash_key, const void *aux, size_t aux_size) {
AMS_ASSERT(aux != nullptr);
AMS_ASSERT(aux_size <= MaxAuxiliarySize);
Position pos;
return this->GetImpl(std::addressof(pos), out, key, hash_key, aux, aux_size);
}
void FindOpen(FindIndex *out) const {
AMS_ASSERT(out != nullptr);
out->ind = static_cast<BucketIndex>(-1);
out->pos = InvalidPosition;
}
Result FindNext(Key *out_key, Value *out_val, FindIndex *find) {
AMS_ASSERT(out_key != nullptr);
AMS_ASSERT(out_val != nullptr);
AMS_ASSERT(find != nullptr);
Element elem;
BucketIndex ind = find->ind;
R_UNLESS((ind < this->bucket_count) || ind == static_cast<BucketIndex>(-1), fs::ResultDbmFindKeyFinished());
while (true) {
if (find->pos != InvalidPosition) {
R_TRY(this->ReadKeyValue(std::addressof(elem), nullptr, nullptr, find->pos));
AMS_ASSERT(elem.next == InvalidPosition || elem.next < this->kv_size);
find->pos = elem.next;
*out_key = elem.key;
*out_val = elem.val;
return ResultSuccess();
}
while (true) {
ind++;
if (ind == this->bucket_count) {
find->ind = ind;
find->pos = InvalidPosition;
return fs::ResultDbmFindKeyFinished();
}
Position pos;
R_TRY(this->ReadBucket(std::addressof(pos), ind));
AMS_ASSERT(pos == InvalidPosition || pos < this->kv_size);
if (pos != InvalidPosition) {
find->ind = ind;
find->pos = pos;
break;
}
}
}
}
protected:
Result AddImpl(Position *out, const Key &key, u32 hash_key, const void *aux, size_t aux_size, const Value &value) {
Position pos, prev_pos;
Element elem;
AMS_ASSERT(out != nullptr);
AMS_ASSERT(this->bucket_count > 0);
AMS_ASSERT(this->kv_size >= 0);
const Result find_res = this->FindImpl(std::addressof(pos), std::addressof(prev_pos), std::addressof(elem), key, hash_key, aux, aux_size);
R_UNLESS(R_FAILED(find_res), fs::ResultDbmAlreadyExists());
R_UNLESS(fs::ResultDbmKeyNotFound::Includes(find_res), find_res);
R_TRY(this->AllocateEntry(std::addressof(pos), aux_size));
Position next_pos;
R_TRY(this->LinkEntry(std::addressof(next_pos), pos, hash_key));
elem = { key, value, next_pos, static_cast<u32>(aux_size) };
*out = pos;
R_TRY(this->WriteKeyValue(std::addressof(elem), pos, aux, aux_size, fs::WriteOption::None));
this->entry_count++;
return ResultSuccess();
}
Result GetImpl(Position *out_pos, Value *out_val, const Key &key, u32 hash_key, const void *aux, size_t aux_size) const {
Position pos, prev_pos;
Element elem;
AMS_ASSERT(out_pos != nullptr);
AMS_ASSERT(out_val != nullptr);
R_TRY(this->FindImpl(std::addressof(pos), std::addressof(prev_pos), std::addressof(elem), key, hash_key, aux, aux_size));
*out_pos = pos;
*out_val = elem.value;
return ResultSuccess();
}
Result GetByPosition(Key *out_key, Value *out_val, void *out_aux, size_t *out_aux_size, Position pos) const {
AMS_ASSERT(out_key != nullptr);
AMS_ASSERT(out_val != nullptr);
Element elem;
R_TRY(this->ReadKeyValue(std::addressof(elem), out_aux, out_aux_size, pos));
*out_key = elem.key;
*out_val = elem.value;
return ResultSuccess();
}
Result SetByPosition(Position pos, const Value &value, fs::WriteOption option) const {
Element elem;
R_TRY(this->ReadKeyValue(std::addressof(elem), nullptr, nullptr, pos));
elem.value = value;
return this->WriteKeyValue(std::addressof(elem), pos, nullptr, 0, option);
}
private:
BucketIndex HashToBucket(u32 hash_key) const {
return hash_key % this->bucket_count;
}
Result FindImpl(Position *out_pos, Position *out_prev, Element *out_elem, const Key &key, u32 hash_key, const void *aux, size_t aux_size) const {
AMS_ASSERT(out_pos != nullptr);
AMS_ASSERT(out_prev != nullptr);
AMS_ASSERT(out_elem != nullptr);
AMS_ASSERT(this->bucket_count > 0);
AMS_ASSERT(this->kv_size >= 0);
*out_pos = 0;
*out_prev = 0;
const BucketIndex ind = HashToBucket(hash_key);
Position cur;
R_TRY(this->ReadBucket(std::addressof(cur), ind));
AMS_ASSERT(cur == InvalidPosition || cur < this->kv_size);
R_UNLESS(cur != InvalidPosition, fs::ResultDbmKeyNotFound());
u8 buf[MaxAuxiliarySize];
while (true) {
size_t cur_aux_size;
R_TRY(this->ReadKeyValue(out_elem, buf, std::addressof(cur_aux_size), cur));
if (key.IsEqual(out_elem->key, aux, aux_size, buf, cur_aux_size)) {
*out_pos = cur;
return ResultSuccess();
}
*out_prev = cur;
cur = out_elem->next;
R_UNLESS(cur != InvalidPosition, fs::ResultDbmKeyNotFound());
}
}
Result AllocateEntry(Position *out, size_t aux_size) {
AMS_ASSERT(out != nullptr);
R_UNLESS(this->total_entry_size + sizeof(Element) + aux_size <= this->kv_size, fs::ResultDbmKeyFull());
*out = static_cast<Position>(this->total_entry_size);
this->total_entry_size = AlignRomAddress(this->total_entry_size + sizeof(Element) + static_cast<u32>(aux_size));
return ResultSuccess();
}
Result LinkEntry(Position *out, Position pos, u32 hash_key) {
AMS_ASSERT(out != nullptr);
const BucketIndex ind = HashToBucket(hash_key);
Position next;
R_TRY(this->ReadBucket(std::addressof(next), ind));
AMS_ASSERT(next == InvalidPosition || next < this->kv_size);
R_TRY(this->WriteBucket(pos, ind, fs::WriteOption::None));
*out = next;
return ResultSuccess();
}
Result ReadBucket(Position *out, BucketIndex ind) const {
AMS_ASSERT(out != nullptr);
AMS_ASSERT(this->bucket_storage != nullptr);
AMS_ASSERT(ind < this->bucket_count);
const s64 offset = this->bucket_offset + ind * sizeof(Position);
return this->bucket_storage->Read(offset, out, sizeof(*out));
}
Result WriteBucket(Position pos, BucketIndex ind, fs::WriteOption option) const {
AMS_ASSERT(this->bucket_storage != nullptr);
AMS_ASSERT(ind < this->bucket_count);
const s64 offset = this->bucket_offset + ind * sizeof(Position);
return this->bucket_storage.Write(offset, std::addressof(pos), sizeof(pos));
}
Result ReadKeyValue(Element *out, void *out_aux, size_t *out_aux_size, Position pos) const {
AMS_ASSERT(out != nullptr);
AMS_ASSERT(this->kv_storage != nullptr);
AMS_ASSERT(pos < this->kv_size);
const s64 offset = this->kv_offset + pos;
R_TRY(this->kv_storage->Read(offset, out, sizeof(*out)));
if (out_aux != nullptr && out_aux_size != nullptr) {
*out_aux_size = out->size;
if (out->size > 0) {
R_TRY(this->kv_storage->Read(offset + sizeof(*out), out_aux, out->size));
}
}
return ResultSuccess();
}
Result WriteKeyValue(const Element *elem, Position pos, const void *aux, size_t aux_size, fs::WriteOption option) const {
AMS_ASSERT(elem != nullptr);
AMS_ASSERT(this->kv_storage != nullptr);
AMS_ASSERT(pos < this->kv_size);
const s64 offset = this->kv_offset + pos;
R_TRY(this->kv_storage->Write(offset, elem, sizeof(*elem)));
if (aux != nullptr && aux_size > 0) {
R_TRY(this->kv_storage->Write(offset + sizeof(*elem), aux, aux_size));
}
return ResultSuccess();
}
};
}

View File

@@ -0,0 +1,114 @@
/*
* 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 <stratosphere/fssystem/fssystem_dbm_rom_types.hpp>
namespace ams::fssystem {
namespace RomPathTool {
constexpr inline u32 MaxPathLength = 0x300;
struct RomEntryName {
size_t length;
const RomPathChar *path;
};
static_assert(std::is_pod<RomEntryName>::value);
constexpr void InitializeRomEntryName(RomEntryName *entry) {
entry->length = 0;
}
constexpr inline bool IsSeparator(RomPathChar c) {
return c == RomStringTraits::DirectorySeparator;
}
constexpr inline bool IsNullTerminator(RomPathChar c) {
return c == RomStringTraits::NullTerminator;
}
constexpr inline bool IsDot(RomPathChar c) {
return c == RomStringTraits::Dot;
}
constexpr inline bool IsCurrentDirectory(const RomEntryName &name) {
return name.length == 1 && IsDot(name.path[0]);
}
constexpr inline bool IsCurrentDirectory(const RomPathChar *p, size_t length) {
return length == 1 && IsDot(p[0]);
}
constexpr inline bool IsCurrentDirectory(const RomPathChar *p) {
return IsDot(p[0]) && IsNullTerminator(p[1]);
}
constexpr inline bool IsParentDirectory(const RomEntryName &name) {
return name.length == 2 && IsDot(name.path[0]) && IsDot(name.path[1]);
}
constexpr inline bool IsParentDirectory(const RomPathChar *p) {
return IsDot(p[0]) && IsDot(p[1]) && IsNullTerminator(p[2]);
}
constexpr inline bool IsParentDirectory(const RomPathChar *p, size_t length) {
return length == 2 && IsDot(p[0]) && IsDot(p[1]);
}
constexpr inline bool IsEqualPath(const RomPathChar *lhs, const RomPathChar *rhs, size_t length) {
return std::strncmp(lhs, rhs, length) == 0;
}
constexpr inline bool IsEqualName(const RomEntryName &lhs, const RomPathChar *rhs) {
if (strnlen(rhs, MaxPathLength) != lhs.length) {
return false;
}
return IsEqualPath(lhs.path, rhs, lhs.length);
}
constexpr inline bool IsEqualName(const RomEntryName &lhs, const RomEntryName &rhs) {
if (lhs.length != rhs.length) {
return false;
}
return IsEqualPath(lhs.path, rhs.path, lhs.length);
}
Result GetParentDirectoryName(RomEntryName *out, const RomEntryName &cur, const RomPathChar *p);
class PathParser {
private:
const RomPathChar *prev_path_start;
const RomPathChar *prev_path_end;
const RomPathChar *next_path;
bool finished;
public:
constexpr PathParser() : prev_path_start(), prev_path_end(), next_path(), finished() { /* ... */ }
Result Initialize(const RomPathChar *path);
void Finalize();
bool IsFinished() const;
bool IsDirectoryPath() const;
Result GetAsDirectoryName(RomEntryName *out) const;
Result GetAsFileName(RomEntryName *out) const;
Result GetNextDirectoryName(RomEntryName *out);
};
}
}

View File

@@ -0,0 +1,59 @@
/*
* 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 <stratosphere/fs/fs_common.hpp>
namespace ams::fssystem {
using RomPathChar = char;
using RomFileId = s32;
using RomDirectoryId = s32;
struct RomFileSystemInformation {
s64 size;
s64 directory_bucket_offset;
s64 directory_bucket_size;
s64 directory_entry_offset;
s64 directory_entry_size;
s64 file_bucket_offset;
s64 file_bucket_size;
s64 file_entry_offset;
s64 file_entry_size;
s64 body_offset;
};
static_assert(std::is_pod<RomFileSystemInformation>::value);
static_assert(sizeof(RomFileSystemInformation) == 0x50);
struct RomDirectoryInfo {
/* ... */
};
static_assert(std::is_pod<RomDirectoryInfo>::value);
struct RomFileInfo {
fs::Int64 offset;
fs::Int64 size;
};
static_assert(std::is_pod<RomFileInfo>::value);
namespace RomStringTraits {
constexpr inline char DirectorySeparator = '/';
constexpr inline char NullTerminator = '\x00';
constexpr inline char Dot = '.';
}
}

View File

@@ -0,0 +1,112 @@
/*
* 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.hpp>
#include <stratosphere/fs/impl/fs_newable.hpp>
namespace ams::fssystem {
constexpr inline size_t BufferPoolAlignment = 4_KB;
constexpr inline size_t BufferPoolWorkSize = 320;
class PooledBuffer {
NON_COPYABLE(PooledBuffer);
private:
char *buffer;
size_t size;
private:
static size_t GetAllocatableSizeMaxCore(bool large);
public:
static size_t GetAllocatableSizeMax() { return GetAllocatableSizeMaxCore(false); }
static size_t GetAllocatableParticularlyLargeSizeMax() { return GetAllocatableSizeMaxCore(true); }
private:
void Swap(PooledBuffer &rhs) {
std::swap(this->buffer, rhs.buffer);
std::swap(this->size, rhs.size);
}
public:
/* Constructor/Destructor. */
constexpr PooledBuffer() : buffer(), size() { /* ... */ }
PooledBuffer(size_t ideal_size, size_t required_size) : buffer(), size() {
this->Allocate(ideal_size, required_size);
}
~PooledBuffer() {
this->Deallocate();
}
/* Move and assignment. */
explicit PooledBuffer(PooledBuffer &&rhs) : buffer(rhs.buffer), size(rhs.size) {
rhs.buffer = nullptr;
rhs.size = 0;
}
PooledBuffer &operator=(PooledBuffer &&rhs) {
PooledBuffer(std::move(rhs)).Swap(*this);
return *this;
}
/* Allocation API. */
void Allocate(size_t ideal_size, size_t required_size) {
return this->AllocateCore(ideal_size, required_size, false);
}
void AllocateParticularlyLarge(size_t ideal_size, size_t required_size) {
return this->AllocateCore(ideal_size, required_size, true);
}
void Shrink(size_t ideal_size);
void Deallocate() {
/* Shrink the buffer to empty. */
this->Shrink(0);
AMS_ASSERT(this->buffer == nullptr);
}
char *GetBuffer() const {
AMS_ASSERT(this->buffer != nullptr);
return this->buffer;
}
size_t GetSize() const {
AMS_ASSERT(this->buffer != nullptr);
return this->size;
}
private:
void AllocateCore(size_t ideal_size, size_t required_size, bool large);
};
Result InitializeBufferPool(char *buffer, size_t size);
Result InitializeBufferPool(char *buffer, size_t size, char *work, size_t work_size);
bool IsPooledBuffer(const void *buffer);
size_t GetPooledBufferRetriedCount();
size_t GetPooledBufferReduceAllocationCount();
size_t GetPooledBufferFreeSizePeak();
void ClearPooledBufferPeak();
void RegisterAdditionalDeviceAddress(uintptr_t address, size_t size);
void UnregisterAdditionalDeviceAddress(uintptr_t address);
bool IsAdditionalDeviceAddress(const void *ptr);
inline bool IsDeviceAddress(const void *buffer) {
return IsPooledBuffer(buffer) || IsAdditionalDeviceAddress(buffer);
}
}

View File

@@ -0,0 +1,71 @@
/*
* 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.hpp>
#include <stratosphere/fs/fsa/fs_ifilesystem.hpp>
#include <stratosphere/fs/impl/fs_newable.hpp>
#include <stratosphere/fssystem/fssystem_dbm_hierarchical_rom_file_table.hpp>
#include <stratosphere/fs/fs_istorage.hpp>
namespace ams::fssystem {
class RomFsFileSystem : public fs::fsa::IFileSystem, public fs::impl::Newable {
NON_COPYABLE(RomFsFileSystem);
public:
using RomFileTable = HierarchicalRomFileTable<fs::IStorage, fs::IStorage, fs::IStorage, fs::IStorage>;
private:
RomFileTable rom_file_table;
fs::IStorage *base_storage;
std::shared_ptr<fs::IStorage> shared_storage;
std::unique_ptr<fs::IStorage> dir_bucket_storage;
std::unique_ptr<fs::IStorage> dir_entry_storage;
std::unique_ptr<fs::IStorage> file_bucket_storage;
std::unique_ptr<fs::IStorage> file_entry_storage;
s64 entry_size;
private:
Result GetFileInfo(RomFileTable::FileInfo *out, const char *path);
public:
static Result GetRequiredWorkingMemorySize(size_t *out, fs::IStorage *storage);
public:
RomFsFileSystem();
virtual ~RomFsFileSystem() override;
Result Initialize(fs::IStorage *base, void *work, size_t work_size, bool use_cache);
Result Initialize(std::shared_ptr<fs::IStorage> base, void *work, size_t work_size, bool use_cache);
fs::IStorage *GetBaseStorage();
RomFileTable *GetRomFileTable();
Result GetFileBaseOffset(s64 *out, const char *path);
public:
virtual Result CreateFileImpl(const char *path, s64 size, int flags) override;
virtual Result DeleteFileImpl(const char *path) override;
virtual Result CreateDirectoryImpl(const char *path) override;
virtual Result DeleteDirectoryImpl(const char *path) override;
virtual Result DeleteDirectoryRecursivelyImpl(const char *path) override;
virtual Result RenameFileImpl(const char *old_path, const char *new_path) override;
virtual Result RenameDirectoryImpl(const char *old_path, const char *new_path) override;
virtual Result GetEntryTypeImpl(fs::DirectoryEntryType *out, const char *path) override;
virtual Result OpenFileImpl(std::unique_ptr<fs::fsa::IFile> *out_file, const char *path, fs::OpenMode mode) override;
virtual Result OpenDirectoryImpl(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const char *path, fs::OpenDirectoryMode mode) override;
virtual Result CommitImpl() override;
virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) override;
virtual Result CleanDirectoryRecursivelyImpl(const char *path) override;
/* These aren't accessible as commands. */
virtual Result CommitProvisionallyImpl(s64 counter) override;
};
}

View File

@@ -0,0 +1,39 @@
/*
* 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.hpp>
#include <stratosphere/os.hpp>
namespace ams::fssystem {
class ScopedThreadPriorityChanger {
public:
enum class Mode {
Absolute,
Relative,
};
private:
/* TODO */
public:
ALWAYS_INLINE explicit ScopedThreadPriorityChanger(s32 priority, Mode mode) {
/* TODO */
}
ALWAYS_INLINE ~ScopedThreadPriorityChanger() {
/* TODO */
}
};
}

View File

@@ -170,4 +170,6 @@ namespace ams::fssystem {
}
}
void AddCounter(void *counter, size_t counter_size, u64 value);
}

View File

@@ -14,15 +14,16 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "../../fs/fs_common.hpp"
#include "../../fs/fsa/fs_ifile.hpp"
#include "../../fs/fsa/fs_idirectory.hpp"
#include "../../fs/fsa/fs_ifilesystem.hpp"
#include <stratosphere/fs/fs_common.hpp>
#include <stratosphere/fs/fsa/fs_ifile.hpp>
#include <stratosphere/fs/fsa/fs_idirectory.hpp>
#include <stratosphere/fs/fsa/fs_ifilesystem.hpp>
#include <stratosphere/fs/impl/fs_newable.hpp>
namespace ams::fssystem::impl {
template<typename Impl>
class IPathResolutionFileSystem : public fs::fsa::IFileSystem {
class IPathResolutionFileSystem : public fs::fsa::IFileSystem, public fs::impl::Newable {
NON_COPYABLE(IPathResolutionFileSystem);
private:
std::shared_ptr<fs::fsa::IFileSystem> shared_fs;

View File

@@ -37,7 +37,7 @@ namespace ams::kvdb {
rhs.size = 0;
}
AutoBuffer& operator=(AutoBuffer &&rhs) {
AutoBuffer &operator=(AutoBuffer &&rhs) {
AutoBuffer(std::move(rhs)).Swap(*this);
return *this;
}

View File

@@ -70,7 +70,7 @@ namespace ams::kvdb {
Path GetPath(const void *key, size_t key_size);
Result GetKey(size_t *out_size, void *out_key, size_t max_out_size, const FileName &file_name);
public:
FileKeyValueStore() { /* ... */ }
FileKeyValueStore() : lock(false) { /* ... */ }
/* Basic accessors. */
Result Initialize(const char *dir);

View File

@@ -85,7 +85,7 @@ namespace ams::lmem::impl {
void *heap_start;
void *heap_end;
os::Mutex mutex;
os::MutexType mutex;
u8 option;
ImplementationHeapHead impl_head;
};

View File

@@ -28,7 +28,7 @@ namespace ams::lr {
std::shared_ptr<IRegisteredLocationResolver> registered_location_resolver = nullptr;
std::shared_ptr<IAddOnContentLocationResolver> add_on_content_location_resolver = nullptr;
os::Mutex mutex;
os::Mutex mutex{false};
public:
/* Actual commands. */
virtual Result OpenLocationResolver(sf::Out<std::shared_ptr<ILocationResolver>> out, ncm::StorageId storage_id) override;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2020 Adubbz, Atmosphère-NX
* Copyright (c) 2019-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,

View File

@@ -17,13 +17,25 @@
#pragma once
#include <stratosphere/ncm/ncm_ids.hpp>
#include <stratosphere/ncm/ncm_max_count.hpp>
#include <stratosphere/ncm/ncm_program_location.hpp>
#include <stratosphere/ncm/ncm_auto_buffer.hpp>
#include <stratosphere/ncm/ncm_make_path.hpp>
#include <stratosphere/ncm/ncm_content_id_utils.hpp>
#include <stratosphere/ncm/ncm_content_info_utils.hpp>
#include <stratosphere/ncm/ncm_content_meta.hpp>
#include <stratosphere/ncm/ncm_content_meta_extended_data.hpp>
#include <stratosphere/ncm/ncm_content_meta_database.hpp>
#include <stratosphere/ncm/ncm_content_storage.hpp>
#include <stratosphere/ncm/ncm_content_manager_impl.hpp>
#include <stratosphere/ncm/ncm_content_meta_utils.hpp>
#include <stratosphere/ncm/ncm_firmware_variation.hpp>
#include <stratosphere/ncm/ncm_install_task_base.hpp>
#include <stratosphere/ncm/ncm_install_task_data.hpp>
#include <stratosphere/ncm/ncm_install_task_occupied_size.hpp>
#include <stratosphere/ncm/ncm_package_install_task_base.hpp>
#include <stratosphere/ncm/ncm_package_install_task.hpp>
#include <stratosphere/ncm/ncm_package_system_update_task.hpp>
#include <stratosphere/ncm/ncm_submission_package_install_task.hpp>
#include <stratosphere/ncm/ncm_storage_utils.hpp>
#include <stratosphere/ncm/ncm_api.hpp>

View File

@@ -37,7 +37,7 @@ namespace ams::ncm {
rhs.size = 0;
}
AutoBuffer& operator=(AutoBuffer &&rhs) {
AutoBuffer &operator=(AutoBuffer &&rhs) {
AutoBuffer(std::move(rhs)).Swap(*this);
return *this;
}

View File

@@ -21,19 +21,19 @@ namespace ams::ncm {
struct alignas(4) ContentId {
util::Uuid uuid;
bool operator==(const ContentId& other) const {
bool operator==(const ContentId &other) const {
return this->uuid == other.uuid;
}
bool operator!=(const ContentId& other) const {
bool operator!=(const ContentId &other) const {
return this->uuid != other.uuid;
}
bool operator==(const util::Uuid& other) const {
bool operator==(const util::Uuid &other) const {
return this->uuid == other;
}
bool operator!=(const util::Uuid& other) const {
bool operator!=(const util::Uuid &other) const {
return this->uuid != other;
}
};

View File

@@ -32,6 +32,10 @@ namespace ams::ncm {
ContentIdString GetContentIdString(ContentId id);
void GetStringFromContentId(char *dst, size_t dst_size, ContentId id);
void GetStringFromRightsId(char *dst, size_t dst_size, fs::RightsId id);
void GetTicketFileStringFromRightsId(char *dst, size_t dst_size, fs::RightsId id);
void GetCertificateFileStringFromRightsId(char *dst, size_t dst_size, fs::RightsId id);
std::optional<ContentId> GetContentIdFromString(const char *str, size_t len);

View File

@@ -25,6 +25,13 @@ namespace ams::ncm {
u8 data[crypto::Sha256Generator::HashSize];
};
enum class InstallState : u8 {
NotPrepared,
Prepared,
Installed,
AlreadyExists,
};
struct PackagedContentInfo {
Digest digest;
ContentInfo info;
@@ -42,4 +49,74 @@ namespace ams::ncm {
}
};
struct InstallContentInfo {
Digest digest;
crypto::Sha256Context context;
u8 buffered_data[crypto::Sha256Generator::BlockSize];
u64 buffered_data_size;
ContentInfo info;
PlaceHolderId placeholder_id;
ContentMetaType meta_type;
InstallState install_state;
bool verify_digest;
StorageId storage_id;
bool is_temporary;
bool is_sha256_calculated;
s64 written;
constexpr const ContentId &GetId() const {
return this->info.GetId();
}
constexpr const u64 GetSize() const {
return this->info.GetSize();
}
constexpr const ContentType GetType() const {
return this->info.GetType();
}
constexpr const u8 GetIdOffset() const {
return this->info.GetIdOffset();
}
constexpr const PlaceHolderId &GetPlaceHolderId() const {
return this->placeholder_id;
}
constexpr const ContentMetaType GetContentMetaType() const {
return this->meta_type;
}
constexpr const InstallState GetInstallState() const {
return this->install_state;
}
constexpr const StorageId GetStorageId() const {
return this->storage_id;
}
constexpr s64 GetSizeWritten() const {
return this->written;
}
static constexpr InstallContentInfo Make(const ContentInfo &info, ContentMetaType meta_type) {
return {
.info = info,
.meta_type = meta_type,
};
}
static constexpr InstallContentInfo Make(const PackagedContentInfo &info, ContentMetaType meta_type) {
return {
.digest = info.digest,
.info = info.info,
.meta_type = meta_type,
.verify_digest = true,
};
}
};
static_assert(sizeof(InstallContentInfo) == 0xC8);
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright (c) 2019-2020 Adubbz, 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.hpp>
#include <stratosphere/ncm/ncm_content_meta_key.hpp>
namespace ams::ncm {
constexpr inline s64 MaxClusterSize = 256_KB;
s64 CalculateRequiredSize(s64 file_size, s64 cluster_size = MaxClusterSize);
s64 CalculateRequiredSizeForExtension(s64 file_size, s64 cluster_size = MaxClusterSize);
class ContentMetaDatabase;
Result EstimateRequiredSize(s64 *out_size, const ContentMetaKey &key, ContentMetaDatabase *db);
}

View File

@@ -83,7 +83,7 @@ namespace ams::ncm {
ContentMetaDatabaseRoot() { /* ... */ }
};
private:
os::RecursiveMutex mutex;
os::Mutex mutex;
bool initialized;
ContentStorageRoot content_storage_roots[MaxContentStorageRoots];
ContentMetaDatabaseRoot content_meta_database_roots[MaxContentMetaDatabaseRoots];
@@ -91,7 +91,7 @@ namespace ams::ncm {
u32 num_content_meta_entries;
RightsIdCache rights_id_cache;
public:
ContentManagerImpl() : initialized(false) { /* ... */ };
ContentManagerImpl() : mutex(true), initialized(false) { /* ... */ };
~ContentManagerImpl();
public:
Result Initialize(const ContentManagerConfig &config);

View File

@@ -18,6 +18,7 @@
#include <stratosphere/ncm/ncm_content_meta_key.hpp>
#include <stratosphere/ncm/ncm_content_info.hpp>
#include <stratosphere/ncm/ncm_content_info_data.hpp>
#include <stratosphere/ncm/ncm_firmware_variation.hpp>
#include <stratosphere/ncm/ncm_storage_id.hpp>
namespace ams::ncm {
@@ -72,15 +73,16 @@ namespace ams::ncm {
u8 attributes;
u8 storage_id;
ContentInstallType install_type;
u8 reserved_17;
bool committed;
u32 required_download_system_version;
u8 reserved_1C[4];
};
static_assert(sizeof(PackagedContentMetaHeader) == 0x20);
static_assert(OFFSETOF(PackagedContentMetaHeader, reserved_0D) == 0x0D);
static_assert(OFFSETOF(PackagedContentMetaHeader, reserved_17) == 0x17);
static_assert(OFFSETOF(PackagedContentMetaHeader, reserved_1C) == 0x1C);
using InstallContentMetaHeader = PackagedContentMetaHeader;
struct ApplicationMetaExtendedHeader {
PatchId patch_id;
u32 required_system_version;
@@ -106,6 +108,10 @@ namespace ams::ncm {
u32 padding;
};
struct SystemUpdateMetaExtendedHeader {
u32 extended_data_size;
};
template<typename ContentMetaHeaderType, typename ContentInfoType>
class ContentMetaAccessor {
public:
@@ -194,6 +200,18 @@ namespace ams::ncm {
return nullptr;
}
s64 CalculateContentRequiredSize() const {
s64 required_size = 0;
for (size_t i = 0; i < this->GetContentCount(); i++) {
required_size += CalculateRequiredSize(this->GetContentInfo(i)->info.GetSize());
}
return required_size;
}
void SetStorageId(StorageId storage_id) {
this->GetWritableHeader()->storage_id = static_cast<u8>(storage_id);
}
public:
const void *GetData() const {
return this->data;
@@ -203,6 +221,11 @@ namespace ams::ncm {
return this->size;
}
HeaderType *GetWritableHeader() const {
AMS_ABORT_UNLESS(this->is_header_valid);
return reinterpret_cast<HeaderType *>(this->data);
}
const HeaderType *GetHeader() const {
AMS_ABORT_UNLESS(this->is_header_valid);
return static_cast<const HeaderType *>(this->data);
@@ -252,9 +275,10 @@ namespace ams::ncm {
size_t GetExtendedDataSize() const {
switch (this->GetHeader()->type) {
case ContentMetaType::Patch: return this->GetExtendedHeader<PatchMetaExtendedHeader>()->extended_data_size;
case ContentMetaType::Delta: return this->GetExtendedHeader<DeltaMetaExtendedHeader>()->extended_data_size;
default: return 0;
case ContentMetaType::Patch: return this->GetExtendedHeader<PatchMetaExtendedHeader>()->extended_data_size;
case ContentMetaType::Delta: return this->GetExtendedHeader<DeltaMetaExtendedHeader>()->extended_data_size;
case ContentMetaType::SystemUpdate: return this->GetExtendedHeaderSize() == 0 ? 0 : this->GetExtendedHeader<SystemUpdateMetaExtendedHeader>()->extended_data_size;
default: return 0;
}
}
@@ -275,6 +299,10 @@ namespace ams::ncm {
return false;
}
StorageId GetStorageId() const {
return static_cast<StorageId>(this->GetHeader()->storage_id);
}
std::optional<ApplicationId> GetApplicationId(const ContentMetaKey &key) const {
switch (key.type) {
case ContentMetaType::Application: return ApplicationId{ key.id };
@@ -301,10 +329,15 @@ namespace ams::ncm {
public:
constexpr PackagedContentMetaReader(const void *data, size_t size) : ContentMetaAccessor(data, size) { /* ... */ }
size_t CalculateConvertContentMetaSize() const;
size_t CalculateConvertInstallContentMetaSize() const;
void ConvertToInstallContentMeta(void *dst, size_t size, const InstallContentInfo &meta);
size_t CalculateConvertContentMetaSize() const;
void ConvertToContentMeta(void *dst, size_t size, const ContentInfo &meta);
Result CalculateConvertFragmentOnlyInstallContentMetaSize(size_t *out_size, u32 source_version) const;
Result ConvertToFragmentOnlyInstallContentMeta(void *dst, size_t size, const InstallContentInfo &content_info, u32 source_version);
size_t CountDeltaFragments() const;
static constexpr size_t CalculateSize(ContentMetaType type, size_t content_count, size_t content_meta_count, size_t extended_data_size) {
@@ -312,4 +345,27 @@ namespace ams::ncm {
}
};
class InstallContentMetaReader : public ContentMetaAccessor<InstallContentMetaHeader, InstallContentInfo> {
public:
constexpr InstallContentMetaReader(const void *data, size_t size) : ContentMetaAccessor(data, size) { /* ... */ }
using ContentMetaAccessor::CalculateSize;
using ContentMetaAccessor::CalculateContentRequiredSize;
using ContentMetaAccessor::GetStorageId;
size_t CalculateConvertSize() const;
void ConvertToContentMeta(void *dst, size_t size) const;
};
class InstallContentMetaWriter : public ContentMetaAccessor<InstallContentMetaHeader, InstallContentInfo> {
public:
InstallContentMetaWriter(const void *data, size_t size) : ContentMetaAccessor(data, size) { /* ... */ }
using ContentMetaAccessor::CalculateSize;
using ContentMetaAccessor::CalculateContentRequiredSize;
using ContentMetaAccessor::GetWritableContentInfo;
using ContentMetaAccessor::SetStorageId;
};
}

View File

@@ -0,0 +1,384 @@
/*
* 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 <stratosphere/ncm/ncm_content_info.hpp>
#include <stratosphere/ncm/ncm_content_meta_id.hpp>
#include <stratosphere/ncm/ncm_content_meta.hpp>
#include <stratosphere/ncm/ncm_firmware_variation.hpp>
namespace ams::ncm {
enum class UpdateType : u8 {
ApplyAsDelta = 0,
Overwrite = 1,
Create = 2,
};
struct FragmentIndicator {
u16 content_info_index;
u16 fragment_index;
};
struct FragmentSet {
ContentId source_content_id;
ContentId destination_content_id;
u32 source_size_low;
u16 source_size_high;
u16 destination_size_high;
u32 destination_size_low;
u16 fragment_count;
ContentType target_content_type;
UpdateType update_type;
u8 reserved[4];
constexpr s64 GetSourceSize() const {
return (static_cast<s64>(this->source_size_high) << 32) + this->source_size_low;
}
constexpr s64 GetDestinationSize() const {
return (static_cast<s64>(this->destination_size_high) << 32) + this->destination_size_low;
}
constexpr void SetSourceSize(s64 size) {
this->source_size_low = size & 0xFFFFFFFFll;
this->source_size_high = static_cast<u16>(size >> 32);
}
constexpr void SetDestinationSize(s64 size) {
this->destination_size_low = size & 0xFFFFFFFFll;
this->destination_size_high = static_cast<u16>(size >> 32);
}
};
struct SystemUpdateMetaExtendedDataHeader {
u32 unk; // Always seems to be set to 2
u32 firmware_variation_count;
};
struct DeltaMetaExtendedDataHeader {
PatchId source_id;
PatchId destination_id;
u32 source_version;
u32 destination_version;
u16 fragment_set_count;
u8 reserved[6];
};
struct PatchMetaExtendedDataHeader {
u32 history_count;
u32 delta_history_count;
u32 delta_count;
u32 fragment_set_count;
u32 history_content_total_count;
u32 delta_content_total_count;
u8 reserved[4];
};
struct PatchHistoryHeader {
ContentMetaKey key;
Digest digest;
u16 content_count;
u8 reserved[2];
};
struct PatchDeltaHistory {
PatchId source_id;
PatchId destination_id;
u32 source_version;
u32 destination_version;
u64 download_size;
u8 reserved[4];
};
struct PatchDeltaHeader {
DeltaMetaExtendedDataHeader delta;
u16 content_count;
u8 reserved[4];
};
template<typename MemberTypePointer, typename DataTypePointer>
class PatchMetaExtendedDataReaderWriterBase {
private:
MemberTypePointer data;
const size_t size;
public:
PatchMetaExtendedDataReaderWriterBase(MemberTypePointer d, size_t sz) : data(d), size(sz) { /* ... */ }
protected:
s32 CountFragmentSet(s32 delta_index) const {
auto delta_header = this->GetPatchDeltaHeader(0);
s32 count = 0;
for (s32 i = 0; i < delta_index; i++) {
count += delta_header[i].delta.fragment_set_count;
}
return count;
}
s32 CountHistoryContent(s32 history_index) const {
auto history_header = this->GetPatchHistoryHeader(0);
s32 count = 0;
for (s32 i = 0; i < history_index; i++) {
count += history_header[i].content_count;
}
return count;
}
s32 CountDeltaContent(s32 delta_index) const {
auto delta_header = this->GetPatchDeltaHeader(0);
s32 count = 0;
for (s32 i = 0; i < delta_index; i++) {
count += delta_header[i].content_count;
}
return count;
}
s32 CountFragment(s32 index) const {
auto fragment_set = this->GetFragmentSet(0, 0);
s32 count = 0;
for (s32 i = 0; i < index; i++) {
count += fragment_set[i].fragment_count;
}
return count;
}
DataTypePointer GetHeaderAddress() const {
return reinterpret_cast<DataTypePointer>(this->data);
}
DataTypePointer GetPatchHistoryHeaderAddress(s32 index) const {
auto header = this->GetHeader();
AMS_ABORT_UNLESS(static_cast<u16>(index) < header->history_count);
return this->GetHeaderAddress()
+ sizeof(PatchMetaExtendedDataHeader)
+ sizeof(PatchHistoryHeader) * index;
}
DataTypePointer GetPatchDeltaHistoryAddress(s32 index) const {
auto header = this->GetHeader();
AMS_ABORT_UNLESS(static_cast<u16>(index) < header->delta_history_count);
return this->GetHeaderAddress()
+ sizeof(PatchMetaExtendedDataHeader)
+ sizeof(PatchHistoryHeader) * header->history_count
+ sizeof(PatchDeltaHistory) * index;
}
DataTypePointer GetPatchDeltaHeaderAddress(s32 index) const {
auto header = this->GetHeader();
AMS_ABORT_UNLESS(static_cast<u16>(index) < header->delta_count);
return this->GetHeaderAddress()
+ sizeof(PatchMetaExtendedDataHeader)
+ sizeof(PatchHistoryHeader) * header->history_count
+ sizeof(PatchDeltaHistory) * header->delta_history_count
+ sizeof(PatchDeltaHeader) * index;
}
DataTypePointer GetFragmentSetAddress(s32 delta_index, s32 fragment_set_index) const {
auto header = this->GetHeader();
AMS_ABORT_UNLESS(static_cast<u16>(delta_index) < header->delta_count);
auto delta_header = this->GetPatchDeltaHeader(delta_index);
AMS_ABORT_UNLESS(static_cast<u16>(fragment_set_index) < delta_header->delta.fragment_set_count);
auto previous_fragment_set_count = this->CountFragmentSet(delta_index);
return this->GetHeaderAddress()
+ sizeof(PatchMetaExtendedDataHeader)
+ sizeof(PatchHistoryHeader) * header->history_count
+ sizeof(PatchDeltaHistory) * header->delta_history_count
+ sizeof(PatchDeltaHeader) * header->delta_count
+ sizeof(FragmentSet) * (previous_fragment_set_count + fragment_set_index);
}
DataTypePointer GetPatchHistoryContentInfoAddress(s32 history_index, s32 content_index) const {
auto header = this->GetHeader();
auto history_header = this->GetPatchHistoryHeader(history_index);
AMS_ABORT_UNLESS(static_cast<u16>(content_index) < history_header->content_count);
auto prev_history_count = this->CountHistoryContent(history_index);
return this->GetHeaderAddress()
+ sizeof(PatchMetaExtendedDataHeader)
+ sizeof(PatchHistoryHeader) * header->history_count
+ sizeof(PatchDeltaHistory) * header->delta_history_count
+ sizeof(PatchDeltaHeader) * header->delta_count
+ sizeof(FragmentSet) * header->fragment_set_count
+ sizeof(ContentInfo) * (prev_history_count + content_index);
}
DataTypePointer GetPatchDeltaPackagedContentInfoAddress(s32 delta_index, s32 content_index) const {
auto header = this->GetHeader();
auto delta_header = this->GetPatchDeltaHeader(delta_index);
AMS_ABORT_UNLESS(static_cast<u16>(content_index) < delta_header->content_count);
auto content_count = this->CountDeltaContent(delta_index);
return this->GetHeaderAddress()
+ sizeof(PatchMetaExtendedDataHeader)
+ sizeof(PatchHistoryHeader) * header->history_count
+ sizeof(PatchDeltaHistory) * header->delta_history_count
+ sizeof(PatchDeltaHeader) * header->delta_count
+ sizeof(FragmentSet) * header->fragment_set_count
+ sizeof(ContentInfo) * header->history_content_total_count
+ sizeof(PackagedContentInfo) * (content_count + content_index);
}
DataTypePointer GetFragmentIndicatorAddress(s32 delta_index, s32 fragment_set_index, s32 index) const {
auto header = this->GetHeader();
auto fragment_set = this->GetFragmentSet(delta_index, fragment_set_index);
AMS_ABORT_UNLESS(static_cast<u16>(index) < fragment_set->fragment_count);
auto fragment_set_count = this->CountFragmentSet(delta_index);
auto fragment_count = this->CountFragment(fragment_set_count + fragment_set_index);
return this->GetHeaderAddress()
+ sizeof(PatchMetaExtendedDataHeader)
+ sizeof(PatchHistoryHeader) * header->history_count
+ sizeof(PatchDeltaHistory) * header->delta_history_count
+ sizeof(PatchDeltaHeader) * header->delta_count
+ sizeof(FragmentSet) * header->fragment_set_count
+ sizeof(ContentInfo) * header->history_content_total_count
+ sizeof(PackagedContentInfo) * header->delta_content_total_count
+ sizeof(FragmentIndicator) * (fragment_count + index);
}
public:
const PatchMetaExtendedDataHeader *GetHeader() const {
return reinterpret_cast<const PatchMetaExtendedDataHeader *>(this->GetHeaderAddress());
}
const PatchHistoryHeader *GetPatchHistoryHeader(s32 index) const {
return reinterpret_cast<const PatchHistoryHeader *>(this->GetPatchHistoryHeaderAddress(index));
}
const PatchDeltaHistory *GetPatchDeltaHistory(s32 index) const {
return reinterpret_cast<const PatchDeltaHistory *>(this->GetPatchDeltaHistoryAddress(index));
}
const ContentInfo *GetPatchHistoryContentInfo(s32 history_index, s32 content_index) const {
return reinterpret_cast<const ContentInfo *>(this->GetPatchHistoryContentInfoAddress(history_index, content_index));
}
const PatchDeltaHeader *GetPatchDeltaHeader(s32 index) const {
return reinterpret_cast<const PatchDeltaHeader *>(this->GetPatchDeltaHeaderAddress(index));
}
const PackagedContentInfo *GetPatchDeltaPackagedContentInfo(s32 delta_index, s32 content_index) const {
return reinterpret_cast<const PackagedContentInfo *>(this->GetPatchDeltaPackagedContentInfoAddress(delta_index, content_index));
}
const FragmentSet *GetFragmentSet(s32 delta_index, s32 fragment_set_index) const {
return reinterpret_cast<const FragmentSet *>(this->GetFragmentSetIndex(delta_index, fragment_set_index));
}
const FragmentIndicator *GetFragmentIndicator(s32 delta_index, s32 fragment_set_index, s32 index) const {
return reinterpret_cast<const FragmentIndicator *>(this->GetFragmentIndicatorAddress(delta_index, fragment_set_index, index));
}
const FragmentIndicator *FindFragmentIndicator(s32 delta_index, s32 fragment_set_index, s32 fragment_index) const {
auto fragment_set = this->GetFragmentSet(delta_index, fragment_set_index);
auto fragment = this->GetFragmentIndicator(delta_index, fragment_set_index, 0);
for (s32 i = 0; i < fragment_set->fragment_count; i++) {
if (fragment[i].fragment_index == fragment_index) {
return std::addressof(fragment[i]);
}
}
return nullptr;
}
};
class PatchMetaExtendedDataReader : public PatchMetaExtendedDataReaderWriterBase<const void *, const u8 *> {
public:
PatchMetaExtendedDataReader(const void *data, size_t size) : PatchMetaExtendedDataReaderWriterBase(data, size) { /* ... */ }
};
class SystemUpdateMetaExtendedDataReaderWriterBase {
private:
void *data;
const size_t size;
bool is_header_valid;
protected:
constexpr SystemUpdateMetaExtendedDataReaderWriterBase(const void *d, size_t sz) : data(const_cast<void *>(d)), size(sz), is_header_valid(true) { /* ... */ }
constexpr SystemUpdateMetaExtendedDataReaderWriterBase(void *d, size_t sz) : data(d), size(sz), is_header_valid(false) { /* ... */ }
uintptr_t GetHeaderAddress() const {
return reinterpret_cast<uintptr_t>(this->data);
}
uintptr_t GetFirmwarVariationIdStartAddress() const {
return this->GetHeaderAddress() + sizeof(SystemUpdateMetaExtendedDataHeader);
}
uintptr_t GetFirmwareVariationIdAddress(size_t i) const {
return this->GetFirmwarVariationIdStartAddress() + i * sizeof(FirmwareVariationId);
}
uintptr_t GetFirmwareVariationInfoStartAddress() const {
return this->GetFirmwareVariationIdAddress(this->GetFirmwareVariationCount());
}
uintptr_t GetFirmwareVariationInfoAddress(size_t i) const {
return this->GetFirmwarVariationIdStartAddress() + i * sizeof(FirmwareVariationInfo);
}
uintptr_t GetContentMetaInfoStartAddress() const {
return this->GetFirmwareVariationInfoAddress(this->GetFirmwareVariationCount());
}
uintptr_t GetContentMetaInfoAddress(size_t i) const {
return this->GetContentMetaInfoStartAddress() + i * sizeof(ContentMetaInfo);
}
public:
const SystemUpdateMetaExtendedDataHeader *GetHeader() const {
AMS_ABORT_UNLESS(this->is_header_valid);
return reinterpret_cast<const SystemUpdateMetaExtendedDataHeader *>(this->GetHeaderAddress());
}
size_t GetFirmwareVariationCount() const {
return this->GetHeader()->firmware_variation_count;
}
const FirmwareVariationId *GetFirmwareVariationId(size_t i) const {
AMS_ABORT_UNLESS(i < this->GetFirmwareVariationCount());
return reinterpret_cast<FirmwareVariationId *>(this->GetFirmwareVariationIdAddress(i));
}
const FirmwareVariationInfo *GetFirmwareVariationInfo(size_t i) const {
AMS_ABORT_UNLESS(i < this->GetFirmwareVariationCount());
return reinterpret_cast<FirmwareVariationInfo *>(this->GetFirmwareVariationInfoAddress(i));
}
void GetContentMetaInfoList(Span<const ContentMetaInfo> *out_list, size_t i) const {
size_t preceding_content_meta_count = 0;
/* Count the number of preceding content metas. */
for (size_t j = 0; j < i; j++) {
preceding_content_meta_count += this->GetFirmwareVariationInfo(j)->content_meta_count;
}
/* Output the list. */
*out_list = Span<const ContentMetaInfo>(reinterpret_cast<const ContentMetaInfo *>(this->GetContentMetaInfoAddress(preceding_content_meta_count)), this->GetFirmwareVariationInfo(i)->content_meta_count);
}
};
class SystemUpdateMetaExtendedDataReader : public SystemUpdateMetaExtendedDataReaderWriterBase {
public:
constexpr SystemUpdateMetaExtendedDataReader(const void *data, size_t size) : SystemUpdateMetaExtendedDataReaderWriterBase(data, size) { /* ... */ }
};
}

View File

@@ -34,15 +34,15 @@ namespace ams::ncm {
ContentInstallType install_type;
u8 padding[2];
bool operator<(const ContentMetaKey& rhs) const {
bool operator<(const ContentMetaKey &rhs) const {
return std::tie(this->id, this->version, this->type, this->install_type) < std::tie(rhs.id, rhs.version, rhs.type, rhs.install_type);
}
constexpr bool operator==(const ContentMetaKey& rhs) const {
constexpr bool operator==(const ContentMetaKey &rhs) const {
return std::tie(this->id, this->version, this->type, this->install_type) == std::tie(rhs.id, rhs.version, rhs.type, rhs.install_type);
}
constexpr bool operator!=(const ContentMetaKey& rhs) const {
constexpr bool operator!=(const ContentMetaKey &rhs) const {
return !(*this == rhs);
}

View File

@@ -19,9 +19,12 @@
#include <stratosphere/ncm/ncm_content_storage.hpp>
#include <stratosphere/ncm/ncm_content_meta_key.hpp>
#include <stratosphere/ncm/ncm_content_meta_database.hpp>
#include <stratosphere/ncm/ncm_firmware_variation.hpp>
namespace ams::ncm {
Result ReadContentMetaPath(AutoBuffer *out, const char *path);
Result ReadVariationContentMetaInfoList(s32 *out_count, std::unique_ptr<ContentMetaInfo[]> *out_meta_infos, const Path &path, FirmwareVariationId firmware_variation_id);
}

View File

@@ -0,0 +1,40 @@
/*
* 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.hpp>
namespace ams::ncm {
struct FirmwareVariationInfo {
bool refer_to_base;
u8 _0x1[3];
u32 content_meta_count;
u8 reserved[0x18];
};
struct FirmwareVariationId {
u32 value;
};
constexpr inline bool operator==(const FirmwareVariationId &lhs, const FirmwareVariationId &rhs) {
return lhs.value == rhs.value;
}
constexpr inline bool operator!=(const FirmwareVariationId &lhs, const FirmwareVariationId &rhs) {
return lhs.value != rhs.value;
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2019-2020 Adubbz, 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
namespace ams::ncm {
enum class InstallProgressState : u8 {
NotPrepared = 0,
DataPrepared = 1,
Prepared = 2,
Downloaded = 3,
Committed = 4,
Fatal = 5,
};
struct InstallProgress {
InstallProgressState state;
u8 pad[3];
TYPED_STORAGE(Result) last_result;
s64 installed_size;
s64 total_size;
Result GetLastResult() const {
return util::GetReference(last_result);
}
void SetLastResult(Result result) {
*util::GetPointer(last_result) = result;
}
};
}

View File

@@ -0,0 +1,203 @@
/*
* Copyright (c) 2019-2020 Adubbz, 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 <stratosphere/ncm/ncm_install_task_data.hpp>
#include <stratosphere/ncm/ncm_install_task_occupied_size.hpp>
namespace ams::ncm {
enum class ListContentMetaKeyFilter : u8 {
All = 0,
Committed = 1,
NotCommitted = 2,
};
enum InstallConfig {
InstallConfig_None = (0 << 0),
InstallConfig_SystemUpdate = (1 << 2),
InstallConfig_RequiresExFatDriver = (1 << 3),
InstallConfig_IgnoreTicket = (1 << 4),
};
struct InstallThroughput {
s64 installed;
TimeSpan elapsed_time;
};
struct InstallContentMetaInfo {
ContentId content_id;
s64 content_size;
ContentMetaKey key;
bool verify_digest;
bool has_key;
Digest digest;
static constexpr InstallContentMetaInfo MakeVerifiable(const ContentId &cid, s64 sz, const ContentMetaKey &ky, const Digest &d) {
return {
.content_id = cid,
.content_size = sz,
.key = ky,
.verify_digest = true,
.has_key = true,
.digest = d,
};
}
static constexpr InstallContentMetaInfo MakeUnverifiable(const ContentId &cid, s64 sz, const ContentMetaKey &ky) {
return {
.content_id = cid,
.content_size = sz,
.key = ky,
.verify_digest = false,
.has_key = true,
};
}
static constexpr InstallContentMetaInfo MakeUnverifiable(const ContentId &cid, s64 sz) {
return {
.content_id = cid,
.content_size = sz,
.verify_digest = false,
.has_key = false,
};
}
};
static_assert(sizeof(InstallContentMetaInfo) == 0x50);
class InstallTaskBase {
NON_COPYABLE(InstallTaskBase);
NON_MOVEABLE(InstallTaskBase);
private:
crypto::Sha256Generator sha256_generator;
StorageId install_storage;
InstallTaskDataBase *data;
InstallProgress progress;
os::Mutex progress_mutex;
u32 config;
os::Mutex cancel_mutex;
bool cancel_requested;
InstallThroughput throughput;
TimeSpan throughput_start_time;
os::Mutex throughput_mutex;
FirmwareVariationId firmware_variation_id;
private:
ALWAYS_INLINE Result SetLastResultOnFailure(Result result) {
if (R_FAILED(result)) {
this->SetLastResult(result);
}
return result;
}
public:
InstallTaskBase() : data(), progress(), progress_mutex(false), cancel_mutex(false), cancel_requested(), throughput_mutex(false) { /* ... */ }
virtual ~InstallTaskBase() { /* ... */ };
public:
virtual void Cancel();
virtual void ResetCancel();
Result Prepare();
Result GetPreparedPlaceHolderPath(Path *out_path, u64 id, ContentMetaType meta_type, ContentType type);
Result CalculateRequiredSize(s64 *out_size);
Result Cleanup();
Result ListContentMetaKey(s32 *out_keys_written, StorageContentMetaKey *out_keys, s32 out_keys_count, s32 offset, ListContentMetaKeyFilter filter);
Result ListContentMetaKey(s32 *out_keys_written, StorageContentMetaKey *out_keys, s32 out_keys_count, s32 offset) { return this->ListContentMetaKey(out_keys_written, out_keys, out_keys_count, offset, ListContentMetaKeyFilter::All); }
Result ListApplicationContentMetaKey(s32 *out_keys_written, ApplicationContentMetaKey *out_keys, s32 out_keys_count, s32 offset);
Result Execute();
Result PrepareAndExecute();
Result Commit(const StorageContentMetaKey *keys, s32 num_keys);
Result Commit() { return this->Commit(nullptr, 0); }
virtual InstallProgress GetProgress();
void ResetLastResult();
Result IncludesExFatDriver(bool *out);
InstallThroughput GetThroughput();
Result CalculateContentsSize(s64 *out_size, const ContentMetaKey &key, StorageId storage_id);
Result ListOccupiedSize(s32 *out_written, InstallTaskOccupiedSize *out_list, s32 out_list_size, s32 offset);
Result FindMaxRequiredApplicationVersion(u32 *out);
Result FindMaxRequiredSystemVersion(u32 *out);
protected:
Result Initialize(StorageId install_storage, InstallTaskDataBase *data, u32 config);
Result PrepareContentMeta(const InstallContentMetaInfo &meta_info, std::optional<ContentMetaKey> key, std::optional<u32> source_version);
Result PrepareContentMeta(ContentId content_id, s64 size, ContentMetaType meta_type, AutoBuffer *buffer);
Result WritePlaceHolderBuffer(InstallContentInfo *content_info, const void *data, size_t data_size);
void PrepareAgain();
Result CountInstallContentMetaData(s32 *out_count);
Result GetInstallContentMetaData(InstallContentMeta *out_content_meta, s32 index);
Result DeleteInstallContentMetaData(const ContentMetaKey *keys, s32 num_keys);
virtual Result PrepareDependency();
Result PrepareSystemUpdateDependency();
Result PrepareContentMetaIfLatest(const ContentMetaKey &key);
u32 GetConfig() const { return this->config; }
Result WriteContentMetaToPlaceHolder(InstallContentInfo *out_install_content_info, ContentStorage *storage, const InstallContentMetaInfo &meta_info, std::optional<bool> is_temporary);
StorageId GetInstallStorage() const { return this->install_storage; }
virtual Result OnPrepareComplete() { return ResultSuccess(); }
Result GetSystemUpdateTaskApplyInfo(SystemUpdateTaskApplyInfo *out);
Result CanContinue();
private:
bool IsCancelRequested();
Result PrepareImpl();
Result ExecuteImpl();
Result CommitImpl(const StorageContentMetaKey *keys, s32 num_keys);
Result CleanupOne(const InstallContentMeta &content_meta);
Result VerifyAllNotCommitted(const StorageContentMetaKey *keys, s32 num_keys);
virtual Result PrepareInstallContentMetaData() = 0;
virtual Result GetInstallContentMetaInfo(InstallContentMetaInfo *out_info, const ContentMetaKey &key) = 0;
virtual Result GetLatestVersion(std::optional<u32> *out_version, u64 id) { return ncm::ResultContentMetaNotFound(); }
virtual Result OnExecuteComplete() { return ResultSuccess(); }
Result WritePlaceHolder(const ContentMetaKey &key, InstallContentInfo *content_info);
virtual Result OnWritePlaceHolder(const ContentMetaKey &key, InstallContentInfo *content_info) = 0;
bool IsNecessaryInstallTicket(const fs::RightsId &rights_id);
virtual Result InstallTicket(const fs::RightsId &rights_id, ContentMetaType meta_type) = 0;
Result IsNewerThanInstalled(bool *out, const ContentMetaKey &key);
Result PreparePlaceHolder();
void SetProgressState(InstallProgressState state);
void IncrementProgress(s64 size);
void SetTotalSize(s64 size);
void SetLastResult(Result last_result);
void CleanupProgress();
void ResetThroughputMeasurement();
void StartThroughputMeasurement();
void UpdateThroughputMeasurement(s64 throughput);
Result GetInstallContentMetaDataFromPath(AutoBuffer *out, const Path &path, const InstallContentInfo &content_info, std::optional<u32> source_version);
InstallContentInfo MakeInstallContentInfoFrom(const InstallContentMetaInfo &info, const PlaceHolderId &placeholder_id, std::optional<bool> is_temporary);
Result ReadContentMetaInfoList(s32 *out_count, std::unique_ptr<ContentMetaInfo[]> *out_meta_infos, const ContentMetaKey &key);
Result ListRightsIdsByInstallContentMeta(s32 *out_count, Span<RightsId> out_span, const InstallContentMeta &content_meta, s32 offset);
public:
virtual Result CheckInstallable() { return ResultSuccess(); }
void SetFirmwareVariationId(FirmwareVariationId id) { this->firmware_variation_id = id; }
Result ListRightsIds(s32 *out_count, Span<RightsId> out_span, const ContentMetaKey &key, s32 offset);
};
}

View File

@@ -0,0 +1,149 @@
/*
* Copyright (c) 2019-2020 Adubbz, 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 <stratosphere/ncm/ncm_content_meta.hpp>
#include <stratosphere/ncm/ncm_install_progress.hpp>
#include <stratosphere/ncm/ncm_system_update_task_apply_info.hpp>
namespace ams::ncm {
struct InstallContentMeta {
std::unique_ptr<char[]> data;
size_t size;
InstallContentMetaReader GetReader() const {
return InstallContentMetaReader(this->data.get(), this->size);
}
InstallContentMetaWriter GetWriter() const {
return InstallContentMetaWriter(this->data.get(), this->size);
}
};
class InstallTaskDataBase {
public:
Result Get(InstallContentMeta *out, s32 index);
Result Update(const InstallContentMeta &content_meta, s32 index);
Result Has(bool *out, u64 id);
public:
virtual Result GetProgress(InstallProgress *out_progress) = 0;
virtual Result GetSystemUpdateTaskApplyInfo(SystemUpdateTaskApplyInfo *out_info) = 0;
virtual Result SetState(InstallProgressState state) = 0;
virtual Result SetLastResult(Result result) = 0;
virtual Result SetSystemUpdateTaskApplyInfo(SystemUpdateTaskApplyInfo info) = 0;
virtual Result Push(const void *data, size_t data_size) = 0;
virtual Result Count(s32 *out) = 0;
virtual Result Delete(const ContentMetaKey *keys, s32 num_keys) = 0;
virtual Result Cleanup() = 0;
private:
virtual Result GetSize(size_t *out_size, s32 index) = 0;
virtual Result Get(s32 index, void *out, size_t out_size) = 0;
virtual Result Update(s32 index, const void *data, size_t data_size) = 0;
};
class MemoryInstallTaskData : public InstallTaskDataBase {
private:
struct DataHolder : public InstallContentMeta, public util::IntrusiveListBaseNode<DataHolder>{};
using DataList = util::IntrusiveListBaseTraits<DataHolder>::ListType;
private:
DataList data_list;
InstallProgressState state;
Result last_result;
SystemUpdateTaskApplyInfo system_update_task_apply_info;
public:
MemoryInstallTaskData() : state(InstallProgressState::NotPrepared), last_result(ResultSuccess()) { /* ... */ };
~MemoryInstallTaskData() {
this->Cleanup();
}
public:
virtual Result GetProgress(InstallProgress *out_progress) override;
virtual Result GetSystemUpdateTaskApplyInfo(SystemUpdateTaskApplyInfo *out_info) override;
virtual Result SetState(InstallProgressState state) override;
virtual Result SetLastResult(Result result) override;
virtual Result SetSystemUpdateTaskApplyInfo(SystemUpdateTaskApplyInfo info) override;
virtual Result Push(const void *data, size_t data_size) override;
virtual Result Count(s32 *out) override;
virtual Result Delete(const ContentMetaKey *keys, s32 num_keys) override;
virtual Result Cleanup() override;
private:
virtual Result GetSize(size_t *out_size, s32 index) override;
virtual Result Get(s32 index, void *out, size_t out_size) override;
virtual Result Update(s32 index, const void *data, size_t data_size) override;
};
class FileInstallTaskData : public InstallTaskDataBase {
private:
struct Header {
u32 max_entries;
u32 count;
s64 last_data_offset;
Result last_result;
InstallProgressState progress_state;
SystemUpdateTaskApplyInfo system_update_task_apply_info;
};
static_assert(sizeof(Header) == 0x18);
struct EntryInfo {
s64 offset;
s64 size;
};
static_assert(sizeof(EntryInfo) == 0x10);
private:
Header header;
char path[64];
private:
static constexpr Header MakeInitialHeader(s32 max_entries) {
return {
.max_entries = static_cast<u32>(max_entries),
.count = 0,
.last_data_offset = GetEntryInfoOffset(max_entries),
.last_result = ResultSuccess(),
.progress_state = InstallProgressState::NotPrepared,
.system_update_task_apply_info = SystemUpdateTaskApplyInfo::Unknown,
};
}
static constexpr s64 GetEntryInfoOffset(s32 index) {
return index * sizeof(EntryInfo) + sizeof(Header);
}
public:
static Result Create(const char *path, s32 max_entries);
Result Initialize(const char *path);
public:
virtual Result GetProgress(InstallProgress *out_progress) override;
virtual Result GetSystemUpdateTaskApplyInfo(SystemUpdateTaskApplyInfo *out_info) override;
virtual Result SetState(InstallProgressState state) override;
virtual Result SetLastResult(Result result) override;
virtual Result SetSystemUpdateTaskApplyInfo(SystemUpdateTaskApplyInfo info) override;
virtual Result Push(const void *data, size_t data_size) override;
virtual Result Count(s32 *out) override;
virtual Result Delete(const ContentMetaKey *keys, s32 num_keys) override;
virtual Result Cleanup() override;
private:
virtual Result GetSize(size_t *out_size, s32 index) override;
virtual Result Get(s32 index, void *out, size_t out_size) override;
virtual Result Update(s32 index, const void *data, size_t data_size) override;
Result GetEntryInfo(EntryInfo *out_entry_info, s32 index);
Result Write(const void *data, size_t size, s64 offset);
Result Read(void *out, size_t out_size, s64 offset);
Result WriteHeader();
};
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (c) 2019-2020 Adubbz, 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 <stratosphere/ncm/ncm_content_meta_key.hpp>
namespace ams::ncm {
struct InstallTaskOccupiedSize {
ContentMetaKey key;
s64 size;
StorageId storage_id;
u8 reserved[7];
};
static_assert(sizeof(InstallTaskOccupiedSize) == 0x20);
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) 2019-2020 Adubbz, 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.hpp>
namespace ams::ncm {
constexpr inline s32 SystemMaxContentMetaCount = 0x800;
constexpr inline s32 GameCardMaxContentMetaCount = 0x800;
constexpr inline s32 UserMaxContentMetaCount = 0x2000;
constexpr inline s32 SdCardMaxContentMetaCount = 0x2000;
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2019-2020 Adubbz, 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 <stratosphere/ncm/ncm_package_install_task_base.hpp>
namespace ams::ncm {
class PackageInstallTask : public PackageInstallTaskBase {
private:
MemoryInstallTaskData data;
public:
Result Initialize(const char *package_root, StorageId storage_id, void *buffer, size_t buffer_size, bool ignore_ticket);
protected:
bool IsContentMetaContentName(const char *name);
virtual Result PrepareInstallContentMetaData() override;
private:
virtual Result GetInstallContentMetaInfo(InstallContentMetaInfo *out_info, const ContentMetaKey &key) override;
};
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 2019-2020 Adubbz, 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 <stratosphere/kvdb/kvdb_bounded_string.hpp>
#include <stratosphere/ncm/ncm_install_task_base.hpp>
namespace ams::ncm {
class PackageInstallTaskBase : public InstallTaskBase {
private:
using PackagePath = kvdb::BoundedString<256>;
private:
PackagePath package_root;
void *buffer;
size_t buffer_size;
public:
PackageInstallTaskBase() : package_root() { /* ... */ }
Result Initialize(const char *package_root_path, void *buffer, size_t buffer_size, StorageId storage_id, InstallTaskDataBase *data, u32 config);
protected:
const char *GetPackageRootPath() {
return this->package_root.Get();
}
private:
virtual Result OnWritePlaceHolder(const ContentMetaKey &key, InstallContentInfo *content_info) override;
virtual Result InstallTicket(const fs::RightsId &rights_id, ContentMetaType meta_type) override;
void CreateContentMetaPath(PackagePath *out_path, ContentId content_id);
void CreateContentPath(PackagePath *out_path, ContentId content_id);
void CreateTicketPath(PackagePath *out_path, fs::RightsId id);
void CreateCertificatePath(PackagePath *out_path, fs::RightsId id);
};
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2019-2020 Adubbz, 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 <stratosphere/ncm/ncm_package_install_task_base.hpp>
namespace ams::ncm {
class PackageSystemUpdateTask : public PackageInstallTaskBase {
private:
using PackagePath = kvdb::BoundedString<0x100>;
private:
PackagePath context_path;
FileInstallTaskData data;
ContentMetaDatabase package_db;
bool gamecard_content_meta_database_active;
public:
~PackageSystemUpdateTask();
void Inactivate();
Result Initialize(const char *package_root, const char *context_path, void *buffer, size_t buffer_size, bool requires_exfat_driver, FirmwareVariationId firmware_variation_id);
std::optional<ContentMetaKey> GetSystemUpdateMetaKey();
protected:
virtual Result PrepareInstallContentMetaData() override;
private:
virtual Result PrepareDependency() override;
virtual Result GetInstallContentMetaInfo(InstallContentMetaInfo *out, const ContentMetaKey &key) override;
Result GetContentInfoOfContentMeta(ContentInfo *out, const ContentMetaKey &key);
};
}

View File

@@ -21,19 +21,19 @@ namespace ams::ncm {
struct alignas(8) PlaceHolderId {
util::Uuid uuid;
bool operator==(const PlaceHolderId& other) const {
bool operator==(const PlaceHolderId &other) const {
return this->uuid == other.uuid;
}
bool operator!=(const PlaceHolderId& other) const {
bool operator!=(const PlaceHolderId &other) const {
return this->uuid != other.uuid;
}
bool operator==(const util::Uuid& other) const {
bool operator==(const util::Uuid &other) const {
return this->uuid == other;
}
bool operator!=(const util::Uuid& other) const {
bool operator!=(const util::Uuid &other) const {
return this->uuid != other;
}
};

View File

@@ -27,4 +27,15 @@ namespace ams::ncm {
static_assert(sizeof(RightsId) == 0x18);
static_assert(std::is_pod<RightsId>::value);
inline bool operator==(const RightsId &lhs, const RightsId &rhs) {
return std::tie(lhs.id, lhs.key_generation) == std::tie(rhs.id, rhs.key_generation);
}
inline bool operator!=(const RightsId &lhs, const RightsId &rhs) {
return !(lhs == rhs);
}
inline bool operator<(const RightsId &lhs, const RightsId &rhs) {
return std::tie(lhs.id, lhs.key_generation) < std::tie(rhs.id, rhs.key_generation);
}
}

View File

@@ -37,7 +37,7 @@ namespace ams::ncm {
u64 counter;
os::Mutex mutex;
public:
RightsIdCache() {
RightsIdCache() : mutex(false) {
this->Invalidate();
}

View File

@@ -26,6 +26,11 @@ namespace ams::ncm {
BuiltInUser = 4,
SdCard = 5,
Any = 6,
/* Aliases. */
Card = GameCard,
BuildInSystem = BuiltInSystem,
BuildInUser = BuiltInUser,
};
constexpr inline bool IsUniqueStorage(StorageId id) {

View File

@@ -0,0 +1,76 @@
/*
* Copyright (c) 2019-2020 Adubbz, 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 <stratosphere/ncm/ncm_storage_id.hpp>
#include <stratosphere/ncm/ncm_content_meta_id.hpp>
namespace ams::ncm {
class StorageList {
public:
static constexpr s32 MaxCount = 10;
private:
StorageId ids[MaxCount];
s32 count;
public:
constexpr StorageList() : ids(), count() { /* ... */ }
void Push(StorageId storage_id) {
AMS_ABORT_UNLESS(this->count < MaxCount);
for (s32 i = 0; i < MaxCount; i++) {
if (this->ids[i] == storage_id) {
return;
}
}
this->ids[this->count++] = storage_id;
}
s32 Count() const {
return this->count;
}
StorageId operator[](s32 i) const {
AMS_ABORT_UNLESS(i < this->count);
return this->ids[i];
}
};
constexpr StorageList GetStorageList(StorageId storage_id) {
StorageList list;
switch (storage_id) {
case StorageId::BuiltInSystem:
case StorageId::BuiltInUser:
case StorageId::SdCard:
list.Push(storage_id);
break;
case StorageId::Any:
list.Push(StorageId::SdCard);
list.Push(StorageId::BuiltInUser);
break;
AMS_UNREACHABLE_DEFAULT_CASE();
}
return list;
}
Result SelectDownloadableStorage(StorageId *out_storage_id, StorageId storage_id, s64 required_size);
Result SelectPatchStorage(StorageId *out_storage_id, StorageId storage_id, PatchId patch_id);
const char *GetStorageIdString(StorageId storage_id);
const char *GetStorageIdStringForPlayReport(StorageId storage_id);
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2019-2020 Adubbz, 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 <stratosphere/fs/fs_file_storage.hpp>
#include <stratosphere/ncm/ncm_package_install_task.hpp>
namespace ams::ncm {
class SubmissionPackageInstallTask : public PackageInstallTask {
private:
class Impl;
private:
std::unique_ptr<Impl> impl;
public:
SubmissionPackageInstallTask();
virtual ~SubmissionPackageInstallTask() override;
Result Initialize(fs::FileHandle handle, StorageId storage_id, void *buffer, size_t buffer_size, bool ignore_ticket = false);
};
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) 2019-2020 Adubbz, 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.hpp>
namespace ams::ncm {
enum class SystemUpdateTaskApplyInfo : u8 {
Unknown = 0,
RequireReboot = 1,
RequireNoReboot = 2,
};
}

View File

@@ -24,7 +24,7 @@ namespace ams::nim {
void FinalizeForNetworkInstallManager();
/* Service API. */
Result DestroySystemUpdateTask(const SystemUpdateTaskId& id);
Result DestroySystemUpdateTask(const SystemUpdateTaskId &id);
s32 ListSystemUpdateTask(SystemUpdateTaskId *out_list, size_t out_list_size);

View File

@@ -26,15 +26,13 @@
#include <stratosphere/os/os_process_handle.hpp>
#include <stratosphere/os/os_random.hpp>
#include <stratosphere/os/os_mutex.hpp>
#include <stratosphere/os/os_condvar.hpp>
#include <stratosphere/os/os_condition_variable.hpp>
#include <stratosphere/os/os_rw_lock.hpp>
#include <stratosphere/os/os_semaphore.hpp>
#include <stratosphere/os/os_timeout_helper.hpp>
#include <stratosphere/os/os_event.hpp>
#include <stratosphere/os/os_system_event.hpp>
#include <stratosphere/os/os_interrupt_event.hpp>
#include <stratosphere/os/os_thread_local_storage_api.hpp>
#include <stratosphere/os/os_thread.hpp>
#include <stratosphere/os/os_message_queue.hpp>
#include <stratosphere/os/os_waitable_holder.hpp>
#include <stratosphere/os/os_waitable_manager.hpp>
#include <stratosphere/os/os_waitable.hpp>

View File

@@ -0,0 +1,58 @@
/*
* 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.hpp>
#include <stratosphere/os/os_condition_variable_common.hpp>
#if defined(ATMOSPHERE_OS_HORIZON)
#include <stratosphere/os/impl/os_internal_condition_variable_impl.os.horizon.hpp>
#else
#error "Unknown OS for ams::os::impl::InternalConditionVariableImpl"
#endif
namespace ams::os::impl {
class InternalConditionVariable {
private:
InternalConditionVariableImpl impl;
public:
constexpr InternalConditionVariable() : impl() { /* ... */ }
constexpr void Initialize() {
this->impl.Initialize();
}
void Signal() {
this->impl.Signal();
}
void Broadcast() {
this->impl.Broadcast();
}
void Wait(InternalCriticalSection *cs) {
this->impl.Wait(cs);
}
ConditionVariableStatus TimedWait(InternalCriticalSection *cs, const TimeoutHelper &timeout_helper) {
return this->impl.TimedWait(cs, timeout_helper);
}
};
using InternalConditionVariableStorage = TYPED_STORAGE(InternalConditionVariable);
}

View File

@@ -0,0 +1,43 @@
/*
* 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.hpp>
#include <stratosphere/os/os_condition_variable_common.hpp>
#include <stratosphere/os/impl/os_internal_critical_section.hpp>
namespace ams::os::impl {
class TimeoutHelper;
class InternalConditionVariableImpl {
private:
u32 value;
public:
constexpr InternalConditionVariableImpl() : value(0) { /* ... */ }
constexpr void Initialize() {
this->value = 0;
}
void Signal();
void Broadcast();
void Wait(InternalCriticalSection *cs);
ConditionVariableStatus TimedWait(InternalCriticalSection *cs, const TimeoutHelper &timeout_helper);
};
}

View File

@@ -0,0 +1,62 @@
/*
* 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.hpp>
#if defined(ATMOSPHERE_OS_HORIZON)
#include <stratosphere/os/impl/os_internal_critical_section_impl.os.horizon.hpp>
#else
#error "Unknown OS for ams::os::impl::InternalCriticalSectionImpl"
#endif
namespace ams::os::impl {
class InternalCriticalSection {
private:
InternalCriticalSectionImpl impl;
public:
constexpr InternalCriticalSection() : impl() { /* ... */ }
constexpr void Initialize() { this->impl.Initialize(); }
constexpr void Finalize() { this->impl.Finalize(); }
void Enter() { return this->impl.Enter(); }
bool TryEnter() { return this->impl.TryEnter(); }
void Leave() { return this->impl.Leave(); }
bool IsLockedByCurrentThread() const { return this->impl.IsLockedByCurrentThread(); }
ALWAYS_INLINE void Lock() { return this->Enter(); }
ALWAYS_INLINE bool TryLock() { return this->TryEnter(); }
ALWAYS_INLINE void Unlock() { return this->Leave(); }
ALWAYS_INLINE void lock() { return this->Lock(); }
ALWAYS_INLINE bool try_lock() { return this->TryLock(); }
ALWAYS_INLINE void unlock() { return this->Unlock(); }
InternalCriticalSectionImpl *Get() {
return std::addressof(this->impl);
}
const InternalCriticalSectionImpl *Get() const {
return std::addressof(this->impl);
}
};
using InternalCriticalSectionStorage = TYPED_STORAGE(InternalCriticalSection);
}

View File

@@ -0,0 +1,52 @@
/*
* 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.hpp>
namespace ams::os::impl {
class ReadWriteLockImpl;
class InternalConditionVariableImpl;
class InternalCriticalSectionImpl {
private:
friend class ReadWriteLockImpl;
friend class InternalConditionVariableImpl;
private:
u32 thread_handle;
public:
constexpr InternalCriticalSectionImpl() : thread_handle(svc::InvalidHandle) { /* ... */ }
constexpr void Initialize() { this->thread_handle = svc::InvalidHandle; }
constexpr void Finalize() { /* ... */}
void Enter();
bool TryEnter();
void Leave();
bool IsLockedByCurrentThread() const;
ALWAYS_INLINE void Lock() { return this->Enter(); }
ALWAYS_INLINE bool TryLock() { return this->TryEnter(); }
ALWAYS_INLINE void Unlock() { return this->Leave(); }
ALWAYS_INLINE void lock() { return this->Lock(); }
ALWAYS_INLINE bool try_lock() { return this->TryLock(); }
ALWAYS_INLINE void unlock() { return this->Unlock(); }
};
}

View File

@@ -0,0 +1,65 @@
/*
* 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.hpp>
#include <stratosphere/os/os_mutex_types.hpp>
#include <stratosphere/os/os_condition_variable_common.hpp>
#include <stratosphere/os/os_condition_variable_types.hpp>
#include <stratosphere/os/os_condition_variable_api.hpp>
namespace ams::os {
class ConditionVariable {
NON_COPYABLE(ConditionVariable);
NON_MOVEABLE(ConditionVariable);
private:
ConditionVariableType cv;
public:
constexpr ConditionVariable() : cv{::ams::os::ConditionVariableType::State_Initialized, {{0}}} { /* ... */ }
~ConditionVariable() { FinalizeConditionVariable(std::addressof(this->cv)); }
void Signal() {
SignalConditionVariable(std::addressof(this->cv));
}
void Broadcast() {
BroadcastConditionVariable(std::addressof(this->cv));
}
void Wait(ams::os::MutexType &mutex) {
WaitConditionVariable(std::addressof(this->cv), std::addressof(mutex));
}
ConditionVariableStatus TimedWait(ams::os::MutexType &mutex, TimeSpan timeout) {
return TimedWaitConditionVariable(std::addressof(this->cv), std::addressof(mutex), timeout);
}
operator ConditionVariableType &() {
return this->cv;
}
operator const ConditionVariableType &() const {
return this->cv;
}
ConditionVariableType *GetBase() {
return std::addressof(this->cv);
}
};
}

View File

@@ -0,0 +1,35 @@
/*
* 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.hpp>
#include <stratosphere/os/os_condition_variable_common.hpp>
namespace ams::os {
struct MutexType;
struct ConditionVariableType;
void InitializeConditionVariable(ConditionVariableType *cv);
void FinalizeConditionVariable(ConditionVariableType *cv);
void SignalConditionVariable(ConditionVariableType *cv);
void BroadcastConditionVariable(ConditionVariableType *cv);
void WaitConditionVariable(ConditionVariableType *cv, MutexType *m);
ConditionVariableStatus TimedWaitConditionVariable(ConditionVariableType *cv, MutexType *m, TimeSpan timeout);
}

View File

@@ -0,0 +1,26 @@
/*
* 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.hpp>
namespace ams::os {
enum class ConditionVariableStatus {
TimedOut = 0,
Success = 1,
};
}

View File

@@ -0,0 +1,37 @@
/*
* 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.hpp>
#include <stratosphere/os/impl/os_internal_condition_variable.hpp>
namespace ams::os {
struct ConditionVariableType {
enum State {
State_NotInitialized = 0,
State_Initialized = 1,
};
u8 state;
union {
s32 _arr[sizeof(impl::InternalConditionVariableStorage) / sizeof(s32)];
impl::InternalConditionVariableStorage _storage;
};
};
static_assert(std::is_trivial<ConditionVariableType>::value);
}

View File

@@ -1,68 +0,0 @@
/*
* 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 "os_mutex.hpp"
namespace ams::os {
enum class ConditionVariableStatus {
TimedOut = 0,
Success = 1,
};
class ConditionVariable {
NON_COPYABLE(ConditionVariable);
NON_MOVEABLE(ConditionVariable);
private:
CondVar cv;
public:
constexpr ConditionVariable() : cv() { /* ... */ }
ConditionVariableStatus TimedWait(::Mutex *m, u64 timeout) {
if (timeout > 0) {
/* Abort on any error other than timed out/success. */
R_TRY_CATCH(condvarWaitTimeout(&this->cv, m, timeout)) {
R_CATCH(svc::ResultTimedOut) { return ConditionVariableStatus::TimedOut; }
} R_END_TRY_CATCH_WITH_ABORT_UNLESS;
return ConditionVariableStatus::Success;
}
return ConditionVariableStatus::TimedOut;
}
void Wait(::Mutex *m) {
R_ABORT_UNLESS(condvarWait(&this->cv, m));
}
ConditionVariableStatus TimedWait(os::Mutex *m, u64 timeout) {
return this->TimedWait(m->GetMutex(), timeout);
}
void Wait(os::Mutex *m) {
return this->Wait(m->GetMutex());
}
void Signal() {
condvarWakeOne(&this->cv);
}
void Broadcast() {
condvarWakeAll(&this->cv);
}
};
}

View File

@@ -15,39 +15,58 @@
*/
#pragma once
#include "os_mutex.hpp"
#include "os_condvar.hpp"
#include "os_timeout_helper.hpp"
#include <vapours.hpp>
#include <stratosphere/os/os_event_common.hpp>
#include <stratosphere/os/os_event_types.hpp>
#include <stratosphere/os/os_event_api.hpp>
namespace ams::os {
namespace impl {
class WaitableObjectList;
class WaitableHolderOfEvent;
}
class Event {
friend class impl::WaitableHolderOfEvent;
NON_COPYABLE(Event);
NON_MOVEABLE(Event);
private:
util::TypedStorage<impl::WaitableObjectList, sizeof(util::IntrusiveListNode), alignof(util::IntrusiveListNode)> waitable_object_list_storage;
Mutex lock;
ConditionVariable cv;
u64 counter = 0;
bool auto_clear;
bool signaled;
EventType event;
public:
Event(bool a = true, bool s = false);
~Event();
explicit Event(EventClearMode clear_mode) {
InitializeEvent(std::addressof(this->event), false, clear_mode);
}
void Signal();
void Reset();
void Wait();
bool TryWait();
bool TimedWait(u64 ns);
~Event() {
FinalizeEvent(std::addressof(this->event));
}
void Wait() {
return WaitEvent(std::addressof(this->event));
}
bool TryWait() {
return TryWaitEvent(std::addressof(this->event));
}
bool TimedWait(TimeSpan timeout) {
return TimedWaitEvent(std::addressof(this->event), timeout);
}
void Signal() {
return SignalEvent(std::addressof(this->event));
}
void Clear() {
return ClearEvent(std::addressof(this->event));
}
operator EventType &() {
return this->event;
}
operator const EventType &() const {
return this->event;
}
EventType *GetBase() {
return std::addressof(this->event);
}
};
}

View File

@@ -0,0 +1,37 @@
/*
* 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.hpp>
#include <stratosphere/os/os_event_common.hpp>
namespace ams::os {
struct EventType;
struct WaitableHolderType;
void InitializeEvent(EventType *event, bool signaled, EventClearMode clear_mode);
void FinalizeEvent(EventType *event);
void SignalEvent(EventType *event);
void WaitEvent(EventType *event);
bool TryWaitEvent(EventType *event);
bool TimedWaitEvent(EventType *event, TimeSpan timeout);
void ClearEvent(EventType *event);
void InitializeWaitableHolder(WaitableHolderType *waitable_holder, EventType *event);
}

View File

@@ -0,0 +1,26 @@
/*
* 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.hpp>
namespace ams::os {
enum EventClearMode {
EventClearMode_ManualClear = 0,
EventClearMode_AutoClear = 1,
};
}

View File

@@ -0,0 +1,49 @@
/*
* 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.hpp>
#include <stratosphere/os/impl/os_internal_critical_section.hpp>
#include <stratosphere/os/impl/os_internal_condition_variable.hpp>
namespace ams::os {
namespace impl {
class WaitableObjectList;
}
struct EventType {
enum State {
State_NotInitialized = 0,
State_Initialized = 1,
};
util::TypedStorage<impl::WaitableObjectList, sizeof(util::IntrusiveListNode), alignof(util::IntrusiveListNode)> waitable_object_list_storage;
bool signaled;
bool initially_signaled;
u8 clear_mode;
u8 state;
u32 broadcast_counter_low;
u32 broadcast_counter_high;
impl::InternalCriticalSectionStorage cs_event;
impl::InternalConditionVariableStorage cv_signaled;
};
static_assert(std::is_trivial<EventType>::value);
}

View File

@@ -15,35 +15,56 @@
*/
#pragma once
#include "os_managed_handle.hpp"
#include <vapours.hpp>
#include <stratosphere/os/os_event_common.hpp>
#include <stratosphere/os/os_interrupt_event_common.hpp>
#include <stratosphere/os/os_interrupt_event_types.hpp>
#include <stratosphere/os/os_interrupt_event_api.hpp>
namespace ams::os {
namespace impl {
class WaitableHolderOfInterruptEvent;
}
class InterruptEvent {
friend class impl::WaitableHolderOfInterruptEvent;
NON_COPYABLE(InterruptEvent);
NON_MOVEABLE(InterruptEvent);
private:
ManagedHandle handle;
bool auto_clear;
bool is_initialized;
InterruptEventType event;
public:
InterruptEvent() : auto_clear(true), is_initialized(false) { }
InterruptEvent(u32 interrupt_id, bool autoclear = true);
explicit InterruptEvent(InterruptName name, EventClearMode clear_mode) {
InitializeInterruptEvent(std::addressof(this->event), name, clear_mode);
}
Result Initialize(u32 interrupt_id, bool autoclear = true);
void Finalize();
~InterruptEvent() {
FinalizeInterruptEvent(std::addressof(this->event));
}
void Reset();
void Wait();
bool TryWait();
bool TimedWait(u64 ns);
void Wait() {
return WaitInterruptEvent(std::addressof(this->event));
}
bool TryWait() {
return TryWaitInterruptEvent(std::addressof(this->event));
}
bool TimedWait(TimeSpan timeout) {
return TimedWaitInterruptEvent(std::addressof(this->event), timeout);
}
void Clear() {
return ClearInterruptEvent(std::addressof(this->event));
}
operator InterruptEventType &() {
return this->event;
}
operator const InterruptEventType &() const {
return this->event;
}
InterruptEventType *GetBase() {
return std::addressof(this->event);
}
};
}

View File

@@ -0,0 +1,36 @@
/*
* 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.hpp>
#include <stratosphere/os/os_interrupt_event_common.hpp>
namespace ams::os {
struct InterruptEventType;
struct WaitableHolderType;
void InitializeInterruptEvent(InterruptEventType *event, InterruptName name, EventClearMode clear_mode);
void FinalizeInterruptEvent(InterruptEventType *event);
void WaitInterruptEvent(InterruptEventType *event);
bool TryWaitInterruptEvent(InterruptEventType *event);
bool TimedWaitInterruptEvent(InterruptEventType *event, TimeSpan timeout);
void ClearInterruptEvent(InterruptEventType *event);
void InitializeWaitableHolder(WaitableHolderType *waitable_holder, InterruptEventType *event);
}

View File

@@ -0,0 +1,23 @@
/*
* 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.hpp>
namespace ams::os {
using InterruptName = s32;
}

View File

@@ -0,0 +1,46 @@
/*
* 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.hpp>
#include <stratosphere/os/impl/os_internal_critical_section.hpp>
#include <stratosphere/os/impl/os_internal_condition_variable.hpp>
namespace ams::os {
namespace impl {
class WaitableObjectList;
class InterruptEventImpl;
}
struct InterruptEventType {
enum State {
State_NotInitialized = 0,
State_Initialized = 1,
};
util::TypedStorage<impl::WaitableObjectList, sizeof(util::IntrusiveListNode), alignof(util::IntrusiveListNode)> waitable_object_list_storage;
u8 clear_mode;
u8 state;
util::TypedStorage<impl::InterruptEventImpl, sizeof(svc::Handle) * 2, alignof(svc::Handle)> impl;
};
static_assert(std::is_trivial<InterruptEventType>::value);
}

View File

@@ -38,7 +38,7 @@ namespace ams::os {
rhs.hnd = INVALID_HANDLE;
}
ManagedHandle& operator=(ManagedHandle&& rhs) {
ManagedHandle &operator=(ManagedHandle&& rhs) {
rhs.Swap(*this);
return *this;
}
@@ -47,7 +47,7 @@ namespace ams::os {
return this->hnd != INVALID_HANDLE;
}
void Swap(ManagedHandle& rhs) {
void Swap(ManagedHandle &rhs) {
std::swap(this->hnd, rhs.hnd);
}

View File

@@ -15,75 +15,87 @@
*/
#pragma once
#include "os_mutex.hpp"
#include "os_condvar.hpp"
#include <stratosphere/os/os_message_queue_common.hpp>
#include <stratosphere/os/os_message_queue_types.hpp>
#include <stratosphere/os/os_message_queue_api.hpp>
namespace ams::os {
namespace impl {
class WaitableObjectList;
template<MessageQueueWaitKind WaitKind>
class WaitableHolderOfMessageQueue;
}
class MessageQueue {
template<MessageQueueWaitKind WaitKind>
friend class impl::WaitableHolderOfMessageQueue;
NON_COPYABLE(MessageQueue);
NON_MOVEABLE(MessageQueue);
private:
util::TypedStorage<impl::WaitableObjectList, sizeof(util::IntrusiveListNode), alignof(util::IntrusiveListNode)> waitlist_not_empty;
util::TypedStorage<impl::WaitableObjectList, sizeof(util::IntrusiveListNode), alignof(util::IntrusiveListNode)> waitlist_not_full;
Mutex queue_lock;
ConditionVariable cv_not_full;
ConditionVariable cv_not_empty;
std::unique_ptr<uintptr_t[]> buffer;
size_t capacity;
size_t count;
size_t offset;
private:
constexpr inline bool IsFull() const {
return this->count >= this->capacity;
}
constexpr inline bool IsEmpty() const {
return this->count == 0;
}
void SendInternal(uintptr_t data);
void SendNextInternal(uintptr_t data);
uintptr_t ReceiveInternal();
uintptr_t PeekInternal();
MessageQueueType mq;
public:
MessageQueue(std::unique_ptr<uintptr_t[]> buf, size_t c);
~MessageQueue();
explicit MessageQueue(uintptr_t *buf, size_t count) {
InitializeMessageQueue(std::addressof(this->mq), buf, count);
}
/* For convenience. */
MessageQueue(size_t c) : MessageQueue(std::make_unique<uintptr_t[]>(c), c) { /* ... */ }
~MessageQueue() { FinalizeMessageQueue(std::addressof(this->mq)); }
/* Sending (FIFO functionality) */
void Send(uintptr_t data);
bool TrySend(uintptr_t data);
bool TimedSend(uintptr_t data, u64 timeout);
void Send(uintptr_t data) {
return SendMessageQueue(std::addressof(this->mq), data);
}
bool TrySend(uintptr_t data) {
return TrySendMessageQueue(std::addressof(this->mq), data);
}
bool TimedSend(uintptr_t data, TimeSpan timeout) {
return TimedSendMessageQueue(std::addressof(this->mq), data, timeout);
}
/* Sending (LIFO functionality) */
void SendNext(uintptr_t data);
bool TrySendNext(uintptr_t data);
bool TimedSendNext(uintptr_t data, u64 timeout);
void SendNext(uintptr_t data) {
return SendNextMessageQueue(std::addressof(this->mq), data);
}
bool TrySendNext(uintptr_t data) {
return TrySendNextMessageQueue(std::addressof(this->mq), data);
}
bool TimedSendNext(uintptr_t data, TimeSpan timeout) {
return TimedSendNextMessageQueue(std::addressof(this->mq), data, timeout);
}
/* Receive functionality */
void Receive(uintptr_t *out);
bool TryReceive(uintptr_t *out);
bool TimedReceive(uintptr_t *out, u64 timeout);
void Receive(uintptr_t *out) {
return ReceiveMessageQueue(out, std::addressof(this->mq));
}
bool TryReceive(uintptr_t *out) {
return TryReceiveMessageQueue(out, std::addressof(this->mq));
}
bool TimedReceive(uintptr_t *out, TimeSpan timeout) {
return TimedReceiveMessageQueue(out, std::addressof(this->mq), timeout);
}
/* Peek functionality */
void Peek(uintptr_t *out);
bool TryPeek(uintptr_t *out);
bool TimedPeek(uintptr_t *out, u64 timeout);
void Peek(uintptr_t *out) const {
return PeekMessageQueue(out, std::addressof(this->mq));
}
bool TryPeek(uintptr_t *out) const {
return TryPeekMessageQueue(out, std::addressof(this->mq));
}
bool TimedPeek(uintptr_t *out, TimeSpan timeout) const {
return TimedPeekMessageQueue(out, std::addressof(this->mq), timeout);
}
operator MessageQueueType &() {
return this->mq;
}
operator const MessageQueueType &() const {
return this->mq;
}
MessageQueueType *GetBase() {
return std::addressof(this->mq);
}
};
}

View File

@@ -0,0 +1,51 @@
/*
* 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.hpp>
#include <stratosphere/os/os_message_queue_common.hpp>
namespace ams::os {
struct MessageQueueType;
struct WaitableHolderType;
void InitializeMessageQueue(MessageQueueType *mq, uintptr_t *buffer, size_t count);
void FinalizeMessageQueue(MessageQueueType *mq);
/* Sending (FIFO functionality) */
void SendMessageQueue(MessageQueueType *mq, uintptr_t data);
bool TrySendMessageQueue(MessageQueueType *mq, uintptr_t data);
bool TimedSendMessageQueue(MessageQueueType *mq, uintptr_t data, TimeSpan timeout);
/* Sending (LIFO functionality) */
void SendNextMessageQueue(MessageQueueType *mq, uintptr_t data);
bool TrySendNextMessageQueue(MessageQueueType *mq, uintptr_t data);
bool TimedSendNextMessageQueue(MessageQueueType *mq, uintptr_t data, TimeSpan timeout);
/* Receive functionality */
void ReceiveMessageQueue(uintptr_t *out, MessageQueueType *mq);
bool TryReceiveMessageQueue(uintptr_t *out, MessageQueueType *mq);
bool TimedReceiveMessageQueue(uintptr_t *out, MessageQueueType *mq, TimeSpan timeout);
/* Peek functionality */
void PeekMessageQueue(uintptr_t *out, const MessageQueueType *mq);
bool TryPeekMessageQueue(uintptr_t *out, const MessageQueueType *mq);
bool TimedPeekMessageQueue(uintptr_t *out, const MessageQueueType *mq, TimeSpan timeout);
void InitializeWaitableHolder(WaitableHolderType *waitable_holder, MessageQueueType *event, MessageQueueWaitType wait_type);
}

View File

@@ -0,0 +1,26 @@
/*
* 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.hpp>
namespace ams::os {
enum class MessageQueueWaitType {
ForNotFull = 1,
ForNotEmpty = 2,
};
}

View File

@@ -0,0 +1,50 @@
/*
* 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.hpp>
#include <stratosphere/os/impl/os_internal_critical_section.hpp>
#include <stratosphere/os/impl/os_internal_condition_variable.hpp>
namespace ams::os {
namespace impl {
class WaitableObjectList;
}
struct MessageQueueType {
enum State {
State_NotInitialized = 0,
State_Initialized = 1,
};
util::TypedStorage<impl::WaitableObjectList, sizeof(util::IntrusiveListNode), alignof(util::IntrusiveListNode)> waitlist_not_full;
util::TypedStorage<impl::WaitableObjectList, sizeof(util::IntrusiveListNode), alignof(util::IntrusiveListNode)> waitlist_not_empty;
uintptr_t *buffer;
s32 capacity;
s32 count;
s32 offset;
u8 state;
mutable impl::InternalCriticalSectionStorage cs_queue;
mutable impl::InternalConditionVariableStorage cv_not_full;
mutable impl::InternalConditionVariableStorage cv_not_empty;
};
static_assert(std::is_trivial<MessageQueueType>::value);
}

View File

@@ -15,82 +15,60 @@
*/
#pragma once
#include "os_common_types.hpp"
#include <stratosphere/os/os_mutex_common.hpp>
#include <stratosphere/os/os_mutex_types.hpp>
#include <stratosphere/os/os_mutex_api.hpp>
namespace ams::os {
class ConditionVariable;
class Mutex {
NON_COPYABLE(Mutex);
NON_MOVEABLE(Mutex);
friend class ams::os::ConditionVariable;
private:
::Mutex m;
private:
constexpr ::Mutex *GetMutex() {
return &this->m;
}
MutexType mutex;
public:
constexpr Mutex() : m() { /* ... */ }
constexpr explicit Mutex(bool recursive) : mutex{::ams::os::MutexType::State_Initialized, recursive, 0, 0, nullptr, {{0}}} { /* ... */ }
~Mutex() { FinalizeMutex(std::addressof(this->mutex)); }
void lock() {
mutexLock(GetMutex());
return LockMutex(std::addressof(this->mutex));
}
void unlock() {
mutexUnlock(GetMutex());
return UnlockMutex(std::addressof(this->mutex));
}
bool try_lock() {
return mutexTryLock(GetMutex());
return TryLockMutex(std::addressof(this->mutex));
}
void Lock() {
lock();
bool IsLockedByCurrentThread() const {
return IsMutexLockedByCurrentThread(std::addressof(this->mutex));
}
void Unlock() {
unlock();
ALWAYS_INLINE void Lock() {
return this->lock();
}
bool TryLock() {
return try_lock();
}
};
class RecursiveMutex {
private:
::RMutex m;
private:
constexpr ::RMutex *GetMutex() {
return &this->m;
}
public:
constexpr RecursiveMutex() : m() { /* ... */ }
void lock() {
rmutexLock(GetMutex());
ALWAYS_INLINE void Unlock() {
return this->unlock();
}
void unlock() {
rmutexUnlock(GetMutex());
ALWAYS_INLINE bool TryLock() {
return this->try_lock();
}
bool try_lock() {
return rmutexTryLock(GetMutex());
operator MutexType &() {
return this->mutex;
}
void Lock() {
lock();
operator const MutexType &() const {
return this->mutex;
}
void Unlock() {
unlock();
}
bool TryLock() {
return try_lock();
MutexType *GetBase() {
return std::addressof(this->mutex);
}
};

View File

@@ -0,0 +1,34 @@
/*
* 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.hpp>
#include <stratosphere/os/os_mutex_common.hpp>
namespace ams::os {
struct MutexType;
void InitializeMutex(MutexType *mutex, bool recursive, int lock_level);
void FinalizeMutex(MutexType *mutex);
void LockMutex(MutexType *mutex);
bool TryLockMutex(MutexType *mutex);
void UnlockMutex(MutexType *mutex);
bool IsMutexLockedByCurrentThread(const MutexType *mutex);
}

View File

@@ -0,0 +1,27 @@
/*
* 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.hpp>
namespace ams::os {
constexpr inline s32 MutexLockLevelMin = 1;
constexpr inline s32 MutexLockLevelMax = BITSIZEOF(s32) - 1;
constexpr inline s32 MutexLockLevelInitial = 0;
constexpr inline s32 MutexRecursiveLockCountMax = (1 << BITSIZEOF(u16)) - 1;
}

View File

@@ -0,0 +1,43 @@
/*
* 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.hpp>
#include <stratosphere/os/impl/os_internal_critical_section.hpp>
namespace ams::os {
struct ThreadType;
struct MutexType {
enum State {
State_NotInitialized = 0,
State_Initialized = 1,
};
u8 state;
bool is_recursive;
s32 lock_level;
s32 nest_count;
ThreadType *owner_thread;
union {
s32 _arr[sizeof(impl::InternalCriticalSectionStorage) / sizeof(s32)];
impl::InternalCriticalSectionStorage _storage;
};
};
static_assert(std::is_trivial<MutexType>::value);
}

View File

@@ -13,43 +13,58 @@
* 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 "os_mutex.hpp"
#include "os_condvar.hpp"
#include <stratosphere/os/os_semaphore_types.hpp>
#include <stratosphere/os/os_semaphore_api.hpp>
namespace ams::os {
namespace impl {
class WaitableObjectList;
class WaitableHolderOfSemaphore;
}
class Semaphore {
friend class impl::WaitableHolderOfSemaphore;
NON_COPYABLE(Semaphore);
NON_MOVEABLE(Semaphore);
private:
util::TypedStorage<impl::WaitableObjectList, sizeof(util::IntrusiveListNode), alignof(util::IntrusiveListNode)> waitlist;
os::Mutex mutex;
os::ConditionVariable condvar;
int count;
int max_count;
SemaphoreType sema;
public:
explicit Semaphore(int c, int mc);
~Semaphore();
explicit Semaphore(s32 count, s32 max_count) {
InitializeSemaphore(std::addressof(this->sema), count, max_count);
}
void Acquire();
bool TryAcquire();
bool TimedAcquire(u64 timeout);
~Semaphore() { FinalizeSemaphore(std::addressof(this->sema)); }
void Release();
void Release(int count);
void Acquire() {
return os::AcquireSemaphore(std::addressof(this->sema));
}
constexpr inline int GetCurrentCount() const {
return this->count;
bool TryAcquire() {
return os::TryAcquireSemaphore(std::addressof(this->sema));
}
bool TimedAcquire(TimeSpan timeout) {
return os::TimedAcquireSemaphore(std::addressof(this->sema), timeout);
}
void Release() {
return os::ReleaseSemaphore(std::addressof(this->sema));
}
void Release(s32 count) {
return os::ReleaseSemaphore(std::addressof(this->sema), count);
}
s32 GetCurrentCount() const {
return os::GetCurrentSemaphoreCount(std::addressof(this->sema));
}
operator SemaphoreType &() {
return this->sema;
}
operator const SemaphoreType &() const {
return this->sema;
}
SemaphoreType *GetBase() {
return std::addressof(this->sema);
}
};

View File

@@ -0,0 +1,39 @@
/*
* 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.hpp>
namespace ams::os {
struct SemaphoreType;
struct WaitableHolderType;
void InitializeSemaphore(SemaphoreType *sema, s32 count, s32 max_count);
void FinalizeSemaphore(SemaphoreType *sema);
void AcquireSemaphore(SemaphoreType *sema);
bool TryAcquireSemaphore(SemaphoreType *sema);
bool TimedAcquireSemaphore(SemaphoreType *sema, TimeSpan timeout);
void ReleaseSemaphore(SemaphoreType *sema);
void ReleaseSemaphore(SemaphoreType *sema, s32 count);
s32 GetCurrentSemaphoreCount(const SemaphoreType *sema);
void InitializeWaitableHolder(WaitableHolderType *waitable_holder, SemaphoreType *sema);
}

Some files were not shown because too many files have changed in this diff Show More