diff options
-rw-r--r-- | Documentation/devicetree/bindings/barebox/virtual-reg.rst | 29 | ||||
-rw-r--r-- | drivers/mtd/nor/cfi_flash.c | 5 | ||||
-rw-r--r-- | drivers/of/platform.c | 20 |
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", |