summaryrefslogtreecommitdiffstats
path: root/arch/arm/cpu
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/cpu')
-rw-r--r--arch/arm/cpu/Kconfig20
-rw-r--r--arch/arm/cpu/Makefile31
-rw-r--r--arch/arm/cpu/atf.c176
-rw-r--r--arch/arm/cpu/board-dt-2nd-aarch64.S30
-rw-r--r--arch/arm/cpu/board-dt-2nd.c99
-rw-r--r--arch/arm/cpu/bootm-elf.c56
-rw-r--r--arch/arm/cpu/cache-armv4.S2
-rw-r--r--arch/arm/cpu/cache-armv5.S2
-rw-r--r--arch/arm/cpu/cache-armv6.S2
-rw-r--r--arch/arm/cpu/cache-armv7.S2
-rw-r--r--arch/arm/cpu/cache-l2x0.c2
-rw-r--r--arch/arm/cpu/cache_32.c (renamed from arch/arm/cpu/cache.c)87
-rw-r--r--arch/arm/cpu/cache_64.c16
-rw-r--r--arch/arm/cpu/common.c44
-rw-r--r--arch/arm/cpu/cpu.c24
-rw-r--r--arch/arm/cpu/cpuinfo.c61
-rw-r--r--arch/arm/cpu/dma_32.c19
-rw-r--r--arch/arm/cpu/dma_64.c15
-rw-r--r--arch/arm/cpu/dtb.c26
-rw-r--r--arch/arm/cpu/efi-header-aarch64.S122
-rw-r--r--arch/arm/cpu/entry.c7
-rw-r--r--arch/arm/cpu/entry.h2
-rw-r--r--arch/arm/cpu/entry_ll_32.S (renamed from arch/arm/cpu/entry_ll.S)2
-rw-r--r--arch/arm/cpu/entry_ll_64.S2
-rw-r--r--arch/arm/cpu/exceptions_32.S (renamed from arch/arm/cpu/exceptions.S)2
-rw-r--r--arch/arm/cpu/head_64.S33
-rw-r--r--arch/arm/cpu/hyp.S2
-rw-r--r--arch/arm/cpu/interrupts_32.c (renamed from arch/arm/cpu/interrupts.c)40
-rw-r--r--arch/arm/cpu/interrupts_64.c63
-rw-r--r--arch/arm/cpu/lowlevel_32.S (renamed from arch/arm/cpu/lowlevel.S)5
-rw-r--r--arch/arm/cpu/lowlevel_64.S2
-rw-r--r--arch/arm/cpu/mmu-common.c88
-rw-r--r--arch/arm/cpu/mmu-common.h20
-rw-r--r--arch/arm/cpu/mmu-early.c69
-rw-r--r--arch/arm/cpu/mmu-early_64.c91
-rw-r--r--arch/arm/cpu/mmu_32.c (renamed from arch/arm/cpu/mmu.c)421
-rw-r--r--arch/arm/cpu/mmu_32.h (renamed from arch/arm/cpu/mmu.h)21
-rw-r--r--arch/arm/cpu/mmu_64.c221
-rw-r--r--arch/arm/cpu/mmu_64.h20
-rw-r--r--arch/arm/cpu/mmuinfo.c136
-rw-r--r--arch/arm/cpu/mmuinfo_32.c80
-rw-r--r--arch/arm/cpu/mmuinfo_64.c215
-rw-r--r--arch/arm/cpu/no-mmu.c18
-rw-r--r--arch/arm/cpu/psci-client.c15
-rw-r--r--arch/arm/cpu/psci-of.c7
-rw-r--r--arch/arm/cpu/psci.c15
-rw-r--r--arch/arm/cpu/sections.c2
-rw-r--r--arch/arm/cpu/setupc_32.S (renamed from arch/arm/cpu/setupc.S)8
-rw-r--r--arch/arm/cpu/setupc_64.S37
-rw-r--r--arch/arm/cpu/sm.c3
-rw-r--r--arch/arm/cpu/sm_as.S2
-rw-r--r--arch/arm/cpu/smccc-call_32.S (renamed from arch/arm/cpu/smccc-call.S)16
-rw-r--r--arch/arm/cpu/smccc-call_64.S16
-rw-r--r--arch/arm/cpu/start.c118
-rw-r--r--arch/arm/cpu/uncompress.c38
55 files changed, 1690 insertions, 983 deletions
diff --git a/arch/arm/cpu/Kconfig b/arch/arm/cpu/Kconfig
index 6b4fed5269..e69acaacdf 100644
--- a/arch/arm/cpu/Kconfig
+++ b/arch/arm/cpu/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
comment "Processor Type"
config PHYS_ADDR_T_64BIT
@@ -6,14 +8,20 @@ config PHYS_ADDR_T_64BIT
config CPU_32
bool
select HAS_MODULES
+ select HAVE_MOD_ARCH_SPECIFIC
select HAS_DMA
select HAVE_PBL_IMAGE
+ select ARCH_HAS_ZERO_PAGE
config CPU_64
bool
select PHYS_ADDR_T_64BIT
select HAVE_PBL_IMAGE
+ select HAVE_PBL_MULTI_IMAGES
select HAS_DMA
+ select ARCH_WANT_FRAME_POINTERS
+ select ARCH_HAS_ZERO_PAGE
+ select HAVE_EFI_PAYLOAD
# Select CPU types depending on the architecture selected. This selects
# which CPUs we support in the kernel image, and the compiler instruction
@@ -84,7 +92,6 @@ config CPU_V7
config CPU_V8
bool
select CPU_64v8
- select CPU_SUPPORTS_64BIT_KERNEL
select ARM_EXCEPTIONS
select GENERIC_FIND_NEXT_BIT
select ARCH_HAS_STACK_DUMP
@@ -152,14 +159,3 @@ config CACHE_L2X0
bool "Enable L2x0 PrimeCell"
depends on MMU && ARCH_HAS_L2X0
-config SYS_SUPPORTS_32BIT_KERNEL
- bool
-
-config SYS_SUPPORTS_64BIT_KERNEL
- bool
-
-config CPU_SUPPORTS_32BIT_KERNEL
- bool
-
-config CPU_SUPPORTS_64BIT_KERNEL
- bool
diff --git a/arch/arm/cpu/Makefile b/arch/arm/cpu/Makefile
index f7f9c30415..28161cd7d7 100644
--- a/arch/arm/cpu/Makefile
+++ b/arch/arm/cpu/Makefile
@@ -1,19 +1,25 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
obj-y += cpu.o
-obj-$(CONFIG_ARM_EXCEPTIONS) += exceptions$(S64).o interrupts$(S64).o
-obj-$(CONFIG_MMU) += mmu$(S64).o mmu-common.o
-obj-pbl-y += lowlevel$(S64).o
-obj-pbl-$(CONFIG_MMU) += mmu-early$(S64).o
+obj-$(CONFIG_ARM_EXCEPTIONS) += exceptions_$(S64_32).o interrupts_$(S64_32).o
+obj-$(CONFIG_MMU) += mmu-common.o
+obj-pbl-$(CONFIG_MMU) += mmu_$(S64_32).o
+obj-$(CONFIG_MMU) += dma_$(S64_32).o
+obj-pbl-y += lowlevel_$(S64_32).o
obj-pbl-$(CONFIG_CPU_32v7) += hyp.o
AFLAGS_hyp.o :=-Wa,-march=armv7-a -Wa,-mcpu=all
AFLAGS_hyp.pbl.o :=-Wa,-march=armv7-a -Wa,-mcpu=all
-obj-y += start.o entry.o entry_ll$(S64).o
+obj-y += start.o entry.o entry_ll_$(S64_32).o
+KASAN_SANITIZE_start.o := n
+
+pbl-$(CONFIG_CPU_64) += head_64.o
pbl-$(CONFIG_BOARD_ARM_GENERIC_DT) += board-dt-2nd.o
pbl-$(CONFIG_BOARD_ARM_GENERIC_DT_AARCH64) += board-dt-2nd-aarch64.o
-obj-pbl-y += setupc$(S64).o cache$(S64).o
+obj-pbl-y += setupc_$(S64_32).o cache_$(S64_32).o
obj-$(CONFIG_ARM_PSCI_CLIENT) += psci-client.o
@@ -21,8 +27,9 @@ obj-$(CONFIG_ARM_PSCI_CLIENT) += psci-client.o
# Any variants can be called as start-armxyz.S
#
obj-$(CONFIG_CMD_ARM_CPUINFO) += cpuinfo.o
-obj-$(CONFIG_CMD_ARM_MMUINFO) += mmuinfo.o
+obj-$(CONFIG_MMUINFO) += mmuinfo.o mmuinfo_$(S64_32).o
obj-$(CONFIG_OFDEVICE) += dtb.o
+obj-$(CONFIG_BOOTM_ELF) += bootm-elf.o
ifeq ($(CONFIG_MMU),)
obj-$(CONFIG_CPU_32v7) += no-mmu.o
@@ -30,9 +37,9 @@ endif
obj-$(CONFIG_ARM_PSCI) += psci.o
obj-$(CONFIG_ARM_PSCI_OF) += psci-of.o
-obj-pbl-$(CONFIG_ARM_SMCCC) += smccc-call$(S64).o
-AFLAGS_smccc-call$(S64).o :=-Wa,-march=armv$(if $(S64),8,7)-a
-AFLAGS_smccc-call$(S64).pbl.o :=-Wa,-march=armv$(if $(S64),8,7)-a
+obj-pbl-$(CONFIG_ARM_SMCCC) += smccc-call_$(S64_32).o
+AFLAGS_smccc-call_$(S64_32).o :=-Wa,-march=armv$(if $(S64),8,7)-a
+AFLAGS_smccc-call_$(S64_32).pbl.o :=-Wa,-march=armv$(if $(S64),8,7)-a
obj-$(CONFIG_ARM_SECURE_MONITOR) += sm.o sm_as.o
AFLAGS_sm_as.o :=-Wa,-march=armv7-a
@@ -47,7 +54,9 @@ obj-pbl-$(CONFIG_CPU_64v8) += cache-armv8.o
AFLAGS_cache-armv8.o :=-Wa,-march=armv8-a
AFLAGS-cache-armv8.pbl.o :=-Wa,-march=armv8-a
-pbl-y += entry.o entry_ll$(S64).o
+pbl-y += entry.o entry_ll_$(S64_32).o
pbl-y += uncompress.o
+pbl-$(CONFIG_ARM_ATF) += atf.o
obj-pbl-y += common.o sections.o
+KASAN_SANITIZE_common.o := n
diff --git a/arch/arm/cpu/atf.c b/arch/arm/cpu/atf.c
new file mode 100644
index 0000000000..d01e20508c
--- /dev/null
+++ b/arch/arm/cpu/atf.c
@@ -0,0 +1,176 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <common.h>
+#include <asm/atf_common.h>
+#include <asm/system.h>
+
+static inline void raw_write_daif(unsigned int daif)
+{
+ __asm__ __volatile__("msr DAIF, %0\n\t" : : "r" (daif) : "memory");
+}
+
+void bl31_entry(uintptr_t bl31_entry, uintptr_t bl32_entry,
+ uintptr_t bl33_entry, uintptr_t fdt_addr)
+{
+ struct atf_image_info bl31_image_info = {
+ .h = {
+ .type = ATF_PARAM_IMAGE_BINARY,
+ .version = ATF_VERSION_1,
+ .size = sizeof(bl31_image_info),
+ },
+ };
+ struct atf_image_info bl32_image_info = {
+ .h = {
+ .type = ATF_PARAM_IMAGE_BINARY,
+ .version = ATF_VERSION_1,
+ .size = sizeof(bl32_image_info),
+ },
+ };
+ struct entry_point_info bl32_ep_info = {
+ .h = {
+ .type = ATF_PARAM_EP,
+ .version = ATF_VERSION_1,
+ .attr = ATF_EP_SECURE,
+ .size = sizeof(bl32_ep_info),
+ },
+ .pc = bl32_entry,
+ .spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXECPTIONS),
+ .args = {
+ .arg3 = fdt_addr,
+ },
+ };
+ struct atf_image_info bl33_image_info = {
+ .h = {
+ .type = ATF_PARAM_IMAGE_BINARY,
+ .version = ATF_VERSION_1,
+ .size = sizeof(bl33_image_info),
+ },
+ };
+ struct entry_point_info bl33_ep_info = {
+ .h = {
+ .type = ATF_PARAM_EP,
+ .version = ATF_VERSION_1,
+ .attr = ATF_EP_NON_SECURE,
+ .size = sizeof(bl33_ep_info),
+ },
+ .pc = bl33_entry,
+ .spsr = SPSR_64(MODE_EL2, MODE_SP_ELX, DISABLE_ALL_EXECPTIONS),
+ .args = {
+ /* BL33 expects to receive the primary CPU MPID (through x0) */
+ .arg0 = 0xffff & read_mpidr(),
+ },
+ };
+ struct bl31_params bl31_params = {
+ .h = {
+ .type = ATF_PARAM_BL31,
+ .version = ATF_VERSION_1,
+ .size = sizeof(bl31_params),
+ },
+ .bl31_image_info = &bl31_image_info,
+ .bl32_ep_info = &bl32_ep_info,
+ .bl32_image_info = &bl32_image_info,
+ .bl33_ep_info = &bl33_ep_info,
+ .bl33_image_info = &bl33_image_info,
+ };
+ void (*atf_entry)(struct bl31_params *params, uintptr_t plat_params);
+
+ raw_write_daif(SPSR_EXCEPTION_MASK);
+
+ atf_entry = (void *)bl31_entry;
+
+ atf_entry(&bl31_params, fdt_addr);
+}
+
+struct bl2_to_bl31_params_mem_v2 *bl2_plat_get_bl31_params_v2(uintptr_t bl32_entry,
+ uintptr_t bl33_entry, uintptr_t fdt_addr)
+{
+ static struct bl2_to_bl31_params_mem_v2 p = {
+ .bl_params = {
+ .h = {
+ .type = ATF_PARAM_BL_PARAMS,
+ .version = ATF_VERSION_2,
+ .size = sizeof(struct bl_params),
+ .attr = 0,
+ },
+ .head = &p.bl31_params_node,
+ },
+ .bl31_params_node = {
+ .image_id = ATF_BL31_IMAGE_ID,
+ .image_info = &p.bl31_image_info,
+ .ep_info = &p.bl31_ep_info,
+ .next_params_info = &p.bl32_params_node,
+ },
+ .bl32_params_node = {
+ .image_id = ATF_BL32_IMAGE_ID,
+ .image_info = &p.bl32_image_info,
+ .ep_info = &p.bl32_ep_info,
+ .next_params_info = &p.bl33_params_node,
+ },
+ .bl33_params_node = {
+ .image_id = ATF_BL33_IMAGE_ID,
+ .image_info = &p.bl33_image_info,
+ .ep_info = &p.bl33_ep_info,
+ .next_params_info = NULL,
+ },
+ .bl32_ep_info = {
+ .h = {
+ .type = ATF_PARAM_EP,
+ .version = ATF_VERSION_2,
+ .size = sizeof(struct entry_point_info),
+ .attr = ATF_EP_SECURE,
+ },
+ .spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXECPTIONS),
+ },
+ .bl33_ep_info = {
+ .h = {
+ .type = ATF_PARAM_EP,
+ .version = ATF_VERSION_2,
+ .size = sizeof(struct entry_point_info),
+ .attr = ATF_EP_NON_SECURE,
+ },
+ .spsr = SPSR_64(MODE_EL2, MODE_SP_ELX, DISABLE_ALL_EXECPTIONS),
+ },
+ .bl33_image_info = {
+ .h = {
+ .type = ATF_PARAM_IMAGE_BINARY,
+ .version = ATF_VERSION_2,
+ .size = sizeof(struct atf_image_info),
+ .attr = 0,
+ },
+ },
+ .bl32_image_info = {
+ .h = {
+ .type = ATF_PARAM_IMAGE_BINARY,
+ .version = ATF_VERSION_2,
+ .size = sizeof(struct atf_image_info),
+ .attr = ATF_EP_SECURE,
+ },
+ },
+ .bl31_image_info = {
+ .h = {
+ .type = ATF_PARAM_IMAGE_BINARY,
+ .version = ATF_VERSION_2,
+ .size = sizeof(struct atf_image_info),
+ .attr = 0,
+ },
+ },
+ };
+
+ p.bl33_ep_info.args.arg0 = 0xffff & read_mpidr();
+ p.bl33_ep_info.pc = bl33_entry;
+ p.bl32_ep_info.args.arg3 = fdt_addr;
+ p.bl32_ep_info.pc = bl32_entry;
+
+ return &p;
+}
+
+void bl31_entry_v2(uintptr_t bl31_entry, struct bl_params *params, void *fdt_addr)
+{
+ void (*atf_entry)(struct bl_params *params, uintptr_t plat_params);
+
+ raw_write_daif(SPSR_EXCEPTION_MASK);
+
+ atf_entry = (void *)bl31_entry;
+
+ atf_entry(params, (uintptr_t)fdt_addr);
+}
diff --git a/arch/arm/cpu/board-dt-2nd-aarch64.S b/arch/arm/cpu/board-dt-2nd-aarch64.S
index 0540a1690d..030366c1cb 100644
--- a/arch/arm/cpu/board-dt-2nd-aarch64.S
+++ b/arch/arm/cpu/board-dt-2nd-aarch64.S
@@ -1,11 +1,33 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include <linux/linkage.h>
#include <asm/barebox-arm64.h>
+#include <asm/image.h>
+#include "efi-header-aarch64.S"
-ENTRY_PROC(start_dt_2nd)
- adr x1, stack
+#define IMAGE_FLAGS \
+ (ARM64_IMAGE_FLAG_PAGE_SIZE_4K << ARM64_IMAGE_FLAG_PAGE_SIZE_SHIFT) | \
+ (ARM64_IMAGE_FLAG_PHYS_BASE << ARM64_IMAGE_FLAG_PHYS_BASE_SHIFT)
+
+.section .text_head_entry_start_dt_2nd
+ENTRY("start_dt_2nd")
+ efi_signature_nop /* code0 */
+ b 2f /* code1 */
+ .xword 0x80000 /* Image load offset */
+ .xword _barebox_image_size /* Effective Image size */
+ .xword IMAGE_FLAGS /* Kernel flags */
+ .xword 0 /* reserved */
+ .xword 0 /* reserved */
+ .xword 0 /* reserved */
+ .ascii ARM64_IMAGE_MAGIC /* magic number */
+ .int .Lpe_header_offset /* reserved (PE-COFF offset) */
+ .asciz "barebox" /* unused for now */
+2:
+ adr x1, 0
mov sp, x1
+ /* Stack now grows into the 0x80000 image load offset specified
+ * above. This is more than enough until FDT /memory is decoded.
+ */
b dt_2nd_aarch64
-.word 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
-stack:
+
+ __EFI_PE_HEADER
ENTRY_PROC_END(start_dt_2nd)
diff --git a/arch/arm/cpu/board-dt-2nd.c b/arch/arm/cpu/board-dt-2nd.c
index 4e7d575e8a..6f69a6dd27 100644
--- a/arch/arm/cpu/board-dt-2nd.c
+++ b/arch/arm/cpu/board-dt-2nd.c
@@ -8,101 +8,32 @@
#include <debug_ll.h>
#include <asm/cache.h>
#include <asm/sections.h>
-#include <linux/libfdt.h>
-
-static void of_find_mem(void *fdt, unsigned long *membase, unsigned long *memsize)
-{
- const __be32 *nap, *nsp, *reg;
- uint32_t na, ns;
- uint64_t memsize64, membase64;
- int node, size, i;
-
- /* Make sure FDT blob is sane */
- if (fdt_check_header(fdt) != 0) {
- pr_err("Invalid device tree blob\n");
- goto err;
- }
-
- /* Find the #address-cells and #size-cells properties */
- node = fdt_path_offset(fdt, "/");
- if (node < 0) {
- pr_err("Cannot find root node\n");
- goto err;
- }
-
- nap = fdt_getprop(fdt, node, "#address-cells", &size);
- if (!nap || (size != 4)) {
- pr_err("Cannot find #address-cells property");
- goto err;
- }
- na = fdt32_to_cpu(*nap);
-
- nsp = fdt_getprop(fdt, node, "#size-cells", &size);
- if (!nsp || (size != 4)) {
- pr_err("Cannot find #size-cells property");
- goto err;
- }
- ns = fdt32_to_cpu(*nap);
-
- /* Find the memory range */
- node = fdt_node_offset_by_prop_value(fdt, -1, "device_type",
- "memory", sizeof("memory"));
- if (node < 0) {
- pr_err("Cannot find memory node\n");
- goto err;
- }
-
- reg = fdt_getprop(fdt, node, "reg", &size);
- if (size < (na + ns) * sizeof(u32)) {
- pr_err("cannot get memory range\n");
- goto err;
- }
-
- membase64 = 0;
- for (i = 0; i < na; i++)
- membase64 = (membase64 << 32) | fdt32_to_cpu(*reg++);
-
- /* get the memsize and truncate it to under 4G on 32 bit machines */
- memsize64 = 0;
- for (i = 0; i < ns; i++)
- memsize64 = (memsize64 << 32) | fdt32_to_cpu(*reg++);
-
- *membase = membase64;
- *memsize = memsize64;
-
- return;
-err:
- pr_err("No memory, cannot continue\n");
- while (1);
-}
+#include <pbl.h>
#ifdef CONFIG_CPU_V8
-static noinline void dt_2nd_continue_aarch64(void *fdt)
-{
- unsigned long membase, memsize;
-
- if (!fdt)
- hang();
-
- of_find_mem(fdt, &membase, &memsize);
-
- barebox_arm_entry(membase, memsize, fdt);
-}
-
/* called from assembly */
void dt_2nd_aarch64(void *fdt);
void dt_2nd_aarch64(void *fdt)
{
- unsigned long image_start = (unsigned long)_text + global_variable_offset();
+ unsigned long membase, memsize;
- arm_setup_stack(image_start);
+ putc_ll('>');
+
+ /* entry point already set up stack */
+
+ arm_cpu_lowlevel_init();
relocate_to_current_adr();
setup_c();
- dt_2nd_continue_aarch64(fdt);
+ if (!fdt)
+ hang();
+
+ fdt_find_mem(fdt, &membase, &memsize);
+
+ barebox_arm_entry(membase, memsize, fdt);
}
#else
@@ -114,7 +45,7 @@ static noinline void dt_2nd_continue(void *fdt)
if (!fdt)
hang();
- of_find_mem(fdt, &membase, &memsize);
+ fdt_find_mem(fdt, &membase, &memsize);
barebox_arm_entry(membase, memsize, fdt);
}
@@ -123,6 +54,8 @@ ENTRY_FUNCTION(start_dt_2nd, r0, r1, r2)
{
unsigned long image_start = (unsigned long)_text + global_variable_offset();
+ arm_cpu_lowlevel_init();
+
arm_setup_stack(image_start);
relocate_to_current_adr();
diff --git a/arch/arm/cpu/bootm-elf.c b/arch/arm/cpu/bootm-elf.c
new file mode 100644
index 0000000000..bcca3931f2
--- /dev/null
+++ b/arch/arm/cpu/bootm-elf.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#define pr_fmt(fmt) "ELF: " fmt
+
+#include <bootm.h>
+#include <elf.h>
+#include <common.h>
+#include <init.h>
+#include <errno.h>
+
+static int do_bootm_elf(struct image_data *data)
+{
+ void (*fn)(unsigned long x0, unsigned long x1, unsigned long x2,
+ unsigned long x3);
+ struct elf_image *elf = data->elf;
+ int ret;
+
+ if (elf_hdr_e_machine(elf, elf->hdr_buf) != ELF_ARCH) {
+ pr_err("Unsupported machine: 0x%02x, but 0x%02x expected\n",
+ elf_hdr_e_machine(elf, elf->hdr_buf), ELF_ARCH);
+
+ return -EINVAL;
+ }
+
+ ret = bootm_load_os(data, data->os_address);
+ if (ret)
+ return ret;
+
+ if (data->dryrun)
+ return ret;
+
+ ret = of_overlay_load_firmware();
+ if (ret)
+ return ret;
+
+ shutdown_barebox();
+
+ fn = (void *) (unsigned long) data->os_address;
+
+ fn(0, 0, 0, 0);
+
+ pr_err("ELF application terminated\n");
+ return -EINVAL;
+}
+
+static struct image_handler elf_handler = {
+ .name = "ELF",
+ .bootm = do_bootm_elf,
+ .filetype = filetype_elf,
+};
+
+static int arm_register_elf_image_handler(void)
+{
+ return register_image_handler(&elf_handler);
+}
+late_initcall(arm_register_elf_image_handler);
diff --git a/arch/arm/cpu/cache-armv4.S b/arch/arm/cpu/cache-armv4.S
index db87de17e9..78a098b2fe 100644
--- a/arch/arm/cpu/cache-armv4.S
+++ b/arch/arm/cpu/cache-armv4.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
#include <linux/linkage.h>
#include <init.h>
diff --git a/arch/arm/cpu/cache-armv5.S b/arch/arm/cpu/cache-armv5.S
index 4267f3e37f..bcb7ebf466 100644
--- a/arch/arm/cpu/cache-armv5.S
+++ b/arch/arm/cpu/cache-armv5.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
#include <linux/linkage.h>
#include <init.h>
diff --git a/arch/arm/cpu/cache-armv6.S b/arch/arm/cpu/cache-armv6.S
index 7a06751997..cc720314c0 100644
--- a/arch/arm/cpu/cache-armv6.S
+++ b/arch/arm/cpu/cache-armv6.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
#include <linux/linkage.h>
#include <init.h>
diff --git a/arch/arm/cpu/cache-armv7.S b/arch/arm/cpu/cache-armv7.S
index 0f6108426c..efd9fe412f 100644
--- a/arch/arm/cpu/cache-armv7.S
+++ b/arch/arm/cpu/cache-armv7.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
#include <linux/linkage.h>
#include <init.h>
diff --git a/arch/arm/cpu/cache-l2x0.c b/arch/arm/cpu/cache-l2x0.c
index e975ecffc7..82ae16ba4d 100644
--- a/arch/arm/cpu/cache-l2x0.c
+++ b/arch/arm/cpu/cache-l2x0.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
#define pr_fmt(fmt) "l2x0: " fmt
#include <common.h>
diff --git a/arch/arm/cpu/cache.c b/arch/arm/cpu/cache_32.c
index 2b6e958a4e..0ac50c4d9a 100644
--- a/arch/arm/cpu/cache.c
+++ b/arch/arm/cpu/cache_32.c
@@ -1,10 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
#include <common.h>
#include <init.h>
#include <asm/mmu.h>
#include <asm/cache.h>
#include <asm/system_info.h>
-#include "mmu.h"
+#include "mmu_32.h"
struct cache_fns {
void (*dma_clean_range)(unsigned long start, unsigned long end);
@@ -15,8 +17,6 @@ struct cache_fns {
void (*mmu_cache_flush)(void);
};
-struct cache_fns *cache_fns;
-
#define DEFINE_CPU_FNS(arch) \
void arch##_dma_clean_range(unsigned long start, unsigned long end); \
void arch##_dma_flush_range(unsigned long start, unsigned long end); \
@@ -39,50 +39,13 @@ DEFINE_CPU_FNS(v5)
DEFINE_CPU_FNS(v6)
DEFINE_CPU_FNS(v7)
-void __dma_clean_range(unsigned long start, unsigned long end)
+static struct cache_fns *cache_functions(void)
{
- if (cache_fns)
- cache_fns->dma_clean_range(start, end);
-}
+ static struct cache_fns *cache_fns;
-void __dma_flush_range(unsigned long start, unsigned long end)
-{
if (cache_fns)
- cache_fns->dma_flush_range(start, end);
-}
+ return cache_fns;
-void __dma_inv_range(unsigned long start, unsigned long end)
-{
- if (cache_fns)
- cache_fns->dma_inv_range(start, end);
-}
-
-#ifdef CONFIG_MMU
-
-void __mmu_cache_on(void)
-{
- if (cache_fns)
- cache_fns->mmu_cache_on();
-}
-
-void __mmu_cache_off(void)
-{
- if (cache_fns)
- cache_fns->mmu_cache_off();
-}
-
-void __mmu_cache_flush(void)
-{
- if (cache_fns)
- cache_fns->mmu_cache_flush();
- if (outer_cache.flush_all)
- outer_cache.flush_all();
-}
-
-#endif
-
-int arm_set_cache_functions(void)
-{
switch (cpu_architecture()) {
#ifdef CONFIG_CPU_32v4T
case CPU_ARCH_ARMv4T:
@@ -111,9 +74,45 @@ int arm_set_cache_functions(void)
while(1);
}
- return 0;
+ return cache_fns;
+}
+
+void __dma_clean_range(unsigned long start, unsigned long end)
+{
+ cache_functions()->dma_clean_range(start, end);
+}
+
+void __dma_flush_range(unsigned long start, unsigned long end)
+{
+ cache_functions()->dma_flush_range(start, end);
+}
+
+void __dma_inv_range(unsigned long start, unsigned long end)
+{
+ cache_functions()->dma_inv_range(start, end);
+}
+
+#ifdef CONFIG_MMU
+
+void __mmu_cache_on(void)
+{
+ cache_functions()->mmu_cache_on();
+}
+
+void __mmu_cache_off(void)
+{
+ cache_functions()->mmu_cache_off();
}
+void __mmu_cache_flush(void)
+{
+ cache_functions()->mmu_cache_flush();
+ if (outer_cache.flush_all)
+ outer_cache.flush_all();
+}
+
+#endif
+
/*
* Early function to flush the caches. This is for use when the
* C environment is not yet fully initialized.
diff --git a/arch/arm/cpu/cache_64.c b/arch/arm/cpu/cache_64.c
index 6e18d981a4..3a30296128 100644
--- a/arch/arm/cpu/cache_64.c
+++ b/arch/arm/cpu/cache_64.c
@@ -1,13 +1,4 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; version 2.
- *
- * This program is distributed in the hope that 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.
- */
+// SPDX-License-Identifier: GPL-2.0-only
#include <common.h>
#include <init.h>
@@ -15,11 +6,6 @@
#include <asm/cache.h>
#include <asm/system_info.h>
-int arm_set_cache_functions(void)
-{
- return 0;
-}
-
/*
* Early function to flush the caches. This is for use when the
* C environment is not yet fully initialized.
diff --git a/arch/arm/cpu/common.c b/arch/arm/cpu/common.c
index bc5d9b5882..e9118b450d 100644
--- a/arch/arm/cpu/common.c
+++ b/arch/arm/cpu/common.c
@@ -1,16 +1,5 @@
-/*
- * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that 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.
- *
- */
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2010 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
#include <common.h>
#include <init.h>
@@ -34,6 +23,12 @@
*/
void sync_caches_for_execution(void)
{
+ /* if caches are disabled, don't do data cache maintenance */
+ if (!(get_cr() & CR_C)) {
+ icache_invalidate();
+ return;
+ }
+
/*
* Despite the name arm_early_mmu_cache_flush not only flushes the
* data cache, but also invalidates the instruction cache.
@@ -64,18 +59,21 @@ void pbl_barebox_break(void)
/*
* relocate binary to the currently running address
*/
-void relocate_to_current_adr(void)
+void __prereloc relocate_to_current_adr(void)
{
- unsigned long offset, offset_var;
+ unsigned long offset;
unsigned long __maybe_unused *dynsym, *dynend;
void *dstart, *dend;
/* Get offset between linked address and runtime address */
offset = get_runtime_offset();
- offset_var = global_variable_offset();
- dstart = (void *)__rel_dyn_start + offset_var;
- dend = (void *)__rel_dyn_end + offset_var;
+ /*
+ * We have yet to relocate, so using runtime_address
+ * to compute the relocated address
+ */
+ dstart = runtime_address(__rel_dyn_start);
+ dend = runtime_address(__rel_dyn_end);
#if defined(CONFIG_CPU_64)
while (dstart < dend) {
@@ -95,14 +93,14 @@ void relocate_to_current_adr(void)
putc_ll(' ');
puthex_ll(rel->r_addend);
putc_ll('\n');
- panic("");
+ __hang();
}
dstart += sizeof(*rel);
}
#elif defined(CONFIG_CPU_32)
- dynsym = (void *)__dynsym_start + offset_var;
- dynend = (void *)__dynsym_end + offset_var;
+ dynsym = runtime_address(__dynsym_start);
+ dynend = runtime_address(__dynsym_end);
while (dstart < dend) {
struct elf32_rel *rel = dstart;
@@ -125,13 +123,13 @@ void relocate_to_current_adr(void)
putc_ll(' ');
puthex_ll(rel->r_offset);
putc_ll('\n');
- panic("");
+ __hang();
}
dstart += sizeof(*rel);
}
- memset(dynsym, 0, (unsigned long)dynend - (unsigned long)dynsym);
+ __memset(dynsym, 0, (unsigned long)dynend - (unsigned long)dynsym);
#else
#error "Architecture not specified"
#endif
diff --git a/arch/arm/cpu/cpu.c b/arch/arm/cpu/cpu.c
index 0db852b33d..5f1ffe9a3c 100644
--- a/arch/arm/cpu/cpu.c
+++ b/arch/arm/cpu/cpu.c
@@ -1,17 +1,5 @@
-/*
- * cpu.c - A few helper functions for ARM
- *
- * Copyright (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that 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.
- */
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
/**
* @file
@@ -29,8 +17,7 @@
#include <asm/cputype.h>
#include <asm/cache.h>
#include <asm/ptrace.h>
-
-#include "mmu.h"
+#include <efi/efi-mode.h>
/**
* Enable processor's instruction cache
@@ -96,6 +83,8 @@ static void disable_interrupts(void)
*/
static void arch_shutdown(void)
{
+ if (efi_is_payload())
+ return;
#ifdef CONFIG_MMU
mmu_disable();
@@ -110,6 +99,9 @@ extern unsigned long arm_stack_top;
static int arm_request_stack(void)
{
+ if (efi_is_payload())
+ return 0;
+
if (!request_sdram_region("stack", arm_stack_top - STACK_SIZE, STACK_SIZE))
pr_err("Error: Cannot request SDRAM region for stack\n");
diff --git a/arch/arm/cpu/cpuinfo.c b/arch/arm/cpu/cpuinfo.c
index dd67b51ac2..2d3fe2ac8d 100644
--- a/arch/arm/cpu/cpuinfo.c
+++ b/arch/arm/cpu/cpuinfo.c
@@ -1,19 +1,10 @@
-/*
- * cpuinfo.c - Show information about cp15 registers
- *
- * Copyright (c) 2009 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that 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.
- */
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2009 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+
+/* cpuinfo.c - Show information about cp15 registers */
#include <common.h>
+#include <getopt.h>
#include <command.h>
#include <complete.h>
#include <asm/system.h>
@@ -37,6 +28,7 @@
#define ARM_CPU_PART_CORTEX_A15 0xC0F0
#define ARM_CPU_PART_CORTEX_A53 0xD030
#define ARM_CPU_PART_CORTEX_A57 0xD070
+#define ARM_CPU_PART_CORTEX_A72 0xD080
static void decode_cache(unsigned long size)
{
@@ -58,9 +50,23 @@ static int do_cpuinfo(int argc, char *argv[])
{
unsigned long mainid, cache, cr;
char *architecture, *implementer;
- int i;
+ int opt, i;
int cpu_arch;
+ while ((opt = getopt(argc, argv, "s")) > 0) {
+ switch (opt) {
+ case 's':
+ if (!IS_ENABLED(CONFIG_ARCH_HAS_STACK_DUMP))
+ return -ENOSYS;
+
+ printf("SP: 0x%08lx\n", get_sp());
+ dump_stack();
+ return 0;
+ default:
+ return COMMAND_ERROR_USAGE;
+ }
+ }
+
#ifdef CONFIG_CPU_64v8
__asm__ __volatile__(
"mrs %0, midr_el1\n"
@@ -201,7 +207,7 @@ static int do_cpuinfo(int argc, char *argv[])
if (cpu_arch >= CPU_ARCH_ARMv7) {
unsigned int major, minor;
- char *part;
+ const char *part = NULL;
major = (mainid >> 20) & 0xf;
minor = mainid & 0xf;
switch (mainid & 0xfff0) {
@@ -226,12 +232,23 @@ static int do_cpuinfo(int argc, char *argv[])
case ARM_CPU_PART_CORTEX_A57:
part = "Cortex-A57";
break;
+ case ARM_CPU_PART_CORTEX_A72:
+ part = "Cortex-A72";
+ break;
default:
- part = "unknown";
+ printf("core: unknown (0x%08lx) r%up%u\n",
+ mainid, major, minor);
+ break;
}
- printf("core: %s r%up%u\n", part, major, minor);
+
+ if (part)
+ printf("core: %s r%up%u\n", part, major, minor);
}
+#ifdef CONFIG_CPU_64v8
+ printf("exception level: %u\n", current_el());
+#endif
+
if (cache & (1 << 24)) {
/* separate I/D cache */
printf("I-cache: ");
@@ -253,10 +270,16 @@ static int do_cpuinfo(int argc, char *argv[])
return 0;
}
+BAREBOX_CMD_HELP_START(cpuinfo)
+BAREBOX_CMD_HELP_TEXT("Shows misc info about CPU")
+BAREBOX_CMD_HELP_OPT ("-s", "print call stack info (if supported)")
+BAREBOX_CMD_HELP_END
+
BAREBOX_CMD_START(cpuinfo)
.cmd = do_cpuinfo,
BAREBOX_CMD_DESC("show info about CPU")
+ BAREBOX_CMD_OPTS("[-s]")
BAREBOX_CMD_GROUP(CMD_GRP_INFO)
BAREBOX_CMD_COMPLETE(empty_complete)
+ BAREBOX_CMD_HELP(cmd_cpuinfo_help)
BAREBOX_CMD_END
-
diff --git a/arch/arm/cpu/dma_32.c b/arch/arm/cpu/dma_32.c
new file mode 100644
index 0000000000..842ea7033a
--- /dev/null
+++ b/arch/arm/cpu/dma_32.c
@@ -0,0 +1,19 @@
+#include <dma.h>
+#include <asm/mmu.h>
+
+void arch_sync_dma_for_device(void *vaddr, size_t size,
+ enum dma_data_direction dir)
+{
+ unsigned long start = (unsigned long)vaddr;
+ unsigned long end = start + size;
+
+ if (dir == DMA_FROM_DEVICE) {
+ __dma_inv_range(start, end);
+ if (outer_cache.inv_range)
+ outer_cache.inv_range(start, end);
+ } else {
+ __dma_clean_range(start, end);
+ if (outer_cache.clean_range)
+ outer_cache.clean_range(start, end);
+ }
+}
diff --git a/arch/arm/cpu/dma_64.c b/arch/arm/cpu/dma_64.c
new file mode 100644
index 0000000000..74d7167860
--- /dev/null
+++ b/arch/arm/cpu/dma_64.c
@@ -0,0 +1,15 @@
+#include <dma.h>
+#include <asm/mmu.h>
+#include <asm/cache.h>
+
+void arch_sync_dma_for_device(void *vaddr, size_t size,
+ enum dma_data_direction dir)
+{
+ unsigned long start = (unsigned long)vaddr;
+ unsigned long end = start + size - 1;
+
+ if (dir == DMA_FROM_DEVICE)
+ v8_inv_dcache_range(start, end);
+ else
+ v8_flush_dcache_range(start, end);
+}
diff --git a/arch/arm/cpu/dtb.c b/arch/arm/cpu/dtb.c
index 1d126a827d..9aa979ca08 100644
--- a/arch/arm/cpu/dtb.c
+++ b/arch/arm/cpu/dtb.c
@@ -1,16 +1,6 @@
-/*
- * Copyright (c) 2013 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that 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.
- *
- */
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2013 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+
#include <common.h>
#include <init.h>
#include <of.h>
@@ -36,14 +26,6 @@ static int of_arm_init(void)
return 0;
}
- root = of_unflatten_dtb(fdt);
- if (!IS_ERR(root)) {
- of_set_root_node(root);
- of_fix_tree(root);
- if (IS_ENABLED(CONFIG_OFDEVICE))
- of_probe();
- }
-
- return 0;
+ return barebox_register_fdt(fdt);
}
core_initcall(of_arm_init);
diff --git a/arch/arm/cpu/efi-header-aarch64.S b/arch/arm/cpu/efi-header-aarch64.S
new file mode 100644
index 0000000000..941d0d8fdc
--- /dev/null
+++ b/arch/arm/cpu/efi-header-aarch64.S
@@ -0,0 +1,122 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2013 - 2017 Linaro, Ltd.
+ * Copyright (C) 2013, 2014 Red Hat, Inc.
+ */
+
+#include <linux/pe.h>
+#include <linux/sizes.h>
+#include <asm/memory.h>
+
+ .macro efi_signature_nop
+#ifdef CONFIG_EFI_STUB
+.L_head:
+ /*
+ * This ccmp instruction has no meaningful effect except that
+ * its opcode forms the magic "MZ" signature required by UEFI.
+ */
+ ccmp x18, #0, #0xd, pl
+#else
+ /*
+ * Bootloaders may inspect the opcode at the start of the kernel
+ * image to decide if the kernel is capable of booting via UEFI.
+ * So put an ordinary NOP here, not the "MZ.." pseudo-nop above.
+ */
+ nop
+#endif
+ .endm
+
+ .macro __EFI_PE_HEADER
+#ifdef CONFIG_EFI_STUB
+ .set .Lpe_header_offset, . - .L_head
+ .long PE_MAGIC
+ .short IMAGE_FILE_MACHINE_ARM64 // Machine
+ .short .Lsection_count // NumberOfSections
+ .long 0 // TimeDateStamp
+ .long 0 // PointerToSymbolTable
+ .long 0 // NumberOfSymbols
+ .short .Lsection_table - .Loptional_header // SizeOfOptionalHeader
+ .short IMAGE_FILE_DEBUG_STRIPPED | \
+ IMAGE_FILE_EXECUTABLE_IMAGE | \
+ IMAGE_FILE_LINE_NUMS_STRIPPED // Characteristics
+
+.Loptional_header:
+ .short PE_OPT_MAGIC_PE32PLUS // PE32+ format
+ .byte 0x02 // MajorLinkerVersion
+ .byte 0x14 // MinorLinkerVersion
+ .long _sdata - .Lefi_header_end // SizeOfCode
+ .long __pecoff_data_size // SizeOfInitializedData
+ .long 0 // SizeOfUninitializedData
+ .long __efistub_efi_pe_entry - .L_head // AddressOfEntryPoint
+ .long .Lefi_header_end - .L_head // BaseOfCode
+
+ .quad 0 // ImageBase
+ .long PBL_SEGMENT_ALIGN // SectionAlignment
+ .long PECOFF_FILE_ALIGNMENT // FileAlignment
+ .short 0 // MajorOperatingSystemVersion
+ .short 0 // MinorOperatingSystemVersion
+ .short LINUX_EFISTUB_MAJOR_VERSION // MajorImageVersion
+ .short LINUX_EFISTUB_MINOR_VERSION // MinorImageVersion
+ .short 0 // MajorSubsystemVersion
+ .short 0 // MinorSubsystemVersion
+ .long 0 // Win32VersionValue
+
+ .long __image_end - .L_head // SizeOfImage
+
+ // Everything before the kernel image is considered part of the header
+ .long .Lefi_header_end - .L_head // SizeOfHeaders
+ .long 0 // CheckSum
+ .short IMAGE_SUBSYSTEM_EFI_APPLICATION // Subsystem
+ .short 0 // DllCharacteristics
+ .quad 0 // SizeOfStackReserve
+ .quad 0 // SizeOfStackCommit
+ .quad 0 // SizeOfHeapReserve
+ .quad 0 // SizeOfHeapCommit
+ .long 0 // LoaderFlags
+ .long (.Lsection_table - .) / 8 // NumberOfRvaAndSizes
+
+ .quad 0 // ExportTable
+ .quad 0 // ImportTable
+ .quad 0 // ResourceTable
+ .quad 0 // ExceptionTable
+ .quad 0 // CertificationTable
+ .quad 0 // BaseRelocationTable
+
+ // Section table
+.Lsection_table:
+ .ascii ".text\0\0\0"
+ .long _sdata - .Lefi_header_end // VirtualSize
+ .long .Lefi_header_end - .L_head // VirtualAddress
+ .long _sdata - .Lefi_header_end // SizeOfRawData
+ .long .Lefi_header_end - .L_head // PointerToRawData
+
+ .long 0 // PointerToRelocations
+ .long 0 // PointerToLineNumbers
+ .short 0 // NumberOfRelocations
+ .short 0 // NumberOfLineNumbers
+ .long IMAGE_SCN_CNT_CODE | \
+ IMAGE_SCN_MEM_READ | \
+ IMAGE_SCN_MEM_EXECUTE // Characteristics
+
+ .ascii ".data\0\0\0"
+ .long __pecoff_data_size // VirtualSize
+ .long _sdata - .L_head // VirtualAddress
+ .long __pecoff_data_rawsize // SizeOfRawData
+ .long _sdata - .L_head // PointerToRawData
+
+ .long 0 // PointerToRelocations
+ .long 0 // PointerToLineNumbers
+ .short 0 // NumberOfRelocations
+ .short 0 // NumberOfLineNumbers
+ .long IMAGE_SCN_CNT_INITIALIZED_DATA | \
+ IMAGE_SCN_MEM_READ | \
+ IMAGE_SCN_MEM_WRITE // Characteristics
+
+ .set .Lsection_count, (. - .Lsection_table) / 40
+
+ .balign PBL_SEGMENT_ALIGN
+.Lefi_header_end:
+#else
+ .set .Lpe_header_offset, 0x0
+#endif
+ .endm
diff --git a/arch/arm/cpu/entry.c b/arch/arm/cpu/entry.c
index 0b447de801..cc08d0ff7e 100644
--- a/arch/arm/cpu/entry.c
+++ b/arch/arm/cpu/entry.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
#include <types.h>
#include <asm/cache.h>
@@ -38,5 +40,8 @@ void NAKED __noreturn barebox_arm_entry(unsigned long membase,
unsigned long memsize, void *boarddata)
{
__barebox_arm_entry(membase, memsize, boarddata,
- arm_mem_stack_top(membase, membase + memsize));
+ arm_mem_stack_top(membase + memsize));
}
+
+void __noreturn barebox_pbl_entry(ulong, ulong, void *)
+ __alias(barebox_arm_entry);
diff --git a/arch/arm/cpu/entry.h b/arch/arm/cpu/entry.h
index 18110eadf3..ba0d3a25fe 100644
--- a/arch/arm/cpu/entry.h
+++ b/arch/arm/cpu/entry.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
#ifndef __ENTRY_H__
#define __ENTRY_H__
diff --git a/arch/arm/cpu/entry_ll.S b/arch/arm/cpu/entry_ll_32.S
index 8cc7a84f10..2800174c45 100644
--- a/arch/arm/cpu/entry_ll.S
+++ b/arch/arm/cpu/entry_ll_32.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
#include <linux/linkage.h>
#include <asm/sections.h>
diff --git a/arch/arm/cpu/entry_ll_64.S b/arch/arm/cpu/entry_ll_64.S
index fb8645e0a0..6530bec5eb 100644
--- a/arch/arm/cpu/entry_ll_64.S
+++ b/arch/arm/cpu/entry_ll_64.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
#include <linux/linkage.h>
#include <asm/sections.h>
diff --git a/arch/arm/cpu/exceptions.S b/arch/arm/cpu/exceptions_32.S
index 55014c8d46..749c713aab 100644
--- a/arch/arm/cpu/exceptions.S
+++ b/arch/arm/cpu/exceptions_32.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
#include <config.h>
#include <linux/linkage.h>
#include <asm-generic/memory_layout.h>
diff --git a/arch/arm/cpu/head_64.S b/arch/arm/cpu/head_64.S
new file mode 100644
index 0000000000..546efc263a
--- /dev/null
+++ b/arch/arm/cpu/head_64.S
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <linux/linkage.h>
+#include <asm/barebox-arm64.h>
+#include <asm/image.h>
+
+/* Linker will point these at board-specific symbols */
+.globl __pbl_board_stack_top
+.globl __pbl_board_entry
+
+.section .text_head_prologue_common, "x"
+ENTRY(__barebox_arm64_head)
+ nop
+ adr x9, __pbl_board_stack_top
+ ldr x9, [x9]
+ cbz x9, 1f
+ mov sp, x9
+1:
+#ifdef CONFIG_PBL_BREAK
+ brk #17
+ nop
+#else
+ nop
+ nop
+#endif
+ b __pbl_board_entry
+ .org 0x20
+ .asciz "barebox"
+ .word 0xffffffff
+ .word _barebox_image_size /* image size to copy */
+ .rept 8
+ .word 0x55555555
+ .endr
+ENDPROC(__barebox_arm64_head)
diff --git a/arch/arm/cpu/hyp.S b/arch/arm/cpu/hyp.S
index 1314b56eab..b5e4807877 100644
--- a/arch/arm/cpu/hyp.S
+++ b/arch/arm/cpu/hyp.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
#include <linux/linkage.h>
#include <asm/system.h>
#include <asm/opcodes-virt.h>
diff --git a/arch/arm/cpu/interrupts.c b/arch/arm/cpu/interrupts_32.c
index 703a5a3ba7..468dcdd30e 100644
--- a/arch/arm/cpu/interrupts.c
+++ b/arch/arm/cpu/interrupts_32.c
@@ -1,18 +1,5 @@
-/*
- * interrupts.c - Interrupt Support Routines
- *
- * Copyright (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that 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.
- *
- */
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
/**
* @file
@@ -21,7 +8,9 @@
#include <common.h>
#include <abort.h>
+#include <linux/sizes.h>
#include <asm/ptrace.h>
+#include <asm/barebox-arm.h>
#include <asm/unwind.h>
#include <init.h>
@@ -81,7 +70,7 @@ static void __noreturn do_exception(struct pt_regs *pt_regs)
{
show_regs(pt_regs);
- panic("");
+ panic_no_stacktrace("");
}
/**
@@ -119,6 +108,22 @@ void do_prefetch_abort (struct pt_regs *pt_regs)
do_exception(pt_regs);
}
+static const char *data_abort_reason(ulong far)
+{
+ ulong guard_page;
+
+ if (far < PAGE_SIZE)
+ return "NULL pointer dereference";
+
+ if (IS_ENABLED(CONFIG_STACK_GUARD_PAGE)) {
+ guard_page = arm_mem_guard_page_get();
+ if (guard_page <= far && far < guard_page + PAGE_SIZE)
+ return "stack overflow";
+ }
+
+ return "paging request";
+}
+
/**
* The CPU catches a data abort. That really should not happen!
* @param[in] pt_regs Register set content when the accident happens
@@ -132,8 +137,7 @@ void do_data_abort (struct pt_regs *pt_regs)
asm volatile ("mrc p15, 0, %0, c6, c0, 0" : "=r" (far) : : "cc");
printf("unable to handle %s at address 0x%08x\n",
- far < PAGE_SIZE ? "NULL pointer dereference" :
- "paging request", far);
+ data_abort_reason(far), far);
do_exception(pt_regs);
}
diff --git a/arch/arm/cpu/interrupts_64.c b/arch/arm/cpu/interrupts_64.c
index f462835ffd..6262ba8872 100644
--- a/arch/arm/cpu/interrupts_64.c
+++ b/arch/arm/cpu/interrupts_64.c
@@ -1,26 +1,17 @@
-/*
- * interrupts_64.c - Interrupt Support Routines
- *
- * Copyright (c) 2018 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that 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.
- *
- */
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2018 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+
+/* interrupts_64.c - Interrupt Support Routines */
#include <common.h>
#include <abort.h>
#include <asm/ptrace.h>
+#include <asm/barebox-arm.h>
#include <asm/unwind.h>
#include <init.h>
#include <asm/system.h>
#include <asm/esr.h>
+#include <efi/efi-mode.h>
/* Avoid missing prototype warning, called from assembly */
void do_bad_sync (struct pt_regs *pt_regs);
@@ -99,7 +90,7 @@ static void __noreturn do_exception(struct pt_regs *pt_regs)
unwind_backtrace(pt_regs);
- panic("panic: unhandled exception");
+ panic_no_stacktrace("panic: unhandled exception");
}
/**
@@ -153,17 +144,38 @@ void do_bad_error(struct pt_regs *pt_regs)
extern volatile int arm_ignore_data_abort;
extern volatile int arm_data_abort_occurred;
+static const char *data_abort_reason(ulong far)
+{
+ ulong guard_page;
+
+ if (far < PAGE_SIZE)
+ return "NULL pointer dereference: ";
+
+ if (IS_ENABLED(CONFIG_STACK_GUARD_PAGE)) {
+ guard_page = arm_mem_guard_page_get();
+ if (guard_page <= far && far < guard_page + PAGE_SIZE)
+ return "Stack overflow: ";
+ }
+
+ return NULL;
+}
+
void do_sync(struct pt_regs *pt_regs, unsigned int esr, unsigned long far)
{
- if ((esr >> ESR_ELx_EC_SHIFT) == ESR_ELx_EC_DABT_CUR &&
- arm_ignore_data_abort) {
- arm_data_abort_occurred = 1;
- pt_regs->elr += 4;
- return;
+ const char *extra = NULL;
+
+ if ((esr >> ESR_ELx_EC_SHIFT) == ESR_ELx_EC_DABT_CUR) {
+ if (arm_ignore_data_abort) {
+ arm_data_abort_occurred = 1;
+ pt_regs->elr += 4;
+ return;
+ }
+
+ extra = data_abort_reason(far);
}
- printf("%s exception (ESR 0x%08x) at 0x%016lx\n", esr_get_class_string(esr),
- esr, far);
+ printf("%s%s exception (ESR 0x%08x) at 0x%016lx\n", extra ?: "",
+ esr_get_class_string(esr), esr, far);
do_exception(pt_regs);
}
@@ -193,6 +205,9 @@ static int aarch64_init_vectors(void)
{
unsigned int el;
+ if (efi_is_payload())
+ return 0;
+
el = current_el();
switch (el) {
case 3:
@@ -210,4 +225,4 @@ static int aarch64_init_vectors(void)
return 0;
}
-pure_initcall(aarch64_init_vectors);
+core_initcall(aarch64_init_vectors);
diff --git a/arch/arm/cpu/lowlevel.S b/arch/arm/cpu/lowlevel_32.S
index 203a4afc47..960a92b78c 100644
--- a/arch/arm/cpu/lowlevel.S
+++ b/arch/arm/cpu/lowlevel_32.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
#include <linux/linkage.h>
#include <init.h>
#include <asm/system.h>
@@ -7,6 +9,8 @@
ENTRY(arm_cpu_lowlevel_init)
/* save lr, since it may be banked away with a processor mode change */
mov r2, lr
+ /* save sp, because possible HYP -> SVC transition below clobbers it */
+ mov r3, sp
#ifdef CONFIG_CPU_32v7
/* careful: the hyp install corrupts r0 and r1 */
@@ -75,6 +79,7 @@ THUMB( orr r12, r12, #PSR_T_BIT )
mcr p15, 0, r12, c1, c0, 0 /* SCTLR */
+ mov sp, r3
mov pc, r2
ENDPROC(arm_cpu_lowlevel_init)
diff --git a/arch/arm/cpu/lowlevel_64.S b/arch/arm/cpu/lowlevel_64.S
index 6a23132ed1..ed00c8c470 100644
--- a/arch/arm/cpu/lowlevel_64.S
+++ b/arch/arm/cpu/lowlevel_64.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
#include <linux/linkage.h>
#include <init.h>
#include <asm/system.h>
diff --git a/arch/arm/cpu/mmu-common.c b/arch/arm/cpu/mmu-common.c
index 287622b203..aeaf6c269d 100644
--- a/arch/arm/cpu/mmu-common.c
+++ b/arch/arm/cpu/mmu-common.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
#define pr_fmt(fmt) "mmu: " fmt
@@ -7,56 +9,17 @@
#include <dma.h>
#include <mmu.h>
#include <asm/system.h>
+#include <asm/barebox-arm.h>
#include <memory.h>
-#include "mmu.h"
-
+#include <zero_page.h>
+#include "mmu-common.h"
+#include <efi/efi-mode.h>
-static inline dma_addr_t cpu_to_dma(struct device_d *dev, unsigned long cpu_addr)
+void arch_sync_dma_for_cpu(void *vaddr, size_t size,
+ enum dma_data_direction dir)
{
- dma_addr_t dma_addr = cpu_addr;
-
- if (dev)
- dma_addr -= dev->dma_offset;
-
- return dma_addr;
-}
-
-static inline unsigned long dma_to_cpu(struct device_d *dev, dma_addr_t addr)
-{
- unsigned long cpu_addr = addr;
-
- if (dev)
- cpu_addr += dev->dma_offset;
-
- return cpu_addr;
-}
-
-void dma_sync_single_for_cpu(dma_addr_t address, size_t size,
- enum dma_data_direction dir)
-{
- /*
- * FIXME: This function needs a device argument to support non 1:1 mappings
- */
if (dir != DMA_TO_DEVICE)
- dma_inv_range((void *)address, size);
-}
-
-dma_addr_t dma_map_single(struct device_d *dev, void *ptr, size_t size,
- enum dma_data_direction dir)
-{
- unsigned long addr = (unsigned long)ptr;
-
- dma_sync_single_for_device(addr, size, dir);
-
- return cpu_to_dma(dev, addr);
-}
-
-void dma_unmap_single(struct device_d *dev, dma_addr_t dma_addr, size_t size,
- enum dma_data_direction dir)
-{
- unsigned long addr = dma_to_cpu(dev, dma_addr);
-
- dma_sync_single_for_cpu(addr, size, dir);
+ dma_inv_range(vaddr, size);
}
void *dma_alloc_map(size_t size, dma_addr_t *dma_handle, unsigned flags)
@@ -71,7 +34,7 @@ void *dma_alloc_map(size_t size, dma_addr_t *dma_handle, unsigned flags)
memset(ret, 0, size);
dma_flush_range(ret, size);
- arch_remap_range(ret, size, flags);
+ remap_range(ret, size, flags);
return ret;
}
@@ -88,24 +51,47 @@ void *dma_alloc_coherent(size_t size, dma_addr_t *dma_handle)
void dma_free_coherent(void *mem, dma_addr_t dma_handle, size_t size)
{
size = PAGE_ALIGN(size);
- arch_remap_range(mem, size, MAP_CACHED);
+ remap_range(mem, size, MAP_CACHED);
free(mem);
}
+void zero_page_access(void)
+{
+ remap_range(0x0, PAGE_SIZE, MAP_CACHED);
+}
+
+void zero_page_faulting(void)
+{
+ remap_range(0x0, PAGE_SIZE, MAP_FAULT);
+}
+
static int mmu_init(void)
{
- if (list_empty(&memory_banks))
+ if (efi_is_payload())
+ return 0;
+
+ if (list_empty(&memory_banks)) {
+ resource_size_t start;
+ int ret;
+
/*
* If you see this it means you have no memory registered.
* This can be done either with arm_add_mem_device() in an
* initcall prior to mmu_initcall or via devicetree in the
* memory node.
*/
- panic("MMU: No memory bank found! Cannot continue\n");
+ pr_emerg("No memory bank registered. Limping along with initial memory\n");
+
+ start = arm_mem_membase_get();
+ ret = barebox_add_memory_bank("initmem", start,
+ arm_mem_endmem_get() - start);
+ if (ret)
+ panic("");
+ }
__mmu_init(get_cr() & CR_M);
return 0;
}
-mmu_initcall(mmu_init); \ No newline at end of file
+mmu_initcall(mmu_init);
diff --git a/arch/arm/cpu/mmu-common.h b/arch/arm/cpu/mmu-common.h
index 0a33b138e1..7a69122ee6 100644
--- a/arch/arm/cpu/mmu-common.h
+++ b/arch/arm/cpu/mmu-common.h
@@ -1,6 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
#ifndef __ARM_MMU_COMMON_H
#define __ARM_MMU_COMMON_H
+#include <printk.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/sizes.h>
+
void dma_inv_range(void *ptr, size_t size);
void dma_flush_range(void *ptr, size_t size);
void *dma_alloc_map(size_t size, dma_addr_t *dma_handle, unsigned flags);
@@ -17,4 +25,14 @@ static inline void arm_mmu_not_initialized_error(void)
panic("MMU not initialized\n");
}
-#endif \ No newline at end of file
+static inline size_t resource_first_page(const struct resource *res)
+{
+ return ALIGN_DOWN(res->start, SZ_4K);
+}
+
+static inline size_t resource_count_pages(const struct resource *res)
+{
+ return ALIGN(resource_size(res), SZ_4K);
+}
+
+#endif
diff --git a/arch/arm/cpu/mmu-early.c b/arch/arm/cpu/mmu-early.c
deleted file mode 100644
index b985aa455f..0000000000
--- a/arch/arm/cpu/mmu-early.c
+++ /dev/null
@@ -1,69 +0,0 @@
-#include <common.h>
-#include <asm/mmu.h>
-#include <errno.h>
-#include <linux/sizes.h>
-#include <asm/memory.h>
-#include <asm/system.h>
-#include <asm/cache.h>
-#include <asm-generic/sections.h>
-
-#include "mmu.h"
-
-static uint32_t *ttb;
-
-static inline void map_region(unsigned long start, unsigned long size,
- uint64_t flags)
-
-{
- start = ALIGN_DOWN(start, SZ_1M);
- size = ALIGN(size, SZ_1M);
-
- create_sections(ttb, start, start + size - 1, flags);
-}
-
-void mmu_early_enable(unsigned long membase, unsigned long memsize,
- unsigned long _ttb)
-{
- ttb = (uint32_t *)_ttb;
-
- arm_set_cache_functions();
-
- set_ttbr(ttb);
-
- /* For the XN bit to take effect, we can't be using DOMAIN_MANAGER. */
- if (cpu_architecture() >= CPU_ARCH_ARMv7)
- set_domain(DOMAIN_CLIENT);
- else
- set_domain(DOMAIN_MANAGER);
-
- /*
- * This marks the whole address space as uncachable as well as
- * unexecutable if possible
- */
- create_flat_mapping(ttb);
-
- /*
- * There can be SoCs that have a section shared between device memory
- * and the on-chip RAM hosting the PBL. Thus mark this section
- * uncachable, but executable.
- * On such SoCs, executing from OCRAM could cause the instruction
- * prefetcher to speculatively access that device memory, triggering
- * potential errant behavior.
- *
- * If your SoC has such a memory layout, you should rewrite the code
- * here to map the OCRAM page-wise.
- */
- map_region((unsigned long)_stext, _etext - _stext, PMD_SECT_DEF_UNCACHED);
-
- /* maps main memory as cachable */
- map_region(membase, memsize, PMD_SECT_DEF_CACHED);
-
- /*
- * With HAB enabled we call into the ROM code later in imx6_hab_get_status().
- * Map the ROM cached which has the effect that the XN bit is not set.
- */
- if (IS_ENABLED(CONFIG_HABV4) && IS_ENABLED(CONFIG_ARCH_IMX6))
- map_region(0x0, SZ_1M, PMD_SECT_DEF_CACHED);
-
- __mmu_cache_on();
-}
diff --git a/arch/arm/cpu/mmu-early_64.c b/arch/arm/cpu/mmu-early_64.c
deleted file mode 100644
index a7598f28aa..0000000000
--- a/arch/arm/cpu/mmu-early_64.c
+++ /dev/null
@@ -1,91 +0,0 @@
-#include <common.h>
-#include <dma-dir.h>
-#include <init.h>
-#include <mmu.h>
-#include <errno.h>
-#include <linux/sizes.h>
-#include <asm/memory.h>
-#include <asm/pgtable64.h>
-#include <asm/barebox-arm.h>
-#include <asm/system.h>
-#include <asm/cache.h>
-#include <memory.h>
-#include <asm/system_info.h>
-
-#include "mmu_64.h"
-
-static void create_sections(void *ttb, uint64_t virt, uint64_t phys,
- uint64_t size, uint64_t attr)
-{
- uint64_t block_size;
- uint64_t block_shift;
- uint64_t *pte;
- uint64_t idx;
- uint64_t addr;
- uint64_t *table;
-
- addr = virt;
-
- attr &= ~PTE_TYPE_MASK;
-
- table = ttb;
-
- while (1) {
- block_shift = level2shift(1);
- idx = (addr & level2mask(1)) >> block_shift;
- block_size = (1ULL << block_shift);
-
- pte = table + idx;
-
- *pte = phys | attr | PTE_TYPE_BLOCK;
-
- if (size < block_size)
- break;
-
- addr += block_size;
- phys += block_size;
- size -= block_size;
- }
-}
-
-#define EARLY_BITS_PER_VA 39
-
-void mmu_early_enable(unsigned long membase, unsigned long memsize,
- unsigned long ttb)
-{
- int el;
-
- /*
- * For the early code we only create level 1 pagetables which only
- * allow for a 1GiB granularity. If our membase is not aligned to that
- * bail out without enabling the MMU.
- */
- if (membase & ((1ULL << level2shift(1)) - 1))
- return;
-
- memset((void *)ttb, 0, GRANULE_SIZE);
-
- el = current_el();
- set_ttbr_tcr_mair(el, ttb, calc_tcr(el, EARLY_BITS_PER_VA), MEMORY_ATTRIBUTES);
- create_sections((void *)ttb, 0, 0, 1UL << (EARLY_BITS_PER_VA - 1),
- attrs_uncached_mem());
- create_sections((void *)ttb, membase, membase, memsize, CACHED_MEM);
- tlb_invalidate();
- isb();
- set_cr(get_cr() | CR_M);
-}
-
-void mmu_early_disable(void)
-{
- unsigned int cr;
-
- cr = get_cr();
- cr &= ~(CR_M | CR_C);
-
- set_cr(cr);
- v8_flush_dcache_all();
- tlb_invalidate();
-
- dsb();
- isb();
-} \ No newline at end of file
diff --git a/arch/arm/cpu/mmu.c b/arch/arm/cpu/mmu_32.c
index 2aa53229b3..3a8d025ecd 100644
--- a/arch/arm/cpu/mmu.c
+++ b/arch/arm/cpu/mmu_32.c
@@ -1,16 +1,5 @@
-/*
- * Copyright (c) 2009-2013 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that 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.
- *
- */
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2009-2013 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
#define pr_fmt(fmt) "mmu: " fmt
@@ -20,6 +9,7 @@
#include <init.h>
#include <mmu.h>
#include <errno.h>
+#include <zero_page.h>
#include <linux/sizes.h>
#include <asm/memory.h>
#include <asm/barebox-arm.h>
@@ -28,13 +18,18 @@
#include <memory.h>
#include <asm/system_info.h>
#include <asm/sections.h>
+#include <linux/pagemap.h>
-#include "mmu.h"
+#include "mmu_32.h"
#define PTRS_PER_PTE (PGDIR_SIZE / PAGE_SIZE)
#define ARCH_MAP_WRITECOMBINE ((unsigned)-1)
-static uint32_t *ttb;
+static inline uint32_t *get_ttb(void)
+{
+ /* Clear unpredictable bits [13:0] */
+ return (uint32_t *)(get_ttbr() & ~0x3fff);
+}
/*
* Do it the simple way for now and invalidate the entire
@@ -63,29 +58,36 @@ static inline void tlb_invalidate(void)
PMD_SECT_BUFFERABLE | PMD_SECT_XN)
#define PGD_FLAGS_UNCACHED_V7 (PMD_SECT_DEF_UNCACHED | PMD_SECT_XN)
-/*
- * PTE flags to set cached and uncached areas.
- * This will be determined at runtime.
- */
-static uint32_t pte_flags_cached;
-static uint32_t pte_flags_wc;
-static uint32_t pte_flags_uncached;
-static uint32_t pgd_flags_wc;
-static uint32_t pgd_flags_uncached;
-
-#define PTE_MASK ((1 << 12) - 1)
-
static bool pgd_type_table(u32 pgd)
{
return (pgd & PMD_TYPE_MASK) == PMD_TYPE_TABLE;
}
+#define PTE_SIZE (PTRS_PER_PTE * sizeof(u32))
+
+#ifdef __PBL__
+static uint32_t *alloc_pte(void)
+{
+ static unsigned int idx = 3;
+
+ idx++;
+
+ if (idx * PTE_SIZE >= ARM_EARLY_PAGETABLE_SIZE)
+ return NULL;
+
+ return get_ttb() + idx * PTE_SIZE;
+}
+#else
+static uint32_t *alloc_pte(void)
+{
+ return xmemalign(PTE_SIZE, PTE_SIZE);
+}
+#endif
+
static u32 *find_pte(unsigned long adr)
{
u32 *table;
-
- if (!ttb)
- arm_mmu_not_initialized_error();
+ uint32_t *ttb = get_ttb();
if (!pgd_type_table(ttb[pgd_index(adr)]))
return NULL;
@@ -103,6 +105,7 @@ void dma_flush_range(void *ptr, size_t size)
unsigned long end = start + size;
__dma_flush_range(start, end);
+
if (outer_cache.flush_range)
outer_cache.flush_range(start, end);
}
@@ -114,6 +117,7 @@ void dma_inv_range(void *ptr, size_t size)
if (outer_cache.inv_range)
outer_cache.inv_range(start, end);
+
__dma_inv_range(start, end);
}
@@ -122,24 +126,24 @@ void dma_inv_range(void *ptr, size_t size)
* We initially create a flat uncached mapping on it.
* Not yet exported, but may be later if someone finds use for it.
*/
-static u32 *arm_create_pte(unsigned long virt, uint32_t flags)
+static u32 *arm_create_pte(unsigned long virt, unsigned long phys,
+ uint32_t flags)
{
+ uint32_t *ttb = get_ttb();
u32 *table;
int i, ttb_idx;
virt = ALIGN_DOWN(virt, PGDIR_SIZE);
+ phys = ALIGN_DOWN(phys, PGDIR_SIZE);
- table = xmemalign(PTRS_PER_PTE * sizeof(u32),
- PTRS_PER_PTE * sizeof(u32));
-
- if (!ttb)
- arm_mmu_not_initialized_error();
+ table = alloc_pte();
ttb_idx = pgd_index(virt);
for (i = 0; i < PTRS_PER_PTE; i++) {
- table[i] = virt | PTE_TYPE_SMALL | flags;
+ table[i] = phys | PTE_TYPE_SMALL | flags;
virt += PAGE_SIZE;
+ phys += PAGE_SIZE;
}
dma_flush_range(table, PTRS_PER_PTE * sizeof(u32));
@@ -149,44 +153,125 @@ static u32 *arm_create_pte(unsigned long virt, uint32_t flags)
return table;
}
-int arch_remap_range(void *start, size_t size, unsigned flags)
+static u32 pmd_flags_to_pte(u32 pmd)
+{
+ u32 pte = 0;
+
+ if (pmd & PMD_SECT_BUFFERABLE)
+ pte |= PTE_BUFFERABLE;
+ if (pmd & PMD_SECT_CACHEABLE)
+ pte |= PTE_CACHEABLE;
+
+ if (cpu_architecture() >= CPU_ARCH_ARMv7) {
+ if (pmd & PMD_SECT_nG)
+ pte |= PTE_EXT_NG;
+ if (pmd & PMD_SECT_XN)
+ pte |= PTE_EXT_XN;
+
+ /* TEX[2:0] */
+ pte |= PTE_EXT_TEX((pmd >> 12) & 7);
+ /* AP[1:0] */
+ pte |= ((pmd >> 10) & 0x3) << 4;
+ /* AP[2] */
+ pte |= ((pmd >> 15) & 0x1) << 9;
+ } else {
+ pte |= PTE_SMALL_AP_UNO_SRW;
+ }
+
+ return pte;
+}
+
+static u32 pte_flags_to_pmd(u32 pte)
{
- u32 addr = (u32)start;
- u32 pte_flags;
- u32 pgd_flags;
-
- BUG_ON(!IS_ALIGNED(addr, PAGE_SIZE));
-
- switch (flags) {
- case MAP_CACHED:
- pte_flags = pte_flags_cached;
- pgd_flags = PMD_SECT_DEF_CACHED;
- break;
- case MAP_UNCACHED:
- pte_flags = pte_flags_uncached;
- pgd_flags = pgd_flags_uncached;
- break;
- case ARCH_MAP_WRITECOMBINE:
- pte_flags = pte_flags_wc;
- pgd_flags = pgd_flags_wc;
- break;
- default:
- return -EINVAL;
+ u32 pmd = 0;
+
+ if (pte & PTE_BUFFERABLE)
+ pmd |= PMD_SECT_BUFFERABLE;
+ if (pte & PTE_CACHEABLE)
+ pmd |= PMD_SECT_CACHEABLE;
+
+ if (cpu_architecture() >= CPU_ARCH_ARMv7) {
+ if (pte & PTE_EXT_NG)
+ pmd |= PMD_SECT_nG;
+ if (pte & PTE_EXT_XN)
+ pmd |= PMD_SECT_XN;
+
+ /* TEX[2:0] */
+ pmd |= ((pte >> 6) & 7) << 12;
+ /* AP[1:0] */
+ pmd |= ((pte >> 4) & 0x3) << 10;
+ /* AP[2] */
+ pmd |= ((pte >> 9) & 0x1) << 15;
+ } else {
+ pmd |= PMD_SECT_AP_WRITE | PMD_SECT_AP_READ;
}
+ return pmd;
+}
+
+static uint32_t get_pte_flags(int map_type)
+{
+ if (cpu_architecture() >= CPU_ARCH_ARMv7) {
+ switch (map_type) {
+ case MAP_CACHED:
+ return PTE_FLAGS_CACHED_V7;
+ case MAP_UNCACHED:
+ return PTE_FLAGS_UNCACHED_V7;
+ case ARCH_MAP_WRITECOMBINE:
+ return PTE_FLAGS_WC_V7;
+ case MAP_FAULT:
+ default:
+ return 0x0;
+ }
+ } else {
+ switch (map_type) {
+ case MAP_CACHED:
+ return PTE_FLAGS_CACHED_V4;
+ case MAP_UNCACHED:
+ case ARCH_MAP_WRITECOMBINE:
+ return PTE_FLAGS_UNCACHED_V4;
+ case MAP_FAULT:
+ default:
+ return 0x0;
+ }
+ }
+}
+
+static uint32_t get_pmd_flags(int map_type)
+{
+ return pte_flags_to_pmd(get_pte_flags(map_type));
+}
+
+static void __arch_remap_range(void *_virt_addr, phys_addr_t phys_addr, size_t size, unsigned map_type)
+{
+ u32 virt_addr = (u32)_virt_addr;
+ u32 pte_flags, pmd_flags;
+ uint32_t *ttb = get_ttb();
+
+ BUG_ON(!IS_ALIGNED(virt_addr, PAGE_SIZE));
+ BUG_ON(!IS_ALIGNED(phys_addr, PAGE_SIZE));
+
+ pte_flags = get_pte_flags(map_type);
+ pmd_flags = pte_flags_to_pmd(pte_flags);
+
+ size = PAGE_ALIGN(size);
+
while (size) {
- const bool pgdir_size_aligned = IS_ALIGNED(addr, PGDIR_SIZE);
- u32 *pgd = (u32 *)&ttb[pgd_index(addr)];
+ const bool pgdir_size_aligned = IS_ALIGNED(virt_addr, PGDIR_SIZE);
+ u32 *pgd = (u32 *)&ttb[pgd_index(virt_addr)];
size_t chunk;
if (size >= PGDIR_SIZE && pgdir_size_aligned &&
+ IS_ALIGNED(phys_addr, PGDIR_SIZE) &&
!pgd_type_table(*pgd)) {
/*
* TODO: Add code to discard a page table and
* replace it with a section
*/
chunk = PGDIR_SIZE;
- *pgd = addr | pgd_flags;
+ *pgd = phys_addr | pmd_flags;
+ if (map_type != MAP_FAULT)
+ *pgd |= PMD_TYPE_SECT;
dma_flush_range(pgd, sizeof(*pgd));
} else {
unsigned int num_ptes;
@@ -201,7 +286,7 @@ int arch_remap_range(void *start, size_t size, unsigned flags)
* was not aligned on PGDIR_SIZE boundary)
*/
chunk = pgdir_size_aligned ?
- PGDIR_SIZE : ALIGN(addr, PGDIR_SIZE) - addr;
+ PGDIR_SIZE : ALIGN(virt_addr, PGDIR_SIZE) - virt_addr;
/*
* At the same time we want to make sure that
* we don't go on remapping past requested
@@ -211,43 +296,78 @@ int arch_remap_range(void *start, size_t size, unsigned flags)
chunk = min(chunk, size);
num_ptes = chunk / PAGE_SIZE;
- pte = find_pte(addr);
+ pte = find_pte(virt_addr);
if (!pte) {
/*
* If PTE is not found it means that
* we needs to split this section and
* create a new page table for it
- *
- * NOTE: Here we assume that section
- * we just split was mapped as cached
*/
- table = arm_create_pte(addr, pte_flags_cached);
- pte = find_pte(addr);
+ table = arm_create_pte(virt_addr, phys_addr,
+ pmd_flags_to_pte(*pgd));
+ pte = find_pte(virt_addr);
BUG_ON(!pte);
}
for (i = 0; i < num_ptes; i++) {
- pte[i] &= ~PTE_MASK;
- pte[i] |= pte_flags | PTE_TYPE_SMALL;
+ pte[i] = phys_addr + i * PAGE_SIZE;
+ pte[i] |= pte_flags;
+ if (map_type != MAP_FAULT)
+ pte[i] |= PTE_TYPE_SMALL;
}
dma_flush_range(pte, num_ptes * sizeof(u32));
}
- addr += chunk;
+ virt_addr += chunk;
+ phys_addr += chunk;
size -= chunk;
}
tlb_invalidate();
+}
+static void early_remap_range(u32 addr, size_t size, unsigned map_type)
+{
+ __arch_remap_range((void *)addr, addr, size, map_type);
+}
+
+int arch_remap_range(void *virt_addr, phys_addr_t phys_addr, size_t size, unsigned map_type)
+{
+ __arch_remap_range(virt_addr, phys_addr, size, map_type);
+
+ if (map_type == MAP_UNCACHED)
+ dma_inv_range(virt_addr, size);
+
return 0;
}
+static void create_sections(unsigned long first, unsigned long last,
+ unsigned int flags)
+{
+ uint32_t *ttb = get_ttb();
+ unsigned long ttb_start = pgd_index(first);
+ unsigned long ttb_end = pgd_index(last) + 1;
+ unsigned int i, addr = first;
+
+ for (i = ttb_start; i < ttb_end; i++) {
+ ttb[i] = addr | flags;
+ addr += PGDIR_SIZE;
+ }
+}
+
+static inline void create_flat_mapping(void)
+{
+ /* create a flat mapping using 1MiB sections */
+ create_sections(0, 0xffffffff, attrs_uncached_mem());
+}
+
void *map_io_sections(unsigned long phys, void *_start, size_t size)
{
unsigned long start = (unsigned long)_start, sec;
+ uint32_t *ttb = get_ttb();
for (sec = start; sec < start + size; sec += PGDIR_SIZE, phys += PGDIR_SIZE)
- ttb[pgd_index(sec)] = phys | pgd_flags_uncached;
+ ttb[pgd_index(sec)] = phys | get_pmd_flags(MAP_UNCACHED);
dma_flush_range(ttb, 0x4000);
tlb_invalidate();
@@ -288,9 +408,9 @@ static void create_vector_table(unsigned long adr)
vectors = xmemalign(PAGE_SIZE, PAGE_SIZE);
pr_debug("Creating vector table, virt = 0x%p, phys = 0x%08lx\n",
vectors, adr);
- arm_create_pte(adr, pte_flags_uncached);
+ arm_create_pte(adr, adr, get_pte_flags(MAP_UNCACHED));
pte = find_pte(adr);
- *pte = (u32)vectors | PTE_TYPE_SMALL | pte_flags_cached;
+ *pte = (u32)vectors | PTE_TYPE_SMALL | get_pte_flags(MAP_CACHED);
}
arm_fixup_vectors();
@@ -348,21 +468,28 @@ static int set_vector_table(unsigned long adr)
static void create_zero_page(void)
{
- struct resource *zero_sdram;
- u32 *zero;
+ /*
+ * In case the zero page is in SDRAM request it to prevent others
+ * from using it
+ */
+ request_sdram_region("zero page", 0x0, PAGE_SIZE);
- zero_sdram = request_sdram_region("zero page", 0x0, PAGE_SIZE);
- if (zero_sdram) {
- /*
- * Here we would need to set the second level page table
- * entry to faulting. This is not yet implemented.
- */
- pr_debug("zero page is in SDRAM area, currently not supported\n");
- } else {
- zero = arm_create_pte(0x0, pte_flags_uncached);
- zero[0] = 0;
- pr_debug("Created zero page\n");
- }
+ zero_page_faulting();
+ pr_debug("Created zero page\n");
+}
+
+static void create_guard_page(void)
+{
+ ulong guard_page;
+
+ if (!IS_ENABLED(CONFIG_STACK_GUARD_PAGE))
+ return;
+
+ guard_page = arm_mem_guard_page_get();
+ request_sdram_region("guard page", guard_page, PAGE_SIZE);
+ remap_range((void *)guard_page, PAGE_SIZE, MAP_FAULT);
+
+ pr_debug("Created guard page\n");
}
/*
@@ -370,6 +497,8 @@ static void create_zero_page(void)
*/
static void vectors_init(void)
{
+ create_guard_page();
+
/*
* First try to use the vectors where they actually are, works
* on ARMv7 and later.
@@ -404,67 +533,44 @@ static void vectors_init(void)
void __mmu_init(bool mmu_on)
{
struct memory_bank *bank;
+ uint32_t *ttb = get_ttb();
- arm_set_cache_functions();
-
- if (cpu_architecture() >= CPU_ARCH_ARMv7) {
- pte_flags_cached = PTE_FLAGS_CACHED_V7;
- pte_flags_wc = PTE_FLAGS_WC_V7;
- pgd_flags_wc = PGD_FLAGS_WC_V7;
- pgd_flags_uncached = PGD_FLAGS_UNCACHED_V7;
- pte_flags_uncached = PTE_FLAGS_UNCACHED_V7;
- } else {
- pte_flags_cached = PTE_FLAGS_CACHED_V4;
- pte_flags_wc = PTE_FLAGS_UNCACHED_V4;
- pgd_flags_wc = PMD_SECT_DEF_UNCACHED;
- pgd_flags_uncached = PMD_SECT_DEF_UNCACHED;
- pte_flags_uncached = PTE_FLAGS_UNCACHED_V4;
- }
-
- if (mmu_on) {
+ if (!request_sdram_region("ttb", (unsigned long)ttb,
+ ARM_EARLY_PAGETABLE_SIZE))
/*
- * Early MMU code has already enabled the MMU. We assume a
- * flat 1:1 section mapping in this case.
+ * This can mean that:
+ * - the early MMU code has put the ttb into a place
+ * which we don't have inside our available memory
+ * - Somebody else has occupied the ttb region which means
+ * the ttb will get corrupted.
*/
- /* Clear unpredictable bits [13:0] */
- ttb = (uint32_t *)(get_ttbr() & ~0x3fff);
-
- if (!request_sdram_region("ttb", (unsigned long)ttb, SZ_16K))
- /*
- * This can mean that:
- * - the early MMU code has put the ttb into a place
- * which we don't have inside our available memory
- * - Somebody else has occupied the ttb region which means
- * the ttb will get corrupted.
- */
- pr_crit("Critical Error: Can't request SDRAM region for ttb at %p\n",
+ pr_crit("Critical Error: Can't request SDRAM region for ttb at %p\n",
ttb);
- } else {
- ttb = xmemalign(ARM_TTB_SIZE, ARM_TTB_SIZE);
-
- set_ttbr(ttb);
- /* For the XN bit to take effect, we can't be using DOMAIN_MANAGER. */
- if (cpu_architecture() >= CPU_ARCH_ARMv7)
- set_domain(DOMAIN_CLIENT);
- else
- set_domain(DOMAIN_MANAGER);
+ pr_debug("ttb: 0x%p\n", ttb);
- create_flat_mapping(ttb);
- __mmu_cache_flush();
- }
+ /*
+ * Early mmu init will have mapped everything but the initial memory area
+ * (excluding final OPTEE_SIZE bytes) uncached. We have now discovered
+ * all memory banks, so let's map all pages, excluding reserved memory areas,
+ * cacheable and executable.
+ */
+ for_each_memory_bank(bank) {
+ struct resource *rsv;
+ resource_size_t pos;
- pr_debug("ttb: 0x%p\n", ttb);
+ pos = bank->start;
- vectors_init();
+ /* Skip reserved regions */
+ for_each_reserved_region(bank, rsv) {
+ remap_range((void *)pos, rsv->start - pos, MAP_CACHED);
+ pos = rsv->end + 1;
+ }
- for_each_memory_bank(bank) {
- create_sections(ttb, bank->start, bank->start + bank->size - 1,
- PMD_SECT_DEF_CACHED);
- __mmu_cache_flush();
+ remap_range((void *)pos, bank->start + bank->size - pos, MAP_CACHED);
}
- __mmu_cache_on();
+ vectors_init();
}
/*
@@ -485,20 +591,33 @@ void *dma_alloc_writecombine(size_t size, dma_addr_t *dma_handle)
return dma_alloc_map(size, dma_handle, ARCH_MAP_WRITECOMBINE);
}
-void dma_sync_single_for_device(dma_addr_t address, size_t size,
- enum dma_data_direction dir)
+void mmu_early_enable(unsigned long membase, unsigned long memsize)
{
+ uint32_t *ttb = (uint32_t *)arm_mem_ttb(membase + memsize);
+
+ pr_debug("enabling MMU, ttb @ 0x%p\n", ttb);
+
+ if (get_cr() & CR_M)
+ return;
+
+ set_ttbr(ttb);
+
+ /* For the XN bit to take effect, we can't be using DOMAIN_MANAGER. */
+ if (cpu_architecture() >= CPU_ARCH_ARMv7)
+ set_domain(DOMAIN_CLIENT);
+ else
+ set_domain(DOMAIN_MANAGER);
+
/*
- * FIXME: This function needs a device argument to support non 1:1 mappings
+ * This marks the whole address space as uncachable as well as
+ * unexecutable if possible
*/
+ create_flat_mapping();
- if (dir == DMA_FROM_DEVICE) {
- __dma_inv_range(address, address + size);
- if (outer_cache.inv_range)
- outer_cache.inv_range(address, address + size);
- } else {
- __dma_clean_range(address, address + size);
- if (outer_cache.clean_range)
- outer_cache.clean_range(address, address + size);
- }
+ /* maps main memory as cachable */
+ early_remap_range(membase, memsize - OPTEE_SIZE, MAP_CACHED);
+ early_remap_range(membase + memsize - OPTEE_SIZE, OPTEE_SIZE, MAP_UNCACHED);
+ early_remap_range(PAGE_ALIGN_DOWN((uintptr_t)_stext), PAGE_ALIGN(_etext - _stext), MAP_CACHED);
+
+ __mmu_cache_on();
}
diff --git a/arch/arm/cpu/mmu.h b/arch/arm/cpu/mmu_32.h
index c85e0ea050..607d9e8608 100644
--- a/arch/arm/cpu/mmu.h
+++ b/arch/arm/cpu/mmu_32.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
#ifndef __ARM_MMU_H
#define __ARM_MMU_H
@@ -54,32 +56,17 @@ static inline void set_domain(unsigned val)
asm volatile ("mcr p15,0,%0,c3,c0,0" : : "r"(val) /*:*/);
}
-static inline void
-create_sections(uint32_t *ttb, unsigned long first,
- unsigned long last, unsigned int flags)
-{
- unsigned long ttb_start = pgd_index(first);
- unsigned long ttb_end = pgd_index(last) + 1;
- unsigned int i, addr = first;
-
- for (i = ttb_start; i < ttb_end; i++) {
- ttb[i] = addr | flags;
- addr += PGDIR_SIZE;
- }
-}
-
#define PMD_SECT_DEF_UNCACHED (PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | PMD_TYPE_SECT)
#define PMD_SECT_DEF_CACHED (PMD_SECT_WB | PMD_SECT_DEF_UNCACHED)
-static inline void create_flat_mapping(uint32_t *ttb)
+static inline unsigned long attrs_uncached_mem(void)
{
unsigned int flags = PMD_SECT_DEF_UNCACHED;
if (cpu_architecture() >= CPU_ARCH_ARMv7)
flags |= PMD_SECT_XN;
- /* create a flat mapping using 1MiB sections */
- create_sections(ttb, 0, 0xffffffff, flags);
+ return flags;
}
#endif /* __ARM_MMU_H */
diff --git a/arch/arm/cpu/mmu_64.c b/arch/arm/cpu/mmu_64.c
index 8324cedb25..f907421da9 100644
--- a/arch/arm/cpu/mmu_64.c
+++ b/arch/arm/cpu/mmu_64.c
@@ -1,17 +1,6 @@
-/*
- * Copyright (c) 2009-2013 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- * Copyright (c) 2016 Raphaël Poggi <poggi.raph@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that 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.
- *
- */
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2009-2013 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+// SPDX-FileCopyrightText: 2016 Raphaël Poggi <poggi.raph@gmail.com>
#define pr_fmt(fmt) "mmu: " fmt
@@ -21,6 +10,7 @@
#include <init.h>
#include <mmu.h>
#include <errno.h>
+#include <zero_page.h>
#include <linux/sizes.h>
#include <asm/memory.h>
#include <asm/pgtable64.h>
@@ -29,10 +19,15 @@
#include <asm/cache.h>
#include <memory.h>
#include <asm/system_info.h>
+#include <linux/pagemap.h>
+#include <tee/optee.h>
#include "mmu_64.h"
-static uint64_t *ttb;
+static uint64_t *get_ttb(void)
+{
+ return (uint64_t *)get_ttbr(current_el());
+}
static void set_table(uint64_t *pt, uint64_t *table_addr)
{
@@ -42,7 +37,20 @@ static void set_table(uint64_t *pt, uint64_t *table_addr)
*pt = val;
}
-static uint64_t *create_table(void)
+#ifdef __PBL__
+static uint64_t *alloc_pte(void)
+{
+ static unsigned int idx;
+
+ idx++;
+
+ if (idx * GRANULE_SIZE >= ARM_EARLY_PAGETABLE_SIZE)
+ return NULL;
+
+ return (void *)get_ttb() + idx * GRANULE_SIZE;
+}
+#else
+static uint64_t *alloc_pte(void)
{
uint64_t *new_table = xmemalign(GRANULE_SIZE, GRANULE_SIZE);
@@ -51,6 +59,7 @@ static uint64_t *create_table(void)
return new_table;
}
+#endif
static __maybe_unused uint64_t *find_pte(uint64_t addr)
{
@@ -59,7 +68,7 @@ static __maybe_unused uint64_t *find_pte(uint64_t addr)
uint64_t idx;
int i;
- pte = ttb;
+ pte = get_ttb();
for (i = 0; i < 4; i++) {
block_shift = level2shift(i);
@@ -91,7 +100,10 @@ static void split_block(uint64_t *pte, int level)
/* level describes the parent level, we need the child ones */
levelshift = level2shift(level + 1);
- new_table = create_table();
+ new_table = alloc_pte();
+ if (!new_table)
+ panic("Unable to allocate PTE\n");
+
for (i = 0; i < MAX_PTE_ENTRIES; i++) {
new_table[i] = old_pte | (i << levelshift);
@@ -108,6 +120,7 @@ static void split_block(uint64_t *pte, int level)
static void create_sections(uint64_t virt, uint64_t phys, uint64_t size,
uint64_t attr)
{
+ uint64_t *ttb = get_ttb();
uint64_t block_size;
uint64_t block_shift;
uint64_t *pte;
@@ -117,13 +130,12 @@ static void create_sections(uint64_t virt, uint64_t phys, uint64_t size,
uint64_t type;
int level;
- if (!ttb)
- arm_mmu_not_initialized_error();
-
addr = virt;
attr &= ~PTE_TYPE_MASK;
+ size = PAGE_ALIGN(size);
+
while (size) {
table = ttb;
for (level = 0; level < 4; level++) {
@@ -133,7 +145,8 @@ static void create_sections(uint64_t virt, uint64_t phys, uint64_t size,
pte = table + idx;
- if (size >= block_size && IS_ALIGNED(addr, block_size)) {
+ if (size >= block_size && IS_ALIGNED(addr, block_size) &&
+ IS_ALIGNED(phys, block_size)) {
type = (level == 3) ?
PTE_TYPE_PAGE : PTE_TYPE_BLOCK;
*pte = phys | attr | type;
@@ -153,23 +166,42 @@ static void create_sections(uint64_t virt, uint64_t phys, uint64_t size,
tlb_invalidate();
}
-int arch_remap_range(void *_start, size_t size, unsigned flags)
+static unsigned long get_pte_attrs(unsigned flags)
{
- unsigned long attrs;
-
switch (flags) {
case MAP_CACHED:
- attrs = CACHED_MEM;
- break;
+ return CACHED_MEM;
case MAP_UNCACHED:
- attrs = attrs_uncached_mem();
- break;
+ return attrs_uncached_mem();
+ case MAP_FAULT:
+ return 0x0;
default:
- return -EINVAL;
+ return ~0UL;
}
+}
+
+static void early_remap_range(uint64_t addr, size_t size, unsigned flags)
+{
+ unsigned long attrs = get_pte_attrs(flags);
+
+ if (WARN_ON(attrs == ~0UL))
+ return;
+
+ create_sections(addr, addr, size, attrs);
+}
+
+int arch_remap_range(void *virt_addr, phys_addr_t phys_addr, size_t size, unsigned flags)
+{
+ unsigned long attrs = get_pte_attrs(flags);
+
+ if (attrs == ~0UL)
+ return -EINVAL;
+
+ create_sections((uint64_t)virt_addr, phys_addr, (uint64_t)size, attrs);
+
+ if (flags == MAP_UNCACHED)
+ dma_inv_range(virt_addr, size);
- create_sections((uint64_t)_start, (uint64_t)_start, (uint64_t)size,
- attrs);
return 0;
}
@@ -179,35 +211,57 @@ static void mmu_enable(void)
set_cr(get_cr() | CR_M | CR_C | CR_I);
}
+static void create_guard_page(void)
+{
+ ulong guard_page;
+
+ if (!IS_ENABLED(CONFIG_STACK_GUARD_PAGE))
+ return;
+
+ guard_page = arm_mem_guard_page_get();
+ request_sdram_region("guard page", guard_page, PAGE_SIZE);
+ remap_range((void *)guard_page, PAGE_SIZE, MAP_FAULT);
+
+ pr_debug("Created guard page\n");
+}
+
/*
* Prepare MMU for usage enable it.
*/
void __mmu_init(bool mmu_on)
{
+ uint64_t *ttb = get_ttb();
struct memory_bank *bank;
- unsigned int el;
-
- if (mmu_on)
- mmu_disable();
-
- ttb = create_table();
- el = current_el();
- set_ttbr_tcr_mair(el, (uint64_t)ttb, calc_tcr(el, BITS_PER_VA),
- MEMORY_ATTRIBUTES);
-
- pr_debug("ttb: 0x%p\n", ttb);
- /* create a flat mapping */
- create_sections(0, 0, 1UL << (BITS_PER_VA - 1), attrs_uncached_mem());
+ if (!request_sdram_region("ttb", (unsigned long)ttb,
+ ARM_EARLY_PAGETABLE_SIZE))
+ /*
+ * This can mean that:
+ * - the early MMU code has put the ttb into a place
+ * which we don't have inside our available memory
+ * - Somebody else has occupied the ttb region which means
+ * the ttb will get corrupted.
+ */
+ pr_crit("Can't request SDRAM region for ttb at %p\n", ttb);
+
+ for_each_memory_bank(bank) {
+ struct resource *rsv;
+ resource_size_t pos;
+
+ pos = bank->start;
+
+ /* Skip reserved regions */
+ for_each_reserved_region(bank, rsv) {
+ remap_range((void *)pos, rsv->start - pos, MAP_CACHED);
+ pos = rsv->end + 1;
+ }
- /* Map sdram cached. */
- for_each_memory_bank(bank)
- create_sections(bank->start, bank->start, bank->size, CACHED_MEM);
+ remap_range((void *)pos, bank->start + bank->size - pos, MAP_CACHED);
+ }
/* Make zero page faulting to catch NULL pointer derefs */
- create_sections(0x0, 0x0, 0x1000, 0x0);
-
- mmu_enable();
+ zero_page_faulting();
+ create_guard_page();
}
void mmu_disable(void)
@@ -241,15 +295,66 @@ void dma_flush_range(void *ptr, size_t size)
v8_flush_dcache_range(start, end);
}
-void dma_sync_single_for_device(dma_addr_t address, size_t size,
- enum dma_data_direction dir)
+static void init_range(size_t total_level0_tables)
+{
+ uint64_t *ttb = get_ttb();
+ uint64_t addr = 0;
+
+ while (total_level0_tables--) {
+ early_remap_range(addr, L0_XLAT_SIZE, MAP_UNCACHED);
+ split_block(ttb, 0);
+ addr += L0_XLAT_SIZE;
+ ttb++;
+ }
+}
+
+void mmu_early_enable(unsigned long membase, unsigned long memsize)
{
+ int el;
+ u64 optee_membase;
+ unsigned long ttb = arm_mem_ttb(membase + memsize);
+
+ if (get_cr() & CR_M)
+ return;
+
+ pr_debug("enabling MMU, ttb @ 0x%08lx\n", ttb);
+
+ el = current_el();
+ set_ttbr_tcr_mair(el, ttb, calc_tcr(el, BITS_PER_VA), MEMORY_ATTRIBUTES);
+ if (el == 3)
+ set_ttbr_tcr_mair(2, ttb, calc_tcr(2, BITS_PER_VA), MEMORY_ATTRIBUTES);
+
+ memset((void *)ttb, 0, GRANULE_SIZE);
+
/*
- * FIXME: This function needs a device argument to support non 1:1 mappings
+ * Assume maximum BITS_PER_PA set to 40 bits.
+ * Set 1:1 mapping of VA->PA. So to cover the full 1TB range we need 2 tables.
*/
+ init_range(2);
+
+ early_remap_range(membase, memsize, MAP_CACHED);
- if (dir == DMA_FROM_DEVICE)
- v8_inv_dcache_range(address, address + size - 1);
- else
- v8_flush_dcache_range(address, address + size - 1);
+ if (optee_get_membase(&optee_membase))
+ optee_membase = membase + memsize - OPTEE_SIZE;
+
+ early_remap_range(optee_membase, OPTEE_SIZE, MAP_FAULT);
+
+ early_remap_range(PAGE_ALIGN_DOWN((uintptr_t)_stext), PAGE_ALIGN(_etext - _stext), MAP_CACHED);
+
+ mmu_enable();
+}
+
+void mmu_early_disable(void)
+{
+ unsigned int cr;
+
+ cr = get_cr();
+ cr &= ~(CR_M | CR_C);
+
+ set_cr(cr);
+ v8_flush_dcache_all();
+ tlb_invalidate();
+
+ dsb();
+ isb();
}
diff --git a/arch/arm/cpu/mmu_64.h b/arch/arm/cpu/mmu_64.h
index 9bbb62fc6b..e3959e4407 100644
--- a/arch/arm/cpu/mmu_64.h
+++ b/arch/arm/cpu/mmu_64.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
#include "mmu-common.h"
@@ -104,12 +105,27 @@ static inline uint64_t level2mask(int level)
return mask;
}
+/**
+ * @brief Returns the TCR (Translation Control Register) value
+ *
+ * @param el - Exception Level
+ * @param va_bits - Virtual Address bits
+ * @return uint64_t TCR
+ */
static inline uint64_t calc_tcr(int el, int va_bits)
{
- u64 ips;
- u64 tcr;
+ u64 ips; // Intermediate Physical Address Size
+ u64 tcr; // Translation Control Register
+#if (BITS_PER_PA == 40)
ips = 2;
+#elif (BITS_PER_PA == 36)
+ ips = 1;
+#elif (BITS_PER_PA == 32)
+ ips = 0;
+#else
+#error "Unsupported"
+#endif
if (el == 1)
tcr = (ips << 32) | TCR_EPD1_DISABLE;
diff --git a/arch/arm/cpu/mmuinfo.c b/arch/arm/cpu/mmuinfo.c
index 1db6eb3869..44d6980a75 100644
--- a/arch/arm/cpu/mmuinfo.c
+++ b/arch/arm/cpu/mmuinfo.c
@@ -1,101 +1,85 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2012 Jan Luebbe <j.luebbe@pengutronix.de>, Pengutronix
/*
- * mmuinfo.c - Show MMU/cache information from cp15 registers
- *
- * Copyright (c) Jan Luebbe <j.luebbe@pengutronix.de>, Pengutronix
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that 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.
- *
+ * mmuinfo.c - Show MMU/cache information
*/
#include <common.h>
#include <command.h>
+#include <getopt.h>
+#include <asm/mmuinfo.h>
+#include <asm/system_info.h>
+#include <zero_page.h>
+#include <mmu.h>
-static char *inner_attr[] = {
- "0b000 Non-cacheable",
- "0b001 Strongly-ordered",
- "0b010 (reserved)",
- "0b011 Device",
- "0b100 (reserved)",
- "0b101 Write-Back, Write-Allocate",
- "0b110 Write-Through",
- "0b111 Write-Back, no Write-Allocate",
-};
-
-static char *outer_attr[] = {
- "0b00 Non-cacheable",
- "0b01 Write-Back, Write-Allocate",
- "0b10 Write-Through, no Write-Allocate",
- "0b11 Write-Back, no Write-Allocate",
-};
-
-static void decode_par(unsigned long par)
+int mmuinfo(void *addr)
{
- printf(" Physical Address [31:12]: 0x%08lx\n", par & 0xFFFFF000);
- printf(" Reserved [11]: 0x%lx\n", (par >> 11) & 0x1);
- printf(" Not Outer Shareable [10]: 0x%lx\n", (par >> 10) & 0x1);
- printf(" Non-Secure [9]: 0x%lx\n", (par >> 9) & 0x1);
- printf(" Impl. def. [8]: 0x%lx\n", (par >> 8) & 0x1);
- printf(" Shareable [7]: 0x%lx\n", (par >> 7) & 0x1);
- printf(" Inner mem. attr. [6:4]: 0x%lx (%s)\n", (par >> 4) & 0x7,
- inner_attr[(par >> 4) & 0x7]);
- printf(" Outer mem. attr. [3:2]: 0x%lx (%s)\n", (par >> 2) & 0x3,
- outer_attr[(par >> 2) & 0x3]);
- printf(" SuperSection [1]: 0x%lx\n", (par >> 1) & 0x1);
- printf(" Failure [0]: 0x%lx\n", (par >> 0) & 0x1);
+ if (IS_ENABLED(CONFIG_CPU_V8))
+ return mmuinfo_v8(addr);
+ if (IS_ENABLED(CONFIG_CPU_V7) && cpu_architecture() == CPU_ARCH_ARMv7)
+ return mmuinfo_v7(addr);
+
+ return -ENOSYS;
}
-static int do_mmuinfo(int argc, char *argv[])
+static __maybe_unused int do_mmuinfo(int argc, char *argv[])
{
- unsigned long addr = 0, priv_read, priv_write;
+ unsigned long addr;
+ int access_zero_page = -1;
+ int opt;
- if (argc < 2)
- return COMMAND_ERROR_USAGE;
+ while ((opt = getopt(argc, argv, "zZ")) > 0) {
+ switch (opt) {
+ case 'z':
+ access_zero_page = true;
+ break;
+ case 'Z':
+ access_zero_page = false;
+ break;
+ default:
+ return COMMAND_ERROR_USAGE;
+ }
+ }
- addr = strtoul_suffix(argv[1], NULL, 0);
+ if (access_zero_page >= 0) {
+ if (argc - optind != 0)
+ return COMMAND_ERROR_USAGE;
- __asm__ __volatile__(
- "mcr p15, 0, %0, c7, c8, 0 @ write VA to PA translation (priv read)\n"
- :
- : "r" (addr)
- : "memory");
+ if (!zero_page_remappable()) {
+ pr_warn("No architecture support for zero page remap\n");
+ return -ENOSYS;
+ }
- __asm__ __volatile__(
- "mrc p15, 0, %0, c7, c4, 0 @ read PAR\n"
- : "=r" (priv_read)
- :
- : "memory");
+ if (access_zero_page)
+ zero_page_access();
+ else
+ zero_page_faulting();
- __asm__ __volatile__(
- "mcr p15, 0, %0, c7, c8, 1 @ write VA to PA translation (priv write)\n"
- :
- : "r" (addr)
- : "memory");
+ return 0;
+ }
- __asm__ __volatile__(
- "mrc p15, 0, %0, c7, c4, 0 @ read PAR\n"
- : "=r" (priv_write)
- :
- : "memory");
+ if (argc - optind != 1)
+ return COMMAND_ERROR_USAGE;
- printf("PAR result for 0x%08lx: \n", addr);
- printf(" privileged read: 0x%08lx\n", priv_read);
- decode_par(priv_read);
- printf(" privileged write: 0x%08lx\n", priv_write);
- decode_par(priv_write);
+ addr = strtoul_suffix(argv[1], NULL, 0);
- return 0;
+ return mmuinfo((void *)addr);
}
+BAREBOX_CMD_HELP_START(mmuinfo)
+BAREBOX_CMD_HELP_TEXT("Show MMU/cache information using the cp15/model-specific registers.")
+BAREBOX_CMD_HELP_TEXT("")
+BAREBOX_CMD_HELP_TEXT("Options:")
+BAREBOX_CMD_HELP_OPT ("-z", "enable access to zero page")
+BAREBOX_CMD_HELP_OPT ("-Z", "disable access to zero page")
+BAREBOX_CMD_HELP_END
+
+#ifdef CONFIG_COMMAND_SUPPORT
BAREBOX_CMD_START(mmuinfo)
.cmd = do_mmuinfo,
BAREBOX_CMD_DESC("show MMU/cache information of an address")
- BAREBOX_CMD_OPTS("ADDRESS")
+ BAREBOX_CMD_OPTS("[-zZ | ADDRESS]")
BAREBOX_CMD_GROUP(CMD_GRP_INFO)
+ BAREBOX_CMD_HELP(cmd_mmuinfo_help)
BAREBOX_CMD_END
+#endif
diff --git a/arch/arm/cpu/mmuinfo_32.c b/arch/arm/cpu/mmuinfo_32.c
new file mode 100644
index 0000000000..e26dabc9b3
--- /dev/null
+++ b/arch/arm/cpu/mmuinfo_32.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2012 Jan Luebbe <j.luebbe@pengutronix.de>, Pengutronix
+/*
+ * mmuinfo_32.c - Show MMU/cache information from cp15 registers
+ */
+
+#include <common.h>
+#include <asm/mmuinfo.h>
+
+static char *inner_attr[] = {
+ "0b000 Non-cacheable",
+ "0b001 Strongly-ordered",
+ "0b010 (reserved)",
+ "0b011 Device",
+ "0b100 (reserved)",
+ "0b101 Write-Back, Write-Allocate",
+ "0b110 Write-Through",
+ "0b111 Write-Back, no Write-Allocate",
+};
+
+static char *outer_attr[] = {
+ "0b00 Non-cacheable",
+ "0b01 Write-Back, Write-Allocate",
+ "0b10 Write-Through, no Write-Allocate",
+ "0b11 Write-Back, no Write-Allocate",
+};
+
+static void decode_par(unsigned long par)
+{
+ printf(" Physical Address [31:12]: 0x%08lx\n", par & 0xFFFFF000);
+ printf(" Reserved [11]: 0x%lx\n", (par >> 11) & 0x1);
+ printf(" Not Outer Shareable [10]: 0x%lx\n", (par >> 10) & 0x1);
+ printf(" Non-Secure [9]: 0x%lx\n", (par >> 9) & 0x1);
+ printf(" Impl. def. [8]: 0x%lx\n", (par >> 8) & 0x1);
+ printf(" Shareable [7]: 0x%lx\n", (par >> 7) & 0x1);
+ printf(" Inner mem. attr. [6:4]: 0x%lx (%s)\n", (par >> 4) & 0x7,
+ inner_attr[(par >> 4) & 0x7]);
+ printf(" Outer mem. attr. [3:2]: 0x%lx (%s)\n", (par >> 2) & 0x3,
+ outer_attr[(par >> 2) & 0x3]);
+ printf(" SuperSection [1]: 0x%lx\n", (par >> 1) & 0x1);
+ printf(" Failure [0]: 0x%lx\n", (par >> 0) & 0x1);
+}
+
+int mmuinfo_v7(void *_addr)
+{
+ unsigned long addr = (unsigned long)_addr;
+ unsigned long priv_read, priv_write;
+
+ __asm__ __volatile__(
+ "mcr p15, 0, %0, c7, c8, 0 @ write VA to PA translation (priv read)\n"
+ :
+ : "r" (addr)
+ : "memory");
+
+ __asm__ __volatile__(
+ "mrc p15, 0, %0, c7, c4, 0 @ read PAR\n"
+ : "=r" (priv_read)
+ :
+ : "memory");
+
+ __asm__ __volatile__(
+ "mcr p15, 0, %0, c7, c8, 1 @ write VA to PA translation (priv write)\n"
+ :
+ : "r" (addr)
+ : "memory");
+
+ __asm__ __volatile__(
+ "mrc p15, 0, %0, c7, c4, 0 @ read PAR\n"
+ : "=r" (priv_write)
+ :
+ : "memory");
+
+ printf("PAR result for 0x%08lx: \n", addr);
+ printf(" privileged read: 0x%08lx\n", priv_read);
+ decode_par(priv_read);
+ printf(" privileged write: 0x%08lx\n", priv_write);
+ decode_par(priv_write);
+
+ return 0;
+}
diff --git a/arch/arm/cpu/mmuinfo_64.c b/arch/arm/cpu/mmuinfo_64.c
new file mode 100644
index 0000000000..de4945f43e
--- /dev/null
+++ b/arch/arm/cpu/mmuinfo_64.c
@@ -0,0 +1,215 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2023 Ahmad Fatoum <a.fatoum@pengutronix.de>, Pengutronix
+/*
+ * mmuinfo_64.c - Show MMU/cache information via AT instruction
+ */
+
+#include <common.h>
+#include <asm/mmuinfo.h>
+#include <asm/system.h>
+#include <asm/sysreg.h>
+#include <linux/bitfield.h>
+
+#define at_par(reg, addr) ({ \
+ asm volatile("at " reg ", %0\n" :: "r" (addr)); \
+ isb(); \
+ read_sysreg_par(); \
+})
+
+#define BITS(from, to, val) FIELD_GET(GENMASK(from, to), val)
+
+static const char *decode_devmem_attr(u8 attr)
+{
+ switch (attr & ~0x1) {
+ case 0b00000000:
+ return "0b0000 Device-nGnRnE memory";
+ case 0b00000100:
+ return "0b0100 Device-nGnRE memory";
+ case 0b00001000:
+ return "0b1000 Device-nGRE memory";
+ case 0b00001100:
+ return "0b1100 Device-GRE memory";
+ default:
+ return "unknown";
+ };
+}
+
+static char *cache_attr[] = {
+ "0b0000 Wrongly decoded",
+ "0b0001 Write-Through Transient, Write-Allocate, no Read-Allocate",
+ "0b0010 Write-Through Transient, no Write-Allocate",
+ "0b0011 Write-Through Transient, Write-Allocate",
+ "0b0100 Non-Cacheable",
+ "0b0101 Write-Back Transient, Write-Allocate, no Read-Allocate",
+ "0b0110 Write-Back Transient, no Write-Allocate",
+ "0b0111 Write-Back Transient, Write-Allocate",
+ "0b1000 Write-Through Non-transient, no Write-Allocate no Read-Allocate",
+ "0b1001 Write-Through Non-transient, Write-Allocate no Read-Allocate",
+ "0b1010 Write-Through Non-transient, no Write-Allocate",
+ "0b1011 Write-Through Non-transient, Write-Allocate",
+ "0b1100 Write-Back Non-transient, no Write-Allocate no Read-Allocate",
+ "0b1101 Write-Back Non-transient, Write-Allocate no Read-Allocate",
+ "0b1110 Write-Back Non-transient, no Write-Allocate",
+ "0b1111 Write-Back Non-transient, Write-Allocate",
+};
+
+static char *share_attr[] = {
+ "0b00 Non-Shareable",
+ "0b01 Reserved",
+ "0b10 Outer Shareable",
+ "0b11 Inner Shareable",
+};
+
+static char *stage_fault[] = {
+ "stage 1 translation",
+ "stage 2 translation",
+};
+
+static char *fault_status_leveled[] = {
+ "Address size fault", /* of translation or translation table base register */
+ "Translation fault",
+ "Access flag fault",
+ "Permission fault",
+ "Synchronous External abort", /* level -1 */
+ "Synchronous External abort", /* on translation table walk or hardware update of translation table */
+ "Synchronous parity or ECC error", /* level -1 */
+ "Synchronous parity or ECC error", /* on memory access on translation table walk or hardware update of translation table */
+};
+
+static const char *decode_fault_status_level(u8 fst)
+{
+ if (!(fst & BIT(5)))
+ return "";
+
+ switch (BITS(5, 0, fst)) {
+ case 0b010011:
+ case 0b011011:
+ return ", level -1";
+ }
+
+ switch (BITS(1, 0, fst)) {
+ case 0b00:
+ return ", level 0";
+ case 0b01:
+ return ", level 1";
+ case 0b10:
+ return ", level 2";
+ case 0b11:
+ return ", level 3";
+ }
+
+ BUG();
+}
+
+static const char *decode_fault_status(u8 fst)
+{
+
+ switch (BITS(5, 0, fst)) {
+ case 0b101001: /* When FEAT_LPA2 is implemented */
+ return "Address size fault, level -1";
+ case 0b101011: /* When FEAT_LPA2 is implemented */
+ return "Translation fault, level -1";
+ case 0b110000:
+ return "TLB conflict abort";
+ case 0b110001: /* When FEAT_HAFDBS is implemented */
+ return "Unsupported atomic hardware update fault";
+ case 0b111101: /* When EL1 is capable of using AArch32 */
+ return "Section Domain fault, from an AArch32 stage 1 EL1&0 "
+ "translation regime using Short-descriptor translation "
+ "table format";
+ case 0b111110: /* When EL1 is capable of using AArch32 */
+ return "Page Domain fault, from an AArch32 stage 1 EL1&0 "
+ "translation regime using Short-descriptor translation "
+ "table format";
+ default:
+ if (fst & BIT(5))
+ return fault_status_leveled[BITS(4, 2, fst)];
+
+ return "Reserved";
+ }
+};
+
+static void decode_par(unsigned long par)
+{
+ u8 devmem_attr = BITS(63, 56, par);
+
+ if (par & 1) {
+ printf(" Translation aborted [9:8]: because of a fault in the %s%s\n",
+ stage_fault[BITS(9, 9, par)],
+ BITS(8, 8, par) ? " during a stage 1 translation table walk" : "");
+ printf(" Fault Status Code [6:1]: 0x%02lx (%s%s)\n", BITS(6, 1, par),
+ decode_fault_status(BITS(6, 1, par)),
+ decode_fault_status_level(BITS(6, 1, par)));
+ printf(" Failure [0]: 0x1\n");
+ } else {
+ if ((devmem_attr & 0xf0) && (devmem_attr & 0x0f)) {
+ printf(" Outer mem. attr. [63:60]: 0x%02lx (%s)\n", BITS(63, 60, par),
+ cache_attr[BITS(63, 60, par)]);
+ printf(" Inner mem. attr. [59:56]: 0x%02lx (%s)\n", BITS(59, 56, par),
+ cache_attr[BITS(59, 56, par)]);
+ } else if ((devmem_attr & 0b11110010) == 0) {
+ printf(" Memory attr. [63:56]: 0x%02x (%s)\n",
+ devmem_attr, decode_devmem_attr(devmem_attr));
+ if (devmem_attr & 1)
+ printf(" (XS == 0 if FEAT_XS implemented)\n");
+ } else if (devmem_attr == 0b01000000) {
+ printf(" Outer mem. attr. [63:56]: 0x%02lx (%s)\n", BITS(63, 56, par),
+ "Non-Cacheable");
+ printf(" Inner mem. attr. [63:56]: 0x%02lx (%s)\n", BITS(63, 56, par),
+ "Non-Cacheable");
+ printf(" (XS == 0 if FEAT_XS implemented)\n");
+ } else if (devmem_attr == 0b10100000) {
+ printf(" Outer mem. attr. [63:56]: 0x%02lx (%s)\n", BITS(63, 56, par),
+ "Write-Through, No Write-Allocate");
+ printf(" Inner mem. attr. [63:56]: 0x%02lx (%s)\n", BITS(63, 56, par),
+ "Write-Through");
+ printf(" (XS == 0 if FEAT_XS implemented)\n");
+ } else if (devmem_attr == 0b11110000) {
+ printf(" Outer mem. attr. [63:56]: 0x%02lx (%s)\n", BITS(63, 56, par),
+ "Write-Back");
+ printf(" Inner mem. attr. [63:56]: 0x%02lx (%s)\n", BITS(63, 56, par),
+ "Write-Back, Write-Allocate, Non-transient");
+ printf(" (if FEAT_MTE2 implemented)\n");
+ }
+ printf(" Physical Address [51:12]: 0x%08lx\n", par & GENMASK(51, 12));
+ printf(" Non-Secure [9]: 0x%lx\n", BITS(9, 9, par));
+ printf(" Shareability attr. [8:7]: 0x%02lx (%s)\n", BITS(8, 7, par),
+ share_attr[BITS(8, 7, par)]);
+ printf(" Failure [0]: 0x0\n");
+ }
+}
+
+int mmuinfo_v8(void *_addr)
+{
+ unsigned long addr = (unsigned long)_addr;
+ unsigned long priv_read, priv_write;
+
+ switch (current_el()) {
+ case 3:
+ priv_read = at_par("s1e3r", addr);
+ priv_write = at_par("s1e3w", addr);
+ break;
+ case 2:
+ priv_read = at_par("s1e2r", addr);
+ priv_write = at_par("s1e2w", addr);
+ break;
+ case 1:
+ priv_read = at_par("s1e1r", addr);
+ priv_write = at_par("s1e1w", addr);
+ break;
+ case 0:
+ priv_read = at_par("s1e0r", addr);
+ priv_write = at_par("s1e0w", addr);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ printf("PAR result for 0x%08lx: \n", addr);
+ printf(" privileged read: 0x%08lx\n", priv_read);
+ decode_par(priv_read);
+ printf(" privileged write: 0x%08lx\n", priv_write);
+ decode_par(priv_write);
+
+ return 0;
+}
diff --git a/arch/arm/cpu/no-mmu.c b/arch/arm/cpu/no-mmu.c
index 7268fa9b9d..be3cfaf12b 100644
--- a/arch/arm/cpu/no-mmu.c
+++ b/arch/arm/cpu/no-mmu.c
@@ -1,17 +1,7 @@
-/*
- * Copyright (c) 2015 Zodiac Inflight Innovation
- * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that 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.
- *
- */
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2015 Zodiac Inflight Innovation
+
+/* Author: Andrey Smirnov <andrew.smirnov@gmail.com> */
#define pr_fmt(fmt) "nommu: " fmt
diff --git a/arch/arm/cpu/psci-client.c b/arch/arm/cpu/psci-client.c
index b5d0d37497..c865e754fd 100644
--- a/arch/arm/cpu/psci-client.c
+++ b/arch/arm/cpu/psci-client.c
@@ -15,7 +15,7 @@
static struct restart_handler restart;
-static void __noreturn psci_invoke_noreturn(int function)
+static void __noreturn psci_invoke_noreturn(ulong function)
{
int ret;
@@ -108,12 +108,12 @@ static u32 invoke_psci_fn_smc(ulong function, ulong arg0, ulong arg1, ulong arg2
return res.a0;
}
-static int of_psci_do_fixup(struct device_node *root, void *context)
+static int of_psci_do_fixup(struct device_node *root, void *method)
{
- return of_psci_fixup(root, *(u32 *)context);
+ return of_psci_fixup(root, version, (const void *)method);
}
-static int __init psci_probe(struct device_d *dev)
+static int __init psci_probe(struct device *dev)
{
const char *method;
ulong of_version, actual_version;
@@ -123,7 +123,7 @@ static int __init psci_probe(struct device_d *dev)
if (ret)
return -ENODEV;
- ret = of_property_read_string(dev->device_node, "method", &method);
+ ret = of_property_read_string(dev->of_node, "method", &method);
if (ret) {
dev_warn(dev, "missing \"method\" property\n");
return -ENXIO;
@@ -156,7 +156,7 @@ static int __init psci_probe(struct device_d *dev)
version >> 16, version & 0xffff);
if (actual_version != of_version)
- of_register_fixup(of_psci_do_fixup, &version);
+ of_register_fixup(of_psci_do_fixup, (void *)method);
ret = poweroff_handler_register_fn(psci_poweroff);
if (ret)
@@ -181,8 +181,9 @@ static __maybe_unused struct of_device_id psci_dt_ids[] = {
{ .compatible = "arm,psci-1.0", .data = (void*)ARM_PSCI_VER(1,0) },
{ /* sentinel */ },
};
+MODULE_DEVICE_TABLE(of, psci_dt_ids);
-static struct driver_d psci_driver = {
+static struct driver psci_driver = {
.name = "psci",
.probe = psci_probe,
.of_compatible = DRV_OF_COMPAT(psci_dt_ids),
diff --git a/arch/arm/cpu/psci-of.c b/arch/arm/cpu/psci-of.c
index ef83b0edee..1b6371ddd6 100644
--- a/arch/arm/cpu/psci-of.c
+++ b/arch/arm/cpu/psci-of.c
@@ -7,7 +7,8 @@
#include <asm/psci.h>
#include <linux/arm-smccc.h>
-int of_psci_fixup(struct device_node *root, unsigned long psci_version)
+int of_psci_fixup(struct device_node *root, unsigned long psci_version,
+ const char *method)
{
struct device_node *psci;
int ret;
@@ -39,14 +40,14 @@ int of_psci_fixup(struct device_node *root, unsigned long psci_version)
if (!cpu)
break;
of_property_write_string(cpu, "enable-method", "psci");
- pr_debug("Fixed %s\n", cpu->full_name);
+ pr_debug("Fixed %pOF\n", cpu);
}
ret = of_property_write_string(psci, "compatible", compat);
if (ret)
return ret;
- ret = of_property_write_string(psci, "method", "smc");
+ ret = of_property_write_string(psci, "method", method);
if (ret)
return ret;
diff --git a/arch/arm/cpu/psci.c b/arch/arm/cpu/psci.c
index 5a69aaa810..70c97e03a5 100644
--- a/arch/arm/cpu/psci.c
+++ b/arch/arm/cpu/psci.c
@@ -1,13 +1,4 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; version 2.
- *
- * This program is distributed in the hope that 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.
- */
+// SPDX-License-Identifier: GPL-2.0-only
#define pr_fmt(fmt) "psci: " fmt
@@ -98,7 +89,7 @@ static unsigned long psci_cpu_suspend(u32 power_state, unsigned long entry,
{
psci_printf("%s\n", __func__);
- if (psci_ops->cpu_off)
+ if (psci_ops->cpu_suspend)
return psci_ops->cpu_suspend(power_state, entry, context_id);
return ARM_PSCI_RET_NOT_SUPPORTED;
@@ -198,7 +189,7 @@ static int of_psci_do_fixup(struct device_node *root, void *unused)
if (bootm_arm_security_state() < ARM_STATE_NONSECURE)
return 0;
- return of_psci_fixup(root, ARM_PSCI_VER_1_0);
+ return of_psci_fixup(root, ARM_PSCI_VER_1_0, "smc");
}
int psci_cpu_entry_c(void)
diff --git a/arch/arm/cpu/sections.c b/arch/arm/cpu/sections.c
index a53236d900..f310578ba2 100644
--- a/arch/arm/cpu/sections.c
+++ b/arch/arm/cpu/sections.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
#include <asm/sections.h>
#include <linux/types.h>
diff --git a/arch/arm/cpu/setupc.S b/arch/arm/cpu/setupc_32.S
index 8ae7c89a2c..eafc9b52c6 100644
--- a/arch/arm/cpu/setupc.S
+++ b/arch/arm/cpu/setupc_32.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
#include <linux/linkage.h>
#include <asm/sections.h>
@@ -21,12 +23,12 @@ ENTRY(setup_c)
ldr r2,=__bss_start
sub r2, r2, r0
add r1, r0, r4
- bl memcpy /* memcpy(_text, _text + offset, __bss_start - _text) */
+ bl __memcpy /* memcpy(_text, _text + offset, __bss_start - _text) */
1: ldr r0, =__bss_start
mov r1, #0
ldr r2, =__bss_stop
sub r2, r2, r0
- bl memset /* clear bss */
+ bl __memset /* clear bss */
bl sync_caches_for_execution
sub lr, r5, r4 /* adjust return address to new location */
pop {r4, r5}
@@ -67,7 +69,7 @@ ENTRY(relocate_to_adr)
sub r7, r7, r1 /* sub address where we are actually running */
add r7, r7, r0 /* add address where we are going to run */
- bl memcpy /* copy binary */
+ bl __memcpy /* copy binary */
bl sync_caches_for_execution
diff --git a/arch/arm/cpu/setupc_64.S b/arch/arm/cpu/setupc_64.S
index ee9ea6cfc0..2138c2a600 100644
--- a/arch/arm/cpu/setupc_64.S
+++ b/arch/arm/cpu/setupc_64.S
@@ -1,4 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
#include <linux/linkage.h>
+#include <asm/assembler.h>
#include <asm/sections.h>
.section .text.setupc
@@ -8,11 +11,11 @@
*/
ENTRY(setup_c)
mov x15, x30
- ldr x0, =__bss_start
+ adr_l x0, __bss_start
mov x1, #0
- ldr x2, =__bss_stop
+ adr_l x2, __bss_stop
sub x2, x2, x0
- bl memset /* clear bss */
+ bl __memset /* clear bss */
mov x30, x15
ret
ENDPROC(setup_c)
@@ -24,9 +27,18 @@ ENDPROC(setup_c)
* executing at new address.
*/
.section .text.relocate_to_adr
-ENTRY(relocate_to_adr)
/* x0: target address */
+#ifdef __PBL__
+ENTRY(relocate_to_adr_full)
+ adr_l x2, __image_end
+ b 1f
+#endif
+
+ENTRY(relocate_to_adr)
+ adr_l x2, __bss_start
+ b 1f
+1:
stp x19, x20, [sp, #-16]!
stp x21, x22, [sp, #-16]!
@@ -34,34 +46,27 @@ ENTRY(relocate_to_adr)
mov x21, x0
- bl get_runtime_offset
- mov x5, x0
-
- ldr x0, =_text
- mov x20, x0
-
- add x1, x0, x5 /* x1: from address */
+ adr_l x1, _text
+ mov x20, x1
cmp x1, x21 /* already at correct address? */
beq 1f /* yes, skip copy to new address */
- ldr x2, =__bss_start
-
- sub x2, x2, x0 /* x2: size */
+ sub x2, x2, x1 /* x2: size */
mov x0, x21 /* x0: target */
/* adjust return address */
sub x19, x19, x1 /* sub address where we are actually running */
add x19, x19, x0 /* add address where we are going to run */
- bl memcpy /* copy binary */
+ bl __memcpy /* copy binary */
bl sync_caches_for_execution
mov x0,#0
ic ivau, x0 /* flush icache */
- ldr x0,=1f
+ adr_l x0, 1f
sub x0, x0, x20
add x0, x0, x21
br x0 /* jump to relocated address */
diff --git a/arch/arm/cpu/sm.c b/arch/arm/cpu/sm.c
index f5a1edbd4f..53f5142b63 100644
--- a/arch/arm/cpu/sm.c
+++ b/arch/arm/cpu/sm.c
@@ -19,8 +19,7 @@
#include <linux/arm-smccc.h>
#include <asm-generic/sections.h>
#include <asm/secure.h>
-
-#include "mmu.h"
+#include "mmu_32.h"
static unsigned int read_id_pfr1(void)
{
diff --git a/arch/arm/cpu/sm_as.S b/arch/arm/cpu/sm_as.S
index de6cd0406f..f55ac8661c 100644
--- a/arch/arm/cpu/sm_as.S
+++ b/arch/arm/cpu/sm_as.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
#include <linux/linkage.h>
#include <asm/ptrace.h>
#include <asm-generic/memory_layout.h>
diff --git a/arch/arm/cpu/smccc-call.S b/arch/arm/cpu/smccc-call_32.S
index b6bdc8b3b5..9875e1f947 100644
--- a/arch/arm/cpu/smccc-call.S
+++ b/arch/arm/cpu/smccc-call_32.S
@@ -1,16 +1,6 @@
-/*
- * Copyright (c) 2015, Linaro Limited
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that 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.
- *
- */
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* SPDX-FileCopyrightText: 2015 Linaro Limited */
+
#include <linux/linkage.h>
#include <asm/unwind.h>
diff --git a/arch/arm/cpu/smccc-call_64.S b/arch/arm/cpu/smccc-call_64.S
index 44888fb594..c2959050d2 100644
--- a/arch/arm/cpu/smccc-call_64.S
+++ b/arch/arm/cpu/smccc-call_64.S
@@ -1,16 +1,6 @@
-/*
- * Copyright (c) 2015, Linaro Limited
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that 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.
- *
- */
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* SPDX-FileCopyrightText: 2015 Linaro Limited */
+
#include <linux/linkage.h>
#include <linux/arm-smccc.h>
#include <asm/asm-offsets.h>
diff --git a/arch/arm/cpu/start.c b/arch/arm/cpu/start.c
index 2cf21459da..0351dcb927 100644
--- a/arch/arm/cpu/start.c
+++ b/arch/arm/cpu/start.c
@@ -1,18 +1,12 @@
-/*
- * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that 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.
- *
- */
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2010 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+
#define pr_fmt(fmt) "start.c: " fmt
+#ifdef CONFIG_DEBUG_INITCALLS
+#define DEBUG
+#endif
+
#include <common.h>
#include <init.h>
#include <linux/sizes.h>
@@ -25,8 +19,10 @@
#include <asm/unaligned.h>
#include <asm/cache.h>
#include <asm/mmu.h>
+#include <linux/kasan.h>
#include <memory.h>
#include <uncompress.h>
+#include <compressed-dtb.h>
#include <malloc.h>
#include <debug_ll.h>
@@ -36,44 +32,36 @@
unsigned long arm_stack_top;
static unsigned long arm_barebox_size;
static unsigned long arm_endmem;
+static unsigned long arm_membase;
static void *barebox_boarddata;
static unsigned long barebox_boarddata_size;
-static bool blob_is_fdt(const void *blob)
-{
- return get_unaligned_be32(blob) == FDT_MAGIC;
-}
-
-static bool blob_is_compressed_fdt(const void *blob)
+static bool blob_is_arm_boarddata(const void *blob)
{
- const struct barebox_arm_boarddata_compressed_dtb *dtb = blob;
+ const struct barebox_arm_boarddata *bd = blob;
- return dtb->magic == BAREBOX_ARM_BOARDDATA_COMPRESSED_DTB_MAGIC;
+ return bd->magic == BAREBOX_ARM_BOARDDATA_MAGIC;
}
-static bool blob_is_arm_boarddata(const void *blob)
+const struct barebox_boarddata *barebox_get_boarddata(void)
{
- const struct barebox_arm_boarddata *bd = blob;
+ if (!barebox_boarddata || !blob_is_arm_boarddata(barebox_boarddata))
+ return NULL;
- return bd->magic == BAREBOX_ARM_BOARDDATA_MAGIC;
+ return barebox_boarddata;
}
u32 barebox_arm_machine(void)
{
- if (barebox_boarddata && blob_is_arm_boarddata(barebox_boarddata)) {
- const struct barebox_arm_boarddata *bd = barebox_boarddata;
- return bd->machine;
- } else {
- return 0;
- }
+ const struct barebox_boarddata *bd = barebox_get_boarddata();
+ return bd ? bd->machine : 0;
}
void *barebox_arm_boot_dtb(void)
{
void *dtb;
- void *data;
- int ret;
- struct barebox_arm_boarddata_compressed_dtb *compressed_dtb;
+ int ret = 0;
+ struct barebox_boarddata_compressed_dtb *compressed_dtb;
static void *boot_dtb;
if (boot_dtb)
@@ -84,8 +72,7 @@ void *barebox_arm_boot_dtb(void)
return barebox_boarddata;
}
- if (!IS_ENABLED(CONFIG_ARM_USE_COMPRESSED_DTB) || !barebox_boarddata
- || !blob_is_compressed_fdt(barebox_boarddata))
+ if (!fdt_blob_can_be_decompressed(barebox_boarddata))
return NULL;
compressed_dtb = barebox_boarddata;
@@ -96,10 +83,13 @@ void *barebox_arm_boot_dtb(void)
if (!dtb)
return NULL;
- data = compressed_dtb + 1;
+ if (IS_ENABLED(CONFIG_IMAGE_COMPRESSION_NONE))
+ memcpy(dtb, compressed_dtb->data,
+ compressed_dtb->datalen_uncompressed);
+ else
+ ret = uncompress(compressed_dtb->data, compressed_dtb->datalen,
+ NULL, NULL, dtb, NULL, NULL);
- ret = uncompress(data, compressed_dtb->datalen, NULL, NULL,
- dtb, NULL, NULL);
if (ret) {
pr_err("uncompressing dtb failed\n");
free(dtb);
@@ -125,7 +115,7 @@ static inline unsigned long arm_mem_boarddata(unsigned long membase,
unsigned long arm_mem_ramoops_get(void)
{
- return arm_mem_ramoops(0, arm_stack_top);
+ return arm_mem_ramoops(arm_stack_top);
}
EXPORT_SYMBOL_GPL(arm_mem_ramoops_get);
@@ -135,17 +125,27 @@ unsigned long arm_mem_endmem_get(void)
}
EXPORT_SYMBOL_GPL(arm_mem_endmem_get);
+unsigned long arm_mem_membase_get(void)
+{
+ return arm_membase;
+}
+EXPORT_SYMBOL_GPL(arm_mem_membase_get);
+
static int barebox_memory_areas_init(void)
{
if(barebox_boarddata)
request_sdram_region("board data", (unsigned long)barebox_boarddata,
barebox_boarddata_size);
+ if (IS_ENABLED(CONFIG_KASAN))
+ request_sdram_region("kasan shadow", kasan_shadow_base,
+ mem_malloc_start() - kasan_shadow_base);
+
return 0;
}
device_initcall(barebox_memory_areas_init);
-__noreturn void barebox_non_pbl_start(unsigned long membase,
+__noreturn __prereloc void barebox_non_pbl_start(unsigned long membase,
unsigned long memsize, void *boarddata)
{
unsigned long endmem = membase + memsize;
@@ -169,23 +169,12 @@ __noreturn void barebox_non_pbl_start(unsigned long membase,
pr_debug("memory at 0x%08lx, size 0x%08lx\n", membase, memsize);
+ arm_membase = membase;
arm_endmem = endmem;
- arm_stack_top = arm_mem_stack_top(membase, endmem);
+ arm_stack_top = arm_mem_stack_top(endmem);
arm_barebox_size = barebox_size;
malloc_end = barebox_base;
- if (IS_ENABLED(CONFIG_MMU_EARLY)) {
- unsigned long ttb = arm_mem_ttb(membase, endmem);
-
- if (IS_ENABLED(CONFIG_PBL_IMAGE)) {
- arm_set_cache_functions();
- } else {
- pr_debug("enabling MMU, ttb @ 0x%08lx\n", ttb);
- arm_early_mmu_cache_invalidate();
- mmu_early_enable(membase, memsize, ttb);
- }
- }
-
if (boarddata) {
uint32_t totalsize = 0;
const char *name;
@@ -194,24 +183,12 @@ __noreturn void barebox_non_pbl_start(unsigned long membase,
totalsize = get_unaligned_be32(boarddata + 4);
name = "DTB";
} else if (blob_is_compressed_fdt(boarddata)) {
- struct barebox_arm_boarddata_compressed_dtb *bd = boarddata;
+ struct barebox_boarddata_compressed_dtb *bd = boarddata;
totalsize = bd->datalen + sizeof(*bd);
name = "Compressed DTB";
} else if (blob_is_arm_boarddata(boarddata)) {
totalsize = sizeof(struct barebox_arm_boarddata);
name = "machine type";
- } else if ((unsigned long)boarddata < 8192) {
- struct barebox_arm_boarddata *bd;
- uint32_t machine_type = (unsigned long)boarddata;
- unsigned long mem = arm_mem_boarddata(membase, endmem,
- sizeof(*bd));
- pr_debug("found machine type %d in boarddata\n",
- machine_type);
- bd = barebox_boarddata = (void *)mem;
- barebox_boarddata_size = sizeof(*bd);
- bd->magic = BAREBOX_ARM_BOARDDATA_MAGIC;
- bd->machine = machine_type;
- malloc_end = mem;
}
if (totalsize) {
@@ -243,8 +220,15 @@ __noreturn void barebox_non_pbl_start(unsigned long membase,
pr_debug("initializing malloc pool at 0x%08lx (size 0x%08lx)\n",
malloc_start, malloc_end - malloc_start);
+ kasan_init(membase, memsize, malloc_start - (memsize >> KASAN_SHADOW_SCALE_SHIFT));
+
mem_malloc_init((void *)malloc_start, (void *)malloc_end - 1);
+ if (IS_ENABLED(CONFIG_MMU) && !IS_ENABLED(CONFIG_PBL_IMAGE)) {
+ arm_early_mmu_cache_invalidate();
+ mmu_early_enable(membase, memsize);
+ }
+
if (IS_ENABLED(CONFIG_BOOTM_OPTEE))
of_add_reserve_entry(endmem - OPTEE_SIZE, endmem - 1);
@@ -269,7 +253,7 @@ void start(unsigned long membase, unsigned long memsize, void *boarddata);
* First function in the uncompressed image. We get here from
* the pbl. The stack already has been set up by the pbl.
*/
-void NAKED __section(.text_entry) start(unsigned long membase,
+void NAKED __prereloc __section(.text_entry) start(unsigned long membase,
unsigned long memsize, void *boarddata)
{
barebox_non_pbl_start(membase, memsize, boarddata);
diff --git a/arch/arm/cpu/uncompress.c b/arch/arm/cpu/uncompress.c
index 3eb0132d53..a481c4634d 100644
--- a/arch/arm/cpu/uncompress.c
+++ b/arch/arm/cpu/uncompress.c
@@ -1,19 +1,9 @@
-/*
- * uncompress.c - uncompressor code for self extracing pbl image
- *
- * Copyright (c) 2010-2013 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- * Copyright (c) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that 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.
- *
- */
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2010-2013 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+// SPDX-FileCopyrightText: 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+
+/* uncompress.c - uncompressor code for self extracing pbl image */
+
#define pr_fmt(fmt) "uncompress.c: " fmt
#include <common.h>
@@ -62,8 +52,9 @@ void __noreturn barebox_pbl_start(unsigned long membase, unsigned long memsize,
void *pg_start, *pg_end;
unsigned long pc = get_pc();
- pg_start = input_data + global_variable_offset();
- pg_end = input_data_end + global_variable_offset();
+ /* piggy data is not relocated, so determine the bounds now */
+ pg_start = runtime_address(input_data);
+ pg_end = runtime_address(input_data_end);
if (IS_ENABLED(CONFIG_PBL_RELOCATABLE)) {
/*
@@ -90,14 +81,11 @@ void __noreturn barebox_pbl_start(unsigned long membase, unsigned long memsize,
pr_debug("memory at 0x%08lx, size 0x%08lx\n", membase, memsize);
- if (IS_ENABLED(CONFIG_MMU_EARLY)) {
- unsigned long ttb = arm_mem_ttb(membase, endmem);
- pr_debug("enabling MMU, ttb @ 0x%08lx\n", ttb);
- mmu_early_enable(membase, memsize, ttb);
- }
+ if (IS_ENABLED(CONFIG_MMU))
+ mmu_early_enable(membase, memsize);
- free_mem_ptr = arm_mem_early_malloc(membase, endmem);
- free_mem_end_ptr = arm_mem_early_malloc_end(membase, endmem);
+ free_mem_ptr = arm_mem_early_malloc(endmem);
+ free_mem_end_ptr = arm_mem_early_malloc_end(endmem);
pr_debug("uncompressing barebox binary at 0x%p (size 0x%08x) to 0x%08lx (uncompressed size: 0x%08x)\n",
pg_start, pg_len, barebox_base, uncompressed_len);