From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from us-smtp-1.mimecast.com (us-smtp-1.mimecast.com [207.211.31.120]) by mx.groups.io with SMTP id smtpd.web10.1968.1583231509769765157 for ; Tue, 03 Mar 2020 02:31:50 -0800 Authentication-Results: mx.groups.io; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=KU9xpTSZ; spf=pass (domain: redhat.com, ip: 207.211.31.120, mailfrom: lersek@redhat.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1583231508; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=6na3uyQRoQQ1skKqtt0R913YzgRPAwjVMbjz60wMIE8=; b=KU9xpTSZG61HJSTElpagvpa94Bgmcun5ZqVFZf5iyVK/raqGNo1zB1DEZ0jvRM/STurBGV YGjM7YkoY+g9wpRPR3F8K4tCDZ+d8S+IC3grz5wT0Ehs0ldettpyUJy6313nvA3zBjy5M3 sUs1OdZ+l9ngc+p0Z1qMAd/28L26ZJM= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-195-PAt1JW8ANzStj_EGQnwdKQ-1; Tue, 03 Mar 2020 05:31:44 -0500 X-MC-Unique: PAt1JW8ANzStj_EGQnwdKQ-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 6301F107ACC4; Tue, 3 Mar 2020 10:31:43 +0000 (UTC) Received: from lacos-laptop-7.usersys.redhat.com (ovpn-117-34.ams2.redhat.com [10.36.117.34]) by smtp.corp.redhat.com (Postfix) with ESMTP id 80C4D5DA60; Tue, 3 Mar 2020 10:31:41 +0000 (UTC) Subject: Re: [PATCH v2 09/16] OvmfPkg/CpuHotplugSmm: add function for collecting CPUs with events To: =?UTF-8?Q?Philippe_Mathieu-Daud=c3=a9?= , edk2-devel-groups-io Cc: Ard Biesheuvel , Igor Mammedov , Jiewen Yao , Jordan Justen , Michael Kinney References: <20200226221156.29589-1-lersek@redhat.com> <20200226221156.29589-10-lersek@redhat.com> From: "Laszlo Ersek" Message-ID: <3b172735-2b25-919a-6762-02775d334daa@redhat.com> Date: Tue, 3 Mar 2020 11:31:40 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.9.1 MIME-Version: 1.0 In-Reply-To: X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Language: en-US Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable On 03/02/20 21:34, Philippe Mathieu-Daud=C3=A9 wrote: > On 2/26/20 11:11 PM, Laszlo Ersek wrote: >> Add a function that collects the APIC IDs of CPUs that have just been >> hot-plugged, or are about to be hot-unplugged. >> >> Pending events are only located and never cleared; QEMU's AML needs the >> firmware to leave the status bits intact in the hotplug register block. >> >> Cc: Ard Biesheuvel >> Cc: Igor Mammedov >> Cc: Jiewen Yao >> Cc: Jordan Justen >> Cc: Michael Kinney >> Cc: Philippe Mathieu-Daud=C3=A9 >> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3D1512 >> Signed-off-by: Laszlo Ersek >> Acked-by: Ard Biesheuvel >> --- >> >> Notes: >> =C2=A0=C2=A0=C2=A0=C2=A0 v2: >> =C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0 - Pick up Ard's Acked-= by, which is conditional on approval >> from Intel >> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 reviewers on Cc. (I'd like to save = Ard the churn of re-acking >> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 unmodified patches.) >> >> =C2=A0 OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h |=C2=A0=C2=A0 2= + >> =C2=A0 OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 |=C2=A0=C2=A0 1 + >> =C2=A0 OvmfPkg/CpuHotplugSmm/ApicId.h=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0 |=C2=A0 23 +++ >> =C2=A0 OvmfPkg/CpuHotplugSmm/QemuCpuhp.h=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 |=C2=A0 = 20 ++- >> =C2=A0 OvmfPkg/CpuHotplugSmm/QemuCpuhp.c=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 | 171 >> +++++++++++++++++++- >> =C2=A0 5 files changed, 211 insertions(+), 6 deletions(-) >> >> diff --git a/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h >> b/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h >> index 3d013633501b..a34a6d3fae61 100644 >> --- a/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h >> +++ b/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h >> @@ -13,32 +13,34 @@ >> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 The new ("modern") hotplug interface appe= ared in QEMU v2.7.0. >> =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 The macros in this header file map= to the minimal subset of >> the modern >> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 interface that OVMF needs. >> =C2=A0 **/ >> =C2=A0 =C2=A0 #ifndef QEMU_CPU_HOTPLUG_H_ >> =C2=A0 #define QEMU_CPU_HOTPLUG_H_ >> =C2=A0 =C2=A0 #include >> =C2=A0 =C2=A0 // >> =C2=A0 // Each register offset is: >> =C2=A0 // - relative to the board-dependent IO base address of the regis= ter >> block, >> =C2=A0 // - named QEMU_CPUHP_(R|W|RW)_*, according to the possible acces= s >> modes of the >> =C2=A0 //=C2=A0=C2=A0 register, >> =C2=A0 // - followed by distinguished bitmasks or values in the register= . >> =C2=A0 // >> =C2=A0 #define QEMU_CPUHP_R_CMD_DATA2=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 0x0 >> =C2=A0 =C2=A0 #define QEMU_CPUHP_R_CPU_STAT=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 0x4 >> =C2=A0 #define QEMU_CPUHP_STAT_ENABLED=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 BIT0 >> +#define QEMU_CPUHP_STAT_INSERT=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 BIT1 >> +#define QEMU_CPUHP_STAT_REMOVE=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 BIT2 >> =C2=A0 =C2=A0 #define QEMU_CPUHP_RW_CMD_DATA=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 0x8 >> =C2=A0 =C2=A0 #define QEMU_CPUHP_W_CPU_SEL=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 0x0 >> =C2=A0 =C2=A0 #define QEMU_CPUHP_W_CMD=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0 0x5 >> =C2=A0 #define QEMU_CPUHP_CMD_GET_PENDING=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 0x0 >> =C2=A0 #define QEMU_CPUHP_CMD_GET_ARCH_ID=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 0x3 >> =C2=A0 =C2=A0 #endif // QEMU_CPU_HOTPLUG_H_ >> diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf >> b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf >> index ac4ca4c1f4f2..ab690a9e5e20 100644 >> --- a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf >> +++ b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf >> @@ -3,44 +3,45 @@ >> =C2=A0 # >> =C2=A0 # Copyright (c) 2020, Red Hat, Inc. >> =C2=A0 # >> =C2=A0 # SPDX-License-Identifier: BSD-2-Clause-Patent >> =C2=A0 ## >> =C2=A0 =C2=A0 [Defines] >> =C2=A0=C2=A0=C2=A0 INF_VERSION=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =3D 1.29 >> =C2=A0=C2=A0=C2=A0 PI_SPECIFICATION_VERSION=C2=A0=C2=A0 =3D 0x00010046= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0 >> # PI-1.7.0 >> =C2=A0=C2=A0=C2=A0 BASE_NAME=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =3D CpuHotplug= Smm >> =C2=A0=C2=A0=C2=A0 FILE_GUID=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =3D 84EEA114-C= 6BE-4445-8F90-51D97863E363 >> =C2=A0=C2=A0=C2=A0 MODULE_TYPE=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =3D DXE_SMM_DRIVER >> =C2=A0=C2=A0=C2=A0 ENTRY_POINT=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =3D CpuHotplugEntry >> =C2=A0 =C2=A0 # >> =C2=A0 # The following information is for reference only and not require= d >> by the build >> =C2=A0 # tools. >> =C2=A0 # >> =C2=A0 # VALID_ARCHITECTURES=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 = =3D IA32 X64 >> =C2=A0 # >> =C2=A0 =C2=A0 [Sources] >> +=C2=A0 ApicId.h >> =C2=A0=C2=A0=C2=A0 CpuHotplug.c >> =C2=A0=C2=A0=C2=A0 QemuCpuhp.c >> =C2=A0=C2=A0=C2=A0 QemuCpuhp.h >> =C2=A0 =C2=A0 [Packages] >> =C2=A0=C2=A0=C2=A0 MdePkg/MdePkg.dec >> =C2=A0=C2=A0=C2=A0 OvmfPkg/OvmfPkg.dec >> =C2=A0 =C2=A0 [LibraryClasses] >> =C2=A0=C2=A0=C2=A0 BaseLib >> =C2=A0=C2=A0=C2=A0 DebugLib >> =C2=A0=C2=A0=C2=A0 MmServicesTableLib >> =C2=A0=C2=A0=C2=A0 PcdLib >> =C2=A0=C2=A0=C2=A0 UefiDriverEntryPoint >> =C2=A0 =C2=A0 [Protocols] >> =C2=A0=C2=A0=C2=A0 gEfiMmCpuIoProtocolGuid=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 >> ## CONSUMES >> =C2=A0 =C2=A0 [Pcd] >> =C2=A0=C2=A0=C2=A0 gUefiOvmfPkgTokenSpaceGuid.PcdQ35SmramAtDefaultSmbase= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 >> ## CONSUMES >> =C2=A0 =C2=A0 [FeaturePcd] >> diff --git a/OvmfPkg/CpuHotplugSmm/ApicId.h >> b/OvmfPkg/CpuHotplugSmm/ApicId.h >> new file mode 100644 >> index 000000000000..3c365148ed02 >> --- /dev/null >> +++ b/OvmfPkg/CpuHotplugSmm/ApicId.h >> @@ -0,0 +1,23 @@ >> +/** @file >> +=C2=A0 Type and macro definitions for representing and printing APIC ID= s, >> compatibly >> +=C2=A0 with the LocalApicLib and PrintLib classes, respectively. >> + >> +=C2=A0 Copyright (c) 2020, Red Hat, Inc. >> + >> +=C2=A0 SPDX-License-Identifier: BSD-2-Clause-Patent >> +**/ >> + >> +#ifndef APIC_ID_H_ >> +#define APIC_ID_H_ >> + >> +// >> +// The type that LocalApicLib represents an APIC ID with. >> +// >> +typedef UINT32 APIC_ID; >> + >> +// >> +// The PrintLib conversion specification for formatting an APIC_ID. >> +// >> +#define FMT_APIC_ID "0x%08x" >> + >> +#endif // APIC_ID_H_ >> diff --git a/OvmfPkg/CpuHotplugSmm/QemuCpuhp.h >> b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.h >> index 82f88f0b73bb..8adaa0ad91f0 100644 >> --- a/OvmfPkg/CpuHotplugSmm/QemuCpuhp.h >> +++ b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.h >> @@ -1,47 +1,61 @@ >> =C2=A0 /** @file >> -=C2=A0 Simple wrapper functions that access QEMU's modern CPU hotplug >> register >> -=C2=A0 block. >> +=C2=A0 Simple wrapper functions and utility functions that access QEMU'= s >> modern CPU >> +=C2=A0 hotplug register block. >> =C2=A0 -=C2=A0 These functions thinly wrap some of the registers describ= ed in >> +=C2=A0 These functions manipulate some of the registers described in >> =C2=A0=C2=A0=C2=A0 "docs/specs/acpi_cpu_hotplug.txt" in the QEMU source.= IO Ports are >> accessed >> =C2=A0=C2=A0=C2=A0 via EFI_MM_CPU_IO_PROTOCOL. If a protocol call fails,= these >> functions don't >> =C2=A0=C2=A0=C2=A0 return. >> =C2=A0 =C2=A0=C2=A0=C2=A0 Copyright (c) 2020, Red Hat, Inc. >> =C2=A0 =C2=A0=C2=A0=C2=A0 SPDX-License-Identifier: BSD-2-Clause-Patent >> =C2=A0 **/ >> =C2=A0 =C2=A0 #ifndef QEMU_CPUHP_H_ >> =C2=A0 #define QEMU_CPUHP_H_ >> =C2=A0 =C2=A0 #include =C2=A0 // EFI_MM_CPU_IO_PROTO= COL >> +#include // EFI_STATUS >> + >> +#include "ApicId.h"=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0 // APIC_ID >> =C2=A0 =C2=A0 UINT32 >> =C2=A0 QemuCpuhpReadCommandData2 ( >> =C2=A0=C2=A0=C2=A0 IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo >> =C2=A0=C2=A0=C2=A0 ); >> =C2=A0 =C2=A0 UINT8 >> =C2=A0 QemuCpuhpReadCpuStatus ( >> =C2=A0=C2=A0=C2=A0 IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo >> =C2=A0=C2=A0=C2=A0 ); >> =C2=A0 =C2=A0 UINT32 >> =C2=A0 QemuCpuhpReadCommandData ( >> =C2=A0=C2=A0=C2=A0 IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo >> =C2=A0=C2=A0=C2=A0 ); >> =C2=A0 =C2=A0 VOID >> =C2=A0 QemuCpuhpWriteCpuSelector ( >> =C2=A0=C2=A0=C2=A0 IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo, >> =C2=A0=C2=A0=C2=A0 IN UINT32=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0 Selector >> =C2=A0=C2=A0=C2=A0 ); >> =C2=A0 =C2=A0 VOID >> =C2=A0 QemuCpuhpWriteCommand ( >> =C2=A0=C2=A0=C2=A0 IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo, >> =C2=A0=C2=A0=C2=A0 IN UINT8=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 Command >> =C2=A0=C2=A0=C2=A0 ); >> =C2=A0 +EFI_STATUS >> +QemuCpuhpCollectApicIds ( >> +=C2=A0 IN=C2=A0 CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo, >> +=C2=A0 IN=C2=A0 UINT32=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 PossibleCpuCount, >> +=C2=A0 IN=C2=A0 UINT32=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 ApicIdCount, >> +=C2=A0 OUT APIC_ID=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= *PluggedApicIds, >> +=C2=A0 OUT UINT32=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 *PluggedCount, >> +=C2=A0 OUT APIC_ID=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= *ToUnplugApicIds, >> +=C2=A0 OUT UINT32=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 *ToUnplugCount >> +=C2=A0 ); >> + >> =C2=A0 #endif // QEMU_CPUHP_H_ >> diff --git a/OvmfPkg/CpuHotplugSmm/QemuCpuhp.c >> b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.c >> index 31e46f51934a..8d4a6693c8d6 100644 >> --- a/OvmfPkg/CpuHotplugSmm/QemuCpuhp.c >> +++ b/OvmfPkg/CpuHotplugSmm/QemuCpuhp.c >> @@ -1,27 +1,27 @@ >> =C2=A0 /** @file >> -=C2=A0 Simple wrapper functions that access QEMU's modern CPU hotplug >> register >> -=C2=A0 block. >> +=C2=A0 Simple wrapper functions and utility functions that access QEMU'= s >> modern CPU >> +=C2=A0 hotplug register block. >> =C2=A0 -=C2=A0 These functions thinly wrap some of the registers describ= ed in >> +=C2=A0 These functions manipulate some of the registers described in >> =C2=A0=C2=A0=C2=A0 "docs/specs/acpi_cpu_hotplug.txt" in the QEMU source.= IO Ports are >> accessed >> =C2=A0=C2=A0=C2=A0 via EFI_MM_CPU_IO_PROTOCOL. If a protocol call fails,= these >> functions don't >> =C2=A0=C2=A0=C2=A0 return. >> =C2=A0 =C2=A0=C2=A0=C2=A0 Copyright (c) 2020, Red Hat, Inc. >> =C2=A0 =C2=A0=C2=A0=C2=A0 SPDX-License-Identifier: BSD-2-Clause-Patent >> =C2=A0 **/ >> =C2=A0 =C2=A0 #include =C2=A0=C2=A0=C2=A0= =C2=A0 // ICH9_CPU_HOTPLUG_BASE >> =C2=A0 #include // QEMU_CPUHP_R_CMD_= DATA2 >> =C2=A0 #include =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 // CpuDeadLoop= () >> =C2=A0 #include =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 // DEBUG() >> =C2=A0 =C2=A0 #include "QemuCpuhp.h" >> =C2=A0 =C2=A0 UINT32 >> =C2=A0 QemuCpuhpReadCommandData2 ( >> =C2=A0=C2=A0=C2=A0 IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo >> =C2=A0=C2=A0=C2=A0 ) >> =C2=A0 { >> =C2=A0=C2=A0=C2=A0 UINT32=C2=A0=C2=A0=C2=A0=C2=A0 CommandData2; >> @@ -115,22 +115,187 @@ QemuCpuhpWriteCpuSelector ( >> =C2=A0 =C2=A0 VOID >> =C2=A0 QemuCpuhpWriteCommand ( >> =C2=A0=C2=A0=C2=A0 IN CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo, >> =C2=A0=C2=A0=C2=A0 IN UINT8=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 Command >> =C2=A0=C2=A0=C2=A0 ) >> =C2=A0 { >> =C2=A0=C2=A0=C2=A0 EFI_STATUS Status; >> =C2=A0 =C2=A0=C2=A0=C2=A0 Status =3D MmCpuIo->Io.Write ( >> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 MmCpuIo, >> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 MM_IO_UINT8, >> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 ICH9_CPU_HOTPLUG_BASE + QEMU_CPUHP_W_CMD, >> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 1, >> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 &Command >> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 ); >> =C2=A0=C2=A0=C2=A0 if (EFI_ERROR (Status)) { >> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTI= ON__, Status)); >> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ASSERT (FALSE); >> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 CpuDeadLoop (); >> =C2=A0=C2=A0=C2=A0 } >> =C2=A0 } >> + >> +/** >> +=C2=A0 Collect the APIC IDs of >> +=C2=A0 - the CPUs that have been hot-plugged, >> +=C2=A0 - the CPUs that are about to be hot-unplugged. >> + >> +=C2=A0 This function only scans for events -- it does not modify them -= - >> in the >> +=C2=A0 hotplug registers. >> + >> +=C2=A0 On error, the contents of the output parameters are undefined. >> + >> +=C2=A0 @param[in] MmCpuIo=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0 The EFI_MM_CPU_IO_PROTOCOL instance for >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 accessing IO Ports. >> + >> +=C2=A0 @param[in] PossibleCpuCount=C2=A0 The number of possible CPUs in= the >> system. Must >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 be positive. >=20 > Maybe nitpicking: "positive (non zero)"? Zero is not positive, zero is zero. Positive implies nonzero. :) Thanks Laszlo >=20 >> + >> +=C2=A0 @param[in] ApicIdCount=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 The n= umber of elements each one of the >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 PluggedApicIds and ToUnplugApicIds >> arrays can >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 accommodate. Must be positive. >> + >> +=C2=A0 @param[out] PluggedApicIds=C2=A0=C2=A0 The APIC IDs of the CPUs = that have been >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 hot-plugged. >> + >> +=C2=A0 @param[out] PluggedCount=C2=A0=C2=A0=C2=A0=C2=A0 The number of f= illed-in APIC IDs in >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 PluggedApicIds. >> + >> +=C2=A0 @param[out] ToUnplugApicIds=C2=A0 The APIC IDs of the CPUs that = are >> about to be >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 hot-unplugged. >> + >> +=C2=A0 @param[out] ToUnplugCount=C2=A0=C2=A0=C2=A0 The number of filled= -in APIC IDs in >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ToUnplugApicIds. >> + >> +=C2=A0 @retval EFI_INVALID_PARAMETER=C2=A0 PossibleCpuCount is zero, or >> ApicIdCount is >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 zero. >> + >> +=C2=A0 @retval EFI_PROTOCOL_ERROR=C2=A0=C2=A0=C2=A0=C2=A0 Invalid bitma= p detected in the >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 QEMU_CPUHP_R_CPU_STAT regi= ster. >> + >> +=C2=A0 @retval EFI_BUFFER_TOO_SMALL=C2=A0=C2=A0 There was an attempt to= place more than >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ApicIdCount APIC IDs into = one of the >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 PluggedApicIds and ToUnplu= gApicIds >> arrays. >> + >> +=C2=A0 @retval EFI_SUCCESS=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 Output parameters have been set >> successfully. >> +**/ >> +EFI_STATUS >> +QemuCpuhpCollectApicIds ( >> +=C2=A0 IN=C2=A0 CONST EFI_MM_CPU_IO_PROTOCOL *MmCpuIo, >> +=C2=A0 IN=C2=A0 UINT32=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 PossibleCpuCount, >> +=C2=A0 IN=C2=A0 UINT32=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 ApicIdCount, >> +=C2=A0 OUT APIC_ID=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= *PluggedApicIds, >> +=C2=A0 OUT UINT32=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 *PluggedCount, >> +=C2=A0 OUT APIC_ID=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= *ToUnplugApicIds, >> +=C2=A0 OUT UINT32=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 *ToUnplugCount >> +=C2=A0 ) >> +{ >> +=C2=A0 UINT32 CurrentSelector; >> + >> +=C2=A0 if (PossibleCpuCount =3D=3D 0 || ApicIdCount =3D=3D 0) { >> +=C2=A0=C2=A0=C2=A0 return EFI_INVALID_PARAMETER; >> +=C2=A0 } >> + >> +=C2=A0 *PluggedCount =3D 0; >> +=C2=A0 *ToUnplugCount =3D 0; >> + >> +=C2=A0 CurrentSelector =3D 0; >> +=C2=A0 do { >> +=C2=A0=C2=A0=C2=A0 UINT32=C2=A0 PendingSelector; >> +=C2=A0=C2=A0=C2=A0 UINT8=C2=A0=C2=A0 CpuStatus; >> +=C2=A0=C2=A0=C2=A0 APIC_ID *ExtendIds; >> +=C2=A0=C2=A0=C2=A0 UINT32=C2=A0 *ExtendCount; >> +=C2=A0=C2=A0=C2=A0 APIC_ID NewApicId; >> + >> +=C2=A0=C2=A0=C2=A0 // >> +=C2=A0=C2=A0=C2=A0 // Write CurrentSelector (which is valid) to the CPU= selector >> register. >> +=C2=A0=C2=A0=C2=A0 // Consequences: >> +=C2=A0=C2=A0=C2=A0 // >> +=C2=A0=C2=A0=C2=A0 // - Other register accesses will be permitted. >> +=C2=A0=C2=A0=C2=A0 // >> +=C2=A0=C2=A0=C2=A0 // - The QEMU_CPUHP_CMD_GET_PENDING command will sta= rt scanning >> for a CPU >> +=C2=A0=C2=A0=C2=A0 //=C2=A0=C2=A0 with pending events at CurrentSelecto= r (inclusive). >> +=C2=A0=C2=A0=C2=A0 // >> +=C2=A0=C2=A0=C2=A0 QemuCpuhpWriteCpuSelector (MmCpuIo, CurrentSelector)= ; >> +=C2=A0=C2=A0=C2=A0 // >> +=C2=A0=C2=A0=C2=A0 // Write the QEMU_CPUHP_CMD_GET_PENDING command. Con= sequences >> +=C2=A0=C2=A0=C2=A0 // (independently of each other): >> +=C2=A0=C2=A0=C2=A0 // >> +=C2=A0=C2=A0=C2=A0 // - If there is a CPU with pending events, starting= at >> CurrentSelector >> +=C2=A0=C2=A0=C2=A0 //=C2=A0=C2=A0 (inclusive), the CPU selector will be= updated to that CPU. >> Note that >> +=C2=A0=C2=A0=C2=A0 //=C2=A0=C2=A0 the scanning in QEMU may wrap around,= because we must never >> clear the >> +=C2=A0=C2=A0=C2=A0 //=C2=A0=C2=A0 event bits. >> +=C2=A0=C2=A0=C2=A0 // >> +=C2=A0=C2=A0=C2=A0 // - The QEMU_CPUHP_RW_CMD_DATA register will return= the >> (possibly updated) >> +=C2=A0=C2=A0=C2=A0 //=C2=A0=C2=A0 CPU selector value. >> +=C2=A0=C2=A0=C2=A0 // >> +=C2=A0=C2=A0=C2=A0 QemuCpuhpWriteCommand (MmCpuIo, QEMU_CPUHP_CMD_GET_P= ENDING); >> +=C2=A0=C2=A0=C2=A0 PendingSelector =3D QemuCpuhpReadCommandData (MmCpuI= o); >> +=C2=A0=C2=A0=C2=A0 if (PendingSelector < CurrentSelector) { >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 DEBUG ((DEBUG_VERBOSE, "%a: CurrentSelec= tor=3D%u >> PendingSelector=3D%u: " >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "wrap-around\n", __FUNCTION_= _, CurrentSelector, >> PendingSelector)); >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 break; >> +=C2=A0=C2=A0=C2=A0 } >> +=C2=A0=C2=A0=C2=A0 CurrentSelector =3D PendingSelector; >> + >> +=C2=A0=C2=A0=C2=A0 // >> +=C2=A0=C2=A0=C2=A0 // Check the known status / event bits for the curre= ntly selected >> CPU. >> +=C2=A0=C2=A0=C2=A0 // >> +=C2=A0=C2=A0=C2=A0 CpuStatus =3D QemuCpuhpReadCpuStatus (MmCpuIo); >> +=C2=A0=C2=A0=C2=A0 if ((CpuStatus & QEMU_CPUHP_STAT_INSERT) !=3D 0) { >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 // >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 // The "insert" event guarantees the "en= abled" status; plus it >> excludes >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 // the "remove" event. >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 // >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if ((CpuStatus & QEMU_CPUHP_STAT_ENABLED= ) =3D=3D 0 || >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (CpuStatus & QEM= U_CPUHP_STAT_REMOVE) !=3D 0) { >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 DEBUG ((DEBUG_ERROR, "%a: Cu= rrentSelector=3D%u CpuStatus=3D0x%x: " >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "inconsistent CP= U status\n", __FUNCTION__, CurrentSelector, >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 CpuStatus)); >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return EFI_PROTOCOL_ERROR; >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } >> + >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 DEBUG ((DEBUG_VERBOSE, "%a: CurrentSelec= tor=3D%u: insert\n", >> __FUNCTION__, >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 CurrentSelector)); >> + >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ExtendIds=C2=A0=C2=A0 =3D PluggedApicIds= ; >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ExtendCount =3D PluggedCount; >> +=C2=A0=C2=A0=C2=A0 } else if ((CpuStatus & QEMU_CPUHP_STAT_REMOVE) !=3D= 0) { >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 DEBUG ((DEBUG_VERBOSE, "%a: CurrentSelec= tor=3D%u: remove\n", >> __FUNCTION__, >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 CurrentSelector)); >> + >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ExtendIds=C2=A0=C2=A0 =3D ToUnplugApicId= s; >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ExtendCount =3D ToUnplugCount; >> +=C2=A0=C2=A0=C2=A0 } else { >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 DEBUG ((DEBUG_VERBOSE, "%a: CurrentSelec= tor=3D%u: no event\n", >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 __FUNCTION__, CurrentSelecto= r)); >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 break; >> +=C2=A0=C2=A0=C2=A0 } >> + >> +=C2=A0=C2=A0=C2=A0 // >> +=C2=A0=C2=A0=C2=A0 // Save the APIC ID of the CPU with the pending even= t, to the >> corresponding >> +=C2=A0=C2=A0=C2=A0 // APIC ID array. >> +=C2=A0=C2=A0=C2=A0 // >> +=C2=A0=C2=A0=C2=A0 if (*ExtendCount =3D=3D ApicIdCount) { >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 DEBUG ((DEBUG_ERROR, "%a: APIC ID array = too small\n", >> __FUNCTION__)); >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return EFI_BUFFER_TOO_SMALL; >> +=C2=A0=C2=A0=C2=A0 } >> +=C2=A0=C2=A0=C2=A0 QemuCpuhpWriteCommand (MmCpuIo, QEMU_CPUHP_CMD_GET_A= RCH_ID); >> +=C2=A0=C2=A0=C2=A0 NewApicId =3D QemuCpuhpReadCommandData (MmCpuIo); >> +=C2=A0=C2=A0=C2=A0 DEBUG ((DEBUG_VERBOSE, "%a: ApicId=3D" FMT_APIC_ID "= \n", __FUNCTION__, >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 NewApicId)); >> +=C2=A0=C2=A0=C2=A0 ExtendIds[(*ExtendCount)++] =3D NewApicId; >> + >> +=C2=A0=C2=A0=C2=A0 // >> +=C2=A0=C2=A0=C2=A0 // We've processed the CPU with (known) pending even= ts, but we >> must never >> +=C2=A0=C2=A0=C2=A0 // clear events. Therefore we need to advance past t= his CPU >> manually; >> +=C2=A0=C2=A0=C2=A0 // otherwise, QEMU_CPUHP_CMD_GET_PENDING would stick= to the >> currently >> +=C2=A0=C2=A0=C2=A0 // selected CPU. >> +=C2=A0=C2=A0=C2=A0 // >> +=C2=A0=C2=A0=C2=A0 CurrentSelector++; >> +=C2=A0 } while (CurrentSelector < PossibleCpuCount); >> + >> +=C2=A0 DEBUG ((DEBUG_VERBOSE, "%a: PluggedCount=3D%u ToUnplugCount=3D%u= \n", >> +=C2=A0=C2=A0=C2=A0 __FUNCTION__, *PluggedCount, *ToUnplugCount)); >> +=C2=A0 return EFI_SUCCESS; >> +} >> >=20 > Reviewed-by: Philippe Mathieu-Daude >=20