From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from NAM10-DM6-obe.outbound.protection.outlook.com (NAM10-DM6-obe.outbound.protection.outlook.com [40.107.93.71]) by mx.groups.io with SMTP id smtpd.web12.110.1634144263734777729 for ; Wed, 13 Oct 2021 09:57:43 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="body hash did not verify" header.i=@amd.com header.s=selector1 header.b=QSo8flQU; spf=permerror, err=parse error for token &{10 18 %{i}._ip.%{h}._ehlo.%{d}._spf.vali.email}: invalid domain name (domain: amd.com, ip: 40.107.93.71, mailfrom: brijesh.singh@amd.com) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=Uaj/3ToB0dtrrio2pLEZMn3liQSpF4ToWxNABDvK/M7O8QyERnQyjYyUb72+gkAG+9e3YErWKODEiqZ7A7ZybjvQ3FjUR3ldBV/Gl9ln3DctyMPl2xVKxVeYHIojrHIMVLtc5uFcZQuRYWzi9+kKPRTpBbDFe4KFicr6ZV8IBCrnxrIyIO1D8taWBLYQmfQdkFYCKwRVfBlMIhVtJZipPczYVwPD4TgdLhKox3G78ReRHiaYTZGNkGJ/X4s5G23pcKNguSGgI6mApurfuN7qsJcV11GbryBZbGWvhXo71M+ZQchlnuMVJ+otKpmENovW6dexV+PqkuysiH45MRj1QA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; 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=XFw81/VdnZTV6s8iSc/cTLsVp8a2N98OPbm3nTlTU98=; b=SvlFwPmq8VLimZPOhET3X7wIlY/KN614WoELuE5eallOiJr5JVkOHbGfX2j2SWrd7KN/XD+f6pJ61+OuW12a3wnDYYip7/C98Mtal+CiE/o9osPy3EUHvX4/4L0+jtHmnuiBGbXDB3w0jDzrCt46NReUlLlH2uG2bx8GDsmWQpADKzNRQJUU/Hm9zt5A+Y5FuBp7l1nXM7Y0jDSsAGpiBGT/M4d6M0H4/r9It8/ui4lC3d+8J8U/HbKGt6M5FnbERVEyzT+bXMigExkPGNuW+Nsl/zUUIIjh0DjB3OxYGK5jSbVlY4KN6O0HKTi/4EtnXsjNtQPPAMHrt1fVxv6xbg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=edk2.groups.io smtp.mailfrom=amd.com; dmarc=pass (p=quarantine sp=quarantine pct=100) action=none header.from=amd.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amd.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=XFw81/VdnZTV6s8iSc/cTLsVp8a2N98OPbm3nTlTU98=; b=QSo8flQUhIXvyej7wfhL/5mcFLl0MrhQSpcD2/Ol/L1ssi04A3s59M5FEYodT2wFfi56xcGrG1EZcqbiT2evZ2zJWCQOyNP7IFyaCIoFFLGSkb0JrC5m6v06o5AnxKJvTiAUznpqiBpuOaUxsYepSdL48i0jG1N9NS2cHw8nuOQ= Received: from MW4PR04CA0044.namprd04.prod.outlook.com (2603:10b6:303:6a::19) by CH0PR12MB5075.namprd12.prod.outlook.com (2603:10b6:610:e2::15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4608.16; Wed, 13 Oct 2021 16:57:40 +0000 Received: from CO1NAM11FT039.eop-nam11.prod.protection.outlook.com (2603:10b6:303:6a:cafe::97) by MW4PR04CA0044.outlook.office365.com (2603:10b6:303:6a::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4587.26 via Frontend Transport; Wed, 13 Oct 2021 16:57:40 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 165.204.84.17) smtp.mailfrom=amd.com; edk2.groups.io; dkim=none (message not signed) header.d=none;edk2.groups.io; dmarc=pass action=none header.from=amd.com; Received-SPF: Pass (protection.outlook.com: domain of amd.com designates 165.204.84.17 as permitted sender) receiver=protection.outlook.com; client-ip=165.204.84.17; helo=SATLEXMB04.amd.com; Received: from SATLEXMB04.amd.com (165.204.84.17) by CO1NAM11FT039.mail.protection.outlook.com (10.13.174.110) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.4608.15 via Frontend Transport; Wed, 13 Oct 2021 16:57:40 +0000 Received: from sbrijesh-desktop.amd.com (10.180.168.240) by SATLEXMB04.amd.com (10.181.40.145) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2308.8; Wed, 13 Oct 2021 11:57:37 -0500 From: "Brijesh Singh" To: CC: James Bottomley , Min Xu , "Jiewen Yao" , Tom Lendacky , "Jordan Justen" , Ard Biesheuvel , Erdem Aktas , "Michael Roth" , Gerd Hoffmann , Brijesh Singh , Eric Dong , Ray Ni , Rahul Kumar , Michael Roth , Jiewen Yao Subject: [PATCH v9 02/32] UefiCpuPkg/MpInitLib: move SEV specific routines in AmdSev.c Date: Wed, 13 Oct 2021 11:56:43 -0500 Message-ID: <20211013165713.727815-3-brijesh.singh@amd.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20211013165713.727815-1-brijesh.singh@amd.com> References: <20211013165713.727815-1-brijesh.singh@amd.com> MIME-Version: 1.0 Return-Path: brijesh.singh@amd.com X-Originating-IP: [10.180.168.240] X-ClientProxiedBy: SATLEXMB04.amd.com (10.181.40.145) To SATLEXMB04.amd.com (10.181.40.145) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 817c1f49-21f1-43b7-a6a5-08d98e6a9119 X-MS-TrafficTypeDiagnostic: CH0PR12MB5075: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:9508; X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: ORP2dFus2YdER5D7w5fTD6HEHQfbElbjOjvfU84RpO6sR+y5cKZC5yTSuI/8A4g/LrUij8F6/9FqZy9D/h73rTPBWMtOKUxPoBPmdoU+4gaOJ8pZLeO9S3aTLGN+ihnyXgAIvmQbbsQeJOGqz+Yy/m69vOe/9Ha/osa9g1r8n62kc8ceQbw4kKQBQhUjvhk16fWOwamz++CBDjhdN/5kROmJi1bNNghfpMxbPOP2orX7af6ifO9lZttJjNnrjAXDtgVoZAUED1avNFOz1ONwpA39yBBDEvxpbAkrNUdezhGNytupQwUWP6A6tk+qmDdyjQRvAkerDI5fRltyHptPGxAEb814vICcAQfwHlZZV4+FCtJosV36rdNBSxFCrPDIussTJZBorApCQTnqrVMlemCGwMAfT/sY32JCnpG6GP5LPJwassmBGMhD270VGvMAZtoPeW4sprUs7/ZtdyXIH6ET+lpff+vLN6+nK4pZWWuMFGNuhc0SFrMKzbjW/r4a4LefVjqklMfPioZKIw0zmKkwDWPvG61eNROrZlqUMYVDpMRra36EOwHstn9mCmU7r9r8Fji7m/Z0RtsA6ULW/OrEi/SRoDj7UmaaTQkLalJdopoTssuY0GPi9iPWYGXoCQ1W6zs+wrjAORA51QKSSSJk11obkong8NM2REL+H610JbW48QERXGLCulAfOrytxe7kYEl+5ZH2CUQdo08ExnEUEuqa2USf6Oz/VaDWirdwauL9tnqSyinUqoBI2R75L32OMhDWyh5J0dnZuaKAwnoj1i7GEKYB+Bl+Ltd05qbU3frUktxtqb3M9WNBHt2f X-Forefront-Antispam-Report: CIP:165.204.84.17;CTRY:US;LANG:en;SCL:1;SRV:;IPV:CAL;SFV:NSPM;H:SATLEXMB04.amd.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(6029001)(4636009)(46966006)(36840700001)(8936002)(70206006)(70586007)(26005)(19627235002)(186003)(7416002)(54906003)(316002)(356005)(8676002)(16526019)(7696005)(82310400003)(966005)(2616005)(1076003)(30864003)(36860700001)(6916009)(4326008)(36756003)(426003)(47076005)(6666004)(44832011)(83380400001)(86362001)(508600001)(2906002)(5660300002)(81166007)(336012)(36900700001);DIR:OUT;SFP:1101; X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 13 Oct 2021 16:57:40.0181 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 817c1f49-21f1-43b7-a6a5-08d98e6a9119 X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d;Ip=[165.204.84.17];Helo=[SATLEXMB04.amd.com] X-MS-Exchange-CrossTenant-AuthSource: CO1NAM11FT039.eop-nam11.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH0PR12MB5075 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3D3275 Move all the SEV specific function in AmdSev.c. No functional change intended. Cc: Eric Dong Cc: Ray Ni Cc: Rahul Kumar Cc: Michael Roth Cc: James Bottomley Cc: Min Xu Cc: Jiewen Yao Cc: Tom Lendacky Cc: Jordan Justen Cc: Ard Biesheuvel Cc: Erdem Aktas Cc: Gerd Hoffmann Suggested-by: Jiewen Yao Signed-off-by: Brijesh Singh --- UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf | 1 + UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf | 1 + UefiCpuPkg/Library/MpInitLib/MpLib.h | 33 +++ UefiCpuPkg/Library/MpInitLib/AmdSev.c | 239 ++++++++++++++++++ UefiCpuPkg/Library/MpInitLib/MpLib.c | 218 +--------------- UefiCpuPkg/Library/MpInitLib/X64/AmdSev.nasm | 119 +++++++++ UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm | 100 ++------ 7 files changed, 413 insertions(+), 298 deletions(-) create mode 100644 UefiCpuPkg/Library/MpInitLib/AmdSev.c create mode 100644 UefiCpuPkg/Library/MpInitLib/X64/AmdSev.nasm diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Lib= rary/MpInitLib/DxeMpInitLib.inf index d34419c2a524..6e510aa89120 100644 --- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf +++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf @@ -28,6 +28,7 @@ [Sources.X64] X64/MpFuncs.nasm =20 [Sources.common] + AmdSev.c MpEqu.inc DxeMpLib.c MpLib.c diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Lib= rary/MpInitLib/PeiMpInitLib.inf index 36fcb96b5852..2cbd9b8b8acc 100644 --- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf +++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf @@ -28,6 +28,7 @@ [Sources.X64] X64/MpFuncs.nasm =20 [Sources.common] + AmdSev.c MpEqu.inc PeiMpLib.c MpLib.c diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpIn= itLib/MpLib.h index e88a5355c983..3d4446df8ce6 100644 --- a/UefiCpuPkg/Library/MpInitLib/MpLib.h +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h @@ -34,6 +34,9 @@ #include #include =20 +#include +#include + #include =20 #define WAKEUP_AP_SIGNAL SIGNATURE_32 ('S', 'T', 'A', 'P') @@ -741,5 +744,35 @@ PlatformShadowMicrocode ( IN OUT CPU_MP_DATA *CpuMpData ); =20 +/** + Allocate the SEV-ES AP jump table buffer. + + @param[in, out] CpuMpData The pointer to CPU MP Data structure. +**/ +VOID +AllocateSevEsAPMemory ( + IN OUT CPU_MP_DATA *CpuMpData + ); + +/** + Program the SEV-ES AP jump table buffer. + + @param[in] SipiVector The SIPI vector used for the AP Reset +**/ +VOID +SetSevEsJumpTable ( + IN UINTN SipiVector + ); + +/** + The function puts the AP in halt loop. + + @param[in] CpuMpData The pointer to CPU MP Data structure. +**/ +VOID +SevEsPlaceApHlt ( + CPU_MP_DATA *CpuMpData + ); + #endif =20 diff --git a/UefiCpuPkg/Library/MpInitLib/AmdSev.c b/UefiCpuPkg/Library/MpI= nitLib/AmdSev.c new file mode 100644 index 000000000000..7dbf117c2b71 --- /dev/null +++ b/UefiCpuPkg/Library/MpInitLib/AmdSev.c @@ -0,0 +1,239 @@ +/** @file + CPU MP Initialize helper function for AMD SEV. + + Copyright (c) 2021, AMD Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "MpLib.h" +#include + +/** + Get Protected mode code segment with 16-bit default addressing + from current GDT table. + + @return Protected mode 16-bit code segment value. +**/ +STATIC +UINT16 +GetProtectedMode16CS ( + VOID + ) +{ + IA32_DESCRIPTOR GdtrDesc; + IA32_SEGMENT_DESCRIPTOR *GdtEntry; + UINTN GdtEntryCount; + UINT16 Index; + + Index =3D (UINT16) -1; + AsmReadGdtr (&GdtrDesc); + GdtEntryCount =3D (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR= ); + GdtEntry =3D (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base; + for (Index =3D 0; Index < GdtEntryCount; Index++) { + if (GdtEntry->Bits.L =3D=3D 0 && + GdtEntry->Bits.DB =3D=3D 0 && + GdtEntry->Bits.Type > 8) { + break; + } + GdtEntry++; + } + ASSERT (Index !=3D GdtEntryCount); + return Index * 8; +} + +/** + Get Protected mode code segment with 32-bit default addressing + from current GDT table. + + @return Protected mode 32-bit code segment value. +**/ +STATIC +UINT16 +GetProtectedMode32CS ( + VOID + ) +{ + IA32_DESCRIPTOR GdtrDesc; + IA32_SEGMENT_DESCRIPTOR *GdtEntry; + UINTN GdtEntryCount; + UINT16 Index; + + Index =3D (UINT16) -1; + AsmReadGdtr (&GdtrDesc); + GdtEntryCount =3D (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR= ); + GdtEntry =3D (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base; + for (Index =3D 0; Index < GdtEntryCount; Index++) { + if (GdtEntry->Bits.L =3D=3D 0 && + GdtEntry->Bits.DB =3D=3D 1 && + GdtEntry->Bits.Type > 8) { + break; + } + GdtEntry++; + } + ASSERT (Index !=3D GdtEntryCount); + return Index * 8; +} + +/** + Reset an AP when in SEV-ES mode. + + If successful, this function never returns. + + @param[in] Ghcb Pointer to the GHCB + @param[in] CpuMpData Pointer to CPU MP Data + +**/ +VOID +MpInitLibSevEsAPReset ( + IN GHCB *Ghcb, + IN CPU_MP_DATA *CpuMpData + ) +{ + EFI_STATUS Status; + UINTN ProcessorNumber; + UINT16 Code16, Code32; + AP_RESET *APResetFn; + UINTN BufferStart; + UINTN StackStart; + + Status =3D GetProcessorNumber (CpuMpData, &ProcessorNumber); + ASSERT_EFI_ERROR (Status); + + Code16 =3D GetProtectedMode16CS (); + Code32 =3D GetProtectedMode32CS (); + + if (CpuMpData->WakeupBufferHigh !=3D 0) { + APResetFn =3D (AP_RESET *) (CpuMpData->WakeupBufferHigh + CpuMpData->A= ddressMap.SwitchToRealNoNxOffset); + } else { + APResetFn =3D (AP_RESET *) (CpuMpData->MpCpuExchangeInfo->BufferStart = + CpuMpData->AddressMap.SwitchToRealOffset); + } + + BufferStart =3D CpuMpData->MpCpuExchangeInfo->BufferStart; + StackStart =3D CpuMpData->SevEsAPResetStackStart - + (AP_RESET_STACK_SIZE * ProcessorNumber); + + // + // This call never returns. + // + APResetFn (BufferStart, Code16, Code32, StackStart); +} + +/** + Allocate the SEV-ES AP jump table buffer. + + @param[in, out] CpuMpData The pointer to CPU MP Data structure. +**/ +VOID +AllocateSevEsAPMemory ( + IN OUT CPU_MP_DATA *CpuMpData + ) +{ + if (CpuMpData->SevEsAPBuffer =3D=3D (UINTN) -1) { + CpuMpData->SevEsAPBuffer =3D + CpuMpData->SevEsIsEnabled ? GetSevEsAPMemory () : 0; + } +} + +/** + Program the SEV-ES AP jump table buffer. + + @param[in] SipiVector The SIPI vector used for the AP Reset +**/ +VOID +SetSevEsJumpTable ( + IN UINTN SipiVector + ) +{ + SEV_ES_AP_JMP_FAR *JmpFar; + UINT32 Offset, InsnByte; + UINT8 LoNib, HiNib; + + JmpFar =3D (SEV_ES_AP_JMP_FAR *) (UINTN) FixedPcdGet32 (PcdSevEsWorkArea= Base); + ASSERT (JmpFar !=3D NULL); + + // + // Obtain the address of the Segment/Rip location in the workarea. + // This will be set to a value derived from the SIPI vector and will + // be the memory address used for the far jump below. + // + Offset =3D FixedPcdGet32 (PcdSevEsWorkAreaBase); + Offset +=3D sizeof (JmpFar->InsnBuffer); + LoNib =3D (UINT8) Offset; + HiNib =3D (UINT8) (Offset >> 8); + + // + // Program the workarea (which is the initial AP boot address) with + // far jump to the SIPI vector (where XX and YY represent the + // address of where the SIPI vector is stored. + // + // JMP FAR [CS:XXYY] =3D> 2E FF 2E YY XX + // + InsnByte =3D 0; + JmpFar->InsnBuffer[InsnByte++] =3D 0x2E; // CS override prefix + JmpFar->InsnBuffer[InsnByte++] =3D 0xFF; // JMP (FAR) + JmpFar->InsnBuffer[InsnByte++] =3D 0x2E; // ModRM (JMP memory location) + JmpFar->InsnBuffer[InsnByte++] =3D LoNib; // YY offset ... + JmpFar->InsnBuffer[InsnByte++] =3D HiNib; // XX offset ... + + // + // Program the Segment/Rip based on the SIPI vector (always at least + // 16-byte aligned, so Rip is set to 0). + // + JmpFar->Rip =3D 0; + JmpFar->Segment =3D (UINT16) (SipiVector >> 4); +} + +/** + The function puts the AP in halt loop. + + @param[in] CpuMpData The pointer to CPU MP Data structure. +**/ +VOID +SevEsPlaceApHlt ( + CPU_MP_DATA *CpuMpData + ) +{ + MSR_SEV_ES_GHCB_REGISTER Msr; + GHCB *Ghcb; + UINT64 Status; + BOOLEAN DoDecrement; + BOOLEAN InterruptState; + + DoDecrement =3D (BOOLEAN) (CpuMpData->InitFlag =3D=3D ApInitConfig); + + while (TRUE) { + Msr.GhcbPhysicalAddress =3D AsmReadMsr64 (MSR_SEV_ES_GHCB); + Ghcb =3D Msr.Ghcb; + + VmgInit (Ghcb, &InterruptState); + + if (DoDecrement) { + DoDecrement =3D FALSE; + + // + // Perform the delayed decrement just before issuing the first + // VMGEXIT with AP_RESET_HOLD. + // + InterlockedDecrement ((UINT32 *) &CpuMpData->MpCpuExchangeInfo->NumA= psExecuting); + } + + Status =3D VmgExit (Ghcb, SVM_EXIT_AP_RESET_HOLD, 0, 0); + if ((Status =3D=3D 0) && (Ghcb->SaveArea.SwExitInfo2 !=3D 0)) { + VmgDone (Ghcb, InterruptState); + break; + } + + VmgDone (Ghcb, InterruptState); + } + + // + // Awakened in a new phase? Use the new CpuMpData + // + if (CpuMpData->NewCpuMpData !=3D NULL) { + CpuMpData =3D CpuMpData->NewCpuMpData; + } + + MpInitLibSevEsAPReset (Ghcb, CpuMpData); +} diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpIn= itLib/MpLib.c index b9a06747edbf..890945bc5994 100644 --- a/UefiCpuPkg/Library/MpInitLib/MpLib.c +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c @@ -596,117 +596,6 @@ InitializeApData ( SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle); } =20 -/** - Get Protected mode code segment with 16-bit default addressing - from current GDT table. - - @return Protected mode 16-bit code segment value. -**/ -STATIC -UINT16 -GetProtectedMode16CS ( - VOID - ) -{ - IA32_DESCRIPTOR GdtrDesc; - IA32_SEGMENT_DESCRIPTOR *GdtEntry; - UINTN GdtEntryCount; - UINT16 Index; - - Index =3D (UINT16) -1; - AsmReadGdtr (&GdtrDesc); - GdtEntryCount =3D (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR= ); - GdtEntry =3D (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base; - for (Index =3D 0; Index < GdtEntryCount; Index++) { - if (GdtEntry->Bits.L =3D=3D 0 && - GdtEntry->Bits.DB =3D=3D 0 && - GdtEntry->Bits.Type > 8) { - break; - } - GdtEntry++; - } - ASSERT (Index !=3D GdtEntryCount); - return Index * 8; -} - -/** - Get Protected mode code segment with 32-bit default addressing - from current GDT table. - - @return Protected mode 32-bit code segment value. -**/ -STATIC -UINT16 -GetProtectedMode32CS ( - VOID - ) -{ - IA32_DESCRIPTOR GdtrDesc; - IA32_SEGMENT_DESCRIPTOR *GdtEntry; - UINTN GdtEntryCount; - UINT16 Index; - - Index =3D (UINT16) -1; - AsmReadGdtr (&GdtrDesc); - GdtEntryCount =3D (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR= ); - GdtEntry =3D (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base; - for (Index =3D 0; Index < GdtEntryCount; Index++) { - if (GdtEntry->Bits.L =3D=3D 0 && - GdtEntry->Bits.DB =3D=3D 1 && - GdtEntry->Bits.Type > 8) { - break; - } - GdtEntry++; - } - ASSERT (Index !=3D GdtEntryCount); - return Index * 8; -} - -/** - Reset an AP when in SEV-ES mode. - - If successful, this function never returns. - - @param[in] Ghcb Pointer to the GHCB - @param[in] CpuMpData Pointer to CPU MP Data - -**/ -STATIC -VOID -MpInitLibSevEsAPReset ( - IN GHCB *Ghcb, - IN CPU_MP_DATA *CpuMpData - ) -{ - EFI_STATUS Status; - UINTN ProcessorNumber; - UINT16 Code16, Code32; - AP_RESET *APResetFn; - UINTN BufferStart; - UINTN StackStart; - - Status =3D GetProcessorNumber (CpuMpData, &ProcessorNumber); - ASSERT_EFI_ERROR (Status); - - Code16 =3D GetProtectedMode16CS (); - Code32 =3D GetProtectedMode32CS (); - - if (CpuMpData->WakeupBufferHigh !=3D 0) { - APResetFn =3D (AP_RESET *) (CpuMpData->WakeupBufferHigh + CpuMpData->A= ddressMap.SwitchToRealNoNxOffset); - } else { - APResetFn =3D (AP_RESET *) (CpuMpData->MpCpuExchangeInfo->BufferStart = + CpuMpData->AddressMap.SwitchToRealOffset); - } - - BufferStart =3D CpuMpData->MpCpuExchangeInfo->BufferStart; - StackStart =3D CpuMpData->SevEsAPResetStackStart - - (AP_RESET_STACK_SIZE * ProcessorNumber); - - // - // This call never returns. - // - APResetFn (BufferStart, Code16, Code32, StackStart); -} - /** This function will be called from AP reset code if BSP uses WakeUpAP. =20 @@ -884,47 +773,7 @@ ApWakeupFunction ( while (TRUE) { DisableInterrupts (); if (CpuMpData->SevEsIsEnabled) { - MSR_SEV_ES_GHCB_REGISTER Msr; - GHCB *Ghcb; - UINT64 Status; - BOOLEAN DoDecrement; - BOOLEAN InterruptState; - - DoDecrement =3D (BOOLEAN) (CpuMpData->InitFlag =3D=3D ApInitConf= ig); - - while (TRUE) { - Msr.GhcbPhysicalAddress =3D AsmReadMsr64 (MSR_SEV_ES_GHCB); - Ghcb =3D Msr.Ghcb; - - VmgInit (Ghcb, &InterruptState); - - if (DoDecrement) { - DoDecrement =3D FALSE; - - // - // Perform the delayed decrement just before issuing the fir= st - // VMGEXIT with AP_RESET_HOLD. - // - InterlockedDecrement ((UINT32 *) &CpuMpData->MpCpuExchangeIn= fo->NumApsExecuting); - } - - Status =3D VmgExit (Ghcb, SVM_EXIT_AP_RESET_HOLD, 0, 0); - if ((Status =3D=3D 0) && (Ghcb->SaveArea.SwExitInfo2 !=3D 0)) = { - VmgDone (Ghcb, InterruptState); - break; - } - - VmgDone (Ghcb, InterruptState); - } - - // - // Awakened in a new phase? Use the new CpuMpData - // - if (CpuMpData->NewCpuMpData !=3D NULL) { - CpuMpData =3D CpuMpData->NewCpuMpData; - } - - MpInitLibSevEsAPReset (Ghcb, CpuMpData); + SevEsPlaceApHlt (CpuMpData); } else { CpuSleep (); } @@ -1252,71 +1101,6 @@ FreeResetVector ( } } =20 -/** - Allocate the SEV-ES AP jump table buffer. - - @param[in, out] CpuMpData The pointer to CPU MP Data structure. -**/ -VOID -AllocateSevEsAPMemory ( - IN OUT CPU_MP_DATA *CpuMpData - ) -{ - if (CpuMpData->SevEsAPBuffer =3D=3D (UINTN) -1) { - CpuMpData->SevEsAPBuffer =3D - CpuMpData->SevEsIsEnabled ? GetSevEsAPMemory () : 0; - } -} - -/** - Program the SEV-ES AP jump table buffer. - - @param[in] SipiVector The SIPI vector used for the AP Reset -**/ -VOID -SetSevEsJumpTable ( - IN UINTN SipiVector - ) -{ - SEV_ES_AP_JMP_FAR *JmpFar; - UINT32 Offset, InsnByte; - UINT8 LoNib, HiNib; - - JmpFar =3D (SEV_ES_AP_JMP_FAR *) (UINTN) FixedPcdGet32 (PcdSevEsWorkArea= Base); - ASSERT (JmpFar !=3D NULL); - - // - // Obtain the address of the Segment/Rip location in the workarea. - // This will be set to a value derived from the SIPI vector and will - // be the memory address used for the far jump below. - // - Offset =3D FixedPcdGet32 (PcdSevEsWorkAreaBase); - Offset +=3D sizeof (JmpFar->InsnBuffer); - LoNib =3D (UINT8) Offset; - HiNib =3D (UINT8) (Offset >> 8); - - // - // Program the workarea (which is the initial AP boot address) with - // far jump to the SIPI vector (where XX and YY represent the - // address of where the SIPI vector is stored. - // - // JMP FAR [CS:XXYY] =3D> 2E FF 2E YY XX - // - InsnByte =3D 0; - JmpFar->InsnBuffer[InsnByte++] =3D 0x2E; // CS override prefix - JmpFar->InsnBuffer[InsnByte++] =3D 0xFF; // JMP (FAR) - JmpFar->InsnBuffer[InsnByte++] =3D 0x2E; // ModRM (JMP memory location) - JmpFar->InsnBuffer[InsnByte++] =3D LoNib; // YY offset ... - JmpFar->InsnBuffer[InsnByte++] =3D HiNib; // XX offset ... - - // - // Program the Segment/Rip based on the SIPI vector (always at least - // 16-byte aligned, so Rip is set to 0). - // - JmpFar->Rip =3D 0; - JmpFar->Segment =3D (UINT16) (SipiVector >> 4); -} - /** This function will be called by BSP to wakeup AP. =20 diff --git a/UefiCpuPkg/Library/MpInitLib/X64/AmdSev.nasm b/UefiCpuPkg/Libr= ary/MpInitLib/X64/AmdSev.nasm new file mode 100644 index 000000000000..0ccafe25eca4 --- /dev/null +++ b/UefiCpuPkg/Library/MpInitLib/X64/AmdSev.nasm @@ -0,0 +1,119 @@ +;-------------------------------------------------------------------------= ----- ; +; Copyright (c) 2021, AMD Inc. All rights reserved.
+; SPDX-License-Identifier: BSD-2-Clause-Patent +; +; Module Name: +; +; AmdSev.nasm +; +; Abstract: +; +; This provides helper used by the MpFunc.nasm. If AMD SEV-ES is active +; then helpers perform the additional setups (such as GHCB). +; +;-------------------------------------------------------------------------= ------ + +%define SIZE_4KB 0x1000 + +; +; The function checks whether SEV-ES is enabled, if enabled +; then setup the GHCB page. +; +SevEsSetupGhcb: + lea edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevEsIsEnabled)] + cmp byte [edi], 1 ; SevEsIsEnabled + jne SevEsSetupGhcbExit + + ; + ; program GHCB + ; Each page after the GHCB is a per-CPU page, so the calculation pro= grams + ; a GHCB to be every 8KB. + ; + mov eax, SIZE_4KB + shl eax, 1 ; EAX =3D SIZE_4K * 2 + mov ecx, ebx + mul ecx ; EAX =3D SIZE_4K * 2 * C= puNumber + mov edi, esi + add edi, MP_CPU_EXCHANGE_INFO_FIELD (GhcbBase) + add rax, qword [edi] + mov rdx, rax + shr rdx, 32 + mov rcx, 0xc0010130 + wrmsr + +SevEsSetupGhcbExit: + OneTimeCallRet SevEsSetupGhcb + +; +; The function checks whether SEV-ES is enabled, if enabled, use +; the GHCB +; +SevEsGetApicId: + lea edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevEsIsEnabled)] + cmp byte [edi], 1 ; SevEsIsEnabled + jne SevEsGetApicIdExit + + ; + ; Since we don't have a stack yet, we can't take a #VC + ; exception. Use the GHCB protocol to perform the CPUID + ; calls. + ; + mov rcx, 0xc0010130 + rdmsr + shl rdx, 32 + or rax, rdx + mov rdi, rax ; RDI now holds the original GHCB GPA + + mov rdx, 0 ; CPUID function 0 + mov rax, 0 ; RAX register requested + or rax, 4 + wrmsr + rep vmmcall + rdmsr + cmp edx, 0bh + jb NoX2ApicSevEs ; CPUID level below CPUID_EXTENDED_TOP= OLOGY + + mov rdx, 0bh ; CPUID function 0x0b + mov rax, 040000000h ; RBX register requested + or rax, 4 + wrmsr + rep vmmcall + rdmsr + test edx, 0ffffh + jz NoX2ApicSevEs ; CPUID.0BH:EBX[15:0] is zero + + mov rdx, 0bh ; CPUID function 0x0b + mov rax, 0c0000000h ; RDX register requested + or rax, 4 + wrmsr + rep vmmcall + rdmsr + + ; Processor is x2APIC capable; 32-bit x2APIC ID is now in EDX + jmp RestoreGhcb + +NoX2ApicSevEs: + ; Processor is not x2APIC capable, so get 8-bit APIC ID + mov rdx, 1 ; CPUID function 1 + mov rax, 040000000h ; RBX register requested + or rax, 4 + wrmsr + rep vmmcall + rdmsr + shr edx, 24 + +RestoreGhcb: + mov rbx, rdx ; Save x2APIC/APIC ID + + mov rdx, rdi ; RDI holds the saved GHCB GPA + shr rdx, 32 + mov eax, edi + wrmsr + + mov rdx, rbx + + ; x2APIC ID or APIC ID is in EDX + jmp GetProcessorNumber + +SevEsGetApicIdExit: + OneTimeCallRet SevEsGetApicId diff --git a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm b/UefiCpuPkg/Lib= rary/MpInitLib/X64/MpFuncs.nasm index 50df802d1fca..f7f2937fafad 100644 --- a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm +++ b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm @@ -15,6 +15,15 @@ %include "MpEqu.inc" extern ASM_PFX(InitializeFloatingPointUnits) =20 +%macro OneTimeCall 1 + jmp %1 +%1 %+ OneTimerCallReturn: +%endmacro + +%macro OneTimeCallRet 1 + jmp %1 %+ OneTimerCallReturn +%endmacro + DEFAULT REL =20 SECTION .text @@ -144,6 +153,12 @@ SkipEnable5LevelPaging: jmp far [edi] =20 BITS 64 + +; +; Required for the AMD SEV helper functions +; +%include "AmdSev.nasm" + LongModeStart: mov esi, ebx lea edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (InitFlag)] @@ -175,94 +190,17 @@ LongModeStart: add rax, qword [edi] mov rsp, rax =20 - lea edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevEsIsEnabled)] - cmp byte [edi], 1 ; SevEsIsEnabled - jne CProcedureInvoke - ; - ; program GHCB - ; Each page after the GHCB is a per-CPU page, so the calculation pro= grams - ; a GHCB to be every 8KB. + ; Setup the GHCB when AMD SEV-ES active. ; - mov eax, SIZE_4KB - shl eax, 1 ; EAX =3D SIZE_4K * 2 - mov ecx, ebx - mul ecx ; EAX =3D SIZE_4K * 2 * C= puNumber - mov edi, esi - add edi, MP_CPU_EXCHANGE_INFO_FIELD (GhcbBase) - add rax, qword [edi] - mov rdx, rax - shr rdx, 32 - mov rcx, 0xc0010130 - wrmsr + OneTimeCall SevEsSetupGhcb jmp CProcedureInvoke =20 GetApicId: - lea edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevEsIsEnabled)] - cmp byte [edi], 1 ; SevEsIsEnabled - jne DoCpuid - ; - ; Since we don't have a stack yet, we can't take a #VC - ; exception. Use the GHCB protocol to perform the CPUID - ; calls. + ; Use the GHCB protocol to get the ApicId when SEV-ES is active. ; - mov rcx, 0xc0010130 - rdmsr - shl rdx, 32 - or rax, rdx - mov rdi, rax ; RDI now holds the original GHCB GPA - - mov rdx, 0 ; CPUID function 0 - mov rax, 0 ; RAX register requested - or rax, 4 - wrmsr - rep vmmcall - rdmsr - cmp edx, 0bh - jb NoX2ApicSevEs ; CPUID level below CPUID_EXTENDED_TOP= OLOGY - - mov rdx, 0bh ; CPUID function 0x0b - mov rax, 040000000h ; RBX register requested - or rax, 4 - wrmsr - rep vmmcall - rdmsr - test edx, 0ffffh - jz NoX2ApicSevEs ; CPUID.0BH:EBX[15:0] is zero - - mov rdx, 0bh ; CPUID function 0x0b - mov rax, 0c0000000h ; RDX register requested - or rax, 4 - wrmsr - rep vmmcall - rdmsr - - ; Processor is x2APIC capable; 32-bit x2APIC ID is now in EDX - jmp RestoreGhcb - -NoX2ApicSevEs: - ; Processor is not x2APIC capable, so get 8-bit APIC ID - mov rdx, 1 ; CPUID function 1 - mov rax, 040000000h ; RBX register requested - or rax, 4 - wrmsr - rep vmmcall - rdmsr - shr edx, 24 - -RestoreGhcb: - mov rbx, rdx ; Save x2APIC/APIC ID - - mov rdx, rdi ; RDI holds the saved GHCB GPA - shr rdx, 32 - mov eax, edi - wrmsr - - mov rdx, rbx - - ; x2APIC ID or APIC ID is in EDX - jmp GetProcessorNumber + OneTimeCall SevEsGetApicId =20 DoCpuid: mov eax, 0 --=20 2.25.1