Revert "hoc-clk: add live vdd2, live boost clock and basic pwm dimming"
This reverts commit 15b7df8ef1.
This commit is contained in:
@@ -1,42 +0,0 @@
|
||||
ATMOSPHERE_BUILD_CONFIGS :=
|
||||
all: nx_release
|
||||
|
||||
THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||
CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE)))
|
||||
|
||||
define ATMOSPHERE_ADD_TARGET
|
||||
|
||||
ATMOSPHERE_BUILD_CONFIGS += $(strip $1)
|
||||
|
||||
$(strip $1):
|
||||
@echo "Building $(strip $1)"
|
||||
@$$(MAKE) -f $(CURRENT_DIRECTORY)/libexosphere.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5)
|
||||
|
||||
clean-$(strip $1):
|
||||
@echo "Cleaning $(strip $1)"
|
||||
@$$(MAKE) -f $(CURRENT_DIRECTORY)/libexosphere.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5)
|
||||
|
||||
endef
|
||||
|
||||
define ATMOSPHERE_ADD_TARGETS
|
||||
|
||||
$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \
|
||||
ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \
|
||||
))
|
||||
|
||||
$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \
|
||||
ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \
|
||||
))
|
||||
|
||||
$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \
|
||||
ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \
|
||||
))
|
||||
|
||||
endef
|
||||
|
||||
$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,))
|
||||
$(eval $(call ATMOSPHERE_ADD_TARGETS, nx_bpmp, nx-hac-001, arm7tdmi,))
|
||||
|
||||
clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config))
|
||||
|
||||
.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config))
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <exosphere/common.hpp>
|
||||
#include <exosphere/hw.hpp>
|
||||
#include <exosphere/util.hpp>
|
||||
#include <exosphere/mmu.hpp>
|
||||
#include <exosphere/br.hpp>
|
||||
#include <exosphere/charger.hpp>
|
||||
#include <exosphere/gic.hpp>
|
||||
#include <exosphere/wdt.hpp>
|
||||
#include <exosphere/pkg1.hpp>
|
||||
#include <exosphere/pkg2.hpp>
|
||||
#include <exosphere/tsec.hpp>
|
||||
#include <exosphere/se.hpp>
|
||||
#include <exosphere/flow.hpp>
|
||||
#include <exosphere/fuse.hpp>
|
||||
#include <exosphere/i2c.hpp>
|
||||
#include <exosphere/uart.hpp>
|
||||
#include <exosphere/pinmux.hpp>
|
||||
#include <exosphere/pmic.hpp>
|
||||
#include <exosphere/pmic_setup.hpp>
|
||||
#include <exosphere/rtc.hpp>
|
||||
#include <exosphere/log.hpp>
|
||||
#include <exosphere/clkrst.hpp>
|
||||
#include <exosphere/actmon.hpp>
|
||||
#include <exosphere/pmc.hpp>
|
||||
#include <exosphere/secmon.hpp>
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::actmon {
|
||||
|
||||
using InterruptHandler = void(*)();
|
||||
|
||||
void SetRegisterAddress(uintptr_t address);
|
||||
|
||||
void HandleInterrupt();
|
||||
|
||||
void StartMonitoringBpmp(InterruptHandler handler);
|
||||
void StopMonitoringBpmp();
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <exosphere/br/br_types.hpp>
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <exosphere/br/impl/br_erista_types.hpp>
|
||||
#include <exosphere/br/impl/br_mariko_types.hpp>
|
||||
|
||||
namespace ams::br {
|
||||
|
||||
struct BootEcid {
|
||||
u32 ecid[4];
|
||||
};
|
||||
static_assert(util::is_pod<BootEcid>::value);
|
||||
static_assert(sizeof(BootEcid) == 0x10);
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::br {
|
||||
|
||||
enum BootMemoryType : u32 {
|
||||
BootMemoryType_None,
|
||||
BootMemoryType_LpDdr2,
|
||||
BootMemoryType_Ddr3,
|
||||
BootMemoryType_LpDdr4,
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,500 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <exosphere/br/impl/br_common_types.hpp>
|
||||
|
||||
namespace ams::br::erista {
|
||||
|
||||
struct BootSdramParams {
|
||||
BootMemoryType MemoryType;
|
||||
u32 PllMInputDivider;
|
||||
u32 PllMFeedbackDivider;
|
||||
u32 PllMStableTime;
|
||||
u32 PllMSetupControl;
|
||||
u32 PllMPostDivider;
|
||||
u32 PllMKCP;
|
||||
u32 PllMKVCO;
|
||||
u32 EmcBctSpare0;
|
||||
u32 EmcBctSpare1;
|
||||
u32 EmcBctSpare2;
|
||||
u32 EmcBctSpare3;
|
||||
u32 EmcBctSpare4;
|
||||
u32 EmcBctSpare5;
|
||||
u32 EmcBctSpare6;
|
||||
u32 EmcBctSpare7;
|
||||
u32 EmcBctSpare8;
|
||||
u32 EmcBctSpare9;
|
||||
u32 EmcBctSpare10;
|
||||
u32 EmcBctSpare11;
|
||||
u32 EmcBctSpare12;
|
||||
u32 EmcBctSpare13;
|
||||
u32 EmcClockSource;
|
||||
u32 EmcClockSourceDll;
|
||||
u32 ClkRstControllerPllmMisc2Override;
|
||||
u32 ClkRstControllerPllmMisc2OverrideEnable;
|
||||
u32 ClearClk2Mc1;
|
||||
u32 EmcAutoCalInterval;
|
||||
u32 EmcAutoCalConfig;
|
||||
u32 EmcAutoCalConfig2;
|
||||
u32 EmcAutoCalConfig3;
|
||||
u32 EmcAutoCalConfig4;
|
||||
u32 EmcAutoCalConfig5;
|
||||
u32 EmcAutoCalConfig6;
|
||||
u32 EmcAutoCalConfig7;
|
||||
u32 EmcAutoCalConfig8;
|
||||
u32 EmcAutoCalVrefSel0;
|
||||
u32 EmcAutoCalVrefSel1;
|
||||
u32 EmcAutoCalChannel;
|
||||
u32 EmcPmacroAutocalCfg0;
|
||||
u32 EmcPmacroAutocalCfg1;
|
||||
u32 EmcPmacroAutocalCfg2;
|
||||
u32 EmcPmacroRxTerm;
|
||||
u32 EmcPmacroDqTxDrv;
|
||||
u32 EmcPmacroCaTxDrv;
|
||||
u32 EmcPmacroCmdTxDrv;
|
||||
u32 EmcPmacroAutocalCfgCommon;
|
||||
u32 EmcPmacroZctrl;
|
||||
u32 EmcAutoCalWait;
|
||||
u32 EmcXm2CompPadCtrl;
|
||||
u32 EmcXm2CompPadCtrl2;
|
||||
u32 EmcXm2CompPadCtrl3;
|
||||
u32 EmcAdrCfg;
|
||||
u32 EmcPinProgramWait;
|
||||
u32 EmcPinExtraWait;
|
||||
u32 EmcPinGpioEn;
|
||||
u32 EmcPinGpio;
|
||||
u32 EmcTimingControlWait;
|
||||
u32 EmcRc;
|
||||
u32 EmcRfc;
|
||||
u32 EmcRfcPb;
|
||||
u32 EmcRefctrl2;
|
||||
u32 EmcRfcSlr;
|
||||
u32 EmcRas;
|
||||
u32 EmcRp;
|
||||
u32 EmcR2r;
|
||||
u32 EmcW2w;
|
||||
u32 EmcR2w;
|
||||
u32 EmcW2r;
|
||||
u32 EmcR2p;
|
||||
u32 EmcW2p;
|
||||
u32 EmcTppd;
|
||||
u32 EmcCcdmw;
|
||||
u32 EmcRdRcd;
|
||||
u32 EmcWrRcd;
|
||||
u32 EmcRrd;
|
||||
u32 EmcRext;
|
||||
u32 EmcWext;
|
||||
u32 EmcWdv;
|
||||
u32 EmcWdvChk;
|
||||
u32 EmcWsv;
|
||||
u32 EmcWev;
|
||||
u32 EmcWdvMask;
|
||||
u32 EmcWsDuration;
|
||||
u32 EmcWeDuration;
|
||||
u32 EmcQUse;
|
||||
u32 EmcQuseWidth;
|
||||
u32 EmcIbdly;
|
||||
u32 EmcObdly;
|
||||
u32 EmcEInput;
|
||||
u32 EmcEInputDuration;
|
||||
u32 EmcPutermExtra;
|
||||
u32 EmcPutermWidth;
|
||||
u32 EmcQRst;
|
||||
u32 EmcQSafe;
|
||||
u32 EmcRdv;
|
||||
u32 EmcRdvMask;
|
||||
u32 EmcRdvEarly;
|
||||
u32 EmcRdvEarlyMask;
|
||||
u32 EmcQpop;
|
||||
u32 EmcRefresh;
|
||||
u32 EmcBurstRefreshNum;
|
||||
u32 EmcPreRefreshReqCnt;
|
||||
u32 EmcPdEx2Wr;
|
||||
u32 EmcPdEx2Rd;
|
||||
u32 EmcPChg2Pden;
|
||||
u32 EmcAct2Pden;
|
||||
u32 EmcAr2Pden;
|
||||
u32 EmcRw2Pden;
|
||||
u32 EmcCke2Pden;
|
||||
u32 EmcPdex2Cke;
|
||||
u32 EmcPdex2Mrr;
|
||||
u32 EmcTxsr;
|
||||
u32 EmcTxsrDll;
|
||||
u32 EmcTcke;
|
||||
u32 EmcTckesr;
|
||||
u32 EmcTpd;
|
||||
u32 EmcTfaw;
|
||||
u32 EmcTrpab;
|
||||
u32 EmcTClkStable;
|
||||
u32 EmcTClkStop;
|
||||
u32 EmcTRefBw;
|
||||
u32 EmcFbioCfg5;
|
||||
u32 EmcFbioCfg7;
|
||||
u32 EmcFbioCfg8;
|
||||
u32 EmcCmdMappingCmd0_0;
|
||||
u32 EmcCmdMappingCmd0_1;
|
||||
u32 EmcCmdMappingCmd0_2;
|
||||
u32 EmcCmdMappingCmd1_0;
|
||||
u32 EmcCmdMappingCmd1_1;
|
||||
u32 EmcCmdMappingCmd1_2;
|
||||
u32 EmcCmdMappingCmd2_0;
|
||||
u32 EmcCmdMappingCmd2_1;
|
||||
u32 EmcCmdMappingCmd2_2;
|
||||
u32 EmcCmdMappingCmd3_0;
|
||||
u32 EmcCmdMappingCmd3_1;
|
||||
u32 EmcCmdMappingCmd3_2;
|
||||
u32 EmcCmdMappingByte;
|
||||
u32 EmcFbioSpare;
|
||||
u32 EmcCfgRsv;
|
||||
u32 EmcMrs;
|
||||
u32 EmcEmrs;
|
||||
u32 EmcEmrs2;
|
||||
u32 EmcEmrs3;
|
||||
u32 EmcMrw1;
|
||||
u32 EmcMrw2;
|
||||
u32 EmcMrw3;
|
||||
u32 EmcMrw4;
|
||||
u32 EmcMrw6;
|
||||
u32 EmcMrw8;
|
||||
u32 EmcMrw9;
|
||||
u32 EmcMrw10;
|
||||
u32 EmcMrw12;
|
||||
u32 EmcMrw13;
|
||||
u32 EmcMrw14;
|
||||
u32 EmcMrwExtra;
|
||||
u32 EmcWarmBootMrwExtra;
|
||||
u32 EmcWarmBootExtraModeRegWriteEnable;
|
||||
u32 EmcExtraModeRegWriteEnable;
|
||||
u32 EmcMrwResetCommand;
|
||||
u32 EmcMrwResetNInitWait;
|
||||
u32 EmcMrsWaitCnt;
|
||||
u32 EmcMrsWaitCnt2;
|
||||
u32 EmcCfg;
|
||||
u32 EmcCfg2;
|
||||
u32 EmcCfgPipe;
|
||||
u32 EmcCfgPipeClk;
|
||||
u32 EmcFdpdCtrlCmdNoRamp;
|
||||
u32 EmcCfgUpdate;
|
||||
u32 EmcDbg;
|
||||
u32 EmcDbgWriteMux;
|
||||
u32 EmcCmdQ;
|
||||
u32 EmcMc2EmcQ;
|
||||
u32 EmcDynSelfRefControl;
|
||||
u32 AhbArbitrationXbarCtrlMemInitDone;
|
||||
u32 EmcCfgDigDll;
|
||||
u32 EmcCfgDigDll_1;
|
||||
u32 EmcCfgDigDllPeriod;
|
||||
u32 EmcDevSelect;
|
||||
u32 EmcSelDpdCtrl;
|
||||
u32 EmcFdpdCtrlDq;
|
||||
u32 EmcFdpdCtrlCmd;
|
||||
u32 EmcPmacroIbVrefDq_0;
|
||||
u32 EmcPmacroIbVrefDq_1;
|
||||
u32 EmcPmacroIbVrefDqs_0;
|
||||
u32 EmcPmacroIbVrefDqs_1;
|
||||
u32 EmcPmacroIbRxrt;
|
||||
u32 EmcCfgPipe1;
|
||||
u32 EmcCfgPipe2;
|
||||
u32 EmcPmacroQuseDdllRank0_0;
|
||||
u32 EmcPmacroQuseDdllRank0_1;
|
||||
u32 EmcPmacroQuseDdllRank0_2;
|
||||
u32 EmcPmacroQuseDdllRank0_3;
|
||||
u32 EmcPmacroQuseDdllRank0_4;
|
||||
u32 EmcPmacroQuseDdllRank0_5;
|
||||
u32 EmcPmacroQuseDdllRank1_0;
|
||||
u32 EmcPmacroQuseDdllRank1_1;
|
||||
u32 EmcPmacroQuseDdllRank1_2;
|
||||
u32 EmcPmacroQuseDdllRank1_3;
|
||||
u32 EmcPmacroQuseDdllRank1_4;
|
||||
u32 EmcPmacroQuseDdllRank1_5;
|
||||
u32 EmcPmacroObDdllLongDqRank0_0;
|
||||
u32 EmcPmacroObDdllLongDqRank0_1;
|
||||
u32 EmcPmacroObDdllLongDqRank0_2;
|
||||
u32 EmcPmacroObDdllLongDqRank0_3;
|
||||
u32 EmcPmacroObDdllLongDqRank0_4;
|
||||
u32 EmcPmacroObDdllLongDqRank0_5;
|
||||
u32 EmcPmacroObDdllLongDqRank1_0;
|
||||
u32 EmcPmacroObDdllLongDqRank1_1;
|
||||
u32 EmcPmacroObDdllLongDqRank1_2;
|
||||
u32 EmcPmacroObDdllLongDqRank1_3;
|
||||
u32 EmcPmacroObDdllLongDqRank1_4;
|
||||
u32 EmcPmacroObDdllLongDqRank1_5;
|
||||
u32 EmcPmacroObDdllLongDqsRank0_0;
|
||||
u32 EmcPmacroObDdllLongDqsRank0_1;
|
||||
u32 EmcPmacroObDdllLongDqsRank0_2;
|
||||
u32 EmcPmacroObDdllLongDqsRank0_3;
|
||||
u32 EmcPmacroObDdllLongDqsRank0_4;
|
||||
u32 EmcPmacroObDdllLongDqsRank0_5;
|
||||
u32 EmcPmacroObDdllLongDqsRank1_0;
|
||||
u32 EmcPmacroObDdllLongDqsRank1_1;
|
||||
u32 EmcPmacroObDdllLongDqsRank1_2;
|
||||
u32 EmcPmacroObDdllLongDqsRank1_3;
|
||||
u32 EmcPmacroObDdllLongDqsRank1_4;
|
||||
u32 EmcPmacroObDdllLongDqsRank1_5;
|
||||
u32 EmcPmacroIbDdllLongDqsRank0_0;
|
||||
u32 EmcPmacroIbDdllLongDqsRank0_1;
|
||||
u32 EmcPmacroIbDdllLongDqsRank0_2;
|
||||
u32 EmcPmacroIbDdllLongDqsRank0_3;
|
||||
u32 EmcPmacroIbDdllLongDqsRank1_0;
|
||||
u32 EmcPmacroIbDdllLongDqsRank1_1;
|
||||
u32 EmcPmacroIbDdllLongDqsRank1_2;
|
||||
u32 EmcPmacroIbDdllLongDqsRank1_3;
|
||||
u32 EmcPmacroDdllLongCmd_0;
|
||||
u32 EmcPmacroDdllLongCmd_1;
|
||||
u32 EmcPmacroDdllLongCmd_2;
|
||||
u32 EmcPmacroDdllLongCmd_3;
|
||||
u32 EmcPmacroDdllLongCmd_4;
|
||||
u32 EmcPmacroDdllShortCmd_0;
|
||||
u32 EmcPmacroDdllShortCmd_1;
|
||||
u32 EmcPmacroDdllShortCmd_2;
|
||||
u32 WarmBootWait;
|
||||
u32 EmcOdtWrite;
|
||||
u32 EmcZcalInterval;
|
||||
u32 EmcZcalWaitCnt;
|
||||
u32 EmcZcalMrwCmd;
|
||||
u32 EmcMrsResetDll;
|
||||
u32 EmcZcalInitDev0;
|
||||
u32 EmcZcalInitDev1;
|
||||
u32 EmcZcalInitWait;
|
||||
u32 EmcZcalWarmColdBootEnables;
|
||||
u32 EmcMrwLpddr2ZcalWarmBoot;
|
||||
u32 EmcZqCalDdr3WarmBoot;
|
||||
u32 EmcZqCalLpDdr4WarmBoot;
|
||||
u32 EmcZcalWarmBootWait;
|
||||
u32 EmcMrsWarmBootEnable;
|
||||
u32 EmcMrsResetDllWait;
|
||||
u32 EmcMrsExtra;
|
||||
u32 EmcWarmBootMrsExtra;
|
||||
u32 EmcEmrsDdr2DllEnable;
|
||||
u32 EmcMrsDdr2DllReset;
|
||||
u32 EmcEmrsDdr2OcdCalib;
|
||||
u32 EmcDdr2Wait;
|
||||
u32 EmcClkenOverride;
|
||||
u32 EmcExtraRefreshNum;
|
||||
u32 EmcClkenOverrideAllWarmBoot;
|
||||
u32 McClkenOverrideAllWarmBoot;
|
||||
u32 EmcCfgDigDllPeriodWarmBoot;
|
||||
u32 PmcVddpSel;
|
||||
u32 PmcVddpSelWait;
|
||||
u32 PmcDdrPwr;
|
||||
u32 PmcDdrCfg;
|
||||
u32 PmcIoDpd3Req;
|
||||
u32 PmcIoDpd3ReqWait;
|
||||
u32 PmcIoDpd4ReqWait;
|
||||
u32 PmcRegShort;
|
||||
u32 PmcNoIoPower;
|
||||
u32 PmcDdrCntrlWait;
|
||||
u32 PmcDdrCntrl;
|
||||
u32 EmcAcpdControl;
|
||||
u32 EmcSwizzleRank0Byte0;
|
||||
u32 EmcSwizzleRank0Byte1;
|
||||
u32 EmcSwizzleRank0Byte2;
|
||||
u32 EmcSwizzleRank0Byte3;
|
||||
u32 EmcSwizzleRank1Byte0;
|
||||
u32 EmcSwizzleRank1Byte1;
|
||||
u32 EmcSwizzleRank1Byte2;
|
||||
u32 EmcSwizzleRank1Byte3;
|
||||
u32 EmcTxdsrvttgen;
|
||||
u32 EmcDataBrlshft0;
|
||||
u32 EmcDataBrlshft1;
|
||||
u32 EmcDqsBrlshft0;
|
||||
u32 EmcDqsBrlshft1;
|
||||
u32 EmcCmdBrlshft0;
|
||||
u32 EmcCmdBrlshft1;
|
||||
u32 EmcCmdBrlshft2;
|
||||
u32 EmcCmdBrlshft3;
|
||||
u32 EmcQuseBrlshft0;
|
||||
u32 EmcQuseBrlshft1;
|
||||
u32 EmcQuseBrlshft2;
|
||||
u32 EmcQuseBrlshft3;
|
||||
u32 EmcDllCfg0;
|
||||
u32 EmcDllCfg1;
|
||||
u32 EmcPmcScratch1;
|
||||
u32 EmcPmcScratch2;
|
||||
u32 EmcPmcScratch3;
|
||||
u32 EmcPmacroPadCfgCtrl;
|
||||
u32 EmcPmacroVttgenCtrl0;
|
||||
u32 EmcPmacroVttgenCtrl1;
|
||||
u32 EmcPmacroVttgenCtrl2;
|
||||
u32 EmcPmacroBrickCtrlRfu1;
|
||||
u32 EmcPmacroCmdBrickCtrlFdpd;
|
||||
u32 EmcPmacroBrickCtrlRfu2;
|
||||
u32 EmcPmacroDataBrickCtrlFdpd;
|
||||
u32 EmcPmacroBgBiasCtrl0;
|
||||
u32 EmcPmacroDataPadRxCtrl;
|
||||
u32 EmcPmacroCmdPadRxCtrl;
|
||||
u32 EmcPmacroDataRxTermMode;
|
||||
u32 EmcPmacroCmdRxTermMode;
|
||||
u32 EmcPmacroDataPadTxCtrl;
|
||||
u32 EmcPmacroCommonPadTxCtrl;
|
||||
u32 EmcPmacroCmdPadTxCtrl;
|
||||
u32 EmcCfg3;
|
||||
u32 EmcPmacroTxPwrd0;
|
||||
u32 EmcPmacroTxPwrd1;
|
||||
u32 EmcPmacroTxPwrd2;
|
||||
u32 EmcPmacroTxPwrd3;
|
||||
u32 EmcPmacroTxPwrd4;
|
||||
u32 EmcPmacroTxPwrd5;
|
||||
u32 EmcConfigSampleDelay;
|
||||
u32 EmcPmacroBrickMapping0;
|
||||
u32 EmcPmacroBrickMapping1;
|
||||
u32 EmcPmacroBrickMapping2;
|
||||
u32 EmcPmacroTxSelClkSrc0;
|
||||
u32 EmcPmacroTxSelClkSrc1;
|
||||
u32 EmcPmacroTxSelClkSrc2;
|
||||
u32 EmcPmacroTxSelClkSrc3;
|
||||
u32 EmcPmacroTxSelClkSrc4;
|
||||
u32 EmcPmacroTxSelClkSrc5;
|
||||
u32 EmcPmacroDdllBypass;
|
||||
u32 EmcPmacroDdllPwrd0;
|
||||
u32 EmcPmacroDdllPwrd1;
|
||||
u32 EmcPmacroDdllPwrd2;
|
||||
u32 EmcPmacroCmdCtrl0;
|
||||
u32 EmcPmacroCmdCtrl1;
|
||||
u32 EmcPmacroCmdCtrl2;
|
||||
u32 McEmemAdrCfg;
|
||||
u32 McEmemAdrCfgDev0;
|
||||
u32 McEmemAdrCfgDev1;
|
||||
u32 McEmemAdrCfgChannelMask;
|
||||
u32 McEmemAdrCfgBankMask0;
|
||||
u32 McEmemAdrCfgBankMask1;
|
||||
u32 McEmemAdrCfgBankMask2;
|
||||
u32 McEmemCfg;
|
||||
u32 McEmemArbCfg;
|
||||
u32 McEmemArbOutstandingReq;
|
||||
u32 McEmemArbRefpbHpCtrl;
|
||||
u32 McEmemArbRefpbBankCtrl;
|
||||
u32 McEmemArbTimingRcd;
|
||||
u32 McEmemArbTimingRp;
|
||||
u32 McEmemArbTimingRc;
|
||||
u32 McEmemArbTimingRas;
|
||||
u32 McEmemArbTimingFaw;
|
||||
u32 McEmemArbTimingRrd;
|
||||
u32 McEmemArbTimingRap2Pre;
|
||||
u32 McEmemArbTimingWap2Pre;
|
||||
u32 McEmemArbTimingR2R;
|
||||
u32 McEmemArbTimingW2W;
|
||||
u32 McEmemArbTimingR2W;
|
||||
u32 McEmemArbTimingW2R;
|
||||
u32 McEmemArbTimingRFCPB;
|
||||
u32 McEmemArbDaTurns;
|
||||
u32 McEmemArbDaCovers;
|
||||
u32 McEmemArbMisc0;
|
||||
u32 McEmemArbMisc1;
|
||||
u32 McEmemArbMisc2;
|
||||
u32 McEmemArbRing1Throttle;
|
||||
u32 McEmemArbOverride;
|
||||
u32 McEmemArbOverride1;
|
||||
u32 McEmemArbRsv;
|
||||
u32 McDaCfg0;
|
||||
u32 McEmemArbTimingCcdmw;
|
||||
u32 McClkenOverride;
|
||||
u32 McStatControl;
|
||||
u32 McVideoProtectBom;
|
||||
u32 McVideoProtectBomAdrHi;
|
||||
u32 McVideoProtectSizeMb;
|
||||
u32 McVideoProtectVprOverride;
|
||||
u32 McVideoProtectVprOverride1;
|
||||
u32 McVideoProtectGpuOverride0;
|
||||
u32 McVideoProtectGpuOverride1;
|
||||
u32 McSecCarveoutBom;
|
||||
u32 McSecCarveoutAdrHi;
|
||||
u32 McSecCarveoutSizeMb;
|
||||
u32 McVideoProtectWriteAccess;
|
||||
u32 McSecCarveoutProtectWriteAccess;
|
||||
u32 McGeneralizedCarveout1Bom;
|
||||
u32 McGeneralizedCarveout1BomHi;
|
||||
u32 McGeneralizedCarveout1Size128kb;
|
||||
u32 McGeneralizedCarveout1Access0;
|
||||
u32 McGeneralizedCarveout1Access1;
|
||||
u32 McGeneralizedCarveout1Access2;
|
||||
u32 McGeneralizedCarveout1Access3;
|
||||
u32 McGeneralizedCarveout1Access4;
|
||||
u32 McGeneralizedCarveout1ForceInternalAccess0;
|
||||
u32 McGeneralizedCarveout1ForceInternalAccess1;
|
||||
u32 McGeneralizedCarveout1ForceInternalAccess2;
|
||||
u32 McGeneralizedCarveout1ForceInternalAccess3;
|
||||
u32 McGeneralizedCarveout1ForceInternalAccess4;
|
||||
u32 McGeneralizedCarveout1Cfg0;
|
||||
u32 McGeneralizedCarveout2Bom;
|
||||
u32 McGeneralizedCarveout2BomHi;
|
||||
u32 McGeneralizedCarveout2Size128kb;
|
||||
u32 McGeneralizedCarveout2Access0;
|
||||
u32 McGeneralizedCarveout2Access1;
|
||||
u32 McGeneralizedCarveout2Access2;
|
||||
u32 McGeneralizedCarveout2Access3;
|
||||
u32 McGeneralizedCarveout2Access4;
|
||||
u32 McGeneralizedCarveout2ForceInternalAccess0;
|
||||
u32 McGeneralizedCarveout2ForceInternalAccess1;
|
||||
u32 McGeneralizedCarveout2ForceInternalAccess2;
|
||||
u32 McGeneralizedCarveout2ForceInternalAccess3;
|
||||
u32 McGeneralizedCarveout2ForceInternalAccess4;
|
||||
u32 McGeneralizedCarveout2Cfg0;
|
||||
u32 McGeneralizedCarveout3Bom;
|
||||
u32 McGeneralizedCarveout3BomHi;
|
||||
u32 McGeneralizedCarveout3Size128kb;
|
||||
u32 McGeneralizedCarveout3Access0;
|
||||
u32 McGeneralizedCarveout3Access1;
|
||||
u32 McGeneralizedCarveout3Access2;
|
||||
u32 McGeneralizedCarveout3Access3;
|
||||
u32 McGeneralizedCarveout3Access4;
|
||||
u32 McGeneralizedCarveout3ForceInternalAccess0;
|
||||
u32 McGeneralizedCarveout3ForceInternalAccess1;
|
||||
u32 McGeneralizedCarveout3ForceInternalAccess2;
|
||||
u32 McGeneralizedCarveout3ForceInternalAccess3;
|
||||
u32 McGeneralizedCarveout3ForceInternalAccess4;
|
||||
u32 McGeneralizedCarveout3Cfg0;
|
||||
u32 McGeneralizedCarveout4Bom;
|
||||
u32 McGeneralizedCarveout4BomHi;
|
||||
u32 McGeneralizedCarveout4Size128kb;
|
||||
u32 McGeneralizedCarveout4Access0;
|
||||
u32 McGeneralizedCarveout4Access1;
|
||||
u32 McGeneralizedCarveout4Access2;
|
||||
u32 McGeneralizedCarveout4Access3;
|
||||
u32 McGeneralizedCarveout4Access4;
|
||||
u32 McGeneralizedCarveout4ForceInternalAccess0;
|
||||
u32 McGeneralizedCarveout4ForceInternalAccess1;
|
||||
u32 McGeneralizedCarveout4ForceInternalAccess2;
|
||||
u32 McGeneralizedCarveout4ForceInternalAccess3;
|
||||
u32 McGeneralizedCarveout4ForceInternalAccess4;
|
||||
u32 McGeneralizedCarveout4Cfg0;
|
||||
u32 McGeneralizedCarveout5Bom;
|
||||
u32 McGeneralizedCarveout5BomHi;
|
||||
u32 McGeneralizedCarveout5Size128kb;
|
||||
u32 McGeneralizedCarveout5Access0;
|
||||
u32 McGeneralizedCarveout5Access1;
|
||||
u32 McGeneralizedCarveout5Access2;
|
||||
u32 McGeneralizedCarveout5Access3;
|
||||
u32 McGeneralizedCarveout5Access4;
|
||||
u32 McGeneralizedCarveout5ForceInternalAccess0;
|
||||
u32 McGeneralizedCarveout5ForceInternalAccess1;
|
||||
u32 McGeneralizedCarveout5ForceInternalAccess2;
|
||||
u32 McGeneralizedCarveout5ForceInternalAccess3;
|
||||
u32 McGeneralizedCarveout5ForceInternalAccess4;
|
||||
u32 McGeneralizedCarveout5Cfg0;
|
||||
u32 EmcCaTrainingEnable;
|
||||
u32 SwizzleRankByteEncode;
|
||||
u32 BootRomPatchControl;
|
||||
u32 BootRomPatchData;
|
||||
u32 McMtsCarveoutBom;
|
||||
u32 McMtsCarveoutAdrHi;
|
||||
u32 McMtsCarveoutSizeMb;
|
||||
u32 McMtsCarveoutRegCtrl;
|
||||
};
|
||||
static_assert(sizeof(BootSdramParams) == 0x768);
|
||||
|
||||
}
|
||||
@@ -1,552 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <exosphere/br/impl/br_common_types.hpp>
|
||||
|
||||
namespace ams::br::mariko {
|
||||
|
||||
struct BootSdramParams {
|
||||
BootMemoryType MemoryType;
|
||||
u32 PllMInputDivider;
|
||||
u32 PllMFeedbackDivider;
|
||||
u32 PllMStableTime;
|
||||
u32 PllMSetupControl;
|
||||
u32 PllMPostDivider;
|
||||
u32 PllMKCP;
|
||||
u32 PllMKVCO;
|
||||
u32 EmcBctSpare0;
|
||||
u32 EmcBctSpare1;
|
||||
u32 EmcBctSpare2;
|
||||
u32 EmcBctSpare3;
|
||||
u32 EmcBctSpare4;
|
||||
u32 EmcBctSpare5;
|
||||
u32 EmcBctSpare6;
|
||||
u32 EmcBctSpare7;
|
||||
u32 EmcBctSpare8;
|
||||
u32 EmcBctSpare9;
|
||||
u32 EmcBctSpare10;
|
||||
u32 EmcBctSpare11;
|
||||
u32 EmcBctSpare12;
|
||||
u32 EmcBctSpare13;
|
||||
u32 EmcBctSpareSecure0;
|
||||
u32 EmcBctSpareSecure1;
|
||||
u32 EmcBctSpareSecure2;
|
||||
u32 EmcBctSpareSecure3;
|
||||
u32 EmcBctSpareSecure4;
|
||||
u32 EmcBctSpareSecure5;
|
||||
u32 EmcBctSpareSecure6;
|
||||
u32 EmcBctSpareSecure7;
|
||||
u32 EmcBctSpareSecure8;
|
||||
u32 EmcBctSpareSecure9;
|
||||
u32 EmcBctSpareSecure10;
|
||||
u32 EmcBctSpareSecure11;
|
||||
u32 EmcBctSpareSecure12;
|
||||
u32 EmcBctSpareSecure13;
|
||||
u32 EmcBctSpareSecure14;
|
||||
u32 EmcBctSpareSecure15;
|
||||
u32 EmcBctSpareSecure16;
|
||||
u32 EmcBctSpareSecure17;
|
||||
u32 EmcBctSpareSecure18;
|
||||
u32 EmcBctSpareSecure19;
|
||||
u32 EmcBctSpareSecure20;
|
||||
u32 EmcBctSpareSecure21;
|
||||
u32 EmcBctSpareSecure22;
|
||||
u32 EmcBctSpareSecure23;
|
||||
u32 EmcClockSource;
|
||||
u32 EmcClockSourceDll;
|
||||
u32 ClkRstControllerPllmMisc2Override;
|
||||
u32 ClkRstControllerPllmMisc2OverrideEnable;
|
||||
u32 ClearClk2Mc1;
|
||||
u32 EmcAutoCalInterval;
|
||||
u32 EmcAutoCalConfig;
|
||||
u32 EmcAutoCalConfig2;
|
||||
u32 EmcAutoCalConfig3;
|
||||
u32 EmcAutoCalConfig4;
|
||||
u32 EmcAutoCalConfig5;
|
||||
u32 EmcAutoCalConfig6;
|
||||
u32 EmcAutoCalConfig7;
|
||||
u32 EmcAutoCalConfig8;
|
||||
u32 EmcAutoCalConfig9;
|
||||
u32 EmcAutoCalVrefSel0;
|
||||
u32 EmcAutoCalVrefSel1;
|
||||
u32 EmcAutoCalChannel;
|
||||
u32 EmcPmacroAutocalCfg0;
|
||||
u32 EmcPmacroAutocalCfg1;
|
||||
u32 EmcPmacroAutocalCfg2;
|
||||
u32 EmcPmacroRxTerm;
|
||||
u32 EmcPmacroDqTxDrv;
|
||||
u32 EmcPmacroCaTxDrv;
|
||||
u32 EmcPmacroCmdTxDrv;
|
||||
u32 EmcPmacroAutocalCfgCommon;
|
||||
u32 EmcPmacroZctrl;
|
||||
u32 EmcAutoCalWait;
|
||||
u32 EmcXm2CompPadCtrl;
|
||||
u32 EmcXm2CompPadCtrl2;
|
||||
u32 EmcXm2CompPadCtrl3;
|
||||
u32 EmcAdrCfg;
|
||||
u32 EmcPinProgramWait;
|
||||
u32 EmcPinExtraWait;
|
||||
u32 EmcPinGpioEn;
|
||||
u32 EmcPinGpio;
|
||||
u32 EmcTimingControlWait;
|
||||
u32 EmcRc;
|
||||
u32 EmcRfc;
|
||||
u32 EmcRfcPb;
|
||||
u32 EmcRefctrl2;
|
||||
u32 EmcRfcSlr;
|
||||
u32 EmcRas;
|
||||
u32 EmcRp;
|
||||
u32 EmcR2r;
|
||||
u32 EmcW2w;
|
||||
u32 EmcR2w;
|
||||
u32 EmcW2r;
|
||||
u32 EmcR2p;
|
||||
u32 EmcW2p;
|
||||
u32 EmcTppd;
|
||||
u32 EmcTrtm;
|
||||
u32 EmcTwtm;
|
||||
u32 EmcTratm;
|
||||
u32 EmcTwatm;
|
||||
u32 EmcTr2ref;
|
||||
u32 EmcCcdmw;
|
||||
u32 EmcRdRcd;
|
||||
u32 EmcWrRcd;
|
||||
u32 EmcRrd;
|
||||
u32 EmcRext;
|
||||
u32 EmcWext;
|
||||
u32 EmcWdv;
|
||||
u32 EmcWdvChk;
|
||||
u32 EmcWsv;
|
||||
u32 EmcWev;
|
||||
u32 EmcWdvMask;
|
||||
u32 EmcWsDuration;
|
||||
u32 EmcWeDuration;
|
||||
u32 EmcQUse;
|
||||
u32 EmcQuseWidth;
|
||||
u32 EmcIbdly;
|
||||
u32 EmcObdly;
|
||||
u32 EmcEInput;
|
||||
u32 EmcEInputDuration;
|
||||
u32 EmcPutermExtra;
|
||||
u32 EmcPutermWidth;
|
||||
u32 EmcQRst;
|
||||
u32 EmcQSafe;
|
||||
u32 EmcRdv;
|
||||
u32 EmcRdvMask;
|
||||
u32 EmcRdvEarly;
|
||||
u32 EmcRdvEarlyMask;
|
||||
u32 EmcQpop;
|
||||
u32 EmcRefresh;
|
||||
u32 EmcBurstRefreshNum;
|
||||
u32 EmcPreRefreshReqCnt;
|
||||
u32 EmcPdEx2Wr;
|
||||
u32 EmcPdEx2Rd;
|
||||
u32 EmcPChg2Pden;
|
||||
u32 EmcAct2Pden;
|
||||
u32 EmcAr2Pden;
|
||||
u32 EmcRw2Pden;
|
||||
u32 EmcCke2Pden;
|
||||
u32 EmcPdex2Cke;
|
||||
u32 EmcPdex2Mrr;
|
||||
u32 EmcTxsr;
|
||||
u32 EmcTxsrDll;
|
||||
u32 EmcTcke;
|
||||
u32 EmcTckesr;
|
||||
u32 EmcTpd;
|
||||
u32 EmcTfaw;
|
||||
u32 EmcTrpab;
|
||||
u32 EmcTClkStable;
|
||||
u32 EmcTClkStop;
|
||||
u32 EmcTRefBw;
|
||||
u32 EmcFbioCfg5;
|
||||
u32 EmcFbioCfg7;
|
||||
u32 EmcFbioCfg8;
|
||||
u32 EmcCmdMappingCmd0_0;
|
||||
u32 EmcCmdMappingCmd0_1;
|
||||
u32 EmcCmdMappingCmd0_2;
|
||||
u32 EmcCmdMappingCmd1_0;
|
||||
u32 EmcCmdMappingCmd1_1;
|
||||
u32 EmcCmdMappingCmd1_2;
|
||||
u32 EmcCmdMappingCmd2_0;
|
||||
u32 EmcCmdMappingCmd2_1;
|
||||
u32 EmcCmdMappingCmd2_2;
|
||||
u32 EmcCmdMappingCmd3_0;
|
||||
u32 EmcCmdMappingCmd3_1;
|
||||
u32 EmcCmdMappingCmd3_2;
|
||||
u32 EmcCmdMappingByte;
|
||||
u32 EmcFbioSpare;
|
||||
u32 EmcCfgRsv;
|
||||
u32 EmcMrs;
|
||||
u32 EmcEmrs;
|
||||
u32 EmcEmrs2;
|
||||
u32 EmcEmrs3;
|
||||
u32 EmcMrw1;
|
||||
u32 EmcMrw2;
|
||||
u32 EmcMrw3;
|
||||
u32 EmcMrw4;
|
||||
u32 EmcMrw6;
|
||||
u32 EmcMrw8;
|
||||
u32 EmcMrw9;
|
||||
u32 EmcMrw10;
|
||||
u32 EmcMrw12;
|
||||
u32 EmcMrw13;
|
||||
u32 EmcMrw14;
|
||||
u32 EmcMrwExtra;
|
||||
u32 EmcWarmBootMrwExtra;
|
||||
u32 EmcWarmBootExtraModeRegWriteEnable;
|
||||
u32 EmcExtraModeRegWriteEnable;
|
||||
u32 EmcMrwResetCommand;
|
||||
u32 EmcMrwResetNInitWait;
|
||||
u32 EmcMrsWaitCnt;
|
||||
u32 EmcMrsWaitCnt2;
|
||||
u32 EmcCfg;
|
||||
u32 EmcCfg2;
|
||||
u32 EmcCfgPipe;
|
||||
u32 EmcCfgPipeClk;
|
||||
u32 EmcFdpdCtrlCmdNoRamp;
|
||||
u32 EmcCfgUpdate;
|
||||
u32 EmcDbg;
|
||||
u32 EmcDbgWriteMux;
|
||||
u32 EmcCmdQ;
|
||||
u32 EmcMc2EmcQ;
|
||||
u32 EmcDynSelfRefControl;
|
||||
u32 AhbArbitrationXbarCtrlMemInitDone;
|
||||
u32 EmcCfgDigDll;
|
||||
u32 EmcCfgDigDll_1;
|
||||
u32 EmcCfgDigDllPeriod;
|
||||
u32 EmcDevSelect;
|
||||
u32 EmcSelDpdCtrl;
|
||||
u32 EmcFdpdCtrlDq;
|
||||
u32 EmcFdpdCtrlCmd;
|
||||
u32 EmcPmacroIbVrefDq_0;
|
||||
u32 EmcPmacroIbVrefDq_1;
|
||||
u32 EmcPmacroIbVrefDqs_0;
|
||||
u32 EmcPmacroIbVrefDqs_1;
|
||||
u32 EmcPmacroIbRxrt;
|
||||
u32 EmcCfgPipe1;
|
||||
u32 EmcCfgPipe2;
|
||||
u32 EmcPmacroQuseDdllRank0_0;
|
||||
u32 EmcPmacroQuseDdllRank0_1;
|
||||
u32 EmcPmacroQuseDdllRank0_2;
|
||||
u32 EmcPmacroQuseDdllRank0_3;
|
||||
u32 EmcPmacroQuseDdllRank0_4;
|
||||
u32 EmcPmacroQuseDdllRank0_5;
|
||||
u32 EmcPmacroQuseDdllRank1_0;
|
||||
u32 EmcPmacroQuseDdllRank1_1;
|
||||
u32 EmcPmacroQuseDdllRank1_2;
|
||||
u32 EmcPmacroQuseDdllRank1_3;
|
||||
u32 EmcPmacroQuseDdllRank1_4;
|
||||
u32 EmcPmacroQuseDdllRank1_5;
|
||||
u32 EmcPmacroObDdllLongDqRank0_0;
|
||||
u32 EmcPmacroObDdllLongDqRank0_1;
|
||||
u32 EmcPmacroObDdllLongDqRank0_2;
|
||||
u32 EmcPmacroObDdllLongDqRank0_3;
|
||||
u32 EmcPmacroObDdllLongDqRank0_4;
|
||||
u32 EmcPmacroObDdllLongDqRank0_5;
|
||||
u32 EmcPmacroObDdllLongDqRank1_0;
|
||||
u32 EmcPmacroObDdllLongDqRank1_1;
|
||||
u32 EmcPmacroObDdllLongDqRank1_2;
|
||||
u32 EmcPmacroObDdllLongDqRank1_3;
|
||||
u32 EmcPmacroObDdllLongDqRank1_4;
|
||||
u32 EmcPmacroObDdllLongDqRank1_5;
|
||||
u32 EmcPmacroObDdllLongDqsRank0_0;
|
||||
u32 EmcPmacroObDdllLongDqsRank0_1;
|
||||
u32 EmcPmacroObDdllLongDqsRank0_2;
|
||||
u32 EmcPmacroObDdllLongDqsRank0_3;
|
||||
u32 EmcPmacroObDdllLongDqsRank0_4;
|
||||
u32 EmcPmacroObDdllLongDqsRank0_5;
|
||||
u32 EmcPmacroObDdllLongDqsRank1_0;
|
||||
u32 EmcPmacroObDdllLongDqsRank1_1;
|
||||
u32 EmcPmacroObDdllLongDqsRank1_2;
|
||||
u32 EmcPmacroObDdllLongDqsRank1_3;
|
||||
u32 EmcPmacroObDdllLongDqsRank1_4;
|
||||
u32 EmcPmacroObDdllLongDqsRank1_5;
|
||||
u32 EmcPmacroIbDdllLongDqsRank0_0;
|
||||
u32 EmcPmacroIbDdllLongDqsRank0_1;
|
||||
u32 EmcPmacroIbDdllLongDqsRank0_2;
|
||||
u32 EmcPmacroIbDdllLongDqsRank0_3;
|
||||
u32 EmcPmacroIbDdllLongDqsRank1_0;
|
||||
u32 EmcPmacroIbDdllLongDqsRank1_1;
|
||||
u32 EmcPmacroIbDdllLongDqsRank1_2;
|
||||
u32 EmcPmacroIbDdllLongDqsRank1_3;
|
||||
u32 EmcPmacroDdllLongCmd_0;
|
||||
u32 EmcPmacroDdllLongCmd_1;
|
||||
u32 EmcPmacroDdllLongCmd_2;
|
||||
u32 EmcPmacroDdllLongCmd_3;
|
||||
u32 EmcPmacroDdllLongCmd_4;
|
||||
u32 EmcPmacroDdllShortCmd_0;
|
||||
u32 EmcPmacroDdllShortCmd_1;
|
||||
u32 EmcPmacroDdllShortCmd_2;
|
||||
u32 EmcPmacroDdllPeriodicOffset;
|
||||
u32 WarmBootWait;
|
||||
u32 EmcOdtWrite;
|
||||
u32 EmcZcalInterval;
|
||||
u32 EmcZcalWaitCnt;
|
||||
u32 EmcZcalMrwCmd;
|
||||
u32 EmcMrsResetDll;
|
||||
u32 EmcZcalInitDev0;
|
||||
u32 EmcZcalInitDev1;
|
||||
u32 EmcZcalInitWait;
|
||||
u32 EmcZcalWarmColdBootEnables;
|
||||
u32 EmcMrwLpddr2ZcalWarmBoot;
|
||||
u32 EmcZqCalDdr3WarmBoot;
|
||||
u32 EmcZqCalLpDdr4WarmBoot;
|
||||
u32 EmcZcalWarmBootWait;
|
||||
u32 EmcMrsWarmBootEnable;
|
||||
u32 EmcMrsResetDllWait;
|
||||
u32 EmcMrsExtra;
|
||||
u32 EmcWarmBootMrsExtra;
|
||||
u32 EmcEmrsDdr2DllEnable;
|
||||
u32 EmcMrsDdr2DllReset;
|
||||
u32 EmcEmrsDdr2OcdCalib;
|
||||
u32 EmcDdr2Wait;
|
||||
u32 EmcClkenOverride;
|
||||
u32 EmcExtraRefreshNum;
|
||||
u32 EmcClkenOverrideAllWarmBoot;
|
||||
u32 McClkenOverrideAllWarmBoot;
|
||||
u32 EmcCfgDigDllPeriodWarmBoot;
|
||||
u32 PmcVddpSel;
|
||||
u32 PmcVddpSelWait;
|
||||
u32 PmcDdrCfg;
|
||||
u32 PmcIoDpd3Req;
|
||||
u32 PmcIoDpd3ReqWait;
|
||||
u32 PmcIoDpd4ReqWait;
|
||||
u32 PmcRegShort;
|
||||
u32 PmcNoIoPower;
|
||||
u32 PmcDdrCntrlWait;
|
||||
u32 PmcDdrCntrl;
|
||||
u32 EmcAcpdControl;
|
||||
u32 EmcSwizzleRank0Byte0;
|
||||
u32 EmcSwizzleRank0Byte1;
|
||||
u32 EmcSwizzleRank0Byte2;
|
||||
u32 EmcSwizzleRank0Byte3;
|
||||
u32 EmcSwizzleRank1Byte0;
|
||||
u32 EmcSwizzleRank1Byte1;
|
||||
u32 EmcSwizzleRank1Byte2;
|
||||
u32 EmcSwizzleRank1Byte3;
|
||||
u32 EmcTxdsrvttgen;
|
||||
u32 EmcDataBrlshft0;
|
||||
u32 EmcDataBrlshft1;
|
||||
u32 EmcDqsBrlshft0;
|
||||
u32 EmcDqsBrlshft1;
|
||||
u32 EmcCmdBrlshft0;
|
||||
u32 EmcCmdBrlshft1;
|
||||
u32 EmcCmdBrlshft2;
|
||||
u32 EmcCmdBrlshft3;
|
||||
u32 EmcQuseBrlshft0;
|
||||
u32 EmcQuseBrlshft1;
|
||||
u32 EmcQuseBrlshft2;
|
||||
u32 EmcQuseBrlshft3;
|
||||
u32 EmcPmacroDllCfg0;
|
||||
u32 EmcPmacroDllCfg1;
|
||||
u32 EmcPmcScratch1;
|
||||
u32 EmcPmcScratch2;
|
||||
u32 EmcPmcScratch3;
|
||||
u32 EmcPmacroPadCfgCtrl;
|
||||
u32 EmcPmacroVttgenCtrl0;
|
||||
u32 EmcPmacroVttgenCtrl1;
|
||||
u32 EmcPmacroVttgenCtrl2;
|
||||
u32 EmcPmacroDsrVttgenCtrl0;
|
||||
u32 EmcPmacroBrickCtrlRfu1;
|
||||
u32 EmcPmacroCmdBrickCtrlFdpd;
|
||||
u32 EmcPmacroBrickCtrlRfu2;
|
||||
u32 EmcPmacroDataBrickCtrlFdpd;
|
||||
u32 EmcPmacroBgBiasCtrl0;
|
||||
u32 EmcPmacroDataPadRxCtrl;
|
||||
u32 EmcPmacroCmdPadRxCtrl;
|
||||
u32 EmcPmacroDataRxTermMode;
|
||||
u32 EmcPmacroCmdRxTermMode;
|
||||
u32 EmcPmacroDataPadTxCtrl;
|
||||
u32 EmcPmacroCmdPadTxCtrl;
|
||||
u32 EmcCfg3;
|
||||
u32 EmcPmacroTxPwrd0;
|
||||
u32 EmcPmacroTxPwrd1;
|
||||
u32 EmcPmacroTxPwrd2;
|
||||
u32 EmcPmacroTxPwrd3;
|
||||
u32 EmcPmacroTxPwrd4;
|
||||
u32 EmcPmacroTxPwrd5;
|
||||
u32 EmcConfigSampleDelay;
|
||||
u32 EmcPmacroBrickMapping0;
|
||||
u32 EmcPmacroBrickMapping1;
|
||||
u32 EmcPmacroBrickMapping2;
|
||||
u32 EmcPmacroTxSelClkSrc0;
|
||||
u32 EmcPmacroTxSelClkSrc1;
|
||||
u32 EmcPmacroTxSelClkSrc2;
|
||||
u32 EmcPmacroTxSelClkSrc3;
|
||||
u32 EmcPmacroTxSelClkSrc4;
|
||||
u32 EmcPmacroTxSelClkSrc5;
|
||||
u32 EmcPmacroPerbitFgcgCtrl0;
|
||||
u32 EmcPmacroPerbitFgcgCtrl1;
|
||||
u32 EmcPmacroPerbitFgcgCtrl2;
|
||||
u32 EmcPmacroPerbitFgcgCtrl3;
|
||||
u32 EmcPmacroPerbitFgcgCtrl4;
|
||||
u32 EmcPmacroPerbitFgcgCtrl5;
|
||||
u32 EmcPmacroPerbitRfuCtrl0;
|
||||
u32 EmcPmacroPerbitRfuCtrl1;
|
||||
u32 EmcPmacroPerbitRfuCtrl2;
|
||||
u32 EmcPmacroPerbitRfuCtrl3;
|
||||
u32 EmcPmacroPerbitRfuCtrl4;
|
||||
u32 EmcPmacroPerbitRfuCtrl5;
|
||||
u32 EmcPmacroPerbitRfu1Ctrl0;
|
||||
u32 EmcPmacroPerbitRfu1Ctrl1;
|
||||
u32 EmcPmacroPerbitRfu1Ctrl2;
|
||||
u32 EmcPmacroPerbitRfu1Ctrl3;
|
||||
u32 EmcPmacroPerbitRfu1Ctrl4;
|
||||
u32 EmcPmacroPerbitRfu1Ctrl5;
|
||||
u32 EmcPmacroDataPiCtrl;
|
||||
u32 EmcPmacroCmdPiCtrl;
|
||||
u32 EmcPmacroDdllBypass;
|
||||
u32 EmcPmacroDdllPwrd0;
|
||||
u32 EmcPmacroDdllPwrd1;
|
||||
u32 EmcPmacroDdllPwrd2;
|
||||
u32 EmcPmacroCmdCtrl0;
|
||||
u32 EmcPmacroCmdCtrl1;
|
||||
u32 EmcPmacroCmdCtrl2;
|
||||
u32 McEmemAdrCfg;
|
||||
u32 McEmemAdrCfgDev0;
|
||||
u32 McEmemAdrCfgDev1;
|
||||
u32 McEmemAdrCfgChannelMask;
|
||||
u32 McEmemAdrCfgBankMask0;
|
||||
u32 McEmemAdrCfgBankMask1;
|
||||
u32 McEmemAdrCfgBankMask2;
|
||||
u32 McEmemCfg;
|
||||
u32 McEmemArbCfg;
|
||||
u32 McEmemArbOutstandingReq;
|
||||
u32 McEmemArbRefpbHpCtrl;
|
||||
u32 McEmemArbRefpbBankCtrl;
|
||||
u32 McEmemArbTimingRcd;
|
||||
u32 McEmemArbTimingRp;
|
||||
u32 McEmemArbTimingRc;
|
||||
u32 McEmemArbTimingRas;
|
||||
u32 McEmemArbTimingFaw;
|
||||
u32 McEmemArbTimingRrd;
|
||||
u32 McEmemArbTimingRap2Pre;
|
||||
u32 McEmemArbTimingWap2Pre;
|
||||
u32 McEmemArbTimingR2R;
|
||||
u32 McEmemArbTimingW2W;
|
||||
u32 McEmemArbTimingR2W;
|
||||
u32 McEmemArbTimingW2R;
|
||||
u32 McEmemArbTimingRFCPB;
|
||||
u32 McEmemArbDaTurns;
|
||||
u32 McEmemArbDaCovers;
|
||||
u32 McEmemArbMisc0;
|
||||
u32 McEmemArbMisc1;
|
||||
u32 McEmemArbMisc2;
|
||||
u32 McEmemArbRing1Throttle;
|
||||
u32 McEmemArbOverride;
|
||||
u32 McEmemArbOverride1;
|
||||
u32 McEmemArbRsv;
|
||||
u32 McDaCfg0;
|
||||
u32 McEmemArbTimingCcdmw;
|
||||
u32 McClkenOverride;
|
||||
u32 McStatControl;
|
||||
u32 McVideoProtectBom;
|
||||
u32 McVideoProtectBomAdrHi;
|
||||
u32 McVideoProtectSizeMb;
|
||||
u32 McVideoProtectVprOverride;
|
||||
u32 McVideoProtectVprOverride1;
|
||||
u32 McVideoProtectGpuOverride0;
|
||||
u32 McVideoProtectGpuOverride1;
|
||||
u32 McSecCarveoutBom;
|
||||
u32 McSecCarveoutAdrHi;
|
||||
u32 McSecCarveoutSizeMb;
|
||||
u32 McVideoProtectWriteAccess;
|
||||
u32 McSecCarveoutProtectWriteAccess;
|
||||
u32 McGeneralizedCarveout1Bom;
|
||||
u32 McGeneralizedCarveout1BomHi;
|
||||
u32 McGeneralizedCarveout1Size128kb;
|
||||
u32 McGeneralizedCarveout1Access0;
|
||||
u32 McGeneralizedCarveout1Access1;
|
||||
u32 McGeneralizedCarveout1Access2;
|
||||
u32 McGeneralizedCarveout1Access3;
|
||||
u32 McGeneralizedCarveout1Access4;
|
||||
u32 McGeneralizedCarveout1ForceInternalAccess0;
|
||||
u32 McGeneralizedCarveout1ForceInternalAccess1;
|
||||
u32 McGeneralizedCarveout1ForceInternalAccess2;
|
||||
u32 McGeneralizedCarveout1ForceInternalAccess3;
|
||||
u32 McGeneralizedCarveout1ForceInternalAccess4;
|
||||
u32 McGeneralizedCarveout1Cfg0;
|
||||
u32 McGeneralizedCarveout2Bom;
|
||||
u32 McGeneralizedCarveout2BomHi;
|
||||
u32 McGeneralizedCarveout2Size128kb;
|
||||
u32 McGeneralizedCarveout2Access0;
|
||||
u32 McGeneralizedCarveout2Access1;
|
||||
u32 McGeneralizedCarveout2Access2;
|
||||
u32 McGeneralizedCarveout2Access3;
|
||||
u32 McGeneralizedCarveout2Access4;
|
||||
u32 McGeneralizedCarveout2ForceInternalAccess0;
|
||||
u32 McGeneralizedCarveout2ForceInternalAccess1;
|
||||
u32 McGeneralizedCarveout2ForceInternalAccess2;
|
||||
u32 McGeneralizedCarveout2ForceInternalAccess3;
|
||||
u32 McGeneralizedCarveout2ForceInternalAccess4;
|
||||
u32 McGeneralizedCarveout2Cfg0;
|
||||
u32 McGeneralizedCarveout3Bom;
|
||||
u32 McGeneralizedCarveout3BomHi;
|
||||
u32 McGeneralizedCarveout3Size128kb;
|
||||
u32 McGeneralizedCarveout3Access0;
|
||||
u32 McGeneralizedCarveout3Access1;
|
||||
u32 McGeneralizedCarveout3Access2;
|
||||
u32 McGeneralizedCarveout3Access3;
|
||||
u32 McGeneralizedCarveout3Access4;
|
||||
u32 McGeneralizedCarveout3ForceInternalAccess0;
|
||||
u32 McGeneralizedCarveout3ForceInternalAccess1;
|
||||
u32 McGeneralizedCarveout3ForceInternalAccess2;
|
||||
u32 McGeneralizedCarveout3ForceInternalAccess3;
|
||||
u32 McGeneralizedCarveout3ForceInternalAccess4;
|
||||
u32 McGeneralizedCarveout3Cfg0;
|
||||
u32 McGeneralizedCarveout4Bom;
|
||||
u32 McGeneralizedCarveout4BomHi;
|
||||
u32 McGeneralizedCarveout4Size128kb;
|
||||
u32 McGeneralizedCarveout4Access0;
|
||||
u32 McGeneralizedCarveout4Access1;
|
||||
u32 McGeneralizedCarveout4Access2;
|
||||
u32 McGeneralizedCarveout4Access3;
|
||||
u32 McGeneralizedCarveout4Access4;
|
||||
u32 McGeneralizedCarveout4ForceInternalAccess0;
|
||||
u32 McGeneralizedCarveout4ForceInternalAccess1;
|
||||
u32 McGeneralizedCarveout4ForceInternalAccess2;
|
||||
u32 McGeneralizedCarveout4ForceInternalAccess3;
|
||||
u32 McGeneralizedCarveout4ForceInternalAccess4;
|
||||
u32 McGeneralizedCarveout4Cfg0;
|
||||
u32 McGeneralizedCarveout5Bom;
|
||||
u32 McGeneralizedCarveout5BomHi;
|
||||
u32 McGeneralizedCarveout5Size128kb;
|
||||
u32 McGeneralizedCarveout5Access0;
|
||||
u32 McGeneralizedCarveout5Access1;
|
||||
u32 McGeneralizedCarveout5Access2;
|
||||
u32 McGeneralizedCarveout5Access3;
|
||||
u32 McGeneralizedCarveout5Access4;
|
||||
u32 McGeneralizedCarveout5ForceInternalAccess0;
|
||||
u32 McGeneralizedCarveout5ForceInternalAccess1;
|
||||
u32 McGeneralizedCarveout5ForceInternalAccess2;
|
||||
u32 McGeneralizedCarveout5ForceInternalAccess3;
|
||||
u32 McGeneralizedCarveout5ForceInternalAccess4;
|
||||
u32 McGeneralizedCarveout5Cfg0;
|
||||
u32 EmcCaTrainingEnable;
|
||||
u32 SwizzleRankByteEncode;
|
||||
u32 BootRomPatchControl;
|
||||
u32 BootRomPatchData;
|
||||
u32 McMtsCarveoutBom;
|
||||
u32 McMtsCarveoutAdrHi;
|
||||
u32 McMtsCarveoutSizeMb;
|
||||
u32 McMtsCarveoutRegCtrl;
|
||||
u32 McUntranslatedRegionCheck;
|
||||
u32 BCT_NA;
|
||||
};
|
||||
static_assert(sizeof(BootSdramParams) == 0x838);
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::charger {
|
||||
|
||||
bool IsHiZMode();
|
||||
void EnterHiZMode();
|
||||
void ExitHiZMode();
|
||||
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::clkrst {
|
||||
|
||||
void SetRegisterAddress(uintptr_t address);
|
||||
|
||||
void SetFuseVisibility(bool visible);
|
||||
|
||||
void EnableUartAClock();
|
||||
void EnableUartBClock();
|
||||
void EnableUartCClock();
|
||||
void EnableActmonClock();
|
||||
void EnableI2c1Clock();
|
||||
void EnableI2c5Clock();
|
||||
|
||||
void EnableSeClock();
|
||||
void EnableCldvfsClock();
|
||||
void EnableCsiteClock();
|
||||
void EnableTzramClock();
|
||||
|
||||
void EnableCache2Clock();
|
||||
void EnableCram2Clock();
|
||||
|
||||
void EnableHost1xClock();
|
||||
void EnableTsecClock();
|
||||
void EnableSorSafeClock();
|
||||
void EnableSor0Clock();
|
||||
void EnableSor1Clock();
|
||||
void EnableKfuseClock();
|
||||
|
||||
void DisableI2c1Clock();
|
||||
|
||||
void DisableHost1xClock();
|
||||
void DisableTsecClock();
|
||||
void DisableSorSafeClock();
|
||||
void DisableSor0Clock();
|
||||
void DisableSor1Clock();
|
||||
void DisableKfuseClock();
|
||||
|
||||
|
||||
enum BpmpClockRate {
|
||||
BpmpClockRate_408MHz,
|
||||
BpmpClockRate_544MHz,
|
||||
BpmpClockRate_576MHz,
|
||||
BpmpClockRate_589MHz,
|
||||
|
||||
BpmpClockRate_Count,
|
||||
};
|
||||
|
||||
BpmpClockRate GetBpmpClockRate();
|
||||
BpmpClockRate SetBpmpClockRate(BpmpClockRate rate);
|
||||
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 1 || defined(AMS_BUILD_FOR_AUDITING)
|
||||
#define EXOSPHERE_BUILD_FOR_AUDITING
|
||||
#endif
|
||||
|
||||
#if defined(EXOSPHERE_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING)
|
||||
#define EXOSPHERE_BUILD_FOR_DEBUGGING
|
||||
#endif
|
||||
|
||||
#ifdef EXOSPHERE_BUILD_FOR_DEBUGGING
|
||||
#define EXOSPHERE_ENABLE_ASSERTIONS
|
||||
#define EXOSPHERE_ENABLE_DEBUG_PRINT
|
||||
#endif
|
||||
@@ -1,119 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
|
||||
void AbortImpl(const char *expr, const char *func, const char *file, int line) {
|
||||
#if defined(AMS_ENABLE_DETAILED_ASSERTIONS)
|
||||
{
|
||||
AMS_LOG("Abort Called\n");
|
||||
AMS_LOG(" Location: %s:%d\n", file, line);
|
||||
AMS_LOG(" Function: %s\n", func);
|
||||
AMS_LOG(" Expression: %s\n", expr);
|
||||
AMS_LOG("\n");
|
||||
}
|
||||
#else
|
||||
AMS_UNUSED(file, line, func, expr);
|
||||
#endif
|
||||
AbortImpl();
|
||||
}
|
||||
|
||||
void AbortImpl(const char *expr, const char *func, const char *file, int line, const char *format, ...) {
|
||||
#if defined(AMS_ENABLE_DETAILED_ASSERTIONS)
|
||||
{
|
||||
AMS_LOG("Abort Called\n");
|
||||
AMS_LOG(" Location: %s:%d\n", file, line);
|
||||
AMS_LOG(" Function: %s\n", func);
|
||||
AMS_LOG(" Expression: %s\n", expr);
|
||||
AMS_LOG(" Value: %016" PRIx64 "\n", value);
|
||||
AMS_LOG("\n");
|
||||
{
|
||||
::std::va_list vl;
|
||||
va_start(vl, format);
|
||||
AMS_VLOG(format, vl);
|
||||
va_end(vl);
|
||||
AMS_LOG("\n");
|
||||
}
|
||||
}
|
||||
#else
|
||||
AMS_UNUSED(file, line, func, expr, format);
|
||||
#endif
|
||||
AbortImpl();
|
||||
}
|
||||
|
||||
void AbortImpl(const char *expr, const char *func, const char *file, int line, const ::ams::Result *result, const char *format, ...) {
|
||||
#if defined(AMS_ENABLE_DETAILED_ASSERTIONS)
|
||||
{
|
||||
AMS_LOG("Abort Called\n");
|
||||
AMS_LOG(" Location: %s:%d\n", file, line);
|
||||
AMS_LOG(" Function: %s\n", func);
|
||||
AMS_LOG(" Expression: %s\n", expr);
|
||||
AMS_LOG(" Result: 0x%08" PRIx32 "\n", result->GetValue());
|
||||
AMS_LOG("\n");
|
||||
{
|
||||
::std::va_list vl;
|
||||
va_start(vl, format);
|
||||
AMS_VLOG(format, vl);
|
||||
va_end(vl);
|
||||
AMS_LOG("\n");
|
||||
}
|
||||
}
|
||||
#else
|
||||
AMS_UNUSED(file, line, func, expr, result, format);
|
||||
#endif
|
||||
AbortImpl();
|
||||
}
|
||||
|
||||
void OnAssertionFailure(AssertionType type, const char *expr, const char *func, const char *file, int line) {
|
||||
#if defined(AMS_ENABLE_DETAILED_ASSERTIONS)
|
||||
{
|
||||
AMS_LOG("Assertion Failure\n");
|
||||
AMS_LOG(" Location: %s:%d\n", file, line);
|
||||
AMS_LOG(" Function: %s\n", func);
|
||||
AMS_LOG(" Expression: %s\n", expr);
|
||||
AMS_LOG(" Value: %016" PRIx64 "\n", value);
|
||||
AMS_LOG("\n");
|
||||
|
||||
AMS_UNUSED(type);
|
||||
}
|
||||
#else
|
||||
AMS_UNUSED(type, expr, func, file, line);
|
||||
#endif
|
||||
AbortImpl();
|
||||
}
|
||||
|
||||
void OnAssertionFailure(AssertionType type, const char *expr, const char *func, const char *file, int line, const char *format, ...) {
|
||||
#if defined(AMS_ENABLE_DETAILED_ASSERTIONS)
|
||||
{
|
||||
AMS_LOG("Assertion Failure\n");
|
||||
AMS_LOG(" Location: %s:%d\n", file, line);
|
||||
AMS_LOG(" Function: %s\n", func);
|
||||
AMS_LOG(" Expression: %s\n", expr);
|
||||
AMS_LOG(" Value: %016" PRIx64 "\n", value);
|
||||
AMS_LOG("\n");
|
||||
{
|
||||
::std::va_list vl;
|
||||
va_start(vl, format);
|
||||
AMS_VLOG(format, vl);
|
||||
va_end(vl);
|
||||
AMS_LOG("\n");
|
||||
}
|
||||
|
||||
AMS_UNUSED(type);
|
||||
}
|
||||
#else
|
||||
AMS_UNUSED(type, expr, func, file, line, format);
|
||||
#endif
|
||||
AbortImpl();
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::flow {
|
||||
|
||||
void SetRegisterAddress(uintptr_t address);
|
||||
|
||||
void ResetCpuRegisters(int core);
|
||||
|
||||
void SetCpuCsr(int core, u32 enable_ext);
|
||||
void SetHaltCpuEvents(int core, bool resume_on_irq);
|
||||
void SetCc4Ctrl(int core, u32 value);
|
||||
void ClearL2FlushControl();
|
||||
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <exosphere/br.hpp>
|
||||
#include <exosphere/pmic.hpp>
|
||||
|
||||
namespace ams::fuse {
|
||||
|
||||
enum HardwareType {
|
||||
HardwareType_Icosa = 0,
|
||||
HardwareType_Copper = 1,
|
||||
HardwareType_Hoag = 2,
|
||||
HardwareType_Iowa = 3,
|
||||
HardwareType_Calcio = 4,
|
||||
HardwareType_Aula = 5,
|
||||
|
||||
HardwareType_Undefined = 0xF,
|
||||
};
|
||||
|
||||
enum SocType {
|
||||
SocType_Erista = 0,
|
||||
SocType_Mariko = 1,
|
||||
SocType_Undefined = 0xF,
|
||||
};
|
||||
|
||||
enum HardwareState {
|
||||
HardwareState_Development = 0,
|
||||
HardwareState_Production = 1,
|
||||
HardwareState_Undefined = 2,
|
||||
};
|
||||
|
||||
enum PatchVersion {
|
||||
PatchVersion_Odnx02A2 = (SocType_Erista << 12) | 0x07F,
|
||||
};
|
||||
|
||||
enum DramId {
|
||||
DramId_IcosaSamsung4GB = 0,
|
||||
DramId_IcosaHynix4GB = 1,
|
||||
DramId_IcosaMicron4GB = 2,
|
||||
DramId_IowaHynix1y4GB = 3,
|
||||
DramId_IcosaSamsung6GB = 4,
|
||||
DramId_HoagHynix1y4GB = 5,
|
||||
DramId_AulaHynix1y4GB = 6,
|
||||
DramId_Deprecated7 = 7,
|
||||
DramId_IowaSansung4GB = 8,
|
||||
DramId_IowaSamsung8GB = 9,
|
||||
DramId_IowaHynix4GB = 10,
|
||||
DramId_IowaMicron4GB = 11,
|
||||
DramId_HoagSamsung4GB = 12,
|
||||
DramId_HoagSamsung8GB = 13,
|
||||
DramId_HoagHynix4GB = 14,
|
||||
DramId_HoagMicron4GB = 15,
|
||||
DramId_Deprecated16 = 16,
|
||||
DramId_IowaSamsung1y4GBX = 17,
|
||||
DramId_IowaSamsung1y8GBX = 18,
|
||||
DramId_HoagSamsung1y4GBX = 19,
|
||||
DramId_IowaSamsung1z4GB = 20,
|
||||
DramId_HoagSamsung1z4GB = 21,
|
||||
DramId_AulaSamsung1z4GB = 22,
|
||||
DramId_HoagSamsung1y8GBX = 23,
|
||||
DramId_AulaSamsung1y4GBX = 24,
|
||||
DramId_IowaMicron1y4GB = 25,
|
||||
DramId_HoagMicron1y4GB = 26,
|
||||
DramId_AulaMicron1y4GB = 27,
|
||||
DramId_AulaSamsung1y8GBX = 28,
|
||||
DramId_IowaX1X2Samsung4GB = 29,
|
||||
DramId_HoagX1X2Samsung4GB = 30,
|
||||
DramId_AulaX1X2Samsung4GB = 31,
|
||||
DramId_IowaSamsung4GBY = 32,
|
||||
DramId_HoagSamsung4GBY = 33,
|
||||
DramId_AulaSamsung4GBY = 34,
|
||||
|
||||
DramId_Count,
|
||||
};
|
||||
|
||||
enum RetailInteractiveDisplayState {
|
||||
RetailInteractiveDisplayState_Disabled = 0,
|
||||
RetailInteractiveDisplayState_Enabled = 1,
|
||||
};
|
||||
|
||||
void SetRegisterAddress(uintptr_t address);
|
||||
void SetWriteSecureOnly();
|
||||
void Lockout();
|
||||
|
||||
void Activate();
|
||||
void Deactivate();
|
||||
void Reload();
|
||||
|
||||
u32 ReadWord(int address);
|
||||
|
||||
u32 GetOdmWord(int index);
|
||||
|
||||
DramId GetDramId();
|
||||
|
||||
bool GetSecureBootKey(void *dst);
|
||||
|
||||
void GetEcid(br::BootEcid *out);
|
||||
HardwareType GetHardwareType();
|
||||
HardwareState GetHardwareState();
|
||||
u64 GetDeviceId();
|
||||
PatchVersion GetPatchVersion();
|
||||
RetailInteractiveDisplayState GetRetailInteractiveDisplayState();
|
||||
pmic::Regulator GetRegulator();
|
||||
int GetDeviceUniqueKeyGeneration();
|
||||
|
||||
SocType GetSocType();
|
||||
int GetExpectedFuseVersion(TargetFirmware target_fw);
|
||||
int GetFuseVersion();
|
||||
bool HasRcmVulnerabilityPatch();
|
||||
|
||||
bool IsOdmProductionMode();
|
||||
void ConfigureFuseBypass();
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::gic {
|
||||
|
||||
enum InterruptMode {
|
||||
InterruptMode_Level = 0,
|
||||
InterruptMode_Edge = 1,
|
||||
};
|
||||
|
||||
constexpr inline s32 HighestPriority = 0;
|
||||
constexpr inline s32 InterruptCount = 224;
|
||||
|
||||
void SetRegisterAddress(uintptr_t distributor_address, uintptr_t cpu_interface_address);
|
||||
void InitializeCommon();
|
||||
void InitializeCoreUnique();
|
||||
|
||||
void SetPriority(int interrupt_id, int priority);
|
||||
void SetInterruptGroup(int interrupt_id, int group);
|
||||
void SetEnable(int interrupt_id, bool enable);
|
||||
void SetSpiTargetCpu(int interrupt_id, u32 cpu_mask);
|
||||
void SetSpiMode(int interrupt_id, InterruptMode mode);
|
||||
|
||||
void SetPending(int interrupt_id);
|
||||
|
||||
int GetInterruptRequestId();
|
||||
void SetEndOfInterrupt(int interrupt_id);
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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_ARCH_ARM64)
|
||||
#include <exosphere/hw/hw_arm64.hpp>
|
||||
namespace ams::hw { using namespace ams::hw::arch::arm64; }
|
||||
#elif defined(ATMOSPHERE_ARCH_ARM)
|
||||
#include <exosphere/hw/hw_arm.hpp>
|
||||
namespace ams::hw { using namespace ams::hw::arch::arm; }
|
||||
#else
|
||||
#error "Unknown architecture for hw!"
|
||||
#endif
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::hw::arch::arm {
|
||||
|
||||
#ifdef __BPMP__
|
||||
constexpr inline size_t DataCacheLineSize = 0x20;
|
||||
constexpr inline size_t DataCacheSize = 32_KB;
|
||||
|
||||
ALWAYS_INLINE void DataSynchronizationBarrier() {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void DataSynchronizationBarrierInnerShareable() {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void DataMemoryBarrier() {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void InstructionSynchronizationBarrier() {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
void InitializeDataCache();
|
||||
void FinalizeDataCache();
|
||||
|
||||
void InvalidateEntireDataCache();
|
||||
void StoreEntireDataCache();
|
||||
void FlushEntireDataCache();
|
||||
|
||||
void InvalidateDataCacheLine(void *ptr);
|
||||
void StoreDataCacheLine(void *ptr);
|
||||
void FlushDataCacheLine(void *ptr);
|
||||
|
||||
void InvalidateDataCache(void *ptr, size_t size);
|
||||
void StoreDataCache(const void *ptr, size_t size);
|
||||
void FlushDataCache(const void *ptr, size_t size);
|
||||
#else
|
||||
#error "Unknown ARM board for ams::hw"
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <exosphere/hw/hw_arm64_system_registers.hpp>
|
||||
#include <exosphere/hw/hw_arm64_cache.hpp>
|
||||
|
||||
namespace ams::hw::arch::arm64 {
|
||||
|
||||
ALWAYS_INLINE void DataSynchronizationBarrier() {
|
||||
__asm__ __volatile__("dsb sy" ::: "memory");
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void DataSynchronizationBarrierInnerShareable() {
|
||||
__asm__ __volatile__("dsb ish" ::: "memory");
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void DataMemoryBarrier() {
|
||||
__asm__ __volatile__("dmb sy" ::: "memory");
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void InstructionSynchronizationBarrier() {
|
||||
__asm__ __volatile__("isb" ::: "memory");
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void WaitForInterrupt() {
|
||||
__asm__ __volatile__("wfi" ::: "memory");
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void WaitForEvent() {
|
||||
__asm__ __volatile__("wfe" ::: "memory");
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void SendEvent() {
|
||||
__asm__ __volatile__("sev" ::: "memory");
|
||||
}
|
||||
|
||||
ALWAYS_INLINE int CountLeadingZeros(u64 v) {
|
||||
u64 z;
|
||||
__asm__ __volatile__("clz %[z], %[v]" : [z]"=r"(z) : [v]"r"(v));
|
||||
return z;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE int CountLeadingZeros(u32 v) {
|
||||
u32 z;
|
||||
__asm__ __volatile__("clz %w[z], %w[v]" : [z]"=r"(z) : [v]"r"(v));
|
||||
return z;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE int GetCurrentCoreId() {
|
||||
u64 mpidr;
|
||||
HW_CPU_GET_MPIDR_EL1(mpidr);
|
||||
return mpidr & 0xFF;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::hw::arch::arm64 {
|
||||
|
||||
#if defined(ATMOSPHERE_CPU_ARM_CORTEX_A57) || defined(ATMOSPHERE_CPU_ARM_CORTEX_A53)
|
||||
constexpr inline size_t InstructionCacheLineSize = 0x40;
|
||||
constexpr inline size_t DataCacheLineSize = 0x40;
|
||||
constexpr inline size_t NumPerformanceCounters = 6;
|
||||
#else
|
||||
#error "Unknown CPU for cache line sizes"
|
||||
#endif
|
||||
|
||||
ALWAYS_INLINE void InvalidateEntireTlb() {
|
||||
__asm__ __volatile__("tlbi alle3is" ::: "memory");
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void InvalidateDataCacheLine(void *ptr) {
|
||||
__asm __volatile__("dc ivac, %[ptr]" :: [ptr]"r"(ptr) : "memory");
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void FlushDataCacheLine(void *ptr) {
|
||||
__asm __volatile__("dc civac, %[ptr]" :: [ptr]"r"(ptr) : "memory");
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void InvalidateEntireInstructionCache() {
|
||||
__asm__ __volatile__("ic iallu" ::: "memory");
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void InvalidateTlb(uintptr_t address) {
|
||||
const uintptr_t page_index = address / 4_KB;
|
||||
__asm__ __volatile__("tlbi vae3is, %[page_index]" :: [page_index]"r"(page_index) : "memory");
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void InvalidateTlbLastLevel(uintptr_t address) {
|
||||
const uintptr_t page_index = address / 4_KB;
|
||||
__asm__ __volatile__("tlbi vale3is, %[page_index]" :: [page_index]"r"(page_index) : "memory");
|
||||
}
|
||||
|
||||
void FlushDataCache(const void *ptr, size_t size);
|
||||
void InvalidateDataCache(const void *ptr, size_t size);
|
||||
|
||||
}
|
||||
@@ -1,348 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::hw::arch::arm64 {
|
||||
|
||||
#define HW_CPU_GET_SYSREG(name, value) __asm__ __volatile__("mrs %0, " #name "" : "=&r"(value) :: "memory");
|
||||
|
||||
#define HW_CPU_SET_SYSREG(name, value) __asm__ __volatile__("msr " #name ", %0" :: "r"(value) : "memory", "cc")
|
||||
|
||||
#define HW_CPU_GET_SCTLR_EL3(value) HW_CPU_GET_SYSREG(sctlr_el3, value)
|
||||
#define HW_CPU_SET_SCTLR_EL3(value) HW_CPU_SET_SYSREG(sctlr_el3, value)
|
||||
|
||||
#define HW_CPU_GET_SCR_EL3(value) HW_CPU_GET_SYSREG(scr_el3, value)
|
||||
#define HW_CPU_SET_SCR_EL3(value) HW_CPU_SET_SYSREG(scr_el3, value)
|
||||
|
||||
#define HW_CPU_GET_CPTR_EL3(value) HW_CPU_GET_SYSREG(cptr_el3, value)
|
||||
#define HW_CPU_SET_CPTR_EL3(value) HW_CPU_SET_SYSREG(cptr_el3, value)
|
||||
|
||||
#define HW_CPU_GET_TTBR0_EL3(value) HW_CPU_GET_SYSREG(ttbr0_el3, value)
|
||||
#define HW_CPU_SET_TTBR0_EL3(value) HW_CPU_SET_SYSREG(ttbr0_el3, value)
|
||||
|
||||
#define HW_CPU_GET_TCR_EL3(value) HW_CPU_GET_SYSREG(tcr_el3, value)
|
||||
#define HW_CPU_SET_TCR_EL3(value) HW_CPU_SET_SYSREG(tcr_el3, value)
|
||||
|
||||
#define HW_CPU_GET_MAIR_EL3(value) HW_CPU_GET_SYSREG(mair_el3, value)
|
||||
#define HW_CPU_SET_MAIR_EL3(value) HW_CPU_SET_SYSREG(mair_el3, value)
|
||||
|
||||
#define HW_CPU_GET_VBAR_EL3(value) HW_CPU_GET_SYSREG(vbar_el3, value)
|
||||
#define HW_CPU_SET_VBAR_EL3(value) HW_CPU_SET_SYSREG(vbar_el3, value)
|
||||
|
||||
#define HW_CPU_GET_ELR_EL3(value) HW_CPU_GET_SYSREG(elr_el3, value)
|
||||
#define HW_CPU_SET_ELR_EL3(value) HW_CPU_SET_SYSREG(elr_el3, value)
|
||||
|
||||
#define HW_CPU_GET_FAR_EL3(value) HW_CPU_GET_SYSREG(far_el3, value)
|
||||
#define HW_CPU_SET_FAR_EL3(value) HW_CPU_SET_SYSREG(far_el3, value)
|
||||
|
||||
#define HW_CPU_GET_ESR_EL3(value) HW_CPU_GET_SYSREG(esr_el3, value)
|
||||
#define HW_CPU_SET_ESR_EL3(value) HW_CPU_SET_SYSREG(esr_el3, value)
|
||||
|
||||
#define HW_CPU_GET_CLIDR_EL1(value) HW_CPU_GET_SYSREG(clidr_el1, value)
|
||||
#define HW_CPU_SET_CLIDR_EL1(value) HW_CPU_SET_SYSREG(clidr_el1, value)
|
||||
|
||||
#define HW_CPU_GET_CCSIDR_EL1(value) HW_CPU_GET_SYSREG(ccsidr_el1, value)
|
||||
#define HW_CPU_SET_CCSIDR_EL1(value) HW_CPU_SET_SYSREG(ccsidr_el1, value)
|
||||
|
||||
#define HW_CPU_GET_CSSELR_EL1(value) HW_CPU_GET_SYSREG(csselr_el1, value)
|
||||
#define HW_CPU_SET_CSSELR_EL1(value) HW_CPU_SET_SYSREG(csselr_el1, value)
|
||||
|
||||
#define HW_CPU_GET_CPUACTLR_EL1(value) HW_CPU_GET_SYSREG(s3_1_c15_c2_0, value)
|
||||
#define HW_CPU_SET_CPUACTLR_EL1(value) HW_CPU_SET_SYSREG(s3_1_c15_c2_0, value)
|
||||
|
||||
#define HW_CPU_GET_CPUECTLR_EL1(value) HW_CPU_GET_SYSREG(s3_1_c15_c2_1, value)
|
||||
#define HW_CPU_SET_CPUECTLR_EL1(value) HW_CPU_SET_SYSREG(s3_1_c15_c2_1, value)
|
||||
|
||||
#define HW_CPU_GET_DBGAUTHSTATUS_EL1(value) HW_CPU_GET_SYSREG(dbgauthstatus_el1, value)
|
||||
#define HW_CPU_SET_DBGAUTHSTATUS_EL1(value) HW_CPU_SET_SYSREG(dbgauthstatus_el1, value)
|
||||
|
||||
#define HW_CPU_GET_MPIDR_EL1(value) HW_CPU_GET_SYSREG(mpidr_el1, value)
|
||||
|
||||
#define HW_CPU_GET_OSLAR_EL1(value) HW_CPU_GET_SYSREG(oslar_el1, value)
|
||||
#define HW_CPU_SET_OSLAR_EL1(value) HW_CPU_SET_SYSREG(oslar_el1, value)
|
||||
|
||||
#define HW_CPU_GET_OSDTRRX_EL1(value) HW_CPU_GET_SYSREG(osdtrrx_el1, value)
|
||||
#define HW_CPU_SET_OSDTRRX_EL1(value) HW_CPU_SET_SYSREG(osdtrrx_el1, value)
|
||||
|
||||
#define HW_CPU_GET_OSDTRTX_EL1(value) HW_CPU_GET_SYSREG(osdtrtx_el1, value)
|
||||
#define HW_CPU_SET_OSDTRTX_EL1(value) HW_CPU_SET_SYSREG(osdtrtx_el1, value)
|
||||
|
||||
#define HW_CPU_GET_MDSCR_EL1(value) HW_CPU_GET_SYSREG(mdscr_el1, value)
|
||||
#define HW_CPU_SET_MDSCR_EL1(value) HW_CPU_SET_SYSREG(mdscr_el1, value)
|
||||
|
||||
#define HW_CPU_GET_OSECCR_EL1(value) HW_CPU_GET_SYSREG(oseccr_el1, value)
|
||||
#define HW_CPU_SET_OSECCR_EL1(value) HW_CPU_SET_SYSREG(oseccr_el1, value)
|
||||
|
||||
#define HW_CPU_GET_MDCCINT_EL1(value) HW_CPU_GET_SYSREG(mdccint_el1, value)
|
||||
#define HW_CPU_SET_MDCCINT_EL1(value) HW_CPU_SET_SYSREG(mdccint_el1, value)
|
||||
|
||||
#define HW_CPU_GET_DBGCLAIMCLR_EL1(value) HW_CPU_GET_SYSREG(dbgclaimclr_el1, value)
|
||||
#define HW_CPU_SET_DBGCLAIMCLR_EL1(value) HW_CPU_SET_SYSREG(dbgclaimclr_el1, value)
|
||||
|
||||
#define HW_CPU_GET_FAR_EL1(value) HW_CPU_GET_SYSREG(far_el1, value)
|
||||
#define HW_CPU_SET_FAR_EL1(value) HW_CPU_SET_SYSREG(far_el1, value)
|
||||
|
||||
#define HW_CPU_GET_DBGVCR32_EL2(value) HW_CPU_GET_SYSREG(dbgvcr32_el2, value)
|
||||
#define HW_CPU_SET_DBGVCR32_EL2(value) HW_CPU_SET_SYSREG(dbgvcr32_el2, value)
|
||||
|
||||
#define HW_CPU_GET_SDER32_EL3(value) HW_CPU_GET_SYSREG(sder32_el3, value)
|
||||
#define HW_CPU_SET_SDER32_EL3(value) HW_CPU_SET_SYSREG(sder32_el3, value)
|
||||
|
||||
#define HW_CPU_GET_MDCR_EL2(value) HW_CPU_GET_SYSREG(mdcr_el2, value)
|
||||
#define HW_CPU_SET_MDCR_EL2(value) HW_CPU_SET_SYSREG(mdcr_el2, value)
|
||||
|
||||
#define HW_CPU_GET_MDCR_EL3(value) HW_CPU_GET_SYSREG(mdcr_el3, value)
|
||||
#define HW_CPU_SET_MDCR_EL3(value) HW_CPU_SET_SYSREG(mdcr_el3, value)
|
||||
|
||||
#define HW_CPU_GET_SPSR_EL3(value) HW_CPU_GET_SYSREG(spsr_el3, value)
|
||||
#define HW_CPU_SET_SPSR_EL3(value) HW_CPU_SET_SYSREG(spsr_el3, value)
|
||||
|
||||
#define HW_CPU_GET_DBGBVR0_EL1(value) HW_CPU_GET_SYSREG(dbgbvr0_el1, value)
|
||||
#define HW_CPU_SET_DBGBVR0_EL1(value) HW_CPU_SET_SYSREG(dbgbvr0_el1, value)
|
||||
#define HW_CPU_GET_DBGBCR0_EL1(value) HW_CPU_GET_SYSREG(dbgbcr0_el1, value)
|
||||
#define HW_CPU_SET_DBGBCR0_EL1(value) HW_CPU_SET_SYSREG(dbgbcr0_el1, value)
|
||||
#define HW_CPU_GET_DBGBVR1_EL1(value) HW_CPU_GET_SYSREG(dbgbvr1_el1, value)
|
||||
#define HW_CPU_SET_DBGBVR1_EL1(value) HW_CPU_SET_SYSREG(dbgbvr1_el1, value)
|
||||
#define HW_CPU_GET_DBGBCR1_EL1(value) HW_CPU_GET_SYSREG(dbgbcr1_el1, value)
|
||||
#define HW_CPU_SET_DBGBCR1_EL1(value) HW_CPU_SET_SYSREG(dbgbcr1_el1, value)
|
||||
#define HW_CPU_GET_DBGBVR2_EL1(value) HW_CPU_GET_SYSREG(dbgbvr2_el1, value)
|
||||
#define HW_CPU_SET_DBGBVR2_EL1(value) HW_CPU_SET_SYSREG(dbgbvr2_el1, value)
|
||||
#define HW_CPU_GET_DBGBCR2_EL1(value) HW_CPU_GET_SYSREG(dbgbcr2_el1, value)
|
||||
#define HW_CPU_SET_DBGBCR2_EL1(value) HW_CPU_SET_SYSREG(dbgbcr2_el1, value)
|
||||
#define HW_CPU_GET_DBGBVR3_EL1(value) HW_CPU_GET_SYSREG(dbgbvr3_el1, value)
|
||||
#define HW_CPU_SET_DBGBVR3_EL1(value) HW_CPU_SET_SYSREG(dbgbvr3_el1, value)
|
||||
#define HW_CPU_GET_DBGBCR3_EL1(value) HW_CPU_GET_SYSREG(dbgbcr3_el1, value)
|
||||
#define HW_CPU_SET_DBGBCR3_EL1(value) HW_CPU_SET_SYSREG(dbgbcr3_el1, value)
|
||||
#define HW_CPU_GET_DBGBVR4_EL1(value) HW_CPU_GET_SYSREG(dbgbvr4_el1, value)
|
||||
#define HW_CPU_SET_DBGBVR4_EL1(value) HW_CPU_SET_SYSREG(dbgbvr4_el1, value)
|
||||
#define HW_CPU_GET_DBGBCR4_EL1(value) HW_CPU_GET_SYSREG(dbgbcr4_el1, value)
|
||||
#define HW_CPU_SET_DBGBCR4_EL1(value) HW_CPU_SET_SYSREG(dbgbcr4_el1, value)
|
||||
#define HW_CPU_GET_DBGBVR5_EL1(value) HW_CPU_GET_SYSREG(dbgbvr5_el1, value)
|
||||
#define HW_CPU_SET_DBGBVR5_EL1(value) HW_CPU_SET_SYSREG(dbgbvr5_el1, value)
|
||||
#define HW_CPU_GET_DBGBCR5_EL1(value) HW_CPU_GET_SYSREG(dbgbcr5_el1, value)
|
||||
#define HW_CPU_SET_DBGBCR5_EL1(value) HW_CPU_SET_SYSREG(dbgbcr5_el1, value)
|
||||
|
||||
#define HW_CPU_GET_DBGWVR0_EL1(value) HW_CPU_GET_SYSREG(dbgwvr0_el1, value)
|
||||
#define HW_CPU_SET_DBGWVR0_EL1(value) HW_CPU_SET_SYSREG(dbgwvr0_el1, value)
|
||||
#define HW_CPU_GET_DBGWCR0_EL1(value) HW_CPU_GET_SYSREG(dbgwcr0_el1, value)
|
||||
#define HW_CPU_SET_DBGWCR0_EL1(value) HW_CPU_SET_SYSREG(dbgwcr0_el1, value)
|
||||
#define HW_CPU_GET_DBGWVR1_EL1(value) HW_CPU_GET_SYSREG(dbgwvr1_el1, value)
|
||||
#define HW_CPU_SET_DBGWVR1_EL1(value) HW_CPU_SET_SYSREG(dbgwvr1_el1, value)
|
||||
#define HW_CPU_GET_DBGWCR1_EL1(value) HW_CPU_GET_SYSREG(dbgwcr1_el1, value)
|
||||
#define HW_CPU_SET_DBGWCR1_EL1(value) HW_CPU_SET_SYSREG(dbgwcr1_el1, value)
|
||||
#define HW_CPU_GET_DBGWVR2_EL1(value) HW_CPU_GET_SYSREG(dbgwvr2_el1, value)
|
||||
#define HW_CPU_SET_DBGWVR2_EL1(value) HW_CPU_SET_SYSREG(dbgwvr2_el1, value)
|
||||
#define HW_CPU_GET_DBGWCR2_EL1(value) HW_CPU_GET_SYSREG(dbgwcr2_el1, value)
|
||||
#define HW_CPU_SET_DBGWCR2_EL1(value) HW_CPU_SET_SYSREG(dbgwcr2_el1, value)
|
||||
#define HW_CPU_GET_DBGWVR3_EL1(value) HW_CPU_GET_SYSREG(dbgwvr3_el1, value)
|
||||
#define HW_CPU_SET_DBGWVR3_EL1(value) HW_CPU_SET_SYSREG(dbgwvr3_el1, value)
|
||||
#define HW_CPU_GET_DBGWCR3_EL1(value) HW_CPU_GET_SYSREG(dbgwcr3_el1, value)
|
||||
#define HW_CPU_SET_DBGWCR3_EL1(value) HW_CPU_SET_SYSREG(dbgwcr3_el1, value)
|
||||
|
||||
#define HW_CPU_GET_CNTFRQ_EL0(value) HW_CPU_GET_SYSREG(cntfrq_el0, value)
|
||||
#define HW_CPU_SET_CNTFRQ_EL0(value) HW_CPU_SET_SYSREG(cntfrq_el0, value)
|
||||
|
||||
#define HW_CPU_GET_CNTHCTL_EL2(value) HW_CPU_GET_SYSREG(cnthctl_el2, value)
|
||||
#define HW_CPU_SET_CNTHCTL_EL2(value) HW_CPU_SET_SYSREG(cnthctl_el2, value)
|
||||
|
||||
#define HW_CPU_GET_ACTLR_EL2(value) HW_CPU_GET_SYSREG(actlr_el2, value)
|
||||
#define HW_CPU_SET_ACTLR_EL2(value) HW_CPU_SET_SYSREG(actlr_el2, value)
|
||||
|
||||
#define HW_CPU_GET_ACTLR_EL3(value) HW_CPU_GET_SYSREG(actlr_el3, value)
|
||||
#define HW_CPU_SET_ACTLR_EL3(value) HW_CPU_SET_SYSREG(actlr_el3, value)
|
||||
|
||||
#define HW_CPU_GET_HCR_EL2(value) HW_CPU_GET_SYSREG(hcr_el2, value)
|
||||
#define HW_CPU_SET_HCR_EL2(value) HW_CPU_SET_SYSREG(hcr_el2, value)
|
||||
|
||||
#define HW_CPU_GET_DACR32_EL2(value) HW_CPU_GET_SYSREG(dacr32_el2, value)
|
||||
#define HW_CPU_SET_DACR32_EL2(value) HW_CPU_SET_SYSREG(dacr32_el2, value)
|
||||
|
||||
#define HW_CPU_GET_SCTLR_EL2(value) HW_CPU_GET_SYSREG(sctlr_el2, value)
|
||||
#define HW_CPU_SET_SCTLR_EL2(value) HW_CPU_SET_SYSREG(sctlr_el2, value)
|
||||
|
||||
#define HW_CPU_GET_SCTLR_EL1(value) HW_CPU_GET_SYSREG(sctlr_el1, value)
|
||||
#define HW_CPU_SET_SCTLR_EL1(value) HW_CPU_SET_SYSREG(sctlr_el1, value)
|
||||
|
||||
/* https://developer.arm.com/docs/ddi0488/h/system-control/aarch64-register-descriptions/system-control-register-el3 */
|
||||
struct SctlrEl3 {
|
||||
using M = util::BitPack64::Field< 0, 1>;
|
||||
using A = util::BitPack64::Field< 1, 1>;
|
||||
using C = util::BitPack64::Field< 2, 1>;
|
||||
using Sa = util::BitPack64::Field< 3, 1>;
|
||||
using I = util::BitPack64::Field<12, 1>;
|
||||
using Wxn = util::BitPack64::Field<19, 1>;
|
||||
using Ee = util::BitPack64::Field<25, 1>;
|
||||
|
||||
static constexpr u64 Res1 = 0x30C50830;
|
||||
};
|
||||
|
||||
/* https://static.docs.arm.com/ddi0487/fb/DDI0487F_b_armv8_arm.pdf */
|
||||
struct SctlrEl2 {
|
||||
using M = util::BitPack64::Field< 0, 1>;
|
||||
using A = util::BitPack64::Field< 1, 1>;
|
||||
using C = util::BitPack64::Field< 2, 1>;
|
||||
using Sa = util::BitPack64::Field< 3, 1>;
|
||||
using I = util::BitPack64::Field<12, 1>;
|
||||
using Wxn = util::BitPack64::Field<19, 1>;
|
||||
using Ee = util::BitPack64::Field<25, 1>;
|
||||
|
||||
static constexpr u64 Res1 = 0x30C50830;
|
||||
};
|
||||
|
||||
/* https://developer.arm.com/docs/ddi0488/h/system-control/aarch64-register-descriptions/system-control-register-el1 */
|
||||
struct SctlrEl1 {
|
||||
using M = util::BitPack64::Field< 0, 1>;
|
||||
using A = util::BitPack64::Field< 1, 1>;
|
||||
using C = util::BitPack64::Field< 2, 1>;
|
||||
using Sa = util::BitPack64::Field< 3, 1>;
|
||||
using Sa0 = util::BitPack64::Field< 4, 1>;
|
||||
using Cp15BEn = util::BitPack64::Field< 5, 1>;
|
||||
using Thee = util::BitPack64::Field< 6, 1>;
|
||||
using Itd = util::BitPack64::Field< 7, 1>;
|
||||
using Sed = util::BitPack64::Field< 8, 1>;
|
||||
using Uma = util::BitPack64::Field< 9, 1>;
|
||||
using I = util::BitPack64::Field<12, 1>;
|
||||
using Dze = util::BitPack64::Field<14, 1>;
|
||||
using Uct = util::BitPack64::Field<15, 1>;
|
||||
using Ntwi = util::BitPack64::Field<16, 1>;
|
||||
using Ntwe = util::BitPack64::Field<18, 1>;
|
||||
using Wxn = util::BitPack64::Field<19, 1>;
|
||||
using E0e = util::BitPack64::Field<24, 1>;
|
||||
using Ee = util::BitPack64::Field<25, 1>;
|
||||
using Uci = util::BitPack64::Field<26, 1>;
|
||||
|
||||
static constexpr u64 Res1 = 0x30D00800;
|
||||
};
|
||||
|
||||
/* http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0488c/BABGIHHJ.html */
|
||||
struct ScrEl3 {
|
||||
using Ns = util::BitPack32::Field< 0, 1>;
|
||||
using Irq = util::BitPack32::Field< 1, 1>;
|
||||
using Fiq = util::BitPack32::Field< 2, 1>;
|
||||
using Ea = util::BitPack32::Field< 3, 1>;
|
||||
using Fw = util::BitPack32::Field< 4, 1>;
|
||||
using Aw = util::BitPack32::Field< 5, 1>;
|
||||
using Net = util::BitPack32::Field< 6, 1>;
|
||||
using Smd = util::BitPack32::Field< 7, 1>;
|
||||
using Hce = util::BitPack32::Field< 8, 1>;
|
||||
using Sif = util::BitPack32::Field< 9, 1>;
|
||||
using RwCortexA53 = util::BitPack32::Field<10, 1>;
|
||||
using StCortexA53 = util::BitPack32::Field<11, 1>;
|
||||
using Twi = util::BitPack32::Field<12, 1>;
|
||||
using Twe = util::BitPack32::Field<13, 1>;
|
||||
};
|
||||
|
||||
/* http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0488c/CIHDEBIG.html */
|
||||
struct CptrEl3 {
|
||||
using Tfp = util::BitPack32::Field<10, 1>;
|
||||
using Tta = util::BitPack32::Field<20, 1>;
|
||||
using Tcpac = util::BitPack32::Field<31, 1>;
|
||||
};
|
||||
|
||||
/* https://developer.arm.com/docs/ddi0488/h/system-control/aarch64-register-descriptions/translation-control-register-el3 */
|
||||
struct TcrEl3 {
|
||||
using T0sz = util::BitPack32::Field< 0, 6>;
|
||||
using Irgn0 = util::BitPack32::Field< 8, 2>;
|
||||
using Orgn0 = util::BitPack32::Field<10, 2>;
|
||||
using Sh0 = util::BitPack32::Field<12, 2>;
|
||||
using Tg0 = util::BitPack32::Field<14, 2>;
|
||||
using Ps = util::BitPack32::Field<16, 3>;
|
||||
using Tbi = util::BitPack32::Field<20, 1>;
|
||||
|
||||
static constexpr u32 Res1 = 0x80800000;
|
||||
};
|
||||
|
||||
struct ClidrEl1 {
|
||||
using Ctype1 = util::BitPack32::Field< 0, 3>;
|
||||
using Ctype2 = util::BitPack32::Field< 3, 3>;
|
||||
using Ctype3 = util::BitPack32::Field< 6, 3>;
|
||||
using Louis = util::BitPack32::Field<21, 3>;
|
||||
using Loc = util::BitPack32::Field<24, 3>;
|
||||
using Louu = util::BitPack32::Field<27, 3>;
|
||||
};
|
||||
|
||||
struct CcsidrEl1 {
|
||||
using LineSize = util::BitPack32::Field< 0, 3>;
|
||||
using Associativity = util::BitPack32::Field< 3, 10>;
|
||||
using NumSets = util::BitPack32::Field<13, 15>;
|
||||
using Wa = util::BitPack32::Field<28, 1>;
|
||||
using Ra = util::BitPack32::Field<29, 1>;
|
||||
using Wb = util::BitPack32::Field<30, 1>;
|
||||
using Wt = util::BitPack32::Field<31, 1>;
|
||||
};
|
||||
|
||||
struct CsselrEl1 {
|
||||
using InD = util::BitPack32::Field<0, 1>;
|
||||
using Level = util::BitPack32::Field<1, 3>;
|
||||
};
|
||||
|
||||
/* https://developer.arm.com/docs/ddi0488/h/system-control/aarch64-register-descriptions/cpu-auxiliary-control-register-el1 */
|
||||
struct CpuactlrEl1CortexA57 {
|
||||
/* TODO: Other bits */
|
||||
using NonCacheableStreamingEnhancement = util::BitPack64::Field<24, 1>;
|
||||
/* TODO: Other bits */
|
||||
using DisableLoadPassDmb = util::BitPack64::Field<59, 1>;
|
||||
using ForceProcessorRcgEnablesActive = util::BitPack64::Field<63, 1>;
|
||||
};
|
||||
|
||||
/* https://developer.arm.com/docs/ddi0488/h/system-control/aarch64-register-descriptions/cpu-extended-control-register-el1 */
|
||||
struct CpuectlrEl1CortexA57 {
|
||||
using ProcessorDynamicRetentionControl = util::BitPack64::Field< 0, 2>;
|
||||
using Smpen = util::BitPack64::Field< 6, 1>;
|
||||
using L2LoadStoreDataPrefetchDistance = util::BitPack64::Field<32, 2>;
|
||||
using L2InstructionFetchPrefetchDistance = util::BitPack64::Field<35, 2>;
|
||||
using DisableTableWalkDescriptorAccessPrefetch = util::BitPack64::Field<38, 1>;
|
||||
};
|
||||
|
||||
/* https://developer.arm.com/docs/ddi0595/b/aarch64-system-registers/dbgauthstatus_el1 */
|
||||
struct DbgAuthStatusEl1 {
|
||||
using Nsid = util::BitPack32::Field<0, 2>;
|
||||
using Nsnid = util::BitPack32::Field<2, 2>;
|
||||
using Sid = util::BitPack32::Field<4, 2>;
|
||||
using Snid = util::BitPack32::Field<6, 2>;
|
||||
};
|
||||
|
||||
/* https://developer.arm.com/docs/ddi0595/b/aarch64-system-registers/cnthctl_el2 */
|
||||
struct CnthctlEl2 {
|
||||
using El1PctEn = util::BitPack32::Field<0, 1>;
|
||||
using El1PcEn = util::BitPack32::Field<1, 1>;
|
||||
using EvntEn = util::BitPack32::Field<2, 1>;
|
||||
using EvntDir = util::BitPack32::Field<3, 1>;
|
||||
using EvntI = util::BitPack32::Field<4, 4>;
|
||||
};
|
||||
|
||||
/* https://developer.arm.com/docs/ddi0488/h/system-control/aarch64-register-descriptions/auxiliary-control-register-el3 */
|
||||
struct ActlrCortexA57 {
|
||||
using Cpuactlr = util::BitPack32::Field<0, 1>;
|
||||
using Cpuectlr = util::BitPack32::Field<1, 1>;
|
||||
using L2ctlr = util::BitPack32::Field<4, 1>;
|
||||
using L2ectlr = util::BitPack32::Field<5, 1>;
|
||||
using L2actlr = util::BitPack32::Field<6, 1>;
|
||||
};
|
||||
|
||||
/* https://developer.arm.com/docs/ddi0488/h/system-control/aarch64-register-descriptions/hypervisor-configuration-register-el2 */
|
||||
struct HcrEl2 {
|
||||
using Rw = util::BitPack64::Field<31, 1>;
|
||||
};
|
||||
|
||||
struct EsrEl3 {
|
||||
using Iss = util::BitPack32::Field< 0, 25>;
|
||||
using Il = util::BitPack32::Field<25, 1>;
|
||||
using Ec = util::BitPack32::Field<26, 6>;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::i2c {
|
||||
|
||||
enum Port {
|
||||
Port_1 = 0,
|
||||
/* TODO: Support other ports? */
|
||||
Port_5 = 4,
|
||||
|
||||
Port_Count = 5,
|
||||
};
|
||||
|
||||
void SetRegisterAddress(Port port, uintptr_t address);
|
||||
|
||||
void Initialize(Port port);
|
||||
|
||||
bool Query(void *dst, size_t dst_size, Port port, int address, int r);
|
||||
bool Send(Port port, int address, int r, const void *src, size_t src_size);
|
||||
|
||||
inline u8 QueryByte(Port port, int address, int r) {
|
||||
u8 byte;
|
||||
Query(std::addressof(byte), sizeof(byte), port, address, r);
|
||||
return byte;
|
||||
}
|
||||
|
||||
inline void SendByte(Port port, int address, int r, u8 byte) {
|
||||
Send(port, address, r, std::addressof(byte), sizeof(byte));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::log {
|
||||
|
||||
#if defined(AMS_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING)
|
||||
#define AMS_IMPL_ENABLE_LOG
|
||||
#endif
|
||||
|
||||
#if defined(AMS_IMPL_ENABLE_LOG)
|
||||
#define AMS_LOG(...) ::ams::log::Printf(__VA_ARGS__)
|
||||
#define AMS_VLOG(...) ::ams::log::VPrintf(__VA_ARGS__)
|
||||
#define AMS_DUMP(...) ::ams::log::Dump(__VA_ARGS__)
|
||||
#define AMS_LOG_FLUSH() ::ams::log::Flush()
|
||||
#else
|
||||
#define AMS_LOG(...) static_cast<void>(0)
|
||||
#define AMS_VLOG(...) static_cast<void>(0)
|
||||
#define AMS_DUMP(...) static_cast<void>(0)
|
||||
#define AMS_LOG_FLUSH() static_cast<void>(0)
|
||||
#endif
|
||||
|
||||
void Initialize();
|
||||
void Initialize(uart::Port port, u32 baud_rate, u32 flags);
|
||||
void Finalize();
|
||||
|
||||
void Printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
|
||||
void VPrintf(const char *fmt, ::std::va_list vl);
|
||||
void Dump(const void *src, size_t size);
|
||||
|
||||
void SendText(const void *text, size_t size);
|
||||
void Flush();
|
||||
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <exosphere/mmu/mmu_api.hpp>
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::mmu::arch::arm {
|
||||
|
||||
/* NOTE: mmu is not supported by libexosphere-on-arm. */
|
||||
/* However, we want the memory layout to be parseable, so we will include some arm64 mmu definitions. */
|
||||
constexpr inline u64 L1EntryShift = 30;
|
||||
constexpr inline u64 L2EntryShift = 21;
|
||||
constexpr inline u64 L3EntryShift = 12;
|
||||
|
||||
constexpr inline u64 L1EntrySize = 1_GB;
|
||||
constexpr inline u64 L2EntrySize = 2_MB;
|
||||
constexpr inline u64 L3EntrySize = 4_KB;
|
||||
|
||||
constexpr inline u64 PageSize = L3EntrySize;
|
||||
|
||||
constexpr inline u64 L1EntryMask = ((static_cast<u64>(1) << (48 - L1EntryShift)) - 1) << L1EntryShift;
|
||||
constexpr inline u64 L2EntryMask = ((static_cast<u64>(1) << (48 - L2EntryShift)) - 1) << L2EntryShift;
|
||||
constexpr inline u64 L3EntryMask = ((static_cast<u64>(1) << (48 - L3EntryShift)) - 1) << L3EntryShift;
|
||||
|
||||
constexpr inline u64 TableEntryMask = L3EntryMask;
|
||||
|
||||
static_assert(L1EntryMask == 0x0000FFFFC0000000ul);
|
||||
static_assert(L2EntryMask == 0x0000FFFFFFE00000ul);
|
||||
static_assert(L3EntryMask == 0x0000FFFFFFFFF000ul);
|
||||
|
||||
}
|
||||
@@ -1,286 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::mmu::arch::arm64 {
|
||||
|
||||
enum PageTableTableAttribute : u64 {
|
||||
PageTableTableAttribute_None = (0ul << 0),
|
||||
PageTableTableAttribute_PrivilegedExecuteNever = (1ul << 59),
|
||||
PageTableTableAttribute_ExecuteNever = (1ul << 60),
|
||||
PageTableTableAttribute_NonSecure = (1ul << 63),
|
||||
|
||||
PageTableTableAttributes_El3SecureCode = PageTableTableAttribute_None,
|
||||
PageTableTableAttributes_El3SecureData = PageTableTableAttribute_ExecuteNever,
|
||||
PageTableTableAttributes_El3NonSecureCode = PageTableTableAttributes_El3SecureCode | PageTableTableAttribute_NonSecure,
|
||||
PageTableTableAttributes_El3NonSecureData = PageTableTableAttributes_El3SecureData | PageTableTableAttribute_NonSecure,
|
||||
};
|
||||
|
||||
enum PageTableMappingAttribute : u64{
|
||||
/* Security. */
|
||||
PageTableMappingAttribute_NonSecure = (1ul << 5),
|
||||
|
||||
/* El1 Access. */
|
||||
PageTableMappingAttribute_El1NotAllowed = (0ul << 6),
|
||||
PageTableMappingAttribute_El1Allowed = (1ul << 6),
|
||||
|
||||
/* RW Permission. */
|
||||
PageTableMappingAttribute_PermissionReadWrite = (0ul << 7),
|
||||
PageTableMappingAttribute_PermissionReadOnly = (1ul << 7),
|
||||
|
||||
/* Shareability. */
|
||||
PageTableMappingAttribute_ShareabilityNonShareable = (0ul << 8),
|
||||
PageTableMappingAttribute_ShareabiltiyOuterShareable = (2ul << 8),
|
||||
PageTableMappingAttribute_ShareabilityInnerShareable = (3ul << 8),
|
||||
|
||||
/* Access flag. */
|
||||
PageTableMappingAttribute_AccessFlagNotAccessed = (0ul << 10),
|
||||
PageTableMappingAttribute_AccessFlagAccessed = (1ul << 10),
|
||||
|
||||
/* Global. */
|
||||
PageTableMappingAttribute_Global = (0ul << 11),
|
||||
PageTableMappingAttribute_NonGlobal = (1ul << 11),
|
||||
|
||||
/* Contiguous */
|
||||
PageTableMappingAttribute_NonContiguous = (0ul << 52),
|
||||
PageTableMappingAttribute_Contiguous = (1ul << 52),
|
||||
|
||||
/* Privileged Execute Never */
|
||||
PageTableMappingAttribute_PrivilegedExecuteNever = (1ul << 53),
|
||||
|
||||
/* Execute Never */
|
||||
PageTableMappingAttribute_ExecuteNever = (1ul << 54),
|
||||
|
||||
|
||||
/* Useful definitions. */
|
||||
PageTableMappingAttributes_El3SecureRwCode = (
|
||||
PageTableMappingAttribute_PermissionReadWrite |
|
||||
PageTableMappingAttribute_ShareabilityInnerShareable
|
||||
),
|
||||
|
||||
PageTableMappingAttributes_El3SecureRoCode = (
|
||||
PageTableMappingAttribute_PermissionReadOnly |
|
||||
PageTableMappingAttribute_ShareabilityInnerShareable
|
||||
),
|
||||
|
||||
PageTableMappingAttributes_El3SecureRoData = (
|
||||
PageTableMappingAttribute_PermissionReadOnly |
|
||||
PageTableMappingAttribute_ShareabilityInnerShareable |
|
||||
PageTableMappingAttribute_ExecuteNever
|
||||
),
|
||||
|
||||
PageTableMappingAttributes_El3SecureRwData = (
|
||||
PageTableMappingAttribute_PermissionReadWrite |
|
||||
PageTableMappingAttribute_ShareabilityInnerShareable |
|
||||
PageTableMappingAttribute_ExecuteNever
|
||||
),
|
||||
|
||||
PageTableMappingAttributes_El3NonSecureRwCode = PageTableMappingAttributes_El3SecureRwCode | PageTableMappingAttribute_NonSecure,
|
||||
PageTableMappingAttributes_El3NonSecureRoCode = PageTableMappingAttributes_El3SecureRoCode | PageTableMappingAttribute_NonSecure,
|
||||
PageTableMappingAttributes_El3NonSecureRoData = PageTableMappingAttributes_El3SecureRoData | PageTableMappingAttribute_NonSecure,
|
||||
PageTableMappingAttributes_El3NonSecureRwData = PageTableMappingAttributes_El3SecureRwData | PageTableMappingAttribute_NonSecure,
|
||||
|
||||
|
||||
PageTableMappingAttributes_El3SecureDevice = PageTableMappingAttributes_El3SecureRwData,
|
||||
PageTableMappingAttributes_El3NonSecureDevice = PageTableMappingAttributes_El3NonSecureRwData,
|
||||
};
|
||||
|
||||
enum MemoryRegionAttribute : u64 {
|
||||
MemoryRegionAttribute_Device_nGnRnE = (0ul << 2),
|
||||
MemoryRegionAttribute_Device_nGnRE = (1ul << 2),
|
||||
MemoryRegionAttribute_NormalMemory = (2ul << 2),
|
||||
MemoryRegionAttribute_NormalMemoryNotCacheable = (3ul << 2),
|
||||
|
||||
MemoryRegionAttribute_NormalInnerShift = 0,
|
||||
MemoryRegionAttribute_NormalOuterShift = 4,
|
||||
|
||||
#define AMS_MRA_DEFINE_NORMAL_ATTR(__NAME__, __VAL__) \
|
||||
MemoryRegionAttribute_NormalInner##__NAME__ = (__VAL__ << MemoryRegionAttribute_NormalInnerShift), \
|
||||
MemoryRegionAttribute_NormalOuter##__NAME__ = (__VAL__ << MemoryRegionAttribute_NormalOuterShift)
|
||||
|
||||
AMS_MRA_DEFINE_NORMAL_ATTR(NonCacheable, 4),
|
||||
|
||||
AMS_MRA_DEFINE_NORMAL_ATTR(WriteAllocate, (1ul << 0)),
|
||||
AMS_MRA_DEFINE_NORMAL_ATTR(ReadAllocate, (1ul << 1)),
|
||||
|
||||
AMS_MRA_DEFINE_NORMAL_ATTR(WriteThroughTransient, (0ul << 2)),
|
||||
AMS_MRA_DEFINE_NORMAL_ATTR(WriteBackTransient, (1ul << 2)),
|
||||
AMS_MRA_DEFINE_NORMAL_ATTR(WriteThroughNonTransient, (2ul << 2)),
|
||||
AMS_MRA_DEFINE_NORMAL_ATTR(WriteBackNonTransient, (3ul << 2)),
|
||||
|
||||
#undef AMS_MRA_DEFINE_NORMAL_ATTR
|
||||
|
||||
MemoryRegionAttributes_Normal = (
|
||||
MemoryRegionAttribute_NormalInnerReadAllocate |
|
||||
MemoryRegionAttribute_NormalOuterReadAllocate |
|
||||
MemoryRegionAttribute_NormalInnerWriteAllocate |
|
||||
MemoryRegionAttribute_NormalOuterWriteAllocate |
|
||||
MemoryRegionAttribute_NormalInnerWriteBackNonTransient |
|
||||
MemoryRegionAttribute_NormalOuterWriteBackNonTransient
|
||||
),
|
||||
|
||||
MemoryRegionAttributes_Device = (
|
||||
MemoryRegionAttribute_Device_nGnRE
|
||||
),
|
||||
};
|
||||
|
||||
constexpr inline u64 MemoryRegionAttributeWidth = 8;
|
||||
|
||||
constexpr ALWAYS_INLINE PageTableMappingAttribute AddMappingAttributeIndex(PageTableMappingAttribute attr, int index) {
|
||||
return static_cast<PageTableMappingAttribute>(attr | (static_cast<typename std::underlying_type<PageTableMappingAttribute>::type>(index) << 2));
|
||||
}
|
||||
|
||||
constexpr inline u64 L1EntryShift = 30;
|
||||
constexpr inline u64 L2EntryShift = 21;
|
||||
constexpr inline u64 L3EntryShift = 12;
|
||||
|
||||
constexpr inline u64 L1EntrySize = 1_GB;
|
||||
constexpr inline u64 L2EntrySize = 2_MB;
|
||||
constexpr inline u64 L3EntrySize = 4_KB;
|
||||
|
||||
constexpr inline u64 PageSize = L3EntrySize;
|
||||
|
||||
constexpr inline u64 L1EntryMask = ((1ul << (48 - L1EntryShift)) - 1) << L1EntryShift;
|
||||
constexpr inline u64 L2EntryMask = ((1ul << (48 - L2EntryShift)) - 1) << L2EntryShift;
|
||||
constexpr inline u64 L3EntryMask = ((1ul << (48 - L3EntryShift)) - 1) << L3EntryShift;
|
||||
|
||||
constexpr inline u64 TableEntryMask = L3EntryMask;
|
||||
|
||||
static_assert(L1EntryMask == 0x0000FFFFC0000000ul);
|
||||
static_assert(L2EntryMask == 0x0000FFFFFFE00000ul);
|
||||
static_assert(L3EntryMask == 0x0000FFFFFFFFF000ul);
|
||||
|
||||
constexpr inline u64 TableEntryIndexMask = 0x1FF;
|
||||
|
||||
constexpr inline u64 EntryBlock = 0x1ul;
|
||||
constexpr inline u64 EntryPage = 0x3ul;
|
||||
|
||||
constexpr ALWAYS_INLINE u64 MakeTableEntry(u64 address, PageTableTableAttribute attr) {
|
||||
return address | static_cast<u64>(attr) | 0x3ul;
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE u64 MakeL1BlockEntry(u64 address, PageTableMappingAttribute attr) {
|
||||
return address | static_cast<u64>(attr) | static_cast<u64>(PageTableMappingAttribute_AccessFlagAccessed) | 0x1ul;
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE u64 MakeL2BlockEntry(u64 address, PageTableMappingAttribute attr) {
|
||||
return address | static_cast<u64>(attr) | static_cast<u64>(PageTableMappingAttribute_AccessFlagAccessed) | 0x1ul;
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE u64 MakeL3BlockEntry(u64 address, PageTableMappingAttribute attr) {
|
||||
return address | static_cast<u64>(attr) | static_cast<u64>(PageTableMappingAttribute_AccessFlagAccessed) | 0x3ul;
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE uintptr_t GetL2Offset(uintptr_t address) {
|
||||
return address & ((1ul << L2EntryShift) - 1);
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE u64 GetL1EntryIndex(uintptr_t address) {
|
||||
return ((address >> L1EntryShift) & TableEntryIndexMask);
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE u64 GetL2EntryIndex(uintptr_t address) {
|
||||
return ((address >> L2EntryShift) & TableEntryIndexMask);
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE u64 GetL3EntryIndex(uintptr_t address) {
|
||||
return ((address >> L3EntryShift) & TableEntryIndexMask);
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE void SetTableEntryImpl(volatile u64 *table, u64 index, u64 value) {
|
||||
/* Write the value. */
|
||||
table[index] = value;
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE void SetTableEntry(u64 *table, u64 index, u64 value) {
|
||||
/* Ensure (for constexpr validation purposes) that the entry we set is clear. */
|
||||
if (std::is_constant_evaluated()) {
|
||||
if (table[index]) {
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the value. */
|
||||
SetTableEntryImpl(table, index, value);
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE void SetL1TableEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, PageTableTableAttribute attr) {
|
||||
SetTableEntry(table, GetL1EntryIndex(virt_addr), MakeTableEntry(phys_addr & TableEntryMask, attr));
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE void SetL2TableEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, PageTableTableAttribute attr) {
|
||||
SetTableEntry(table, GetL2EntryIndex(virt_addr), MakeTableEntry(phys_addr & TableEntryMask, attr));
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE void SetL1BlockEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, size_t size, PageTableMappingAttribute attr) {
|
||||
const u64 start = GetL1EntryIndex(virt_addr);
|
||||
const u64 count = (size >> L1EntryShift);
|
||||
|
||||
for (u64 i = 0; i < count; ++i) {
|
||||
SetTableEntry(table, start + i, MakeL1BlockEntry((phys_addr & L1EntryMask) + (i << L1EntryShift), attr));
|
||||
}
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE void SetL2BlockEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, size_t size, PageTableMappingAttribute attr) {
|
||||
const u64 start = GetL2EntryIndex(virt_addr);
|
||||
const u64 count = (size >> L2EntryShift);
|
||||
|
||||
for (u64 i = 0; i < count; ++i) {
|
||||
SetTableEntry(table, start + i, MakeL2BlockEntry((phys_addr & L2EntryMask) + (i << L2EntryShift), attr));
|
||||
}
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE void SetL3BlockEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, size_t size, PageTableMappingAttribute attr) {
|
||||
const u64 start = GetL3EntryIndex(virt_addr);
|
||||
const u64 count = (size >> L3EntryShift);
|
||||
|
||||
for (u64 i = 0; i < count; ++i) {
|
||||
SetTableEntry(table, start + i, MakeL3BlockEntry((phys_addr & L3EntryMask) + (i << L3EntryShift), attr));
|
||||
}
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE void InvalidateL1Entries(volatile u64 *table, uintptr_t virt_addr, size_t size) {
|
||||
const u64 start = GetL1EntryIndex(virt_addr);
|
||||
const u64 count = (size >> L1EntryShift);
|
||||
const u64 end = start + count;
|
||||
|
||||
for (u64 i = start; i < end; ++i) {
|
||||
table[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE void InvalidateL2Entries(volatile u64 *table, uintptr_t virt_addr, size_t size) {
|
||||
const u64 start = GetL2EntryIndex(virt_addr);
|
||||
const u64 count = (size >> L2EntryShift);
|
||||
const u64 end = start + count;
|
||||
|
||||
for (u64 i = start; i < end; ++i) {
|
||||
table[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE void InvalidateL3Entries(volatile u64 *table, uintptr_t virt_addr, size_t size) {
|
||||
const u64 start = GetL3EntryIndex(virt_addr);
|
||||
const u64 count = (size >> L3EntryShift);
|
||||
const u64 end = start + count;
|
||||
|
||||
for (u64 i = start; i < end; ++i) {
|
||||
table[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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_ARCH_ARM64)
|
||||
#include <exosphere/mmu/mmu_api.arch.arm64.hpp>
|
||||
#elif defined(ATMOSPHERE_ARCH_ARM)
|
||||
#include <exosphere/mmu/mmu_api.arch.arm.hpp>
|
||||
#else
|
||||
#error "Unknown architecture for mmu!"
|
||||
#endif
|
||||
|
||||
namespace ams::mmu {
|
||||
|
||||
#if defined(ATMOSPHERE_ARCH_ARM64)
|
||||
using namespace ams::mmu::arch::arm64;
|
||||
#elif defined(ATMOSPHERE_ARCH_ARM)
|
||||
using namespace ams::mmu::arch::arm;
|
||||
#else
|
||||
#error "Unknown architecture for mmu!"
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <exosphere/fuse.hpp>
|
||||
|
||||
namespace ams::pinmux {
|
||||
|
||||
void SetRegisterAddress(uintptr_t pinmux_address, uintptr_t gpio_address);
|
||||
|
||||
void SetupFirst(fuse::HardwareType hw_type);
|
||||
|
||||
void SetupUartA();
|
||||
void SetupUartB();
|
||||
void SetupUartC();
|
||||
void SetupI2c1();
|
||||
void SetupI2c5();
|
||||
|
||||
void SetupVolumeButton();
|
||||
void SetupHomeButton();
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <exosphere/pkg1/pkg1_bootloader_parameters.hpp>
|
||||
#include <exosphere/pkg1/pkg1_boot_config.hpp>
|
||||
#include <exosphere/pkg1/pkg1_error_types.hpp>
|
||||
#include <exosphere/pkg1/pkg1_key_generation.hpp>
|
||||
#include <exosphere/pkg1/pkg1_se_key_slots.hpp>
|
||||
#include <exosphere/pkg1/pkg1_api.hpp>
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::pkg1 {
|
||||
|
||||
bool IsProduction();
|
||||
bool IsProductionForVersionCheck();
|
||||
bool IsProductionForPublicKey();
|
||||
|
||||
}
|
||||
@@ -1,145 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::pkg1 {
|
||||
|
||||
enum MemorySize {
|
||||
MemorySize_4GB = 0,
|
||||
MemorySize_6GB = 1,
|
||||
MemorySize_8GB = 2,
|
||||
};
|
||||
|
||||
enum MemoryArrange {
|
||||
MemoryArrange_Normal = 1,
|
||||
MemoryArrange_AppletDev = 2,
|
||||
MemoryArrange_SystemDev = 3,
|
||||
};
|
||||
|
||||
enum MemoryMode {
|
||||
MemoryMode_SizeShift = 4,
|
||||
MemoryMode_SizeMask = 0x30,
|
||||
|
||||
MemoryMode_ArrangeMask = 0x0F,
|
||||
|
||||
MemoryMode_Auto = 0x00,
|
||||
|
||||
MemoryMode_4GB = ((MemorySize_4GB << MemoryMode_SizeShift) | (MemoryArrange_Normal)),
|
||||
MemoryMode_4GBAppletDev = ((MemorySize_4GB << MemoryMode_SizeShift) | (MemoryArrange_AppletDev)),
|
||||
MemoryMode_4GBSystemDev = ((MemorySize_4GB << MemoryMode_SizeShift) | (MemoryArrange_SystemDev)),
|
||||
|
||||
MemoryMode_6GB = ((MemorySize_6GB << MemoryMode_SizeShift) | (MemoryArrange_Normal)),
|
||||
MemoryMode_6GBAppletDev = ((MemorySize_6GB << MemoryMode_SizeShift) | (MemoryArrange_AppletDev)),
|
||||
|
||||
MemoryMode_8GB = ((MemorySize_8GB << MemoryMode_SizeShift) | (MemoryArrange_Normal)),
|
||||
};
|
||||
|
||||
constexpr ALWAYS_INLINE MemorySize GetMemorySize(MemoryMode mode) {
|
||||
return static_cast<MemorySize>(mode >> MemoryMode_SizeShift);
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE MemoryArrange GetMemoryArrange(MemoryMode mode) {
|
||||
return static_cast<MemoryArrange>(mode & MemoryMode_ArrangeMask);
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE MemoryMode MakeMemoryMode(MemorySize size, MemoryArrange arrange) {
|
||||
return static_cast<MemoryMode>((size << MemoryMode_SizeShift) | (arrange));
|
||||
}
|
||||
|
||||
struct BootConfigData {
|
||||
u32 version;
|
||||
u32 reserved_04;
|
||||
u32 reserved_08;
|
||||
u32 reserved_0C;
|
||||
u8 flags1[0x10];
|
||||
u8 flags0[0x10];
|
||||
u64 initial_tsc_value;
|
||||
u8 padding_38[0x200 - 0x38];
|
||||
|
||||
constexpr bool IsDevelopmentFunctionEnabled() const {
|
||||
return (this->flags1[0] & (1 << 1)) != 0;
|
||||
}
|
||||
|
||||
constexpr bool IsSErrorDebugEnabled() const {
|
||||
return (this->flags1[0] & (1 << 2)) != 0;
|
||||
}
|
||||
|
||||
constexpr u8 GetKernelFlags0() const {
|
||||
return this->flags0[1];
|
||||
}
|
||||
|
||||
constexpr u8 GetKernelFlags1() const {
|
||||
return this->flags1[0];
|
||||
}
|
||||
|
||||
constexpr MemoryMode GetMemoryMode() const {
|
||||
return static_cast<MemoryMode>(this->flags0[3]);
|
||||
}
|
||||
|
||||
constexpr bool IsInitialTscValueValid() const {
|
||||
return (this->flags0[4] & (1 << 0)) != 0;
|
||||
}
|
||||
|
||||
constexpr u64 GetInitialTscValue() const {
|
||||
return this->IsInitialTscValueValid() ? this->initial_tsc_value : 0;
|
||||
}
|
||||
};
|
||||
static_assert(util::is_pod<BootConfigData>::value);
|
||||
static_assert(sizeof(BootConfigData) == 0x200);
|
||||
|
||||
struct BootConfigSignedData {
|
||||
u32 version;
|
||||
u32 reserved_04;
|
||||
u8 flags;
|
||||
u8 reserved_09[0x10 - 9];
|
||||
u8 ecid[0x10];
|
||||
u8 flags1[0x10];
|
||||
u8 flags0[0x10];
|
||||
u8 padding_40[0x100 - 0x40];
|
||||
|
||||
constexpr bool IsPackage2EncryptionDisabled() const {
|
||||
return (this->flags & (1 << 0)) != 0;
|
||||
}
|
||||
|
||||
constexpr bool IsPackage2SignatureVerificationDisabled() const {
|
||||
return (this->flags & (1 << 1)) != 0;
|
||||
}
|
||||
|
||||
constexpr bool IsProgramVerificationDisabled() const {
|
||||
return (this->flags1[0] & (1 << 0)) != 0;
|
||||
}
|
||||
|
||||
constexpr void SetPackage2SignatureVerificationDisabled(bool decrypted) {
|
||||
this->flags |= decrypted ? (1 << 1) : (0 << 0);
|
||||
}
|
||||
|
||||
constexpr void SetPackage2EncryptionDisabled(bool decrypted) {
|
||||
this->flags |= decrypted ? (1 << 0) : (0 << 0);
|
||||
}
|
||||
};
|
||||
static_assert(util::is_pod<BootConfigSignedData>::value);
|
||||
static_assert(sizeof(BootConfigSignedData) == 0x100);
|
||||
|
||||
struct BootConfig {
|
||||
BootConfigData data;
|
||||
u8 signature[0x100];
|
||||
BootConfigSignedData signed_data;
|
||||
};
|
||||
static_assert(util::is_pod<BootConfig>::value);
|
||||
static_assert(sizeof(BootConfig) == 0x400);
|
||||
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::pkg1 {
|
||||
|
||||
enum BootloaderState {
|
||||
BootloaderState_Start = 0,
|
||||
BootloaderState_LoadedBootConfig = 1,
|
||||
BootloaderState_InitializedDram = 2,
|
||||
BootloaderState_LoadedPackage2 = 3,
|
||||
BootloaderState_Done = 4,
|
||||
};
|
||||
|
||||
enum SecureMonitorState {
|
||||
SecureMonitorState_Start = 0,
|
||||
SecureMonitorState_Initialized = 1,
|
||||
};
|
||||
|
||||
struct BctParameters {
|
||||
u32 bootloader_version;
|
||||
u32 bootloader_start_block;
|
||||
u32 bootloader_start_page;
|
||||
u32 bootloader_attributes;
|
||||
};
|
||||
static_assert(util::is_pod<BctParameters>::value && sizeof(BctParameters) == 0x10);
|
||||
|
||||
struct SecureMonitorParameters {
|
||||
u32 bootloader_start_time;
|
||||
u32 bootloader_end_time;
|
||||
u32 secmon_start_time;
|
||||
u32 secmon_end_time;
|
||||
BctParameters bct_params;
|
||||
u32 deprecated_boot_reason_value;
|
||||
u8 deprecated_boot_reason_state;
|
||||
u8 reserved[0xD3];
|
||||
u32 bootloader_state;
|
||||
u32 secmon_state;
|
||||
u8 reserved2[0x100];
|
||||
};
|
||||
static_assert(util::is_pod<SecureMonitorParameters>::value);
|
||||
static_assert(sizeof(SecureMonitorParameters) == 0x200);
|
||||
|
||||
static_assert(AMS_OFFSETOF(SecureMonitorParameters, bct_params) == 0x10);
|
||||
static_assert(AMS_OFFSETOF(SecureMonitorParameters, bootloader_state) == 0xF8);
|
||||
static_assert(AMS_OFFSETOF(SecureMonitorParameters, secmon_state) == 0xFC);
|
||||
|
||||
enum BootloaderAttribute {
|
||||
BootloaderAttribute_None = (0u << 0),
|
||||
BootloaderAttribute_RecoveryBoot = (1u << 0),
|
||||
|
||||
BootloaderAttribute_RestrictedSmcShift = 1,
|
||||
BootloaderAttribute_RestrictedSmcMask = (0xFu << BootloaderAttribute_RestrictedSmcShift),
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::pkg1 {
|
||||
|
||||
enum ErrorReason {
|
||||
ErrorReason_None = 0,
|
||||
ErrorReason_InvalidPackage2Signature = 1,
|
||||
ErrorReason_InvalidPackage2Meta = 2,
|
||||
ErrorReason_InvalidPackage2Version = 3,
|
||||
ErrorReason_InvalidPackage2Payload = 4,
|
||||
ErrorReason_UnknownSmc = 5,
|
||||
ErrorReason_UnknownAbort = 6,
|
||||
ErrorReason_InvalidCoreContext = 7,
|
||||
ErrorReason_InvalidSecurityEngineStickyBits = 8,
|
||||
ErrorReason_UnexpectedReset = 9,
|
||||
|
||||
ErrorReason_Exception = 0x10,
|
||||
|
||||
ErrorReason_TransitionToSafeMode = 0x20,
|
||||
ErrorReason_SecureInitializerReboot = 0x21,
|
||||
|
||||
ErrorReason_SdmmcError = 0x30,
|
||||
ErrorReason_InvalidDramId = 0x31,
|
||||
ErrorReason_InvalidPackage2 = 0x32,
|
||||
ErrorReason_InvalidBct = 0x33,
|
||||
ErrorReason_InvalidGpt = 0x34,
|
||||
ErrorReason_FailedToTransitionToSafeMode = 0x35,
|
||||
ErrorReason_ActivityMonitorInterrupt = 0x36,
|
||||
|
||||
ErrorReason_KernelPanic = 0x40,
|
||||
};
|
||||
|
||||
enum ErrorColor {
|
||||
ErrorColor_Black = 0x000,
|
||||
|
||||
ErrorColor_Red = 0x00F,
|
||||
ErrorColor_Yellow = 0x0FF,
|
||||
ErrorColor_Orange = 0x07F,
|
||||
ErrorColor_Blue = 0xF00,
|
||||
ErrorColor_LightBlue = 0xFF0,
|
||||
ErrorColor_Pink = 0xF7F,
|
||||
ErrorColor_Purple = 0xF0A,
|
||||
};
|
||||
|
||||
enum ErrorInfo {
|
||||
ErrorInfo_ReasonMask = 0xFF,
|
||||
ErrorInfo_ColorShift = 20,
|
||||
|
||||
#define MAKE_ERROR_INFO(_COLOR_, _DESC_) ((static_cast<u32>(ErrorColor_##_COLOR_) << ErrorInfo_ColorShift) | (ErrorReason_##_DESC_))
|
||||
|
||||
ErrorInfo_None = MAKE_ERROR_INFO(Black, None),
|
||||
|
||||
ErrorInfo_InvalidPackage2Signature = MAKE_ERROR_INFO(Blue, InvalidPackage2Signature),
|
||||
ErrorInfo_InvalidPackage2Meta = MAKE_ERROR_INFO(Blue, InvalidPackage2Meta),
|
||||
ErrorInfo_InvalidPackage2Version = MAKE_ERROR_INFO(Blue, InvalidPackage2Version),
|
||||
ErrorInfo_InvalidPackage2Payload = MAKE_ERROR_INFO(Blue, InvalidPackage2Payload),
|
||||
|
||||
ErrorInfo_UnknownSmc = MAKE_ERROR_INFO(LightBlue, UnknownSmc),
|
||||
|
||||
ErrorInfo_UnknownAbort = MAKE_ERROR_INFO(Yellow, UnknownAbort),
|
||||
|
||||
ErrorInfo_InvalidCoreContext = MAKE_ERROR_INFO(Pink, InvalidCoreContext),
|
||||
ErrorInfo_InvalidSecurityEngineStickyBits = MAKE_ERROR_INFO(Pink, InvalidSecurityEngineStickyBits),
|
||||
ErrorInfo_UnexpectedReset = MAKE_ERROR_INFO(Pink, UnexpectedReset),
|
||||
|
||||
ErrorInfo_Exception = MAKE_ERROR_INFO(Orange, Exception),
|
||||
|
||||
ErrorInfo_TransitionToSafeMode = MAKE_ERROR_INFO(Black, TransitionToSafeMode),
|
||||
ErrorInfo_SecureInitializerReboot = MAKE_ERROR_INFO(Black, SecureInitializerReboot),
|
||||
|
||||
ErrorInfo_SdmmcError = MAKE_ERROR_INFO(Purple, SdmmcError),
|
||||
ErrorInfo_InvalidDramId = MAKE_ERROR_INFO(Purple, InvalidDramId),
|
||||
ErrorInfo_InvalidPackage2 = MAKE_ERROR_INFO(Purple, InvalidPackage2),
|
||||
ErrorInfo_InvalidBct = MAKE_ERROR_INFO(Purple, InvalidBct),
|
||||
ErrorInfo_InvalidGpt = MAKE_ERROR_INFO(Purple, InvalidGpt),
|
||||
ErrorInfo_FailedToTransitionToSafeMode = MAKE_ERROR_INFO(Purple, FailedToTransitionToSafeMode),
|
||||
ErrorInfo_ActivityMonitorInterrupt = MAKE_ERROR_INFO(Purple, ActivityMonitorInterrupt),
|
||||
|
||||
#undef MAKE_ERROR_INFO
|
||||
};
|
||||
|
||||
constexpr inline ErrorReason GetErrorReason(u32 info) {
|
||||
return static_cast<ErrorReason>(info & ErrorInfo_ReasonMask);
|
||||
}
|
||||
|
||||
constexpr inline ErrorInfo MakeKernelPanicResetInfo(u32 color) {
|
||||
return static_cast<ErrorInfo>((color << ErrorInfo_ColorShift) | (ErrorReason_KernelPanic));
|
||||
}
|
||||
|
||||
#define PKG1_SECURE_MONITOR_PMC_ERROR_SCRATCH (0x840)
|
||||
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::pkg1 {
|
||||
|
||||
enum KeyGeneration : int {
|
||||
|
||||
KeyGeneration_1_0_0 = 0x00,
|
||||
KeyGeneration_3_0_0 = 0x01,
|
||||
KeyGeneration_3_0_1 = 0x02,
|
||||
KeyGeneration_4_0_0 = 0x03,
|
||||
KeyGeneration_5_0_0 = 0x04,
|
||||
KeyGeneration_6_0_0 = 0x05,
|
||||
KeyGeneration_6_2_0 = 0x06,
|
||||
KeyGeneration_7_0_0 = 0x07,
|
||||
KeyGeneration_8_1_0 = 0x08,
|
||||
KeyGeneration_9_0_0 = 0x09,
|
||||
KeyGeneration_9_1_0 = 0x0A,
|
||||
KeyGeneration_12_1_0 = 0x0B,
|
||||
KeyGeneration_13_0_0 = 0x0C,
|
||||
KeyGeneration_14_0_0 = 0x0D,
|
||||
KeyGeneration_15_0_0 = 0x0E,
|
||||
KeyGeneration_16_0_0 = 0x0F,
|
||||
KeyGeneration_17_0_0 = 0x10,
|
||||
KeyGeneration_18_0_0 = 0x11,
|
||||
KeyGeneration_19_0_0 = 0x12,
|
||||
KeyGeneration_20_0_0 = 0x13,
|
||||
|
||||
KeyGeneration_Count,
|
||||
|
||||
KeyGeneration_Current = KeyGeneration_Count - 1,
|
||||
|
||||
KeyGeneration_Min = 0x00,
|
||||
KeyGeneration_Max = 0x20,
|
||||
};
|
||||
static_assert(KeyGeneration_Count <= KeyGeneration_Max);
|
||||
|
||||
constexpr inline const int OldMasterKeyCount = KeyGeneration_Count - 1;
|
||||
constexpr inline const int OldDeviceMasterKeyCount = KeyGeneration_Count - KeyGeneration_4_0_0;
|
||||
|
||||
constexpr bool IsValidDeviceUniqueKeyGeneration(int generation) {
|
||||
return generation == KeyGeneration_1_0_0 || (KeyGeneration_4_0_0 <= generation && generation <= KeyGeneration_Current);
|
||||
}
|
||||
|
||||
constexpr bool IsValidKeyGeneration(int generation) {
|
||||
return KeyGeneration_Min <= generation && generation <= KeyGeneration_Current;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::pkg1 {
|
||||
|
||||
enum AesKeySlot {
|
||||
AesKeySlot_UserStart = 0,
|
||||
|
||||
AesKeySlot_TzramSaveKek = 2,
|
||||
AesKeySlot_TzramSaveKey = 3,
|
||||
|
||||
AesKeySlot_UserLast = 5,
|
||||
AesKeySlot_UserEnd = AesKeySlot_UserLast + 1,
|
||||
|
||||
AesKeySlot_SecmonStart = 8,
|
||||
|
||||
AesKeySlot_Temporary = 8,
|
||||
AesKeySlot_Smc = 9,
|
||||
AesKeySlot_RandomForUserWrap = 10,
|
||||
AesKeySlot_RandomForKeyStorageWrap = 11,
|
||||
AesKeySlot_DeviceMaster = 12,
|
||||
AesKeySlot_Master = 13,
|
||||
AesKeySlot_Device = 15,
|
||||
|
||||
AesKeySlot_Count = 16,
|
||||
AesKeySlot_SecmonEnd = AesKeySlot_Count,
|
||||
|
||||
/* Used only during boot. */
|
||||
AesKeySlot_TsecRootDev = 11,
|
||||
AesKeySlot_Tsec = 12,
|
||||
AesKeySlot_TsecRoot = 13,
|
||||
AesKeySlot_SecureBoot = 14,
|
||||
AesKeySlot_SecureStorage = 15,
|
||||
|
||||
AesKeySlot_DeviceMasterKeySourceKekErista = 10,
|
||||
AesKeySlot_MasterKek = 13,
|
||||
AesKeySlot_DeviceMasterKeySourceKekMariko = 14,
|
||||
|
||||
/* Mariko only keyslots, used during boot. */
|
||||
AesKeySlot_MarikoKek = 12,
|
||||
AesKeySlot_MarikoBek = 13,
|
||||
|
||||
/* Bootloader keyslots, for fusee only. */
|
||||
AesKeySlot_BootloaderSystem0 = 2,
|
||||
AesKeySlot_BootloaderSystem1 = 3,
|
||||
AesKeySlot_BootloaderDeviceMaster = 6,
|
||||
AesKeySlot_BootloaderMaster = 7,
|
||||
AesKeySlot_BootloaderTemporary = 8,
|
||||
};
|
||||
|
||||
enum RsaKeySlot {
|
||||
RsaKeySlot_Temporary = 0,
|
||||
RsaKeySlot_PrivateKey = 1,
|
||||
};
|
||||
|
||||
constexpr bool IsUserAesKeySlot(int slot) {
|
||||
return AesKeySlot_UserStart <= slot && slot < AesKeySlot_UserEnd;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::pkg2 {
|
||||
|
||||
constexpr inline size_t Package2SizeMax = 8_MB - 16_KB;
|
||||
constexpr inline size_t PayloadAlignment = 4;
|
||||
|
||||
constexpr inline int PayloadCount = 3;
|
||||
|
||||
constexpr inline int MinimumValidDataVersion = 0; /* We allow older package2 to load; this value is currently 0x18 in Nintendo's code. */
|
||||
constexpr inline int CurrentBootloaderVersion = 0x17;
|
||||
|
||||
struct Package2Meta {
|
||||
using Magic = util::FourCC<'P','K','2','1'>;
|
||||
|
||||
u32 package2_size;
|
||||
u8 key_generation;
|
||||
u8 header_iv_remainder[11];
|
||||
u8 payload_ivs[PayloadCount][0x10];
|
||||
u8 padding_40[0x10];
|
||||
u8 magic[4];
|
||||
u32 entrypoint;
|
||||
u8 padding_58[4];
|
||||
u8 package2_version;
|
||||
u8 bootloader_version;
|
||||
u8 padding_5E[2];
|
||||
u32 payload_sizes[PayloadCount];
|
||||
u8 padding_6C[4];
|
||||
u32 payload_offsets[PayloadCount];
|
||||
u8 padding_7C[4];
|
||||
u8 payload_hashes[PayloadCount][crypto::Sha256Generator::HashSize];
|
||||
u8 padding_E0[0x20];
|
||||
|
||||
private:
|
||||
static ALWAYS_INLINE u32 ReadWord(const void *ptr, int offset) {
|
||||
return util::LoadLittleEndian(reinterpret_cast<const u32 *>(reinterpret_cast<uintptr_t>(ptr) + offset));
|
||||
}
|
||||
public:
|
||||
ALWAYS_INLINE u8 GetKeyGeneration() const {
|
||||
return static_cast<u8>(std::max<s32>(0, static_cast<s32>(this->key_generation ^ this->header_iv_remainder[1] ^ this->header_iv_remainder[2]) - 1));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE u32 GetSize() const {
|
||||
return this->package2_size ^ ReadWord(this->header_iv_remainder, 3) ^ ReadWord(this->header_iv_remainder, 7);
|
||||
}
|
||||
};
|
||||
static_assert(util::is_pod<Package2Meta>::value);
|
||||
static_assert(sizeof(Package2Meta) == 0x100);
|
||||
|
||||
struct Package2Header {
|
||||
u8 signature[0x100];
|
||||
Package2Meta meta;
|
||||
};
|
||||
static_assert(util::is_pod<Package2Header>::value);
|
||||
static_assert(sizeof(Package2Header) == 0x200);
|
||||
|
||||
struct StorageLayout {
|
||||
u8 boot_config[16_KB];
|
||||
Package2Header package2_header;
|
||||
u8 data[Package2SizeMax - sizeof(Package2Header)];
|
||||
};
|
||||
static_assert(util::is_pod<StorageLayout>::value);
|
||||
static_assert(sizeof(StorageLayout) == 8_MB);
|
||||
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::pmc {
|
||||
|
||||
enum SecureRegister {
|
||||
SecureRegister_Other = (1 << 0),
|
||||
SecureRegister_DramParameters = (1 << 1),
|
||||
SecureRegister_ResetVector = (1 << 2),
|
||||
SecureRegister_Carveout = (1 << 3),
|
||||
SecureRegister_CmacWrite = (1 << 4),
|
||||
SecureRegister_CmacRead = (1 << 5),
|
||||
SecureRegister_KeySourceWrite = (1 << 6),
|
||||
SecureRegister_KeySourceRead = (1 << 7),
|
||||
SecureRegister_Srk = (1 << 8),
|
||||
|
||||
SecureRegister_CmacReadWrite = SecureRegister_CmacRead | SecureRegister_CmacWrite,
|
||||
SecureRegister_KeySourceReadWrite = SecureRegister_KeySourceRead | SecureRegister_KeySourceWrite,
|
||||
};
|
||||
|
||||
void SetRegisterAddress(uintptr_t address);
|
||||
|
||||
void InitializeRandomScratch();
|
||||
void EnableWakeEventDetection();
|
||||
void ConfigureForSc7Entry();
|
||||
|
||||
void LockSecureRegister(SecureRegister reg);
|
||||
|
||||
enum class LockState {
|
||||
Locked = 0,
|
||||
NotLocked = 1,
|
||||
PartiallyLocked = 2,
|
||||
};
|
||||
|
||||
LockState GetSecureRegisterLockState(SecureRegister reg);
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::pmic {
|
||||
|
||||
enum Regulator {
|
||||
/* Erista regulators. */
|
||||
Regulator_Erista_Max77621 = 0, /* Device code 0x3A000001 */
|
||||
|
||||
/* Mariko regulators. */
|
||||
Regulator_Mariko_Max77812_A = 1, /* Device code 0x3A000002 */
|
||||
Regulator_Mariko_Max77812_B = 2, /* Device code 0x3A000006 */
|
||||
};
|
||||
|
||||
void SetEnBit(Regulator regulator);
|
||||
void EnableVddCpu(Regulator regulator);
|
||||
void DisableVddCpu(Regulator regulator);
|
||||
void EnableSleep();
|
||||
void PowerOff();
|
||||
void ShutdownSystem(bool reboot);
|
||||
bool IsAcOk();
|
||||
bool IsPowerButtonPressed();
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <exosphere/pmic.hpp>
|
||||
#include <exosphere/fuse.hpp>
|
||||
|
||||
namespace ams::pmic {
|
||||
|
||||
void SetSystemSetting(fuse::SocType soc_type);
|
||||
void EnableVddCore(fuse::SocType soc_type);
|
||||
void EnableLdo8();
|
||||
|
||||
void EnableVddMemory(fuse::SocType soc_type);
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::rtc {
|
||||
|
||||
void StopAlarm();
|
||||
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <exosphere/se/se_common.hpp>
|
||||
#include <exosphere/se/se_management.hpp>
|
||||
#include <exosphere/se/se_aes.hpp>
|
||||
#include <exosphere/se/se_hash.hpp>
|
||||
#include <exosphere/se/se_oaep.hpp>
|
||||
#include <exosphere/se/se_rsa.hpp>
|
||||
#include <exosphere/se/se_rng.hpp>
|
||||
#include <exosphere/se/se_suspend.hpp>
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <exosphere/se/se_common.hpp>
|
||||
|
||||
namespace ams::se {
|
||||
|
||||
constexpr inline int AesKeySlotCount = 16;
|
||||
constexpr inline size_t AesBlockSize = crypto::AesEncryptor128::BlockSize;
|
||||
|
||||
void ClearAesKeySlot(int slot);
|
||||
void ClearAesKeyIv(int slot);
|
||||
void LockAesKeySlot(int slot, u32 flags);
|
||||
|
||||
/* NOTE: This is Nintendo's API, but if we actually want to use SE2 we should use a different one. */
|
||||
void ClearAesKeySlot2(int slot);
|
||||
|
||||
void SetAesKey(int slot, const void *key, size_t key_size);
|
||||
|
||||
void SetEncryptedAesKey128(int dst_slot, int kek_slot, const void *key, size_t key_size);
|
||||
void SetEncryptedAesKey256(int dst_slot, int kek_slot, const void *key, size_t key_size);
|
||||
|
||||
void EncryptAes128(void *dst, size_t dst_size, int slot, const void *src, size_t src_size);
|
||||
void DecryptAes128(void *dst, size_t dst_size, int slot, const void *src, size_t src_size);
|
||||
|
||||
void ComputeAes128Ctr(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size);
|
||||
|
||||
void ComputeAes128Cmac(void *dst, size_t dst_size, int slot, const void *src, size_t src_size);
|
||||
void ComputeAes256Cmac(void *dst, size_t dst_size, int slot, const void *src, size_t src_size);
|
||||
|
||||
void EncryptAes128Cbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size);
|
||||
void EncryptAes256Cbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size);
|
||||
void DecryptAes128Cbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size);
|
||||
void DecryptAes256Cbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size);
|
||||
|
||||
void DecryptAes128Xts(void *dst, size_t dst_size, int slot_enc, int slot_tweak, const void *src, size_t src_size, size_t sector);
|
||||
|
||||
void EncryptAes128CbcAsync(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, const void *iv, size_t iv_size, DoneHandler handler);
|
||||
void DecryptAes128CbcAsync(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, const void *iv, size_t iv_size, DoneHandler handler);
|
||||
void ComputeAes128CtrAsync(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, const void *iv, size_t iv_size, DoneHandler handler);
|
||||
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::secmon {
|
||||
|
||||
u8 *GetSecurityEngineEphemeralWorkBlock();
|
||||
|
||||
}
|
||||
|
||||
namespace ams::se {
|
||||
|
||||
using DoneHandler = void(*)();
|
||||
|
||||
enum KeySlotLockFlags {
|
||||
KeySlotLockFlags_None = 0,
|
||||
KeySlotLockFlags_KeyRead = (1u << 0),
|
||||
KeySlotLockFlags_KeyWrite = (1u << 1),
|
||||
KeySlotLockFlags_OriginalIvRead = (1u << 2),
|
||||
KeySlotLockFlags_OriginalIvWrite = (1u << 3),
|
||||
KeySlotLockFlags_UpdatedIvRead = (1u << 4),
|
||||
KeySlotLockFlags_UpdatedIvWrite = (1u << 5),
|
||||
KeySlotLockFlags_KeyUse = (1u << 6),
|
||||
KeySlotLockFlags_DstKeyTableOnly = (1u << 7),
|
||||
KeySlotLockFlags_PerKey = (1u << 8),
|
||||
|
||||
KeySlotLockFlags_AllReadLock = (KeySlotLockFlags_KeyRead | KeySlotLockFlags_OriginalIvRead | KeySlotLockFlags_UpdatedIvRead),
|
||||
KeySlotLockFlags_AllLockKek = 0x1FF,
|
||||
KeySlotLockFlags_AllLockKey = (KeySlotLockFlags_AllLockKek & ~KeySlotLockFlags_DstKeyTableOnly),
|
||||
|
||||
KeySlotLockFlags_EristaMask = 0x7F,
|
||||
KeySlotLockFlags_MarikoMask = 0xFF,
|
||||
};
|
||||
|
||||
ALWAYS_INLINE u8 *GetEphemeralWorkBlock() {
|
||||
return ::ams::secmon::GetSecurityEngineEphemeralWorkBlock();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::se {
|
||||
|
||||
constexpr inline int Sha256HashSize = crypto::Sha256Generator::HashSize;
|
||||
|
||||
union Sha256Hash {
|
||||
u8 bytes[Sha256HashSize / sizeof(u8) ];
|
||||
u32 words[Sha256HashSize / sizeof(u32)];
|
||||
};
|
||||
|
||||
void CalculateSha256(Sha256Hash *dst, const void *src, size_t src_size);
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::se {
|
||||
|
||||
void SetRegisterAddress(uintptr_t address, uintptr_t address2);
|
||||
|
||||
void Initialize();
|
||||
|
||||
void SetSecure(bool secure);
|
||||
void SetTzramSecure();
|
||||
void SetPerKeySecure();
|
||||
void SetContextSaveSecure();
|
||||
|
||||
void Lockout();
|
||||
|
||||
void HandleInterrupt();
|
||||
|
||||
void ValidateErrStatus();
|
||||
void ValidateAesOperationResult();
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::se {
|
||||
|
||||
size_t DecodeRsaOaepSha256(void *dst, size_t dst_size, void *src, size_t src_size, const void *label_digest, size_t label_digest_size);
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::se {
|
||||
|
||||
void InitializeRandom();
|
||||
|
||||
void GenerateRandomBytes(void *dst, size_t size);
|
||||
void SetRandomKey(int slot);
|
||||
|
||||
void GenerateSrk();
|
||||
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <exosphere/se/se_common.hpp>
|
||||
|
||||
namespace ams::se {
|
||||
|
||||
constexpr inline int RsaKeySlotCount = 2;
|
||||
constexpr inline int RsaSize = 0x100;
|
||||
|
||||
void ClearRsaKeySlot(int slot);
|
||||
void LockRsaKeySlot(int slot, u32 flags);
|
||||
|
||||
void SetRsaKey(int slot, const void *mod, size_t mod_size, const void *exp, size_t exp_size);
|
||||
|
||||
void ModularExponentiate(void *dst, size_t dst_size, int slot, const void *src, size_t src_size);
|
||||
void ModularExponentiateAsync(int slot, const void *src, size_t src_size, DoneHandler handler);
|
||||
|
||||
void GetRsaResult(void *dst, size_t dst_size);
|
||||
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <exosphere/se/se_aes.hpp>
|
||||
#include <exosphere/se/se_rsa.hpp>
|
||||
|
||||
namespace ams::se {
|
||||
|
||||
/* 256-bit AES keyslots are two 128-bit keys. */
|
||||
constexpr inline int AesKeySlotPartCount = 2;
|
||||
|
||||
/* RSA keys are both a modulus and an exponent. */
|
||||
constexpr inline int RsaKeySlotPartCount = 2;
|
||||
|
||||
constexpr inline size_t StickyBitContextSize = 2 * AesBlockSize;
|
||||
|
||||
struct Context {
|
||||
u8 random[AesBlockSize];
|
||||
u8 sticky_bits[StickyBitContextSize / AesBlockSize][AesBlockSize];
|
||||
u8 aes_key[AesKeySlotCount][AesKeySlotPartCount][AesBlockSize];
|
||||
u8 aes_oiv[AesKeySlotCount][AesBlockSize];
|
||||
u8 aes_uiv[AesKeySlotCount][AesBlockSize];
|
||||
u8 rsa_key[RsaKeySlotCount][RsaKeySlotPartCount][RsaSize / AesBlockSize][AesBlockSize];
|
||||
u8 fixed_pattern[AesBlockSize];
|
||||
};
|
||||
static_assert(sizeof(Context) == 0x840);
|
||||
static_assert(util::is_pod<Context>::value);
|
||||
|
||||
struct StickyBits {
|
||||
u8 se_security;
|
||||
u8 tzram_security;
|
||||
u16 crypto_security_perkey;
|
||||
u8 crypto_keytable_access[AesKeySlotCount];
|
||||
u8 rsa_security_perkey;
|
||||
u8 rsa_keytable_access[RsaKeySlotCount];
|
||||
};
|
||||
static_assert(util::is_pod<StickyBits>::value);
|
||||
|
||||
bool ValidateStickyBits(const StickyBits &bits);
|
||||
void SaveContext(Context *dst);
|
||||
|
||||
void ConfigureAutomaticContextSave();
|
||||
void SaveContextAutomatic();
|
||||
void SaveTzramAutomatic();
|
||||
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <exosphere/secmon/secmon_log.hpp>
|
||||
#include <exosphere/secmon/secmon_memory_layout.hpp>
|
||||
#include <exosphere/secmon/secmon_configuration_context.hpp>
|
||||
#include <exosphere/secmon/secmon_volatile_context.hpp>
|
||||
@@ -1,139 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <exosphere/pkg1.hpp>
|
||||
#include <exosphere/se.hpp>
|
||||
#include <exosphere/secmon/secmon_monitor_context.hpp>
|
||||
|
||||
namespace ams::secmon {
|
||||
|
||||
struct ConfigurationContext {
|
||||
union {
|
||||
SecureMonitorConfiguration secmon_cfg;
|
||||
u8 _raw_exosphere_config[0x80];
|
||||
};
|
||||
union {
|
||||
EmummcConfiguration emummc_cfg;
|
||||
u8 _raw_emummc_config[0x120];
|
||||
};
|
||||
u8 sealed_device_keys[pkg1::KeyGeneration_Max][se::AesBlockSize];
|
||||
u8 sealed_master_keys[pkg1::KeyGeneration_Max][se::AesBlockSize];
|
||||
pkg1::BootConfig boot_config;
|
||||
u8 rsa_private_exponents[4][se::RsaSize];
|
||||
union {
|
||||
u8 _misc_data[0xFC0 - sizeof(_raw_exosphere_config) - sizeof(_raw_emummc_config) - sizeof(sealed_device_keys) - sizeof(sealed_master_keys) - sizeof(boot_config) - sizeof(rsa_private_exponents)];
|
||||
};
|
||||
/* u8 l1_page_table[0x40]; */
|
||||
};
|
||||
static_assert(sizeof(ConfigurationContext) == 0xFC0);
|
||||
static_assert(util::is_pod<ConfigurationContext>::value);
|
||||
|
||||
namespace impl {
|
||||
|
||||
ALWAYS_INLINE uintptr_t GetConfigurationContextAddress() {
|
||||
register uintptr_t x18 asm("x18");
|
||||
__asm__ __volatile__("" : [x18]"=r"(x18));
|
||||
return x18;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE ConfigurationContext &GetConfigurationContext() {
|
||||
return *reinterpret_cast<ConfigurationContext *>(GetConfigurationContextAddress());
|
||||
}
|
||||
|
||||
ALWAYS_INLINE u8 *GetMasterKeyStorage(int generation) {
|
||||
return GetConfigurationContext().sealed_master_keys[generation];
|
||||
}
|
||||
|
||||
ALWAYS_INLINE u8 *GetDeviceMasterKeyStorage(int generation) {
|
||||
return GetConfigurationContext().sealed_device_keys[generation];
|
||||
}
|
||||
|
||||
ALWAYS_INLINE u8 *GetRsaPrivateExponentStorage(int which) {
|
||||
return GetConfigurationContext().rsa_private_exponents[which];
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void SetKeyGeneration(int generation) {
|
||||
GetConfigurationContext().secmon_cfg.key_generation = generation;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void SetTargetFirmware(ams::TargetFirmware target_firmware) {
|
||||
GetConfigurationContext().secmon_cfg.target_firmware = target_firmware;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE pkg1::BootConfig *GetBootConfigStorage() {
|
||||
return std::addressof(GetConfigurationContext().boot_config);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ALWAYS_INLINE const ConfigurationContext &GetConfigurationContext() {
|
||||
return *reinterpret_cast<const ConfigurationContext *>(impl::GetConfigurationContextAddress());
|
||||
}
|
||||
|
||||
ALWAYS_INLINE const SecureMonitorConfiguration &GetSecmonConfiguration() {
|
||||
return GetConfigurationContext().secmon_cfg;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE const EmummcConfiguration &GetEmummcConfiguration() {
|
||||
return GetConfigurationContext().emummc_cfg;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE const pkg1::BootConfig &GetBootConfig() {
|
||||
return GetConfigurationContext().boot_config;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE ams::TargetFirmware GetTargetFirmware() {
|
||||
return GetSecmonConfiguration().GetTargetFirmware();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE int GetKeyGeneration() {
|
||||
return GetSecmonConfiguration().GetKeyGeneration();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE fuse::HardwareType GetHardwareType() {
|
||||
return GetSecmonConfiguration().GetHardwareType();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE fuse::SocType GetSocType() {
|
||||
return GetSecmonConfiguration().GetSocType();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE fuse::HardwareState GetHardwareState() {
|
||||
return GetSecmonConfiguration().GetHardwareState();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE u16 GetLcdVendor() {
|
||||
return GetSecmonConfiguration().GetLcdVendor();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE uart::Port GetLogPort() {
|
||||
return GetSecmonConfiguration().GetLogPort();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE u8 GetLogFlags() {
|
||||
return GetSecmonConfiguration().GetLogFlags();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE u32 GetLogBaudRate() {
|
||||
return GetSecmonConfiguration().GetLogBaudRate();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE bool IsProduction() {
|
||||
return GetSecmonConfiguration().IsProduction();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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_ARCH_ARM64)
|
||||
#include <exosphere/secmon/secmon_configuration_context.arch.arm64.hpp>
|
||||
#elif defined(ATMOSPHERE_ARCH_ARM)
|
||||
/* Nothing to include. */
|
||||
#else
|
||||
#error "Unknown architecture for secmon::ConfigurationContext.hpp"
|
||||
#endif
|
||||
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::secmon {
|
||||
|
||||
enum EmummcType : u32 {
|
||||
EmummcType_None = 0,
|
||||
EmummcType_Partition = 1,
|
||||
EmummcType_File = 2,
|
||||
};
|
||||
|
||||
enum EmummcMmc {
|
||||
EmummcMmc_Nand = 0,
|
||||
EmummcMmc_Sd = 1,
|
||||
EmummcMmc_Gc = 2,
|
||||
};
|
||||
|
||||
constexpr inline size_t EmummcFilePathLengthMax = 0x80;
|
||||
|
||||
struct EmummcFilePath {
|
||||
char str[EmummcFilePathLengthMax];
|
||||
};
|
||||
static_assert(util::is_pod<EmummcFilePath>::value);
|
||||
static_assert(sizeof(EmummcFilePath) == EmummcFilePathLengthMax);
|
||||
|
||||
struct EmummcBaseConfiguration {
|
||||
static constexpr u32 Magic = util::FourCC<'E','F','S','0'>::Code;
|
||||
|
||||
u32 magic;
|
||||
EmummcType type;
|
||||
u32 id;
|
||||
u32 fs_version;
|
||||
|
||||
constexpr bool IsValid() const {
|
||||
return this->magic == Magic;
|
||||
}
|
||||
|
||||
constexpr bool IsEmummcActive() const {
|
||||
return this->IsValid() && this->type != EmummcType_None;
|
||||
}
|
||||
};
|
||||
static_assert(util::is_pod<EmummcBaseConfiguration>::value);
|
||||
static_assert(sizeof(EmummcBaseConfiguration) == 0x10);
|
||||
|
||||
struct EmummcPartitionConfiguration {
|
||||
u64 start_sector;
|
||||
};
|
||||
static_assert(util::is_pod<EmummcPartitionConfiguration>::value);
|
||||
|
||||
struct EmummcFileConfiguration {
|
||||
EmummcFilePath path;
|
||||
};
|
||||
static_assert(util::is_pod<EmummcFileConfiguration>::value);
|
||||
|
||||
struct EmummcConfiguration {
|
||||
EmummcBaseConfiguration base_cfg;
|
||||
union {
|
||||
EmummcPartitionConfiguration partition_cfg;
|
||||
EmummcFileConfiguration file_cfg;
|
||||
};
|
||||
EmummcFilePath emu_dir_path;
|
||||
|
||||
constexpr bool IsValid() const {
|
||||
return this->base_cfg.IsValid();
|
||||
}
|
||||
|
||||
constexpr bool IsEmummcActive() const {
|
||||
return this->base_cfg.IsEmummcActive();
|
||||
}
|
||||
};
|
||||
static_assert(util::is_pod<EmummcConfiguration>::value);
|
||||
static_assert(sizeof(EmummcConfiguration) <= 0x200);
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <exosphere/log.hpp>
|
||||
|
||||
#define AMS_SECMON_LOG(...) AMS_LOG(" [secmon] " __VA_ARGS__)
|
||||
@@ -1,348 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <exosphere/mmu.hpp>
|
||||
|
||||
namespace ams::secmon {
|
||||
|
||||
using Address = u64;
|
||||
|
||||
struct MemoryRegion {
|
||||
private:
|
||||
Address m_start_address;
|
||||
Address m_end_address;
|
||||
public:
|
||||
consteval MemoryRegion(Address address, size_t size) : m_start_address(address), m_end_address(address + size) {
|
||||
if (m_end_address < m_start_address) {
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
constexpr Address GetStartAddress() const {
|
||||
return m_start_address;
|
||||
}
|
||||
|
||||
constexpr Address GetAddress() const {
|
||||
return this->GetStartAddress();
|
||||
}
|
||||
|
||||
constexpr Address GetEndAddress() const {
|
||||
return m_end_address;
|
||||
}
|
||||
|
||||
constexpr Address GetLastAddress() const {
|
||||
return m_end_address - 1;
|
||||
}
|
||||
|
||||
constexpr size_t GetSize() const {
|
||||
return m_end_address - m_start_address;
|
||||
}
|
||||
|
||||
constexpr bool Contains(Address address, size_t size) const {
|
||||
return m_start_address <= address && (address + size - 1) <= this->GetLastAddress();
|
||||
}
|
||||
|
||||
constexpr bool Contains(const MemoryRegion &rhs) const {
|
||||
return this->Contains(rhs.GetStartAddress(), rhs.GetSize());
|
||||
}
|
||||
|
||||
template<typename T = void> requires (std::is_same<T, void>::value || util::is_pod<T>::value)
|
||||
ALWAYS_INLINE T *GetPointer() const {
|
||||
return reinterpret_cast<T *>(this->GetAddress());
|
||||
}
|
||||
|
||||
template<typename T = void> requires (std::is_same<T, void>::value || util::is_pod<T>::value)
|
||||
ALWAYS_INLINE T *GetEndPointer() const {
|
||||
return reinterpret_cast<T *>(this->GetEndAddress());
|
||||
}
|
||||
};
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtual = MemoryRegion(UINT64_C(0x1F0000000), 2_MB);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysical = MemoryRegion(UINT64_C( 0x40000000), 1_GB);
|
||||
constexpr inline const MemoryRegion MemoryRegionDram = MemoryRegion(UINT64_C( 0x80000000), 2_GB);
|
||||
constexpr inline const MemoryRegion MemoryRegionDramHigh = MemoryRegion(MemoryRegionDram.GetEndAddress(), 2_GB);
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionDramForMarikoProgram = MemoryRegion(UINT64_C(0xC0000000), 1_GB);
|
||||
constexpr inline const MemoryRegion MemoryRegionDramDcFramebuffer = MemoryRegion(UINT64_C(0xC0000000), 4_MB);
|
||||
static_assert(MemoryRegionDram.Contains(MemoryRegionDramForMarikoProgram));
|
||||
static_assert(MemoryRegionDramForMarikoProgram.Contains(MemoryRegionDramDcFramebuffer));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionDramGpuCarveout = MemoryRegion(UINT64_C(0x80020000), UINT64_C(0x40000));
|
||||
static_assert(MemoryRegionDram.Contains(MemoryRegionDramGpuCarveout));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionDramDefaultKernelCarveout = MemoryRegion(UINT64_C(0x80060000), UINT64_C(0x1FFE0000));
|
||||
static_assert(MemoryRegionDram.Contains(MemoryRegionDramDefaultKernelCarveout));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionDramPackage2Payloads = MemoryRegion(MemoryRegionDram.GetAddress(), 8_MB);
|
||||
static_assert(MemoryRegionDram.Contains(MemoryRegionDramPackage2Payloads));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionDramPackage2 = MemoryRegion(UINT64_C(0xA9800000), UINT64_C(0x07FC0000));
|
||||
static_assert(MemoryRegionDram.Contains(MemoryRegionDramPackage2));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalIram = MemoryRegion(UINT64_C(0x40000000), 0x40000);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalTzram = MemoryRegion(UINT64_C(0x7C010000), 0x10000);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalTzramMariko = MemoryRegion(UINT64_C(0x7C010000), 0x40000);
|
||||
static_assert(MemoryRegionPhysical.Contains(MemoryRegionPhysicalIram));
|
||||
static_assert(MemoryRegionPhysical.Contains(MemoryRegionPhysicalTzram));
|
||||
static_assert(MemoryRegionPhysicalTzramMariko.Contains(MemoryRegionPhysicalTzram));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalTzramVolatile(UINT64_C(0x7C010000), 0x2000);
|
||||
static_assert(MemoryRegionPhysicalTzram.Contains(MemoryRegionPhysicalTzramVolatile));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalTzramNonVolatile(UINT64_C(0x7C012000), 0xE000);
|
||||
static_assert(MemoryRegionPhysicalTzram.Contains(MemoryRegionPhysicalTzramNonVolatile));
|
||||
|
||||
static_assert(MemoryRegionPhysicalTzram.GetSize() == MemoryRegionPhysicalTzramNonVolatile.GetSize() + MemoryRegionPhysicalTzramVolatile.GetSize());
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualL1 = MemoryRegion(util::AlignDown(MemoryRegionVirtual.GetAddress(), mmu::L1EntrySize), mmu::L1EntrySize);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalL1 = MemoryRegion(util::AlignDown(MemoryRegionPhysical.GetAddress(), mmu::L1EntrySize), mmu::L1EntrySize);
|
||||
static_assert(MemoryRegionVirtualL1.Contains(MemoryRegionVirtual));
|
||||
static_assert(MemoryRegionPhysicalL1.Contains(MemoryRegionPhysical));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualL2 = MemoryRegion(util::AlignDown(MemoryRegionVirtual.GetAddress(), mmu::L2EntrySize), mmu::L2EntrySize);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalIramL2 = MemoryRegion(util::AlignDown(MemoryRegionPhysicalIram.GetAddress(), mmu::L2EntrySize), mmu::L2EntrySize);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalTzramL2 = MemoryRegion(util::AlignDown(MemoryRegionPhysicalTzram.GetAddress(), mmu::L2EntrySize), mmu::L2EntrySize);
|
||||
static_assert(MemoryRegionVirtualL2.Contains(MemoryRegionVirtual));
|
||||
static_assert(MemoryRegionPhysicalIramL2.Contains(MemoryRegionPhysicalIram));
|
||||
static_assert(MemoryRegionPhysicalTzramL2.Contains(MemoryRegionPhysicalTzram));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootCode = MemoryRegion(UINT64_C(0x40020000), 0x20000);
|
||||
static_assert(MemoryRegionPhysicalIram.Contains(MemoryRegionPhysicalIramBootCode));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualDevice = MemoryRegion(UINT64_C(0x1F0040000), UINT64_C(0x40000));
|
||||
static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualDevice));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualDeviceEmpty = MemoryRegion(MemoryRegionVirtualDevice.GetStartAddress(), 0);
|
||||
|
||||
#define AMS_SECMON_FOREACH_DEVICE_REGION(HANDLER, ...) \
|
||||
HANDLER(GicDistributor, Empty, UINT64_C(0x50041000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(GicCpuInterface, GicDistributor, UINT64_C(0x50042000), UINT64_C(0x2000), true, ## __VA_ARGS__) \
|
||||
HANDLER(Uart, GicCpuInterface, UINT64_C(0x70006000), UINT64_C(0x1000), false, ## __VA_ARGS__) \
|
||||
HANDLER(ClkRst, Uart, UINT64_C(0x60006000), UINT64_C(0x1000), false, ## __VA_ARGS__) \
|
||||
HANDLER(RtcPmc, ClkRst, UINT64_C(0x7000E000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(Timer, RtcPmc, UINT64_C(0x60005000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(System, Timer, UINT64_C(0x6000C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(SecurityEngine, System, UINT64_C(0x70012000), UINT64_C(0x2000), true, ## __VA_ARGS__) \
|
||||
HANDLER(SecurityEngine2, SecurityEngine, UINT64_C(0x70412000), UINT64_C(0x2000), true, ## __VA_ARGS__) \
|
||||
HANDLER(SysCtr0, SecurityEngine2, UINT64_C(0x700F0000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(MemoryController, SysCtr0, UINT64_C(0x70019000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(ExternalMemoryController, MemoryController, UINT64_C(0x7001b000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(FuseKFuse, ExternalMemoryController, UINT64_C(0x7000F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(ApbMisc, FuseKFuse, UINT64_C(0x70000000), UINT64_C(0x4000), true, ## __VA_ARGS__) \
|
||||
HANDLER(FlowController, ApbMisc, UINT64_C(0x60007000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(BootloaderParams, FlowController, UINT64_C(0x40000000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(I2c5, BootloaderParams, UINT64_C(0x7000D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(Gpio, I2c5, UINT64_C(0x6000D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(I2c1, Gpio, UINT64_C(0x7000C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(ExceptionVectors, I2c1, UINT64_C(0x6000F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(MemoryController0, ExceptionVectors, UINT64_C(0x7001C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(MemoryController1, MemoryController0, UINT64_C(0x7001D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(Sdmmc, MemoryController1, UINT64_C(0x700B0000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(Disp1, Sdmmc, UINT64_C(0x54200000), UINT64_C(0x3000), true, ## __VA_ARGS__) \
|
||||
HANDLER(Dsi, Disp1, UINT64_C(0x54300000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(MipiCal, Dsi, UINT64_C(0x700E3000), UINT64_C(0x1000), true, ## __VA_ARGS__)
|
||||
|
||||
#define DEFINE_DEVICE_REGION(_NAME_, _PREV_, _ADDRESS_, _SIZE_, _SECURE_) \
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualDevice##_NAME_ = MemoryRegion(MemoryRegionVirtualDevice##_PREV_.GetEndAddress() + 0x1000, _SIZE_); \
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalDevice##_NAME_ = MemoryRegion(_ADDRESS_, _SIZE_); \
|
||||
static_assert(MemoryRegionVirtualDevice.Contains(MemoryRegionVirtualDevice##_NAME_)); \
|
||||
static_assert(MemoryRegionPhysical.Contains(MemoryRegionPhysicalDevice##_NAME_));
|
||||
|
||||
AMS_SECMON_FOREACH_DEVICE_REGION(DEFINE_DEVICE_REGION)
|
||||
|
||||
#undef DEFINE_DEVICE_REGION
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualDeviceFuses = MemoryRegion(MemoryRegionVirtualDeviceFuseKFuse.GetAddress() + 0x800, 0x400);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalDeviceFuses = MemoryRegion(MemoryRegionPhysicalDeviceFuseKFuse.GetAddress() + 0x800, 0x400);
|
||||
static_assert(MemoryRegionVirtualDeviceFuseKFuse.Contains(MemoryRegionVirtualDeviceFuses));
|
||||
static_assert(MemoryRegionPhysicalDeviceFuseKFuse.Contains(MemoryRegionPhysicalDeviceFuses));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualDeviceActivityMonitor = MemoryRegion(MemoryRegionVirtualDeviceSystem.GetAddress() + 0x800, 0x400);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalDeviceActivityMonitor = MemoryRegion(MemoryRegionPhysicalDeviceSystem.GetAddress() + 0x800, 0x400);
|
||||
static_assert(MemoryRegionVirtualDeviceSystem.Contains(MemoryRegionVirtualDeviceActivityMonitor));
|
||||
static_assert(MemoryRegionPhysicalDeviceSystem.Contains(MemoryRegionPhysicalDeviceActivityMonitor));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualDeviceUartA = MemoryRegion(MemoryRegionVirtualDeviceUart.GetAddress() + 0x000, 0x040);
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualDeviceUartB = MemoryRegion(MemoryRegionVirtualDeviceUart.GetAddress() + 0x040, 0x040);
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualDeviceUartC = MemoryRegion(MemoryRegionVirtualDeviceUart.GetAddress() + 0x200, 0x100);
|
||||
static_assert(MemoryRegionVirtualDeviceUart.Contains(MemoryRegionVirtualDeviceUartA));
|
||||
static_assert(MemoryRegionVirtualDeviceUart.Contains(MemoryRegionVirtualDeviceUartB));
|
||||
static_assert(MemoryRegionVirtualDeviceUart.Contains(MemoryRegionVirtualDeviceUartC));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalDeviceUartA = MemoryRegion(MemoryRegionPhysicalDeviceUart.GetAddress() + 0x000, 0x040);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalDeviceUartB = MemoryRegion(MemoryRegionPhysicalDeviceUart.GetAddress() + 0x040, 0x040);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalDeviceUartC = MemoryRegion(MemoryRegionPhysicalDeviceUart.GetAddress() + 0x200, 0x100);
|
||||
static_assert(MemoryRegionPhysicalDeviceUart.Contains(MemoryRegionPhysicalDeviceUartA));
|
||||
static_assert(MemoryRegionPhysicalDeviceUart.Contains(MemoryRegionPhysicalDeviceUartB));
|
||||
static_assert(MemoryRegionPhysicalDeviceUart.Contains(MemoryRegionPhysicalDeviceUartC));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualDevicePmc = MemoryRegion(MemoryRegionVirtualDeviceRtcPmc.GetAddress() + 0x400, 0xC00);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalDevicePmc = MemoryRegion(MemoryRegionPhysicalDeviceRtcPmc.GetAddress() + 0x400, 0xC00);
|
||||
static_assert(MemoryRegionVirtualDeviceRtcPmc.Contains(MemoryRegionVirtualDevicePmc));
|
||||
static_assert(MemoryRegionPhysicalDeviceRtcPmc.Contains(MemoryRegionPhysicalDevicePmc));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualTzramReadOnlyAlias = MemoryRegion(UINT64_C(0x1F00A0000), MemoryRegionPhysicalTzram.GetSize());
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalTzramReadOnlyAlias = MemoryRegion(MemoryRegionPhysicalTzram.GetAddress(), MemoryRegionPhysicalTzram.GetSize());
|
||||
static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualTzramReadOnlyAlias));
|
||||
static_assert(MemoryRegionPhysicalTzram.Contains(MemoryRegionPhysicalTzramReadOnlyAlias));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualTzramProgram(UINT64_C(0x1F00C0000), 0xC000);
|
||||
static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualTzramProgram));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualTzramProgramExceptionVectors(UINT64_C(0x1F00C0000), 0x800);
|
||||
static_assert(MemoryRegionVirtualTzramProgram.Contains(MemoryRegionVirtualTzramProgramExceptionVectors));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualTzramMarikoProgram(UINT64_C(0x1F00D0000), 0x20000);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalTzramMarikoProgram(UINT64_C(0x7C020000), 0x20000);
|
||||
static_assert(MemoryRegionPhysicalTzramMariko.Contains(MemoryRegionPhysicalTzramMarikoProgram));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualTzramMarikoProgramFatalErrorContext(UINT64_C(0x1F00EF000), 0x1000);
|
||||
static_assert(MemoryRegionVirtualTzramMarikoProgram.Contains(MemoryRegionVirtualTzramMarikoProgramFatalErrorContext));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalIramFatalErrorContext(UINT64_C(0x4003E000), 0x1000);
|
||||
static_assert(MemoryRegionPhysicalIram.Contains(MemoryRegionPhysicalIramFatalErrorContext));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualTzramMarikoProgramStack(UINT64_C(0x1F00F4000), 0x8000);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalTzramMarikoProgramStack(UINT64_C(0x7C040000), 0x8000);
|
||||
static_assert(MemoryRegionPhysicalTzramMariko.Contains(MemoryRegionPhysicalTzramMarikoProgramStack));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalMarikoProgramImage(UINT64_C(0x80020000), 0x20000);
|
||||
static_assert(MemoryRegionDram.Contains(MemoryRegionPhysicalMarikoProgramImage));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualTzramProgramMain(UINT64_C(0x1F00C0800), 0xB800);
|
||||
static_assert(MemoryRegionVirtualTzramProgram.Contains(MemoryRegionVirtualTzramProgramMain));
|
||||
|
||||
static_assert(MemoryRegionVirtualTzramProgram.GetSize() == MemoryRegionVirtualTzramProgramExceptionVectors.GetSize() + MemoryRegionVirtualTzramProgramMain.GetSize());
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalTzramProgram(UINT64_C(0x7C012000), 0xC000);
|
||||
static_assert(MemoryRegionPhysicalTzramNonVolatile.Contains(MemoryRegionPhysicalTzramProgram));
|
||||
|
||||
constexpr inline const Address PhysicalTzramProgramResetVector = MemoryRegionPhysicalTzramProgram.GetAddress() + MemoryRegionVirtualTzramProgramExceptionVectors.GetSize();
|
||||
static_assert(static_cast<u32>(PhysicalTzramProgramResetVector) == PhysicalTzramProgramResetVector);
|
||||
|
||||
constexpr uintptr_t GetPhysicalTzramProgramAddress(uintptr_t virtual_address) {
|
||||
return virtual_address - MemoryRegionVirtualTzramProgram.GetStartAddress() + MemoryRegionPhysicalTzramNonVolatile.GetStartAddress();
|
||||
}
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualIramSc7Work = MemoryRegion(UINT64_C(0x1F0120000), MemoryRegionPhysicalTzram.GetSize());
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalIramSc7Work = MemoryRegion( UINT64_C(0x40020000), MemoryRegionPhysicalTzram.GetSize());
|
||||
static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualIramSc7Work));
|
||||
static_assert(MemoryRegionPhysicalIram.Contains(MemoryRegionPhysicalIramSc7Work));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualIramSc7Firmware = MemoryRegion(UINT64_C(0x1F0140000), 0x1000);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalIramSc7Firmware = MemoryRegion( UINT64_C(0x40003000), 0x1000);
|
||||
static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualIramSc7Firmware));
|
||||
static_assert(MemoryRegionPhysicalIram.Contains(MemoryRegionPhysicalIramSc7Firmware));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalIramSecureMonitorDebug(UINT64_C(0x40034000), 0x4000);
|
||||
static_assert(MemoryRegionPhysicalIram.Contains(MemoryRegionPhysicalIramSecureMonitorDebug));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualDebugCode = MemoryRegion(UINT64_C(0x1F0150000), 0x4000);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalDebugCode = MemoryRegion(UINT64_C(0x40034000), 0x4000);
|
||||
static_assert(MemoryRegionPhysicalIramSecureMonitorDebug.Contains(MemoryRegionPhysicalDebugCode));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualDebug = MemoryRegion(UINT64_C(0x1F0160000), 0x10000);
|
||||
static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualDebug));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualTzramBootCode = MemoryRegion(UINT64_C(0x1F01C0000), 0x2000);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalTzramBootCode = MemoryRegion( UINT64_C(0x7C010000), 0x2000);
|
||||
static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualTzramBootCode));
|
||||
static_assert(MemoryRegionPhysicalTzramVolatile.Contains(MemoryRegionPhysicalTzramBootCode));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalDramMonitorConfiguration = MemoryRegion( UINT64_C(0x8000F000), 0x1000);
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualDramSecureDataStore = MemoryRegion(UINT64_C(0x1F0100000), 0x10000);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalDramSecureDataStore = MemoryRegion( UINT64_C(0x80010000), 0x10000);
|
||||
static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualDramSecureDataStore));
|
||||
static_assert(MemoryRegionDram.Contains(MemoryRegionPhysicalDramSecureDataStore));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualDramDebugDataStore = MemoryRegion(UINT64_C(0x1F0110000), 0x4000);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalDramDebugDataStore = MemoryRegion( UINT64_C(0x8000C000), 0x4000);
|
||||
static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualDramSecureDataStore));
|
||||
static_assert(MemoryRegionDram.Contains(MemoryRegionPhysicalDramSecureDataStore));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualDramSdmmcMappedData = MemoryRegion(UINT64_C(0x1F0100000), 0xC000);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalDramSdmmcMappedData = MemoryRegion(UINT64_C(0x80010000), 0xC000);
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualDramDcL0DevicePageTable = MemoryRegion(UINT64_C(0x1F010C000), 0x1000);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalDramDcL0DevicePageTable = MemoryRegion( UINT64_C(0x8001C000), 0x1000);
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualDramSdmmc1L0DevicePageTable = MemoryRegion(UINT64_C(0x1F010E000), 0x1000);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalDramSdmmc1L0DevicePageTable = MemoryRegion( UINT64_C(0x8001E000), 0x1000);
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualDramSdmmc1L1DevicePageTable = MemoryRegion(UINT64_C(0x1F010F000), 0x1000);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalDramSdmmc1L1DevicePageTable = MemoryRegion( UINT64_C(0x8001F000), 0x1000);
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualDramSecureDataStoreTzram = MemoryRegion(UINT64_C(0x1F0100000), 0xE000);
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualDramSecureDataStoreWarmbootFirmware = MemoryRegion(UINT64_C(0x1F010E000), 0x17C0);
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualDramSecureDataStoreSecurityEngineState = MemoryRegion(UINT64_C(0x1F010F7C0), 0x0840);
|
||||
static_assert(MemoryRegionVirtualDramSecureDataStore.Contains(MemoryRegionVirtualDramSecureDataStoreTzram));
|
||||
static_assert(MemoryRegionVirtualDramSecureDataStore.Contains(MemoryRegionVirtualDramSecureDataStoreWarmbootFirmware));
|
||||
static_assert(MemoryRegionVirtualDramSecureDataStore.Contains(MemoryRegionVirtualDramSecureDataStoreSecurityEngineState));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalDramSecureDataStoreTzram = MemoryRegion(UINT64_C(0x80010000), 0xE000);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalDramSecureDataStoreWarmbootFirmware = MemoryRegion(UINT64_C(0x8001E000), 0x17C0);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalDramSecureDataStoreSecurityEngineState = MemoryRegion(UINT64_C(0x8001F7C0), 0x0840);
|
||||
static_assert(MemoryRegionPhysicalDramSecureDataStore.Contains(MemoryRegionPhysicalDramSecureDataStoreTzram));
|
||||
static_assert(MemoryRegionPhysicalDramSecureDataStore.Contains(MemoryRegionPhysicalDramSecureDataStoreWarmbootFirmware));
|
||||
static_assert(MemoryRegionPhysicalDramSecureDataStore.Contains(MemoryRegionPhysicalDramSecureDataStoreSecurityEngineState));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualAtmosphereIramPage = MemoryRegion(UINT64_C(0x1F01F0000), 0x1000);
|
||||
static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualAtmosphereIramPage));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualAtmosphereUserPage = MemoryRegion(UINT64_C(0x1F01F2000), 0x1000);
|
||||
static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualAtmosphereUserPage));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualSmcUserPage = MemoryRegion(UINT64_C(0x1F01F4000), 0x1000);
|
||||
static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualSmcUserPage));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualTzramVolatileData = MemoryRegion(UINT64_C(0x1F01F6000), 0x1000);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalTzramVolatileData = MemoryRegion( UINT64_C(0x7C010000), 0x1000);
|
||||
static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualTzramVolatileData));
|
||||
static_assert(MemoryRegionPhysicalTzramVolatile.Contains(MemoryRegionPhysicalTzramVolatileData));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualTzramVolatileStack = MemoryRegion(UINT64_C(0x1F01F8000), 0x1000);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalTzramVolatileStack = MemoryRegion( UINT64_C(0x7C011000), 0x1000);
|
||||
static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualTzramVolatileStack));
|
||||
static_assert(MemoryRegionPhysicalTzramVolatile.Contains(MemoryRegionPhysicalTzramVolatileStack));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualTzramConfigurationData = MemoryRegion(UINT64_C(0x1F01FA000), 0x1000);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalTzramConfigurationData = MemoryRegion( UINT64_C(0x7C01E000), 0x1000);
|
||||
static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualTzramConfigurationData));
|
||||
static_assert(MemoryRegionPhysicalTzramNonVolatile.Contains(MemoryRegionPhysicalTzramConfigurationData));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualTzramL1PageTable = MemoryRegion(UINT64_C(0x1F01FCFC0), 0x40);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalTzramL1PageTable = MemoryRegion( UINT64_C(0x7C01EFC0), 0x40);
|
||||
static_assert(MemoryRegionPhysicalTzramConfigurationData.Contains(MemoryRegionPhysicalTzramL1PageTable));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionVirtualTzramL2L3PageTable = MemoryRegion(UINT64_C(0x1F01FE000), 0x1000);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalTzramL2L3PageTable = MemoryRegion( UINT64_C(0x7C01F000), 0x1000);
|
||||
static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualTzramL2L3PageTable));
|
||||
static_assert(MemoryRegionPhysicalTzramNonVolatile.Contains(MemoryRegionPhysicalTzramL2L3PageTable));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalTzramFullProgramImage = MemoryRegion(UINT64_C(0x7C010800), 0xD800);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootCodeImage = MemoryRegion(UINT64_C(0x40032000), 0xC000);
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootCodeCode = MemoryRegion(UINT64_C(0x40032000), 0x1000);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootCodeKeys = MemoryRegion(UINT64_C(0x40033000), 0x1000);
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalIramWarmbootBin = MemoryRegion(UINT64_C(0x4003E000), 0x17F0);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootConfig = MemoryRegion(UINT64_C(0x4003F800), 0x400);
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalIramRebootStub = MemoryRegion(UINT64_C(0x4003F000), 0x1000);
|
||||
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <exosphere/fuse.hpp>
|
||||
#include <exosphere/uart.hpp>
|
||||
#include <exosphere/secmon/secmon_emummc_context.hpp>
|
||||
|
||||
namespace ams::secmon {
|
||||
|
||||
enum SecureMonitorConfigurationFlag : u32 {
|
||||
SecureMonitorConfigurationFlag_None = (0u << 0),
|
||||
SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForKernel = (1u << 1),
|
||||
SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForUser = (1u << 2),
|
||||
SecureMonitorConfigurationFlag_DisableUserModeExceptionHandlers = (1u << 3),
|
||||
SecureMonitorConfigurationFlag_EnableUserModePerformanceCounterAccess = (1u << 4),
|
||||
SecureMonitorConfigurationFlag_ShouldUseBlankCalibrationBinary = (1u << 5),
|
||||
SecureMonitorConfigurationFlag_AllowWritingToCalibrationBinarySysmmc = (1u << 6),
|
||||
SecureMonitorConfigurationFlag_ForceEnableUsb30 = (1u << 7),
|
||||
|
||||
SecureMonitorConfigurationFlag_Default = SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForKernel,
|
||||
};
|
||||
|
||||
struct SecureMonitorStorageConfiguration {
|
||||
static constexpr u32 Magic = util::FourCC<'E','X','O','0'>::Code;
|
||||
|
||||
u32 magic;
|
||||
ams::TargetFirmware target_firmware;
|
||||
u32 flags[2];
|
||||
u16 lcd_vendor;
|
||||
u8 log_port;
|
||||
u8 log_flags;
|
||||
u32 log_baud_rate;
|
||||
u32 reserved1[2];
|
||||
EmummcConfiguration emummc_cfg;
|
||||
|
||||
constexpr bool IsValid() const { return this->magic == Magic; }
|
||||
};
|
||||
static_assert(util::is_pod<SecureMonitorStorageConfiguration>::value);
|
||||
static_assert(sizeof(SecureMonitorStorageConfiguration) == 0x130);
|
||||
|
||||
struct SecureMonitorConfiguration {
|
||||
ams::TargetFirmware target_firmware;
|
||||
s32 key_generation;
|
||||
u8 hardware_type;
|
||||
u8 soc_type;
|
||||
u8 hardware_state;
|
||||
u8 log_port;
|
||||
u32 flags[2];
|
||||
u16 lcd_vendor;
|
||||
u8 log_flags;
|
||||
u8 reserved0;
|
||||
u32 log_baud_rate;
|
||||
u32 reserved1[(0x80 - 0x1C) / sizeof(u32)];
|
||||
|
||||
constexpr void CopyFrom(const SecureMonitorStorageConfiguration &storage) {
|
||||
this->target_firmware = storage.target_firmware;
|
||||
this->flags[0] = storage.flags[0];
|
||||
this->flags[1] = storage.flags[1];
|
||||
this->lcd_vendor = storage.lcd_vendor;
|
||||
this->log_port = storage.log_port;
|
||||
this->log_flags = storage.log_flags;
|
||||
this->log_baud_rate = storage.log_baud_rate != 0 ? storage.log_baud_rate : 115200;
|
||||
}
|
||||
|
||||
void SetFuseInfo() {
|
||||
this->hardware_type = fuse::GetHardwareType();
|
||||
this->soc_type = fuse::GetSocType();
|
||||
this->hardware_state = fuse::GetHardwareState();
|
||||
}
|
||||
|
||||
constexpr ams::TargetFirmware GetTargetFirmware() const { return this->target_firmware; }
|
||||
constexpr int GetKeyGeneration() const { return this->key_generation; }
|
||||
constexpr fuse::HardwareType GetHardwareType() const { return static_cast<fuse::HardwareType>(this->hardware_type); }
|
||||
constexpr fuse::SocType GetSocType() const { return static_cast<fuse::SocType>(this->soc_type); }
|
||||
constexpr fuse::HardwareState GetHardwareState() const { return static_cast<fuse::HardwareState>(this->hardware_state); }
|
||||
constexpr uart::Port GetLogPort() const { return static_cast<uart::Port>(this->log_port); }
|
||||
constexpr u8 GetLogFlags() const { return this->log_flags; }
|
||||
|
||||
constexpr u16 GetLcdVendor() const { return this->lcd_vendor; }
|
||||
|
||||
constexpr u32 GetLogBaudRate() const { return this->log_baud_rate; }
|
||||
|
||||
constexpr bool IsProduction() const { return this->GetHardwareState() != fuse::HardwareState_Development; }
|
||||
|
||||
constexpr bool IsDevelopmentFunctionEnabledForKernel() const { return (this->flags[0] & SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForKernel) != 0; }
|
||||
constexpr bool IsDevelopmentFunctionEnabledForUser() const { return (this->flags[0] & SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForUser) != 0; }
|
||||
constexpr bool DisableUserModeExceptionHandlers() const { return (this->flags[0] & SecureMonitorConfigurationFlag_DisableUserModeExceptionHandlers) != 0; }
|
||||
constexpr bool EnableUserModePerformanceCounterAccess() const { return (this->flags[0] & SecureMonitorConfigurationFlag_EnableUserModePerformanceCounterAccess) != 0; }
|
||||
constexpr bool ShouldUseBlankCalibrationBinary() const { return (this->flags[0] & SecureMonitorConfigurationFlag_ShouldUseBlankCalibrationBinary) != 0; }
|
||||
constexpr bool AllowWritingToCalibrationBinarySysmmc() const { return (this->flags[0] & SecureMonitorConfigurationFlag_AllowWritingToCalibrationBinarySysmmc) != 0; }
|
||||
constexpr bool IsUsb30ForceEnabled() const { return (this->flags[0] & SecureMonitorConfigurationFlag_ForceEnableUsb30) != 0; }
|
||||
|
||||
constexpr bool IsDevelopmentFunctionEnabled(bool for_kern) const { return for_kern ? this->IsDevelopmentFunctionEnabledForKernel() : this->IsDevelopmentFunctionEnabledForUser(); }
|
||||
};
|
||||
static_assert(util::is_pod<SecureMonitorConfiguration>::value);
|
||||
static_assert(sizeof(SecureMonitorConfiguration) == 0x80);
|
||||
|
||||
constexpr inline const SecureMonitorConfiguration DefaultSecureMonitorConfiguration = {
|
||||
.target_firmware = ams::TargetFirmware_Current,
|
||||
.key_generation = {},
|
||||
.hardware_type = {},
|
||||
.soc_type = {},
|
||||
.hardware_state = {},
|
||||
.log_port = uart::Port_ReservedDebug,
|
||||
.flags = { SecureMonitorConfigurationFlag_Default, SecureMonitorConfigurationFlag_None },
|
||||
.lcd_vendor = {},
|
||||
.log_flags = {},
|
||||
.reserved0 = {},
|
||||
.log_baud_rate = 115200,
|
||||
.reserved1 = {},
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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 <exosphere/pkg1.hpp>
|
||||
#include <exosphere/pkg2.hpp>
|
||||
|
||||
namespace ams::secmon {
|
||||
|
||||
/* The VolatileStack page is reserved entirely for use for core 3 SMC handling. */
|
||||
constexpr inline const Address Core3SmcStackAddress = MemoryRegionVirtualTzramVolatileStack.GetAddress() + MemoryRegionVirtualTzramVolatileStack.GetSize();
|
||||
|
||||
constexpr inline const size_t CoreExceptionStackSize = 0x80;
|
||||
|
||||
/* Volatile keydata that we lose access to after boot. */
|
||||
struct VolatileKeys {
|
||||
u8 boot_config_rsa_modulus[0x100];
|
||||
u8 package2_dev_rsa_modulus[0x100];
|
||||
u8 package2_prod_rsa_modulus[0x100];
|
||||
u8 package2_aes_key[0x10];
|
||||
u8 master_key_source[0x10];
|
||||
u8 device_master_key_source_kek_source[0x10];
|
||||
u8 mariko_dev_master_kek_source[0x10];
|
||||
u8 mariko_prod_master_kek_source[0x10];
|
||||
u8 dev_master_key_vectors[pkg1::OldMasterKeyCount + 1][0x10];
|
||||
u8 prod_master_key_vectors[pkg1::OldMasterKeyCount + 1][0x10];
|
||||
u8 device_master_key_source_sources[pkg1::OldDeviceMasterKeyCount][0x10];
|
||||
u8 dev_device_master_kek_sources[pkg1::OldDeviceMasterKeyCount][0x10];
|
||||
u8 prod_device_master_kek_sources[pkg1::OldDeviceMasterKeyCount][0x10];
|
||||
};
|
||||
static_assert(util::is_pod<VolatileKeys>::value);
|
||||
static_assert(sizeof(VolatileKeys) <= 0x1000);
|
||||
|
||||
/* Nintendo uses the bottom 0x740 of this as a stack for warmboot setup, and another 0x740 for the core 0/1/2 SMC stacks. */
|
||||
/* This is...wasteful. The warmboot stack is not deep. We will thus save 1K+ of nonvolatile storage by keeping the random cache in here. */
|
||||
struct VolatileData {
|
||||
u8 se_work_block[crypto::AesEncryptor128::BlockSize];
|
||||
union {
|
||||
u8 random_cache[0x400];
|
||||
pkg2::Package2Meta pkg2_meta;
|
||||
};
|
||||
u8 reserved_danger_zone[0x30]; /* This memory is "available", but careful consideration must be taken before declaring it used. */
|
||||
u8 warmboot_stack[0x380];
|
||||
u8 core012_smc_stack[0x6C0];
|
||||
u8 core_exception_stacks[3][CoreExceptionStackSize];
|
||||
};
|
||||
static_assert(util::is_pod<VolatileData>::value);
|
||||
static_assert(sizeof(VolatileData) == 0x1000);
|
||||
|
||||
ALWAYS_INLINE VolatileData &GetVolatileData() {
|
||||
return *MemoryRegionVirtualTzramVolatileData.GetPointer<VolatileData>();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE u8 *GetRandomBytesCache() {
|
||||
return GetVolatileData().random_cache;
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE size_t GetRandomBytesCacheSize() {
|
||||
return sizeof(VolatileData::random_cache);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE u8 *GetSecurityEngineEphemeralWorkBlock() {
|
||||
return GetVolatileData().se_work_block;
|
||||
}
|
||||
|
||||
namespace boot {
|
||||
|
||||
ALWAYS_INLINE VolatileKeys &GetVolatileKeys() {
|
||||
return *MemoryRegionPhysicalIramBootCodeKeys.GetPointer<VolatileKeys>();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE const u8 *GetBootConfigRsaModulus() {
|
||||
return GetVolatileKeys().boot_config_rsa_modulus;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE const u8 *GetPackage2RsaModulus(bool is_prod) {
|
||||
auto &keys = GetVolatileKeys();
|
||||
return is_prod ? keys.package2_prod_rsa_modulus : keys.package2_dev_rsa_modulus;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE const u8 *GetPackage2AesKey() {
|
||||
return GetVolatileKeys().package2_aes_key;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE const u8 *GetMasterKeySource() {
|
||||
return GetVolatileKeys().master_key_source;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE const u8 *GetDeviceMasterKeySourceKekSource() {
|
||||
return GetVolatileKeys().device_master_key_source_kek_source;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE const u8 *GetMarikoMasterKekSource(bool is_prod) {
|
||||
auto &keys = GetVolatileKeys();
|
||||
return is_prod ? keys.mariko_prod_master_kek_source : keys.mariko_dev_master_kek_source;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE const u8 *GetMasterKeyVector(bool is_prod, size_t i) {
|
||||
auto &keys = GetVolatileKeys();
|
||||
return is_prod ? keys.prod_master_key_vectors[i] : keys.dev_master_key_vectors[i];
|
||||
}
|
||||
|
||||
ALWAYS_INLINE const u8 *GetDeviceMasterKeySourceSource(size_t i) {
|
||||
return GetVolatileKeys().device_master_key_source_sources[i];
|
||||
}
|
||||
|
||||
ALWAYS_INLINE const u8 *GetDeviceMasterKekSource(bool is_prod, size_t i) {
|
||||
auto &keys = GetVolatileKeys();
|
||||
return is_prod ? keys.prod_device_master_kek_sources[i] : keys.dev_device_master_kek_sources[i];
|
||||
}
|
||||
|
||||
ALWAYS_INLINE pkg2::Package2Meta &GetEphemeralPackage2Meta() {
|
||||
return GetVolatileData().pkg2_meta;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
constexpr inline const Address WarmbootStackAddress = MemoryRegionVirtualTzramVolatileData.GetAddress() + AMS_OFFSETOF(VolatileData, warmboot_stack) + sizeof(VolatileData::warmboot_stack);
|
||||
constexpr inline const Address Core012SmcStackAddress = MemoryRegionVirtualTzramVolatileData.GetAddress() + AMS_OFFSETOF(VolatileData, core012_smc_stack) + sizeof(VolatileData::core012_smc_stack);
|
||||
|
||||
constexpr inline const Address Core0ExceptionStackAddress = MemoryRegionVirtualTzramVolatileData.GetAddress() + AMS_OFFSETOF(VolatileData, core_exception_stacks) + CoreExceptionStackSize;
|
||||
constexpr inline const Address Core1ExceptionStackAddress = Core0ExceptionStackAddress + CoreExceptionStackSize;
|
||||
constexpr inline const Address Core2ExceptionStackAddress = Core1ExceptionStackAddress + CoreExceptionStackSize;
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::tsec {
|
||||
|
||||
bool RunTsecFirmware(const void *fw, size_t fw_size);
|
||||
|
||||
void Lock();
|
||||
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::uart {
|
||||
|
||||
enum Port {
|
||||
Port_A = 0,
|
||||
Port_B = 1,
|
||||
Port_C = 2,
|
||||
|
||||
Port_Count = 3,
|
||||
|
||||
Port_ReservedDebug = Port_A,
|
||||
Port_RightJoyCon = Port_B,
|
||||
Port_LeftJoyCon = Port_C,
|
||||
};
|
||||
|
||||
enum Flags {
|
||||
Flag_None = (0u << 0),
|
||||
Flag_Inverted = (1u << 0),
|
||||
};
|
||||
|
||||
void SetRegisterAddress(uintptr_t address);
|
||||
|
||||
void Initialize(Port port, int baud_rate, u32 flags);
|
||||
|
||||
void SendText(Port port, const void *data, size_t size);
|
||||
|
||||
void WaitFlush(Port port);
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::util {
|
||||
|
||||
void SetRegisterAddress(uintptr_t address);
|
||||
|
||||
void ClearMemory(void *ptr, size_t size);
|
||||
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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::wdt {
|
||||
|
||||
void SetRegisterAddress(uintptr_t address);
|
||||
void Reboot();
|
||||
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
# pull in common atmosphere configuration
|
||||
#---------------------------------------------------------------------------------
|
||||
THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||
CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE)))
|
||||
include $(CURRENT_DIRECTORY)/../config/common.mk
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
PRECOMPILED_HEADERS :=
|
||||
|
||||
ifeq ($(strip $(ATMOSPHERE_ARCH_NAME)),arm64)
|
||||
|
||||
ifeq ($(ATMOSPHERE_BUILD_FOR_DEBUGGING),1)
|
||||
ATMOSPHERE_OPTIMIZATION_FLAG := -Os
|
||||
else
|
||||
ATMOSPHERE_OPTIMIZATION_FLAG := -Os
|
||||
endif
|
||||
|
||||
else
|
||||
|
||||
ifeq ($(ATMOSPHERE_BUILD_FOR_DEBUGGING),1)
|
||||
ATMOSPHERE_OPTIMIZATION_FLAG := -Os
|
||||
else
|
||||
ATMOSPHERE_OPTIMIZATION_FLAG := -O2
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE -DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS
|
||||
SETTINGS := $(ATMOSPHERE_SETTINGS) $(ATMOSPHERE_OPTIMIZATION_FLAG) -Wextra -Werror -fno-non-call-exceptions -Wno-array-bounds -Wno-stringop-overflow -Wno-stringop-overread
|
||||
|
||||
ifeq ($(strip $(ATMOSPHERE_ARCH_NAME)),arm64)
|
||||
SETTINGS += -mgeneral-regs-only -ffixed-x18
|
||||
else ifeq ($(strip $(ATMOSPHERE_ARCH_NAME)),arm)
|
||||
SETTINGS += -flto
|
||||
endif
|
||||
|
||||
CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
|
||||
CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit
|
||||
ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
|
||||
|
||||
SOURCES += $(call ALL_SOURCE_DIRS,../libvapours/source)
|
||||
|
||||
LIBS :=
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
# include and lib
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIRS := $(ATMOSPHERE_LIBRARIES_DIR)/libvapours
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# no real need to edit anything past this point unless you need to add additional
|
||||
# rules for different file extensions
|
||||
#---------------------------------------------------------------------------------
|
||||
ifneq ($(__RECURSIVE__),1)
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||
|
||||
CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c)
|
||||
CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp)
|
||||
SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# use CXX for linking C++ projects, CC for standard C
|
||||
#---------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(CPPFILES)),)
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CC)
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CXX)
|
||||
#---------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
|
||||
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
export GCH_DIRS := $(PRECOMPILED_HEADERS:.hpp=.hpp.gch)
|
||||
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
||||
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I.
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
.PHONY: clean all
|
||||
|
||||
all: $(ATMOSPHERE_LIBRARY_DIR) $(ATMOSPHERE_BUILD_DIR) $(SOURCES) $(INCLUDES) $(GCH_DIRS) $(CPPFILES) $(CFILES) $(SFILES)
|
||||
@$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURDIR)/$(ATMOSPHERE_LIBRARY_DIR)/$(TARGET).a \
|
||||
DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \
|
||||
--no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \
|
||||
-f $(THIS_MAKEFILE)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean $(ATMOSPHERE_BUILD_NAME) ...
|
||||
@rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_OUT_DIR)
|
||||
@rm -fr $(foreach hdr,$(GCH_DIRS),$(hdr)/$(ATMOSPHERE_GCH_IDENTIFIER))
|
||||
@for i in $(GCH_DIRS); do [ -d $$i ] && rmdir $$i 2>/dev/null || true; done
|
||||
|
||||
$(ATMOSPHERE_LIBRARY_DIR) $(ATMOSPHERE_BUILD_DIR) $(GCH_DIRS):
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
|
||||
GCH_FILES := $(foreach hdr,$(PRECOMPILED_HEADERS:.hpp=.hpp.gch),$(CURRENT_DIRECTORY)/$(hdr)/$(ATMOSPHERE_GCH_IDENTIFIER))
|
||||
DEPENDS := $(OFILES:.o=.d) $(foreach hdr,$(GCH_FILES),$(notdir $(patsubst %.hpp.gch/,%.d,$(dir $(hdr)))))
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#---------------------------------------------------------------------------------
|
||||
$(OUTPUT) : $(OFILES)
|
||||
|
||||
$(OFILES) : $(GCH_FILES)
|
||||
|
||||
$(OFILES_SRC) : $(HFILES_BIN)
|
||||
|
||||
libc.o: CFLAGS += -fno-builtin
|
||||
|
||||
ifeq ($(strip $(ATMOSPHERE_ARCH_NAME)),arm)
|
||||
libc.o: CFLAGS += -fno-lto
|
||||
util_api.o: CFLAGS += -fno-lto
|
||||
endif
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%_bin.h %.bin.o : %.bin
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------------
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "actmon_registers.hpp"
|
||||
|
||||
namespace ams::actmon {
|
||||
|
||||
namespace {
|
||||
|
||||
constinit uintptr_t g_register_address = secmon::MemoryRegionPhysicalDeviceActivityMonitor.GetAddress();
|
||||
|
||||
constinit InterruptHandler g_interrupt_handler = nullptr;
|
||||
|
||||
}
|
||||
|
||||
void SetRegisterAddress(uintptr_t address) {
|
||||
g_register_address = address;
|
||||
}
|
||||
|
||||
void HandleInterrupt() {
|
||||
/* Get the registers. */
|
||||
const uintptr_t ACTMON = g_register_address;
|
||||
|
||||
/* Disable the actmon interrupt. */
|
||||
reg::Write(ACTMON + ACTMON_COP_CTRL, ACTMON_REG_BITS_ENUM(COP_CTRL_ENB, DISABLE));
|
||||
|
||||
/* Update the interrupt status. */
|
||||
reg::Write(ACTMON + ACTMON_COP_INTR_STATUS, reg::Read(ACTMON + ACTMON_COP_INTR_STATUS));
|
||||
|
||||
/* Invoke the handler. */
|
||||
if (g_interrupt_handler != nullptr) {
|
||||
g_interrupt_handler();
|
||||
g_interrupt_handler = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void StartMonitoringBpmp(InterruptHandler handler) {
|
||||
/* Get the registers. */
|
||||
const uintptr_t ACTMON = g_register_address;
|
||||
|
||||
/* Configure the activity monitor to poll once per microsecond. */
|
||||
reg::Write(ACTMON + ACTMON_GLB_PERIOD_CTRL, ACTMON_REG_BITS_ENUM (GLB_PERIOD_CTRL_SOURCE, USEC),
|
||||
ACTMON_REG_BITS_VALUE(GLB_PERIOD_CTRL_SAMPLE_PERIOD, 0));
|
||||
|
||||
/* Configure the activity monitor to generate an interrupt the first time the event occurs. */
|
||||
reg::Write(ACTMON + ACTMON_COP_UPPER_WMARK, 0);
|
||||
|
||||
/* Set the interrupt handler. */
|
||||
g_interrupt_handler = handler;
|
||||
|
||||
/* Configure the activity monitor to generate events whenever the bpmp is woken up. */
|
||||
reg::Write(ACTMON + ACTMON_COP_CTRL, ACTMON_REG_BITS_ENUM (COP_CTRL_ENB, ENABLE),
|
||||
ACTMON_REG_BITS_ENUM (COP_CTRL_CONSECUTIVE_ABOVE_WMARK_EN, ENABLE),
|
||||
ACTMON_REG_BITS_ENUM (COP_CTRL_CONSECUTIVE_BELOW_WMARK_EN, DISABLE),
|
||||
ACTMON_REG_BITS_VALUE(COP_CTRL_ABOVE_WMARK_NUM, 0),
|
||||
ACTMON_REG_BITS_VALUE(COP_CTRL_BELOW_WMARK_NUM, 0),
|
||||
ACTMON_REG_BITS_ENUM (COP_CTRL_WHEN_OVERFLOW_EN, DISABLE),
|
||||
ACTMON_REG_BITS_ENUM (COP_CTRL_AVG_ABOVE_WMARK_EN, DISABLE),
|
||||
ACTMON_REG_BITS_ENUM (COP_CTRL_AVG_BELOW_WMARK_EN, DISABLE),
|
||||
ACTMON_REG_BITS_ENUM (COP_CTRL_AT_END_EN, DISABLE),
|
||||
ACTMON_REG_BITS_ENUM (COP_CTRL_ENB_PERIODIC, ENABLE));
|
||||
|
||||
/* Read the activity monitor control register to make sure our configuration takes. */
|
||||
reg::Read(ACTMON + ACTMON_COP_CTRL);
|
||||
}
|
||||
|
||||
void StopMonitoringBpmp() {
|
||||
/* Get the registers. */
|
||||
const uintptr_t ACTMON = g_register_address;
|
||||
|
||||
/* Disable the actmon interrupt. */
|
||||
reg::Write(ACTMON + ACTMON_COP_CTRL, ACTMON_REG_BITS_ENUM(COP_CTRL_ENB, DISABLE));
|
||||
|
||||
/* Update the interrupt status. */
|
||||
reg::Write(ACTMON + ACTMON_COP_INTR_STATUS, reg::Read(ACTMON + ACTMON_COP_INTR_STATUS));
|
||||
|
||||
/* Clear the interrupt handler. */
|
||||
g_interrupt_handler = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::actmon {
|
||||
|
||||
#define ACTMON_GLB_PERIOD_CTRL (0x004)
|
||||
#define ACTMON_COP_CTRL (0x0C0)
|
||||
#define ACTMON_COP_UPPER_WMARK (0x0C4)
|
||||
#define ACTMON_COP_INTR_STATUS (0x0E4)
|
||||
|
||||
/* Actmon source enums. */
|
||||
#define ACTMON_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (ACTMON, NAME)
|
||||
#define ACTMON_REG_BITS_VALUE(NAME, VALUE) REG_NAMED_BITS_VALUE (ACTMON, NAME, VALUE)
|
||||
#define ACTMON_REG_BITS_ENUM(NAME, ENUM) REG_NAMED_BITS_ENUM (ACTMON, NAME, ENUM)
|
||||
#define ACTMON_REG_BITS_ENUM_SEL(NAME, __COND__, TRUE_ENUM, FALSE_ENUM) REG_NAMED_BITS_ENUM_SEL(ACTMON, NAME, __COND__, TRUE_ENUM, FALSE_ENUM)
|
||||
|
||||
#define DEFINE_ACTMON_REG(NAME, __OFFSET__, __WIDTH__) REG_DEFINE_NAMED_REG (ACTMON, NAME, __OFFSET__, __WIDTH__)
|
||||
#define DEFINE_ACTMON_REG_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE) REG_DEFINE_NAMED_BIT_ENUM (ACTMON, NAME, __OFFSET__, ZERO, ONE)
|
||||
#define DEFINE_ACTMON_REG_TWO_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE) REG_DEFINE_NAMED_TWO_BIT_ENUM (ACTMON, NAME, __OFFSET__, ZERO, ONE, TWO, THREE)
|
||||
#define DEFINE_ACTMON_REG_THREE_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) REG_DEFINE_NAMED_THREE_BIT_ENUM(ACTMON, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN)
|
||||
#define DEFINE_ACTMON_REG_FOUR_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) REG_DEFINE_NAMED_FOUR_BIT_ENUM (ACTMON, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN)
|
||||
|
||||
DEFINE_ACTMON_REG(GLB_PERIOD_CTRL_SAMPLE_PERIOD, 0, 8);
|
||||
DEFINE_ACTMON_REG_BIT_ENUM(GLB_PERIOD_CTRL_SOURCE, 8, MSEC, USEC);
|
||||
|
||||
DEFINE_ACTMON_REG(COP_CTRL_K_VAL, 10, 3);
|
||||
DEFINE_ACTMON_REG_BIT_ENUM(COP_CTRL_ENB_PERIODIC, 18, DISABLE, ENABLE);
|
||||
DEFINE_ACTMON_REG_BIT_ENUM(COP_CTRL_AT_END_EN, 19, DISABLE, ENABLE);
|
||||
DEFINE_ACTMON_REG_BIT_ENUM(COP_CTRL_AVG_BELOW_WMARK_EN, 20, DISABLE, ENABLE);
|
||||
DEFINE_ACTMON_REG_BIT_ENUM(COP_CTRL_AVG_ABOVE_WMARK_EN, 21, DISABLE, ENABLE);
|
||||
DEFINE_ACTMON_REG_BIT_ENUM(COP_CTRL_WHEN_OVERFLOW_EN, 22, DISABLE, ENABLE);
|
||||
DEFINE_ACTMON_REG(COP_CTRL_BELOW_WMARK_NUM, 23, 3);
|
||||
DEFINE_ACTMON_REG(COP_CTRL_ABOVE_WMARK_NUM, 26, 3);
|
||||
DEFINE_ACTMON_REG_BIT_ENUM(COP_CTRL_CONSECUTIVE_BELOW_WMARK_EN, 29, DISABLE, ENABLE);
|
||||
DEFINE_ACTMON_REG_BIT_ENUM(COP_CTRL_CONSECUTIVE_ABOVE_WMARK_EN, 30, DISABLE, ENABLE);
|
||||
DEFINE_ACTMON_REG_BIT_ENUM(COP_CTRL_ENB, 31, DISABLE, ENABLE);
|
||||
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::charger {
|
||||
|
||||
namespace {
|
||||
|
||||
/* https://www.ti.com/lit/ds/symlink/bq24193.pdf */
|
||||
constexpr inline int I2cAddressBq24193 = 0x6B;
|
||||
|
||||
constexpr inline int Bq24193RegisterInputSourceControl = 0x00;
|
||||
|
||||
/* 8.5.1.1 EN_HIZ */
|
||||
enum EnHiZ : u8 {
|
||||
EnHiZ_Disable = (0u << 7),
|
||||
EnHiZ_Enable = (1u << 7),
|
||||
|
||||
EnHiZ_Mask = (1u << 7),
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
bool IsHiZMode() {
|
||||
return (i2c::QueryByte(i2c::Port_1, I2cAddressBq24193, Bq24193RegisterInputSourceControl) & EnHiZ_Mask) == EnHiZ_Enable;
|
||||
}
|
||||
|
||||
void EnterHiZMode() {
|
||||
u8 ctrl = i2c::QueryByte(i2c::Port_1, I2cAddressBq24193, Bq24193RegisterInputSourceControl);
|
||||
ctrl &= ~EnHiZ_Mask;
|
||||
ctrl |= EnHiZ_Enable;
|
||||
i2c::SendByte(i2c::Port_1, I2cAddressBq24193, Bq24193RegisterInputSourceControl, ctrl);
|
||||
}
|
||||
|
||||
void ExitHiZMode() {
|
||||
u8 ctrl = i2c::QueryByte(i2c::Port_1, I2cAddressBq24193, Bq24193RegisterInputSourceControl);
|
||||
ctrl &= ~EnHiZ_Mask;
|
||||
ctrl |= EnHiZ_Disable;
|
||||
i2c::SendByte(i2c::Port_1, I2cAddressBq24193, Bq24193RegisterInputSourceControl, ctrl);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,357 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::clkrst {
|
||||
|
||||
namespace {
|
||||
|
||||
constinit uintptr_t g_register_address = secmon::MemoryRegionPhysicalDeviceClkRst.GetAddress();
|
||||
|
||||
constinit BpmpClockRate g_bpmp_clock_rate = BpmpClockRate_408MHz;
|
||||
|
||||
struct ClockParameters {
|
||||
uintptr_t reset_offset;
|
||||
uintptr_t clk_enb_offset;
|
||||
uintptr_t clk_src_offset;
|
||||
u8 index;
|
||||
u8 clk_src;
|
||||
u8 clk_div;
|
||||
};
|
||||
|
||||
void EnableClock(const ClockParameters ¶m) {
|
||||
/* Hold reset. */
|
||||
reg::ReadWrite(g_register_address + param.reset_offset, REG_BITS_VALUE(param.index, 1, 1));
|
||||
|
||||
/* Disable clock. */
|
||||
reg::ReadWrite(g_register_address + param.clk_enb_offset, REG_BITS_VALUE(param.index, 1, 0));
|
||||
|
||||
/* Set the clock source. */
|
||||
if (param.clk_src_offset != 0) {
|
||||
reg::Write(g_register_address + param.clk_src_offset, (param.clk_src << 29) | (param.clk_div << 0));
|
||||
}
|
||||
|
||||
/* Enable clk. */
|
||||
reg::ReadWrite(g_register_address + param.clk_enb_offset, REG_BITS_VALUE(param.index, 1, 1));
|
||||
|
||||
/* Release reset. */
|
||||
reg::ReadWrite(g_register_address + param.reset_offset, REG_BITS_VALUE(param.index, 1, 0));
|
||||
}
|
||||
|
||||
void DisableClock(const ClockParameters ¶m) {
|
||||
/* Hold reset. */
|
||||
reg::ReadWrite(g_register_address + param.reset_offset, REG_BITS_VALUE(param.index, 1, 1));
|
||||
|
||||
/* Disable clock. */
|
||||
reg::ReadWrite(g_register_address + param.clk_enb_offset, REG_BITS_VALUE(param.index, 1, 0));
|
||||
}
|
||||
|
||||
#define DEFINE_CLOCK_PARAMETERS(_VARNAME_, _REG_, _NAME_, _CLK_, _DIV_) \
|
||||
constexpr inline const ClockParameters _VARNAME_ = { \
|
||||
.reset_offset = CLK_RST_CONTROLLER_RST_DEVICES_##_REG_, \
|
||||
.clk_enb_offset = CLK_RST_CONTROLLER_CLK_OUT_ENB_##_REG_, \
|
||||
.clk_src_offset = CLK_RST_CONTROLLER_CLK_SOURCE_##_NAME_, \
|
||||
.index = CLK_RST_CONTROLLER_CLK_ENB_##_NAME_##_INDEX, \
|
||||
.clk_src = CLK_RST_CONTROLLER_CLK_SOURCE_##_NAME_##_##_NAME_##_CLK_SRC_##_CLK_, \
|
||||
.clk_div = _DIV_, \
|
||||
}
|
||||
|
||||
#define DEFINE_CLOCK_PARAMETERS_WITHOUT_CLKDIV(_VARNAME_, _REG_, _NAME_) \
|
||||
constexpr inline const ClockParameters _VARNAME_ = { \
|
||||
.reset_offset = CLK_RST_CONTROLLER_RST_DEVICES_##_REG_, \
|
||||
.clk_enb_offset = CLK_RST_CONTROLLER_CLK_OUT_ENB_##_REG_, \
|
||||
.clk_src_offset = 0, \
|
||||
.index = CLK_RST_CONTROLLER_CLK_ENB_##_NAME_##_INDEX, \
|
||||
.clk_src = 0, \
|
||||
.clk_div = 0, \
|
||||
}
|
||||
|
||||
DEFINE_CLOCK_PARAMETERS(UartAClock, L, UARTA, PLLP_OUT0, 0);
|
||||
DEFINE_CLOCK_PARAMETERS(UartBClock, L, UARTB, PLLP_OUT0, 0);
|
||||
DEFINE_CLOCK_PARAMETERS(UartCClock, H, UARTC, PLLP_OUT0, 0);
|
||||
DEFINE_CLOCK_PARAMETERS(I2c1Clock, L, I2C1, CLK_M, 0);
|
||||
DEFINE_CLOCK_PARAMETERS(I2c5Clock, H, I2C5, CLK_M, 0);
|
||||
DEFINE_CLOCK_PARAMETERS(SeClock, V, SE, PLLP_OUT0, 0);
|
||||
DEFINE_CLOCK_PARAMETERS(ActmonClock, V, ACTMON, CLK_M, 0);
|
||||
|
||||
DEFINE_CLOCK_PARAMETERS(CsiteClock, U, CSITE, PLLP_OUT0, 4);
|
||||
DEFINE_CLOCK_PARAMETERS(Host1xClock, L, HOST1X, PLLP_OUT0, 3);
|
||||
DEFINE_CLOCK_PARAMETERS(TsecClock, U, TSEC, PLLP_OUT0, 2);
|
||||
DEFINE_CLOCK_PARAMETERS(Sor1Clock, X, SOR1, PLLP_OUT0, 2);
|
||||
|
||||
DEFINE_CLOCK_PARAMETERS_WITHOUT_CLKDIV(CldvfsClock, W, DVFS);
|
||||
|
||||
DEFINE_CLOCK_PARAMETERS_WITHOUT_CLKDIV(TzramClock, V, TZRAM);
|
||||
|
||||
DEFINE_CLOCK_PARAMETERS_WITHOUT_CLKDIV(SorSafeClock, Y, SOR_SAFE);
|
||||
DEFINE_CLOCK_PARAMETERS_WITHOUT_CLKDIV(Sor0Clock, X, SOR0);
|
||||
DEFINE_CLOCK_PARAMETERS_WITHOUT_CLKDIV(KfuseClock, H, KFUSE);
|
||||
|
||||
DEFINE_CLOCK_PARAMETERS_WITHOUT_CLKDIV(Cache2Clock, L, CACHE2);
|
||||
DEFINE_CLOCK_PARAMETERS_WITHOUT_CLKDIV(Cram2Clock, U, CRAM2);
|
||||
|
||||
constexpr const u32 PllcDivn[] = {
|
||||
[BpmpClockRate_408MHz] = 0,
|
||||
[BpmpClockRate_544MHz] = 85,
|
||||
[BpmpClockRate_576MHz] = 90,
|
||||
[BpmpClockRate_589MHz] = 92,
|
||||
};
|
||||
|
||||
void EnablePllc(BpmpClockRate rate) {
|
||||
const u32 desired_divn = PllcDivn[rate];
|
||||
|
||||
/* Check if we're already enabled. */
|
||||
const bool is_enabled = reg::HasValue(g_register_address + CLK_RST_CONTROLLER_PLLC_BASE, CLK_RST_REG_BITS_ENUM(PLLC_BASE_PLLC_ENABLE, ENABLE));
|
||||
const bool is_good_divn = reg::HasValue(g_register_address + CLK_RST_CONTROLLER_PLLC_BASE, CLK_RST_REG_BITS_VALUE(PLLC_BASE_PLLC_DIVN, desired_divn));
|
||||
if (is_enabled && is_good_divn) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Take PLLC out of reset. */
|
||||
reg::Write(g_register_address + CLK_RST_CONTROLLER_PLLC_MISC, (reg::Read(g_register_address + CLK_RST_CONTROLLER_PLLC_MISC) & 0xBFF0000F) | (0x80000 << 4));
|
||||
reg::SetBits(g_register_address + CLK_RST_CONTROLLER_PLLC_MISC2, 0xF0 << 8);
|
||||
|
||||
/* Disable pll. */
|
||||
reg::ReadWrite(g_register_address + CLK_RST_CONTROLLER_PLLC_BASE, CLK_RST_REG_BITS_ENUM(PLLC_BASE_PLLC_ENABLE, DISABLE));
|
||||
reg::ClearBits(g_register_address + CLK_RST_CONTROLLER_PLLC_MISC1, (1u << 27));
|
||||
util::WaitMicroSeconds(10);
|
||||
|
||||
/* Set dividers. */
|
||||
reg::Write(g_register_address + CLK_RST_CONTROLLER_PLLC_BASE, CLK_RST_REG_BITS_VALUE(PLLC_BASE_PLLC_DIVM, 4),
|
||||
CLK_RST_REG_BITS_VALUE(PLLC_BASE_PLLC_DIVN, desired_divn));
|
||||
|
||||
/* Enable pll. */
|
||||
reg::ReadWrite(g_register_address + CLK_RST_CONTROLLER_PLLC_BASE, CLK_RST_REG_BITS_ENUM(PLLC_BASE_PLLC_ENABLE, ENABLE));
|
||||
while (!reg::HasValue(g_register_address + CLK_RST_CONTROLLER_PLLC_BASE, CLK_RST_REG_BITS_ENUM(PLLC_BASE_PLLC_LOCK, LOCK))) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
/* Disable PLLC_OUT1. */
|
||||
reg::Write(g_register_address + CLK_RST_CONTROLLER_PLLC_OUT, CLK_RST_REG_BITS_VALUE(PLLC_OUT_PLLC_OUT1_RATIO, 1));
|
||||
|
||||
/* Enable PLLC_OUT1. */
|
||||
reg::ReadWrite(g_register_address + CLK_RST_CONTROLLER_PLLC_OUT, CLK_RST_REG_BITS_ENUM(PLLC_OUT_PLLC_OUT1_RSTN, RESET_DISABLE),
|
||||
CLK_RST_REG_BITS_ENUM(PLLC_OUT_PLLC_OUT1_CLKEN, ENABLE));
|
||||
util::WaitMicroSeconds(1'000);
|
||||
}
|
||||
|
||||
void DisablePllc() {
|
||||
/* Disable PLLC/PLLC_OUT1. */
|
||||
reg::ReadWrite(g_register_address + CLK_RST_CONTROLLER_PLLC_OUT, CLK_RST_REG_BITS_ENUM(PLLC_OUT_PLLC_OUT1_RSTN, RESET_ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(PLLC_OUT_PLLC_OUT1_CLKEN, DISABLE));
|
||||
|
||||
reg::ReadWrite(g_register_address + CLK_RST_CONTROLLER_PLLC_BASE, CLK_RST_REG_BITS_ENUM(PLLC_BASE_PLLC_ENABLE, DISABLE));
|
||||
reg::ReadWrite(g_register_address + CLK_RST_CONTROLLER_PLLC_BASE, CLK_RST_REG_BITS_ENUM(PLLC_BASE_PLLC_REF_DIS, REF_DISABLE));
|
||||
reg::SetBits(g_register_address + CLK_RST_CONTROLLER_PLLC_MISC1, (1u << 27));
|
||||
reg::SetBits(g_register_address + CLK_RST_CONTROLLER_PLLC_MISC, (1u << 30));
|
||||
util::WaitMicroSeconds(10);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SetRegisterAddress(uintptr_t address) {
|
||||
g_register_address = address;
|
||||
}
|
||||
|
||||
void SetFuseVisibility(bool visible) {
|
||||
reg::ReadWrite(g_register_address + CLK_RST_CONTROLLER_MISC_CLK_ENB, CLK_RST_REG_BITS_VALUE(MISC_CLK_ENB_CFG_ALL_VISIBLE, visible ? 1 : 0));
|
||||
}
|
||||
|
||||
void EnableUartAClock() {
|
||||
EnableClock(UartAClock);
|
||||
}
|
||||
|
||||
void EnableUartBClock() {
|
||||
EnableClock(UartBClock);
|
||||
}
|
||||
|
||||
void EnableUartCClock() {
|
||||
EnableClock(UartCClock);
|
||||
}
|
||||
|
||||
void EnableActmonClock() {
|
||||
EnableClock(ActmonClock);
|
||||
}
|
||||
|
||||
void EnableI2c1Clock() {
|
||||
EnableClock(I2c1Clock);
|
||||
}
|
||||
|
||||
void EnableI2c5Clock() {
|
||||
EnableClock(I2c5Clock);
|
||||
}
|
||||
|
||||
void EnableSeClock() {
|
||||
EnableClock(SeClock);
|
||||
if (fuse::GetSocType() == fuse::SocType_Mariko) {
|
||||
reg::ReadWrite(g_register_address + CLK_RST_CONTROLLER_CLK_SOURCE_SE, CLK_RST_REG_BITS_ENUM(CLK_SOURCE_SE_CLK_LOCK, ENABLE));
|
||||
}
|
||||
}
|
||||
|
||||
void EnableCldvfsClock() {
|
||||
EnableClock(CldvfsClock);
|
||||
}
|
||||
|
||||
void EnableCsiteClock() {
|
||||
EnableClock(CsiteClock);
|
||||
}
|
||||
|
||||
void EnableTzramClock() {
|
||||
EnableClock(TzramClock);
|
||||
}
|
||||
|
||||
void EnableCache2Clock() {
|
||||
EnableClock(Cache2Clock);
|
||||
}
|
||||
|
||||
void EnableCram2Clock() {
|
||||
EnableClock(Cram2Clock);
|
||||
}
|
||||
|
||||
void EnableHost1xClock() {
|
||||
EnableClock(Host1xClock);
|
||||
}
|
||||
|
||||
void EnableTsecClock() {
|
||||
EnableClock(TsecClock);
|
||||
}
|
||||
|
||||
void EnableSorSafeClock() {
|
||||
EnableClock(SorSafeClock);
|
||||
}
|
||||
|
||||
void EnableSor0Clock() {
|
||||
EnableClock(Sor0Clock);
|
||||
}
|
||||
|
||||
void EnableSor1Clock() {
|
||||
EnableClock(Sor1Clock);
|
||||
}
|
||||
|
||||
void EnableKfuseClock() {
|
||||
EnableClock(KfuseClock);
|
||||
}
|
||||
|
||||
void DisableI2c1Clock() {
|
||||
DisableClock(I2c1Clock);
|
||||
}
|
||||
|
||||
void DisableHost1xClock() {
|
||||
DisableClock(Host1xClock);
|
||||
}
|
||||
|
||||
void DisableTsecClock() {
|
||||
DisableClock(TsecClock);
|
||||
}
|
||||
|
||||
void DisableSorSafeClock() {
|
||||
DisableClock(SorSafeClock);
|
||||
}
|
||||
|
||||
void DisableSor0Clock() {
|
||||
DisableClock(Sor0Clock);
|
||||
}
|
||||
|
||||
void DisableSor1Clock() {
|
||||
DisableClock(Sor1Clock);
|
||||
}
|
||||
|
||||
void DisableKfuseClock() {
|
||||
DisableClock(KfuseClock);
|
||||
}
|
||||
|
||||
BpmpClockRate GetBpmpClockRate() {
|
||||
return g_bpmp_clock_rate;
|
||||
}
|
||||
|
||||
BpmpClockRate SetBpmpClockRate(BpmpClockRate rate) {
|
||||
/* Get the current rate. */
|
||||
const auto prev_rate = g_bpmp_clock_rate;
|
||||
|
||||
/* Cap our rate. */
|
||||
if (rate >= BpmpClockRate_Count) {
|
||||
rate = BpmpClockRate_589MHz;
|
||||
}
|
||||
|
||||
/* Change the rate, if we need to. */
|
||||
if (rate == prev_rate) {
|
||||
return prev_rate;
|
||||
}
|
||||
|
||||
/* Configure the rate. */
|
||||
if (rate != BpmpClockRate_408MHz) {
|
||||
/* If we were previously overclocked, restore to PLLP_OUT. */
|
||||
if (prev_rate != BpmpClockRate_408MHz) {
|
||||
reg::Write(g_register_address + CLK_RST_CONTROLLER_SCLK_BURST_POLICY, CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SYS_STATE, RUN),
|
||||
CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_COP_AUTO_SWAKEUP_FROM_FIQ, NOP),
|
||||
CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_CPU_AUTO_SWAKEUP_FROM_FIQ, NOP),
|
||||
CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_COP_AUTO_SWAKEUP_FROM_IRQ, NOP),
|
||||
CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_CPU_AUTO_SWAKEUP_FROM_IRQ, NOP),
|
||||
CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_FIQ_SOURCE, PLLP_OUT0),
|
||||
CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_IRQ_SOURCE, PLLP_OUT0),
|
||||
CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_RUN_SOURCE, PLLP_OUT0),
|
||||
CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_IDLE_SOURCE, PLLP_OUT0));
|
||||
util::WaitMicroSeconds(1'000);
|
||||
}
|
||||
|
||||
/* Configure PLLC. */
|
||||
EnablePllc(rate);
|
||||
|
||||
/* Set SCLK. */
|
||||
reg::Write(g_register_address + CLK_RST_CONTROLLER_CLK_SYSTEM_RATE, CLK_RST_REG_BITS_VALUE(CLK_SYSTEM_RATE_HCLK_DIS, 0),
|
||||
CLK_RST_REG_BITS_VALUE(CLK_SYSTEM_RATE_AHB_RATE, 0),
|
||||
CLK_RST_REG_BITS_VALUE(CLK_SYSTEM_RATE_PCLK_DIS, 0),
|
||||
CLK_RST_REG_BITS_VALUE(CLK_SYSTEM_RATE_APB_RATE, 3));
|
||||
|
||||
reg::Write(g_register_address + CLK_RST_CONTROLLER_SCLK_BURST_POLICY, CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SYS_STATE, RUN),
|
||||
CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_COP_AUTO_SWAKEUP_FROM_FIQ, NOP),
|
||||
CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_CPU_AUTO_SWAKEUP_FROM_FIQ, NOP),
|
||||
CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_COP_AUTO_SWAKEUP_FROM_IRQ, NOP),
|
||||
CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_CPU_AUTO_SWAKEUP_FROM_IRQ, NOP),
|
||||
CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_FIQ_SOURCE, PLLP_OUT0),
|
||||
CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_IRQ_SOURCE, PLLP_OUT0),
|
||||
CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_RUN_SOURCE, PLLC_OUT1),
|
||||
CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_IDLE_SOURCE, CLKM));
|
||||
} else {
|
||||
/* Configure to use PLLP_OUT0. */
|
||||
reg::Write(g_register_address + CLK_RST_CONTROLLER_SCLK_BURST_POLICY, CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SYS_STATE, RUN),
|
||||
CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_COP_AUTO_SWAKEUP_FROM_FIQ, NOP),
|
||||
CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_CPU_AUTO_SWAKEUP_FROM_FIQ, NOP),
|
||||
CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_COP_AUTO_SWAKEUP_FROM_IRQ, NOP),
|
||||
CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_CPU_AUTO_SWAKEUP_FROM_IRQ, NOP),
|
||||
CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_FIQ_SOURCE, PLLP_OUT0),
|
||||
CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_IRQ_SOURCE, PLLP_OUT0),
|
||||
CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_RUN_SOURCE, PLLP_OUT0),
|
||||
CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_IDLE_SOURCE, CLKM));
|
||||
util::WaitMicroSeconds(1'000);
|
||||
|
||||
reg::Write(g_register_address + CLK_RST_CONTROLLER_CLK_SYSTEM_RATE, CLK_RST_REG_BITS_VALUE(CLK_SYSTEM_RATE_HCLK_DIS, 0),
|
||||
CLK_RST_REG_BITS_VALUE(CLK_SYSTEM_RATE_AHB_RATE, 0),
|
||||
CLK_RST_REG_BITS_VALUE(CLK_SYSTEM_RATE_PCLK_DIS, 0),
|
||||
CLK_RST_REG_BITS_VALUE(CLK_SYSTEM_RATE_APB_RATE, 2));
|
||||
|
||||
/* Disable PLLC. */
|
||||
DisablePllc();
|
||||
}
|
||||
|
||||
/* Set the clock rate. */
|
||||
g_bpmp_clock_rate = rate;
|
||||
|
||||
/* Return the previous rate. */
|
||||
return prev_rate;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::crypto::impl {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr bool IsSupportedKeySize(size_t size) {
|
||||
return size == 16 || size == 24 || size == 32;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<size_t KeySize>
|
||||
AesImpl<KeySize>::~AesImpl() {
|
||||
ClearMemory(this, sizeof(*this));
|
||||
}
|
||||
|
||||
template<size_t KeySize>
|
||||
void AesImpl<KeySize>::Initialize(const void *key, size_t key_size, bool is_encrypt) {
|
||||
static_assert(IsSupportedKeySize(KeySize));
|
||||
AMS_ASSERT(key_size == sizeof(int));
|
||||
AMS_UNUSED(key_size, is_encrypt);
|
||||
|
||||
/* Set the security engine keyslot. */
|
||||
m_slot = *static_cast<const int *>(key);
|
||||
}
|
||||
|
||||
template<size_t KeySize>
|
||||
void AesImpl<KeySize>::EncryptBlock(void *dst, size_t dst_size, const void *src, size_t src_size) const {
|
||||
static_assert(IsSupportedKeySize(KeySize));
|
||||
AMS_ASSERT(src_size >= BlockSize);
|
||||
AMS_ASSERT(dst_size >= BlockSize);
|
||||
|
||||
if constexpr (KeySize == 16) {
|
||||
/* Aes 128. */
|
||||
se::EncryptAes128(dst, dst_size, m_slot, src, src_size);
|
||||
} else if constexpr (KeySize == 24) {
|
||||
/* Aes 192. */
|
||||
/* TODO: se::EncryptAes192(dst, dst_size, m_slot, src, src_size); */
|
||||
AMS_UNUSED(dst, dst_size, src, src_size);
|
||||
} else if constexpr (KeySize == 32) {
|
||||
/* Aes 256. */
|
||||
/* TODO: se::EncryptAes256(dst, dst_size, m_slot, src, src_size); */
|
||||
AMS_UNUSED(dst, dst_size, src, src_size);
|
||||
} else {
|
||||
/* Invalid key size. */
|
||||
static_assert(!std::is_same<AesImpl<KeySize>, AesImpl<KeySize>>::value);
|
||||
}
|
||||
}
|
||||
|
||||
template<size_t KeySize>
|
||||
void AesImpl<KeySize>::DecryptBlock(void *dst, size_t dst_size, const void *src, size_t src_size) const {
|
||||
static_assert(IsSupportedKeySize(KeySize));
|
||||
AMS_ASSERT(src_size >= BlockSize);
|
||||
AMS_ASSERT(dst_size >= BlockSize);
|
||||
|
||||
if constexpr (KeySize == 16) {
|
||||
/* Aes 128. */
|
||||
se::DecryptAes128(dst, dst_size, m_slot, src, src_size);
|
||||
} else if constexpr (KeySize == 24) {
|
||||
/* Aes 192. */
|
||||
/* TODO: se::DecryptAes192(dst, dst_size, m_slot, src, src_size); */
|
||||
AMS_UNUSED(dst, dst_size, src, src_size);
|
||||
} else if constexpr (KeySize == 32) {
|
||||
/* Aes 256. */
|
||||
/* TODO: se::DecryptAes256(dst, dst_size, m_slot, src, src_size); */
|
||||
AMS_UNUSED(dst, dst_size, src, src_size);
|
||||
} else {
|
||||
/* Invalid key size. */
|
||||
static_assert(!std::is_same<AesImpl<KeySize>, AesImpl<KeySize>>::value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Explicitly instantiate the three supported key sizes. */
|
||||
template class AesImpl<16>;
|
||||
template class AesImpl<24>;
|
||||
template class AesImpl<32>;
|
||||
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::flow {
|
||||
|
||||
namespace {
|
||||
|
||||
struct FlowControllerRegisterOffset {
|
||||
u16 cpu_csr;
|
||||
u16 halt_cpu_events;
|
||||
u16 cc4_core_ctrl;
|
||||
};
|
||||
|
||||
constinit uintptr_t g_register_address = secmon::MemoryRegionPhysicalDeviceFlowController.GetAddress();
|
||||
|
||||
constexpr const FlowControllerRegisterOffset FlowControllerRegisterOffsets[] = {
|
||||
{ FLOW_CTLR_CPU0_CSR, FLOW_CTLR_HALT_CPU0_EVENTS, FLOW_CTLR_CC4_CORE0_CTRL, },
|
||||
{ FLOW_CTLR_CPU1_CSR, FLOW_CTLR_HALT_CPU1_EVENTS, FLOW_CTLR_CC4_CORE1_CTRL, },
|
||||
{ FLOW_CTLR_CPU2_CSR, FLOW_CTLR_HALT_CPU2_EVENTS, FLOW_CTLR_CC4_CORE2_CTRL, },
|
||||
{ FLOW_CTLR_CPU3_CSR, FLOW_CTLR_HALT_CPU3_EVENTS, FLOW_CTLR_CC4_CORE3_CTRL, },
|
||||
};
|
||||
|
||||
constexpr u32 GetHaltCpuEventsValue(bool resume_on_irq) {
|
||||
if (resume_on_irq) {
|
||||
return reg::Encode(FLOW_REG_BITS_ENUM(HALT_CPUN_EVENTS_FLOW_MODE, WAITEVENT),
|
||||
FLOW_REG_BITS_ENUM(HALT_CPUN_EVENTS_LIC_IRQN, ENABLE),
|
||||
FLOW_REG_BITS_ENUM(HALT_CPUN_EVENTS_LIC_FIQN, ENABLE),
|
||||
FLOW_REG_BITS_ENUM(HALT_CPUN_EVENTS_GIC_IRQN, ENABLE),
|
||||
FLOW_REG_BITS_ENUM(HALT_CPUN_EVENTS_GIC_FIQN, ENABLE));
|
||||
} else {
|
||||
return reg::Encode(FLOW_REG_BITS_ENUM(HALT_CPUN_EVENTS_FLOW_MODE, WAITEVENT));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SetRegisterAddress(uintptr_t address) {
|
||||
g_register_address = address;
|
||||
}
|
||||
|
||||
void ResetCpuRegisters(int core) {
|
||||
AMS_ASSUME(core >= 0);
|
||||
|
||||
const auto &offsets = FlowControllerRegisterOffsets[core];
|
||||
reg::Write(g_register_address + offsets.cpu_csr, 0);
|
||||
reg::Write(g_register_address + offsets.halt_cpu_events, 0);
|
||||
}
|
||||
|
||||
void SetCpuCsr(int core, u32 enable_ext) {
|
||||
reg::Write(g_register_address + FlowControllerRegisterOffsets[core].cpu_csr, FLOW_REG_BITS_ENUM (CPUN_CSR_INTR_FLAG, TRUE),
|
||||
FLOW_REG_BITS_ENUM (CPUN_CSR_EVENT_FLAG, TRUE),
|
||||
FLOW_REG_BITS_VALUE(CPUN_CSR_ENABLE_EXT, enable_ext),
|
||||
FLOW_REG_BITS_VALUE(CPUN_CSR_WAIT_WFI_BITMAP, (1u << core)),
|
||||
FLOW_REG_BITS_ENUM (CPUN_CSR_ENABLE, ENABLE));
|
||||
}
|
||||
|
||||
void SetHaltCpuEvents(int core, bool resume_on_irq) {
|
||||
reg::Write(g_register_address + FlowControllerRegisterOffsets[core].halt_cpu_events, GetHaltCpuEventsValue(resume_on_irq));
|
||||
}
|
||||
|
||||
void SetCc4Ctrl(int core, u32 value) {
|
||||
reg::Write(g_register_address + FlowControllerRegisterOffsets[core].cc4_core_ctrl, value);
|
||||
}
|
||||
|
||||
void ClearL2FlushControl() {
|
||||
reg::Write(g_register_address + FLOW_CTLR_L2FLUSH_CONTROL, 0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,521 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "fuse_registers.hpp"
|
||||
|
||||
namespace ams::fuse {
|
||||
|
||||
namespace {
|
||||
|
||||
static constexpr SocType SocType_CommonInternal = static_cast<SocType>(-1);
|
||||
static_assert(SocType_CommonInternal != SocType_Erista);
|
||||
static_assert(SocType_CommonInternal != SocType_Mariko);
|
||||
|
||||
constinit SocType g_soc_type = SocType_CommonInternal;
|
||||
|
||||
struct BypassEntry {
|
||||
u32 offset;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
struct OdmWord2 {
|
||||
using DeviceUniqueKeyGeneration = util::BitPack32::Field<0, 5, int>;
|
||||
using Reserved = util::BitPack32::Field<5, 27, int>;
|
||||
};
|
||||
|
||||
struct OdmWord4 {
|
||||
using HardwareState1 = util::BitPack32::Field<0, 2, int>;
|
||||
using HardwareType1 = util::BitPack32::Field<HardwareState1::Next, 1, int>;
|
||||
using DramId1 = util::BitPack32::Field<HardwareType1::Next, 5, int>;
|
||||
using HardwareType2 = util::BitPack32::Field<DramId1::Next, 1, int>;
|
||||
using HardwareState2 = util::BitPack32::Field<HardwareType2::Next, 1, int>;
|
||||
using RetailInteractiveDisplayState = util::BitPack32::Field<HardwareState2::Next, 1, int>;
|
||||
using FormatVersion = util::BitPack32::Field<RetailInteractiveDisplayState::Next, 1, int>;
|
||||
using DramId2 = util::BitPack32::Field<FormatVersion::Next, 3, int>;
|
||||
using Reserved = util::BitPack32::Field<DramId2::Next, 1, int>;
|
||||
using HardwareType3 = util::BitPack32::Field<Reserved::Next, 4, int>;
|
||||
};
|
||||
|
||||
struct OdmWord28 {
|
||||
using Regulator = util::BitPack32::Field<0, 1, int>;
|
||||
using Reserved = util::BitPack32::Field<1, 31, int>;
|
||||
};
|
||||
|
||||
constexpr ALWAYS_INLINE int GetHardwareStateValue(const util::BitPack32 odm_word4) {
|
||||
constexpr auto HardwareState1Shift = 0;
|
||||
constexpr auto HardwareState2Shift = OdmWord4::HardwareState1::Count + HardwareState1Shift;
|
||||
|
||||
return (odm_word4.Get<OdmWord4::HardwareState1>() << HardwareState1Shift) |
|
||||
(odm_word4.Get<OdmWord4::HardwareState2>() << HardwareState2Shift);
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE int GetHardwareTypeValue(const util::BitPack32 odm_word4) {
|
||||
constexpr auto HardwareType1Shift = 0;
|
||||
constexpr auto HardwareType2Shift = OdmWord4::HardwareType1::Count + HardwareType1Shift;
|
||||
constexpr auto HardwareType3Shift = OdmWord4::HardwareType2::Count + HardwareType2Shift;
|
||||
|
||||
return (odm_word4.Get<OdmWord4::HardwareType1>() << HardwareType1Shift) |
|
||||
(odm_word4.Get<OdmWord4::HardwareType2>() << HardwareType2Shift) |
|
||||
(odm_word4.Get<OdmWord4::HardwareType3>() << HardwareType3Shift);
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE int GetDramIdValue(const util::BitPack32 odm_word4) {
|
||||
constexpr auto DramId1Shift = 0;
|
||||
constexpr auto DramId2Shift = OdmWord4::DramId1::Count + DramId1Shift;
|
||||
|
||||
|
||||
return (odm_word4.Get<OdmWord4::DramId1>() << DramId1Shift) |
|
||||
(odm_word4.Get<OdmWord4::DramId2>() << DramId2Shift);
|
||||
}
|
||||
|
||||
constinit uintptr_t g_register_address = secmon::MemoryRegionPhysicalDeviceFuses.GetAddress();
|
||||
|
||||
constinit bool g_checked_for_rcm_bug_patch = false;
|
||||
constinit bool g_has_rcm_bug_patch = false;
|
||||
|
||||
ALWAYS_INLINE volatile FuseRegisterRegion *GetRegisterRegion() {
|
||||
return reinterpret_cast<volatile FuseRegisterRegion *>(g_register_address);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE volatile FuseRegisters &GetRegisters() {
|
||||
return GetRegisterRegion()->fuse;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE volatile FuseChipRegistersCommon &GetChipRegistersCommon() {
|
||||
return GetRegisterRegion()->chip_common;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE volatile FuseChipRegistersErista &GetChipRegistersErista() {
|
||||
return GetRegisterRegion()->chip_erista;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE volatile FuseChipRegistersMariko &GetChipRegistersMariko() {
|
||||
return GetRegisterRegion()->chip_mariko;
|
||||
}
|
||||
|
||||
bool IsIdle() {
|
||||
return reg::HasValue(GetRegisters().FUSE_FUSECTRL, FUSE_REG_BITS_ENUM(FUSECTRL_STATE, IDLE));
|
||||
}
|
||||
|
||||
void WaitForIdle() {
|
||||
while (!IsIdle()) { /* ... */ }
|
||||
}
|
||||
|
||||
u32 GetOdmWordImpl(int index, fuse::SocType soc_type) {
|
||||
if (index < 8) {
|
||||
volatile auto &chip = GetChipRegistersCommon();
|
||||
return chip.FUSE_RESERVED_ODM_0[index - 0];
|
||||
} else if (soc_type == SocType_Mariko) {
|
||||
volatile auto &chip = GetChipRegistersMariko();
|
||||
if (index < 22) {
|
||||
return chip.FUSE_RESERVED_ODM_8[index - 8];
|
||||
} else if (index < 25) {
|
||||
return chip.FUSE_RESERVED_ODM_22[index - 22];
|
||||
} else if (index < 26) {
|
||||
return chip.FUSE_RESERVED_ODM_25[index - 25];
|
||||
} else if (index < 29) {
|
||||
return chip.FUSE_RESERVED_ODM_26[index - 26];
|
||||
} else if (index < 30) {
|
||||
return chip.FUSE_RESERVED_ODM_29[index - 29];
|
||||
}
|
||||
}
|
||||
AMS_ABORT("Invalid ODM fuse read");
|
||||
}
|
||||
|
||||
u32 GetCommonOdmWord(int index) {
|
||||
return GetOdmWordImpl(index, SocType_CommonInternal);
|
||||
}
|
||||
|
||||
bool IsNewFuseFormat() {
|
||||
/* On mariko, this should always be true. */
|
||||
if (GetSocType() != SocType_Erista) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Require that the format version be non-zero in odm4. */
|
||||
if (util::BitPack32{GetCommonOdmWord(4)}.Get<OdmWord4::FormatVersion>() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check that odm word 0/1 are fused with the magic values. */
|
||||
constexpr u32 NewFuseFormatMagic0 = 0x8E61ECAE;
|
||||
constexpr u32 NewFuseFormatMagic1 = 0xF2BA3BB2;
|
||||
|
||||
const u32 w0 = GetCommonOdmWord(0);
|
||||
const u32 w1 = GetCommonOdmWord(1);
|
||||
|
||||
return w0 == NewFuseFormatMagic0 && w1 == NewFuseFormatMagic1;
|
||||
}
|
||||
|
||||
constexpr u32 CompressLotCode(u32 lot0) {
|
||||
constexpr int Radix = 36;
|
||||
constexpr int Count = 5;
|
||||
constexpr int Width = 6;
|
||||
constexpr u32 Mask = (1u << Width) - 1;
|
||||
|
||||
u32 compressed = 0;
|
||||
|
||||
for (int i = Count - 1; i >= 0; --i) {
|
||||
compressed *= Radix;
|
||||
compressed += (lot0 >> (i * Width)) & Mask;
|
||||
}
|
||||
|
||||
return compressed;
|
||||
}
|
||||
|
||||
constexpr const TargetFirmware FuseVersionIncrementFirmwares[] = {
|
||||
TargetFirmware_20_0_0,
|
||||
TargetFirmware_19_0_0,
|
||||
TargetFirmware_17_0_0,
|
||||
TargetFirmware_16_0_0,
|
||||
TargetFirmware_15_0_0,
|
||||
TargetFirmware_13_2_1,
|
||||
TargetFirmware_12_0_2,
|
||||
TargetFirmware_11_0_0,
|
||||
TargetFirmware_10_0_0,
|
||||
TargetFirmware_9_1_0,
|
||||
TargetFirmware_9_0_0,
|
||||
TargetFirmware_8_1_0,
|
||||
TargetFirmware_7_0_0,
|
||||
TargetFirmware_6_2_0,
|
||||
TargetFirmware_6_0_0,
|
||||
TargetFirmware_5_0_0,
|
||||
TargetFirmware_4_0_0,
|
||||
TargetFirmware_3_0_2,
|
||||
TargetFirmware_3_0_0,
|
||||
TargetFirmware_2_0_0,
|
||||
TargetFirmware_1_0_0,
|
||||
};
|
||||
|
||||
constexpr inline int NumFuseIncrements = util::size(FuseVersionIncrementFirmwares);
|
||||
|
||||
constexpr const BypassEntry FuseBypassEntries[] = {
|
||||
/* Don't configure any fuse bypass entries. */
|
||||
};
|
||||
|
||||
constexpr inline int NumFuseBypassEntries = util::size(FuseBypassEntries);
|
||||
|
||||
/* Verify that the fuse version increment list is sorted. */
|
||||
static_assert([] {
|
||||
for (size_t i = 0; i < util::size(FuseVersionIncrementFirmwares) - 1; ++i) {
|
||||
if (FuseVersionIncrementFirmwares[i] <= FuseVersionIncrementFirmwares[i + 1]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}());
|
||||
|
||||
constexpr int GetExpectedFuseVersionImpl(TargetFirmware target_fw) {
|
||||
for (int i = 0; i < NumFuseIncrements; ++i) {
|
||||
if (target_fw >= FuseVersionIncrementFirmwares[i]) {
|
||||
return NumFuseIncrements - i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static_assert(GetExpectedFuseVersionImpl(TargetFirmware_11_0_0) == 14);
|
||||
static_assert(GetExpectedFuseVersionImpl(TargetFirmware_1_0_0) == 1);
|
||||
static_assert(GetExpectedFuseVersionImpl(static_cast<TargetFirmware>(0)) == 0);
|
||||
|
||||
}
|
||||
|
||||
void SetRegisterAddress(uintptr_t address) {
|
||||
g_register_address = address;
|
||||
}
|
||||
|
||||
void SetWriteSecureOnly() {
|
||||
reg::Write(GetRegisters().FUSE_PRIVATEKEYDISABLE, FUSE_REG_BITS_ENUM(PRIVATEKEYDISABLE_TZ_STICKY_BIT_VAL, KEY_INVISIBLE));
|
||||
}
|
||||
|
||||
void Lockout() {
|
||||
reg::Write(GetRegisters().FUSE_DISABLEREGPROGRAM, FUSE_REG_BITS_ENUM(DISABLEREGPROGRAM_VAL, ENABLE));
|
||||
}
|
||||
|
||||
u32 ReadWord(int address) {
|
||||
/* Require that the fuse array be idle. */
|
||||
AMS_ABORT_UNLESS(IsIdle());
|
||||
|
||||
/* Get the registers. */
|
||||
volatile auto &FUSE = GetRegisters();
|
||||
|
||||
/* Write the address to read. */
|
||||
reg::Write(FUSE.FUSE_FUSEADDR, address);
|
||||
|
||||
/* Set control to read. */
|
||||
reg::ReadWrite(FUSE.FUSE_FUSECTRL, FUSE_REG_BITS_ENUM(FUSECTRL_CMD, READ));
|
||||
|
||||
/* Wait 1 us. */
|
||||
util::WaitMicroSeconds(1);
|
||||
|
||||
/* Wait for the array to be idle. */
|
||||
WaitForIdle();
|
||||
|
||||
return reg::Read(FUSE.FUSE_FUSERDATA);
|
||||
}
|
||||
|
||||
u32 GetOdmWord(int index) {
|
||||
return GetOdmWordImpl(index, GetSocType());
|
||||
}
|
||||
|
||||
void GetEcid(br::BootEcid *out) {
|
||||
/* Get the registers. */
|
||||
volatile auto &chip = GetChipRegistersCommon();
|
||||
|
||||
/* Read the ecid components. */
|
||||
const u32 vendor = reg::Read(chip.FUSE_OPT_VENDOR_CODE) & ((1u << 4) - 1);
|
||||
const u32 fab = reg::Read(chip.FUSE_OPT_FAB_CODE) & ((1u << 6) - 1);
|
||||
const u32 lot0 = reg::Read(chip.FUSE_OPT_LOT_CODE_0) /* all 32 bits */ ;
|
||||
const u32 lot1 = reg::Read(chip.FUSE_OPT_LOT_CODE_1) & ((1u << 28) - 1);
|
||||
const u32 wafer = reg::Read(chip.FUSE_OPT_WAFER_ID) & ((1u << 6) - 1);
|
||||
const u32 x_coord = reg::Read(chip.FUSE_OPT_X_COORDINATE) & ((1u << 9) - 1);
|
||||
const u32 y_coord = reg::Read(chip.FUSE_OPT_Y_COORDINATE) & ((1u << 9) - 1);
|
||||
const u32 reserved = reg::Read(chip.FUSE_OPT_OPS_RESERVED) & ((1u << 6) - 1);
|
||||
|
||||
/* Clear the output. */
|
||||
util::ClearMemory(out, sizeof(*out));
|
||||
|
||||
/* Copy the component bits. */
|
||||
out->ecid[0] = static_cast<u32>((lot1 << 30) | (wafer << 24) | (x_coord << 15) | (y_coord << 6) | (reserved));
|
||||
out->ecid[1] = static_cast<u32>((lot0 << 26) | (lot1 >> 2));
|
||||
out->ecid[2] = static_cast<u32>((fab << 26) | (lot0 >> 6));
|
||||
out->ecid[3] = static_cast<u32>(vendor);
|
||||
}
|
||||
|
||||
u64 GetDeviceId() {
|
||||
/* Get the registers. */
|
||||
volatile auto &chip = GetChipRegistersCommon();
|
||||
|
||||
/* Read the device id components. */
|
||||
/* NOTE: Device ID is "basically" just an alternate encoding of Ecid. */
|
||||
/* It elides lot1 (and compresses lot0), but this is fine because */
|
||||
/* lot1 is fixed-value for all fused devices. */
|
||||
const u64 fab = reg::Read(chip.FUSE_OPT_FAB_CODE) & ((1u << 6) - 1);
|
||||
const u32 lot0 = reg::Read(chip.FUSE_OPT_LOT_CODE_0) /* all 32 bits */ ;
|
||||
const u64 wafer = reg::Read(chip.FUSE_OPT_WAFER_ID) & ((1u << 6) - 1);
|
||||
const u64 x_coord = reg::Read(chip.FUSE_OPT_X_COORDINATE) & ((1u << 9) - 1);
|
||||
const u64 y_coord = reg::Read(chip.FUSE_OPT_Y_COORDINATE) & ((1u << 9) - 1);
|
||||
|
||||
/* Compress lot0 down from 32-bits to 26. */
|
||||
const u64 clot0 = CompressLotCode(lot0) & ((1u << 26) - 1);
|
||||
|
||||
return (y_coord << 0) |
|
||||
(x_coord << 9) |
|
||||
(wafer << 18) |
|
||||
(clot0 << 24) |
|
||||
(fab << 50);
|
||||
}
|
||||
|
||||
DramId GetDramId() {
|
||||
/* Get the value. */
|
||||
return static_cast<DramId>(GetDramIdValue(util::BitPack32{GetCommonOdmWord(4)}));
|
||||
}
|
||||
|
||||
HardwareType GetHardwareType() {
|
||||
/* Read the odm word. */
|
||||
const util::BitPack32 odm_word4 = { GetCommonOdmWord(4) };
|
||||
|
||||
/* Get the value. */
|
||||
const auto value = GetHardwareTypeValue(odm_word4);
|
||||
|
||||
switch (value) {
|
||||
case 0x01: return HardwareType_Icosa;
|
||||
case 0x02: return (true /* TODO: GetSocType() == SocType_Mariko */) ? HardwareType_Calcio : HardwareType_Copper;
|
||||
case 0x04: return HardwareType_Iowa;
|
||||
case 0x08: return HardwareType_Hoag;
|
||||
case 0x10: return HardwareType_Aula;
|
||||
default: return HardwareType_Undefined;
|
||||
}
|
||||
}
|
||||
|
||||
HardwareState GetHardwareState() {
|
||||
/* Read the odm word. */
|
||||
const util::BitPack32 odm_word4 = { GetCommonOdmWord(4) };
|
||||
|
||||
/* Get the value. */
|
||||
const auto value = GetHardwareStateValue(odm_word4);
|
||||
|
||||
switch (value) {
|
||||
case 3: return HardwareState_Development;
|
||||
case 4: return HardwareState_Production;
|
||||
default: return HardwareState_Undefined;
|
||||
}
|
||||
}
|
||||
|
||||
PatchVersion GetPatchVersion() {
|
||||
const auto patch_version = reg::Read(GetChipRegistersCommon().FUSE_SOC_SPEEDO_1_CALIB);
|
||||
return static_cast<PatchVersion>(static_cast<int>(GetSocType() << 12) | patch_version);
|
||||
}
|
||||
|
||||
RetailInteractiveDisplayState GetRetailInteractiveDisplayState() {
|
||||
return static_cast<RetailInteractiveDisplayState>(util::BitPack32{GetCommonOdmWord(4)}.Get<OdmWord4::RetailInteractiveDisplayState>());
|
||||
}
|
||||
|
||||
pmic::Regulator GetRegulator() {
|
||||
if (GetSocType() == SocType_Mariko) {
|
||||
/* Read the odm word. */
|
||||
const util::BitPack32 odm_word28 = { GetOdmWordImpl(28, SocType_Mariko) };
|
||||
|
||||
return static_cast<pmic::Regulator>(odm_word28.Get<OdmWord28::Regulator>() + 1);
|
||||
} else /* if (GetSocType() == SocType_Erista) */ {
|
||||
return pmic::Regulator_Erista_Max77621;
|
||||
}
|
||||
}
|
||||
|
||||
int GetDeviceUniqueKeyGeneration() {
|
||||
if (IsNewFuseFormat()) {
|
||||
return util::BitPack32{GetCommonOdmWord(2)}.Get<OdmWord2::DeviceUniqueKeyGeneration>();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
SocType GetSocType() {
|
||||
if (AMS_LIKELY(g_soc_type != SocType_CommonInternal)) {
|
||||
return g_soc_type;
|
||||
} else {
|
||||
switch (GetHardwareType()) {
|
||||
case HardwareType_Icosa:
|
||||
case HardwareType_Copper:
|
||||
g_soc_type = SocType_Erista;
|
||||
break;
|
||||
case HardwareType_Iowa:
|
||||
case HardwareType_Hoag:
|
||||
case HardwareType_Calcio:
|
||||
case HardwareType_Aula:
|
||||
g_soc_type = SocType_Mariko;
|
||||
break;
|
||||
default:
|
||||
g_soc_type = SocType_Undefined;
|
||||
break;
|
||||
}
|
||||
|
||||
return g_soc_type;
|
||||
}
|
||||
}
|
||||
|
||||
int GetExpectedFuseVersion(TargetFirmware target_fw) {
|
||||
return GetExpectedFuseVersionImpl(target_fw);
|
||||
}
|
||||
|
||||
int GetFuseVersion() {
|
||||
return util::PopCount(GetCommonOdmWord(7));
|
||||
}
|
||||
|
||||
bool HasRcmVulnerabilityPatch() {
|
||||
/* Only check for RCM bug patch once, and cache our result. */
|
||||
if (!g_checked_for_rcm_bug_patch) {
|
||||
do {
|
||||
/* Mariko units are necessarily patched. */
|
||||
if (fuse::GetSocType() != SocType_Erista) {
|
||||
g_has_rcm_bug_patch = true;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Some patched units use XUSB in RCM. */
|
||||
if (reg::Read(GetChipRegistersCommon().FUSE_RESERVED_SW) & 0x80) {
|
||||
g_has_rcm_bug_patch = true;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Other units have a proper ipatch instead. */
|
||||
u32 word_count = reg::Read(GetChipRegistersCommon().FUSE_FIRST_BOOTROM_PATCH_SIZE) & 0x7F;
|
||||
u32 word_addr = 191;
|
||||
|
||||
while (word_count && !g_has_rcm_bug_patch) {
|
||||
u32 word0 = ReadWord(word_addr);
|
||||
u32 ipatch_count = (word0 >> 16) & 0xF;
|
||||
|
||||
for (u32 i = 0; i < ipatch_count && !g_has_rcm_bug_patch; ++i) {
|
||||
u32 word = ReadWord(word_addr - (i + 1));
|
||||
u32 addr = (word >> 16) * 2;
|
||||
|
||||
if (addr == 0x769a) {
|
||||
g_has_rcm_bug_patch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
word_addr -= word_count;
|
||||
word_count = word0 >> 25;
|
||||
}
|
||||
} while (0);
|
||||
|
||||
g_checked_for_rcm_bug_patch = true;
|
||||
}
|
||||
|
||||
return g_has_rcm_bug_patch;
|
||||
}
|
||||
|
||||
bool IsOdmProductionMode() {
|
||||
return reg::HasValue(GetChipRegistersCommon().FUSE_SECURITY_MODE, FUSE_REG_BITS_ENUM(SECURITY_MODE_SECURITY_MODE, ENABLED));
|
||||
}
|
||||
|
||||
bool GetSecureBootKey(void *dst) {
|
||||
/* Get the sbk from fuse data. */
|
||||
bool valid = false;
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
const u32 key_word = GetChipRegistersCommon().FUSE_PRIVATE_KEY[i];
|
||||
|
||||
static_cast<u32 *>(dst)[i] = key_word;
|
||||
valid |= key_word != 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
void ConfigureFuseBypass() {
|
||||
/* Make the fuse registers visible. */
|
||||
clkrst::SetFuseVisibility(true);
|
||||
|
||||
/* Only perform bypass configuration if fuse programming is allowed. */
|
||||
if (!reg::HasValue(GetRegisters().FUSE_DISABLEREGPROGRAM, FUSE_REG_BITS_ENUM(DISABLEREGPROGRAM_VAL, DISABLE))) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Enable software writes to fuses. */
|
||||
reg::ReadWrite(GetRegisters().FUSE_WRITE_ACCESS_SW, FUSE_REG_BITS_ENUM(WRITE_ACCESS_SW_CTRL, READWRITE),
|
||||
FUSE_REG_BITS_ENUM(WRITE_ACCESS_SW_STATUS, WRITE));
|
||||
|
||||
/* Enable fuse bypass. */
|
||||
reg::Write(GetRegisters().FUSE_FUSEBYPASS, FUSE_REG_BITS_ENUM(FUSEBYPASS_VAL, ENABLE));
|
||||
|
||||
/* Override fuses. */
|
||||
for (const auto &entry : FuseBypassEntries) {
|
||||
reg::Write(g_register_address + entry.offset, entry.value);
|
||||
}
|
||||
|
||||
/* Disable software writes to fuses. */
|
||||
reg::ReadWrite(GetRegisters().FUSE_WRITE_ACCESS_SW, FUSE_REG_BITS_ENUM(WRITE_ACCESS_SW_CTRL, READONLY));
|
||||
|
||||
/* NOTE: Here, NVidia almost certainly intends to *disable* fuse bypass, but they write enable instead... */
|
||||
reg::Write(GetRegisters().FUSE_FUSEBYPASS, FUSE_REG_BITS_ENUM(FUSEBYPASS_VAL, ENABLE));
|
||||
|
||||
/* NOTE: Here, NVidia intends to disable fuse programming. However, they fuck up -- and *clear* the disable bit. */
|
||||
/* It should be noted that this is a sticky bit, and thus software clears have no effect. */
|
||||
reg::ReadWrite(GetRegisters().FUSE_DISABLEREGPROGRAM, FUSE_REG_BITS_ENUM(DISABLEREGPROGRAM_VAL, DISABLE));
|
||||
|
||||
/* Configure FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT. */
|
||||
constexpr const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress();
|
||||
const bool key_invisible = reg::HasValue(PMC + APBDEV_PMC_SECURE_SCRATCH21, FUSE_REG_BITS_ENUM(PRIVATEKEYDISABLE_TZ_STICKY_BIT_VAL, KEY_INVISIBLE));
|
||||
|
||||
reg::ReadWrite(GetRegisters().FUSE_PRIVATEKEYDISABLE, FUSE_REG_BITS_ENUM_SEL(PRIVATEKEYDISABLE_TZ_STICKY_BIT_VAL, key_invisible, KEY_INVISIBLE, KEY_VISIBLE));
|
||||
|
||||
/* Write-lock PMC_SECURE_SCRATCH21. */
|
||||
reg::ReadWrite(PMC + APBDEV_PMC_SEC_DISABLE2, PMC_REG_BITS_ENUM(SEC_DISABLE2_WRITE21, ON));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,555 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::fuse {
|
||||
|
||||
struct FuseRegisters {
|
||||
u32 FUSE_FUSECTRL;
|
||||
u32 FUSE_FUSEADDR;
|
||||
u32 FUSE_FUSERDATA;
|
||||
u32 FUSE_FUSEWDATA;
|
||||
u32 FUSE_FUSETIME_RD1;
|
||||
u32 FUSE_FUSETIME_RD2;
|
||||
u32 FUSE_FUSETIME_PGM1;
|
||||
u32 FUSE_FUSETIME_PGM2;
|
||||
u32 FUSE_PRIV2INTFC_START;
|
||||
u32 FUSE_FUSEBYPASS;
|
||||
u32 FUSE_PRIVATEKEYDISABLE;
|
||||
u32 FUSE_DISABLEREGPROGRAM;
|
||||
u32 FUSE_WRITE_ACCESS_SW;
|
||||
u32 FUSE_PWR_GOOD_SW;
|
||||
u32 _0x38;
|
||||
u32 FUSE_PRIV2RESHIFT;
|
||||
u32 _0x40[0x3];
|
||||
u32 FUSE_FUSETIME_RD3;
|
||||
u32 _0x50[0xC];
|
||||
u32 FUSE_PRIVATE_KEY0_NONZERO;
|
||||
u32 FUSE_PRIVATE_KEY1_NONZERO;
|
||||
u32 FUSE_PRIVATE_KEY2_NONZERO;
|
||||
u32 FUSE_PRIVATE_KEY3_NONZERO;
|
||||
u32 FUSE_PRIVATE_KEY4_NONZERO;
|
||||
u32 _0x94;
|
||||
};
|
||||
static_assert(util::is_pod<FuseRegisters>::value);
|
||||
static_assert(sizeof(FuseRegisters) == 0x98);
|
||||
|
||||
struct FuseChipRegistersCommon {
|
||||
u32 _0x98[0x1A];
|
||||
u32 FUSE_PRODUCTION_MODE;
|
||||
u32 FUSE_JTAG_SECUREID_VALID;
|
||||
u32 FUSE_ODM_LOCK;
|
||||
u32 FUSE_OPT_OPENGL_EN;
|
||||
u32 FUSE_SKU_INFO;
|
||||
u32 FUSE_CPU_SPEEDO_0_CALIB;
|
||||
u32 FUSE_CPU_IDDQ_CALIB;
|
||||
u32 _0x11C;
|
||||
u32 _0x120;
|
||||
u32 _0x124;
|
||||
u32 FUSE_OPT_FT_REV;
|
||||
u32 FUSE_CPU_SPEEDO_1_CALIB;
|
||||
u32 FUSE_CPU_SPEEDO_2_CALIB;
|
||||
u32 FUSE_SOC_SPEEDO_0_CALIB;
|
||||
u32 FUSE_SOC_SPEEDO_1_CALIB;
|
||||
u32 FUSE_SOC_SPEEDO_2_CALIB;
|
||||
u32 FUSE_SOC_IDDQ_CALIB;
|
||||
u32 _0x144;
|
||||
u32 FUSE_FA;
|
||||
u32 FUSE_RESERVED_PRODUCTION;
|
||||
u32 FUSE_HDMI_LANE0_CALIB;
|
||||
u32 FUSE_HDMI_LANE1_CALIB;
|
||||
u32 FUSE_HDMI_LANE2_CALIB;
|
||||
u32 FUSE_HDMI_LANE3_CALIB;
|
||||
u32 FUSE_ENCRYPTION_RATE;
|
||||
u32 FUSE_PUBLIC_KEY[0x8];
|
||||
u32 FUSE_TSENSOR1_CALIB;
|
||||
u32 FUSE_TSENSOR2_CALIB;
|
||||
u32 _0x18C;
|
||||
u32 FUSE_OPT_CP_REV;
|
||||
u32 FUSE_OPT_PFG;
|
||||
u32 FUSE_TSENSOR0_CALIB;
|
||||
u32 FUSE_FIRST_BOOTROM_PATCH_SIZE;
|
||||
u32 FUSE_SECURITY_MODE;
|
||||
u32 FUSE_PRIVATE_KEY[0x5];
|
||||
u32 FUSE_ARM_JTAG_DIS;
|
||||
u32 FUSE_BOOT_DEVICE_INFO;
|
||||
u32 FUSE_RESERVED_SW;
|
||||
u32 FUSE_OPT_VP9_DISABLE;
|
||||
u32 FUSE_RESERVED_ODM_0[8 - 0];
|
||||
u32 FUSE_OBS_DIS;
|
||||
u32 _0x1EC;
|
||||
u32 FUSE_USB_CALIB;
|
||||
u32 FUSE_SKU_DIRECT_CONFIG;
|
||||
u32 FUSE_KFUSE_PRIVKEY_CTRL;
|
||||
u32 FUSE_PACKAGE_INFO;
|
||||
u32 FUSE_OPT_VENDOR_CODE;
|
||||
u32 FUSE_OPT_FAB_CODE;
|
||||
u32 FUSE_OPT_LOT_CODE_0;
|
||||
u32 FUSE_OPT_LOT_CODE_1;
|
||||
u32 FUSE_OPT_WAFER_ID;
|
||||
u32 FUSE_OPT_X_COORDINATE;
|
||||
u32 FUSE_OPT_Y_COORDINATE;
|
||||
u32 FUSE_OPT_SEC_DEBUG_EN;
|
||||
u32 FUSE_OPT_OPS_RESERVED;
|
||||
u32 _0x224;
|
||||
u32 FUSE_GPU_IDDQ_CALIB;
|
||||
u32 FUSE_TSENSOR3_CALIB;
|
||||
u32 _0x234;
|
||||
u32 _0x238;
|
||||
u32 _0x23C;
|
||||
u32 _0x240;
|
||||
u32 _0x244;
|
||||
u32 FUSE_OPT_SAMPLE_TYPE;
|
||||
u32 FUSE_OPT_SUBREVISION;
|
||||
u32 FUSE_OPT_SW_RESERVED_0;
|
||||
u32 FUSE_OPT_SW_RESERVED_1;
|
||||
u32 FUSE_TSENSOR4_CALIB;
|
||||
u32 FUSE_TSENSOR5_CALIB;
|
||||
u32 FUSE_TSENSOR6_CALIB;
|
||||
u32 FUSE_TSENSOR7_CALIB;
|
||||
u32 FUSE_OPT_PRIV_SEC_EN;
|
||||
u32 _0x268;
|
||||
u32 _0x26C;
|
||||
u32 _0x270;
|
||||
u32 _0x274;
|
||||
u32 _0x278;
|
||||
u32 FUSE_FUSE2TSEC_DEBUG_DISABLE;
|
||||
u32 FUSE_TSENSOR_COMMON;
|
||||
u32 FUSE_OPT_CP_BIN;
|
||||
u32 FUSE_OPT_GPU_DISABLE;
|
||||
u32 FUSE_OPT_FT_BIN;
|
||||
u32 FUSE_OPT_DONE_MAP;
|
||||
u32 _0x294;
|
||||
u32 FUSE_APB2JTAG_DISABLE;
|
||||
u32 FUSE_ODM_INFO;
|
||||
u32 _0x2A0;
|
||||
u32 _0x2A4;
|
||||
u32 FUSE_ARM_CRYPT_DE_FEATURE;
|
||||
u32 _0x2AC;
|
||||
u32 _0x2B0;
|
||||
u32 _0x2B4;
|
||||
u32 _0x2B8;
|
||||
u32 _0x2BC;
|
||||
u32 FUSE_WOA_SKU_FLAG;
|
||||
u32 FUSE_ECO_RESERVE_1;
|
||||
u32 FUSE_GCPLEX_CONFIG_FUSE;
|
||||
u32 FUSE_PRODUCTION_MONTH;
|
||||
u32 FUSE_RAM_REPAIR_INDICATOR;
|
||||
u32 FUSE_TSENSOR9_CALIB;
|
||||
u32 _0x2D8;
|
||||
u32 FUSE_VMIN_CALIBRATION;
|
||||
u32 FUSE_AGING_SENSOR_CALIBRATION;
|
||||
u32 FUSE_DEBUG_AUTHENTICATION;
|
||||
u32 FUSE_SECURE_PROVISION_INDEX;
|
||||
u32 FUSE_SECURE_PROVISION_INFO;
|
||||
u32 FUSE_OPT_GPU_DISABLE_CP1;
|
||||
u32 FUSE_SPARE_ENDIS;
|
||||
u32 FUSE_ECO_RESERVE_0;
|
||||
u32 _0x2FC;
|
||||
u32 _0x300;
|
||||
u32 FUSE_RESERVED_CALIB0;
|
||||
u32 FUSE_RESERVED_CALIB1;
|
||||
u32 FUSE_OPT_GPU_TPC0_DISABLE;
|
||||
u32 FUSE_OPT_GPU_TPC0_DISABLE_CP1;
|
||||
u32 FUSE_OPT_CPU_DISABLE;
|
||||
u32 FUSE_OPT_CPU_DISABLE_CP1;
|
||||
u32 FUSE_TSENSOR10_CALIB;
|
||||
u32 FUSE_TSENSOR10_CALIB_AUX;
|
||||
u32 _0x324;
|
||||
u32 _0x328;
|
||||
u32 _0x32C;
|
||||
u32 _0x330;
|
||||
u32 _0x334;
|
||||
u32 FUSE_OPT_GPU_TPC0_DISABLE_CP2;
|
||||
u32 FUSE_OPT_GPU_TPC1_DISABLE;
|
||||
u32 FUSE_OPT_GPU_TPC1_DISABLE_CP1;
|
||||
u32 FUSE_OPT_GPU_TPC1_DISABLE_CP2;
|
||||
u32 FUSE_OPT_CPU_DISABLE_CP2;
|
||||
u32 FUSE_OPT_GPU_DISABLE_CP2;
|
||||
u32 FUSE_USB_CALIB_EXT;
|
||||
u32 FUSE_RESERVED_FIELD;
|
||||
u32 _0x358;
|
||||
u32 _0x35C;
|
||||
u32 _0x360;
|
||||
u32 _0x364;
|
||||
u32 _0x368;
|
||||
u32 _0x36C;
|
||||
u32 _0x370;
|
||||
u32 _0x374;
|
||||
u32 _0x378;
|
||||
u32 FUSE_SPARE_REALIGNMENT_REG;
|
||||
u32 FUSE_SPARE_BIT[0x20];
|
||||
};
|
||||
static_assert(util::is_pod<FuseChipRegistersCommon>::value);
|
||||
static_assert(sizeof(FuseChipRegistersCommon) == 0x400 - 0x98);
|
||||
|
||||
struct FuseChipRegistersErista {
|
||||
u32 _0x98[0x1A];
|
||||
u32 FUSE_PRODUCTION_MODE;
|
||||
u32 FUSE_JTAG_SECUREID_VALID;
|
||||
u32 FUSE_ODM_LOCK;
|
||||
u32 FUSE_OPT_OPENGL_EN;
|
||||
u32 FUSE_SKU_INFO;
|
||||
u32 FUSE_CPU_SPEEDO_0_CALIB;
|
||||
u32 FUSE_CPU_IDDQ_CALIB;
|
||||
u32 FUSE_DAC_CRT_CALIB;
|
||||
u32 FUSE_DAC_HDTV_CALIB;
|
||||
u32 FUSE_DAC_SDTV_CALIB;
|
||||
u32 FUSE_OPT_FT_REV;
|
||||
u32 FUSE_CPU_SPEEDO_1_CALIB;
|
||||
u32 FUSE_CPU_SPEEDO_2_CALIB;
|
||||
u32 FUSE_SOC_SPEEDO_0_CALIB;
|
||||
u32 FUSE_SOC_SPEEDO_1_CALIB;
|
||||
u32 FUSE_SOC_SPEEDO_2_CALIB;
|
||||
u32 FUSE_SOC_IDDQ_CALIB;
|
||||
u32 FUSE_RESERVED_PRODUCTION_WP;
|
||||
u32 FUSE_FA;
|
||||
u32 FUSE_RESERVED_PRODUCTION;
|
||||
u32 FUSE_HDMI_LANE0_CALIB;
|
||||
u32 FUSE_HDMI_LANE1_CALIB;
|
||||
u32 FUSE_HDMI_LANE2_CALIB;
|
||||
u32 FUSE_HDMI_LANE3_CALIB;
|
||||
u32 FUSE_ENCRYPTION_RATE;
|
||||
u32 FUSE_PUBLIC_KEY[0x8];
|
||||
u32 FUSE_TSENSOR1_CALIB;
|
||||
u32 FUSE_TSENSOR2_CALIB;
|
||||
u32 FUSE_VSENSOR_CALIB;
|
||||
u32 FUSE_OPT_CP_REV;
|
||||
u32 FUSE_OPT_PFG;
|
||||
u32 FUSE_TSENSOR0_CALIB;
|
||||
u32 FUSE_FIRST_BOOTROM_PATCH_SIZE;
|
||||
u32 FUSE_SECURITY_MODE;
|
||||
u32 FUSE_PRIVATE_KEY[0x5];
|
||||
u32 FUSE_ARM_JTAG_DIS;
|
||||
u32 FUSE_BOOT_DEVICE_INFO;
|
||||
u32 FUSE_RESERVED_SW;
|
||||
u32 FUSE_OPT_VP9_DISABLE;
|
||||
u32 FUSE_RESERVED_ODM_0[8 - 0];
|
||||
u32 FUSE_OBS_DIS;
|
||||
u32 FUSE_NOR_INFO;
|
||||
u32 FUSE_USB_CALIB;
|
||||
u32 FUSE_SKU_DIRECT_CONFIG;
|
||||
u32 FUSE_KFUSE_PRIVKEY_CTRL;
|
||||
u32 FUSE_PACKAGE_INFO;
|
||||
u32 FUSE_OPT_VENDOR_CODE;
|
||||
u32 FUSE_OPT_FAB_CODE;
|
||||
u32 FUSE_OPT_LOT_CODE_0;
|
||||
u32 FUSE_OPT_LOT_CODE_1;
|
||||
u32 FUSE_OPT_WAFER_ID;
|
||||
u32 FUSE_OPT_X_COORDINATE;
|
||||
u32 FUSE_OPT_Y_COORDINATE;
|
||||
u32 FUSE_OPT_SEC_DEBUG_EN;
|
||||
u32 FUSE_OPT_OPS_RESERVED;
|
||||
u32 FUSE_SATA_CALIB;
|
||||
u32 FUSE_GPU_IDDQ_CALIB;
|
||||
u32 FUSE_TSENSOR3_CALIB;
|
||||
u32 FUSE_SKU_BOND_OUT_L;
|
||||
u32 FUSE_SKU_BOND_OUT_H;
|
||||
u32 FUSE_SKU_BOND_OUT_U;
|
||||
u32 FUSE_SKU_BOND_OUT_V;
|
||||
u32 FUSE_SKU_BOND_OUT_W;
|
||||
u32 FUSE_OPT_SAMPLE_TYPE;
|
||||
u32 FUSE_OPT_SUBREVISION;
|
||||
u32 FUSE_OPT_SW_RESERVED_0;
|
||||
u32 FUSE_OPT_SW_RESERVED_1;
|
||||
u32 FUSE_TSENSOR4_CALIB;
|
||||
u32 FUSE_TSENSOR5_CALIB;
|
||||
u32 FUSE_TSENSOR6_CALIB;
|
||||
u32 FUSE_TSENSOR7_CALIB;
|
||||
u32 FUSE_OPT_PRIV_SEC_EN;
|
||||
u32 FUSE_PKC_DISABLE;
|
||||
u32 _0x26C;
|
||||
u32 _0x270;
|
||||
u32 _0x274;
|
||||
u32 _0x278;
|
||||
u32 FUSE_FUSE2TSEC_DEBUG_DISABLE;
|
||||
u32 FUSE_TSENSOR_COMMON;
|
||||
u32 FUSE_OPT_CP_BIN;
|
||||
u32 FUSE_OPT_GPU_DISABLE;
|
||||
u32 FUSE_OPT_FT_BIN;
|
||||
u32 FUSE_OPT_DONE_MAP;
|
||||
u32 _0x294;
|
||||
u32 FUSE_APB2JTAG_DISABLE;
|
||||
u32 FUSE_ODM_INFO;
|
||||
u32 _0x2A0;
|
||||
u32 _0x2A4;
|
||||
u32 FUSE_ARM_CRYPT_DE_FEATURE;
|
||||
u32 _0x2AC;
|
||||
u32 _0x2B0;
|
||||
u32 _0x2B4;
|
||||
u32 _0x2B8;
|
||||
u32 _0x2BC;
|
||||
u32 FUSE_WOA_SKU_FLAG;
|
||||
u32 FUSE_ECO_RESERVE_1;
|
||||
u32 FUSE_GCPLEX_CONFIG_FUSE;
|
||||
u32 FUSE_PRODUCTION_MONTH;
|
||||
u32 FUSE_RAM_REPAIR_INDICATOR;
|
||||
u32 FUSE_TSENSOR9_CALIB;
|
||||
u32 _0x2D8;
|
||||
u32 FUSE_VMIN_CALIBRATION;
|
||||
u32 FUSE_AGING_SENSOR_CALIBRATION;
|
||||
u32 FUSE_DEBUG_AUTHENTICATION;
|
||||
u32 FUSE_SECURE_PROVISION_INDEX;
|
||||
u32 FUSE_SECURE_PROVISION_INFO;
|
||||
u32 FUSE_OPT_GPU_DISABLE_CP1;
|
||||
u32 FUSE_SPARE_ENDIS;
|
||||
u32 FUSE_ECO_RESERVE_0;
|
||||
u32 _0x2FC;
|
||||
u32 _0x300;
|
||||
u32 FUSE_RESERVED_CALIB0;
|
||||
u32 FUSE_RESERVED_CALIB1;
|
||||
u32 FUSE_OPT_GPU_TPC0_DISABLE;
|
||||
u32 FUSE_OPT_GPU_TPC0_DISABLE_CP1;
|
||||
u32 FUSE_OPT_CPU_DISABLE;
|
||||
u32 FUSE_OPT_CPU_DISABLE_CP1;
|
||||
u32 FUSE_TSENSOR10_CALIB;
|
||||
u32 FUSE_TSENSOR10_CALIB_AUX;
|
||||
u32 FUSE_OPT_RAM_SVOP_DP;
|
||||
u32 FUSE_OPT_RAM_SVOP_PDP;
|
||||
u32 FUSE_OPT_RAM_SVOP_REG;
|
||||
u32 FUSE_OPT_RAM_SVOP_SP;
|
||||
u32 FUSE_OPT_RAM_SVOP_SMPDP;
|
||||
u32 FUSE_OPT_GPU_TPC0_DISABLE_CP2;
|
||||
u32 FUSE_OPT_GPU_TPC1_DISABLE;
|
||||
u32 FUSE_OPT_GPU_TPC1_DISABLE_CP1;
|
||||
u32 FUSE_OPT_GPU_TPC1_DISABLE_CP2;
|
||||
u32 FUSE_OPT_CPU_DISABLE_CP2;
|
||||
u32 FUSE_OPT_GPU_DISABLE_CP2;
|
||||
u32 FUSE_USB_CALIB_EXT;
|
||||
u32 FUSE_RESERVED_FIELD;
|
||||
u32 FUSE_OPT_ECC_EN;
|
||||
u32 _0x35C;
|
||||
u32 _0x360;
|
||||
u32 _0x364;
|
||||
u32 _0x368;
|
||||
u32 _0x36C;
|
||||
u32 _0x370;
|
||||
u32 _0x374;
|
||||
u32 _0x378;
|
||||
u32 FUSE_SPARE_REALIGNMENT_REG;
|
||||
u32 FUSE_SPARE_BIT[0x20];
|
||||
};
|
||||
static_assert(util::is_pod<FuseChipRegistersErista>::value);
|
||||
static_assert(sizeof(FuseChipRegistersErista) == 0x400 - 0x98);
|
||||
|
||||
struct FuseChipRegistersMariko {
|
||||
u32 FUSE_RESERVED_ODM_8[22 - 8];
|
||||
u32 FUSE_KEK[4];
|
||||
u32 FUSE_BEK[4];
|
||||
u32 _0xF0[4];
|
||||
u32 FUSE_PRODUCTION_MODE;
|
||||
u32 FUSE_JTAG_SECUREID_VALID;
|
||||
u32 FUSE_ODM_LOCK;
|
||||
u32 FUSE_OPT_OPENGL_EN;
|
||||
u32 FUSE_SKU_INFO;
|
||||
u32 FUSE_CPU_SPEEDO_0_CALIB;
|
||||
u32 FUSE_CPU_IDDQ_CALIB;
|
||||
u32 FUSE_RESERVED_ODM_22[25 - 22];
|
||||
u32 FUSE_OPT_FT_REV;
|
||||
u32 FUSE_CPU_SPEEDO_1_CALIB;
|
||||
u32 FUSE_CPU_SPEEDO_2_CALIB;
|
||||
u32 FUSE_SOC_SPEEDO_0_CALIB;
|
||||
u32 FUSE_SOC_SPEEDO_1_CALIB;
|
||||
u32 FUSE_SOC_SPEEDO_2_CALIB;
|
||||
u32 FUSE_SOC_IDDQ_CALIB;
|
||||
u32 FUSE_RESERVED_ODM_25[26 - 25];
|
||||
u32 FUSE_FA;
|
||||
u32 FUSE_RESERVED_PRODUCTION;
|
||||
u32 FUSE_HDMI_LANE0_CALIB;
|
||||
u32 FUSE_HDMI_LANE1_CALIB;
|
||||
u32 FUSE_HDMI_LANE2_CALIB;
|
||||
u32 FUSE_HDMI_LANE3_CALIB;
|
||||
u32 FUSE_ENCRYPTION_RATE;
|
||||
u32 FUSE_PUBLIC_KEY[0x8];
|
||||
u32 FUSE_TSENSOR1_CALIB;
|
||||
u32 FUSE_TSENSOR2_CALIB;
|
||||
u32 FUSE_OPT_SECURE_SCC_DIS;
|
||||
u32 FUSE_OPT_CP_REV;
|
||||
u32 FUSE_OPT_PFG;
|
||||
u32 FUSE_TSENSOR0_CALIB;
|
||||
u32 FUSE_FIRST_BOOTROM_PATCH_SIZE;
|
||||
u32 FUSE_SECURITY_MODE;
|
||||
u32 FUSE_PRIVATE_KEY[0x5];
|
||||
u32 FUSE_ARM_JTAG_DIS;
|
||||
u32 FUSE_BOOT_DEVICE_INFO;
|
||||
u32 FUSE_RESERVED_SW;
|
||||
u32 FUSE_OPT_VP9_DISABLE;
|
||||
u32 FUSE_RESERVED_ODM_0[8 - 0];
|
||||
u32 FUSE_OBS_DIS;
|
||||
u32 _0x1EC;
|
||||
u32 FUSE_USB_CALIB;
|
||||
u32 FUSE_SKU_DIRECT_CONFIG;
|
||||
u32 FUSE_KFUSE_PRIVKEY_CTRL;
|
||||
u32 FUSE_PACKAGE_INFO;
|
||||
u32 FUSE_OPT_VENDOR_CODE;
|
||||
u32 FUSE_OPT_FAB_CODE;
|
||||
u32 FUSE_OPT_LOT_CODE_0;
|
||||
u32 FUSE_OPT_LOT_CODE_1;
|
||||
u32 FUSE_OPT_WAFER_ID;
|
||||
u32 FUSE_OPT_X_COORDINATE;
|
||||
u32 FUSE_OPT_Y_COORDINATE;
|
||||
u32 FUSE_OPT_SEC_DEBUG_EN;
|
||||
u32 FUSE_OPT_OPS_RESERVED;
|
||||
u32 _0x224;
|
||||
u32 FUSE_GPU_IDDQ_CALIB;
|
||||
u32 FUSE_TSENSOR3_CALIB;
|
||||
u32 FUSE_CLOCK_BONDOUT0;
|
||||
u32 FUSE_CLOCK_BONDOUT1;
|
||||
u32 FUSE_RESERVED_ODM_26[29 - 26];
|
||||
u32 FUSE_OPT_SAMPLE_TYPE;
|
||||
u32 FUSE_OPT_SUBREVISION;
|
||||
u32 FUSE_OPT_SW_RESERVED_0;
|
||||
u32 FUSE_OPT_SW_RESERVED_1;
|
||||
u32 FUSE_TSENSOR4_CALIB;
|
||||
u32 FUSE_TSENSOR5_CALIB;
|
||||
u32 FUSE_TSENSOR6_CALIB;
|
||||
u32 FUSE_TSENSOR7_CALIB;
|
||||
u32 FUSE_OPT_PRIV_SEC_EN;
|
||||
u32 FUSE_BOOT_SECURITY_INFO;
|
||||
u32 _0x26C;
|
||||
u32 _0x270;
|
||||
u32 _0x274;
|
||||
u32 _0x278;
|
||||
u32 FUSE_FUSE2TSEC_DEBUG_DISABLE;
|
||||
u32 FUSE_TSENSOR_COMMON;
|
||||
u32 FUSE_OPT_CP_BIN;
|
||||
u32 FUSE_OPT_GPU_DISABLE;
|
||||
u32 FUSE_OPT_FT_BIN;
|
||||
u32 FUSE_OPT_DONE_MAP;
|
||||
u32 FUSE_RESERVED_ODM_29[30 - 29];
|
||||
u32 FUSE_APB2JTAG_DISABLE;
|
||||
u32 FUSE_ODM_INFO;
|
||||
u32 _0x2A0;
|
||||
u32 _0x2A4;
|
||||
u32 FUSE_ARM_CRYPT_DE_FEATURE;
|
||||
u32 _0x2AC;
|
||||
u32 _0x2B0;
|
||||
u32 _0x2B4;
|
||||
u32 _0x2B8;
|
||||
u32 _0x2BC;
|
||||
u32 FUSE_WOA_SKU_FLAG;
|
||||
u32 FUSE_ECO_RESERVE_1;
|
||||
u32 FUSE_GCPLEX_CONFIG_FUSE;
|
||||
u32 FUSE_PRODUCTION_MONTH;
|
||||
u32 FUSE_RAM_REPAIR_INDICATOR;
|
||||
u32 FUSE_TSENSOR9_CALIB;
|
||||
u32 _0x2D8;
|
||||
u32 FUSE_VMIN_CALIBRATION;
|
||||
u32 FUSE_AGING_SENSOR_CALIBRATION;
|
||||
u32 FUSE_DEBUG_AUTHENTICATION;
|
||||
u32 FUSE_SECURE_PROVISION_INDEX;
|
||||
u32 FUSE_SECURE_PROVISION_INFO;
|
||||
u32 FUSE_OPT_GPU_DISABLE_CP1;
|
||||
u32 FUSE_SPARE_ENDIS;
|
||||
u32 FUSE_ECO_RESERVE_0;
|
||||
u32 _0x2FC;
|
||||
u32 _0x300;
|
||||
u32 FUSE_RESERVED_CALIB0;
|
||||
u32 FUSE_RESERVED_CALIB1;
|
||||
u32 FUSE_OPT_GPU_TPC0_DISABLE;
|
||||
u32 FUSE_OPT_GPU_TPC0_DISABLE_CP1;
|
||||
u32 FUSE_OPT_CPU_DISABLE;
|
||||
u32 FUSE_OPT_CPU_DISABLE_CP1;
|
||||
u32 FUSE_TSENSOR10_CALIB;
|
||||
u32 FUSE_TSENSOR10_CALIB_AUX;
|
||||
u32 _0x324;
|
||||
u32 _0x328;
|
||||
u32 _0x32C;
|
||||
u32 _0x330;
|
||||
u32 _0x334;
|
||||
u32 FUSE_OPT_GPU_TPC0_DISABLE_CP2;
|
||||
u32 FUSE_OPT_GPU_TPC1_DISABLE;
|
||||
u32 FUSE_OPT_GPU_TPC1_DISABLE_CP1;
|
||||
u32 FUSE_OPT_GPU_TPC1_DISABLE_CP2;
|
||||
u32 FUSE_OPT_CPU_DISABLE_CP2;
|
||||
u32 FUSE_OPT_GPU_DISABLE_CP2;
|
||||
u32 FUSE_USB_CALIB_EXT;
|
||||
u32 FUSE_RESERVED_FIELD;
|
||||
u32 _0x358;
|
||||
u32 _0x35C;
|
||||
u32 _0x360;
|
||||
u32 _0x364;
|
||||
u32 _0x368;
|
||||
u32 _0x36C;
|
||||
u32 _0x370;
|
||||
u32 _0x374;
|
||||
u32 _0x378;
|
||||
u32 FUSE_SPARE_REALIGNMENT_REG;
|
||||
u32 FUSE_SPARE_BIT[0x20];
|
||||
};
|
||||
static_assert(util::is_pod<FuseChipRegistersMariko>::value);
|
||||
static_assert(sizeof(FuseChipRegistersMariko) == 0x400 - 0x98);
|
||||
|
||||
struct FuseRegisterRegion {
|
||||
FuseRegisters fuse;
|
||||
union {
|
||||
FuseChipRegistersCommon chip_common;
|
||||
FuseChipRegistersErista chip_erista;
|
||||
FuseChipRegistersMariko chip_mariko;
|
||||
};
|
||||
};
|
||||
static_assert(util::is_pod<FuseRegisterRegion>::value);
|
||||
static_assert(sizeof(FuseRegisterRegion) == secmon::MemoryRegionPhysicalDeviceFuses.GetSize());
|
||||
|
||||
#define FUSE_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (FUSE, NAME)
|
||||
#define FUSE_REG_BITS_VALUE(NAME, VALUE) REG_NAMED_BITS_VALUE (FUSE, NAME, VALUE)
|
||||
#define FUSE_REG_BITS_ENUM(NAME, ENUM) REG_NAMED_BITS_ENUM (FUSE, NAME, ENUM)
|
||||
#define FUSE_REG_BITS_ENUM_SEL(NAME, __COND__, TRUE_ENUM, FALSE_ENUM) REG_NAMED_BITS_ENUM_SEL(FUSE, NAME, __COND__, TRUE_ENUM, FALSE_ENUM)
|
||||
|
||||
#define DEFINE_FUSE_REG(NAME, __OFFSET__, __WIDTH__) REG_DEFINE_NAMED_REG (FUSE, NAME, __OFFSET__, __WIDTH__)
|
||||
#define DEFINE_FUSE_REG_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE) REG_DEFINE_NAMED_BIT_ENUM (FUSE, NAME, __OFFSET__, ZERO, ONE)
|
||||
#define DEFINE_FUSE_REG_TWO_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE) REG_DEFINE_NAMED_TWO_BIT_ENUM (FUSE, NAME, __OFFSET__, ZERO, ONE, TWO, THREE)
|
||||
#define DEFINE_FUSE_REG_THREE_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) REG_DEFINE_NAMED_THREE_BIT_ENUM(FUSE, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN)
|
||||
#define DEFINE_FUSE_REG_FOUR_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) REG_DEFINE_NAMED_FOUR_BIT_ENUM (FUSE, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN)
|
||||
|
||||
DEFINE_FUSE_REG_TWO_BIT_ENUM(FUSECTRL_CMD, 0, IDLE, READ, WRITE, SENSE_CTRL);
|
||||
|
||||
DEFINE_FUSE_REG(FUSECTRL_STATE, 16, 5);
|
||||
|
||||
enum FUSE_FUSECTRL_STATE {
|
||||
FUSE_FUSECTRL_STATE_RESET = 0,
|
||||
FUSE_FUSECTRL_STATE_POST_RESET = 1,
|
||||
FUSE_FUSECTRL_STATE_LOAD_ROW0 = 2,
|
||||
FUSE_FUSECTRL_STATE_LOAD_ROW1 = 3,
|
||||
FUSE_FUSECTRL_STATE_IDLE = 4,
|
||||
FUSE_FUSECTRL_STATE_READ_SETUP = 5,
|
||||
FUSE_FUSECTRL_STATE_READ_STROBE = 6,
|
||||
FUSE_FUSECTRL_STATE_SAMPLE_FUSES = 7,
|
||||
FUSE_FUSECTRL_STATE_READ_HOLD = 8,
|
||||
FUSE_FUSECTRL_STATE_FUSE_SRC_SETUP = 9,
|
||||
FUSE_FUSECTRL_STATE_WRITE_SETUP = 10,
|
||||
FUSE_FUSECTRL_STATE_WRITE_ADDR_SETUP = 11,
|
||||
FUSE_FUSECTRL_STATE_WRITE_PROGRAM = 12,
|
||||
FUSE_FUSECTRL_STATE_WRITE_ADDR_HOLD = 13,
|
||||
FUSE_FUSECTRL_STATE_FUSE_SRC_HOLD = 14,
|
||||
FUSE_FUSECTRL_STATE_LOAD_RIR = 15,
|
||||
FUSE_FUSECTRL_STATE_READ_BEFORE_WRITE_SETUP = 16,
|
||||
FUSE_FUSECTRL_STATE_READ_DEASSERT_PD = 17,
|
||||
};
|
||||
|
||||
DEFINE_FUSE_REG_BIT_ENUM(PRIVATEKEYDISABLE_TZ_STICKY_BIT_VAL, 4, KEY_VISIBLE, KEY_INVISIBLE);
|
||||
DEFINE_FUSE_REG_BIT_ENUM(PRIVATEKEYDISABLE_PRIVATEKEYDISABLE_VAL_KEY, 0, VISIBLE, INVISIBLE);
|
||||
|
||||
DEFINE_FUSE_REG_BIT_ENUM(FUSEBYPASS_VAL, 0, DISABLE, ENABLE);
|
||||
|
||||
DEFINE_FUSE_REG_BIT_ENUM(DISABLEREGPROGRAM_VAL, 0, DISABLE, ENABLE);
|
||||
|
||||
DEFINE_FUSE_REG_BIT_ENUM(WRITE_ACCESS_SW_CTRL, 0, READWRITE, READONLY);
|
||||
DEFINE_FUSE_REG_BIT_ENUM(WRITE_ACCESS_SW_STATUS, 16, NOWRITE, WRITE);
|
||||
|
||||
DEFINE_FUSE_REG_BIT_ENUM(SECURITY_MODE_SECURITY_MODE, 0, DISABLED, ENABLED);
|
||||
|
||||
}
|
||||
@@ -1,225 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::gic {
|
||||
|
||||
namespace {
|
||||
|
||||
struct GicDistributor {
|
||||
u32 ctlr;
|
||||
u32 typer;
|
||||
u32 iidr;
|
||||
u32 reserved_0x0c;
|
||||
u32 statusr;
|
||||
u32 reserved_0x14[3];
|
||||
u32 impldef_0x20[8];
|
||||
u32 setspi_nsr;
|
||||
u32 reserved_0x44;
|
||||
u32 clrspi_nsr;
|
||||
u32 reserved_0x4c;
|
||||
u32 setspi_sr;
|
||||
u32 reserved_0x54;
|
||||
u32 clrspi_sr;
|
||||
u32 reserved_0x5c[9];
|
||||
u32 igroupr[32];
|
||||
u32 isenabler[32];
|
||||
u32 icenabler[32];
|
||||
u32 ispendr[32];
|
||||
u32 icpendr[32];
|
||||
u32 isactiver[32];
|
||||
u32 icactiver[32];
|
||||
union {
|
||||
u8 bytes[1020];
|
||||
u32 words[255];
|
||||
} ipriorityr;
|
||||
u32 _0x7fc;
|
||||
union {
|
||||
u8 bytes[1020];
|
||||
u32 words[255];
|
||||
} itargetsr;
|
||||
u32 _0xbfc;
|
||||
u32 icfgr[64];
|
||||
u32 igrpmodr[32];
|
||||
u32 _0xd80[32];
|
||||
u32 nsacr[64];
|
||||
u32 sgir;
|
||||
u32 _0xf04[3];
|
||||
u32 cpendsgir[4];
|
||||
u32 spendsgir[4];
|
||||
u32 reserved_0xf30[52];
|
||||
|
||||
static constexpr size_t SgirCpuTargetListShift = 16;
|
||||
|
||||
enum SgirTargetListFilter : u32 {
|
||||
SgirTargetListFilter_CpuTargetList = (0 << 24),
|
||||
SgirTargetListFilter_Others = (1 << 24),
|
||||
SgirTargetListFilter_Self = (2 << 24),
|
||||
SgirTargetListFilter_Reserved = (3 << 24),
|
||||
};
|
||||
};
|
||||
static_assert(util::is_pod<GicDistributor>::value);
|
||||
static_assert(sizeof(GicDistributor) == 0x1000);
|
||||
static_assert(sizeof(GicDistributor) == secmon::MemoryRegionPhysicalDeviceGicDistributor.GetSize());
|
||||
|
||||
struct GicCpuInterface {
|
||||
u32 ctlr;
|
||||
u32 pmr;
|
||||
u32 bpr;
|
||||
u32 iar;
|
||||
u32 eoir;
|
||||
u32 rpr;
|
||||
u32 hppir;
|
||||
u32 abpr;
|
||||
u32 aiar;
|
||||
u32 aeoir;
|
||||
u32 ahppir;
|
||||
u32 statusr;
|
||||
u32 reserved_30[4];
|
||||
u32 impldef_40[36];
|
||||
u32 apr[4];
|
||||
u32 nsapr[4];
|
||||
u32 reserved_f0[3];
|
||||
u32 iidr;
|
||||
u32 reserved_100[960];
|
||||
u32 dir;
|
||||
u32 _0x1004[1023];
|
||||
};
|
||||
static_assert(util::is_pod<GicCpuInterface>::value);
|
||||
static_assert(sizeof(GicCpuInterface) == 0x2000);
|
||||
static_assert(sizeof(GicCpuInterface) == secmon::MemoryRegionPhysicalDeviceGicCpuInterface.GetSize());
|
||||
|
||||
constexpr inline int InterruptWords = InterruptCount / BITSIZEOF(u32);
|
||||
constexpr inline int SpiIndex = BITSIZEOF(u32);
|
||||
|
||||
constinit uintptr_t g_distributor_address = secmon::MemoryRegionPhysicalDeviceGicDistributor.GetAddress();
|
||||
constinit uintptr_t g_cpu_interface_address = secmon::MemoryRegionPhysicalDeviceGicCpuInterface.GetAddress();
|
||||
|
||||
volatile GicDistributor *GetDistributor() {
|
||||
return reinterpret_cast<volatile GicDistributor *>(g_distributor_address);
|
||||
}
|
||||
|
||||
volatile GicCpuInterface *GetCpuInterface() {
|
||||
return reinterpret_cast<volatile GicCpuInterface *>(g_cpu_interface_address);
|
||||
}
|
||||
|
||||
void ReadWrite(uintptr_t address, int width, int i, u32 value) {
|
||||
/* This code will never be invoked with a negative interrupt id. */
|
||||
AMS_ASSUME(i >= 0);
|
||||
|
||||
const int scale = BITSIZEOF(u32) / width;
|
||||
const int word = i / scale;
|
||||
const int bit = (i % scale) * width;
|
||||
|
||||
const u32 mask = ((1u << width) - 1) << bit;
|
||||
|
||||
const uintptr_t reg_addr = address + sizeof(u32) * word;
|
||||
const u32 old = reg::Read(reg_addr) & ~mask;
|
||||
reg::Write(reg_addr, old | ((value << bit) & mask));
|
||||
}
|
||||
|
||||
void Write(uintptr_t address, int width, int i, u32 value) {
|
||||
/* This code will never be invoked with a negative interrupt id. */
|
||||
AMS_ASSUME(i >= 0);
|
||||
|
||||
const int scale = BITSIZEOF(u32) / width;
|
||||
const int word = i / scale;
|
||||
const int bit = (i % scale) * width;
|
||||
|
||||
reg::Write(address + sizeof(u32) * word, value << bit);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SetRegisterAddress(uintptr_t distributor_address, uintptr_t cpu_interface_address) {
|
||||
g_distributor_address = distributor_address;
|
||||
g_cpu_interface_address = cpu_interface_address;
|
||||
}
|
||||
|
||||
void InitializeCommon() {
|
||||
/* Get the gicd registers. */
|
||||
auto *gicd = GetDistributor();
|
||||
|
||||
/* Set IGROUPR for to be FFs. */
|
||||
for (int i = SpiIndex / BITSIZEOF(u32); i < InterruptWords; ++i) {
|
||||
gicd->igroupr[i] = 0xFFFFFFFFu;
|
||||
}
|
||||
|
||||
/* Set IPRIORITYR for spi interrupts to be 0x80. */
|
||||
for (int i = SpiIndex; i < InterruptCount; ++i) {
|
||||
gicd->ipriorityr.bytes[i] = 0x80;
|
||||
}
|
||||
|
||||
/* Enable group 0. */
|
||||
gicd->ctlr = 1;
|
||||
}
|
||||
|
||||
void InitializeCoreUnique() {
|
||||
/* Get the registers. */
|
||||
auto *gicd = GetDistributor();
|
||||
auto *gicc = GetCpuInterface();
|
||||
|
||||
/* Set IGROUPR0 to be FFs. */
|
||||
gicd->igroupr[0] = 0xFFFFFFFFu;
|
||||
|
||||
/* Set IPRIORITYR for core local interrupts to be 0x80. */
|
||||
for (int i = 0; i < SpiIndex; ++i) {
|
||||
gicd->ipriorityr.bytes[i] = 0x80;
|
||||
}
|
||||
|
||||
/* Enable group 0 as FIQs. */
|
||||
gicc->ctlr = 0x1D9;
|
||||
|
||||
/* Set PMR. */
|
||||
gicc->pmr = 0x80;
|
||||
|
||||
/* Set BPR. */
|
||||
gicc->bpr = 7;
|
||||
}
|
||||
|
||||
void SetPriority(int interrupt_id, int priority) {
|
||||
ReadWrite(g_distributor_address + AMS_OFFSETOF(GicDistributor, ipriorityr), BITSIZEOF(u8), interrupt_id, priority);
|
||||
}
|
||||
|
||||
void SetInterruptGroup(int interrupt_id, int group) {
|
||||
ReadWrite(g_distributor_address + AMS_OFFSETOF(GicDistributor, igroupr), 1, interrupt_id, group);
|
||||
}
|
||||
|
||||
void SetEnable(int interrupt_id, bool enable) {
|
||||
Write(g_distributor_address + AMS_OFFSETOF(GicDistributor, isenabler), 1, interrupt_id, enable);
|
||||
}
|
||||
|
||||
void SetSpiTargetCpu(int interrupt_id, u32 cpu_mask) {
|
||||
ReadWrite(g_distributor_address + AMS_OFFSETOF(GicDistributor, itargetsr), BITSIZEOF(u8), interrupt_id, cpu_mask);
|
||||
}
|
||||
|
||||
void SetSpiMode(int interrupt_id, InterruptMode mode) {
|
||||
ReadWrite(g_distributor_address + AMS_OFFSETOF(GicDistributor, icfgr), 2, interrupt_id, static_cast<u32>(mode) << 1);
|
||||
}
|
||||
|
||||
void SetPending(int interrupt_id) {
|
||||
Write(g_distributor_address + AMS_OFFSETOF(GicDistributor, ispendr), 1, interrupt_id, 1);
|
||||
}
|
||||
|
||||
int GetInterruptRequestId() {
|
||||
return reg::Read(GetCpuInterface()->iar);
|
||||
}
|
||||
|
||||
void SetEndOfInterrupt(int interrupt_id) {
|
||||
reg::Write(GetCpuInterface()->eoir, interrupt_id);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,253 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::hw::arch::arm {
|
||||
|
||||
#ifdef __BPMP__
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline uintptr_t AVP_CACHE = AVP_CACHE_ADDR(0);
|
||||
|
||||
ALWAYS_INLINE bool IsLargeBuffer(size_t size) {
|
||||
/* From TRM: For very large physical buffers or when the full cache needs to be cleared, */
|
||||
/* software should simply loop over all lines in all ways and run the *_LINE command on each of them. */
|
||||
return size >= DataCacheSize / 4;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE bool IsCacheEnabled() {
|
||||
return reg::HasValue(AVP_CACHE + AVP_CACHE_CONFIG, AVP_CACHE_REG_BITS_ENUM(CONFIG_ENABLE_CACHE, TRUE));
|
||||
}
|
||||
|
||||
void DoPhyCacheOperation(AVP_CACHE_MAINT_OPCODE op, uintptr_t addr) {
|
||||
/* Clear maintenance done. */
|
||||
reg::Write(AVP_CACHE + AVP_CACHE_INT_CLEAR, AVP_CACHE_REG_BITS_ENUM(INT_CLEAR_MAINTENANCE_DONE, TRUE));
|
||||
|
||||
/* Write maintenance address. */
|
||||
reg::Write(AVP_CACHE + AVP_CACHE_MAINT_0, addr);
|
||||
|
||||
/* Write maintenance request. */
|
||||
reg::Write(AVP_CACHE + AVP_CACHE_MAINT_2, AVP_CACHE_REG_BITS_VALUE(MAINT_2_WAY_BITMAP, 0x0),
|
||||
AVP_CACHE_REG_BITS_VALUE(MAINT_2_OPCODE, op));
|
||||
|
||||
/* Wait for maintenance to be done. */
|
||||
while (!reg::HasValue(AVP_CACHE + AVP_CACHE_INT_RAW_EVENT, AVP_CACHE_REG_BITS_ENUM(INT_RAW_EVENT_MAINTENANCE_DONE, TRUE))) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
/* Clear raw event. */
|
||||
reg::Write(AVP_CACHE + AVP_CACHE_INT_CLEAR, reg::Read(AVP_CACHE + AVP_CACHE_INT_RAW_EVENT));
|
||||
}
|
||||
|
||||
void DoEntireCacheOperation(AVP_CACHE_MAINT_OPCODE op) {
|
||||
/* Clear maintenance done. */
|
||||
reg::Write(AVP_CACHE + AVP_CACHE_INT_CLEAR, AVP_CACHE_REG_BITS_ENUM(INT_CLEAR_MAINTENANCE_DONE, TRUE));
|
||||
|
||||
/* Write maintenance request. */
|
||||
reg::Write(AVP_CACHE + AVP_CACHE_MAINT_2, AVP_CACHE_REG_BITS_VALUE(MAINT_2_WAY_BITMAP, 0xF),
|
||||
AVP_CACHE_REG_BITS_VALUE(MAINT_2_OPCODE, op));
|
||||
|
||||
/* Wait for maintenance to be done. */
|
||||
while (!reg::HasValue(AVP_CACHE + AVP_CACHE_INT_RAW_EVENT, AVP_CACHE_REG_BITS_ENUM(INT_RAW_EVENT_MAINTENANCE_DONE, TRUE))) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
/* Clear raw event. */
|
||||
reg::Write(AVP_CACHE + AVP_CACHE_INT_CLEAR, reg::Read(AVP_CACHE + AVP_CACHE_INT_RAW_EVENT));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define REQUIRE_CACHE_ENABLED() \
|
||||
do { \
|
||||
if (AMS_UNLIKELY(!IsCacheEnabled())) { \
|
||||
return; \
|
||||
} \
|
||||
} while (false) \
|
||||
|
||||
|
||||
#define REQUIRE_CACHE_DISABLED() \
|
||||
do { \
|
||||
if (AMS_UNLIKELY(IsCacheEnabled())) { \
|
||||
return; \
|
||||
} \
|
||||
} while (false) \
|
||||
|
||||
void InitializeDataCache() {
|
||||
REQUIRE_CACHE_DISABLED();
|
||||
|
||||
/* Issue init mmu command. */
|
||||
reg::Write(AVP_CACHE + AVP_CACHE_MMU_CMD, AVP_CACHE_REG_BITS_ENUM(MMU_CMD_CMD, INIT));
|
||||
|
||||
/* Set mmu fallback entry as RWX, uncached. */
|
||||
reg::Write(AVP_CACHE + AVP_CACHE_MMU_FALLBACK_ENTRY, AVP_CACHE_REG_BITS_ENUM(MMU_FALLBACK_ENTRY_WR_ENA, ENABLE),
|
||||
AVP_CACHE_REG_BITS_ENUM(MMU_FALLBACK_ENTRY_RD_ENA, ENABLE),
|
||||
AVP_CACHE_REG_BITS_ENUM(MMU_FALLBACK_ENTRY_EXE_ENA, ENABLE),
|
||||
AVP_CACHE_REG_BITS_ENUM(MMU_FALLBACK_ENTRY_CACHED, DISABLE));
|
||||
|
||||
/* Set mmu cfg. */
|
||||
reg::Write(AVP_CACHE + AVP_CACHE_MMU_CFG, AVP_CACHE_REG_BITS_ENUM(MMU_CFG_CLR_ABORT, NOP),
|
||||
AVP_CACHE_REG_BITS_ENUM(MMU_CFG_ABORT_MODE, STORE_LAST),
|
||||
AVP_CACHE_REG_BITS_ENUM(MMU_CFG_SEQ_CHECK_ALL_ENTRIES, DISABLE),
|
||||
AVP_CACHE_REG_BITS_ENUM(MMU_CFG_TLB_ENA, ENABLE),
|
||||
AVP_CACHE_REG_BITS_ENUM(MMU_CFG_SEQ_ENA, ENABLE),
|
||||
AVP_CACHE_REG_BITS_ENUM(MMU_CFG_BLOCK_MAIN_ENTRY_WR, DISABLE));
|
||||
|
||||
/* Initialize mmu entries. */
|
||||
{
|
||||
/* Clear shadow copy mask. */
|
||||
reg::Write(AVP_CACHE + AVP_CACHE_MMU_SHADOW_COPY_MASK_0, 0);
|
||||
|
||||
/* Add DRAM as index 0, RWX/Cached. */
|
||||
{
|
||||
reg::Write(AVP_CACHE + AVP_CACHE_MMU_SHADOW_ENTRY_0_MIN_ADDR, 0x80000000);
|
||||
reg::Write(AVP_CACHE + AVP_CACHE_MMU_SHADOW_ENTRY_0_MAX_ADDR, util::AlignDown(0xFFFFFFFF, DataCacheLineSize));
|
||||
|
||||
reg::Write(AVP_CACHE + AVP_CACHE_MMU_SHADOW_ENTRY_0_CFG, AVP_CACHE_REG_BITS_ENUM(SHADOW_ENTRY_CFG_WR_ENA, ENABLE),
|
||||
AVP_CACHE_REG_BITS_ENUM(SHADOW_ENTRY_CFG_RD_ENA, ENABLE),
|
||||
AVP_CACHE_REG_BITS_ENUM(SHADOW_ENTRY_CFG_EXE_ENA, ENABLE),
|
||||
AVP_CACHE_REG_BITS_ENUM(SHADOW_ENTRY_CFG_CACHED, ENABLE));
|
||||
|
||||
reg::SetBits(AVP_CACHE + AVP_CACHE_MMU_SHADOW_COPY_MASK_0, (1 << 0));
|
||||
}
|
||||
|
||||
/* Add IRAM as index 1, RWX/Cached. */
|
||||
{
|
||||
reg::Write(AVP_CACHE + AVP_CACHE_MMU_SHADOW_ENTRY_1_MIN_ADDR, 0x40000000);
|
||||
reg::Write(AVP_CACHE + AVP_CACHE_MMU_SHADOW_ENTRY_1_MAX_ADDR, util::AlignDown(0x4003FFFF, DataCacheLineSize));
|
||||
|
||||
reg::Write(AVP_CACHE + AVP_CACHE_MMU_SHADOW_ENTRY_1_CFG, AVP_CACHE_REG_BITS_ENUM(SHADOW_ENTRY_CFG_WR_ENA, ENABLE),
|
||||
AVP_CACHE_REG_BITS_ENUM(SHADOW_ENTRY_CFG_RD_ENA, ENABLE),
|
||||
AVP_CACHE_REG_BITS_ENUM(SHADOW_ENTRY_CFG_EXE_ENA, ENABLE),
|
||||
AVP_CACHE_REG_BITS_ENUM(SHADOW_ENTRY_CFG_CACHED, ENABLE));
|
||||
|
||||
reg::SetBits(AVP_CACHE + AVP_CACHE_MMU_SHADOW_COPY_MASK_0, (1 << 1));
|
||||
}
|
||||
|
||||
/* Issue copy shadow mmu command. */
|
||||
reg::Write(AVP_CACHE + AVP_CACHE_MMU_CMD, AVP_CACHE_REG_BITS_ENUM(MMU_CMD_CMD, COPY_SHADOW));
|
||||
}
|
||||
|
||||
/* Invalidate entire cache. */
|
||||
DoEntireCacheOperation(AVP_CACHE_MAINT_OPCODE_INVALID_WAY);
|
||||
|
||||
/* Enable the cache. */
|
||||
reg::Write(AVP_CACHE + AVP_CACHE_CONFIG, AVP_CACHE_REG_BITS_ENUM(CONFIG_ENABLE_CACHE, TRUE),
|
||||
AVP_CACHE_REG_BITS_ENUM(CONFIG_FORCE_WRITE_THROUGH, TRUE),
|
||||
AVP_CACHE_REG_BITS_ENUM(CONFIG_MMU_TAG_MODE, PARALLEL),
|
||||
AVP_CACHE_REG_BITS_ENUM(CONFIG_TAG_CHECK_ABORT_ON_ERROR, TRUE));
|
||||
|
||||
/* Invalidate entire cache again (WAR for hardware bug). */
|
||||
DoEntireCacheOperation(AVP_CACHE_MAINT_OPCODE_INVALID_WAY);
|
||||
}
|
||||
|
||||
void FinalizeDataCache() {
|
||||
REQUIRE_CACHE_ENABLED();
|
||||
|
||||
/* Flush entire data cache. */
|
||||
FlushEntireDataCache();
|
||||
|
||||
/* Disable cache. */
|
||||
reg::Write(AVP_CACHE + AVP_CACHE_CONFIG, AVP_CACHE_REG_BITS_ENUM(CONFIG_ENABLE_CACHE, FALSE));
|
||||
}
|
||||
|
||||
void InvalidateEntireDataCache() {
|
||||
REQUIRE_CACHE_ENABLED();
|
||||
|
||||
DoEntireCacheOperation(AVP_CACHE_MAINT_OPCODE_INVALID_WAY);
|
||||
}
|
||||
|
||||
void StoreEntireDataCache() {
|
||||
REQUIRE_CACHE_ENABLED();
|
||||
|
||||
DoEntireCacheOperation(AVP_CACHE_MAINT_OPCODE_CLEAN_WAY);
|
||||
}
|
||||
|
||||
void FlushEntireDataCache() {
|
||||
REQUIRE_CACHE_ENABLED();
|
||||
|
||||
DoEntireCacheOperation(AVP_CACHE_MAINT_OPCODE_CLEAN_INVALID_WAY);
|
||||
}
|
||||
|
||||
void InvalidateDataCacheLine(void *ptr) {
|
||||
/* NOTE: Don't check cache enabled as an optimization, as only direct caller will be InvalidateDataCache(). */
|
||||
/* REQUIRE_CACHE_ENABLED(); */
|
||||
|
||||
DoPhyCacheOperation(AVP_CACHE_MAINT_OPCODE_INVALID_PHY, reinterpret_cast<uintptr_t>(ptr));
|
||||
}
|
||||
|
||||
void StoreDataCacheLine(void *ptr) {
|
||||
/* NOTE: Don't check cache enabled as an optimization, as only direct caller will be FlushDataCache(). */
|
||||
/* REQUIRE_CACHE_ENABLED(); */
|
||||
|
||||
DoPhyCacheOperation(AVP_CACHE_MAINT_OPCODE_CLEAN_PHY, reinterpret_cast<uintptr_t>(ptr));
|
||||
}
|
||||
|
||||
void FlushDataCacheLine(void *ptr) {
|
||||
/* NOTE: Don't check cache enabled as an optimization, as only direct caller will be FlushDataCache(). */
|
||||
/* REQUIRE_CACHE_ENABLED(); */
|
||||
|
||||
DoPhyCacheOperation(AVP_CACHE_MAINT_OPCODE_CLEAN_INVALID_PHY, reinterpret_cast<uintptr_t>(ptr));
|
||||
}
|
||||
|
||||
void InvalidateDataCache(void *ptr, size_t size) {
|
||||
REQUIRE_CACHE_ENABLED();
|
||||
|
||||
if (IsLargeBuffer(size)) {
|
||||
InvalidateEntireDataCache();
|
||||
} else {
|
||||
const uintptr_t start = reinterpret_cast<uintptr_t>(ptr);
|
||||
const uintptr_t end = util::AlignUp(start + size, hw::DataCacheLineSize);
|
||||
|
||||
for (uintptr_t cur = start; cur < end; cur += hw::DataCacheLineSize) {
|
||||
InvalidateDataCacheLine(reinterpret_cast<void *>(cur));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StoreDataCache(const void *ptr, size_t size) {
|
||||
REQUIRE_CACHE_ENABLED();
|
||||
|
||||
if (IsLargeBuffer(size)) {
|
||||
StoreEntireDataCache();
|
||||
} else {
|
||||
const uintptr_t start = reinterpret_cast<uintptr_t>(ptr);
|
||||
const uintptr_t end = util::AlignUp(start + size, hw::DataCacheLineSize);
|
||||
|
||||
for (uintptr_t cur = start; cur < end; cur += hw::DataCacheLineSize) {
|
||||
StoreDataCacheLine(reinterpret_cast<void *>(cur));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FlushDataCache(const void *ptr, size_t size) {
|
||||
REQUIRE_CACHE_ENABLED();
|
||||
|
||||
if (IsLargeBuffer(size)) {
|
||||
FlushEntireDataCache();
|
||||
} else {
|
||||
const uintptr_t start = reinterpret_cast<uintptr_t>(ptr);
|
||||
const uintptr_t end = util::AlignUp(start + size, hw::DataCacheLineSize);
|
||||
|
||||
for (uintptr_t cur = start; cur < end; cur += hw::DataCacheLineSize) {
|
||||
FlushDataCacheLine(reinterpret_cast<void *>(cur));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::hw::arch::arm64 {
|
||||
|
||||
void FlushDataCache(const void *ptr, size_t size) {
|
||||
const uintptr_t start = reinterpret_cast<uintptr_t>(ptr);
|
||||
const uintptr_t end = util::AlignUp(start + size, hw::DataCacheLineSize);
|
||||
|
||||
for (uintptr_t cur = start; cur < end; cur += hw::DataCacheLineSize) {
|
||||
FlushDataCacheLine(reinterpret_cast<void *>(cur));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void InvalidateDataCache(const void *ptr, size_t size) {
|
||||
const uintptr_t start = reinterpret_cast<uintptr_t>(ptr);
|
||||
const uintptr_t end = util::AlignUp(start + size, hw::DataCacheLineSize);
|
||||
|
||||
for (uintptr_t cur = start; cur < end; cur += hw::DataCacheLineSize) {
|
||||
InvalidateDataCacheLine(reinterpret_cast<void *>(cur));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,205 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::i2c {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline size_t MaxTransferSize = sizeof(u32);
|
||||
|
||||
constinit std::array<uintptr_t, Port_Count> g_register_addresses = [] {
|
||||
std::array<uintptr_t, Port_Count> arr = {};
|
||||
|
||||
arr[Port_1] = secmon::MemoryRegionPhysicalDeviceI2c1.GetAddress();
|
||||
arr[Port_5] = secmon::MemoryRegionPhysicalDeviceI2c5.GetAddress();
|
||||
|
||||
return arr;
|
||||
}();
|
||||
|
||||
void LoadConfig(uintptr_t address) {
|
||||
/* Configure for TIMEOUT and MSTR config load. */
|
||||
/* NOTE: Nintendo writes value 1 to reserved bit 5 here. This bit is documented as having no meaning. */
|
||||
/* We will reproduce the write just in case it is undocumented. */
|
||||
reg::Write(address + I2C_CONFIG_LOAD, I2C_REG_BITS_VALUE(CONFIG_LOAD_RESERVED_BIT_5, 1),
|
||||
I2C_REG_BITS_ENUM (CONFIG_LOAD_TIMEOUT_CONFIG_LOAD, ENABLE),
|
||||
I2C_REG_BITS_ENUM (CONFIG_LOAD_SLV_CONFIG_LOAD, DISABLE),
|
||||
I2C_REG_BITS_ENUM (CONFIG_LOAD_MSTR_CONFIG_LOAD, ENABLE));
|
||||
|
||||
/* Wait up to 20 microseconds for the master config to be loaded. */
|
||||
for (int i = 0; i < 20; ++i) {
|
||||
if (reg::HasValue(address + I2C_CONFIG_LOAD, I2C_REG_BITS_ENUM(CONFIG_LOAD_MSTR_CONFIG_LOAD, DISABLE))) {
|
||||
return;
|
||||
}
|
||||
util::WaitMicroSeconds(1);
|
||||
}
|
||||
}
|
||||
|
||||
void ClearBus(uintptr_t address) {
|
||||
/* Configure the bus clear register. */
|
||||
reg::Write(address + I2C_BUS_CLEAR_CONFIG, I2C_REG_BITS_VALUE(BUS_CLEAR_CONFIG_BC_SCLK_THRESHOLD, 9),
|
||||
I2C_REG_BITS_ENUM (BUS_CLEAR_CONFIG_BC_STOP_COND, NO_STOP),
|
||||
I2C_REG_BITS_ENUM (BUS_CLEAR_CONFIG_BC_TERMINATE, IMMEDIATE),
|
||||
I2C_REG_BITS_ENUM (BUS_CLEAR_CONFIG_BC_ENABLE, ENABLE));
|
||||
|
||||
/* Load the config. */
|
||||
LoadConfig(address);
|
||||
|
||||
/* Wait up to 250us (in 25 us increments) until the bus clear is done. */
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
if (reg::HasValue(address + I2C_INTERRUPT_STATUS_REGISTER, I2C_REG_BITS_ENUM(INTERRUPT_STATUS_REGISTER_BUS_CLEAR_DONE, SET))) {
|
||||
break;
|
||||
}
|
||||
|
||||
util::WaitMicroSeconds(25);
|
||||
}
|
||||
|
||||
/* Read the bus clear status. */
|
||||
reg::Read(address + I2C_BUS_CLEAR_STATUS);
|
||||
}
|
||||
|
||||
void InitializePort(uintptr_t address) {
|
||||
/* Calculate the divisor. */
|
||||
constexpr int Divisor = util::DivideUp(19200, 8 * 400);
|
||||
|
||||
/* Set the divisor. */
|
||||
reg::Write(address + I2C_CLK_DIVISOR_REGISTER, I2C_REG_BITS_VALUE(CLK_DIVISOR_REGISTER_STD_FAST_MODE, Divisor - 1),
|
||||
I2C_REG_BITS_VALUE(CLK_DIVISOR_REGISTER_HSMODE, 1));
|
||||
|
||||
/* Clear the bus. */
|
||||
ClearBus(address);
|
||||
|
||||
/* Clear the status. */
|
||||
reg::Write(address + I2C_INTERRUPT_STATUS_REGISTER, reg::Read(address + I2C_INTERRUPT_STATUS_REGISTER));
|
||||
}
|
||||
|
||||
bool Write(uintptr_t base_address, Port port, int address, const void *src, size_t src_size, bool unused) {
|
||||
AMS_UNUSED(port, unused);
|
||||
|
||||
/* Ensure we don't write too much. */
|
||||
u32 data = 0;
|
||||
if (src_size > MaxTransferSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Copy the data to a transfer word. */
|
||||
std::memcpy(std::addressof(data), src, src_size);
|
||||
|
||||
|
||||
/* Configure the to write the 7-bit address. */
|
||||
reg::Write(base_address + I2C_I2C_CMD_ADDR0, I2C_REG_BITS_VALUE(I2C_CMD_ADDR0_7BIT_ADDR, address),
|
||||
I2C_REG_BITS_ENUM (I2C_CMD_ADDR0_7BIT_RW, WRITE));
|
||||
|
||||
/* Configure to write the data. */
|
||||
reg::Write(base_address + I2C_I2C_CMD_DATA1, data);
|
||||
|
||||
/* Configure to write the correct amount of data. */
|
||||
reg::Write(base_address + I2C_I2C_CNFG, I2C_REG_BITS_ENUM (I2C_CNFG_DEBOUNCE_CNT, DEBOUNCE_4T),
|
||||
I2C_REG_BITS_ENUM (I2C_CNFG_NEW_MASTER_FSM, ENABLE),
|
||||
I2C_REG_BITS_ENUM (I2C_CNFG_CMD1, WRITE),
|
||||
I2C_REG_BITS_VALUE(I2C_CNFG_LENGTH, src_size - 1));
|
||||
|
||||
/* Load the configuration. */
|
||||
LoadConfig(base_address);
|
||||
|
||||
/* Start the command. */
|
||||
reg::ReadWrite(base_address + I2C_I2C_CNFG, I2C_REG_BITS_ENUM(I2C_CNFG_SEND, GO));
|
||||
|
||||
/* Wait for the command to be done. */
|
||||
while (!reg::HasValue(base_address + I2C_I2C_STATUS, I2C_REG_BITS_ENUM(I2C_STATUS_BUSY, NOT_BUSY))) { /* ... */ }
|
||||
|
||||
/* Check if the transfer was successful. */
|
||||
return reg::HasValue(base_address + I2C_I2C_STATUS, I2C_REG_BITS_ENUM(I2C_STATUS_CMD1_STAT, SL1_XFER_SUCCESSFUL));
|
||||
}
|
||||
|
||||
bool Read(uintptr_t base_address, Port port, void *dst, size_t dst_size, int address, bool unused) {
|
||||
AMS_UNUSED(port, unused);
|
||||
|
||||
/* Ensure we don't read too much. */
|
||||
if (dst_size > MaxTransferSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Configure the to read the 7-bit address. */
|
||||
reg::Write(base_address + I2C_I2C_CMD_ADDR0, I2C_REG_BITS_VALUE(I2C_CMD_ADDR0_7BIT_ADDR, address),
|
||||
I2C_REG_BITS_ENUM (I2C_CMD_ADDR0_7BIT_RW, READ));
|
||||
|
||||
/* Configure to read the correct amount of data. */
|
||||
reg::Write(base_address + I2C_I2C_CNFG, I2C_REG_BITS_ENUM (I2C_CNFG_DEBOUNCE_CNT, DEBOUNCE_4T),
|
||||
I2C_REG_BITS_ENUM (I2C_CNFG_NEW_MASTER_FSM, ENABLE),
|
||||
I2C_REG_BITS_ENUM (I2C_CNFG_CMD1, READ),
|
||||
I2C_REG_BITS_VALUE(I2C_CNFG_LENGTH, dst_size - 1));
|
||||
|
||||
/* Load the configuration. */
|
||||
LoadConfig(base_address);
|
||||
|
||||
/* Start the command. */
|
||||
reg::ReadWrite(base_address + I2C_I2C_CNFG, I2C_REG_BITS_ENUM(I2C_CNFG_SEND, GO));
|
||||
|
||||
/* Wait for the command to be done. */
|
||||
while (!reg::HasValue(base_address + I2C_I2C_STATUS, I2C_REG_BITS_ENUM(I2C_STATUS_BUSY, NOT_BUSY))) { /* ... */ }
|
||||
|
||||
/* Check that the transfer was successful. */
|
||||
if (!reg::HasValue(base_address + I2C_I2C_STATUS, I2C_REG_BITS_ENUM(I2C_STATUS_CMD1_STAT, SL1_XFER_SUCCESSFUL))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Read and copy out the data. */
|
||||
u32 data = reg::Read(base_address + I2C_I2C_CMD_DATA1);
|
||||
std::memcpy(dst, std::addressof(data), dst_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SetRegisterAddress(Port port, uintptr_t address) {
|
||||
g_register_addresses[port] = address;
|
||||
}
|
||||
|
||||
void Initialize(Port port) {
|
||||
InitializePort(g_register_addresses[port]);
|
||||
}
|
||||
|
||||
bool Query(void *dst, size_t dst_size, Port port, int address, int r) {
|
||||
const uintptr_t base_address = g_register_addresses[port];
|
||||
|
||||
/* Select the register we want to read. */
|
||||
bool success = Write(base_address, port, address, std::addressof(r), 1, false);
|
||||
if (success) {
|
||||
/* If we successfully selected, read data from the register. */
|
||||
success = Read(base_address, port, dst, dst_size, address, true);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool Send(Port port, int address, int r, const void *src, size_t src_size) {
|
||||
const uintptr_t base_address = g_register_addresses[port];
|
||||
|
||||
/* Create a transfer buffer, make sure we can use it. */
|
||||
u8 buffer[MaxTransferSize];
|
||||
if (src_size > sizeof(buffer) - 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Copy data into the buffer. */
|
||||
buffer[0] = static_cast<u8>(r);
|
||||
std::memcpy(buffer + 1, src, src_size);
|
||||
|
||||
return Write(base_address, port, address, buffer, src_size + 1, false);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::impl {
|
||||
|
||||
NORETURN void UnexpectedDefaultImpl(const char *func, const char *file, int line) {
|
||||
::ams::diag::AbortImpl("", func, file, line);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
|
||||
#define KFUSE_STATE (0x080)
|
||||
|
||||
#define KFUSE_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (KFUSE, NAME)
|
||||
#define KFUSE_REG_BITS_VALUE(NAME, VALUE) REG_NAMED_BITS_VALUE (KFUSE, NAME, VALUE)
|
||||
#define KFUSE_REG_BITS_ENUM(NAME, ENUM) REG_NAMED_BITS_ENUM (KFUSE, NAME, ENUM)
|
||||
#define KFUSE_REG_BITS_ENUM_KFUSEL(NAME, __COND__, TRUE_ENUM, FALKFUSE_ENUM) REG_NAMED_BITS_ENUM_KFUSEL(KFUSE, NAME, __COND__, TRUE_ENUM, FALKFUSE_ENUM)
|
||||
|
||||
#define DEFINE_KFUSE_REG(NAME, __OFFKFUSET__, __WIDTH__) REG_DEFINE_NAMED_REG (KFUSE, NAME, __OFFKFUSET__, __WIDTH__)
|
||||
#define DEFINE_KFUSE_REG_BIT_ENUM(NAME, __OFFKFUSET__, ZERO, ONE) REG_DEFINE_NAMED_BIT_ENUM (KFUSE, NAME, __OFFKFUSET__, ZERO, ONE)
|
||||
#define DEFINE_KFUSE_REG_TWO_BIT_ENUM(NAME, __OFFKFUSET__, ZERO, ONE, TWO, THREE) REG_DEFINE_NAMED_TWO_BIT_ENUM (KFUSE, NAME, __OFFKFUSET__, ZERO, ONE, TWO, THREE)
|
||||
#define DEFINE_KFUSE_REG_THREE_BIT_ENUM(NAME, __OFFKFUSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, KFUSEVEN) REG_DEFINE_NAMED_THREE_BIT_ENUM(KFUSE, NAME, __OFFKFUSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, KFUSEVEN)
|
||||
#define DEFINE_KFUSE_REG_FOUR_BIT_ENUM(NAME, __OFFKFUSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, KFUSEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) REG_DEFINE_NAMED_FOUR_BIT_ENUM (KFUSE, NAME, __OFFKFUSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, KFUSEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN)
|
||||
|
||||
DEFINE_KFUSE_REG_BIT_ENUM(STATE_DONE, 16, NOT_DONE, DONE);
|
||||
DEFINE_KFUSE_REG_BIT_ENUM(STATE_CRCPASS, 17, FAIL, PASS);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* cxx implementation details to be stubbed here, as needed. */
|
||||
void __cxa_pure_virtual() { AMS_ABORT("pure virtual function call"); }
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
@@ -1,116 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::log {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline uart::Port DefaultLogPort = uart::Port_ReservedDebug;
|
||||
constexpr inline u32 DefaultLogFlags = static_cast<u32>(uart::Flag_None);
|
||||
constexpr inline int DefaultBaudRate = 115200;
|
||||
constinit uart::Port g_log_port = DefaultLogPort;
|
||||
constinit bool g_initialized_uart = false;
|
||||
|
||||
ALWAYS_INLINE void SetupUartClock(uart::Port port) {
|
||||
/* The debug port must always be set up, for compatibility with official hos. */
|
||||
pinmux::SetupUartA();
|
||||
clkrst::EnableUartAClock();
|
||||
|
||||
/* If logging to a joy-con port, configure appropriately. */
|
||||
if (port == uart::Port_LeftJoyCon) {
|
||||
/* Logging to left joy-con (e.g. with Joyless). */
|
||||
static_assert(uart::Port_LeftJoyCon == uart::Port_C);
|
||||
pinmux::SetupUartC();
|
||||
clkrst::EnableUartCClock();
|
||||
} else if (port == uart::Port_RightJoyCon) {
|
||||
/* Logging to right joy-con (e.g. with Joyless). */
|
||||
static_assert(uart::Port_RightJoyCon == uart::Port_B);
|
||||
pinmux::SetupUartB();
|
||||
clkrst::EnableUartBClock();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Initialize() {
|
||||
return Initialize(DefaultLogPort, DefaultBaudRate, DefaultLogFlags);
|
||||
}
|
||||
|
||||
void Initialize(uart::Port port, u32 baud_rate, u32 flags) {
|
||||
/* Initialize pinmux and clock for the target uart port. */
|
||||
SetupUartClock(port);
|
||||
|
||||
/* Initialize the target uart port. */
|
||||
uart::Initialize(port, baud_rate, flags);
|
||||
|
||||
/* Note that we've initialized. */
|
||||
g_log_port = port;
|
||||
g_initialized_uart = true;
|
||||
}
|
||||
|
||||
void Finalize() {
|
||||
g_initialized_uart = false;
|
||||
}
|
||||
|
||||
NOINLINE void VPrintf(const char *fmt, ::std::va_list vl) {
|
||||
/* TODO: What's a good size for the log buffer? Nintendo uses 0x100, but this seems big. */
|
||||
char log_buf[0x80];
|
||||
const auto len = util::TVSNPrintf(log_buf, sizeof(log_buf), fmt, vl);
|
||||
|
||||
if (g_initialized_uart) {
|
||||
uart::SendText(g_log_port, log_buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
NOINLINE void Printf(const char *fmt, ...) {
|
||||
::std::va_list vl;
|
||||
va_start(vl, fmt);
|
||||
VPrintf(fmt, vl);
|
||||
va_end(vl);
|
||||
}
|
||||
|
||||
NOINLINE void Dump(const void *src, size_t size) {
|
||||
const u8 *src_u8 = static_cast<const u8 *>(src);
|
||||
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
if ((i % 0x20) == 0x00) {
|
||||
Printf("%03zx| ", i);
|
||||
}
|
||||
Printf("%02x ", src_u8[i]);
|
||||
if ((i % 0x20) == 0x1F) {
|
||||
Printf("\n");
|
||||
}
|
||||
}
|
||||
if ((size % 0x20) != 0) {
|
||||
Printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SendText(const void *text, size_t size) {
|
||||
if (g_initialized_uart) {
|
||||
uart::SendText(g_log_port, text, size);
|
||||
}
|
||||
}
|
||||
|
||||
void Flush() {
|
||||
if (g_initialized_uart) {
|
||||
uart::WaitFlush(g_log_port);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,259 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::pinmux {
|
||||
|
||||
namespace {
|
||||
|
||||
constinit uintptr_t g_pinmux_address = secmon::MemoryRegionPhysicalDeviceApbMisc.GetAddress();
|
||||
constinit uintptr_t g_gpio_address = secmon::MemoryRegionPhysicalDeviceGpio.GetAddress();
|
||||
|
||||
void SetupFirstImpl(bool tx_cross_ext_con) {
|
||||
if (tx_cross_ext_con) {
|
||||
reg::Write(g_pinmux_address + PINMUX_AUX_UART2_TX, PINMUX_REG_BITS_ENUM(AUX_UART2_PM, UARTB),
|
||||
PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_INPUT, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE));
|
||||
|
||||
reg::Write(g_pinmux_address + PINMUX_AUX_UART3_TX, PINMUX_REG_BITS_ENUM(AUX_UART3_PM, UARTC),
|
||||
PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_INPUT, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE));
|
||||
|
||||
/* Configure GPIO for Uart-B/Uart-C. */
|
||||
reg::ReadWrite(g_gpio_address + 0x108, REG_BITS_VALUE(0, 1, 1));
|
||||
reg::ReadWrite(g_gpio_address + 0x00C, REG_BITS_VALUE(1, 1, 1));
|
||||
reg::ReadWrite(g_gpio_address + 0x118, REG_BITS_VALUE(0, 1, 0));
|
||||
reg::ReadWrite(g_gpio_address + 0x01C, REG_BITS_VALUE(1, 1, 0));
|
||||
}
|
||||
|
||||
/* Configure PE6/PH6 */
|
||||
reg::Write(g_pinmux_address + PINMUX_AUX_GPIO_PE6, PINMUX_REG_BITS_ENUM(AUX_GPIO_PE6_PM, RSVD0),
|
||||
PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE));
|
||||
|
||||
reg::Write(g_pinmux_address + PINMUX_AUX_GPIO_PH6, PINMUX_REG_BITS_ENUM(AUX_GPIO_PH6_PM, RSVD0),
|
||||
PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE));
|
||||
|
||||
/* Configure GPIO E6/H6. */
|
||||
reg::ReadWrite(g_gpio_address + 0x100, REG_BITS_VALUE(6, 1, 1));
|
||||
reg::ReadWrite(g_gpio_address + 0x10C, REG_BITS_VALUE(6, 1, 1));
|
||||
reg::ReadWrite(g_gpio_address + 0x110, REG_BITS_VALUE(6, 1, 0));
|
||||
reg::ReadWrite(g_gpio_address + 0x11C, REG_BITS_VALUE(6, 1, 0));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SetRegisterAddress(uintptr_t pinmux_address, uintptr_t gpio_address) {
|
||||
g_pinmux_address = pinmux_address;
|
||||
g_gpio_address = gpio_address;
|
||||
}
|
||||
|
||||
void SetupFirst(fuse::HardwareType hw_type) {
|
||||
switch (hw_type) {
|
||||
case fuse::HardwareType_Icosa:
|
||||
case fuse::HardwareType_Iowa:
|
||||
case fuse::HardwareType_Aula:
|
||||
SetupFirstImpl(true);
|
||||
break;
|
||||
case fuse::HardwareType_Hoag:
|
||||
case fuse::HardwareType_Calcio:
|
||||
SetupFirstImpl(false);
|
||||
break;
|
||||
case fuse::HardwareType_Copper:
|
||||
case fuse::HardwareType_Undefined:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SetupUartA() {
|
||||
/* Get the registers. */
|
||||
const uintptr_t PINMUX = g_pinmux_address;
|
||||
|
||||
/* Configure Uart-A. */
|
||||
reg::Write(PINMUX + PINMUX_AUX_UART1_TX, PINMUX_REG_BITS_ENUM(AUX_UART1_PM, UARTA),
|
||||
PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_INPUT, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE));
|
||||
|
||||
reg::Write(PINMUX + PINMUX_AUX_UART1_RX, PINMUX_REG_BITS_ENUM(AUX_UART1_PM, UARTA),
|
||||
PINMUX_REG_BITS_ENUM(AUX_PUPD, PULL_UP),
|
||||
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE));
|
||||
|
||||
reg::Write(PINMUX + PINMUX_AUX_UART1_RTS, PINMUX_REG_BITS_ENUM(AUX_UART1_PM, UARTA),
|
||||
PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_INPUT, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE));
|
||||
|
||||
reg::Write(PINMUX + PINMUX_AUX_UART1_CTS, PINMUX_REG_BITS_ENUM(AUX_UART1_PM, UARTA),
|
||||
PINMUX_REG_BITS_ENUM(AUX_PUPD, PULL_DOWN),
|
||||
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE));
|
||||
}
|
||||
|
||||
void SetupUartB() {
|
||||
/* Get the registers. */
|
||||
const uintptr_t PINMUX = g_pinmux_address;
|
||||
|
||||
/* Configure Uart-B. */
|
||||
reg::Write(PINMUX + PINMUX_AUX_UART2_TX, PINMUX_REG_BITS_ENUM(AUX_UART2_PM, UARTB),
|
||||
PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_INPUT, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE));
|
||||
|
||||
reg::Write(PINMUX + PINMUX_AUX_UART2_RX, PINMUX_REG_BITS_ENUM(AUX_UART2_PM, UARTB),
|
||||
PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE));
|
||||
|
||||
reg::Write(PINMUX + PINMUX_AUX_UART2_RTS, PINMUX_REG_BITS_ENUM(AUX_UART2_PM, UARTB),
|
||||
PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_INPUT, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE));
|
||||
|
||||
reg::Write(PINMUX + PINMUX_AUX_UART2_CTS, PINMUX_REG_BITS_ENUM(AUX_UART2_PM, UARTB),
|
||||
PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE));
|
||||
|
||||
/* Configure GPIO for Uart-B. */
|
||||
reg::ReadWrite(g_gpio_address + 0x108, REG_BITS_VALUE(0, 4, 0));
|
||||
}
|
||||
|
||||
void SetupUartC() {
|
||||
/* Get the registers. */
|
||||
const uintptr_t PINMUX = g_pinmux_address;
|
||||
|
||||
/* Configure Uart-C. */
|
||||
reg::Write(PINMUX + PINMUX_AUX_UART3_TX, PINMUX_REG_BITS_ENUM(AUX_UART3_PM, UARTC),
|
||||
PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_INPUT, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE));
|
||||
|
||||
reg::Write(PINMUX + PINMUX_AUX_UART3_RX, PINMUX_REG_BITS_ENUM(AUX_UART3_PM, UARTC),
|
||||
PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, TRISTATE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE));
|
||||
|
||||
reg::Write(PINMUX + PINMUX_AUX_UART3_RTS, PINMUX_REG_BITS_ENUM(AUX_UART3_PM, UARTC),
|
||||
PINMUX_REG_BITS_ENUM(AUX_PUPD, PULL_DOWN),
|
||||
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_INPUT, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE));
|
||||
|
||||
reg::Write(PINMUX + PINMUX_AUX_UART3_CTS, PINMUX_REG_BITS_ENUM(AUX_UART3_PM, UARTC),
|
||||
PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, TRISTATE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE));
|
||||
|
||||
/* Configure GPIO for Uart-C. */
|
||||
reg::ReadWrite(g_gpio_address + 0x118, REG_BITS_VALUE(0, 1, 1));
|
||||
reg::Read(g_gpio_address + 0x118);
|
||||
reg::ReadWrite(g_gpio_address + 0x00C, REG_BITS_VALUE(1, 1, 0));
|
||||
reg::Read(g_gpio_address + 0x00C);
|
||||
}
|
||||
|
||||
void SetupI2c1() {
|
||||
/* Get the registers. */
|
||||
const uintptr_t PINMUX = g_pinmux_address;
|
||||
|
||||
/* Configure I2c1 */
|
||||
reg::Write(PINMUX + PINMUX_AUX_GEN1_I2C_SCL, PINMUX_REG_BITS_ENUM(AUX_GEN1_I2C_PM, I2C1),
|
||||
PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE));
|
||||
|
||||
reg::Write(PINMUX + PINMUX_AUX_GEN1_I2C_SDA, PINMUX_REG_BITS_ENUM(AUX_GEN1_I2C_PM, I2C1),
|
||||
PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE));
|
||||
}
|
||||
|
||||
void SetupI2c5() {
|
||||
/* Get the registers. */
|
||||
const uintptr_t PINMUX = g_pinmux_address;
|
||||
|
||||
/* Configure I2c5 */
|
||||
reg::Write(PINMUX + PINMUX_AUX_PWR_I2C_SCL, PINMUX_REG_BITS_ENUM(AUX_PWR_I2C_PM, I2CPMU),
|
||||
PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE));
|
||||
|
||||
reg::Write(PINMUX + PINMUX_AUX_PWR_I2C_SDA, PINMUX_REG_BITS_ENUM(AUX_PWR_I2C_PM, I2CPMU),
|
||||
PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE));
|
||||
}
|
||||
|
||||
void SetupVolumeButton() {
|
||||
/* Configure VOL_UP/VOL_DOWN */
|
||||
reg::ReadWrite(g_gpio_address + 0x50C, REG_BITS_VALUE(6, 1, 1));
|
||||
reg::ReadWrite(g_gpio_address + 0x50C, REG_BITS_VALUE(7, 1, 1));
|
||||
reg::ReadWrite(g_gpio_address + 0x51C, REG_BITS_VALUE(6, 1, 0));
|
||||
reg::ReadWrite(g_gpio_address + 0x51C, REG_BITS_VALUE(7, 1, 0));
|
||||
}
|
||||
|
||||
void SetupHomeButton() {
|
||||
/* Configure BUTTON_HOME */
|
||||
reg::ReadWrite(g_gpio_address + 0x600, REG_BITS_VALUE(1, 1, 1));
|
||||
reg::ReadWrite(g_gpio_address + 0x610, REG_BITS_VALUE(1, 1, 0));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::pkg1 {
|
||||
|
||||
namespace {
|
||||
|
||||
bool IsProductionImpl() {
|
||||
return fuse::GetHardwareState() != fuse::HardwareState_Development;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool IsProduction() {
|
||||
return IsProductionImpl();
|
||||
}
|
||||
|
||||
bool IsProductionForVersionCheck() {
|
||||
return IsProductionImpl();
|
||||
}
|
||||
|
||||
bool IsProductionForPublicKey() {
|
||||
return IsProductionImpl();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,301 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::pmc {
|
||||
|
||||
namespace {
|
||||
|
||||
constinit uintptr_t g_register_address = secmon::MemoryRegionPhysicalDevicePmc.GetAddress();
|
||||
|
||||
constexpr inline u32 WriteMask = 0x1;
|
||||
constexpr inline u32 ReadMask = 0x2;
|
||||
|
||||
enum class LockMode {
|
||||
Read,
|
||||
Write,
|
||||
ReadWrite,
|
||||
};
|
||||
|
||||
template<LockMode Mode>
|
||||
constexpr inline u32 LockMask = [] {
|
||||
switch (Mode) {
|
||||
case LockMode::Read: return ReadMask;
|
||||
case LockMode::Write: return WriteMask;
|
||||
case LockMode::ReadWrite: return ReadMask | WriteMask;
|
||||
default: __builtin_unreachable();
|
||||
}
|
||||
}();
|
||||
|
||||
constexpr inline size_t NumSecureScratchRegisters = 120;
|
||||
constexpr inline size_t NumSecureDisableRegisters = 8;
|
||||
|
||||
template<size_t SecureScratch> requires (SecureScratch < NumSecureScratchRegisters)
|
||||
constexpr inline std::pair<size_t, size_t> DisableRegisterIndex = [] {
|
||||
if constexpr (SecureScratch < 8) {
|
||||
return std::pair<size_t, size_t>{0, 4 + 2 * SecureScratch};
|
||||
} else {
|
||||
constexpr size_t Relative = SecureScratch - 8;
|
||||
return std::pair<size_t, size_t>{1 + (Relative / 16), 2 * (Relative % 16)};
|
||||
}
|
||||
}();
|
||||
|
||||
struct LockInfo {
|
||||
size_t scratch;
|
||||
LockMode mode;
|
||||
};
|
||||
|
||||
template<LockInfo Info>
|
||||
constexpr ALWAYS_INLINE void SetSecureScratchMask(std::array<u32, NumSecureDisableRegisters> &disables) {
|
||||
constexpr std::pair<size_t, size_t> Location = DisableRegisterIndex<Info.scratch>;
|
||||
disables[Location.first] |= LockMask<Info.mode> << Location.second;
|
||||
}
|
||||
|
||||
template<LockInfo... Info>
|
||||
constexpr ALWAYS_INLINE void SetSecureScratchMasks(std::array<u32, NumSecureDisableRegisters> &disables) {
|
||||
(SetSecureScratchMask<Info>(disables), ...);
|
||||
}
|
||||
|
||||
template<size_t... Ix>
|
||||
constexpr ALWAYS_INLINE void SetSecureScratchReadWriteMasks(std::array<u32, NumSecureDisableRegisters> &disables) {
|
||||
(SetSecureScratchMask<LockInfo{Ix, LockMode::ReadWrite}>(disables), ...);
|
||||
}
|
||||
|
||||
template<size_t... Ix>
|
||||
constexpr ALWAYS_INLINE void SetSecureScratchReadMasks(std::array<u32, NumSecureDisableRegisters> &disables) {
|
||||
(SetSecureScratchMask<LockInfo{Ix, LockMode::Read}>(disables), ...);
|
||||
}
|
||||
|
||||
template<size_t... Ix>
|
||||
constexpr ALWAYS_INLINE void SetSecureScratchWriteMasks(std::array<u32, NumSecureDisableRegisters> &disables) {
|
||||
(SetSecureScratchMask<LockInfo{Ix, LockMode::Write}>(disables), ...);
|
||||
}
|
||||
|
||||
template<SecureRegister Register>
|
||||
constexpr ALWAYS_INLINE std::array<u32, NumSecureDisableRegisters> GetSecureScratchMasks() {
|
||||
std::array<u32, NumSecureDisableRegisters> disables = {};
|
||||
|
||||
if constexpr ((Register & SecureRegister_Other) != 0) {
|
||||
constexpr std::array<u32, NumSecureDisableRegisters> NonOtherDisables = GetSecureScratchMasks<static_cast<SecureRegister>(~SecureRegister_Other)>();
|
||||
for (size_t i = 0; i < NumSecureDisableRegisters; i++) {
|
||||
disables[i] |= ~NonOtherDisables[i];
|
||||
}
|
||||
disables[0] &= 0x007FFFF0;
|
||||
}
|
||||
if constexpr ((Register & SecureRegister_DramParameters) != 0) {
|
||||
SetSecureScratchReadWriteMasks< 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
17, 18, 19, 20,
|
||||
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
|
||||
52, 53, 54,
|
||||
56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
|
||||
79, 80, 81, 82, 83, 84,
|
||||
86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,
|
||||
104, 105, 106, 107
|
||||
>(disables);
|
||||
}
|
||||
if constexpr ((Register & SecureRegister_ResetVector) != 0) {
|
||||
SetSecureScratchReadWriteMasks<34, 35>(disables);
|
||||
}
|
||||
if constexpr ((Register & SecureRegister_Carveout) != 0) {
|
||||
SetSecureScratchReadWriteMasks<16, 39, 51, 55, 74, 75, 76, 77, 78, 99, 100, 101, 102, 103>(disables);
|
||||
}
|
||||
if constexpr ((Register & SecureRegister_CmacWrite) != 0) {
|
||||
SetSecureScratchWriteMasks<112, 113, 114, 115>(disables);
|
||||
}
|
||||
if constexpr ((Register & SecureRegister_CmacRead) != 0) {
|
||||
SetSecureScratchReadMasks<112, 113, 114, 115>(disables);
|
||||
}
|
||||
if constexpr ((Register & SecureRegister_KeySourceWrite) != 0) {
|
||||
SetSecureScratchWriteMasks<24, 25, 26, 27>(disables);
|
||||
}
|
||||
if constexpr ((Register & SecureRegister_KeySourceRead) != 0) {
|
||||
SetSecureScratchReadMasks<24, 25, 26, 27>(disables);
|
||||
}
|
||||
if constexpr ((Register & SecureRegister_Srk) != 0) {
|
||||
SetSecureScratchReadWriteMasks<4, 5, 6, 7>(disables);
|
||||
}
|
||||
|
||||
return disables;
|
||||
}
|
||||
|
||||
/* Validate that the secure scratch masks produced are correct. */
|
||||
#include "pmc_secure_scratch_test.inc"
|
||||
|
||||
ALWAYS_INLINE void LockBits(uintptr_t address, u32 mask) {
|
||||
reg::Write(address, reg::Read(address) | mask);
|
||||
}
|
||||
|
||||
template<SecureRegister Register>
|
||||
ALWAYS_INLINE void SetSecureScratchMasks(uintptr_t address) {
|
||||
constexpr auto Masks = GetSecureScratchMasks<Register>();
|
||||
|
||||
if constexpr (Masks[0] != 0) { LockBits(address + APBDEV_PMC_SEC_DISABLE , Masks[0]); }
|
||||
if constexpr (Masks[1] != 0) { LockBits(address + APBDEV_PMC_SEC_DISABLE2, Masks[1]); }
|
||||
if constexpr (Masks[2] != 0) { LockBits(address + APBDEV_PMC_SEC_DISABLE3, Masks[2]); }
|
||||
if constexpr (Masks[3] != 0) { LockBits(address + APBDEV_PMC_SEC_DISABLE4, Masks[3]); }
|
||||
if constexpr (Masks[4] != 0) { LockBits(address + APBDEV_PMC_SEC_DISABLE5, Masks[4]); }
|
||||
if constexpr (Masks[5] != 0) { LockBits(address + APBDEV_PMC_SEC_DISABLE6, Masks[5]); }
|
||||
if constexpr (Masks[6] != 0) { LockBits(address + APBDEV_PMC_SEC_DISABLE7, Masks[6]); }
|
||||
if constexpr (Masks[7] != 0) { LockBits(address + APBDEV_PMC_SEC_DISABLE8, Masks[7]); }
|
||||
|
||||
static_assert(Masks.size() == 8);
|
||||
}
|
||||
|
||||
template<SecureRegister Register>
|
||||
ALWAYS_INLINE bool TestSecureScratchMasks(uintptr_t address) {
|
||||
constexpr auto Masks = GetSecureScratchMasks<Register>();
|
||||
|
||||
if constexpr (Masks[0] != 0) { if ((reg::Read(address + APBDEV_PMC_SEC_DISABLE ) & Masks[0]) != Masks[0]) { return false; } }
|
||||
if constexpr (Masks[1] != 0) { if ((reg::Read(address + APBDEV_PMC_SEC_DISABLE2) & Masks[1]) != Masks[1]) { return false; } }
|
||||
if constexpr (Masks[2] != 0) { if ((reg::Read(address + APBDEV_PMC_SEC_DISABLE3) & Masks[2]) != Masks[2]) { return false; } }
|
||||
if constexpr (Masks[3] != 0) { if ((reg::Read(address + APBDEV_PMC_SEC_DISABLE4) & Masks[3]) != Masks[3]) { return false; } }
|
||||
if constexpr (Masks[4] != 0) { if ((reg::Read(address + APBDEV_PMC_SEC_DISABLE5) & Masks[4]) != Masks[4]) { return false; } }
|
||||
if constexpr (Masks[5] != 0) { if ((reg::Read(address + APBDEV_PMC_SEC_DISABLE6) & Masks[5]) != Masks[5]) { return false; } }
|
||||
if constexpr (Masks[6] != 0) { if ((reg::Read(address + APBDEV_PMC_SEC_DISABLE7) & Masks[6]) != Masks[6]) { return false; } }
|
||||
if constexpr (Masks[7] != 0) { if ((reg::Read(address + APBDEV_PMC_SEC_DISABLE8) & Masks[7]) != Masks[7]) { return false; } }
|
||||
static_assert(Masks.size() == 8);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
NOINLINE void WriteRandomValueToRegister(uintptr_t offset) {
|
||||
/* Create an aligned buffer. */
|
||||
util::AlignedBuffer<hw::DataCacheLineSize, sizeof(u32)> buf;
|
||||
|
||||
/* Generate random bytes into it. */
|
||||
se::GenerateRandomBytes(buf, sizeof(u32));
|
||||
|
||||
/* Read the random value. */
|
||||
const u32 random = *reinterpret_cast<const u32 *>(static_cast<u8 *>(buf));
|
||||
|
||||
/* Get the address. */
|
||||
const uintptr_t address = g_register_address + offset;
|
||||
|
||||
/* Write the value. */
|
||||
reg::Write(address, random);
|
||||
|
||||
/* Verify it was written. */
|
||||
AMS_ABORT_UNLESS(reg::Read(address) == random);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SetRegisterAddress(uintptr_t address) {
|
||||
g_register_address = address;
|
||||
}
|
||||
|
||||
void InitializeRandomScratch() {
|
||||
/* Write random data to the scratch that contains the SRK. */
|
||||
WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH4);
|
||||
WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH5);
|
||||
WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH6);
|
||||
WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH7);
|
||||
|
||||
/* Lock the SRK scratch. */
|
||||
LockSecureRegister(SecureRegister_Srk);
|
||||
|
||||
/* Write random data to the scratch used for tzram cmac. */
|
||||
WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH112);
|
||||
WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH113);
|
||||
WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH114);
|
||||
WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH115);
|
||||
|
||||
/* Write random data to the scratch used for tzram key source. */
|
||||
WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH24);
|
||||
WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH25);
|
||||
WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH26);
|
||||
WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH27);
|
||||
|
||||
/* Here, Nintendo locks the SRK scratch a second time. */
|
||||
/* This may just be "to be sure". */
|
||||
LockSecureRegister(SecureRegister_Srk);
|
||||
}
|
||||
|
||||
void EnableWakeEventDetection() {
|
||||
/* Get the address. */
|
||||
const uintptr_t address = g_register_address;
|
||||
|
||||
/* Wait 75us, then enable event detection, then wait another 75us. */
|
||||
util::WaitMicroSeconds(75);
|
||||
reg::ReadWrite(address + APBDEV_PMC_CNTRL2, PMC_REG_BITS_ENUM(CNTRL2_WAKE_DET_EN, ENABLE));
|
||||
util::WaitMicroSeconds(75);
|
||||
|
||||
/* Enable all wake events. */
|
||||
reg::Write(address + APBDEV_PMC_WAKE_STATUS, 0xFFFFFFFFu);
|
||||
reg::Write(address + APBDEV_PMC_WAKE2_STATUS, 0xFFFFFFFFu);
|
||||
util::WaitMicroSeconds(75);
|
||||
}
|
||||
|
||||
void ConfigureForSc7Entry() {
|
||||
/* Get the address. */
|
||||
const uintptr_t address = g_register_address;
|
||||
|
||||
/* Configure the bootrom to perform a warmboot. */
|
||||
reg::Write(address + APBDEV_PMC_SCRATCH0, 0x1);
|
||||
|
||||
/* Enable the TSC multiplier. */
|
||||
reg::ReadWrite(address + APBDEV_PMC_DPD_ENABLE, PMC_REG_BITS_ENUM(DPD_ENABLE_TSC_MULT_EN, ENABLE));
|
||||
}
|
||||
|
||||
void LockSecureRegister(SecureRegister reg) {
|
||||
/* Get the address. */
|
||||
const uintptr_t address = g_register_address;
|
||||
|
||||
/* Apply each mask. */
|
||||
#define PMC_PROCESS_REG(REG) do { if ((reg & SecureRegister_##REG) != 0) { SetSecureScratchMasks<SecureRegister_##REG>(address); } } while (0)
|
||||
PMC_PROCESS_REG(Other);
|
||||
PMC_PROCESS_REG(DramParameters);
|
||||
PMC_PROCESS_REG(ResetVector);
|
||||
PMC_PROCESS_REG(Carveout);
|
||||
PMC_PROCESS_REG(CmacWrite);
|
||||
PMC_PROCESS_REG(CmacRead);
|
||||
PMC_PROCESS_REG(KeySourceWrite);
|
||||
PMC_PROCESS_REG(KeySourceRead);
|
||||
PMC_PROCESS_REG(Srk);
|
||||
#undef PMC_PROCESS_REG
|
||||
|
||||
}
|
||||
|
||||
LockState GetSecureRegisterLockState(SecureRegister reg) {
|
||||
bool all_valid = true;
|
||||
bool any_valid = false;
|
||||
|
||||
/* Get the address. */
|
||||
const uintptr_t address = g_register_address;
|
||||
|
||||
/* Test each mask. */
|
||||
#define PMC_PROCESS_REG(REG) do { if ((reg & SecureRegister_##REG) != 0) { const bool test = TestSecureScratchMasks<SecureRegister_##REG>(address); all_valid &= test; any_valid |= test; } } while (0)
|
||||
PMC_PROCESS_REG(Other);
|
||||
PMC_PROCESS_REG(DramParameters);
|
||||
PMC_PROCESS_REG(ResetVector);
|
||||
PMC_PROCESS_REG(Carveout);
|
||||
PMC_PROCESS_REG(CmacWrite);
|
||||
PMC_PROCESS_REG(CmacRead);
|
||||
PMC_PROCESS_REG(KeySourceWrite);
|
||||
PMC_PROCESS_REG(KeySourceRead);
|
||||
PMC_PROCESS_REG(Srk);
|
||||
#undef PMC_PROCESS_REG
|
||||
|
||||
if (all_valid) {
|
||||
return LockState::Locked;
|
||||
} else if (any_valid) {
|
||||
return LockState::PartiallyLocked;
|
||||
} else {
|
||||
return LockState::NotLocked;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
|
||||
namespace test {
|
||||
|
||||
constexpr inline auto Other = GetSecureScratchMasks<SecureRegister_Other>();
|
||||
static_assert(Other[0] == 0x00700FF0u);
|
||||
static_assert(Other[1] == 0xFC000000u);
|
||||
static_assert(Other[2] == 0x3F0FFF00u);
|
||||
static_assert(Other[3] == 0x00000000u);
|
||||
static_assert(Other[4] == 0x00000000u);
|
||||
static_assert(Other[5] == 0x0C000000u);
|
||||
static_assert(Other[6] == 0x00000000u);
|
||||
static_assert(Other[7] == 0xFF00FF00u);
|
||||
|
||||
constexpr inline auto DramParameters = GetSecureScratchMasks<SecureRegister_DramParameters>();
|
||||
static_assert(DramParameters[0] == 0x00000000u);
|
||||
static_assert(DramParameters[1] == 0x03FCFFFFu);
|
||||
static_assert(DramParameters[2] == 0x00000000u);
|
||||
static_assert(DramParameters[3] == 0x3F3FFFFFu);
|
||||
static_assert(DramParameters[4] == 0xFFFFFFFFu);
|
||||
static_assert(DramParameters[5] == 0xF3FFC00Fu);
|
||||
static_assert(DramParameters[6] == 0x003FFFFFu);
|
||||
static_assert(DramParameters[7] == 0x000000FFu);
|
||||
|
||||
constexpr inline auto ResetVector = GetSecureScratchMasks<SecureRegister_ResetVector>();
|
||||
static_assert(ResetVector[0] == 0x00000000u);
|
||||
static_assert(ResetVector[1] == 0x00000000u);
|
||||
static_assert(ResetVector[2] == 0x00F00000u);
|
||||
static_assert(ResetVector[3] == 0x00000000u);
|
||||
static_assert(ResetVector[4] == 0x00000000u);
|
||||
static_assert(ResetVector[5] == 0x00000000u);
|
||||
static_assert(ResetVector[6] == 0x00000000u);
|
||||
static_assert(ResetVector[7] == 0x00000000u);
|
||||
|
||||
constexpr inline auto CmacWrite = GetSecureScratchMasks<SecureRegister_CmacWrite>();
|
||||
static_assert(CmacWrite[0] == 0x00000000u);
|
||||
static_assert(CmacWrite[1] == 0x00000000u);
|
||||
static_assert(CmacWrite[2] == 0x00000000u);
|
||||
static_assert(CmacWrite[3] == 0x00000000u);
|
||||
static_assert(CmacWrite[4] == 0x00000000u);
|
||||
static_assert(CmacWrite[5] == 0x00000000u);
|
||||
static_assert(CmacWrite[6] == 0x00000000u);
|
||||
static_assert(CmacWrite[7] == 0x00550000u);
|
||||
|
||||
constexpr inline auto CmacRead = GetSecureScratchMasks<SecureRegister_CmacRead>();
|
||||
static_assert(CmacRead[0] == 0x00000000u);
|
||||
static_assert(CmacRead[1] == 0x00000000u);
|
||||
static_assert(CmacRead[2] == 0x00000000u);
|
||||
static_assert(CmacRead[3] == 0x00000000u);
|
||||
static_assert(CmacRead[4] == 0x00000000u);
|
||||
static_assert(CmacRead[5] == 0x00000000u);
|
||||
static_assert(CmacRead[6] == 0x00000000u);
|
||||
static_assert(CmacRead[7] == 0x00AA0000u);
|
||||
|
||||
constexpr inline auto KeySourceWrite = GetSecureScratchMasks<SecureRegister_KeySourceWrite>();
|
||||
static_assert(KeySourceWrite[0] == 0x00000000u);
|
||||
static_assert(KeySourceWrite[1] == 0x00000000u);
|
||||
static_assert(KeySourceWrite[2] == 0x00000055u);
|
||||
static_assert(KeySourceWrite[3] == 0x00000000u);
|
||||
static_assert(KeySourceWrite[4] == 0x00000000u);
|
||||
static_assert(KeySourceWrite[5] == 0x00000000u);
|
||||
static_assert(KeySourceWrite[6] == 0x00000000u);
|
||||
static_assert(KeySourceWrite[7] == 0x00000000u);
|
||||
|
||||
constexpr inline auto KeySourceRead = GetSecureScratchMasks<SecureRegister_KeySourceRead>();
|
||||
static_assert(KeySourceRead[0] == 0x00000000u);
|
||||
static_assert(KeySourceRead[1] == 0x00000000u);
|
||||
static_assert(KeySourceRead[2] == 0x000000AAu);
|
||||
static_assert(KeySourceRead[3] == 0x00000000u);
|
||||
static_assert(KeySourceRead[4] == 0x00000000u);
|
||||
static_assert(KeySourceRead[5] == 0x00000000u);
|
||||
static_assert(KeySourceRead[6] == 0x00000000u);
|
||||
static_assert(KeySourceRead[7] == 0x00000000u);
|
||||
|
||||
constexpr inline auto Srk = GetSecureScratchMasks<SecureRegister_Srk>();
|
||||
static_assert(Srk[0] == 0x000FF000u);
|
||||
static_assert(Srk[1] == 0x00000000u);
|
||||
static_assert(Srk[2] == 0x00000000u);
|
||||
static_assert(Srk[3] == 0x00000000u);
|
||||
static_assert(Srk[4] == 0x00000000u);
|
||||
static_assert(Srk[5] == 0x00000000u);
|
||||
static_assert(Srk[6] == 0x00000000u);
|
||||
static_assert(Srk[7] == 0x00000000u);
|
||||
|
||||
|
||||
}
|
||||
@@ -1,340 +0,0 @@
|
||||
/*
|
||||
* Defining registers address and its bit definitions of MAX77620 and MAX20024
|
||||
*
|
||||
* Copyright (c) 2016 NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2019 CTCaer
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _MFD_MAX77620_H_
|
||||
#define _MFD_MAX77620_H_
|
||||
|
||||
#define MAX77620_I2C_ADDR 0x3C
|
||||
|
||||
/* GLOBAL, PMIC, GPIO, FPS, ONOFFC, CID Registers */
|
||||
#define MAX77620_REG_CNFGGLBL1 0x00
|
||||
#define MAX77620_CNFGGLBL1_LBDAC_EN (1 << 7)
|
||||
#define MAX77620_CNFGGLBL1_MPPLD (1 << 6)
|
||||
#define MAX77620_CNFGGLBL1_LBHYST ((1 << 5) | (1 << 4))
|
||||
#define MAX77620_CNFGGLBL1_LBHYST_100 (0 << 4)
|
||||
#define MAX77620_CNFGGLBL1_LBHYST_200 (1 << 4)
|
||||
#define MAX77620_CNFGGLBL1_LBHYST_300 (2 << 4)
|
||||
#define MAX77620_CNFGGLBL1_LBHYST_400 (3 << 4)
|
||||
#define MAX77620_CNFGGLBL1_LBDAC_MASK 0x0E
|
||||
#define MAX77620_CNFGGLBL1_LBDAC_2700 (0 << 1)
|
||||
#define MAX77620_CNFGGLBL1_LBDAC_2800 (1 << 1)
|
||||
#define MAX77620_CNFGGLBL1_LBDAC_2900 (2 << 1)
|
||||
#define MAX77620_CNFGGLBL1_LBDAC_3000 (3 << 1)
|
||||
#define MAX77620_CNFGGLBL1_LBDAC_3100 (4 << 1)
|
||||
#define MAX77620_CNFGGLBL1_LBDAC_3200 (5 << 1)
|
||||
#define MAX77620_CNFGGLBL1_LBDAC_3300 (6 << 1)
|
||||
#define MAX77620_CNFGGLBL1_LBDAC_3400 (7 << 1)
|
||||
#define MAX77620_CNFGGLBL1_LBRSTEN (1 << 0)
|
||||
|
||||
#define MAX77620_REG_CNFGGLBL2 0x01
|
||||
#define MAX77620_REG_CNFGGLBL3 0x02
|
||||
#define MAX77620_WDTC_MASK 0x3
|
||||
#define MAX77620_WDTOFFC (1 << 4)
|
||||
#define MAX77620_WDTSLPC (1 << 3)
|
||||
#define MAX77620_WDTEN (1 << 2)
|
||||
#define MAX77620_TWD_MASK 0x3
|
||||
#define MAX77620_TWD_2s 0x0
|
||||
#define MAX77620_TWD_16s 0x1
|
||||
#define MAX77620_TWD_64s 0x2
|
||||
#define MAX77620_TWD_128s 0x3
|
||||
|
||||
#define MAX77620_REG_CNFG1_32K 0x03
|
||||
#define MAX77620_CNFG1_32K_OUT0_EN (1 << 2)
|
||||
|
||||
#define MAX77620_REG_CNFGBBC 0x04
|
||||
#define MAX77620_CNFGBBC_ENABLE (1 << 0)
|
||||
#define MAX77620_CNFGBBC_CURRENT_MASK 0x06
|
||||
#define MAX77620_CNFGBBC_CURRENT_SHIFT 1
|
||||
#define MAX77620_CNFGBBC_VOLTAGE_MASK 0x18
|
||||
#define MAX77620_CNFGBBC_VOLTAGE_SHIFT 3
|
||||
#define MAX77620_CNFGBBC_LOW_CURRENT_DISABLE (1 << 5)
|
||||
#define MAX77620_CNFGBBC_RESISTOR_MASK 0xC0
|
||||
#define MAX77620_CNFGBBC_RESISTOR_SHIFT 6
|
||||
#define MAX77620_CNFGBBC_RESISTOR_100 (0 << MAX77620_CNFGBBC_RESISTOR_SHIFT)
|
||||
#define MAX77620_CNFGBBC_RESISTOR_1K (1 << MAX77620_CNFGBBC_RESISTOR_SHIFT)
|
||||
#define MAX77620_CNFGBBC_RESISTOR_3K (2 << MAX77620_CNFGBBC_RESISTOR_SHIFT)
|
||||
#define MAX77620_CNFGBBC_RESISTOR_6K (3 << MAX77620_CNFGBBC_RESISTOR_SHIFT)
|
||||
|
||||
#define MAX77620_REG_IRQTOP 0x05
|
||||
#define MAX77620_IRQ_TOP_GLBL_MASK (1 << 7)
|
||||
#define MAX77620_IRQ_TOP_SD_MASK (1 << 6)
|
||||
#define MAX77620_IRQ_TOP_LDO_MASK (1 << 5)
|
||||
#define MAX77620_IRQ_TOP_GPIO_MASK (1 << 4)
|
||||
#define MAX77620_IRQ_TOP_RTC_MASK (1 << 3)
|
||||
#define MAX77620_IRQ_TOP_32K_MASK (1 << 2)
|
||||
#define MAX77620_IRQ_TOP_ONOFF_MASK (1 << 1)
|
||||
|
||||
#define MAX77620_REG_INTLBT 0x06
|
||||
#define MAX77620_REG_IRQTOPM 0x0D
|
||||
#define MAX77620_IRQ_LBM_MASK (1 << 3)
|
||||
#define MAX77620_IRQ_TJALRM1_MASK (1 << 2)
|
||||
#define MAX77620_IRQ_TJALRM2_MASK (1 << 1)
|
||||
|
||||
#define MAX77620_REG_IRQSD 0x07
|
||||
#define MAX77620_REG_IRQ_LVL2_L0_7 0x08
|
||||
#define MAX77620_REG_IRQ_LVL2_L8 0x09
|
||||
#define MAX77620_REG_IRQ_LVL2_GPIO 0x0A
|
||||
#define MAX77620_REG_ONOFFIRQ 0x0B
|
||||
#define MAX77620_REG_NVERC 0x0C
|
||||
|
||||
#define MAX77620_REG_INTENLBT 0x0E
|
||||
#define MAX77620_GLBLM_MASK (1 << 0)
|
||||
|
||||
#define MAX77620_REG_IRQMASKSD 0x0F
|
||||
#define MAX77620_REG_IRQ_MSK_L0_7 0x10
|
||||
#define MAX77620_REG_IRQ_MSK_L8 0x11
|
||||
#define MAX77620_REG_ONOFFIRQM 0x12
|
||||
#define MAX77620_REG_STATLBT 0x13
|
||||
#define MAX77620_REG_STATSD 0x14
|
||||
#define MAX77620_REG_ONOFFSTAT 0x15
|
||||
|
||||
/* SD and LDO Registers */
|
||||
#define MAX77620_REG_SD0 0x16
|
||||
#define MAX77620_REG_SD1 0x17
|
||||
#define MAX77620_REG_SD2 0x18
|
||||
#define MAX77620_REG_SD3 0x19
|
||||
#define MAX77620_REG_SD4 0x1A
|
||||
#define MAX77620_SDX_VOLT_MASK 0xFF
|
||||
#define MAX77620_SD0_VOLT_MASK 0x3F
|
||||
#define MAX77620_SD1_VOLT_MASK 0x7F
|
||||
#define MAX77620_LDO_VOLT_MASK 0x3F
|
||||
#define MAX77620_REG_DVSSD0 0x1B
|
||||
#define MAX77620_REG_DVSSD1 0x1C
|
||||
#define MAX77620_REG_SD0_CFG 0x1D
|
||||
#define MAX77620_REG_SD1_CFG 0x1E
|
||||
#define MAX77620_REG_SD2_CFG 0x1F
|
||||
#define MAX77620_REG_SD3_CFG 0x20
|
||||
#define MAX77620_REG_SD4_CFG 0x21
|
||||
#define MAX77620_REG_SD_CFG2 0x22
|
||||
#define MAX77620_REG_LDO0_CFG 0x23
|
||||
#define MAX77620_REG_LDO0_CFG2 0x24
|
||||
#define MAX77620_REG_LDO1_CFG 0x25
|
||||
#define MAX77620_REG_LDO1_CFG2 0x26
|
||||
#define MAX77620_REG_LDO2_CFG 0x27
|
||||
#define MAX77620_REG_LDO2_CFG2 0x28
|
||||
#define MAX77620_REG_LDO3_CFG 0x29
|
||||
#define MAX77620_REG_LDO3_CFG2 0x2A
|
||||
#define MAX77620_REG_LDO4_CFG 0x2B
|
||||
#define MAX77620_REG_LDO4_CFG2 0x2C
|
||||
#define MAX77620_REG_LDO5_CFG 0x2D
|
||||
#define MAX77620_REG_LDO5_CFG2 0x2E
|
||||
#define MAX77620_REG_LDO6_CFG 0x2F
|
||||
#define MAX77620_REG_LDO6_CFG2 0x30
|
||||
#define MAX77620_REG_LDO7_CFG 0x31
|
||||
#define MAX77620_REG_LDO7_CFG2 0x32
|
||||
#define MAX77620_REG_LDO8_CFG 0x33
|
||||
#define MAX77620_REG_LDO8_CFG2 0x34
|
||||
#define MAX77620_LDO_POWER_MODE_MASK 0xC0
|
||||
#define MAX77620_LDO_POWER_MODE_SHIFT 6
|
||||
#define MAX77620_POWER_MODE_NORMAL 3
|
||||
#define MAX77620_POWER_MODE_LPM 2
|
||||
#define MAX77620_POWER_MODE_GLPM 1
|
||||
#define MAX77620_POWER_MODE_DISABLE 0
|
||||
#define MAX20024_LDO_CFG2_MPOK_MASK (1 << 2)
|
||||
#define MAX77620_LDO_CFG2_ADE_MASK (1 << 1)
|
||||
#define MAX77620_LDO_CFG2_ADE_DISABLE (0 << 1)
|
||||
#define MAX77620_LDO_CFG2_ADE_ENABLE (1 << 1)
|
||||
#define MAX77620_LDO_CFG2_SS_MASK (1 << 0)
|
||||
#define MAX77620_LDO_CFG2_SS_FAST (1 << 0)
|
||||
#define MAX77620_LDO_CFG2_SS_SLOW 0
|
||||
|
||||
#define MAX77620_REG_LDO_CFG3 0x35
|
||||
#define MAX77620_TRACK4_MASK (1 << 5)
|
||||
#define MAX77620_TRACK4_SHIFT 5
|
||||
|
||||
#define MAX77620_LDO_SLEW_RATE_MASK 0x1
|
||||
|
||||
#define MAX77620_REG_GPIO0 0x36
|
||||
#define MAX77620_REG_GPIO1 0x37
|
||||
#define MAX77620_REG_GPIO2 0x38
|
||||
#define MAX77620_REG_GPIO3 0x39
|
||||
#define MAX77620_REG_GPIO4 0x3A
|
||||
#define MAX77620_REG_GPIO5 0x3B
|
||||
#define MAX77620_REG_GPIO6 0x3C
|
||||
#define MAX77620_REG_GPIO7 0x3D
|
||||
#define MAX77620_REG_PUE_GPIO 0x3E
|
||||
#define MAX77620_REG_PDE_GPIO 0x3F
|
||||
#define MAX77620_REG_AME_GPIO 0x40
|
||||
#define MAX77620_CNFG_GPIO_DRV_MASK (1 << 0)
|
||||
#define MAX77620_CNFG_GPIO_DRV_PUSHPULL (1 << 0)
|
||||
#define MAX77620_CNFG_GPIO_DRV_OPENDRAIN (0 << 0)
|
||||
#define MAX77620_CNFG_GPIO_DIR_MASK (1 << 1)
|
||||
#define MAX77620_CNFG_GPIO_DIR_INPUT (1 << 1)
|
||||
#define MAX77620_CNFG_GPIO_DIR_OUTPUT (0 << 1)
|
||||
#define MAX77620_CNFG_GPIO_INPUT_VAL_MASK (1 << 2)
|
||||
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK (1 << 3)
|
||||
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH (1 << 3)
|
||||
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW (0 << 3)
|
||||
#define MAX77620_CNFG_GPIO_INT_MASK (0x3 << 4)
|
||||
#define MAX77620_CNFG_GPIO_INT_FALLING (1 << 4)
|
||||
#define MAX77620_CNFG_GPIO_INT_RISING (1 << 5)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_MASK (0x3 << 6)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_None (0x0 << 6)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_8ms (0x1 << 6)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_16ms (0x2 << 6)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_32ms (0x3 << 6)
|
||||
|
||||
#define MAX77620_REG_ONOFFCNFG1 0x41
|
||||
#define MAX77620_ONOFFCNFG1_SFT_RST (1 << 7)
|
||||
#define MAX77620_ONOFFCNFG1_MRT_MASK 0x38
|
||||
#define MAX77620_ONOFFCNFG1_MRT_SHIFT 0x3
|
||||
#define MAX77620_ONOFFCNFG1_SLPEN (1 << 2)
|
||||
#define MAX77620_ONOFFCNFG1_PWR_OFF (1 << 1)
|
||||
#define MAX20024_ONOFFCNFG1_CLRSE 0x18
|
||||
|
||||
#define MAX77620_REG_ONOFFCNFG2 0x42
|
||||
#define MAX77620_ONOFFCNFG2_SFT_RST_WK (1 << 7)
|
||||
#define MAX77620_ONOFFCNFG2_WD_RST_WK (1 << 6)
|
||||
#define MAX77620_ONOFFCNFG2_SLP_LPM_MSK (1 << 5)
|
||||
#define MAX77620_ONOFFCNFG2_WK_ALARM1 (1 << 2)
|
||||
#define MAX77620_ONOFFCNFG2_WK_EN0 (1 << 0)
|
||||
|
||||
/* FPS Registers */
|
||||
#define MAX77620_REG_FPS_CFG0 0x43
|
||||
#define MAX77620_REG_FPS_CFG1 0x44
|
||||
#define MAX77620_REG_FPS_CFG2 0x45
|
||||
#define MAX77620_REG_FPS_LDO0 0x46
|
||||
#define MAX77620_REG_FPS_LDO1 0x47
|
||||
#define MAX77620_REG_FPS_LDO2 0x48
|
||||
#define MAX77620_REG_FPS_LDO3 0x49
|
||||
#define MAX77620_REG_FPS_LDO4 0x4A
|
||||
#define MAX77620_REG_FPS_LDO5 0x4B
|
||||
#define MAX77620_REG_FPS_LDO6 0x4C
|
||||
#define MAX77620_REG_FPS_LDO7 0x4D
|
||||
#define MAX77620_REG_FPS_LDO8 0x4E
|
||||
#define MAX77620_REG_FPS_SD0 0x4F
|
||||
#define MAX77620_REG_FPS_SD1 0x50
|
||||
#define MAX77620_REG_FPS_SD2 0x51
|
||||
#define MAX77620_REG_FPS_SD3 0x52
|
||||
#define MAX77620_REG_FPS_SD4 0x53
|
||||
#define MAX77620_REG_FPS_NONE 0
|
||||
#define MAX77620_FPS_SRC_MASK 0xC0
|
||||
#define MAX77620_FPS_SRC_SHIFT 6
|
||||
#define MAX77620_FPS_PU_PERIOD_MASK 0x38
|
||||
#define MAX77620_FPS_PU_PERIOD_SHIFT 3
|
||||
#define MAX77620_FPS_PD_PERIOD_MASK 0x07
|
||||
#define MAX77620_FPS_PD_PERIOD_SHIFT 0
|
||||
|
||||
/* Minimum and maximum FPS period time (in microseconds) are
|
||||
* different for MAX77620 and Max20024.
|
||||
*/
|
||||
#define MAX77620_FPS_COUNT 3
|
||||
|
||||
#define MAX77620_FPS_PERIOD_MIN_US 40
|
||||
#define MAX20024_FPS_PERIOD_MIN_US 20
|
||||
|
||||
#define MAX77620_FPS_PERIOD_MAX_US 2560
|
||||
#define MAX20024_FPS_PERIOD_MAX_US 5120
|
||||
|
||||
#define MAX77620_REG_FPS_GPIO1 0x54
|
||||
#define MAX77620_REG_FPS_GPIO2 0x55
|
||||
#define MAX77620_REG_FPS_GPIO3 0x56
|
||||
#define MAX77620_FPS_TIME_PERIOD_MASK 0x38
|
||||
#define MAX77620_FPS_TIME_PERIOD_SHIFT 3
|
||||
#define MAX77620_FPS_EN_SRC_MASK 0x06
|
||||
#define MAX77620_FPS_EN_SRC_SHIFT 1
|
||||
#define MAX77620_FPS_ENFPS_SW_MASK 0x01
|
||||
#define MAX77620_FPS_ENFPS_SW 0x01
|
||||
|
||||
#define MAX77620_REG_FPS_RSO 0x57
|
||||
#define MAX77620_REG_CID0 0x58
|
||||
#define MAX77620_REG_CID1 0x59
|
||||
#define MAX77620_REG_CID2 0x5A
|
||||
#define MAX77620_REG_CID3 0x5B
|
||||
#define MAX77620_REG_CID4 0x5C
|
||||
#define MAX77620_REG_CID5 0x5D
|
||||
|
||||
#define MAX77620_REG_DVSSD4 0x5E
|
||||
#define MAX20024_REG_MAX_ADD 0x70
|
||||
|
||||
#define MAX77620_CID_DIDM_MASK 0xF0
|
||||
#define MAX77620_CID_DIDM_SHIFT 4
|
||||
|
||||
/* CNCG2SD */
|
||||
#define MAX77620_SD_CNF2_ROVS_EN_SD1 (1 << 1)
|
||||
#define MAX77620_SD_CNF2_ROVS_EN_SD0 (1 << 2)
|
||||
|
||||
/* Device Identification Metal */
|
||||
#define MAX77620_CID5_DIDM(n) (((n) >> 4) & 0xF)
|
||||
/* Device Indentification OTP */
|
||||
#define MAX77620_CID5_DIDO(n) ((n) & 0xF)
|
||||
|
||||
/* SD CNFG1 */
|
||||
#define MAX77620_SD_SR_MASK 0xC0
|
||||
#define MAX77620_SD_SR_SHIFT 6
|
||||
#define MAX77620_SD_POWER_MODE_MASK 0x30
|
||||
#define MAX77620_SD_POWER_MODE_SHIFT 4
|
||||
#define MAX77620_SD_CFG1_ADE_MASK (1 << 3)
|
||||
#define MAX77620_SD_CFG1_ADE_DISABLE 0
|
||||
#define MAX77620_SD_CFG1_ADE_ENABLE (1 << 3)
|
||||
#define MAX77620_SD_FPWM_MASK 0x04
|
||||
#define MAX77620_SD_FPWM_SHIFT 2
|
||||
#define MAX77620_SD_FSRADE_MASK 0x01
|
||||
#define MAX77620_SD_FSRADE_SHIFT 0
|
||||
#define MAX77620_SD_CFG1_FPWM_SD_MASK (1 << 2)
|
||||
#define MAX77620_SD_CFG1_FPWM_SD_SKIP 0
|
||||
#define MAX77620_SD_CFG1_FPWM_SD_FPWM (1 << 2)
|
||||
#define MAX20024_SD_CFG1_MPOK_MASK (1 << 1)
|
||||
#define MAX77620_SD_CFG1_FSRADE_SD_MASK (1 << 0)
|
||||
#define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0
|
||||
#define MAX77620_SD_CFG1_FSRADE_SD_ENABLE (1 << 0)
|
||||
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE0 (1 << 0)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE1 (1 << 1)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE2 (1 << 2)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE3 (1 << 3)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE4 (1 << 4)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE5 (1 << 5)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE6 (1 << 6)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE7 (1 << 7)
|
||||
|
||||
/* Interrupts */
|
||||
enum {
|
||||
MAX77620_IRQ_TOP_GLBL, /* Low-Battery */
|
||||
MAX77620_IRQ_TOP_SD, /* SD power fail */
|
||||
MAX77620_IRQ_TOP_LDO, /* LDO power fail */
|
||||
MAX77620_IRQ_TOP_GPIO, /* TOP GPIO internal int to MAX77620 */
|
||||
MAX77620_IRQ_TOP_RTC, /* RTC */
|
||||
MAX77620_IRQ_TOP_32K, /* 32kHz oscillator */
|
||||
MAX77620_IRQ_TOP_ONOFF, /* ON/OFF oscillator */
|
||||
MAX77620_IRQ_LBT_MBATLOW, /* Thermal alarm status, > 120C */
|
||||
MAX77620_IRQ_LBT_TJALRM1, /* Thermal alarm status, > 120C */
|
||||
MAX77620_IRQ_LBT_TJALRM2, /* Thermal alarm status, > 140C */
|
||||
};
|
||||
|
||||
/* GPIOs */
|
||||
enum {
|
||||
MAX77620_GPIO0,
|
||||
MAX77620_GPIO1,
|
||||
MAX77620_GPIO2,
|
||||
MAX77620_GPIO3,
|
||||
MAX77620_GPIO4,
|
||||
MAX77620_GPIO5,
|
||||
MAX77620_GPIO6,
|
||||
MAX77620_GPIO7,
|
||||
MAX77620_GPIO_NR,
|
||||
};
|
||||
|
||||
/* FPS Source */
|
||||
enum max77620_fps_src {
|
||||
MAX77620_FPS_SRC_0,
|
||||
MAX77620_FPS_SRC_1,
|
||||
MAX77620_FPS_SRC_2,
|
||||
MAX77620_FPS_SRC_NONE,
|
||||
MAX77620_FPS_SRC_DEF,
|
||||
};
|
||||
|
||||
enum max77620_chip_id {
|
||||
MAX77620,
|
||||
MAX20024,
|
||||
};
|
||||
|
||||
#endif /* _MFD_MAX77620_H_ */
|
||||
@@ -1,109 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2019 CTCaer
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef _MAX7762X_H_
|
||||
#define _MAX7762X_H_
|
||||
|
||||
/*
|
||||
* Switch Power domains (max77620):
|
||||
* Name | Usage | uV step | uV min | uV default | uV max | Init
|
||||
*-------+---------------+---------+--------+------------+---------+------------------
|
||||
* sd0 | core | 12500 | 600000 | 625000 | 1400000 | 1.125V (pkg1.1)
|
||||
* sd1 | SDRAM | 12500 | 600000 | 1125000 | 1125000 | 1.1V (pkg1.1)
|
||||
* sd2 | ldo{0-1, 7-8} | 12500 | 600000 | 1325000 | 1350000 | 1.325V (pcv)
|
||||
* sd3 | 1.8V general | 12500 | 600000 | 1800000 | 1800000 |
|
||||
* ldo0 | Display Panel | 25000 | 800000 | 1200000 | 1200000 | 1.2V (pkg1.1)
|
||||
* ldo1 | XUSB, PCIE | 25000 | 800000 | 1050000 | 1050000 | 1.05V (pcv)
|
||||
* ldo2 | SDMMC1 | 50000 | 800000 | 1800000 | 3300000 |
|
||||
* ldo3 | GC ASIC | 50000 | 800000 | 3100000 | 3100000 | 3.1V (pcv)
|
||||
* ldo4 | RTC | 12500 | 800000 | 850000 | 850000 |
|
||||
* ldo5 | GC ASIC | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv)
|
||||
* ldo6 | Touch, ALS | 50000 | 800000 | 2900000 | 2900000 | 2.9V
|
||||
* ldo7 | XUSB | 50000 | 800000 | 1050000 | 1050000 |
|
||||
* ldo8 | XUSB, DC | 50000 | 800000 | 1050000 | 1050000 |
|
||||
*/
|
||||
|
||||
/*
|
||||
* MAX77620_AME_GPIO: control GPIO modes (bits 0 - 7 correspond to GPIO0 - GPIO7); 0 -> GPIO, 1 -> alt-mode
|
||||
* MAX77620_REG_GPIOx: 0x9 sets output and enable
|
||||
*/
|
||||
|
||||
/*! MAX77620 partitions. */
|
||||
#define REGULATOR_SD0 0
|
||||
#define REGULATOR_SD1 1
|
||||
#define REGULATOR_SD2 2
|
||||
#define REGULATOR_SD3 3
|
||||
#define REGULATOR_LDO0 4
|
||||
#define REGULATOR_LDO1 5
|
||||
#define REGULATOR_LDO2 6
|
||||
#define REGULATOR_LDO3 7
|
||||
#define REGULATOR_LDO4 8
|
||||
#define REGULATOR_LDO5 9
|
||||
#define REGULATOR_LDO6 10
|
||||
#define REGULATOR_LDO7 11
|
||||
#define REGULATOR_LDO8 12
|
||||
#define REGULATOR_MAX 12
|
||||
|
||||
#define MAX77621_CPU_I2C_ADDR 0x1B
|
||||
#define MAX77621_GPU_I2C_ADDR 0x1C
|
||||
|
||||
#define MAX77621_VOUT_REG 0
|
||||
#define MAX77621_VOUT_DVC_REG 1
|
||||
#define MAX77621_CONTROL1_REG 2
|
||||
#define MAX77621_CONTROL2_REG 3
|
||||
|
||||
/* MAX77621_VOUT */
|
||||
#define MAX77621_VOUT_DISABLE (0 << 7)
|
||||
#define MAX77621_VOUT_ENABLE (1 << 7)
|
||||
#define MAX77621_VOUT_MASK 0x7F
|
||||
#define MAX77621_VOUT_0_95V 0x37
|
||||
#define MAX77621_VOUT_1_09V 0x4F
|
||||
|
||||
/* MAX77621_VOUT_DVC_DVS */
|
||||
#define MAX77621_DVS_VOUT_MASK 0x7F
|
||||
|
||||
/* MAX77621_CONTROL1 */
|
||||
#define MAX77621_SNS_ENABLE (1 << 7)
|
||||
#define MAX77621_FPWM_EN_M (1 << 6)
|
||||
#define MAX77621_NFSR_ENABLE (1 << 5)
|
||||
#define MAX77621_AD_ENABLE (1 << 4)
|
||||
#define MAX77621_BIAS_ENABLE (1 << 3)
|
||||
#define MAX77621_FREQSHIFT_9PER (1 << 2)
|
||||
|
||||
#define MAX77621_RAMP_12mV_PER_US 0x0
|
||||
#define MAX77621_RAMP_25mV_PER_US 0x1
|
||||
#define MAX77621_RAMP_50mV_PER_US 0x2
|
||||
#define MAX77621_RAMP_200mV_PER_US 0x3
|
||||
#define MAX77621_RAMP_MASK 0x3
|
||||
|
||||
/* MAX77621_CONTROL2 */
|
||||
#define MAX77621_WDTMR_ENABLE (1 << 6)
|
||||
#define MAX77621_DISCH_ENBABLE (1 << 5)
|
||||
#define MAX77621_FT_ENABLE (1 << 4)
|
||||
#define MAX77621_T_JUNCTION_120 (1 << 7)
|
||||
|
||||
#define MAX77621_CKKADV_TRIP_DISABLE 0xC
|
||||
#define MAX77621_CKKADV_TRIP_75mV_PER_US 0x0
|
||||
#define MAX77621_CKKADV_TRIP_150mV_PER_US 0x4
|
||||
#define MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS 0x8
|
||||
|
||||
#define MAX77621_INDUCTOR_MIN_30_PER 0x0
|
||||
#define MAX77621_INDUCTOR_NOMINAL 0x1
|
||||
#define MAX77621_INDUCTOR_PLUS_30_PER 0x2
|
||||
#define MAX77621_INDUCTOR_PLUS_60_PER 0x3
|
||||
|
||||
#endif
|
||||
@@ -1,291 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "max77620.h"
|
||||
#include "max7762x.h"
|
||||
|
||||
namespace ams::pmic {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline int I2cAddressEristaMax77621 = 0x1B;
|
||||
constexpr inline int I2cAddressMarikoMax77812_A = 0x31;
|
||||
constexpr inline int I2cAddressMarikoMax77812_B = 0x33;
|
||||
|
||||
constexpr inline int I2cAddressMax77620Pmic = 0x3C;
|
||||
|
||||
/* https://github.com/Atmosphere-NX/Atmosphere/blob/master/emummc/source/power/max77620.h */
|
||||
/* https://github.com/Atmosphere-NX/Atmosphere/blob/master/emummc/source/power/max7762x.h */
|
||||
/* TODO: Find datasheet, link to it instead. */
|
||||
/* NOTE: Tentatively, Max77620 "mostly" matches https://datasheets.maximintegrated.com/en/ds/MAX77863.pdf. */
|
||||
/* This does not contain Max77621 documentation, though. */
|
||||
constexpr inline int Max77620RegisterCnfgBbc = 0x04;
|
||||
constexpr inline int Max77620RegisterOnOffStat = 0x15;
|
||||
constexpr inline int Max77620RegisterSd0 = 0x16;
|
||||
constexpr inline int Max77620RegisterSd1 = 0x17;
|
||||
constexpr inline int Max77620RegisterCnfg2Sd = 0x22;
|
||||
constexpr inline int Max77620RegisterCnfg1Ldo8 = 0x33;
|
||||
constexpr inline int Max77620RegisterGpio0 = 0x36;
|
||||
constexpr inline int Max77620RegisterAmeGpio = 0x40;
|
||||
constexpr inline int Max77620RegisterOnOffCnfg1 = 0x41;
|
||||
constexpr inline int Max77620RegisterCnfgFps0 = 0x43;
|
||||
constexpr inline int Max77620RegisterCnfgFps1 = 0x44;
|
||||
constexpr inline int Max77620RegisterCnfgFps2 = 0x45;
|
||||
constexpr inline int Max77620RegisterFpsLdo4 = 0x4A;
|
||||
constexpr inline int Max77620RegisterFpsLdo8 = 0x4E;
|
||||
constexpr inline int Max77620RegisterFpsSd0 = 0x4F;
|
||||
constexpr inline int Max77620RegisterFpsSd1 = 0x50;
|
||||
constexpr inline int Max77620RegisterFpsSd3 = 0x52;
|
||||
constexpr inline int Max77620RegisterFpsGpio3 = 0x56;
|
||||
|
||||
constexpr inline int Max77621RegisterVOut = 0x00;
|
||||
constexpr inline int Max77621RegisterVOutDvc = 0x01;
|
||||
constexpr inline int Max77621RegisterControl1 = 0x02;
|
||||
constexpr inline int Max77621RegisterControl2 = 0x03;
|
||||
|
||||
|
||||
/* https://datasheets.maximintegrated.com/en/ds/MAX77812.pdf */
|
||||
constexpr inline int Max77812RegisterEnCtrl = 0x06;
|
||||
constexpr inline int Max77812RegisterM4VOut = 0x26;
|
||||
|
||||
void Max77620EnableGpio(int gpio) {
|
||||
u8 val;
|
||||
|
||||
/* Clear the AE for the GPIO */
|
||||
if (i2c::Query(std::addressof(val), sizeof(val), i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterAmeGpio)) {
|
||||
val &= ~(1 << gpio);
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterAmeGpio, val);
|
||||
}
|
||||
|
||||
/* Set GPIO_DRV_PUSHPULL (bit 0), GPIO_OUTPUT_VAL_HIGH (bit 3). */
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterGpio0 + gpio, MAX77620_CNFG_GPIO_DRV_PUSHPULL | MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH);
|
||||
}
|
||||
|
||||
void SetEnBitErista() {
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressEristaMax77621, Max77621RegisterVOut, MAX77621_VOUT_ENABLE);
|
||||
}
|
||||
|
||||
void EnableVddCpuErista() {
|
||||
/* Enable GPIO 5. */
|
||||
/* TODO: What does this control? */
|
||||
Max77620EnableGpio(5);
|
||||
|
||||
/* Configure Max77621 control registers. */
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressEristaMax77621, Max77621RegisterControl1, MAX77621_AD_ENABLE | MAX77621_NFSR_ENABLE | MAX77621_SNS_ENABLE | MAX77621_RAMP_12mV_PER_US);
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressEristaMax77621, Max77621RegisterControl2, MAX77621_T_JUNCTION_120 | MAX77621_WDTMR_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US| MAX77621_INDUCTOR_NOMINAL);
|
||||
|
||||
/* Configure Max77621 VOut to 0.95v */
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressEristaMax77621, Max77621RegisterVOut, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V);
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressEristaMax77621, Max77621RegisterVOutDvc, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V);
|
||||
}
|
||||
|
||||
void DisableVddCpuErista() {
|
||||
/* Disable Max77621 VOut. */
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressEristaMax77621, Max77621RegisterVOut, MAX77621_VOUT_DISABLE);
|
||||
}
|
||||
|
||||
int GetI2cAddressForMarikoMax77812(Regulator regulator) {
|
||||
switch (regulator) {
|
||||
case Regulator_Mariko_Max77812_A: return I2cAddressMarikoMax77812_A;
|
||||
case Regulator_Mariko_Max77812_B: return I2cAddressMarikoMax77812_B;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
void SetEnBitMariko(Regulator regulator) {
|
||||
/* Set EN_M3_LPM to enable BUCK Master 3 low power mode. */
|
||||
i2c::SendByte(i2c::Port_5, GetI2cAddressForMarikoMax77812(regulator), Max77812RegisterEnCtrl, 0x40);
|
||||
}
|
||||
|
||||
void EnableVddCpuMariko(Regulator regulator) {
|
||||
const int address = GetI2cAddressForMarikoMax77812(regulator);
|
||||
|
||||
/* Set EN_M3_LPM to enable BUCK Master 3 low power mode. */
|
||||
u8 ctrl;
|
||||
if (i2c::Query(std::addressof(ctrl), sizeof(ctrl), i2c::Port_5, address, Max77812RegisterEnCtrl)) {
|
||||
ctrl |= 0x40;
|
||||
i2c::SendByte(i2c::Port_5, address, Max77812RegisterEnCtrl, ctrl);
|
||||
}
|
||||
|
||||
/* Set BUCK Master 4 output voltage to 110. */
|
||||
i2c::SendByte(i2c::Port_5, address, Max77812RegisterM4VOut, 110);
|
||||
}
|
||||
|
||||
void DisableVddCpuMariko(Regulator regulator) {
|
||||
const int address = GetI2cAddressForMarikoMax77812(regulator);
|
||||
|
||||
/* Clear EN_M3_LPM to disable BUCK Master 3 low power mode. */
|
||||
u8 ctrl;
|
||||
if (i2c::Query(std::addressof(ctrl), sizeof(ctrl), i2c::Port_5, address, Max77812RegisterEnCtrl)) {
|
||||
ctrl &= ~0x40;
|
||||
i2c::SendByte(i2c::Port_5, address, Max77812RegisterEnCtrl, ctrl);
|
||||
}
|
||||
}
|
||||
|
||||
u8 GetPmicOnOffStat() {
|
||||
return i2c::QueryByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterOnOffStat);
|
||||
}
|
||||
|
||||
void ShutdownSystemImpl(bool reboot) {
|
||||
/* Get value, set or clear software reset mask. */
|
||||
u8 on_off_2_val = i2c::QueryByte(i2c::Port_5, I2cAddressMax77620Pmic, MAX77620_REG_ONOFFCNFG2);
|
||||
if (reboot) {
|
||||
on_off_2_val |= MAX77620_ONOFFCNFG2_SFT_RST_WK;
|
||||
} else {
|
||||
on_off_2_val &= ~(MAX77620_ONOFFCNFG2_SFT_RST_WK);
|
||||
}
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, MAX77620_REG_ONOFFCNFG2, on_off_2_val);
|
||||
|
||||
/* Get value, set software reset mask. */
|
||||
u8 on_off_1_val = i2c::QueryByte(i2c::Port_5, I2cAddressMax77620Pmic, MAX77620_REG_ONOFFCNFG1);
|
||||
on_off_1_val |= MAX77620_ONOFFCNFG1_SFT_RST;
|
||||
|
||||
/* NOTE: Here, userland finalizes the battery on non-Calcio. */
|
||||
if (fuse::GetHardwareType() != fuse::HardwareType_Calcio) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
/* Actually write the value to trigger shutdown/reset. */
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, MAX77620_REG_ONOFFCNFG1, on_off_1_val);
|
||||
}
|
||||
|
||||
void SetBackupBatteryConfig() {
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterCnfgBbc, 0x40);
|
||||
}
|
||||
|
||||
void SetForcePowerOffTimeConfig() {
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterOnOffCnfg1, 0x58);
|
||||
}
|
||||
|
||||
void SetFlexiblePowerSequencer() {
|
||||
/* Configure FPS registers. */
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterCnfgFps0, 0x38);
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterCnfgFps1, 0x3A);
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterCnfgFps2, 0x38);
|
||||
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterFpsLdo4, 0x0F);
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterFpsLdo8, 0xC7);
|
||||
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterFpsSd0, 0x4F);
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterFpsSd1, 0x29);
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterFpsSd3, 0x1B);
|
||||
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterFpsGpio3, 0x22);
|
||||
}
|
||||
|
||||
void SetVoltage(int reg, int mv) {
|
||||
const u8 v = ((mv - 600) * 1000) / 12500;
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, reg, v);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SetEnBit(Regulator regulator) {
|
||||
switch (regulator) {
|
||||
case Regulator_Erista_Max77621:
|
||||
return SetEnBitErista();
|
||||
case Regulator_Mariko_Max77812_A:
|
||||
case Regulator_Mariko_Max77812_B:
|
||||
return SetEnBitMariko(regulator);
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
void EnableVddCpu(Regulator regulator) {
|
||||
switch (regulator) {
|
||||
case Regulator_Erista_Max77621:
|
||||
return EnableVddCpuErista();
|
||||
case Regulator_Mariko_Max77812_A:
|
||||
case Regulator_Mariko_Max77812_B:
|
||||
return EnableVddCpuMariko(regulator);
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
void DisableVddCpu(Regulator regulator) {
|
||||
switch (regulator) {
|
||||
case Regulator_Erista_Max77621:
|
||||
return DisableVddCpuErista();
|
||||
case Regulator_Mariko_Max77812_A:
|
||||
case Regulator_Mariko_Max77812_B:
|
||||
return DisableVddCpuMariko(regulator);
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
void EnableSleep() {
|
||||
/* Get the current onoff cfg. */
|
||||
u8 cnfg = i2c::QueryByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterOnOffCnfg1);
|
||||
|
||||
/* Set SlpEn. */
|
||||
cnfg |= MAX77620_ONOFFCNFG1_SLPEN;
|
||||
|
||||
/* Write the new cfg. */
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterOnOffCnfg1, cnfg);
|
||||
}
|
||||
|
||||
void ShutdownSystem(bool reboot) {
|
||||
ShutdownSystemImpl(reboot);
|
||||
|
||||
/* Allow up to 5 seconds for shutdown/reboot to take place. */
|
||||
util::WaitMicroSeconds(5'000'000ul);
|
||||
|
||||
AMS_ABORT("Shutdown failed");
|
||||
}
|
||||
|
||||
void PowerOff() {
|
||||
ShutdownSystemImpl(false);
|
||||
}
|
||||
|
||||
bool IsAcOk() {
|
||||
return (GetPmicOnOffStat() & (1 << 1)) != 0;
|
||||
}
|
||||
|
||||
bool IsPowerButtonPressed() {
|
||||
return (GetPmicOnOffStat() & (1 << 2)) != 0;
|
||||
}
|
||||
|
||||
void SetSystemSetting(fuse::SocType soc_type) {
|
||||
SetBackupBatteryConfig();
|
||||
SetForcePowerOffTimeConfig();
|
||||
if (soc_type == fuse::SocType_Erista) {
|
||||
SetFlexiblePowerSequencer();
|
||||
}
|
||||
}
|
||||
|
||||
void EnableVddCore(fuse::SocType soc_type) {
|
||||
if (soc_type == fuse::SocType_Erista) {
|
||||
SetVoltage(Max77620RegisterSd0, 1125);
|
||||
} else /* if (soc_type == fuse::SocType_Mariko) */ {
|
||||
SetVoltage(Max77620RegisterSd0, 1050);
|
||||
}
|
||||
}
|
||||
|
||||
void EnableLdo8() {
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterCnfg1Ldo8, 0xE8);
|
||||
}
|
||||
|
||||
void EnableVddMemory(fuse::SocType soc_type) {
|
||||
/* Disable remote sense for Sd1. */
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterCnfg2Sd, 0x05);
|
||||
|
||||
/* On Erista, set Sd1 voltage. */
|
||||
if (soc_type == fuse::SocType_Erista) {
|
||||
SetVoltage(Max77620RegisterSd1, 1100);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC
|
||||
*
|
||||
* Copyright (c) 2018 CTCaer
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef _MFD_MAX77620_RTC_H_
|
||||
#define _MFD_MAX77620_RTC_H_
|
||||
|
||||
#define MAX77620_RTC_I2C_ADDR 0x68
|
||||
|
||||
#define MAX77620_RTC_NR_TIME_REGS 7
|
||||
|
||||
#define MAX77620_RTC_CONTROLM_REG 0x02
|
||||
#define MAX77620_RTC_CONTROL_REG 0x03
|
||||
#define MAX77620_RTC_BIN_FORMAT (1 << 0)
|
||||
#define MAX77620_RTC_24H (1 << 1)
|
||||
|
||||
#define MAX77620_RTC_UPDATE0_REG 0x04
|
||||
#define MAX77620_RTC_WRITE_UPDATE (1 << 0)
|
||||
#define MAX77620_RTC_READ_UPDATE (1 << 4)
|
||||
|
||||
#define MAX77620_RTC_SEC_REG 0x07
|
||||
#define MAX77620_RTC_MIN_REG 0x08
|
||||
#define MAX77620_RTC_HOUR_REG 0x09
|
||||
#define MAX77620_RTC_HOUR_PM_MASK (1 << 6)
|
||||
#define MAX77620_RTC_WEEKDAY_REG 0x0A
|
||||
#define MAX77620_RTC_MONTH_REG 0x0B
|
||||
#define MAX77620_RTC_YEAR_REG 0x0C
|
||||
#define MAX77620_RTC_DATE_REG 0x0D
|
||||
|
||||
#define MAX77620_ALARM1_SEC_REG 0x0E
|
||||
#define MAX77620_ALARM1_MIN_REG 0x0F
|
||||
#define MAX77620_ALARM1_HOUR_REG 0x10
|
||||
#define MAX77620_ALARM1_WEEKDAY_REG 0x11
|
||||
#define MAX77620_ALARM1_MONTH_REG 0x12
|
||||
#define MAX77620_ALARM1_YEAR_REG 0x13
|
||||
#define MAX77620_ALARM1_DATE_REG 0x14
|
||||
#define MAX77620_ALARM2_SEC_REG 0x15
|
||||
#define MAX77620_ALARM2_MIN_REG 0x16
|
||||
#define MAX77620_ALARM2_HOUR_REG 0x17
|
||||
#define MAX77620_ALARM2_WEEKDAY_REG 0x18
|
||||
#define MAX77620_ALARM2_MONTH_REG 0x19
|
||||
#define MAX77620_ALARM2_YEAR_REG 0x1A
|
||||
#define MAX77620_ALARM2_DATE_REG 0x1B
|
||||
#define MAX77620_RTC_ALARM_EN_MASK (1 << 7)
|
||||
|
||||
#endif /* _MFD_MAX77620_RTC_H_ */
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "max77620-rtc.h"
|
||||
|
||||
namespace ams::rtc {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline int I2cAddressMax77620Rtc = 0x68;
|
||||
|
||||
/* TODO: Find datasheet, link to it instead. */
|
||||
/* NOTE: Tentatively, Max77620 "mostly" matches https://datasheets.maximintegrated.com/en/ds/MAX77863.pdf. */
|
||||
constexpr inline int Max77620RtcRegisterUpdate0 = 0x04;
|
||||
|
||||
constexpr inline int Max77620RtcRegisterAlarmStart = 0x0E;
|
||||
|
||||
constexpr inline int Max77620RtcRegisterAlarm1Sec = 0x0E;
|
||||
constexpr inline int Max77620RtcRegisterAlarm1Min = 0x0F;
|
||||
constexpr inline int Max77620RtcRegisterAlarm1Hour = 0x10;
|
||||
constexpr inline int Max77620RtcRegisterAlarm1Weekday = 0x11;
|
||||
constexpr inline int Max77620RtcRegisterAlarm1Month = 0x12;
|
||||
constexpr inline int Max77620RtcRegisterAlarm1Year = 0x13;
|
||||
constexpr inline int Max77620RtcRegisterAlarm1Date = 0x14;
|
||||
constexpr inline int Max77620RtcRegisterAlarm2Sec = 0x15;
|
||||
constexpr inline int Max77620RtcRegisterAlarm2Min = 0x16;
|
||||
constexpr inline int Max77620RtcRegisterAlarm2Hour = 0x17;
|
||||
constexpr inline int Max77620RtcRegisterAlarm2Weekday = 0x18;
|
||||
constexpr inline int Max77620RtcRegisterAlarm2Month = 0x19;
|
||||
constexpr inline int Max77620RtcRegisterAlarm2Year = 0x1A;
|
||||
constexpr inline int Max77620RtcRegisterAlarm2Date = 0x1B;
|
||||
|
||||
constexpr inline int Max77620RtcRegisterAlarmLast = 0x1B;
|
||||
|
||||
}
|
||||
|
||||
void StopAlarm() {
|
||||
/* Begin update. */
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressMax77620Rtc, Max77620RtcRegisterUpdate0, MAX77620_RTC_READ_UPDATE);
|
||||
|
||||
/* Clear ALARM_EN for all alarm registers. */
|
||||
for (auto reg = Max77620RtcRegisterAlarmStart; reg <= Max77620RtcRegisterAlarmLast; ++reg) {
|
||||
u8 val = i2c::QueryByte(i2c::Port_5, I2cAddressMax77620Rtc, reg);
|
||||
val &= ~MAX77620_RTC_ALARM_EN_MASK;
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressMax77620Rtc, reg, val);
|
||||
}
|
||||
|
||||
/* End update. */
|
||||
i2c::SendByte(i2c::Port_5, I2cAddressMax77620Rtc, Max77620RtcRegisterUpdate0, MAX77620_RTC_WRITE_UPDATE);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,703 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "se_execute.hpp"
|
||||
|
||||
namespace ams::se {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline int AesKeySizeMax = 256 / BITSIZEOF(u8);
|
||||
|
||||
enum AesMode {
|
||||
AesMode_Aes128 = ((SE_CONFIG_ENC_MODE_AESMODE_KEY128 << SE_CONFIG_ENC_MODE_OFFSET) | (SE_CONFIG_DEC_MODE_AESMODE_KEY128 << SE_CONFIG_DEC_MODE_OFFSET)) >> SE_CONFIG_DEC_MODE_OFFSET,
|
||||
AesMode_Aes192 = ((SE_CONFIG_ENC_MODE_AESMODE_KEY192 << SE_CONFIG_ENC_MODE_OFFSET) | (SE_CONFIG_DEC_MODE_AESMODE_KEY192 << SE_CONFIG_DEC_MODE_OFFSET)) >> SE_CONFIG_DEC_MODE_OFFSET,
|
||||
AesMode_Aes256 = ((SE_CONFIG_ENC_MODE_AESMODE_KEY256 << SE_CONFIG_ENC_MODE_OFFSET) | (SE_CONFIG_DEC_MODE_AESMODE_KEY256 << SE_CONFIG_DEC_MODE_OFFSET)) >> SE_CONFIG_DEC_MODE_OFFSET,
|
||||
};
|
||||
|
||||
enum MemoryInterface {
|
||||
MemoryInterface_Ahb = SE_CRYPTO_CONFIG_MEMIF_AHB,
|
||||
MemoryInterface_Mc = SE_CRYPTO_CONFIG_MEMIF_MCCIF,
|
||||
};
|
||||
|
||||
constexpr inline u32 AesConfigEcb = reg::Encode(SE_REG_BITS_VALUE(CRYPTO_CONFIG_CTR_CNTN, 0),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_KEYSCH_BYPASS, DISABLE),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_IV_SELECT, ORIGINAL),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_VCTRAM_SEL, MEMORY),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_INPUT_SEL, MEMORY),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_XOR_POS, BYPASS),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_HASH_ENB, DISABLE));
|
||||
|
||||
constexpr inline u32 AesConfigCtr = reg::Encode(SE_REG_BITS_VALUE(CRYPTO_CONFIG_CTR_CNTN, 1),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_KEYSCH_BYPASS, DISABLE),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_IV_SELECT, ORIGINAL),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_VCTRAM_SEL, MEMORY),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_INPUT_SEL, LINEAR_CTR),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_XOR_POS, BOTTOM),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_HASH_ENB, DISABLE));
|
||||
|
||||
constexpr inline u32 AesConfigCmac = reg::Encode(SE_REG_BITS_VALUE(CRYPTO_CONFIG_CTR_CNTN, 0),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_KEYSCH_BYPASS, DISABLE),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_IV_SELECT, ORIGINAL),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_VCTRAM_SEL, INIT_AESOUT),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_INPUT_SEL, MEMORY),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_XOR_POS, TOP),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_HASH_ENB, ENABLE));
|
||||
|
||||
constexpr inline u32 AesConfigCbcEncrypt = reg::Encode(SE_REG_BITS_VALUE(CRYPTO_CONFIG_CTR_CNTN, 0),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_KEYSCH_BYPASS, DISABLE),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_IV_SELECT, ORIGINAL),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_VCTRAM_SEL, INIT_AESOUT),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_INPUT_SEL, MEMORY),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_XOR_POS, TOP),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_HASH_ENB, DISABLE));
|
||||
|
||||
constexpr inline u32 AesConfigCbcDecrypt = reg::Encode(SE_REG_BITS_VALUE(CRYPTO_CONFIG_CTR_CNTN, 0),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_KEYSCH_BYPASS, DISABLE),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_IV_SELECT, ORIGINAL),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_VCTRAM_SEL, INIT_PREV_MEMORY),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_INPUT_SEL, MEMORY),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_XOR_POS, BOTTOM),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_HASH_ENB, DISABLE));
|
||||
|
||||
void SetConfig(volatile SecurityEngineRegisters *SE, bool encrypt, SE_CONFIG_DST dst) {
|
||||
reg::Write(SE->SE_CONFIG, SE_REG_BITS_ENUM (CONFIG_ENC_MODE, AESMODE_KEY128),
|
||||
SE_REG_BITS_ENUM (CONFIG_DEC_MODE, AESMODE_KEY128),
|
||||
SE_REG_BITS_ENUM_SEL(CONFIG_ENC_ALG, encrypt, AES_ENC, NOP),
|
||||
SE_REG_BITS_ENUM_SEL(CONFIG_DEC_ALG, encrypt, NOP, AES_DEC),
|
||||
SE_REG_BITS_VALUE (CONFIG_DST, dst));
|
||||
}
|
||||
|
||||
void SetAesConfig(volatile SecurityEngineRegisters *SE, int slot, bool encrypt, u32 config) {
|
||||
const u32 encoded = reg::Encode(SE_REG_BITS_ENUM (CRYPTO_CONFIG_MEMIF, AHB),
|
||||
SE_REG_BITS_VALUE (CRYPTO_CONFIG_KEY_INDEX, slot),
|
||||
SE_REG_BITS_ENUM_SEL(CRYPTO_CONFIG_CORE_SEL, encrypt, ENCRYPT, DECRYPT));
|
||||
|
||||
reg::Write(SE->SE_CRYPTO_CONFIG, (config | encoded));
|
||||
}
|
||||
|
||||
void SetBlockCount(volatile SecurityEngineRegisters *SE, int count) {
|
||||
reg::Write(SE->SE_CRYPTO_LAST_BLOCK, count - 1);
|
||||
}
|
||||
|
||||
void UpdateAesMode(volatile SecurityEngineRegisters *SE, AesMode mode) {
|
||||
reg::ReadWrite(SE->SE_CONFIG, REG_BITS_VALUE(16, 16, mode));
|
||||
}
|
||||
|
||||
void UpdateMemoryInterface(volatile SecurityEngineRegisters *SE, MemoryInterface memif) {
|
||||
reg::ReadWrite(SE->SE_CRYPTO_CONFIG, SE_REG_BITS_VALUE(CRYPTO_CONFIG_MEMIF, memif));
|
||||
}
|
||||
|
||||
void SetCounter(volatile SecurityEngineRegisters *SE, const void *ctr) {
|
||||
const u32 *ctr_32 = reinterpret_cast<const u32 *>(ctr);
|
||||
|
||||
/* Copy the input ctr to the linear CTR registers. */
|
||||
reg::Write(SE->SE_CRYPTO_LINEAR_CTR[0], util::LoadLittleEndian(ctr_32 + 0));
|
||||
reg::Write(SE->SE_CRYPTO_LINEAR_CTR[1], util::LoadLittleEndian(ctr_32 + 1));
|
||||
reg::Write(SE->SE_CRYPTO_LINEAR_CTR[2], util::LoadLittleEndian(ctr_32 + 2));
|
||||
reg::Write(SE->SE_CRYPTO_LINEAR_CTR[3], util::LoadLittleEndian(ctr_32 + 3));
|
||||
}
|
||||
|
||||
void SetAesKeyIv(volatile SecurityEngineRegisters *SE, int slot, const void *iv, size_t iv_size) {
|
||||
AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount);
|
||||
AMS_ABORT_UNLESS(iv_size <= AesBlockSize);
|
||||
|
||||
/* Set each iv word in order. */
|
||||
const u32 *iv_u32 = static_cast<const u32 *>(iv);
|
||||
const int num_words = iv_size / sizeof(u32);
|
||||
for (int i = 0; i < num_words; ++i) {
|
||||
/* Select the keyslot. */
|
||||
reg::Write(SE->SE_CRYPTO_KEYTABLE_ADDR, SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_SLOT, slot),
|
||||
SE_REG_BITS_ENUM (CRYPTO_KEYTABLE_ADDR_KEYIV_KEYIV_SEL, IV),
|
||||
SE_REG_BITS_ENUM (CRYPTO_KEYTABLE_ADDR_KEYIV_IV_SEL, ORIGINAL_IV),
|
||||
SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_WORD, i));
|
||||
|
||||
/* Set the iv word. */
|
||||
SE->SE_CRYPTO_KEYTABLE_DATA = *(iv_u32++);
|
||||
}
|
||||
}
|
||||
|
||||
void SetEncryptedAesKey(int dst_slot, int kek_slot, const void *key, size_t key_size, AesMode mode) {
|
||||
AMS_ABORT_UNLESS(key_size <= AesKeySizeMax);
|
||||
AMS_ABORT_UNLESS(0 <= dst_slot && dst_slot < AesKeySlotCount);
|
||||
AMS_ABORT_UNLESS(0 <= kek_slot && kek_slot < AesKeySlotCount);
|
||||
|
||||
/* Get the engine. */
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Configure for single AES ECB decryption to key table. */
|
||||
SetConfig(SE, false, SE_CONFIG_DST_KEYTABLE);
|
||||
SetAesConfig(SE, kek_slot, false, AesConfigEcb);
|
||||
UpdateAesMode(SE, mode);
|
||||
SetBlockCount(SE, 1);
|
||||
|
||||
/* Select the destination keyslot. */
|
||||
reg::Write(SE->SE_CRYPTO_KEYTABLE_DST, SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_DST_KEY_INDEX, dst_slot), SE_REG_BITS_ENUM(CRYPTO_KEYTABLE_DST_WORD_QUAD, KEYS_0_3));
|
||||
|
||||
/* Ensure that the se sees the keydata we want it to. */
|
||||
hw::FlushDataCache(key, key_size);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Execute the operation. */
|
||||
ExecuteOperation(SE, SE_OPERATION_OP_START, nullptr, 0, key, key_size);
|
||||
}
|
||||
|
||||
void EncryptAes(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, AesMode mode) {
|
||||
/* If nothing to decrypt, succeed. */
|
||||
if (src_size == 0) { return; }
|
||||
|
||||
/* Validate input. */
|
||||
AMS_ABORT_UNLESS(dst_size == AesBlockSize);
|
||||
AMS_ABORT_UNLESS(src_size == AesBlockSize);
|
||||
AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount);
|
||||
|
||||
/* Get the engine. */
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Configure for AES-ECB encryption to memory. */
|
||||
SetConfig(SE, true, SE_CONFIG_DST_MEMORY);
|
||||
SetAesConfig(SE, slot, true, AesConfigEcb);
|
||||
UpdateAesMode(SE, mode);
|
||||
|
||||
/* Execute the operation. */
|
||||
ExecuteOperationSingleBlock(SE, dst, dst_size, src, src_size);
|
||||
}
|
||||
|
||||
void ExpandSubkey(u8 *subkey) {
|
||||
/* Shift everything left one bit. */
|
||||
u8 prev = 0;
|
||||
for (int i = AesBlockSize - 1; i >= 0; --i) {
|
||||
const u8 top = (subkey[i] >> 7);
|
||||
subkey[i] = ((subkey[i] << 1) | prev);
|
||||
prev = top;
|
||||
}
|
||||
|
||||
/* And xor with Rb if necessary. */
|
||||
if (prev != 0) {
|
||||
subkey[AesBlockSize - 1] ^= 0x87;
|
||||
}
|
||||
}
|
||||
|
||||
void ExpandSubkeyLittleEndian(u8 *subkey) {
|
||||
/* Shift everything left one bit. */
|
||||
u8 prev = 0;
|
||||
for (size_t i = 0; i < AesBlockSize; ++i) {
|
||||
const u8 top = (subkey[i] >> 7);
|
||||
subkey[i] = ((subkey[i] << 1) | prev);
|
||||
prev = top;
|
||||
}
|
||||
|
||||
/* And xor with Rb if necessary. */
|
||||
if (prev != 0) {
|
||||
subkey[0] ^= 0x87;
|
||||
}
|
||||
}
|
||||
|
||||
void GetCmacResult(volatile SecurityEngineRegisters *SE, void *dst, size_t dst_size) {
|
||||
const int num_words = dst_size / sizeof(u32);
|
||||
for (int i = 0; i < num_words; ++i) {
|
||||
reg::Write(static_cast<u32 *>(dst) + i, reg::Read(SE->SE_HASH_RESULT[i]));
|
||||
}
|
||||
}
|
||||
|
||||
void ComputeAesCmac(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, AesMode mode) {
|
||||
/* Validate input. */
|
||||
AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount);
|
||||
|
||||
/* Get the engine. */
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Determine mac extents. */
|
||||
const int num_blocks = util::DivideUp(src_size, AesBlockSize);
|
||||
const size_t last_block_size = (src_size == 0) ? 0 : (src_size - ((num_blocks - 1) * AesBlockSize));
|
||||
|
||||
/* Create subkey. */
|
||||
u8 subkey[AesBlockSize];
|
||||
{
|
||||
/* Encrypt zeroes. */
|
||||
std::memset(subkey, 0, sizeof(subkey));
|
||||
EncryptAes(subkey, sizeof(subkey), slot, subkey, sizeof(subkey), mode);
|
||||
|
||||
/* Expand. */
|
||||
ExpandSubkey(subkey);
|
||||
|
||||
/* Account for last block. */
|
||||
if (last_block_size != AesBlockSize) {
|
||||
ExpandSubkey(subkey);
|
||||
}
|
||||
}
|
||||
|
||||
/* Configure for AES-CMAC. */
|
||||
SetConfig(SE, true, SE_CONFIG_DST_HASH_REG);
|
||||
SetAesConfig(SE, slot, true, AesConfigCmac);
|
||||
UpdateAesMode(SE, mode);
|
||||
|
||||
/* Set the IV to zero. */
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
/* Select the keyslot. */
|
||||
reg::Write(SE->SE_CRYPTO_KEYTABLE_ADDR, SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_SLOT, slot),
|
||||
SE_REG_BITS_ENUM (CRYPTO_KEYTABLE_ADDR_KEYIV_KEYIV_SEL, IV),
|
||||
SE_REG_BITS_ENUM (CRYPTO_KEYTABLE_ADDR_KEYIV_IV_SEL, ORIGINAL_IV),
|
||||
SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_WORD, i));
|
||||
|
||||
/* Set the iv word. */
|
||||
SE->SE_CRYPTO_KEYTABLE_DATA = 0;
|
||||
}
|
||||
|
||||
/* Handle blocks before the last. */
|
||||
if (num_blocks > 1) {
|
||||
SetBlockCount(SE, num_blocks - 1);
|
||||
ExecuteOperation(SE, SE_OPERATION_OP_START, nullptr, 0, src, src_size);
|
||||
reg::ReadWrite(SE->SE_CRYPTO_CONFIG, SE_REG_BITS_ENUM(CRYPTO_CONFIG_IV_SELECT, UPDATED));
|
||||
}
|
||||
|
||||
/* Handle the last block. */
|
||||
{
|
||||
SetBlockCount(SE, 1);
|
||||
|
||||
/* Create the last block. */
|
||||
u8 last_block[AesBlockSize];
|
||||
if (last_block_size < sizeof(last_block)) {
|
||||
std::memset(last_block, 0, sizeof(last_block));
|
||||
last_block[last_block_size] = 0x80;
|
||||
}
|
||||
std::memcpy(last_block, static_cast<const u8 *>(src) + src_size - last_block_size, last_block_size);
|
||||
|
||||
/* Xor with the subkey. */
|
||||
for (size_t i = 0; i < AesBlockSize; ++i) {
|
||||
last_block[i] ^= subkey[i];
|
||||
}
|
||||
|
||||
/* Ensure the SE sees correct data. */
|
||||
hw::FlushDataCache(last_block, sizeof(last_block));
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
ExecuteOperation(SE, SE_OPERATION_OP_START, nullptr, 0, last_block, sizeof(last_block));
|
||||
}
|
||||
|
||||
/* Get the output. */
|
||||
GetCmacResult(SE, dst, dst_size);
|
||||
}
|
||||
|
||||
void EncryptAesCbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size, AesMode mode) {
|
||||
/* If nothing to encrypt, succeed. */
|
||||
if (src_size == 0) { return; }
|
||||
|
||||
/* Validate input. */
|
||||
AMS_ABORT_UNLESS(iv_size == AesBlockSize);
|
||||
AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount);
|
||||
|
||||
/* Get the engine. */
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Determine extents. */
|
||||
const size_t num_blocks = src_size / AesBlockSize;
|
||||
const size_t aligned_size = num_blocks * AesBlockSize;
|
||||
AMS_ABORT_UNLESS(src_size == aligned_size);
|
||||
|
||||
/* Configure for aes-cbc encryption. */
|
||||
SetConfig(SE, true, SE_CONFIG_DST_MEMORY);
|
||||
SetAesConfig(SE, slot, true, AesConfigCbcEncrypt);
|
||||
UpdateAesMode(SE, mode);
|
||||
|
||||
/* Set the iv. */
|
||||
SetAesKeyIv(SE, slot, iv, iv_size);
|
||||
|
||||
/* Set the block count. */
|
||||
SetBlockCount(SE, num_blocks);
|
||||
|
||||
/* Execute the operation. */
|
||||
ExecuteOperation(SE, SE_OPERATION_OP_START, dst, dst_size, src, aligned_size);
|
||||
}
|
||||
|
||||
void DecryptAesCbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size, AesMode mode) {
|
||||
/* If nothing to decrypt, succeed. */
|
||||
if (src_size == 0) { return; }
|
||||
|
||||
/* Validate input. */
|
||||
AMS_ABORT_UNLESS(iv_size == AesBlockSize);
|
||||
AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount);
|
||||
|
||||
/* Get the engine. */
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Determine extents. */
|
||||
const size_t num_blocks = src_size / AesBlockSize;
|
||||
const size_t aligned_size = num_blocks * AesBlockSize;
|
||||
AMS_ABORT_UNLESS(src_size == aligned_size);
|
||||
|
||||
/* Configure for aes-cbc encryption. */
|
||||
SetConfig(SE, false, SE_CONFIG_DST_MEMORY);
|
||||
SetAesConfig(SE, slot, false, AesConfigCbcDecrypt);
|
||||
UpdateAesMode(SE, mode);
|
||||
|
||||
/* Set the iv. */
|
||||
SetAesKeyIv(SE, slot, iv, iv_size);
|
||||
|
||||
/* Set the block count. */
|
||||
SetBlockCount(SE, num_blocks);
|
||||
|
||||
/* Execute the operation. */
|
||||
ExecuteOperation(SE, SE_OPERATION_OP_START, dst, dst_size, src, aligned_size);
|
||||
}
|
||||
|
||||
void XorWithXtsTweak(void *dst, size_t dst_size, const void *src, size_t src_size, const void *base_tweak) {
|
||||
/* Copy tweak. */
|
||||
u8 tweak[se::AesBlockSize];
|
||||
std::memcpy(tweak, base_tweak, sizeof(tweak));
|
||||
|
||||
/* Perform xor. */
|
||||
u8 *dst_u8 = static_cast<u8 *>(dst);
|
||||
const u8 *src_u8 = static_cast<const u8 *>(src);
|
||||
|
||||
const size_t num_blocks = std::min<size_t>(dst_size, src_size) / sizeof(tweak);
|
||||
for (size_t i = 0; i < num_blocks; ++i) {
|
||||
for (size_t j = 0; j < sizeof(tweak); ++j) {
|
||||
dst_u8[j] = src_u8[j] ^ tweak[j];
|
||||
}
|
||||
|
||||
dst_u8 += sizeof(tweak);
|
||||
src_u8 += sizeof(tweak);
|
||||
|
||||
ExpandSubkeyLittleEndian(tweak);
|
||||
}
|
||||
}
|
||||
|
||||
void DecryptAesXts(void *dst, size_t dst_size, int slot_enc, int slot_tweak, const void *src, size_t src_size, size_t sector, AesMode mode) {
|
||||
/* If nothing to decrypt, succeed. */
|
||||
if (src_size == 0) { return; }
|
||||
|
||||
/* Validate input. */
|
||||
AMS_ABORT_UNLESS(util::IsAligned(dst_size, AesBlockSize));
|
||||
AMS_ABORT_UNLESS(util::IsAligned(src_size, AesBlockSize));
|
||||
AMS_ABORT_UNLESS(0 <= slot_enc && slot_enc < AesKeySlotCount);
|
||||
AMS_ABORT_UNLESS(0 <= slot_tweak && slot_tweak < AesKeySlotCount);
|
||||
|
||||
/* Generate tweak. */
|
||||
u32 base_tweak[se::AesBlockSize / sizeof(u32)] = {};
|
||||
base_tweak[util::size(base_tweak) - 1] = util::ConvertToBigEndian<u32>(static_cast<u32>(sector));
|
||||
if constexpr (sizeof(sector) > sizeof(u32)) {
|
||||
static_assert(sizeof(sector) <= sizeof(u64));
|
||||
base_tweak[util::size(base_tweak) - 2] = util::ConvertToBigEndian<u32>(static_cast<u32>(sector >> BITSIZEOF(u32)));
|
||||
}
|
||||
se::EncryptAes128(base_tweak, sizeof(base_tweak), slot_tweak, base_tweak, sizeof(base_tweak));
|
||||
|
||||
/* Xor all data. */
|
||||
XorWithXtsTweak(dst, dst_size, src, src_size, base_tweak);
|
||||
|
||||
/* Ensure the SE sees correct data. */
|
||||
hw::FlushDataCache(dst, dst_size);
|
||||
|
||||
/* Decrypt all data. */
|
||||
{
|
||||
/* Get the engine. */
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Determine extents. */
|
||||
const size_t num_blocks = dst_size / AesBlockSize;
|
||||
|
||||
/* Configure for AES-ECB decryption to memory. */
|
||||
SetConfig(SE, false, SE_CONFIG_DST_MEMORY);
|
||||
SetAesConfig(SE, slot_enc, false, AesConfigEcb);
|
||||
UpdateAesMode(SE, mode);
|
||||
|
||||
/* Set the block count. */
|
||||
SetBlockCount(SE, num_blocks);
|
||||
|
||||
/* Execute the operation. */
|
||||
ExecuteOperation(SE, SE_OPERATION_OP_START, dst, dst_size, dst, dst_size);
|
||||
|
||||
/* Ensure the cpu sees correct data. */
|
||||
hw::InvalidateDataCache(dst, dst_size);
|
||||
}
|
||||
|
||||
/* Xor all data. */
|
||||
XorWithXtsTweak(dst, dst_size, dst, dst_size, base_tweak);
|
||||
}
|
||||
|
||||
void ComputeAes128Async(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, DoneHandler handler, u32 config, bool encrypt, volatile SecurityEngineRegisters *SE) {
|
||||
/* If nothing to decrypt, succeed. */
|
||||
if (size == 0) { return; }
|
||||
|
||||
/* Validate input. */
|
||||
AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount);
|
||||
|
||||
/* Configure for the specific operation. */
|
||||
SetConfig(SE, encrypt, SE_CONFIG_DST_MEMORY);
|
||||
SetAesConfig(SE, slot, encrypt, config);
|
||||
UpdateMemoryInterface(SE, MemoryInterface_Mc);
|
||||
|
||||
/* Configure the number of blocks. */
|
||||
const int num_blocks = size / AesBlockSize;
|
||||
SetBlockCount(SE, num_blocks);
|
||||
|
||||
/* Set the done handler. */
|
||||
SetDoneHandler(SE, handler);
|
||||
|
||||
/* Start the raw operation. */
|
||||
StartOperationRaw(SE, SE_OPERATION_OP_START, out_ll_address, in_ll_address);
|
||||
}
|
||||
|
||||
void ClearAesKeySlot(volatile SecurityEngineRegisters *SE, int slot) {
|
||||
/* Validate the key slot. */
|
||||
AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount);
|
||||
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
/* Select the keyslot. */
|
||||
reg::Write(SE->SE_CRYPTO_KEYTABLE_ADDR, SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_SLOT, slot), SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_WORD, i));
|
||||
|
||||
/* Write the data. */
|
||||
SE->SE_CRYPTO_KEYTABLE_DATA = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ClearAesKeySlot(int slot) {
|
||||
/* Clear the slot in SE1. */
|
||||
ClearAesKeySlot(GetRegisters(), slot);
|
||||
}
|
||||
|
||||
void ClearAesKeySlot2(int slot) {
|
||||
/* Clear the slot in SE2. */
|
||||
ClearAesKeySlot(GetRegisters2(), slot);
|
||||
}
|
||||
|
||||
void ClearAesKeyIv(int slot) {
|
||||
/* Validate the key slot. */
|
||||
AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount);
|
||||
|
||||
/* Get the engine. */
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Set each iv word in order. */
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
/* Select the keyslot original iv. */
|
||||
reg::Write(SE->SE_CRYPTO_KEYTABLE_ADDR, SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_SLOT, slot),
|
||||
SE_REG_BITS_ENUM (CRYPTO_KEYTABLE_ADDR_KEYIV_KEYIV_SEL, IV),
|
||||
SE_REG_BITS_ENUM (CRYPTO_KEYTABLE_ADDR_KEYIV_IV_SEL, ORIGINAL_IV),
|
||||
SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_WORD, i));
|
||||
|
||||
/* Set the iv word. */
|
||||
SE->SE_CRYPTO_KEYTABLE_DATA = 0;
|
||||
|
||||
/* Select the keyslot updated iv. */
|
||||
reg::Write(SE->SE_CRYPTO_KEYTABLE_ADDR, SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_SLOT, slot),
|
||||
SE_REG_BITS_ENUM (CRYPTO_KEYTABLE_ADDR_KEYIV_KEYIV_SEL, IV),
|
||||
SE_REG_BITS_ENUM (CRYPTO_KEYTABLE_ADDR_KEYIV_IV_SEL, UPDATED_IV),
|
||||
SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_WORD, i));
|
||||
|
||||
/* Set the iv word. */
|
||||
SE->SE_CRYPTO_KEYTABLE_DATA = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void LockAesKeySlot(int slot, u32 flags) {
|
||||
/* Validate the key slot. */
|
||||
AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount);
|
||||
|
||||
/* Get the engine. */
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Set non per-key flags. */
|
||||
if ((flags & ~KeySlotLockFlags_PerKey) != 0) {
|
||||
/* KeySlotLockFlags_DstKeyTableOnly is Mariko-only. */
|
||||
if (fuse::GetSocType() == fuse::SocType_Mariko) {
|
||||
reg::ReadWrite(SE->SE_CRYPTO_KEYTABLE_ACCESS[slot], REG_BITS_VALUE(0, 7, ~flags), REG_BITS_VALUE(7, 1, ((flags & KeySlotLockFlags_DstKeyTableOnly) != 0) ? 1 : 0));
|
||||
} else {
|
||||
reg::ReadWrite(SE->SE_CRYPTO_KEYTABLE_ACCESS[slot], REG_BITS_VALUE(0, 7, ~flags));
|
||||
}
|
||||
}
|
||||
|
||||
/* Set per-key flag. */
|
||||
if ((flags & KeySlotLockFlags_PerKey) != 0) {
|
||||
reg::ReadWrite(SE->SE_CRYPTO_SECURITY_PERKEY, REG_BITS_VALUE(slot, 1, 0));
|
||||
}
|
||||
}
|
||||
|
||||
void SetAesKey(int slot, const void *key, size_t key_size) {
|
||||
/* Validate the key slot and key size. */
|
||||
AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount);
|
||||
AMS_ABORT_UNLESS(key_size <= AesKeySizeMax);
|
||||
|
||||
/* Get the engine. */
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Set each key word in order. */
|
||||
const u32 *key_u32 = static_cast<const u32 *>(key);
|
||||
const int num_words = key_size / sizeof(u32);
|
||||
for (int i = 0; i < num_words; ++i) {
|
||||
/* Select the keyslot. */
|
||||
reg::Write(SE->SE_CRYPTO_KEYTABLE_ADDR, SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_SLOT, slot),
|
||||
SE_REG_BITS_ENUM (CRYPTO_KEYTABLE_ADDR_KEYIV_KEYIV_SEL, KEY),
|
||||
SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_WORD, i));
|
||||
|
||||
/* Set the key word. */
|
||||
SE->SE_CRYPTO_KEYTABLE_DATA = *(key_u32++);
|
||||
}
|
||||
}
|
||||
|
||||
void SetEncryptedAesKey128(int dst_slot, int kek_slot, const void *key, size_t key_size) {
|
||||
return SetEncryptedAesKey(dst_slot, kek_slot, key, key_size, AesMode_Aes128);
|
||||
}
|
||||
|
||||
void SetEncryptedAesKey256(int dst_slot, int kek_slot, const void *key, size_t key_size) {
|
||||
return SetEncryptedAesKey(dst_slot, kek_slot, key, key_size, AesMode_Aes256);
|
||||
}
|
||||
|
||||
void EncryptAes128(void *dst, size_t dst_size, int slot, const void *src, size_t src_size) {
|
||||
return EncryptAes(dst, dst_size, slot, src, src_size, AesMode_Aes128);
|
||||
}
|
||||
|
||||
void DecryptAes128(void *dst, size_t dst_size, int slot, const void *src, size_t src_size) {
|
||||
/* If nothing to decrypt, succeed. */
|
||||
if (src_size == 0) { return; }
|
||||
|
||||
/* Validate input. */
|
||||
AMS_ABORT_UNLESS(dst_size == AesBlockSize);
|
||||
AMS_ABORT_UNLESS(src_size == AesBlockSize);
|
||||
AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount);
|
||||
|
||||
/* Get the engine. */
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Configure for AES-ECB decryption to memory. */
|
||||
SetConfig(SE, false, SE_CONFIG_DST_MEMORY);
|
||||
SetAesConfig(SE, slot, false, AesConfigEcb);
|
||||
|
||||
ExecuteOperationSingleBlock(SE, dst, dst_size, src, src_size);
|
||||
}
|
||||
|
||||
void ComputeAes128Ctr(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size) {
|
||||
/* If nothing to do, succeed. */
|
||||
if (src_size == 0) { return; }
|
||||
|
||||
/* Validate input. */
|
||||
AMS_ABORT_UNLESS(iv_size == AesBlockSize);
|
||||
AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount);
|
||||
|
||||
/* Get the engine. */
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Determine how many full blocks we can operate on. */
|
||||
const size_t num_blocks = src_size / AesBlockSize;
|
||||
const size_t aligned_size = num_blocks * AesBlockSize;
|
||||
const size_t fractional = src_size - aligned_size;
|
||||
|
||||
/* Here Nintendo writes 1 to SE_SPARE. It's unclear why they do this, but we will do so as well. */
|
||||
SE->SE_SPARE = 0x1;
|
||||
|
||||
/* Configure for AES-CTR encryption/decryption to memory. */
|
||||
SetConfig(SE, true, SE_CONFIG_DST_MEMORY);
|
||||
SetAesConfig(SE, slot, true, AesConfigCtr);
|
||||
|
||||
/* Set the counter. */
|
||||
SetCounter(SE, iv);
|
||||
|
||||
/* Process as many aligned blocks as we can. */
|
||||
if (aligned_size > 0) {
|
||||
/* Configure the engine to process the right number of blocks. */
|
||||
SetBlockCount(SE, num_blocks);
|
||||
|
||||
/* Execute the operation. */
|
||||
ExecuteOperation(SE, SE_OPERATION_OP_START, dst, dst_size, src, aligned_size);
|
||||
|
||||
/* Synchronize around this point. */
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
}
|
||||
|
||||
/* Process a single block to output. */
|
||||
if (fractional > 0 && dst_size > aligned_size) {
|
||||
const size_t copy_size = std::min(fractional, dst_size - aligned_size);
|
||||
|
||||
ExecuteOperationSingleBlock(SE, static_cast<u8 *>(dst) + aligned_size, copy_size, static_cast<const u8 *>(src) + aligned_size, fractional);
|
||||
}
|
||||
}
|
||||
|
||||
void ComputeAes128Cmac(void *dst, size_t dst_size, int slot, const void *src, size_t src_size) {
|
||||
return ComputeAesCmac(dst, dst_size, slot, src, src_size, AesMode_Aes128);
|
||||
}
|
||||
|
||||
void ComputeAes256Cmac(void *dst, size_t dst_size, int slot, const void *src, size_t src_size) {
|
||||
return ComputeAesCmac(dst, dst_size, slot, src, src_size, AesMode_Aes256);
|
||||
}
|
||||
|
||||
void EncryptAes128Cbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size) {
|
||||
return EncryptAesCbc(dst, dst_size, slot, src, src_size, iv, iv_size, AesMode_Aes128);
|
||||
}
|
||||
|
||||
void EncryptAes256Cbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size) {
|
||||
return EncryptAesCbc(dst, dst_size, slot, src, src_size, iv, iv_size, AesMode_Aes256);
|
||||
}
|
||||
|
||||
void DecryptAes128Cbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size) {
|
||||
return DecryptAesCbc(dst, dst_size, slot, src, src_size, iv, iv_size, AesMode_Aes128);
|
||||
}
|
||||
|
||||
void DecryptAes256Cbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size) {
|
||||
return DecryptAesCbc(dst, dst_size, slot, src, src_size, iv, iv_size, AesMode_Aes256);
|
||||
}
|
||||
|
||||
void DecryptAes128Xts(void *dst, size_t dst_size, int slot_enc, int slot_tweak, const void *src, size_t src_size, size_t sector) {
|
||||
return DecryptAesXts(dst, dst_size, slot_enc, slot_tweak, src, src_size, sector, AesMode_Aes128);
|
||||
}
|
||||
|
||||
void EncryptAes128CbcAsync(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, const void *iv, size_t iv_size, DoneHandler handler) {
|
||||
/* Validate the iv. */
|
||||
AMS_ABORT_UNLESS(iv_size == AesBlockSize);
|
||||
|
||||
/* Get the registers. */
|
||||
volatile auto *SE = GetRegisters();
|
||||
|
||||
/* Set the iv. */
|
||||
SetAesKeyIv(SE, slot, iv, iv_size);
|
||||
|
||||
/* Perform the asynchronous aes operation. */
|
||||
ComputeAes128Async(out_ll_address, slot, in_ll_address, size, handler, AesConfigCbcEncrypt, true, SE);
|
||||
}
|
||||
|
||||
void DecryptAes128CbcAsync(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, const void *iv, size_t iv_size, DoneHandler handler) {
|
||||
/* Validate the iv. */
|
||||
AMS_ABORT_UNLESS(iv_size == AesBlockSize);
|
||||
|
||||
/* Get the registers. */
|
||||
volatile auto *SE = GetRegisters();
|
||||
|
||||
/* Set the iv. */
|
||||
SetAesKeyIv(SE, slot, iv, iv_size);
|
||||
|
||||
/* Perform the asynchronous aes operation. */
|
||||
ComputeAes128Async(out_ll_address, slot, in_ll_address, size, handler, AesConfigCbcDecrypt, false, SE);
|
||||
}
|
||||
|
||||
void ComputeAes128CtrAsync(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, const void *iv, size_t iv_size, DoneHandler handler) {
|
||||
/* Validate the iv. */
|
||||
AMS_ABORT_UNLESS(iv_size == AesBlockSize);
|
||||
|
||||
/* Get the registers. */
|
||||
volatile auto *SE = GetRegisters();
|
||||
|
||||
/* Here Nintendo writes 1 to SE_SPARE. It's unclear why they do this, but we will do so as well. */
|
||||
SE->SE_SPARE = 0x1;
|
||||
|
||||
/* Set the counter. */
|
||||
SetCounter(SE, iv);
|
||||
|
||||
/* Perform the asynchronous aes operation. */
|
||||
ComputeAes128Async(out_ll_address, slot, in_ll_address, size, handler, AesConfigCtr, true, SE);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "se_execute.hpp"
|
||||
|
||||
namespace ams::se {
|
||||
|
||||
namespace {
|
||||
|
||||
struct LinkedListEntry {
|
||||
u32 zero;
|
||||
u32 address;
|
||||
u32 size;
|
||||
};
|
||||
static_assert(util::is_pod<LinkedListEntry>::value);
|
||||
static_assert(sizeof(LinkedListEntry) == 0xC);
|
||||
|
||||
uintptr_t GetPhysicalAddress(const void *ptr) {
|
||||
const uintptr_t virt_address = reinterpret_cast<uintptr_t>(ptr);
|
||||
|
||||
#if defined(ATMOSPHERE_ARCH_ARM64)
|
||||
u64 phys_address;
|
||||
__asm__ __volatile__("at s1e3r, %[virt]; mrs %[phys], par_el1" : [phys]"=r"(phys_address) : [virt]"r"(virt_address) : "memory", "cc");
|
||||
return (phys_address & 0x0000FFFFFFFFF000ul) | (virt_address & 0x0000000000000FFFul);
|
||||
#elif defined(ATMOSPHERE_ARCH_ARM)
|
||||
return virt_address;
|
||||
#else
|
||||
#error "Unknown architecture for Tegra Security Engine physical address translation"
|
||||
#endif
|
||||
}
|
||||
|
||||
constexpr void SetLinkedListEntry(LinkedListEntry *entry, const void *ptr, size_t size) {
|
||||
/* Clear the zero field. */
|
||||
entry->zero = 0;
|
||||
|
||||
/* Set the address. */
|
||||
if (ptr != nullptr) {
|
||||
entry->address = GetPhysicalAddress(ptr);
|
||||
entry->size = static_cast<u32>(size);
|
||||
} else {
|
||||
entry->address = 0;
|
||||
entry->size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void StartOperation(volatile SecurityEngineRegisters *SE, SE_OPERATION_OP op) {
|
||||
/* Write back the current values of the error and interrupt status. */
|
||||
reg::Write(SE->SE_ERR_STATUS, reg::Read(SE->SE_ERR_STATUS));
|
||||
reg::Write(SE->SE_INT_STATUS, reg::Read(SE->SE_INT_STATUS));
|
||||
|
||||
/* Write the operation. */
|
||||
reg::Write(SE->SE_OPERATION, SE_REG_BITS_VALUE(OPERATION_OP, op));
|
||||
}
|
||||
|
||||
void EnsureOperationStarted(volatile SecurityEngineRegisters *SE) {
|
||||
/* Read the operation register to make sure our write takes. */
|
||||
reg::Read(SE->SE_OPERATION);
|
||||
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
}
|
||||
|
||||
void WaitForOperationComplete(volatile SecurityEngineRegisters *SE) {
|
||||
/* Spin until the operation is done. */
|
||||
while (reg::HasValue(SE->SE_INT_STATUS, SE_REG_BITS_ENUM(INT_STATUS_SE_OP_DONE, CLEAR))) { /* ... */ }
|
||||
|
||||
/* Check for operation success. */
|
||||
ValidateAesOperationResult(SE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ExecuteOperation(volatile SecurityEngineRegisters *SE, SE_OPERATION_OP op, void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||
/* Set the linked list entries. */
|
||||
LinkedListEntry src_entry;
|
||||
LinkedListEntry dst_entry;
|
||||
|
||||
SetLinkedListEntry(std::addressof(src_entry), src, src_size);
|
||||
SetLinkedListEntry(std::addressof(dst_entry), dst, dst_size);
|
||||
|
||||
/* Ensure the linked list entry data is seen correctly. */
|
||||
hw::FlushDataCache(std::addressof(src_entry), sizeof(src_entry));
|
||||
hw::FlushDataCache(std::addressof(dst_entry), sizeof(dst_entry));
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Configure the linked list addresses. */
|
||||
reg::Write(SE->SE_IN_LL_ADDR, static_cast<u32>(GetPhysicalAddress(std::addressof(src_entry))));
|
||||
reg::Write(SE->SE_OUT_LL_ADDR, static_cast<u32>(GetPhysicalAddress(std::addressof(dst_entry))));
|
||||
|
||||
/* Start the operation. */
|
||||
StartOperation(SE, op);
|
||||
|
||||
/* Wait for the operation to complete. */
|
||||
WaitForOperationComplete(SE);
|
||||
}
|
||||
|
||||
void ExecuteOperationSingleBlock(volatile SecurityEngineRegisters *SE, void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||
/* Validate sizes. */
|
||||
AMS_ABORT_UNLESS(dst_size <= AesBlockSize);
|
||||
AMS_ABORT_UNLESS(src_size <= AesBlockSize);
|
||||
|
||||
/* Set the block count to 1. */
|
||||
reg::Write(SE->SE_CRYPTO_LAST_BLOCK, 0);
|
||||
|
||||
/* Create an aligned buffer. */
|
||||
util::AlignedBuffer<hw::DataCacheLineSize, AesBlockSize> aligned;
|
||||
std::memcpy(aligned, src, src_size);
|
||||
hw::FlushDataCache(aligned, AesBlockSize);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Execute the operation. */
|
||||
ExecuteOperation(SE, SE_OPERATION_OP_START, aligned, AesBlockSize, aligned, AesBlockSize);
|
||||
|
||||
/* Ensure that the CPU will see the correct output. */
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
hw::FlushDataCache(aligned, AesBlockSize);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Copy the output to the destination. */
|
||||
std::memcpy(dst, aligned, dst_size);
|
||||
}
|
||||
|
||||
void StartInputOperation(volatile SecurityEngineRegisters *SE, const void *src, size_t src_size) {
|
||||
/* Set the linked list entry. */
|
||||
LinkedListEntry src_entry;
|
||||
SetLinkedListEntry(std::addressof(src_entry), src, src_size);
|
||||
|
||||
/* Ensure the linked list entry data is seen correctly. */
|
||||
hw::FlushDataCache(std::addressof(src_entry), sizeof(src_entry));
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Configure the linked list addresses. */
|
||||
reg::Write(SE->SE_IN_LL_ADDR, static_cast<u32>(GetPhysicalAddress(std::addressof(src_entry))));
|
||||
|
||||
/* Start the operation. */
|
||||
StartOperation(SE, SE_OPERATION_OP_START);
|
||||
|
||||
/* Ensure the operation is started. */
|
||||
EnsureOperationStarted(SE);
|
||||
}
|
||||
|
||||
void StartOperationRaw(volatile SecurityEngineRegisters *SE, SE_OPERATION_OP op, u32 out_ll_address, u32 in_ll_address) {
|
||||
/* Configure the linked list addresses. */
|
||||
reg::Write(SE->SE_IN_LL_ADDR, in_ll_address);
|
||||
reg::Write(SE->SE_OUT_LL_ADDR, out_ll_address);
|
||||
|
||||
/* Start the operation. */
|
||||
StartOperation(SE, op);
|
||||
|
||||
/* Ensure the operation is started. */
|
||||
EnsureOperationStarted(SE);
|
||||
}
|
||||
|
||||
void ValidateAesOperationResult(volatile SecurityEngineRegisters *SE) {
|
||||
/* Ensure no error occurred. */
|
||||
AMS_ABORT_UNLESS(reg::HasValue(SE->SE_INT_STATUS, SE_REG_BITS_ENUM(INT_STATUS_ERR_STAT, CLEAR)));
|
||||
|
||||
/* Ensure the security engine is idle. */
|
||||
AMS_ABORT_UNLESS(reg::HasValue(SE->SE_STATUS, SE_REG_BITS_ENUM(STATUS_STATE, IDLE)));
|
||||
|
||||
/* Ensure there is no error status. */
|
||||
AMS_ABORT_UNLESS(reg::Read(SE->SE_ERR_STATUS) == 0);
|
||||
}
|
||||
|
||||
void ValidateAesOperationResult() {
|
||||
return ValidateAesOperationResult(GetRegisters());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "se_registers.hpp"
|
||||
|
||||
namespace ams::se {
|
||||
|
||||
volatile SecurityEngineRegisters *GetRegisters();
|
||||
volatile SecurityEngineRegisters *GetRegisters2();
|
||||
|
||||
void ExecuteOperation(volatile SecurityEngineRegisters *SE, SE_OPERATION_OP op, void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||
void ExecuteOperationSingleBlock(volatile SecurityEngineRegisters *SE, void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||
|
||||
void StartInputOperation(volatile SecurityEngineRegisters *SE, const void *src, size_t src_size);
|
||||
void StartOperationRaw(volatile SecurityEngineRegisters *SE, SE_OPERATION_OP op, u32 out_ll_address, u32 in_ll_address);
|
||||
void SetDoneHandler(volatile SecurityEngineRegisters *SE, DoneHandler handler);
|
||||
|
||||
void ValidateAesOperationResult(volatile SecurityEngineRegisters *SE);
|
||||
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "se_execute.hpp"
|
||||
|
||||
namespace ams::se {
|
||||
|
||||
namespace {
|
||||
|
||||
void SetMessageSize(volatile SecurityEngineRegisters *SE, size_t src_size) {
|
||||
/* Set the message size. */
|
||||
reg::Write(SE->SE_SHA_MSG_LENGTH[0], src_size * BITSIZEOF(u8));
|
||||
reg::Write(SE->SE_SHA_MSG_LENGTH[1], 0);
|
||||
reg::Write(SE->SE_SHA_MSG_LENGTH[2], 0);
|
||||
reg::Write(SE->SE_SHA_MSG_LENGTH[3], 0);
|
||||
|
||||
/* Set the message remaining size. */
|
||||
reg::Write(SE->SE_SHA_MSG_LEFT[0], src_size * BITSIZEOF(u8));
|
||||
reg::Write(SE->SE_SHA_MSG_LEFT[1], 0);
|
||||
reg::Write(SE->SE_SHA_MSG_LEFT[2], 0);
|
||||
reg::Write(SE->SE_SHA_MSG_LEFT[3], 0);
|
||||
}
|
||||
|
||||
void GetHashResult(volatile SecurityEngineRegisters *SE, void *dst, size_t dst_size) {
|
||||
/* Copy out the words. */
|
||||
const int num_words = dst_size / sizeof(u32);
|
||||
for (int i = 0; i < num_words; ++i) {
|
||||
const u32 word = reg::Read(SE->SE_HASH_RESULT[i]);
|
||||
util::StoreBigEndian(static_cast<u32 *>(dst) + i, word);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CalculateSha256(Sha256Hash *dst, const void *src, size_t src_size) {
|
||||
/* Get the engine. */
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Configure the engine to perform SHA256 "encryption". */
|
||||
reg::Write(SE->SE_CONFIG, SE_REG_BITS_ENUM(CONFIG_ENC_MODE, SHA256),
|
||||
SE_REG_BITS_ENUM(CONFIG_DEC_MODE, AESMODE_KEY128),
|
||||
SE_REG_BITS_ENUM(CONFIG_ENC_ALG, SHA),
|
||||
SE_REG_BITS_ENUM(CONFIG_DEC_ALG, NOP),
|
||||
SE_REG_BITS_ENUM(CONFIG_DST, HASH_REG));
|
||||
|
||||
/* Begin a hardware hash operation. */
|
||||
reg::Write(SE->SE_SHA_CONFIG, SE_REG_BITS_VALUE(SHA_CONFIG_HW_INIT_HASH, 1));
|
||||
|
||||
/* Set the message size. */
|
||||
SetMessageSize(SE, src_size);
|
||||
|
||||
/* Execute the operation. */
|
||||
ExecuteOperation(SE, SE_OPERATION_OP_START, nullptr, 0, src, src_size);
|
||||
|
||||
/* Get the result. */
|
||||
GetHashResult(SE, dst, sizeof(*dst));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "se_execute.hpp"
|
||||
|
||||
namespace ams::se {
|
||||
|
||||
namespace {
|
||||
|
||||
constinit uintptr_t g_register_address = secmon::MemoryRegionPhysicalDeviceSecurityEngine.GetAddress();
|
||||
constinit uintptr_t g_register2_address = secmon::MemoryRegionPhysicalDeviceSecurityEngine2.GetAddress();
|
||||
constinit DoneHandler g_done_handler = nullptr;
|
||||
|
||||
void SetSecure(volatile SecurityEngineRegisters *SE, bool secure) {
|
||||
/* Set the security software setting. */
|
||||
if (secure) {
|
||||
reg::ReadWrite(SE->SE_SE_SECURITY, SE_REG_BITS_ENUM(SECURITY_SOFT_SETTING, SECURE));
|
||||
} else {
|
||||
reg::ReadWrite(SE->SE_SE_SECURITY, SE_REG_BITS_ENUM(SECURITY_SOFT_SETTING, NONSECURE));
|
||||
}
|
||||
|
||||
/* Read the status register to force an update. */
|
||||
reg::Read(SE->SE_SE_SECURITY);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
volatile SecurityEngineRegisters *GetRegisters() {
|
||||
return reinterpret_cast<volatile SecurityEngineRegisters *>(g_register_address);
|
||||
}
|
||||
|
||||
volatile SecurityEngineRegisters *GetRegisters2() {
|
||||
return reinterpret_cast<volatile SecurityEngineRegisters *>(g_register2_address);
|
||||
}
|
||||
|
||||
void SetRegisterAddress(uintptr_t address, uintptr_t address2) {
|
||||
g_register_address = address;
|
||||
g_register2_address = address2;
|
||||
}
|
||||
|
||||
void Initialize() {
|
||||
auto *SE = GetRegisters();
|
||||
AMS_ABORT_UNLESS(reg::HasValue(SE->SE_STATUS, SE_REG_BITS_ENUM(STATUS_STATE, IDLE)));
|
||||
}
|
||||
|
||||
void SetSecure(bool secure) {
|
||||
/* Set security for SE1. */
|
||||
SetSecure(GetRegisters(), secure);
|
||||
|
||||
/* If SE2 is present, set security for SE2. */
|
||||
if (fuse::GetSocType() == fuse::SocType_Mariko) {
|
||||
SetSecure(GetRegisters2(), secure);
|
||||
}
|
||||
}
|
||||
|
||||
void SetTzramSecure() {
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Set the TZRAM setting to secure. */
|
||||
SE->SE_TZRAM_SECURITY = SE_TZRAM_SETTING_SECURE;
|
||||
}
|
||||
|
||||
void SetPerKeySecure() {
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Update PERKEY_SETTING to secure. */
|
||||
reg::ReadWrite(SE->SE_SE_SECURITY, SE_REG_BITS_ENUM(SECURITY_PERKEY_SETTING, SECURE));
|
||||
}
|
||||
|
||||
|
||||
void SetContextSaveSecure() {
|
||||
/* Context save lock to trustzone secure is only available on mariko. */
|
||||
if (fuse::GetSocType() == fuse::SocType_Mariko) {
|
||||
auto *SE = GetRegisters();
|
||||
auto *SE2 = GetRegisters2();
|
||||
|
||||
reg::ReadWrite(SE->SE_SE_SECURITY, SE_REG_BITS_ENUM(SECURITY_CTX_SAVE_TZ_LOCK, SECURE));
|
||||
reg::ReadWrite(SE2->SE_SE_SECURITY, SE_REG_BITS_ENUM(SECURITY_CTX_SAVE_TZ_LOCK, SECURE));
|
||||
}
|
||||
}
|
||||
|
||||
void Lockout() {
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Lock access to the AES keyslots. */
|
||||
for (int i = 0; i < AesKeySlotCount; ++i) {
|
||||
SE->SE_CRYPTO_KEYTABLE_ACCESS[i] = 0;
|
||||
}
|
||||
|
||||
/* Lock access to the RSA keyslots. */
|
||||
for (int i = 0; i < RsaKeySlotCount; ++i) {
|
||||
SE->SE_RSA_KEYTABLE_ACCESS[i] = 0;
|
||||
}
|
||||
|
||||
/* Set Per Key secure. */
|
||||
SetPerKeySecure();
|
||||
|
||||
/* Configure SE_SECURITY. */
|
||||
{
|
||||
reg::ReadWrite(SE->SE_SE_SECURITY, SE_REG_BITS_ENUM(SECURITY_HARD_SETTING, SECURE),
|
||||
SE_REG_BITS_ENUM(SECURITY_ENG_DIS, DISABLE),
|
||||
SE_REG_BITS_ENUM(SECURITY_PERKEY_SETTING, SECURE),
|
||||
SE_REG_BITS_ENUM(SECURITY_SOFT_SETTING, SECURE));
|
||||
}
|
||||
}
|
||||
|
||||
void HandleInterrupt() {
|
||||
/* Get the registers. */
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Disable the SE interrupt. */
|
||||
reg::Write(SE->SE_INT_ENABLE, 0);
|
||||
|
||||
/* Execute the handler if we have one. */
|
||||
if (const auto handler = g_done_handler; handler != nullptr) {
|
||||
g_done_handler = nullptr;
|
||||
handler();
|
||||
}
|
||||
}
|
||||
|
||||
void SetDoneHandler(volatile SecurityEngineRegisters *SE, DoneHandler handler) {
|
||||
/* Set the done handler. */
|
||||
g_done_handler = handler;
|
||||
|
||||
/* Configure to trigger an interrupt when done. */
|
||||
reg::Write(SE->SE_INT_ENABLE, SE_REG_BITS_ENUM(INT_ENABLE_SE_OP_DONE, ENABLE));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "se_execute.hpp"
|
||||
|
||||
namespace ams::se {
|
||||
|
||||
/* NOTE: This implementation is mostly copy/pasted from crypto::impl::RsaOaepImpl. */
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline size_t HashSize = sizeof(Sha256Hash);
|
||||
|
||||
constexpr inline u8 HeadMagic = 0x00;
|
||||
|
||||
void ApplyMGF1(u8 *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||
/* Check our pre-conditions. */
|
||||
AMS_ABORT_UNLESS(src_size <= RsaSize - (1 + HashSize));
|
||||
|
||||
/* Create a buffer. */
|
||||
util::AlignedBuffer<hw::DataCacheLineSize, RsaSize - (1 + HashSize) + sizeof(u32)> buf;
|
||||
u32 counter = 0;
|
||||
|
||||
while (dst_size > 0) {
|
||||
/* Setup the current hash buffer. */
|
||||
const size_t cur_size = std::min(HashSize, dst_size);
|
||||
std::memcpy(static_cast<u8 *>(buf), src, src_size);
|
||||
{
|
||||
u32 counter_be;
|
||||
util::StoreBigEndian(std::addressof(counter_be), counter++);
|
||||
std::memcpy(static_cast<u8 *>(buf) + src_size, std::addressof(counter_be), sizeof(counter_be));
|
||||
}
|
||||
|
||||
/* Ensure se sees correct data. */
|
||||
hw::FlushDataCache(buf, src_size + sizeof(u32));
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Calculate the hash. */
|
||||
Sha256Hash hash;
|
||||
se::CalculateSha256(std::addressof(hash), buf, src_size + sizeof(u32));
|
||||
|
||||
/* Mask the current output. */
|
||||
const u8 *mask = hash.bytes;
|
||||
for (size_t i = 0; i < cur_size; ++i) {
|
||||
*(dst++) ^= *(mask++);
|
||||
}
|
||||
|
||||
/* Advance. */
|
||||
dst_size -= cur_size;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
size_t DecodeRsaOaepSha256(void *dst, size_t dst_size, void *src, size_t src_size, const void *label_digest, size_t label_digest_size) {
|
||||
/* Check our preconditions. */
|
||||
AMS_ABORT_UNLESS(src_size == RsaSize);
|
||||
AMS_ABORT_UNLESS(label_digest_size == HashSize);
|
||||
|
||||
/* Get a byte-readable copy of the input. */
|
||||
u8 *buf = static_cast<u8 *>(src);
|
||||
|
||||
/* Validate sanity byte. */
|
||||
bool is_valid = buf[0] == HeadMagic;
|
||||
|
||||
/* Decrypt seed and masked db. */
|
||||
size_t db_len = src_size - HashSize - 1;
|
||||
u8 *seed = buf + 1;
|
||||
u8 *db = seed + HashSize;
|
||||
ApplyMGF1(seed, HashSize, db, db_len);
|
||||
ApplyMGF1(db, db_len, seed, HashSize);
|
||||
|
||||
/* Check the label digest. */
|
||||
is_valid &= crypto::IsSameBytes(label_digest, db, HashSize);
|
||||
|
||||
/* Skip past the label digest. */
|
||||
db += HashSize;
|
||||
db_len -= HashSize;
|
||||
|
||||
/* Verify that DB is of the form 0000...0001 < message > */
|
||||
s32 msg_ofs = 0;
|
||||
{
|
||||
int looking_for_one = 1;
|
||||
int invalid_db_padding = 0;
|
||||
int is_zero;
|
||||
int is_one;
|
||||
for (size_t i = 0; i < db_len; /* ... */) {
|
||||
is_zero = (db[i] == 0);
|
||||
is_one = (db[i] == 1);
|
||||
msg_ofs += (looking_for_one & is_one) * (static_cast<s32>(++i));
|
||||
looking_for_one &= ~is_one;
|
||||
invalid_db_padding |= (looking_for_one & ~is_zero);
|
||||
}
|
||||
|
||||
is_valid &= (invalid_db_padding == 0);
|
||||
}
|
||||
|
||||
/* If we're invalid, return zero size. */
|
||||
const size_t valid_msg_size = db_len - msg_ofs;
|
||||
const size_t msg_size = std::min(dst_size, static_cast<size_t>(is_valid) * valid_msg_size);
|
||||
|
||||
/* Copy to output. */
|
||||
std::memcpy(dst, db + msg_ofs, msg_size);
|
||||
|
||||
/* Return copied size. */
|
||||
return msg_size;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,262 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::se {
|
||||
|
||||
struct SecurityEngineRegisters {
|
||||
u32 SE_SE_SECURITY;
|
||||
u32 SE_TZRAM_SECURITY;
|
||||
u32 SE_OPERATION;
|
||||
u32 SE_INT_ENABLE;
|
||||
u32 SE_INT_STATUS;
|
||||
u32 SE_CONFIG;
|
||||
u32 SE_IN_LL_ADDR;
|
||||
u32 SE_IN_CUR_BYTE_ADDR;
|
||||
u32 SE_IN_CUR_LL_ID;
|
||||
u32 SE_OUT_LL_ADDR;
|
||||
u32 SE_OUT_CUR_BYTE_ADDR;
|
||||
u32 SE_OUT_CUR_LL_ID;
|
||||
u32 SE_HASH_RESULT[0x10];
|
||||
u32 SE_CTX_SAVE_CONFIG;
|
||||
u32 SE_CTX_SAVE_AUTO;
|
||||
u32 _0x78[0x62];
|
||||
u32 SE_SHA_CONFIG;
|
||||
u32 SE_SHA_MSG_LENGTH[0x4];
|
||||
u32 SE_SHA_MSG_LEFT[0x4];
|
||||
u32 _0x224[0x17];
|
||||
u32 SE_CRYPTO_SECURITY_PERKEY;
|
||||
u32 SE_CRYPTO_KEYTABLE_ACCESS[0x10];
|
||||
u32 _0x2C4[0x10];
|
||||
u32 SE_CRYPTO_CONFIG;
|
||||
u32 SE_CRYPTO_LINEAR_CTR[0x4];
|
||||
u32 SE_CRYPTO_LAST_BLOCK;
|
||||
u32 SE_CRYPTO_KEYTABLE_ADDR;
|
||||
u32 SE_CRYPTO_KEYTABLE_DATA;
|
||||
u32 _0x324[0x3];
|
||||
u32 SE_CRYPTO_KEYTABLE_DST;
|
||||
u32 _0x334[0x3];
|
||||
u32 SE_RNG_CONFIG;
|
||||
u32 SE_RNG_SRC_CONFIG;
|
||||
u32 SE_RNG_RESEED_INTERVAL;
|
||||
u32 _0x34C[0x2D];
|
||||
u32 SE_RSA_CONFIG;
|
||||
u32 SE_RSA_KEY_SIZE;
|
||||
u32 SE_RSA_EXP_SIZE;
|
||||
u32 SE_RSA_SECURITY_PERKEY;
|
||||
u32 SE_RSA_KEYTABLE_ACCESS[0x2];
|
||||
u32 _0x418[0x2];
|
||||
u32 SE_RSA_KEYTABLE_ADDR;
|
||||
u32 SE_RSA_KEYTABLE_DATA;
|
||||
u32 SE_RSA_OUTPUT[0x40];
|
||||
u32 _0x528[0x6];
|
||||
u32 SE_TZRAM_OPERATION;
|
||||
u32 _0x544[0xAF];
|
||||
u32 SE_STATUS;
|
||||
u32 SE_ERR_STATUS;
|
||||
u32 SE_MISC;
|
||||
u32 SE_SPARE;
|
||||
u32 SE_ENTROPY_DEBUG_COUNTER;
|
||||
u32 _0x814;
|
||||
u32 _0x818;
|
||||
u32 _0x81C;
|
||||
u32 _0x820[0x5F8];
|
||||
};
|
||||
static_assert(util::is_pod<SecurityEngineRegisters>::value);
|
||||
static_assert(sizeof(SecurityEngineRegisters) == secmon::MemoryRegionPhysicalDeviceSecurityEngine.GetSize());
|
||||
|
||||
static_assert(AesKeySlotCount == util::size(SecurityEngineRegisters{}.SE_CRYPTO_KEYTABLE_ACCESS));
|
||||
static_assert(RsaKeySlotCount == util::size(SecurityEngineRegisters{}.SE_RSA_KEYTABLE_ACCESS));
|
||||
|
||||
#define SE_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (SE, NAME)
|
||||
#define SE_REG_BITS_VALUE(NAME, VALUE) REG_NAMED_BITS_VALUE (SE, NAME, VALUE)
|
||||
#define SE_REG_BITS_ENUM(NAME, ENUM) REG_NAMED_BITS_ENUM (SE, NAME, ENUM)
|
||||
#define SE_REG_BITS_ENUM_SEL(NAME, __COND__, TRUE_ENUM, FALSE_ENUM) REG_NAMED_BITS_ENUM_SEL(SE, NAME, __COND__, TRUE_ENUM, FALSE_ENUM)
|
||||
|
||||
#define DEFINE_SE_REG(NAME, __OFFSET__, __WIDTH__) REG_DEFINE_NAMED_REG (SE, NAME, __OFFSET__, __WIDTH__)
|
||||
#define DEFINE_SE_REG_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE) REG_DEFINE_NAMED_BIT_ENUM (SE, NAME, __OFFSET__, ZERO, ONE)
|
||||
#define DEFINE_SE_REG_TWO_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE) REG_DEFINE_NAMED_TWO_BIT_ENUM (SE, NAME, __OFFSET__, ZERO, ONE, TWO, THREE)
|
||||
#define DEFINE_SE_REG_THREE_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) REG_DEFINE_NAMED_THREE_BIT_ENUM(SE, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN)
|
||||
#define DEFINE_SE_REG_FOUR_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) REG_DEFINE_NAMED_FOUR_BIT_ENUM (SE, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN)
|
||||
|
||||
#define DEFINE_SE_REG_BIT_ENUM_WITH_SW_CLEAR(NAME, __OFFSET__) \
|
||||
REG_DEFINE_NAMED_REG(SE, NAME, __OFFSET__, 1); \
|
||||
\
|
||||
enum SE_##NAME { \
|
||||
SE_##NAME##_##CLEAR = 0, \
|
||||
SE_##NAME##_##ACTIVE = 1, \
|
||||
SE_##NAME##_##SW_CLEAR = 1, \
|
||||
};
|
||||
|
||||
/* SE_STATUS. */
|
||||
DEFINE_SE_REG_TWO_BIT_ENUM(STATUS_STATE, 0, IDLE, BUSY, WAIT_OUT, WAIT_IN);
|
||||
DEFINE_SE_REG_BIT_ENUM(STATUS_MEM_INTERFACE, 2, IDLE, BUSY);
|
||||
|
||||
/* SE_SECURITY */
|
||||
DEFINE_SE_REG_BIT_ENUM(SECURITY_HARD_SETTING, 0, SECURE, NONSECURE);
|
||||
DEFINE_SE_REG_BIT_ENUM(SECURITY_ENG_DIS, 1, DISABLE, ENABLE);
|
||||
DEFINE_SE_REG_BIT_ENUM(SECURITY_PERKEY_SETTING, 2, SECURE, NONSECURE);
|
||||
DEFINE_SE_REG_BIT_ENUM(SECURITY_CTX_SAVE_TZ_LOCK, 4, SECURE, NONSECURE);
|
||||
DEFINE_SE_REG_BIT_ENUM(SECURITY_CTX_TZ_LOCK_SOFT, 5, SECURE, NONSECURE);
|
||||
DEFINE_SE_REG_BIT_ENUM(SECURITY_SOFT_SETTING, 16, SECURE, NONSECURE);
|
||||
|
||||
/* SE_TZRAM_SECURITY */
|
||||
DEFINE_SE_REG(TZRAM_SETTING, 0, BITSIZEOF(u32));
|
||||
constexpr inline u32 SE_TZRAM_SETTING_SECURE = 0;
|
||||
|
||||
/* SE_TZRAM_OPERATION */
|
||||
DEFINE_SE_REG_BIT_ENUM(TZRAM_OPERATION_REQ, 0, IDLE, INITIATE);
|
||||
DEFINE_SE_REG_BIT_ENUM(TZRAM_OPERATION_MODE, 1, SAVE, RESTORE);
|
||||
DEFINE_SE_REG_BIT_ENUM(TZRAM_OPERATION_BUSY, 2, NO, YES);
|
||||
DEFINE_SE_REG(TZRAM_OPERATION_CURR_ADDR, 16, 16);
|
||||
|
||||
/* SE_OPERATION */
|
||||
DEFINE_SE_REG_THREE_BIT_ENUM(OPERATION_OP, 0, ABORT, START, RESTART_OUT, CTX_SAVE, RESTART_IN, RESERVED_5, RESERVED_6, RESERVED_7);
|
||||
|
||||
/* SE_INT_ENABLE */
|
||||
DEFINE_SE_REG_BIT_ENUM(INT_ENABLE_IN_LL_BUF_RD, 0, DISABLE, ENABLE);
|
||||
DEFINE_SE_REG_BIT_ENUM(INT_ENABLE_IN_DONE, 1, DISABLE, ENABLE);
|
||||
DEFINE_SE_REG_BIT_ENUM(INT_ENABLE_OUT_LL_BUF_WR, 2, DISABLE, ENABLE);
|
||||
DEFINE_SE_REG_BIT_ENUM(INT_ENABLE_OUT_DONE, 3, DISABLE, ENABLE);
|
||||
DEFINE_SE_REG_BIT_ENUM(INT_ENABLE_SE_OP_DONE, 4, DISABLE, ENABLE);
|
||||
DEFINE_SE_REG_BIT_ENUM(INT_ENABLE_RESEED_CNTR_EXHAUSTED, 5, DISABLE, ENABLE);
|
||||
DEFINE_SE_REG_BIT_ENUM(INT_ENABLE_ERR_STAT, 16, DISABLE, ENABLE);
|
||||
|
||||
/* SE_INT_STATUS */
|
||||
DEFINE_SE_REG_BIT_ENUM_WITH_SW_CLEAR(INT_STATUS_IN_LL_BUF_RD, 0);
|
||||
DEFINE_SE_REG_BIT_ENUM_WITH_SW_CLEAR(INT_STATUS_IN_DONE, 1);
|
||||
DEFINE_SE_REG_BIT_ENUM_WITH_SW_CLEAR(INT_STATUS_OUT_LL_BUF_WR, 2);
|
||||
DEFINE_SE_REG_BIT_ENUM_WITH_SW_CLEAR(INT_STATUS_OUT_DONE, 3);
|
||||
DEFINE_SE_REG_BIT_ENUM_WITH_SW_CLEAR(INT_STATUS_SE_OP_DONE, 4);
|
||||
DEFINE_SE_REG_BIT_ENUM_WITH_SW_CLEAR(INT_STATUS_RESEED_CNTR_EXHAUSTED, 5);
|
||||
DEFINE_SE_REG_BIT_ENUM_WITH_SW_CLEAR(INT_STATUS_ERR_STAT, 16);
|
||||
|
||||
/* SE_CONFIG */
|
||||
DEFINE_SE_REG(CONFIG_DEC_MODE, 16, 8);
|
||||
DEFINE_SE_REG(CONFIG_ENC_MODE, 24, 8);
|
||||
|
||||
DEFINE_SE_REG_THREE_BIT_ENUM(CONFIG_DST, 2, MEMORY, HASH_REG, KEYTABLE, SRK, RSA_REG, RESERVED5, RESERVED6, RESERVED7);
|
||||
DEFINE_SE_REG_FOUR_BIT_ENUM(CONFIG_DEC_ALG, 8, NOP, AES_DEC, RESERVED2, RESERVED3, RESERVED4, RESERVED5, RESERVED6, RESERVED7, RESERVED8, RESERVED9, RESERVED10, RESERVED11, RESERVED12, RESERVED13, RESERVED14, RESERVED15);
|
||||
DEFINE_SE_REG_FOUR_BIT_ENUM(CONFIG_ENC_ALG, 12, NOP, AES_ENC, RNG, SHA, RSA, RESERVED5, RESERVED6, RESERVED7, RESERVED8, RESERVED9, RESERVED10, RESERVED11, RESERVED12, RESERVED13, RESERVED14, RESERVED15);
|
||||
|
||||
enum SE_CONFIG_DEC_MODE {
|
||||
SE_CONFIG_DEC_MODE_AESMODE_KEY128 = 0,
|
||||
SE_CONFIG_DEC_MODE_AESMODE_KEY192 = 1,
|
||||
SE_CONFIG_DEC_MODE_AESMODE_KEY256 = 2,
|
||||
};
|
||||
|
||||
enum SE_CONFIG_ENC_MODE {
|
||||
SE_CONFIG_ENC_MODE_AESMODE_KEY128 = 0,
|
||||
SE_CONFIG_ENC_MODE_AESMODE_KEY192 = 1,
|
||||
SE_CONFIG_ENC_MODE_AESMODE_KEY256 = 2,
|
||||
|
||||
SE_CONFIG_ENC_MODE_SHA1 = 1,
|
||||
SE_CONFIG_ENC_MODE_SHA224 = 4,
|
||||
SE_CONFIG_ENC_MODE_SHA256 = 5,
|
||||
SE_CONFIG_ENC_MODE_SHA384 = 6,
|
||||
SE_CONFIG_ENC_MODE_SHA512 = 7,
|
||||
};
|
||||
|
||||
/* SE_CTX_SAVE_CONFIG */
|
||||
DEFINE_SE_REG_TWO_BIT_ENUM(CTX_SAVE_CONFIG_AES_WORD_QUAD, 0, KEYS_0_3, KEYS_4_7, ORIGINAL_IVS, UPDATED_IVS);
|
||||
DEFINE_SE_REG(CTX_SAVE_CONFIG_PKA1_WORD_QUAD_L, 0, 4);
|
||||
DEFINE_SE_REG(CTX_SAVE_CONFIG_AES_KEY_INDEX, 8, 4);
|
||||
DEFINE_SE_REG(CTX_SAVE_CONFIG_RSA_WORD_QUAD, 12, 4);
|
||||
DEFINE_SE_REG(CTX_SAVE_CONFIG_PKA1_WORD_QUAD_H, 12, 4);
|
||||
DEFINE_SE_REG_TWO_BIT_ENUM(CTX_SAVE_CONFIG_RSA_KEY_INDEX, 16, SLOT0_EXPONENT, SLOT0_MODULUS, SLOT1_EXPONENT, SLOT1_MODULUS);
|
||||
DEFINE_SE_REG_BIT_ENUM(CTX_SAVE_CONFIG_STICKY_WORD_QUAD, 24, WORDS_0_3, WORDS_4_7);
|
||||
DEFINE_SE_REG_THREE_BIT_ENUM(CTX_SAVE_CONFIG_SRC, 29, STICKY_BITS, RSA_KEYTABLE, AES_KEYTABLE, PKA1_STICKY_BITS, MEM, RESERVED5, SRK, PKA1_KEYTABLE);
|
||||
|
||||
/* SE_CTX_SAVE_AUTO */
|
||||
DEFINE_SE_REG_BIT_ENUM(CTX_SAVE_AUTO_ENABLE, 0, NO, YES);
|
||||
DEFINE_SE_REG_BIT_ENUM(CTX_SAVE_AUTO_LOCK, 8, NO, YES);
|
||||
DEFINE_SE_REG(CTX_SAVE_AUTO_CURR_CNT, 16, 10);
|
||||
|
||||
/* SE_SHA_CONFIG */
|
||||
DEFINE_SE_REG(SHA_CONFIG_HW_INIT_HASH, 0, 1);
|
||||
|
||||
|
||||
/* SE_CRYPTO_KEYTABLE_ADDR */
|
||||
DEFINE_SE_REG(CRYPTO_KEYTABLE_ADDR_KEYIV_WORD, 0, 4);
|
||||
DEFINE_SE_REG(CRYPTO_KEYTABLE_ADDR_KEYIV_IV_WORD, 0, 2);
|
||||
DEFINE_SE_REG(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_WORD, 0, 3);
|
||||
|
||||
enum SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD {
|
||||
SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_KEY_0 = 0u,
|
||||
SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_KEY_1 = 1u,
|
||||
SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_KEY_2 = 2u,
|
||||
SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_KEY_3 = 3u,
|
||||
SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_KEY_4 = 4u,
|
||||
SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_KEY_5 = 5u,
|
||||
SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_KEY_6 = 6u,
|
||||
SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_KEY_7 = 7u,
|
||||
SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_OIV_0 = 8u,
|
||||
SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_OIV_1 = 9u,
|
||||
SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_OIV_2 = 10u,
|
||||
SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_OIV_3 = 11u,
|
||||
SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_UIV_0 = 12u,
|
||||
SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_UIV_1 = 13u,
|
||||
SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_UIV_2 = 14u,
|
||||
SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_UIV_3 = 15u,
|
||||
};
|
||||
|
||||
DEFINE_SE_REG_BIT_ENUM(CRYPTO_KEYTABLE_ADDR_KEYIV_IV_SEL, 2, ORIGINAL_IV, UPDATED_IV);
|
||||
DEFINE_SE_REG_BIT_ENUM(CRYPTO_KEYTABLE_ADDR_KEYIV_KEYIV_SEL, 3, KEY, IV);
|
||||
|
||||
DEFINE_SE_REG(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_SLOT, 4, 4);
|
||||
|
||||
/* SE_RSA_CONFIG */
|
||||
DEFINE_SE_REG(RSA_CONFIG_KEY_SLOT, 24, 1);
|
||||
|
||||
/* SE_RSA_KEYTABLE_ADDR */
|
||||
DEFINE_SE_REG(RSA_KEYTABLE_ADDR_WORD_ADDR, 0, 6);
|
||||
DEFINE_SE_REG_BIT_ENUM(RSA_KEYTABLE_ADDR_EXPMOD_SEL, 6, EXPONENT, MODULUS);
|
||||
DEFINE_SE_REG(RSA_KEYTABLE_ADDR_KEY_SLOT, 7, 1);
|
||||
DEFINE_SE_REG_BIT_ENUM(RSA_KEYTABLE_ADDR_INPUT_MODE, 8, REGISTER, MEMORY);
|
||||
|
||||
/* SE_RSA_KEYTABLE_ACCESS */
|
||||
DEFINE_SE_REG_BIT_ENUM(RSA_KEYTABLE_ACCESS_KEYREAD, 0, DISABLE, ENABLE);
|
||||
DEFINE_SE_REG_BIT_ENUM(RSA_KEYTABLE_ACCESS_KEYUPDATE, 1, DISABLE, ENABLE);
|
||||
DEFINE_SE_REG_BIT_ENUM(RSA_KEYTABLE_ACCESS_KEYUSE, 2, DISABLE, ENABLE);
|
||||
|
||||
/* SE_CRYPTO_CONFIG */
|
||||
DEFINE_SE_REG_BIT_ENUM(CRYPTO_CONFIG_HASH_ENB, 0, DISABLE, ENABLE);
|
||||
DEFINE_SE_REG_TWO_BIT_ENUM(CRYPTO_CONFIG_XOR_POS, 1, BYPASS, RESERVED, TOP, BOTTOM);
|
||||
DEFINE_SE_REG_TWO_BIT_ENUM(CRYPTO_CONFIG_INPUT_SEL, 3, MEMORY, RANDOM, INIT_AESOUT, LINEAR_CTR);
|
||||
DEFINE_SE_REG_TWO_BIT_ENUM(CRYPTO_CONFIG_VCTRAM_SEL, 5, MEMORY, RESERVED, INIT_AESOUT, INIT_PREV_MEMORY);
|
||||
DEFINE_SE_REG_BIT_ENUM(CRYPTO_CONFIG_IV_SELECT, 7, ORIGINAL, UPDATED);
|
||||
DEFINE_SE_REG_BIT_ENUM(CRYPTO_CONFIG_CORE_SEL, 8, DECRYPT, ENCRYPT);
|
||||
DEFINE_SE_REG_BIT_ENUM(CRYPTO_CONFIG_KEYSCH_BYPASS, 10, DISABLE, ENABLE);
|
||||
DEFINE_SE_REG(CRYPTO_CONFIG_CTR_CNTN, 11, 8);
|
||||
DEFINE_SE_REG(CRYPTO_CONFIG_KEY_INDEX, 24, 4);
|
||||
DEFINE_SE_REG_BIT_ENUM(CRYPTO_CONFIG_MEMIF, 31, AHB, MCCIF);
|
||||
|
||||
/* SE_CRYPTO_KEYTABLE_DST */
|
||||
DEFINE_SE_REG_TWO_BIT_ENUM(CRYPTO_KEYTABLE_DST_WORD_QUAD, 0, KEYS_0_3, KEYS_4_7, ORIGINAL_IV, UPDATED_IV);
|
||||
DEFINE_SE_REG(CRYPTO_KEYTABLE_DST_KEY_INDEX, 8, 4);
|
||||
|
||||
/* SE_RNG_CONFIG */
|
||||
DEFINE_SE_REG_TWO_BIT_ENUM(RNG_CONFIG_MODE, 0, NORMAL, FORCE_INSTANTIATION, FORCE_RESEED, RESERVED3);
|
||||
DEFINE_SE_REG_TWO_BIT_ENUM(RNG_CONFIG_SRC, 2, NONE, ENTROPY, LFSR, RESERVED3);
|
||||
|
||||
/* SE_RNG_SRC_CONFIG */
|
||||
DEFINE_SE_REG_BIT_ENUM(RNG_SRC_CONFIG_RO_ENTROPY_SOURCE_LOCK, 0, DISABLE, ENABLE);
|
||||
DEFINE_SE_REG_BIT_ENUM(RNG_SRC_CONFIG_RO_ENTROPY_SOURCE, 1, DISABLE, ENABLE);
|
||||
DEFINE_SE_REG_BIT_ENUM(RNG_SRC_CONFIG_HW_DISABLE_CYA, 2, DISABLE, ENABLE);
|
||||
DEFINE_SE_REG(RNG_SRC_CONFIG_RO_ENTROPY_SUBSAMPLE, 4, 3);
|
||||
DEFINE_SE_REG(RNG_SRC_CONFIG_RO_ENTROPY_DATA_FLUSH, 8, 1);
|
||||
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "se_execute.hpp"
|
||||
|
||||
namespace ams::se {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline int RngReseedInterval = 70001;
|
||||
|
||||
void ConfigRng(volatile SecurityEngineRegisters *SE, SE_CONFIG_DST dst, SE_RNG_CONFIG_MODE mode) {
|
||||
/* Configure the engine to do RNG encryption. */
|
||||
reg::Write(SE->SE_CONFIG, SE_REG_BITS_ENUM (CONFIG_ENC_MODE, AESMODE_KEY128),
|
||||
SE_REG_BITS_ENUM (CONFIG_DEC_MODE, AESMODE_KEY128),
|
||||
SE_REG_BITS_ENUM (CONFIG_ENC_ALG, RNG),
|
||||
SE_REG_BITS_ENUM (CONFIG_DEC_ALG, NOP),
|
||||
SE_REG_BITS_VALUE(CONFIG_DST, dst));
|
||||
|
||||
reg::Write(SE->SE_CRYPTO_CONFIG, SE_REG_BITS_ENUM (CRYPTO_CONFIG_MEMIF, AHB),
|
||||
SE_REG_BITS_VALUE(CRYPTO_CONFIG_CTR_CNTN, 0),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_KEYSCH_BYPASS, DISABLE),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_CORE_SEL, ENCRYPT),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_IV_SELECT, ORIGINAL),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_VCTRAM_SEL, MEMORY),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_INPUT_SEL, RANDOM),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_XOR_POS, BYPASS),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_HASH_ENB, DISABLE));
|
||||
|
||||
/* Configure the RNG to use Entropy as source. */
|
||||
reg::Write(SE->SE_RNG_CONFIG, SE_REG_BITS_ENUM(RNG_CONFIG_SRC, ENTROPY), SE_REG_BITS_VALUE(RNG_CONFIG_MODE, mode));
|
||||
}
|
||||
|
||||
void InitializeRandom(volatile SecurityEngineRegisters *SE) {
|
||||
/* Lock the entropy source. */
|
||||
reg::Write(SE->SE_RNG_SRC_CONFIG, SE_REG_BITS_ENUM(RNG_SRC_CONFIG_RO_ENTROPY_SOURCE, ENABLE),
|
||||
SE_REG_BITS_ENUM(RNG_SRC_CONFIG_RO_ENTROPY_SOURCE_LOCK, ENABLE));
|
||||
|
||||
/* Set the reseed interval to force a reseed every 70000 blocks. */
|
||||
SE->SE_RNG_RESEED_INTERVAL = RngReseedInterval;
|
||||
|
||||
/* Initialize the DRBG. */
|
||||
{
|
||||
u8 dummy_buf[AesBlockSize];
|
||||
|
||||
/* Configure the engine to force drbg instantiation by writing random to memory. */
|
||||
ConfigRng(SE, SE_CONFIG_DST_MEMORY, SE_RNG_CONFIG_MODE_FORCE_INSTANTIATION);
|
||||
|
||||
/* Configure to do a single RNG block operation to trigger DRBG init. */
|
||||
SE->SE_CRYPTO_LAST_BLOCK = 0;
|
||||
|
||||
/* Execute the operation. */
|
||||
ExecuteOperation(SE, SE_OPERATION_OP_START, dummy_buf, sizeof(dummy_buf), nullptr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void GenerateSrk(volatile SecurityEngineRegisters *SE) {
|
||||
/* Configure the RNG to output to SRK and force a reseed. */
|
||||
ConfigRng(SE, SE_CONFIG_DST_SRK, SE_RNG_CONFIG_MODE_FORCE_RESEED);
|
||||
|
||||
/* Configure a single block operation. */
|
||||
SE->SE_CRYPTO_LAST_BLOCK = 0;
|
||||
|
||||
/* Execute the operation. */
|
||||
ExecuteOperation(SE, SE_OPERATION_OP_START, nullptr, 0, nullptr, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void InitializeRandom() {
|
||||
/* Initialize random for SE1. */
|
||||
InitializeRandom(GetRegisters());
|
||||
|
||||
/* If we have SE2, initialize random for SE2. */
|
||||
/* NOTE: Nintendo's implementation of this is incorrect. */
|
||||
if (fuse::GetSocType() == fuse::SocType_Mariko) {
|
||||
InitializeRandom(GetRegisters2());
|
||||
}
|
||||
}
|
||||
|
||||
void GenerateRandomBytes(void *dst, size_t size) {
|
||||
/* If we're not generating any bytes, there's nothing to do. */
|
||||
if (size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the engine. */
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Determine how many blocks to generate. */
|
||||
const size_t num_blocks = size / AesBlockSize;
|
||||
const size_t aligned_size = num_blocks * AesBlockSize;
|
||||
const size_t fractional = size - aligned_size;
|
||||
|
||||
/* Configure the RNG to generate random to memory. */
|
||||
ConfigRng(SE, SE_CONFIG_DST_MEMORY, SE_RNG_CONFIG_MODE_NORMAL);
|
||||
|
||||
/* Generate as many aligned blocks as we can. */
|
||||
if (aligned_size > 0) {
|
||||
/* Configure the engine to generate the right number of blocks. */
|
||||
SE->SE_CRYPTO_LAST_BLOCK = num_blocks - 1;
|
||||
|
||||
/* Execute the operation. */
|
||||
ExecuteOperation(SE, SE_OPERATION_OP_START, dst, aligned_size, nullptr, 0);
|
||||
}
|
||||
|
||||
/* Generate a single block to output. */
|
||||
if (fractional > 0) {
|
||||
ExecuteOperationSingleBlock(SE, static_cast<u8 *>(dst) + aligned_size, fractional, nullptr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void SetRandomKey(int slot) {
|
||||
/* NOTE: Nintendo does not validate the destination keyslot here. */
|
||||
|
||||
/* Get the engine. */
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Configure the RNG to output to the keytable. */
|
||||
ConfigRng(SE, SE_CONFIG_DST_KEYTABLE, SE_RNG_CONFIG_MODE_NORMAL);
|
||||
|
||||
/* Configure the keytable destination to be the low part of the key. */
|
||||
reg::Write(SE->SE_CRYPTO_KEYTABLE_DST, SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_DST_KEY_INDEX, slot), SE_REG_BITS_ENUM(CRYPTO_KEYTABLE_DST_WORD_QUAD, KEYS_0_3));
|
||||
|
||||
/* Configure a single block operation. */
|
||||
SE->SE_CRYPTO_LAST_BLOCK = 0;
|
||||
|
||||
/* Execute the operation to generate a random low-part of the key. */
|
||||
ExecuteOperation(SE, SE_OPERATION_OP_START, nullptr, 0, nullptr, 0);
|
||||
|
||||
/* Configure the keytable destination to be the high part of the key. */
|
||||
reg::Write(SE->SE_CRYPTO_KEYTABLE_DST, SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_DST_KEY_INDEX, slot), SE_REG_BITS_ENUM(CRYPTO_KEYTABLE_DST_WORD_QUAD, KEYS_4_7));
|
||||
|
||||
/* Execute the operation to generate a random high-part of the key. */
|
||||
ExecuteOperation(SE, SE_OPERATION_OP_START, nullptr, 0, nullptr, 0);
|
||||
}
|
||||
|
||||
void GenerateSrk() {
|
||||
/* Generate SRK for SE1. */
|
||||
GenerateSrk(GetRegisters());
|
||||
|
||||
/* If we have SE2, generate SRK for SE2. */
|
||||
/* NOTE: Nintendo's implementation of this is incorrect. */
|
||||
if (fuse::GetSocType() == fuse::SocType_Mariko) {
|
||||
GenerateSrk(GetRegisters2());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,230 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "se_execute.hpp"
|
||||
|
||||
namespace ams::se {
|
||||
|
||||
namespace {
|
||||
|
||||
struct RsaKeyInfo {
|
||||
int modulus_size_val;
|
||||
int exponent_size_val;
|
||||
};
|
||||
|
||||
constinit RsaKeyInfo g_rsa_key_infos[RsaKeySlotCount] = {};
|
||||
|
||||
void ClearRsaKeySlot(volatile SecurityEngineRegisters *SE, int slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL expmod) {
|
||||
constexpr int NumWords = se::RsaSize / sizeof(u32);
|
||||
for (int i = 0; i < NumWords; ++i) {
|
||||
/* Select the keyslot word. */
|
||||
reg::Write(SE->SE_RSA_KEYTABLE_ADDR, SE_REG_BITS_ENUM (RSA_KEYTABLE_ADDR_INPUT_MODE, REGISTER),
|
||||
SE_REG_BITS_VALUE(RSA_KEYTABLE_ADDR_KEY_SLOT, slot),
|
||||
SE_REG_BITS_VALUE(RSA_KEYTABLE_ADDR_EXPMOD_SEL, expmod),
|
||||
SE_REG_BITS_VALUE(RSA_KEYTABLE_ADDR_WORD_ADDR, i));
|
||||
|
||||
/* Clear the keyslot word. */
|
||||
SE->SE_RSA_KEYTABLE_DATA = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SetRsaKey(volatile SecurityEngineRegisters *SE, int slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL expmod, const void *key, size_t key_size) {
|
||||
const int num_words = key_size / sizeof(u32);
|
||||
for (int i = 0; i < num_words; ++i) {
|
||||
/* Select the keyslot word. */
|
||||
reg::Write(SE->SE_RSA_KEYTABLE_ADDR, SE_REG_BITS_ENUM (RSA_KEYTABLE_ADDR_INPUT_MODE, REGISTER),
|
||||
SE_REG_BITS_VALUE(RSA_KEYTABLE_ADDR_KEY_SLOT, slot),
|
||||
SE_REG_BITS_VALUE(RSA_KEYTABLE_ADDR_EXPMOD_SEL, expmod),
|
||||
SE_REG_BITS_VALUE(RSA_KEYTABLE_ADDR_WORD_ADDR, i));
|
||||
|
||||
/* Get the word. */
|
||||
const u32 word = util::LoadBigEndian(static_cast<const u32 *>(key) + (num_words - 1 - i));
|
||||
|
||||
/* Write the keyslot word. */
|
||||
SE->SE_RSA_KEYTABLE_DATA = word;
|
||||
}
|
||||
}
|
||||
|
||||
void GetRsaResult(volatile SecurityEngineRegisters *SE, void *dst, size_t size) {
|
||||
/* Copy out the words. */
|
||||
const int num_words = size / sizeof(u32);
|
||||
for (int i = 0; i < num_words; ++i) {
|
||||
const u32 word = reg::Read(SE->SE_RSA_OUTPUT[i]);
|
||||
util::StoreBigEndian(static_cast<u32 *>(dst) + num_words - 1 - i, word);
|
||||
}
|
||||
}
|
||||
|
||||
void WaitForInputReadComplete(volatile SecurityEngineRegisters *SE) {
|
||||
while (reg::HasValue(SE->SE_INT_STATUS, SE_REG_BITS_ENUM(INT_STATUS_IN_DONE, CLEAR))) { /* ... */ }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ClearRsaKeySlot(int slot) {
|
||||
/* Validate the key slot. */
|
||||
AMS_ABORT_UNLESS(0 <= slot && slot < RsaKeySlotCount);
|
||||
|
||||
/* Clear the info. */
|
||||
g_rsa_key_infos[slot] = {};
|
||||
|
||||
/* Get the engine. */
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Clear the modulus. */
|
||||
ClearRsaKeySlot(SE, slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL_MODULUS);
|
||||
|
||||
/* Clear the exponent. */
|
||||
ClearRsaKeySlot(SE, slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL_EXPONENT);
|
||||
}
|
||||
|
||||
void LockRsaKeySlot(int slot, u32 flags) {
|
||||
/* Validate the key slot. */
|
||||
AMS_ABORT_UNLESS(0 <= slot && slot < RsaKeySlotCount);
|
||||
|
||||
/* Get the engine. */
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Set non per-key flags. */
|
||||
if ((flags & ~KeySlotLockFlags_PerKey) != 0) {
|
||||
/* Pack the flags into the expected format. */
|
||||
u32 value = 0;
|
||||
value |= ((flags & KeySlotLockFlags_KeyRead) == 0) ? (1u << 0) : 0;
|
||||
value |= ((flags & KeySlotLockFlags_KeyRead) == 0) ? (1u << 1) : 0;
|
||||
value |= ((flags & KeySlotLockFlags_KeyRead) == 0) ? (1u << 2) : 0;
|
||||
|
||||
reg::Write(SE->SE_RSA_KEYTABLE_ACCESS[slot], SE_REG_BITS_ENUM_SEL(RSA_KEYTABLE_ACCESS_KEYREAD, (flags & KeySlotLockFlags_KeyRead) != 0, DISABLE, ENABLE),
|
||||
SE_REG_BITS_ENUM_SEL(RSA_KEYTABLE_ACCESS_KEYUPDATE, (flags & KeySlotLockFlags_KeyWrite) != 0, DISABLE, ENABLE),
|
||||
SE_REG_BITS_ENUM_SEL(RSA_KEYTABLE_ACCESS_KEYUSE, (flags & KeySlotLockFlags_KeyUse) != 0, DISABLE, ENABLE));
|
||||
}
|
||||
|
||||
/* Set per-key flag. */
|
||||
if ((flags & KeySlotLockFlags_PerKey) != 0) {
|
||||
reg::ReadWrite(SE->SE_RSA_SECURITY_PERKEY, REG_BITS_VALUE(slot, 1, 0));
|
||||
}
|
||||
}
|
||||
|
||||
void SetRsaKey(int slot, const void *mod, size_t mod_size, const void *exp, size_t exp_size) {
|
||||
/* Validate the key slot and sizes. */
|
||||
AMS_ABORT_UNLESS(0 <= slot && slot < RsaKeySlotCount);
|
||||
AMS_ABORT_UNLESS(mod_size <= RsaSize);
|
||||
AMS_ABORT_UNLESS(exp_size <= RsaSize);
|
||||
|
||||
/* Set the sizes in the info. */
|
||||
auto &info = g_rsa_key_infos[slot];
|
||||
info.modulus_size_val = (mod_size / 64) - 1;
|
||||
info.exponent_size_val = (exp_size / 4);
|
||||
|
||||
/* Get the engine. */
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Set the modulus and exponent. */
|
||||
SetRsaKey(SE, slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL_MODULUS, mod, mod_size);
|
||||
SetRsaKey(SE, slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL_EXPONENT, exp, exp_size);
|
||||
}
|
||||
|
||||
void ModularExponentiate(void *dst, size_t dst_size, int slot, const void *src, size_t src_size) {
|
||||
/* Validate the slot and sizes. */
|
||||
AMS_ABORT_UNLESS(0 <= slot && slot < RsaKeySlotCount);
|
||||
AMS_ABORT_UNLESS(src_size <= RsaSize);
|
||||
AMS_ABORT_UNLESS(dst_size <= RsaSize);
|
||||
|
||||
/* Get the engine. */
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Create a work buffer. */
|
||||
u8 work[RsaSize];
|
||||
util::ClearMemory(work, sizeof(work));
|
||||
|
||||
/* Copy the input into the work buffer (reversing endianness). */
|
||||
const u8 *src_u8 = static_cast<const u8 *>(src);
|
||||
for (size_t i = 0; i < src_size; ++i) {
|
||||
work[src_size - 1 - i] = src_u8[i];
|
||||
}
|
||||
|
||||
/* Flush the work buffer to ensure the SE sees correct results. */
|
||||
hw::FlushDataCache(work, sizeof(work));
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Configure the engine to perform RSA encryption. */
|
||||
reg::Write(SE->SE_CONFIG, SE_REG_BITS_ENUM(CONFIG_ENC_MODE, AESMODE_KEY128),
|
||||
SE_REG_BITS_ENUM(CONFIG_DEC_MODE, AESMODE_KEY128),
|
||||
SE_REG_BITS_ENUM(CONFIG_ENC_ALG, RSA),
|
||||
SE_REG_BITS_ENUM(CONFIG_DEC_ALG, NOP),
|
||||
SE_REG_BITS_ENUM(CONFIG_DST, RSA_REG));
|
||||
|
||||
/* Configure the engine to use the keyslot and correct modulus/exp sizes. */
|
||||
const auto &info = g_rsa_key_infos[slot];
|
||||
reg::Write(SE->SE_RSA_CONFIG, SE_REG_BITS_VALUE(RSA_CONFIG_KEY_SLOT, slot));
|
||||
reg::Write(SE->SE_RSA_KEY_SIZE, info.modulus_size_val);
|
||||
reg::Write(SE->SE_RSA_EXP_SIZE, info.exponent_size_val);
|
||||
|
||||
/* Execute the operation. */
|
||||
ExecuteOperation(SE, SE_OPERATION_OP_START, nullptr, 0, work, src_size);
|
||||
|
||||
/* Copy out the result. */
|
||||
GetRsaResult(SE, dst, dst_size);
|
||||
}
|
||||
|
||||
void ModularExponentiateAsync(int slot, const void *src, size_t src_size, DoneHandler handler) {
|
||||
/* Validate the slot and size. */
|
||||
AMS_ABORT_UNLESS(0 <= slot && slot < RsaKeySlotCount);
|
||||
AMS_ABORT_UNLESS(src_size <= RsaSize);
|
||||
|
||||
/* Get the engine. */
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Create a work buffer. */
|
||||
u8 work[RsaSize];
|
||||
util::ClearMemory(work, sizeof(work));
|
||||
|
||||
/* Copy the input into the work buffer (reversing endianness). */
|
||||
const u8 *src_u8 = static_cast<const u8 *>(src);
|
||||
for (size_t i = 0; i < src_size; ++i) {
|
||||
work[src_size - 1 - i] = src_u8[i];
|
||||
}
|
||||
|
||||
/* Flush the work buffer to ensure the SE sees correct results. */
|
||||
hw::FlushDataCache(work, sizeof(work));
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Configure the engine to perform RSA encryption. */
|
||||
reg::Write(SE->SE_CONFIG, SE_REG_BITS_ENUM(CONFIG_ENC_MODE, AESMODE_KEY128),
|
||||
SE_REG_BITS_ENUM(CONFIG_DEC_MODE, AESMODE_KEY128),
|
||||
SE_REG_BITS_ENUM(CONFIG_ENC_ALG, RSA),
|
||||
SE_REG_BITS_ENUM(CONFIG_DEC_ALG, NOP),
|
||||
SE_REG_BITS_ENUM(CONFIG_DST, RSA_REG));
|
||||
|
||||
/* Configure the engine to use the keyslot and correct modulus/exp sizes. */
|
||||
const auto &info = g_rsa_key_infos[slot];
|
||||
reg::Write(SE->SE_RSA_CONFIG, SE_REG_BITS_VALUE(RSA_CONFIG_KEY_SLOT, slot));
|
||||
reg::Write(SE->SE_RSA_KEY_SIZE, info.modulus_size_val);
|
||||
reg::Write(SE->SE_RSA_EXP_SIZE, info.exponent_size_val);
|
||||
|
||||
/* Set the done handler. */
|
||||
SetDoneHandler(SE, handler);
|
||||
|
||||
/* Trigger the input operation. */
|
||||
StartInputOperation(SE, work, src_size);
|
||||
|
||||
/* Wait for input to be read by the se. */
|
||||
WaitForInputReadComplete(SE);
|
||||
}
|
||||
|
||||
void GetRsaResult(void *dst, size_t dst_size) {
|
||||
GetRsaResult(GetRegisters(), dst, dst_size);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,354 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "se_execute.hpp"
|
||||
|
||||
namespace ams::se {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline size_t SE1ContextSaveOperationCount = 133;
|
||||
constexpr inline size_t SE2ContextSaveOperationCount = 646;
|
||||
static_assert(((SE1ContextSaveOperationCount - 2) + 1) * se::AesBlockSize == sizeof(se::Context));
|
||||
|
||||
constinit const u8 FixedPattern[AesBlockSize] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
|
||||
};
|
||||
|
||||
bool TestRegister(volatile u32 &r, u16 v) {
|
||||
return (static_cast<u16>(reg::Read(r))) == v;
|
||||
}
|
||||
|
||||
void ExecuteContextSaveOperation(volatile SecurityEngineRegisters *SE, void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||
/* Save the output to a temporary buffer. */
|
||||
util::AlignedBuffer<hw::DataCacheLineSize, AesBlockSize> temp;
|
||||
AMS_ABORT_UNLESS(dst_size <= AesBlockSize);
|
||||
|
||||
/* Ensure that the cpu and SE see consistent data. */
|
||||
if (src_size > 0) {
|
||||
hw::FlushDataCache(src, src_size);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
}
|
||||
if (dst_size > 0) {
|
||||
hw::FlushDataCache(temp, AesBlockSize);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
}
|
||||
|
||||
/* Execute the operation. */
|
||||
ExecuteOperation(SE, SE_OPERATION_OP_CTX_SAVE, temp, dst_size, src, src_size);
|
||||
|
||||
/* Copy output from the operation, if any. */
|
||||
if (dst_size > 0) {
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
hw::FlushDataCache(temp, AesBlockSize);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
std::memcpy(dst, temp, dst_size);
|
||||
}
|
||||
}
|
||||
|
||||
void SaveContextBlock(volatile SecurityEngineRegisters *SE, void *dst) {
|
||||
/* Configure to encrypt a single block. */
|
||||
reg::Write(SE->SE_CRYPTO_LAST_BLOCK, 0);
|
||||
|
||||
/* Execute the operation. */
|
||||
ExecuteContextSaveOperation(SE, dst, AesBlockSize, nullptr, 0);
|
||||
}
|
||||
|
||||
void ConfigureForAutomaticContextSave(volatile SecurityEngineRegisters *SE) {
|
||||
/* Configure the engine to do RNG encryption. */
|
||||
reg::Write(SE->SE_CONFIG, SE_REG_BITS_ENUM(CONFIG_ENC_MODE, AESMODE_KEY128),
|
||||
SE_REG_BITS_ENUM(CONFIG_DEC_MODE, AESMODE_KEY128),
|
||||
SE_REG_BITS_ENUM(CONFIG_ENC_ALG, RNG),
|
||||
SE_REG_BITS_ENUM(CONFIG_DEC_ALG, NOP),
|
||||
SE_REG_BITS_ENUM(CONFIG_DST, MEMORY));
|
||||
|
||||
reg::Write(SE->SE_CRYPTO_CONFIG, SE_REG_BITS_ENUM (CRYPTO_CONFIG_MEMIF, AHB),
|
||||
SE_REG_BITS_VALUE(CRYPTO_CONFIG_CTR_CNTN, 0),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_KEYSCH_BYPASS, DISABLE),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_CORE_SEL, ENCRYPT),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_IV_SELECT, ORIGINAL),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_VCTRAM_SEL, MEMORY),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_INPUT_SEL, RANDOM),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_XOR_POS, BYPASS),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_HASH_ENB, DISABLE));
|
||||
}
|
||||
|
||||
void WaitAutomaticContextSaveDone(volatile SecurityEngineRegisters *SE) {
|
||||
/* Wait for operation. */
|
||||
while (!reg::HasValue(SE->SE_INT_STATUS, SE_REG_BITS_ENUM(INT_STATUS_SE_OP_DONE, ACTIVE))) { /* ... */ }
|
||||
|
||||
/* Wait for the engine to be idle. */
|
||||
while (!reg::HasValue(SE->SE_STATUS, SE_REG_BITS_ENUM(STATUS_STATE, IDLE))) { /* ... */ }
|
||||
|
||||
/* Wait for the memory interface to be idle. */
|
||||
while (!reg::HasValue(SE->SE_STATUS, SE_REG_BITS_ENUM(STATUS_MEM_INTERFACE, IDLE))) { /* ... */ }
|
||||
}
|
||||
|
||||
void ValidateErrStatus(volatile SecurityEngineRegisters *SE) {
|
||||
/* Ensure there is no error status. */
|
||||
AMS_ABORT_UNLESS(reg::Read(SE->SE_ERR_STATUS) == 0);
|
||||
|
||||
/* Ensure no error occurred. */
|
||||
AMS_ABORT_UNLESS(reg::HasValue(SE->SE_INT_STATUS, SE_REG_BITS_ENUM(INT_STATUS_ERR_STAT, CLEAR)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool ValidateStickyBits(const StickyBits &bits) {
|
||||
/* Get the registers. */
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Check SE_SECURITY. */
|
||||
if (!TestRegister(SE->SE_SE_SECURITY, bits.se_security)) { return false; }
|
||||
|
||||
/* Check TZRAM_SECURITY. */
|
||||
if (!TestRegister(SE->SE_TZRAM_SECURITY, bits.tzram_security)) { return false; }
|
||||
|
||||
/* Check CRYPTO_SECURITY_PERKEY. */
|
||||
if (!TestRegister(SE->SE_CRYPTO_SECURITY_PERKEY, bits.crypto_security_perkey)) { return false; }
|
||||
|
||||
/* Check CRYPTO_KEYTABLE_ACCESS. */
|
||||
for (int i = 0; i < AesKeySlotCount; ++i) {
|
||||
if (!TestRegister(SE->SE_CRYPTO_KEYTABLE_ACCESS[i], bits.crypto_keytable_access[i])) { return false; }
|
||||
}
|
||||
|
||||
/* Test RSA_SECURITY_PERKEY */
|
||||
if (!TestRegister(SE->SE_RSA_SECURITY_PERKEY, bits.rsa_security_perkey)) { return false; }
|
||||
|
||||
/* Check RSA_KEYTABLE_ACCESS. */
|
||||
for (int i = 0; i < RsaKeySlotCount; ++i) {
|
||||
if (!TestRegister(SE->SE_RSA_KEYTABLE_ACCESS[i], bits.rsa_keytable_access[i])) { return false; }
|
||||
}
|
||||
|
||||
/* All sticky bits are valid. */
|
||||
return true;
|
||||
}
|
||||
|
||||
void SaveContext(Context *dst) {
|
||||
/* Get the registers. */
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Generate a random srk. */
|
||||
GenerateSrk();
|
||||
|
||||
/* Save a randomly-generated block. */
|
||||
{
|
||||
util::AlignedBuffer<hw::DataCacheLineSize, AesBlockSize> random_block;
|
||||
|
||||
/* Flush the region we're about to fill to ensure consistency with the SE. */
|
||||
hw::FlushDataCache(random_block, AesBlockSize);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Generate random bytes. */
|
||||
GenerateRandomBytes(random_block, AesBlockSize);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Flush to ensure the CPU sees consistent data for the region. */
|
||||
hw::FlushDataCache(random_block, AesBlockSize);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Configure to encrypt the random block to memory. */
|
||||
reg::Write(SE->SE_CONFIG, SE_REG_BITS_ENUM(CONFIG_ENC_MODE, AESMODE_KEY128),
|
||||
SE_REG_BITS_ENUM(CONFIG_DEC_MODE, AESMODE_KEY128),
|
||||
SE_REG_BITS_ENUM(CONFIG_ENC_ALG, AES_ENC),
|
||||
SE_REG_BITS_ENUM(CONFIG_DEC_ALG, NOP),
|
||||
SE_REG_BITS_ENUM(CONFIG_DST, MEMORY));
|
||||
|
||||
/* Configure to context save using memory as source. */
|
||||
reg::Write(SE->SE_CTX_SAVE_CONFIG, SE_REG_BITS_ENUM(CTX_SAVE_CONFIG_SRC, MEM));
|
||||
|
||||
/* Configure to encrypt a single block. */
|
||||
reg::Write(SE->SE_CRYPTO_LAST_BLOCK, 0);
|
||||
|
||||
/* Execute the operation. */
|
||||
ExecuteContextSaveOperation(SE, dst->random, AesBlockSize, random_block, AesBlockSize);
|
||||
}
|
||||
|
||||
/* Save the sticky bits. */
|
||||
for (size_t i = 0; i < util::size(dst->sticky_bits); ++i) {
|
||||
/* Configure to encrypt the sticky bits block. */
|
||||
reg::Write(SE->SE_CTX_SAVE_CONFIG, SE_REG_BITS_ENUM (CTX_SAVE_CONFIG_SRC, STICKY_BITS),
|
||||
SE_REG_BITS_VALUE(CTX_SAVE_CONFIG_STICKY_WORD_QUAD, i));
|
||||
|
||||
/* Save the block. */
|
||||
SaveContextBlock(SE, dst->sticky_bits[i]);
|
||||
}
|
||||
|
||||
/* Save the aes keytable. */
|
||||
{
|
||||
for (size_t key = 0; key < util::size(dst->aes_key); ++key) {
|
||||
for (auto part = 0; part < AesKeySlotPartCount; ++part) {
|
||||
/* Configure to encrypt the part of the key. */
|
||||
reg::Write(SE->SE_CTX_SAVE_CONFIG, SE_REG_BITS_ENUM (CTX_SAVE_CONFIG_SRC, AES_KEYTABLE),
|
||||
SE_REG_BITS_VALUE(CTX_SAVE_CONFIG_AES_KEY_INDEX, key),
|
||||
SE_REG_BITS_VALUE(CTX_SAVE_CONFIG_AES_WORD_QUAD, part));
|
||||
|
||||
/* Save the block. */
|
||||
SaveContextBlock(SE, dst->aes_key[key][part]);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t key = 0; key < util::size(dst->aes_oiv); ++key) {
|
||||
/* Configure to encrypt the original iv. */
|
||||
reg::Write(SE->SE_CTX_SAVE_CONFIG, SE_REG_BITS_ENUM (CTX_SAVE_CONFIG_SRC, AES_KEYTABLE),
|
||||
SE_REG_BITS_VALUE(CTX_SAVE_CONFIG_AES_KEY_INDEX, key),
|
||||
SE_REG_BITS_ENUM (CTX_SAVE_CONFIG_AES_WORD_QUAD, ORIGINAL_IVS));
|
||||
|
||||
/* Save the block. */
|
||||
SaveContextBlock(SE, dst->aes_oiv[key]);
|
||||
}
|
||||
|
||||
for (size_t key = 0; key < util::size(dst->aes_uiv); ++key) {
|
||||
/* Configure to encrypt the updated iv. */
|
||||
reg::Write(SE->SE_CTX_SAVE_CONFIG, SE_REG_BITS_ENUM (CTX_SAVE_CONFIG_SRC, AES_KEYTABLE),
|
||||
SE_REG_BITS_VALUE(CTX_SAVE_CONFIG_AES_KEY_INDEX, key),
|
||||
SE_REG_BITS_ENUM (CTX_SAVE_CONFIG_AES_WORD_QUAD, UPDATED_IVS));
|
||||
|
||||
/* Save the block. */
|
||||
SaveContextBlock(SE, dst->aes_uiv[key]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Save the rsa keytable. */
|
||||
for (size_t key = 0; key < util::size(dst->rsa_key); ++key) {
|
||||
for (auto part = 0; part < RsaKeySlotPartCount; ++part) {
|
||||
/* Note that the parts are done in reverse order. */
|
||||
const auto part_index = RsaKeySlotPartCount - 1 - part;
|
||||
|
||||
/* Determine a total key index. */
|
||||
const auto key_index = key * util::size(dst->rsa_key) + part_index;
|
||||
|
||||
for (size_t block = 0; block < RsaSize / AesBlockSize; ++block) {
|
||||
/* Configure to encrypt the part of the key. */
|
||||
reg::Write(SE->SE_CTX_SAVE_CONFIG, SE_REG_BITS_ENUM (CTX_SAVE_CONFIG_SRC, RSA_KEYTABLE),
|
||||
SE_REG_BITS_VALUE(CTX_SAVE_CONFIG_RSA_KEY_INDEX, key_index),
|
||||
SE_REG_BITS_VALUE(CTX_SAVE_CONFIG_RSA_WORD_QUAD, block));
|
||||
|
||||
/* Save the block. */
|
||||
SaveContextBlock(SE, dst->rsa_key[key][part][block]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Save the fixed pattern. */
|
||||
{
|
||||
/* Configure to context save using memory as source. */
|
||||
reg::Write(SE->SE_CTX_SAVE_CONFIG, SE_REG_BITS_ENUM(CTX_SAVE_CONFIG_SRC, MEM));
|
||||
|
||||
/* Configure to encrypt a single block. */
|
||||
reg::Write(SE->SE_CRYPTO_LAST_BLOCK, 0);
|
||||
|
||||
/* Execute the operation. */
|
||||
ExecuteContextSaveOperation(SE, dst->fixed_pattern, AesBlockSize, FixedPattern, AesBlockSize);
|
||||
}
|
||||
|
||||
/* Save the srk. */
|
||||
{
|
||||
/* Configure to context save using srk as source. */
|
||||
reg::Write(SE->SE_CTX_SAVE_CONFIG, SE_REG_BITS_ENUM(CTX_SAVE_CONFIG_SRC, SRK));
|
||||
|
||||
/* Configure to encrypt a single block. */
|
||||
reg::Write(SE->SE_CRYPTO_LAST_BLOCK, 0);
|
||||
|
||||
/* Execute the operation. */
|
||||
ExecuteContextSaveOperation(SE, nullptr, 0, nullptr, 0);
|
||||
}
|
||||
|
||||
/* Perform a no-op context save operation. */
|
||||
{
|
||||
/* Configure to perform no-op. */
|
||||
reg::Write(SE->SE_CONFIG, SE_REG_BITS_ENUM(CONFIG_ENC_ALG, NOP),
|
||||
SE_REG_BITS_ENUM(CONFIG_DEC_ALG, NOP));
|
||||
|
||||
/* Execute the operation. */
|
||||
ExecuteContextSaveOperation(SE, nullptr, 0, nullptr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigureAutomaticContextSave() {
|
||||
/* Get registers. */
|
||||
auto *SE = GetRegisters();
|
||||
auto *SE2 = GetRegisters2();
|
||||
|
||||
/* Automatic context save is supported only on mariko. */
|
||||
if (fuse::GetSocType() == fuse::SocType_Mariko) {
|
||||
/* Configure SE1 to do automatic context save. */
|
||||
reg::Write(SE->SE_CTX_SAVE_AUTO, SE_REG_BITS_ENUM(CTX_SAVE_AUTO_ENABLE, YES),
|
||||
SE_REG_BITS_ENUM(CTX_SAVE_AUTO_LOCK, YES));
|
||||
|
||||
/* Configure SE2 to do automatic context save. */
|
||||
reg::Write(SE2->SE_CTX_SAVE_AUTO, SE_REG_BITS_ENUM(CTX_SAVE_AUTO_ENABLE, YES),
|
||||
SE_REG_BITS_ENUM(CTX_SAVE_AUTO_LOCK, YES));
|
||||
}
|
||||
}
|
||||
|
||||
void SaveContextAutomatic() {
|
||||
/* Get registers. */
|
||||
auto *SE = GetRegisters();
|
||||
auto *SE2 = GetRegisters2();
|
||||
|
||||
/* Ensure there's no error status before or after we save context. */
|
||||
ValidateErrStatus();
|
||||
ON_SCOPE_EXIT { ValidateErrStatus(); };
|
||||
|
||||
/* Perform atomic context save. */
|
||||
{
|
||||
/* Check that context save has not already been performed. */
|
||||
AMS_ABORT_UNLESS(reg::HasValue(SE->SE_CTX_SAVE_AUTO, SE_REG_BITS_VALUE(CTX_SAVE_AUTO_CURR_CNT, 0)));
|
||||
AMS_ABORT_UNLESS(reg::HasValue(SE2->SE_CTX_SAVE_AUTO, SE_REG_BITS_VALUE(CTX_SAVE_AUTO_CURR_CNT, 0)));
|
||||
|
||||
/* Configure SE1 to do context save. */
|
||||
ConfigureForAutomaticContextSave(SE);
|
||||
ConfigureForAutomaticContextSave(SE2);
|
||||
|
||||
/* Start the context save operation. */
|
||||
reg::Write(SE->SE_OPERATION, SE_REG_BITS_ENUM(OPERATION_OP, CTX_SAVE));
|
||||
reg::Write(SE2->SE_OPERATION, SE_REG_BITS_ENUM(OPERATION_OP, CTX_SAVE));
|
||||
|
||||
/* Wait for the context save operation to complete. */
|
||||
WaitAutomaticContextSaveDone(SE);
|
||||
WaitAutomaticContextSaveDone(SE2);
|
||||
|
||||
/* Check that the correct sizes were written. */
|
||||
AMS_ABORT_UNLESS(reg::HasValue(SE->SE_CTX_SAVE_AUTO, SE_REG_BITS_VALUE(CTX_SAVE_AUTO_CURR_CNT, SE1ContextSaveOperationCount)));
|
||||
AMS_ABORT_UNLESS(reg::HasValue(SE2->SE_CTX_SAVE_AUTO, SE_REG_BITS_VALUE(CTX_SAVE_AUTO_CURR_CNT, SE2ContextSaveOperationCount)));
|
||||
}
|
||||
}
|
||||
|
||||
void SaveTzramAutomatic() {
|
||||
/* Get registers. */
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Begin save-to-shadow-tzram operation. */
|
||||
reg::Write(SE->SE_TZRAM_OPERATION, SE_REG_BITS_ENUM(TZRAM_OPERATION_MODE, SAVE),
|
||||
SE_REG_BITS_ENUM(TZRAM_OPERATION_REQ, INITIATE));
|
||||
|
||||
/* Wait for operation to complete. */
|
||||
while (reg::HasValue(SE->SE_TZRAM_OPERATION, SE_REG_BITS_ENUM(TZRAM_OPERATION_BUSY, YES))) { /* ... */ }
|
||||
}
|
||||
|
||||
void ValidateErrStatus() {
|
||||
/* Ensure SE has no error status. */
|
||||
ValidateErrStatus(GetRegisters());
|
||||
|
||||
/* If on mariko, ensure SE2 has no error status. */
|
||||
if (fuse::GetSocType() == fuse::SocType_Mariko) {
|
||||
ValidateErrStatus(GetRegisters2());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "tsec_registers.hpp"
|
||||
#include "../kfuse/kfuse_registers.hpp"
|
||||
|
||||
namespace ams::tsec {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline const uintptr_t KFUSE = 0x7000FC00;
|
||||
constexpr inline const uintptr_t TSEC = 0x54500000;
|
||||
|
||||
enum TsecResult : u32 {
|
||||
TsecResult_Success = 0xB0B0B0B0,
|
||||
TsecResult_Failure = 0xD0D0D0D0,
|
||||
};
|
||||
|
||||
enum TsecMemory {
|
||||
TsecMemory_Imem,
|
||||
TsecMemory_Dmem,
|
||||
};
|
||||
|
||||
bool WaitForKfuseReady() {
|
||||
constexpr auto KfuseTimeout = 10 * 1000; /* 10 ms. */
|
||||
|
||||
const u32 end_time = util::GetMicroSeconds() + KfuseTimeout;
|
||||
|
||||
/* Wait for STATE_DONE. */
|
||||
while (!reg::HasValue(KFUSE + KFUSE_STATE, KFUSE_REG_BITS_ENUM(STATE_DONE, DONE))) {
|
||||
if (util::GetMicroSeconds() >= end_time) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for STATE_CRCPASS. */
|
||||
return reg::HasValue(KFUSE + KFUSE_STATE, KFUSE_REG_BITS_ENUM(STATE_CRCPASS, PASS));
|
||||
}
|
||||
|
||||
void WaitForDmaIdle() {
|
||||
constexpr auto DmaTimeout = 10 * 1000 * 1000; /* 10 Seconds. */
|
||||
|
||||
u32 cur_time = util::GetMicroSeconds();
|
||||
const u32 end_time = cur_time + DmaTimeout;
|
||||
|
||||
while (cur_time <= end_time) {
|
||||
if (reg::HasValue(TSEC + TSEC_FALCON_DMATRFCMD, TSEC_REG_BITS_ENUM(FALCON_DMATRFCMD_BUSY, IDLE))) {
|
||||
return;
|
||||
}
|
||||
|
||||
cur_time = util::GetMicroSeconds();
|
||||
}
|
||||
|
||||
AMS_ABORT("tsec dma timeout");
|
||||
}
|
||||
|
||||
void WaitForTsecIdle() {
|
||||
constexpr auto TsecTimeout = 2 * 1000 * 1000; /* 2 Seconds. */
|
||||
|
||||
u32 cur_time = util::GetMicroSeconds();
|
||||
const u32 end_time = cur_time + TsecTimeout;
|
||||
|
||||
while (cur_time <= end_time) {
|
||||
if (reg::HasValue(TSEC + TSEC_FALCON_CPUCTL, TSEC_REG_BITS_ENUM(FALCON_CPUCTL_HALTED, TRUE))) {
|
||||
return;
|
||||
}
|
||||
|
||||
cur_time = util::GetMicroSeconds();
|
||||
}
|
||||
|
||||
AMS_ABORT("tsec timeout");
|
||||
}
|
||||
|
||||
void DoDma256(TsecMemory memory, u32 dst_offset, u32 src_offset) {
|
||||
reg::Write(TSEC + TSEC_FALCON_DMATRFMOFFS, TSEC_REG_BITS_VALUE(FALCON_DMATRFMOFFS_OFFSET, dst_offset));
|
||||
reg::Write(TSEC + TSEC_FALCON_DMATRFFBOFFS, src_offset);
|
||||
|
||||
if (memory == TsecMemory_Imem) {
|
||||
reg::Write(TSEC + TSEC_FALCON_DMATRFCMD, TSEC_REG_BITS_ENUM(FALCON_DMATRFCMD_TO, IMEM),
|
||||
TSEC_REG_BITS_ENUM(FALCON_DMATRFCMD_SIZE, 4B));
|
||||
} else {
|
||||
reg::Write(TSEC + TSEC_FALCON_DMATRFCMD, TSEC_REG_BITS_ENUM(FALCON_DMATRFCMD_TO, DMEM),
|
||||
TSEC_REG_BITS_ENUM(FALCON_DMATRFCMD_SIZE, 256B));
|
||||
}
|
||||
|
||||
WaitForDmaIdle();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool RunTsecFirmware(const void *fw, size_t fw_size) {
|
||||
/* Enable relevant clocks. */
|
||||
clkrst::EnableHost1xClock();
|
||||
clkrst::EnableTsecClock();
|
||||
clkrst::EnableSorSafeClock();
|
||||
clkrst::EnableSor0Clock();
|
||||
clkrst::EnableSor1Clock();
|
||||
clkrst::EnableKfuseClock();
|
||||
|
||||
/* Disable clocks once we're done. */
|
||||
ON_SCOPE_EXIT {
|
||||
clkrst::DisableHost1xClock();
|
||||
clkrst::DisableTsecClock();
|
||||
clkrst::DisableSorSafeClock();
|
||||
clkrst::DisableSor0Clock();
|
||||
clkrst::DisableSor1Clock();
|
||||
clkrst::DisableKfuseClock();
|
||||
};
|
||||
|
||||
/* Wait for kfuse to be ready. */
|
||||
if (!WaitForKfuseReady()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Configure falcon. */
|
||||
reg::Write(TSEC + TSEC_FALCON_DMACTL, 0);
|
||||
reg::Write(TSEC + TSEC_FALCON_IRQMSET, 0xFFF2);
|
||||
reg::Write(TSEC + TSEC_FALCON_IRQDEST, 0xFFF0);
|
||||
reg::Write(TSEC + TSEC_FALCON_ITFEN, 0x3);
|
||||
|
||||
/* Wait for TSEC dma to be idle. */
|
||||
WaitForDmaIdle();
|
||||
|
||||
/* Set the base address for transfers. */
|
||||
reg::Write(TSEC + TSEC_FALCON_DMATRFBASE, reinterpret_cast<uintptr_t>(fw) >> 8);
|
||||
|
||||
/* Transfer all data to TSEC imem. */
|
||||
for (size_t i = 0; i < fw_size; i += 0x100) {
|
||||
DoDma256(TsecMemory_Imem, i, i);
|
||||
}
|
||||
|
||||
/* Write the magic value to host1x syncpoint 160. */
|
||||
reg::Write(0x50003300, 0x34C2E1DA);
|
||||
|
||||
/* Execute the firmware. */
|
||||
reg::Write(TSEC + TSEC_FALCON_MAILBOX0, 0);
|
||||
reg::Write(TSEC + TSEC_FALCON_MAILBOX1, 0);
|
||||
reg::Write(TSEC + TSEC_FALCON_BOOTVEC, 0);
|
||||
reg::Write(TSEC + TSEC_FALCON_CPUCTL, TSEC_REG_BITS_ENUM(FALCON_CPUCTL_STARTCPU, TRUE));
|
||||
|
||||
/* Wait for TSEC dma to be idle. */
|
||||
WaitForDmaIdle();
|
||||
|
||||
/* Wait for TSEC to complete. */
|
||||
WaitForTsecIdle();
|
||||
|
||||
/* Clear magic value from host1x syncpoint 160. */
|
||||
reg::Write(0x50003300, 0);
|
||||
|
||||
/* Return whether the tsec firmware succeeded. */
|
||||
return reg::Read(TSEC + TSEC_FALCON_MAILBOX1) == TsecResult_Success;
|
||||
}
|
||||
|
||||
void Lock() {
|
||||
/* Set the tsec host1x syncpoint (160) to be secure. */
|
||||
/* TODO: constexpr value. */
|
||||
reg::ReadWrite(0x500038F8, REG_BITS_VALUE(0, 1, 0));
|
||||
|
||||
/* Clear the tsec host1x syncpoint. */
|
||||
reg::Write(0x50003300, 0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
|
||||
#define TSEC_FALCON_IRQMSET (0x1010)
|
||||
#define TSEC_FALCON_IRQDEST (0x101C)
|
||||
#define TSEC_FALCON_MAILBOX0 (0x1040)
|
||||
#define TSEC_FALCON_MAILBOX1 (0x1044)
|
||||
#define TSEC_FALCON_ITFEN (0x1048)
|
||||
#define TSEC_FALCON_CPUCTL (0x1100)
|
||||
#define TSEC_FALCON_BOOTVEC (0x1104)
|
||||
#define TSEC_FALCON_DMACTL (0x110C)
|
||||
#define TSEC_FALCON_DMATRFBASE (0x1110)
|
||||
#define TSEC_FALCON_DMATRFMOFFS (0x1114)
|
||||
#define TSEC_FALCON_DMATRFCMD (0x1118)
|
||||
#define TSEC_FALCON_DMATRFFBOFFS (0x111C)
|
||||
|
||||
#define TSEC_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (TSEC, NAME)
|
||||
#define TSEC_REG_BITS_VALUE(NAME, VALUE) REG_NAMED_BITS_VALUE (TSEC, NAME, VALUE)
|
||||
#define TSEC_REG_BITS_ENUM(NAME, ENUM) REG_NAMED_BITS_ENUM (TSEC, NAME, ENUM)
|
||||
#define TSEC_REG_BITS_ENUM_TSECL(NAME, __COND__, TRUE_ENUM, FALTSEC_ENUM) REG_NAMED_BITS_ENUM_TSECL(TSEC, NAME, __COND__, TRUE_ENUM, FALTSEC_ENUM)
|
||||
|
||||
#define DEFINE_TSEC_REG(NAME, __OFFTSECT__, __WIDTH__) REG_DEFINE_NAMED_REG (TSEC, NAME, __OFFTSECT__, __WIDTH__)
|
||||
#define DEFINE_TSEC_REG_BIT_ENUM(NAME, __OFFTSECT__, ZERO, ONE) REG_DEFINE_NAMED_BIT_ENUM (TSEC, NAME, __OFFTSECT__, ZERO, ONE)
|
||||
#define DEFINE_TSEC_REG_TWO_BIT_ENUM(NAME, __OFFTSECT__, ZERO, ONE, TWO, THREE) REG_DEFINE_NAMED_TWO_BIT_ENUM (TSEC, NAME, __OFFTSECT__, ZERO, ONE, TWO, THREE)
|
||||
#define DEFINE_TSEC_REG_THREE_BIT_ENUM(NAME, __OFFTSECT__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, TSECVEN) REG_DEFINE_NAMED_THREE_BIT_ENUM(TSEC, NAME, __OFFTSECT__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, TSECVEN)
|
||||
#define DEFINE_TSEC_REG_FOUR_BIT_ENUM(NAME, __OFFTSECT__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, TSECVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) REG_DEFINE_NAMED_FOUR_BIT_ENUM (TSEC, NAME, __OFFTSECT__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, TSECVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN)
|
||||
|
||||
DEFINE_TSEC_REG_BIT_ENUM(FALCON_CPUCTL_STARTCPU, 1, FALSE, TRUE);
|
||||
DEFINE_TSEC_REG_BIT_ENUM(FALCON_CPUCTL_HALTED, 4, FALSE, TRUE);
|
||||
|
||||
DEFINE_TSEC_REG(FALCON_DMATRFMOFFS_OFFSET, 0, 16);
|
||||
|
||||
DEFINE_TSEC_REG_BIT_ENUM(FALCON_DMATRFCMD_BUSY, 1, BUSY, IDLE);
|
||||
DEFINE_TSEC_REG_BIT_ENUM(FALCON_DMATRFCMD_TO, 4, DMEM, IMEM);
|
||||
DEFINE_TSEC_REG_THREE_BIT_ENUM(FALCON_DMATRFCMD_SIZE, 8, 4B, 8B, 16B, 32B, 64B, 128B, 256B, RSVD7);
|
||||
@@ -1,149 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "uart_registers.hpp"
|
||||
|
||||
namespace ams::uart {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline const u16 UartRegisterOffsets[Port_Count] = {
|
||||
secmon::MemoryRegionPhysicalDeviceUartA.GetAddress() - secmon::MemoryRegionPhysicalDeviceUart.GetAddress(),
|
||||
secmon::MemoryRegionPhysicalDeviceUartB.GetAddress() - secmon::MemoryRegionPhysicalDeviceUart.GetAddress(),
|
||||
secmon::MemoryRegionPhysicalDeviceUartC.GetAddress() - secmon::MemoryRegionPhysicalDeviceUart.GetAddress(),
|
||||
};
|
||||
|
||||
constinit uintptr_t g_register_address = secmon::MemoryRegionPhysicalDeviceUart.GetAddress();
|
||||
|
||||
volatile UartRegisters *GetRegisters(Port port) {
|
||||
return reinterpret_cast<volatile UartRegisters *>(g_register_address + UartRegisterOffsets[port]);
|
||||
}
|
||||
|
||||
void WaitSymbols(int baud, u32 num) {
|
||||
util::WaitMicroSeconds(util::DivideUp(num * 1'000'000, baud));
|
||||
}
|
||||
|
||||
void WaitCycles(int baud, u32 num) {
|
||||
util::WaitMicroSeconds(util::DivideUp(num * 1'000'000, 16 * baud));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void WaitFifoNotFull(volatile UartRegisters *uart) {
|
||||
while ((uart->lsr & UART_LSR_TX_FIFO_FULL) != 0) { /* ... */ }
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void WaitFifoNotEmpty(volatile UartRegisters *uart) {
|
||||
while ((uart->lsr & UART_LSR_RX_FIFO_EMPTY) != 0) { /* ... */ }
|
||||
}
|
||||
|
||||
void WaitIdle(volatile UartRegisters *uart, u32 vendor_state) {
|
||||
if (vendor_state & UART_VENDOR_STATE_TX_IDLE) {
|
||||
while ((uart->lsr & UART_LSR_TMTY) == 0) { /* ... */ }
|
||||
}
|
||||
|
||||
if (vendor_state & UART_VENDOR_STATE_RX_IDLE) {
|
||||
while ((uart->lsr & UART_LSR_RDR) != 0) { /* ... */ }
|
||||
}
|
||||
}
|
||||
|
||||
constexpr inline u32 LockBit = (1 << 6);
|
||||
|
||||
}
|
||||
|
||||
void SetRegisterAddress(uintptr_t address) {
|
||||
g_register_address = address;
|
||||
}
|
||||
|
||||
void Initialize(Port port, int baud_rate, u32 flags) {
|
||||
/* Get the registers. */
|
||||
auto *uart = GetRegisters(port);
|
||||
|
||||
/* Parse flags. */
|
||||
const bool inverted = (flags & Flag_Inverted) != 0;
|
||||
|
||||
/* Calculate the baud rate divisor. */
|
||||
constexpr u32 UartClock = 408000000;
|
||||
const u32 divisor = (UartClock + (baud_rate * 16) / 2) / (baud_rate * 16);
|
||||
|
||||
/* Wait for idle state. */
|
||||
WaitIdle(uart, UART_VENDOR_STATE_TX_IDLE);
|
||||
|
||||
/* Wait 100 us. */
|
||||
util::WaitMicroSeconds(100);
|
||||
|
||||
/* Disable interrupts. */
|
||||
uart->lcr = uart->lcr & ~UART_LCR_DLAB;
|
||||
uart->ier = 0;
|
||||
uart->mcr = 0;
|
||||
|
||||
/* Setup the uart in FIFO mode. */
|
||||
uart->lcr = UART_LCR_DLAB | UART_LCR_WD_LENGTH_8;
|
||||
uart->dll = static_cast<u8>(divisor);
|
||||
uart->dlh = static_cast<u8>(divisor >> 8);
|
||||
uart->lcr = uart->lcr & ~UART_LCR_DLAB;
|
||||
reg::Read(std::addressof(uart->spr));
|
||||
|
||||
/* Wait three symbols. */
|
||||
WaitSymbols(baud_rate, 3);
|
||||
|
||||
/* Enable FIFO with default settings. */
|
||||
uart->fcr = UART_FCR_FCR_EN_FIFO;
|
||||
uart->irda_csr = inverted ? UART_IRDA_CSR_INVERT_TXD : 0;
|
||||
reg::Read(std::addressof(uart->spr));
|
||||
|
||||
/* Wait three cycles. */
|
||||
WaitCycles(baud_rate, 3);
|
||||
|
||||
/* Flush the FIFO. */
|
||||
WaitIdle(uart, UART_VENDOR_STATE_TX_IDLE);
|
||||
uart->fcr = uart->fcr | UART_FCR_RX_CLR | UART_FCR_TX_CLR;
|
||||
WaitCycles(baud_rate, 32);
|
||||
|
||||
/* Wait for idle state. */
|
||||
WaitIdle(uart, UART_VENDOR_STATE_TX_IDLE | UART_VENDOR_STATE_RX_IDLE);
|
||||
|
||||
/* Wait 100 us. */
|
||||
util::WaitMicroSeconds(100);
|
||||
}
|
||||
|
||||
void SendText(Port port, const void *data, size_t size) {
|
||||
/* Get the registers. */
|
||||
auto *uart = GetRegisters(port);
|
||||
|
||||
/* Get pointer to data. */
|
||||
const u8 *p = static_cast<const u8 *>(data);
|
||||
|
||||
/* Send each byte. */
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
WaitFifoNotFull(uart);
|
||||
|
||||
if (p[i] == '\n') {
|
||||
*reinterpret_cast<volatile u8 *>(std::addressof(uart->thr)) = '\r';
|
||||
WaitFifoNotFull(uart);
|
||||
}
|
||||
|
||||
*reinterpret_cast<volatile u8 *>(std::addressof(uart->thr)) = p[i];
|
||||
}
|
||||
}
|
||||
|
||||
void WaitFlush(Port port) {
|
||||
/* Get the registers. */
|
||||
auto *uart = GetRegisters(port);
|
||||
|
||||
/* Wait for idle. */
|
||||
WaitIdle(uart, UART_VENDOR_STATE_TX_IDLE);
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user