[PATCH v8 7/7] xen/riscv: introduce early_fdt_map()

Oleksii Kurochko posted 7 patches 1 month, 4 weeks ago
There is a newer version of this series
[PATCH v8 7/7] xen/riscv: introduce early_fdt_map()
Posted by Oleksii Kurochko 1 month, 4 weeks ago
Introduce function which allows to map FDT to Xen.

Also, initialization of device_tree_flattened happens using
early_fdt_map().

Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
---
 xen/arch/riscv/include/asm/mm.h |  2 ++
 xen/arch/riscv/mm.c             | 55 +++++++++++++++++++++++++++++++++
 xen/arch/riscv/setup.c          |  7 +++++
 3 files changed, 64 insertions(+)

diff --git a/xen/arch/riscv/include/asm/mm.h b/xen/arch/riscv/include/asm/mm.h
index ce1557bb27..4b7b00b850 100644
--- a/xen/arch/riscv/include/asm/mm.h
+++ b/xen/arch/riscv/include/asm/mm.h
@@ -259,4 +259,6 @@ static inline unsigned int arch_get_dma_bitsize(void)
 
 void setup_fixmap_mappings(void);
 
+void *early_fdt_map(paddr_t fdt_paddr);
+
 #endif /* _ASM_RISCV_MM_H */
diff --git a/xen/arch/riscv/mm.c b/xen/arch/riscv/mm.c
index e8430def14..4a628aef83 100644
--- a/xen/arch/riscv/mm.c
+++ b/xen/arch/riscv/mm.c
@@ -1,13 +1,16 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 
+#include <xen/bootfdt.h>
 #include <xen/bug.h>
 #include <xen/compiler.h>
 #include <xen/init.h>
 #include <xen/kernel.h>
+#include <xen/libfdt/libfdt.h>
 #include <xen/macros.h>
 #include <xen/mm.h>
 #include <xen/pfn.h>
 #include <xen/sections.h>
+#include <xen/sizes.h>
 
 #include <asm/early_printk.h>
 #include <asm/csr.h>
@@ -369,3 +372,55 @@ int destroy_xen_mappings(unsigned long s, unsigned long e)
     BUG_ON("unimplemented");
     return -1;
 }
+
+void * __init early_fdt_map(paddr_t fdt_paddr)
+{
+    /* We are using 2MB superpage for mapping the FDT */
+    paddr_t base_paddr = fdt_paddr & XEN_PT_LEVEL_MAP_MASK(1);
+    paddr_t offset;
+    void *fdt_virt;
+    uint32_t size;
+    int rc;
+
+    /*
+     * Check whether the physical FDT address is set and meets the minimum
+     * alignment requirement. Since we are relying on MIN_FDT_ALIGN to be at
+     * least 8 bytes so that we always access the magic and size fields
+     * of the FDT header after mapping the first chunk, double check if
+     * that is indeed the case.
+     */
+    BUILD_BUG_ON(MIN_FDT_ALIGN < 8);
+    if ( !fdt_paddr || fdt_paddr % MIN_FDT_ALIGN )
+        return NULL;
+
+    /* The FDT is mapped using 2MB superpage */
+    BUILD_BUG_ON(BOOT_FDT_VIRT_START % MB(2));
+
+    rc = map_pages_to_xen(BOOT_FDT_VIRT_START, maddr_to_mfn(base_paddr),
+                          MB(2) >> PAGE_SHIFT,
+                          PAGE_HYPERVISOR_RO);
+    if ( rc )
+        panic("Unable to map the device-tree.\n");
+
+    offset = fdt_paddr % XEN_PT_LEVEL_SIZE(1);
+    fdt_virt = (void *)BOOT_FDT_VIRT_START + offset;
+
+    if ( fdt_magic(fdt_virt) != FDT_MAGIC )
+        return NULL;
+
+    size = fdt_totalsize(fdt_virt);
+    if ( size > BOOT_FDT_VIRT_SIZE )
+        return NULL;
+
+    if ( (offset + size) > MB(2) )
+    {
+        rc = map_pages_to_xen(BOOT_FDT_VIRT_START + MB(2),
+                              maddr_to_mfn(base_paddr + MB(2)),
+                              MB(2) >> PAGE_SHIFT,
+                              PAGE_HYPERVISOR_RO);
+        if ( rc )
+            panic("Unable to map the device-tree\n");
+    }
+
+    return fdt_virt;
+}
diff --git a/xen/arch/riscv/setup.c b/xen/arch/riscv/setup.c
index c4fadd36c6..a316901fd4 100644
--- a/xen/arch/riscv/setup.c
+++ b/xen/arch/riscv/setup.c
@@ -2,6 +2,7 @@
 
 #include <xen/bug.h>
 #include <xen/compile.h>
+#include <xen/device_tree.h>
 #include <xen/init.h>
 #include <xen/mm.h>
 #include <xen/shutdown.h>
@@ -57,6 +58,12 @@ void __init noreturn start_xen(unsigned long bootcpu_id,
 
     setup_fixmap_mappings();
 
+    device_tree_flattened = early_fdt_map(dtb_addr);
+    if ( !device_tree_flattened )
+        panic("Invalid device tree blob at physical address %#lx. The DTB must be 8-byte aligned and must not exceed %lld bytes in size.\n\n"
+              "Please check your bootloader.\n",
+              dtb_addr, BOOT_FDT_VIRT_SIZE);
+
     printk("All set up\n");
 
     machine_halt();
-- 
2.46.1
Re: [PATCH v8 7/7] xen/riscv: introduce early_fdt_map()
Posted by oleksii.kurochko@gmail.com 1 month, 3 weeks ago
Add missing revision log:

---
Changes in V6-V8:
 - Nothing changed. Only rebase.
---
Changes in V5:
 - drop usage of PTE_BLOCK for flag argument of map_pages_to_xen() in
early_fdt_map()
   as block mapping is now default behaviour. Also PTE_BLOCK was
dropped in the patch
   "xen/riscv: page table handling".
---
Changes in V4:
 - s/_PAGE_BLOCK/PTE_BLOCK
 - Add Acked-by: Jan Beulich <jbeulich@suse.com>
 - unwarap two lines in panic() in case when device_tree_flattened is
NULL
   so  grep-ing for any part of the message line will always produce a
hit.
 - slightly update the commit message.
---
Changes in V3:
 - Code style fixes
 - s/SZ_2M/MB(2)
 - fix condition to check if early_fdt_map() in setup.c return NULL or
not.
---
Changes in V2:
 - rework early_fdt_map to use map_pages_to_xen()
 - move call early_fdt_map() to C code after MMU is enabled.
---

~ Oleksii

On Fri, 2024-09-27 at 18:33 +0200, Oleksii Kurochko wrote:
> Introduce function which allows to map FDT to Xen.
> 
> Also, initialization of device_tree_flattened happens using
> early_fdt_map().
> 
> Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
> Acked-by: Jan Beulich <jbeulich@suse.com>
> ---
>  xen/arch/riscv/include/asm/mm.h |  2 ++
>  xen/arch/riscv/mm.c             | 55
> +++++++++++++++++++++++++++++++++
>  xen/arch/riscv/setup.c          |  7 +++++
>  3 files changed, 64 insertions(+)
> 
> diff --git a/xen/arch/riscv/include/asm/mm.h
> b/xen/arch/riscv/include/asm/mm.h
> index ce1557bb27..4b7b00b850 100644
> --- a/xen/arch/riscv/include/asm/mm.h
> +++ b/xen/arch/riscv/include/asm/mm.h
> @@ -259,4 +259,6 @@ static inline unsigned int
> arch_get_dma_bitsize(void)
>  
>  void setup_fixmap_mappings(void);
>  
> +void *early_fdt_map(paddr_t fdt_paddr);
> +
>  #endif /* _ASM_RISCV_MM_H */
> diff --git a/xen/arch/riscv/mm.c b/xen/arch/riscv/mm.c
> index e8430def14..4a628aef83 100644
> --- a/xen/arch/riscv/mm.c
> +++ b/xen/arch/riscv/mm.c
> @@ -1,13 +1,16 @@
>  /* SPDX-License-Identifier: GPL-2.0-only */
>  
> +#include <xen/bootfdt.h>
>  #include <xen/bug.h>
>  #include <xen/compiler.h>
>  #include <xen/init.h>
>  #include <xen/kernel.h>
> +#include <xen/libfdt/libfdt.h>
>  #include <xen/macros.h>
>  #include <xen/mm.h>
>  #include <xen/pfn.h>
>  #include <xen/sections.h>
> +#include <xen/sizes.h>
>  
>  #include <asm/early_printk.h>
>  #include <asm/csr.h>
> @@ -369,3 +372,55 @@ int destroy_xen_mappings(unsigned long s,
> unsigned long e)
>      BUG_ON("unimplemented");
>      return -1;
>  }
> +
> +void * __init early_fdt_map(paddr_t fdt_paddr)
> +{
> +    /* We are using 2MB superpage for mapping the FDT */
> +    paddr_t base_paddr = fdt_paddr & XEN_PT_LEVEL_MAP_MASK(1);
> +    paddr_t offset;
> +    void *fdt_virt;
> +    uint32_t size;
> +    int rc;
> +
> +    /*
> +     * Check whether the physical FDT address is set and meets the
> minimum
> +     * alignment requirement. Since we are relying on MIN_FDT_ALIGN
> to be at
> +     * least 8 bytes so that we always access the magic and size
> fields
> +     * of the FDT header after mapping the first chunk, double check
> if
> +     * that is indeed the case.
> +     */
> +    BUILD_BUG_ON(MIN_FDT_ALIGN < 8);
> +    if ( !fdt_paddr || fdt_paddr % MIN_FDT_ALIGN )
> +        return NULL;
> +
> +    /* The FDT is mapped using 2MB superpage */
> +    BUILD_BUG_ON(BOOT_FDT_VIRT_START % MB(2));
> +
> +    rc = map_pages_to_xen(BOOT_FDT_VIRT_START,
> maddr_to_mfn(base_paddr),
> +                          MB(2) >> PAGE_SHIFT,
> +                          PAGE_HYPERVISOR_RO);
> +    if ( rc )
> +        panic("Unable to map the device-tree.\n");
> +
> +    offset = fdt_paddr % XEN_PT_LEVEL_SIZE(1);
> +    fdt_virt = (void *)BOOT_FDT_VIRT_START + offset;
> +
> +    if ( fdt_magic(fdt_virt) != FDT_MAGIC )
> +        return NULL;
> +
> +    size = fdt_totalsize(fdt_virt);
> +    if ( size > BOOT_FDT_VIRT_SIZE )
> +        return NULL;
> +
> +    if ( (offset + size) > MB(2) )
> +    {
> +        rc = map_pages_to_xen(BOOT_FDT_VIRT_START + MB(2),
> +                              maddr_to_mfn(base_paddr + MB(2)),
> +                              MB(2) >> PAGE_SHIFT,
> +                              PAGE_HYPERVISOR_RO);
> +        if ( rc )
> +            panic("Unable to map the device-tree\n");
> +    }
> +
> +    return fdt_virt;
> +}
> diff --git a/xen/arch/riscv/setup.c b/xen/arch/riscv/setup.c
> index c4fadd36c6..a316901fd4 100644
> --- a/xen/arch/riscv/setup.c
> +++ b/xen/arch/riscv/setup.c
> @@ -2,6 +2,7 @@
>  
>  #include <xen/bug.h>
>  #include <xen/compile.h>
> +#include <xen/device_tree.h>
>  #include <xen/init.h>
>  #include <xen/mm.h>
>  #include <xen/shutdown.h>
> @@ -57,6 +58,12 @@ void __init noreturn start_xen(unsigned long
> bootcpu_id,
>  
>      setup_fixmap_mappings();
>  
> +    device_tree_flattened = early_fdt_map(dtb_addr);
> +    if ( !device_tree_flattened )
> +        panic("Invalid device tree blob at physical address %#lx.
> The DTB must be 8-byte aligned and must not exceed %lld bytes in
> size.\n\n"
> +              "Please check your bootloader.\n",
> +              dtb_addr, BOOT_FDT_VIRT_SIZE);
> +
>      printk("All set up\n");
>  
>      machine_halt();