From cdcf55584e7e6b9be92a258d70d4d08a0216dbd0 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Thu, 4 Jan 2018 11:07:14 -0700 Subject: [PATCH] ARM: Tegra186: don't map memory not in RAM banks Tegra186 currently restricts its DRAM usage to entries in the /memory node in the DTB passed to it. However, the MMU configuration always maps the entire first 2GB of RAM. This could allow the CPU to speculatively access RAM that isn't part of the in-use banks. This patch switches to runtime construction of the table that's used to construct the MMU translation tables, and thus prevents access to RAM that's not part of a valid bank. Note: This patch is intended to prevent access to RAM regions which U-Boot does not need to access, with the primary purpose of avoiding theoretical speculative access to physical regions for which the HW will throw errors (e.g. carve-outs that the CPU has no permission to access at a bus level, bad ECC pages, etc.). In particular, this patch is not deliberately related to the speculation-related security issues that were recently announced. The apparent similarity is a coincidence. Signed-off-by: Stephen Warren Signed-off-by: Tom Warren --- arch/arm/mach-tegra/arm64-mmu.c | 3 +- arch/arm/mach-tegra/tegra186/nvtboot_mem.c | 78 +++++++++++++++------- 2 files changed, 55 insertions(+), 26 deletions(-) diff --git a/arch/arm/mach-tegra/arm64-mmu.c b/arch/arm/mach-tegra/arm64-mmu.c index a79a5192e0..3a126bdec4 100644 --- a/arch/arm/mach-tegra/arm64-mmu.c +++ b/arch/arm/mach-tegra/arm64-mmu.c @@ -12,7 +12,8 @@ #include #include -static struct mm_region tegra_mem_map[] = { +/* size: IO + NR_DRAM_BANKS + terminator */ +struct mm_region tegra_mem_map[1 + CONFIG_NR_DRAM_BANKS + 1] = { { .virt = 0x0UL, .phys = 0x0UL, diff --git a/arch/arm/mach-tegra/tegra186/nvtboot_mem.c b/arch/arm/mach-tegra/tegra186/nvtboot_mem.c index 33e331f4ca..2ca59747d4 100644 --- a/arch/arm/mach-tegra/tegra186/nvtboot_mem.c +++ b/arch/arm/mach-tegra/tegra186/nvtboot_mem.c @@ -8,6 +8,7 @@ #include #include #include +#include #define SZ_4G 0x100000000ULL @@ -28,6 +29,7 @@ DECLARE_GLOBAL_DATA_PTR; extern unsigned long nvtboot_boot_x0; +extern struct mm_region tegra_mem_map[]; /* * These variables are written to before relocation, and hence cannot be @@ -36,12 +38,6 @@ extern unsigned long nvtboot_boot_x0; * also has the nice side-effect of the content being valid after relocation. */ -/* A parsed version of /memory/reg from the DTB passed to U-Boot in x0 */ -static struct { - u64 start; - u64 size; -} ram_banks[CONFIG_NR_DRAM_BANKS] __attribute__((section(".data"))); - /* The number of valid entries in ram_banks[] */ static int ram_bank_count __attribute__((section(".data"))); @@ -62,8 +58,6 @@ int dram_init(void) int node, len, i; const u32 *prop; - memset(ram_banks, 0, sizeof(ram_banks)); - na = fdtdec_get_uint(nvtboot_blob, 0, "#address-cells", 2); ns = fdtdec_get_uint(nvtboot_blob, 0, "#size-cells", 2); @@ -81,36 +75,70 @@ int dram_init(void) /* Calculate the true # of base/size pairs to read */ len /= 4; /* Convert bytes to number of cells */ len /= (na + ns); /* Convert cells to number of banks */ - if (len > ARRAY_SIZE(ram_banks)) - len = ARRAY_SIZE(ram_banks); - ram_bank_count = len; + if (len > CONFIG_NR_DRAM_BANKS) + len = CONFIG_NR_DRAM_BANKS; + /* Parse the /memory node, and save useful entries */ gd->ram_size = 0; - for (i = 0; i < ram_bank_count; i++) { - u64 bank_end, usable_bank_size; + ram_bank_count = 0; + for (i = 0; i < len; i++) { + u64 bank_start, bank_end, bank_size, usable_bank_size; - ram_banks[i].start = fdt_read_number(prop, na); + /* Extract raw memory region data from DTB */ + bank_start = fdt_read_number(prop, na); prop += na; - ram_banks[i].size = fdt_read_number(prop, ns); + bank_size = fdt_read_number(prop, ns); prop += ns; - gd->ram_size += ram_banks[i].size; - debug("Bank %d: start: %llx size: %llx\n", i, - ram_banks[i].start, ram_banks[i].size); - - bank_end = ram_banks[i].start + ram_banks[i].size; - debug(" end %llx\n", bank_end); + gd->ram_size += bank_size; + bank_end = bank_start + bank_size; + debug("Bank %d: %llx..%llx (+%llx)\n", i, + bank_start, bank_end, bank_size); + + /* + * Align the bank to MMU section size. This is not strictly + * necessary, since the translation table construction code + * handles page granularity without issue. However, aligning + * the MMU entries reduces the size and number of levels in the + * page table, so is worth it. + */ + bank_start = ROUND(bank_start, SZ_2M); + bank_end = bank_end & ~(SZ_2M - 1); + bank_size = bank_end - bank_start; + debug(" aligned: %llx..%llx (+%llx)\n", + bank_start, bank_end, bank_size); + if (bank_end <= bank_start) + continue; + + /* Record data used to create MMU translation tables */ + ram_bank_count++; + /* Index below is deliberately 1-based to skip MMIO entry */ + tegra_mem_map[ram_bank_count].virt = bank_start; + tegra_mem_map[ram_bank_count].phys = bank_start; + tegra_mem_map[ram_bank_count].size = bank_size; + tegra_mem_map[ram_bank_count].attrs = + PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_INNER_SHARE; + + /* Determine best bank to relocate U-Boot into */ if (bank_end > SZ_4G) bank_end = SZ_4G; debug(" end %llx (usable)\n", bank_end); - usable_bank_size = bank_end - ram_banks[i].start; + usable_bank_size = bank_end - bank_start; debug(" size %llx (usable)\n", usable_bank_size); if ((usable_bank_size >= MIN_USABLE_RAM_SIZE) && (bank_end > ram_top)) { ram_top = bank_end; - region_base = ram_banks[i].start; + region_base = bank_start; debug("ram top now %llx\n", ram_top); } } + + /* Ensure memory map contains the desired sentinel entry */ + tegra_mem_map[ram_bank_count + 1].virt = 0; + tegra_mem_map[ram_bank_count + 1].phys = 0; + tegra_mem_map[ram_bank_count + 1].size = 0; + tegra_mem_map[ram_bank_count + 1].attrs = 0; + + /* Error out if a relocation target couldn't be found */ if (!ram_top) { pr_err("Can't find a usable RAM top"); hang(); @@ -129,8 +157,8 @@ int dram_init_banksize(void) } for (i = 0; i < ram_bank_count; i++) { - gd->bd->bi_dram[i].start = ram_banks[i].start; - gd->bd->bi_dram[i].size = ram_banks[i].size; + gd->bd->bi_dram[i].start = tegra_mem_map[1 + i].virt; + gd->bd->bi_dram[i].size = tegra_mem_map[1 + i].size; } #ifdef CONFIG_PCI -- 2.39.5