summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/barebox/virtual-reg.rst29
-rw-r--r--drivers/mtd/nor/cfi_flash.c5
-rw-r--r--drivers/of/platform.c20
3 files changed, 53 insertions, 1 deletions
diff --git a/Documentation/devicetree/bindings/barebox/virtual-reg.rst b/Documentation/devicetree/bindings/barebox/virtual-reg.rst
new file mode 100644
index 0000000000..7d576d0cef
--- /dev/null
+++ b/Documentation/devicetree/bindings/barebox/virtual-reg.rst
@@ -0,0 +1,29 @@
+virtual-reg property
+====================
+
+The ``virtual-reg`` property provides a hint on the 32-bit virtual
+address mapping the first physical base address in the ``reg`` property.
+This is meant to allow the OS to use the boot firmware's virtual memory
+mapping to access device resources early in the kernel boot process.
+
+When barebox is compiled with ``CONFIG_MMU`` support and the
+implementation supports remapping, devices with ``virtual_reg`` will have
+all their resources remapped at the physical/virtual address offset calculated
+by subtracting ``virtual-reg`` from the first address in ``reg``.
+
+This is normally used to map I/O memory away from the zero page, so it
+can be used again to trap null pointer dereferences, while allowing
+full access to the device memory::
+
+.. code-block:: none
+
+ &{/soc} {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ flash@0 {
+ reg = <0 0x10000>;
+ virtual-reg = <0x1000>;
+ /* => memory region remapped from [0x1000, 0x11000] to [0x0000, 0x10000] */
+ };
+ };
diff --git a/drivers/mtd/nor/cfi_flash.c b/drivers/mtd/nor/cfi_flash.c
index 8b5302d7a7..f1555a72a4 100644
--- a/drivers/mtd/nor/cfi_flash.c
+++ b/drivers/mtd/nor/cfi_flash.c
@@ -965,7 +965,10 @@ static int cfi_probe_one(struct flash_info *info, int num)
return PTR_ERR(iores);
info->base = IOMEM(iores->start);
- /* TODO: either remap memory region or disable NULL pointer page */
+ /*
+ * Platforms hitting this should remap memory region, e.g. via virtual-reg
+ * device tree property or disable MMU.
+ */
if (IS_ENABLED(CONFIG_MMU) && iores->start == 0)
return -EPERM;
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 23b8fa7934..ab73762932 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -12,6 +12,7 @@
#include <of.h>
#include <of_address.h>
#include <linux/amba/bus.h>
+#include <mmu.h>
/**
* of_find_device_by_node - Find the platform_device associated with a node
@@ -145,6 +146,7 @@ struct device *of_platform_device_create(struct device_node *np,
struct resource *res = NULL, temp_res;
resource_size_t resinval;
int i, ret, num_reg = 0;
+ u32 virt;
if (!of_device_is_available(np))
return NULL;
@@ -186,6 +188,24 @@ struct device *of_platform_device_create(struct device_node *np,
of_dma_configure(dev, np);
+ if (num_reg && !of_property_read_u32(np, "virtual-reg", &virt)) {
+ resource_size_t remap_offset = virt - res[0].start;
+
+ for (i = 0; i < num_reg; i++) {
+ void *new_virt = (void *)res[i].start + remap_offset;
+ resource_size_t size = resource_size(&res[i]);
+
+ ret = arch_remap_range(new_virt, res[i].start, size, MAP_UNCACHED);
+ if (!ret) {
+ debug("%s: remap device %s resource %d: %pa -> 0x%p\n",
+ __func__, dev_name(dev), i, &res[i].start, new_virt);
+
+ res[i].start = (resource_size_t)new_virt;
+ res[i].end = res[i].start + size - 1;
+ }
+ }
+ }
+
resinval = (-1);
debug("%s: register device %s, io=%pa\n",