From nobody Fri Dec 12 14:05:28 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; arc=fail (Bad Signature); dmarc=pass(p=reject dis=none) header.from=lists.libvirt.org Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1764098640818714.4696822638407; Tue, 25 Nov 2025 11:24:00 -0800 (PST) Received: by lists.libvirt.org (Postfix, from userid 993) id D8B7B43EE8; Tue, 25 Nov 2025 14:23:58 -0500 (EST) Received: from [172.19.199.68] (lists.libvirt.org [8.43.85.245]) by lists.libvirt.org (Postfix) with ESMTP id A2C8344C53; Tue, 25 Nov 2025 14:17:42 -0500 (EST) Received: by lists.libvirt.org (Postfix, from userid 993) id A9AE544B6F; Tue, 25 Nov 2025 14:17:25 -0500 (EST) Received: from BYAPR05CU005.outbound.protection.outlook.com (mail-westusazon11010032.outbound.protection.outlook.com [52.101.85.32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (prime256v1) server-signature RSA-PSS (3072 bits) server-digest SHA256) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id C01124495C for ; Tue, 25 Nov 2025 14:17:19 -0500 (EST) Received: from PH7PR12MB6834.namprd12.prod.outlook.com (2603:10b6:510:1b4::18) by MW6PR12MB9000.namprd12.prod.outlook.com (2603:10b6:303:24b::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9343.17; Tue, 25 Nov 2025 19:17:09 +0000 Received: from PH7PR12MB6834.namprd12.prod.outlook.com ([fe80::f432:162b:b94e:d2cb]) by PH7PR12MB6834.namprd12.prod.outlook.com ([fe80::f432:162b:b94e:d2cb%6]) with mapi id 15.20.9343.016; Tue, 25 Nov 2025 19:17:09 +0000 X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-5.0 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIM_INVALID,DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED,RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED,SPF_PASS autolearn=unavailable autolearn_force=no version=4.0.1 ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=xaiJtqYiY02jOMzP4d/6bAAq0RaBQNs/H9LurEskvn4IL3fg6GZ4M939+rix9tIqAlPCPxdQgrIbUh6SNFthDnNJV2g/aK4ebv/fVjscZWOR5jgo/2mkvI7wzi9V6IRK8VWGpVG9KWtAJKDC1wFTfn+AZR5s4DwbXNt/rfFvbYrtD4tz0bW3qGpaVuuLzazzEmtMaOhVDcxzJ50WVdwQivCWxcn2ukkM81PSKmaeJ98N89LwlmhLaxlDXcso46ip52f3Ve07X+Q/UaIH0TrrlA98IJqsUFFizaofmHIGwObLCH/Wqq8yTFuWR97Ty0kc41frHot6Canz4xsUGcLC/w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=RRFhH3YtUC10dec+XaD0VCrthSfDyi15ufo+Gw3+Pe4=; b=QaIO9GHApx7KnmP57kxWkCerCA+/vrCAcr3Y1NKkjXHrOBgwi4I1GaXY/EnAFhRXOpGIbhgYLq1S2GE1gVaGriK4zI43i+GZNHQvBxax2W8X6n/Z6jt0VyZ3bkC32/8BkrQZI4B5TmV13quNi2WePViKBTaajLlHXq3hs3H8MAOwbNnBRya83WX93SwdRbptm62ALXdrA80u+QuJy9dS9um0oHGbEhXVif/3RLDXr3uflkZiTfoSQYPCF3SV9IXWwLOReaiw/lvRE3s8Q6AT9Jika69w/7V4eQpz3bVmmQE+PvesNt48mVhyqk8UnPGKyMr5lBBxGX/GLd7riK49og== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nvidia.com; dmarc=pass action=none header.from=nvidia.com; dkim=pass header.d=nvidia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=RRFhH3YtUC10dec+XaD0VCrthSfDyi15ufo+Gw3+Pe4=; b=g3MpnhfFfVG0Crcgp9PA/hQBVRFnXkCfvRE3Ecdw36Ziw6dlum26In680WhGNDgyMDwbV8DhKt73kLCEVOp1s8NFGf6FBDoysvVQEJMqee0WkR/E9BGE0b/eAvk1D44As2Zk8nYTXuluCW/kSpZg5m+rXD1u3cnRRbZ3hnjyfVxXpKnChxOCb0lknrTG1ZRzpb3rYNBy7ZIHizTZo9J43CEjyS4uAlPXQXF71GHUDNrNczWR1kCPJrQI36MLjPXQhd/kEK/QEZ82z3wI8SWAFtxtgp15ZKG7ZdQQwCHikaIczzNXnWPWFgGHtLDrMUYZUrBMYi8svJbu/WWO3lzlsA== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; To: devel@lists.libvirt.org Subject: [RFC PATCH v3 3/4] qemu: Add qemu CLI support for EGM Date: Tue, 25 Nov 2025 11:17:03 -0800 Message-ID: <20251125191704.644477-4-nathanc@nvidia.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251125191704.644477-1-nathanc@nvidia.com> References: <20251125191704.644477-1-nathanc@nvidia.com> Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: SJ0PR03CA0065.namprd03.prod.outlook.com (2603:10b6:a03:331::10) To PH7PR12MB6834.namprd12.prod.outlook.com (2603:10b6:510:1b4::18) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PH7PR12MB6834:EE_|MW6PR12MB9000:EE_ X-MS-Office365-Filtering-Correlation-Id: 30632a13-7392-44ed-1a9f-08de2c573ace X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|366016|1800799024; X-Microsoft-Antispam-Message-Info: =?us-ascii?Q?jVAZ2+Mq/zNCU32ymqNoh4o/6ZqgUl/4PlpAxUKIhKA1kh1lhatGV4c4xtOD?= =?us-ascii?Q?AvyMi1HNLv9JWEZR8wx2//lFrbtiXUD4GirGWP1rqrTjp0nVJ4f9osHaf67U?= =?us-ascii?Q?8nQoMdUphG/KQP1tioM8CBFfopXrEw6S08lzbVCATazVpBjnEiv0msyTiq2M?= =?us-ascii?Q?49TcALpAu7w68FapM/r6ZCjwSy2TpwEOm3WYq4t55Hg7zG6pyDQwZ+Fmu55W?= =?us-ascii?Q?VEI+UnY27t3L6ebxUkcWRtQIe18qNMkuZ9lzVIPuWdg4CQW1dH/wQ1AhcsnK?= =?us-ascii?Q?bbkIxC7AoH6PeTQicUZxItBqC9KU/EVrgafOTKubz6jk3SFgiz2r4lRohJ/x?= =?us-ascii?Q?US/fLLMatVHNgLu0zGw21Y6/z37fRZjjP/1t+l6C6l3OJNpd6Rn976gD+QIS?= =?us-ascii?Q?yDnHn9w23GaSFTwM74ZUi2J20VD336vhU/xLZE/j4FUzli4yGJjF59pdMAWE?= =?us-ascii?Q?Lr7OVIrQopovqURG+h6DcYnVJZRJuEDgtWSIUMKDqGDBIqkWju9cRSk/zVCV?= =?us-ascii?Q?UEY2YRlgKQhGPOpiDKF4rr0cjah8hZPUSlL7tUUqNgXdw+WJIII0BThli2w2?= =?us-ascii?Q?PMuQRGiYaTFJdShKOmScrKSVdrTrgPE6zaEBqaVrL7Fj54VncqUolev7qEng?= =?us-ascii?Q?iuwoetNi9bE5GudgZwGVo/JioN34oFIJdfDOnzfpYjy7Ki+LPWUluHnzX/NK?= =?us-ascii?Q?puZ65ecQSybWBoUnOUi5DEmscuRCvgxL+MWWoofNqDcLTg9jrsrxJIK+BhCe?= =?us-ascii?Q?QW5NQJyntSQSiwX+dmJcQHYyF8uNO1dqjmvQinVboQ/BIsiOMxOIX4xKWX7l?= =?us-ascii?Q?9LBrg/jPR3nYaAUxq2J19dc+YQTFd+H6qQCwNegEtCPQYOyVqJvg6MfSg4yQ?= =?us-ascii?Q?MAgNjKPaN4xiHdW1C84VBV3lV/U1oXS465dEhLyiKL0fB0rz9uq90DPeh2rH?= =?us-ascii?Q?mf0V7svEEnsogHOk+wD0y5WoO2g7ZRBtYOH9I2b3FuuopY+kU0JkUliRj2PS?= =?us-ascii?Q?TQ8L13rVNyOxeEKkPyKMwWq+cdu/Meg8HV/V+t3bc+y1+yG3yMuWQmzgvOr+?= =?us-ascii?Q?R1YArkJ+dcmsozxRQO6UFKXqS9xOF4F7jzYJEgqfiFprdNo3zeTk7rHIQSvt?= =?us-ascii?Q?15pLjTglBECd7PUfaRZD5gc8y2xKm+regg8XZ1YDR5oLGDuLmdT8xfp5VS8C?= =?us-ascii?Q?5EVnbioY5qQeTWb5cod5lLKft66INqDCsy+940g4uSZX2QI+NvXFIIM8BJTM?= =?us-ascii?Q?L99Wz88xW4TSjiNOQVUk4ha1Tzlmw5iNDyq37FSJHM6jsN1K1Rge+qPe/yvL?= =?us-ascii?Q?BBWOkh2c3MLzv7RQc1QMP2UZhPowHChMH0ckP9d/gx9CSvDUh5nTXN5N2OFi?= =?us-ascii?Q?iZ/+R1uNrBhPXFcWSG67vr5zJUzI/mn3K0VBuP8gUHl4ie6cppxzGp4NOeio?= =?us-ascii?Q?Z6WD0CvaJ8Bl2sihsCQ/cgwfnQFp3j/n?= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:PH7PR12MB6834.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(376014)(366016)(1800799024);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?5FnMJeL/rZc8sm3ociAkrLLH+27uMMH/PsoyUcAbws0ZFJ+3D/+0ZKnhop1d?= =?us-ascii?Q?pnX4CSQQqbRYwVFgHBEJt8ASXxKXbhxAcmwedPdiMav+Se/v8ChsyQkX79oN?= =?us-ascii?Q?KXOx04tjAxv9yoTnbPrq0J/IjX1nPJElui4AARtfxZE8xSZIuDp0Opg5Su8s?= =?us-ascii?Q?d5WhFhCCaxS81kTTtVCqKh/PMA17Bu5uZpAq60e8Zfb9eLhIQPai+fxsHXQF?= =?us-ascii?Q?KHFclbe3XJQmlofRsPTcYCeP72sbmrZQ6gBrf+Z4XJTjl539j4lE9PsqnSFs?= =?us-ascii?Q?vmPU1gV8WoWe8+VDHN/llSIYZ7I8jLsOfXlWBfS+VcXPT/IcsrtnFixvSTSD?= =?us-ascii?Q?OM85Ln8vZQLhxGyvEcBMznzIzwdnmVi1gX4059RfUXdAXjBoco6uVsRYw3o3?= =?us-ascii?Q?aE57KwzZCx9xF1rgmmczDBONpAKWFyp+ys+3a/3knbsrGRiGz4v75v7r1RSb?= =?us-ascii?Q?SEvUiRleOcBqOurfoQXf9wkx6MOosVILix3XHqChoERi5xX3vZ3a5Xnb2Ibs?= =?us-ascii?Q?VJN7gBOWKllblh5Coe4fN+8HadljLnRaBBrnWel0+HlMCX63WSFvKrUN9hrT?= =?us-ascii?Q?KNzmJrIJhYeWdf3MYx7WXsMxkHl4bncMOOvb90bskbOAlqoHwYeZFRplPJXq?= =?us-ascii?Q?uUz8CzATncPGOnErBqsdu3jlqyNPMTl0rwPP7WYnJkg87EWrrTV9uFD37+eN?= =?us-ascii?Q?h77nboBe05dO9y5rNpnas8bvj1WGJzq3Oh7ywutxsJkkIMxIHjNTbOQFcm2Q?= =?us-ascii?Q?dfDH4xdK9SIoWFm/wVbzzF09K1h1/clxijUCjErevCf6zLhMQ4VhVVp39EsU?= =?us-ascii?Q?arZLeMtpLpXXAYRFL9ESC9KguDHmQB3C1LJpx9VhD5ejwFIf6b27Y1JEpAfv?= =?us-ascii?Q?Yw5cWVFzu04FnClRL1ATIjMwzTm0P8RUQDkmRaepSOl4qyu08P3NRRschByY?= =?us-ascii?Q?VFbLJFubd+EFWmCCiEgg8Ol+KJJh/2bp5TrQ42EMDEGVpp2TY7HvUBTPsAvU?= =?us-ascii?Q?Uh/WHd8twZSO0gg562f4VOZBxyZi1buguZGLgnXp0iosuqXU+sQszmOFWiw9?= =?us-ascii?Q?NuXExPcthU4ByL5EE69HFzTFHtE+uCqEevWeKtniBRLaIt/2JGmPVZ92t4km?= =?us-ascii?Q?sM8diEnLA79wWv06Klfe0Wu/72rwI5J4bVFc8jEqJZN5jUtj48m6ZRzW7AjZ?= =?us-ascii?Q?1L6ECHuN5iCIn8sMgWicISa3D6Muzy/eGjPJXWCF5Zvcr0m3Q0xmUrY/W6LQ?= =?us-ascii?Q?AlAyCc8SCfeQ9n9+srn+p/P3eAw75sPsnHSY+9QcImuJaLH4FWIGIWJ+CEHj?= =?us-ascii?Q?10ByLXkUHELUa0ImGqzItQ5u6fCD5TVy2AHMatugEHiL3Qh89g6U0cvzoWQ6?= =?us-ascii?Q?ovF8zSZH7rnpvavBJFpOKng8R5LkoRTXANX3OVWMnAJoLYQU3JE1lNyJKF5q?= =?us-ascii?Q?qKoGkCNb0PqTLMFY14h2CJaour6lv4m+fJVxiavmF4V1D5dgjaNbHhSDfARc?= =?us-ascii?Q?1CoFtd+zdHoMCZuP4CMNmGq1GCtscrkhEuYpq4NjDT/DP98TQ+YXgXdP0k8w?= =?us-ascii?Q?xxkjWNufkNlRSefoHRW8I+caA2OVmo8dsL48a6DQ?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 30632a13-7392-44ed-1a9f-08de2c573ace X-MS-Exchange-CrossTenant-AuthSource: PH7PR12MB6834.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 25 Nov 2025 19:17:09.4849 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: AC443Sn732P+LBJOyGyi7SjfhmceR+IQHjpu39cjoPIUN2ymuUr3Jsp2oXSvxu+qGaLqKLeW4oUisKQYzAMFyA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: MW6PR12MB9000 Message-ID-Hash: ZGBZAZJ47Q46J6LYBQFLETALDQ6NKEHC X-Message-ID-Hash: ZGBZAZJ47Q46J6LYBQFLETALDQ6NKEHC X-MailFrom: nathanc@nvidia.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-devel.lists.libvirt.org-0; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: skolothumtho@nvidia.com, nicolinc@nvidia.com, nathanc@nvidia.com, mochs@nvidia.com X-Mailman-Version: 3.3.10 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Nathan Chen via Devel Reply-To: Nathan Chen X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1764098642144019100 Content-Type: text/plain; charset="utf-8" Add qemu CLI support for EGM memory device model: - Specify EGM device path to memory-backend-file object - Support acpi-egm-memory object with id, pci-dev, and node attributes - Consolidate all acpi-egm-memory objects' memory into a single memory-backend-file per EGM chardev specified. Signed-off-by: Ian May Signed-off-by: Nathan Chen --- src/qemu/qemu_alias.c | 7 +- src/qemu/qemu_capabilities.c | 2 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 158 ++++++++++++++++++++++++++++++--- src/qemu/qemu_domain.c | 13 ++- src/qemu/qemu_domain_address.c | 3 + src/qemu/qemu_driver.c | 1 + src/qemu/qemu_hotplug.c | 1 + src/qemu/qemu_monitor_json.c | 1 + src/qemu/qemu_postparse.c | 1 + src/qemu/qemu_process.c | 2 + src/qemu/qemu_validate.c | 6 ++ 12 files changed, 180 insertions(+), 16 deletions(-) diff --git a/src/qemu/qemu_alias.c b/src/qemu/qemu_alias.c index 400ce73283..719224e1ba 100644 --- a/src/qemu/qemu_alias.c +++ b/src/qemu/qemu_alias.c @@ -504,7 +504,8 @@ qemuDeviceMemoryGetAliasID(virDomainDef *def, * valid */ if (mem->model !=3D VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM && mem->model !=3D VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM && - mem->model !=3D VIR_DOMAIN_MEMORY_MODEL_SGX_EPC) + mem->model !=3D VIR_DOMAIN_MEMORY_MODEL_SGX_EPC && + mem->model !=3D VIR_DOMAIN_MEMORY_MODEL_EGM) return mem->info.addr.dimm.slot; =20 for (i =3D 0; i < def->nmems; i++) { @@ -553,6 +554,10 @@ qemuAssignDeviceMemoryAlias(virDomainDef *def, case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: prefix =3D "epc"; break; + case VIR_DOMAIN_MEMORY_MODEL_EGM: { + prefix =3D "egm"; + break; + } case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: default: diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 92b863a826..3fc8fee4b3 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -755,6 +755,7 @@ VIR_ENUM_IMPL(virQEMUCaps, "disk-timed-stats", /* QEMU_CAPS_DISK_TIMED_STATS */ "query-accelerators", /* QEMU_CAPS_QUERY_ACCELERATORS */ "mshv", /* QEMU_CAPS_MSHV */ + "acpi-egm-memory", /* QEMU_CAPS_DEVICE_ACPI_EGM_MEMORY */ ); =20 =20 @@ -1462,6 +1463,7 @@ struct virQEMUCapsStringFlags virQEMUCapsObjectTypes[= ] =3D { { "tpm-emulator", QEMU_CAPS_DEVICE_TPM_EMULATOR }, { "tpm-passthrough", QEMU_CAPS_DEVICE_TPM_PASSTHROUGH }, { "acpi-generic-initiator", QEMU_CAPS_ACPI_GENERIC_INITIATOR }, + { "acpi-egm-memory", QEMU_CAPS_DEVICE_ACPI_EGM_MEMORY }, }; =20 =20 diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index f180844e66..3eb12235f4 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -730,6 +730,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for = syntax-check */ QEMU_CAPS_DISK_TIMED_STATS, /* timed stats support ('stats-intervals' = property of disk frontends) */ QEMU_CAPS_QUERY_ACCELERATORS, /* query-accelerators command */ QEMU_CAPS_MSHV, /* -accel mshv */ + QEMU_CAPS_DEVICE_ACPI_EGM_MEMORY, /* For using extended GPU memory */ =20 QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index b69fe23236..33848aa781 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -135,6 +135,21 @@ VIR_ENUM_IMPL(qemuACPITableSIG, "SLIC", "MSDM"); =20 +typedef struct _qemuEGMBackendInfo { + char *alias; + unsigned long long totalSize; + bool created; + virDomainMemoryDef *firstMem; /* Pointer to first device for this pat= h */ +} qemuEGMBackendInfo; + +static void +qemuEGMBackendInfoFree(qemuEGMBackendInfo *info) +{ + if (!info) + return; + g_free(info->alias); + g_free(info); +} =20 const char * qemuAudioDriverTypeToString(virDomainAudioType type) @@ -992,6 +1007,7 @@ qemuBuildVirtioDevGetConfigDev(const virDomainDeviceDe= f *device, case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; @@ -3162,6 +3178,7 @@ qemuBuildMemoryGetPagesize(virQEMUDriverConfig *cfg, nvdimmPath =3D mem->source.virtio_pmem.path; break; case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; @@ -3362,6 +3379,9 @@ qemuBuildMemoryBackendProps(virJSONValue **backendPro= ps, case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: nvdimmPath =3D mem->source.virtio_pmem.path; break; + case VIR_DOMAIN_MEMORY_MODEL_EGM: + nvdimmPath =3D mem->source.egm.path; + break; case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; @@ -3573,12 +3593,17 @@ qemuBuildMemoryDimmBackendStr(virCommand *cmd, virDomainMemoryDef *mem, virDomainDef *def, virQEMUDriverConfig *cfg, - qemuDomainObjPrivate *priv) + qemuDomainObjPrivate *priv, + GHashTable *egmBackends) { g_autoptr(virJSONValue) props =3D NULL; g_autoptr(virJSONValue) tcProps =3D NULL; virBitmap *nodemask =3D NULL; g_autofree char *alias =3D NULL; + unsigned long long originalSize =3D 0; + bool isEGM =3D (mem->model =3D=3D VIR_DOMAIN_MEMORY_MODEL_EGM); + bool shouldCreateBackend =3D true; + qemuEGMBackendInfo *egmInfo =3D NULL; =20 if (!mem->info.alias) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -3588,19 +3613,65 @@ qemuBuildMemoryDimmBackendStr(virCommand *cmd, =20 alias =3D g_strdup_printf("mem%s", mem->info.alias); =20 - if (qemuBuildMemoryBackendProps(&props, alias, cfg, priv, - def, mem, true, false, &nodemask) < 0) - return -1; + /* Handle EGM shared backend logic */ + if (isEGM && egmBackends) { + const char *egmPath =3D mem->source.egm.path; + egmInfo =3D g_hash_table_lookup(egmBackends, egmPath); =20 - if (qemuBuildThreadContextProps(&tcProps, &props, def, priv, nodemask)= < 0) - return -1; + if (egmInfo) { + alias =3D g_strdup(egmInfo->alias); + if (egmInfo->created) { + /* Backend already created, skip backend creation */ + shouldCreateBackend =3D false; + } else { + /* First device for this path - temporarily use accumulate= d size */ + originalSize =3D mem->size; + mem->size =3D egmInfo->totalSize; + egmInfo->created =3D true; + } + } + } =20 - if (tcProps && - qemuBuildObjectCommandlineFromJSON(cmd, tcProps) < 0) - return -1; + if (shouldCreateBackend) { + /* Use existing function unchanged */ + if (qemuBuildMemoryBackendProps(&props, alias, cfg, priv, + def, mem, true, false, &nodemask) = < 0) { + if (originalSize > 0) + mem->size =3D originalSize; /* Restore on error */ + return -1; + } =20 - if (qemuBuildObjectCommandlineFromJSON(cmd, props) < 0) - return -1; + /* Restore original size after backend props are built */ + if (originalSize > 0) + mem->size =3D originalSize; + + if (qemuBuildThreadContextProps(&tcProps, &props, def, priv, nodem= ask) < 0) + return -1; + + if (tcProps && + qemuBuildObjectCommandlineFromJSON(cmd, tcProps) < 0) + return -1; + + if (qemuBuildObjectCommandlineFromJSON(cmd, props) < 0) + return -1; + } + + if (isEGM) { + g_autofree char *egmObjStr =3D NULL; + g_auto(virBuffer) buf =3D VIR_BUFFER_INITIALIZER; + + virBufferAsprintf(&buf, "acpi-egm-memory,id=3D%s", mem->info.alias= ); + + if (mem->target.egm.pciDev) + virBufferAsprintf(&buf, ",pci-dev=3D%s", mem->target.egm.pciDev= ); + + if (mem->targetNode >=3D 0) + virBufferAsprintf(&buf, ",node=3D%d", mem->targetNode); + + egmObjStr =3D virBufferContentAndReset(&buf); + + virCommandAddArgList(cmd, "-object", egmObjStr, NULL); + } =20 return 0; } @@ -3671,6 +3742,7 @@ qemuBuildMemoryDeviceProps(virQEMUDriverConfig *cfg, dynamicMemslots =3D mem->target.virtio_mem.dynamicMemslots; break; =20 + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: @@ -7104,6 +7176,7 @@ qemuAppendDomainMemoryMachineParams(virBuffer *buf, case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; @@ -7821,6 +7894,8 @@ qemuBuildNumaCommandLine(virQEMUDriverConfig *cfg, size_t ncells =3D virDomainNumaGetNodeCount(def->numa); ssize_t masterInitiator =3D -1; int rc; + g_autoptr(GHashTable) egmBackends =3D NULL; + size_t egmBackendCount =3D 0; =20 if (!virDomainNumatuneNodesetIsAvailable(def->numa, priv->autoNodeset)) goto cleanup; @@ -7835,6 +7910,37 @@ qemuBuildNumaCommandLine(virQEMUDriverConfig *cfg, hmat =3D true; } =20 + /* Pre-scan EGM devices to group by path and calculate total sizes */ + egmBackends =3D g_hash_table_new_full(g_str_hash, g_str_equal, g_free, + (GDestroyNotify)qemuEGMBackendInfo= Free); + + for (i =3D 0; i < def->nmems; i++) { + if (def->mems[i]->model =3D=3D VIR_DOMAIN_MEMORY_MODEL_EGM) { + const char *egmPath =3D def->mems[i]->source.egm.path; + qemuEGMBackendInfo *info =3D g_hash_table_lookup(egmBackends, = egmPath); + + if (!info) { + info =3D g_new0(qemuEGMBackendInfo, 1); + info->alias =3D g_strdup_printf("memegm%zu", egmBackendCou= nt); + egmBackendCount++; + info->totalSize =3D def->mems[i]->size; + info->created =3D false; + info->firstMem =3D def->mems[i]; + g_hash_table_insert(egmBackends, g_strdup(egmPath), info); + } else { + info->totalSize +=3D def->mems[i]->size; + } + } + } + + /* Build the actual backend and device objects */ + for (i =3D 0; i < def->nmems; i++) { + if (def->mems[i]->model =3D=3D VIR_DOMAIN_MEMORY_MODEL_EGM) { + if (qemuBuildMemoryDimmBackendStr(cmd, def->mems[i], def, cfg,= priv, egmBackends) < 0) + goto cleanup; + } + } + nodeBackends =3D g_new0(virJSONValue *, ncells); nodemask =3D g_new0(virBitmap *, ncells); =20 @@ -7870,8 +7976,18 @@ qemuBuildNumaCommandLine(virQEMUDriverConfig *cfg, for (i =3D 0; i < ncells; i++) { ssize_t initiator =3D virDomainNumaGetNodeInitiator(def->numa, i); unsigned long long memSize =3D virDomainNumaGetNodeMemorySize(def-= >numa, i); + bool egmBacked =3D false; + size_t k; + + for (k =3D 0; k < def->nmems; k++) { + if (def->mems[k]->model =3D=3D VIR_DOMAIN_MEMORY_MODEL_EGM && + def->mems[k]->targetNode =3D=3D (int)i) { + egmBacked =3D true; + break; + } + } =20 - if (needBackend && memSize > 0) { + if (needBackend && memSize > 0 && !egmBacked) { g_autoptr(virJSONValue) tcProps =3D NULL; =20 if (qemuBuildThreadContextProps(&tcProps, &nodeBackends[i], @@ -7901,7 +8017,15 @@ qemuBuildNumaCommandLine(virQEMUDriverConfig *cfg, =20 if (memSize > 0) { if (needBackend) { - virBufferAsprintf(&buf, ",memdev=3Dram-node%zu", i); + if (egmBacked) { + /* Look up the actual backend alias for EGM */ + const char *egmPath =3D def->mems[k]->source.egm.path; + qemuEGMBackendInfo *egmInfo =3D g_hash_table_lookup(eg= mBackends, egmPath); + const char *backendAlias =3D egmInfo ? egmInfo->alias = : def->mems[k]->info.alias; + virBufferAsprintf(&buf, ",memdev=3D%s", backendAlias); + } else { + virBufferAsprintf(&buf, ",memdev=3Dram-node%zu", i); + } } else { virBufferAsprintf(&buf, ",mem=3D%llu", memSize / 1024); } @@ -7965,7 +8089,10 @@ qemuBuildMemoryDeviceCommandLine(virCommand *cmd, for (i =3D 0; i < def->nmems; i++) { g_autoptr(virJSONValue) props =3D NULL; =20 - if (qemuBuildMemoryDimmBackendStr(cmd, def->mems[i], def, cfg, pri= v) < 0) + if (def->mems[i]->model =3D=3D VIR_DOMAIN_MEMORY_MODEL_EGM) + continue; + + if (qemuBuildMemoryDimmBackendStr(cmd, def->mems[i], def, cfg, pri= v, NULL) < 0) return -1; =20 switch (def->mems[i]->model) { @@ -7985,6 +8112,9 @@ qemuBuildMemoryDeviceCommandLine(virCommand *cmd, case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: break; =20 + /* EGM memory backing is via memory-backend-file object */ + case VIR_DOMAIN_MEMORY_MODEL_EGM: + break; case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index ac56fc7cb4..14f2b3ec5d 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -7219,6 +7219,7 @@ qemuDomainUpdateMemoryDeviceInfo(virDomainObj *vm, break; =20 case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; @@ -7453,7 +7454,8 @@ qemuDomainAlignMemorySizes(virDomainDef *def) def->mems[i]->size =3D VIR_ROUND_UP(def->mems[i]->size, align); } =20 - hotplugmem +=3D def->mems[i]->size; + if (def->mems[i]->model !=3D VIR_DOMAIN_MEMORY_MODEL_EGM) + hotplugmem +=3D def->mems[i]->size; =20 if (def->mems[i]->size > maxmemkb) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, @@ -7941,6 +7943,12 @@ qemuDomainDefValidateMemoryHotplugDevice(const virDo= mainMemoryDef *mem, virDomainMemoryModelTypeToString(mem->model)); return -1; =20 + case VIR_DOMAIN_MEMORY_MODEL_EGM: + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("hotplug is not supported for the %1$s device"), + virDomainMemoryModelTypeToString(mem->model)); + return -1; + case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: return -1; @@ -7999,6 +8007,7 @@ qemuDomainDefValidateMemoryHotplug(const virDomainDef= *def, case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_LAST: case VIR_DOMAIN_MEMORY_MODEL_NONE: break; @@ -8046,6 +8055,8 @@ qemuDomainDefValidateMemoryHotplug(const virDomainDef= *def, =20 case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: /* sgx epc memory does not support hotplug, skip this check */ + case VIR_DOMAIN_MEMORY_MODEL_EGM: + /* egm memory does not support hotplug, skip this check */ case VIR_DOMAIN_MEMORY_MODEL_LAST: case VIR_DOMAIN_MEMORY_MODEL_NONE: break; diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 7233df888c..97e533bf9a 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -3124,6 +3124,7 @@ qemuDomainAssignMemoryDeviceSlot(virDomainObj *vm, return qemuDomainEnsureVirtioAddress(&releaseaddr, vm, &dev); =20 case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; @@ -3151,6 +3152,7 @@ qemuDomainReleaseMemoryDeviceSlot(virDomainObj *vm, break; =20 case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; @@ -3185,6 +3187,7 @@ qemuDomainAssignMemorySlots(virDomainDef *def) /* handled in qemuDomainAssignPCIAddresses() */ break; case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index f2e024dae3..e0ee056b92 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -6712,6 +6712,7 @@ qemuDomainAttachMemoryConfig(virDomainDef *vmdef, case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_EGM: break; case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index fb426deb1a..890bb052b6 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -7348,6 +7348,7 @@ qemuDomainChangeMemoryLiveValidateChange(const virDom= ainMemoryDef *oldDef, case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_LAST: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("cannot modify memory of model '%1$s'"), diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 494d7ef515..081f0cedfd 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -7213,6 +7213,7 @@ qemuMonitorJSONGetMemoryDeviceInfo(qemuMonitor *mon, switch ((virDomainMemoryModel) model) { case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: /* While 'id' attribute is marked as optional in QEMU's QAPI diff --git a/src/qemu/qemu_postparse.c b/src/qemu/qemu_postparse.c index dc5ade829a..3c2867edb3 100644 --- a/src/qemu/qemu_postparse.c +++ b/src/qemu/qemu_postparse.c @@ -1839,6 +1839,7 @@ qemuDomainDefNumaAutoAdd(virDomainDef *def, case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; } diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 0e50cd1ccc..d451c12dd0 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -4156,6 +4156,7 @@ qemuProcessDomainMemoryDefNeedHugepagesPath(const vir= DomainMemoryDef *mem, case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: pagesize =3D mem->source.virtio_mem.pagesize; break; + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: @@ -4245,6 +4246,7 @@ qemuProcessNeedMemoryBackingPath(virDomainDef *def, case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_LAST: /* Backed by user provided path. Not stored in memory * backing dir anyway. */ diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index da08fd17cd..e026e2fdd0 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -5861,6 +5861,12 @@ qemuValidateDomainDeviceDefMemory(const virDomainMem= oryDef *mem, =20 break; =20 + case VIR_DOMAIN_MEMORY_MODEL_EGM: + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_ACPI_EGM_MEMORY)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("ACPI EGM memory device is not supported with = this QEMU binary")); + return -1; + } case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; --=20 2.43.0