summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAtish Patra <atish.patra@wdc.com>2020-05-10 02:47:26 +0300
committerAnup Patel <anup@brainfault.org>2020-05-10 07:30:02 +0300
commit79d0fadb0681acbba55bb6b4afcd3c2e6f725928 (patch)
tree3d8d4c832ba0c69e726e6d5e429e2f87874872b6 /lib
parent13ca20d8df3b402d12e5701c651a53409db167d8 (diff)
downloadopensbi-79d0fadb0681acbba55bb6b4afcd3c2e6f725928.tar.xz
lib: utils: Update reserved memory fdt node even if PMP is not present
As per RISC-V ISA, pmp is not mandatory. Currently, we only add reserved memory node in DT only if PMP is present. That allows supervisor to access the memory where OpenSBI continue to exist without realizing it for non-pmp based platforms. It may result in corrupting OpenSBI. That's why OpenSBI should at least let the supervisor know where it continue to exist. This a best effort service provided by OpenSBI expecting that supervisor software is not buggy and properly sets up its memory after parsing the reserved-memory device tree node. Signed-off-by: Atish Patra <atish.patra@wdc.com> Reviewed-by: Anup Patel <anup.patel@wdc.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/utils/fdt/fdt_fixup.c123
1 files changed, 71 insertions, 52 deletions
diff --git a/lib/utils/fdt/fdt_fixup.c b/lib/utils/fdt/fdt_fixup.c
index 9a9b435..e209cb6 100644
--- a/lib/utils/fdt/fdt_fixup.c
+++ b/lib/utils/fdt/fdt_fixup.c
@@ -10,6 +10,7 @@
#include <libfdt.h>
#include <sbi/riscv_asm.h>
#include <sbi/sbi_console.h>
+#include <sbi/sbi_math.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_string.h>
@@ -67,6 +68,63 @@ void fdt_plic_fixup(void *fdt, const char *compat)
}
}
+static int fdt_resv_memory_update_node(void *fdt, unsigned long addr,
+ unsigned long size, int index,
+ int parent)
+{
+ int na = fdt_address_cells(fdt, 0);
+ int ns = fdt_size_cells(fdt, 0);
+ fdt32_t addr_high, addr_low;
+ fdt32_t size_high, size_low;
+ int subnode, err;
+ fdt32_t reg[4];
+ fdt32_t *val;
+ char name[32];
+
+ addr_high = (u64)addr >> 32;
+ addr_low = addr;
+ size_high = (u64)size >> 32;
+ size_low = size;
+
+ if (na > 1 && addr_high)
+ sbi_snprintf(name, sizeof(name),
+ "mmode_pmp%d@%x,%x", index,
+ addr_high, addr_low);
+ else
+ sbi_snprintf(name, sizeof(name),
+ "mmode_pmp%d@%x", index,
+ addr_low);
+
+ subnode = fdt_add_subnode(fdt, parent, name);
+ if (subnode < 0)
+ return subnode;
+
+ /*
+ * Tell operating system not to create a virtual
+ * mapping of the region as part of its standard
+ * mapping of system memory.
+ */
+ err = fdt_setprop_empty(fdt, subnode, "no-map");
+ if (err < 0)
+ return err;
+
+ /* encode the <reg> property value */
+ val = reg;
+ if (na > 1)
+ *val++ = cpu_to_fdt32(addr_high);
+ *val++ = cpu_to_fdt32(addr_low);
+ if (ns > 1)
+ *val++ = cpu_to_fdt32(size_high);
+ *val++ = cpu_to_fdt32(size_low);
+
+ err = fdt_setprop(fdt, subnode, "reg", reg,
+ (na + ns) * sizeof(fdt32_t));
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
/**
* We use PMP to protect OpenSBI firmware to safe-guard it from buggy S-mode
* software, see pmp_init() in lib/sbi/sbi_hart.c. The protected memory region
@@ -87,19 +145,10 @@ int fdt_reserved_memory_fixup(void *fdt)
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
unsigned long prot, addr, size;
+ int parent, i, j;
+ int err;
int na = fdt_address_cells(fdt, 0);
int ns = fdt_size_cells(fdt, 0);
- fdt32_t addr_high, addr_low;
- fdt32_t size_high, size_low;
- fdt32_t reg[4];
- fdt32_t *val;
- char name[32];
- int parent, subnode;
- int i, j;
- int err;
-
- if (!sbi_platform_has_pmp(plat))
- return 0;
/* expand the device tree to accommodate new node */
err = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 256);
@@ -134,6 +183,15 @@ int fdt_reserved_memory_fixup(void *fdt)
return err;
}
+ if (!sbi_platform_has_pmp(plat)) {
+ /* update the DT with firmware start & size even if PMP is not
+ * supported. This makes sure that supervisor OS is always
+ * aware of wheren OpenSBI resident memory area.
+ */
+ addr = scratch->fw_start & ~(scratch->fw_size - 1UL);
+ size = (1UL << log2roundup(scratch->fw_size));
+ return fdt_resv_memory_update_node(fdt, addr, size, 0, parent);
+ }
/*
* We assume the given device tree does not contain any memory region
* child node protected by PMP. Normally PMP programming happens at
@@ -148,47 +206,8 @@ int fdt_reserved_memory_fixup(void *fdt)
if (!(prot & PMP_A))
continue;
if (!(prot & (PMP_R | PMP_W | PMP_X))) {
- addr_high = (u64)addr >> 32;
- addr_low = addr;
- size_high = (u64)size >> 32;
- size_low = size;
-
- if (na > 1 && addr_high)
- sbi_snprintf(name, sizeof(name),
- "mmode_pmp%d@%x,%x", j,
- addr_high, addr_low);
- else
- sbi_snprintf(name, sizeof(name),
- "mmode_pmp%d@%x", j,
- addr_low);
-
- subnode = fdt_add_subnode(fdt, parent, name);
- if (subnode < 0)
- return subnode;
-
- /*
- * Tell operating system not to create a virtual
- * mapping of the region as part of its standard
- * mapping of system memory.
- */
- err = fdt_setprop_empty(fdt, subnode, "no-map");
- if (err < 0)
- return err;
-
- /* encode the <reg> property value */
- val = reg;
- if (na > 1)
- *val++ = cpu_to_fdt32(addr_high);
- *val++ = cpu_to_fdt32(addr_low);
- if (ns > 1)
- *val++ = cpu_to_fdt32(size_high);
- *val++ = cpu_to_fdt32(size_low);
-
- err = fdt_setprop(fdt, subnode, "reg", reg,
- (na + ns) * sizeof(fdt32_t));
- if (err < 0)
- return err;
-
+ return fdt_resv_memory_update_node(fdt, addr, size,
+ j, parent);
j++;
}
}