From patchwork Mon Apr 14 15:56:34 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleksii Kurochko X-Patchwork-Id: 14050654 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id CB3C1C369A2 for ; Mon, 14 Apr 2025 15:57:00 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.950711.1346948 (Exim 4.92) (envelope-from ) id 1u4MAz-00008A-Vr; Mon, 14 Apr 2025 15:56:49 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 950711.1346948; Mon, 14 Apr 2025 15:56:49 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1u4MAz-00007v-RD; Mon, 14 Apr 2025 15:56:49 +0000 Received: by outflank-mailman (input) for mailman id 950711; Mon, 14 Apr 2025 15:56:48 +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 1u4MAy-0008LI-LV for xen-devel@lists.xenproject.org; Mon, 14 Apr 2025 15:56:48 +0000 Received: from mail-ej1-x636.google.com (mail-ej1-x636.google.com [2a00:1450:4864:20::636]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id 119cce06-1949-11f0-9ffb-bf95429c2676; Mon, 14 Apr 2025 17:56:46 +0200 (CEST) Received: by mail-ej1-x636.google.com with SMTP id a640c23a62f3a-ac2a81e41e3so808862266b.1 for ; Mon, 14 Apr 2025 08:56:46 -0700 (PDT) Received: from fedora.. (user-109-243-64-225.play-internet.pl. [109.243.64.225]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-acaa1cb4288sm951760866b.96.2025.04.14.08.56.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 14 Apr 2025 08:56:45 -0700 (PDT) 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: 119cce06-1949-11f0-9ffb-bf95429c2676 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1744646206; x=1745251006; darn=lists.xenproject.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=4Lq5mEW6mI18WMUBH5O3rO4qgR6VSRrIO7ZvgOMZ7TA=; b=j6Hqv32Pe9SiuH/rKZ2faDSILfZrgmUIrCvH1cTz5oteciSciZw8eZnZq30UyjIt3n sc2cF2h/k4va+iEGgoMtXQpYq6CQr97IlygxZXucEwBvy9c8mWnjQze26zuXJAi1pbn8 E9LbX2hYld5A+MPxLVokr9LI6J/wtl4BmJoMG34Bjsvi+UfvM97TYM5lLS8haxCLXe08 zfei5qj3N7gSiCBj0CWkJvzBILifGNceQ/JCKQyYgMKgo9Y9G1b3VTI9wY55fwEbS3RA ze/RASOqPkjLfeYTAgq5yRVhkJDZMA69SNllxVNgqNtWg/qHbnPwTH5OF1fjr+U0kJK4 itng== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744646206; x=1745251006; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=4Lq5mEW6mI18WMUBH5O3rO4qgR6VSRrIO7ZvgOMZ7TA=; b=rrHTA7hkTV5w9hwgDuS4Zt0+VTcvErpoHhxFENFUu7TEm0OxVOy1w/18Gs2N+TNeSQ HVZuGtWhGQKaSVSbVBPx8mwX1y2YyhP5R9ZMMxZQkY4K3f48mv94yTjX+1r1wOmtz4zw 4QLSCFsSo4EvhpwXYUoJRAEzB9r4VaS4dqby9bCYgrlHU/oGIXVgRLF0CwruN/mqdcbq rdA6Y7bRA1dOgbKypRiGLxcbgrw/ah2GoDBOyPsPTr8wZFUEX7WQYiou25l/Kwdzv+YW rDJne9B++PNVHVSeiMEIvK1zN9stHHO6yE+Sb2LmhnGIj9xavQ/cS1kAMZIZf/ZtWxSj 5mBA== X-Gm-Message-State: AOJu0YwNIb5caOOMvpBcz081wulmJuVHvGW2Iiju3Z1VSwoQpNyObpZe dbAKC/Kjr2DfBLvw0eEew6m24mXES1G8LliyC5nL5HPINxwinEV5YF7LTw== X-Gm-Gg: ASbGncvc7wsGdtL9cZWfwIG7UQ1b8xxw6gbxw72sv9OAElHpKB+UgvwKN7o00cHhQH9 oLeOMYUhwveG0RlskhKiwPlEIsiKxR+AEZtyVsPwXdbIpznfa46mDp6C7aJkOVleHcjh1tzZ6YV +Kf4gSH5It8eMCxnJJ7ktqJoydfA4syich+Du7zvPwkE4SjeWoLgVMwn+PxqkrINMfvS4zM3kwY 6f4eLIqieMuNortSwMc+DE2cgzjOLHNglzY9YE0YwtStD8jukFdfeYYbVm82IYw16xiMJW0ks1S psLh7dncHbdcs/8btFhBRF7kuCDSNTk5iaUGA7gZMbvL2thQn6WPgNBSOxe3K0PuVTiSBzw5YBN H+lmvDgdzMacIRV0oJXos X-Google-Smtp-Source: AGHT+IGdJchHJ7P4CPTBsMcZjyAW+4qwRb+NegY1OFv/HcLj0sn/mAXf+megG2Ra8AGAsBOFPrHCGw== X-Received: by 2002:a17:906:6a25:b0:ac3:17bb:34fc with SMTP id a640c23a62f3a-acad36d89f6mr984525966b.52.1744646205570; Mon, 14 Apr 2025 08:56:45 -0700 (PDT) From: Oleksii Kurochko To: xen-devel@lists.xenproject.org Cc: Oleksii Kurochko , Stefano Stabellini , Julien Grall , Bertrand Marquis , Michal Orzel , Volodymyr Babchuk Subject: [PATCH v2 1/8] xen/arm: drop declaration of handle_device_interrupts() Date: Mon, 14 Apr 2025 17:56:34 +0200 Message-ID: X-Mailer: git-send-email 2.49.0 In-Reply-To: References: MIME-Version: 1.0 There is no any users of handle_device_interrupts() thereby it could be dropped. Signed-off-by: Oleksii Kurochko Reviewed-by: Michal Orzel --- Changes in V2: - New patch. --- xen/arch/arm/include/asm/domain_build.h | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/xen/arch/arm/include/asm/domain_build.h b/xen/arch/arm/include/asm/domain_build.h index 134290853c..38546de477 100644 --- a/xen/arch/arm/include/asm/domain_build.h +++ b/xen/arch/arm/include/asm/domain_build.h @@ -27,17 +27,6 @@ void evtchn_allocate(struct domain *d); unsigned int get_allocation_size(paddr_t size); -/* - * handle_device_interrupts retrieves the interrupts configuration from - * a device tree node and maps those interrupts to the target domain. - * - * Returns: - * < 0 error - * 0 success - */ -int handle_device_interrupts(struct domain *d, struct dt_device_node *dev, - bool need_mapping); - /* * Helper to write an interrupts with the GIC format * This code is assuming the irq is an PPI. From patchwork Mon Apr 14 15:56:35 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleksii Kurochko X-Patchwork-Id: 14050659 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 4C260C369BB for ; Mon, 14 Apr 2025 15:57:03 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.950712.1346951 (Exim 4.92) (envelope-from ) id 1u4MB0-0000Bb-6M; Mon, 14 Apr 2025 15:56:50 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 950712.1346951; Mon, 14 Apr 2025 15:56:50 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1u4MB0-0000AW-2a; Mon, 14 Apr 2025 15:56:50 +0000 Received: by outflank-mailman (input) for mailman id 950712; Mon, 14 Apr 2025 15:56:48 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1u4MAy-0008KQ-OJ for xen-devel@lists.xenproject.org; Mon, 14 Apr 2025 15:56:48 +0000 Received: from mail-ed1-x532.google.com (mail-ed1-x532.google.com [2a00:1450:4864:20::532]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id 1217939f-1949-11f0-9eae-5ba50f476ded; Mon, 14 Apr 2025 17:56:47 +0200 (CEST) Received: by mail-ed1-x532.google.com with SMTP id 4fb4d7f45d1cf-5e5c7d6b96fso8327622a12.3 for ; Mon, 14 Apr 2025 08:56:47 -0700 (PDT) Received: from fedora.. (user-109-243-64-225.play-internet.pl. [109.243.64.225]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-acaa1cb4288sm951760866b.96.2025.04.14.08.56.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 14 Apr 2025 08:56:46 -0700 (PDT) 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: 1217939f-1949-11f0-9eae-5ba50f476ded DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1744646207; x=1745251007; darn=lists.xenproject.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=7xXk8n5tiuPiaJ2LAGcxcApCGF2bFVEp873eW1/6Bqs=; b=Cnpdu2GucD+Gxs61H7bNWvwsoA91HiQUXcsj8ZDxte8IVuykDnU+EhN+NdVYO1sPAY kbg48pwsP+W3vCoI0YFMa1MB66gbnhN89hmaciNqCSvU72FaKHZnYKHk5OsPreHb3Dm4 dsZwWGGiBnAJHkqQxZbxyB7uF7jGz4gSjoExGb9a15pEthPivN8r9CbeiXeh0Z4AYvBa U5t/RvR8Wc0o2z38ydJfFyc30M6PXjyUdot+EcFTAe8bOaIMZ7fH+o9S54LkDfixp2BM 9XfLJ1ol4StHzXzUmccl7AsLH4r4vEQmTse1+jcw2USEwavIPvUFqTsNcnL/0Q9VeTFx qb+w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744646207; x=1745251007; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=7xXk8n5tiuPiaJ2LAGcxcApCGF2bFVEp873eW1/6Bqs=; b=bfcCUp0rkQOutAxg34B5VRZo3+mHwRWl008uOSeE4Be9giaX8K9IOzSUKkJgPdAwgO CNc7F282/rnLcdktjmlfFdsHpDcd9EcIQdF4xSsX0fRHsyrY5fbQ/6MZ0WA8sh2xqg9I ESCLAmV99jDgl3lqJcaskvzqXXHDpEMN8miFlBOxO0fsdMzFHof7XwJGMizAPeWT/NGq BHS4TDbcSz6TLsGKMyQxcMGatGYU7y0XILtY4mQbxpGBPCe+O7XAjN7GtKkCHBP0oUH6 lfhCfLM8nL9c9Ug87MNwdFhXQaCG6DFKs9Jy7YHBTiw/EQsFOaWs6pZUEOcAeC6/8BIo qN2g== X-Gm-Message-State: AOJu0YwFDEMGkXFl5uebhoPOsbLl2VdYkWHYGpM/dlzXAmp4qGbTyqen aLFWTt68bhJPypvFT/nKFtK1Pe3J6KqgXepKMMxcl5trnukRAgcTPASKcg== X-Gm-Gg: ASbGnct1EdXc1i08NvmNY3JElmIgcuBCWO2KROeCWpLEbQBeUuVlzH637kwKlBnc0Wx XiYEJ2nY2lflveB+AHsqLdr0HSSHrqdsxJMlPAFv3piUUiGilLx01x95rY4Hwo5PtWsZSuugwn0 d/4OM/L6fLwRwmICiuRdfhRmTrI6wiRin2NC1kMN/RB8LgP7pnUPPvspVuA+PV2NNWKNaNO2zGn 9MOalfRhySz7spLggS0bgG7jth7A/Us7u2ZmRf25KrKuETSOIGBBXNh/vi3/NZOeuQx78fxLG9k G5igxbPyN5eW2ipbfy8pi/24WjxWpEkrxrbOvyAgxzuSqYAppICf2JZmHJJ6jgdqkKQTOD86opm SuKHThvb8mngMGjYpITpK X-Google-Smtp-Source: AGHT+IFouBH0yq3agxvOsTISd3+AK5jSrx3hH9W+fwnU0fTwrzZR3ITlBYr5zXc9VWJoi9nJ5X6fPA== X-Received: by 2002:a17:906:dc94:b0:ac7:3a23:569c with SMTP id a640c23a62f3a-acad34468e4mr1329138866b.1.1744646206456; Mon, 14 Apr 2025 08:56:46 -0700 (PDT) From: Oleksii Kurochko To: xen-devel@lists.xenproject.org Cc: Oleksii Kurochko , Stefano Stabellini , Julien Grall , Bertrand Marquis , Michal Orzel , Volodymyr Babchuk , Andrew Cooper , Anthony PERARD , Jan Beulich , =?utf-8?q?Roger_Pau_Monn=C3=A9?= Subject: [PATCH v2 2/8] xen/common: dom0less: make some parts of Arm's CONFIG_DOM0LESS common Date: Mon, 14 Apr 2025 17:56:35 +0200 Message-ID: X-Mailer: git-send-email 2.49.0 In-Reply-To: References: MIME-Version: 1.0 Move some parts of Arm's Dom0Less code to be reused by other architectures. At the moment, RISC-V is going to reuse these parts. Move dom0less-build.h from the Arm-specific directory to asm-generic as these header is expected to be the same across acrhictectures with some updates: add the following declaration of construct_domU(), arch_xen_domctl_createdomain() and arch_create_domus() as there are some parts which are still architecture-specific. Introduce HAS_DOM0LESS to provide ability to enable generic Dom0less code for an architecture. Relocate the CONFIG_DOM0LESS configuration to the common with adding "depends on HAS_DOM0LESS" to not break builds for architectures which don't support CONFIG_DOM0LESS config, especically it would be useful to not provide stubs for construct_domU(), arch_xen_domctl_createdomain() and arch_create_domus() in case of *-randconfig which may set CONFIG_DOM0LESS=y. Move is_dom0less_mode() function to the common code, as it depends on boot modules that are already part of the common code. Move create_domUs() function to the common code with some updates: - Add function arch_xen_domctl_createdomain() as structure xen_domctl_createdomain may have some arch-spicific information and initialization. - Add arch_create_domus() to cover parsing of arch-specific features, for example, SVE (Scalar Vector Extension ) exists only in Arm. Signed-off-by: Oleksii Kurochko --- Changes in v2: - Convert 'depends on Arm' to 'depends on HAS_DOM0LESS' for CONFIG_DOM0LESS_BOOT. - Change 'default Arm' to 'default y' for CONFIG_DOM0LESS_BOOT as there is dependency on HAS_DOM0LESS. - Introduce HAS_DOM0LESS and enable it for Arm. - Update the commit message. --- xen/arch/arm/Kconfig | 9 +- xen/arch/arm/dom0less-build.c | 270 ++++++---------------- xen/arch/arm/include/asm/Makefile | 1 + xen/arch/arm/include/asm/dom0less-build.h | 32 --- xen/common/Kconfig | 12 + xen/common/device-tree/Makefile | 1 + xen/common/device-tree/dom0less-build.c | 161 +++++++++++++ xen/include/asm-generic/dom0less-build.h | 40 ++++ 8 files changed, 287 insertions(+), 239 deletions(-) delete mode 100644 xen/arch/arm/include/asm/dom0less-build.h create mode 100644 xen/common/device-tree/dom0less-build.c create mode 100644 xen/include/asm-generic/dom0less-build.h diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig index 565f288331..060389c3c8 100644 --- a/xen/arch/arm/Kconfig +++ b/xen/arch/arm/Kconfig @@ -15,6 +15,7 @@ config ARM select GENERIC_UART_INIT select HAS_ALTERNATIVE if HAS_VMAP select HAS_DEVICE_TREE + select HAS_DOM0LESS select HAS_UBSAN config ARCH_DEFCONFIG @@ -119,14 +120,6 @@ config GICV2 Driver for the ARM Generic Interrupt Controller v2. If unsure, say Y -config DOM0LESS_BOOT - bool "Dom0less boot support" if EXPERT - default y - help - Dom0less boot support enables Xen to create and start domU guests during - Xen boot without the need of a control domain (Dom0), which could be - present anyway. - config GICV3 bool "GICv3 driver" depends on !NEW_VGIC diff --git a/xen/arch/arm/dom0less-build.c b/xen/arch/arm/dom0less-build.c index bd15563750..7ec3f85795 100644 --- a/xen/arch/arm/dom0less-build.c +++ b/xen/arch/arm/dom0less-build.c @@ -20,38 +20,6 @@ #include #include -bool __init is_dom0less_mode(void) -{ - struct bootmodules *mods = &bootinfo.modules; - struct bootmodule *mod; - unsigned int i; - bool dom0found = false; - bool domUfound = false; - - /* Look into the bootmodules */ - for ( i = 0 ; i < mods->nr_mods ; i++ ) - { - mod = &mods->module[i]; - /* Find if dom0 and domU kernels are present */ - if ( mod->kind == BOOTMOD_KERNEL ) - { - if ( mod->domU == false ) - { - dom0found = true; - break; - } - else - domUfound = true; - } - } - - /* - * If there is no dom0 kernel but at least one domU, then we are in - * dom0less mode - */ - return ( !dom0found && domUfound ); -} - #ifdef CONFIG_VGICV2 static int __init make_gicv2_domU_node(struct kernel_info *kinfo) { @@ -869,8 +837,8 @@ static inline int domain_p2m_set_allocation(struct domain *d, uint64_t mem, } #endif /* CONFIG_ARCH_PAGING_MEMPOOL */ -static int __init construct_domU(struct domain *d, - const struct dt_device_node *node) +int __init construct_domU(struct domain *d, + const struct dt_device_node *node) { struct kernel_info kinfo = KERNEL_INFO_INIT; const char *dom0less_enhanced; @@ -965,188 +933,92 @@ static int __init construct_domU(struct domain *d, return alloc_xenstore_params(&kinfo); } -void __init create_domUs(void) -{ - struct dt_device_node *node; - const char *dom0less_iommu; - bool iommu = false; - const struct dt_device_node *cpupool_node, - *chosen = dt_find_node_by_path("/chosen"); - const char *llc_colors_str = NULL; - - BUG_ON(chosen == NULL); - dt_for_each_child_node(chosen, node) - { - struct domain *d; - struct xen_domctl_createdomain d_cfg = { - .arch.gic_version = XEN_DOMCTL_CONFIG_GIC_NATIVE, - .flags = XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap, - /* - * The default of 1023 should be sufficient for guests because - * on ARM we don't bind physical interrupts to event channels. - * The only use of the evtchn port is inter-domain communications. - * 1023 is also the default value used in libxl. - */ - .max_evtchn_port = 1023, - .max_grant_frames = -1, - .max_maptrack_frames = -1, - .grant_opts = XEN_DOMCTL_GRANT_version(opt_gnttab_max_version), - }; - unsigned int flags = 0U; - uint32_t val; - int rc; - - if ( !dt_device_is_compatible(node, "xen,domain") ) - continue; - - if ( (max_init_domid + 1) >= DOMID_FIRST_RESERVED ) - panic("No more domain IDs available\n"); - - if ( dt_find_property(node, "xen,static-mem", NULL) ) - { - if ( llc_coloring_enabled ) - panic("LLC coloring and static memory are incompatible\n"); - - flags |= CDF_staticmem; - } - - if ( dt_property_read_bool(node, "direct-map") ) - { - if ( !(flags & CDF_staticmem) ) - panic("direct-map is not valid for domain %s without static allocation.\n", - dt_node_name(node)); - - flags |= CDF_directmap; - } - if ( !dt_property_read_u32(node, "cpus", &d_cfg.max_vcpus) ) - panic("Missing property 'cpus' for domain %s\n", - dt_node_name(node)); - - if ( !dt_property_read_string(node, "passthrough", &dom0less_iommu) && - !strcmp(dom0less_iommu, "enabled") ) - iommu = true; +struct xen_domctl_createdomain __init arch_xen_domctl_createdomain(void) +{ + struct xen_domctl_createdomain d_cfg = { + .arch.gic_version = XEN_DOMCTL_CONFIG_GIC_NATIVE, + .flags = XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap, + /* + * The default of 1023 should be sufficient for guests because + * on ARM we don't bind physical interrupts to event channels. + * The only use of the evtchn port is inter-domain communications. + * 1023 is also the default value used in libxl. + */ + .max_evtchn_port = 1023, + .max_grant_frames = -1, + .max_maptrack_frames = -1, + .grant_opts = XEN_DOMCTL_GRANT_version(opt_gnttab_max_version), + }; + + return d_cfg; +} - if ( iommu_enabled && - (iommu || dt_find_compatible_node(node, NULL, - "multiboot,device-tree")) ) - d_cfg.flags |= XEN_DOMCTL_CDF_iommu; +void __init arch_create_domus(struct dt_device_node *node, + struct xen_domctl_createdomain *d_cfg, + unsigned int flags) +{ + uint32_t val; - if ( !dt_property_read_u32(node, "nr_spis", &d_cfg.arch.nr_spis) ) - { - int vpl011_virq = GUEST_VPL011_SPI; - - d_cfg.arch.nr_spis = VGIC_DEF_NR_SPIS; - - /* - * The VPL011 virq is GUEST_VPL011_SPI, unless direct-map is - * set, in which case it'll match the hardware. - * - * Since the domain is not yet created, we can't use - * d->arch.vpl011.irq. So the logic to find the vIRQ has to - * be hardcoded. - * The logic here shall be consistent with the one in - * domain_vpl011_init(). - */ - if ( flags & CDF_directmap ) - { - vpl011_virq = serial_irq(SERHND_DTUART); - if ( vpl011_virq < 0 ) - panic("Error getting IRQ number for this serial port %d\n", - SERHND_DTUART); - } + if ( !dt_property_read_u32(node, "nr_spis", &d_cfg->arch.nr_spis) ) + { + int vpl011_virq = GUEST_VPL011_SPI; - /* - * vpl011 uses one emulated SPI. If vpl011 is requested, make - * sure that we allocate enough SPIs for it. - */ - if ( dt_property_read_bool(node, "vpl011") ) - d_cfg.arch.nr_spis = MAX(d_cfg.arch.nr_spis, - vpl011_virq - 32 + 1); - } + d_cfg->arch.nr_spis = VGIC_DEF_NR_SPIS; - /* Get the optional property domain-cpupool */ - cpupool_node = dt_parse_phandle(node, "domain-cpupool", 0); - if ( cpupool_node ) + /* + * The VPL011 virq is GUEST_VPL011_SPI, unless direct-map is + * set, in which case it'll match the hardware. + * + * Since the domain is not yet created, we can't use + * d->arch.vpl011.irq. So the logic to find the vIRQ has to + * be hardcoded. + * The logic here shall be consistent with the one in + * domain_vpl011_init(). + */ + if ( flags & CDF_directmap ) { - int pool_id = btcpupools_get_domain_pool_id(cpupool_node); - if ( pool_id < 0 ) - panic("Error getting cpupool id from domain-cpupool (%d)\n", - pool_id); - d_cfg.cpupool_id = pool_id; + vpl011_virq = serial_irq(SERHND_DTUART); + if ( vpl011_virq < 0 ) + panic("Error getting IRQ number for this serial port %d\n", + SERHND_DTUART); } - if ( dt_property_read_u32(node, "max_grant_version", &val) ) - d_cfg.grant_opts = XEN_DOMCTL_GRANT_version(val); + /* + * vpl011 uses one emulated SPI. If vpl011 is requested, make + * sure that we allocate enough SPIs for it. + */ + if ( dt_property_read_bool(node, "vpl011") ) + d_cfg->arch.nr_spis = MAX(d_cfg->arch.nr_spis, + vpl011_virq - 32 + 1); + } - if ( dt_property_read_u32(node, "max_grant_frames", &val) ) - { - if ( val > INT32_MAX ) - panic("max_grant_frames (%"PRIu32") overflow\n", val); - d_cfg.max_grant_frames = val; - } + if ( dt_get_property(node, "sve", &val) ) + { +#ifdef CONFIG_ARM64_SVE + unsigned int sve_vl_bits; + bool ret = false; - if ( dt_property_read_u32(node, "max_maptrack_frames", &val) ) + if ( !val ) { - if ( val > INT32_MAX ) - panic("max_maptrack_frames (%"PRIu32") overflow\n", val); - d_cfg.max_maptrack_frames = val; + /* Property found with no value, means max HW VL supported */ + ret = sve_domctl_vl_param(-1, &sve_vl_bits); } - - if ( dt_get_property(node, "sve", &val) ) + else { -#ifdef CONFIG_ARM64_SVE - unsigned int sve_vl_bits; - bool ret = false; - - if ( !val ) - { - /* Property found with no value, means max HW VL supported */ - ret = sve_domctl_vl_param(-1, &sve_vl_bits); - } + if ( dt_property_read_u32(node, "sve", &val) ) + ret = sve_domctl_vl_param(val, &sve_vl_bits); else - { - if ( dt_property_read_u32(node, "sve", &val) ) - ret = sve_domctl_vl_param(val, &sve_vl_bits); - else - panic("Error reading 'sve' property\n"); - } + panic("Error reading 'sve' property\n"); + } - if ( ret ) - d_cfg.arch.sve_vl = sve_encode_vl(sve_vl_bits); - else - panic("SVE vector length error\n"); + if ( ret ) + d_cfg->arch.sve_vl = sve_encode_vl(sve_vl_bits); + else + panic("SVE vector length error\n"); #else - panic("'sve' property found, but CONFIG_ARM64_SVE not selected\n"); + panic("'sve' property found, but CONFIG_ARM64_SVE not selected\n"); #endif - } - - dt_property_read_string(node, "llc-colors", &llc_colors_str); - if ( !llc_coloring_enabled && llc_colors_str ) - panic("'llc-colors' found, but LLC coloring is disabled\n"); - - /* - * The variable max_init_domid is initialized with zero, so here it's - * very important to use the pre-increment operator to call - * domain_create() with a domid > 0. (domid == 0 is reserved for Dom0) - */ - d = domain_create(++max_init_domid, &d_cfg, flags); - if ( IS_ERR(d) ) - panic("Error creating domain %s (rc = %ld)\n", - dt_node_name(node), PTR_ERR(d)); - - if ( llc_coloring_enabled && - (rc = domain_set_llc_colors_from_str(d, llc_colors_str)) ) - panic("Error initializing LLC coloring for domain %s (rc = %d)\n", - dt_node_name(node), rc); - - d->is_console = true; - dt_device_set_used_by(node, d->domain_id); - - rc = construct_domU(d, node); - if ( rc ) - panic("Could not set up domain %s (rc = %d)\n", - dt_node_name(node), rc); } } diff --git a/xen/arch/arm/include/asm/Makefile b/xen/arch/arm/include/asm/Makefile index 4a4036c951..831c914cce 100644 --- a/xen/arch/arm/include/asm/Makefile +++ b/xen/arch/arm/include/asm/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only generic-y += altp2m.h generic-y += device.h +generic-y += dom0less-build.h generic-y += hardirq.h generic-y += iocap.h generic-y += paging.h diff --git a/xen/arch/arm/include/asm/dom0less-build.h b/xen/arch/arm/include/asm/dom0less-build.h deleted file mode 100644 index 5864944bda..0000000000 --- a/xen/arch/arm/include/asm/dom0less-build.h +++ /dev/null @@ -1,32 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ - -#ifndef __ASM_DOM0LESS_BUILD_H_ -#define __ASM_DOM0LESS_BUILD_H_ - -#include - -#ifdef CONFIG_DOM0LESS_BOOT - -void create_domUs(void); -bool is_dom0less_mode(void); - -#else /* !CONFIG_DOM0LESS_BOOT */ - -static inline void create_domUs(void) {} -static inline bool is_dom0less_mode(void) -{ - return false; -} - -#endif /* CONFIG_DOM0LESS_BOOT */ - -#endif /* __ASM_DOM0LESS_BUILD_H_ */ - -/* - * Local variables: - * mode: C - * c-file-style: "BSD" - * c-basic-offset: 4 - * indent-tabs-mode: nil - * End: - */ diff --git a/xen/common/Kconfig b/xen/common/Kconfig index 06ae9751aa..2fd79aea5b 100644 --- a/xen/common/Kconfig +++ b/xen/common/Kconfig @@ -12,6 +12,15 @@ config CORE_PARKING bool depends on NR_CPUS > 1 +config DOM0LESS_BOOT + bool "Dom0less boot support" if EXPERT + depends on HAS_DOM0LESS + default y + help + Dom0less boot support enables Xen to create and start domU guests during + Xen boot without the need of a control domain (Dom0), which could be + present anyway. + config GRANT_TABLE bool "Grant table support" if EXPERT default y @@ -73,6 +82,9 @@ config HAS_COMPAT config HAS_DEVICE_TREE bool +config HAS_DOM0LESS + bool + config HAS_DIT # Data Independent Timing bool diff --git a/xen/common/device-tree/Makefile b/xen/common/device-tree/Makefile index 7c549be38a..f3dafc9b81 100644 --- a/xen/common/device-tree/Makefile +++ b/xen/common/device-tree/Makefile @@ -1,5 +1,6 @@ obj-y += bootfdt.init.o obj-y += bootinfo.init.o obj-y += device-tree.o +obj-$(CONFIG_DOM0LESS_BOOT) += dom0less-build.o obj-$(CONFIG_OVERLAY_DTB) += dt-overlay.o obj-y += intc.o diff --git a/xen/common/device-tree/dom0less-build.c b/xen/common/device-tree/dom0less-build.c new file mode 100644 index 0000000000..19bfa5e005 --- /dev/null +++ b/xen/common/device-tree/dom0less-build.c @@ -0,0 +1,161 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +bool __init is_dom0less_mode(void) +{ + struct bootmodules *mods = &bootinfo.modules; + struct bootmodule *mod; + unsigned int i; + bool dom0found = false; + bool domUfound = false; + + /* Look into the bootmodules */ + for ( i = 0 ; i < mods->nr_mods ; i++ ) + { + mod = &mods->module[i]; + /* Find if dom0 and domU kernels are present */ + if ( mod->kind == BOOTMOD_KERNEL ) + { + if ( mod->domU == false ) + { + dom0found = true; + break; + } + else + domUfound = true; + } + } + + /* + * If there is no dom0 kernel but at least one domU, then we are in + * dom0less mode + */ + return ( !dom0found && domUfound ); +} + +void __init create_domUs(void) +{ + struct dt_device_node *node; + const char *dom0less_iommu; + bool iommu = false; + const struct dt_device_node *cpupool_node, + *chosen = dt_find_node_by_path("/chosen"); + const char *llc_colors_str = NULL; + + BUG_ON(chosen == NULL); + dt_for_each_child_node(chosen, node) + { + struct domain *d; + struct xen_domctl_createdomain d_cfg = arch_xen_domctl_createdomain(); + unsigned int flags = 0U; + uint32_t val; + int rc; + + if ( !dt_device_is_compatible(node, "xen,domain") ) + continue; + + if ( (max_init_domid + 1) >= DOMID_FIRST_RESERVED ) + panic("No more domain IDs available\n"); + + if ( dt_find_property(node, "xen,static-mem", NULL) ) + { + if ( llc_coloring_enabled ) + panic("LLC coloring and static memory are incompatible\n"); + + flags |= CDF_staticmem; + } + + if ( dt_property_read_bool(node, "direct-map") ) + { + if ( !(flags & CDF_staticmem) ) + panic("direct-map is not valid for domain %s without static allocation.\n", + dt_node_name(node)); + + flags |= CDF_directmap; + } + + if ( !dt_property_read_u32(node, "cpus", &d_cfg.max_vcpus) ) + panic("Missing property 'cpus' for domain %s\n", + dt_node_name(node)); + + if ( !dt_property_read_string(node, "passthrough", &dom0less_iommu) && + !strcmp(dom0less_iommu, "enabled") ) + iommu = true; + + if ( iommu_enabled && + (iommu || dt_find_compatible_node(node, NULL, + "multiboot,device-tree")) ) + d_cfg.flags |= XEN_DOMCTL_CDF_iommu; + + /* Get the optional property domain-cpupool */ + cpupool_node = dt_parse_phandle(node, "domain-cpupool", 0); + if ( cpupool_node ) + { + int pool_id = btcpupools_get_domain_pool_id(cpupool_node); + if ( pool_id < 0 ) + panic("Error getting cpupool id from domain-cpupool (%d)\n", + pool_id); + d_cfg.cpupool_id = pool_id; + } + + if ( dt_property_read_u32(node, "max_grant_version", &val) ) + d_cfg.grant_opts = XEN_DOMCTL_GRANT_version(val); + + if ( dt_property_read_u32(node, "max_grant_frames", &val) ) + { + if ( val > INT32_MAX ) + panic("max_grant_frames (%"PRIu32") overflow\n", val); + d_cfg.max_grant_frames = val; + } + + if ( dt_property_read_u32(node, "max_maptrack_frames", &val) ) + { + if ( val > INT32_MAX ) + panic("max_maptrack_frames (%"PRIu32") overflow\n", val); + d_cfg.max_maptrack_frames = val; + } + + dt_property_read_string(node, "llc-colors", &llc_colors_str); + if ( !llc_coloring_enabled && llc_colors_str ) + panic("'llc-colors' found, but LLC coloring is disabled\n"); + + arch_create_domus(node, &d_cfg, flags); + + /* + * The variable max_init_domid is initialized with zero, so here it's + * very important to use the pre-increment operator to call + * domain_create() with a domid > 0. (domid == 0 is reserved for Dom0) + */ + d = domain_create(++max_init_domid, &d_cfg, flags); + if ( IS_ERR(d) ) + panic("Error creating domain %s (rc = %ld)\n", + dt_node_name(node), PTR_ERR(d)); + + if ( llc_coloring_enabled && + (rc = domain_set_llc_colors_from_str(d, llc_colors_str)) ) + panic("Error initializing LLC coloring for domain %s (rc = %d)\n", + dt_node_name(node), rc); + + d->is_console = true; + dt_device_set_used_by(node, d->domain_id); + + rc = construct_domU(d, node); + if ( rc ) + panic("Could not set up domain %s (rc = %d)\n", + dt_node_name(node), rc); + } +} diff --git a/xen/include/asm-generic/dom0less-build.h b/xen/include/asm-generic/dom0less-build.h new file mode 100644 index 0000000000..a6985bc20a --- /dev/null +++ b/xen/include/asm-generic/dom0less-build.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __ASM_GENERIC_DOM0LESS_BUILD_H__ +#define __ASM_GENERIC_DOM0LESS_BUILD_H__ + +#include + +#ifdef CONFIG_DOM0LESS_BOOT + +#include + +void create_domUs(void); +bool is_dom0less_mode(void); + +int construct_domU(struct domain *d, const struct dt_device_node *node); + +struct xen_domctl_createdomain arch_xen_domctl_createdomain(void); +void arch_create_domus(struct dt_device_node *node, + struct xen_domctl_createdomain *d_cfg, + unsigned int flags); + +#else /* !CONFIG_DOM0LESS_BOOT */ + +static inline void create_domUs(void) {} +static inline bool is_dom0less_mode(void) +{ + return false; +} + +#endif /* CONFIG_DOM0LESS_BOOT */ + +#endif /* __ASM_GENERIC_DOM0LESS_BUILD_H__ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ From patchwork Mon Apr 14 15:56:36 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleksii Kurochko X-Patchwork-Id: 14050658 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id E1D97C369BA for ; Mon, 14 Apr 2025 15:57:02 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.950713.1346967 (Exim 4.92) (envelope-from ) id 1u4MB1-0000bu-Lg; Mon, 14 Apr 2025 15:56:51 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 950713.1346967; Mon, 14 Apr 2025 15:56:51 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1u4MB1-0000bn-HJ; Mon, 14 Apr 2025 15:56:51 +0000 Received: by outflank-mailman (input) for mailman id 950713; Mon, 14 Apr 2025 15:56:50 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1u4MAz-0008KQ-Un for xen-devel@lists.xenproject.org; Mon, 14 Apr 2025 15:56:50 +0000 Received: from mail-ej1-x62a.google.com (mail-ej1-x62a.google.com [2a00:1450:4864:20::62a]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id 12d08264-1949-11f0-9eae-5ba50f476ded; Mon, 14 Apr 2025 17:56:48 +0200 (CEST) Received: by mail-ej1-x62a.google.com with SMTP id a640c23a62f3a-ac3b12e8518so758593166b.0 for ; Mon, 14 Apr 2025 08:56:48 -0700 (PDT) Received: from fedora.. (user-109-243-64-225.play-internet.pl. [109.243.64.225]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-acaa1cb4288sm951760866b.96.2025.04.14.08.56.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 14 Apr 2025 08:56:47 -0700 (PDT) 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: 12d08264-1949-11f0-9eae-5ba50f476ded DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1744646208; x=1745251008; darn=lists.xenproject.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=KlvlGdP3RguuAXd8DMZPpi8Btp1s7EmOSfOIyUOydDM=; b=Vq+u11x3W61bB+PQKMU3082sX/rVEEBzlsQDgAj1j+hHuUq+dn4LyN6usn/HNDS0OI CPl6GFWxTEJPR5UYTO5zYm3nO3NXAxAjPVF8fzlVuMGU2hclVZaNhAFn4PF3NdOpAoXa INYBxp0jhnMhZ+qc0pon3AOPLR5lN27yQ5NQjgIHmSPEjBC1kHMDA/41TLJCGszFX2nd 2BOSfZMo70YpyPeV04UgZSSa9imESD3aHL+6wNbqOl1Uf+khQqj9Y1X3wyOVSEpJxLmy dNIb6KUWusZkF2pqPrTWNgxe0EcdLYwJ5e2R0idHhw4+ZSQrm6Gne4wIfFWuFy9WFQ3t OHFw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744646208; x=1745251008; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=KlvlGdP3RguuAXd8DMZPpi8Btp1s7EmOSfOIyUOydDM=; b=lr7/VzR5bthAac7uGENBA2aEWmj6gGhWiRHwqn4bx4JFPV2bor+t08cbu5zZkk175j /mMNK+fOI5w6dNp5S/vx68aa0ig9ceVI6ZunrjBb+ACy+V6Cu559dLPAYdr3zzHS+xhK Z+fMrG7jIyPsc4GrUEoSW6cJV4uQpdfmmHG1zBEywg4scrizLy6qAZoMKuE0Zv16qr7L 9yNV60Q71GANZbBUxXdqkwQI93D7qG0I+FIoS7PjlbVlaVRTdiM4ct0HSi8wvokTGm8C U2PcQxTXGqhksIrwnvGbYiv5J1GQI3tCObQAqKkeEPKG5NWDf39qWI+9lo97SEdCGnYU V6Kg== X-Gm-Message-State: AOJu0YwC3J/IQ9u5j3LyZNuW6LlD7H/DgfIOg1g/XVUcp9JP/PyklMxB wuZ1gfsFeNAgN5SrERthkRwJ8feJbcgmQHlbn1hZOSUyGpm8+1GcqkPDgA== X-Gm-Gg: ASbGncsaXGvAsjlTxendvMSKlxDO5MZax3PLN6CvoEsk1Lbcr5mMf0YJqYuEL5VycUN 8bxJU468CXAzslmPlJ+2QF+OOkf4Yp8qEugMTXcF4x8B3MtE8mwDVS3NMiO82WPWovJKd+JkJDq l33O5SZRuzB4nPSo8H5cy+6WrXWgZKeKHWNfaFXYCGhqiG5Fl9B56/1qnLNGCUCrZHk4jdrst41 t/ZMmZdXnZLAOE6p44sWwd77kugY7z8/xOqJ4kI8TD+wxbR0ghE8o5h51aps0+AiIRPkpaq8AGQ OLuDkeS9G0b3SKgv2IomTjAzTvmzWa+t4U9CCaIvL0HPXG3kjb33raH86CQbAotz7ARL1Z1tqMu igOYIWeGInYe4JCTF64Qf X-Google-Smtp-Source: AGHT+IHTRv40vtlxklxwQ9vtvsCn5SJzxQaoWzyWTeW2GornEf3GHlek7Owtttibq6wkI/jVDDg+7w== X-Received: by 2002:a17:907:94d0:b0:ac2:fd70:ddcc with SMTP id a640c23a62f3a-acad36a452fmr930081566b.47.1744646207727; Mon, 14 Apr 2025 08:56:47 -0700 (PDT) From: Oleksii Kurochko To: xen-devel@lists.xenproject.org Cc: Oleksii Kurochko , Stefano Stabellini , Julien Grall , Bertrand Marquis , Michal Orzel , Volodymyr Babchuk , Andrew Cooper , Anthony PERARD , Jan Beulich , =?utf-8?q?Roger_Pau_Monn=C3=A9?= Subject: [PATCH v2 3/8] asm-generic: move parts of Arm's asm/kernel.h to common code Date: Mon, 14 Apr 2025 17:56:36 +0200 Message-ID: X-Mailer: git-send-email 2.49.0 In-Reply-To: References: MIME-Version: 1.0 Move the following parts to common with the following changes: - struct kernel_info: - Create arch_kernel_info for arch specific kernel information. At the moment, it contains domain_type for Arm. - Rename vpl011 to vuart to have more generic name suitable for other archs. - s/phandle_gic/phandle_intc to have more generic name suitable for other archs. - Make text_offset of zimage structure available for RISCV_64. - Wrap by `#ifdef KERNEL_INFO_SHM_MEM_INIT` definition of KERNEL_SHM_MEM_INIT and wrap by `#ifndef KERNEL_INFO_INIT` definition of KERNEL_INFO_INIT to have ability to override KERNEL_INFO_SHM_MEM_INIT for arch in case it doesn't want to use generic one. - Move DOM0LESS_* macros to dom0less-build.h. - Move all others parts of Arm's kernel.h to xen/fdt-kernel.h. Because of the changes in struct kernel_info the correspondent parts of Arm's code are updated. As part of this patch the following clean up happens: - Drop asm/setup.h from asm/kernel.h as nothing depends from it. Add inclusion of asm/setup.h for a code which uses device_tree_get_reg() to avoid compilation issues for CONFIG_STATIC_MEMORY and CONFIG_STATIC_SHM. - Drop inclusion of asm/kernel.h everywhere except xen/fdt-kernel.h. Signed-off-by: Oleksii Kurochko --- Changes in v2: - Introduce xen/fdt-kernel.h. - Move DOM0LESS_* macros to dom0less-build.h. - Move the rest in asm-generic/kernel.h to xen/fdt-kernel.h. - Drop inclusion of asm/kernel.h everywhere except xen/fdt-kernel.h. - Wrap by #if __has_include(....) the member of kernel_info structure: struct arch_kernel_info arch. - Update the commit message. --- xen/arch/arm/acpi/domain_build.c | 2 +- xen/arch/arm/dom0less-build.c | 29 ++--- xen/arch/arm/domain_build.c | 12 +- xen/arch/arm/include/asm/domain_build.h | 2 +- xen/arch/arm/include/asm/kernel.h | 126 +-------------------- xen/arch/arm/include/asm/static-memory.h | 2 +- xen/arch/arm/include/asm/static-shmem.h | 2 +- xen/arch/arm/kernel.c | 13 ++- xen/arch/arm/static-memory.c | 1 + xen/arch/arm/static-shmem.c | 1 + xen/common/device-tree/dt-overlay.c | 2 +- xen/include/asm-generic/dom0less-build.h | 28 +++++ xen/include/xen/fdt-kernel.h | 133 +++++++++++++++++++++++ 13 files changed, 198 insertions(+), 155 deletions(-) create mode 100644 xen/include/xen/fdt-kernel.h diff --git a/xen/arch/arm/acpi/domain_build.c b/xen/arch/arm/acpi/domain_build.c index 2ce75543d0..f9ca8b47e5 100644 --- a/xen/arch/arm/acpi/domain_build.c +++ b/xen/arch/arm/acpi/domain_build.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -18,7 +19,6 @@ #include #include #include -#include #include /* Override macros from asm/page.h to make them work with mfn_t */ diff --git a/xen/arch/arm/dom0less-build.c b/xen/arch/arm/dom0less-build.c index 7ec3f85795..5810083951 100644 --- a/xen/arch/arm/dom0less-build.c +++ b/xen/arch/arm/dom0less-build.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ #include #include +#include #include #include #include @@ -60,11 +61,11 @@ static int __init make_gicv2_domU_node(struct kernel_info *kinfo) if (res) return res; - res = fdt_property_cell(fdt, "linux,phandle", kinfo->phandle_gic); + res = fdt_property_cell(fdt, "linux,phandle", kinfo->phandle_intc); if (res) return res; - res = fdt_property_cell(fdt, "phandle", kinfo->phandle_gic); + res = fdt_property_cell(fdt, "phandle", kinfo->phandle_intc); if (res) return res; @@ -131,11 +132,11 @@ static int __init make_gicv3_domU_node(struct kernel_info *kinfo) if (res) return res; - res = fdt_property_cell(fdt, "linux,phandle", kinfo->phandle_gic); + res = fdt_property_cell(fdt, "linux,phandle", kinfo->phandle_intc); if (res) return res; - res = fdt_property_cell(fdt, "phandle", kinfo->phandle_gic); + res = fdt_property_cell(fdt, "phandle", kinfo->phandle_intc); if (res) return res; @@ -196,7 +197,7 @@ static int __init make_vpl011_uart_node(struct kernel_info *kinfo) return res; res = fdt_property_cell(fdt, "interrupt-parent", - kinfo->phandle_gic); + kinfo->phandle_intc); if ( res ) return res; @@ -482,10 +483,10 @@ static int __init domain_handle_dtb_bootmodule(struct domain *d, */ if ( dt_node_cmp(name, "gic") == 0 ) { - uint32_t phandle_gic = fdt_get_phandle(pfdt, node_next); + uint32_t phandle_intc = fdt_get_phandle(pfdt, node_next); - if ( phandle_gic != 0 ) - kinfo->phandle_gic = phandle_gic; + if ( phandle_intc != 0 ) + kinfo->phandle_intc = phandle_intc; continue; } @@ -528,7 +529,7 @@ static int __init prepare_dtb_domU(struct domain *d, struct kernel_info *kinfo) int addrcells, sizecells; int ret, fdt_size = DOMU_DTB_SIZE; - kinfo->phandle_gic = GUEST_PHANDLE_GIC; + kinfo->phandle_intc = GUEST_PHANDLE_GIC; kinfo->gnttab_start = GUEST_GNTTAB_BASE; kinfo->gnttab_size = GUEST_GNTTAB_SIZE; @@ -590,7 +591,7 @@ static int __init prepare_dtb_domU(struct domain *d, struct kernel_info *kinfo) /* * domain_handle_dtb_bootmodule has to be called before the rest of * the device tree is generated because it depends on the value of - * the field phandle_gic. + * the field phandle_intc. */ if ( kinfo->dtb_bootmodule ) { @@ -607,7 +608,7 @@ static int __init prepare_dtb_domU(struct domain *d, struct kernel_info *kinfo) if ( ret ) goto err; - if ( kinfo->vpl011 ) + if ( kinfo->vuart ) { ret = -EINVAL; #ifdef CONFIG_SBSA_VUART_CONSOLE @@ -860,7 +861,7 @@ int __init construct_domU(struct domain *d, printk("*** LOADING DOMU cpus=%u memory=%#"PRIx64"KB ***\n", d->max_vcpus, mem); - kinfo.vpl011 = dt_property_read_bool(node, "vpl011"); + kinfo.vuart = dt_property_read_bool(node, "vpl011"); rc = dt_property_read_string(node, "xen,enhanced", &dom0less_enhanced); if ( rc == -EILSEQ || @@ -895,7 +896,7 @@ int __init construct_domU(struct domain *d, #ifdef CONFIG_ARM_64 /* type must be set before allocate memory */ - d->arch.type = kinfo.type; + d->arch.type = kinfo.arch.type; #endif if ( !dt_find_property(node, "xen,static-mem", NULL) ) allocate_memory(d, &kinfo); @@ -913,7 +914,7 @@ int __init construct_domU(struct domain *d, * tree node in prepare_dtb_domU, so initialization on related variables * shall be done first. */ - if ( kinfo.vpl011 ) + if ( kinfo.vuart ) { rc = domain_vpl011_init(d, NULL); if ( rc < 0 ) diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index 634333cdde..a19914f836 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ #include #include +#include #include #include #include @@ -20,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -747,7 +747,7 @@ static int __init fdt_property_interrupts(const struct kernel_info *kinfo, return res; res = fdt_property_cell(kinfo->fdt, "interrupt-parent", - kinfo->phandle_gic); + kinfo->phandle_intc); return res; } @@ -2026,7 +2026,7 @@ static int __init prepare_dtb_hwdom(struct domain *d, struct kernel_info *kinfo) ASSERT(dt_host && (dt_host->sibling == NULL)); - kinfo->phandle_gic = dt_interrupt_controller->phandle; + kinfo->phandle_intc = dt_interrupt_controller->phandle; fdt = device_tree_flattened; new_size = fdt_totalsize(fdt) + DOM0_FDT_EXTRA_SIZE; @@ -2196,13 +2196,13 @@ int __init construct_domain(struct domain *d, struct kernel_info *kinfo) #ifdef CONFIG_ARM_64 /* if aarch32 mode is not supported at EL1 do not allow 32-bit domain */ - if ( !(cpu_has_el1_32) && kinfo->type == DOMAIN_32BIT ) + if ( !(cpu_has_el1_32) && kinfo->arch.type == DOMAIN_32BIT ) { printk("Platform does not support 32-bit domain\n"); return -EINVAL; } - if ( is_sve_domain(d) && (kinfo->type == DOMAIN_32BIT) ) + if ( is_sve_domain(d) && (kinfo->arch.type == DOMAIN_32BIT) ) { printk("SVE is not available for 32-bit domain\n"); return -EINVAL; @@ -2317,7 +2317,7 @@ int __init construct_hwdom(struct kernel_info *kinfo) #ifdef CONFIG_ARM_64 /* type must be set before allocate_memory */ - d->arch.type = kinfo->type; + d->arch.type = kinfo->arch.type; #endif find_gnttab_region(d, kinfo); if ( is_domain_direct_mapped(d) ) diff --git a/xen/arch/arm/include/asm/domain_build.h b/xen/arch/arm/include/asm/domain_build.h index 38546de477..7136857ce4 100644 --- a/xen/arch/arm/include/asm/domain_build.h +++ b/xen/arch/arm/include/asm/domain_build.h @@ -1,8 +1,8 @@ #ifndef __ASM_DOMAIN_BUILD_H__ #define __ASM_DOMAIN_BUILD_H__ +#include #include -#include typedef __be32 gic_interrupt_t[3]; typedef bool (*alloc_domheap_mem_cb)(struct domain *d, struct page_info *pg, diff --git a/xen/arch/arm/include/asm/kernel.h b/xen/arch/arm/include/asm/kernel.h index bdc96f4c18..cfeab792c7 100644 --- a/xen/arch/arm/include/asm/kernel.h +++ b/xen/arch/arm/include/asm/kernel.h @@ -6,137 +6,15 @@ #ifndef __ARCH_ARM_KERNEL_H__ #define __ARCH_ARM_KERNEL_H__ -#include #include -#include -/* - * List of possible features for dom0less domUs - * - * DOM0LESS_ENHANCED_NO_XS: Notify the OS it is running on top of Xen. All the - * default features (excluding Xenstore) will be - * available. Note that an OS *must* not rely on the - * availability of Xen features if this is not set. - * DOM0LESS_XENSTORE: Xenstore will be enabled for the VM. The - * xenstore page allocation is done by Xen at - * domain creation. This feature can't be - * enabled without the DOM0LESS_ENHANCED_NO_XS. - * DOM0LESS_XS_LEGACY Xenstore will be enabled for the VM, the - * xenstore page allocation will happen in - * init-dom0less. This feature can't be enabled - * without the DOM0LESS_ENHANCED_NO_XS. - * DOM0LESS_ENHANCED: Notify the OS it is running on top of Xen. All the - * default features (including Xenstore) will be - * available. Note that an OS *must* not rely on the - * availability of Xen features if this is not set. - * DOM0LESS_ENHANCED_LEGACY: Same as before, but using DOM0LESS_XS_LEGACY. - */ -#define DOM0LESS_ENHANCED_NO_XS BIT(0, U) -#define DOM0LESS_XENSTORE BIT(1, U) -#define DOM0LESS_XS_LEGACY BIT(2, U) -#define DOM0LESS_ENHANCED_LEGACY (DOM0LESS_ENHANCED_NO_XS | DOM0LESS_XS_LEGACY) -#define DOM0LESS_ENHANCED (DOM0LESS_ENHANCED_NO_XS | DOM0LESS_XENSTORE) - -struct kernel_info { +struct arch_kernel_info +{ #ifdef CONFIG_ARM_64 enum domain_type type; #endif - - struct domain *d; - - void *fdt; /* flat device tree */ - paddr_t unassigned_mem; /* RAM not (yet) assigned to a bank */ - struct meminfo mem; -#ifdef CONFIG_STATIC_SHM - struct shared_meminfo shm_mem; -#endif - - /* kernel entry point */ - paddr_t entry; - - /* grant table region */ - paddr_t gnttab_start; - paddr_t gnttab_size; - - /* boot blob load addresses */ - const struct bootmodule *kernel_bootmodule, *initrd_bootmodule, *dtb_bootmodule; - const char* cmdline; - paddr_t dtb_paddr; - paddr_t initrd_paddr; - - /* Enable pl011 emulation */ - bool vpl011; - - /* Enable/Disable PV drivers interfaces */ - uint16_t dom0less_feature; - - /* GIC phandle */ - uint32_t phandle_gic; - - /* loader to use for this kernel */ - void (*load)(struct kernel_info *info); - /* loader specific state */ - union { - struct { - paddr_t kernel_addr; - paddr_t len; -#ifdef CONFIG_ARM_64 - paddr_t text_offset; /* 64-bit Image only */ -#endif - paddr_t start; /* Must be 0 for 64-bit Image */ - } zimage; - }; }; -static inline struct membanks *kernel_info_get_mem(struct kernel_info *kinfo) -{ - return container_of(&kinfo->mem.common, struct membanks, common); -} - -static inline const struct membanks * -kernel_info_get_mem_const(const struct kernel_info *kinfo) -{ - return container_of(&kinfo->mem.common, const struct membanks, common); -} - -#ifdef CONFIG_STATIC_SHM -#define KERNEL_INFO_SHM_MEM_INIT \ - .shm_mem.common.max_banks = NR_SHMEM_BANKS, \ - .shm_mem.common.type = STATIC_SHARED_MEMORY, -#else -#define KERNEL_INFO_SHM_MEM_INIT -#endif - -#define KERNEL_INFO_INIT \ -{ \ - .mem.common.max_banks = NR_MEM_BANKS, \ - .mem.common.type = MEMORY, \ - KERNEL_INFO_SHM_MEM_INIT \ -} - -/* - * Probe the kernel to detemine its type and select a loader. - * - * Sets in info: - * ->type - * ->load hook, and sets loader specific variables ->zimage - */ -int kernel_probe(struct kernel_info *info, const struct dt_device_node *domain); - -/* - * Loads the kernel into guest RAM. - * - * Expects to be set in info when called: - * ->mem - * ->fdt - * - * Sets in info: - * ->entry - * ->dtb_paddr - * ->initrd_paddr - */ -void kernel_load(struct kernel_info *info); - #endif /* #ifdef __ARCH_ARM_KERNEL_H__ */ /* diff --git a/xen/arch/arm/include/asm/static-memory.h b/xen/arch/arm/include/asm/static-memory.h index 804166e541..a32a3c6553 100644 --- a/xen/arch/arm/include/asm/static-memory.h +++ b/xen/arch/arm/include/asm/static-memory.h @@ -3,8 +3,8 @@ #ifndef __ASM_STATIC_MEMORY_H_ #define __ASM_STATIC_MEMORY_H_ +#include #include -#include #ifdef CONFIG_STATIC_MEMORY diff --git a/xen/arch/arm/include/asm/static-shmem.h b/xen/arch/arm/include/asm/static-shmem.h index 94eaa9d500..a4f853805a 100644 --- a/xen/arch/arm/include/asm/static-shmem.h +++ b/xen/arch/arm/include/asm/static-shmem.h @@ -3,8 +3,8 @@ #ifndef __ASM_STATIC_SHMEM_H_ #define __ASM_STATIC_SHMEM_H_ +#include #include -#include #include #ifdef CONFIG_STATIC_SHM diff --git a/xen/arch/arm/kernel.c b/xen/arch/arm/kernel.c index 6eaf9e2b06..5482cf4239 100644 --- a/xen/arch/arm/kernel.c +++ b/xen/arch/arm/kernel.c @@ -6,6 +6,7 @@ */ #include #include +#include #include #include #include @@ -16,7 +17,7 @@ #include #include -#include +#include #include #define UIMAGE_MAGIC 0x27051956 @@ -101,7 +102,7 @@ static paddr_t __init kernel_zimage_place(struct kernel_info *info) paddr_t load_addr; #ifdef CONFIG_ARM_64 - if ( (info->type == DOMAIN_64BIT) && (info->zimage.start == 0) ) + if ( (info->arch.type == DOMAIN_64BIT) && (info->zimage.start == 0) ) return mem->bank[0].start + info->zimage.text_offset; #endif @@ -371,10 +372,10 @@ static int __init kernel_uimage_probe(struct kernel_info *info, switch ( uimage.arch ) { case IH_ARCH_ARM: - info->type = DOMAIN_32BIT; + info->arch.type = DOMAIN_32BIT; break; case IH_ARCH_ARM64: - info->type = DOMAIN_64BIT; + info->arch.type = DOMAIN_64BIT; break; default: printk(XENLOG_ERR "Unsupported uImage arch type %d\n", uimage.arch); @@ -444,7 +445,7 @@ static int __init kernel_zimage64_probe(struct kernel_info *info, info->load = kernel_zimage_load; - info->type = DOMAIN_64BIT; + info->arch.type = DOMAIN_64BIT; return 0; } @@ -496,7 +497,7 @@ static int __init kernel_zimage32_probe(struct kernel_info *info, info->load = kernel_zimage_load; #ifdef CONFIG_ARM_64 - info->type = DOMAIN_32BIT; + info->arch.type = DOMAIN_32BIT; #endif return 0; diff --git a/xen/arch/arm/static-memory.c b/xen/arch/arm/static-memory.c index d4585c5a06..e0f76afcd8 100644 --- a/xen/arch/arm/static-memory.c +++ b/xen/arch/arm/static-memory.c @@ -2,6 +2,7 @@ #include +#include #include static bool __init append_static_memory_to_bank(struct domain *d, diff --git a/xen/arch/arm/static-shmem.c b/xen/arch/arm/static-shmem.c index e8d4ca3ba3..14ae48fb1e 100644 --- a/xen/arch/arm/static-shmem.c +++ b/xen/arch/arm/static-shmem.c @@ -6,6 +6,7 @@ #include #include +#include #include #include diff --git a/xen/common/device-tree/dt-overlay.c b/xen/common/device-tree/dt-overlay.c index 97fb99eaaa..81107cb48d 100644 --- a/xen/common/device-tree/dt-overlay.c +++ b/xen/common/device-tree/dt-overlay.c @@ -6,8 +6,8 @@ * Written by Vikram Garhwal * */ -#include #include +#include #include #include #include diff --git a/xen/include/asm-generic/dom0less-build.h b/xen/include/asm-generic/dom0less-build.h index a6985bc20a..7092f7fc7e 100644 --- a/xen/include/asm-generic/dom0less-build.h +++ b/xen/include/asm-generic/dom0less-build.h @@ -8,6 +8,34 @@ #include +/* + * List of possible features for dom0less domUs + * + * DOM0LESS_ENHANCED_NO_XS: Notify the OS it is running on top of Xen. All the + * default features (excluding Xenstore) will be + * available. Note that an OS *must* not rely on the + * availability of Xen features if this is not set. + * DOM0LESS_XENSTORE: Xenstore will be enabled for the VM. The + * xenstore page allocation is done by Xen at + * domain creation. This feature can't be + * enabled without the DOM0LESS_ENHANCED_NO_XS. + * DOM0LESS_XS_LEGACY Xenstore will be enabled for the VM, the + * xenstore page allocation will happen in + * init-dom0less. This feature can't be enabled + * without the DOM0LESS_ENHANCED_NO_XS. + * DOM0LESS_ENHANCED: Notify the OS it is running on top of Xen. All the + * default features (including Xenstore) will be + * available. Note that an OS *must* not rely on the + * availability of Xen features if this is not set. + * DOM0LESS_ENHANCED_LEGACY: Same as before, but using DOM0LESS_XS_LEGACY. + + */ +#define DOM0LESS_ENHANCED_NO_XS BIT(0, U) +#define DOM0LESS_XENSTORE BIT(1, U) +#define DOM0LESS_XS_LEGACY BIT(2, U) +#define DOM0LESS_ENHANCED_LEGACY (DOM0LESS_ENHANCED_NO_XS | DOM0LESS_XS_LEGACY) +#define DOM0LESS_ENHANCED (DOM0LESS_ENHANCED_NO_XS | DOM0LESS_XENSTORE) + void create_domUs(void); bool is_dom0less_mode(void); diff --git a/xen/include/xen/fdt-kernel.h b/xen/include/xen/fdt-kernel.h new file mode 100644 index 0000000000..c81e759423 --- /dev/null +++ b/xen/include/xen/fdt-kernel.h @@ -0,0 +1,133 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * For Kernel image loading. + * + * Copyright (C) 2011 Citrix Systems, Inc. + */ +#ifndef __XEN_FDT_KERNEL_H__ +#define __XEN_FDT_KERNEL_H__ + +#include +#include +#include + +#if __has_include() +# include +#endif + +struct kernel_info { + struct domain *d; + + void *fdt; /* flat device tree */ + paddr_t unassigned_mem; /* RAM not (yet) assigned to a bank */ + struct meminfo mem; +#ifdef CONFIG_STATIC_SHM + struct shared_meminfo shm_mem; +#endif + + /* kernel entry point */ + paddr_t entry; + + /* grant table region */ + paddr_t gnttab_start; + paddr_t gnttab_size; + + /* boot blob load addresses */ + const struct bootmodule *kernel_bootmodule, *initrd_bootmodule, *dtb_bootmodule; + const char* cmdline; + paddr_t dtb_paddr; + paddr_t initrd_paddr; + + /* Enable uart emulation */ + bool vuart; + + /* Enable/Disable PV drivers interfaces */ + uint16_t dom0less_feature; + + /* Interrupt controller phandle */ + uint32_t phandle_intc; + + /* loader to use for this kernel */ + void (*load)(struct kernel_info *info); + + /* loader specific state */ + union { + struct { + paddr_t kernel_addr; + paddr_t len; +#if defined(CONFIG_ARM_64) || defined(CONFIG_RISCV_64) + paddr_t text_offset; /* 64-bit Image only */ +#endif + paddr_t start; /* Must be 0 for 64-bit Image */ + } zimage; + }; + +#if __has_include() + struct arch_kernel_info arch; +#endif +}; + +static inline struct membanks *kernel_info_get_mem(struct kernel_info *kinfo) +{ + return container_of(&kinfo->mem.common, struct membanks, common); +} + +static inline const struct membanks * +kernel_info_get_mem_const(const struct kernel_info *kinfo) +{ + return container_of(&kinfo->mem.common, const struct membanks, common); +} + +#ifndef KERNEL_INFO_SHM_MEM_INIT + +#ifdef CONFIG_STATIC_SHM +#define KERNEL_INFO_SHM_MEM_INIT .shm_mem.common.max_banks = NR_SHMEM_BANKS, +#else +#define KERNEL_INFO_SHM_MEM_INIT +#endif + +#endif /* KERNEL_INFO_SHM_MEM_INIT */ + +#ifndef KERNEL_INFO_INIT + +#define KERNEL_INFO_INIT \ +{ \ + .mem.common.max_banks = NR_MEM_BANKS, \ + KERNEL_INFO_SHM_MEM_INIT \ +} + +#endif /* KERNEL_INFO_INIT */ + +/* + * Probe the kernel to detemine its type and select a loader. + * + * Sets in info: + * ->type + * ->load hook, and sets loader specific variables ->zimage + */ +int kernel_probe(struct kernel_info *info, const struct dt_device_node *domain); + +/* + * Loads the kernel into guest RAM. + * + * Expects to be set in info when called: + * ->mem + * ->fdt + * + * Sets in info: + * ->entry + * ->dtb_paddr + * ->initrd_paddr + */ +void kernel_load(struct kernel_info *info); + +#endif /* __XEN_FDT_KERNEL_H__ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ From patchwork Mon Apr 14 15:56:37 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleksii Kurochko X-Patchwork-Id: 14050656 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 2125BC369B9 for ; Mon, 14 Apr 2025 15:57:03 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.950714.1346977 (Exim 4.92) (envelope-from ) id 1u4MB2-0000r8-SG; Mon, 14 Apr 2025 15:56:52 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 950714.1346977; Mon, 14 Apr 2025 15:56:52 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1u4MB2-0000qx-OM; Mon, 14 Apr 2025 15:56:52 +0000 Received: by outflank-mailman (input) for mailman id 950714; Mon, 14 Apr 2025 15:56:51 +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 1u4MB1-0008LI-II for xen-devel@lists.xenproject.org; Mon, 14 Apr 2025 15:56:51 +0000 Received: from mail-ej1-x630.google.com (mail-ej1-x630.google.com [2a00:1450:4864:20::630]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id 13899891-1949-11f0-9ffb-bf95429c2676; Mon, 14 Apr 2025 17:56:50 +0200 (CEST) Received: by mail-ej1-x630.google.com with SMTP id a640c23a62f3a-abbd96bef64so931326766b.3 for ; Mon, 14 Apr 2025 08:56:50 -0700 (PDT) Received: from fedora.. (user-109-243-64-225.play-internet.pl. [109.243.64.225]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-acaa1cb4288sm951760866b.96.2025.04.14.08.56.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 14 Apr 2025 08:56:48 -0700 (PDT) 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: 13899891-1949-11f0-9ffb-bf95429c2676 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1744646209; x=1745251009; darn=lists.xenproject.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=biW/0L6vulzOGgUZkJVlWvo9rwiN4vFTilKp0PPEU6k=; b=fV2YKndCMGdv8s2r2VAVgGvK9UNFr2M4eeH4xuYTBPE88Ul+sdX/scrtgngt0ka+Vy A6AMzX9j8+VsbjiTXkK7OQdFIvgwMzLzaEOgIOuUDI4xQAEBtps6XjzmMMCztWrjAhQY sToMSqComRYi8aziJgeQlCScTgnvaLG7gR8iUAZ0iriD8RATBVSJuTDlGUb4eV/df0C9 kSpFBJjbCID2GS+aXrYVZQ4wSurSW+rBPlEv/unTQ6cS/x+mMVlRcL6HqSuTYK8IQXej 62rN/KEsVrEsk8UkANn+SSfB5/HpcSAYWXZrkKhj/98cVBrfb2CvqTdTvxwlsvzYbgIP 3pOA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744646209; x=1745251009; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=biW/0L6vulzOGgUZkJVlWvo9rwiN4vFTilKp0PPEU6k=; b=ey//pClvkm7sqB/DRc+Bq95/OccRNLSkxcUdjnIFGi0K5oGDk1f3Xx9PmdbFMqemVh WMkljyDwdHtmXfgShxSeEp8Ws4oFOu5bffpPj3ybpTtOWrs9NTzxnBQ5mXR79g5ewptk VRcqhQ5de40ds/8Qfn6YoW5JzphdFCCwEMDg22SbsIreZYjvP7UJsvrWMAqPNSGBAy56 b249GXQZ9jKS0/Ofy3GNfI0J0JdEunQhlV6ZklficlQ9exPnXIm072Csrf4LI9j2SPDM UN8HwCePifRaqpBQTU34ut3Rlj45v8iT/MV9DMIMGG2gSr6Dx4D01lsFSRoRe7uoaDe/ 8Jgg== X-Gm-Message-State: AOJu0YxezawntTNdmGyIVKCKSQx6niYyj1NXVJrSt3TGT2cNmmZrgHPD 4VHOddk1Uagl0IjU9h3VEAXDVkmT0LMCXyGvdcyf082r5/UqZHPesScEzw== X-Gm-Gg: ASbGncv5tUxJZQErzSNRPIpC86mc3YAAzYu5ttOkpt2zo972ZtNpLJd/5z9fCszvbuk ryPWG4vPbsryF2BtgdmfKpB0sVNgQL3Fb7GwJdOwDw/bCbD/OM+kLnmXQv6BSIba7pbWjIZUaF2 5WweUbXS/jrMsQBpvT8sqdQZj+cmjWomyBa+ZSxUSvPVr7cxJxeSR9bAELG+NHGu2IOzxsOGUvl 1ddIqKojoFelGOrAb2rya4iUB+E7DHso/oxVV5Y3vYzTBk2gXVGW4lhYTRa1QJaMVfw5BR/eHeF ++iMtDdgDCPNH6B0nwEoo0NBgZ7rM9/meEtecEUaES4qWfBHA3cGsvM1qVNsVpAYQxt370/qhZZ VFu/xTyshkw== X-Google-Smtp-Source: AGHT+IG4/0yxABSmXWjkum4i1iaahql5lRZoMC/3qZoz0LCLoqDSmONznruxyWC97BQZbKdCT+n5IA== X-Received: by 2002:a17:907:3ea7:b0:aca:a1c9:d155 with SMTP id a640c23a62f3a-acad3430e5dmr1038809366b.11.1744646208500; Mon, 14 Apr 2025 08:56:48 -0700 (PDT) From: Oleksii Kurochko To: xen-devel@lists.xenproject.org Cc: Oleksii Kurochko , Stefano Stabellini , Julien Grall , Bertrand Marquis , Michal Orzel , Volodymyr Babchuk Subject: [PATCH v2 4/8] arm/static-shmem.h: drop inclusion of asm/setup.h Date: Mon, 14 Apr 2025 17:56:37 +0200 Message-ID: <96e1f798ff19bcee73e613ae9b74056cc37eb5c3.1744626032.git.oleksii.kurochko@gmail.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: References: MIME-Version: 1.0 Nothing is dependent from asm/setup.h in asm/static-shmem.h so inclusion of asm/setup.h is droped. After this drop the following compilation error related to impicit declaration of the following functions device_tree_get_reg and map_device_irqs_to_domain, device_tree_get_u32 occur during compilation of dom0less-build.c ( as they are declared in asm/setup.h ). Add inclusion of in dt-overlay.c as it is using handle_device() declared in . Signed-off-by: Oleksii Kurochko --- Changes in V2: - Nothing changed. Only rebase. --- xen/arch/arm/dom0less-build.c | 1 + xen/common/device-tree/dt-overlay.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/xen/arch/arm/dom0less-build.c b/xen/arch/arm/dom0less-build.c index 5810083951..122739061c 100644 --- a/xen/arch/arm/dom0less-build.c +++ b/xen/arch/arm/dom0less-build.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include diff --git a/xen/common/device-tree/dt-overlay.c b/xen/common/device-tree/dt-overlay.c index 81107cb48d..d184186c01 100644 --- a/xen/common/device-tree/dt-overlay.c +++ b/xen/common/device-tree/dt-overlay.c @@ -13,6 +13,8 @@ #include #include +#include + #define DT_OVERLAY_MAX_SIZE KB(500) static LIST_HEAD(overlay_tracker); From patchwork Mon Apr 14 15:56:38 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleksii Kurochko X-Patchwork-Id: 14050657 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id B4CF8C369B2 for ; Mon, 14 Apr 2025 15:57:02 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.950715.1346988 (Exim 4.92) (envelope-from ) id 1u4MB4-00018e-D7; Mon, 14 Apr 2025 15:56:54 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 950715.1346988; Mon, 14 Apr 2025 15:56:54 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1u4MB4-00018V-76; Mon, 14 Apr 2025 15:56:54 +0000 Received: by outflank-mailman (input) for mailman id 950715; Mon, 14 Apr 2025 15:56:53 +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 1u4MB3-0008LI-3P for xen-devel@lists.xenproject.org; Mon, 14 Apr 2025 15:56:53 +0000 Received: from mail-ej1-x62c.google.com (mail-ej1-x62c.google.com [2a00:1450:4864:20::62c]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id 1455e5e2-1949-11f0-9ffb-bf95429c2676; Mon, 14 Apr 2025 17:56:51 +0200 (CEST) Received: by mail-ej1-x62c.google.com with SMTP id a640c23a62f3a-ac289147833so904633266b.2 for ; Mon, 14 Apr 2025 08:56:51 -0700 (PDT) Received: from fedora.. (user-109-243-64-225.play-internet.pl. [109.243.64.225]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-acaa1cb4288sm951760866b.96.2025.04.14.08.56.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 14 Apr 2025 08:56:49 -0700 (PDT) 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: 1455e5e2-1949-11f0-9ffb-bf95429c2676 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1744646210; x=1745251010; darn=lists.xenproject.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=TZ8ilnGbjlP1yuQbeojo9A7mCx6DCnxf3o5NdQt6Z4Y=; b=QpF1Q+8KVaS5WatA6PkW/XlgIaLS6R7TqcHNh7MaAtaji1dMMSmz4HWGNCyMfAewWZ 7JCYdR722FGXZSZOiPgZgedIH4cDYliryZo09/20kb8pRdwQRPIRNoLuDHlLNS9NrrZK xJOBtDUCEQZlaoHQi+HgsnQjIRjk8ruW3xHtGMVePZ9Nz9oYKoUOYaZd8dhFUi2TdKu7 UQxCiQ9Q/qHmIITlJcaIT7MuLdvvzlx3yIyS2sUocTTKoOlsPeNtqcmZ11E9jmVBsV61 B5SSozr55om/Tvac43L0Fw7faWZ93nVDieozcZ2u9d2V0EtV44Mv+24qtrFdPRW1nDj7 P3YQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744646210; x=1745251010; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=TZ8ilnGbjlP1yuQbeojo9A7mCx6DCnxf3o5NdQt6Z4Y=; b=s2YW58BmLI0I6MlQ/qIgTVLlPsSNc9C+QEFapBo9cWooC+2TNoDsj0cQ9WtweTWR9U B/u5H2W7Dq8YsKkuqWQrNaYnVDU0WgkRxVGfRKki48aJAIDrlQf/qa1QUY6kIllRJwqv UwH88kivqlqBe5ii+b99ptKytiXCaPC9sDFKRyVYIu0WdWYkdeV00Eb9x5JCQfOhABuq mU28sqt92t1nsu+4FTSAHj994jdQe1e9Quc1MofHegFEjPKX9AQQB5+LjL6DTRHQwVlS ePpKCZiKM9PZMRU3DkrbZbtlGA+bwdMcvKdIImL7n6/Zpdh/rQ7Yv24TYMJdDpYomGg1 +0Hg== X-Gm-Message-State: AOJu0Yw9FgeBMjN3jh0cZQeU0IdxEbDLVbqwgrdqUJTrt2WRs9XjvV06 pqq7Ot3c0pgr/Z4pdL26mGHxU4Wq2zqhz/Mf8bt25fzK9tEyqXxii+Ne3g== X-Gm-Gg: ASbGnctYWZPuMXO8K0/uETpXofEtYVGvA9EzOUvR9natLWDvjjtyBZHHQNg6/uLyxPR T9rqNJfqiyylDVm3JmurWgcjtyxnNZaCGHJldhY4OMrZ6i+BRdwwwdLiSRmH7Fyi4invG2oWo3V y+4Uk1F0795YSVpqlQDKWHGCGT3Y8CqOaJ3VuDMwmkoy5wkzjhZvAj1/TjrJgo+L3ENOyTmqyA0 Xsr8MJWSnwu9V20ETTkTx6sMuOKDxT/EZx5hW1Moa18sGOjcz5dEuHKu7Pd2gbnLQAA5zUtms2q uBYXToZ9xSmGJkOBZYXRcWNaofC6+uHlSJUg1KpHyiWT16V3iJG3vMLmbbnazB+4xh4dCwthxuv vAcOmow0qI6EpqqvOK2uM X-Google-Smtp-Source: AGHT+IG0C0ZurGkiwvr+LZl7qZuXUegCn9ZRSjOc7uzRpnyAXHlFf7rk+YLGhIy5MyPirggeRe76Gw== X-Received: by 2002:a17:907:3d0e:b0:ac4:5fd:6e29 with SMTP id a640c23a62f3a-acad34d8a60mr1232191666b.26.1744646210030; Mon, 14 Apr 2025 08:56:50 -0700 (PDT) From: Oleksii Kurochko To: xen-devel@lists.xenproject.org Cc: Oleksii Kurochko , Stefano Stabellini , Julien Grall , Bertrand Marquis , Michal Orzel , Volodymyr Babchuk , Andrew Cooper , Anthony PERARD , Jan Beulich , =?utf-8?q?Roger_Pau_Monn=C3=A9?= Subject: [PATCH v2 5/8] asm-generic: move some parts of Arm's domain_build.h to common Date: Mon, 14 Apr 2025 17:56:38 +0200 Message-ID: <1c67078147c4a89e46f253f040bef5046fac9ca9.1744626032.git.oleksii.kurochko@gmail.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: References: MIME-Version: 1.0 Nothing changed. Only some functions declaration are moved to xen/include/ headers as they are expected to be used by common code of domain builing or dom0less. Signed-off-by: Oleksii Kurochko --- Chnages in v2: - Add missed declaration of construct_hwdom(). - Drop unnessary blank line. - Introduce xen/fdt-domain-build.h and move parts of Arm's domain_build.h to it. - Update the commit message. --- xen/arch/arm/acpi/domain_build.c | 2 +- xen/arch/arm/dom0less-build.c | 2 +- xen/arch/arm/domain_build.c | 2 +- xen/arch/arm/include/asm/domain_build.h | 18 +--------- xen/arch/arm/kernel.c | 2 +- xen/arch/arm/static-shmem.c | 2 +- xen/include/xen/fdt-domain-build.h | 46 +++++++++++++++++++++++++ 7 files changed, 52 insertions(+), 22 deletions(-) create mode 100644 xen/include/xen/fdt-domain-build.h diff --git a/xen/arch/arm/acpi/domain_build.c b/xen/arch/arm/acpi/domain_build.c index f9ca8b47e5..2b0768b7d5 100644 --- a/xen/arch/arm/acpi/domain_build.c +++ b/xen/arch/arm/acpi/domain_build.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -19,7 +20,6 @@ #include #include #include -#include /* Override macros from asm/page.h to make them work with mfn_t */ #undef virt_to_mfn diff --git a/xen/arch/arm/dom0less-build.c b/xen/arch/arm/dom0less-build.c index 122739061c..ca78cff655 100644 --- a/xen/arch/arm/dom0less-build.c +++ b/xen/arch/arm/dom0less-build.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ #include #include +#include #include #include #include @@ -17,7 +18,6 @@ #include #include -#include #include #include #include diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index a19914f836..75f048f58c 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ #include #include +#include #include #include #include @@ -30,7 +31,6 @@ #include #include #include -#include #include #include diff --git a/xen/arch/arm/include/asm/domain_build.h b/xen/arch/arm/include/asm/domain_build.h index 7136857ce4..5f9b063be1 100644 --- a/xen/arch/arm/include/asm/domain_build.h +++ b/xen/arch/arm/include/asm/domain_build.h @@ -5,27 +5,11 @@ #include typedef __be32 gic_interrupt_t[3]; -typedef bool (*alloc_domheap_mem_cb)(struct domain *d, struct page_info *pg, - unsigned int order, void *extra); -bool allocate_domheap_memory(struct domain *d, paddr_t tot_size, - alloc_domheap_mem_cb cb, void *extra); -bool allocate_bank_memory(struct kernel_info *kinfo, gfn_t sgfn, - paddr_t tot_size); -void allocate_memory(struct domain *d, struct kernel_info *kinfo); -int construct_domain(struct domain *d, struct kernel_info *kinfo); -int construct_hwdom(struct kernel_info *kinfo); int domain_fdt_begin_node(void *fdt, const char *name, uint64_t unit); -int make_chosen_node(const struct kernel_info *kinfo); -int make_cpus_node(const struct domain *d, void *fdt); -int make_hypervisor_node(struct domain *d, const struct kernel_info *kinfo, - int addrcells, int sizecells); -int make_memory_node(const struct kernel_info *kinfo, int addrcells, - int sizecells, const struct membanks *mem); int make_psci_node(void *fdt); -int make_timer_node(const struct kernel_info *kinfo); void evtchn_allocate(struct domain *d); -unsigned int get_allocation_size(paddr_t size); +int construct_hwdom(struct kernel_info *kinfo); /* * Helper to write an interrupts with the GIC format diff --git a/xen/arch/arm/kernel.c b/xen/arch/arm/kernel.c index 5482cf4239..164f417e75 100644 --- a/xen/arch/arm/kernel.c +++ b/xen/arch/arm/kernel.c @@ -6,6 +6,7 @@ */ #include #include +#include #include #include #include @@ -17,7 +18,6 @@ #include #include -#include #include #define UIMAGE_MAGIC 0x27051956 diff --git a/xen/arch/arm/static-shmem.c b/xen/arch/arm/static-shmem.c index 14ae48fb1e..07ebd8b41f 100644 --- a/xen/arch/arm/static-shmem.c +++ b/xen/arch/arm/static-shmem.c @@ -1,11 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0-only */ #include +#include #include #include #include -#include #include #include #include diff --git a/xen/include/xen/fdt-domain-build.h b/xen/include/xen/fdt-domain-build.h new file mode 100644 index 0000000000..41454e75ca --- /dev/null +++ b/xen/include/xen/fdt-domain-build.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __XEN_FDT_DOMAIN_BUILD_H__ +#define __XEN_FDT_DOMAIN_BUILD_H__ + +#include +#include +#include +#include + +#if __has_include() +# include +#endif + +struct domain; +struct page_info; +struct membanks; + +typedef bool (*alloc_domheap_mem_cb)(struct domain *d, struct page_info *pg, + unsigned int order, void *extra); +bool allocate_domheap_memory(struct domain *d, paddr_t tot_size, + alloc_domheap_mem_cb cb, void *extra); + +bool allocate_bank_memory(struct kernel_info *kinfo, gfn_t sgfn, + paddr_t tot_size); +void allocate_memory(struct domain *d, struct kernel_info *kinfo); +int construct_domain(struct domain *d, struct kernel_info *kinfo); +int make_chosen_node(const struct kernel_info *kinfo); +int make_cpus_node(const struct domain *d, void *fdt); +int make_hypervisor_node(struct domain *d, const struct kernel_info *kinfo, + int addrcells, int sizecells); +int make_memory_node(const struct kernel_info *kinfo, int addrcells, + int sizecells, const struct membanks *mem); +int make_timer_node(const struct kernel_info *kinfo); + +unsigned int get_allocation_size(paddr_t size); + +#endif /* __XEN_FDT_DOMAIN_BUILD_H__ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ From patchwork Mon Apr 14 15:56:39 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleksii Kurochko X-Patchwork-Id: 14050660 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 10306C369A2 for ; Mon, 14 Apr 2025 15:57:04 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.950716.1346991 (Exim 4.92) (envelope-from ) id 1u4MB4-0001Bd-L1; Mon, 14 Apr 2025 15:56:54 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 950716.1346991; Mon, 14 Apr 2025 15:56:54 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1u4MB4-0001AM-G8; Mon, 14 Apr 2025 15:56:54 +0000 Received: by outflank-mailman (input) for mailman id 950716; Mon, 14 Apr 2025 15:56:53 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1u4MB3-0008KQ-4Q for xen-devel@lists.xenproject.org; Mon, 14 Apr 2025 15:56:53 +0000 Received: from mail-ed1-x536.google.com (mail-ed1-x536.google.com [2a00:1450:4864:20::536]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id 14c5f803-1949-11f0-9eae-5ba50f476ded; Mon, 14 Apr 2025 17:56:52 +0200 (CEST) Received: by mail-ed1-x536.google.com with SMTP id 4fb4d7f45d1cf-5e6c18e2c7dso8470894a12.3 for ; Mon, 14 Apr 2025 08:56:52 -0700 (PDT) Received: from fedora.. (user-109-243-64-225.play-internet.pl. [109.243.64.225]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-acaa1cb4288sm951760866b.96.2025.04.14.08.56.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 14 Apr 2025 08:56:50 -0700 (PDT) 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: 14c5f803-1949-11f0-9eae-5ba50f476ded DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1744646211; x=1745251011; darn=lists.xenproject.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=8ZZ/u0hxjggT9kUQsInM8UwdJHGGhdTplVjxpUlrRZk=; b=QHaZhUwjCxxz3GyKnxMKs8NUkScPzUNNFQDJSvVszHDW99aDzlSVGQccG1Zr+2ZdI/ A+UOixBhmkdIGLcfGU3o671Y7pTVCzUOdS5g38AI2BXo7+DCyuGhytnUCua/pQa6suxs XQiRMYzbjf+YpktwvOjruya2QWKTRAWGAmkIm8IdvA5c5mP743wYdH5Wy5YQnZh8X/TZ WPYodScLcOjmnRfBKrGfjvvGRlxW+IBlVmTt+f6MAFyclqUBoPgYn43nQ+hLj500k9TX fuIMMBDn5EqFZ+eS182GsaTLkfNa0r0y28TL/ZTNBBLR7UXslUo65eXiOxSFdeU5jdjg fbIg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744646211; x=1745251011; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=8ZZ/u0hxjggT9kUQsInM8UwdJHGGhdTplVjxpUlrRZk=; b=kKqGMCgMzVYTS9acDZJNnXbHHBl7IDSwF0RXoO6vMGXe13EGGc3MZdsigIPpCHanXJ XDT7pVD1UBf50yJuZPZYgY9pi6gci7XIZxT4lcTmAxL48/Ljn116UJt8/d0k7z7zFGxg +pa5Y/Tm0axBjywz+bXfwMiBYug5USZD2h866mTnb8mdc0IAfA8OMojKKU2s33iZUe4e /76vNIvgfjQHIZfahFhY7G4jlQztE06bw0OZI0/wf+LIigHLOxCSZV++DK32hKMLkxn8 bfkA+VdjfR4QXZhYpzhU+uRPwPQAPI1z3QIhZbWtmUC2SsWE2srD10Px3JDyzM2wVuQQ PDDA== X-Gm-Message-State: AOJu0Yxo+OWSM9wxS7+RrtwZQWpYSPVVSNOaDvMF8f+VVnF/QdsFvIaD ICG7d20zPaX+jQvPpkqArQn3nWQdrzcfx6EGw+ZJireKwge6nzcnECeu4w== X-Gm-Gg: ASbGncvUgcJ1jClhBA6KFGT5+nyDNv/gnNfPLazkZN61lNeWhrA4yYzNjczAsy7dHdl AMGnrKYUvnwBKKGGopBu6vvDHvS/E3eqvVKLbpipX5I7GOeLB1lByuz/2h1X1MEK9YZN3efu+tg I90H+5UOtPJ5exwJAGaoiJLKTe6vM56CzxMszt6UDBFcz2yuy9lSzZ0hhCfobblyl4IYNZ2iez7 SKWO+O6QuPcNdjvyBfyCFzrz/lYE6dElHwZhU8HrhGoNyEtbP/maFXK/WMs0Lx+HsARR869t4Yv Anqmn45XiObtk4a3U5Hc6dQD96jlI0oPeO+QXtYPBIYtVygwrDTowaVqkizRtK7UoMHQpY81Gi4 Vthk7gNlIHg== X-Google-Smtp-Source: AGHT+IEeNfVxBgh4tiqFXnMpNZk7El2K59Ap6eo71j00Ua28M7HCHIXAxo/7YFQ1dSrQkC+kkdkEzw== X-Received: by 2002:a17:907:fd0e:b0:aca:de15:f2ad with SMTP id a640c23a62f3a-acade15fc19mr899424566b.60.1744646211037; Mon, 14 Apr 2025 08:56:51 -0700 (PDT) From: Oleksii Kurochko To: xen-devel@lists.xenproject.org Cc: Oleksii Kurochko , Stefano Stabellini , Julien Grall , Bertrand Marquis , Michal Orzel , Volodymyr Babchuk , Andrew Cooper , Anthony PERARD , Jan Beulich , =?utf-8?q?Roger_Pau_Monn=C3=A9?= Subject: [PATCH v2 6/8] xen/common: dom0less: introduce common kernel.c Date: Mon, 14 Apr 2025 17:56:39 +0200 Message-ID: X-Mailer: git-send-email 2.49.0 In-Reply-To: References: MIME-Version: 1.0 The following functions don't have arch specific things so it is moved to common: - kernel_prboe() - kernel_load() - output_length() Functions necessary for dom0less are only moved. The following changes are done: - Swap __init and return type of kernel_decompress() function to be consistent with defintions of functions in other files. The same for output_length(). - Wrap by "ifdef CONFIG_ARM" the call of kernel_uimage_probe() in kernel_probe() as uImage isn't really used nowadays thereby leave kernel_uimage_probe() call here just for compatability with Arm code. - Introduce kernel_zimage_probe() to cover the case that arch can have different zimage header. - Add ASSERT() for kernel_load() to check that it argument isn't NULL. - Make kernel_uimage_probe() non-static in Arm's code as it is used in common/kernel.c. Introduce CONFIG_DOMAIN_BUILD_HELPERS to not provide stubs for archs which don't provide enough functionality to enable it. Select CONFIG_DOMAIN_BUILD_HELPERS for CONFIG_ARM as only Arm supports it, at the moment. Signed-off-by: Oleksii Kurochko --- Change in v2: - Drop inclusion of asm/kernel.h in kernel.c as everything necessary has been moved to xen/fdt-kernel.h. --- xen/arch/arm/Kconfig | 1 + xen/arch/arm/kernel.c | 221 +---------------------------- xen/common/Kconfig | 9 +- xen/common/device-tree/Makefile | 1 + xen/common/device-tree/kernel.c | 242 ++++++++++++++++++++++++++++++++ xen/include/xen/fdt-kernel.h | 13 ++ 6 files changed, 271 insertions(+), 216 deletions(-) create mode 100644 xen/common/device-tree/kernel.c diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig index 060389c3c8..d63c0dc669 100644 --- a/xen/arch/arm/Kconfig +++ b/xen/arch/arm/Kconfig @@ -11,6 +11,7 @@ config ARM_64 config ARM def_bool y + select DOMAIN_BUILD_HELPERS select FUNCTION_ALIGNMENT_4B select GENERIC_UART_INIT select HAS_ALTERNATIVE if HAS_VMAP diff --git a/xen/arch/arm/kernel.c b/xen/arch/arm/kernel.c index 164f417e75..1a5ae4b95c 100644 --- a/xen/arch/arm/kernel.c +++ b/xen/arch/arm/kernel.c @@ -161,105 +161,6 @@ static void __init kernel_zimage_load(struct kernel_info *info) iounmap(kernel); } -static __init uint32_t output_length(char *image, unsigned long image_len) -{ - return *(uint32_t *)&image[image_len - 4]; -} - -static __init int kernel_decompress(struct bootmodule *mod, uint32_t offset) -{ - char *output, *input; - char magic[2]; - int rc; - unsigned int kernel_order_out; - paddr_t output_size; - struct page_info *pages; - mfn_t mfn; - int i; - paddr_t addr = mod->start; - paddr_t size = mod->size; - - if ( size < offset ) - return -EINVAL; - - /* - * It might be that gzip header does not appear at the start address - * (e.g. in case of compressed uImage) so take into account offset to - * gzip header. - */ - addr += offset; - size -= offset; - - if ( size < 2 ) - return -EINVAL; - - copy_from_paddr(magic, addr, sizeof(magic)); - - /* only gzip is supported */ - if ( !gzip_check(magic, size) ) - return -EINVAL; - - input = ioremap_cache(addr, size); - if ( input == NULL ) - return -EFAULT; - - output_size = output_length(input, size); - kernel_order_out = get_order_from_bytes(output_size); - pages = alloc_domheap_pages(NULL, kernel_order_out, 0); - if ( pages == NULL ) - { - iounmap(input); - return -ENOMEM; - } - mfn = page_to_mfn(pages); - output = vmap_contig(mfn, 1 << kernel_order_out); - - rc = perform_gunzip(output, input, size); - clean_dcache_va_range(output, output_size); - iounmap(input); - vunmap(output); - - if ( rc ) - { - free_domheap_pages(pages, kernel_order_out); - return rc; - } - - mod->start = page_to_maddr(pages); - mod->size = output_size; - - /* - * Need to free pages after output_size here because they won't be - * freed by discard_initial_modules - */ - i = PFN_UP(output_size); - for ( ; i < (1 << kernel_order_out); i++ ) - free_domheap_page(pages + i); - - /* - * When using static heap feature, don't give bootmodules memory back to - * the heap allocator - */ - if ( using_static_heap ) - return 0; - - /* - * When freeing the kernel, we need to pass the module start address and - * size as they were before taking an offset to gzip header into account, - * so that the entire region will be freed. - */ - addr -= offset; - size += offset; - - /* - * Free the original kernel, update the pointers to the - * decompressed kernel - */ - fw_unreserved_regions(addr, addr + size, init_domheap_pages, 0); - - return 0; -} - /* * Uimage CPU Architecture Codes */ @@ -272,8 +173,8 @@ static __init int kernel_decompress(struct bootmodule *mod, uint32_t offset) /* * Check if the image is a uImage and setup kernel_info */ -static int __init kernel_uimage_probe(struct kernel_info *info, - struct bootmodule *mod) +int __init kernel_uimage_probe(struct kernel_info *info, + struct bootmodule *mod) { struct { __be32 magic; /* Image Header Magic Number */ @@ -503,130 +404,20 @@ static int __init kernel_zimage32_probe(struct kernel_info *info, return 0; } -int __init kernel_probe(struct kernel_info *info, - const struct dt_device_node *domain) +int __init kernel_zimage_probe(struct kernel_info *info, paddr_t addr, + paddr_t size) { - struct bootmodule *mod = NULL; - struct bootcmdline *cmd = NULL; - struct dt_device_node *node; - u64 kernel_addr, initrd_addr, dtb_addr, size; int rc; - /* - * We need to initialize start to 0. This field may be populated during - * kernel_xxx_probe() if the image has a fixed entry point (for e.g. - * uimage.ep). - * We will use this to determine if the image has a fixed entry point or - * the load address should be used as the start address. - */ - info->entry = 0; - - /* domain is NULL only for the hardware domain */ - if ( domain == NULL ) - { - ASSERT(is_hardware_domain(info->d)); - - mod = boot_module_find_by_kind(BOOTMOD_KERNEL); - - info->kernel_bootmodule = mod; - info->initrd_bootmodule = boot_module_find_by_kind(BOOTMOD_RAMDISK); - - cmd = boot_cmdline_find_by_kind(BOOTMOD_KERNEL); - if ( cmd ) - info->cmdline = &cmd->cmdline[0]; - } - else - { - const char *name = NULL; - - dt_for_each_child_node(domain, node) - { - if ( dt_device_is_compatible(node, "multiboot,kernel") ) - { - u32 len; - const __be32 *val; - - val = dt_get_property(node, "reg", &len); - dt_get_range(&val, node, &kernel_addr, &size); - mod = boot_module_find_by_addr_and_kind( - BOOTMOD_KERNEL, kernel_addr); - info->kernel_bootmodule = mod; - } - else if ( dt_device_is_compatible(node, "multiboot,ramdisk") ) - { - u32 len; - const __be32 *val; - - val = dt_get_property(node, "reg", &len); - dt_get_range(&val, node, &initrd_addr, &size); - info->initrd_bootmodule = boot_module_find_by_addr_and_kind( - BOOTMOD_RAMDISK, initrd_addr); - } - else if ( dt_device_is_compatible(node, "multiboot,device-tree") ) - { - uint32_t len; - const __be32 *val; - - val = dt_get_property(node, "reg", &len); - if ( val == NULL ) - continue; - dt_get_range(&val, node, &dtb_addr, &size); - info->dtb_bootmodule = boot_module_find_by_addr_and_kind( - BOOTMOD_GUEST_DTB, dtb_addr); - } - else - continue; - } - name = dt_node_name(domain); - cmd = boot_cmdline_find_by_name(name); - if ( cmd ) - info->cmdline = &cmd->cmdline[0]; - } - if ( !mod || !mod->size ) - { - printk(XENLOG_ERR "Missing kernel boot module?\n"); - return -ENOENT; - } - - printk("Loading %pd kernel from boot module @ %"PRIpaddr"\n", - info->d, info->kernel_bootmodule->start); - if ( info->initrd_bootmodule ) - printk("Loading ramdisk from boot module @ %"PRIpaddr"\n", - info->initrd_bootmodule->start); - - /* - * uImage header always appears at the top of the image (even compressed), - * so it needs to be probed first. Note that in case of compressed uImage, - * kernel_decompress is called from kernel_uimage_probe making the function - * self-containing (i.e. fall through only in case of a header not found). - */ - rc = kernel_uimage_probe(info, mod); - if ( rc != -ENOENT ) - return rc; - - /* - * If it is a gzip'ed image, 32bit or 64bit, uncompress it. - * At this point, gzip header appears (if at all) at the top of the image, - * so pass 0 as an offset. - */ - rc = kernel_decompress(mod, 0); - if ( rc && rc != -EINVAL ) - return rc; - #ifdef CONFIG_ARM_64 - rc = kernel_zimage64_probe(info, mod->start, mod->size); + rc = kernel_zimage64_probe(info, addr, size); if (rc < 0) #endif - rc = kernel_zimage32_probe(info, mod->start, mod->size); + rc = kernel_zimage32_probe(info, addr, size); return rc; } -void __init kernel_load(struct kernel_info *info) -{ - info->load(info); -} - /* * Local variables: * mode: C diff --git a/xen/common/Kconfig b/xen/common/Kconfig index 2fd79aea5b..b2f915c429 100644 --- a/xen/common/Kconfig +++ b/xen/common/Kconfig @@ -14,13 +14,20 @@ config CORE_PARKING config DOM0LESS_BOOT bool "Dom0less boot support" if EXPERT - depends on HAS_DOM0LESS + depends on HAS_DOM0LESS && DOMAIN_BUILD_HELPERS default y help Dom0less boot support enables Xen to create and start domU guests during Xen boot without the need of a control domain (Dom0), which could be present anyway. +config DOMAIN_BUILD_HELPERS + bool + help + Introduce functions necessary for working with domain creation, kernel, + etc. As an examples, these type of functions are going to be used by + CONFIG_DOM0LESS_BOOT. + config GRANT_TABLE bool "Grant table support" if EXPERT default y diff --git a/xen/common/device-tree/Makefile b/xen/common/device-tree/Makefile index f3dafc9b81..e88a4d5799 100644 --- a/xen/common/device-tree/Makefile +++ b/xen/common/device-tree/Makefile @@ -4,3 +4,4 @@ obj-y += device-tree.o obj-$(CONFIG_DOM0LESS_BOOT) += dom0less-build.o obj-$(CONFIG_OVERLAY_DTB) += dt-overlay.o obj-y += intc.o +obj-$(CONFIG_DOMAIN_BUILD_HELPERS) += kernel.o diff --git a/xen/common/device-tree/kernel.c b/xen/common/device-tree/kernel.c new file mode 100644 index 0000000000..1bf3bbf64e --- /dev/null +++ b/xen/common/device-tree/kernel.c @@ -0,0 +1,242 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static uint32_t __init output_length(char *image, unsigned long image_len) +{ + return *(uint32_t *)&image[image_len - 4]; +} + +int __init kernel_decompress(struct bootmodule *mod, uint32_t offset) +{ + char *output, *input; + char magic[2]; + int rc; + unsigned int kernel_order_out; + paddr_t output_size; + struct page_info *pages; + mfn_t mfn; + int i; + paddr_t addr = mod->start; + paddr_t size = mod->size; + + if ( size < offset ) + return -EINVAL; + + /* + * It might be that gzip header does not appear at the start address + * (e.g. in case of compressed uImage) so take into account offset to + * gzip header. + */ + addr += offset; + size -= offset; + + if ( size < 2 ) + return -EINVAL; + + copy_from_paddr(magic, addr, sizeof(magic)); + + /* only gzip is supported */ + if ( !gzip_check(magic, size) ) + return -EINVAL; + + input = ioremap_cache(addr, size); + if ( input == NULL ) + return -EFAULT; + + output_size = output_length(input, size); + kernel_order_out = get_order_from_bytes(output_size); + pages = alloc_domheap_pages(NULL, kernel_order_out, 0); + if ( pages == NULL ) + { + iounmap(input); + return -ENOMEM; + } + mfn = page_to_mfn(pages); + output = vmap_contig(mfn, 1 << kernel_order_out); + + rc = perform_gunzip(output, input, size); + clean_dcache_va_range(output, output_size); + iounmap(input); + vunmap(output); + + if ( rc ) + { + free_domheap_pages(pages, kernel_order_out); + return rc; + } + + mod->start = page_to_maddr(pages); + mod->size = output_size; + + /* + * Need to free pages after output_size here because they won't be + * freed by discard_initial_modules + */ + i = PFN_UP(output_size); + for ( ; i < (1 << kernel_order_out); i++ ) + free_domheap_page(pages + i); + + /* + * When using static heap feature, don't give bootmodules memory back to + * the heap allocator + */ + if ( using_static_heap ) + return 0; + + /* + * When freeing the kernel, we need to pass the module start address and + * size as they were before taking an offset to gzip header into account, + * so that the entire region will be freed. + */ + addr -= offset; + size += offset; + + /* + * Free the original kernel, update the pointers to the + * decompressed kernel + */ + fw_unreserved_regions(addr, addr + size, init_domheap_pages, 0); + + return 0; +} + +int __init kernel_probe(struct kernel_info *info, + const struct dt_device_node *domain) +{ + struct bootmodule *mod = NULL; + struct bootcmdline *cmd = NULL; + struct dt_device_node *node; + u64 kernel_addr, initrd_addr, dtb_addr, size; + int rc; + + /* + * We need to initialize start to 0. This field may be populated during + * kernel_xxx_probe() if the image has a fixed entry point (for e.g. + * uimage.ep). + * We will use this to determine if the image has a fixed entry point or + * the load address should be used as the start address. + */ + info->entry = 0; + + /* domain is NULL only for the hardware domain */ + if ( domain == NULL ) + { + ASSERT(is_hardware_domain(info->d)); + + mod = boot_module_find_by_kind(BOOTMOD_KERNEL); + + info->kernel_bootmodule = mod; + info->initrd_bootmodule = boot_module_find_by_kind(BOOTMOD_RAMDISK); + + cmd = boot_cmdline_find_by_kind(BOOTMOD_KERNEL); + if ( cmd ) + info->cmdline = &cmd->cmdline[0]; + } + else + { + const char *name = NULL; + + dt_for_each_child_node(domain, node) + { + if ( dt_device_is_compatible(node, "multiboot,kernel") ) + { + u32 len; + const __be32 *val; + + val = dt_get_property(node, "reg", &len); + dt_get_range(&val, node, &kernel_addr, &size); + mod = boot_module_find_by_addr_and_kind( + BOOTMOD_KERNEL, kernel_addr); + info->kernel_bootmodule = mod; + } + else if ( dt_device_is_compatible(node, "multiboot,ramdisk") ) + { + u32 len; + const __be32 *val; + + val = dt_get_property(node, "reg", &len); + dt_get_range(&val, node, &initrd_addr, &size); + info->initrd_bootmodule = boot_module_find_by_addr_and_kind( + BOOTMOD_RAMDISK, initrd_addr); + } + else if ( dt_device_is_compatible(node, "multiboot,device-tree") ) + { + uint32_t len; + const __be32 *val; + + val = dt_get_property(node, "reg", &len); + if ( val == NULL ) + continue; + dt_get_range(&val, node, &dtb_addr, &size); + info->dtb_bootmodule = boot_module_find_by_addr_and_kind( + BOOTMOD_GUEST_DTB, dtb_addr); + } + else + continue; + } + name = dt_node_name(domain); + cmd = boot_cmdline_find_by_name(name); + if ( cmd ) + info->cmdline = &cmd->cmdline[0]; + } + if ( !mod || !mod->size ) + { + printk(XENLOG_ERR "Missing kernel boot module?\n"); + return -ENOENT; + } + + printk("Loading %pd kernel from boot module @ %"PRIpaddr"\n", + info->d, info->kernel_bootmodule->start); + if ( info->initrd_bootmodule ) + printk("Loading ramdisk from boot module @ %"PRIpaddr"\n", + info->initrd_bootmodule->start); + + /* + * uImage isn't really used nowadays thereby leave kernel_uimage_probe() + * call here just for compatability with Arm code. + */ +#ifdef CONFIG_ARM + /* + * uImage header always appears at the top of the image (even compressed), + * so it needs to be probed first. Note that in case of compressed uImage, + * kernel_decompress is called from kernel_uimage_probe making the function + * self-containing (i.e. fall through only in case of a header not found). + */ + rc = kernel_uimage_probe(info, mod); + if ( rc != -ENOENT ) + return rc; +#endif + + /* + * If it is a gzip'ed image, 32bit or 64bit, uncompress it. + * At this point, gzip header appears (if at all) at the top of the image, + * so pass 0 as an offset. + */ + rc = kernel_decompress(mod, 0); + if ( rc && rc != -EINVAL ) + return rc; + + rc = kernel_zimage_probe(info, mod->start, mod->size); + + return rc; +} + +void __init kernel_load(struct kernel_info *info) +{ + ASSERT(info && info->load); + + info->load(info); +} diff --git a/xen/include/xen/fdt-kernel.h b/xen/include/xen/fdt-kernel.h index c81e759423..d85324c867 100644 --- a/xen/include/xen/fdt-kernel.h +++ b/xen/include/xen/fdt-kernel.h @@ -121,6 +121,19 @@ int kernel_probe(struct kernel_info *info, const struct dt_device_node *domain); */ void kernel_load(struct kernel_info *info); +int kernel_decompress(struct bootmodule *mod, uint32_t offset); + +int kernel_zimage_probe(struct kernel_info *info, paddr_t addr, paddr_t size); + +/* + * uImage isn't really used nowadays thereby leave kernel_uimage_probe() + * call here just for compatability with Arm code. + */ +#ifdef CONFIG_ARM +struct bootmodule; +int kernel_uimage_probe(struct kernel_info *info, struct bootmodule *mod); +#endif + #endif /* __XEN_FDT_KERNEL_H__ */ /* From patchwork Mon Apr 14 15:56:40 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleksii Kurochko X-Patchwork-Id: 14050661 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id A114FC369BC for ; Mon, 14 Apr 2025 15:57:05 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.950717.1347007 (Exim 4.92) (envelope-from ) id 1u4MB7-0001h5-6g; Mon, 14 Apr 2025 15:56:57 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 950717.1347007; Mon, 14 Apr 2025 15:56:57 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1u4MB7-0001gr-2Q; Mon, 14 Apr 2025 15:56:57 +0000 Received: by outflank-mailman (input) for mailman id 950717; Mon, 14 Apr 2025 15:56:55 +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 1u4MB5-0008LI-Mv for xen-devel@lists.xenproject.org; Mon, 14 Apr 2025 15:56:55 +0000 Received: from mail-ej1-x62a.google.com (mail-ej1-x62a.google.com [2a00:1450:4864:20::62a]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id 159654b7-1949-11f0-9ffb-bf95429c2676; Mon, 14 Apr 2025 17:56:53 +0200 (CEST) Received: by mail-ej1-x62a.google.com with SMTP id a640c23a62f3a-ac298c8fa50so726759766b.1 for ; Mon, 14 Apr 2025 08:56:53 -0700 (PDT) Received: from fedora.. (user-109-243-64-225.play-internet.pl. [109.243.64.225]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-acaa1cb4288sm951760866b.96.2025.04.14.08.56.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 14 Apr 2025 08:56:51 -0700 (PDT) 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: 159654b7-1949-11f0-9ffb-bf95429c2676 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1744646212; x=1745251012; darn=lists.xenproject.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=ACPMjXk9mJ90kJc+Qerlr9VRihJ7jzc3C4qF/ym8lGA=; b=ZDcLvQi51+oNWUGqKFUxk84BS3lpt79kTyeDZTsgP/eZYZwKC9NakAYbVy1WKHgyjo Vqs9RdnZVLsLwZ+NdqieRo5+13NIaIODcsASK+HYl4VSQ/4/YLh37OBVBqkAFl0XgaO1 5qyeKe54otU+lIIAbQNuzFSrXCj0JW54qLSt7YR4n8A7lPklKusdfFblrtL8cxuvgTbb DVKVTl0TEz+NP3EzKoTBYKTvIBjDh3CQXo7p0JHA5N2IQtWCUFwBKaD/vaGfixfqP8lp aGvP/QcQCU3sH4rhjU5mMb09PPNwJi8zPyo/H4kXOBpJSNuISsrXk7oi6Ql/hDk3ZvB9 c/8g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744646212; x=1745251012; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ACPMjXk9mJ90kJc+Qerlr9VRihJ7jzc3C4qF/ym8lGA=; b=MJLprTmFgLt2F6FS6/ADr+Ug/9akhKYXw+enmBplx5QCYtMkl+q9iC+QjLdCabyzGi BIb3FUTpHT4e/skhemVjwKvcv6pNxNpdWk1Tpj95fmsLwfOkcT8n9Ym8xe/lD4dlq1hl mIIRNeqVH8bc0BJyGxAcmKQnqnzW/zLynSoaeBf85yobLCuTw6yr8W2tHQkKUTMf60j/ mmgWVAdBFlVBXrdtBWe1TFFP3Gr6qZcllBkHvan/Vl49AY3Gp47Gf4aCUuAnUqck4Pea tmVQp65oafSnV68O04yBAW3JoqieBCs97K2da12DW6tWa2JVtJF4asEiPx9I+8ikaJbJ xlDw== X-Gm-Message-State: AOJu0YwYDx3wqrvtYt7cdYZhFarIJ68XZ7EN7KtQeVY89V1MlVbYUGYc iRV1RCmTItJGoDVTREqJNsGeIJCFqslBUCo4+bRsXyT0XVzj7Ztv75XcUA== X-Gm-Gg: ASbGncvOK39ClHER4S0Cp+t9dLAG0r2XF1ibwVqEfnVKvbMfB1AT6viYC5+BrW2arif cH0oRzU5h9yPqM3lYCCnlHqUagGlruJ93Jk4VzmMZzklfiedfJJrc7L92TBeQubwxGxx+E2JdJc p/TNBLKhWJdmAzDu8iPqrBs9pv4bs7gmf0bGNBK+On1JCGIJeWaXtTs2+oXGwHEfuEDJUS0hjc+ B0KyMrwUfg7twvfE+J0sDaCcjgavL3e6cMq3GRrcPddDZSpLA5HyIL1s+Ek8TI9NcO/vuAqLXNb hIsbBcqABEhdU3BXadkYY5GkOIgI9+2ZJvmUClu9yG+DVD1512izZZefbD2UKNyd4jK8+bIjtiu t24Q8C04lXA== X-Google-Smtp-Source: AGHT+IF3SjysRv98H53A6BxgnPvW1cPNx51aBxIe/73BMU9A3UizkVh7JtB2ITkhTVvrKw0+c17kzQ== X-Received: by 2002:a17:906:cec5:b0:aca:d63b:3ebe with SMTP id a640c23a62f3a-acad63b4519mr961042466b.21.1744646212270; Mon, 14 Apr 2025 08:56:52 -0700 (PDT) From: Oleksii Kurochko To: xen-devel@lists.xenproject.org Cc: Oleksii Kurochko , Stefano Stabellini , Julien Grall , Bertrand Marquis , Michal Orzel , Volodymyr Babchuk , Andrew Cooper , Anthony PERARD , Jan Beulich , =?utf-8?q?Roger_Pau_Monn=C3=A9?= Subject: [PATCH v2 7/8] xen/common: dom0less: introduce common domain-build.c Date: Mon, 14 Apr 2025 17:56:40 +0200 Message-ID: <9dbf651ce177a7292f80879373e86a51305f216e.1744626032.git.oleksii.kurochko@gmail.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: References: MIME-Version: 1.0 Some functions of Arm's domain_build.c could be reused by dom0less or other features connected to domain construction/build. The following functions are moved to common: - get_allocation_size(). - allocate_domheap_memory(). - guest_map_pages(). - allocate_bank_memory(). - add_hwdom_free_regions(). - find_unallocated_memory(). - allocate_memory(). - dtb_load(). - initrd_load(). Prototype of dtb_load() and initrd_load() is updated to recieve a pointer to copy_to_guest_phys() as some archs require copy_to_guest_phys_fluch_dcache(). Update arm/include/asm/Makefile to generate domain-build.h for Arm as it is used by domain-build.c. Signed-off-by: Oleksii Kurochko --- Change in v2: - Use xen/fdt-domain-build.h instead of asm/domain_build.h. --- xen/arch/arm/domain_build.c | 397 +------------------------ xen/common/device-tree/Makefile | 1 + xen/common/device-tree/domain-build.c | 404 ++++++++++++++++++++++++++ xen/include/xen/fdt-domain-build.h | 33 ++- 4 files changed, 439 insertions(+), 396 deletions(-) create mode 100644 xen/common/device-tree/domain-build.c diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index 75f048f58c..86fcaefa26 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -119,18 +119,6 @@ struct vcpu *__init alloc_dom0_vcpu0(struct domain *dom0) return vcpu_create(dom0, 0); } -unsigned int __init get_allocation_size(paddr_t size) -{ - /* - * get_order_from_bytes returns the order greater than or equal to - * the given size, but we need less than or equal. Adding one to - * the size pushes an evenly aligned size into the next order, so - * we can then unconditionally subtract 1 from the order which is - * returned. - */ - return get_order_from_bytes(size + 1) - 1; -} - /* * Insert the given pages into a memory bank, banks are ordered by address. * @@ -417,98 +405,6 @@ static void __init allocate_memory_11(struct domain *d, } } -bool __init allocate_domheap_memory(struct domain *d, paddr_t tot_size, - alloc_domheap_mem_cb cb, void *extra) -{ - unsigned int max_order = UINT_MAX; - - while ( tot_size > 0 ) - { - unsigned int order = get_allocation_size(tot_size); - struct page_info *pg; - - order = min(max_order, order); - - pg = alloc_domheap_pages(d, order, 0); - if ( !pg ) - { - /* - * If we can't allocate one page, then it is unlikely to - * succeed in the next iteration. So bail out. - */ - if ( !order ) - return false; - - /* - * If we can't allocate memory with order, then it is - * unlikely to succeed in the next iteration. - * Record the order - 1 to avoid re-trying. - */ - max_order = order - 1; - continue; - } - - if ( !cb(d, pg, order, extra) ) - return false; - - tot_size -= (1ULL << (PAGE_SHIFT + order)); - } - - return true; -} - -static bool __init guest_map_pages(struct domain *d, struct page_info *pg, - unsigned int order, void *extra) -{ - gfn_t *sgfn = (gfn_t *)extra; - int res; - - BUG_ON(!sgfn); - res = guest_physmap_add_page(d, *sgfn, page_to_mfn(pg), order); - if ( res ) - { - dprintk(XENLOG_ERR, "Failed map pages to DOMU: %d", res); - return false; - } - - *sgfn = gfn_add(*sgfn, 1UL << order); - - return true; -} - -bool __init allocate_bank_memory(struct kernel_info *kinfo, gfn_t sgfn, - paddr_t tot_size) -{ - struct membanks *mem = kernel_info_get_mem(kinfo); - struct domain *d = kinfo->d; - struct membank *bank; - - /* - * allocate_bank_memory can be called with a tot_size of zero for - * the second memory bank. It is not an error and we can safely - * avoid creating a zero-size memory bank. - */ - if ( tot_size == 0 ) - return true; - - bank = &mem->bank[mem->nr_banks]; - bank->start = gfn_to_gaddr(sgfn); - bank->size = tot_size; - - /* - * Allocate pages from the heap until tot_size is zero and map them to the - * guest using guest_map_pages, passing the starting gfn as extra parameter - * for the map operation. - */ - if ( !allocate_domheap_memory(d, tot_size, guest_map_pages, &sgfn) ) - return false; - - mem->nr_banks++; - kinfo->unassigned_mem -= bank->size; - - return true; -} - /* * When PCI passthrough is available we want to keep the * "linux,pci-domain" in sync for every host bridge. @@ -899,226 +795,6 @@ int __init add_ext_regions(unsigned long s_gfn, unsigned long e_gfn, return 0; } -static int __init add_hwdom_free_regions(unsigned long s_gfn, - unsigned long e_gfn, void *data) -{ - struct membanks *free_regions = data; - paddr_t start, size; - paddr_t s = pfn_to_paddr(s_gfn); - paddr_t e = pfn_to_paddr(e_gfn); - unsigned int i, j; - - if ( free_regions->nr_banks >= free_regions->max_banks ) - return 0; - - /* - * Both start and size of the free region should be 2MB aligned to - * potentially allow superpage mapping. - */ - start = (s + SZ_2M - 1) & ~(SZ_2M - 1); - if ( start > e ) - return 0; - - /* - * e is actually "end-1" because it is called by rangeset functions - * which are inclusive of the last address. - */ - e += 1; - size = (e - start) & ~(SZ_2M - 1); - - /* Find the insert position (descending order). */ - for ( i = 0; i < free_regions->nr_banks ; i++ ) - if ( size > free_regions->bank[i].size ) - break; - - /* Move the other banks to make space. */ - for ( j = free_regions->nr_banks; j > i ; j-- ) - { - free_regions->bank[j].start = free_regions->bank[j - 1].start; - free_regions->bank[j].size = free_regions->bank[j - 1].size; - } - - free_regions->bank[i].start = start; - free_regions->bank[i].size = size; - free_regions->nr_banks++; - - return 0; -} - -/* - * Find unused regions of Host address space which can be exposed to domain - * using the host memory layout. In order to calculate regions we exclude every - * region passed in mem_banks from the Host RAM. - */ -static int __init find_unallocated_memory(const struct kernel_info *kinfo, - const struct membanks *mem_banks[], - unsigned int nr_mem_banks, - struct membanks *free_regions, - int (*cb)(unsigned long s_gfn, - unsigned long e_gfn, - void *data)) -{ - const struct membanks *mem = bootinfo_get_mem(); - struct rangeset *unalloc_mem; - paddr_t start, end; - unsigned int i, j; - int res; - - ASSERT(domain_use_host_layout(kinfo->d)); - - unalloc_mem = rangeset_new(NULL, NULL, 0); - if ( !unalloc_mem ) - return -ENOMEM; - - /* Start with all available RAM */ - for ( i = 0; i < mem->nr_banks; i++ ) - { - start = mem->bank[i].start; - end = mem->bank[i].start + mem->bank[i].size; - res = rangeset_add_range(unalloc_mem, PFN_DOWN(start), - PFN_DOWN(end - 1)); - if ( res ) - { - printk(XENLOG_ERR "Failed to add: %#"PRIpaddr"->%#"PRIpaddr"\n", - start, end); - goto out; - } - } - - /* Remove all regions listed in mem_banks */ - for ( i = 0; i < nr_mem_banks; i++ ) - for ( j = 0; j < mem_banks[i]->nr_banks; j++ ) - { - start = mem_banks[i]->bank[j].start; - - /* Shared memory banks can contain INVALID_PADDR as start */ - if ( INVALID_PADDR == start ) - continue; - - end = mem_banks[i]->bank[j].start + mem_banks[i]->bank[j].size; - res = rangeset_remove_range(unalloc_mem, PFN_DOWN(start), - PFN_DOWN(end - 1)); - if ( res ) - { - printk(XENLOG_ERR - "Failed to add: %#"PRIpaddr"->%#"PRIpaddr", error %d\n", - start, end, res); - goto out; - } - } - - start = 0; - end = (1ULL << p2m_ipa_bits) - 1; - res = rangeset_report_ranges(unalloc_mem, PFN_DOWN(start), PFN_DOWN(end), - cb, free_regions); - if ( res ) - free_regions->nr_banks = 0; - else if ( !free_regions->nr_banks ) - res = -ENOENT; - -out: - rangeset_destroy(unalloc_mem); - - return res; -} - -void __init allocate_memory(struct domain *d, struct kernel_info *kinfo) -{ - struct membanks *mem = kernel_info_get_mem(kinfo); - unsigned int i, nr_banks = GUEST_RAM_BANKS; - struct membanks *hwdom_free_mem = NULL; - - printk(XENLOG_INFO "Allocating mappings totalling %ldMB for %pd:\n", - /* Don't want format this as PRIpaddr (16 digit hex) */ - (unsigned long)(kinfo->unassigned_mem >> 20), d); - - mem->nr_banks = 0; - /* - * Use host memory layout for hwdom. Only case for this is when LLC coloring - * is enabled. - */ - if ( is_hardware_domain(d) ) - { - struct membanks *gnttab = membanks_xzalloc(1, MEMORY); - /* - * Exclude the following regions: - * 1) Remove reserved memory - * 2) Grant table assigned to hwdom - */ - const struct membanks *mem_banks[] = { - bootinfo_get_reserved_mem(), - gnttab, - }; - - if ( !gnttab ) - goto fail; - - gnttab->nr_banks = 1; - gnttab->bank[0].start = kinfo->gnttab_start; - gnttab->bank[0].size = kinfo->gnttab_size; - - hwdom_free_mem = membanks_xzalloc(NR_MEM_BANKS, MEMORY); - if ( !hwdom_free_mem ) - goto fail; - - if ( find_unallocated_memory(kinfo, mem_banks, ARRAY_SIZE(mem_banks), - hwdom_free_mem, add_hwdom_free_regions) ) - goto fail; - - nr_banks = hwdom_free_mem->nr_banks; - xfree(gnttab); - } - - for ( i = 0; kinfo->unassigned_mem > 0 && nr_banks > 0; i++, nr_banks-- ) - { - paddr_t bank_start, bank_size; - - if ( is_hardware_domain(d) ) - { - bank_start = hwdom_free_mem->bank[i].start; - bank_size = hwdom_free_mem->bank[i].size; - } - else - { - const uint64_t bankbase[] = GUEST_RAM_BANK_BASES; - const uint64_t banksize[] = GUEST_RAM_BANK_SIZES; - - if ( i >= GUEST_RAM_BANKS ) - goto fail; - - bank_start = bankbase[i]; - bank_size = banksize[i]; - } - - bank_size = MIN(bank_size, kinfo->unassigned_mem); - if ( !allocate_bank_memory(kinfo, gaddr_to_gfn(bank_start), bank_size) ) - goto fail; - } - - if ( kinfo->unassigned_mem ) - goto fail; - - for( i = 0; i < mem->nr_banks; i++ ) - { - printk(XENLOG_INFO "%pd BANK[%d] %#"PRIpaddr"-%#"PRIpaddr" (%ldMB)\n", - d, - i, - mem->bank[i].start, - mem->bank[i].start + mem->bank[i].size, - /* Don't want format this as PRIpaddr (16 digit hex) */ - (unsigned long)(mem->bank[i].size >> 20)); - } - - xfree(hwdom_free_mem); - return; - - fail: - panic("Failed to allocate requested domain memory." - /* Don't want format this as PRIpaddr (16 digit hex) */ - " %ldKB unallocated. Fix the VMs configurations.\n", - (unsigned long)kinfo->unassigned_mem >> 10); -} - static int __init handle_pci_range(const struct dt_device_node *dev, uint64_t addr, uint64_t len, void *data) { @@ -2058,75 +1734,6 @@ static int __init prepare_dtb_hwdom(struct domain *d, struct kernel_info *kinfo) return -EINVAL; } -static void __init dtb_load(struct kernel_info *kinfo) -{ - unsigned long left; - - printk("Loading %pd DTB to 0x%"PRIpaddr"-0x%"PRIpaddr"\n", - kinfo->d, kinfo->dtb_paddr, - kinfo->dtb_paddr + fdt_totalsize(kinfo->fdt)); - - left = copy_to_guest_phys_flush_dcache(kinfo->d, kinfo->dtb_paddr, - kinfo->fdt, - fdt_totalsize(kinfo->fdt)); - - if ( left != 0 ) - panic("Unable to copy the DTB to %pd memory (left = %lu bytes)\n", - kinfo->d, left); - xfree(kinfo->fdt); -} - -static void __init initrd_load(struct kernel_info *kinfo) -{ - const struct bootmodule *mod = kinfo->initrd_bootmodule; - paddr_t load_addr = kinfo->initrd_paddr; - paddr_t paddr, len; - int node; - int res; - __be32 val[2]; - __be32 *cellp; - void __iomem *initrd; - - if ( !mod || !mod->size ) - return; - - paddr = mod->start; - len = mod->size; - - printk("Loading %pd initrd from %"PRIpaddr" to 0x%"PRIpaddr"-0x%"PRIpaddr"\n", - kinfo->d, paddr, load_addr, load_addr + len); - - /* Fix up linux,initrd-start and linux,initrd-end in /chosen */ - node = fdt_path_offset(kinfo->fdt, "/chosen"); - if ( node < 0 ) - panic("Cannot find the /chosen node\n"); - - cellp = (__be32 *)val; - dt_set_cell(&cellp, ARRAY_SIZE(val), load_addr); - res = fdt_setprop_inplace(kinfo->fdt, node, "linux,initrd-start", - val, sizeof(val)); - if ( res ) - panic("Cannot fix up \"linux,initrd-start\" property\n"); - - cellp = (__be32 *)val; - dt_set_cell(&cellp, ARRAY_SIZE(val), load_addr + len); - res = fdt_setprop_inplace(kinfo->fdt, node, "linux,initrd-end", - val, sizeof(val)); - if ( res ) - panic("Cannot fix up \"linux,initrd-end\" property\n"); - - initrd = ioremap_wc(paddr, len); - if ( !initrd ) - panic("Unable to map the %pd initrd\n", kinfo->d); - - res = copy_to_guest_phys_flush_dcache(kinfo->d, load_addr, - initrd, len); - if ( res != 0 ) - panic("Unable to copy the initrd in the %pd memory\n", kinfo->d); - - iounmap(initrd); -} - /* * Allocate the event channel PPIs and setup the HVM_PARAM_CALLBACK_IRQ. * The allocated IRQ will be found in d->arch.evtchn_irq. @@ -2219,8 +1826,8 @@ int __init construct_domain(struct domain *d, struct kernel_info *kinfo) */ kernel_load(kinfo); /* initrd_load will fix up the fdt, so call it before dtb_load */ - initrd_load(kinfo); - dtb_load(kinfo); + initrd_load(kinfo, copy_to_guest_phys_flush_dcache); + dtb_load(kinfo, copy_to_guest_phys_flush_dcache); memset(regs, 0, sizeof(*regs)); diff --git a/xen/common/device-tree/Makefile b/xen/common/device-tree/Makefile index e88a4d5799..831b91399b 100644 --- a/xen/common/device-tree/Makefile +++ b/xen/common/device-tree/Makefile @@ -1,6 +1,7 @@ obj-y += bootfdt.init.o obj-y += bootinfo.init.o obj-y += device-tree.o +obj-$(CONFIG_DOMAIN_BUILD_HELPERS) += domain-build.o obj-$(CONFIG_DOM0LESS_BOOT) += dom0less-build.o obj-$(CONFIG_OVERLAY_DTB) += dt-overlay.o obj-y += intc.o diff --git a/xen/common/device-tree/domain-build.c b/xen/common/device-tree/domain-build.c new file mode 100644 index 0000000000..69257a15ba --- /dev/null +++ b/xen/common/device-tree/domain-build.c @@ -0,0 +1,404 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +bool __init allocate_domheap_memory(struct domain *d, paddr_t tot_size, + alloc_domheap_mem_cb cb, void *extra) +{ + unsigned int max_order = UINT_MAX; + + while ( tot_size > 0 ) + { + unsigned int order = get_allocation_size(tot_size); + struct page_info *pg; + + order = min(max_order, order); + + pg = alloc_domheap_pages(d, order, 0); + if ( !pg ) + { + /* + * If we can't allocate one page, then it is unlikely to + * succeed in the next iteration. So bail out. + */ + if ( !order ) + return false; + + /* + * If we can't allocate memory with order, then it is + * unlikely to succeed in the next iteration. + * Record the order - 1 to avoid re-trying. + */ + max_order = order - 1; + continue; + } + + if ( !cb(d, pg, order, extra) ) + return false; + + tot_size -= (1ULL << (PAGE_SHIFT + order)); + } + + return true; +} + +static bool __init guest_map_pages(struct domain *d, struct page_info *pg, + unsigned int order, void *extra) +{ + gfn_t *sgfn = (gfn_t *)extra; + int res; + + BUG_ON(!sgfn); + res = guest_physmap_add_page(d, *sgfn, page_to_mfn(pg), order); + if ( res ) + { + dprintk(XENLOG_ERR, "Failed map pages to DOMU: %d", res); + return false; + } + + *sgfn = gfn_add(*sgfn, 1UL << order); + + return true; +} + +bool __init allocate_bank_memory(struct kernel_info *kinfo, gfn_t sgfn, + paddr_t tot_size) +{ + struct membanks *mem = kernel_info_get_mem(kinfo); + struct domain *d = kinfo->d; + struct membank *bank; + + /* + * allocate_bank_memory can be called with a tot_size of zero for + * the second memory bank. It is not an error and we can safely + * avoid creating a zero-size memory bank. + */ + if ( tot_size == 0 ) + return true; + + bank = &mem->bank[mem->nr_banks]; + bank->start = gfn_to_gaddr(sgfn); + bank->size = tot_size; + + /* + * Allocate pages from the heap until tot_size is zero and map them to the + * guest using guest_map_pages, passing the starting gfn as extra parameter + * for the map operation. + */ + if ( !allocate_domheap_memory(d, tot_size, guest_map_pages, &sgfn) ) + return false; + + mem->nr_banks++; + kinfo->unassigned_mem -= bank->size; + + return true; +} + +static int __init add_hwdom_free_regions(unsigned long s_gfn, + unsigned long e_gfn, void *data) +{ + struct membanks *free_regions = data; + paddr_t start, size; + paddr_t s = pfn_to_paddr(s_gfn); + paddr_t e = pfn_to_paddr(e_gfn); + unsigned int i, j; + + if ( free_regions->nr_banks >= free_regions->max_banks ) + return 0; + + /* + * Both start and size of the free region should be 2MB aligned to + * potentially allow superpage mapping. + */ + start = (s + SZ_2M - 1) & ~(SZ_2M - 1); + if ( start > e ) + return 0; + + /* + * e is actually "end-1" because it is called by rangeset functions + * which are inclusive of the last address. + */ + e += 1; + size = (e - start) & ~(SZ_2M - 1); + + /* Find the insert position (descending order). */ + for ( i = 0; i < free_regions->nr_banks ; i++ ) + if ( size > free_regions->bank[i].size ) + break; + + /* Move the other banks to make space. */ + for ( j = free_regions->nr_banks; j > i ; j-- ) + { + free_regions->bank[j].start = free_regions->bank[j - 1].start; + free_regions->bank[j].size = free_regions->bank[j - 1].size; + } + + free_regions->bank[i].start = start; + free_regions->bank[i].size = size; + free_regions->nr_banks++; + + return 0; +} + +/* + * Find unused regions of Host address space which can be exposed to domain + * using the host memory layout. In order to calculate regions we exclude every + * region passed in mem_banks from the Host RAM. + */ +int __init find_unallocated_memory(const struct kernel_info *kinfo, + const struct membanks *mem_banks[], + unsigned int nr_mem_banks, + struct membanks *free_regions, + int (*cb)(unsigned long s_gfn, + unsigned long e_gfn, + void *data)) +{ + const struct membanks *mem = bootinfo_get_mem(); + struct rangeset *unalloc_mem; + paddr_t start, end; + unsigned int i, j; + int res; + + ASSERT(domain_use_host_layout(kinfo->d)); + + unalloc_mem = rangeset_new(NULL, NULL, 0); + if ( !unalloc_mem ) + return -ENOMEM; + + /* Start with all available RAM */ + for ( i = 0; i < mem->nr_banks; i++ ) + { + start = mem->bank[i].start; + end = mem->bank[i].start + mem->bank[i].size; + res = rangeset_add_range(unalloc_mem, PFN_DOWN(start), + PFN_DOWN(end - 1)); + if ( res ) + { + printk(XENLOG_ERR "Failed to add: %#"PRIpaddr"->%#"PRIpaddr"\n", + start, end); + goto out; + } + } + + /* Remove all regions listed in mem_banks */ + for ( i = 0; i < nr_mem_banks; i++ ) + for ( j = 0; j < mem_banks[i]->nr_banks; j++ ) + { + start = mem_banks[i]->bank[j].start; + + /* Shared memory banks can contain INVALID_PADDR as start */ + if ( INVALID_PADDR == start ) + continue; + + end = mem_banks[i]->bank[j].start + mem_banks[i]->bank[j].size; + res = rangeset_remove_range(unalloc_mem, PFN_DOWN(start), + PFN_DOWN(end - 1)); + if ( res ) + { + printk(XENLOG_ERR + "Failed to add: %#"PRIpaddr"->%#"PRIpaddr", error %d\n", + start, end, res); + goto out; + } + } + + start = 0; + end = (1ULL << p2m_ipa_bits) - 1; + res = rangeset_report_ranges(unalloc_mem, PFN_DOWN(start), PFN_DOWN(end), + cb, free_regions); + if ( res ) + free_regions->nr_banks = 0; + else if ( !free_regions->nr_banks ) + res = -ENOENT; + +out: + rangeset_destroy(unalloc_mem); + + return res; +} + +void __init allocate_memory(struct domain *d, struct kernel_info *kinfo) +{ + struct membanks *mem = kernel_info_get_mem(kinfo); + unsigned int i, nr_banks = GUEST_RAM_BANKS; + struct membanks *hwdom_free_mem = NULL; + + printk(XENLOG_INFO "Allocating mappings totalling %ldMB for %pd:\n", + /* Don't want format this as PRIpaddr (16 digit hex) */ + (unsigned long)(kinfo->unassigned_mem >> 20), d); + + mem->nr_banks = 0; + /* + * Use host memory layout for hwdom. Only case for this is when LLC coloring + * is enabled. + */ + if ( is_hardware_domain(d) ) + { + struct membanks *gnttab = xzalloc_flex_struct(struct membanks, bank, 1); + /* + * Exclude the following regions: + * 1) Remove reserved memory + * 2) Grant table assigned to hwdom + */ + const struct membanks *mem_banks[] = { + bootinfo_get_reserved_mem(), + gnttab, + }; + + if ( !gnttab ) + goto fail; + + gnttab->nr_banks = 1; + gnttab->bank[0].start = kinfo->gnttab_start; + gnttab->bank[0].size = kinfo->gnttab_size; + + hwdom_free_mem = xzalloc_flex_struct(struct membanks, bank, + NR_MEM_BANKS); + if ( !hwdom_free_mem ) + goto fail; + + hwdom_free_mem->max_banks = NR_MEM_BANKS; + + if ( find_unallocated_memory(kinfo, mem_banks, ARRAY_SIZE(mem_banks), + hwdom_free_mem, add_hwdom_free_regions) ) + goto fail; + + nr_banks = hwdom_free_mem->nr_banks; + xfree(gnttab); + } + + for ( i = 0; kinfo->unassigned_mem > 0 && nr_banks > 0; i++, nr_banks-- ) + { + paddr_t bank_start, bank_size; + + if ( is_hardware_domain(d) ) + { + bank_start = hwdom_free_mem->bank[i].start; + bank_size = hwdom_free_mem->bank[i].size; + } + else + { + const uint64_t bankbase[] = GUEST_RAM_BANK_BASES; + const uint64_t banksize[] = GUEST_RAM_BANK_SIZES; + + if ( i >= GUEST_RAM_BANKS ) + goto fail; + + bank_start = bankbase[i]; + bank_size = banksize[i]; + } + + bank_size = MIN(bank_size, kinfo->unassigned_mem); + if ( !allocate_bank_memory(kinfo, gaddr_to_gfn(bank_start), bank_size) ) + goto fail; + } + + if ( kinfo->unassigned_mem ) + goto fail; + + for( i = 0; i < mem->nr_banks; i++ ) + { + printk(XENLOG_INFO "%pd BANK[%d] %#"PRIpaddr"-%#"PRIpaddr" (%ldMB)\n", + d, + i, + mem->bank[i].start, + mem->bank[i].start + mem->bank[i].size, + /* Don't want format this as PRIpaddr (16 digit hex) */ + (unsigned long)(mem->bank[i].size >> 20)); + } + + xfree(hwdom_free_mem); + return; + + fail: + panic("Failed to allocate requested domain memory." + /* Don't want format this as PRIpaddr (16 digit hex) */ + " %ldKB unallocated. Fix the VMs configurations.\n", + (unsigned long)kinfo->unassigned_mem >> 10); +} + +/* Copy data to guest physical address, then clean the region. */ +typedef unsigned long (*copy_to_guest_phys_cb)(struct domain *d, + paddr_t gpa, + void *buf, + unsigned int len); + +void __init dtb_load(struct kernel_info *kinfo, + copy_to_guest_phys_cb copy_to_guest) +{ + unsigned long left; + + printk("Loading %pd DTB to 0x%"PRIpaddr"-0x%"PRIpaddr"\n", + kinfo->d, kinfo->dtb_paddr, + kinfo->dtb_paddr + fdt_totalsize(kinfo->fdt)); + + left = copy_to_guest(kinfo->d, kinfo->dtb_paddr, + kinfo->fdt, + fdt_totalsize(kinfo->fdt)); + + if ( left != 0 ) + panic("Unable to copy the DTB to %pd memory (left = %lu bytes)\n", + kinfo->d, left); + xfree(kinfo->fdt); +} + +void __init initrd_load(struct kernel_info *kinfo, + copy_to_guest_phys_cb copy_to_guest) +{ + const struct bootmodule *mod = kinfo->initrd_bootmodule; + paddr_t load_addr = kinfo->initrd_paddr; + paddr_t paddr, len; + int node; + int res; + __be32 val[2]; + __be32 *cellp; + void __iomem *initrd; + + if ( !mod || !mod->size ) + return; + + paddr = mod->start; + len = mod->size; + + printk("Loading %pd initrd from %"PRIpaddr" to 0x%"PRIpaddr"-0x%"PRIpaddr"\n", + kinfo->d, paddr, load_addr, load_addr + len); + + /* Fix up linux,initrd-start and linux,initrd-end in /chosen */ + node = fdt_path_offset(kinfo->fdt, "/chosen"); + if ( node < 0 ) + panic("Cannot find the /chosen node\n"); + + cellp = (__be32 *)val; + dt_set_cell(&cellp, ARRAY_SIZE(val), load_addr); + res = fdt_setprop_inplace(kinfo->fdt, node, "linux,initrd-start", + val, sizeof(val)); + if ( res ) + panic("Cannot fix up \"linux,initrd-start\" property\n"); + + cellp = (__be32 *)val; + dt_set_cell(&cellp, ARRAY_SIZE(val), load_addr + len); + res = fdt_setprop_inplace(kinfo->fdt, node, "linux,initrd-end", + val, sizeof(val)); + if ( res ) + panic("Cannot fix up \"linux,initrd-end\" property\n"); + + initrd = ioremap_wc(paddr, len); + if ( !initrd ) + panic("Unable to map the hwdom initrd\n"); + + res = copy_to_guest(kinfo->d, load_addr, + initrd, len); + if ( res != 0 ) + panic("Unable to copy the initrd in the hwdom memory\n"); + + iounmap(initrd); +} diff --git a/xen/include/xen/fdt-domain-build.h b/xen/include/xen/fdt-domain-build.h index 41454e75ca..0af2b927fc 100644 --- a/xen/include/xen/fdt-domain-build.h +++ b/xen/include/xen/fdt-domain-build.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #if __has_include() @@ -32,7 +33,37 @@ int make_memory_node(const struct kernel_info *kinfo, int addrcells, int sizecells, const struct membanks *mem); int make_timer_node(const struct kernel_info *kinfo); -unsigned int get_allocation_size(paddr_t size); + +static inline int get_allocation_size(paddr_t size) +{ + /* + * get_order_from_bytes returns the order greater than or equal to + * the given size, but we need less than or equal. Adding one to + * the size pushes an evenly aligned size into the next order, so + * we can then unconditionally subtract 1 from the order which is + * returned. + */ + return get_order_from_bytes(size + 1) - 1; +} + +typedef unsigned long (*copy_to_guest_phys_cb)(struct domain *d, + paddr_t gpa, + void *buf, + unsigned int len); + +void initrd_load(struct kernel_info *kinfo, + copy_to_guest_phys_cb copy_to_guest); + +void dtb_load(struct kernel_info *kinfo, + copy_to_guest_phys_cb copy_to_guest); + +int find_unallocated_memory(const struct kernel_info *kinfo, + const struct membanks *mem_banks[], + unsigned int nr_mem_banks, + struct membanks *free_regions, + int (*cb)(unsigned long s_gfn, + unsigned long e_gfn, + void *data)); #endif /* __XEN_FDT_DOMAIN_BUILD_H__ */ From patchwork Mon Apr 14 15:56:41 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleksii Kurochko X-Patchwork-Id: 14050663 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 2613CC369B4 for ; Mon, 14 Apr 2025 15:57:13 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.950719.1347017 (Exim 4.92) (envelope-from ) id 1u4MB9-00024h-Rt; Mon, 14 Apr 2025 15:56:59 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 950719.1347017; Mon, 14 Apr 2025 15:56:59 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1u4MB9-00024N-Km; Mon, 14 Apr 2025 15:56:59 +0000 Received: by outflank-mailman (input) for mailman id 950719; Mon, 14 Apr 2025 15:56:57 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1u4MB7-0008KQ-Es for xen-devel@lists.xenproject.org; Mon, 14 Apr 2025 15:56:57 +0000 Received: from mail-ej1-x62a.google.com (mail-ej1-x62a.google.com [2a00:1450:4864:20::62a]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id 165b9b8a-1949-11f0-9eae-5ba50f476ded; Mon, 14 Apr 2025 17:56:54 +0200 (CEST) Received: by mail-ej1-x62a.google.com with SMTP id a640c23a62f3a-ac289147833so904644866b.2 for ; Mon, 14 Apr 2025 08:56:54 -0700 (PDT) Received: from fedora.. (user-109-243-64-225.play-internet.pl. [109.243.64.225]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-acaa1cb4288sm951760866b.96.2025.04.14.08.56.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 14 Apr 2025 08:56:52 -0700 (PDT) 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: 165b9b8a-1949-11f0-9eae-5ba50f476ded DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1744646214; x=1745251014; darn=lists.xenproject.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=dc1pgFJf0G84e6oD2r9vhEyJ/iTT6BHM7/kWkDBbrBE=; b=dKVRurjCZ83HpPFOKKUAYV5YHd9X2gFrNmIgMVN/JsmjMksoXgSeCgCSU6Jk8tYu8o YMchGi0w7ZAh50I2mGSd9Ai7wT9JsQl18ATQDCPfjXy0Caj3cLUj20/5QWOkYs9B0SNa mxwy8pdKs6pqZNz+hjf432KVm+YrFDm5elPzXfR8K9pWoRmdnAVIX56cp02GkI4cZh4J qDAjjg8l2sSNRATW9mrCZAYEWfIrm/FsOGQiNQDhKOztLODkHx0tAuJ29lvyjaYoaOCM Mxur0Ds4vUAGq7EpkYmbWiQADqadgZ78xh6hsp+uWDM1yiSSIP3e7Kp2KROBGoTrrPl4 DLCA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744646214; x=1745251014; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=dc1pgFJf0G84e6oD2r9vhEyJ/iTT6BHM7/kWkDBbrBE=; b=bN3tGSo9ByyGccj+ZZh9B1Fn551sckAIRDob+0eeQnaPzn1XL1Qox0suhppyHZ+Vd6 OsUulp1cxepZZO/biFX0viB/gjpJir4MMrgnaj6eXFO890g8HxHpUkoNWC51nzuHbRun UsdgUJxJvQ+d8r5WpzUsNy4gVxiEmrsi5Fo+XGhPEkAKrVVlr2v0EhqFBtKCDBczQfL5 4sbajp0DJ3jUC56YMpxMzZf/Q5fhpYdK6wsZn46q0+8/JWFd36i19N6BAqDIPZ0h4rgZ U8Uu2qMfbWuV+WMpXMvWWgBaO7LJZILxoq0cK8krSeNUxnY2n7e/ZmLUW0sGHnLgZG1x 2hlA== X-Gm-Message-State: AOJu0Yxy4+v1DM7BXbH/nB3aeVMtN8qJblpVUL61VbaVp9UtVywXL1NA 7FSPtkPmVmVr5UqAtQKSoINT82MIFVFzPzG0ODHnFDwuuvIGEt21dXHgyw== X-Gm-Gg: ASbGncsyBThcFUNCXQmONuKKdkQ0bpRuUNTfUb6ljuqZ5yGhb0pJxrxH3VeZ3W8Jor9 Ys4g2h1vUxlraTN4na6kVBeg9cxsv2wv2KyOqYnHyi9Z57lJ4zxL3jqTi2BpHeDPHIFX72zssiv exaxpoW9jcEfRLIbnGzh9wg66hwxUJrcg706GfaysNEtdAvnpLJB30i/WEWwHUeLGst+SY+fGwo R0XBH/WnA4a9sQ+4p4Lptl2ZkZbIODu4IMvGTeQbbQEnsIOHsJ8BGhftgHXsOp3yxPwuYx/Ksbu yc/Fxkvbh9bURMGMSJcEX9ZglknCJW+lBVAxqK+n5s7f79HOoqkvCmsgP/vTQsLvg6Pdbz3qdbO s1A+EpzaHDg== X-Google-Smtp-Source: AGHT+IGCasdmzz8rTJ2FsuF3O1m7X9brnOvutE7iSnFgTffy1w92B0xGksV0jWLJ9pd36jVPcwOJ5w== X-Received: by 2002:a17:906:c14a:b0:ac7:81b0:62c8 with SMTP id a640c23a62f3a-acad34d94a8mr1030484266b.31.1744646213503; Mon, 14 Apr 2025 08:56:53 -0700 (PDT) From: Oleksii Kurochko To: xen-devel@lists.xenproject.org Cc: Oleksii Kurochko , Stefano Stabellini , Julien Grall , Bertrand Marquis , Michal Orzel , Volodymyr Babchuk , Andrew Cooper , Anthony PERARD , Jan Beulich , =?utf-8?q?Roger_Pau_Monn=C3=A9?= Subject: [PATCH v2 8/8] xen/common: dom0less: introduce common dom0less-build.c Date: Mon, 14 Apr 2025 17:56:41 +0200 Message-ID: <034190a9d2cfc98306b47dbfe4a70937f5820562.1744626032.git.oleksii.kurochko@gmail.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: References: MIME-Version: 1.0 Part of Arm's dom0less-build.c could be common between architectures which are using device tree files to create guest domains. Thereby move some parts of Arm's dom0less-build.c to common code with minor changes. As a part of theses changes the following changes are introduced: - Introduce make_arch_nodes() to cover arch-specific nodes. For example, in case of Arm, it is PSCI and vpl011 nodes. - Introduce set_domain_type() to abstract a way how setting of domain type happens. For example, RISC-V won't have this member of arch_domain structure as vCPUs will always have the same bitness as hypervisor. In case of Arm, it is possible that Arm64 could create 32-bit and 64-bit domains. - Introduce init_vuart() to cover details of virtual uart initialization. - Introduce init_intc_phandle() to cover some details of interrupt controller phandle initialization. As an example, RISC-V could have different name for interrupt controller node ( APLIC, PLIC, IMSIC, etc ) but the code in domain_handle_dtb_bootmodule() could handle only one interrupt controller node name. - s/make_gic_domU_node/make_intc_domU_node as GIC is Arm specific naming and add prototype of make_intc_domU_node() to dom0less-build.h The following functions are moved to xen/common/device-tree: - Functions which are moved as is: - domain_p2m_pages(). - handle_passthrough_prop(). - handle_prop_pfdt(). - scan_pfdt_node(). - check_partial_fdt(). - Functions which are moved with some minor changes: - alloc_xenstore_evtchn(): - ifdef-ing by CONFIG_HVM accesses to hvm.params. - prepare_dtb_domU(): - ifdef-ing access to gnttab_{start,size} by CONFIG_GRANT_TABLE. - s/make_gic_domU_node/make_intc_domU_node. - Add call of make_arch_nodes(). - domain_handle_dtb_bootmodule(): - hide details of interrupt controller phandle initialization by calling init_intc_phandle(). - Update the comment above init_intc_phandle(): s/gic/interrupt controller. - construct_domU(): - ifdef-ing by CONFIG_HVM accesses to hvm.params. - Call init_vuart() to hide Arm's vpl011_init() details there. - Add call of set_domain_type() instead of setting kinfo->arch.type explicitly. Some parts of dom0less-build.c are wraped by #ifdef CONFIG_STATIC_{SHMEM,MEMORY} as not all archs support these configs. Signed-off-by: Oleksii Kurochko --- Change in v2: - Wrap by #ifdef CONFIG_STATIC_* inclusions of and . Wrap also the code which uses something from the mentioned headers. - Add handling of legacy case in construct_domU(). - Use xen/fdt-kernel.h and xen/fdt-domain-build.h instead of asm/*. - Update the commit message. --- xen/arch/arm/dom0less-build.c | 721 ++-------------------- xen/common/device-tree/dom0less-build.c | 730 +++++++++++++++++++++++ xen/include/asm-generic/dom0less-build.h | 14 + 3 files changed, 779 insertions(+), 686 deletions(-) diff --git a/xen/arch/arm/dom0less-build.c b/xen/arch/arm/dom0less-build.c index ca78cff655..463c38ae6c 100644 --- a/xen/arch/arm/dom0less-build.c +++ b/xen/arch/arm/dom0less-build.c @@ -147,7 +147,7 @@ static int __init make_gicv3_domU_node(struct kernel_info *kinfo) } #endif -static int __init make_gic_domU_node(struct kernel_info *kinfo) +int __init make_intc_domU_node(struct kernel_info *kinfo) { switch ( kinfo->d->arch.vgic.version ) { @@ -213,729 +213,62 @@ static int __init make_vpl011_uart_node(struct kernel_info *kinfo) } #endif -/* - * Scan device tree properties for passthrough specific information. - * Returns < 0 on error - * 0 on success - */ -static int __init handle_passthrough_prop(struct kernel_info *kinfo, - const struct fdt_property *xen_reg, - const struct fdt_property *xen_path, - bool xen_force, - uint32_t address_cells, - uint32_t size_cells) -{ - const __be32 *cell; - unsigned int i, len; - struct dt_device_node *node; - int res; - paddr_t mstart, size, gstart; - - /* xen,reg specifies where to map the MMIO region */ - cell = (const __be32 *)xen_reg->data; - len = fdt32_to_cpu(xen_reg->len) / ((address_cells * 2 + size_cells) * - sizeof(uint32_t)); - - for ( i = 0; i < len; i++ ) - { - device_tree_get_reg(&cell, address_cells, size_cells, - &mstart, &size); - gstart = dt_next_cell(address_cells, &cell); - - if ( gstart & ~PAGE_MASK || mstart & ~PAGE_MASK || size & ~PAGE_MASK ) - { - printk(XENLOG_ERR - "DomU passthrough config has not page aligned addresses/sizes\n"); - return -EINVAL; - } - - res = iomem_permit_access(kinfo->d, paddr_to_pfn(mstart), - paddr_to_pfn(PAGE_ALIGN(mstart + size - 1))); - if ( res ) - { - printk(XENLOG_ERR "Unable to permit to dom%d access to" - " 0x%"PRIpaddr" - 0x%"PRIpaddr"\n", - kinfo->d->domain_id, - mstart & PAGE_MASK, PAGE_ALIGN(mstart + size) - 1); - return res; - } - - res = map_regions_p2mt(kinfo->d, - gaddr_to_gfn(gstart), - PFN_DOWN(size), - maddr_to_mfn(mstart), - p2m_mmio_direct_dev); - if ( res < 0 ) - { - printk(XENLOG_ERR - "Failed to map %"PRIpaddr" to the guest at%"PRIpaddr"\n", - mstart, gstart); - return -EFAULT; - } - } - - /* - * If xen_force, we let the user assign a MMIO region with no - * associated path. - */ - if ( xen_path == NULL ) - return xen_force ? 0 : -EINVAL; - - /* - * xen,path specifies the corresponding node in the host DT. - * Both interrupt mappings and IOMMU settings are based on it, - * as they are done based on the corresponding host DT node. - */ - node = dt_find_node_by_path(xen_path->data); - if ( node == NULL ) - { - printk(XENLOG_ERR "Couldn't find node %s in host_dt!\n", - xen_path->data); - return -EINVAL; - } - - res = map_device_irqs_to_domain(kinfo->d, node, true, NULL); - if ( res < 0 ) - return res; - - res = iommu_add_dt_device(node); - if ( res < 0 ) - return res; - - /* If xen_force, we allow assignment of devices without IOMMU protection. */ - if ( xen_force && !dt_device_is_protected(node) ) - return 0; - - return iommu_assign_dt_device(kinfo->d, node); -} - -static int __init handle_prop_pfdt(struct kernel_info *kinfo, - const void *pfdt, int nodeoff, - uint32_t address_cells, uint32_t size_cells, - bool scan_passthrough_prop) -{ - void *fdt = kinfo->fdt; - int propoff, nameoff, res; - const struct fdt_property *prop, *xen_reg = NULL, *xen_path = NULL; - const char *name; - bool found, xen_force = false; - - for ( propoff = fdt_first_property_offset(pfdt, nodeoff); - propoff >= 0; - propoff = fdt_next_property_offset(pfdt, propoff) ) - { - if ( !(prop = fdt_get_property_by_offset(pfdt, propoff, NULL)) ) - return -FDT_ERR_INTERNAL; - - found = false; - nameoff = fdt32_to_cpu(prop->nameoff); - name = fdt_string(pfdt, nameoff); - - if ( scan_passthrough_prop ) - { - if ( dt_prop_cmp("xen,reg", name) == 0 ) - { - xen_reg = prop; - found = true; - } - else if ( dt_prop_cmp("xen,path", name) == 0 ) - { - xen_path = prop; - found = true; - } - else if ( dt_prop_cmp("xen,force-assign-without-iommu", - name) == 0 ) - { - xen_force = true; - found = true; - } - } - - /* - * Copy properties other than the ones above: xen,reg, xen,path, - * and xen,force-assign-without-iommu. - */ - if ( !found ) - { - res = fdt_property(fdt, name, prop->data, fdt32_to_cpu(prop->len)); - if ( res ) - return res; - } - } - - /* - * Only handle passthrough properties if both xen,reg and xen,path - * are present, or if xen,force-assign-without-iommu is specified. - */ - if ( xen_reg != NULL && (xen_path != NULL || xen_force) ) - { - res = handle_passthrough_prop(kinfo, xen_reg, xen_path, xen_force, - address_cells, size_cells); - if ( res < 0 ) - { - printk(XENLOG_ERR "Failed to assign device to %pd\n", kinfo->d); - return res; - } - } - else if ( (xen_path && !xen_reg) || (xen_reg && !xen_path && !xen_force) ) - { - printk(XENLOG_ERR "xen,reg or xen,path missing for %pd\n", - kinfo->d); - return -EINVAL; - } - - /* FDT_ERR_NOTFOUND => There is no more properties for this node */ - return ( propoff != -FDT_ERR_NOTFOUND ) ? propoff : 0; -} - -static int __init scan_pfdt_node(struct kernel_info *kinfo, const void *pfdt, - int nodeoff, - uint32_t address_cells, uint32_t size_cells, - bool scan_passthrough_prop) -{ - int rc = 0; - void *fdt = kinfo->fdt; - int node_next; - - rc = fdt_begin_node(fdt, fdt_get_name(pfdt, nodeoff, NULL)); - if ( rc ) - return rc; - - rc = handle_prop_pfdt(kinfo, pfdt, nodeoff, address_cells, size_cells, - scan_passthrough_prop); - if ( rc ) - return rc; - - address_cells = device_tree_get_u32(pfdt, nodeoff, "#address-cells", - DT_ROOT_NODE_ADDR_CELLS_DEFAULT); - size_cells = device_tree_get_u32(pfdt, nodeoff, "#size-cells", - DT_ROOT_NODE_SIZE_CELLS_DEFAULT); - - node_next = fdt_first_subnode(pfdt, nodeoff); - while ( node_next > 0 ) - { - rc = scan_pfdt_node(kinfo, pfdt, node_next, address_cells, size_cells, - scan_passthrough_prop); - if ( rc ) - return rc; - - node_next = fdt_next_subnode(pfdt, node_next); - } - - return fdt_end_node(fdt); -} - -static int __init check_partial_fdt(void *pfdt, size_t size) -{ - int res; - - if ( fdt_magic(pfdt) != FDT_MAGIC ) - { - dprintk(XENLOG_ERR, "Partial FDT is not a valid Flat Device Tree"); - return -EINVAL; - } - - res = fdt_check_header(pfdt); - if ( res ) - { - dprintk(XENLOG_ERR, "Failed to check the partial FDT (%d)", res); - return -EINVAL; - } - - if ( fdt_totalsize(pfdt) > size ) - { - dprintk(XENLOG_ERR, "Partial FDT totalsize is too big"); - return -EINVAL; - } - - return 0; -} - -static int __init domain_handle_dtb_bootmodule(struct domain *d, - struct kernel_info *kinfo) -{ - void *pfdt; - int res, node_next; - - pfdt = ioremap_cache(kinfo->dtb_bootmodule->start, - kinfo->dtb_bootmodule->size); - if ( pfdt == NULL ) - return -EFAULT; - - res = check_partial_fdt(pfdt, kinfo->dtb_bootmodule->size); - if ( res < 0 ) - goto out; - - for ( node_next = fdt_first_subnode(pfdt, 0); - node_next > 0; - node_next = fdt_next_subnode(pfdt, node_next) ) - { - const char *name = fdt_get_name(pfdt, node_next, NULL); - - if ( name == NULL ) - continue; - - /* - * Only scan /gic /aliases /passthrough, ignore the rest. - * They don't have to be parsed in order. - * - * Take the GIC phandle value from the special /gic node in the - * DTB fragment. - */ - if ( dt_node_cmp(name, "gic") == 0 ) - { - uint32_t phandle_intc = fdt_get_phandle(pfdt, node_next); - - if ( phandle_intc != 0 ) - kinfo->phandle_intc = phandle_intc; - continue; - } - - if ( dt_node_cmp(name, "aliases") == 0 ) - { - res = scan_pfdt_node(kinfo, pfdt, node_next, - DT_ROOT_NODE_ADDR_CELLS_DEFAULT, - DT_ROOT_NODE_SIZE_CELLS_DEFAULT, - false); - if ( res ) - goto out; - continue; - } - if ( dt_node_cmp(name, "passthrough") == 0 ) - { - res = scan_pfdt_node(kinfo, pfdt, node_next, - DT_ROOT_NODE_ADDR_CELLS_DEFAULT, - DT_ROOT_NODE_SIZE_CELLS_DEFAULT, - true); - if ( res ) - goto out; - continue; - } - } - - out: - iounmap(pfdt); - - return res; -} - -/* - * The max size for DT is 2MB. However, the generated DT is small (not including - * domU passthrough DT nodes whose size we account separately), 4KB are enough - * for now, but we might have to increase it in the future. - */ -#define DOMU_DTB_SIZE 4096 -static int __init prepare_dtb_domU(struct domain *d, struct kernel_info *kinfo) +int __init make_arch_nodes(struct kernel_info *kinfo) { - int addrcells, sizecells; - int ret, fdt_size = DOMU_DTB_SIZE; - - kinfo->phandle_intc = GUEST_PHANDLE_GIC; - kinfo->gnttab_start = GUEST_GNTTAB_BASE; - kinfo->gnttab_size = GUEST_GNTTAB_SIZE; - - addrcells = GUEST_ROOT_ADDRESS_CELLS; - sizecells = GUEST_ROOT_SIZE_CELLS; - - /* Account for domU passthrough DT size */ - if ( kinfo->dtb_bootmodule ) - fdt_size += kinfo->dtb_bootmodule->size; - - /* Cap to max DT size if needed */ - fdt_size = min(fdt_size, SZ_2M); - - kinfo->fdt = xmalloc_bytes(fdt_size); - if ( kinfo->fdt == NULL ) - return -ENOMEM; - - ret = fdt_create(kinfo->fdt, fdt_size); - if ( ret < 0 ) - goto err; - - ret = fdt_finish_reservemap(kinfo->fdt); - if ( ret < 0 ) - goto err; - - ret = fdt_begin_node(kinfo->fdt, ""); - if ( ret < 0 ) - goto err; - - ret = fdt_property_cell(kinfo->fdt, "#address-cells", addrcells); - if ( ret ) - goto err; - - ret = fdt_property_cell(kinfo->fdt, "#size-cells", sizecells); - if ( ret ) - goto err; - - ret = make_chosen_node(kinfo); - if ( ret ) - goto err; + int ret; ret = make_psci_node(kinfo->fdt); if ( ret ) - goto err; - - ret = make_cpus_node(d, kinfo->fdt); - if ( ret ) - goto err; - - ret = make_memory_node(kinfo, addrcells, sizecells, - kernel_info_get_mem(kinfo)); - if ( ret ) - goto err; - - ret = make_resv_memory_node(kinfo, addrcells, sizecells); - if ( ret ) - goto err; - - /* - * domain_handle_dtb_bootmodule has to be called before the rest of - * the device tree is generated because it depends on the value of - * the field phandle_intc. - */ - if ( kinfo->dtb_bootmodule ) - { - ret = domain_handle_dtb_bootmodule(d, kinfo); - if ( ret ) - goto err; - } - - ret = make_gic_domU_node(kinfo); - if ( ret ) - goto err; - - ret = make_timer_node(kinfo); - if ( ret ) - goto err; + return -EINVAL; if ( kinfo->vuart ) { - ret = -EINVAL; #ifdef CONFIG_SBSA_VUART_CONSOLE ret = make_vpl011_uart_node(kinfo); #endif if ( ret ) - goto err; - } - - if ( kinfo->dom0less_feature & DOM0LESS_ENHANCED_NO_XS ) - { - ret = make_hypervisor_node(d, kinfo, addrcells, sizecells); - if ( ret ) - goto err; + return -EINVAL; } - ret = fdt_end_node(kinfo->fdt); - if ( ret < 0 ) - goto err; - - ret = fdt_finish(kinfo->fdt); - if ( ret < 0 ) - goto err; - return 0; - - err: - printk("Device tree generation failed (%d).\n", ret); - xfree(kinfo->fdt); - - return -EINVAL; } -static int __init alloc_xenstore_evtchn(struct domain *d) +/* TODO: make arch.type generic ? */ +#ifdef CONFIG_ARM_64 +void __init set_domain_type(struct domain *d, struct kernel_info *kinfo) { - evtchn_alloc_unbound_t alloc; - int rc; - - alloc.dom = d->domain_id; - alloc.remote_dom = hardware_domain->domain_id; - rc = evtchn_alloc_unbound(&alloc, 0); - if ( rc ) - { - printk("Failed allocating event channel for domain\n"); - return rc; - } - - d->arch.hvm.params[HVM_PARAM_STORE_EVTCHN] = alloc.port; - - return 0; + /* type must be set before allocate memory */ + d->arch.type = kinfo->arch.type; } - -#define XENSTORE_PFN_OFFSET 1 -static int __init alloc_xenstore_page(struct domain *d) +#else +void __init set_domain_type(struct domain *d, struct kernel_info *kinfo) { - struct page_info *xenstore_pg; - struct xenstore_domain_interface *interface; - mfn_t mfn; - gfn_t gfn; - int rc; - - if ( (UINT_MAX - d->max_pages) < 1 ) - { - printk(XENLOG_ERR "%pd: Over-allocation for d->max_pages by 1 page.\n", - d); - return -EINVAL; - } - - d->max_pages += 1; - xenstore_pg = alloc_domheap_page(d, MEMF_bits(32)); - if ( xenstore_pg == NULL && is_64bit_domain(d) ) - xenstore_pg = alloc_domheap_page(d, 0); - if ( xenstore_pg == NULL ) - return -ENOMEM; - - mfn = page_to_mfn(xenstore_pg); - if ( !mfn_x(mfn) ) - return -ENOMEM; - - if ( !is_domain_direct_mapped(d) ) - gfn = gaddr_to_gfn(GUEST_MAGIC_BASE + - (XENSTORE_PFN_OFFSET << PAGE_SHIFT)); - else - gfn = gaddr_to_gfn(mfn_to_maddr(mfn)); - - rc = guest_physmap_add_page(d, gfn, mfn, 0); - if ( rc ) - { - free_domheap_page(xenstore_pg); - return rc; - } - - d->arch.hvm.params[HVM_PARAM_STORE_PFN] = gfn_x(gfn); - interface = map_domain_page(mfn); - interface->connection = XENSTORE_RECONNECT; - unmap_domain_page(interface); - - return 0; + /* Nothing to do */ } +#endif -static int __init alloc_xenstore_params(struct kernel_info *kinfo) +int __init init_vuart(struct domain *d, struct kernel_info *kinfo, + const struct dt_device_node *node) { - struct domain *d = kinfo->d; int rc = 0; - if ( kinfo->dom0less_feature & (DOM0LESS_XENSTORE | DOM0LESS_XS_LEGACY) ) - { - ASSERT(hardware_domain); - rc = alloc_xenstore_evtchn(d); - if ( rc < 0 ) - return rc; - d->arch.hvm.params[HVM_PARAM_STORE_PFN] = ~0ULL; - } - - if ( kinfo->dom0less_feature & DOM0LESS_XENSTORE ) - { - rc = alloc_xenstore_page(d); - if ( rc < 0 ) - return rc; - } - - return rc; -} - -static void __init domain_vcpu_affinity(struct domain *d, - const struct dt_device_node *node) -{ - struct dt_device_node *np; - - dt_for_each_child_node(node, np) - { - const char *hard_affinity_str = NULL; - uint32_t val; - int rc; - struct vcpu *v; - cpumask_t affinity; - - if ( !dt_device_is_compatible(np, "xen,vcpu") ) - continue; - - if ( !dt_property_read_u32(np, "id", &val) ) - panic("Invalid xen,vcpu node for domain %s\n", dt_node_name(node)); - - if ( val >= d->max_vcpus ) - panic("Invalid vcpu_id %u for domain %s, max_vcpus=%u\n", val, - dt_node_name(node), d->max_vcpus); - - v = d->vcpu[val]; - rc = dt_property_read_string(np, "hard-affinity", &hard_affinity_str); - if ( rc < 0 ) - continue; - - cpumask_clear(&affinity); - while ( *hard_affinity_str != '\0' ) - { - unsigned int start, end; - - start = simple_strtoul(hard_affinity_str, &hard_affinity_str, 0); - - if ( *hard_affinity_str == '-' ) /* Range */ - { - hard_affinity_str++; - end = simple_strtoul(hard_affinity_str, &hard_affinity_str, 0); - } - else /* Single value */ - end = start; - - if ( end >= nr_cpu_ids ) - panic("Invalid pCPU %u for domain %s\n", end, dt_node_name(node)); - - for ( ; start <= end; start++ ) - cpumask_set_cpu(start, &affinity); - - if ( *hard_affinity_str == ',' ) - hard_affinity_str++; - else if ( *hard_affinity_str != '\0' ) - break; - } - - rc = vcpu_set_hard_affinity(v, &affinity); - if ( rc ) - panic("vcpu%d: failed (rc=%d) to set hard affinity for domain %s\n", - v->vcpu_id, rc, dt_node_name(node)); - } -} - -#ifdef CONFIG_ARCH_PAGING_MEMPOOL -static unsigned long __init domain_p2m_pages(unsigned long maxmem_kb, - unsigned int smp_cpus) -{ - /* - * Keep in sync with libxl__get_required_paging_memory(). - * 256 pages (1MB) per vcpu, plus 1 page per MiB of RAM for the P2M map, - * plus 128 pages to cover extended regions. - */ - unsigned long memkb = 4 * (256 * smp_cpus + (maxmem_kb / 1024) + 128); - - BUILD_BUG_ON(PAGE_SIZE != SZ_4K); - - return DIV_ROUND_UP(memkb, 1024) << (20 - PAGE_SHIFT); -} - -static int __init domain_p2m_set_allocation(struct domain *d, uint64_t mem, - const struct dt_device_node *node) -{ - unsigned long p2m_pages; - uint32_t p2m_mem_mb; - int rc; - - rc = dt_property_read_u32(node, "xen,domain-p2m-mem-mb", &p2m_mem_mb); - /* If xen,domain-p2m-mem-mb is not specified, use the default value. */ - p2m_pages = rc ? - p2m_mem_mb << (20 - PAGE_SHIFT) : - domain_p2m_pages(mem, d->max_vcpus); - - spin_lock(&d->arch.paging.lock); - rc = p2m_set_allocation(d, p2m_pages, NULL); - spin_unlock(&d->arch.paging.lock); - - return rc; -} -#else /* !CONFIG_ARCH_PAGING_MEMPOOL */ -static inline int domain_p2m_set_allocation(struct domain *d, uint64_t mem, - const struct dt_device_node *node) -{ - return 0; -} -#endif /* CONFIG_ARCH_PAGING_MEMPOOL */ - -int __init construct_domU(struct domain *d, - const struct dt_device_node *node) -{ - struct kernel_info kinfo = KERNEL_INFO_INIT; - const char *dom0less_enhanced; - int rc; - u64 mem; - - rc = dt_property_read_u64(node, "memory", &mem); - if ( !rc ) - { - printk("Error building DomU: cannot read \"memory\" property\n"); - return -EINVAL; - } - kinfo.unassigned_mem = (paddr_t)mem * SZ_1K; - - rc = domain_p2m_set_allocation(d, mem, node); - if ( rc != 0 ) - return rc; - - printk("*** LOADING DOMU cpus=%u memory=%#"PRIx64"KB ***\n", - d->max_vcpus, mem); - - kinfo.vuart = dt_property_read_bool(node, "vpl011"); - - rc = dt_property_read_string(node, "xen,enhanced", &dom0less_enhanced); - if ( rc == -EILSEQ || - rc == -ENODATA || - (rc == 0 && !strcmp(dom0less_enhanced, "enabled")) ) - { - if ( hardware_domain ) - kinfo.dom0less_feature = DOM0LESS_ENHANCED; - else - panic("At the moment, Xenstore support requires dom0 to be present\n"); - } - else if ( rc == 0 && !strcmp(dom0less_enhanced, "legacy") ) - { - if ( hardware_domain ) - kinfo.dom0less_feature = DOM0LESS_ENHANCED_LEGACY; - else - panic("At the moment, Xenstore support requires dom0 to be present\n"); - } - else if ( rc == 0 && !strcmp(dom0less_enhanced, "no-xenstore") ) - kinfo.dom0less_feature = DOM0LESS_ENHANCED_NO_XS; - - if ( vcpu_create(d, 0) == NULL ) - return -ENOMEM; - - d->max_pages = ((paddr_t)mem * SZ_1K) >> PAGE_SHIFT; - - kinfo.d = d; - - rc = kernel_probe(&kinfo, node); - if ( rc < 0 ) - return rc; - -#ifdef CONFIG_ARM_64 - /* type must be set before allocate memory */ - d->arch.type = kinfo.arch.type; -#endif - if ( !dt_find_property(node, "xen,static-mem", NULL) ) - allocate_memory(d, &kinfo); - else if ( !is_domain_direct_mapped(d) ) - allocate_static_memory(d, &kinfo, node); - else - assign_static_memory_11(d, &kinfo, node); - - rc = process_shm(d, &kinfo, node); - if ( rc < 0 ) - return rc; + kinfo->vuart = dt_property_read_bool(node, "vpl011"); /* * Base address and irq number are needed when creating vpl011 device * tree node in prepare_dtb_domU, so initialization on related variables * shall be done first. */ - if ( kinfo.vuart ) + if ( kinfo->vuart ) { rc = domain_vpl011_init(d, NULL); if ( rc < 0 ) return rc; } - rc = prepare_dtb_domU(d, &kinfo); - if ( rc < 0 ) - return rc; - - rc = construct_domain(d, &kinfo); - if ( rc < 0 ) - return rc; - - domain_vcpu_affinity(d, node); - - return alloc_xenstore_params(&kinfo); + return rc; } - struct xen_domctl_createdomain __init arch_xen_domctl_createdomain(void) { struct xen_domctl_createdomain d_cfg = { @@ -1024,6 +357,22 @@ void __init arch_create_domus(struct dt_device_node *node, } } +int __init init_intc_phandle(struct kernel_info *kinfo, const char *name, + const int node_next, const void *pfdt) +{ + if ( dt_node_cmp(name, "gic") == 0 ) + { + uint32_t phandle_intc = fdt_get_phandle(pfdt, node_next); + + if ( phandle_intc != 0 ) + kinfo->phandle_intc = phandle_intc; + + return 0; + } + + return 1; +} + /* * Local variables: * mode: C diff --git a/xen/common/device-tree/dom0less-build.c b/xen/common/device-tree/dom0less-build.c index 19bfa5e005..9ee0e25deb 100644 --- a/xen/common/device-tree/dom0less-build.c +++ b/xen/common/device-tree/dom0less-build.c @@ -2,19 +2,36 @@ #include #include #include +#include #include +#include +#include +#include #include +#include #include +#include #include +#include #include #include #include +#include #include +#include #include #include +#ifdef CONFIG_STATIC_MEMORY +#include +#endif + +#ifdef CONFIG_STATIC_SHM +#include +#endif + bool __init is_dom0less_mode(void) { struct bootmodules *mods = &bootinfo.modules; @@ -159,3 +176,716 @@ void __init create_domUs(void) dt_node_name(node), rc); } } + +/* + * Scan device tree properties for passthrough specific information. + * Returns < 0 on error + * 0 on success + */ +static int __init handle_passthrough_prop(struct kernel_info *kinfo, + const struct fdt_property *xen_reg, + const struct fdt_property *xen_path, + bool xen_force, + uint32_t address_cells, + uint32_t size_cells) +{ + const __be32 *cell; + unsigned int i, len; + struct dt_device_node *node; + int res; + paddr_t mstart, size, gstart; + + /* xen,reg specifies where to map the MMIO region */ + cell = (const __be32 *)xen_reg->data; + len = fdt32_to_cpu(xen_reg->len) / ((address_cells * 2 + size_cells) * + sizeof(uint32_t)); + + for ( i = 0; i < len; i++ ) + { + device_tree_get_reg(&cell, address_cells, size_cells, + &mstart, &size); + gstart = dt_next_cell(address_cells, &cell); + + if ( gstart & ~PAGE_MASK || mstart & ~PAGE_MASK || size & ~PAGE_MASK ) + { + printk(XENLOG_ERR + "DomU passthrough config has not page aligned addresses/sizes\n"); + return -EINVAL; + } + + res = iomem_permit_access(kinfo->d, paddr_to_pfn(mstart), + paddr_to_pfn(PAGE_ALIGN(mstart + size - 1))); + if ( res ) + { + printk(XENLOG_ERR "Unable to permit to dom%d access to" + " 0x%"PRIpaddr" - 0x%"PRIpaddr"\n", + kinfo->d->domain_id, + mstart & PAGE_MASK, PAGE_ALIGN(mstart + size) - 1); + return res; + } + + res = map_regions_p2mt(kinfo->d, + gaddr_to_gfn(gstart), + PFN_DOWN(size), + maddr_to_mfn(mstart), + p2m_mmio_direct_dev); + if ( res < 0 ) + { + printk(XENLOG_ERR + "Failed to map %"PRIpaddr" to the guest at%"PRIpaddr"\n", + mstart, gstart); + return -EFAULT; + } + } + + /* + * If xen_force, we let the user assign a MMIO region with no + * associated path. + */ + if ( xen_path == NULL ) + return xen_force ? 0 : -EINVAL; + + /* + * xen,path specifies the corresponding node in the host DT. + * Both interrupt mappings and IOMMU settings are based on it, + * as they are done based on the corresponding host DT node. + */ + node = dt_find_node_by_path(xen_path->data); + if ( node == NULL ) + { + printk(XENLOG_ERR "Couldn't find node %s in host_dt!\n", + xen_path->data); + return -EINVAL; + } + + res = map_device_irqs_to_domain(kinfo->d, node, true, NULL); + if ( res < 0 ) + return res; + + res = iommu_add_dt_device(node); + if ( res < 0 ) + return res; + + /* If xen_force, we allow assignment of devices without IOMMU protection. */ + if ( xen_force && !dt_device_is_protected(node) ) + return 0; + + return iommu_assign_dt_device(kinfo->d, node); +} + +static int __init handle_prop_pfdt(struct kernel_info *kinfo, + const void *pfdt, int nodeoff, + uint32_t address_cells, uint32_t size_cells, + bool scan_passthrough_prop) +{ + void *fdt = kinfo->fdt; + int propoff, nameoff, res; + const struct fdt_property *prop, *xen_reg = NULL, *xen_path = NULL; + const char *name; + bool found, xen_force = false; + + for ( propoff = fdt_first_property_offset(pfdt, nodeoff); + propoff >= 0; + propoff = fdt_next_property_offset(pfdt, propoff) ) + { + if ( !(prop = fdt_get_property_by_offset(pfdt, propoff, NULL)) ) + return -FDT_ERR_INTERNAL; + + found = false; + nameoff = fdt32_to_cpu(prop->nameoff); + name = fdt_string(pfdt, nameoff); + + if ( scan_passthrough_prop ) + { + if ( dt_prop_cmp("xen,reg", name) == 0 ) + { + xen_reg = prop; + found = true; + } + else if ( dt_prop_cmp("xen,path", name) == 0 ) + { + xen_path = prop; + found = true; + } + else if ( dt_prop_cmp("xen,force-assign-without-iommu", + name) == 0 ) + { + xen_force = true; + found = true; + } + } + + /* + * Copy properties other than the ones above: xen,reg, xen,path, + * and xen,force-assign-without-iommu. + */ + if ( !found ) + { + res = fdt_property(fdt, name, prop->data, fdt32_to_cpu(prop->len)); + if ( res ) + return res; + } + } + + /* + * Only handle passthrough properties if both xen,reg and xen,path + * are present, or if xen,force-assign-without-iommu is specified. + */ + if ( xen_reg != NULL && (xen_path != NULL || xen_force) ) + { + res = handle_passthrough_prop(kinfo, xen_reg, xen_path, xen_force, + address_cells, size_cells); + if ( res < 0 ) + { + printk(XENLOG_ERR "Failed to assign device to %pd\n", kinfo->d); + return res; + } + } + else if ( (xen_path && !xen_reg) || (xen_reg && !xen_path && !xen_force) ) + { + printk(XENLOG_ERR "xen,reg or xen,path missing for %pd\n", + kinfo->d); + return -EINVAL; + } + + /* FDT_ERR_NOTFOUND => There is no more properties for this node */ + return ( propoff != -FDT_ERR_NOTFOUND ) ? propoff : 0; +} + +static int __init scan_pfdt_node(struct kernel_info *kinfo, const void *pfdt, + int nodeoff, + uint32_t address_cells, uint32_t size_cells, + bool scan_passthrough_prop) +{ + int rc = 0; + void *fdt = kinfo->fdt; + int node_next; + + rc = fdt_begin_node(fdt, fdt_get_name(pfdt, nodeoff, NULL)); + if ( rc ) + return rc; + + rc = handle_prop_pfdt(kinfo, pfdt, nodeoff, address_cells, size_cells, + scan_passthrough_prop); + if ( rc ) + return rc; + + address_cells = device_tree_get_u32(pfdt, nodeoff, "#address-cells", + DT_ROOT_NODE_ADDR_CELLS_DEFAULT); + size_cells = device_tree_get_u32(pfdt, nodeoff, "#size-cells", + DT_ROOT_NODE_SIZE_CELLS_DEFAULT); + + node_next = fdt_first_subnode(pfdt, nodeoff); + while ( node_next > 0 ) + { + rc = scan_pfdt_node(kinfo, pfdt, node_next, address_cells, size_cells, + scan_passthrough_prop); + if ( rc ) + return rc; + + node_next = fdt_next_subnode(pfdt, node_next); + } + + return fdt_end_node(fdt); +} + +static int __init check_partial_fdt(void *pfdt, size_t size) +{ + int res; + + if ( fdt_magic(pfdt) != FDT_MAGIC ) + { + dprintk(XENLOG_ERR, "Partial FDT is not a valid Flat Device Tree"); + return -EINVAL; + } + + res = fdt_check_header(pfdt); + if ( res ) + { + dprintk(XENLOG_ERR, "Failed to check the partial FDT (%d)", res); + return -EINVAL; + } + + if ( fdt_totalsize(pfdt) > size ) + { + dprintk(XENLOG_ERR, "Partial FDT totalsize is too big"); + return -EINVAL; + } + + return 0; +} + +static int __init domain_handle_dtb_bootmodule(struct domain *d, + struct kernel_info *kinfo) +{ + void *pfdt; + int res, node_next; + + pfdt = ioremap_cache(kinfo->dtb_bootmodule->start, + kinfo->dtb_bootmodule->size); + if ( pfdt == NULL ) + return -EFAULT; + + res = check_partial_fdt(pfdt, kinfo->dtb_bootmodule->size); + if ( res < 0 ) + goto out; + + for ( node_next = fdt_first_subnode(pfdt, 0); + node_next > 0; + node_next = fdt_next_subnode(pfdt, node_next) ) + { + const char *name = fdt_get_name(pfdt, node_next, NULL); + + if ( name == NULL ) + continue; + + /* + * Only scan /$(interrupt_controller) /aliases /passthrough, + * ignore the rest. + * They don't have to be parsed in order. + * + * Take the interrupt controller phandle value from the special + * interrupt controller node in the DTB fragment. + */ + if ( init_intc_phandle(kinfo, name, node_next, pfdt) == 0 ) + continue; + + if ( dt_node_cmp(name, "aliases") == 0 ) + { + res = scan_pfdt_node(kinfo, pfdt, node_next, + DT_ROOT_NODE_ADDR_CELLS_DEFAULT, + DT_ROOT_NODE_SIZE_CELLS_DEFAULT, + false); + if ( res ) + goto out; + continue; + } + if ( dt_node_cmp(name, "passthrough") == 0 ) + { + res = scan_pfdt_node(kinfo, pfdt, node_next, + DT_ROOT_NODE_ADDR_CELLS_DEFAULT, + DT_ROOT_NODE_SIZE_CELLS_DEFAULT, + true); + if ( res ) + goto out; + continue; + } + } + + out: + iounmap(pfdt); + + return res; +} + +/* + * The max size for DT is 2MB. However, the generated DT is small (not including + * domU passthrough DT nodes whose size we account separately), 4KB are enough + * for now, but we might have to increase it in the future. + */ +#define DOMU_DTB_SIZE 4096 +static int __init prepare_dtb_domU(struct domain *d, struct kernel_info *kinfo) +{ + int addrcells, sizecells; + int ret, fdt_size = DOMU_DTB_SIZE; + + kinfo->phandle_intc = GUEST_PHANDLE_GIC; + +#ifdef CONFIG_GRANT_TABLE + kinfo->gnttab_start = GUEST_GNTTAB_BASE; + kinfo->gnttab_size = GUEST_GNTTAB_SIZE; +#endif + + addrcells = GUEST_ROOT_ADDRESS_CELLS; + sizecells = GUEST_ROOT_SIZE_CELLS; + + /* Account for domU passthrough DT size */ + if ( kinfo->dtb_bootmodule ) + fdt_size += kinfo->dtb_bootmodule->size; + + /* Cap to max DT size if needed */ + fdt_size = min(fdt_size, SZ_2M); + + kinfo->fdt = xmalloc_bytes(fdt_size); + if ( kinfo->fdt == NULL ) + return -ENOMEM; + + ret = fdt_create(kinfo->fdt, fdt_size); + if ( ret < 0 ) + goto err; + + ret = fdt_finish_reservemap(kinfo->fdt); + if ( ret < 0 ) + goto err; + + ret = fdt_begin_node(kinfo->fdt, ""); + if ( ret < 0 ) + goto err; + + ret = fdt_property_cell(kinfo->fdt, "#address-cells", addrcells); + if ( ret ) + goto err; + + ret = fdt_property_cell(kinfo->fdt, "#size-cells", sizecells); + if ( ret ) + goto err; + + ret = make_chosen_node(kinfo); + if ( ret ) + goto err; + + ret = make_cpus_node(d, kinfo->fdt); + if ( ret ) + goto err; + + ret = make_memory_node(kinfo, addrcells, sizecells, + kernel_info_get_mem(kinfo)); + if ( ret ) + goto err; + +#ifdef CONFIG_STATIC_SHM + ret = make_resv_memory_node(kinfo, addrcells, sizecells); + if ( ret ) + goto err; +#endif + + /* + * domain_handle_dtb_bootmodule has to be called before the rest of + * the device tree is generated because it depends on the value of + * the field phandle_intc. + */ + if ( kinfo->dtb_bootmodule ) + { + ret = domain_handle_dtb_bootmodule(d, kinfo); + if ( ret ) + goto err; + } + + ret = make_intc_domU_node(kinfo); + if ( ret ) + goto err; + + ret = make_timer_node(kinfo); + if ( ret ) + goto err; + + if ( kinfo->dom0less_feature & DOM0LESS_ENHANCED_NO_XS ) + { + ret = make_hypervisor_node(d, kinfo, addrcells, sizecells); + if ( ret ) + goto err; + } + + ret = make_arch_nodes(kinfo); + if ( ret ) + goto err; + + ret = fdt_end_node(kinfo->fdt); + if ( ret < 0 ) + goto err; + + ret = fdt_finish(kinfo->fdt); + if ( ret < 0 ) + goto err; + + return 0; + + err: + printk("Device tree generation failed (%d).\n", ret); + xfree(kinfo->fdt); + + return -EINVAL; +} + +static int __init alloc_xenstore_evtchn(struct domain *d) +{ + evtchn_alloc_unbound_t alloc; + int rc; + + alloc.dom = d->domain_id; + alloc.remote_dom = hardware_domain->domain_id; + rc = evtchn_alloc_unbound(&alloc, 0); + if ( rc ) + { + printk("Failed allocating event channel for domain\n"); + return rc; + } + +#ifdef CONFIG_HVM + d->arch.hvm.params[HVM_PARAM_STORE_EVTCHN] = alloc.port; +#endif + + return 0; +} + +#define XENSTORE_PFN_OFFSET 1 +static int __init alloc_xenstore_page(struct domain *d) +{ + struct page_info *xenstore_pg; + struct xenstore_domain_interface *interface; + mfn_t mfn; + gfn_t gfn; + int rc; + + if ( (UINT_MAX - d->max_pages) < 1 ) + { + printk(XENLOG_ERR "%pd: Over-allocation for d->max_pages by 1 page.\n", + d); + return -EINVAL; + } + + d->max_pages += 1; + xenstore_pg = alloc_domheap_page(d, MEMF_bits(32)); + if ( xenstore_pg == NULL && is_64bit_domain(d) ) + xenstore_pg = alloc_domheap_page(d, 0); + if ( xenstore_pg == NULL ) + return -ENOMEM; + + mfn = page_to_mfn(xenstore_pg); + if ( !mfn_x(mfn) ) + return -ENOMEM; + + if ( !is_domain_direct_mapped(d) ) + gfn = gaddr_to_gfn(GUEST_MAGIC_BASE + + (XENSTORE_PFN_OFFSET << PAGE_SHIFT)); + else + gfn = gaddr_to_gfn(mfn_to_maddr(mfn)); + + rc = guest_physmap_add_page(d, gfn, mfn, 0); + if ( rc ) + { + free_domheap_page(xenstore_pg); + return rc; + } + +#ifdef CONFIG_HVM + d->arch.hvm.params[HVM_PARAM_STORE_PFN] = gfn_x(gfn); +#endif + interface = map_domain_page(mfn); + interface->connection = XENSTORE_RECONNECT; + unmap_domain_page(interface); + + return 0; +} + +static int __init alloc_xenstore_params(struct kernel_info *kinfo) +{ + struct domain *d = kinfo->d; + int rc = 0; + + if ( kinfo->dom0less_feature & (DOM0LESS_XENSTORE | DOM0LESS_XS_LEGACY) ) + { + ASSERT(hardware_domain); + rc = alloc_xenstore_evtchn(d); + if ( rc < 0 ) + return rc; + +#ifdef CONFIG_HVM + d->arch.hvm.params[HVM_PARAM_STORE_PFN] = ~0ULL; +#endif + } + + if ( kinfo->dom0less_feature & DOM0LESS_XENSTORE ) + { + rc = alloc_xenstore_page(d); + if ( rc < 0 ) + return rc; + } + + return rc; +} + + +static void __init domain_vcpu_affinity(struct domain *d, + const struct dt_device_node *node) +{ + struct dt_device_node *np; + + dt_for_each_child_node(node, np) + { + const char *hard_affinity_str = NULL; + uint32_t val; + int rc; + struct vcpu *v; + cpumask_t affinity; + + if ( !dt_device_is_compatible(np, "xen,vcpu") ) + continue; + + if ( !dt_property_read_u32(np, "id", &val) ) + panic("Invalid xen,vcpu node for domain %s\n", dt_node_name(node)); + + if ( val >= d->max_vcpus ) + panic("Invalid vcpu_id %u for domain %s, max_vcpus=%u\n", val, + dt_node_name(node), d->max_vcpus); + + v = d->vcpu[val]; + rc = dt_property_read_string(np, "hard-affinity", &hard_affinity_str); + if ( rc < 0 ) + continue; + + cpumask_clear(&affinity); + while ( *hard_affinity_str != '\0' ) + { + unsigned int start, end; + + start = simple_strtoul(hard_affinity_str, &hard_affinity_str, 0); + + if ( *hard_affinity_str == '-' ) /* Range */ + { + hard_affinity_str++; + end = simple_strtoul(hard_affinity_str, &hard_affinity_str, 0); + } + else /* Single value */ + end = start; + + if ( end >= nr_cpu_ids ) + panic("Invalid pCPU %u for domain %s\n", end, dt_node_name(node)); + + for ( ; start <= end; start++ ) + cpumask_set_cpu(start, &affinity); + + if ( *hard_affinity_str == ',' ) + hard_affinity_str++; + else if ( *hard_affinity_str != '\0' ) + break; + } + + rc = vcpu_set_hard_affinity(v, &affinity); + if ( rc ) + panic("vcpu%d: failed (rc=%d) to set hard affinity for domain %s\n", + v->vcpu_id, rc, dt_node_name(node)); + } +} + +#ifdef CONFIG_ARCH_PAGING_MEMPOOL +static unsigned long __init domain_p2m_pages(unsigned long maxmem_kb, + unsigned int smp_cpus) +{ + /* + * Keep in sync with libxl__get_required_paging_memory(). + * 256 pages (1MB) per vcpu, plus 1 page per MiB of RAM for the P2M map, + * plus 128 pages to cover extended regions. + */ + unsigned long memkb = 4 * (256 * smp_cpus + (maxmem_kb / 1024) + 128); + + BUILD_BUG_ON(PAGE_SIZE != SZ_4K); + + return DIV_ROUND_UP(memkb, 1024) << (20 - PAGE_SHIFT); +} + +static int __init domain_p2m_set_allocation(struct domain *d, uint64_t mem, + const struct dt_device_node *node) +{ + unsigned long p2m_pages; + uint32_t p2m_mem_mb; + int rc; + + rc = dt_property_read_u32(node, "xen,domain-p2m-mem-mb", &p2m_mem_mb); + /* If xen,domain-p2m-mem-mb is not specified, use the default value. */ + p2m_pages = rc ? + p2m_mem_mb << (20 - PAGE_SHIFT) : + domain_p2m_pages(mem, d->max_vcpus); + + spin_lock(&d->arch.paging.lock); + rc = p2m_set_allocation(d, p2m_pages, NULL); + spin_unlock(&d->arch.paging.lock); + + return rc; +} +#else /* !CONFIG_ARCH_PAGING_MEMPOOL */ +static inline int domain_p2m_set_allocation(struct domain *d, uint64_t mem, + const struct dt_device_node *node) +{ + return 0; +} +#endif /* CONFIG_ARCH_PAGING_MEMPOOL */ + + +int __init construct_domU(struct domain *d, + const struct dt_device_node *node) +{ + struct kernel_info kinfo = KERNEL_INFO_INIT; + const char *dom0less_enhanced; + int rc; + u64 mem; + + rc = dt_property_read_u64(node, "memory", &mem); + if ( !rc ) + { + printk("Error building DomU: cannot read \"memory\" property\n"); + return -EINVAL; + } + kinfo.unassigned_mem = (paddr_t)mem * SZ_1K; + + rc = domain_p2m_set_allocation(d, mem, node); + if ( rc != 0 ) + return rc; + + printk("*** LOADING DOMU cpus=%u memory=%#"PRIx64"KB ***\n", + d->max_vcpus, mem); + + rc = dt_property_read_string(node, "xen,enhanced", &dom0less_enhanced); + if ( rc == -EILSEQ || + rc == -ENODATA || + (rc == 0 && !strcmp(dom0less_enhanced, "enabled")) ) + { + if ( hardware_domain ) + kinfo.dom0less_feature = DOM0LESS_ENHANCED; + else + panic("At the moment, Xenstore support requires dom0 to be present\n"); + } + else if ( rc == 0 && !strcmp(dom0less_enhanced, "legacy") ) + { + if ( hardware_domain ) + kinfo.dom0less_feature = DOM0LESS_ENHANCED_LEGACY; + else + panic("At the moment, Xenstore support requires dom0 to be present\n"); + } + else if ( rc == 0 && !strcmp(dom0less_enhanced, "no-xenstore") ) + kinfo.dom0less_feature = DOM0LESS_ENHANCED_NO_XS; + + if ( vcpu_create(d, 0) == NULL ) + return -ENOMEM; + + d->max_pages = ((paddr_t)mem * SZ_1K) >> PAGE_SHIFT; + + kinfo.d = d; + + rc = kernel_probe(&kinfo, node); + if ( rc < 0 ) + return rc; + + set_domain_type(d, &kinfo); + + if ( !dt_find_property(node, "xen,static-mem", NULL) ) + allocate_memory(d, &kinfo); +#ifdef CONFIG_STATIC_MEMORY + else if ( !is_domain_direct_mapped(d) ) + allocate_static_memory(d, &kinfo, node); + else + assign_static_memory_11(d, &kinfo, node); +#endif + +#ifdef CONFIG_STATIC_SHM + rc = process_shm(d, &kinfo, node); + if ( rc < 0 ) + return rc; +#endif + + rc = init_vuart(d, &kinfo, node); + if ( rc < 0 ) + return rc; + + rc = prepare_dtb_domU(d, &kinfo); + if ( rc < 0 ) + return rc; + + rc = construct_domain(d, &kinfo); + if ( rc < 0 ) + return rc; + + domain_vcpu_affinity(d, node); + + return alloc_xenstore_params(&kinfo); +} diff --git a/xen/include/asm-generic/dom0less-build.h b/xen/include/asm-generic/dom0less-build.h index 7092f7fc7e..901cd0eb7b 100644 --- a/xen/include/asm-generic/dom0less-build.h +++ b/xen/include/asm-generic/dom0less-build.h @@ -36,6 +36,9 @@ #define DOM0LESS_ENHANCED_LEGACY (DOM0LESS_ENHANCED_NO_XS | DOM0LESS_XS_LEGACY) #define DOM0LESS_ENHANCED (DOM0LESS_ENHANCED_NO_XS | DOM0LESS_XENSTORE) +struct kernel_info; +struct dt_device_node; + void create_domUs(void); bool is_dom0less_mode(void); @@ -46,6 +49,17 @@ void arch_create_domus(struct dt_device_node *node, struct xen_domctl_createdomain *d_cfg, unsigned int flags); +int init_vuart(struct domain *d, struct kernel_info *kinfo, + const struct dt_device_node *node); + +int make_intc_domU_node(struct kernel_info *kinfo); +int make_arch_nodes(struct kernel_info *kinfo); + +void set_domain_type(struct domain *d, struct kernel_info *kinfo); + +int init_intc_phandle(struct kernel_info *kinfo, const char *name, + const int node_next, const void *pfdt); + #else /* !CONFIG_DOM0LESS_BOOT */ static inline void create_domUs(void) {}