From 3f5f9b60ea59e291ed37708dc0c5309af658d5dc Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 15 Apr 2020 00:14:36 -0700 Subject: [PATCH] exosphere: ... --- exosphere/src/mc0.h | 32 ++++++++++ exosphere/src/mc1.h | 32 ++++++++++ exosphere/src/memory_map.h | 28 +++++---- exosphere/src/smc_api.c | 123 ++++++++++++++++++++++++++----------- 4 files changed, 169 insertions(+), 46 deletions(-) create mode 100644 exosphere/src/mc0.h create mode 100644 exosphere/src/mc1.h diff --git a/exosphere/src/mc0.h b/exosphere/src/mc0.h new file mode 100644 index 000000000..8e4f51848 --- /dev/null +++ b/exosphere/src/mc0.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef EXOSPHERE_MC0_H +#define EXOSPHERE_MC0_H + +#include +#include "memory_map.h" + +/* Exosphere driver for the Tegra X1 MC0. */ + +static inline uintptr_t get_mc0_base(void) { + return MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MC0); +} + +#define MC0_BASE (get_mc0_base()) +#define MAKE_MC0_REG(n) MAKE_REG32(MC0_BASE + n) + +#endif diff --git a/exosphere/src/mc1.h b/exosphere/src/mc1.h new file mode 100644 index 000000000..bcdfe03be --- /dev/null +++ b/exosphere/src/mc1.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef EXOSPHERE_MC0_H +#define EXOSPHERE_MC0_H + +#include +#include "memory_map.h" + +/* Exosphere driver for the Tegra X1 MC1. */ + +static inline uintptr_t get_mc1_base(void) { + return MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MC1); +} + +#define MC1_BASE (get_mc1_base()) +#define MAKE_MC1_REG(n) MAKE_REG32(MC1_BASE + n) + +#endif diff --git a/exosphere/src/memory_map.h b/exosphere/src/memory_map.h index 81c378eb1..aca65bf69 100644 --- a/exosphere/src/memory_map.h +++ b/exosphere/src/memory_map.h @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #ifndef EXOSPHERE_MEMORY_MAP_H #define EXOSPHERE_MEMORY_MAP_H @@ -48,9 +48,11 @@ #define _MMAPDEV15 ( 0x6000D000ull, 0x1000ull, true ) /* GPIO-1 - GPIO-8 */ #define _MMAPDEV16 ( 0x7000C000ull, 0x1000ull, true ) /* I2C-I2C4 */ #define _MMAPDEV17 ( 0x6000F000ull, 0x1000ull, true ) /* Exception vectors */ -#define _MMAPDEV18 ( 0x00000000ull, 0x1000ull, true ) /* AMS irampage, NOT mapped at startup */ -#define _MMAPDEV19 ( 0x00000000ull, 0x1000ull, true ) /* AMS userpage, NOT mapped at startup */ -#define _MMAPDEV20 ( 0x40038000ull, 0x5000ull, true ) /* DEBUG: IRAM */ +#define _MMAPDEV18 ( 0x7001C000ull, 0x1000ull, true ) /* MC0 */ +#define _MMAPDEV19 ( 0x7001D000ull, 0x1000ull, true ) /* MC1 */ +#define _MMAPDEV20 ( 0x00000000ull, 0x1000ull, true ) /* AMS irampage, NOT mapped at startup */ +#define _MMAPDEV21 ( 0x00000000ull, 0x1000ull, true ) /* AMS userpage, NOT mapped at startup */ +#define _MMAPDEV22 ( 0x40038000ull, 0x1000ull, true ) /* DEBUG: IRAM */ /* MMIO 7.0.0+. (addr). */ #define _MMAPDEV7X0 ( 0x50041000ull ) /* ARM Interrupt Distributor */ @@ -71,9 +73,11 @@ #define _MMAPDEV7X15 ( 0x6000D000ull ) /* GPIO-1 - GPIO-8 */ #define _MMAPDEV7X16 ( 0x7000C000ull ) /* I2C-I2C4 */ #define _MMAPDEV7X17 ( 0x6000F000ull ) /* Exception vectors */ -#define _MMAPDEV7X18 ( 0x00000000ull ) /* AMS irampage, NOT mapped at startup */ -#define _MMAPDEV7X19 ( 0x00000000ull ) /* AMS userpage, NOT mapped at startup */ -#define _MMAPDEV7X20 ( 0x40038000ull ) /* DEBUG: IRAM */ +#define _MMAPDEV7X18 ( 0x7001C000ull ) /* MC0 */ +#define _MMAPDEV7X19 ( 0x7001D000ull ) /* MC1 */ +#define _MMAPDEV7X20 ( 0x00000000ull ) /* AMS irampage, NOT mapped at startup */ +#define _MMAPDEV7X21 ( 0x00000000ull ) /* AMS userpage, NOT mapped at startup */ +#define _MMAPDEV7X22 ( 0x40038000ull ) /* DEBUG: IRAM */ /* LP0 entry ram segments (addr, size, additional attributes) */ #define _MMAPLP0ES0 ( 0x40020000ull, 0x10000ull, MMU_PTE_BLOCK_NS | ATTRIB_MEMTYPE_DEVICE ) /* Encrypted TZRAM */ @@ -133,10 +137,12 @@ #define MMIO_DEVID_GPIO 15 #define MMIO_DEVID_DTV_I2C234 16 #define MMIO_DEVID_EXCEPTION_VECTORS 17 -#define MMIO_DEVID_AMS_IRAM_PAGE 18 -#define MMIO_DEVID_AMS_USER_PAGE 19 -#define MMIO_DEVID_DEBUG_IRAM 20 -#define MMIO_DEVID_MAX 21 +#define MMIO_DEVID_MC0 18 +#define MMIO_DEVID_MC1 19 +#define MMIO_DEVID_AMS_IRAM_PAGE 20 +#define MMIO_DEVID_AMS_USER_PAGE 21 +#define MMIO_DEVID_DEBUG_IRAM 22 +#define MMIO_DEVID_MAX 23 #define LP0_ENTRY_RAM_SEGMENT_ID_ENCRYPTED_TZRAM 0 #define LP0_ENTRY_RAM_SEGMENT_ID_LP0_ENTRY_CODE 1 diff --git a/exosphere/src/smc_api.c b/exosphere/src/smc_api.c index 499928451..2338102ac 100644 --- a/exosphere/src/smc_api.c +++ b/exosphere/src/smc_api.c @@ -25,6 +25,8 @@ #include "synchronization.h" #include "masterkey.h" #include "mc.h" +#include "mc0.h" +#include "mc1.h" #include "memory_map.h" #include "pmc.h" #include "randomcache.h" @@ -617,7 +619,7 @@ uint32_t smc_read_write_register(smc_args_t *args) { } /* Check for PMC registers. */ if (0x7000E400 <= address && address <= 0x7000EFFF) { - const uint8_t pmc_whitelist[0x28] = { + static const uint8_t pmc_whitelist[0x28] = { 0xB9, 0xF9, 0x07, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0xC4, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x00, @@ -633,39 +635,83 @@ uint32_t smc_read_write_register(smc_args_t *args) { } else { return 2; } - } else if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400 && MMIO_GET_DEVICE_PA(MMIO_DEVID_MC) <= address && - address < MMIO_GET_DEVICE_PA(MMIO_DEVID_MC) + MMIO_GET_DEVICE_SIZE(MMIO_DEVID_MC)) { - /* Memory Controller RW supported only on 4.0.0+ */ - const uint8_t mc_whitelist[0x68] = { - 0x9F, 0x31, 0x30, 0x00, 0xF0, 0xFF, 0xF7, 0x01, - 0xCD, 0xFE, 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x40, 0x73, 0x3E, 0x2F, 0x00, 0x00, 0x6E, - 0x30, 0x05, 0x06, 0xB0, 0x71, 0xC8, 0x43, 0x04, - 0x80, 0x1F, 0x08, 0x80, 0x03, 0x00, 0x0E, 0x00, - 0x08, 0x00, 0xE0, 0x00, 0x0E, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x30, 0xF0, 0x03, 0x03, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x31, 0x00, 0x40, 0x00, 0x00, - 0x00, 0x03, 0x00, 0x00, 0xE4, 0xFF, 0xFF, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0xFE, 0x0F, - 0x01, 0x00, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00 - }; - uint32_t offset = (uint32_t)(address - 0x70019000); - uint32_t wl_ind = (offset >> 5); - /* If address is whitelisted, allow write. */ - if (wl_ind < sizeof(mc_whitelist) && (mc_whitelist[wl_ind] & (1 << ((offset >> 2) & 0x7)))) { - p_mmio = (volatile uint32_t *)(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MC) + offset); - } else { - /* These addresses are not allowed by the whitelist. */ - /* They correspond to SMMU DISABLE for the BPMP, and for APB-DMA. */ - /* However, smcReadWriteRegister returns 0 for these addresses despite not actually performing the write. */ - /* This is "probably" to fuck with hackers who got access to smcReadWriteRegister and are trying to get */ - /* control of the BPMP for jamais vu etc., since there's no other reason to return 0 despite failure. */ - if (address == 0x7001923C || address == 0x70019298) { - return 0; + } else { + if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_500) { + static const uint8_t mc_whitelist_5x[0xD00/(sizeof(uint32_t) * 8)] = { + 0x9F, 0x31, 0x30, 0x00, 0xF0, 0xFF, 0xF7, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x40, 0x73, 0x3E, 0x2F, 0x00, 0x00, 0x6E, + 0x30, 0x05, 0x06, 0xB0, 0x71, 0xC8, 0x43, 0x04, + 0x80, 0xFF, 0x08, 0x80, 0x03, 0x38, 0x8E, 0x1F, + 0xC8, 0xFF, 0xFF, 0x00, 0x0E, 0x00, 0x00, 0x00, + 0xF0, 0x1F, 0x00, 0x30, 0xF0, 0x03, 0x03, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x31, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xE4, 0xFF, 0xFF, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x0F, + 0x01, 0x00, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00 + }; + static const uint8_t mc01_whitelist_5x[0xC00/(sizeof(uint32_t) * 8)] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xCD, 0xFE, 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x06, 0x00, + }; + static const struct { + uint32_t phys_addr; + uint32_t size; + uint64_t virt_addr; + const uint8_t *whitelist; + } register_whitelists[3] = { + { MMIO_GET_DEVICE_PA(MMIO_DEVID_MC), sizeof(mc_whitelist_5x) * (sizeof(uint32_t) * 8), MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MC), mc_whitelist_5x }, + { MMIO_GET_DEVICE_PA(MMIO_DEVID_MC0), sizeof(mc01_whitelist_5x) * (sizeof(uint32_t) * 8), MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MC0), mc01_whitelist_5x }, + { MMIO_GET_DEVICE_PA(MMIO_DEVID_MC1), sizeof(mc01_whitelist_5x) * (sizeof(uint32_t) * 8), MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MC1), mc01_whitelist_5x }, + }; + for (unsigned int which = 0; which < 3; which++) { + if (register_whitelists[which].phys_addr <= address && address < register_whitelists[which].phys_addr + register_whitelists[which].size) { + uint32_t offset = (uint32_t)(address - register_whitelists[which].phys_addr); + uint32_t wl_ind = (offset >> 5); + /* If address is whitelisted, allow write. */ + if (register_whitelists[which].whitelist[wl_ind] & (1 << ((offset >> 2) & 0x7))) { + p_mmio = (volatile uint32_t *)(register_whitelists[which].virt_addr + offset); + } + break; + } + } + } else if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) { + if (MMIO_GET_DEVICE_PA(MMIO_DEVID_MC) <= address && address < MMIO_GET_DEVICE_PA(MMIO_DEVID_MC) + 0xD00) { + /* Memory Controller RW supported only on 4.0.0+ */ + static const uint8_t mc_whitelist[0x68] = { + 0x9F, 0x31, 0x30, 0x00, 0xF0, 0xFF, 0xF7, 0x01, + 0xCD, 0xFE, 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x40, 0x73, 0x3E, 0x2F, 0x00, 0x00, 0x6E, + 0x30, 0x05, 0x06, 0xB0, 0x71, 0xC8, 0x43, 0x04, + 0x80, 0x1F, 0x08, 0x80, 0x03, 0x00, 0x0E, 0x00, + 0x08, 0x00, 0xE0, 0x00, 0x0E, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x30, 0xF0, 0x03, 0x03, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x31, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0xE4, 0xFF, 0xFF, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0xFE, 0x0F, + 0x01, 0x00, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00 + }; + uint32_t offset = (uint32_t)(address - MMIO_GET_DEVICE_PA(MMIO_DEVID_MC)); + uint32_t wl_ind = (offset >> 5); + /* If address is whitelisted, allow write. */ + if (mc_whitelist[wl_ind] & (1 << ((offset >> 2) & 0x7))) { + p_mmio = (volatile uint32_t *)(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MC) + offset); + } } - return 2; } } @@ -684,9 +730,16 @@ uint32_t smc_read_write_register(smc_args_t *args) { /* Return old value. */ args->X[1] = old_value; return 0; + } else if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400 && (address == 0x7001923C || address == 0x70019298)) { + /* These addresses are not allowed by the whitelist. */ + /* They correspond to SMMU DISABLE for the BPMP, and for APB-DMA. */ + /* However, smcReadWriteRegister returns 0 for these addresses despite not actually performing the write. */ + /* This is "probably" to fuck with hackers who got access to smcReadWriteRegister and are trying to get */ + /* control of the BPMP for jamais vu etc., since there's no other reason to return 0 despite failure. */ + return 0; + } else { + return 2; } - - return 2; }