From nobody Thu May 16 22:46:15 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass(p=quarantine dis=none) header.from=raptorengineering.com ARC-Seal: i=1; a=rsa-sha256; t=1700249011; cv=none; d=zohomail.com; s=zohoarc; b=JEOkGPZqxtbpsMcHqWKNCNIlFk2C3qVOrtjw+uDfCNwKhcNJD7OvnngyarZ4uBmo4qsOSY3wDxDrhhbv5zlzBO3o7zenZE6URXas0rfDvksCJ2G2gBSxJUfgmJecvkglVamcHR1cQcCZLePeodJYnL/efuunD4l9DhcKt/rzyQg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1700249011; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=rrS98yFoCir+fVp7z2VJPB9bRNWgZ1ymV3ZhVtsKbi8=; b=aqKie2yx6MALYeXsfjudGG4TkKVfhAz2leoKdGxvTZjATrA7ZqUz3aRCEvjzT3KZ59ukugg0dzdzf5uAgkhqj7iX/byrJKHhpECUvERqwLyo4zzk/1h2dJ4zntlql0CeDhK4mivEO2QHMfRLsxYQSeA6aG41FTJQ4m2Y91Ru2do= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1700249011080137.0121057731343; Fri, 17 Nov 2023 11:23:31 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.635367.991259 (Exim 4.92) (envelope-from ) id 1r44Ql-0008Nt-Ch; Fri, 17 Nov 2023 19:23:07 +0000 Received: by outflank-mailman (output) from mailman id 635367.991259; Fri, 17 Nov 2023 19:23:07 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1r44Ql-0008Nm-9r; Fri, 17 Nov 2023 19:23:07 +0000 Received: by outflank-mailman (input) for mailman id 635367; Fri, 17 Nov 2023 19:23:05 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1r44Qj-0008Ne-AD for xen-devel@lists.xenproject.org; Fri, 17 Nov 2023 19:23:05 +0000 Received: from raptorengineering.com (mail.raptorengineering.com [23.155.224.40]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id b854243b-857e-11ee-9b0e-b553b5be7939; Fri, 17 Nov 2023 20:23:01 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by mail.rptsys.com (Postfix) with ESMTP id 6B8E482857EB; Fri, 17 Nov 2023 13:22:59 -0600 (CST) Received: from mail.rptsys.com ([127.0.0.1]) by localhost (vali.starlink.edu [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id yNE14JElk8to; Fri, 17 Nov 2023 13:22:57 -0600 (CST) Received: from localhost (localhost [127.0.0.1]) by mail.rptsys.com (Postfix) with ESMTP id 12A1382857EC; Fri, 17 Nov 2023 13:22:57 -0600 (CST) Received: from mail.rptsys.com ([127.0.0.1]) by localhost (vali.starlink.edu [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id IZQe10XAnIj5; Fri, 17 Nov 2023 13:22:56 -0600 (CST) Received: from raptor-ewks-026.2lan (5.edge.rptsys.com [23.155.224.38]) by mail.rptsys.com (Postfix) with ESMTPSA id 92D2482857EB; Fri, 17 Nov 2023 13:22:56 -0600 (CST) X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: b854243b-857e-11ee-9b0e-b553b5be7939 DKIM-Filter: OpenDKIM Filter v2.10.3 mail.rptsys.com 12A1382857EC DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raptorengineering.com; s=B8E824E6-0BE2-11E6-931D-288C65937AAD; t=1700248977; bh=rrS98yFoCir+fVp7z2VJPB9bRNWgZ1ymV3ZhVtsKbi8=; h=From:To:Date:Message-Id:MIME-Version; b=E2J1n4RF7Ir1NJRc83bEKJDlzWkkDHHbd4xNEXApDrWPI1NzfBD+hi5XU9E2/33Y5 vIuSFh2oEGTjrvPIuADxwGILV7WECBUBCvXj8MrN+KpCeNauD/N2jcyl9TTu+jm7Lu Cu32HP8vryP5jTwdxTlOdZCFIuORGJ/nGgf0FytE= X-Virus-Scanned: amavisd-new at rptsys.com From: Shawn Anastasio To: xen-devel@lists.xenproject.org Cc: Timothy Pearson , Jan Beulich , Andrew Cooper , Shawn Anastasio , "Daniel P. Smith" Subject: [PATCH] xen/ppc: Enable Boot Allocator Date: Fri, 17 Nov 2023 13:22:13 -0600 Message-Id: <20231117192213.3848826-1-sanastasio@raptorengineering.com> X-Mailer: git-send-email 2.30.2 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @raptorengineering.com) X-ZM-MESSAGEID: 1700249013417100001 Content-Type: text/plain; charset="utf-8" Adapt arm's earlyfdt parsing code to ppc64 and enable Xen's early boot allocator. Routines for parsing arm-specific devicetree nodes (e.g. multiboot) were excluded, reducing the overall footprint of code that was copied. Signed-off-by: Shawn Anastasio --- xen/arch/ppc/Makefile | 1 + xen/arch/ppc/bootfdt.c | 507 +++++++++++++++++++++++++++++++ xen/arch/ppc/include/asm/setup.h | 113 +++++++ xen/arch/ppc/setup.c | 109 ++++++- 4 files changed, 729 insertions(+), 1 deletion(-) create mode 100644 xen/arch/ppc/bootfdt.c diff --git a/xen/arch/ppc/Makefile b/xen/arch/ppc/Makefile index 71feb5e2c4..8a2a809c70 100644 --- a/xen/arch/ppc/Makefile +++ b/xen/arch/ppc/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_PPC64) +=3D ppc64/ =20 +obj-y +=3D bootfdt.o obj-$(CONFIG_EARLY_PRINTK) +=3D early_printk.init.o obj-y +=3D mm-radix.o obj-y +=3D opal.o diff --git a/xen/arch/ppc/bootfdt.c b/xen/arch/ppc/bootfdt.c new file mode 100644 index 0000000000..791e1ca61f --- /dev/null +++ b/xen/arch/ppc/bootfdt.c @@ -0,0 +1,507 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Early Device Tree and boot info bookkeeping. + * Derived from arch/arm/bootfdt.c and setup.c. + * + * Copyright (C) 2012-2014 Citrix Systems, Inc. + * Copyright (C) Raptor Engineering LLC + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct bootinfo __initdata bootinfo; + +struct bootmodule __init *add_boot_module(bootmodule_kind kind, + paddr_t start, paddr_t size, + bool domU) +{ + struct bootmodules *mods =3D &bootinfo.modules; + struct bootmodule *mod; + unsigned int i; + + if ( mods->nr_mods =3D=3D MAX_MODULES ) + { + printk("Ignoring %s boot module at %"PRIpaddr"-%"PRIpaddr" (too ma= ny)\n", + boot_module_kind_as_string(kind), start, start + size); + return NULL; + } + + if ( check_reserved_regions_overlap(start, size) ) + return NULL; + + for ( i =3D 0 ; i < mods->nr_mods ; i++ ) + { + mod =3D &mods->module[i]; + if ( mod->kind =3D=3D kind && mod->start =3D=3D start ) + { + if ( !domU ) + mod->domU =3D false; + return mod; + } + } + + mod =3D &mods->module[mods->nr_mods++]; + mod->kind =3D kind; + mod->start =3D start; + mod->size =3D size; + mod->domU =3D domU; + + return mod; +} + +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"; + default: BUG(); + } +} + +/* + * TODO: '*_end' could be 0 if the module/region is at the end of the phys= ical + * address space. This is for now not handled as it requires more rework. + */ +static bool __init bootmodules_overlap_check(struct bootmodules *bootmodul= es, + paddr_t region_start, + paddr_t region_size) +{ + paddr_t mod_start =3D INVALID_PADDR, mod_end =3D 0; + paddr_t region_end =3D region_start + region_size; + unsigned int i, mod_num =3D bootmodules->nr_mods; + + for ( i =3D 0; i < mod_num; i++ ) + { + mod_start =3D bootmodules->module[i].start; + mod_end =3D mod_start + bootmodules->module[i].size; + + if ( region_end <=3D mod_start || region_start >=3D mod_end ) + continue; + else + { + printk("Region: [%#"PRIpaddr", %#"PRIpaddr") overlapping with" + " mod[%u]: [%#"PRIpaddr", %#"PRIpaddr")\n", region_star= t, + region_end, i, mod_start, mod_end); + return true; + } + } + + return false; +} + +/* + * TODO: '*_end' could be 0 if the bank/region is at the end of the physic= al + * address space. This is for now not handled as it requires more rework. + */ +static bool __init meminfo_overlap_check(struct meminfo *meminfo, + paddr_t region_start, + paddr_t region_size) +{ + paddr_t bank_start =3D INVALID_PADDR, bank_end =3D 0; + paddr_t region_end =3D region_start + region_size; + unsigned int i, bank_num =3D meminfo->nr_banks; + + for ( i =3D 0; i < bank_num; i++ ) + { + bank_start =3D meminfo->bank[i].start; + bank_end =3D bank_start + meminfo->bank[i].size; + + if ( region_end <=3D bank_start || region_start >=3D bank_end ) + continue; + else + { + printk("Region: [%#"PRIpaddr", %#"PRIpaddr") overlapping with" + " bank[%u]: [%#"PRIpaddr", %#"PRIpaddr")\n", region_sta= rt, + region_end, i, bank_start, bank_end); + return true; + } + } + + return false; +} + +/* + * Given an input physical address range, check if this range is overlappi= ng + * 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) +{ + /* Check if input region is overlapping with bootinfo.reserved_mem ban= ks */ + if ( meminfo_overlap_check(&bootinfo.reserved_mem, + 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; +} + +static bool __init device_tree_node_matches(const void *fdt, int node, + const char *match) +{ + const char *name; + size_t match_len; + + name =3D fdt_get_name(fdt, node, NULL); + match_len =3D strlen(match); + + /* + * Match both "match" and "match@..." patterns but not + * "match-foo". + */ + return strncmp(name, match, match_len) =3D=3D 0 + && (name[match_len] =3D=3D '@' || name[match_len] =3D=3D '\0'); +} + +void __init device_tree_get_reg(const __be32 **cell, uint32_t address_cell= s, + uint32_t size_cells, paddr_t *start, + paddr_t *size) +{ + uint64_t dt_start, dt_size; + + /* + * dt_next_cell will return uint64_t whereas paddr_t may not be 64-bit. + * Thus, there is an implicit cast from uint64_t to paddr_t. + */ + dt_start =3D dt_next_cell(address_cells, cell); + dt_size =3D dt_next_cell(size_cells, cell); + + if ( dt_start !=3D (paddr_t)dt_start ) + { + printk("Physical address greater than max width supported\n"); + WARN(); + } + + if ( dt_size !=3D (paddr_t)dt_size ) + { + printk("Physical size greater than max width supported\n"); + WARN(); + } + + /* + * Xen will truncate the address/size if it is greater than the maximum + * supported width and it will give an appropriate warning. + */ + *start =3D dt_start; + *size =3D dt_size; +} + +static int __init device_tree_get_meminfo(const void *fdt, int node, + const char *prop_name, + uint32_t address_cells, uint32_t= size_cells, + void *data, enum membank_type ty= pe) +{ + const struct fdt_property *prop; + unsigned int i, banks; + const __be32 *cell; + uint32_t reg_cells =3D address_cells + size_cells; + paddr_t start, size; + struct meminfo *mem =3D data; + + if ( address_cells < 1 || size_cells < 1 ) + { + printk("fdt: property `%s': invalid #address-cells or #size-cells", + prop_name); + return -EINVAL; + } + + prop =3D fdt_get_property(fdt, node, prop_name, NULL); + if ( !prop ) + return -ENOENT; + + cell =3D (const __be32 *)prop->data; + banks =3D fdt32_to_cpu(prop->len) / (reg_cells * sizeof(uint32_t)); + + for ( i =3D 0; i < banks && mem->nr_banks < NR_MEM_BANKS; i++ ) + { + device_tree_get_reg(&cell, address_cells, size_cells, &start, &siz= e); + if ( mem =3D=3D &bootinfo.reserved_mem && + check_reserved_regions_overlap(start, size) ) + return -EINVAL; + /* Some DT may describe empty bank, ignore them */ + if ( !size ) + continue; + mem->bank[mem->nr_banks].start =3D start; + mem->bank[mem->nr_banks].size =3D size; + mem->bank[mem->nr_banks].type =3D type; + mem->nr_banks++; + } + + if ( i < banks ) + { + printk("Warning: Max number of supported memory regions reached.\n= "); + return -ENOSPC; + } + + return 0; +} + +uint32_t __init device_tree_get_uint32_t(const void *fdt, int node, + const char *prop_name, uint32_t dflt) +{ + const struct fdt_property *prop; + + prop =3D fdt_get_property(fdt, node, prop_name, NULL); + if ( !prop || prop->len < sizeof(uint32_t) ) + return dflt; + + return fdt32_to_cpu(*(uint32_t*)prop->data); +} + +/** + * device_tree_for_each_node - iterate over all device tree sub-nodes + * @fdt: flat device tree. + * @node: parent node to start the search from + * @func: function to call for each sub-node. + * @data: data to pass to @func. + * + * Any nodes nested at DEVICE_TREE_MAX_DEPTH or deeper are ignored. + * + * Returns 0 if all nodes were iterated over successfully. If @func + * returns a value different from 0, that value is returned immediately. + */ +int __init device_tree_for_each_node(const void *fdt, int node, + device_tree_node_func func, + void *data) +{ + /* + * We only care about relative depth increments, assume depth of + * node is 0 for simplicity. + */ + int depth =3D 0; + const int first_node =3D node; + uint32_t address_cells[DEVICE_TREE_MAX_DEPTH]; + uint32_t size_cells[DEVICE_TREE_MAX_DEPTH]; + int ret; + + do { + const char *name =3D fdt_get_name(fdt, node, NULL); + uint32_t as, ss; + + if ( depth >=3D DEVICE_TREE_MAX_DEPTH ) + { + printk("Warning: device tree node `%s' is nested too deep\n", + name); + continue; + } + + as =3D depth > 0 ? address_cells[depth-1] : DT_ROOT_NODE_ADDR_CELL= S_DEFAULT; + ss =3D depth > 0 ? size_cells[depth-1] : DT_ROOT_NODE_SIZE_CELLS_D= EFAULT; + + address_cells[depth] =3D device_tree_get_uint32_t(fdt, node, + "#address-cells", as); + size_cells[depth] =3D device_tree_get_uint32_t(fdt, node, + "#size-cells", ss); + + /* skip the first node */ + if ( node !=3D first_node ) + { + ret =3D func(fdt, node, name, depth, as, ss, data); + if ( ret !=3D 0 ) + return ret; + } + + node =3D fdt_next_node(fdt, node, &depth); + } while ( node >=3D 0 && depth > 0 ); + + return 0; +} + +static int __init process_memory_node(const void *fdt, int node, + const char *name, int depth, + uint32_t address_cells, uint32_t siz= e_cells, + void *data) +{ + return device_tree_get_meminfo(fdt, node, "reg", address_cells, size_c= ells, + data, MEMBANK_DEFAULT); +} + +static int __init process_reserved_memory_node(const void *fdt, int node, + const char *name, int depth, + uint32_t address_cells, + uint32_t size_cells, + void *data) +{ + int rc; + + rc =3D process_memory_node(fdt, node, name, depth, address_cells, + size_cells, data); + + + if ( rc =3D=3D -ENOSPC ) + panic("Max number of supported reserved-memory regions reached.\n"= ); + else if ( rc !=3D -ENOENT ) + return rc; + return 0; +} + +static int __init process_reserved_memory(const void *fdt, int node, + const char *name, int depth, + uint32_t address_cells, uint32_t= size_cells) +{ + return device_tree_for_each_node(fdt, node, + process_reserved_memory_node, + &bootinfo.reserved_mem); +} + +static int __init process_chosen_node(const void *fdt, int node, + const char *name, + uint32_t address_cells, uint32_t siz= e_cells) +{ + const struct fdt_property *prop; + paddr_t start, end; + int len; + + printk("Checking for initrd in /chosen\n"); + + prop =3D fdt_get_property(fdt, node, "linux,initrd-start", &len); + if ( !prop ) + /* No initrd present. */ + return 0; + if ( len !=3D sizeof(uint32_t) && len !=3D sizeof(uint64_t) ) + { + printk("linux,initrd-start property has invalid length %d\n", len); + return -EINVAL; + } + start =3D dt_read_paddr((void *)&prop->data, dt_size_to_cells(len)); + + prop =3D fdt_get_property(fdt, node, "linux,initrd-end", &len); + if ( !prop ) + { + printk("linux,initrd-end not present but -start was\n"); + return -EINVAL; + } + if ( len !=3D sizeof(uint32_t) && len !=3D sizeof(uint64_t) ) + { + printk("linux,initrd-end property has invalid length %d\n", len); + return -EINVAL; + } + end =3D dt_read_paddr((void *)&prop->data, dt_size_to_cells(len)); + + if ( start >=3D end ) + { + printk("linux,initrd limits invalid: %"PRIpaddr" >=3D %"PRIpaddr"\= n", + start, end); + return -EINVAL; + } + + printk("Initrd %"PRIpaddr"-%"PRIpaddr"\n", start, end); + + add_boot_module(BOOTMOD_RAMDISK, start, end-start, false); + + return 0; +} + +static int __init early_scan_node(const void *fdt, + int node, const char *name, int depth, + uint32_t address_cells, uint32_t size_ce= lls, + void *data) +{ + int rc =3D 0; + + if( device_tree_node_matches(fdt, node, "memory") ) + rc =3D process_memory_node(fdt, node, name, depth, + address_cells, size_cells, &bootinfo.mem); + else if ( depth =3D=3D 1 && !dt_node_cmp(name, "reserved-memory") ) + rc =3D process_reserved_memory(fdt, node, name, depth, + address_cells, size_cells); + else if ( depth =3D=3D 1 && device_tree_node_matches(fdt, node, "chose= n") ) + rc =3D process_chosen_node(fdt, node, name, address_cells, size_ce= lls); + + if ( rc < 0 ) + printk("fdt: node `%s': parsing failed\n", name); + return rc; +} + +static void __init early_print_info(void) +{ + struct meminfo *mi =3D &bootinfo.mem; + struct meminfo *mem_resv =3D &bootinfo.reserved_mem; + struct bootmodules *mods =3D &bootinfo.modules; + struct bootcmdlines *cmds =3D &bootinfo.cmdlines; + unsigned int i, j; + + for ( i =3D 0; i < mi->nr_banks; i++ ) + printk("RAM: %"PRIpaddr" - %"PRIpaddr"\n", + mi->bank[i].start, + mi->bank[i].start + mi->bank[i].size - 1); + printk("\n"); + for ( i =3D 0 ; i < mods->nr_mods; i++ ) + printk("MODULE[%d]: %"PRIpaddr" - %"PRIpaddr" %-12s\n", + i, + mods->module[i].start, + mods->module[i].start + mods->module[i].size, + boot_module_kind_as_string(mods->module[i].kind)); + + for ( j =3D 0; j < mem_resv->nr_banks; j++, i++ ) + { + printk(" RESVD_[%u]: %"PRIpaddr" - %"PRIpaddr"\n", i, + mem_resv->bank[j].start, + mem_resv->bank[j].start + mem_resv->bank[j].size - 1); + } + printk("\n"); + for ( i =3D 0 ; i < cmds->nr_mods; i++ ) + printk("CMDLINE[%"PRIpaddr"]:%s %s\n", cmds->cmdline[i].start, + cmds->cmdline[i].dt_name, + &cmds->cmdline[i].cmdline[0]); + printk("\n"); +} + +/** + * boot_fdt_init - initialize bootinfo from a DTB + * @fdt: flattened device tree binary + * @paddr: physical address of device tree binary + * + * Returns the size of the DTB. + */ +size_t __init boot_fdt_init(const void *fdt, paddr_t paddr) +{ + int ret; + paddr_t xen_start, xen_end; + + ret =3D fdt_check_header(fdt); + if ( ret < 0 ) + panic("No valid device tree\n"); + + device_tree_for_each_node((void *)fdt, 0, early_scan_node, NULL); + + /* + * The device tree passed to us may have been allocated by skiboot, in= which + * case it will exist within a reserved region and this call will fail= . This + * is fine, however, since either way the allocator will know not to s= tep on + * the device tree. + */ + add_boot_module(BOOTMOD_FDT, paddr, fdt_totalsize(fdt), false); + + /* + * Xen relocates itself at the ppc64 entrypoint, so we need to manuall= y mark + * the kernel module. + */ + xen_start =3D __pa(_start); + xen_end =3D PAGE_ALIGN(__pa(_end)); + if ( !add_boot_module(BOOTMOD_KERNEL, xen_start, xen_end, false) ) + panic("Xen overlaps reserved memory! %016lx - %016lx\n", xen_start, + xen_end); + + early_print_info(); + + return fdt_totalsize(fdt); +} diff --git a/xen/arch/ppc/include/asm/setup.h b/xen/arch/ppc/include/asm/se= tup.h index e4f64879b6..f6e1940fa9 100644 --- a/xen/arch/ppc/include/asm/setup.h +++ b/xen/arch/ppc/include/asm/setup.h @@ -3,4 +3,117 @@ =20 #define max_init_domid (0) =20 +#include +#include +#include + +#define MIN_FDT_ALIGN 8 +#define MAX_FDT_SIZE SZ_2M + +#define NR_MEM_BANKS 256 + +#define MAX_MODULES 32 /* Current maximum useful modules */ + +typedef enum { + BOOTMOD_XEN, + BOOTMOD_FDT, + BOOTMOD_KERNEL, + BOOTMOD_RAMDISK, +} 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 (wh= en + * the bank is in 'mem'). + */ + MEMBANK_DEFAULT, + /* + * The MEMBANK_STATIC_DOMAIN type is used to indicate whether the memo= ry + * 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, +}; + +/* Indicates the maximum number of characters(\0 included) for shm_id */ +#define MAX_SHM_ID_LENGTH 16 + +struct membank { + paddr_t start; + paddr_t size; + enum membank_type type; +}; + +struct meminfo { + unsigned int nr_banks; + struct membank bank[NR_MEM_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; + struct meminfo reserved_mem; + struct bootmodules modules; + struct bootcmdlines cmdlines; + bool static_heap; +}; + +extern struct bootinfo bootinfo; + +/* + * setup.c + */ + +bool check_reserved_regions_overlap(paddr_t region_start, paddr_t region_s= ize); +struct bootmodule *add_boot_module(bootmodule_kind kind, + paddr_t start, paddr_t size, bool domU); +void add_boot_cmdline(const char *name, const char *cmdline, + bootmodule_kind kind, paddr_t start, bool domU); +const char *boot_module_kind_as_string(bootmodule_kind kind); + +/* + * bootfdt.c + */ +size_t boot_fdt_init(const void *fdt, paddr_t paddr); + #endif /* __ASM_PPC_SETUP_H__ */ diff --git a/xen/arch/ppc/setup.c b/xen/arch/ppc/setup.c index 101bdd8bb6..90de99051e 100644 --- a/xen/arch/ppc/setup.c +++ b/xen/arch/ppc/setup.c @@ -1,16 +1,116 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ #include #include +#include #include #include #include #include #include #include +#include =20 /* Xen stack for bringing up the first CPU. */ unsigned char __initdata cpu0_boot_stack[STACK_SIZE] __aligned(STACK_SIZE); =20 +/* + * 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 =3D &bootinfo.modules; + paddr_t lowest =3D ~(paddr_t)0; + int i; + + for ( i =3D 0; i < mi->nr_mods; i++ ) + { + paddr_t mod_s =3D mi->module[i].start; + paddr_t mod_e =3D 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 =3D mod_s; + *end =3D min(*end, mod_e); + } + return lowest; +} + +static void __init dt_unreserved_regions(paddr_t s, paddr_t e, + void (*cb)(paddr_t ps, paddr_t pe= ), + unsigned int first) +{ + unsigned int i; + + for ( i =3D 0 ; i < bootinfo.reserved_mem.nr_banks; i++ ) + { + paddr_t r_s =3D bootinfo.reserved_mem.bank[i].start; + paddr_t r_e =3D r_s + bootinfo.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; + } + } + + cb(s, e); +} + +/* + * Populate the boot allocator. Based on arch/arm/setup.c's + * populate_boot_allocator. + * All RAM but the following regions will be added to the boot allocator: + * - Modules (e.g., Xen, Kernel) + * - Reserved regions + */ +static void __init populate_boot_allocator(void) +{ + unsigned int i; + const struct meminfo *banks =3D &bootinfo.mem; + paddr_t s, e; + + for ( i =3D 0; i < banks->nr_banks; i++ ) + { + const struct membank *bank =3D &banks->bank[i]; + paddr_t bank_end =3D bank->start + bank->size; + + s =3D bank->start; + while ( s < bank_end ) + { + paddr_t n =3D bank_end; + + e =3D next_module(s, &n); + + if ( e =3D=3D ~(paddr_t)0 ) + e =3D n =3D bank_end; + + /* + * Module in a RAM bank other than the one which we are + * not dealing with here. + */ + if ( e > bank_end ) + e =3D bank_end; + + dt_unreserved_regions(s, e, init_boot_pages, 0); + + s =3D n; + } + } +} + void setup_exceptions(void) { unsigned long lpcr; @@ -24,6 +124,8 @@ void __init noreturn start_xen(unsigned long r3, unsigne= d long r4, unsigned long r5, unsigned long r6, unsigned long r7) { + void *boot_fdt; + if ( r5 ) { /* Unsupported OpenFirmware boot protocol */ @@ -32,11 +134,16 @@ void __init noreturn start_xen(unsigned long r3, unsig= ned long r4, else { /* kexec boot protocol */ - boot_opal_init((void *)r3); + boot_fdt =3D (void *)r3; + boot_opal_init(boot_fdt); } =20 setup_exceptions(); =20 + boot_fdt_init(boot_fdt, r3); + + populate_boot_allocator(); + setup_initial_pagetables(); =20 early_printk("Hello, ppc64le!\n"); --=20 2.30.2