@@ -295,9 +295,11 @@ M: Stefano Stabellini <sstabellini@kernel.org>
M: Julien Grall <julien@xen.org>
S: Supported
F: xen/common/libfdt/
+F: xen/common/device-tree/
F: xen/common/device_tree.c
F: xen/common/dt-overlay.c
F: xen/include/xen/libfdt/
+F: xen/include/xen/bootfdt.h
F: xen/include/xen/device_tree.h
F: xen/drivers/passthrough/device_tree.c
@@ -3,159 +3,9 @@
#include <public/version.h>
#include <asm/p2m.h>
+#include <xen/bootfdt.h>
#include <xen/device_tree.h>
-#define MIN_FDT_ALIGN 8
-#define MAX_FDT_SIZE SZ_2M
-
-#define NR_MEM_BANKS 256
-#define NR_SHMEM_BANKS 32
-
-#define MAX_MODULES 32 /* Current maximum useful modules */
-
-typedef enum {
- BOOTMOD_XEN,
- BOOTMOD_FDT,
- BOOTMOD_KERNEL,
- BOOTMOD_RAMDISK,
- BOOTMOD_XSM,
- BOOTMOD_GUEST_DTB,
- BOOTMOD_UNKNOWN
-} bootmodule_kind;
-
-enum membank_type {
- /*
- * The MEMBANK_DEFAULT type refers to either reserved memory for the
- * device/firmware (when the bank is in 'reserved_mem') or any RAM (when
- * the bank is in 'mem').
- */
- MEMBANK_DEFAULT,
- /*
- * The MEMBANK_STATIC_DOMAIN type is used to indicate whether the memory
- * bank is bound to a static Xen domain. It is only valid when the bank
- * is in reserved_mem.
- */
- MEMBANK_STATIC_DOMAIN,
- /*
- * The MEMBANK_STATIC_HEAP type is used to indicate whether the memory
- * bank is reserved as static heap. It is only valid when the bank is
- * in reserved_mem.
- */
- MEMBANK_STATIC_HEAP,
- /*
- * The MEMBANK_FDT_RESVMEM type is used to indicate whether the memory
- * bank is from the FDT reserve map.
- */
- MEMBANK_FDT_RESVMEM,
-};
-
-/* Indicates the maximum number of characters(\0 included) for shm_id */
-#define MAX_SHM_ID_LENGTH 16
-
-struct shmem_membank_extra {
- char shm_id[MAX_SHM_ID_LENGTH];
- unsigned int nr_shm_borrowers;
-};
-
-struct membank {
- paddr_t start;
- paddr_t size;
- union {
- enum membank_type type;
-#ifdef CONFIG_STATIC_SHM
- struct shmem_membank_extra *shmem_extra;
-#endif
- };
-};
-
-struct membanks {
- __struct_group(membanks_hdr, common, ,
- unsigned int nr_banks;
- unsigned int max_banks;
- );
- struct membank bank[];
-};
-
-struct meminfo {
- struct membanks_hdr common;
- struct membank bank[NR_MEM_BANKS];
-};
-
-struct shared_meminfo {
- struct membanks_hdr common;
- struct membank bank[NR_SHMEM_BANKS];
- struct shmem_membank_extra extra[NR_SHMEM_BANKS];
-};
-
-/*
- * The domU flag is set for kernels and ramdisks of "xen,domain" nodes.
- * The purpose of the domU flag is to avoid getting confused in
- * kernel_probe, where we try to guess which is the dom0 kernel and
- * initrd to be compatible with all versions of the multiboot spec.
- */
-#define BOOTMOD_MAX_CMDLINE 1024
-struct bootmodule {
- bootmodule_kind kind;
- bool domU;
- paddr_t start;
- paddr_t size;
-};
-
-/* DT_MAX_NAME is the node name max length according the DT spec */
-#define DT_MAX_NAME 41
-struct bootcmdline {
- bootmodule_kind kind;
- bool domU;
- paddr_t start;
- char dt_name[DT_MAX_NAME];
- char cmdline[BOOTMOD_MAX_CMDLINE];
-};
-
-struct bootmodules {
- int nr_mods;
- struct bootmodule module[MAX_MODULES];
-};
-
-struct bootcmdlines {
- unsigned int nr_mods;
- struct bootcmdline cmdline[MAX_MODULES];
-};
-
-struct bootinfo {
- struct meminfo mem;
- /* The reserved regions are only used when booting using Device-Tree */
- struct meminfo reserved_mem;
- struct bootmodules modules;
- struct bootcmdlines cmdlines;
-#ifdef CONFIG_ACPI
- struct meminfo acpi;
-#endif
-#ifdef CONFIG_STATIC_SHM
- struct shared_meminfo shmem;
-#endif
- bool static_heap;
-};
-
-#ifdef CONFIG_ACPI
-#define BOOTINFO_ACPI_INIT .acpi.common.max_banks = NR_MEM_BANKS,
-#else
-#define BOOTINFO_ACPI_INIT
-#endif
-
-#ifdef CONFIG_STATIC_SHM
-#define BOOTINFO_SHMEM_INIT .shmem.common.max_banks = NR_SHMEM_BANKS,
-#else
-#define BOOTINFO_SHMEM_INIT
-#endif
-
-#define BOOTINFO_INIT \
-{ \
- .mem.common.max_banks = NR_MEM_BANKS, \
- .reserved_mem.common.max_banks = NR_MEM_BANKS, \
- BOOTINFO_ACPI_INIT \
- BOOTINFO_SHMEM_INIT \
-}
-
struct map_range_data
{
struct domain *d;
@@ -167,39 +17,8 @@ struct map_range_data
struct rangeset *irq_ranges;
};
-extern struct bootinfo bootinfo;
-
extern domid_t max_init_domid;
-static inline struct membanks *bootinfo_get_mem(void)
-{
- return container_of(&bootinfo.mem.common, struct membanks, common);
-}
-
-static inline struct membanks *bootinfo_get_reserved_mem(void)
-{
- return container_of(&bootinfo.reserved_mem.common, struct membanks, common);
-}
-
-#ifdef CONFIG_ACPI
-static inline struct membanks *bootinfo_get_acpi(void)
-{
- return container_of(&bootinfo.acpi.common, struct membanks, common);
-}
-#endif
-
-#ifdef CONFIG_STATIC_SHM
-static inline struct membanks *bootinfo_get_shmem(void)
-{
- return container_of(&bootinfo.shmem.common, struct membanks, common);
-}
-
-static inline struct shmem_membank_extra *bootinfo_get_shmem_extra(void)
-{
- return bootinfo.shmem.extra;
-}
-#endif
-
void copy_from_paddr(void *dst, paddr_t paddr, unsigned long len);
size_t estimate_efi_size(unsigned int mem_nr_banks);
@@ -220,9 +39,6 @@ void fw_unreserved_regions(paddr_t s, paddr_t e,
void (*cb)(paddr_t ps, paddr_t pe),
unsigned int first);
-size_t boot_fdt_info(const void *fdt, paddr_t paddr);
-const char *boot_fdt_cmdline(const void *fdt);
-
bool check_reserved_regions_overlap(paddr_t region_start, paddr_t region_size);
struct bootmodule *add_boot_module(bootmodule_kind kind,
@@ -237,7 +53,6 @@ struct bootcmdline * boot_cmdline_find_by_name(const char *name);
const char *boot_module_kind_as_string(bootmodule_kind kind);
void init_pdx(void);
-void populate_boot_allocator(void);
void setup_mm(void);
extern uint32_t hyp_traps_vector[];
@@ -48,8 +48,6 @@
#include <xsm/xsm.h>
#include <asm/acpi.h>
-struct bootinfo __initdata bootinfo = BOOTINFO_INIT;
-
/*
* Sanitized version of cpuinfo containing only features available on all
* cores (only on arm64 as there is no sanitization support on arm32).
@@ -203,321 +201,6 @@ static void __init processor_id(void)
processor_setup();
}
-static void __init dt_unreserved_regions(paddr_t s, paddr_t e,
- void (*cb)(paddr_t ps, paddr_t pe),
- unsigned int first)
-{
- const struct membanks *reserved_mem = bootinfo_get_reserved_mem();
-#ifdef CONFIG_STATIC_SHM
- const struct membanks *shmem = bootinfo_get_shmem();
- unsigned int offset;
-#endif
- unsigned int i;
-
- /*
- * i is the current bootmodule we are evaluating across all possible
- * kinds.
- */
- for ( i = first; i < reserved_mem->nr_banks; i++ )
- {
- paddr_t r_s = reserved_mem->bank[i].start;
- paddr_t r_e = r_s + reserved_mem->bank[i].size;
-
- if ( s < r_e && r_s < e )
- {
- dt_unreserved_regions(r_e, e, cb, i + 1);
- dt_unreserved_regions(s, r_s, cb, i + 1);
- return;
- }
- }
-
-#ifdef CONFIG_STATIC_SHM
- /*
- * When retrieving the corresponding shared memory addresses
- * below, we need to index the shmem->bank starting from 0, hence
- * we need to use i - reserved_mem->nr_banks.
- */
- offset = reserved_mem->nr_banks;
- for ( ; i - offset < shmem->nr_banks; i++ )
- {
- paddr_t r_s, r_e;
-
- r_s = shmem->bank[i - offset].start;
-
- /* Shared memory banks can contain INVALID_PADDR as start */
- if ( INVALID_PADDR == r_s )
- continue;
-
- r_e = r_s + shmem->bank[i - offset].size;
-
- if ( s < r_e && r_s < e )
- {
- dt_unreserved_regions(r_e, e, cb, i + 1);
- dt_unreserved_regions(s, r_s, cb, i + 1);
- return;
- }
- }
-#endif
-
- cb(s, e);
-}
-
-/*
- * TODO: '*_end' could be 0 if the bank/region is at the end of the physical
- * address space. This is for now not handled as it requires more rework.
- */
-static bool __init meminfo_overlap_check(const struct membanks *mem,
- paddr_t region_start,
- paddr_t region_size)
-{
- paddr_t bank_start = INVALID_PADDR, bank_end = 0;
- paddr_t region_end = region_start + region_size;
- unsigned int i, bank_num = mem->nr_banks;
-
- for ( i = 0; i < bank_num; i++ )
- {
- bank_start = mem->bank[i].start;
- bank_end = bank_start + mem->bank[i].size;
-
- if ( INVALID_PADDR == bank_start || region_end <= bank_start ||
- region_start >= bank_end )
- continue;
- else
- {
- printk("Region: [%#"PRIpaddr", %#"PRIpaddr") overlapping with bank[%u]: [%#"PRIpaddr", %#"PRIpaddr")\n",
- region_start, region_end, i, bank_start, bank_end);
- return true;
- }
- }
-
- return false;
-}
-
-/*
- * TODO: '*_end' could be 0 if the module/region is at the end of the physical
- * address space. This is for now not handled as it requires more rework.
- */
-static bool __init bootmodules_overlap_check(struct bootmodules *bootmodules,
- paddr_t region_start,
- paddr_t region_size)
-{
- paddr_t mod_start = INVALID_PADDR, mod_end = 0;
- paddr_t region_end = region_start + region_size;
- unsigned int i, mod_num = bootmodules->nr_mods;
-
- for ( i = 0; i < mod_num; i++ )
- {
- mod_start = bootmodules->module[i].start;
- mod_end = mod_start + bootmodules->module[i].size;
-
- if ( region_end <= mod_start || region_start >= mod_end )
- continue;
- else
- {
- printk("Region: [%#"PRIpaddr", %#"PRIpaddr") overlapping with mod[%u]: [%#"PRIpaddr", %#"PRIpaddr")\n",
- region_start, region_end, i, mod_start, mod_end);
- return true;
- }
- }
-
- return false;
-}
-
-void __init fw_unreserved_regions(paddr_t s, paddr_t e,
- void (*cb)(paddr_t ps, paddr_t pe),
- unsigned int first)
-{
- if ( acpi_disabled )
- dt_unreserved_regions(s, e, cb, first);
- else
- cb(s, e);
-}
-
-/*
- * Given an input physical address range, check if this range is overlapping
- * with the existing reserved memory regions defined in bootinfo.
- * Return true if the input physical address range is overlapping with any
- * existing reserved memory regions, otherwise false.
- */
-bool __init check_reserved_regions_overlap(paddr_t region_start,
- paddr_t region_size)
-{
- const struct membanks *mem_banks[] = {
- bootinfo_get_reserved_mem(),
-#ifdef CONFIG_ACPI
- bootinfo_get_acpi(),
-#endif
-#ifdef CONFIG_STATIC_SHM
- bootinfo_get_shmem(),
-#endif
- };
- unsigned int i;
-
- /*
- * Check if input region is overlapping with reserved memory banks or
- * ACPI EfiACPIReclaimMemory (when ACPI feature is enabled) or static
- * shared memory banks (when static shared memory feature is enabled)
- */
- for ( i = 0; i < ARRAY_SIZE(mem_banks); i++ )
- if ( meminfo_overlap_check(mem_banks[i], region_start, region_size) )
- return true;
-
- /* Check if input region is overlapping with bootmodules */
- if ( bootmodules_overlap_check(&bootinfo.modules,
- region_start, region_size) )
- return true;
-
- return false;
-}
-
-struct bootmodule __init *add_boot_module(bootmodule_kind kind,
- paddr_t start, paddr_t size,
- bool domU)
-{
- struct bootmodules *mods = &bootinfo.modules;
- struct bootmodule *mod;
- unsigned int i;
-
- if ( mods->nr_mods == MAX_MODULES )
- {
- printk("Ignoring %s boot module at %"PRIpaddr"-%"PRIpaddr" (too many)\n",
- boot_module_kind_as_string(kind), start, start + size);
- return NULL;
- }
-
- if ( check_reserved_regions_overlap(start, size) )
- return NULL;
-
- for ( i = 0 ; i < mods->nr_mods ; i++ )
- {
- mod = &mods->module[i];
- if ( mod->kind == kind && mod->start == start )
- {
- if ( !domU )
- mod->domU = false;
- return mod;
- }
- }
-
- mod = &mods->module[mods->nr_mods++];
- mod->kind = kind;
- mod->start = start;
- mod->size = size;
- mod->domU = domU;
-
- return mod;
-}
-
-/*
- * boot_module_find_by_kind can only be used to return Xen modules (e.g
- * XSM, DTB) or Dom0 modules. This is not suitable for looking up guest
- * modules.
- */
-struct bootmodule * __init boot_module_find_by_kind(bootmodule_kind kind)
-{
- struct bootmodules *mods = &bootinfo.modules;
- struct bootmodule *mod;
- int i;
- for (i = 0 ; i < mods->nr_mods ; i++ )
- {
- mod = &mods->module[i];
- if ( mod->kind == kind && !mod->domU )
- return mod;
- }
- return NULL;
-}
-
-void __init add_boot_cmdline(const char *name, const char *cmdline,
- bootmodule_kind kind, paddr_t start, bool domU)
-{
- struct bootcmdlines *cmds = &bootinfo.cmdlines;
- struct bootcmdline *cmd;
-
- if ( cmds->nr_mods == MAX_MODULES )
- {
- printk("Ignoring %s cmdline (too many)\n", name);
- return;
- }
-
- cmd = &cmds->cmdline[cmds->nr_mods++];
- cmd->kind = kind;
- cmd->domU = domU;
- cmd->start = start;
-
- ASSERT(strlen(name) <= DT_MAX_NAME);
- safe_strcpy(cmd->dt_name, name);
-
- if ( strlen(cmdline) > BOOTMOD_MAX_CMDLINE )
- panic("module %s command line too long\n", name);
- safe_strcpy(cmd->cmdline, cmdline);
-}
-
-/*
- * boot_cmdline_find_by_kind can only be used to return Xen modules (e.g
- * XSM, DTB) or Dom0 modules. This is not suitable for looking up guest
- * modules.
- */
-struct bootcmdline * __init boot_cmdline_find_by_kind(bootmodule_kind kind)
-{
- struct bootcmdlines *cmds = &bootinfo.cmdlines;
- struct bootcmdline *cmd;
- int i;
-
- for ( i = 0 ; i < cmds->nr_mods ; i++ )
- {
- cmd = &cmds->cmdline[i];
- if ( cmd->kind == kind && !cmd->domU )
- return cmd;
- }
- return NULL;
-}
-
-struct bootcmdline * __init boot_cmdline_find_by_name(const char *name)
-{
- struct bootcmdlines *mods = &bootinfo.cmdlines;
- struct bootcmdline *mod;
- unsigned int i;
-
- for (i = 0 ; i < mods->nr_mods ; i++ )
- {
- mod = &mods->cmdline[i];
- if ( strcmp(mod->dt_name, name) == 0 )
- return mod;
- }
- return NULL;
-}
-
-struct bootmodule * __init boot_module_find_by_addr_and_kind(bootmodule_kind kind,
- paddr_t start)
-{
- struct bootmodules *mods = &bootinfo.modules;
- struct bootmodule *mod;
- unsigned int i;
-
- for (i = 0 ; i < mods->nr_mods ; i++ )
- {
- mod = &mods->module[i];
- if ( mod->kind == kind && mod->start == start )
- return mod;
- }
- return NULL;
-}
-
-const char * __init boot_module_kind_as_string(bootmodule_kind kind)
-{
- switch ( kind )
- {
- case BOOTMOD_XEN: return "Xen";
- case BOOTMOD_FDT: return "Device Tree";
- case BOOTMOD_KERNEL: return "Kernel";
- case BOOTMOD_RAMDISK: return "Ramdisk";
- case BOOTMOD_XSM: return "XSM";
- case BOOTMOD_GUEST_DTB: return "DTB";
- case BOOTMOD_UNKNOWN: return "Unknown";
- default: BUG();
- }
-}
-
void __init discard_initial_modules(void)
{
struct bootmodules *mi = &bootinfo.modules;
@@ -556,40 +239,6 @@ static void * __init relocate_fdt(paddr_t dtb_paddr, size_t dtb_size)
return fdt;
}
-/*
- * Return the end of the non-module region starting at s. In other
- * words return s the start of the next modules after s.
- *
- * On input *end is the end of the region which should be considered
- * and it is updated to reflect the end of the module, clipped to the
- * end of the region if it would run over.
- */
-static paddr_t __init next_module(paddr_t s, paddr_t *end)
-{
- struct bootmodules *mi = &bootinfo.modules;
- paddr_t lowest = ~(paddr_t)0;
- int i;
-
- for ( i = 0; i < mi->nr_mods; i++ )
- {
- paddr_t mod_s = mi->module[i].start;
- paddr_t mod_e = mod_s + mi->module[i].size;
-
- if ( !mi->module[i].size )
- continue;
-
- if ( mod_s < s )
- continue;
- if ( mod_s > lowest )
- continue;
- if ( mod_s > *end )
- continue;
- lowest = mod_s;
- *end = min(*end, mod_e);
- }
- return lowest;
-}
-
void __init init_pdx(void)
{
const struct membanks *mem = bootinfo_get_mem();
@@ -635,87 +284,6 @@ void __init init_pdx(void)
}
}
-/*
- * Populate the boot allocator.
- * If a static heap was not provided by the admin, all the RAM but the
- * following regions will be added:
- * - Modules (e.g., Xen, Kernel)
- * - Reserved regions
- * - Xenheap (arm32 only)
- * If a static heap was provided by the admin, populate the boot
- * allocator with the corresponding regions only, but with Xenheap excluded
- * on arm32.
- */
-void __init populate_boot_allocator(void)
-{
- unsigned int i;
- const struct membanks *banks = bootinfo_get_mem();
- const struct membanks *reserved_mem = bootinfo_get_reserved_mem();
- paddr_t s, e;
-
- if ( bootinfo.static_heap )
- {
- for ( i = 0 ; i < reserved_mem->nr_banks; i++ )
- {
- if ( reserved_mem->bank[i].type != MEMBANK_STATIC_HEAP )
- continue;
-
- s = reserved_mem->bank[i].start;
- e = s + reserved_mem->bank[i].size;
-#ifdef CONFIG_ARM_32
- /* Avoid the xenheap, note that the xenheap cannot across a bank */
- if ( s <= mfn_to_maddr(directmap_mfn_start) &&
- e >= mfn_to_maddr(directmap_mfn_end) )
- {
- init_boot_pages(s, mfn_to_maddr(directmap_mfn_start));
- init_boot_pages(mfn_to_maddr(directmap_mfn_end), e);
- }
- else
-#endif
- init_boot_pages(s, e);
- }
-
- return;
- }
-
- for ( i = 0; i < banks->nr_banks; i++ )
- {
- const struct membank *bank = &banks->bank[i];
- paddr_t bank_end = bank->start + bank->size;
-
- s = bank->start;
- while ( s < bank_end )
- {
- paddr_t n = bank_end;
-
- e = next_module(s, &n);
-
- if ( e == ~(paddr_t)0 )
- e = n = bank_end;
-
- /*
- * Module in a RAM bank other than the one which we are
- * not dealing with here.
- */
- if ( e > bank_end )
- e = bank_end;
-
-#ifdef CONFIG_ARM_32
- /* Avoid the xenheap */
- if ( s < mfn_to_maddr(directmap_mfn_end) &&
- mfn_to_maddr(directmap_mfn_start) < e )
- {
- e = mfn_to_maddr(directmap_mfn_start);
- n = mfn_to_maddr(directmap_mfn_end);
- }
-#endif
-
- fw_unreserved_regions(s, e, init_boot_pages, 0);
- s = n;
- }
- }
-}
-
size_t __read_mostly dcache_line_bytes;
/* C entry point for boot CPU */
@@ -77,6 +77,7 @@ obj-$(CONFIG_UBSAN) += ubsan/
obj-$(CONFIG_NEEDS_LIBELF) += libelf/
obj-$(CONFIG_HAS_DEVICE_TREE) += libfdt/
+obj-$(CONFIG_HAS_DEVICE_TREE) += device-tree/
CONF_FILE := $(if $(patsubst /%,,$(KCONFIG_CONFIG)),$(objtree)/)$(KCONFIG_CONFIG)
$(obj)/config.gz: $(CONF_FILE)
new file mode 100644
@@ -0,0 +1 @@
+obj-y += bootinfo.init.o
new file mode 100644
@@ -0,0 +1,459 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Derived from $xen/arch/arm/setup.c.
+ *
+ * bookkeeping routines.
+ *
+ * Tim Deegan <tim@xen.org>
+ * Copyright (c) 2011 Citrix Systems.
+ * Copyright (c) 2024 Raptor Engineering LLC
+ */
+
+#include <xen/acpi.h>
+#include <xen/bootfdt.h>
+#include <xen/bug.h>
+#include <xen/device_tree.h>
+#include <xen/init.h>
+#include <xen/libfdt/libfdt-xen.h>
+#include <xen/mm.h>
+
+struct bootinfo __initdata bootinfo = BOOTINFO_INIT;
+
+const char * __init boot_module_kind_as_string(bootmodule_kind kind)
+{
+ switch ( kind )
+ {
+ case BOOTMOD_XEN: return "Xen";
+ case BOOTMOD_FDT: return "Device Tree";
+ case BOOTMOD_KERNEL: return "Kernel";
+ case BOOTMOD_RAMDISK: return "Ramdisk";
+ case BOOTMOD_XSM: return "XSM";
+ case BOOTMOD_GUEST_DTB: return "DTB";
+ case BOOTMOD_UNKNOWN: return "Unknown";
+ default: BUG();
+ }
+}
+
+static void __init dt_unreserved_regions(paddr_t s, paddr_t e,
+ void (*cb)(paddr_t ps, paddr_t pe),
+ unsigned int first)
+{
+ const struct membanks *reserved_mem = bootinfo_get_reserved_mem();
+#ifdef CONFIG_STATIC_SHM
+ const struct membanks *shmem = bootinfo_get_shmem();
+ unsigned int offset;
+#endif
+ unsigned int i;
+
+ /*
+ * i is the current bootmodule we are evaluating across all possible
+ * kinds.
+ */
+ for ( i = first; i < reserved_mem->nr_banks; i++ )
+ {
+ paddr_t r_s = reserved_mem->bank[i].start;
+ paddr_t r_e = r_s + reserved_mem->bank[i].size;
+
+ if ( s < r_e && r_s < e )
+ {
+ dt_unreserved_regions(r_e, e, cb, i + 1);
+ dt_unreserved_regions(s, r_s, cb, i + 1);
+ return;
+ }
+ }
+
+#ifdef CONFIG_STATIC_SHM
+ /*
+ * When retrieving the corresponding shared memory addresses
+ * below, we need to index the shmem->bank starting from 0, hence
+ * we need to use i - reserved_mem->nr_banks.
+ */
+ offset = reserved_mem->nr_banks;
+ for ( ; i - offset < shmem->nr_banks; i++ )
+ {
+ paddr_t r_s, r_e;
+
+ r_s = shmem->bank[i - offset].start;
+
+ /* Shared memory banks can contain INVALID_PADDR as start */
+ if ( INVALID_PADDR == r_s )
+ continue;
+
+ r_e = r_s + shmem->bank[i - offset].size;
+
+ if ( s < r_e && r_s < e )
+ {
+ dt_unreserved_regions(r_e, e, cb, i + 1);
+ dt_unreserved_regions(s, r_s, cb, i + 1);
+ return;
+ }
+ }
+#endif
+
+ cb(s, e);
+}
+
+/*
+ * TODO: '*_end' could be 0 if the bank/region is at the end of the physical
+ * address space. This is for now not handled as it requires more rework.
+ */
+static bool __init meminfo_overlap_check(const struct membanks *mem,
+ paddr_t region_start,
+ paddr_t region_size)
+{
+ paddr_t bank_start = INVALID_PADDR, bank_end = 0;
+ paddr_t region_end = region_start + region_size;
+ unsigned int i, bank_num = mem->nr_banks;
+
+ for ( i = 0; i < bank_num; i++ )
+ {
+ bank_start = mem->bank[i].start;
+ bank_end = bank_start + mem->bank[i].size;
+
+ if ( INVALID_PADDR == bank_start || region_end <= bank_start ||
+ region_start >= bank_end )
+ continue;
+ else
+ {
+ printk("Region: [%#"PRIpaddr", %#"PRIpaddr") overlapping with bank[%u]: [%#"PRIpaddr", %#"PRIpaddr")\n",
+ region_start, region_end, i, bank_start, bank_end);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/*
+ * TODO: '*_end' could be 0 if the module/region is at the end of the physical
+ * address space. This is for now not handled as it requires more rework.
+ */
+static bool __init bootmodules_overlap_check(struct bootmodules *bootmodules,
+ paddr_t region_start,
+ paddr_t region_size)
+{
+ paddr_t mod_start = INVALID_PADDR, mod_end = 0;
+ paddr_t region_end = region_start + region_size;
+ unsigned int i, mod_num = bootmodules->nr_mods;
+
+ for ( i = 0; i < mod_num; i++ )
+ {
+ mod_start = bootmodules->module[i].start;
+ mod_end = mod_start + bootmodules->module[i].size;
+
+ if ( region_end <= mod_start || region_start >= mod_end )
+ continue;
+ else
+ {
+ printk("Region: [%#"PRIpaddr", %#"PRIpaddr") overlapping with mod[%u]: [%#"PRIpaddr", %#"PRIpaddr")\n",
+ region_start, region_end, i, mod_start, mod_end);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void __init fw_unreserved_regions(paddr_t s, paddr_t e,
+ void (*cb)(paddr_t ps, paddr_t pe),
+ unsigned int first)
+{
+ if ( acpi_disabled )
+ dt_unreserved_regions(s, e, cb, first);
+ else
+ cb(s, e);
+}
+
+/*
+ * Given an input physical address range, check if this range is overlapping
+ * with the existing reserved memory regions defined in bootinfo.
+ * Return true if the input physical address range is overlapping with any
+ * existing reserved memory regions, otherwise false.
+ */
+bool __init check_reserved_regions_overlap(paddr_t region_start,
+ paddr_t region_size)
+{
+ const struct membanks *mem_banks[] = {
+ bootinfo_get_reserved_mem(),
+#ifdef CONFIG_ACPI
+ bootinfo_get_acpi(),
+#endif
+#ifdef CONFIG_STATIC_SHM
+ bootinfo_get_shmem(),
+#endif
+ };
+ unsigned int i;
+
+ /*
+ * Check if input region is overlapping with reserved memory banks or
+ * ACPI EfiACPIReclaimMemory (when ACPI feature is enabled) or static
+ * shared memory banks (when static shared memory feature is enabled)
+ */
+ for ( i = 0; i < ARRAY_SIZE(mem_banks); i++ )
+ if ( meminfo_overlap_check(mem_banks[i], region_start, region_size) )
+ return true;
+
+ /* Check if input region is overlapping with bootmodules */
+ if ( bootmodules_overlap_check(&bootinfo.modules,
+ region_start, region_size) )
+ return true;
+
+ return false;
+}
+
+struct bootmodule __init *add_boot_module(bootmodule_kind kind,
+ paddr_t start, paddr_t size,
+ bool domU)
+{
+ struct bootmodules *mods = &bootinfo.modules;
+ struct bootmodule *mod;
+ unsigned int i;
+
+ if ( mods->nr_mods == MAX_MODULES )
+ {
+ printk("Ignoring %s boot module at %"PRIpaddr"-%"PRIpaddr" (too many)\n",
+ boot_module_kind_as_string(kind), start, start + size);
+ return NULL;
+ }
+
+ if ( check_reserved_regions_overlap(start, size) )
+ return NULL;
+
+ for ( i = 0 ; i < mods->nr_mods ; i++ )
+ {
+ mod = &mods->module[i];
+ if ( mod->kind == kind && mod->start == start )
+ {
+ if ( !domU )
+ mod->domU = false;
+ return mod;
+ }
+ }
+
+ mod = &mods->module[mods->nr_mods++];
+ mod->kind = kind;
+ mod->start = start;
+ mod->size = size;
+ mod->domU = domU;
+
+ return mod;
+}
+
+/*
+ * boot_module_find_by_kind can only be used to return Xen modules (e.g
+ * XSM, DTB) or Dom0 modules. This is not suitable for looking up guest
+ * modules.
+ */
+struct bootmodule * __init boot_module_find_by_kind(bootmodule_kind kind)
+{
+ struct bootmodules *mods = &bootinfo.modules;
+ struct bootmodule *mod;
+ int i;
+ for (i = 0 ; i < mods->nr_mods ; i++ )
+ {
+ mod = &mods->module[i];
+ if ( mod->kind == kind && !mod->domU )
+ return mod;
+ }
+ return NULL;
+}
+
+void __init add_boot_cmdline(const char *name, const char *cmdline,
+ bootmodule_kind kind, paddr_t start, bool domU)
+{
+ struct bootcmdlines *cmds = &bootinfo.cmdlines;
+ struct bootcmdline *cmd;
+
+ if ( cmds->nr_mods == MAX_MODULES )
+ {
+ printk("Ignoring %s cmdline (too many)\n", name);
+ return;
+ }
+
+ cmd = &cmds->cmdline[cmds->nr_mods++];
+ cmd->kind = kind;
+ cmd->domU = domU;
+ cmd->start = start;
+
+ ASSERT(strlen(name) <= DT_MAX_NAME);
+ safe_strcpy(cmd->dt_name, name);
+
+ if ( strlen(cmdline) > BOOTMOD_MAX_CMDLINE )
+ panic("module %s command line too long\n", name);
+ safe_strcpy(cmd->cmdline, cmdline);
+}
+
+/*
+ * boot_cmdline_find_by_kind can only be used to return Xen modules (e.g
+ * XSM, DTB) or Dom0 modules. This is not suitable for looking up guest
+ * modules.
+ */
+struct bootcmdline * __init boot_cmdline_find_by_kind(bootmodule_kind kind)
+{
+ struct bootcmdlines *cmds = &bootinfo.cmdlines;
+ struct bootcmdline *cmd;
+ int i;
+
+ for ( i = 0 ; i < cmds->nr_mods ; i++ )
+ {
+ cmd = &cmds->cmdline[i];
+ if ( cmd->kind == kind && !cmd->domU )
+ return cmd;
+ }
+ return NULL;
+}
+
+struct bootcmdline * __init boot_cmdline_find_by_name(const char *name)
+{
+ struct bootcmdlines *mods = &bootinfo.cmdlines;
+ struct bootcmdline *mod;
+ unsigned int i;
+
+ for (i = 0 ; i < mods->nr_mods ; i++ )
+ {
+ mod = &mods->cmdline[i];
+ if ( strcmp(mod->dt_name, name) == 0 )
+ return mod;
+ }
+ return NULL;
+}
+
+struct bootmodule * __init boot_module_find_by_addr_and_kind(bootmodule_kind kind,
+ paddr_t start)
+{
+ struct bootmodules *mods = &bootinfo.modules;
+ struct bootmodule *mod;
+ unsigned int i;
+
+ for (i = 0 ; i < mods->nr_mods ; i++ )
+ {
+ mod = &mods->module[i];
+ if ( mod->kind == kind && mod->start == start )
+ return mod;
+ }
+ return NULL;
+}
+
+/*
+ * Return the end of the non-module region starting at s. In other
+ * words return s the start of the next modules after s.
+ *
+ * On input *end is the end of the region which should be considered
+ * and it is updated to reflect the end of the module, clipped to the
+ * end of the region if it would run over.
+ */
+static paddr_t __init next_module(paddr_t s, paddr_t *end)
+{
+ struct bootmodules *mi = &bootinfo.modules;
+ paddr_t lowest = ~(paddr_t)0;
+ int i;
+
+ for ( i = 0; i < mi->nr_mods; i++ )
+ {
+ paddr_t mod_s = mi->module[i].start;
+ paddr_t mod_e = mod_s + mi->module[i].size;
+
+ if ( !mi->module[i].size )
+ continue;
+
+ if ( mod_s < s )
+ continue;
+ if ( mod_s > lowest )
+ continue;
+ if ( mod_s > *end )
+ continue;
+ lowest = mod_s;
+ *end = min(*end, mod_e);
+ }
+ return lowest;
+}
+
+/*
+ * Populate the boot allocator.
+ * If a static heap was not provided by the admin, all the RAM but the
+ * following regions will be added:
+ * - Modules (e.g., Xen, Kernel)
+ * - Reserved regions
+ * - Xenheap (CONFIG_SEPARATE_XENHEAP only)
+ * If a static heap was provided by the admin, populate the boot
+ * allocator with the corresponding regions only, but with Xenheap excluded
+ * on CONFIG_SEPARATE_XENHEAP.
+ */
+void __init populate_boot_allocator(void)
+{
+ unsigned int i;
+ const struct membanks *banks = bootinfo_get_mem();
+ const struct membanks *reserved_mem = bootinfo_get_reserved_mem();
+ paddr_t s, e;
+
+ if ( bootinfo.static_heap )
+ {
+ for ( i = 0 ; i < reserved_mem->nr_banks; i++ )
+ {
+ if ( reserved_mem->bank[i].type != MEMBANK_STATIC_HEAP )
+ continue;
+
+ s = reserved_mem->bank[i].start;
+ e = s + reserved_mem->bank[i].size;
+#ifdef CONFIG_SEPARATE_XENHEAP
+ /* Avoid the xenheap, note that the xenheap cannot across a bank */
+ if ( s <= mfn_to_maddr(directmap_mfn_start) &&
+ e >= mfn_to_maddr(directmap_mfn_end) )
+ {
+ init_boot_pages(s, mfn_to_maddr(directmap_mfn_start));
+ init_boot_pages(mfn_to_maddr(directmap_mfn_end), e);
+ }
+ else
+#endif
+ init_boot_pages(s, e);
+ }
+
+ return;
+ }
+
+ for ( i = 0; i < banks->nr_banks; i++ )
+ {
+ const struct membank *bank = &banks->bank[i];
+ paddr_t bank_end = bank->start + bank->size;
+
+ s = bank->start;
+ while ( s < bank_end )
+ {
+ paddr_t n = bank_end;
+
+ e = next_module(s, &n);
+
+ if ( e == ~(paddr_t)0 )
+ e = n = bank_end;
+
+ /*
+ * Module in a RAM bank other than the one which we are
+ * not dealing with here.
+ */
+ if ( e > bank_end )
+ e = bank_end;
+
+#ifdef CONFIG_SEPARATE_XENHEAP
+ /* Avoid the xenheap */
+ if ( s < mfn_to_maddr(directmap_mfn_end) &&
+ mfn_to_maddr(directmap_mfn_start) < e )
+ {
+ e = mfn_to_maddr(directmap_mfn_start);
+ n = mfn_to_maddr(directmap_mfn_end);
+ }
+#endif
+
+ fw_unreserved_regions(s, e, init_boot_pages, 0);
+ s = n;
+ }
+ }
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
new file mode 100644
@@ -0,0 +1,196 @@
+#ifndef __XEN_BOOTFDT_H__
+#define __XEN_BOOTFDT_H__
+
+#include <xen/types.h>
+#include <xen/kernel.h>
+#include <xen/macros.h>
+
+#define MIN_FDT_ALIGN 8
+#define MAX_FDT_SIZE SZ_2M
+
+#define NR_MEM_BANKS 256
+#define NR_SHMEM_BANKS 32
+
+#define MAX_MODULES 32 /* Current maximum useful modules */
+
+typedef enum {
+ BOOTMOD_XEN,
+ BOOTMOD_FDT,
+ BOOTMOD_KERNEL,
+ BOOTMOD_RAMDISK,
+ BOOTMOD_XSM,
+ BOOTMOD_GUEST_DTB,
+ BOOTMOD_UNKNOWN
+} bootmodule_kind;
+
+enum membank_type {
+ /*
+ * The MEMBANK_DEFAULT type refers to either reserved memory for the
+ * device/firmware (when the bank is in 'reserved_mem') or any RAM (when
+ * the bank is in 'mem').
+ */
+ MEMBANK_DEFAULT,
+ /*
+ * The MEMBANK_STATIC_DOMAIN type is used to indicate whether the memory
+ * bank is bound to a static Xen domain. It is only valid when the bank
+ * is in reserved_mem.
+ */
+ MEMBANK_STATIC_DOMAIN,
+ /*
+ * The MEMBANK_STATIC_HEAP type is used to indicate whether the memory
+ * bank is reserved as static heap. It is only valid when the bank is
+ * in reserved_mem.
+ */
+ MEMBANK_STATIC_HEAP,
+ /*
+ * The MEMBANK_FDT_RESVMEM type is used to indicate whether the memory
+ * bank is from the FDT reserve map.
+ */
+ MEMBANK_FDT_RESVMEM,
+};
+
+/* Indicates the maximum number of characters(\0 included) for shm_id */
+#define MAX_SHM_ID_LENGTH 16
+
+struct shmem_membank_extra {
+ char shm_id[MAX_SHM_ID_LENGTH];
+ unsigned int nr_shm_borrowers;
+};
+
+struct membank {
+ paddr_t start;
+ paddr_t size;
+ union {
+ enum membank_type type;
+#ifdef CONFIG_STATIC_SHM
+ struct shmem_membank_extra *shmem_extra;
+#endif
+ };
+};
+
+struct membanks {
+ __struct_group(membanks_hdr, common, ,
+ unsigned int nr_banks;
+ unsigned int max_banks;
+ );
+ struct membank bank[];
+};
+
+struct meminfo {
+ struct membanks_hdr common;
+ struct membank bank[NR_MEM_BANKS];
+};
+
+struct shared_meminfo {
+ struct membanks_hdr common;
+ struct membank bank[NR_SHMEM_BANKS];
+ struct shmem_membank_extra extra[NR_SHMEM_BANKS];
+};
+
+/*
+ * The domU flag is set for kernels and ramdisks of "xen,domain" nodes.
+ * The purpose of the domU flag is to avoid getting confused in
+ * kernel_probe, where we try to guess which is the dom0 kernel and
+ * initrd to be compatible with all versions of the multiboot spec.
+ */
+#define BOOTMOD_MAX_CMDLINE 1024
+struct bootmodule {
+ bootmodule_kind kind;
+ bool domU;
+ paddr_t start;
+ paddr_t size;
+};
+
+/* DT_MAX_NAME is the node name max length according the DT spec */
+#define DT_MAX_NAME 41
+struct bootcmdline {
+ bootmodule_kind kind;
+ bool domU;
+ paddr_t start;
+ char dt_name[DT_MAX_NAME];
+ char cmdline[BOOTMOD_MAX_CMDLINE];
+};
+
+struct bootmodules {
+ int nr_mods;
+ struct bootmodule module[MAX_MODULES];
+};
+
+struct bootcmdlines {
+ unsigned int nr_mods;
+ struct bootcmdline cmdline[MAX_MODULES];
+};
+
+struct bootinfo {
+ struct meminfo mem;
+ /* The reserved regions are only used when booting using Device-Tree */
+ struct meminfo reserved_mem;
+ struct bootmodules modules;
+ struct bootcmdlines cmdlines;
+#ifdef CONFIG_ACPI
+ struct meminfo acpi;
+#endif
+#ifdef CONFIG_STATIC_SHM
+ struct shared_meminfo shmem;
+#endif
+ bool static_heap;
+};
+
+#ifdef CONFIG_ACPI
+#define BOOTINFO_ACPI_INIT .acpi.common.max_banks = NR_MEM_BANKS,
+#else
+#define BOOTINFO_ACPI_INIT
+#endif
+
+#ifdef CONFIG_STATIC_SHM
+#define BOOTINFO_SHMEM_INIT .shmem.common.max_banks = NR_SHMEM_BANKS,
+#else
+#define BOOTINFO_SHMEM_INIT
+#endif
+
+#define BOOTINFO_INIT \
+{ \
+ .mem.common.max_banks = NR_MEM_BANKS, \
+ .reserved_mem.common.max_banks = NR_MEM_BANKS, \
+ BOOTINFO_ACPI_INIT \
+ BOOTINFO_SHMEM_INIT \
+}
+
+extern struct bootinfo bootinfo;
+
+void populate_boot_allocator(void);
+
+size_t boot_fdt_info(const void *fdt, paddr_t paddr);
+
+const char *boot_fdt_cmdline(const void *fdt);
+
+static inline struct membanks *bootinfo_get_reserved_mem(void)
+{
+ return container_of(&bootinfo.reserved_mem.common, struct membanks, common);
+}
+
+static inline struct membanks *bootinfo_get_mem(void)
+{
+ return container_of(&bootinfo.mem.common, struct membanks, common);
+}
+
+#ifdef CONFIG_ACPI
+static inline struct membanks *bootinfo_get_acpi(void)
+{
+ return container_of(&bootinfo.acpi.common, struct membanks, common);
+}
+#endif
+
+#ifdef CONFIG_STATIC_SHM
+static inline struct membanks *bootinfo_get_shmem(void)
+{
+ return container_of(&bootinfo.shmem.common, struct membanks, common);
+}
+
+static inline struct shmem_membank_extra *bootinfo_get_shmem_extra(void)
+{
+ return bootinfo.shmem.extra;
+}
+#endif
+
+#endif /* __XEN_BOOTFDT_H__ */