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;
}