Revert "hoc-clk: add live vdd2, live boost clock and basic pwm dimming"

This reverts commit 15b7df8ef1.
This commit is contained in:
souldbminersmwc
2025-11-09 16:14:52 -05:00
parent 22ec140738
commit 21a3f953d7
3804 changed files with 435 additions and 570162 deletions

View File

@@ -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/>.
*/
using __ACCESS_TABLE_NAME__ = AccessTable<__ACCESS_TABLE_ADDRESS__, [] {
/* Declare a table. */
std::array<u8, 0x80> table = {};
/* Declare a helper. */
auto SetRegisterAllowed = [&](uintptr_t reg) { SetRegisterTableAllowed(table, reg); };
/* Populate the table. */
#include __ACCESS_TABLE_INC__
return table;
}()>;
static_assert(__ACCESS_TABLE_NAME__::Address >= __ACCESS_TABLE_ADDRESS__);

View File

@@ -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/>.
*/
#define __ACCESS_TABLE_NAME__ EmcAccessTable
#define __ACCESS_TABLE_ADDRESS__ MemoryRegionPhysicalDeviceExternalMemoryController.GetAddress()
#define __ACCESS_TABLE_INC__ "secmon_emc_access_table_data.inc"
#include "secmon_define_access_table.inc"
#undef __ACCESS_TABLE_INC__
#undef __ACCESS_TABLE_ADDRESS__
#undef __ACCESS_TABLE_NAME__

View File

@@ -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/>.
*/
#define __ACCESS_TABLE_NAME__ Mc01AccessTable
#define __ACCESS_TABLE_ADDRESS__ 0
#define __ACCESS_TABLE_INC__ "secmon_mc01_access_table_data.inc"
#include "secmon_define_access_table.inc"
#undef __ACCESS_TABLE_INC__
#undef __ACCESS_TABLE_ADDRESS__
#undef __ACCESS_TABLE_NAME__

View File

@@ -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/>.
*/
#define __ACCESS_TABLE_NAME__ McAccessTable
#define __ACCESS_TABLE_ADDRESS__ MemoryRegionPhysicalDeviceMemoryController.GetAddress()
#define __ACCESS_TABLE_INC__ "secmon_mc_access_table_data.inc"
#include "secmon_define_access_table.inc"
#undef __ACCESS_TABLE_INC__
#undef __ACCESS_TABLE_ADDRESS__
#undef __ACCESS_TABLE_NAME__

View File

@@ -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/>.
*/
#define __ACCESS_TABLE_NAME__ PmcAccessTable
#define __ACCESS_TABLE_ADDRESS__ MemoryRegionPhysicalDevicePmc.GetAddress()
#define __ACCESS_TABLE_INC__ "secmon_pmc_access_table_data.inc"
#include "secmon_define_access_table.inc"
#undef __ACCESS_TABLE_INC__
#undef __ACCESS_TABLE_ADDRESS__
#undef __ACCESS_TABLE_NAME__

View File

@@ -1,967 +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/>.
*/
SetRegisterAllowed(0x0);
SetRegisterAllowed(0x4);
SetRegisterAllowed(0x8);
SetRegisterAllowed(0xC);
SetRegisterAllowed(0x10);
SetRegisterAllowed(0x14);
SetRegisterAllowed(0x18);
SetRegisterAllowed(0x1C);
SetRegisterAllowed(0x20);
SetRegisterAllowed(0x24);
SetRegisterAllowed(0x28);
SetRegisterAllowed(0x2C);
SetRegisterAllowed(0x30);
SetRegisterAllowed(0x34);
SetRegisterAllowed(0x38);
SetRegisterAllowed(0x3C);
SetRegisterAllowed(0x40);
SetRegisterAllowed(0x44);
SetRegisterAllowed(0x48);
SetRegisterAllowed(0x4C);
SetRegisterAllowed(0x50);
SetRegisterAllowed(0x54);
SetRegisterAllowed(0x58);
SetRegisterAllowed(0x5C);
SetRegisterAllowed(0x60);
SetRegisterAllowed(0x64);
SetRegisterAllowed(0x68);
SetRegisterAllowed(0x6C);
SetRegisterAllowed(0x70);
SetRegisterAllowed(0x74);
SetRegisterAllowed(0x78);
SetRegisterAllowed(0x7C);
SetRegisterAllowed(0x80);
SetRegisterAllowed(0x84);
SetRegisterAllowed(0x88);
SetRegisterAllowed(0x8C);
SetRegisterAllowed(0x90);
SetRegisterAllowed(0x94);
SetRegisterAllowed(0x98);
SetRegisterAllowed(0x9C);
SetRegisterAllowed(0xA0);
SetRegisterAllowed(0xA4);
SetRegisterAllowed(0xA8);
SetRegisterAllowed(0xAC);
SetRegisterAllowed(0xB0);
SetRegisterAllowed(0xB4);
SetRegisterAllowed(0xB8);
SetRegisterAllowed(0xBC);
SetRegisterAllowed(0xC0);
SetRegisterAllowed(0xC4);
SetRegisterAllowed(0xC8);
SetRegisterAllowed(0xCC);
SetRegisterAllowed(0xD0);
SetRegisterAllowed(0xD4);
SetRegisterAllowed(0xD8);
SetRegisterAllowed(0xDC);
SetRegisterAllowed(0xE0);
SetRegisterAllowed(0xE4);
SetRegisterAllowed(0xE8);
SetRegisterAllowed(0xEC);
SetRegisterAllowed(0xF0);
SetRegisterAllowed(0xF4);
SetRegisterAllowed(0xF8);
SetRegisterAllowed(0xFC);
SetRegisterAllowed(0x100);
SetRegisterAllowed(0x104);
SetRegisterAllowed(0x108);
SetRegisterAllowed(0x10C);
SetRegisterAllowed(0x110);
SetRegisterAllowed(0x114);
SetRegisterAllowed(0x118);
SetRegisterAllowed(0x11C);
SetRegisterAllowed(0x120);
SetRegisterAllowed(0x124);
SetRegisterAllowed(0x128);
SetRegisterAllowed(0x12C);
SetRegisterAllowed(0x130);
SetRegisterAllowed(0x134);
SetRegisterAllowed(0x138);
SetRegisterAllowed(0x13C);
SetRegisterAllowed(0x140);
SetRegisterAllowed(0x144);
SetRegisterAllowed(0x148);
SetRegisterAllowed(0x14C);
SetRegisterAllowed(0x150);
SetRegisterAllowed(0x154);
SetRegisterAllowed(0x158);
SetRegisterAllowed(0x15C);
SetRegisterAllowed(0x160);
SetRegisterAllowed(0x164);
SetRegisterAllowed(0x168);
SetRegisterAllowed(0x16C);
SetRegisterAllowed(0x170);
SetRegisterAllowed(0x174);
SetRegisterAllowed(0x178);
SetRegisterAllowed(0x17C);
SetRegisterAllowed(0x180);
SetRegisterAllowed(0x184);
SetRegisterAllowed(0x188);
SetRegisterAllowed(0x18C);
SetRegisterAllowed(0x190);
SetRegisterAllowed(0x194);
SetRegisterAllowed(0x198);
SetRegisterAllowed(0x19C);
SetRegisterAllowed(0x1A0);
SetRegisterAllowed(0x1A4);
SetRegisterAllowed(0x1A8);
SetRegisterAllowed(0x1AC);
SetRegisterAllowed(0x1B0);
SetRegisterAllowed(0x1B4);
SetRegisterAllowed(0x1B8);
SetRegisterAllowed(0x1BC);
SetRegisterAllowed(0x1C0);
SetRegisterAllowed(0x1C4);
SetRegisterAllowed(0x1C8);
SetRegisterAllowed(0x1CC);
SetRegisterAllowed(0x1D0);
SetRegisterAllowed(0x1D4);
SetRegisterAllowed(0x1D8);
SetRegisterAllowed(0x1DC);
SetRegisterAllowed(0x1E0);
SetRegisterAllowed(0x1E4);
SetRegisterAllowed(0x1E8);
SetRegisterAllowed(0x1EC);
SetRegisterAllowed(0x1F0);
SetRegisterAllowed(0x1F4);
SetRegisterAllowed(0x1F8);
SetRegisterAllowed(0x1FC);
SetRegisterAllowed(0x200);
SetRegisterAllowed(0x204);
SetRegisterAllowed(0x208);
SetRegisterAllowed(0x20C);
SetRegisterAllowed(0x210);
SetRegisterAllowed(0x214);
SetRegisterAllowed(0x218);
SetRegisterAllowed(0x21C);
SetRegisterAllowed(0x220);
SetRegisterAllowed(0x224);
SetRegisterAllowed(0x228);
SetRegisterAllowed(0x22C);
SetRegisterAllowed(0x230);
SetRegisterAllowed(0x234);
SetRegisterAllowed(0x238);
SetRegisterAllowed(0x23C);
SetRegisterAllowed(0x240);
SetRegisterAllowed(0x244);
SetRegisterAllowed(0x248);
SetRegisterAllowed(0x24C);
SetRegisterAllowed(0x250);
SetRegisterAllowed(0x254);
SetRegisterAllowed(0x258);
SetRegisterAllowed(0x25C);
SetRegisterAllowed(0x260);
SetRegisterAllowed(0x264);
SetRegisterAllowed(0x268);
SetRegisterAllowed(0x26C);
SetRegisterAllowed(0x270);
SetRegisterAllowed(0x274);
SetRegisterAllowed(0x278);
SetRegisterAllowed(0x27C);
SetRegisterAllowed(0x280);
SetRegisterAllowed(0x284);
SetRegisterAllowed(0x288);
SetRegisterAllowed(0x28C);
SetRegisterAllowed(0x290);
SetRegisterAllowed(0x294);
SetRegisterAllowed(0x298);
SetRegisterAllowed(0x29C);
SetRegisterAllowed(0x2A0);
SetRegisterAllowed(0x2A4);
SetRegisterAllowed(0x2A8);
SetRegisterAllowed(0x2AC);
SetRegisterAllowed(0x2B0);
SetRegisterAllowed(0x2B4);
SetRegisterAllowed(0x2B8);
SetRegisterAllowed(0x2BC);
SetRegisterAllowed(0x2C0);
SetRegisterAllowed(0x2C4);
SetRegisterAllowed(0x2C8);
SetRegisterAllowed(0x2CC);
SetRegisterAllowed(0x2D0);
SetRegisterAllowed(0x2D4);
SetRegisterAllowed(0x2D8);
SetRegisterAllowed(0x2DC);
SetRegisterAllowed(0x2E0);
SetRegisterAllowed(0x2E4);
SetRegisterAllowed(0x2E8);
SetRegisterAllowed(0x2EC);
SetRegisterAllowed(0x2F0);
SetRegisterAllowed(0x2F4);
SetRegisterAllowed(0x2F8);
SetRegisterAllowed(0x2FC);
SetRegisterAllowed(0x300);
SetRegisterAllowed(0x304);
SetRegisterAllowed(0x308);
SetRegisterAllowed(0x30C);
SetRegisterAllowed(0x310);
SetRegisterAllowed(0x314);
SetRegisterAllowed(0x318);
SetRegisterAllowed(0x31C);
SetRegisterAllowed(0x320);
SetRegisterAllowed(0x324);
SetRegisterAllowed(0x328);
SetRegisterAllowed(0x32C);
SetRegisterAllowed(0x330);
SetRegisterAllowed(0x334);
SetRegisterAllowed(0x338);
SetRegisterAllowed(0x33C);
SetRegisterAllowed(0x340);
SetRegisterAllowed(0x344);
SetRegisterAllowed(0x348);
SetRegisterAllowed(0x34C);
SetRegisterAllowed(0x350);
SetRegisterAllowed(0x354);
SetRegisterAllowed(0x358);
SetRegisterAllowed(0x35C);
SetRegisterAllowed(0x360);
SetRegisterAllowed(0x364);
SetRegisterAllowed(0x368);
SetRegisterAllowed(0x36C);
SetRegisterAllowed(0x370);
SetRegisterAllowed(0x374);
SetRegisterAllowed(0x378);
SetRegisterAllowed(0x37C);
SetRegisterAllowed(0x380);
SetRegisterAllowed(0x384);
SetRegisterAllowed(0x388);
SetRegisterAllowed(0x38C);
SetRegisterAllowed(0x390);
SetRegisterAllowed(0x394);
SetRegisterAllowed(0x398);
SetRegisterAllowed(0x39C);
SetRegisterAllowed(0x3A0);
SetRegisterAllowed(0x3A4);
SetRegisterAllowed(0x3A8);
SetRegisterAllowed(0x3AC);
SetRegisterAllowed(0x3B0);
SetRegisterAllowed(0x3B4);
SetRegisterAllowed(0x3B8);
SetRegisterAllowed(0x3BC);
SetRegisterAllowed(0x3C0);
SetRegisterAllowed(0x3C4);
SetRegisterAllowed(0x3C8);
SetRegisterAllowed(0x3CC);
SetRegisterAllowed(0x3D0);
SetRegisterAllowed(0x3D4);
SetRegisterAllowed(0x3D8);
SetRegisterAllowed(0x3DC);
SetRegisterAllowed(0x3E0);
SetRegisterAllowed(0x3E4);
SetRegisterAllowed(0x3E8);
SetRegisterAllowed(0x3EC);
SetRegisterAllowed(0x3F0);
SetRegisterAllowed(0x3F4);
SetRegisterAllowed(0x3F8);
SetRegisterAllowed(0x3FC);
SetRegisterAllowed(0x400);
SetRegisterAllowed(0x404);
SetRegisterAllowed(0x408);
SetRegisterAllowed(0x40C);
SetRegisterAllowed(0x410);
SetRegisterAllowed(0x414);
SetRegisterAllowed(0x418);
SetRegisterAllowed(0x41C);
SetRegisterAllowed(0x420);
SetRegisterAllowed(0x424);
SetRegisterAllowed(0x428);
SetRegisterAllowed(0x42C);
SetRegisterAllowed(0x430);
SetRegisterAllowed(0x434);
SetRegisterAllowed(0x438);
SetRegisterAllowed(0x43C);
SetRegisterAllowed(0x440);
SetRegisterAllowed(0x444);
SetRegisterAllowed(0x448);
SetRegisterAllowed(0x44C);
SetRegisterAllowed(0x450);
SetRegisterAllowed(0x454);
SetRegisterAllowed(0x458);
SetRegisterAllowed(0x45C);
SetRegisterAllowed(0x460);
SetRegisterAllowed(0x464);
SetRegisterAllowed(0x468);
SetRegisterAllowed(0x46C);
SetRegisterAllowed(0x470);
SetRegisterAllowed(0x474);
SetRegisterAllowed(0x478);
SetRegisterAllowed(0x47C);
SetRegisterAllowed(0x480);
SetRegisterAllowed(0x484);
SetRegisterAllowed(0x488);
SetRegisterAllowed(0x48C);
SetRegisterAllowed(0x490);
SetRegisterAllowed(0x494);
SetRegisterAllowed(0x498);
SetRegisterAllowed(0x49C);
SetRegisterAllowed(0x4A0);
SetRegisterAllowed(0x4A4);
SetRegisterAllowed(0x4A8);
SetRegisterAllowed(0x4AC);
SetRegisterAllowed(0x4B0);
SetRegisterAllowed(0x4B4);
SetRegisterAllowed(0x4B8);
SetRegisterAllowed(0x4BC);
SetRegisterAllowed(0x4C0);
SetRegisterAllowed(0x4C4);
SetRegisterAllowed(0x4C8);
SetRegisterAllowed(0x4CC);
SetRegisterAllowed(0x4D0);
SetRegisterAllowed(0x4D4);
SetRegisterAllowed(0x4D8);
SetRegisterAllowed(0x4DC);
SetRegisterAllowed(0x4E0);
SetRegisterAllowed(0x4E4);
SetRegisterAllowed(0x4E8);
SetRegisterAllowed(0x4EC);
SetRegisterAllowed(0x4F0);
SetRegisterAllowed(0x4F4);
SetRegisterAllowed(0x4F8);
SetRegisterAllowed(0x4FC);
SetRegisterAllowed(0x500);
SetRegisterAllowed(0x504);
SetRegisterAllowed(0x508);
SetRegisterAllowed(0x50C);
SetRegisterAllowed(0x510);
SetRegisterAllowed(0x514);
SetRegisterAllowed(0x518);
SetRegisterAllowed(0x51C);
SetRegisterAllowed(0x520);
SetRegisterAllowed(0x524);
SetRegisterAllowed(0x528);
SetRegisterAllowed(0x52C);
SetRegisterAllowed(0x530);
SetRegisterAllowed(0x534);
SetRegisterAllowed(0x538);
SetRegisterAllowed(0x53C);
SetRegisterAllowed(0x540);
SetRegisterAllowed(0x544);
SetRegisterAllowed(0x548);
SetRegisterAllowed(0x54C);
SetRegisterAllowed(0x550);
SetRegisterAllowed(0x554);
SetRegisterAllowed(0x558);
SetRegisterAllowed(0x55C);
SetRegisterAllowed(0x560);
SetRegisterAllowed(0x564);
SetRegisterAllowed(0x568);
SetRegisterAllowed(0x56C);
SetRegisterAllowed(0x570);
SetRegisterAllowed(0x574);
SetRegisterAllowed(0x578);
SetRegisterAllowed(0x57C);
SetRegisterAllowed(0x580);
SetRegisterAllowed(0x584);
SetRegisterAllowed(0x588);
SetRegisterAllowed(0x58C);
SetRegisterAllowed(0x590);
SetRegisterAllowed(0x594);
SetRegisterAllowed(0x598);
SetRegisterAllowed(0x59C);
SetRegisterAllowed(0x5A0);
SetRegisterAllowed(0x5A4);
SetRegisterAllowed(0x5A8);
SetRegisterAllowed(0x5AC);
SetRegisterAllowed(0x5B0);
SetRegisterAllowed(0x5B4);
SetRegisterAllowed(0x5B8);
SetRegisterAllowed(0x5BC);
SetRegisterAllowed(0x5C0);
SetRegisterAllowed(0x5C4);
SetRegisterAllowed(0x5C8);
SetRegisterAllowed(0x5CC);
SetRegisterAllowed(0x5D0);
SetRegisterAllowed(0x5D4);
SetRegisterAllowed(0x5D8);
SetRegisterAllowed(0x5DC);
SetRegisterAllowed(0x5E0);
SetRegisterAllowed(0x5E4);
SetRegisterAllowed(0x5E8);
SetRegisterAllowed(0x5EC);
SetRegisterAllowed(0x5F0);
SetRegisterAllowed(0x5F4);
SetRegisterAllowed(0x5F8);
SetRegisterAllowed(0x5FC);
SetRegisterAllowed(0x600);
SetRegisterAllowed(0x604);
SetRegisterAllowed(0x608);
SetRegisterAllowed(0x60C);
SetRegisterAllowed(0x610);
SetRegisterAllowed(0x614);
SetRegisterAllowed(0x618);
SetRegisterAllowed(0x61C);
SetRegisterAllowed(0x620);
SetRegisterAllowed(0x624);
SetRegisterAllowed(0x628);
SetRegisterAllowed(0x62C);
SetRegisterAllowed(0x630);
SetRegisterAllowed(0x634);
SetRegisterAllowed(0x638);
SetRegisterAllowed(0x63C);
SetRegisterAllowed(0x640);
SetRegisterAllowed(0x644);
SetRegisterAllowed(0x648);
SetRegisterAllowed(0x64C);
SetRegisterAllowed(0x650);
SetRegisterAllowed(0x654);
SetRegisterAllowed(0x658);
SetRegisterAllowed(0x65C);
SetRegisterAllowed(0x660);
SetRegisterAllowed(0x664);
SetRegisterAllowed(0x668);
SetRegisterAllowed(0x66C);
SetRegisterAllowed(0x670);
SetRegisterAllowed(0x674);
SetRegisterAllowed(0x678);
SetRegisterAllowed(0x67C);
SetRegisterAllowed(0x680);
SetRegisterAllowed(0x684);
SetRegisterAllowed(0x688);
SetRegisterAllowed(0x68C);
SetRegisterAllowed(0x690);
SetRegisterAllowed(0x694);
SetRegisterAllowed(0x698);
SetRegisterAllowed(0x69C);
SetRegisterAllowed(0x6A0);
SetRegisterAllowed(0x6A4);
SetRegisterAllowed(0x6A8);
SetRegisterAllowed(0x6AC);
SetRegisterAllowed(0x6B0);
SetRegisterAllowed(0x6B4);
SetRegisterAllowed(0x6B8);
SetRegisterAllowed(0x6BC);
SetRegisterAllowed(0x6C0);
SetRegisterAllowed(0x6C4);
SetRegisterAllowed(0x6C8);
SetRegisterAllowed(0x6CC);
SetRegisterAllowed(0x6D0);
SetRegisterAllowed(0x6D4);
SetRegisterAllowed(0x6D8);
SetRegisterAllowed(0x6DC);
SetRegisterAllowed(0x6E0);
SetRegisterAllowed(0x6E4);
SetRegisterAllowed(0x6E8);
SetRegisterAllowed(0x6EC);
SetRegisterAllowed(0x6F0);
SetRegisterAllowed(0x6F4);
SetRegisterAllowed(0x6F8);
SetRegisterAllowed(0x6FC);
SetRegisterAllowed(0x700);
SetRegisterAllowed(0x704);
SetRegisterAllowed(0x708);
SetRegisterAllowed(0x70C);
SetRegisterAllowed(0x710);
SetRegisterAllowed(0x714);
SetRegisterAllowed(0x718);
SetRegisterAllowed(0x71C);
SetRegisterAllowed(0x720);
SetRegisterAllowed(0x724);
SetRegisterAllowed(0x728);
SetRegisterAllowed(0x72C);
SetRegisterAllowed(0x730);
SetRegisterAllowed(0x734);
SetRegisterAllowed(0x738);
SetRegisterAllowed(0x73C);
SetRegisterAllowed(0x740);
SetRegisterAllowed(0x744);
SetRegisterAllowed(0x748);
SetRegisterAllowed(0x74C);
SetRegisterAllowed(0x750);
SetRegisterAllowed(0x754);
SetRegisterAllowed(0x758);
SetRegisterAllowed(0x75C);
SetRegisterAllowed(0x760);
SetRegisterAllowed(0x764);
SetRegisterAllowed(0x768);
SetRegisterAllowed(0x76C);
SetRegisterAllowed(0x770);
SetRegisterAllowed(0x774);
SetRegisterAllowed(0x778);
SetRegisterAllowed(0x77C);
SetRegisterAllowed(0x780);
SetRegisterAllowed(0x784);
SetRegisterAllowed(0x788);
SetRegisterAllowed(0x78C);
SetRegisterAllowed(0x790);
SetRegisterAllowed(0x794);
SetRegisterAllowed(0x798);
SetRegisterAllowed(0x79C);
SetRegisterAllowed(0x7A0);
SetRegisterAllowed(0x7A4);
SetRegisterAllowed(0x7A8);
SetRegisterAllowed(0x7AC);
SetRegisterAllowed(0x7B0);
SetRegisterAllowed(0x7B4);
SetRegisterAllowed(0x7B8);
SetRegisterAllowed(0x7BC);
SetRegisterAllowed(0x7C0);
SetRegisterAllowed(0x7C4);
SetRegisterAllowed(0x7C8);
SetRegisterAllowed(0x7CC);
SetRegisterAllowed(0x7D0);
SetRegisterAllowed(0x7D4);
SetRegisterAllowed(0x7D8);
SetRegisterAllowed(0x7DC);
SetRegisterAllowed(0x7E0);
SetRegisterAllowed(0x7E4);
SetRegisterAllowed(0x7E8);
SetRegisterAllowed(0x7EC);
SetRegisterAllowed(0x7F0);
SetRegisterAllowed(0x7F4);
SetRegisterAllowed(0x7F8);
SetRegisterAllowed(0x7FC);
SetRegisterAllowed(0x800);
SetRegisterAllowed(0x804);
SetRegisterAllowed(0x808);
SetRegisterAllowed(0x80C);
SetRegisterAllowed(0x810);
SetRegisterAllowed(0x814);
SetRegisterAllowed(0x818);
SetRegisterAllowed(0x81C);
SetRegisterAllowed(0x820);
SetRegisterAllowed(0x824);
SetRegisterAllowed(0x828);
SetRegisterAllowed(0x82C);
SetRegisterAllowed(0x830);
SetRegisterAllowed(0x834);
SetRegisterAllowed(0x838);
SetRegisterAllowed(0x83C);
SetRegisterAllowed(0x840);
SetRegisterAllowed(0x844);
SetRegisterAllowed(0x848);
SetRegisterAllowed(0x84C);
SetRegisterAllowed(0x850);
SetRegisterAllowed(0x854);
SetRegisterAllowed(0x858);
SetRegisterAllowed(0x85C);
SetRegisterAllowed(0x860);
SetRegisterAllowed(0x864);
SetRegisterAllowed(0x868);
SetRegisterAllowed(0x86C);
SetRegisterAllowed(0x870);
SetRegisterAllowed(0x874);
SetRegisterAllowed(0x878);
SetRegisterAllowed(0x87C);
SetRegisterAllowed(0x880);
SetRegisterAllowed(0x884);
SetRegisterAllowed(0x888);
SetRegisterAllowed(0x88C);
SetRegisterAllowed(0x890);
SetRegisterAllowed(0x894);
SetRegisterAllowed(0x898);
SetRegisterAllowed(0x89C);
SetRegisterAllowed(0x8A0);
SetRegisterAllowed(0x8A4);
SetRegisterAllowed(0x8A8);
SetRegisterAllowed(0x8AC);
SetRegisterAllowed(0x8B0);
SetRegisterAllowed(0x8B4);
SetRegisterAllowed(0x8B8);
SetRegisterAllowed(0x8BC);
SetRegisterAllowed(0x8C0);
SetRegisterAllowed(0x8C4);
SetRegisterAllowed(0x8C8);
SetRegisterAllowed(0x8CC);
SetRegisterAllowed(0x8D0);
SetRegisterAllowed(0x8D4);
SetRegisterAllowed(0x8D8);
SetRegisterAllowed(0x8DC);
SetRegisterAllowed(0x8E0);
SetRegisterAllowed(0x8E4);
SetRegisterAllowed(0x8E8);
SetRegisterAllowed(0x8EC);
SetRegisterAllowed(0x8F0);
SetRegisterAllowed(0x8F4);
SetRegisterAllowed(0x8F8);
SetRegisterAllowed(0x8FC);
SetRegisterAllowed(0x900);
SetRegisterAllowed(0x904);
SetRegisterAllowed(0x908);
SetRegisterAllowed(0x90C);
SetRegisterAllowed(0x910);
SetRegisterAllowed(0x914);
SetRegisterAllowed(0x918);
SetRegisterAllowed(0x91C);
SetRegisterAllowed(0x920);
SetRegisterAllowed(0x924);
SetRegisterAllowed(0x928);
SetRegisterAllowed(0x92C);
SetRegisterAllowed(0x930);
SetRegisterAllowed(0x934);
SetRegisterAllowed(0x938);
SetRegisterAllowed(0x93C);
SetRegisterAllowed(0x940);
SetRegisterAllowed(0x944);
SetRegisterAllowed(0x948);
SetRegisterAllowed(0x94C);
SetRegisterAllowed(0x950);
SetRegisterAllowed(0x954);
SetRegisterAllowed(0x958);
SetRegisterAllowed(0x95C);
SetRegisterAllowed(0x960);
SetRegisterAllowed(0x964);
SetRegisterAllowed(0x968);
SetRegisterAllowed(0x96C);
SetRegisterAllowed(0x970);
SetRegisterAllowed(0x974);
SetRegisterAllowed(0x978);
SetRegisterAllowed(0x97C);
SetRegisterAllowed(0x980);
SetRegisterAllowed(0x984);
SetRegisterAllowed(0x988);
SetRegisterAllowed(0x98C);
SetRegisterAllowed(0x990);
SetRegisterAllowed(0x994);
SetRegisterAllowed(0x998);
SetRegisterAllowed(0x99C);
SetRegisterAllowed(0x9A0);
SetRegisterAllowed(0x9A4);
SetRegisterAllowed(0x9A8);
SetRegisterAllowed(0x9AC);
SetRegisterAllowed(0x9B0);
SetRegisterAllowed(0x9B4);
SetRegisterAllowed(0x9B8);
SetRegisterAllowed(0x9BC);
SetRegisterAllowed(0x9C0);
SetRegisterAllowed(0x9C4);
SetRegisterAllowed(0x9C8);
SetRegisterAllowed(0x9CC);
SetRegisterAllowed(0x9D0);
SetRegisterAllowed(0x9D4);
SetRegisterAllowed(0x9D8);
SetRegisterAllowed(0x9DC);
SetRegisterAllowed(0x9E0);
SetRegisterAllowed(0x9E4);
SetRegisterAllowed(0x9E8);
SetRegisterAllowed(0x9EC);
SetRegisterAllowed(0x9F0);
SetRegisterAllowed(0x9F4);
SetRegisterAllowed(0x9F8);
SetRegisterAllowed(0x9FC);
SetRegisterAllowed(0xA00);
SetRegisterAllowed(0xA04);
SetRegisterAllowed(0xA08);
SetRegisterAllowed(0xA0C);
SetRegisterAllowed(0xA10);
SetRegisterAllowed(0xA14);
SetRegisterAllowed(0xA18);
SetRegisterAllowed(0xA1C);
SetRegisterAllowed(0xA20);
SetRegisterAllowed(0xA24);
SetRegisterAllowed(0xA28);
SetRegisterAllowed(0xA2C);
SetRegisterAllowed(0xA30);
SetRegisterAllowed(0xA34);
SetRegisterAllowed(0xA38);
SetRegisterAllowed(0xA3C);
SetRegisterAllowed(0xA40);
SetRegisterAllowed(0xA44);
SetRegisterAllowed(0xA48);
SetRegisterAllowed(0xA4C);
SetRegisterAllowed(0xA50);
SetRegisterAllowed(0xA54);
SetRegisterAllowed(0xA58);
SetRegisterAllowed(0xA5C);
SetRegisterAllowed(0xA60);
SetRegisterAllowed(0xA64);
SetRegisterAllowed(0xA68);
SetRegisterAllowed(0xA6C);
SetRegisterAllowed(0xA70);
SetRegisterAllowed(0xA74);
SetRegisterAllowed(0xA78);
SetRegisterAllowed(0xA7C);
SetRegisterAllowed(0xA80);
SetRegisterAllowed(0xA84);
SetRegisterAllowed(0xA88);
SetRegisterAllowed(0xA8C);
SetRegisterAllowed(0xA90);
SetRegisterAllowed(0xA94);
SetRegisterAllowed(0xA98);
SetRegisterAllowed(0xA9C);
SetRegisterAllowed(0xAA0);
SetRegisterAllowed(0xAA4);
SetRegisterAllowed(0xAA8);
SetRegisterAllowed(0xAAC);
SetRegisterAllowed(0xAB0);
SetRegisterAllowed(0xAB4);
SetRegisterAllowed(0xAB8);
SetRegisterAllowed(0xABC);
SetRegisterAllowed(0xAC0);
SetRegisterAllowed(0xAC4);
SetRegisterAllowed(0xAC8);
SetRegisterAllowed(0xACC);
SetRegisterAllowed(0xAD0);
SetRegisterAllowed(0xAD4);
SetRegisterAllowed(0xAD8);
SetRegisterAllowed(0xADC);
SetRegisterAllowed(0xAE0);
SetRegisterAllowed(0xAE4);
SetRegisterAllowed(0xAE8);
SetRegisterAllowed(0xAEC);
SetRegisterAllowed(0xAF0);
SetRegisterAllowed(0xAF4);
SetRegisterAllowed(0xAF8);
SetRegisterAllowed(0xAFC);
SetRegisterAllowed(0xB00);
SetRegisterAllowed(0xB04);
SetRegisterAllowed(0xB08);
SetRegisterAllowed(0xB0C);
SetRegisterAllowed(0xB10);
SetRegisterAllowed(0xB14);
SetRegisterAllowed(0xB18);
SetRegisterAllowed(0xB1C);
SetRegisterAllowed(0xB20);
SetRegisterAllowed(0xB24);
SetRegisterAllowed(0xB28);
SetRegisterAllowed(0xB2C);
SetRegisterAllowed(0xB30);
SetRegisterAllowed(0xB34);
SetRegisterAllowed(0xB38);
SetRegisterAllowed(0xB3C);
SetRegisterAllowed(0xB40);
SetRegisterAllowed(0xB44);
SetRegisterAllowed(0xB48);
SetRegisterAllowed(0xB4C);
SetRegisterAllowed(0xB50);
SetRegisterAllowed(0xB54);
SetRegisterAllowed(0xB58);
SetRegisterAllowed(0xB5C);
SetRegisterAllowed(0xB60);
SetRegisterAllowed(0xB64);
SetRegisterAllowed(0xB68);
SetRegisterAllowed(0xB6C);
SetRegisterAllowed(0xB70);
SetRegisterAllowed(0xB74);
SetRegisterAllowed(0xB78);
SetRegisterAllowed(0xB7C);
SetRegisterAllowed(0xB80);
SetRegisterAllowed(0xB84);
SetRegisterAllowed(0xB88);
SetRegisterAllowed(0xB8C);
SetRegisterAllowed(0xB90);
SetRegisterAllowed(0xB94);
SetRegisterAllowed(0xB98);
SetRegisterAllowed(0xB9C);
SetRegisterAllowed(0xBA0);
SetRegisterAllowed(0xBA4);
SetRegisterAllowed(0xBA8);
SetRegisterAllowed(0xBAC);
SetRegisterAllowed(0xBB0);
SetRegisterAllowed(0xBB4);
SetRegisterAllowed(0xBB8);
SetRegisterAllowed(0xBBC);
SetRegisterAllowed(0xBC0);
SetRegisterAllowed(0xBC4);
SetRegisterAllowed(0xBC8);
SetRegisterAllowed(0xBCC);
SetRegisterAllowed(0xBD0);
SetRegisterAllowed(0xBD4);
SetRegisterAllowed(0xBD8);
SetRegisterAllowed(0xBDC);
SetRegisterAllowed(0xBE0);
SetRegisterAllowed(0xBE4);
SetRegisterAllowed(0xBE8);
SetRegisterAllowed(0xBEC);
SetRegisterAllowed(0xBF0);
SetRegisterAllowed(0xBF4);
SetRegisterAllowed(0xBF8);
SetRegisterAllowed(0xBFC);
SetRegisterAllowed(0xC00);
SetRegisterAllowed(0xC04);
SetRegisterAllowed(0xC08);
SetRegisterAllowed(0xC0C);
SetRegisterAllowed(0xC10);
SetRegisterAllowed(0xC14);
SetRegisterAllowed(0xC18);
SetRegisterAllowed(0xC1C);
SetRegisterAllowed(0xC20);
SetRegisterAllowed(0xC24);
SetRegisterAllowed(0xC28);
SetRegisterAllowed(0xC2C);
SetRegisterAllowed(0xC30);
SetRegisterAllowed(0xC34);
SetRegisterAllowed(0xC38);
SetRegisterAllowed(0xC3C);
SetRegisterAllowed(0xC40);
SetRegisterAllowed(0xC44);
SetRegisterAllowed(0xC48);
SetRegisterAllowed(0xC4C);
SetRegisterAllowed(0xC50);
SetRegisterAllowed(0xC54);
SetRegisterAllowed(0xC58);
SetRegisterAllowed(0xC5C);
SetRegisterAllowed(0xC60);
SetRegisterAllowed(0xC64);
SetRegisterAllowed(0xC68);
SetRegisterAllowed(0xC6C);
SetRegisterAllowed(0xC70);
SetRegisterAllowed(0xC74);
SetRegisterAllowed(0xC78);
SetRegisterAllowed(0xC7C);
SetRegisterAllowed(0xC80);
SetRegisterAllowed(0xC84);
SetRegisterAllowed(0xC88);
SetRegisterAllowed(0xC8C);
SetRegisterAllowed(0xC90);
SetRegisterAllowed(0xC94);
SetRegisterAllowed(0xC98);
SetRegisterAllowed(0xC9C);
SetRegisterAllowed(0xCA0);
SetRegisterAllowed(0xCA4);
SetRegisterAllowed(0xCA8);
SetRegisterAllowed(0xCAC);
SetRegisterAllowed(0xCB0);
SetRegisterAllowed(0xCB4);
SetRegisterAllowed(0xCB8);
SetRegisterAllowed(0xCBC);
SetRegisterAllowed(0xCC0);
SetRegisterAllowed(0xCC4);
SetRegisterAllowed(0xCC8);
SetRegisterAllowed(0xCCC);
SetRegisterAllowed(0xCD0);
SetRegisterAllowed(0xCD4);
SetRegisterAllowed(0xCD8);
SetRegisterAllowed(0xCDC);
SetRegisterAllowed(0xCE0);
SetRegisterAllowed(0xCE4);
SetRegisterAllowed(0xCE8);
SetRegisterAllowed(0xCEC);
SetRegisterAllowed(0xCF0);
SetRegisterAllowed(0xCF4);
SetRegisterAllowed(0xCF8);
SetRegisterAllowed(0xCFC);
SetRegisterAllowed(0xD00);
SetRegisterAllowed(0xD04);
SetRegisterAllowed(0xD08);
SetRegisterAllowed(0xD0C);
SetRegisterAllowed(0xD10);
SetRegisterAllowed(0xD14);
SetRegisterAllowed(0xD18);
SetRegisterAllowed(0xD1C);
SetRegisterAllowed(0xD20);
SetRegisterAllowed(0xD24);
SetRegisterAllowed(0xD28);
SetRegisterAllowed(0xD2C);
SetRegisterAllowed(0xD30);
SetRegisterAllowed(0xD34);
SetRegisterAllowed(0xD38);
SetRegisterAllowed(0xD3C);
SetRegisterAllowed(0xD40);
SetRegisterAllowed(0xD44);
SetRegisterAllowed(0xD48);
SetRegisterAllowed(0xD4C);
SetRegisterAllowed(0xD50);
SetRegisterAllowed(0xD54);
SetRegisterAllowed(0xD58);
SetRegisterAllowed(0xD5C);
SetRegisterAllowed(0xD60);
SetRegisterAllowed(0xD64);
SetRegisterAllowed(0xD68);
SetRegisterAllowed(0xD6C);
SetRegisterAllowed(0xD70);
SetRegisterAllowed(0xD74);
SetRegisterAllowed(0xD78);
SetRegisterAllowed(0xD7C);
SetRegisterAllowed(0xD80);
SetRegisterAllowed(0xD84);
SetRegisterAllowed(0xD88);
SetRegisterAllowed(0xD8C);
SetRegisterAllowed(0xD90);
SetRegisterAllowed(0xD94);
SetRegisterAllowed(0xD98);
SetRegisterAllowed(0xD9C);
SetRegisterAllowed(0xDA0);
SetRegisterAllowed(0xDA4);
SetRegisterAllowed(0xDA8);
SetRegisterAllowed(0xDAC);
SetRegisterAllowed(0xDB0);
SetRegisterAllowed(0xDB4);
SetRegisterAllowed(0xDB8);
SetRegisterAllowed(0xDBC);
SetRegisterAllowed(0xDC0);
SetRegisterAllowed(0xDC4);
SetRegisterAllowed(0xDC8);
SetRegisterAllowed(0xDCC);
SetRegisterAllowed(0xDD0);
SetRegisterAllowed(0xDD4);
SetRegisterAllowed(0xDD8);
SetRegisterAllowed(0xDDC);
SetRegisterAllowed(0xDE0);
SetRegisterAllowed(0xDE4);
SetRegisterAllowed(0xDE8);
SetRegisterAllowed(0xDEC);
SetRegisterAllowed(0xDF0);
SetRegisterAllowed(0xDF4);
SetRegisterAllowed(0xDF8);
SetRegisterAllowed(0xDFC);
SetRegisterAllowed(0xE00);
SetRegisterAllowed(0xE04);
SetRegisterAllowed(0xE08);
SetRegisterAllowed(0xE0C);
SetRegisterAllowed(0xE10);
SetRegisterAllowed(0xE14);
SetRegisterAllowed(0xE18);
SetRegisterAllowed(0xE1C);
SetRegisterAllowed(0xE20);
SetRegisterAllowed(0xE24);
SetRegisterAllowed(0xE28);
SetRegisterAllowed(0xE2C);
SetRegisterAllowed(0xE30);
SetRegisterAllowed(0xE34);
SetRegisterAllowed(0xE38);
SetRegisterAllowed(0xE3C);
SetRegisterAllowed(0xE40);
SetRegisterAllowed(0xE44);
SetRegisterAllowed(0xE48);
SetRegisterAllowed(0xE4C);
SetRegisterAllowed(0xE50);
SetRegisterAllowed(0xE54);
SetRegisterAllowed(0xE58);
SetRegisterAllowed(0xE5C);
SetRegisterAllowed(0xE60);
SetRegisterAllowed(0xE64);
SetRegisterAllowed(0xE68);
SetRegisterAllowed(0xE6C);
SetRegisterAllowed(0xE70);
SetRegisterAllowed(0xE74);
SetRegisterAllowed(0xE78);
SetRegisterAllowed(0xE7C);
SetRegisterAllowed(0xE80);
SetRegisterAllowed(0xE84);
SetRegisterAllowed(0xE88);
SetRegisterAllowed(0xE8C);
SetRegisterAllowed(0xE90);
SetRegisterAllowed(0xE94);
SetRegisterAllowed(0xE98);
SetRegisterAllowed(0xE9C);
SetRegisterAllowed(0xEA0);
SetRegisterAllowed(0xEA4);
SetRegisterAllowed(0xEA8);
SetRegisterAllowed(0xEAC);
SetRegisterAllowed(0xEB0);
SetRegisterAllowed(0xEB4);
SetRegisterAllowed(0xEB8);
SetRegisterAllowed(0xEBC);
SetRegisterAllowed(0xEC0);
SetRegisterAllowed(0xEC4);
SetRegisterAllowed(0xEC8);
SetRegisterAllowed(0xECC);
SetRegisterAllowed(0xED0);
SetRegisterAllowed(0xED4);
SetRegisterAllowed(0xED8);

View File

@@ -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/>.
*/
SetRegisterAllowed(MC_STAT_CONTROL); /* 0x100 */
SetRegisterAllowed(MC_STAT_EMC_CLOCK_LIMIT); /* 0x108 */
SetRegisterAllowed(MC_STAT_EMC_CLOCK_LIMIT_MSBS); /* 0x10C */
SetRegisterAllowed(MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_LO); /* 0x118 */
SetRegisterAllowed(MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_HI); /* 0x11C */
SetRegisterAllowed(MC_STAT_EMC_FILTER_SET0_SPARE); /* 0x124 */
SetRegisterAllowed(MC_STAT_EMC_FILTER_SET0_CLIENT_0); /* 0x128 */
SetRegisterAllowed(MC_STAT_EMC_FILTER_SET0_CLIENT_1); /* 0x12C */
SetRegisterAllowed(MC_STAT_EMC_FILTER_SET0_CLIENT_2); /* 0x130 */
SetRegisterAllowed(MC_STAT_EMC_FILTER_SET0_CLIENT_3); /* 0x134 */
SetRegisterAllowed(MC_STAT_EMC_SET0_COUNT); /* 0x138 */
SetRegisterAllowed(MC_STAT_EMC_SET0_COUNT_MSBS); /* 0x13C */
SetRegisterAllowed(MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_LO); /* 0x158 */
SetRegisterAllowed(MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_HI); /* 0x15C */
SetRegisterAllowed(MC_STAT_EMC_FILTER_SET1_SPARE); /* 0x164 */
SetRegisterAllowed(MC_STAT_EMC_FILTER_SET1_CLIENT_0); /* 0x168 */
SetRegisterAllowed(MC_STAT_EMC_FILTER_SET1_CLIENT_1); /* 0x16C */
SetRegisterAllowed(MC_STAT_EMC_FILTER_SET1_CLIENT_2); /* 0x170 */
SetRegisterAllowed(MC_STAT_EMC_FILTER_SET1_CLIENT_3); /* 0x174 */
SetRegisterAllowed(MC_STAT_EMC_SET1_COUNT); /* 0x178 */
SetRegisterAllowed(MC_STAT_EMC_SET1_COUNT_MSBS); /* 0x17C */
SetRegisterAllowed(MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_UPPER); /* 0xA20 */
SetRegisterAllowed(MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_UPPER); /* 0xA24 */
SetRegisterAllowed(MC_STAT_EMC_FILTER_SET0_CLIENT_4); /* 0xB88 */
SetRegisterAllowed(MC_STAT_EMC_FILTER_SET1_CLIENT_4); /* 0xB8C */
SetRegisterAllowed(MC_STAT_EMC_FILTER_SET0_CLIENT_5); /* 0xBC4 */
SetRegisterAllowed(MC_STAT_EMC_FILTER_SET1_CLIENT_5); /* 0xBC8 */

View File

@@ -1,195 +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/>.
*/
SetRegisterAllowed(MC_INTSTATUS); /* 0x000 */
SetRegisterAllowed(MC_INTMASK); /* 0x004 */
SetRegisterAllowed(MC_ERR_STATUS); /* 0x008 */
SetRegisterAllowed(MC_ERR_ADR); /* 0x00C */
SetRegisterAllowed(MC_SMMU_CONFIG); /* 0x010 */
SetRegisterAllowed(MC_SMMU_PTB_ASID); /* 0x01C */
SetRegisterAllowed(MC_SMMU_PTB_DATA); /* 0x020 */
SetRegisterAllowed(MC_SMMU_TLB_FLUSH); /* 0x030 */
SetRegisterAllowed(MC_SMMU_PTC_FLUSH_0); /* 0x034 */
SetRegisterAllowed(MC_EMEM_CFG); /* 0x050 */
SetRegisterAllowed(MC_EMEM_ADR_CFG); /* 0x054 */
SetRegisterAllowed(MC_EMEM_ARB_CFG); /* 0x090 */
SetRegisterAllowed(MC_EMEM_ARB_OUTSTANDING_REQ); /* 0x094 */
SetRegisterAllowed(MC_EMEM_ARB_TIMING_RCD); /* 0x098 */
SetRegisterAllowed(MC_EMEM_ARB_TIMING_RP); /* 0x09C */
SetRegisterAllowed(MC_EMEM_ARB_TIMING_RC); /* 0x0A0 */
SetRegisterAllowed(MC_EMEM_ARB_TIMING_RAS); /* 0x0A4 */
SetRegisterAllowed(MC_EMEM_ARB_TIMING_FAW); /* 0x0A8 */
SetRegisterAllowed(MC_EMEM_ARB_TIMING_RRD); /* 0x0AC */
SetRegisterAllowed(MC_EMEM_ARB_TIMING_RAP2PRE); /* 0x0B0 */
SetRegisterAllowed(MC_EMEM_ARB_TIMING_WAP2PRE); /* 0x0B4 */
SetRegisterAllowed(MC_EMEM_ARB_TIMING_R2R); /* 0x0B8 */
SetRegisterAllowed(MC_EMEM_ARB_TIMING_W2W); /* 0x0BC */
SetRegisterAllowed(MC_EMEM_ARB_TIMING_R2W); /* 0x0C0 */
SetRegisterAllowed(MC_EMEM_ARB_TIMING_W2R); /* 0x0C4 */
SetRegisterAllowed(MC_EMEM_ARB_MISC2); /* 0x0C8 */
SetRegisterAllowed(MC_EMEM_ARB_DA_TURNS); /* 0x0D0 */
SetRegisterAllowed(MC_EMEM_ARB_DA_COVERS); /* 0x0D4 */
SetRegisterAllowed(MC_EMEM_ARB_MISC0); /* 0x0D8 */
SetRegisterAllowed(MC_EMEM_ARB_MISC1); /* 0x0DC */
SetRegisterAllowed(MC_EMEM_ARB_RING1_THROTTLE); /* 0x0E0 */
SetRegisterAllowed(MC_CLIENT_HOTRESET_CTRL); /* 0x200 */
SetRegisterAllowed(MC_CLIENT_HOTRESET_STATUS); /* 0x204 */
SetRegisterAllowed(MC_SMMU_AFI_ASID); /* 0x238 */
SetRegisterAllowed(MC_SMMU_DC_ASID); /* 0x240 */
SetRegisterAllowed(MC_SMMU_DCB_ASID); /* 0x244 */
SetRegisterAllowed(MC_SMMU_HC_ASID); /* 0x250 */
SetRegisterAllowed(MC_SMMU_HDA_ASID); /* 0x254 */
SetRegisterAllowed(MC_SMMU_ISP2_ASID); /* 0x258 */
SetRegisterAllowed(MC_SMMU_MSENC_NVENC_ASID); /* 0x264 */
SetRegisterAllowed(MC_SMMU_NV_ASID); /* 0x268 */
SetRegisterAllowed(MC_SMMU_NV2_ASID); /* 0x26C */
SetRegisterAllowed(MC_SMMU_PPCS_ASID); /* 0x270 */
SetRegisterAllowed(MC_SMMU_SATA_ASID); /* 0x274 */
SetRegisterAllowed(MC_SMMU_VI_ASID); /* 0x280 */
SetRegisterAllowed(MC_SMMU_VIC_ASID); /* 0x284 */
SetRegisterAllowed(MC_SMMU_XUSB_HOST_ASID); /* 0x288 */
SetRegisterAllowed(MC_SMMU_XUSB_DEV_ASID); /* 0x28C */
SetRegisterAllowed(MC_SMMU_TSEC_ASID); /* 0x294 */
SetRegisterAllowed(MC_LATENCY_ALLOWANCE_AVPC_0); /* 0x2E4 */
SetRegisterAllowed(MC_LATENCY_ALLOWANCE_DC_0); /* 0x2E8 */
SetRegisterAllowed(MC_LATENCY_ALLOWANCE_DC_1); /* 0x2EC */
SetRegisterAllowed(MC_LATENCY_ALLOWANCE_DCB_0); /* 0x2F4 */
SetRegisterAllowed(MC_LATENCY_ALLOWANCE_DCB_1); /* 0x2F8 */
SetRegisterAllowed(MC_LATENCY_ALLOWANCE_HC_0); /* 0x310 */
SetRegisterAllowed(MC_LATENCY_ALLOWANCE_HC_1); /* 0x314 */
SetRegisterAllowed(MC_LATENCY_ALLOWANCE_MPCORE_0); /* 0x320 */
SetRegisterAllowed(MC_LATENCY_ALLOWANCE_NVENC_0); /* 0x328 */
SetRegisterAllowed(MC_LATENCY_ALLOWANCE_PPCS_0); /* 0x344 */
SetRegisterAllowed(MC_LATENCY_ALLOWANCE_PPCS_1); /* 0x348 */
SetRegisterAllowed(MC_LATENCY_ALLOWANCE_ISP2_0); /* 0x370 */
SetRegisterAllowed(MC_LATENCY_ALLOWANCE_ISP2_1); /* 0x374 */
SetRegisterAllowed(MC_LATENCY_ALLOWANCE_XUSB_0); /* 0x37C */
SetRegisterAllowed(MC_LATENCY_ALLOWANCE_XUSB_1); /* 0x380 */
SetRegisterAllowed(MC_LATENCY_ALLOWANCE_TSEC_0); /* 0x390 */
SetRegisterAllowed(MC_LATENCY_ALLOWANCE_VIC_0); /* 0x394 */
SetRegisterAllowed(MC_LATENCY_ALLOWANCE_VI2_0); /* 0x398 */
SetRegisterAllowed(MC_LATENCY_ALLOWANCE_GPU_0); /* 0x3AC */
SetRegisterAllowed(MC_LATENCY_ALLOWANCE_SDMMCA_0); /* 0x3B8 */
SetRegisterAllowed(MC_LATENCY_ALLOWANCE_SDMMCAA_0); /* 0x3BC */
SetRegisterAllowed(MC_LATENCY_ALLOWANCE_SDMMC_0); /* 0x3C0 */
SetRegisterAllowed(MC_LATENCY_ALLOWANCE_SDMMCAB_0); /* 0x3C4 */
SetRegisterAllowed(MC_LATENCY_ALLOWANCE_NVDEC_0); /* 0x3D8 */
SetRegisterAllowed(MC_LATENCY_ALLOWANCE_GPU2_0); /* 0x3E8 */
SetRegisterAllowed(MC_DIS_PTSA_RATE); /* 0x41C */
SetRegisterAllowed(MC_DIS_PTSA_MIN); /* 0x420 */
SetRegisterAllowed(MC_DIS_PTSA_MAX); /* 0x424 */
SetRegisterAllowed(MC_DISB_PTSA_RATE); /* 0x428 */
SetRegisterAllowed(MC_DISB_PTSA_MIN); /* 0x42C */
SetRegisterAllowed(MC_DISB_PTSA_MAX); /* 0x430 */
SetRegisterAllowed(MC_VE_PTSA_RATE); /* 0x434 */
SetRegisterAllowed(MC_VE_PTSA_MIN); /* 0x438 */
SetRegisterAllowed(MC_VE_PTSA_MAX); /* 0x43C */
SetRegisterAllowed(MC_MLL_MPCORER_PTSA_RATE); /* 0x44C */
SetRegisterAllowed(MC_RING1_PTSA_RATE); /* 0x47C */
SetRegisterAllowed(MC_RING1_PTSA_MIN); /* 0x480 */
SetRegisterAllowed(MC_RING1_PTSA_MAX); /* 0x484 */
SetRegisterAllowed(MC_PCX_PTSA_RATE); /* 0x4AC */
SetRegisterAllowed(MC_PCX_PTSA_MIN); /* 0x4B0 */
SetRegisterAllowed(MC_PCX_PTSA_MAX); /* 0x4B4 */
SetRegisterAllowed(MC_MSE_PTSA_RATE); /* 0x4C4 */
SetRegisterAllowed(MC_MSE_PTSA_MIN); /* 0x4C8 */
SetRegisterAllowed(MC_MSE_PTSA_MAX); /* 0x4CC */
SetRegisterAllowed(MC_AHB_PTSA_RATE); /* 0x4DC */
SetRegisterAllowed(MC_AHB_PTSA_MIN); /* 0x4E0 */
SetRegisterAllowed(MC_AHB_PTSA_MAX); /* 0x4E4 */
SetRegisterAllowed(MC_APB_PTSA_RATE); /* 0x4E8 */
SetRegisterAllowed(MC_APB_PTSA_MIN); /* 0x4EC */
SetRegisterAllowed(MC_APB_PTSA_MAX); /* 0x4F0 */
SetRegisterAllowed(MC_FTOP_PTSA_RATE); /* 0x50C */
SetRegisterAllowed(MC_HOST_PTSA_RATE); /* 0x518 */
SetRegisterAllowed(MC_HOST_PTSA_MIN); /* 0x51C */
SetRegisterAllowed(MC_HOST_PTSA_MAX); /* 0x520 */
SetRegisterAllowed(MC_USBX_PTSA_RATE); /* 0x524 */
SetRegisterAllowed(MC_USBX_PTSA_MIN); /* 0x528 */
SetRegisterAllowed(MC_USBX_PTSA_MAX); /* 0x52C */
SetRegisterAllowed(MC_USBD_PTSA_RATE); /* 0x530 */
SetRegisterAllowed(MC_USBD_PTSA_MIN); /* 0x534 */
SetRegisterAllowed(MC_USBD_PTSA_MAX); /* 0x538 */
SetRegisterAllowed(MC_GK_PTSA_RATE); /* 0x53C */
SetRegisterAllowed(MC_GK_PTSA_MIN); /* 0x540 */
SetRegisterAllowed(MC_GK_PTSA_MAX); /* 0x544 */
SetRegisterAllowed(MC_AUD_PTSA_RATE); /* 0x548 */
SetRegisterAllowed(MC_AUD_PTSA_MIN); /* 0x54C */
SetRegisterAllowed(MC_AUD_PTSA_MAX); /* 0x550 */
SetRegisterAllowed(MC_VICPC_PTSA_RATE); /* 0x554 */
SetRegisterAllowed(MC_VICPC_PTSA_MIN); /* 0x558 */
SetRegisterAllowed(MC_VICPC_PTSA_MAX); /* 0x55C */
SetRegisterAllowed(MC_JPG_PTSA_RATE); /* 0x584 */
SetRegisterAllowed(MC_JPG_PTSA_MIN); /* 0x588 */
SetRegisterAllowed(MC_JPG_PTSA_MAX); /* 0x58C */
SetRegisterAllowed(MC_GK2_PTSA_RATE); /* 0x610 */
SetRegisterAllowed(MC_GK2_PTSA_MIN); /* 0x614 */
SetRegisterAllowed(MC_GK2_PTSA_MAX); /* 0x618 */
SetRegisterAllowed(MC_SDM_PTSA_RATE); /* 0x61C */
SetRegisterAllowed(MC_SDM_PTSA_MIN); /* 0x620 */
SetRegisterAllowed(MC_SDM_PTSA_MAX); /* 0x624 */
SetRegisterAllowed(MC_HDAPC_PTSA_RATE); /* 0x628 */
SetRegisterAllowed(MC_HDAPC_PTSA_MIN); /* 0x62C */
SetRegisterAllowed(MC_HDAPC_PTSA_MAX); /* 0x630 */
SetRegisterAllowed(MC_SEC_CARVEOUT_BOM); /* 0x670 */
SetRegisterAllowed(MC_SEC_CARVEOUT_SIZE_MB); /* 0x674 */
SetRegisterAllowed(MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0A); /* 0x690 */
SetRegisterAllowed(MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0AB); /* 0x694 */
SetRegisterAllowed(MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0B); /* 0x698 */
SetRegisterAllowed(MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0BB); /* 0x69C */
SetRegisterAllowed(MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0C); /* 0x6A0 */
SetRegisterAllowed(MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0CB); /* 0x6A4 */
SetRegisterAllowed(MC_EMEM_ARB_TIMING_RFCPB); /* 0x6C0 */
SetRegisterAllowed(MC_EMEM_ARB_TIMING_CCDMW); /* 0x6C4 */
SetRegisterAllowed(MC_EMEM_ARB_REFPB_HP_CTRL); /* 0x6F0 */
SetRegisterAllowed(MC_EMEM_ARB_REFPB_BANK_CTRL); /* 0x6F4 */
SetRegisterAllowed(MC_PTSA_GRANT_DECREMENT); /* 0x960 */
SetRegisterAllowed(MC_CLIENT_HOTRESET_CTRL_1); /* 0x970 */
SetRegisterAllowed(MC_CLIENT_HOTRESET_STATUS_1); /* 0x974 */
SetRegisterAllowed(MC_SMMU_PTC_FLUSH_1); /* 0x9B8 */
SetRegisterAllowed(MC_SMMU_DC1_ASID); /* 0xA88 */
SetRegisterAllowed(MC_SMMU_SDMMC1A_ASID); /* 0xA94 */
SetRegisterAllowed(MC_SMMU_SDMMC2A_ASID); /* 0xA98 */
SetRegisterAllowed(MC_SMMU_SDMMC3A_ASID); /* 0xA9C */
SetRegisterAllowed(MC_SMMU_SDMMC4A_ASID); /* 0xAA0 */
SetRegisterAllowed(MC_SMMU_ISP2B_ASID); /* 0xAA4 */
SetRegisterAllowed(MC_SMMU_GPU_ASID); /* 0xAA8 */
SetRegisterAllowed(MC_SMMU_GPUB_ASID); /* 0xAAC */
SetRegisterAllowed(MC_SMMU_PPCS2_ASID); /* 0xAB0 */
SetRegisterAllowed(MC_SMMU_NVDEC_ASID); /* 0xAB4 */
SetRegisterAllowed(MC_SMMU_APE_ASID); /* 0xAB8 */
SetRegisterAllowed(MC_SMMU_SE_ASID); /* 0xABC */
SetRegisterAllowed(MC_SMMU_NVJPG_ASID); /* 0xAC0 */
SetRegisterAllowed(MC_SMMU_HC1_ASID); /* 0xAC4 */
SetRegisterAllowed(MC_SMMU_SE1_ASID); /* 0xAC8 */
SetRegisterAllowed(MC_SMMU_AXIAP_ASID); /* 0xACC */
SetRegisterAllowed(MC_SMMU_ETR_ASID); /* 0xAD0 */
SetRegisterAllowed(MC_SMMU_TSECB_ASID); /* 0xAD4 */
SetRegisterAllowed(MC_SMMU_TSEC1_ASID); /* 0xAD8 */
SetRegisterAllowed(MC_SMMU_TSECB1_ASID); /* 0xADC */
SetRegisterAllowed(MC_SMMU_NVDEC1_ASID); /* 0xAE0 */
SetRegisterAllowed(MC_EMEM_ARB_DHYST_CTRL); /* 0xBCC */
SetRegisterAllowed(MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_0); /* 0xBD0 */
SetRegisterAllowed(MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_1); /* 0xBD4 */
SetRegisterAllowed(MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_2); /* 0xBD8 */
SetRegisterAllowed(MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_3); /* 0xBDC */
SetRegisterAllowed(MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_4); /* 0xBE0 */
SetRegisterAllowed(MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_5); /* 0xBE4 */
SetRegisterAllowed(MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_6); /* 0xBE8 */
SetRegisterAllowed(MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_7); /* 0xBEC */
SetRegisterAllowed(MC_ERR_GENERALIZED_CARVEOUT_STATUS); /* 0xC00 */
SetRegisterAllowed(MC_SECURITY_CARVEOUT2_BOM); /* 0xC5C */
SetRegisterAllowed(MC_SECURITY_CARVEOUT3_BOM); /* 0xCAC */

View File

@@ -1,47 +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/>.
*/
SetRegisterAllowed(APBDEV_PMC_CNTRL); /* 0x000 */
SetRegisterAllowed(APBDEV_PMC_WAKE_MASK); /* 0x00C */
SetRegisterAllowed(APBDEV_PMC_WAKE_LVL); /* 0x010 */
SetRegisterAllowed(APBDEV_PMC_WAKE_STATUS); /* 0x014 */
SetRegisterAllowed(APBDEV_PMC_DPD_PADS_ORIDE); /* 0x01C */
SetRegisterAllowed(APBDEV_PMC_DPD_SAMPLE); /* 0x020 */
SetRegisterAllowed(APBDEV_PMC_CLAMP_STATUS); /* 0x02C */
SetRegisterAllowed(APBDEV_PMC_PWRGATE_TOGGLE); /* 0x030 */
SetRegisterAllowed(APBDEV_PMC_REMOVE_CLAMPING_CMD ); /* 0x034 */
SetRegisterAllowed(APBDEV_PMC_PWRGATE_STATUS); /* 0x038 */
SetRegisterAllowed(APBDEV_PMC_PWRGOOD_TIMER); /* 0x03C */
SetRegisterAllowed(APBDEV_PMC_BLINK_TIMER); /* 0x040 */
SetRegisterAllowed(APBDEV_PMC_NO_IOPOWER); /* 0x044 */
SetRegisterAllowed(APBDEV_PMC_PWR_DET); /* 0x048 */
SetRegisterAllowed(APBDEV_PMC_AUTO_WAKE_LVL_MASK); /* 0x0DC */
SetRegisterAllowed(APBDEV_PMC_WAKE_DELAY); /* 0x0E0 */
SetRegisterAllowed(APBDEV_PMC_PWR_DET_VAL); /* 0x0E4 */
SetRegisterAllowed(APBDEV_PMC_WAKE2_MASK); /* 0x160 */
SetRegisterAllowed(APBDEV_PMC_WAKE2_LVL); /* 0x164 */
SetRegisterAllowed(APBDEV_PMC_WAKE2_STATUS); /* 0x168 */
SetRegisterAllowed(APBDEV_PMC_AUTO_WAKE2_LVL_MASK ); /* 0x170 */
SetRegisterAllowed(APBDEV_PMC_CLK_OUT_CNTRL); /* 0x1A8 */
SetRegisterAllowed(APBDEV_PMC_IO_DPD_REQ); /* 0x1B8 */
SetRegisterAllowed(APBDEV_PMC_IO_DPD_STATUS); /* 0x1BC */
SetRegisterAllowed(APBDEV_PMC_IO_DPD2_REQ); /* 0x1C0 */
SetRegisterAllowed(APBDEV_PMC_IO_DPD2_STATUS); /* 0x1C4 */
SetRegisterAllowed(APBDEV_PMC_SEL_DPD_TIM); /* 0x1C8 */
SetRegisterAllowed(APBDEV_PMC_TSC_MULT); /* 0x2B4 */
SetRegisterAllowed(APBDEV_PMC_GPU_RG_CNTRL); /* 0x2D4 */
SetRegisterAllowed(APBDEV_PMC_CNTRL2); /* 0x440 */
SetRegisterAllowed(APBDEV_PMC_WAKE_DEBOUNCE_EN); /* 0x4D8 */

View File

@@ -1,96 +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 "secmon_smc_common.hpp"
#include "secmon_random_cache.hpp"
namespace ams::secmon::smc {
namespace {
constinit int g_random_offset_low = 0;
constinit int g_random_offset_high = 0;
void FillRandomCache(int offset, int size) {
/* Get the cache. */
u8 * const random_cache_loc = GetRandomBytesCache() + offset;
/* Flush the region we're about to fill to ensure consistency with the SE. */
hw::FlushDataCache(random_cache_loc, size);
hw::DataSynchronizationBarrierInnerShareable();
/* Generate random bytes. */
se::GenerateRandomBytes(random_cache_loc, size);
hw::DataSynchronizationBarrierInnerShareable();
/* Flush to ensure the CPU sees consistent data for the region. */
hw::FlushDataCache(random_cache_loc, size);
hw::DataSynchronizationBarrierInnerShareable();
}
}
void FillRandomCache() {
/* Fill the cache. */
FillRandomCache(0, GetRandomBytesCacheSize());
/* Set the extents. */
g_random_offset_low = 0;
g_random_offset_high = GetRandomBytesCacheSize() - 1;
}
void RefillRandomCache() {
/* Check that we need to do any refilling. */
if (const int used_start = (g_random_offset_high + 1) % GetRandomBytesCacheSize(); used_start != g_random_offset_low) {
if (used_start < g_random_offset_low) {
/* The region we need to fill is after used_start but before g_random_offset_low. */
const auto size = g_random_offset_low - used_start;
FillRandomCache(used_start, size);
g_random_offset_high += size;
} else {
/* We need to fill the space from high to the end and from low to start. */
const int high_size = GetRandomBytesCacheSize() - used_start;
if (high_size > 0) {
FillRandomCache(used_start, high_size);
g_random_offset_high += high_size;
}
const int low_size = g_random_offset_low;
if (low_size > 0) {
FillRandomCache(0, low_size);
g_random_offset_high += low_size;
}
}
g_random_offset_high %= GetRandomBytesCacheSize();
}
}
void GetRandomFromCache(void *dst, size_t size) {
/* Copy out the requested size. */
std::memcpy(dst, GetRandomBytesCache() + g_random_offset_low, size);
/* Advance. */
g_random_offset_low += size;
/* Ensure that at all times g_random_offset_low is not within 0x38 bytes of the end of the pool. */
if (g_random_offset_low + MaxRandomBytes >= GetRandomBytesCacheSize()) {
g_random_offset_low = 0;
}
}
}

View File

@@ -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 <exosphere.hpp>
#include "secmon_smc_common.hpp"
namespace ams::secmon::smc {
constexpr inline size_t MaxRandomBytes = sizeof(SmcArguments) - sizeof(SmcArguments{}.r[0]);
void FillRandomCache();
void RefillRandomCache();
void GetRandomFromCache(void *dst, size_t size);
}

View File

@@ -1,865 +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 "../secmon_error.hpp"
#include "../secmon_key_storage.hpp"
#include "../secmon_misc.hpp"
#include "../secmon_page_mapper.hpp"
#include "secmon_smc_aes.hpp"
#include "secmon_smc_device_unique_data.hpp"
#include "secmon_smc_se_lock.hpp"
namespace ams::secmon::smc {
namespace {
constexpr inline auto AesKeySize = se::AesBlockSize;
constexpr inline size_t CmacSizeMax = 1_KB;
constexpr inline size_t DeviceUniqueDataSizeMin = 0x130;
constexpr inline size_t DeviceUniqueDataSizeMax = 0x240;
enum SealKey {
SealKey_LoadAesKey = 0,
SealKey_DecryptDeviceUniqueData = 1,
SealKey_ImportLotusKey = 2,
SealKey_ImportEsDeviceKey = 3,
SealKey_ReencryptDeviceUniqueData = 4,
SealKey_ImportSslKey = 5,
SealKey_ImportEsClientCertKey = 6,
SealKey_Count,
};
enum KeyType {
KeyType_Default = 0,
KeyType_NormalOnly = 1,
KeyType_RecoveryOnly = 2,
KeyType_NormalAndRecovery = 3,
KeyType_Count,
};
enum CipherMode {
CipherMode_CbcEncryption = 0,
CipherMode_CbcDecryption = 1,
CipherMode_Ctr = 2,
CipherMode_Cmac = 3,
};
enum SpecificAesKey {
SpecificAesKey_CalibrationEncryption0 = 0,
SpecificAesKey_CalibrationEncryption1 = 1,
SpecificAesKey_Count,
};
enum DeviceUniqueData {
DeviceUniqueData_DecryptDeviceUniqueData = 0,
DeviceUniqueData_ImportLotusKey = 1,
DeviceUniqueData_ImportEsDeviceKey = 2,
DeviceUniqueData_ImportSslKey = 3,
DeviceUniqueData_ImportEsClientCertKey = 4,
DeviceUniqueData_Count,
};
/* Ensure that our "subtract one" simplification is valid for the cases we care about. */
static_assert(DeviceUniqueData_ImportLotusKey - 1 == ImportRsaKey_Lotus);
static_assert(DeviceUniqueData_ImportEsDeviceKey - 1 == ImportRsaKey_EsDrmCert);
static_assert(DeviceUniqueData_ImportSslKey - 1 == ImportRsaKey_Ssl);
static_assert(DeviceUniqueData_ImportEsClientCertKey - 1 == ImportRsaKey_EsClientCert);
constexpr ImportRsaKey ConvertToImportRsaKey(DeviceUniqueData data) {
/* Not necessary, but if this is invoked at compile-time this will force a compile-time error. */
AMS_ASSUME(data != DeviceUniqueData_DecryptDeviceUniqueData);
AMS_ASSUME(data < DeviceUniqueData_Count);
return static_cast<ImportRsaKey>(static_cast<int>(data) - 1);
}
enum SecureData {
SecureData_Calibration = 0,
SecureData_SafeMode = 1,
SecureData_UserSystemProperEncryption = 2,
SecureData_UserSystem = 3,
SecureData_Count,
};
struct GenerateAesKekOption {
using IsDeviceUnique = util::BitPack32::Field<0, 1, bool>;
using KeyTypeIndex = util::BitPack32::Field<1, 4, KeyType>;
using SealKeyIndex = util::BitPack32::Field<5, 3, SealKey>;
using Reserved = util::BitPack32::Field<8, 24, u32>;
};
struct ComputeAesOption {
using KeySlot = util::BitPack32::Field<0, 3, int>;
using CipherModeIndex = util::BitPack32::Field<4, 2, CipherMode>;
};
struct DecryptDeviceUniqueDataOption {
using DeviceUniqueDataIndex = util::BitPack32::Field<0, 3, DeviceUniqueData>;
using Reserved = util::BitPack32::Field<3, 29, u32>;
/* Legacy. */
using EnforceDeviceUnique = util::BitPack32::Field<0, 1, bool>;
};
constexpr const u8 SealKeySources[SealKey_Count][AesKeySize] = {
[SealKey_LoadAesKey] = { 0xF4, 0x0C, 0x16, 0x26, 0x0D, 0x46, 0x3B, 0xE0, 0x8C, 0x6A, 0x56, 0xE5, 0x82, 0xD4, 0x1B, 0xF6 },
[SealKey_DecryptDeviceUniqueData] = { 0x7F, 0x54, 0x2C, 0x98, 0x1E, 0x54, 0x18, 0x3B, 0xBA, 0x63, 0xBD, 0x4C, 0x13, 0x5B, 0xF1, 0x06 },
[SealKey_ImportLotusKey] = { 0xC7, 0x3F, 0x73, 0x60, 0xB7, 0xB9, 0x9D, 0x74, 0x0A, 0xF8, 0x35, 0x60, 0x1A, 0x18, 0x74, 0x63 },
[SealKey_ImportEsDeviceKey] = { 0x0E, 0xE0, 0xC4, 0x33, 0x82, 0x66, 0xE8, 0x08, 0x39, 0x13, 0x41, 0x7D, 0x04, 0x64, 0x2B, 0x6D },
[SealKey_ReencryptDeviceUniqueData] = { 0xE1, 0xA8, 0xAA, 0x6A, 0x2D, 0x9C, 0xDE, 0x43, 0x0C, 0xDE, 0xC6, 0x17, 0xF6, 0xC7, 0xF1, 0xDE },
[SealKey_ImportSslKey] = { 0x74, 0x20, 0xF6, 0x46, 0x77, 0xB0, 0x59, 0x2C, 0xE8, 0x1B, 0x58, 0x64, 0x47, 0x41, 0x37, 0xD9 },
[SealKey_ImportEsClientCertKey] = { 0xAA, 0x19, 0x0F, 0xFA, 0x4C, 0x30, 0x3B, 0x2E, 0xE6, 0xD8, 0x9A, 0xCF, 0xE5, 0x3F, 0xB3, 0x4B },
};
constexpr const u8 KeyTypeSources[KeyType_Count][AesKeySize] = {
[KeyType_Default] = { 0x4D, 0x87, 0x09, 0x86, 0xC4, 0x5D, 0x20, 0x72, 0x2F, 0xBA, 0x10, 0x53, 0xDA, 0x92, 0xE8, 0xA9 },
[KeyType_NormalOnly] = { 0x25, 0x03, 0x31, 0xFB, 0x25, 0x26, 0x0B, 0x79, 0x8C, 0x80, 0xD2, 0x69, 0x98, 0xE2, 0x22, 0x77 },
[KeyType_RecoveryOnly] = { 0x76, 0x14, 0x1D, 0x34, 0x93, 0x2D, 0xE1, 0x84, 0x24, 0x7B, 0x66, 0x65, 0x55, 0x04, 0x65, 0x81 },
[KeyType_NormalAndRecovery] = { 0xAF, 0x3D, 0xB7, 0xF3, 0x08, 0xA2, 0xD8, 0xA2, 0x08, 0xCA, 0x18, 0xA8, 0x69, 0x46, 0xC9, 0x0B },
};
constexpr const u8 SealKeyMasks[SealKey_Count][AesKeySize] = {
[SealKey_LoadAesKey] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
[SealKey_DecryptDeviceUniqueData] = { 0xA2, 0xAB, 0xBF, 0x9C, 0x92, 0x2F, 0xBB, 0xE3, 0x78, 0x79, 0x9B, 0xC0, 0xCC, 0xEA, 0xA5, 0x74 },
[SealKey_ImportLotusKey] = { 0x57, 0xE2, 0xD9, 0x45, 0xE4, 0x92, 0xF4, 0xFD, 0xC3, 0xF9, 0x86, 0x38, 0x89, 0x78, 0x9F, 0x3C },
[SealKey_ImportEsDeviceKey] = { 0xE5, 0x4D, 0x9A, 0x02, 0xF0, 0x4F, 0x5F, 0xA8, 0xAD, 0x76, 0x0A, 0xF6, 0x32, 0x95, 0x59, 0xBB },
[SealKey_ReencryptDeviceUniqueData] = { 0x59, 0xD9, 0x31, 0xF4, 0xA7, 0x97, 0xB8, 0x14, 0x40, 0xD6, 0xA2, 0x60, 0x2B, 0xED, 0x15, 0x31 },
[SealKey_ImportSslKey] = { 0xFD, 0x6A, 0x25, 0xE5, 0xD8, 0x38, 0x7F, 0x91, 0x49, 0xDA, 0xF8, 0x59, 0xA8, 0x28, 0xE6, 0x75 },
[SealKey_ImportEsClientCertKey] = { 0x89, 0x96, 0x43, 0x9A, 0x7C, 0xD5, 0x59, 0x55, 0x24, 0xD5, 0x24, 0x18, 0xAB, 0x6C, 0x04, 0x61 },
};
constexpr const SealKey DeviceUniqueDataToSealKey[DeviceUniqueData_Count] = {
[DeviceUniqueData_DecryptDeviceUniqueData] = SealKey_DecryptDeviceUniqueData,
[DeviceUniqueData_ImportLotusKey] = SealKey_ImportLotusKey,
[DeviceUniqueData_ImportEsDeviceKey] = SealKey_ImportEsDeviceKey,
[DeviceUniqueData_ImportSslKey] = SealKey_ImportSslKey,
[DeviceUniqueData_ImportEsClientCertKey] = SealKey_ImportEsClientCertKey,
};
constexpr const u8 CalibrationKeySource[AesKeySize] = {
0xE2, 0xD6, 0xB8, 0x7A, 0x11, 0x9C, 0xB8, 0x80, 0xE8, 0x22, 0x88, 0x8A, 0x46, 0xFB, 0xA1, 0x95
};
constexpr const u8 EsCommonKeySources[EsCommonKeyType_Count][AesKeySize] = {
[EsCommonKeyType_TitleKey] = { 0x1E, 0xDC, 0x7B, 0x3B, 0x60, 0xE6, 0xB4, 0xD8, 0x78, 0xB8, 0x17, 0x15, 0x98, 0x5E, 0x62, 0x9B },
[EsCommonKeyType_ArchiveKey] = { 0x3B, 0x78, 0xF2, 0x61, 0x0F, 0x9D, 0x5A, 0xE2, 0x7B, 0x4E, 0x45, 0xAF, 0xCB, 0x0B, 0x67, 0x4D },
[EsCommonKeyType_Unknown2] = { 0x42, 0x64, 0x0B, 0xE3, 0x5F, 0xC6, 0xBE, 0x47, 0xC7, 0xB4, 0x84, 0xC5, 0xEB, 0x63, 0xAA, 0x02 },
};
constexpr const u8 EsSealKeySource[AesKeySize] = {
0xCB, 0xB7, 0x6E, 0x38, 0xA1, 0xCB, 0x77, 0x0F, 0xB2, 0xA5, 0xB2, 0x9D, 0xD8, 0x56, 0x9F, 0x76
};
constexpr const u8 SecureDataSource[AesKeySize] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
constexpr const u8 SecureDataCounters[][AesKeySize] = {
[SecureData_Calibration] = { 0x3C, 0xD5, 0x92, 0xEC, 0x68, 0x31, 0x4A, 0x06, 0xD4, 0x1B, 0x0C, 0xD9, 0xF6, 0x2E, 0xD9, 0xE9 },
[SecureData_SafeMode] = { 0x50, 0x81, 0xCF, 0x77, 0x18, 0x11, 0xD7, 0x0D, 0x13, 0x29, 0x60, 0xED, 0x4B, 0x21, 0x3E, 0xFC },
[SecureData_UserSystemProperEncryption] = { 0x98, 0xCB, 0x4C, 0xEB, 0x15, 0xF1, 0x4A, 0x5A, 0x7A, 0x86, 0xB6, 0xF1, 0x94, 0x66, 0xF4, 0x9D },
};
constexpr const u8 SecureDataTweaks[][AesKeySize] = {
[SecureData_Calibration] = { 0xAC, 0xCA, 0x9A, 0xCA, 0xFF, 0x2E, 0xB9, 0x22, 0xCC, 0x1F, 0x4F, 0xAD, 0xDD, 0x77, 0x21, 0x1E },
[SecureData_SafeMode] = { 0x6E, 0xF8, 0x2A, 0x1A, 0xE0, 0x4F, 0xC3, 0x20, 0x08, 0x7B, 0xBA, 0x50, 0xC0, 0xCD, 0x7B, 0x39 },
[SecureData_UserSystemProperEncryption] = { 0x6D, 0x02, 0x56, 0x2D, 0xF4, 0x3D, 0x0A, 0x15, 0xB1, 0x34, 0x5C, 0xC2, 0x84, 0x4C, 0xD4, 0x28 },
};
constexpr const u8 *GetSecureDataCounter(SecureData which) {
switch (which) {
case SecureData_Calibration:
return SecureDataCounters[SecureData_Calibration];
case SecureData_SafeMode:
return SecureDataCounters[SecureData_SafeMode];
case SecureData_UserSystem:
case SecureData_UserSystemProperEncryption:
return SecureDataCounters[SecureData_UserSystemProperEncryption];
default:
return nullptr;
}
}
constexpr const u8 *GetSecureDataTweak(SecureData which) {
switch (which) {
case SecureData_Calibration:
return SecureDataTweaks[SecureData_Calibration];
case SecureData_SafeMode:
return SecureDataTweaks[SecureData_SafeMode];
case SecureData_UserSystem:
case SecureData_UserSystemProperEncryption:
return SecureDataTweaks[SecureData_UserSystemProperEncryption];
default:
return nullptr;
}
}
constexpr uintptr_t LinkedListAddressMinimum = secmon::MemoryRegionDram.GetAddress();
constexpr size_t LinkedListAddressRangeSize = 4_MB - 2_KB;
constexpr uintptr_t LinkedListAddressMaximum = LinkedListAddressMinimum + LinkedListAddressRangeSize;
constexpr size_t LinkedListSize = 12;
constexpr bool IsValidLinkedListAddress(uintptr_t address) {
return LinkedListAddressMinimum <= address && address <= (LinkedListAddressMaximum - LinkedListSize);
}
constinit bool g_is_compute_aes_completed = false;
void SecurityEngineDoneHandler() {
/* Check that the compute succeeded. */
se::ValidateAesOperationResult();
/* End the asynchronous operation. */
g_is_compute_aes_completed = true;
EndAsyncOperation();
}
SmcResult GetComputeAesResult(void *dst, size_t size) {
/* Arguments are unused. */
AMS_UNUSED(dst);
AMS_UNUSED(size);
/* Check that the operation is completed. */
SMC_R_UNLESS(g_is_compute_aes_completed, Busy);
/* Unlock the security engine and succeed. */
UnlockSecurityEngine();
return SmcResult::Success;
}
int PrepareMasterKey(int generation) {
if (generation == GetKeyGeneration()) {
return pkg1::AesKeySlot_Master;
}
constexpr int Slot = pkg1::AesKeySlot_Smc;
LoadMasterKey(Slot, generation);
return Slot;
}
int PrepareDeviceMasterKey(int generation) {
if (generation == pkg1::KeyGeneration_1_0_0 && GetSocType() == fuse::SocType_Erista) {
return pkg1::AesKeySlot_Device;
}
if (generation == GetKeyGeneration()) {
return pkg1::AesKeySlot_DeviceMaster;
}
constexpr int Slot = pkg1::AesKeySlot_Smc;
LoadDeviceMasterKey(Slot, generation);
return Slot;
}
void GetSecureDataImpl(u8 *dst, SecureData which, bool tweak) {
/* Compute the appropriate AES-CTR. */
{
/* Ensure that the SE sees consistent data. */
hw::FlushDataCache(dst, AesKeySize);
hw::DataSynchronizationBarrierInnerShareable();
/* Perform the appropriate AES operation. */
se::ComputeAes128Ctr(dst, AesKeySize, pkg1::AesKeySlot_Device, SecureDataSource, AesKeySize, GetSecureDataCounter(which), AesKeySize);
hw::DataSynchronizationBarrierInnerShareable();
/* Ensure the CPU sees consistent data. */
hw::FlushDataCache(dst, AesKeySize);
hw::DataSynchronizationBarrierInnerShareable();
}
/* Tweak, if we should. */
if (tweak) {
const u8 * const tweak = GetSecureDataTweak(which);
for (size_t i = 0; i < AesKeySize; ++i) {
dst[i] ^= tweak[i];
}
}
}
SmcResult GenerateAesKekImpl(SmcArguments &args) {
/* Decode arguments. */
u8 kek_source[AesKeySize];
std::memcpy(kek_source, std::addressof(args.r[1]), AesKeySize);
const int generation = std::max<int>(static_cast<int>(args.r[3]) - 1, pkg1::KeyGeneration_1_0_0);
const util::BitPack32 option = { static_cast<u32>(args.r[4]) };
const bool is_device_unique = option.Get<GenerateAesKekOption::IsDeviceUnique>();
const auto key_type = option.Get<GenerateAesKekOption::KeyTypeIndex>();
const auto seal_key = option.Get<GenerateAesKekOption::SealKeyIndex>();
const u32 reserved = option.Get<GenerateAesKekOption::Reserved>();
/* Validate arguments. */
SMC_R_UNLESS(reserved == 0, InvalidArgument);
if (is_device_unique) {
SMC_R_UNLESS(pkg1::IsValidDeviceUniqueKeyGeneration(generation), InvalidArgument);
} else {
SMC_R_UNLESS(pkg1::IsValidKeyGeneration(generation), InvalidArgument);
SMC_R_UNLESS(generation <= GetKeyGeneration(), InvalidArgument);
}
SMC_R_UNLESS(0 <= key_type && key_type < KeyType_Count, InvalidArgument);
SMC_R_UNLESS(0 <= seal_key && seal_key < SealKey_Count, InvalidArgument);
switch (key_type) {
case KeyType_NormalOnly: SMC_R_UNLESS(!IsRecoveryBoot(), InvalidArgument); break;
case KeyType_RecoveryOnly: SMC_R_UNLESS( IsRecoveryBoot(), InvalidArgument); break;
default: break;
}
/* Declare temporary data storage. */
u8 static_source[AesKeySize];
u8 generated_key[AesKeySize];
u8 access_key[AesKeySize];
/* Derive the static source. */
for (size_t i = 0; i < sizeof(static_source); ++i) {
static_source[i] = KeyTypeSources[key_type][i] ^ SealKeyMasks[seal_key][i];
}
/* Get the seal key source. */
const u8 * const seal_key_source = SealKeySources[seal_key];
/* Get the key slot. */
const int slot = is_device_unique ? PrepareDeviceMasterKey(generation) : PrepareMasterKey(generation);
/* Derive a static generation kek. */
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Smc, slot, static_source, sizeof(static_source));
/* Decrypt the input with the static generation kek. */
se::DecryptAes128(generated_key, sizeof(generated_key), pkg1::AesKeySlot_Smc, kek_source, sizeof(kek_source));
/* Generate the seal key. */
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Smc, pkg1::AesKeySlot_RandomForUserWrap, seal_key_source, AesKeySize);
/* Seal the generated key. */
se::EncryptAes128(access_key, sizeof(access_key), pkg1::AesKeySlot_Smc, generated_key, sizeof(generated_key));
/* Copy the access key out. */
std::memcpy(std::addressof(args.r[1]), access_key, sizeof(access_key));
return SmcResult::Success;
}
SmcResult LoadAesKeyImpl(SmcArguments &args) {
/* Decode arguments. */
const int slot = args.r[1];
u8 access_key[AesKeySize];
std::memcpy(access_key, std::addressof(args.r[2]), sizeof(access_key));
u8 key_source[AesKeySize];
std::memcpy(key_source, std::addressof(args.r[4]), sizeof(key_source));
/* Validate arguments. */
SMC_R_UNLESS(pkg1::IsUserAesKeySlot(slot), InvalidArgument);
/* Get the seal key source. */
constexpr const u8 * const SealKeySource = SealKeySources[SealKey_LoadAesKey];
/* Derive the seal key. */
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Smc, pkg1::AesKeySlot_RandomForUserWrap, SealKeySource, AesKeySize);
/* Unseal the access key. */
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Smc, pkg1::AesKeySlot_Smc, access_key, sizeof(access_key));
/* Derive the key. */
se::SetEncryptedAesKey128(slot, pkg1::AesKeySlot_Smc, key_source, sizeof(key_source));
return SmcResult::Success;
}
SmcResult ComputeAesImpl(SmcArguments &args) {
/* Decode arguments. */
u8 iv[se::AesBlockSize];
const util::BitPack32 option = { static_cast<u32>(args.r[1]) };
std::memcpy(iv, std::addressof(args.r[2]), sizeof(iv));
const u32 input_address = args.r[4];
const u32 output_address = args.r[5];
const u32 size = args.r[6];
const int slot = option.Get<ComputeAesOption::KeySlot>();
const auto cipher_mode = option.Get<ComputeAesOption::CipherModeIndex>();
/* Validate arguments. */
SMC_R_UNLESS(pkg1::IsUserAesKeySlot(slot), InvalidArgument);
SMC_R_UNLESS(util::IsAligned(size, se::AesBlockSize), InvalidArgument);
SMC_R_UNLESS(IsValidLinkedListAddress(input_address), InvalidArgument);
SMC_R_UNLESS(IsValidLinkedListAddress(output_address), InvalidArgument);
/* We're starting an aes operation, so reset the completion status. */
g_is_compute_aes_completed = false;
/* Dispatch the correct aes operation asynchronously. */
switch (cipher_mode) {
case CipherMode_CbcEncryption: se::EncryptAes128CbcAsync(output_address, slot, input_address, size, iv, sizeof(iv), SecurityEngineDoneHandler); break;
case CipherMode_CbcDecryption: se::DecryptAes128CbcAsync(output_address, slot, input_address, size, iv, sizeof(iv), SecurityEngineDoneHandler); break;
case CipherMode_Ctr: se::ComputeAes128CtrAsync(output_address, slot, input_address, size, iv, sizeof(iv), SecurityEngineDoneHandler); break;
case CipherMode_Cmac:
return SmcResult::NotSupported;
default:
return SmcResult::InvalidArgument;
}
return SmcResult::Success;
}
SmcResult GenerateSpecificAesKeyImpl(SmcArguments &args) {
/* Decode arguments. */
u8 key_source[AesKeySize];
std::memcpy(key_source, std::addressof(args.r[1]), sizeof(key_source));
const int generation = GetTargetFirmware() >= TargetFirmware_4_0_0 ? std::max<int>(static_cast<int>(args.r[3]) - 1, pkg1::KeyGeneration_1_0_0) : pkg1::KeyGeneration_1_0_0;
const auto which = static_cast<SpecificAesKey>(args.r[4]);
/* Validate arguments. */
SMC_R_UNLESS(pkg1::IsValidKeyGeneration(generation), InvalidArgument);
SMC_R_UNLESS(which < SpecificAesKey_Count, InvalidArgument);
/* Generate the specific aes key. */
u8 output_key[AesKeySize];
if (fuse::GetPatchVersion() >= fuse::PatchVersion_Odnx02A2) {
const int slot = PrepareDeviceMasterKey(generation);
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Smc, slot, CalibrationKeySource, sizeof(CalibrationKeySource));
se::DecryptAes128(output_key, sizeof(output_key), pkg1::AesKeySlot_Smc, key_source, sizeof(key_source));
} else {
GetSecureDataImpl(output_key, SecureData_Calibration, which == SpecificAesKey_CalibrationEncryption1);
}
/* Copy the key to output. */
std::memcpy(std::addressof(args.r[1]), output_key, sizeof(output_key));
return SmcResult::Success;
}
SmcResult ComputeCmacImpl(SmcArguments &args) {
/* Decode arguments. */
const int slot = args.r[1];
const uintptr_t data_address = args.r[2];
const size_t data_size = args.r[3];
/* Declare buffer for user data. */
alignas(8) u8 user_data[CmacSizeMax];
/* Validate arguments. */
SMC_R_UNLESS(pkg1::IsUserAesKeySlot(slot), InvalidArgument);
SMC_R_UNLESS(data_size <= sizeof(user_data), InvalidArgument);
/* Map the user data, and copy to stack. */
{
UserPageMapper mapper(data_address);
SMC_R_UNLESS(mapper.Map(), InvalidArgument);
SMC_R_UNLESS(mapper.CopyFromUser(user_data, data_address, data_size), InvalidArgument);
}
/* Ensure the SE sees consistent data. */
hw::FlushDataCache(user_data, data_size);
hw::DataSynchronizationBarrierInnerShareable();
/* Compute the mac. */
{
u8 mac[se::AesBlockSize];
se::ComputeAes128Cmac(mac, sizeof(mac), slot, user_data, data_size);
std::memcpy(std::addressof(args.r[1]), mac, sizeof(mac));
}
return SmcResult::Success;
}
SmcResult LoadPreparedAesKeyImpl(SmcArguments &args) {
/* Decode arguments. */
u8 access_key[AesKeySize];
const int slot = args.r[1];
std::memcpy(access_key, std::addressof(args.r[2]), sizeof(access_key));
/* Validate arguments. */
SMC_R_UNLESS(pkg1::IsUserAesKeySlot(slot), InvalidArgument);
/* Derive the seal key. */
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Smc, pkg1::AesKeySlot_RandomForUserWrap, EsSealKeySource, sizeof(EsSealKeySource));
/* Unseal the key. */
se::SetEncryptedAesKey128(slot, pkg1::AesKeySlot_Smc, access_key, sizeof(access_key));
return SmcResult::Success;
}
SmcResult PrepareEsCommonTitleKeyImpl(SmcArguments &args) {
/* Declare variables. */
u8 key_source[se::AesBlockSize];
u8 key[se::AesBlockSize];
u8 access_key[se::AesBlockSize];
/* Decode arguments. */
std::memcpy(key_source, std::addressof(args.r[1]), sizeof(key_source));
const int generation = GetTargetFirmware() >= TargetFirmware_3_0_0 ? std::max<int>(pkg1::KeyGeneration_1_0_0, static_cast<int>(args.r[3]) - 1) : pkg1::KeyGeneration_1_0_0;
/* Validate arguments. */
SMC_R_UNLESS(pkg1::IsValidKeyGeneration(generation), InvalidArgument);
SMC_R_UNLESS(generation <= GetKeyGeneration(), InvalidArgument);
/* Derive the key. */
DecryptWithEsCommonKey(key, sizeof(key), key_source, sizeof(key_source), EsCommonKeyType_TitleKey, generation);
/* Prepare the aes key. */
PrepareEsAesKey(access_key, sizeof(access_key), key, sizeof(key));
/* Copy the access key to output. */
std::memcpy(std::addressof(args.r[1]), access_key, sizeof(access_key));
return SmcResult::Success;
}
constexpr size_t GetDiscountedMinimumDeviceUniqueDataSize(bool enforce_device_unique) {
if (enforce_device_unique) {
return 0;
} else {
return DeviceUniqueDataTotalMetaSize - DeviceUniqueDataIvSize;
}
}
SmcResult ValidateDeviceUniqueDataSize(DeviceUniqueData mode, size_t data_size, bool enforce_device_unique) {
/* Determine the discounted size towards the minimum. */
const size_t discounted_size = GetDiscountedMinimumDeviceUniqueDataSize(enforce_device_unique);
SMC_R_UNLESS(enforce_device_unique || fuse::GetPatchVersion() < fuse::PatchVersion_Odnx02A2, InvalidArgument);
switch (mode) {
case DeviceUniqueData_DecryptDeviceUniqueData:
{
SMC_R_UNLESS(DeviceUniqueDataTotalMetaSize - discounted_size < data_size && data_size <= DeviceUniqueDataSizeMax, InvalidArgument);
}
break;
case DeviceUniqueData_ImportLotusKey:
case DeviceUniqueData_ImportEsDeviceKey:
case DeviceUniqueData_ImportSslKey:
case DeviceUniqueData_ImportEsClientCertKey:
{
SMC_R_UNLESS(DeviceUniqueDataSizeMin - discounted_size <= data_size && data_size <= DeviceUniqueDataSizeMax, InvalidArgument);
}
break;
default:
return SmcResult::InvalidArgument;
}
return SmcResult::Success;
}
SmcResult DecryptDeviceUniqueDataImpl(const u8 *access_key, const u8 *key_source, const DeviceUniqueData mode, const uintptr_t data_address, const size_t data_size, bool enforce_device_unique) {
/* Validate arguments. */
SMC_R_TRY(ValidateDeviceUniqueDataSize(mode, data_size, enforce_device_unique));
/* Decrypt the device unique data. */
alignas(8) u8 work_buffer[DeviceUniqueDataSizeMax];
ON_SCOPE_EXIT { crypto::ClearMemory(work_buffer, sizeof(work_buffer)); };
{
/* Map and copy in the encrypted data. */
UserPageMapper mapper(data_address);
SMC_R_UNLESS(mapper.Map(), InvalidArgument);
SMC_R_UNLESS(mapper.CopyFromUser(work_buffer, data_address, data_size), InvalidArgument);
/* Determine the seal key to use. */
const auto seal_key_type = DeviceUniqueDataToSealKey[mode];
const u8 * const seal_key_source = SealKeySources[seal_key_type];
/* Decrypt the data. */
if (!DecryptDeviceUniqueData(work_buffer, data_size, nullptr, seal_key_source, se::AesBlockSize, access_key, se::AesBlockSize, key_source, se::AesBlockSize, work_buffer, data_size, enforce_device_unique)) {
return SmcResult::InvalidArgument;
}
/* Either output the key, or import it. */
switch (mode) {
case DeviceUniqueData_DecryptDeviceUniqueData:
{
SMC_R_UNLESS(mapper.CopyToUser(data_address, work_buffer, data_size), InvalidArgument);
}
break;
case DeviceUniqueData_ImportLotusKey:
case DeviceUniqueData_ImportSslKey:
ImportRsaKeyExponent(ConvertToImportRsaKey(mode), work_buffer, se::RsaSize);
break;
case DeviceUniqueData_ImportEsDeviceKey:
case DeviceUniqueData_ImportEsClientCertKey:
ImportRsaKeyExponent(ConvertToImportRsaKey(mode), work_buffer, se::RsaSize);
ImportRsaKeyModulusProvisionally(ConvertToImportRsaKey(mode), work_buffer + se::RsaSize, se::RsaSize);
CommitRsaKeyModulus(ConvertToImportRsaKey(mode));
break;
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
return SmcResult::Success;
}
SmcResult DecryptDeviceUniqueDataImpl(SmcArguments &args) {
/* Decode arguments. */
u8 access_key[se::AesBlockSize];
u8 key_source[se::AesBlockSize];
std::memcpy(access_key, std::addressof(args.r[1]), sizeof(access_key));
const util::BitPack32 option = { static_cast<u32>(args.r[3]) };
const uintptr_t data_address = args.r[4];
const size_t data_size = args.r[5];
std::memcpy(key_source, std::addressof(args.r[6]), sizeof(key_source));
const auto mode = GetTargetFirmware() >= TargetFirmware_5_0_0 ? option.Get<DecryptDeviceUniqueDataOption::DeviceUniqueDataIndex>() : DeviceUniqueData_DecryptDeviceUniqueData;
const auto reserved = option.Get<DecryptDeviceUniqueDataOption::Reserved>();
const bool enforce_device_unique = GetTargetFirmware() >= TargetFirmware_5_0_0 ? true : option.Get<DecryptDeviceUniqueDataOption::EnforceDeviceUnique>();
/* Validate arguments. */
SMC_R_UNLESS(reserved == 0, InvalidArgument);
/* Decrypt the device unique data. */
return DecryptDeviceUniqueDataImpl(access_key, key_source, mode, data_address, data_size, enforce_device_unique);
}
SmcResult DecryptAndImportEsDeviceKeyImpl(SmcArguments &args) {
/* Decode arguments. */
u8 access_key[se::AesBlockSize];
u8 key_source[se::AesBlockSize];
std::memcpy(access_key, std::addressof(args.r[1]), sizeof(access_key));
const util::BitPack32 option = { static_cast<u32>(args.r[3]) };
const uintptr_t data_address = args.r[4];
const size_t data_size = args.r[5];
std::memcpy(key_source, std::addressof(args.r[6]), sizeof(key_source));
const auto mode = DeviceUniqueData_ImportEsDeviceKey;
const auto reserved = option.Get<DecryptDeviceUniqueDataOption::Reserved>();
const bool enforce_device_unique = option.Get<DecryptDeviceUniqueDataOption::EnforceDeviceUnique>();
/* Validate arguments. */
SMC_R_UNLESS(reserved == 0, InvalidArgument);
/* Ensure that the key is exactly the correct size. */
if (enforce_device_unique) {
SMC_R_UNLESS(data_size == util::AlignUp(2 * se::RsaSize + sizeof(u32), se::AesBlockSize) + DeviceUniqueDataTotalMetaSize, InvalidArgument);
} else {
SMC_R_UNLESS(data_size == util::AlignUp(2 * se::RsaSize + sizeof(u32), se::AesBlockSize) + DeviceUniqueDataIvSize, InvalidArgument);
}
/* Decrypt the device unique data. */
return DecryptDeviceUniqueDataImpl(access_key, key_source, mode, data_address, data_size, enforce_device_unique);
}
SmcResult DecryptAndImportLotusKeyImpl(SmcArguments &args) {
/* Decode arguments. */
u8 access_key[se::AesBlockSize];
u8 key_source[se::AesBlockSize];
std::memcpy(access_key, std::addressof(args.r[1]), sizeof(access_key));
const util::BitPack32 option = { static_cast<u32>(args.r[3]) };
const uintptr_t data_address = args.r[4];
const size_t data_size = args.r[5];
std::memcpy(key_source, std::addressof(args.r[6]), sizeof(key_source));
const auto mode = DeviceUniqueData_ImportLotusKey;
const auto reserved = option.Get<DecryptDeviceUniqueDataOption::Reserved>();
const bool enforce_device_unique = option.Get<DecryptDeviceUniqueDataOption::EnforceDeviceUnique>();
/* Validate arguments. */
SMC_R_UNLESS(reserved == 0, InvalidArgument);
/* Ensure that the key is exactly the correct size. */
if (enforce_device_unique) {
SMC_R_UNLESS(data_size == se::RsaSize + DeviceUniqueDataTotalMetaSize, InvalidArgument);
} else {
SMC_R_UNLESS(data_size == se::RsaSize + DeviceUniqueDataIvSize, InvalidArgument);
}
/* Decrypt the device unique data. */
return DecryptDeviceUniqueDataImpl(access_key, key_source, mode, data_address, data_size, enforce_device_unique);
}
SmcResult ReencryptDeviceUniqueDataImpl(SmcArguments &args) {
/* Decode arguments. */
u8 access_key_dec[se::AesBlockSize];
u8 access_key_enc[se::AesBlockSize];
u8 key_source_dec[se::AesBlockSize];
u8 key_source_enc[se::AesBlockSize];
const uintptr_t access_key_dec_address = args.r[1];
const uintptr_t access_key_enc_address = args.r[2];
const util::BitPack32 option = { static_cast<u32>(args.r[3]) };
const uintptr_t data_address = args.r[4];
const size_t data_size = args.r[5];
const uintptr_t key_source_dec_address = args.r[6];
const uintptr_t key_source_enc_address = args.r[7];
const auto mode = option.Get<DecryptDeviceUniqueDataOption::DeviceUniqueDataIndex>();
const auto reserved = option.Get<DecryptDeviceUniqueDataOption::Reserved>();
const bool enforce_device_unique = true;
/* Validate arguments. */
SMC_R_UNLESS(reserved == 0, InvalidArgument);
SMC_R_TRY(ValidateDeviceUniqueDataSize(mode, data_size, enforce_device_unique));
/* Decrypt the device unique data. */
alignas(8) u8 work_buffer[DeviceUniqueDataSizeMax];
ON_SCOPE_EXIT { crypto::ClearMemory(work_buffer, sizeof(work_buffer)); };
{
/* Map and copy in the encrypted data. */
UserPageMapper mapper(data_address);
SMC_R_UNLESS(mapper.Map(), InvalidArgument);
SMC_R_UNLESS(mapper.CopyFromUser(work_buffer, data_address, data_size), InvalidArgument);
SMC_R_UNLESS(mapper.CopyFromUser(access_key_dec, access_key_dec_address, sizeof(access_key_dec)), InvalidArgument);
SMC_R_UNLESS(mapper.CopyFromUser(access_key_enc, access_key_enc_address, sizeof(access_key_enc)), InvalidArgument);
SMC_R_UNLESS(mapper.CopyFromUser(key_source_dec, key_source_dec_address, sizeof(key_source_dec)), InvalidArgument);
SMC_R_UNLESS(mapper.CopyFromUser(key_source_enc, key_source_enc_address, sizeof(key_source_enc)), InvalidArgument);
/* Decrypt the data. */
u8 device_id_high;
{
/* Determine the seal key to use. */
const u8 * const seal_key_source = SealKeySources[SealKey_ReencryptDeviceUniqueData];
if (!DecryptDeviceUniqueData(work_buffer, data_size, std::addressof(device_id_high), seal_key_source, se::AesBlockSize, access_key_dec, sizeof(access_key_dec), key_source_dec, sizeof(key_source_dec), work_buffer, data_size, enforce_device_unique)) {
return SmcResult::InvalidArgument;
}
}
/* Reencrypt the data. */
{
/* Determine the seal key to use. */
const auto seal_key_type = DeviceUniqueDataToSealKey[mode];
const u8 * const seal_key_source = SealKeySources[seal_key_type];
/* Encrypt the data. */
EncryptDeviceUniqueData(work_buffer, data_size, seal_key_source, se::AesBlockSize, access_key_enc, sizeof(access_key_enc), key_source_enc, sizeof(key_source_enc), work_buffer, data_size - DeviceUniqueDataTotalMetaSize, device_id_high);
}
/* Copy the reencrypted data back to user. */
SMC_R_UNLESS(mapper.CopyToUser(data_address, work_buffer, data_size), InvalidArgument);
}
return SmcResult::Success;
}
SmcResult GetSecureDataImpl(SmcArguments &args) {
/* Decode arguments. */
const auto which = static_cast<SecureData>(args.r[1]);
/* Validate arguments/conditions. */
SMC_R_UNLESS(fuse::GetPatchVersion() < fuse::PatchVersion_Odnx02A2, NotSupported);
SMC_R_UNLESS(which < SecureData_Count, NotSupported);
/* Use a temporary buffer. */
u8 secure_data[AesKeySize];
GetSecureDataImpl(secure_data, which, false);
/* Copy out. */
std::memcpy(std::addressof(args.r[1]), secure_data, sizeof(secure_data));
return SmcResult::Success;
}
}
/* Aes functionality. */
SmcResult SmcGenerateAesKek(SmcArguments &args) {
return LockSecurityEngineAndInvoke(args, GenerateAesKekImpl);
}
SmcResult SmcLoadAesKey(SmcArguments &args) {
return LockSecurityEngineAndInvoke(args, LoadAesKeyImpl);
}
SmcResult SmcComputeAes(SmcArguments &args) {
return LockSecurityEngineAndInvokeAsync(args, ComputeAesImpl, GetComputeAesResult);
}
SmcResult SmcGenerateSpecificAesKey(SmcArguments &args) {
return LockSecurityEngineAndInvoke(args, GenerateSpecificAesKeyImpl);
}
SmcResult SmcComputeCmac(SmcArguments &args) {
return LockSecurityEngineAndInvoke(args, ComputeCmacImpl);
}
SmcResult SmcLoadPreparedAesKey(SmcArguments &args) {
return LockSecurityEngineAndInvoke(args, LoadPreparedAesKeyImpl);
}
SmcResult SmcPrepareEsCommonTitleKey(SmcArguments &args) {
return LockSecurityEngineAndInvoke(args, PrepareEsCommonTitleKeyImpl);
}
/* Device unique data functionality. */
SmcResult SmcDecryptDeviceUniqueData(SmcArguments &args) {
return LockSecurityEngineAndInvoke(args, DecryptDeviceUniqueDataImpl);
}
SmcResult SmcReencryptDeviceUniqueData(SmcArguments &args) {
return LockSecurityEngineAndInvoke(args, ReencryptDeviceUniqueDataImpl);
}
/* Legacy APIs. */
SmcResult SmcDecryptAndImportEsDeviceKey(SmcArguments &args) {
return LockSecurityEngineAndInvoke(args, DecryptAndImportEsDeviceKeyImpl);
}
SmcResult SmcDecryptAndImportLotusKey(SmcArguments &args) {
return LockSecurityEngineAndInvoke(args, DecryptAndImportLotusKeyImpl);
}
/* Es encryption utilities. */
void DecryptWithEsCommonKey(void *dst, size_t dst_size, const void *src, size_t src_size, EsCommonKeyType type, int generation) {
/* Validate pre-conditions. */
AMS_ABORT_UNLESS(dst_size == AesKeySize);
AMS_ABORT_UNLESS(src_size == AesKeySize);
AMS_ABORT_UNLESS(0 <= type && type < EsCommonKeyType_Count);
/* Prepare the master key for the generation. */
const int slot = PrepareMasterKey(generation);
/* Derive the es common key. */
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Smc, slot, EsCommonKeySources[type], AesKeySize);
/* Decrypt the input using the common key. */
se::DecryptAes128(dst, dst_size, pkg1::AesKeySlot_Smc, src, src_size);
}
void PrepareEsAesKey(void *dst, size_t dst_size, const void *src, size_t src_size) {
/* Validate pre-conditions. */
AMS_ABORT_UNLESS(dst_size == AesKeySize);
AMS_ABORT_UNLESS(src_size == AesKeySize);
/* Derive the seal key. */
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Smc, pkg1::AesKeySlot_RandomForUserWrap, EsSealKeySource, sizeof(EsSealKeySource));
/* Seal the key. */
se::EncryptAes128(dst, dst_size, pkg1::AesKeySlot_Smc, src, src_size);
}
/* 'Tis the last rose of summer, / Left blooming alone; */
/* Oh! who would inhabit / This bleak world alone? */
SmcResult SmcGetSecureData(SmcArguments &args) {
return LockSecurityEngineAndInvoke(args, GetSecureDataImpl);
}
}

View File

@@ -1,54 +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 <exosphere.hpp>
#include "secmon_smc_common.hpp"
namespace ams::secmon::smc {
enum EsCommonKeyType {
EsCommonKeyType_TitleKey = 0,
EsCommonKeyType_ArchiveKey = 1,
EsCommonKeyType_Unknown2 = 2,
EsCommonKeyType_Count,
};
/* General Aes functionality. */
SmcResult SmcGenerateAesKek(SmcArguments &args);
SmcResult SmcLoadAesKey(SmcArguments &args);
SmcResult SmcComputeAes(SmcArguments &args);
SmcResult SmcGenerateSpecificAesKey(SmcArguments &args);
SmcResult SmcComputeCmac(SmcArguments &args);
SmcResult SmcLoadPreparedAesKey(SmcArguments &args);
SmcResult SmcPrepareEsCommonTitleKey(SmcArguments &args);
/* Device unique data functionality. */
SmcResult SmcDecryptDeviceUniqueData(SmcArguments &args);
SmcResult SmcReencryptDeviceUniqueData(SmcArguments &args);
/* Legacy device unique data functionality. */
SmcResult SmcDecryptAndImportEsDeviceKey(SmcArguments &args);
SmcResult SmcDecryptAndImportLotusKey(SmcArguments &args);
/* Es encryption utilities. */
void DecryptWithEsCommonKey(void *dst, size_t dst_size, const void *src, size_t src_size, EsCommonKeyType type, int generation);
void PrepareEsAesKey(void *dst, size_t dst_size, const void *src, size_t src_size);
/* The last rose of summer. */
SmcResult SmcGetSecureData(SmcArguments &args);
}

View File

@@ -1,41 +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 "../secmon_error.hpp"
#include "../secmon_setup.hpp"
#include "secmon_smc_carveout.hpp"
namespace ams::secmon::smc {
SmcResult SmcSetKernelCarveoutRegion(SmcArguments &args) {
/* Decode arguments. */
const int index = args.r[1];
const uintptr_t address = args.r[2];
const size_t size = args.r[3];
/* Validate arguments. */
SMC_R_UNLESS(0 <= index && index < KernelCarveoutCount, InvalidArgument);
SMC_R_UNLESS(util::IsAligned(address, 128_KB), InvalidArgument);
SMC_R_UNLESS(util::IsAligned(size, 128_KB), InvalidArgument);
SMC_R_UNLESS(size <= CarveoutSizeMax, InvalidArgument);
/* Set the carveout. */
SetKernelCarveoutRegion(index, address, size);
return SmcResult::Success;
}
}

View File

@@ -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 <exosphere.hpp>
#include "secmon_smc_common.hpp"
namespace ams::secmon::smc {
SmcResult SmcSetKernelCarveoutRegion(SmcArguments &args);
}

View File

@@ -1,51 +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 <exosphere.hpp>
namespace ams::secmon::smc {
enum class SmcResult : u32 {
Success = 0,
NotSupported = 1,
InvalidArgument = 2,
Busy = 3,
NoAsyncOperation = 4,
InvalidAsyncOperation = 5,
NotPermitted = 6,
NotInitialized = 7,
PsciSuccess = 0,
PsciNotSupported = static_cast<u32>(-1),
PsciInvalidParameters = static_cast<u32>(-2),
PsciDenied = static_cast<u32>(-3),
PsciAlreadyOn = static_cast<u32>(-4),
};
#define SMC_R_SUCCEEEDED(res) (res == SmcResult::Success)
#define SMC_R_FAILED(res) (res != SmcResult::Success)
#define SMC_R_TRY(res_expr) ({ const auto _tmp_r_try_rc = (res_expr); if (SMC_R_FAILED(_tmp_r_try_rc)) { return _tmp_r_try_rc; } })
#define SMC_R_UNLESS(cond, RES) ({ if (!(cond)) { return SmcResult::RES; }})
struct SmcArguments {
u64 r[8];
};
constexpr inline int SecurityEngineUserInterruptId = 44;
constexpr inline u64 InvalidAsyncKey = 0;
}

View File

@@ -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/>.
*/
/* For some reason GAS doesn't know about it, even with .cpu cortex-a57 */
#define cpuactlr_el1 s3_1_c15_c2_0
#define cpuectlr_el1 s3_1_c15_c2_1
.section .text._ZN3ams6secmon3smc19PivotStackAndInvokeEPvPFvvE, "ax", %progbits
.align 4
.global _ZN3ams6secmon3smc19PivotStackAndInvokeEPvPFvvE
_ZN3ams6secmon3smc19PivotStackAndInvokeEPvPFvvE:
/* Pivot to use the provided stack pointer. */
mov sp, x0
/* Release our lock on the common smc stack. */
mov x19, x1
bl _ZN3ams6secmon25ReleaseCommonSmcStackLockEv
/* Invoke the function with the new stack. */
br x19
.section .text._ZN3ams6secmon3smc16FinalizePowerOffEv, "ax", %progbits
.align 4
.global _ZN3ams6secmon3smc16FinalizePowerOffEv
_ZN3ams6secmon3smc16FinalizePowerOffEv:
/* Disable all caches by clearing sctlr_el1.C. */
mrs x0, sctlr_el1
and x0, x0, #~(1 << 2)
msr sctlr_el1, x0
isb
/* Disable all caches by clearing sctlr_el3.C. */
mrs x0, sctlr_el3
and x0, x0, #~(1 << 2)
msr sctlr_el3, x0
isb
/* Disable prefetching of page table walking descriptors. */
mrs x0, cpuectlr_el1
orr x0, x0, #(1 << 38)
/* Disable prefetching of instructions. */
and x0, x0, #~(3 << 35)
/* Disable prefetching of data. */
and x0, x0, #~(3 << 32)
msr cpuectlr_el1, x0
isb
/* Ensure that all data prefetching prior to our configuration change completes. */
dsb sy
/* Flush the entire data cache (local). */
bl _ZN3ams6secmon25FlushEntireDataCacheLocalEv
/* Disable receiving instruction cache/TLB maintenance operations. */
mrs x0, cpuectlr_el1
and x0, x0, #~(1 << 6)
msr cpuectlr_el1, x0
/* Configure the gic to not send interrupts to the current core. */
ldr x1, =0x1F0043000
mov w0, #0x1E0 /* Set FIQBypDisGrp1, IRQBypDisGrp1, reserved bits 7/8. */
str w0, [x1]
/* Lock the OS Double Lock. */
mrs x0, osdlr_el1
orr x0, x0, #(1 << 0)
msr osdlr_el1, x0
/* Ensure that our configuration takes. */
isb
dsb sy
/* Wait for interrupts, infinitely. */
0:
wfi
b 0b

View File

@@ -1,206 +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 "../secmon_error.hpp"
#include "secmon_smc_device_unique_data.hpp"
namespace ams::secmon::smc {
namespace {
void GenerateIv(void *dst, size_t dst_size) {
/* Flush the region we're about to fill to ensure consistency with the SE. */
hw::FlushDataCache(dst, dst_size);
hw::DataSynchronizationBarrierInnerShareable();
/* Generate random bytes. */
se::GenerateRandomBytes(dst, dst_size);
hw::DataSynchronizationBarrierInnerShareable();
/* Flush to ensure the CPU sees consistent data for the region. */
hw::FlushDataCache(dst, dst_size);
hw::DataSynchronizationBarrierInnerShareable();
}
void PrepareDeviceUniqueDataKey(const void *seal_key_source, size_t seal_key_source_size, const void *access_key, size_t access_key_size, const void *key_source, size_t key_source_size) {
/* Derive the seal key. */
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Smc, pkg1::AesKeySlot_RandomForUserWrap, seal_key_source, seal_key_source_size);
/* Derive the device unique data kek. */
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Smc, pkg1::AesKeySlot_Smc, access_key, access_key_size);
/* Derive the actual device unique data key. */
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Smc, pkg1::AesKeySlot_Smc, key_source, key_source_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) {
/* Ensure that the SE sees consistent data. */
hw::FlushDataCache(src, src_size);
hw::FlushDataCache(dst, dst_size);
hw::DataSynchronizationBarrierInnerShareable();
/* Use the security engine to transform the data. */
se::ComputeAes128Ctr(dst, dst_size, slot, src, src_size, iv, iv_size);
hw::DataSynchronizationBarrierInnerShareable();
/* Ensure the CPU sees consistent data. */
hw::FlushDataCache(dst, dst_size);
hw::DataSynchronizationBarrierInnerShareable();
}
void ComputeGmac(void *dst, size_t dst_size, const void *data, size_t data_size, const void *iv, size_t iv_size) {
/* Declare keyslot (as encryptor will need to take it by pointer/reference). */
constexpr int Slot = pkg1::AesKeySlot_Smc;
/* Calculate the mac. */
crypto::Aes128GcmEncryptor gcm;
gcm.Initialize(std::addressof(Slot), sizeof(Slot), iv, iv_size);
gcm.UpdateAad(data, data_size);
gcm.GetMac(dst, dst_size);
}
constexpr u64 GetDeviceIdLow(u64 device_id) {
/* Mask out the top byte. */
constexpr u64 ByteMask = (static_cast<u64>(1) << BITSIZEOF(u8)) - 1;
constexpr u64 LowMask = ~(ByteMask << (BITSIZEOF(u64) - BITSIZEOF(u8)));
return device_id & LowMask;
}
constexpr u8 GetDeviceIdHigh(u64 device_id) {
/* Get the top byte. */
return static_cast<u8>(device_id >> (BITSIZEOF(u64) - BITSIZEOF(u8)));
}
constexpr u64 EncodeDeviceId(u8 device_id_high, u64 device_id_low) {
return (static_cast<u64>(device_id_high) << (BITSIZEOF(u64) - BITSIZEOF(u8))) | device_id_low;
}
}
bool DecryptDeviceUniqueData(void *dst, size_t dst_size, u8 *out_device_id_high, const void *seal_key_source, size_t seal_key_source_size, const void *access_key, size_t access_key_size, const void *key_source, size_t key_source_size, const void *src, size_t src_size, bool enforce_device_unique) {
/* Determine how much decrypted data there will be. */
const size_t enc_size = src_size - (enforce_device_unique ? DeviceUniqueDataOuterMetaSize : DeviceUniqueDataIvSize);
const size_t dec_size = enc_size - DeviceUniqueDataInnerMetaSize;
/* Ensure that our sizes are allowed. */
AMS_ABORT_UNLESS(src_size > (enforce_device_unique ? DeviceUniqueDataTotalMetaSize : DeviceUniqueDataIvSize));
AMS_ABORT_UNLESS(dst_size >= enc_size);
/* Determine the extents of the data. */
const u8 * const iv = static_cast<const u8 *>(src);
const u8 * const enc = iv + DeviceUniqueDataIvSize;
const u8 * const mac = enc + enc_size;
/* Decrypt the data. */
{
/* Declare temporaries. */
u8 temp_iv[DeviceUniqueDataIvSize];
u8 calc_mac[DeviceUniqueDataMacSize];
ON_SCOPE_EXIT { crypto::ClearMemory(temp_iv, sizeof(temp_iv)); crypto::ClearMemory(calc_mac, sizeof(calc_mac)); };
/* Prepare the key used to decrypt the data. */
PrepareDeviceUniqueDataKey(seal_key_source, seal_key_source_size, access_key, access_key_size, key_source, key_source_size);
/* Copy the iv to stack. */
std::memcpy(temp_iv, iv, sizeof(temp_iv));
/* Decrypt the data. */
ComputeAes128Ctr(dst, dst_size, pkg1::AesKeySlot_Smc, enc, enc_size, temp_iv, DeviceUniqueDataIvSize);
/* If we're not enforcing device unique, there's no mac/device id. */
if (!enforce_device_unique) {
return true;
}
/* Compute the gmac. */
ComputeGmac(calc_mac, DeviceUniqueDataMacSize, dst, enc_size, temp_iv, DeviceUniqueDataIvSize);
/* Validate the gmac. */
if (!crypto::IsSameBytes(mac, calc_mac, sizeof(calc_mac))) {
return false;
}
}
/* Validate device id, output device id if needed. */
{
/* Locate the device id in the decryption output. */
const u8 * const padding = static_cast<const u8 *>(dst) + dec_size;
const u8 * const device_id = padding + DeviceUniqueDataPaddingSize;
/* Load the big endian device id. */
const u64 device_id_val = util::LoadBigEndian(static_cast<const u64 *>(static_cast<const void *>(device_id)));
/* Validate that the device id low matches the value in fuses. */
if (GetDeviceIdLow(device_id_val) != fuse::GetDeviceId()) {
return false;
}
/* Set the output device id high, if needed. */
if (out_device_id_high != nullptr) {
*out_device_id_high = GetDeviceIdHigh(device_id_val);
}
}
return true;
}
void EncryptDeviceUniqueData(void *dst, size_t dst_size, const void *seal_key_source, size_t seal_key_source_size, const void *access_key, size_t access_key_size, const void *key_source, size_t key_source_size, const void *src, size_t src_size, u8 device_id_high) {
/* Determine metadata locations. */
u8 * const dst_iv = static_cast<u8 *>(dst);
u8 * const dst_data = dst_iv + DeviceUniqueDataIvSize;
u8 * const dst_pad = dst_data + src_size;
u8 * const dst_did = dst_pad + DeviceUniqueDataPaddingSize;
u8 * const dst_mac = dst_did + DeviceUniqueDataDeviceIdSize;
/* Verify that our sizes are okay. */
const size_t enc_size = src_size + DeviceUniqueDataInnerMetaSize;
const size_t res_size = src_size + DeviceUniqueDataTotalMetaSize;
AMS_ABORT_UNLESS(res_size <= dst_size);
/* Layout the image as expected. */
{
/* Generate a random iv. */
util::AlignedBuffer<hw::DataCacheLineSize, DeviceUniqueDataIvSize> iv;
GenerateIv(iv, DeviceUniqueDataIvSize);
/* Move the data to the output image. */
std::memmove(dst_data, src, src_size);
/* Copy the iv. */
std::memcpy(dst_iv, iv, DeviceUniqueDataIvSize);
/* Clear the padding. */
std::memset(dst_pad, 0, DeviceUniqueDataPaddingSize);
/* Store the device id. */
util::StoreBigEndian(reinterpret_cast<u64 *>(dst_did), EncodeDeviceId(device_id_high, fuse::GetDeviceId()));
}
/* Encrypt and mac. */
{
/* Prepare the key used to encrypt the data. */
PrepareDeviceUniqueDataKey(seal_key_source, seal_key_source_size, access_key, access_key_size, key_source, key_source_size);
/* Compute the gmac. */
ComputeGmac(dst_mac, DeviceUniqueDataMacSize, dst_data, enc_size, dst_iv, DeviceUniqueDataIvSize);
/* Encrypt the data. */
ComputeAes128Ctr(dst_data, enc_size, pkg1::AesKeySlot_Smc, dst_data, enc_size, dst_iv, DeviceUniqueDataIvSize);
}
}
}

View File

@@ -1,34 +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 <exosphere.hpp>
#include "secmon_smc_common.hpp"
namespace ams::secmon::smc {
constexpr inline size_t DeviceUniqueDataIvSize = se::AesBlockSize;
constexpr inline size_t DeviceUniqueDataMacSize = se::AesBlockSize;
constexpr inline size_t DeviceUniqueDataDeviceIdSize = sizeof(u64);
constexpr inline size_t DeviceUniqueDataPaddingSize = se::AesBlockSize - DeviceUniqueDataDeviceIdSize;
constexpr inline size_t DeviceUniqueDataOuterMetaSize = DeviceUniqueDataIvSize + DeviceUniqueDataMacSize;
constexpr inline size_t DeviceUniqueDataInnerMetaSize = DeviceUniqueDataPaddingSize + DeviceUniqueDataDeviceIdSize;
constexpr inline size_t DeviceUniqueDataTotalMetaSize = DeviceUniqueDataOuterMetaSize + DeviceUniqueDataInnerMetaSize;
bool DecryptDeviceUniqueData(void *dst, size_t dst_size, u8 *out_device_id_high, const void *seal_key_source, size_t seal_key_source_size, const void *access_key, size_t access_key_size, const void *key_source, size_t key_source_size, const void *src, size_t src_size, bool enforce_device_unique);
void EncryptDeviceUniqueData(void *dst, size_t dst_size, const void *seal_key_source, size_t seal_key_source_size, const void *access_key, size_t access_key_size, const void *key_source, size_t key_source_size, const void *src, size_t src_size, u8 device_id_high);
}

View File

@@ -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>
#include "../secmon_error.hpp"
#include "secmon_smc_error.hpp"
namespace ams::secmon::smc {
SmcResult SmcShowError(SmcArguments &args) {
/* Decode arguments. */
const u32 r = ((args.r[1] >> 8) & 0xF);
const u32 g = ((args.r[1] >> 4) & 0xF);
const u32 b = ((args.r[1] >> 0) & 0xF);
const u32 rgb = (b << 8) | (g << 4) | (r << 0);
/* Set the error info. */
SetError(pkg1::MakeKernelPanicResetInfo(rgb));
/* Reboot. */
ErrorReboot();
/* This point will never be reached. */
__builtin_unreachable();
}
}

View File

@@ -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 <exosphere.hpp>
#include "secmon_smc_common.hpp"
namespace ams::secmon::smc {
SmcResult SmcShowError(SmcArguments &args);
}

View File

@@ -1,267 +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 "../secmon_error.hpp"
#include "../secmon_misc.hpp"
#include "secmon_smc_common.hpp"
#include "secmon_smc_handler.hpp"
#include "secmon_smc_aes.hpp"
#include "secmon_smc_carveout.hpp"
#include "secmon_smc_device_unique_data.hpp"
#include "secmon_smc_error.hpp"
#include "secmon_smc_info.hpp"
#include "secmon_smc_memory_access.hpp"
#include "secmon_smc_power_management.hpp"
#include "secmon_smc_random.hpp"
#include "secmon_smc_register_access.hpp"
#include "secmon_smc_result.hpp"
#include "secmon_smc_rsa.hpp"
namespace ams::secmon::smc {
namespace {
struct HandlerInfo {
u32 function_id;
u32 restriction_mask;
SmcHandler handler;
};
struct HandlerTable {
const HandlerInfo *entries;
size_t count;
};
enum HandlerType : int {
HandlerType_User = 0,
HandlerType_Kern = 1,
HandlerType_Count = 2,
};
enum Restriction {
Restriction_None = (0 << 0),
Restriction_Normal = (1 << 0),
Restriction_DeviceUniqueDataNotAllowed = (1 << 1),
Restriction_SafeModeNotAllowed = (1 << 2),
};
enum SmcCallRange {
SmcCallRange_ArmArch = 0,
SmcCallRange_Cpu = 1,
SmcCallRange_Sip = 2,
SmcCallRange_Oem = 3,
SmcCallRange_Standard = 4,
SmcCallRange_TrustedApp = 0x30,
};
enum SmcArgumentType {
ArgumentType_Integer = 0,
ArgumentType_Pointer = 1,
};
enum SmcConvention {
Convention_Smc32 = 0,
Convention_Smc64 = 1,
};
enum SmcCallType {
SmcCallType_YieldingCall = 0,
SmcCallType_FastCall = 1,
};
struct SmcFunctionId {
using FunctionId = util::BitPack64::Field< 0, 8, u32>;
using ArgumentType0 = util::BitPack64::Field< 8, 1, SmcArgumentType>;
using ArgumentType1 = util::BitPack64::Field< 9, 1, SmcArgumentType>;
using ArgumentType2 = util::BitPack64::Field<10, 1, SmcArgumentType>;
using ArgumentType3 = util::BitPack64::Field<11, 1, SmcArgumentType>;
using ArgumentType4 = util::BitPack64::Field<12, 1, SmcArgumentType>;
using ArgumentType5 = util::BitPack64::Field<13, 1, SmcArgumentType>;
using ArgumentType6 = util::BitPack64::Field<14, 1, SmcArgumentType>;
using ArgumentType7 = util::BitPack64::Field<15, 1, SmcArgumentType>;
using Reserved = util::BitPack64::Field<16, 8, u32>;
using CallRange = util::BitPack64::Field<24, 6, SmcCallRange>;
using Convention = util::BitPack64::Field<30, 1, SmcConvention>;
using CallType = util::BitPack64::Field<31, 1, SmcCallType>;
using Reserved2 = util::BitPack64::Field<32, 32, u32>;
};
constinit HandlerInfo g_user_handlers[] = {
{ 0x00000000, Restriction_SafeModeNotAllowed, nullptr },
{ 0xC3000401, Restriction_SafeModeNotAllowed, SmcSetConfig },
{ 0xC3000002, Restriction_Normal, SmcGetConfigUser },
{ 0xC3000003, Restriction_Normal, SmcGetResult },
{ 0xC3000404, Restriction_Normal, SmcGetResultData },
{ 0xC3000E05, Restriction_SafeModeNotAllowed, SmcModularExponentiate },
{ 0xC3000006, Restriction_Normal, SmcGenerateRandomBytes },
{ 0xC3000007, Restriction_Normal, SmcGenerateAesKek },
{ 0xC3000008, Restriction_Normal, SmcLoadAesKey },
{ 0xC3000009, Restriction_Normal, SmcComputeAes },
{ 0xC300000A, Restriction_Normal, SmcGenerateSpecificAesKey },
{ 0xC300040B, Restriction_Normal, SmcComputeCmac },
{ 0xC300D60C, Restriction_Normal, SmcReencryptDeviceUniqueData },
{ 0xC300100D, Restriction_DeviceUniqueDataNotAllowed, SmcDecryptDeviceUniqueData },
{ 0xC300000E, Restriction_SafeModeNotAllowed, nullptr },
{ 0xC300060F, Restriction_DeviceUniqueDataNotAllowed, SmcModularExponentiateByStorageKey },
{ 0xC3000610, Restriction_SafeModeNotAllowed, SmcPrepareEsDeviceUniqueKey },
{ 0xC3000011, Restriction_SafeModeNotAllowed, SmcLoadPreparedAesKey },
{ 0xC3000012, Restriction_SafeModeNotAllowed, SmcPrepareEsCommonTitleKey }
};
/* Deprecated handlerss. */
constexpr inline const HandlerInfo DecryptAndImportEsDeviceKeyHandlerInfo = {
0xC300100C, Restriction_Normal, SmcDecryptAndImportEsDeviceKey
};
constexpr inline const HandlerInfo DecryptAndImportLotusKeyHandlerInfo = {
0xC300100E, Restriction_SafeModeNotAllowed, SmcDecryptAndImportLotusKey
};
constinit HandlerInfo g_kern_handlers[] = {
{ 0x00000000, Restriction_SafeModeNotAllowed, nullptr },
{ 0xC4000001, Restriction_SafeModeNotAllowed, SmcSuspendCpu },
{ 0x84000002, Restriction_SafeModeNotAllowed, SmcPowerOffCpu },
{ 0xC4000003, Restriction_SafeModeNotAllowed, SmcPowerOnCpu },
{ 0xC3000004, Restriction_Normal, SmcGetConfigKern },
{ 0xC3000005, Restriction_Normal, SmcGenerateRandomBytesNonBlocking },
{ 0xC3000006, Restriction_Normal, SmcShowError },
{ 0xC3000007, Restriction_Normal, SmcSetKernelCarveoutRegion },
{ 0xC3000008, Restriction_Normal, SmcReadWriteRegister },
/* NOTE: Atmosphere extension for mesosphere. This ID is subject to change at any time. */
{ 0xC3000409, Restriction_Normal, SmcSetConfig },
};
constinit HandlerInfo g_ams_handlers[] = {
{ 0x00000000, Restriction_SafeModeNotAllowed, nullptr },
{ 0xF0000201, Restriction_None, SmcIramCopy },
{ 0xF0000002, Restriction_None, SmcReadWriteRegister },
{ 0xF0000003, Restriction_None, SmcWriteAddress },
{ 0xF0000404, Restriction_None, SmcGetEmummcConfig },
};
constexpr const HandlerInfo GetSecureDataHandlerInfo = {
0x67891234, Restriction_None, SmcGetSecureData
};
constinit HandlerTable g_handler_tables[] = {
{ g_user_handlers, util::size(g_user_handlers) },
{ g_kern_handlers, util::size(g_kern_handlers) },
};
constinit HandlerTable g_ams_handler_table = {
g_ams_handlers, util::size(g_ams_handlers)
};
NORETURN void InvalidSmcError(u64 id) {
SetError(pkg1::ErrorInfo_UnknownSmc);
AMS_ABORT("Invalid SMC: %lx", id);
}
const HandlerTable &GetHandlerTable(HandlerType type, u64 id) {
/* Ensure we have a valid handler type. */
if (AMS_UNLIKELY(!(0 <= type && type < HandlerType_Count))) {
InvalidSmcError(id);
}
/* Provide support for legacy SmcGetSecureData. */
if (id == GetSecureDataHandlerInfo.function_id) {
return g_handler_tables[HandlerType_User];
}
/* Check if we're a user SMC. */
if (type == HandlerType_User) {
/* Nintendo uses OEM SMCs. */
/* We will assign Atmosphere extension SMCs the TrustedApplication range. */
if (util::BitPack64{id}.Get<SmcFunctionId::CallRange>() == SmcCallRange_TrustedApp) {
return g_ams_handler_table;
}
/* If we're not performing an atmosphere extension smc, require that we're being invoked by spl on core 3. */
if (AMS_UNLIKELY(hw::GetCurrentCoreId() != 3)) {
InvalidSmcError(id);
}
}
return g_handler_tables[type];
}
const HandlerInfo &GetHandlerInfo(const HandlerTable &table, u64 id) {
/* Provide support for legacy SmcGetSecureData. */
if (id == GetSecureDataHandlerInfo.function_id) {
return GetSecureDataHandlerInfo;
}
/* Get and check the index. */
const auto index = util::BitPack64{id}.Get<SmcFunctionId::FunctionId>();
if (AMS_UNLIKELY(index >= table.count)) {
InvalidSmcError(id);
}
/* Get and check the handler info. */
const auto &handler_info = table.entries[index];
/* Check that the handler isn't null. */
if (AMS_UNLIKELY(handler_info.handler == nullptr)) {
InvalidSmcError(id);
}
/* Check that the handler's id matches. */
if (AMS_UNLIKELY(handler_info.function_id != id)) {
InvalidSmcError(id);
}
return handler_info;
}
bool IsHandlerRestricted(const HandlerInfo &info) {
return (info.restriction_mask & secmon::GetRestrictedSmcMask()) != 0;
}
SmcResult InvokeSmcHandler(const HandlerInfo &info, SmcArguments &args) {
/* Check if the smc is restricted. */
if (GetTargetFirmware() >= TargetFirmware_8_0_0 && AMS_UNLIKELY(IsHandlerRestricted(info))) {
return SmcResult::NotPermitted;
}
/* Invoke the smc. */
return info.handler(args);
}
}
void ConfigureSmcHandlersForTargetFirmware() {
const auto target_fw = GetTargetFirmware();
if (target_fw < TargetFirmware_5_0_0) {
g_user_handlers[DecryptAndImportEsDeviceKeyHandlerInfo.function_id & 0xFF] = DecryptAndImportEsDeviceKeyHandlerInfo;
g_user_handlers[DecryptAndImportLotusKeyHandlerInfo.function_id & 0xFF] = DecryptAndImportLotusKeyHandlerInfo;
}
}
void HandleSmc(int type, SmcArguments &args) {
/* Get the table. */
const auto &table = GetHandlerTable(static_cast<HandlerType>(type), args.r[0]);
/* Get the handler info. */
const auto &info = GetHandlerInfo(table, args.r[0]);
/* Set the invocation result. */
args.r[0] = static_cast<u64>(InvokeSmcHandler(info, args));
}
}

View File

@@ -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 <exosphere.hpp>
#include "secmon_smc_common.hpp"
namespace ams::secmon::smc {
using SmcHandler = SmcResult (*)(SmcArguments &args);
void ConfigureSmcHandlersForTargetFirmware();
}

View File

@@ -1,479 +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 "../secmon_error.hpp"
#include "../secmon_map.hpp"
#include "../secmon_misc.hpp"
#include "../secmon_page_mapper.hpp"
#include "../secmon_user_power_management.hpp"
#include "secmon_smc_info.hpp"
#include "secmon_smc_power_management.hpp"
namespace ams::secmon::smc {
namespace {
struct KernelConfiguration {
/* Secure Monitor view. */
using Flags1 = util::BitPack32::Field< 0, 8>;
using Flags0 = util::BitPack32::Field< 8, 8>;
using PhysicalMemorySize = util::BitPack32::Field<16, 2>;
/* Kernel view, from libmesosphere. */
using DebugFillMemory = util::BitPack32::Field<0, 1, bool>;
using EnableUserExceptionHandlers = util::BitPack32::Field<DebugFillMemory::Next, 1, bool>;
using EnableUserPmuAccess = util::BitPack32::Field<EnableUserExceptionHandlers::Next, 1, bool>;
using IncreaseThreadResourceLimit = util::BitPack32::Field<EnableUserPmuAccess::Next, 1, bool>;
using DisableDynamicResourceLimits = util::BitPack32::Field<IncreaseThreadResourceLimit::Next, 1, bool>;
using Reserved5 = util::BitPack32::Field<DisableDynamicResourceLimits::Next, 3, u32>;
using UseSecureMonitorPanicCall = util::BitPack32::Field<Reserved5::Next, 1, bool>;
using Reserved9 = util::BitPack32::Field<UseSecureMonitorPanicCall::Next, 7, u32>;
using MemorySize = util::BitPack32::Field<Reserved9::Next, 2, u32>; /* smc::MemorySize = pkg1::MemorySize */
};
constexpr const pkg1::MemorySize DramIdToMemorySize[fuse::DramId_Count] = {
[fuse::DramId_IcosaSamsung4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_IcosaHynix4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_IcosaMicron4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_IowaHynix1y4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_IcosaSamsung6GB] = pkg1::MemorySize_6GB,
[fuse::DramId_HoagHynix1y4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_AulaHynix1y4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_Deprecated7] = pkg1::MemorySize_4GB,
[fuse::DramId_IowaSansung4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_IowaSamsung8GB] = pkg1::MemorySize_8GB,
[fuse::DramId_IowaHynix4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_IowaMicron4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_HoagSamsung4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_HoagSamsung8GB] = pkg1::MemorySize_8GB,
[fuse::DramId_HoagHynix4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_HoagMicron4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_Deprecated16] = pkg1::MemorySize_4GB,
[fuse::DramId_IowaSamsung1y4GBX] = pkg1::MemorySize_4GB,
[fuse::DramId_IowaSamsung1y8GBX] = pkg1::MemorySize_8GB,
[fuse::DramId_HoagSamsung1y4GBX] = pkg1::MemorySize_4GB,
[fuse::DramId_IowaSamsung1z4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_HoagSamsung1z4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_AulaSamsung1z4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_HoagSamsung1y8GBX] = pkg1::MemorySize_8GB,
[fuse::DramId_AulaSamsung1y4GBX] = pkg1::MemorySize_4GB,
[fuse::DramId_IowaMicron1y4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_HoagMicron1y4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_AulaMicron1y4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_AulaSamsung1y8GBX] = pkg1::MemorySize_8GB,
[fuse::DramId_IowaX1X2Samsung4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_HoagX1X2Samsung4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_AulaX1X2Samsung4GB] = pkg1::MemorySize_4GB,
[fuse::DramId_IowaSamsung4GBY] = pkg1::MemorySize_4GB,
[fuse::DramId_HoagSamsung4GBY] = pkg1::MemorySize_4GB,
[fuse::DramId_AulaSamsung4GBY] = pkg1::MemorySize_4GB,
};
constexpr const pkg1::MemoryMode MemoryModes[] = {
pkg1::MemoryMode_Auto,
pkg1::MemoryMode_4GB,
pkg1::MemoryMode_4GBAppletDev,
pkg1::MemoryMode_4GBSystemDev,
pkg1::MemoryMode_6GB,
pkg1::MemoryMode_6GBAppletDev,
pkg1::MemoryMode_8GB,
};
constexpr bool IsValidMemoryMode(pkg1::MemoryMode mode) {
for (const auto known_mode : MemoryModes) {
if (mode == known_mode) {
return true;
}
}
return false;
}
pkg1::MemoryMode SanitizeMemoryMode(pkg1::MemoryMode mode) {
if (IsValidMemoryMode(mode)) {
return mode;
}
return pkg1::MemoryMode_Auto;
}
pkg1::MemorySize GetAvailableMemorySize(pkg1::MemorySize size) {
return std::min(GetPhysicalMemorySize(), size);
}
pkg1::MemoryMode GetMemoryMode(pkg1::MemoryMode mode) {
/* Sanitize the mode. */
mode = SanitizeMemoryMode(mode);
/* If the mode is auto, construct the memory mode. */
if (mode == pkg1::MemoryMode_Auto) {
return pkg1::MakeMemoryMode(GetPhysicalMemorySize(), pkg1::MemoryArrange_Normal);
} else {
const auto mode_size = GetMemorySize(mode);
const auto mode_arrange = GetMemoryArrange(mode);
const auto size = GetAvailableMemorySize(mode_size);
const auto arrange = (size == mode_size) ? mode_arrange : pkg1::MemoryArrange_Normal;
return pkg1::MakeMemoryMode(size, arrange);
}
}
u32 GetMemoryMode() {
/* Unless development function is enabled, we're 4 GB. */
u32 memory_mode = pkg1::MemoryMode_4GB;
if (const auto &bcd = GetBootConfig().data; bcd.IsDevelopmentFunctionEnabled()) {
memory_mode = GetMemoryMode(bcd.GetMemoryMode());
}
return memory_mode;
}
u32 GetKernelConfiguration() {
pkg1::MemorySize memory_size = pkg1::MemorySize_4GB;
util::BitPack32 value = {};
if (const auto &bcd = GetBootConfig().data; bcd.IsDevelopmentFunctionEnabled()) {
memory_size = GetMemorySize(GetMemoryMode(bcd.GetMemoryMode()));
value.Set<KernelConfiguration::Flags1>(bcd.GetKernelFlags1());
value.Set<KernelConfiguration::Flags0>(bcd.GetKernelFlags0());
}
value.Set<KernelConfiguration::PhysicalMemorySize>(memory_size);
/* Exosphere extensions. */
const auto &sc = GetSecmonConfiguration();
if (!sc.DisableUserModeExceptionHandlers()) {
value.Set<KernelConfiguration::EnableUserExceptionHandlers>(true);
}
if (sc.EnableUserModePerformanceCounterAccess()) {
value.Set<KernelConfiguration::EnableUserPmuAccess>(true);
}
return value.value;
}
constinit u64 g_payload_address = 0;
constinit bool g_set_true_target_firmware = false;
SmcResult GetConfig(SmcArguments &args, bool kern) {
switch (static_cast<ConfigItem>(args.r[1])) {
case ConfigItem::DisableProgramVerification:
args.r[1] = GetBootConfig().signed_data.IsProgramVerificationDisabled();
break;
case ConfigItem::DramId:
args.r[1] = fuse::GetDramId();
break;
case ConfigItem::SecurityEngineInterruptNumber:
args.r[1] = SecurityEngineUserInterruptId;
break;
case ConfigItem::FuseVersion:
args.r[1] = fuse::GetExpectedFuseVersion(GetTargetFirmware());
break;
case ConfigItem::HardwareType:
args.r[1] = fuse::GetHardwareType();
break;
case ConfigItem::HardwareState:
args.r[1] = fuse::GetHardwareState();
break;
case ConfigItem::IsRecoveryBoot:
args.r[1] = IsRecoveryBoot();
break;
case ConfigItem::DeviceId:
args.r[1] = fuse::GetDeviceId();
break;
case ConfigItem::BootReason:
{
/* This was removed in firmware 4.0.0. */
if (GetTargetFirmware() >= TargetFirmware_4_0_0) {
return SmcResult::InvalidArgument;
}
args.r[1] = GetDeprecatedBootReason();
}
break;
case ConfigItem::MemoryMode:
args.r[1] = GetMemoryMode();
break;
case ConfigItem::IsDevelopmentFunctionEnabled:
args.r[1] = GetSecmonConfiguration().IsDevelopmentFunctionEnabled(kern) || GetBootConfig().data.IsDevelopmentFunctionEnabled();
break;
case ConfigItem::KernelConfiguration:
args.r[1] = GetKernelConfiguration();
break;
case ConfigItem::IsChargerHiZModeEnabled:
args.r[1] = IsChargerHiZModeEnabled();
break;
case ConfigItem::RetailInteractiveDisplayState:
args.r[1] = fuse::GetRetailInteractiveDisplayState();
break;
case ConfigItem::RegulatorType:
args.r[1] = fuse::GetRegulator();
break;
case ConfigItem::DeviceUniqueKeyGeneration:
args.r[1] = fuse::GetDeviceUniqueKeyGeneration();
break;
case ConfigItem::Package2Hash:
{
/* Only allow getting the package2 hash in recovery boot. */
if (!IsRecoveryBoot()) {
return SmcResult::InvalidArgument;
}
/* Get the hash. */
se::Sha256Hash tmp_hash;
GetPackage2Hash(std::addressof(tmp_hash));
/* Copy it out. */
static_assert(sizeof(args) - sizeof(args.r[0]) >= sizeof(tmp_hash));
std::memcpy(std::addressof(args.r[1]), std::addressof(tmp_hash), sizeof(tmp_hash));
}
break;
case ConfigItem::ExosphereApiVersion:
/* Get information about the current exosphere version. */
if (kern || g_set_true_target_firmware) {
args.r[1] = (static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MAJOR & 0xFF) << 56) |
(static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MINOR & 0xFF) << 48) |
(static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MICRO & 0xFF) << 40) |
(static_cast<u64>(GetKeyGeneration()) << 32) |
(static_cast<u64>(GetTargetFirmware()) << 0);
} else {
return SmcResult::NotInitialized;
}
break;
case ConfigItem::ExosphereNeedsReboot:
/* We are executing, so we aren't in the process of rebooting. */
args.r[1] = 0;
break;
case ConfigItem::ExosphereNeedsShutdown:
/* We are executing, so we aren't in the process of shutting down. */
args.r[1] = 0;
break;
case ConfigItem::ExosphereGitCommitHash:
/* Get information about the current exosphere git commit hash. */
args.r[1] = ATMOSPHERE_GIT_HASH;
break;
case ConfigItem::ExosphereHasRcmBugPatch:
/* Get information about whether this unit has the RCM bug patched. */
args.r[1] = fuse::HasRcmVulnerabilityPatch();
break;
case ConfigItem::ExosphereBlankProdInfo:
/* Get whether this unit should simulate a "blanked" PRODINFO. */
args.r[1] = GetSecmonConfiguration().ShouldUseBlankCalibrationBinary();
break;
case ConfigItem::ExosphereAllowCalWrites:
/* Get whether this unit should allow writing to the calibration partition. */
args.r[1] = (GetEmummcConfiguration().IsEmummcActive() || GetSecmonConfiguration().AllowWritingToCalibrationBinarySysmmc());
break;
case ConfigItem::ExosphereEmummcType:
/* Get what kind of emummc this unit has active. */
/* NOTE: This may return values other than 1 in the future. */
args.r[1] = (GetEmummcConfiguration().IsEmummcActive() ? 1 : 0);
break;
case ConfigItem::ExospherePayloadAddress:
/* Gets the physical address of the reboot payload buffer, if one exists. */
if (g_payload_address != 0) {
args.r[1] = g_payload_address;
} else {
return SmcResult::NotInitialized;
}
break;
case ConfigItem::ExosphereLogConfiguration:
/* Get the log configuration. */
args.r[1] = (static_cast<u64>(static_cast<u8>(secmon::GetLogPort())) << 32) | static_cast<u64>(secmon::GetLogBaudRate());
break;
case ConfigItem::ExosphereForceEnableUsb30:
/* Get whether usb 3.0 should be force-enabled. */
args.r[1] = GetSecmonConfiguration().IsUsb30ForceEnabled();
break;
case ConfigItem::ExosphereSupportedHosVersion:
/* Get information about the supported hos version. */
args.r[1] = (static_cast<u64>(ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR & 0xFF) << 24) |
(static_cast<u64>(ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR & 0xFF) << 16) |
(static_cast<u64>(ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO & 0xFF) << 8);
break;
case ConfigItem::ExosphereApproximateApiVersion:
/* Get information about the current exosphere version. */
if (!g_set_true_target_firmware) {
args.r[1] = (static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MAJOR & 0xFF) << 56) |
(static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MINOR & 0xFF) << 48) |
(static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MICRO & 0xFF) << 40) |
(static_cast<u64>(GetKeyGeneration()) << 32) |
(static_cast<u64>(GetTargetFirmware()) << 0);
} else {
return SmcResult::Busy;
}
break;
default:
return SmcResult::InvalidArgument;
}
return SmcResult::Success;
}
SmcResult SetConfig(SmcArguments &args) {
const auto soc_type = GetSocType();
switch (static_cast<ConfigItem>(args.r[1])) {
case ConfigItem::IsChargerHiZModeEnabled:
/* Configure the HiZ mode. */
SetChargerHiZModeEnabled(static_cast<bool>(args.r[3]));
break;
case ConfigItem::ExosphereApiVersion:
if (!g_set_true_target_firmware) {
::ams::secmon::impl::SetTargetFirmware(static_cast<ams::TargetFirmware>(args.r[3] & 0xFFFFFFFF));
g_set_true_target_firmware = true;
} else {
return SmcResult::Busy;
}
break;
case ConfigItem::ExosphereNeedsReboot:
if (soc_type == fuse::SocType_Erista) {
switch (static_cast<UserRebootType>(args.r[3])) {
case UserRebootType_None:
break;
case UserRebootType_ToRcm:
PerformUserRebootToRcm();
break;
case UserRebootType_ToPayload:
PerformUserRebootToPayload();
break;
case UserRebootType_ToFatalError:
PerformUserRebootToFatalError();
break;
case UserRebootType_ByPmic:
PerformUserRebootByPmic();
break;
default:
return SmcResult::InvalidArgument;
}
} else /* if (soc_type == fuse::SocType_Mariko) */ {
switch (static_cast<UserRebootType>(args.r[3])) {
case UserRebootType_ToFatalError:
PerformUserRebootToFatalError();
break;
case UserRebootType_ByPmic:
PerformUserRebootByPmic();
break;
default:
return SmcResult::InvalidArgument;
}
}
break;
case ConfigItem::ExosphereNeedsShutdown:
if (args.r[3] != 0) {
PerformUserShutDown();
}
break;
case ConfigItem::ExospherePayloadAddress:
if (g_payload_address == 0) {
if (secmon::IsPhysicalMemoryAddress(args.r[2])) {
g_payload_address = args.r[2];
} else {
return SmcResult::InvalidArgument;
}
} else {
return SmcResult::Busy;
}
break;
default:
return SmcResult::InvalidArgument;
}
return SmcResult::Success;
}
}
SmcResult SmcGetConfigUser(SmcArguments &args) {
return GetConfig(args, false);
}
SmcResult SmcGetConfigKern(SmcArguments &args) {
return GetConfig(args, true);
}
SmcResult SmcSetConfig(SmcArguments &args) {
return SetConfig(args);
}
/* This is an atmosphere extension smc. */
SmcResult SmcGetEmummcConfig(SmcArguments &args) {
/* Decode arguments. */
const auto mmc = static_cast<EmummcMmc>(args.r[1]);
const uintptr_t user_address = args.r[2];
const uintptr_t user_offset = user_address % 4_KB;
/* Validate arguments. */
/* NOTE: In the future, configuration for non-NAND storage may be implemented. */
SMC_R_UNLESS(mmc == EmummcMmc_Nand, NotSupported);
SMC_R_UNLESS(user_offset + 2 * sizeof(EmummcFilePath) <= 4_KB, InvalidArgument);
/* Get the emummc config. */
const auto &cfg = GetEmummcConfiguration();
static_assert(sizeof(cfg.file_cfg) == sizeof(EmummcFilePath));
static_assert(sizeof(cfg.emu_dir_path) == sizeof(EmummcFilePath));
/* Clear the output. */
constexpr size_t InlineOutputSize = sizeof(args) - sizeof(args.r[0]);
u8 * const inline_output = static_cast<u8 *>(static_cast<void *>(std::addressof(args.r[1])));
std::memset(inline_output, 0, InlineOutputSize);
/* Copy out the configuration. */
{
/* Map the user output page. */
AtmosphereUserPageMapper mapper(user_address);
SMC_R_UNLESS(mapper.Map(), InvalidArgument);
/* Copy the base configuration. */
static_assert(sizeof(cfg.base_cfg) <= InlineOutputSize);
std::memcpy(inline_output, std::addressof(cfg.base_cfg), sizeof(cfg.base_cfg));
/* Copy out type-specific data. */
switch (cfg.base_cfg.type) {
case EmummcType_None:
/* No additional configuration needs to be copied. */
break;
case EmummcType_Partition:
/* Copy the partition config. */
static_assert(sizeof(cfg.base_cfg) + sizeof(cfg.partition_cfg) <= InlineOutputSize);
std::memcpy(inline_output + sizeof(cfg.base_cfg), std::addressof(cfg.partition_cfg), sizeof(cfg.partition_cfg));
break;
case EmummcType_File:
/* Copy the file config. */
SMC_R_UNLESS(mapper.CopyToUser(user_address, std::addressof(cfg.file_cfg), sizeof(cfg.file_cfg)), InvalidArgument);
break;
AMS_UNREACHABLE_DEFAULT_CASE();
}
/* Copy the redirection directory path to the user page. */
SMC_R_UNLESS(mapper.CopyToUser(user_address + sizeof(EmummcFilePath), std::addressof(cfg.emu_dir_path), sizeof(cfg.emu_dir_path)), InvalidArgument);
}
return SmcResult::Success;
}
/* For exosphere's usage. */
pkg1::MemorySize GetPhysicalMemorySize() {
const auto dram_id = fuse::GetDramId();
AMS_ABORT_UNLESS(dram_id < fuse::DramId_Count);
return DramIdToMemorySize[dram_id];
}
}

View File

@@ -1,68 +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 <exosphere.hpp>
#include "secmon_smc_common.hpp"
namespace ams::secmon::smc {
enum class ConfigItem : u32 {
/* Standard config items. */
DisableProgramVerification = 1,
DramId = 2,
SecurityEngineInterruptNumber = 3,
FuseVersion = 4,
HardwareType = 5,
HardwareState = 6,
IsRecoveryBoot = 7,
DeviceId = 8,
BootReason = 9,
MemoryMode = 10,
IsDevelopmentFunctionEnabled = 11,
KernelConfiguration = 12,
IsChargerHiZModeEnabled = 13,
RetailInteractiveDisplayState = 14,
RegulatorType = 15,
DeviceUniqueKeyGeneration = 16,
Package2Hash = 17,
/* Extension config items for exosphere. */
ExosphereApiVersion = 65000,
ExosphereNeedsReboot = 65001,
ExosphereNeedsShutdown = 65002,
ExosphereGitCommitHash = 65003,
ExosphereHasRcmBugPatch = 65004,
ExosphereBlankProdInfo = 65005,
ExosphereAllowCalWrites = 65006,
ExosphereEmummcType = 65007,
ExospherePayloadAddress = 65008,
ExosphereLogConfiguration = 65009,
ExosphereForceEnableUsb30 = 65010,
ExosphereSupportedHosVersion = 65011,
ExosphereApproximateApiVersion = 65012,
};
SmcResult SmcGetConfigUser(SmcArguments &args);
SmcResult SmcGetConfigKern(SmcArguments &args);
SmcResult SmcSetConfig(SmcArguments &args);
/* This is an atmosphere extension smc. */
SmcResult SmcGetEmummcConfig(SmcArguments &args);
/* For other parts of exosphere. */
pkg1::MemorySize GetPhysicalMemorySize();
}

View File

@@ -1,76 +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 "../secmon_error.hpp"
#include "../secmon_page_mapper.hpp"
#include "secmon_smc_memory_access.hpp"
namespace ams::secmon::smc {
namespace {
enum IramCopyType {
IramCopyType_FromIramToDram = 0,
IramCopyType_FromDramToIram = 1,
IramCopyType_Count,
};
struct IramCopyOption {
using CopyType = util::BitPack32::Field<0, 1, IramCopyType>;
};
}
/* This is an atmosphere extension smc. */
SmcResult SmcIramCopy(SmcArguments &args) {
/* Decode arguments. */
const uintptr_t dram_address = args.r[1];
const uintptr_t iram_address = args.r[2];
const size_t size = args.r[3];
const util::BitPack32 option = { static_cast<u32>(args.r[4]) };
const auto copy_type = option.Get<IramCopyOption::CopyType>();
/* Validate arguments. */
SMC_R_UNLESS(copy_type < IramCopyType_Count, InvalidArgument);
{
/* Map the pages. */
AtmosphereUserPageMapper dram_mapper(dram_address);
AtmosphereIramPageMapper iram_mapper(iram_address);
SMC_R_UNLESS(dram_mapper.Map(), InvalidArgument);
SMC_R_UNLESS(iram_mapper.Map(), InvalidArgument);
/* Get the ranges we're copying. */
const void * const src = (copy_type == IramCopyType_FromIramToDram) ? iram_mapper.GetPointerTo(iram_address, size) : dram_mapper.GetPointerTo(dram_address, size);
void * const dst = (copy_type == IramCopyType_FromIramToDram) ? dram_mapper.GetPointerTo(dram_address, size) : iram_mapper.GetPointerTo(iram_address, size);
SMC_R_UNLESS(src != nullptr, InvalidArgument);
SMC_R_UNLESS(dst != nullptr, InvalidArgument);
/* Copy the data. */
std::memcpy(dst, src, size);
}
return SmcResult::Success;
}
SmcResult SmcWriteAddress(SmcArguments &args) {
/* NOTE: This smc was deprecated in Atmosphère 0.13.0. */
AMS_UNUSED(args);
return SmcResult::NotSupported;
}
}

View File

@@ -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 <exosphere.hpp>
#include "secmon_smc_common.hpp"
namespace ams::secmon::smc {
/* This is an atmosphere extension smc. */
SmcResult SmcIramCopy(SmcArguments &args);
SmcResult SmcWriteAddress(SmcArguments &args);
}

View File

@@ -1,567 +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 "../secmon_cache.hpp"
#include "../secmon_cpu_context.hpp"
#include "../secmon_error.hpp"
#include "../secmon_misc.hpp"
#include "secmon_smc_power_management.hpp"
#include "secmon_smc_se_lock.hpp"
#include "sc7fw_bin.h"
namespace ams::secmon {
/* Declare assembly functionality. */
void *GetCoreExceptionStackVirtual();
}
namespace ams::secmon::smc {
/* Declare assembly power-management functionality. */
void PivotStackAndInvoke(void *stack, void (*function)());
void FinalizePowerOff();
namespace {
constexpr inline const uintptr_t PMC = MemoryRegionVirtualDevicePmc.GetAddress();
constexpr inline const uintptr_t APB_MISC = MemoryRegionVirtualDeviceApbMisc.GetAddress();
constexpr inline const uintptr_t GPIO = MemoryRegionVirtualDeviceGpio.GetAddress();
constexpr inline const uintptr_t CLK_RST = MemoryRegionVirtualDeviceClkRst.GetAddress();
constexpr inline const uintptr_t EVP = secmon::MemoryRegionVirtualDeviceExceptionVectors.GetAddress();
constexpr inline const uintptr_t FLOW_CTLR = MemoryRegionVirtualDeviceFlowController.GetAddress();
constexpr inline const uintptr_t AHB_ARBC = MemoryRegionVirtualDeviceSystem.GetAddress();
constexpr inline uintptr_t CommonSmcStackTop = MemoryRegionVirtualTzramVolatileData.GetEndAddress() - (0x80 * (NumCores - 1));
enum PowerStateType {
PowerStateType_StandBy = 0,
PowerStateType_PowerDown = 1,
};
enum PowerStateId {
PowerStateId_Sc7 = 27,
};
/* http://infocenter.arm.com/help/topic/com.arm.doc.den0022d/Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf Page 46 */
struct SuspendCpuPowerState {
using StateId = util::BitPack32::Field< 0, 16, PowerStateId>;
using StateType = util::BitPack32::Field<16, 1, PowerStateType>;
using PowerLevel = util::BitPack32::Field<24, 2, u32>;
};
constinit bool g_charger_hi_z_mode_enabled = false;
constinit const reg::BitsMask CpuPowerGateStatusMasks[NumCores] = {
PMC_REG_BITS_MASK(PWRGATE_STATUS_CE0),
PMC_REG_BITS_MASK(PWRGATE_STATUS_CE1),
PMC_REG_BITS_MASK(PWRGATE_STATUS_CE2),
PMC_REG_BITS_MASK(PWRGATE_STATUS_CE3),
};
constinit const APBDEV_PMC_PWRGATE_TOGGLE_PARTID CpuPowerGateTogglePartitionIds[NumCores] = {
APBDEV_PMC_PWRGATE_TOGGLE_PARTID_CE0,
APBDEV_PMC_PWRGATE_TOGGLE_PARTID_CE1,
APBDEV_PMC_PWRGATE_TOGGLE_PARTID_CE2,
APBDEV_PMC_PWRGATE_TOGGLE_PARTID_CE3,
};
bool IsCpuPoweredOn(const reg::BitsMask mask) {
return reg::HasValue(PMC + APBDEV_PMC_PWRGATE_STATUS, REG_BITS_VALUE_FROM_MASK(mask, APBDEV_PMC_PWRGATE_STATUS_STATUS_ON));
}
void PowerOnCpu(const reg::BitsMask mask, u32 toggle_partid) {
/* If the cpu is already on, we have nothing to do. */
if (IsCpuPoweredOn(mask)) {
return;
}
/* Wait until nothing is being powergated. */
int timeout = 5000;
while (true) {
if (reg::HasValue(PMC + APBDEV_PMC_PWRGATE_TOGGLE, PMC_REG_BITS_ENUM(PWRGATE_TOGGLE_START, DISABLE))) {
break;
}
util::WaitMicroSeconds(1);
if ((--timeout) < 0) {
/* NOTE: Nintendo doesn't do any error handling here... */
return;
}
}
/* Toggle on the cpu partition. */
reg::Write(PMC + APBDEV_PMC_PWRGATE_TOGGLE, PMC_REG_BITS_ENUM (PWRGATE_TOGGLE_START, ENABLE),
PMC_REG_BITS_VALUE(PWRGATE_TOGGLE_PARTID, toggle_partid));
/* Wait up to 5000 us for the powergate to complete. */
timeout = 5000;
while (true) {
if (IsCpuPoweredOn(mask)) {
break;
}
util::WaitMicroSeconds(1);
if ((--timeout) < 0) {
/* NOTE: Nintendo doesn't do any error handling here... */
return;
}
}
}
void ResetCpu(int which_core) {
reg::Write(CLK_RST + CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET, REG_BITS_VALUE(which_core + 0x00, 1, 1), /* CPURESETn */
REG_BITS_VALUE(which_core + 0x10, 1, 1)); /* CORERESETn */
}
void StartCpu(int which_core) {
reg::Write(CLK_RST + CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR, REG_BITS_VALUE(which_core + 0x00, 1, 1), /* CPURESETn */
REG_BITS_VALUE(which_core + 0x10, 1, 1)); /* CORERESETn */
}
void PowerOffCpuImpl() {
/* Get the current core id. */
const auto core_id = hw::GetCurrentCoreId();
/* Configure the flow controller to prepare for shutting down the current core. */
flow::SetCpuCsr(core_id, FLOW_CTLR_CPUN_CSR_ENABLE_EXT_POWERGATE_CPU_ONLY);
flow::SetHaltCpuEvents(core_id, false);
flow::SetCc4Ctrl(core_id, 0);
/* Save the core's context for restoration on next power-on. */
SaveDebugRegisters();
SetCoreOff();
/* Ensure there are no pending memory transactions prior to our power-down. */
FlushEntireDataCache();
/* Finalize our powerdown and wait for an interrupt. */
FinalizePowerOff();
}
void ValidateSocStateForSuspend() {
/* Validate that all other cores are off. */
AMS_ABORT_UNLESS(reg::HasValue(PMC + APBDEV_PMC_PWRGATE_STATUS, PMC_REG_BITS_VALUE(PWRGATE_STATUS_CE123, 0)));
/* Validate that the bpmp is appropriately halted. */
const bool jtag = IsJtagEnabled();
AMS_ABORT_UNLESS(reg::Read(FLOW_CTLR + FLOW_CTLR_HALT_COP_EVENTS) == reg::Encode(FLOW_REG_BITS_ENUM (HALT_COP_EVENTS_MODE, FLOW_MODE_STOP),
FLOW_REG_BITS_ENUM_SEL(HALT_COP_EVENTS_JTAG, jtag, ENABLED, DISABLED)));
/* Further validations aren't guaranteed on < 6.0.0. */
if (GetTargetFirmware() < TargetFirmware_6_0_0) {
return;
}
/* Validate that USB2, APB-DMA, AHB-DMA are held in reset. */
AMS_ABORT_UNLESS(reg::HasValue(CLK_RST + CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_REG_BITS_ENUM(RST_DEVICES_H_SWR_USB2_RST, ENABLE),
CLK_RST_REG_BITS_ENUM(RST_DEVICES_H_SWR_APBDMA_RST, ENABLE),
CLK_RST_REG_BITS_ENUM(RST_DEVICES_H_SWR_AHBDMA_RST, ENABLE)));
/* Validate that USBD is held in reset. */
AMS_ABORT_UNLESS(reg::HasValue(CLK_RST + CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_REG_BITS_ENUM(RST_DEVICES_L_SWR_USBD_RST, ENABLE)));
/* Validate that AHB-DMA, USB, USB2, COP are not allowed to arbitrate on the AHB. */
AMS_ABORT_UNLESS(reg::HasValue(AHB_ARBC + AHB_ARBITRATION_DISABLE, AHB_REG_BITS_ENUM(ARBITRATION_DISABLE_COP, DISABLE),
AHB_REG_BITS_ENUM(ARBITRATION_DISABLE_AHBDMA, DISABLE),
AHB_REG_BITS_ENUM(ARBITRATION_DISABLE_USB, DISABLE),
AHB_REG_BITS_ENUM(ARBITRATION_DISABLE_USB2, DISABLE)));
/* Validate that the GPIO controller has clock enabled. */
AMS_ABORT_UNLESS(reg::HasValue(CLK_RST + CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_L_CLK_ENB_GPIO, ENABLE)));
/* Validate that both FUSE and KFUSE have clock enabled. */
AMS_ABORT_UNLESS(reg::HasValue(CLK_RST + CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_H_CLK_ENB_FUSE, ENABLE),
CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_H_CLK_ENB_KFUSE, ENABLE)));
/* Validate that all of IRAM has clock enabled. */
AMS_ABORT_UNLESS(reg::HasValue(CLK_RST + CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_U_CLK_ENB_IRAMA, ENABLE),
CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_U_CLK_ENB_IRAMB, ENABLE),
CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_U_CLK_ENB_IRAMC, ENABLE),
CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_U_CLK_ENB_IRAMD, ENABLE)));
/* Validate that ACTMON has clock enabled. */
AMS_ABORT_UNLESS(reg::HasValue(CLK_RST + CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_V_CLK_ENB_ACTMON, ENABLE)));
/* Validate that ENTROPY has clock enabled. */
AMS_ABORT_UNLESS(reg::HasValue(CLK_RST + CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_W_CLK_ENB_ENTROPY, ENABLE)));
}
void GenerateCryptographicallyRandomBytes(void * const dst, int size) {
/* Flush the region we're about to fill to ensure consistency with the SE. */
hw::FlushDataCache(dst, size);
hw::DataSynchronizationBarrierInnerShareable();
/* Generate random bytes. */
se::GenerateRandomBytes(dst, size);
hw::DataSynchronizationBarrierInnerShareable();
/* Flush to ensure the CPU sees consistent data for the region. */
hw::FlushDataCache(dst, size);
hw::DataSynchronizationBarrierInnerShareable();
}
void SaveSecureContextForErista() {
/* Generate a random key source. */
util::AlignedBuffer<hw::DataCacheLineSize, se::AesBlockSize> key_source;
GenerateCryptographicallyRandomBytes(key_source, se::AesBlockSize);
const u32 * const key_source_32 = reinterpret_cast<const u32 *>(static_cast<u8 *>(key_source));
/* Ensure that the key source registers are not locked. */
AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_KeySourceReadWrite) != pmc::LockState::Locked);
/* Write the key source, lock writes to the key source, and verify that the key source is write-locked. */
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH24, key_source_32[0]);
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH25, key_source_32[1]);
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH26, key_source_32[2]);
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH27, key_source_32[3]);
pmc::LockSecureRegister(pmc::SecureRegister_KeySourceWrite);
AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_KeySourceWrite) == pmc::LockState::Locked);
/* Verify the key source is correct in registers, and read-lock the key source registers. */
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH24) == key_source_32[0]);
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH25) == key_source_32[1]);
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH26) == key_source_32[2]);
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH27) == key_source_32[3]);
pmc::LockSecureRegister(pmc::SecureRegister_KeySourceRead);
/* Ensure that the key source registers are locked. */
AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_KeySourceReadWrite) == pmc::LockState::Locked);
/* Generate a random kek into keyslot 2. */
se::SetRandomKey(pkg1::AesKeySlot_TzramSaveKek);
/* Verify that the se is in a validate state, context save, and validate again. */
{
se::ValidateErrStatus();
ON_SCOPE_EXIT { se::ValidateErrStatus(); };
{
/* Transition to non-secure mode for the duration of the context save operation. */
se::SetSecure(false);
ON_SCOPE_EXIT { se::SetSecure(true); };
/* Get a pointer to the context storage. */
se::Context * const context = MemoryRegionVirtualDramSecureDataStoreSecurityEngineState.GetPointer<se::Context>();
static_assert(MemoryRegionVirtualDramSecureDataStoreSecurityEngineState.GetSize() == sizeof(*context));
/* Save the context. */
se::SaveContext(context);
/* Ensure that the cpu sees consistent data. */
hw::FlushDataCache(context, sizeof(*context));
hw::DataSynchronizationBarrierInnerShareable();
/* Write the context pointer to pmc scratch, so that the bootrom will restore it on wake. */
reg::Write(PMC + APBDEV_PMC_SCRATCH43, MemoryRegionPhysicalDramSecureDataStoreSecurityEngineState.GetAddress());
}
}
/* Clear keyslot 3, and then derive the save key. */
se::ClearAesKeySlot(pkg1::AesKeySlot_TzramSaveKey);
se::SetEncryptedAesKey256(pkg1::AesKeySlot_TzramSaveKey, pkg1::AesKeySlot_TzramSaveKek, key_source, se::AesBlockSize);
/* Declare a temporary block to be used as both iv and mac. */
u32 temp_block[se::AesBlockSize / sizeof(u32)] = {};
/* Ensure that the SE sees consistent data for tzram. */
const void * const tzram_save_src = MemoryRegionVirtualTzramReadOnlyAlias.GetPointer<u8>() + MemoryRegionVirtualTzramVolatileData.GetSize() + MemoryRegionVirtualTzramVolatileStack.GetSize();
void * const tzram_save_dst = MemoryRegionVirtualIramSc7Work.GetPointer<void>();
constexpr size_t TzramSaveSize = MemoryRegionVirtualDramSecureDataStoreTzram.GetSize();
hw::FlushDataCache(tzram_save_src, TzramSaveSize);
hw::FlushDataCache(tzram_save_dst, TzramSaveSize);
hw::DataSynchronizationBarrierInnerShareable();
/* Encrypt tzram using our random key. */
se::EncryptAes256Cbc(tzram_save_dst, TzramSaveSize, pkg1::AesKeySlot_TzramSaveKey, tzram_save_src, TzramSaveSize, temp_block, se::AesBlockSize);
hw::FlushDataCache(tzram_save_dst, TzramSaveSize);
hw::DataSynchronizationBarrierInnerShareable();
/* Copy the data from work space to the secure storage destination. */
void * const tzram_store_dst = MemoryRegionVirtualDramSecureDataStoreTzram.GetPointer<void>();
std::memcpy(tzram_store_dst, tzram_save_dst, TzramSaveSize);
hw::FlushDataCache(tzram_store_dst, TzramSaveSize);
hw::DataSynchronizationBarrierInnerShareable();
/* Compute cmac of tzram into our temporary block. */
se::ComputeAes256Cmac(temp_block, se::AesBlockSize, pkg1::AesKeySlot_TzramSaveKey, tzram_save_src, TzramSaveSize);
/* Ensure that the cmac registers are not locked. */
AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_CmacReadWrite) != pmc::LockState::Locked);
/* Write the cmac, lock writes to the cmac, and verify that the cmac is write-locked. */
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH112, temp_block[0]);
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH113, temp_block[1]);
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH114, temp_block[2]);
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH115, temp_block[3]);
pmc::LockSecureRegister(pmc::SecureRegister_CmacWrite);
AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_CmacWrite) == pmc::LockState::Locked);
/* Verify the key source is correct in registers, and read-lock the key source registers. */
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH112) == temp_block[0]);
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH113) == temp_block[1]);
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH114) == temp_block[2]);
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH115) == temp_block[3]);
pmc::LockSecureRegister(pmc::SecureRegister_CmacRead);
/* Ensure that the key source registers are locked. */
AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_CmacReadWrite) == pmc::LockState::Locked);
}
void SaveSecureContextForMariko() {
/* Save security engine context to TZRAM SE carveout (inaccessible to cpu). */
se::SaveContextAutomatic();
/* Save TZRAM to shadow-TZRAM in always-on power domain. */
se::SaveTzramAutomatic();
}
void SaveSecureContext() {
/* Save the appropriate secure context. */
const auto soc_type = GetSocType();
if (soc_type == fuse::SocType_Erista) {
SaveSecureContextForErista();
} else /* if (soc_type == fuse::SocType_Mariko) */ {
SaveSecureContextForMariko();
}
/* Save the debug code. */
#if defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING)
{
const void * const debug_code_src = MemoryRegionVirtualDebugCode.GetPointer<void>();
void * const debug_code_dst = MemoryRegionVirtualDramDebugDataStore.GetPointer<void>();
std::memcpy(debug_code_dst, debug_code_src, MemoryRegionVirtualDebugCode.GetSize());
hw::FlushDataCache(debug_code_dst, MemoryRegionVirtualDebugCode.GetSize());
hw::DataSynchronizationBarrierInnerShareable();
}
#endif
}
void LoadAndStartSc7BpmpFirmware() {
/* Set BPMP reset. */
reg::Write(CLK_RST + CLK_RST_CONTROLLER_RST_DEV_L_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_L_SET_SET_COP_RST, ENABLE));
/* Set the PMC as insecure, so that the BPMP firmware can access it. */
reg::ReadWrite(APB_MISC + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0, SLAVE_SECURITY_REG_BITS_ENUM(0, PMC, DISABLE));
/* Set the exception vectors for the bpmp. RESET should point to RESET, all others should point to generic exception/panic. */
constexpr const u32 Sc7FirmwareResetVector = static_cast<u32>(MemoryRegionPhysicalIramSc7Firmware.GetAddress() + 0x0);
constexpr const u32 Sc7FirmwarePanicVector = static_cast<u32>(MemoryRegionPhysicalIramSc7Firmware.GetAddress() + 0x4);
reg::Write(EVP + EVP_COP_RESET_VECTOR, Sc7FirmwareResetVector);
reg::Write(EVP + EVP_COP_UNDEF_VECTOR, Sc7FirmwarePanicVector);
reg::Write(EVP + EVP_COP_SWI_VECTOR, Sc7FirmwarePanicVector);
reg::Write(EVP + EVP_COP_PREFETCH_ABORT_VECTOR, Sc7FirmwarePanicVector);
reg::Write(EVP + EVP_COP_DATA_ABORT_VECTOR, Sc7FirmwarePanicVector);
reg::Write(EVP + EVP_COP_RSVD_VECTOR, Sc7FirmwarePanicVector);
reg::Write(EVP + EVP_COP_IRQ_VECTOR, Sc7FirmwarePanicVector);
reg::Write(EVP + EVP_COP_FIQ_VECTOR, Sc7FirmwarePanicVector);
/* Disable activity monitor bpmp monitoring, so that we don't panic upon bpmp wake. */
actmon::StopMonitoringBpmp();
/* Load the bpmp firmware. */
void * const sc7fw_load_address = MemoryRegionVirtualIramSc7Firmware.GetPointer<void>();
std::memcpy(sc7fw_load_address, sc7fw_bin, sc7fw_bin_size);
hw::FlushDataCache(sc7fw_load_address, sc7fw_bin_size);
hw::DataSynchronizationBarrierInnerShareable();
/* Ensure that the bpmp firmware was loaded. */
AMS_ABORT_UNLESS(crypto::IsSameBytes(sc7fw_load_address, sc7fw_bin, sc7fw_bin_size));
/* Clear BPMP reset. */
reg::Write(CLK_RST + CLK_RST_CONTROLLER_RST_DEV_L_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_L_CLR_CLR_COP_RST, ENABLE));
/* Start the bpmp. */
reg::Write(FLOW_CTLR + FLOW_CTLR_HALT_COP_EVENTS, FLOW_REG_BITS_ENUM(HALT_COP_EVENTS_MODE, FLOW_MODE_NONE));
}
void SaveSecureContextAndSuspend() {
/* Ensure there are no pending memory transactions before we continue */
FlushEntireDataCache();
hw::DataSynchronizationBarrierInnerShareable();
/* Save all secure context (security engine state + tzram). */
SaveSecureContext();
/* Load and start the sc7 firmware on the bpmp. */
if (GetTargetFirmware() >= TargetFirmware_2_0_0) {
LoadAndStartSc7BpmpFirmware();
}
/* Log our suspension. */
/* NOTE: Nintendo only does this on dev, but we will always do it. */
if (true /* !pkg1::IsProduction() */) {
log::Initialize(secmon::GetLogPort(), secmon::GetLogBaudRate(), secmon::GetLogFlags());
log::SendText("OYASUMI\n", 8);
log::Flush();
}
/* If we're on erista, configure the bootrom to allow our custom warmboot firmware. */
if (GetSocType() == fuse::SocType_Erista) {
reg::Write(PMC + APBDEV_PMC_SCRATCH31, 0x2202E012);
reg::Write(PMC + APBDEV_PMC_SCRATCH32, 0x6001DC28);
}
/* Finalize our powerdown and wait for an interrupt. */
FinalizePowerOff();
}
SmcResult SuspendCpuImpl(SmcArguments &args) {
/* Decode arguments. */
const util::BitPack32 power_state = { static_cast<u32>(args.r[1]) };
const uintptr_t entry_point = args.r[2];
const uintptr_t context_id = args.r[3];
const auto state_type = power_state.Get<SuspendCpuPowerState::StateType>();
const auto state_id = power_state.Get<SuspendCpuPowerState::StateId>();
const auto core_id = hw::GetCurrentCoreId();
/* Validate arguments. */
SMC_R_UNLESS(state_type == PowerStateType_PowerDown, PsciDenied);
SMC_R_UNLESS(state_id == PowerStateId_Sc7, PsciDenied);
/* Orchestrate charger transition to Hi-Z mode if needed. */
if (IsChargerHiZModeEnabled()) {
/* Ensure we can do comms over i2c-1. */
clkrst::EnableI2c1Clock();
/* If the charger isn't in hi-z mode, perform a transition. */
if (!charger::IsHiZMode()) {
charger::EnterHiZMode();
/* Wait up to 50ms for the transition to complete. */
const auto start_time = util::GetMicroSeconds();
auto current_time = start_time;
while ((current_time - start_time) <= 50'000) {
if (auto intr_status = reg::Read(GPIO + 0x634); (intr_status & 1) == 0) {
/* Wait 256 us to ensure the transition completes. */
util::WaitMicroSeconds(256);
break;
}
current_time = util::GetMicroSeconds();
}
}
/* Disable i2c-1, since we're done communicating over it. */
clkrst::DisableI2c1Clock();
}
/* Enable wake event detection. */
pmc::EnableWakeEventDetection();
/* Ensure that i2c-5 is usable for communicating with the pmic. */
clkrst::EnableI2c5Clock();
i2c::Initialize(i2c::Port_5);
/* Orchestrate sleep entry with the pmic. */
pmic::EnableSleep();
/* Ensure that the soc is in a state valid for us to suspend. */
if (GetTargetFirmware() >= TargetFirmware_2_0_0) {
ValidateSocStateForSuspend();
}
/* Configure the pmc for sc7 entry. */
pmc::ConfigureForSc7Entry();
/* Configure the flow controller for sc7 entry. */
flow::SetCc4Ctrl(core_id, 0);
flow::SetHaltCpuEvents(core_id, false);
flow::ClearL2FlushControl();
flow::SetCpuCsr(core_id, FLOW_CTLR_CPUN_CSR_ENABLE_EXT_POWERGATE_CPU_TURNOFF_CPURAIL);
/* Save the entry context. */
SetEntryContext(core_id, entry_point, context_id);
/* Configure the cpu context for reset. */
SaveDebugRegisters();
SetCoreOff();
SetResetExpected(true);
/* Switch to use the common smc stack (all other cores are off), and perform suspension. */
PivotStackAndInvoke(reinterpret_cast<void *>(CommonSmcStackTop), SaveSecureContextAndSuspend);
/* This code will never be reached. */
__builtin_unreachable();
}
}
void PowerOffCpu() {
/* Get the current core id. */
const auto core_id = hw::GetCurrentCoreId();
/* Note that we're expecting a reset for the current core. */
SetResetExpected(true);
/* If we're on the final core, shut down directly. Otherwise, invoke with special stack. */
if (core_id == NumCores - 1) {
PowerOffCpuImpl();
} else {
PivotStackAndInvoke(GetCoreExceptionStackVirtual(), PowerOffCpuImpl);
}
/* This code will never be reached. */
__builtin_unreachable();
}
SmcResult SmcPowerOffCpu(SmcArguments &args) {
AMS_UNUSED(args);
PowerOffCpu();
}
SmcResult SmcPowerOnCpu(SmcArguments &args) {
/* Get and validate the core to power on. */
const int which_core = args.r[1];
SMC_R_UNLESS(0 <= which_core && which_core < NumCores, PsciInvalidParameters);
/* Ensure the core isn't already on. */
SMC_R_UNLESS(!IsCoreOn(which_core), PsciAlreadyOn);
/* Save the entry context. */
SetEntryContext(which_core, args.r[2], args.r[3]);
/* Reset the cpu. */
ResetCpu(which_core);
/* Turn on the core. */
PowerOnCpu(CpuPowerGateStatusMasks[which_core], CpuPowerGateTogglePartitionIds[which_core]);
/* Start the core. */
StartCpu(which_core);
return SmcResult::PsciSuccess;
}
SmcResult SmcSuspendCpu(SmcArguments &args) {
return LockSecurityEngineAndInvoke(args, SuspendCpuImpl);
}
bool IsChargerHiZModeEnabled() {
return g_charger_hi_z_mode_enabled;
}
void SetChargerHiZModeEnabled(bool en) {
g_charger_hi_z_mode_enabled = en;
}
}

View File

@@ -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/>.
*/
#pragma once
#include <exosphere.hpp>
#include "secmon_smc_common.hpp"
namespace ams::secmon::smc {
NORETURN void PowerOffCpu();
SmcResult SmcPowerOffCpu(SmcArguments &args);
SmcResult SmcPowerOnCpu(SmcArguments &args);
SmcResult SmcSuspendCpu(SmcArguments &args);
bool IsChargerHiZModeEnabled();
void SetChargerHiZModeEnabled(bool en);
}

View File

@@ -1,77 +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 "../secmon_error.hpp"
#include "secmon_smc_random.hpp"
#include "secmon_random_cache.hpp"
#include "secmon_smc_se_lock.hpp"
namespace ams::secmon::smc {
namespace {
SmcResult GenerateRandomBytesImpl(SmcArguments &args) {
/* Validate the input size. */
const size_t size = args.r[1];
SMC_R_UNLESS(size <= MaxRandomBytes, InvalidArgument);
/* Create a buffer that the se can generate bytes into. */
util::AlignedBuffer<hw::DataCacheLineSize, MaxRandomBytes> buffer;
hw::FlushDataCache(buffer, size);
hw::DataSynchronizationBarrierInnerShareable();
/* Generate random bytes into the buffer. */
se::GenerateRandomBytes(buffer, size);
/* Ensure that the cpu sees consistent data. */
hw::DataSynchronizationBarrierInnerShareable();
hw::FlushDataCache(buffer, size);
hw::DataSynchronizationBarrierInnerShareable();
/* Copy the bytes to output. */
std::memcpy(std::addressof(args.r[1]), buffer, size);
return SmcResult::Success;
}
}
SmcResult SmcGenerateRandomBytes(SmcArguments &args) {
return LockSecurityEngineAndInvoke(args, GenerateRandomBytesImpl);
}
SmcResult SmcGenerateRandomBytesNonBlocking(SmcArguments &args) {
/* Try to lock the security engine, so that we can call the standard impl. */
if (TryLockSecurityEngine()) {
/* Ensure we unlock the security engine when done. */
ON_SCOPE_EXIT { UnlockSecurityEngine(); };
/* Take advantage of our lock to refill lthe random cache. */
ON_SCOPE_EXIT { RefillRandomCache(); };
/* If we lock it successfully, we can just call the blocking impl. */
return GenerateRandomBytesImpl(args);
} else {
/* Otherwise, we'll retrieve some bytes from the cache. */
const size_t size = args.r[1];
SMC_R_UNLESS(size <= MaxRandomBytes, InvalidArgument);
/* Get random bytes from the cache. */
GetRandomFromCache(std::addressof(args.r[1]), size);
return SmcResult::Success;
}
}
}

View File

@@ -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 <exosphere.hpp>
#include "secmon_smc_common.hpp"
namespace ams::secmon::smc {
SmcResult SmcGenerateRandomBytes(SmcArguments &args);
SmcResult SmcGenerateRandomBytesNonBlocking(SmcArguments &args);
}

View File

@@ -1,196 +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 "../secmon_error.hpp"
#include "secmon_smc_register_access.hpp"
namespace ams::secmon::smc {
namespace {
template<size_t N>
constexpr void SetRegisterTableAllowed(std::array<u8, N> &arr, uintptr_t reg) {
/* All registers should be four byte aligned. */
AMS_ASSUME(reg % sizeof(u32) == 0);
/* Reduce the register to an index. */
reg /= sizeof(u32);
/* Get the index and mask. */
const auto index = reg / BITSIZEOF(u8);
const auto mask = (1u << (reg % BITSIZEOF(u8)));
/* Check that the permission bit isn't already set. */
AMS_ASSUME((arr[index] & mask) == 0);
/* Set the permission bit. */
arr[index] |= mask;
/* Ensure that indices are set in sorted order. */
for (auto i = (reg % BITSIZEOF(u8)) + 1; i < 8; ++i) {
AMS_ASSUME((arr[index] & (1u << i)) == 0);
}
for (auto i = index + 1; i < arr.size(); ++i) {
AMS_ASSUME(arr[i] == 0);
}
}
template<size_t N>
consteval std::pair<size_t, size_t> GetReducedAccessTableInfo(const std::array<u8, N> &arr) {
for (int last = arr.size() - 1; last >= 0; --last) {
if (arr[last] != 0) {
const int end = last + 1;
for (int start = 0; start < end; ++start) {
if (arr[start] != 0) {
return std::make_pair(static_cast<size_t>(start), static_cast<size_t>(end));
}
}
return std::make_pair(static_cast<size_t>(0), static_cast<size_t>(end));
}
}
/* All empty perm table is disallowed. */
AMS_ASSUME(false);
}
template<u32 _Address, auto RawTable>
struct AccessTable {
static constexpr inline auto ReducedAccessTableInfo = GetReducedAccessTableInfo(RawTable);
static constexpr inline size_t ReducedAccessTableSize = ReducedAccessTableInfo.second - ReducedAccessTableInfo.first;
static constexpr inline auto ReducedAccessTable = []() -> std::array<u8, ReducedAccessTableSize> {
std::array<u8, ReducedAccessTableSize> reduced = {};
for (size_t i = ReducedAccessTableInfo.first; i < ReducedAccessTableInfo.second; ++i) {
reduced[i - ReducedAccessTableInfo.first] = RawTable[i];
}
return reduced;
}();
static constexpr u32 Address = _Address + (ReducedAccessTableInfo.first * sizeof(u32) * BITSIZEOF(u8));
static constexpr u32 Size = static_cast<u32>(ReducedAccessTableSize * sizeof(u32) * BITSIZEOF(u8));
static_assert(Size <= 0x1000);
};
struct AccessTableEntry {
const u8 * const table;
uintptr_t virtual_address;
u32 address;
u32 size;
};
/* Include the access tables. */
#include "secmon_define_pmc_access_table.inc"
#include "secmon_define_mc_access_table.inc"
#include "secmon_define_emc_access_table.inc"
#include "secmon_define_mc01_access_table.inc"
constexpr const AccessTableEntry AccessTables[] = {
{ PmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDevicePmc.GetAddress(), PmcAccessTable::Address, PmcAccessTable::Size, },
{ McAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceMemoryController.GetAddress(), McAccessTable::Address, McAccessTable::Size, },
{ EmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceExternalMemoryController.GetAddress(), EmcAccessTable::Address, EmcAccessTable::Size, },
{ Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController0.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController0.GetAddress(), Mc01AccessTable::Size, },
{ Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController1.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController1.GetAddress(), Mc01AccessTable::Size, },
};
constexpr bool IsAccessAllowed(const AccessTableEntry &entry, uintptr_t address) {
/* Check if the address is within range. */
if (!(entry.address <= address && address < entry.address + entry.size)) {
return false;
}
/* Get the offset. */
const auto offset = address - entry.address;
/* Convert it to an index. */
const auto reg_index = offset / sizeof(u32);
/* Get the bit fields. */
const auto index = reg_index / BITSIZEOF(u8);
const auto mask = (1u << (reg_index % BITSIZEOF(u8)));
/* Validate that we're not going out of bounds. */
if (index >= entry.size / sizeof(u32)) {
return false;
}
return (entry.table[index] & mask) != 0;
}
constexpr const AccessTableEntry *GetAccessTableEntry(uintptr_t address) {
for (const auto &entry : AccessTables) {
if (IsAccessAllowed(entry, address)) {
return std::addressof(entry);
}
}
return nullptr;
}
}
SmcResult SmcReadWriteRegister(SmcArguments &args) {
/* Get the arguments. */
const uintptr_t address = args.r[1];
const u32 mask = args.r[2];
const u32 value = args.r[3];
/* Validate that the address is aligned. */
SMC_R_UNLESS(util::IsAligned(address, alignof(u32)), InvalidArgument);
/* Find the access table. */
const AccessTableEntry * const entry = GetAccessTableEntry(address);
/* Translate our entry into an address to access. */
uintptr_t virtual_address = 0;
if (entry != nullptr) {
/* Get the address to read or write. */
virtual_address = entry->virtual_address + (address - entry->address);
} else {
/* For no clearly discernable reason, SmcReadWriteRegister returns success despite not doing the read/write */
/* when accessing the SMMU controls for the BPMP and for APB-DMA. */
/* This is "probably" to fuck with hackers who got access to the SMC and are trying to get control of the */
/* BPMP to exploit jamais vu, deja vu, or other related DMA/wake-from-sleep vulnerabilities. */
constexpr uintptr_t MC = MemoryRegionPhysicalDeviceMemoryController.GetAddress();
SMC_R_UNLESS((address == (MC + MC_SMMU_AVPC_ASID) || address == (MC + MC_SMMU_PPCS1_ASID)), InvalidArgument);
/* For backwards compatibility, we'll allow access to these devices on 1.0.0. */
if (GetTargetFirmware() < TargetFirmware_2_0_0) {
virtual_address = MemoryRegionVirtualDeviceMemoryController.GetAddress() + (address - MC);
}
}
/* Perform the read or write, if we should. */
if (virtual_address != 0) {
u32 out = 0;
if (mask != ~static_cast<u32>(0)) {
out = reg::Read(virtual_address);
}
if (mask != static_cast<u32>(0)) {
reg::Write(virtual_address, (out & ~mask) | (value & mask));
}
args.r[1] = out;
}
return SmcResult::Success;
}
}

View File

@@ -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 <exosphere.hpp>
#include "secmon_smc_common.hpp"
namespace ams::secmon::smc {
SmcResult SmcReadWriteRegister(SmcArguments &args);
}

View File

@@ -1,106 +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 "../secmon_error.hpp"
#include "../secmon_page_mapper.hpp"
#include "secmon_smc_result.hpp"
namespace ams::secmon::smc {
namespace {
constinit u64 g_async_key = InvalidAsyncKey;
constinit GetResultHandler g_async_handler = nullptr;
u64 GenerateRandomU64() {
/* NOTE: This is one of the only places where Nintendo does not do data flushing. */
/* to ensure coherency when doing random byte generation. */
/* It is not clear why it is necessary elsewhere but not here. */
/* TODO: Figure out why. */
u64 v;
se::GenerateRandomBytes(std::addressof(v), sizeof(v));
return v;
}
}
u64 BeginAsyncOperation(GetResultHandler handler) {
/* Only allow one async operation at a time. */
if (g_async_key != InvalidAsyncKey) {
return InvalidAsyncKey;
}
/* Generate a random async key. */
g_async_key = GenerateRandomU64();
g_async_handler = handler;
return g_async_key;
}
void CancelAsyncOperation(u64 async_key) {
if (async_key == g_async_key) {
g_async_key = InvalidAsyncKey;
}
}
void EndAsyncOperation() {
gic::SetPending(SecurityEngineUserInterruptId);
}
SmcResult SmcGetResult(SmcArguments &args) {
/* Decode arguments. */
const u64 async_key = args.r[1];
/* Validate arguments. */
SMC_R_UNLESS(g_async_key != InvalidAsyncKey, NoAsyncOperation);
SMC_R_UNLESS(g_async_key == async_key, InvalidAsyncOperation);
/* Call the handler. */
args.r[1] = static_cast<u64>(g_async_handler(nullptr, 0));
g_async_key = InvalidAsyncKey;
return SmcResult::Success;
}
SmcResult SmcGetResultData(SmcArguments &args) {
/* Decode arguments. */
const u64 async_key = args.r[1];
const uintptr_t user_phys_addr = args.r[2];
const size_t user_size = args.r[3];
/* Allocate a work buffer on the stack. */
alignas(8) u8 work_buffer[1_KB];
/* Validate arguments. */
SMC_R_UNLESS(g_async_key != InvalidAsyncKey, NoAsyncOperation);
SMC_R_UNLESS(g_async_key == async_key, InvalidAsyncOperation);
SMC_R_UNLESS(user_size <= sizeof(work_buffer), InvalidArgument);
/* Call the handler. */
args.r[1] = static_cast<u64>(g_async_handler(work_buffer, user_size));
g_async_key = InvalidAsyncKey;
/* Map the user buffer. */
{
UserPageMapper mapper(user_phys_addr);
SMC_R_UNLESS(mapper.Map(), InvalidArgument);
SMC_R_UNLESS(mapper.CopyToUser(user_phys_addr, work_buffer, user_size), InvalidArgument);
}
return SmcResult::Success;
}
}

View File

@@ -1,31 +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 <exosphere.hpp>
#include "secmon_smc_common.hpp"
namespace ams::secmon::smc {
using GetResultHandler = SmcResult (*)(void *dst, size_t dst_size);
u64 BeginAsyncOperation(GetResultHandler handler);
void CancelAsyncOperation(u64 async_key);
void EndAsyncOperation();
SmcResult SmcGetResult(SmcArguments &args);
SmcResult SmcGetResultData(SmcArguments &args);
}

View File

@@ -1,368 +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 "../secmon_error.hpp"
#include "../secmon_key_storage.hpp"
#include "../secmon_page_mapper.hpp"
#include "secmon_smc_aes.hpp"
#include "secmon_smc_rsa.hpp"
#include "secmon_smc_se_lock.hpp"
namespace ams::secmon::smc {
namespace {
struct ModularExponentiateByStorageKeyOption {
using Mode = util::BitPack32::Field<0, 2, u32>;
using Reserved = util::BitPack32::Field<2, 30, u32>;
};
struct PrepareEsDeviceUniqueKeyOption {
using KeyGeneration = util::BitPack32::Field<0, 6, int>;
using Type = util::BitPack32::Field<6, 2, EsCommonKeyType>;
using Reserved = util::BitPack32::Field<8, 24, u32>;
};
constexpr const u8 ModularExponentiateByStorageKeyTable[] = {
static_cast<u8>(ImportRsaKey_Lotus),
static_cast<u8>(ImportRsaKey_Ssl),
static_cast<u8>(ImportRsaKey_EsClientCert),
};
constexpr size_t ModularExponentiateByStorageKeyTableSize = util::size(ModularExponentiateByStorageKeyTable);
consteval u32 GetModeForImportRsaKey(ImportRsaKey import_key) {
for (size_t i = 0; i < ModularExponentiateByStorageKeyTableSize; ++i) {
if (static_cast<ImportRsaKey>(ModularExponentiateByStorageKeyTable[i]) == import_key) {
return i;
}
}
AMS_ASSUME(false);
}
class PrepareEsDeviceUniqueKeyAsyncArguments {
private:
int m_generation;
EsCommonKeyType m_type;
u8 m_label_digest[crypto::Sha256Generator::HashSize];
public:
void Set(int gen, EsCommonKeyType t, const u8 ld[crypto::Sha256Generator::HashSize]) {
m_generation = gen;
m_type = t;
std::memcpy(m_label_digest, ld, sizeof(m_label_digest));
}
int GetKeyGeneration() const { return m_generation; }
EsCommonKeyType GetCommonKeyType() const { return m_type; }
void GetLabelDigest(u8 dst[crypto::Sha256Generator::HashSize]) const { std::memcpy(dst, m_label_digest, sizeof(m_label_digest)); }
};
class ModularExponentiateByStorageKeyAsyncArguments {
private:
u8 m_msg[se::RsaSize];
public:
void Set(const void *m, size_t m_size) {
AMS_UNUSED(m_size);
std::memcpy(m_msg, m, sizeof(m_msg));
}
const u8 *GetMessage() const { return m_msg; }
};
constinit SmcResult g_exp_mod_result = SmcResult::Success;
constinit bool g_test_exp_mod_public = false;
constinit int g_test_exp_mod_slot = pkg1::RsaKeySlot_Temporary;
constinit ImportRsaKey g_test_exp_mod_key = {};
constinit union {
ModularExponentiateByStorageKeyAsyncArguments modular_exponentiate_by_storage_key;
PrepareEsDeviceUniqueKeyAsyncArguments prepare_es_device_unique_key;
} g_async_arguments;
ALWAYS_INLINE ModularExponentiateByStorageKeyAsyncArguments &GetModularExponentiateByStorageKeyAsyncArguments() {
return g_async_arguments.modular_exponentiate_by_storage_key;
}
ALWAYS_INLINE PrepareEsDeviceUniqueKeyAsyncArguments &GetPrepareEsDeviceUniqueKeyAsyncArguments() {
return g_async_arguments.prepare_es_device_unique_key;
}
void SecurityEngineDoneHandler() {
/* End the asynchronous operation. */
g_exp_mod_result = SmcResult::Success;
EndAsyncOperation();
}
void TestRsaPublicKey(ImportRsaKey which, int slot, const void *mod, size_t mod_size, se::DoneHandler handler) {
/* Declare a buffer for our test message. */
u8 msg[se::RsaSize];
std::memset(msg, 'D', sizeof(msg));
/* Provisionally import the modulus. */
ImportRsaKeyModulusProvisionally(which, mod, mod_size);
/* Load the provisional public key into the slot. */
LoadProvisionalRsaPublicKey(slot, which);
/* Perform the test exponentiation. */
se::ModularExponentiateAsync(slot, msg, sizeof(msg), handler);
}
void TestRsaPrivateKey(ImportRsaKey which, int slot, se::DoneHandler handler) {
/* Get the result of the public key test. */
u8 msg[se::RsaSize];
se::GetRsaResult(msg, sizeof(msg));
/* Load the provisional private key into the slot. */
LoadProvisionalRsaKey(slot, which);
/* Perform the test exponentiation. */
se::ModularExponentiateAsync(slot, msg, sizeof(msg), handler);
}
void VerifyTestRsaKeyResult(ImportRsaKey which) {
/* Get the result of the test. */
u8 msg[se::RsaSize];
se::GetRsaResult(msg, sizeof(msg));
/* Validate the result. */
const bool is_valid = (msg[0] == 'D') & (crypto::IsSameBytes(msg, msg + 1, sizeof(msg) - 1));
/* If the test passes, the key is no longer provisional. */
if (is_valid) {
CommitRsaKeyModulus(which);
}
}
void TestRsaKeyDoneHandler() {
if (g_test_exp_mod_public) {
/* If we're testing the public key, we still have another exponentiation to do to test the private key. */
g_test_exp_mod_public = false;
/* Test the private key. */
TestRsaPrivateKey(g_test_exp_mod_key, g_test_exp_mod_slot, TestRsaKeyDoneHandler);
} else {
/* We're testing the private key, so validate the result. */
VerifyTestRsaKeyResult(g_test_exp_mod_key);
/* If the test passed, we can proceed to perform the intended exponentiation. */
if (LoadRsaKey(g_test_exp_mod_slot, g_test_exp_mod_key)) {
se::ModularExponentiateAsync(pkg1::RsaKeySlot_Temporary, GetModularExponentiateByStorageKeyAsyncArguments().GetMessage(), se::RsaSize, SecurityEngineDoneHandler);
} else {
/* The test failed, so end the asynchronous operation. */
g_exp_mod_result = SmcResult::InvalidArgument;
EndAsyncOperation();
}
}
}
SmcResult ModularExponentiateImpl(SmcArguments &args) {
/* Decode arguments. */
const uintptr_t msg_address = args.r[1];
const uintptr_t exp_address = args.r[2];
const uintptr_t mod_address = args.r[3];
const size_t exp_size = args.r[4];
/* Validate arguments. */
SMC_R_UNLESS(util::IsAligned(exp_size, sizeof(u32)), InvalidArgument);
SMC_R_UNLESS(exp_size <= se::RsaSize, InvalidArgument);
/* Copy the message and modulus from the user. */
alignas(8) u8 msg[se::RsaSize];
alignas(8) u8 exp[se::RsaSize];
alignas(8) u8 mod[se::RsaSize];
{
UserPageMapper mapper(msg_address);
SMC_R_UNLESS(mapper.Map(), InvalidArgument);
SMC_R_UNLESS(mapper.CopyFromUser(msg, msg_address, sizeof(msg)), InvalidArgument);
SMC_R_UNLESS(mapper.CopyFromUser(exp, exp_address, exp_size), InvalidArgument);
SMC_R_UNLESS(mapper.CopyFromUser(mod, mod_address, sizeof(mod)), InvalidArgument);
}
/* We're performing an operation, so set the result to busy. */
g_exp_mod_result = SmcResult::Busy;
/* Load the key into the temporary keyslot. */
se::SetRsaKey(pkg1::RsaKeySlot_Temporary, mod, sizeof(mod), exp, exp_size);
/* Begin the asynchronous exponentiation. */
se::ModularExponentiateAsync(pkg1::RsaKeySlot_Temporary, msg, sizeof(msg), SecurityEngineDoneHandler);
return SmcResult::Success;
}
SmcResult ModularExponentiateByStorageKeyImpl(SmcArguments &args) {
/* Decode arguments. */
const uintptr_t msg_address = args.r[1];
const uintptr_t mod_address = args.r[2];
const util::BitPack32 option = { static_cast<u32>(args.r[3]) };
const auto mode = GetTargetFirmware() >= TargetFirmware_5_0_0 ? option.Get<ModularExponentiateByStorageKeyOption::Mode>() : GetModeForImportRsaKey(ImportRsaKey_Lotus);
const auto reserved = option.Get<PrepareEsDeviceUniqueKeyOption::Reserved>();
/* Validate arguments. */
SMC_R_UNLESS(reserved == 0, InvalidArgument);
SMC_R_UNLESS(mode < ModularExponentiateByStorageKeyTableSize, InvalidArgument);
/* Convert the mode to an import key. */
const auto import_key = static_cast<ImportRsaKey>(ModularExponentiateByStorageKeyTable[mode]);
/* Copy the message and modulus from the user. */
alignas(8) u8 msg[se::RsaSize];
alignas(8) u8 mod[se::RsaSize];
{
UserPageMapper mapper(msg_address);
SMC_R_UNLESS(mapper.Map(), InvalidArgument);
SMC_R_UNLESS(mapper.CopyFromUser(msg, msg_address, sizeof(msg)), InvalidArgument);
SMC_R_UNLESS(mapper.CopyFromUser(mod, mod_address, sizeof(mod)), InvalidArgument);
}
/* We're performing an operation, so set the result to busy. */
g_exp_mod_result = SmcResult::Busy;
/* In the ideal case, the key pair is already verified. If it is, we can use it directly. */
if (LoadRsaKey(pkg1::RsaKeySlot_Temporary, import_key)) {
se::ModularExponentiateAsync(pkg1::RsaKeySlot_Temporary, msg, sizeof(msg), SecurityEngineDoneHandler);
} else {
/* Set the async arguments. */
GetModularExponentiateByStorageKeyAsyncArguments().Set(msg, sizeof(msg));
/* Test the rsa key. */
g_test_exp_mod_slot = pkg1::RsaKeySlot_Temporary;
g_test_exp_mod_key = import_key;
g_test_exp_mod_public = true;
TestRsaPublicKey(import_key, pkg1::RsaKeySlot_Temporary, mod, sizeof(mod), TestRsaKeyDoneHandler);
}
return SmcResult::Success;
}
SmcResult PrepareEsDeviceUniqueKeyImpl(SmcArguments &args) {
/* Decode arguments. */
u8 label_digest[crypto::Sha256Generator::HashSize];
const uintptr_t msg_address = args.r[1];
const uintptr_t mod_address = args.r[2];
std::memcpy(label_digest, std::addressof(args.r[3]), sizeof(label_digest));
const util::BitPack32 option = { static_cast<u32>(args.r[7]) };
const auto generation = GetTargetFirmware() >= TargetFirmware_3_0_0 ? std::max<int>(pkg1::KeyGeneration_1_0_0, option.Get<PrepareEsDeviceUniqueKeyOption::KeyGeneration>() - 1) : pkg1::KeyGeneration_1_0_0;
const auto type = option.Get<PrepareEsDeviceUniqueKeyOption::Type>();
const auto reserved = option.Get<PrepareEsDeviceUniqueKeyOption::Reserved>();
/* Validate arguments. */
SMC_R_UNLESS(reserved == 0, InvalidArgument);
SMC_R_UNLESS(pkg1::IsValidKeyGeneration(generation), InvalidArgument);
SMC_R_UNLESS(generation <= GetKeyGeneration(), InvalidArgument);
SMC_R_UNLESS(type < EsCommonKeyType_Count, InvalidArgument);
/* Copy the message and modulus from the user. */
alignas(8) u8 msg[se::RsaSize];
alignas(8) u8 mod[se::RsaSize];
{
UserPageMapper mapper(msg_address);
SMC_R_UNLESS(mapper.Map(), InvalidArgument);
SMC_R_UNLESS(mapper.CopyFromUser(msg, msg_address, sizeof(msg)), InvalidArgument);
SMC_R_UNLESS(mapper.CopyFromUser(mod, mod_address, sizeof(mod)), InvalidArgument);
}
/* We're performing an operation, so set the result to busy. */
g_exp_mod_result = SmcResult::Busy;
/* Set the async arguments. */
GetPrepareEsDeviceUniqueKeyAsyncArguments().Set(generation, type, label_digest);
/* Load the es drm key into the security engine. */
SMC_R_UNLESS(LoadRsaKey(pkg1::RsaKeySlot_Temporary, ImportRsaKey_EsDrmCert), NotInitialized);
/* Trigger the asynchronous modular exponentiation. */
se::ModularExponentiateAsync(pkg1::RsaKeySlot_Temporary, msg, sizeof(msg), SecurityEngineDoneHandler);
return SmcResult::Success;
}
SmcResult GetModularExponentiateResult(void *dst, size_t dst_size) {
/* Validate state. */
SMC_R_TRY(g_exp_mod_result);
SMC_R_UNLESS(dst_size == se::RsaSize, InvalidArgument);
/* We want to relinquish our security engine lock at the end of scope. */
ON_SCOPE_EXIT { UnlockSecurityEngine(); };
/* Get the result of the exponentiation. */
se::GetRsaResult(dst, se::RsaSize);
return SmcResult::Success;
}
SmcResult GetPrepareEsDeviceUniqueKeyResult(void *dst, size_t dst_size) {
/* Declare variables. */
u8 key_source[se::AesBlockSize];
u8 key[se::AesBlockSize];
u8 access_key[se::AesBlockSize];
/* Validate state. */
SMC_R_TRY(g_exp_mod_result);
SMC_R_UNLESS(dst_size == sizeof(access_key), InvalidArgument);
/* We want to relinquish our security engine lock at the end of scope. */
ON_SCOPE_EXIT { UnlockSecurityEngine(); };
/* Get the async args. */
const auto &async_args = GetPrepareEsDeviceUniqueKeyAsyncArguments();
/* Get the exponentiation output. */
alignas(8) u8 msg[se::RsaSize];
se::GetRsaResult(msg, sizeof(msg));
/* Decode the key. */
{
/* Get the label digest. */
u8 label_digest[crypto::Sha256Generator::HashSize];
async_args.GetLabelDigest(label_digest);
/* Decode the key source. */
const size_t key_source_size = se::DecodeRsaOaepSha256(key_source, sizeof(key_source), msg, sizeof(msg), label_digest, sizeof(label_digest));
SMC_R_UNLESS(key_source_size == sizeof(key_source), InvalidArgument);
}
/* Decrypt the key. */
DecryptWithEsCommonKey(key, sizeof(key), key_source, sizeof(key_source), async_args.GetCommonKeyType(), async_args.GetKeyGeneration());
PrepareEsAesKey(access_key, sizeof(access_key), key, sizeof(key));
/* Copy the access key to output. */
std::memcpy(dst, access_key, sizeof(access_key));
return SmcResult::Success;
}
}
SmcResult SmcModularExponentiate(SmcArguments &args) {
return LockSecurityEngineAndInvokeAsync(args, ModularExponentiateImpl, GetModularExponentiateResult);
}
SmcResult SmcModularExponentiateByStorageKey(SmcArguments &args) {
return LockSecurityEngineAndInvokeAsync(args, ModularExponentiateByStorageKeyImpl, GetModularExponentiateResult);
}
SmcResult SmcPrepareEsDeviceUniqueKey(SmcArguments &args) {
return LockSecurityEngineAndInvokeAsync(args, PrepareEsDeviceUniqueKeyImpl, GetPrepareEsDeviceUniqueKeyResult);
}
}

View File

@@ -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 <exosphere.hpp>
#include "secmon_smc_common.hpp"
namespace ams::secmon::smc {
SmcResult SmcModularExponentiate(SmcArguments &args);
SmcResult SmcModularExponentiateByStorageKey(SmcArguments &args);
SmcResult SmcPrepareEsDeviceUniqueKey(SmcArguments &args);
}

View File

@@ -1,82 +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 "../secmon_error.hpp"
#include "secmon_smc_se_lock.hpp"
namespace ams::secmon::smc {
namespace {
constinit util::Atomic<bool> g_is_locked = false;
ALWAYS_INLINE bool TryLockSecurityEngineImpl() {
bool value = false;
return g_is_locked.CompareExchangeStrong(value, true);
}
ALWAYS_INLINE void UnlockSecurityEngineImpl() {
g_is_locked = false;
}
ALWAYS_INLINE bool IsSecurityEngineLockedImpl() {
return g_is_locked.Load();
}
}
bool TryLockSecurityEngine() {
return TryLockSecurityEngineImpl();
}
void UnlockSecurityEngine() {
return UnlockSecurityEngineImpl();
}
bool IsSecurityEngineLocked() {
return IsSecurityEngineLockedImpl();
}
SmcResult LockSecurityEngineAndInvoke(SmcArguments &args, SmcHandler impl) {
/* Try to lock the security engine. */
SMC_R_UNLESS(TryLockSecurityEngineImpl(), Busy);
ON_SCOPE_EXIT { UnlockSecurityEngineImpl(); };
return impl(args);
}
SmcResult LockSecurityEngineAndInvokeAsync(SmcArguments &args, SmcHandler impl, GetResultHandler result_handler) {
/* Try to lock the security engine. */
SMC_R_UNLESS(TryLockSecurityEngineImpl(), Busy);
auto se_guard = SCOPE_GUARD { UnlockSecurityEngineImpl(); };
/* Try to start an async operation. */
const u64 async_key = BeginAsyncOperation(result_handler);
SMC_R_UNLESS(async_key != InvalidAsyncKey, Busy);
auto async_guard = SCOPE_GUARD { CancelAsyncOperation(async_key); };
/* Try to invoke the operation. */
SMC_R_TRY(impl(args));
/* We succeeded! Cancel our guards, and return the async key to our caller. */
async_guard.Cancel();
se_guard.Cancel();
args.r[1] = async_key;
return SmcResult::Success;
}
}

View File

@@ -1,31 +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 <exosphere.hpp>
#include "secmon_smc_common.hpp"
#include "secmon_smc_handler.hpp"
#include "secmon_smc_result.hpp"
namespace ams::secmon::smc {
bool TryLockSecurityEngine();
void UnlockSecurityEngine();
bool IsSecurityEngineLocked();
SmcResult LockSecurityEngineAndInvoke(SmcArguments &args, SmcHandler impl);
SmcResult LockSecurityEngineAndInvokeAsync(SmcArguments &args, SmcHandler impl, GetResultHandler result_handler);
}