From nobody Sat May 4 03:30:04 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+82532+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+82532+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1634917619; cv=none; d=zohomail.com; s=zohoarc; b=OZv6RA5Ks1KmGy24qKS04TtVzfQh/7BZpDhTbqZPX9ALAZhnVMFIRTx6zlOd+QhAR3gazDLHLdXv8wkqULExypFyFTcrTzy5dQ4GYuYb7rLzEcEst3aiqNpeiKEh6+VQsa/15qSbMhR/NmM4lw2qTSuFnaF/tvt56emdU15+0fk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1634917619; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:References:Sender:Subject:To; bh=UxDdxPrneCXPicWpfI2YPCFmXNFgtoh0ShNbJwScsNQ=; b=j9Txu+EEceuZJZz+pD/wjkqqwyDIRl6skhXqrNzZ1M9q2GanlS5LTa87tWODQKC0vH6oeiIPO6SeCyzxDKFownTBsHNw6lYbc9Ya4vC7/SWbvgg1GtEQjJyVhLdlwpfBd/nKwFcXebcE6DWW7E33PoZJtHvCrAQ48Qh3v2ZLr0A= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+82532+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 1634917619535935.7713756435595; Fri, 22 Oct 2021 08:46:59 -0700 (PDT) Return-Path: X-Received: by 127.0.0.2 with SMTP id ph9cYY1788612x74Bf4KFJyl; Fri, 22 Oct 2021 08:46:59 -0700 X-Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by mx.groups.io with SMTP id smtpd.web11.10188.1634917617623869169 for ; Fri, 22 Oct 2021 08:46:58 -0700 X-IronPort-AV: E=McAfee;i="6200,9189,10145"; a="209428356" X-IronPort-AV: E=Sophos;i="5.87,173,1631602800"; d="scan'208";a="209428356" X-Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Oct 2021 08:46:40 -0700 X-IronPort-AV: E=Sophos;i="5.87,173,1631602800"; d="scan'208";a="445333053" X-Received: from gdong1-mobl1.amr.corp.intel.com ([10.212.41.65]) by orsmga006-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Oct 2021 08:46:39 -0700 From: "Guo Dong" To: devel@edk2.groups.io Cc: Guo Dong , Ray Ni , Maurice Ma , Benjamin You Subject: [edk2-devel] [`edk2-devel][PATCH V3 1/8] UefiPayloadPkg: Add a common SmmAccessDxe module Date: Fri, 22 Oct 2021 08:46:20 -0700 Message-Id: <20211022154627.1607-2-guo.dong@intel.com> In-Reply-To: <20211022154627.1607-1-guo.dong@intel.com> References: <20211022154627.1607-1-guo.dong@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,guo.dong@intel.com X-Gm-Message-State: wtpWa9fPJlhyJTfsLgzH8aOcx1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1634917619; bh=8nnWwtDIjqG+6SDjZzejP7347Wheax4sy8eUXPswLX0=; h=Cc:Date:From:Reply-To:Subject:To; b=lPm5f4m+FfiE/XOTZTq0Ti0cRgDhkg6XP1r+cFnyQpIC6UT+K5LjMCKx11r4cNyu+1I 1pFL11EKpd4n7L2fzBe0OJ7KiHm9CPA9rZrI690hAG7q2qHnrFIZ6HdoLfwNA9HBLYyA3 X9aAxOGuO8g4qOxCCHYBkf8MDSlHGI7yF4w= X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1634917621934100005 Content-Type: text/plain; charset="utf-8" From: Guo Dong SmmAccessDxe module would consume EFI_SMRAM_HOB_DESCRIPTOR_BLOCK HOB to produce SMM access protocol gEfiSmmAccess2ProtocolGuid (open, close, lock, and GetCapabilities.) Signed-off-by: Guo Dong Cc: Ray Ni Cc: Maurice Ma Cc: Benjamin You Reviewed-by: Ray Ni Reviewed-by: Benjamin You Reviewed-by: Benjamin You + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "SmmAccessDxe.h" + +SMM_ACCESS_PRIVATE_DATA mSmmAccess; + +/** + Update region state from SMRAM description + + @param[in] OrLogic Indicate to use OR if true or AND if false. + @param[in] Value The value to set to region state based on OrLogi= c. + +**/ +VOID +SyncRegionState2SmramDesc( + IN BOOLEAN OrLogic, + IN UINT64 Value + ) +{ + UINT32 Index; + + for (Index =3D 0; Index < mSmmAccess.NumberRegions; Index++) { + if (OrLogic) { + mSmmAccess.SmramDesc[Index].RegionState |=3D Value; + } else { + mSmmAccess.SmramDesc[Index].RegionState &=3D Value; + } + } +} + +/** + This routine accepts a request to "open" a region of SMRAM. The + region could be legacy ABSEG, HSEG, or TSEG near top of physical memory. + The use of "open" means that the memory is visible from all boot-service + and SMM agents. + + @param This Pointer to the SMM Access Interface. + + @retval EFI_SUCCESS The region was successfully opened. + @retval EFI_DEVICE_ERROR The region could not be opened because l= ocked by chipset. + @retval EFI_INVALID_PARAMETER The descriptor index was out of bounds. + +**/ +EFI_STATUS +EFIAPI +Open ( + IN EFI_SMM_ACCESS2_PROTOCOL *This + ) +{ + if ((mSmmAccess.SmmRegionState & EFI_SMRAM_LOCKED) !=3D 0) { + // + // Cannot open a "locked" region + // + DEBUG ((DEBUG_INFO, "Cannot open the locked SMRAM Region\n")); + return EFI_DEVICE_ERROR; + } + + mSmmAccess.SmmRegionState &=3D ~(EFI_SMRAM_CLOSED | EFI_ALLOCATED); + SyncRegionState2SmramDesc(FALSE, (UINT64)(UINTN)(~(EFI_SMRAM_CLOSED | EF= I_ALLOCATED))); + + mSmmAccess.SmmRegionState |=3D EFI_SMRAM_OPEN; + SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_OPEN); + mSmmAccess.SmmAccess.OpenState =3D TRUE; + + return EFI_SUCCESS; +} + +/** + This routine accepts a request to "close" a region of SMRAM. The region + could be legacy AB or TSEG near top of physical memory. + The use of "close" means that the memory is only visible from SMM agent= s, + not from BS or RT code. + + @param This Pointer to the SMM Access Interface. + + @retval EFI_SUCCESS The region was successfully closed. + @retval EFI_DEVICE_ERROR The region could not be closed because= locked by + chipset. + @retval EFI_INVALID_PARAMETER The descriptor index was out of bounds. + +**/ +EFI_STATUS +EFIAPI +Close ( + IN EFI_SMM_ACCESS2_PROTOCOL *This + ) +{ + if ((mSmmAccess.SmmRegionState & EFI_SMRAM_LOCKED) !=3D 0) { + // + // Cannot close a "locked" region + // + DEBUG ((DEBUG_INFO, "Cannot close the locked SMRAM Region\n")); + return EFI_DEVICE_ERROR; + } + + if ((mSmmAccess.SmmRegionState & EFI_SMRAM_CLOSED) !=3D 0) { + return EFI_DEVICE_ERROR; + } + + mSmmAccess.SmmRegionState &=3D ~EFI_SMRAM_OPEN; + SyncRegionState2SmramDesc(FALSE, (UINT64)(UINTN)(~EFI_SMRAM_OPEN)); + + mSmmAccess.SmmRegionState |=3D (EFI_SMRAM_CLOSED | EFI_ALLOCATED); + SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_CLOSED | EFI_ALLOCATED); + + mSmmAccess.SmmAccess.OpenState =3D FALSE; + + return EFI_SUCCESS; +} + +/** + This routine accepts a request to "lock" SMRAM. The + region could be legacy AB or TSEG near top of physical memory. + The use of "lock" means that the memory can no longer be opened + to BS state. + + @param This Pointer to the SMM Access Interface. + + @retval EFI_SUCCESS The region was successfully locked. + @retval EFI_DEVICE_ERROR The region could not be locked because = at least + one range is still open. + @retval EFI_INVALID_PARAMETER The descriptor index was out of bounds. + +**/ +EFI_STATUS +EFIAPI +Lock ( + IN EFI_SMM_ACCESS2_PROTOCOL *This + ) +{ + if (mSmmAccess.SmmAccess.OpenState) { + DEBUG ((DEBUG_INFO, "Cannot lock SMRAM when it is still open\n")); + return EFI_DEVICE_ERROR; + } + + mSmmAccess.SmmRegionState |=3D EFI_SMRAM_LOCKED; + SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_LOCKED); + mSmmAccess.SmmAccess.LockState =3D TRUE; + return EFI_SUCCESS; +} + +/** + This routine services a user request to discover the SMRAM + capabilities of this platform. This will report the possible + ranges that are possible for SMRAM access, based upon the + memory controller capabilities. + + @param This Pointer to the SMRAM Access Interface. + @param SmramMapSize Pointer to the variable containing size of the + buffer to contain the description information. + @param SmramMap Buffer containing the data describing the Smram + region descriptors. + + @retval EFI_BUFFER_TOO_SMALL The user did not provide a sufficient buf= fer. + @retval EFI_SUCCESS The user provided a sufficiently-sized bu= ffer. + +**/ +EFI_STATUS +EFIAPI +GetCapabilities ( + IN CONST EFI_SMM_ACCESS2_PROTOCOL *This, + IN OUT UINTN *SmramMapSize, + IN OUT EFI_SMRAM_DESCRIPTOR *SmramMap + ) +{ + EFI_STATUS Status; + UINTN NecessaryBufferSize; + + NecessaryBufferSize =3D mSmmAccess.NumberRegions * sizeof(EFI_SMRAM_DESC= RIPTOR); + if (*SmramMapSize < NecessaryBufferSize) { + Status =3D EFI_BUFFER_TOO_SMALL; + } else { + CopyMem(SmramMap, mSmmAccess.SmramDesc, NecessaryBufferSize); + Status =3D EFI_SUCCESS; + } + + *SmramMapSize =3D NecessaryBufferSize; + return Status; +} + +/** + This function installs EFI_SMM_ACCESS_PROTOCOL. + + @param ImageHandle Handle for the image of this driver + @param SystemTable Pointer to the EFI System Table + + @retval EFI_UNSUPPORTED There's no Intel ICH on this platform + @return The status returned from InstallProtocolInterface(). + +**/ +EFI_STATUS +EFIAPI +SmmAccessEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HOB_GUID_TYPE *GuidHob; + UINT32 SmmRegionNum; + EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *SmramHob; + UINT32 Index; + + // + // Get SMRAM info HOB + // + GuidHob =3D GetFirstGuidHob (&gEfiSmmSmramMemoryGuid); + if (GuidHob =3D=3D NULL) { + DEBUG ((DEBUG_INFO, "SMRAM HOB NOT found\n")); + return EFI_NOT_FOUND; + } + SmramHob =3D (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *) GET_GUID_HOB_DATA(Gu= idHob); + SmmRegionNum =3D SmramHob->NumberOfSmmReservedRegions; + mSmmAccess.SmramDesc =3D AllocateZeroPool (sizeof (EFI_SMRAM_DESCRIPTOR)= * SmmRegionNum); + if (mSmmAccess.SmramDesc =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem (mSmmAccess.SmramDesc, &SmramHob->Descriptor, sizeof (EFI_SMRAM_= DESCRIPTOR) * SmmRegionNum); + + DEBUG ((DEBUG_INFO, "NumberOfSmmReservedRegions =3D 0x%x\n", SmmRegionNu= m)); + for (Index =3D 0; Index < SmmRegionNum; Index++) { + DEBUG ((DEBUG_INFO, "%d: base=3D0x%x, size =3D 0x%x, State=3D0x%x\n",I= ndex, + SmramHob->Descriptor[Index].PhysicalStart, + SmramHob->Descriptor[Index].PhysicalSize, + SmramHob->Descriptor[Index].RegionState)); + mSmmAccess.SmramDesc[Index].RegionState &=3D EFI_ALLOCATED; + mSmmAccess.SmramDesc[Index].RegionState |=3D EFI_SMRAM_CLOSED | EFI_C= ACHEABLE; + } + + mSmmAccess.Signature =3D SMM_ACCESS_PRIVATE_DATA_SIGN= ATURE; + mSmmAccess.NumberRegions =3D SmmRegionNum; + mSmmAccess.SmmAccess.Open =3D Open; + mSmmAccess.SmmAccess.Close =3D Close; + mSmmAccess.SmmAccess.Lock =3D Lock; + mSmmAccess.SmmAccess.GetCapabilities =3D GetCapabilities; + mSmmAccess.SmmAccess.LockState =3D FALSE; + mSmmAccess.SmmAccess.OpenState =3D FALSE; + mSmmAccess.SmmRegionState =3D EFI_SMRAM_CLOSED; + + Status =3D gBS->InstallMultipleProtocolInterfaces ( + &mSmmAccess.Handle, + &gEfiSmmAccess2ProtocolGuid, + &mSmmAccess.SmmAccess, + NULL + ); + + return Status; +} diff --git a/UefiPayloadPkg/SmmAccessDxe/SmmAccessDxe.h b/UefiPayloadPkg/Sm= mAccessDxe/SmmAccessDxe.h new file mode 100644 index 0000000000..b6d76daef3 --- /dev/null +++ b/UefiPayloadPkg/SmmAccessDxe/SmmAccessDxe.h @@ -0,0 +1,37 @@ +/** @file + The header file of SMM access DXE. + +Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef SMM_ACCESS_DRIVER_H_ +#define SMM_ACCESS_DRIVER_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define SMM_ACCESS_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('S', 'M', 'M', '= A') + +typedef struct { + UINTN Signature; + EFI_HANDLE Handle; + EFI_SMM_ACCESS2_PROTOCOL SmmAccess; + // + // Local Data for SMM Access interface goes here + // + UINT32 SmmRegionState; + UINT32 NumberRegions; + EFI_SMRAM_DESCRIPTOR *SmramDesc; +} SMM_ACCESS_PRIVATE_DATA; + +#endif diff --git a/UefiPayloadPkg/SmmAccessDxe/SmmAccessDxe.inf b/UefiPayloadPkg/= SmmAccessDxe/SmmAccessDxe.inf new file mode 100644 index 0000000000..aac5ee8f28 --- /dev/null +++ b/UefiPayloadPkg/SmmAccessDxe/SmmAccessDxe.inf @@ -0,0 +1,51 @@ +## @file +# SMM Access 2 Protocol Dxe Driver +# +# This module produces the SMM Access 2 Protocol. +# +# Copyright (c) 2021, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D SmmAccessDxe + FILE_GUID =3D 47579CF5-1E4F-4b41-99BB-A5C334846D3B + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D SmmAccessEntryPoint + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 +# + +[Sources] + SmmAccessDxe.c + SmmAccessDxe.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UefiPayloadPkg/UefiPayloadPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + UefiBootServicesTableLib + DebugLib + BaseLib + BaseMemoryLib + MemoryAllocationLib + HobLib + +[Guids] + gEfiSmmSmramMemoryGuid + +[Protocols] + gEfiSmmAccess2ProtocolGuid ## PRODUCES + +[Depex] + TRUE --=20 2.32.0.windows.2 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#82532): https://edk2.groups.io/g/devel/message/82532 Mute This Topic: https://groups.io/mt/86517140/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- From nobody Sat May 4 03:30:04 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+82533+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+82533+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1634917620; cv=none; d=zohomail.com; s=zohoarc; b=Qz+c4SU6iICS1zkZOLpWIAZ/8hj64CTHci4gl7VMASyyP72Z75mupQA2lnx+DjZlORTSJONu/T4hWj2GteWIi+qQLG4ZQChKjft90aWr4p3Nd8QMOxHWXTXaYd6y12dD0Y1Dl4ZRvHn5ALtGNCDxVWmu5b0MdAOlbx4xzTWGeQQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1634917620; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:References:Sender:Subject:To; bh=Et7yMSN0PiAcQ6HRakzbqRi4b+yBPGi4flZM8ZWNT8A=; b=CcI1xTI74QI3lqzKLhktpOVYmpWCwrX7KPWNcPe9g/KlFVVnACglrcw4WdQbei9p0hKJTY02hz/Is9F7lfmA27UkDMQNnV6s+rps+Xj0823+hSz9x9vp5FeU1BSL+8ZaLf5LMEcHTGWXMe0uR2wv/wsDlKzlOZhAopE8DvEOzBI= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+82533+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 1634917620032799.4737513143014; Fri, 22 Oct 2021 08:47:00 -0700 (PDT) Return-Path: X-Received: by 127.0.0.2 with SMTP id rOpIYY1788612xPeRB6xbJfE; Fri, 22 Oct 2021 08:46:59 -0700 X-Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by mx.groups.io with SMTP id smtpd.web10.10216.1634917618991189270 for ; Fri, 22 Oct 2021 08:46:59 -0700 X-IronPort-AV: E=McAfee;i="6200,9189,10145"; a="209428360" X-IronPort-AV: E=Sophos;i="5.87,173,1631602800"; d="scan'208";a="209428360" X-Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Oct 2021 08:46:41 -0700 X-IronPort-AV: E=Sophos;i="5.87,173,1631602800"; d="scan'208";a="445333059" X-Received: from gdong1-mobl1.amr.corp.intel.com ([10.212.41.65]) by orsmga006-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Oct 2021 08:46:40 -0700 From: "Guo Dong" To: devel@edk2.groups.io Cc: Guo Dong , Ray Ni , Maurice Ma , Benjamin You Subject: [edk2-devel] [`edk2-devel][PATCH V3 2/8] UefiPayloadPkg: Add a common SMM control Runtime DXE module Date: Fri, 22 Oct 2021 08:46:21 -0700 Message-Id: <20211022154627.1607-3-guo.dong@intel.com> In-Reply-To: <20211022154627.1607-1-guo.dong@intel.com> References: <20211022154627.1607-1-guo.dong@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,guo.dong@intel.com X-Gm-Message-State: M0fI3HhHcdxASNzueXbbhbMAx1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1634917619; bh=ciUfzLzWq/qPC5Ca4/QEAX5CuXknoZV1AxmGjHHyRXE=; h=Cc:Date:From:Reply-To:Subject:To; b=LuSAYTUg3/vWGbtgQGz00Z8vYNF5SHr8lZ2+MBCj5h0KGjbNxtQ8tfuUeXtxFsFcbqA P/i8yqBJWii4WaTC2ni0QApZ6WN0ZRqFJMoHVeKLpSwqdlLEgEps8JIyypqYKa4WcQk6A Y8q1IL+Q3JApRA/JbseNORUsUxkp8vjls78= X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1634918524487100001 Content-Type: text/plain; charset="utf-8" From: Guo Dong This module consumes SMM Registers HOB (SMI_GBL_EN and SMI_APM_EN) to install SMM control 2 protocol gEfiSmmControl2ProtocolGuid. The protocol activate() would set SMI_GBL_EN and SMI_APM_EN and trigger SMI by writing to IO port 0xB3 and 0xB2. Signed-off-by: Guo Dong Cc: Ray Ni Cc: Maurice Ma Cc: Benjamin You Reviewed-by: Ray Ni Reviewed-by: Benjamin You Reviewed-by: Benjamin You + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef PAYLOAD_SMM_REGISTER_INFO_GUID_H_ +#define PAYLOAD_SMM_REGISTER_INFO_GUID_H_ + +#include + +/// +/// SMM Information GUID +/// +extern EFI_GUID gSmmRegisterInfoGuid; + +/// +/// Reuse ACPI definition +/// AddressSpaceId(0xC0-0xFF) is defined by OEM for MSR and other spaces +/// +typedef EFI_ACPI_3_0_GENERIC_ADDRESS_STRUCTURE PLD_GENERIC_ADDRESS; + +#define REGISTER_ID_SMI_GBL_EN 1 +#define REGISTER_ID_SMI_GBL_EN_LOCK 2 +#define REGISTER_ID_SMI_EOS 3 +#define REGISTER_ID_SMI_APM_EN 4 +#define REGISTER_ID_SMI_APM_STS 5 + +#pragma pack(1) +typedef struct { + UINT64 Id; + UINT64 Value; + PLD_GENERIC_ADDRESS Address; +} PLD_GENERIC_REGISTER; + +typedef struct { + UINT16 Revision; + UINT16 Reserved; + UINT32 Count; + PLD_GENERIC_REGISTER Registers[0]; +} PLD_SMM_REGISTERS; + + +#pragma pack() + +#endif diff --git a/UefiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.c b/U= efiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.c new file mode 100644 index 0000000000..6dd91e2601 --- /dev/null +++ b/UefiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.c @@ -0,0 +1,256 @@ +/** @file + This module produces the SMM Control2 Protocol + + Copyright (c) 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SMM_DATA_PORT 0xB3 +#define SMM_CONTROL_PORT 0xB2 + +typedef struct { + UINT8 GblBitOffset; + UINT8 ApmBitOffset; + UINT32 Address; +} SMM_CONTROL2_REG; + +SMM_CONTROL2_REG mSmiCtrlReg; + +/** + Invokes SMI activation from either the preboot or runtime environment. + + This function generates an SMI. + + @param[in] This The EFI_SMM_CONTROL2_PROTOCOL instanc= e. + @param[in,out] CommandPort The value written to the command port. + @param[in,out] DataPort The value written to the data port. + @param[in] Periodic Optional mechanism to engender a peri= odic stream. + @param[in] ActivationInterval Optional parameter to repeat at this = period one + time or, if the Periodic Boolean is s= et, periodically. + + @retval EFI_SUCCESS The SMI has been engendered. + @retval EFI_DEVICE_ERROR The timing is unsupported. + @retval EFI_INVALID_PARAMETER The activation period is unsupported. + @retval EFI_INVALID_PARAMETER The last periodic activation has not been= cleared. + @retval EFI_NOT_STARTED The MM base service has not been initiali= zed. +**/ +EFI_STATUS +EFIAPI +Activate ( + IN CONST EFI_SMM_CONTROL2_PROTOCOL *This, + IN OUT UINT8 *CommandPort OPTIONAL, + IN OUT UINT8 *DataPort OPTIONAL, + IN BOOLEAN Periodic OPTIONAL, + IN EFI_SMM_PERIOD ActivationInterval OPTIONAL + ) +{ + UINT32 SmiEn; + UINT32 SmiEnableBits; + + if (Periodic) { + return EFI_INVALID_PARAMETER; + } + + SmiEn =3D IoRead32 (mSmiCtrlReg.Address); + SmiEnableBits =3D (1 << mSmiCtrlReg.GblBitOffset) | (1 << mSmiCtrlReg.Ap= mBitOffset); + if ((SmiEn & SmiEnableBits) !=3D SmiEnableBits) { + // + // Set the "global SMI enable" bit and APM bit + // + IoWrite32 (mSmiCtrlReg.Address, SmiEn | SmiEnableBits); + } + + IoWrite8 (SMM_DATA_PORT, DataPort =3D=3D NULL ? 0 : *DataPort); + IoWrite8 (SMM_CONTROL_PORT, CommandPort =3D=3D NULL ? 0 : *CommandPort); + return EFI_SUCCESS; +} + +/** + Clears an SMI. + + @param This Pointer to an instance of EFI_SMM_CONTROL2_PROTOCOL + @param Periodic TRUE to indicate a periodical SMI + + @return Return value from SmmClear () + +**/ +EFI_STATUS +EFIAPI +Deactivate ( + IN CONST EFI_SMM_CONTROL2_PROTOCOL *This, + IN BOOLEAN Periodic + ) +{ + if (Periodic) { + return EFI_INVALID_PARAMETER; + } + + // + // Temporarily do nothing here + // + return EFI_SUCCESS; +} + +/// +/// SMM COntrol2 Protocol instance +/// +EFI_SMM_CONTROL2_PROTOCOL mSmmControl2 =3D { + Activate, + Deactivate, + 0 +}; + +/** + Get specified SMI register based on given register ID + + @param[in] SmmRegister SMI related register array from bootloader + @param[in] Id The register ID to get. + + @retval NULL The register is not found or the format is not = expected. + @return smi register + +**/ +PLD_GENERIC_REGISTER * +GetSmmCtrlRegById ( + IN PLD_SMM_REGISTERS *SmmRegister, + IN UINT32 Id + ) +{ + UINT32 Index; + PLD_GENERIC_REGISTER *PldReg; + + PldReg =3D NULL; + for (Index =3D 0; Index < SmmRegister->Count; Index++) { + if (SmmRegister->Registers[Index].Id =3D=3D Id) { + PldReg =3D &SmmRegister->Registers[Index]; + break; + } + } + + if (PldReg =3D=3D NULL) { + DEBUG ((DEBUG_INFO, "Register %d not found.\n", Id)); + return NULL; + } + + // + // Checking the register if it is expected. + // + if ((PldReg->Address.AccessSize !=3D EFI_ACPI_3_0_DWORD) || + (PldReg->Address.Address =3D=3D 0) || + (PldReg->Address.RegisterBitWidth !=3D 1) || + (PldReg->Address.AddressSpaceId !=3D EFI_ACPI_3_0_SYSTEM_IO) || + (PldReg->Value !=3D 1)) { + DEBUG ((DEBUG_INFO, "Unexpected SMM register.\n")); + DEBUG ((DEBUG_INFO, "AddressSpaceId=3D 0x%x\n", PldReg->Address.Addres= sSpaceId)); + DEBUG ((DEBUG_INFO, "RegBitWidth =3D 0x%x\n", PldReg->Address.Regist= erBitWidth)); + DEBUG ((DEBUG_INFO, "RegBitOffset =3D 0x%x\n", PldReg->Address.Regist= erBitOffset)); + DEBUG ((DEBUG_INFO, "AccessSize =3D 0x%x\n", PldReg->Address.Access= Size)); + DEBUG ((DEBUG_INFO, "Address =3D 0x%lx\n",PldReg->Address.Addres= s )); + return NULL; + } + return PldReg; +} + + +/** + Fixup data pointers so that the services can be called in virtual mode. + + @param[in] Event The event registered. + @param[in] Context Event context. + +**/ +VOID +EFIAPI +SmmControlVirtualAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EfiConvertPointer (0x0, (VOID **) &(mSmmControl2.Trigger)); + EfiConvertPointer (0x0, (VOID **) &(mSmmControl2.Clear)); +} + + +/** + This function installs EFI_SMM_CONTROL2_PROTOCOL. + + @param ImageHandle Handle for the image of this driver + @param SystemTable Pointer to the EFI System Table + + @retval EFI_UNSUPPORTED There's no Intel ICH on this platform + @return The status returned from InstallProtocolInterface(). + +**/ +EFI_STATUS +EFIAPI +SmmControlEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HOB_GUID_TYPE *GuidHob; + PLD_SMM_REGISTERS *SmmRegister; + PLD_GENERIC_REGISTER *SmiGblEnReg; + PLD_GENERIC_REGISTER *SmiApmEnReg; + EFI_EVENT Event; + + GuidHob =3D GetFirstGuidHob (&gSmmRegisterInfoGuid); + if (GuidHob =3D=3D NULL) { + return EFI_UNSUPPORTED; + } + + SmmRegister =3D (PLD_SMM_REGISTERS *) (GET_GUID_HOB_DATA(GuidHob)); + SmiGblEnReg =3D GetSmmCtrlRegById (SmmRegister, REGISTER_ID_SMI_GBL_EN); + if (SmiGblEnReg =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "SMI global enable reg not found.\n")); + return EFI_NOT_FOUND; + } + mSmiCtrlReg.Address =3D (UINT32)SmiGblEnReg->Address.Address; + mSmiCtrlReg.GblBitOffset =3D SmiGblEnReg->Address.RegisterBitOffset; + + SmiApmEnReg =3D GetSmmCtrlRegById (SmmRegister, REGISTER_ID_SMI_APM_EN); + if (SmiApmEnReg =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "SMI APM enable reg not found.\n")); + return EFI_NOT_FOUND; + } + + if (SmiApmEnReg->Address.Address !=3D mSmiCtrlReg.Address) { + DEBUG ((DEBUG_ERROR, "SMI APM EN and SMI GBL EN are expected to have s= ame register base\n")); + DEBUG ((DEBUG_ERROR, "APM:0x%x, GBL:0x%x\n", SmiApmEnReg->Address.Addr= ess, mSmiCtrlReg.Address)); + return EFI_UNSUPPORTED; + } + mSmiCtrlReg.ApmBitOffset =3D SmiApmEnReg->Address.RegisterBitOffset; + + // + // Install our protocol interfaces on the device's handle + // + Status =3D gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gEfiSmmControl2ProtocolGuid, + &mSmmControl2, + NULL + ); + ASSERT_EFI_ERROR (Status); + + Status =3D gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + SmmControlVirtualAddressChangeEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &Event + ); + return Status; +} diff --git a/UefiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.inf b= /UefiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.inf new file mode 100644 index 0000000000..f0c2a4586b --- /dev/null +++ b/UefiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.inf @@ -0,0 +1,50 @@ +## @file +# SMM Control runtime DXE Module +# +# Provides the ability to generate a software SMI. +# +# Copyright (c) 2021, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D SmmControlRuntimeDxe + FILE_GUID =3D C3099578-F815-4a96-84A3-FC593760181D + MODULE_TYPE =3D DXE_RUNTIME_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D SmmControlEntryPoint + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 +# + +[Sources] + SmmControlRuntimeDxe.c + +[Packages] + MdePkg/MdePkg.dec + UefiPayloadPkg/UefiPayloadPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + DebugLib + UefiBootServicesTableLib + UefiRuntimeLib + PcdLib + IoLib + HobLib + +[Guids] + gSmmRegisterInfoGuid + gEfiEventVirtualAddressChangeGuid + +[Protocols] + gEfiSmmControl2ProtocolGuid ## PRODUCES + +[Depex] + TRUE diff --git a/UefiPayloadPkg/UefiPayloadPkg.dec b/UefiPayloadPkg/UefiPayload= Pkg.dec index e5e8db8863..4f93d3e671 100644 --- a/UefiPayloadPkg/UefiPayloadPkg.dec +++ b/UefiPayloadPkg/UefiPayloadPkg.dec @@ -37,6 +37,8 @@ gUefiSerialPortInfoGuid =3D { 0x6c6872fe, 0x56a9, 0x4403, { 0xbb, 0x98,= 0x95, 0x8d, 0x62, 0xde, 0x87, 0xf1 } } gLoaderMemoryMapInfoGuid =3D { 0xa1ff7424, 0x7a1a, 0x478e, { 0xa9, 0xe4,= 0x92, 0xf3, 0x57, 0xd1, 0x28, 0x32 } } =20 + gSmmRegisterInfoGuid =3D { 0xaa9bd7a7, 0xcafb, 0x4499, { 0xa4, 0xa9,= 0xb, 0x34, 0x6b, 0x40, 0xa6, 0x22 } } + [Ppis] gEfiPayLoadHobBasePpiGuid =3D { 0xdbe23aa1, 0xa342, 0x4b97, {0x85, 0xb6,= 0xb2, 0x26, 0xf1, 0x61, 0x73, 0x89} } =20 --=20 2.32.0.windows.2 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#82533): https://edk2.groups.io/g/devel/message/82533 Mute This Topic: https://groups.io/mt/86517141/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- From nobody Sat May 4 03:30:04 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+82534+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+82534+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1634917620; cv=none; d=zohomail.com; s=zohoarc; b=hPrl6m634qhFZRjqBXmwaO6PoBFVzRDl5mIqqXlqW7o7PkMxb1tgbaOwir5z5JepWylU/kCM291V93/e01TWHDuQZOWe8rnQQ5kdhUzx6pdANWS0yWjoWoPAzOfJnHAw6z8uVEDIOjlKt1ULxigzxM3oV5axAy+D4BP26lqnc3U= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1634917620; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:References:Sender:Subject:To; bh=sfsfYWy4Nlhjyo4lERn5pHk1d8kzSoFGKiTmqHcU2Rw=; b=UAQlcaaeh+VCnMth40ZFh5RfRQBeaju+bLdj/OVBWxQz4TDSQ2b5z6hmjXpIni/kdyAfR4Xq3dbs1rDTASvNldcecPZBuub6AvakT7qZOf8jlbZJfoovQ2M7JFGPbQTND1kpm6ESuwasmcN15Qyr6PFBX3UcaopNgV5CJnpMBEY= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+82534+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 1634917620392120.91444024834402; Fri, 22 Oct 2021 08:47:00 -0700 (PDT) Return-Path: X-Received: by 127.0.0.2 with SMTP id dBopYY1788612xHiPDzR6n30; Fri, 22 Oct 2021 08:47:00 -0700 X-Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by mx.groups.io with SMTP id smtpd.web11.10188.1634917617623869169 for ; Fri, 22 Oct 2021 08:46:59 -0700 X-IronPort-AV: E=McAfee;i="6200,9189,10145"; a="209428364" X-IronPort-AV: E=Sophos;i="5.87,173,1631602800"; d="scan'208";a="209428364" X-Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Oct 2021 08:46:41 -0700 X-IronPort-AV: E=Sophos;i="5.87,173,1631602800"; d="scan'208";a="445333065" X-Received: from gdong1-mobl1.amr.corp.intel.com ([10.212.41.65]) by orsmga006-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Oct 2021 08:46:40 -0700 From: "Guo Dong" To: devel@edk2.groups.io Cc: Guo Dong , Ray Ni , Maurice Ma , Benjamin You Subject: [edk2-devel] [`edk2-devel][PATCH V3 3/8] UefiPayloadPkg: Add bootloader SMM support module Date: Fri, 22 Oct 2021 08:46:22 -0700 Message-Id: <20211022154627.1607-4-guo.dong@intel.com> In-Reply-To: <20211022154627.1607-1-guo.dong@intel.com> References: <20211022154627.1607-1-guo.dong@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,guo.dong@intel.com X-Gm-Message-State: H0YQfE0YSPWqI1AIsweAXnW9x1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1634917620; bh=2A3R+K19mMLRwd6J+vEyT7iNzQJyCWwyjsJOI8z+LGE=; h=Cc:Date:From:Reply-To:Subject:To; b=ejT1BJR7nkO4EBF8XxSawwYN1VaU4sUuS/clj0G+jPpdiW/UmrftLqdqnVIzWKvrca1 KbHAEzOv8M7xo5Gzp0FwTEN0Oy7b2QCddrD5DrJqcW3J6lQIPMuzhlUFpRF+6ll6GukP3 x3XC7CpOJZDaT42qOTM5CKOHJOsVcPJ6ciI= X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1634918524603100003 Content-Type: text/plain; charset="utf-8" From: Guo Dong This module is only used for SMM S3 support for the bootloader that doesn't support SMM. The payload would save SMM rebase info to SMM communication area in normal boot and expect the bootloader in S3 path to rebase the SMM and trigger SMI by writing 0xB2 port with the given value from SMM communication area. The payload SMM handler would get chance to restore some registers in S3 path. Signed-off-by: Guo Dong Cc: Ray Ni Cc: Maurice Ma Cc: Benjamin You Reviewed-by: Ray Ni Reviewed-by: Benjamin You Reviewed-by: Benjamin You + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +PLD_S3_COMMUNICATION mPldS3Hob; +EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *mSmramHob =3D NULL; +PLD_SMM_REGISTERS *mSmmRegisterHob =3D NULL;; +UINT64 mSmmFeatureControl =3D 0; + +/** + Save SMM rebase and SMI handler information to SMM communication area + + The function detects SMM communication region for boot loader, if it is = detected, it + will save SMM rebase information and S3 SMI handler information to SMM c= ommunication + region. Bootloader should consume these information in S3 path to restor= e smm base, + and write the 0xB2 port to trigger SMI so that payload could resume S3 r= egisters. + + @param[in] BlSwSmiHandlerInput Value written to 0xB2 to trigger SMI ha= ndler. + + @retval EFI_SUCCESS Save SMM info success. + @retval Others Failed to save SMM info. +**/ +EFI_STATUS +SaveSmmInfoForS3 ( + IN UINT8 BlSwSmiHandlerInput + ) +{ + EFI_STATUS Status; + EFI_PROCESSOR_INFORMATION ProcessorInfo; + EFI_MP_SERVICES_PROTOCOL *MpService; + CPU_SMMBASE *SmmBaseInfo; + PLD_TO_BL_SMM_INFO *PldSmmInfo; + UINTN Index; + + PldSmmInfo =3D (PLD_TO_BL_SMM_INFO *)(UINTN)mPldS3Hob.CommBuffer.Physica= lStart; + PldSmmInfo->Header.Header.HobLength =3D (UINT16)(sizeof (PLD_TO_BL_SMM_I= NFO) + gSmst->NumberOfCpus * sizeof (CPU_SMMBASE)); + for (Index =3D 0; Index < mSmramHob->NumberOfSmmReservedRegions; Index++= ) { + if ((mPldS3Hob.CommBuffer.PhysicalStart >=3D mSmramHob->Descriptor[Ind= ex].PhysicalStart) && + (mPldS3Hob.CommBuffer.PhysicalStart < mSmramHob->Descriptor[Index= ].PhysicalStart + mSmramHob->Descriptor[Index].PhysicalSize)) { + break; + } + } + if (Index =3D=3D mSmramHob->NumberOfSmmReservedRegions) { + return EFI_NOT_FOUND; + } + + // + // Make sure the dedicated region for SMM info communication whose attri= bute is "allocated" (i.e., excluded from SMM memory service) + //=20 + if ((mSmramHob->Descriptor[Index].RegionState & EFI_ALLOCATED) =3D=3D 0)= { + DEBUG ((DEBUG_ERROR, "SMM communication region not set to EFI_ALLOCATE= D\n")); + return EFI_INVALID_PARAMETER; + } + + if (((UINTN)PldSmmInfo + PldSmmInfo->Header.Header.HobLength) > (mSmramH= ob->Descriptor[Index].PhysicalStart + mSmramHob->Descriptor[Index].Physical= Size)) { + DEBUG ((DEBUG_ERROR, "SMM communication buffer (0x%x) is too small.\n"= , (UINTN)PldSmmInfo + PldSmmInfo->Header.Header.HobLength)); + return EFI_BUFFER_TOO_SMALL; + } + + CopyGuid (&PldSmmInfo->Header.Name, &gS3CommunicationGuid); + PldSmmInfo->Header.Header.HobType =3D EFI_HOB_TYPE_GUID_EXTENSION; + PldSmmInfo->S3Info.SwSmiTriggerValue =3D BlSwSmiHandlerInput; + + // + // Save APIC ID and SMM base + // + Status =3D gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID = **)&MpService); + if (EFI_ERROR(Status)) { + return Status; + } + PldSmmInfo->S3Info.CpuCount =3D (UINT32)gSmst->NumberOfCpus; + SmmBaseInfo =3D &PldSmmInfo->S3Info.SmmBase[0]; + for (Index =3D 0; Index < gSmst->NumberOfCpus; Index++) { + Status =3D MpService->GetProcessorInfo (MpService, Index, &ProcessorIn= fo); + if (EFI_ERROR(Status)) { + return Status; + } + + SmmBaseInfo->ApicId =3D (UINT32)(UINTN)ProcessorInfo.ProcessorId; + SmmBaseInfo->SmmBase =3D (UINT32)(UINTN)gSmst->CpuSaveState[Index] - S= MRAM_SAVE_STATE_MAP_OFFSET; + DEBUG ((DEBUG_INFO, "CPU%d ID:%02X Base: %08X\n", Index, SmmBaseInfo->= ApicId, SmmBaseInfo->SmmBase)); + SmmBaseInfo++; + } + + return EFI_SUCCESS; +} + + +/** + Get specified SMI register based on given register ID + + @param[in] Id The register ID to get. + + @retval NULL The register is not found + @return smi register + +**/ +PLD_GENERIC_REGISTER * +GetRegisterById ( + UINT64 Id + ) +{ + UINT32 Index; + + for (Index =3D 0; Index < mSmmRegisterHob->Count; Index++) { + if (mSmmRegisterHob->Registers[Index].Id =3D=3D Id) { + return &mSmmRegisterHob->Registers[Index]; + } + } + return NULL; +} + +/** + Set SMM SMI Global enable lock + +**/ +VOID +LockSmiGlobalEn ( + VOID + ) +{ + PLD_GENERIC_REGISTER *SmiLockReg; + + DEBUG ((DEBUG_ERROR, "LockSmiGlobalEn .....\n")); + + SmiLockReg =3D GetRegisterById (REGISTER_ID_SMI_GBL_EN_LOCK); + if (SmiLockReg =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "SMI global enable lock reg not found.\n")); + return; + } + + // + // Set SMM SMI lock in S3 path + // + if ((SmiLockReg->Address.AccessSize =3D=3D EFI_ACPI_3_0_DWORD) && + (SmiLockReg->Address.Address !=3D 0) && + (SmiLockReg->Address.RegisterBitWidth =3D=3D 1) && + (SmiLockReg->Address.AddressSpaceId =3D=3D EFI_ACPI_3_0_SYSTEM_MEM= ORY) && + (SmiLockReg->Value =3D=3D 1)) { + DEBUG ((DEBUG_ERROR, "LockSmiGlobalEn ....is locked\n")); + + MmioOr32 ((UINT32)SmiLockReg->Address.Address, 1 << SmiLockReg->Addres= s.RegisterBitOffset); + } else { + DEBUG ((DEBUG_ERROR, "Unexpected SMM SMI lock register, need enhanceme= nt here.\n")); + } +} + +/** + Check and set SMM feature lock bit and code check enable bit + in S3 path. + +**/ +VOID +SmmFeatureLockOnS3 ( + VOID + ) +{ + + if (mSmmFeatureControl !=3D 0) { + return; + } + + mSmmFeatureControl =3D AsmReadMsr64(MSR_SMM_FEATURE_CONTROL); + if ((mSmmFeatureControl & 0x5) !=3D 0x5) { + // + // Set Lock bit [BIT0] for this register and SMM code check enable bit= [BIT2] + // + AsmWriteMsr64 (MSR_SMM_FEATURE_CONTROL, mSmmFeatureControl | 0x5); + } + mSmmFeatureControl =3D AsmReadMsr64(MSR_SMM_FEATURE_CONTROL); +} + + + +/** + Function to program SMRR base and mask. + + @param[in] ProcedureArgument Pointer to SMRR_BASE_MASK structure. +**/ +VOID +SetSmrr ( + IN VOID *ProcedureArgument + ) +{ + if (ProcedureArgument !=3D NULL) { + AsmWriteMsr64 (MSR_IA32_SMRR_PHYSBASE, ((SMRR_BASE_MASK *)ProcedureArg= ument)->Base); + AsmWriteMsr64 (MSR_IA32_SMRR_PHYSMASK, ((SMRR_BASE_MASK *)ProcedureArg= ument)->Mask); + } +} + +/** + Set SMRR in S3 path. + +**/ +VOID +SetSmrrOnS3 ( + VOID + ) +{ + EFI_STATUS Status; + SMRR_BASE_MASK Arguments; + UINTN Index; + UINT32 SmmBase; + UINT32 SmmSize; + + if ((AsmReadMsr64 (MSR_IA32_SMRR_PHYSBASE) !=3D 0) && ((AsmReadMsr64 (MS= R_IA32_SMRR_PHYSMASK) & BIT11) !=3D 0)) { + return; + } + + SmmBase =3D (UINT32)(UINTN)mSmramHob->Descriptor[0].PhysicalStart; + SmmSize =3D (UINT32)(UINTN)mSmramHob->Descriptor[0].PhysicalSize; + if ((mSmramHob->NumberOfSmmReservedRegions > 2) || (mSmramHob->NumberOfS= mmReservedRegions =3D=3D 0)) { + DEBUG ((DEBUG_ERROR, "%d SMM ranges are not supported.\n", mSmramHob->= NumberOfSmmReservedRegions)); + return; + } else if (mSmramHob->NumberOfSmmReservedRegions =3D=3D 2) { + if ((mSmramHob->Descriptor[1].PhysicalStart + mSmramHob->Descriptor[1]= .PhysicalSize) =3D=3D SmmBase){ + SmmBase =3D (UINT32)(UINTN)mSmramHob->Descriptor[1].PhysicalStart; + } else if (mSmramHob->Descriptor[1].PhysicalStart !=3D (SmmBase + SmmS= ize)) { + DEBUG ((DEBUG_ERROR, "Two SMM regions are not continous.\n")); + return; + } + SmmSize +=3D (UINT32)(UINTN)mSmramHob->Descriptor[1].PhysicalSize; + } + + if ((SmmBase =3D=3D 0) || (SmmSize < SIZE_4KB)) { + DEBUG ((DEBUG_ERROR, "Invalid SMM range.\n")); + return ; + } + + // + // SMRR size must be of length 2^n + // SMRR base alignment cannot be less than SMRR length + // + if ((SmmSize !=3D GetPowerOfTwo32 (SmmSize)) || ((SmmBase & ~(SmmSize - = 1)) !=3D SmmBase)) { + DEBUG ((DEBUG_ERROR, " Invalid SMM range.\n")); + return ; + } + + // + // Calculate smrr base, mask and pass them as arguments. + // + Arguments.Base =3D (SmmSize | MTRR_CACHE_WRITE_BACK); + Arguments.Mask =3D (~(SmmSize - 1) & EFI_MSR_SMRR_MASK); + + // + // Set SMRR valid bit + // + Arguments.Mask |=3D BIT11; + + // + // Program smrr base and mask on BSP first and then on APs + // + SetSmrr(&Arguments); + for (Index =3D 0; Index < gSmst->NumberOfCpus; Index++) { + if (Index !=3D gSmst->CurrentlyExecutingCpu) { + Status =3D gSmst->SmmStartupThisAp (SetSmrr, Index, (VOID *)&Argumen= ts); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "Programming SMRR on AP# %d status: %r\n", In= dex, Status)); + } + } + } +} + + +/** + Software SMI callback for restoring SMRR base and mask in S3 path. + + @param[in] DispatchHandle The unique handle assigned to this handl= er by SmiHandlerRegister(). + @param[in] Context Points to an optional handler context wh= ich was specified when the + handler was registered. + @param[in, out] CommBuffer A pointer to a collection of data in mem= ory that will + be conveyed from a non-SMM environment i= nto an SMM environment. + @param[in, out] CommBufferSize The size of the CommBuffer. + + @retval EFI_SUCCESS The interrupt was handled successfully. + +**/ +EFI_STATUS +EFIAPI +BlSwSmiHandler ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context, + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommBufferSize + ) +{ + SetSmrrOnS3 (); + SmmFeatureLockOnS3 (); + LockSmiGlobalEn (); + + return EFI_SUCCESS; +} + + +/** + Lock SMI in this SMM ready to lock event. + + @param Protocol Points to the protocol's unique identifier + @param Interface Points to the interface instance + @param Handle The handle on which the interface was installed + + @retval EFI_SUCCESS SmmEventCallback runs successfully + @retval EFI_NOT_FOUND The Fvb protocol for variable is not found. + **/ +EFI_STATUS +EFIAPI +BlSupportSmmReadyToLockCallback ( + IN CONST EFI_GUID *Protocol, + IN VOID *Interface, + IN EFI_HANDLE Handle + ) +{ + // + // Set SMM SMI lock + // + LockSmiGlobalEn (); + return EFI_SUCCESS; +} + + +/** + The driver's entry point. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval Others Some error occurs when executing this entry poin= t. + +**/ +EFI_STATUS +EFIAPI +BlSupportSmm ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch; + EFI_SMM_SW_REGISTER_CONTEXT SwContext; + EFI_HANDLE SwHandle; + EFI_HOB_GUID_TYPE *GuidHob; + VOID *SmmHob; + VOID *Registration; + + // + // Get SMM S3 communication hob and save it + // + GuidHob =3D GetFirstGuidHob (&gS3CommunicationGuid); + if (GuidHob !=3D NULL) { + SmmHob =3D (VOID *) (GET_GUID_HOB_DATA(GuidHob)); + CopyMem (&mPldS3Hob, SmmHob, GET_GUID_HOB_DATA_SIZE(GuidHob)); + } else { + return EFI_NOT_FOUND; + } + + if (mPldS3Hob.PldAcpiS3Enable) { + // Other drivers will take care of S3. + return EFI_SUCCESS; + } + + // + // Get smram hob and save it + // + GuidHob =3D GetFirstGuidHob (&gEfiSmmSmramMemoryGuid); + if (GuidHob !=3D NULL) { + SmmHob =3D (VOID *) (GET_GUID_HOB_DATA(GuidHob)); + mSmramHob =3D AllocatePool (GET_GUID_HOB_DATA_SIZE(GuidHob)); + if (mSmramHob =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem (mSmramHob, SmmHob, GET_GUID_HOB_DATA_SIZE(GuidHob)); + } else { + return EFI_NOT_FOUND; + } + + // + // Get SMM register hob and save it + // + GuidHob =3D GetFirstGuidHob (&gSmmRegisterInfoGuid); + if (GuidHob !=3D NULL) { + SmmHob =3D (VOID *) (GET_GUID_HOB_DATA(GuidHob)); + mSmmRegisterHob =3D AllocatePool (GET_GUID_HOB_DATA_SIZE(GuidHob)); + if (mSmmRegisterHob =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem (mSmmRegisterHob, SmmHob, GET_GUID_HOB_DATA_SIZE(GuidHob)); + } else { + return EFI_NOT_FOUND; + } + + // + // Get the Sw dispatch protocol and register SMI handler. + // + Status =3D gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NU= LL, (VOID**)&SwDispatch); + if (EFI_ERROR (Status)) { + return Status; + } + SwContext.SwSmiInputValue =3D (UINTN) -1; + Status =3D SwDispatch->Register (SwDispatch, BlSwSmiHandler, &SwContext,= &SwHandle); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Registering S3 smi handler failed: %r\n", Status= )); + return Status; + } + + // + // Register SMM ready to lock callback + // + Status =3D gSmst->SmmRegisterProtocolNotify ( + &gEfiSmmReadyToLockProtocolGuid, + BlSupportSmmReadyToLockCallback, + &Registration + ); + ASSERT_EFI_ERROR (Status); + + SaveSmmInfoForS3 ((UINT8)SwContext.SwSmiInputValue); + + return EFI_SUCCESS; +} + diff --git a/UefiPayloadPkg/BlSupportSmm/BlSupportSmm.h b/UefiPayloadPkg/Bl= SupportSmm/BlSupportSmm.h new file mode 100644 index 0000000000..f4386cb842 --- /dev/null +++ b/UefiPayloadPkg/BlSupportSmm/BlSupportSmm.h @@ -0,0 +1,41 @@ +/** @file + The header file of bootloader support SMM. + + Copyright (c) 2021, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#ifndef BL_SUPPORT_SMM_H_ +#define BL_SUPPORT_SMM_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define EFI_MSR_SMRR_MASK 0xFFFFF000 +#define MSR_SMM_FEATURE_CONTROL 0x4E0 +#define SMRAM_SAVE_STATE_MAP_OFFSET 0xFC00 /// Save state offset from= SMBASE + +typedef struct { + UINT32 Base; + UINT32 Mask; +} SMRR_BASE_MASK; + +#endif + diff --git a/UefiPayloadPkg/BlSupportSmm/BlSupportSmm.inf b/UefiPayloadPkg/= BlSupportSmm/BlSupportSmm.inf new file mode 100644 index 0000000000..75d4777971 --- /dev/null +++ b/UefiPayloadPkg/BlSupportSmm/BlSupportSmm.inf @@ -0,0 +1,49 @@ +## @file +# Bootloader Support SMM module +# +# Copyright (c) 2021, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D BlSupportSmm + FILE_GUID =3D AA292DE7-E11E-42E6-846B-5813A5A8D982 + MODULE_TYPE =3D DXE_SMM_DRIVER + PI_SPECIFICATION_VERSION =3D 0x0001000A + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D BlSupportSmm + +[Sources] + BlSupportSmm.c + BlSupportSmm.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + UefiPayloadPkg/UefiPayloadPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + UefiBootServicesTableLib + SmmServicesTableLib + MemoryAllocationLib + BaseLib + IoLib + HobLib + +[Guids] + gS3CommunicationGuid + gEfiSmmSmramMemoryGuid + gSmmRegisterInfoGuid + +[Protocols] + gEfiSmmSwDispatch2ProtocolGuid + gEfiMpServiceProtocolGuid + gEfiSmmReadyToLockProtocolGuid + +[Depex] + gEfiSmmSwDispatch2ProtocolGuid diff --git a/UefiPayloadPkg/Include/Guid/SmmS3CommunicationInfoGuid.h b/Uef= iPayloadPkg/Include/Guid/SmmS3CommunicationInfoGuid.h new file mode 100644 index 0000000000..ee621b25f4 --- /dev/null +++ b/UefiPayloadPkg/Include/Guid/SmmS3CommunicationInfoGuid.h @@ -0,0 +1,54 @@ +/** @file + This file defines the SMM S3 communication hob structure. + + Copyright (c) 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef PAYLOAD_S3_COMMUNICATION_GUID_H_ +#define PAYLOAD_S3_COMMUNICATION_GUID_H_ + +extern EFI_GUID gS3CommunicationGuid; + +#pragma pack(1) + +typedef struct { + EFI_SMRAM_DESCRIPTOR CommBuffer; + BOOLEAN PldAcpiS3Enable; +} PLD_S3_COMMUNICATION; + +/// +/// The information below is used for communication between bootloader and= payload. +/// It is used to save/store some registers in S3 path +/// +/// This region exists only when gEfiAcpiVariableGuid HOB exist. +/// when PLD_S3_INFO.PldAcpiS3Enable is false, the communication buffer is= defined as below. +/// + +typedef struct { + UINT32 ApicId; + UINT32 SmmBase; +} CPU_SMMBASE; + +typedef struct { + UINT8 SwSmiData; + UINT8 SwSmiTriggerValue; + UINT16 Reserved; + UINT32 CpuCount; + CPU_SMMBASE SmmBase[0]; +} SMM_S3_INFO; + +// +// Payload would save this structure to S3 communication area in normal bo= ot. +// In S3 path, bootloader need restore SMM base and writie IO port 0xB2 wi= th SwSmiTriggerValue +// to trigger SMI to let payload to restore S3. +// +typedef struct { + EFI_HOB_GUID_TYPE Header; + SMM_S3_INFO S3Info; +} PLD_TO_BL_SMM_INFO; + +#pragma pack() + +#endif diff --git a/UefiPayloadPkg/UefiPayloadPkg.dec b/UefiPayloadPkg/UefiPayload= Pkg.dec index 4f93d3e671..4c3bd0c2eb 100644 --- a/UefiPayloadPkg/UefiPayloadPkg.dec +++ b/UefiPayloadPkg/UefiPayloadPkg.dec @@ -38,6 +38,7 @@ gLoaderMemoryMapInfoGuid =3D { 0xa1ff7424, 0x7a1a, 0x478e, { 0xa9, 0xe4,= 0x92, 0xf3, 0x57, 0xd1, 0x28, 0x32 } } =20 gSmmRegisterInfoGuid =3D { 0xaa9bd7a7, 0xcafb, 0x4499, { 0xa4, 0xa9,= 0xb, 0x34, 0x6b, 0x40, 0xa6, 0x22 } } + gS3CommunicationGuid =3D { 0x88e31ba1, 0x1856, 0x4b8b, { 0xbb, 0xdf,= 0xf8, 0x16, 0xdd, 0x94, 0xa, 0xef } } =20 [Ppis] gEfiPayLoadHobBasePpiGuid =3D { 0xdbe23aa1, 0xa342, 0x4b97, {0x85, 0xb6,= 0xb2, 0x26, 0xf1, 0x61, 0x73, 0x89} } --=20 2.32.0.windows.2 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#82534): https://edk2.groups.io/g/devel/message/82534 Mute This Topic: https://groups.io/mt/86517142/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- From nobody Sat May 4 03:30:04 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+82536+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+82536+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1634917621; cv=none; d=zohomail.com; s=zohoarc; b=mot9Sqmjgp3G3VEu0WKwRPRdVZHfDH7ApUreSoGkGAXVTBKKga/y6yZPMO4zthkbgccfNy1ZuY1Sa+H8nI1Ra9+ivx5cJeDalI3I+7r1q3tyqQMG10MoWC40uMw1g2uEA5m1UNb6zqVozJ8OoXNt/v95s/PWLKwldJS8SVEeBoI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1634917621; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:References:Sender:Subject:To; bh=/ixf9mOBdArSUoyGDILqdgaWIWiXA1TR8Emc/H07Ve8=; b=FrKnJpvUaImdvrsAYWNJPnnE23IW3GeSrX3cNsJbYsd4Dgn+p2fSZ4SOwlTy4IuUZZrStZq8r/i7DffsR8NfjQFHv16VXoNQC+SdurwtfnDWn/ZBAy+X0HYnKDHFIPCfEgMX9oNGC1Gds1oURyPdfdeyjYuToZ1i9xTqS1ASz6Q= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+82536+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 1634917621568432.1636435315344; Fri, 22 Oct 2021 08:47:01 -0700 (PDT) Return-Path: X-Received: by 127.0.0.2 with SMTP id Zpc7YY1788612xkhBXOtqc9o; Fri, 22 Oct 2021 08:47:01 -0700 X-Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by mx.groups.io with SMTP id smtpd.web11.10188.1634917617623869169 for ; Fri, 22 Oct 2021 08:46:59 -0700 X-IronPort-AV: E=McAfee;i="6200,9189,10145"; a="209428370" X-IronPort-AV: E=Sophos;i="5.87,173,1631602800"; d="scan'208";a="209428370" X-Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Oct 2021 08:46:42 -0700 X-IronPort-AV: E=Sophos;i="5.87,173,1631602800"; d="scan'208";a="445333075" X-Received: from gdong1-mobl1.amr.corp.intel.com ([10.212.41.65]) by orsmga006-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Oct 2021 08:46:41 -0700 From: "Guo Dong" To: devel@edk2.groups.io Cc: Guo Dong , Ray Ni , Maurice Ma , Benjamin You Subject: [edk2-devel] [`edk2-devel][PATCH V3 4/8] UefiPayloadPkg: Add SpiFlashLib Date: Fri, 22 Oct 2021 08:46:23 -0700 Message-Id: <20211022154627.1607-5-guo.dong@intel.com> In-Reply-To: <20211022154627.1607-1-guo.dong@intel.com> References: <20211022154627.1607-1-guo.dong@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,guo.dong@intel.com X-Gm-Message-State: oN204qK2vMHv5tomeBIQn5vfx1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1634917621; bh=PPHWMvwv3AjItGTtKZxe40Zfm8u4SHqk/nHTkfGsrL8=; h=Cc:Date:From:Reply-To:Subject:To; b=UsYGaI4/+234jB1o3h5yxuc77XZWepNAeVry9tY9NI0CBE3JwafWgVQcJQm9KBg9+Yl SeXBVGxQoNoMK6M9rZvN7UdZgxgj//uURjqBR9X2lpKvH6KU/7AYCCsGMfYxTtQsZpBl1 oP9LHFJnmdZk5LM/y3KNvBr3PPBOSVhCBz4= X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1634917622356100018 Content-Type: text/plain; charset="utf-8" From: Guo Dong This is a common SPI Flash library used for the Intel platform that supports SPI hardware sequence. This library provides actual SPI flash operation via Intel PCH SPI controller. Signed-off-by: Guo Dong Cc: Ray Ni Cc: Maurice Ma Cc: Benjamin You Reviewed-by: Ray Ni Reviewed-by: Benjamin You Reviewed-by: Benjamin You + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef SPI_FLASH_INFO_GUID_H_ +#define SPI_FLASH_INFO_GUID_H_ + +#include +// +// SPI Flash infor hob GUID +// +extern EFI_GUID gSpiFlashInfoGuid; + +// +// Set this bit if platform need disable SMM write protection when writing= flash +// in SMM mode using this method: -- AsmWriteMsr32 (0x1FE, MmioRead32 (0x= FED30880) | BIT0); +// +#define FLAGS_SPI_DISABLE_SMM_WRITE_PROTECT BIT0 + +// +// Reuse ACPI definition +// +typedef EFI_ACPI_3_0_GENERIC_ADDRESS_STRUCTURE PLD_GENERIC_ADDRESS; +#define SPACE_ID_PCI_CONFIGURATION EFI_ACPI_3_0_PCI_CONFIGURA= TION_SPACE +#define REGISTER_BIT_WIDTH_DWORD EFI_ACPI_3_0_DWORD + +typedef struct { + UINT8 Revision; + UINT8 Reserved; + UINT16 Flags; + PLD_GENERIC_ADDRESS SpiAddress; +} SPI_FLASH_INFO; + +#endif diff --git a/UefiPayloadPkg/Include/Library/SpiFlashLib.h b/UefiPayloadPkg/= Include/Library/SpiFlashLib.h new file mode 100644 index 0000000000..59840afb70 --- /dev/null +++ b/UefiPayloadPkg/Include/Library/SpiFlashLib.h @@ -0,0 +1,215 @@ +/** @file + PCH SPI Common Driver implements the SPI Host Controller Compatibility I= nterface. + + Copyright (c) 2017 - 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef SPI_FLASH_LIB_H_ +#define SPI_FLASH_LIB_H_ + +/** + Flash Region Type +**/ +typedef enum { + FlashRegionDescriptor, + FlashRegionBios, + FlashRegionMe, + FlashRegionGbE, + FlashRegionPlatformData, + FlashRegionDer, + FlashRegionAll, + FlashRegionMax +} FLASH_REGION_TYPE; + +/** + Read SFDP data from the flash part. + + @param[in] ComponentNumber The Component Number for chip select + @param[in] ByteCount Number of bytes in SFDP data portion of = the SPI cycle, the max number is 64 + @param[out] SfdpData The Pointer to caller-allocated buffer c= ontaining the SFDP data received + It is the caller's responsibility to mak= e sure Buffer is large enough for the total number of bytes read. + + @retval EFI_SUCCESS Command succeed. + @retval EFI_INVALID_PARAMETER The parameters specified are not valid. + @retval EFI_DEVICE_ERROR Device error, command aborts abnormally. +**/ +EFI_STATUS +EFIAPI +SpiFlashReadSfdp ( + IN UINT8 ComponentNumber, + IN UINT32 ByteCount, + OUT UINT8 *SfdpData + ); + +/** + Read Jedec Id from the flash part. + + @param[in] ComponentNumber The Component Number for chip select + @param[in] ByteCount Number of bytes in JedecId data portion = of the SPI cycle, the data size is 3 typically + @param[out] JedecId The Pointer to caller-allocated buffer c= ontaining JEDEC ID received + It is the caller's responsibility to mak= e sure Buffer is large enough for the total number of bytes read. + + @retval EFI_SUCCESS Command succeed. + @retval EFI_INVALID_PARAMETER The parameters specified are not valid. + @retval EFI_DEVICE_ERROR Device error, command aborts abnormally. +**/ +EFI_STATUS +EFIAPI +SpiFlashReadJedecId ( + IN UINT8 ComponentNumber, + IN UINT32 ByteCount, + OUT UINT8 *JedecId + ); + +/** + Write the status register in the flash part. + + @param[in] ByteCount Number of bytes in Status data portion o= f the SPI cycle, the data size is 1 typically + @param[in] StatusValue The Pointer to caller-allocated buffer c= ontaining the value of Status register writing + + @retval EFI_SUCCESS Command succeed. + @retval EFI_INVALID_PARAMETER The parameters specified are not valid. + @retval EFI_DEVICE_ERROR Device error, command aborts abnormally. +**/ +EFI_STATUS +EFIAPI +SpiFlashWriteStatus ( + IN UINT32 ByteCount, + IN UINT8 *StatusValue + ); + +/** + Read status register in the flash part. + + @param[in] ByteCount Number of bytes in Status data portion o= f the SPI cycle, the data size is 1 typically + @param[out] StatusValue The Pointer to caller-allocated buffer c= ontaining the value of Status register received. + + @retval EFI_SUCCESS Command succeed. + @retval EFI_INVALID_PARAMETER The parameters specified are not valid. + @retval EFI_DEVICE_ERROR Device error, command aborts abnormally. +**/ +EFI_STATUS +EFIAPI +SpiFlashReadStatus ( + IN UINT32 ByteCount, + OUT UINT8 *StatusValue + ); + +/** + Read SC Soft Strap Values + + @param[in] SoftStrapAddr SC Soft Strap address offset from FPSBA. + @param[in] ByteCount Number of bytes in SoftStrap data portio= n of the SPI cycle + @param[out] SoftStrapValue The Pointer to caller-allocated buffer c= ontaining SC Soft Strap Value. + It is the caller's responsibility to mak= e sure Buffer is large enough for the total number of bytes read. + + @retval EFI_SUCCESS Command succeed. + @retval EFI_INVALID_PARAMETER The parameters specified are not valid. + @retval EFI_DEVICE_ERROR Device error, command aborts abnormally. +**/ +EFI_STATUS +EFIAPI +SpiReadPchSoftStrap ( + IN UINT32 SoftStrapAddr, + IN UINT32 ByteCount, + OUT UINT8 *SoftStrapValue + ); + + +/** + Read data from the flash part. + + @param[in] FlashRegionType The Flash Region type for flash cycle wh= ich is listed in the Descriptor. + @param[in] Address The Flash Linear Address must fall withi= n a region for which BIOS has access permissions. + @param[in] ByteCount Number of bytes in the data portion of t= he SPI cycle. + @param[out] Buffer The Pointer to caller-allocated buffer c= ontaining the dada received. + It is the caller's responsibility to mak= e sure Buffer is large enough for the total number of bytes read. + + @retval EFI_SUCCESS Command succeed. + @retval EFI_INVALID_PARAMETER The parameters specified are not valid. + @retval EFI_DEVICE_ERROR Device error, command aborts abnormally. +**/ +EFI_STATUS +EFIAPI +SpiFlashRead ( + IN FLASH_REGION_TYPE FlashRegionType, + IN UINT32 Address, + IN UINT32 ByteCount, + OUT UINT8 *Buffer + ); + +/** + Erase some area on the flash part. + + @param[in] FlashRegionType The Flash Region type for flash cycle wh= ich is listed in the Descriptor. + @param[in] Address The Flash Linear Address must fall withi= n a region for which BIOS has access permissions. + @param[in] ByteCount Number of bytes in the data portion of t= he SPI cycle. + + @retval EFI_SUCCESS Command succeed. + @retval EFI_INVALID_PARAMETER The parameters specified are not valid. + @retval EFI_DEVICE_ERROR Device error, command aborts abnormally. +**/ +EFI_STATUS +EFIAPI +SpiFlashErase ( + IN FLASH_REGION_TYPE FlashRegionType, + IN UINT32 Address, + IN UINT32 ByteCount + ); + +/** + Write data to the flash part. + + @param[in] FlashRegionType The Flash Region type for flash cycle wh= ich is listed in the Descriptor. + @param[in] Address The Flash Linear Address must fall withi= n a region for which BIOS has access permissions. + @param[in] ByteCount Number of bytes in the data portion of t= he SPI cycle. + @param[in] Buffer Pointer to caller-allocated buffer conta= ining the data sent during the SPI cycle. + + @retval EFI_SUCCESS Command succeed. + @retval EFI_INVALID_PARAMETER The parameters specified are not valid. + @retval EFI_DEVICE_ERROR Device error, command aborts abnormally. +**/ +EFI_STATUS +EFIAPI +SpiFlashWrite ( + IN FLASH_REGION_TYPE FlashRegionType, + IN UINT32 Address, + IN UINT32 ByteCount, + IN UINT8 *Buffer + ); + +/** + Initialize an SPI library. + + @retval EFI_SUCCESS The protocol instance was properly initi= alized + @retval EFI_NOT_FOUND The expected SPI info could not be found +**/ +EFI_STATUS +EFIAPI +SpiConstructor ( + VOID + ); + +/** + Get the SPI region base and size, based on the enum type + + @param[in] FlashRegionType The Flash Region type for for the base a= ddress which is listed in the Descriptor. + @param[out] BaseAddress The Flash Linear Address for the Region = 'n' Base + @param[out] RegionSize The size for the Region 'n' + + @retval EFI_SUCCESS Read success + @retval EFI_INVALID_PARAMETER Invalid region type given + @retval EFI_DEVICE_ERROR The region is not used +**/ +EFI_STATUS +EFIAPI +SpiGetRegionAddress ( + IN FLASH_REGION_TYPE FlashRegionType, + OUT UINT32 *BaseAddress, OPTIONAL + OUT UINT32 *RegionSize OPTIONAL + ); + +#endif + diff --git a/UefiPayloadPkg/Library/SpiFlashLib/PchSpi.c b/UefiPayloadPkg/L= ibrary/SpiFlashLib/PchSpi.c new file mode 100644 index 0000000000..1dafce19cb --- /dev/null +++ b/UefiPayloadPkg/Library/SpiFlashLib/PchSpi.c @@ -0,0 +1,173 @@ +/** @file + + Copyright (c) 2017-2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "SpiCommon.h" + +/** + Acquire SPI MMIO BAR. + + @param[in] PchSpiBase PCH SPI PCI Base Address + + @retval Return SPI BAR Address + +**/ +UINT32 +AcquireSpiBar0 ( + IN UINTN PchSpiBase + ) +{ + return MmioRead32 (PchSpiBase + R_SPI_BASE) & ~(B_SPI_BAR0_MASK); +} + +/** + Release SPI MMIO BAR. Do nothing. + + @param[in] PchSpiBase PCH SPI PCI Base Address + +**/ +VOID +ReleaseSpiBar0 ( + IN UINTN PchSpiBase + ) +{ +} + + + +/** + This function is to enable/disable BIOS Write Protect in SMM phase. + + @param[in] EnableSmmSts Flag to Enable/disable Bios write protect + +**/ +VOID +CpuSmmDisableBiosWriteProtect ( + IN BOOLEAN EnableSmmSts + ) +{ + UINT32 Data32; + + if(EnableSmmSts){ + // + // Disable BIOS Write Protect in SMM phase. + // + Data32 =3D MmioRead32 ((UINTN) (0xFED30880)) | (UINT32) (BIT0); + AsmWriteMsr32 (0x000001FE, Data32); + } else { + // + // Enable BIOS Write Protect in SMM phase + // + Data32 =3D MmioRead32 ((UINTN) (0xFED30880)) & (UINT32) (~BIT0); + AsmWriteMsr32 (0x000001FE, Data32); + } + + // + // Read FED30880h back to ensure the setting went through. + // + Data32 =3D MmioRead32 (0xFED30880); +} + + +/** + This function is a hook for Spi to disable BIOS Write Protect. + + @param[in] PchSpiBase PCH SPI PCI Base Address + @param[in] CpuSmmBwp Need to disable CPU SMM Bios write prote= ction or not + + @retval EFI_SUCCESS The protocol instance was properly initi= alized + @retval EFI_ACCESS_DENIED The BIOS Region can only be updated in S= MM phase + +**/ +EFI_STATUS +EFIAPI +DisableBiosWriteProtect ( + IN UINTN PchSpiBase, + IN UINT8 CpuSmmBwp + ) +{ + + // + // Write clear BC_SYNC_SS prior to change WPD from 0 to 1. + // + MmioOr8 (PchSpiBase + R_SPI_BCR + 1, (B_SPI_BCR_SYNC_SS >> 8)); + + // + // Enable the access to the BIOS space for both read and write cycles + // + MmioOr8 (PchSpiBase + R_SPI_BCR, B_SPI_BCR_BIOSWE); + + if (CpuSmmBwp !=3D 0) { + CpuSmmDisableBiosWriteProtect (TRUE); + } + + return EFI_SUCCESS; +} + +/** + This function is a hook for Spi to enable BIOS Write Protect. + + @param[in] PchSpiBase PCH SPI PCI Base Address + @param[in] CpuSmmBwp Need to disable CPU SMM Bios write prote= ction or not + +**/ +VOID +EFIAPI +EnableBiosWriteProtect ( + IN UINTN PchSpiBase, + IN UINT8 CpuSmmBwp + ) +{ + + // + // Disable the access to the BIOS space for write cycles + // + MmioAnd8 (PchSpiBase + R_SPI_BCR, (UINT8) (~B_SPI_BCR_BIOSWE)); + + if (CpuSmmBwp !=3D 0) { + CpuSmmDisableBiosWriteProtect (FALSE); + } +} + +/** + This function disables SPI Prefetching and caching, + and returns previous BIOS Control Register value before disabling. + + @param[in] PchSpiBase PCH SPI PCI Base Address + + @retval Previous BIOS Control Register value + +**/ +UINT8 +SaveAndDisableSpiPrefetchCache ( + IN UINTN PchSpiBase + ) +{ + UINT8 BiosCtlSave; + + BiosCtlSave =3D MmioRead8 (PchSpiBase + R_SPI_BCR) & B_SPI_BCR_SRC; + + MmioAndThenOr32 (PchSpiBase + R_SPI_BCR, \ + (UINT32) (~B_SPI_BCR_SRC), \ + (UINT32) (V_SPI_BCR_SRC_PREF_DIS_CACHE_DIS << B_SPI_BCR_SRC)); + + return BiosCtlSave; +} + +/** + This function updates BIOS Control Register with the given value. + + @param[in] PchSpiBase PCH SPI PCI Base Address + @param[in] BiosCtlValue BIOS Control Register Value to be updated + +**/ +VOID +SetSpiBiosControlRegister ( + IN UINTN PchSpiBase, + IN UINT8 BiosCtlValue + ) +{ + MmioAndThenOr8 (PchSpiBase + R_SPI_BCR, (UINT8) ~B_SPI_BCR_SRC, BiosCtlV= alue); +} diff --git a/UefiPayloadPkg/Library/SpiFlashLib/RegsSpi.h b/UefiPayloadPkg/= Library/SpiFlashLib/RegsSpi.h new file mode 100644 index 0000000000..5f22623675 --- /dev/null +++ b/UefiPayloadPkg/Library/SpiFlashLib/RegsSpi.h @@ -0,0 +1,129 @@ +/** @file + Register names for SPI device. + + Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef REGS_SPI_H_ +#define REGS_SPI_H_ + +#define R_SPI_BASE 0x10 ///< 32-bit Memory = Base Address Register +#define B_SPI_BAR0_MASK 0x0FFF +#define R_SPI_BCR 0xDC ///< BIOS Control = Register +#define B_SPI_BCR_SRC (BIT3 | BIT2) ///< SPI Read Confi= guration (SRC) +#define V_SPI_BCR_SRC_PREF_DIS_CACHE_DIS 0x04 ///< Prefetch Disab= le, Cache Disable +#define B_SPI_BCR_SYNC_SS BIT8 +#define B_SPI_BCR_BIOSWE BIT0 ///< Write Protect = Disable (WPD) + +/// +/// SPI Host Interface Registers +#define R_SPI_HSFS 0x04 ///< Hardware Seque= ncing Flash Status and Control Register(32bits) +#define B_SPI_HSFS_FDBC_MASK 0x3F000000 ///< Flash Data Byt= e Count ( <=3D 64), Count =3D (Value in this field) + 1. +#define N_SPI_HSFS_FDBC 24 +#define B_SPI_HSFS_CYCLE_MASK 0x001E0000 ///< Flash Cycle. +#define N_SPI_HSFS_CYCLE 17 +#define V_SPI_HSFS_CYCLE_READ 0 ///< Flash Cycle Re= ad +#define V_SPI_HSFS_CYCLE_WRITE 2 ///< Flash Cycle Wr= ite +#define V_SPI_HSFS_CYCLE_4K_ERASE 3 ///< Flash Cycle 4K= Block Erase +#define V_SPI_HSFS_CYCLE_64K_ERASE 4 ///< Flash Cycle 64= K Sector Erase +#define V_SPI_HSFS_CYCLE_READ_SFDP 5 ///< Flash Cycle Re= ad SFDP +#define V_SPI_HSFS_CYCLE_READ_JEDEC_ID 6 ///< Flash Cycle Re= ad JEDEC ID +#define V_SPI_HSFS_CYCLE_WRITE_STATUS 7 ///< Flash Cycle Wr= ite Status +#define V_SPI_HSFS_CYCLE_READ_STATUS 8 ///< Flash Cycle Re= ad Status +#define B_SPI_HSFS_CYCLE_FGO BIT16 ///< Flash Cycle Go. +#define B_SPI_HSFS_FDV BIT14 ///< Flash Descript= or Valid +#define B_SPI_HSFS_SCIP BIT5 ///< SPI Cycle in P= rogress +#define B_SPI_HSFS_FCERR BIT1 ///< Flash Cycle Er= ror +#define B_SPI_HSFS_FDONE BIT0 ///< Flash Cycle Do= ne + + +#define R_SPI_FADDR 0x08 ///< SPI Flash Address +#define B_SPI_FADDR_MASK 0x07FFFFFF ///< SPI Flash Address= Mask (0~26bit) + + +#define R_SPI_FDATA00 0x10 ///< SPI Data 00 (32 bits) + +#define R_SPI_FRAP 0x50 ///< SPI Flash Regions Acce= ss Permissions Register +#define B_SPI_FRAP_BRWA_PLATFORM BIT12 //< Region write access for= Region4 PlatformData +#define B_SPI_FRAP_BRWA_GBE BIT11 //< Region write access for= Region3 GbE +#define B_SPI_FRAP_BRWA_SEC BIT10 ///< Region Write Access fo= r Region2 SEC +#define B_SPI_FRAP_BRWA_BIOS BIT9 ///< Region Write Access fo= r Region1 BIOS +#define B_SPI_FRAP_BRWA_FLASHD BIT8 ///< Region Write Access fo= r Region0 Flash Descriptor +#define B_SPI_FRAP_BRRA_PLATFORM BIT4 ///< Region read acces= s for Region4 PlatformData +#define B_SPI_FRAP_BRRA_GBE BIT3 ///< Region read acces= s for Region3 GbE +#define B_SPI_FRAP_BRRA_SEC BIT2 ///< Region Read Acces= s for Region2 SEC +#define B_SPI_FRAP_BRRA_BIOS BIT1 ///< Region Read Acces= s for Region1 BIOS +#define B_SPI_FRAP_BRRA_FLASHD BIT0 ///< Region Read Acces= s for Region0 Flash Descriptor + + +#define R_SPI_FREG0_FLASHD 0x54 ///< Flash Region 0 (F= lash Descriptor) (32bits) +#define B_SPI_FREG0_LIMIT_MASK 0x7FFF0000 ///< Size, [30:16] her= e represents limit[26:12] +#define N_SPI_FREG0_LIMIT 4 ///< Bit 30:16 identif= ies address bits [26:12] +#define B_SPI_FREG0_BASE_MASK 0x00007FFF ///< Base, [14:0] her= e represents base [26:12] +#define N_SPI_FREG0_BASE 12 ///< Bit 14:0 identifi= es address bits [26:2] + +#define R_SPI_FREG1_BIOS 0x58 ///< Flash Region 1 (B= IOS) (32bits) +#define B_SPI_FREG1_LIMIT_MASK 0x7FFF0000 ///< Size, [30:16] her= e represents limit[26:12] +#define N_SPI_FREG1_LIMIT 4 ///< Bit 30:16 identif= ies address bits [26:12] +#define B_SPI_FREG1_BASE_MASK 0x00007FFF ///< Base, [14:0] her= e represents base [26:12] +#define N_SPI_FREG1_BASE 12 ///< Bit 14:0 identifi= es address bits [26:2] + +#define R_SPI_FREG2_SEC 0x5C ///< Flash Region 2 (S= EC) (32bits) +#define B_SPI_FREG2_LIMIT_MASK 0x7FFF0000 ///< Size, [30:16] her= e represents limit[26:12] +#define N_SPI_FREG2_LIMIT 4 //< Bit 30:16 identifi= es address bits [26:12] +#define B_SPI_FREG2_BASE_MASK 0x00007FFF ///< Base, [14:0] her= e represents base [26:12] +#define N_SPI_FREG2_BASE 12 //< Bit 14:0 identifie= s address bits [26:2] + +#define R_SPI_FREG3_GBE 0x60 //< Flash Region 3(GbE= )(32bits) +#define B_SPI_FREG3_LIMIT_MASK 0x7FFF0000 ///< Size, [30:16] her= e represents limit[26:12] +#define N_SPI_FREG3_LIMIT 4 //< Bit 30:16 identifi= es address bits [26:12] +#define B_SPI_FREG3_BASE_MASK 0x00007FFF ///< Base, [14:0] her= e represents base [26:12] +#define N_SPI_FREG3_BASE 12 //< Bit 14:0 identifie= s address bits [26:2] + +#define R_SPI_FREG4_PLATFORM_DATA 0x64 ///< Flash Region 4 (P= latform Data) (32bits) +#define B_SPI_FREG4_LIMIT_MASK 0x7FFF0000 ///< Size, [30:16] her= e represents limit[26:12] +#define N_SPI_FREG4_LIMIT 4 ///< Bit 30:16 identif= ies address bits [26:12] +#define B_SPI_FREG4_BASE_MASK 0x00007FFF ///< Base, [14:0] her= e represents base [26:12] +#define N_SPI_FREG4_BASE 12 ///< Bit 14:0 identifi= es address bits [26:2] + + +#define S_SPI_FREGX 4 ///< Size of Flash Reg= ion register +#define B_SPI_FREGX_LIMIT_MASK 0x7FFF0000 ///< Flash Region Limi= t [30:16] represents [26:12], [11:0] are assumed to be FFFh +#define N_SPI_FREGX_LIMIT 16 ///< Region limit bit = position +#define N_SPI_FREGX_LIMIT_REPR 12 ///< Region limit bit = represents position +#define B_SPI_FREGX_BASE_MASK 0x00007FFF ///< Flash Region Base= , [14:0] represents [26:12] + + +#define R_SPI_FDOC 0xB4 ///< Flash Descriptor Obser= vability Control Register (32 bits) +#define B_SPI_FDOC_FDSS_MASK (BIT14 | BIT13 | BIT12) ///< Flas= h Descriptor Section Select +#define V_SPI_FDOC_FDSS_FSDM 0x0000 ///< Flash Signature and D= escriptor Map +#define V_SPI_FDOC_FDSS_COMP 0x1000 ///< Component +#define B_SPI_FDOC_FDSI_MASK 0x0FFC ///< Flash Descriptor Sect= ion Index + +#define R_SPI_FDOD 0xB8 ///< Flash Descriptor Obser= vability Data Register (32 bits) + + +#define R_SPI_LVSCC 0xC4 /// + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef SPI_COMMON_LIB_H_ +#define SPI_COMMON_LIB_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "RegsSpi.h" + +/// +/// Maximum time allowed while waiting the SPI cycle to complete +/// Wait Time =3D 6 seconds =3D 6000000 microseconds +/// Wait Period =3D 10 microseconds +/// +#define WAIT_TIME 6000000 ///< Wait Time =3D 6 seconds =3D 6000000 m= icroseconds +#define WAIT_PERIOD 10 ///< Wait Period =3D 10 microseconds + +/// +/// Flash cycle Type +/// +typedef enum { + FlashCycleRead, + FlashCycleWrite, + FlashCycleErase, + FlashCycleReadSfdp, + FlashCycleReadJedecId, + FlashCycleWriteStatus, + FlashCycleReadStatus, + FlashCycleMax +} FLASH_CYCLE_TYPE; + +/// +/// Flash Component Number +/// +typedef enum { + FlashComponent0, + FlashComponent1, + FlashComponentMax +} FLASH_COMPONENT_NUM; + +/// +/// Private data structure definitions for the driver +/// +#define SC_SPI_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('P', 'S', 'P', 'I') + +typedef struct { + UINTN Signature; + EFI_HANDLE Handle; + UINT32 AcpiTmrReg; + UINTN PchSpiBase; + UINT16 RegionPermission; + UINT32 SfdpVscc0Value; + UINT32 SfdpVscc1Value; + UINT32 StrapBaseAddress; + UINT8 NumberOfComponents; + UINT16 Flags; + UINT32 Component1StartAddr; +} SPI_INSTANCE; + + +/** + Acquire SPI MMIO BAR + + @param[in] PchSpiBase PCH SPI PCI Base Address + + @retval Return SPI BAR Address + +**/ +UINT32 +AcquireSpiBar0 ( + IN UINTN PchSpiBase + ); + + +/** + Release SPI MMIO BAR. Do nothing. + + @param[in] PchSpiBase PCH SPI PCI Base Address + + @retval None + +**/ +VOID +ReleaseSpiBar0 ( + IN UINTN PchSpiBase + ); + + +/** + This function is a hook for Spi to disable BIOS Write Protect + + @param[in] PchSpiBase PCH SPI PCI Base Address + @param[in] CpuSmmBwp Need to disable CPU SMM Bios write prote= ction or not + + @retval EFI_SUCCESS The protocol instance was properly initi= alized + @retval EFI_ACCESS_DENIED The BIOS Region can only be updated in S= MM phase + +**/ +EFI_STATUS +EFIAPI +DisableBiosWriteProtect ( + IN UINTN PchSpiBase, + IN UINT8 CpuSmmBwp + ); + +/** + This function is a hook for Spi to enable BIOS Write Protect + + @param[in] PchSpiBase PCH SPI PCI Base Address + @param[in] CpuSmmBwp Need to disable CPU SMM Bios write prote= ction or not + + @retval None + +**/ +VOID +EFIAPI +EnableBiosWriteProtect ( + IN UINTN PchSpiBase, + IN UINT8 CpuSmmBwp + ); + + +/** + This function disables SPI Prefetching and caching, + and returns previous BIOS Control Register value before disabling. + + @param[in] PchSpiBase PCH SPI PCI Base Address + + @retval Previous BIOS Control Register value + +**/ +UINT8 +SaveAndDisableSpiPrefetchCache ( + IN UINTN PchSpiBase + ); + +/** + This function updates BIOS Control Register with the given value. + + @param[in] PchSpiBase PCH SPI PCI Base Address + @param[in] BiosCtlValue BIOS Control Register Value to be updated + + @retval None + +**/ +VOID +SetSpiBiosControlRegister ( + IN UINTN PchSpiBase, + IN UINT8 BiosCtlValue + ); + + +/** + This function sends the programmed SPI command to the slave device. + + @param[in] SpiRegionType The SPI Region type for flash cycle whic= h is listed in the Descriptor + @param[in] FlashCycleType The Flash SPI cycle type list in HSFC (H= ardware Sequencing Flash Control Register) register + @param[in] Address The Flash Linear Address must fall withi= n a region for which BIOS has access permissions. + @param[in] ByteCount Number of bytes in the data portion of t= he SPI cycle. + @param[in,out] Buffer Pointer to caller-allocated buffer conta= ining the data received or sent during the SPI cycle. + + @retval EFI_SUCCESS SPI command completes successfully. + @retval EFI_DEVICE_ERROR Device error, the command aborts abnorma= lly. + @retval EFI_ACCESS_DENIED Some unrecognized command encountered in= hardware sequencing mode + @retval EFI_INVALID_PARAMETER The parameters specified are not valid. +**/ +EFI_STATUS +SendSpiCmd ( + IN FLASH_REGION_TYPE FlashRegionType, + IN FLASH_CYCLE_TYPE FlashCycleType, + IN UINT32 Address, + IN UINT32 ByteCount, + IN OUT UINT8 *Buffer + ); + +/** + Wait execution cycle to complete on the SPI interface. + + @param[in] PchSpiBar0 Spi MMIO base address + @param[in] ErrorCheck TRUE if the SpiCycle needs to do the err= or check + + @retval TRUE SPI cycle completed on the interface. + @retval FALSE Time out while waiting the SPI cycle to = complete. + It's not safe to program the next comman= d on the SPI interface. +**/ +BOOLEAN +WaitForSpiCycleComplete ( + IN UINT32 PchSpiBar0, + IN BOOLEAN ErrorCheck + ); + +#endif diff --git a/UefiPayloadPkg/Library/SpiFlashLib/SpiFlashLib.c b/UefiPayload= Pkg/Library/SpiFlashLib/SpiFlashLib.c new file mode 100644 index 0000000000..71dfcef740 --- /dev/null +++ b/UefiPayloadPkg/Library/SpiFlashLib/SpiFlashLib.c @@ -0,0 +1,857 @@ +/** @file + Generic driver using Hardware Sequencing registers. + + Copyright (c) 2017-2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "SpiCommon.h" + +SPI_INSTANCE *mSpiInstance =3D NULL; + +/** + Get SPI Instance from library global data.. + + @retval SpiInstance Return SPI instance +**/ +SPI_INSTANCE * +GetSpiInstance ( + VOID +) +{ + if (mSpiInstance =3D=3D NULL) { + mSpiInstance =3D AllocatePool (sizeof(SPI_INSTANCE)); + if (mSpiInstance =3D=3D NULL) { + return NULL; + } + ZeroMem (mSpiInstance, sizeof(SPI_INSTANCE)); + } + + return mSpiInstance; +} + + +/** + Initialize an SPI library. + + @retval EFI_SUCCESS The protocol instance was properly initi= alized + @retval EFI_NOT_FOUND The expected SPI info could not be found +**/ +EFI_STATUS +EFIAPI +SpiConstructor ( + VOID + ) +{ + UINT32 ScSpiBar0; + UINT8 Comp0Density; + SPI_INSTANCE *SpiInstance; + EFI_HOB_GUID_TYPE *GuidHob; + SPI_FLASH_INFO *SpiFlashInfo; + + // + // Find SPI flash hob + // + GuidHob =3D GetFirstGuidHob (&gSpiFlashInfoGuid); + if (GuidHob =3D=3D NULL) { + ASSERT (FALSE); + return EFI_NOT_FOUND; + } + SpiFlashInfo =3D (SPI_FLASH_INFO *) GET_GUID_HOB_DATA (GuidHob); + + // + // Initialize the SPI instance + // + SpiInstance =3D GetSpiInstance (); + if (SpiInstance =3D=3D NULL) { + return EFI_NOT_FOUND; + } + DEBUG ((DEBUG_INFO, "SpiInstance =3D %08X\n", SpiInstance)); + + SpiInstance->Signature =3D SC_SPI_PRIVATE_DATA_SIGNATURE; + SpiInstance->Handle =3D NULL; + + // + // Check the SPI address + // + if ((SpiFlashInfo->SpiAddress.AddressSpaceId !=3D EFI_ACPI_3_0_PCI_CONF= IGURATION_SPACE) || + (SpiFlashInfo->SpiAddress.RegisterBitWidth !=3D 32) || + (SpiFlashInfo->SpiAddress.RegisterBitOffset !=3D 0) || + (SpiFlashInfo->SpiAddress.AccessSize !=3D EFI_ACPI_3_0_DWORD)){ + DEBUG ((DEBUG_ERROR, "SPI FLASH HOB is not expected. need check the ho= b or enhance SPI flash driver.\n")); + } + SpiInstance->PchSpiBase =3D (UINT32)(UINTN)SpiFlashInfo->SpiAddress.Addr= ess; + SpiInstance->Flags =3D SpiFlashInfo->Flags; + DEBUG ((DEBUG_INFO, "PchSpiBase at 0x%x\n", SpiInstance->PchSpiBase)); + + ScSpiBar0 =3D AcquireSpiBar0 (SpiInstance->PchSpiBase); + DEBUG ((DEBUG_INFO, "ScSpiBar0 at 0x%08X\n", ScSpiBar0)); + + if (ScSpiBar0 =3D=3D 0) { + ASSERT (FALSE); + } + + if ((MmioRead32 (ScSpiBar0 + R_SPI_HSFS) & B_SPI_HSFS_FDV) =3D=3D 0) { + DEBUG ((DEBUG_ERROR, "SPI Flash descriptor invalid, cannot use Hardwar= e Sequencing registers!\n")); + ASSERT (FALSE); + } + + MmioOr32 (SpiInstance->PchSpiBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_= MEMORY_SPACE); + SpiInstance->RegionPermission =3D MmioRead16 (ScSpiBar0 + R_SPI_FRAP); + SpiInstance->SfdpVscc0Value =3D MmioRead32 (ScSpiBar0 + R_SPI_LVSCC); + SpiInstance->SfdpVscc1Value =3D MmioRead32 (ScSpiBar0 + R_SPI_UVSCC); + + // + // Select to Flash Map 0 Register to get the number of flash Component + // + MmioAndThenOr32 ( + ScSpiBar0 + R_SPI_FDOC, + (UINT32) (~(B_SPI_FDOC_FDSS_MASK | B_SPI_FDOC_FDSI_MASK)), + (UINT32) (V_SPI_FDOC_FDSS_FSDM | R_SPI_FDBAR_FLASH_MAP0) + ); + + // + // Copy Zero based Number Of Components + // + SpiInstance->NumberOfComponents =3D (UINT8) ((MmioRead16 (ScSpiBar0 + R_= SPI_FDOD) & B_SPI_FDBAR_NC) >> N_SPI_FDBAR_NC); + + MmioAndThenOr32 ( + ScSpiBar0 + R_SPI_FDOC, + (UINT32) (~(B_SPI_FDOC_FDSS_MASK | B_SPI_FDOC_FDSI_MASK)), + (UINT32) (V_SPI_FDOC_FDSS_COMP | R_SPI_FCBA_FLCOMP) + ); + + // + // Copy Component 0 Density + // + Comp0Density =3D (UINT8) MmioRead32 (ScSpiBar0 + R_SPI_FDOD) & B_SPI_FLC= OMP_COMP1_MASK; + SpiInstance->Component1StartAddr =3D (UINT32) (SIZE_512KB << Comp0Densit= y); + + // + // Select FLASH_MAP1 to get Flash SC Strap Base Address + // + MmioAndThenOr32 ( + (ScSpiBar0 + R_SPI_FDOC), + (UINT32) (~(B_SPI_FDOC_FDSS_MASK | B_SPI_FDOC_FDSI_MASK)), + (UINT32) (V_SPI_FDOC_FDSS_FSDM | R_SPI_FDBAR_FLASH_MAP1) + ); + + SpiInstance->StrapBaseAddress =3D MmioRead32 (ScSpiBar0 + R_SPI_FDOD) & = B_SPI_FDBAR_FPSBA; + + // + // Align FPSBA with address bits for the SC Strap portion of flash descr= iptor + // + SpiInstance->StrapBaseAddress &=3D B_SPI_FDBAR_FPSBA; + + return EFI_SUCCESS; +} + + +/** + Read data from the flash part. + + @param[in] FlashRegionType The Flash Region type for flash cycle wh= ich is listed in the Descriptor. + @param[in] Address The Flash Linear Address must fall withi= n a region for which BIOS has access permissions. + @param[in] ByteCount Number of bytes in the data portion of t= he SPI cycle. + @param[out] Buffer The Pointer to caller-allocated buffer c= ontaining the data received. + It is the caller's responsibility to mak= e sure Buffer is large enough for the total number of bytes read. + + @retval EFI_SUCCESS Command succeed. + @retval EFI_INVALID_PARAMETER The parameters specified are not valid. + @retval EFI_DEVICE_ERROR Device error, command aborts abnormally. +**/ +EFI_STATUS +EFIAPI +SpiFlashRead ( + IN FLASH_REGION_TYPE FlashRegionType, + IN UINT32 Address, + IN UINT32 ByteCount, + OUT UINT8 *Buffer + ) +{ + EFI_STATUS Status; + + Status =3D SendSpiCmd (FlashRegionType, FlashCycleRead, Address, ByteCou= nt, Buffer); + return Status; +} + +/** + Write data to the flash part. + + @param[in] FlashRegionType The Flash Region type for flash cycle wh= ich is listed in the Descriptor. + @param[in] Address The Flash Linear Address must fall withi= n a region for which BIOS has access permissions. + @param[in] ByteCount Number of bytes in the data portion of t= he SPI cycle. + @param[in] Buffer Pointer to caller-allocated buffer conta= ining the data sent during the SPI cycle. + + @retval EFI_SUCCESS Command succeed. + @retval EFI_INVALID_PARAMETER The parameters specified are not valid. + @retval EFI_DEVICE_ERROR Device error, command aborts abnormally. +**/ +EFI_STATUS +EFIAPI +SpiFlashWrite ( + IN FLASH_REGION_TYPE FlashRegionType, + IN UINT32 Address, + IN UINT32 ByteCount, + IN UINT8 *Buffer + ) +{ + EFI_STATUS Status; + + Status =3D SendSpiCmd (FlashRegionType, FlashCycleWrite, Address, ByteCo= unt, Buffer); + return Status; +} + +/** + Erase some area on the flash part. + + @param[in] FlashRegionType The Flash Region type for flash cycle wh= ich is listed in the Descriptor. + @param[in] Address The Flash Linear Address must fall withi= n a region for which BIOS has access permissions. + @param[in] ByteCount Number of bytes in the data portion of t= he SPI cycle. + + @retval EFI_SUCCESS Command succeed. + @retval EFI_INVALID_PARAMETER The parameters specified are not valid. + @retval EFI_DEVICE_ERROR Device error, command aborts abnormally. +**/ +EFI_STATUS +EFIAPI +SpiFlashErase ( + IN FLASH_REGION_TYPE FlashRegionType, + IN UINT32 Address, + IN UINT32 ByteCount + ) +{ + EFI_STATUS Status; + + Status =3D SendSpiCmd (FlashRegionType, FlashCycleErase, Address, ByteCo= unt, NULL); + return Status; +} + +/** + Read SFDP data from the flash part. + + @param[in] ComponentNumber The Component Number for chip select + @param[in] ByteCount Number of bytes in SFDP data portion of = the SPI cycle, the max number is 64 + @param[out] SfdpData The Pointer to caller-allocated buffer c= ontaining the SFDP data received + It is the caller's responsibility to mak= e sure Buffer is large enough for the total number of bytes read. + + @retval EFI_SUCCESS Command succeed. + @retval EFI_INVALID_PARAMETER The parameters specified are not valid. + @retval EFI_DEVICE_ERROR Device error, command aborts abnormally. +**/ +EFI_STATUS +EFIAPI +SpiFlashReadSfdp ( + IN UINT8 ComponentNumber, + IN UINT32 ByteCount, + OUT UINT8 *SfdpData + ) +{ + EFI_STATUS Status; + UINT32 Address; + SPI_INSTANCE *SpiInstance; + + SpiInstance =3D GetSpiInstance (); + if (SpiInstance =3D=3D NULL) { + return EFI_DEVICE_ERROR; + } + + if ((ByteCount > 64) || (ComponentNumber > SpiInstance->NumberOfComponen= ts)) { + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + Address =3D 0; + if (ComponentNumber =3D=3D FlashComponent1) { + Address =3D SpiInstance->Component1StartAddr; + } + + Status =3D SendSpiCmd (0, FlashCycleReadSfdp, Address, ByteCount, SfdpDa= ta); + return Status; +} + +/** + Read Jedec Id from the flash part. + + @param[in] ComponentNumber The Component Number for chip select + @param[in] ByteCount Number of bytes in JedecId data portion = of the SPI cycle, the data size is 3 typically + @param[out] JedecId The Pointer to caller-allocated buffer c= ontaining JEDEC ID received + It is the caller's responsibility to mak= e sure Buffer is large enough for the total number of bytes read. + + @retval EFI_SUCCESS Command succeed. + @retval EFI_INVALID_PARAMETER The parameters specified are not valid. + @retval EFI_DEVICE_ERROR Device error, command aborts abnormally. +**/ +EFI_STATUS +EFIAPI +SpiFlashReadJedecId ( + IN UINT8 ComponentNumber, + IN UINT32 ByteCount, + OUT UINT8 *JedecId + ) +{ + EFI_STATUS Status; + UINT32 Address; + SPI_INSTANCE *SpiInstance; + + SpiInstance =3D GetSpiInstance (); + if (SpiInstance =3D=3D NULL) { + return EFI_DEVICE_ERROR; + } + + if (ComponentNumber > SpiInstance->NumberOfComponents) { + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + Address =3D 0; + if (ComponentNumber =3D=3D FlashComponent1) { + Address =3D SpiInstance->Component1StartAddr; + } + + Status =3D SendSpiCmd (0, FlashCycleReadJedecId, Address, ByteCount, Jed= ecId); + return Status; +} + +/** + Write the status register in the flash part. + + @param[in] ByteCount Number of bytes in Status data portion o= f the SPI cycle, the data size is 1 typically + @param[in] StatusValue The Pointer to caller-allocated buffer c= ontaining the value of Status register writing + + @retval EFI_SUCCESS Command succeed. + @retval EFI_INVALID_PARAMETER The parameters specified are not valid. + @retval EFI_DEVICE_ERROR Device error, command aborts abnormally. +**/ +EFI_STATUS +EFIAPI +SpiFlashWriteStatus ( + IN UINT32 ByteCount, + IN UINT8 *StatusValue + ) +{ + EFI_STATUS Status; + + Status =3D SendSpiCmd (0, FlashCycleWriteStatus, 0, ByteCount, StatusVal= ue); + return Status; +} + +/** + Read status register in the flash part. + + @param[in] ByteCount Number of bytes in Status data portion o= f the SPI cycle, the data size is 1 typically + @param[out] StatusValue The Pointer to caller-allocated buffer c= ontaining the value of Status register received. + + @retval EFI_SUCCESS Command succeed. + @retval EFI_INVALID_PARAMETER The parameters specified are not valid. + @retval EFI_DEVICE_ERROR Device error, command aborts abnormally. +**/ +EFI_STATUS +EFIAPI +SpiFlashReadStatus ( + IN UINT32 ByteCount, + OUT UINT8 *StatusValue + ) +{ + EFI_STATUS Status; + + Status =3D SendSpiCmd (0, FlashCycleReadStatus, 0, ByteCount, StatusValu= e); + return Status; +} + +/** + Read SC Soft Strap Values + + @param[in] SoftStrapAddr SC Soft Strap address offset from FPSBA. + @param[in] ByteCount Number of bytes in SoftStrap data portio= n of the SPI cycle + @param[out] SoftStrapValue The Pointer to caller-allocated buffer c= ontaining SC Soft Strap Value. + It is the caller's responsibility to mak= e sure Buffer is large enough for the total number of bytes read. + + @retval EFI_SUCCESS Command succeed. + @retval EFI_INVALID_PARAMETER The parameters specified are not valid. + @retval EFI_DEVICE_ERROR Device error, command aborts abnormally. +**/ +EFI_STATUS +EFIAPI +SpiReadPchSoftStrap ( + IN UINT32 SoftStrapAddr, + IN UINT32 ByteCount, + OUT UINT8 *SoftStrapValue + ) +{ + UINT32 StrapFlashAddr; + EFI_STATUS Status; + SPI_INSTANCE *SpiInstance; + + SpiInstance =3D GetSpiInstance (); + if (SpiInstance =3D=3D NULL) { + return EFI_DEVICE_ERROR; + } + + ASSERT (SpiInstance->StrapBaseAddress !=3D 0); + // + // SC Strap Flash Address =3D FPSBA + RamAddr + // + StrapFlashAddr =3D SpiInstance->StrapBaseAddress + SoftStrapAddr; + + Status =3D SendSpiCmd (FlashRegionDescriptor, FlashCycleRead, StrapFlash= Addr, ByteCount, SoftStrapValue); + return Status; +} + +/** + This function sends the programmed SPI command to the slave device. + + @param[in] FlashRegionType The SPI Region type for flash cycle whic= h is listed in the Descriptor + @param[in] FlashCycleType The Flash SPI cycle type list in HSFC (H= ardware Sequencing Flash Control Register) register + @param[in] Address The Flash Linear Address must fall withi= n a region for which BIOS has access permissions. + @param[in] ByteCount Number of bytes in the data portion of t= he SPI cycle. + @param[in,out] Buffer Pointer to caller-allocated buffer conta= ining the data received or sent during the SPI cycle. + + @retval EFI_SUCCESS SPI command completes successfully. + @retval EFI_DEVICE_ERROR Device error, the command aborts abnorma= lly. + @retval EFI_ACCESS_DENIED Some unrecognized command encountered in= hardware sequencing mode + @retval EFI_INVALID_PARAMETER The parameters specified are not valid. +**/ +EFI_STATUS +SendSpiCmd ( + IN FLASH_REGION_TYPE FlashRegionType, + IN FLASH_CYCLE_TYPE FlashCycleType, + IN UINT32 Address, + IN UINT32 ByteCount, + IN OUT UINT8 *Buffer + ) +{ + EFI_STATUS Status; + UINT32 Index; + UINTN SpiBaseAddress; + UINT32 ScSpiBar0; + UINT32 LimitAddress; + UINT32 HardwareSpiAddr; + UINT16 PermissionBit; + UINT32 SpiDataCount; + UINT32 FlashCycle; + UINT8 BiosCtlSave; + SPI_INSTANCE *SpiInstance; + UINT32 Data32; + + SpiInstance =3D GetSpiInstance (); + if (SpiInstance =3D=3D NULL) { + return EFI_DEVICE_ERROR; + } + + Status =3D EFI_SUCCESS; + SpiBaseAddress =3D SpiInstance->PchSpiBase; + ScSpiBar0 =3D AcquireSpiBar0 (SpiBaseAddress); + BiosCtlSave =3D 0; + SpiInstance->RegionPermission =3D MmioRead16 (ScSpiBar0 + R_SPI_FRAP); + + // + // If it's write cycle, disable Prefetching, Caching and disable BIOS Wr= ite Protect + // + if ((FlashCycleType =3D=3D FlashCycleWrite) || (FlashCycleType =3D=3D Fl= ashCycleErase)) { + Status =3D DisableBiosWriteProtect (SpiBaseAddress, mSpiInstance->Flag= s & FLAGS_SPI_DISABLE_SMM_WRITE_PROTECT); + if (EFI_ERROR (Status)) { + goto SendSpiCmdEnd; + } + BiosCtlSave =3D SaveAndDisableSpiPrefetchCache (SpiBaseAddress); + } + + // + // Make sure it's safe to program the command. + // + if (!WaitForSpiCycleComplete (ScSpiBar0, FALSE)) { + Status =3D EFI_DEVICE_ERROR; + goto SendSpiCmdEnd; + } + + HardwareSpiAddr =3D Address; + if ((FlashCycleType =3D=3D FlashCycleRead) || + (FlashCycleType =3D=3D FlashCycleWrite) || + (FlashCycleType =3D=3D FlashCycleErase)) { + + switch (FlashRegionType) { + case FlashRegionDescriptor: + if (FlashCycleType =3D=3D FlashCycleRead) { + PermissionBit =3D B_SPI_FRAP_BRRA_FLASHD; + } else { + PermissionBit =3D B_SPI_FRAP_BRWA_FLASHD; + } + Data32 =3D MmioRead32 (ScSpiBar0 + R_SPI_FREG0_FLASHD); + HardwareSpiAddr +=3D (Data32 & B_SPI_FREG0_BASE_MASK) << N_SPI_FREG0= _BASE; + LimitAddress =3D (Data32 & B_SPI_FREG0_LIMIT_MASK) >> N_SPI_FREG= 0_LIMIT; + break; + + case FlashRegionBios: + if (FlashCycleType =3D=3D FlashCycleRead) { + PermissionBit =3D B_SPI_FRAP_BRRA_BIOS; + } else { + PermissionBit =3D B_SPI_FRAP_BRWA_BIOS; + } + Data32 =3D MmioRead32 (ScSpiBar0 + R_SPI_FREG1_BIOS); + HardwareSpiAddr +=3D (Data32 & B_SPI_FREG1_BASE_MASK) << N_SPI_FREG1= _BASE; + LimitAddress =3D (Data32 & B_SPI_FREG1_LIMIT_MASK) >> N_SPI_FREG= 1_LIMIT; + break; + + case FlashRegionMe: + if (FlashCycleType =3D=3D FlashCycleRead) { + PermissionBit =3D B_SPI_FRAP_BRRA_SEC; + } else { + PermissionBit =3D B_SPI_FRAP_BRWA_SEC; + } + Data32 =3D MmioRead32 (ScSpiBar0 + R_SPI_FREG2_SEC); + HardwareSpiAddr +=3D (Data32 & B_SPI_FREG2_BASE_MASK) << N_SPI_FREG2= _BASE; + LimitAddress =3D (Data32 & B_SPI_FREG2_LIMIT_MASK) >> N_SPI_FREG= 2_LIMIT; + break; + + case FlashRegionGbE: + if (FlashCycleType =3D=3D FlashCycleRead) { + PermissionBit =3D B_SPI_FRAP_BRRA_GBE; + } else { + PermissionBit =3D B_SPI_FRAP_BRWA_GBE; + } + Data32 =3D MmioRead32 (ScSpiBar0 + R_SPI_FREG3_GBE); + HardwareSpiAddr +=3D (Data32 & B_SPI_FREG3_BASE_MASK) << N_SPI_FREG3= _BASE; + LimitAddress =3D (Data32 & B_SPI_FREG3_LIMIT_MASK) >> N_SPI_FREG= 3_LIMIT; + break; + + case FlashRegionPlatformData: + if (FlashCycleType =3D=3D FlashCycleRead) { + PermissionBit =3D B_SPI_FRAP_BRRA_PLATFORM; + } else { + PermissionBit =3D B_SPI_FRAP_BRWA_PLATFORM; + } + Data32 =3D MmioRead32 (ScSpiBar0 + R_SPI_FREG4_PLATFORM_DATA); + HardwareSpiAddr +=3D (Data32 & B_SPI_FREG4_BASE_MASK) << N_SPI_FREG4= _BASE; + LimitAddress =3D (Data32 & B_SPI_FREG4_LIMIT_MASK) >> N_SPI_FREG= 4_LIMIT; + break; + + case FlashRegionAll: + // + // FlashRegionAll indicates address is relative to flash device + // No error checking for this case + // + LimitAddress =3D 0; + PermissionBit =3D 0; + break; + + default: + Status =3D EFI_UNSUPPORTED; + goto SendSpiCmdEnd; + } + + if ((LimitAddress !=3D 0) && (Address > LimitAddress)) { + Status =3D EFI_INVALID_PARAMETER; + goto SendSpiCmdEnd; + } + + // + // If the operation is read, but the region attribute is not read allo= wed, return error. + // If the operation is write, but the region attribute is not write al= lowed, return error. + // + if ((PermissionBit !=3D 0) && ((SpiInstance->RegionPermission & Permis= sionBit) =3D=3D 0)) { + Status =3D EFI_ACCESS_DENIED; + goto SendSpiCmdEnd; + } + } + + // + // Check for SC SPI hardware sequencing required commands + // + FlashCycle =3D 0; + switch (FlashCycleType) { + case FlashCycleRead: + FlashCycle =3D (UINT32) (V_SPI_HSFS_CYCLE_READ << N_SPI_HSFS_CYCLE); + break; + + case FlashCycleWrite: + FlashCycle =3D (UINT32) (V_SPI_HSFS_CYCLE_WRITE << N_SPI_HSFS_CYCLE); + break; + + case FlashCycleErase: + if (((ByteCount % SIZE_4KB) !=3D 0) || ((HardwareSpiAddr % SIZE_4KB) != =3D 0)) { + DEBUG ((DEBUG_ERROR, "Erase and erase size must be 4KB aligned. \n")= ); + ASSERT (FALSE); + Status =3D EFI_INVALID_PARAMETER; + goto SendSpiCmdEnd; + } + break; + + case FlashCycleReadSfdp: + FlashCycle =3D (UINT32) (V_SPI_HSFS_CYCLE_READ_SFDP << N_SPI_HSFS_CYCL= E); + break; + + case FlashCycleReadJedecId: + FlashCycle =3D (UINT32) (V_SPI_HSFS_CYCLE_READ_JEDEC_ID << N_SPI_HSFS_= CYCLE); + break; + + case FlashCycleWriteStatus: + FlashCycle =3D (UINT32) (V_SPI_HSFS_CYCLE_WRITE_STATUS << N_SPI_HSFS_C= YCLE); + break; + + case FlashCycleReadStatus: + FlashCycle =3D (UINT32) (V_SPI_HSFS_CYCLE_READ_STATUS << N_SPI_HSFS_CY= CLE); + break; + + default: + // + // Unrecognized Operation + // + ASSERT (FALSE); + Status =3D EFI_INVALID_PARAMETER; + goto SendSpiCmdEnd; + break; + } + + do { + SpiDataCount =3D ByteCount; + if ((FlashCycleType =3D=3D FlashCycleRead) || (FlashCycleType =3D=3D F= lashCycleWrite)) { + // + // Trim at 256 byte boundary per operation, + // - SC SPI controller requires trimming at 4KB boundary + // - Some SPI chips require trimming at 256 byte boundary for write = operation + // - Trimming has limited performance impact as we can read / write = at most 64 byte + // per operation + // + if (HardwareSpiAddr + ByteCount > ((HardwareSpiAddr + BIT8) &~(BIT8 = - 1))) { + SpiDataCount =3D (((UINT32) (HardwareSpiAddr) + BIT8) &~(BIT8 - 1)= ) - (UINT32) (HardwareSpiAddr); + } + // + // Calculate the number of bytes to shift in/out during the SPI data= cycle. + // Valid settings for the number of bytes during each data portion o= f the + // SC SPI cycles are: 0, 1, 2, 3, 4, 5, 6, 7, 8, 16, 24, 32, 40, 48,= 56, 64 + // + if (SpiDataCount >=3D 64) { + SpiDataCount =3D 64; + } else if ((SpiDataCount &~0x07) !=3D 0) { + SpiDataCount =3D SpiDataCount &~0x07; + } + } + + if (FlashCycleType =3D=3D FlashCycleErase) { + if (((ByteCount / SIZE_64KB) !=3D 0) && + ((ByteCount % SIZE_64KB) =3D=3D 0) && + ((HardwareSpiAddr % SIZE_64KB) =3D=3D 0)) { + if (HardwareSpiAddr < SpiInstance->Component1StartAddr) { + // + // Check whether Component0 support 64k Erase + // + if ((SpiInstance->SfdpVscc0Value & B_SPI_LVSCC_EO_64K) !=3D 0) { + SpiDataCount =3D SIZE_64KB; + } else { + SpiDataCount =3D SIZE_4KB; + } + } else { + // + // Check whether Component1 support 64k Erase + // + if ((SpiInstance->SfdpVscc1Value & B_SPI_LVSCC_EO_64K) !=3D 0) { + SpiDataCount =3D SIZE_64KB; + } else { + SpiDataCount =3D SIZE_4KB; + } + } + } else { + SpiDataCount =3D SIZE_4KB; + } + if (SpiDataCount =3D=3D SIZE_4KB) { + FlashCycle =3D (UINT32) (V_SPI_HSFS_CYCLE_4K_ERASE << N_SPI_HSFS_C= YCLE); + } else { + FlashCycle =3D (UINT32) (V_SPI_HSFS_CYCLE_64K_ERASE << N_SPI_HSFS_= CYCLE); + } + } + + // + // If it's write cycle, load data into the SPI data buffer. + // + if ((FlashCycleType =3D=3D FlashCycleWrite) || (FlashCycleType =3D=3D = FlashCycleWriteStatus)) { + if ((SpiDataCount & 0x07) !=3D 0) { + // + // Use Byte write if Data Count is 0, 1, 2, 3, 4, 5, 6, 7 + // + for (Index =3D 0; Index < SpiDataCount; Index++) { + MmioWrite8 (ScSpiBar0 + R_SPI_FDATA00 + Index, Buffer[Index]); + } + } else { + // + // Use Dword write if Data Count is 8, 16, 24, 32, 40, 48, 56, 64 + // + for (Index =3D 0; Index < SpiDataCount; Index +=3D sizeof (UINT32)= ) { + MmioWrite32 (ScSpiBar0 + R_SPI_FDATA00 + Index, *(UINT32 *) (Buf= fer + Index)); + } + } + } + + // + // Set the Flash Address + // + MmioWrite32 (ScSpiBar0 + R_SPI_FADDR, (UINT32) (HardwareSpiAddr & B_SP= I_FADDR_MASK)); + + // + // Set Data count, Flash cycle, and Set Go bit to start a cycle + // + MmioAndThenOr32 ( + ScSpiBar0 + R_SPI_HSFS, + (UINT32) (~(B_SPI_HSFS_FDBC_MASK | B_SPI_HSFS_CYCLE_MASK)), + (UINT32) (((SpiDataCount - 1) << N_SPI_HSFS_FDBC) | FlashCycle | B_S= PI_HSFS_CYCLE_FGO) + ); + + // + // Wait for command execution complete. + // + if (!WaitForSpiCycleComplete (ScSpiBar0, TRUE)) { + Status =3D EFI_DEVICE_ERROR; + goto SendSpiCmdEnd; + } + + // + // If it's read cycle, load data into the caller's buffer. + // + if ((FlashCycleType =3D=3D FlashCycleRead) || + (FlashCycleType =3D=3D FlashCycleReadSfdp) || + (FlashCycleType =3D=3D FlashCycleReadJedecId) || + (FlashCycleType =3D=3D FlashCycleReadStatus)) { + if ((SpiDataCount & 0x07) !=3D 0) { + // + // Use Byte read if Data Count is 0, 1, 2, 3, 4, 5, 6, 7 + // + for (Index =3D 0; Index < SpiDataCount; Index++) { + Buffer[Index] =3D MmioRead8 (ScSpiBar0 + R_SPI_FDATA00 + Index); + } + } else { + // + // Use Dword read if Data Count is 8, 16, 24, 32, 40, 48, 56, 64 + // + for (Index =3D 0; Index < SpiDataCount; Index +=3D sizeof (UINT32)= ) { + *(UINT32 *) (Buffer + Index) =3D MmioRead32 (ScSpiBar0 + R_SPI_F= DATA00 + Index); + } + } + } + + HardwareSpiAddr +=3D SpiDataCount; + Buffer +=3D SpiDataCount; + ByteCount -=3D SpiDataCount; + } while (ByteCount > 0); + +SendSpiCmdEnd: + /// + /// Restore the settings for SPI Prefetching and Caching and enable BIOS= Write Protect + /// + if ((FlashCycleType =3D=3D FlashCycleWrite) || (FlashCycleType =3D=3D Fl= ashCycleErase)) { + EnableBiosWriteProtect (SpiBaseAddress, mSpiInstance->Flags & FLAGS_S= PI_DISABLE_SMM_WRITE_PROTECT); + SetSpiBiosControlRegister (SpiBaseAddress, BiosCtlSave); + } + + ReleaseSpiBar0 (SpiBaseAddress); + + return Status; +} + +/** + Wait execution cycle to complete on the SPI interface. + + @param[in] ScSpiBar0 Spi MMIO base address + @param[in] ErrorCheck TRUE if the SpiCycle needs to do the err= or check + + @retval TRUE SPI cycle completed on the interface. + @retval FALSE Time out while waiting the SPI cycle to = complete. + It's not safe to program the next comman= d on the SPI interface. +**/ +BOOLEAN +WaitForSpiCycleComplete ( + IN UINT32 ScSpiBar0, + IN BOOLEAN ErrorCheck + ) +{ + UINT64 WaitTicks; + UINT64 WaitCount; + UINT32 Data32; + + // + // Convert the wait period allowed into to tick count + // + WaitCount =3D WAIT_TIME / WAIT_PERIOD; + // + // Wait for the SPI cycle to complete. + // + for (WaitTicks =3D 0; WaitTicks < WaitCount; WaitTicks++) { + Data32 =3D MmioRead32 (ScSpiBar0 + R_SPI_HSFS); + if ((Data32 & B_SPI_HSFS_SCIP) =3D=3D 0) { + MmioWrite32 (ScSpiBar0 + R_SPI_HSFS, B_SPI_HSFS_FCERR | B_SPI_HSFS_F= DONE); + if (((Data32 & B_SPI_HSFS_FCERR) !=3D 0) && ErrorCheck) { + return FALSE; + } else { + return TRUE; + } + } + MicroSecondDelay ( WAIT_PERIOD); + } + return FALSE; +} + +/** + Get the SPI region base and size, based on the enum type + + @param[in] FlashRegionType The Flash Region type for for the base a= ddress which is listed in the Descriptor. + @param[out] BaseAddress The Flash Linear Address for the Region = 'n' Base + @param[out] RegionSize The size for the Region 'n' + + @retval EFI_SUCCESS Read success + @retval EFI_INVALID_PARAMETER Invalid region type given + @retval EFI_DEVICE_ERROR The region is not used +**/ +EFI_STATUS +EFIAPI +SpiGetRegionAddress ( + IN FLASH_REGION_TYPE FlashRegionType, + OUT UINT32 *BaseAddress, OPTIONAL + OUT UINT32 *RegionSize OPTIONAL + ) +{ + UINT32 ScSpiBar0; + UINT32 ReadValue; + UINT32 Base; + SPI_INSTANCE *SpiInstance; + + if (FlashRegionType >=3D FlashRegionMax) { + return EFI_INVALID_PARAMETER; + } + + SpiInstance =3D GetSpiInstance(); + if (SpiInstance =3D=3D NULL) { + return EFI_DEVICE_ERROR; + } + + if (FlashRegionType =3D=3D FlashRegionAll) { + if (BaseAddress !=3D NULL) { + *BaseAddress =3D 0; + } + if (RegionSize !=3D NULL) { + *RegionSize =3D SpiInstance->Component1StartAddr; + } + return EFI_SUCCESS; + } + + ScSpiBar0 =3D AcquireSpiBar0 (SpiInstance->PchSpiBase); + ReadValue =3D MmioRead32 (ScSpiBar0 + R_SPI_FREG0_FLASHD + S_SPI_FREGX *= (UINT32) FlashRegionType); + ReleaseSpiBar0 (SpiInstance->PchSpiBase); + + // + // If the region is not used, the Region Base is 7FFFh and Region Limit = is 0000h + // + if (ReadValue =3D=3D B_SPI_FREGX_BASE_MASK) { + return EFI_DEVICE_ERROR; + } + + Base =3D (ReadValue & B_SPI_FREG1_BASE_MASK) << N_SPI_FREG1_BASE; + if (BaseAddress !=3D NULL) { + *BaseAddress =3D Base; + } + + if (RegionSize !=3D NULL) { + *RegionSize =3D ((((ReadValue & B_SPI_FREGX_LIMIT_MASK) >> N_SPI_FREG= X_LIMIT) + 1) << + N_SPI_FREGX_LIMIT_REPR) - Base; + } + + return EFI_SUCCESS; +} + diff --git a/UefiPayloadPkg/Library/SpiFlashLib/SpiFlashLib.inf b/UefiPaylo= adPkg/Library/SpiFlashLib/SpiFlashLib.inf new file mode 100644 index 0000000000..3e023079fc --- /dev/null +++ b/UefiPayloadPkg/Library/SpiFlashLib/SpiFlashLib.inf @@ -0,0 +1,48 @@ +## @file +# Library instance for SPI flash library using SPI hardware sequence +# +# Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D SpiFlashLib + FILE_GUID =3D 6F96AFCB-DE89-4ca1-A63F-8703EE8FDE50 + MODULE_TYPE =3D BASE + VERSION_STRING =3D 1.0 + LIBRARY_CLASS =3D SpiFlashLib + CONSTRUCTOR =3D SpiConstructor + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 +# + +[Sources] + RegsSpi.h + SpiCommon.h + PchSpi.c + SpiFlashLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UefiPayloadPkg/UefiPayloadPkg.dec + +[LibraryClasses] + BaseLib + PcdLib + IoLib + PciLib + HobLib + TimerLib + BaseLib + +[Guids] + gSpiFlashInfoGuid + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress diff --git a/UefiPayloadPkg/UefiPayloadPkg.dec b/UefiPayloadPkg/UefiPayload= Pkg.dec index 4c3bd0c2eb..3ffdce550d 100644 --- a/UefiPayloadPkg/UefiPayloadPkg.dec +++ b/UefiPayloadPkg/UefiPayloadPkg.dec @@ -37,6 +37,7 @@ gUefiSerialPortInfoGuid =3D { 0x6c6872fe, 0x56a9, 0x4403, { 0xbb, 0x98,= 0x95, 0x8d, 0x62, 0xde, 0x87, 0xf1 } } gLoaderMemoryMapInfoGuid =3D { 0xa1ff7424, 0x7a1a, 0x478e, { 0xa9, 0xe4,= 0x92, 0xf3, 0x57, 0xd1, 0x28, 0x32 } } =20 + gSpiFlashInfoGuid =3D { 0x2d4aac1b, 0x91a5, 0x4cd5, { 0x9b, 0x5c,= 0xb4, 0x0f, 0x5d, 0x28, 0x51, 0xa1 } } gSmmRegisterInfoGuid =3D { 0xaa9bd7a7, 0xcafb, 0x4499, { 0xa4, 0xa9,= 0xb, 0x34, 0x6b, 0x40, 0xa6, 0x22 } } gS3CommunicationGuid =3D { 0x88e31ba1, 0x1856, 0x4b8b, { 0xbb, 0xdf,= 0xf8, 0x16, 0xdd, 0x94, 0xa, 0xef } } =20 --=20 2.32.0.windows.2 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#82536): https://edk2.groups.io/g/devel/message/82536 Mute This Topic: https://groups.io/mt/86517144/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- From nobody Sat May 4 03:30:04 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+82535+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+82535+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1634917621; cv=none; d=zohomail.com; s=zohoarc; b=BeO3OVo76LddTCzmhBEQ8SEHRq07nGIterS1eE6ph1lpu0H6Nm8ycUtLYtiG3/oMCHrRL+uwoYQNfMKc/Q124yf3kzPhKRlbBFdNbcZm1ciyNOOX9Trfh9IFSBGrirOrRX2iX4u/yl605McPYXqbLZJB4cepLoOYrvGjxL4r1DU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1634917621; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:References:Sender:Subject:To; bh=hs4B++wJk+oRSfOJ8sIFcaUQ7y6GYHaC4W+74eFbItI=; b=NMFnSzC4cMFGrCCwq9TqtuKBSbU4uHlIDQHTguvwpPLNzG7vt41ppUKrCCaJ+poEoFJNxzS35FKnGv69ClEceGHeBMRd7AwF/eXBlHKimgU/yVhqePkjGEbUJuy7JRgBVodNnRkU2lliTg/kcxorv0fuwjWd05xLVb+LYStaOA4= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+82535+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 1634917621041353.15613441635173; Fri, 22 Oct 2021 08:47:01 -0700 (PDT) Return-Path: X-Received: by 127.0.0.2 with SMTP id OcURYY1788612xNXJ12LUQYC; Fri, 22 Oct 2021 08:47:00 -0700 X-Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by mx.groups.io with SMTP id smtpd.web10.10216.1634917618991189270 for ; Fri, 22 Oct 2021 08:46:59 -0700 X-IronPort-AV: E=McAfee;i="6200,9189,10145"; a="209428373" X-IronPort-AV: E=Sophos;i="5.87,173,1631602800"; d="scan'208";a="209428373" X-Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Oct 2021 08:46:43 -0700 X-IronPort-AV: E=Sophos;i="5.87,173,1631602800"; d="scan'208";a="445333081" X-Received: from gdong1-mobl1.amr.corp.intel.com ([10.212.41.65]) by orsmga006-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Oct 2021 08:46:42 -0700 From: "Guo Dong" To: devel@edk2.groups.io Cc: Guo Dong , Ray Ni , Maurice Ma , Benjamin You Subject: [edk2-devel] [`edk2-devel][PATCH V3 5/8] UefiPayloadPkg: Add FlashDeviceLib Date: Fri, 22 Oct 2021 08:46:24 -0700 Message-Id: <20211022154627.1607-6-guo.dong@intel.com> In-Reply-To: <20211022154627.1607-1-guo.dong@intel.com> References: <20211022154627.1607-1-guo.dong@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,guo.dong@intel.com X-Gm-Message-State: xyCR1UTtXNpcwNZO01Mqu3mOx1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1634917620; bh=U0kUq1f/Nxcgizi2q0tJmzgWQpPA2gAwGFGCYzgO48Q=; h=Cc:Date:From:Reply-To:Subject:To; b=H2nw91svg5d2YkVZK5qLEl2yz50sVcGikYKuCVJmELoUYuTQzaYYvLqxj1F/H2RJq7p X8zJQlmtG5jgPIZL3aLo5qeJ+N28HIxHZnwMNqfBXSGEqrGDQVtI0s4bHzIhTK5wYudeh 0fpKJTr8rYHeFwJQwz3I1rwSZosr4poEeDM= X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1634917622260100011 Content-Type: text/plain; charset="utf-8" From: Guo Dong This library provides FlashDeviceLib APIs based on SpiFlashLib and consumed by FVB driver. Signed-off-by: Guo Dong Cc: Ray Ni Cc: Maurice Ma Cc: Benjamin You Reviewed-by: Ray Ni Reviewed-by: Benjamin You Reviewed-by: Benjamin You + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef FLASHDEVICE_LIB_H_ +#define FLASHDEVICE_LIB_H_ + +/** + Read NumBytes bytes of data from the address specified by + PAddress into Buffer. + + @param[in] PAddress The starting physical address of the read. + @param[in,out] NumBytes On input, the number of bytes to read. On ou= tput, the number + of bytes actually read. + @param[out] Buffer The destination data buffer for the read. + + @retval EFI_SUCCESS. Opertion is successful. + @retval EFI_DEVICE_ERROR If there is any device errors. + +**/ +EFI_STATUS +EFIAPI +LibFvbFlashDeviceRead ( + IN UINTN PAddress, + IN OUT UINTN *NumBytes, + OUT UINT8 *Buffer + ); + + +/** + Write NumBytes bytes of data from Buffer to the address specified by + PAddresss. + + @param[in] PAddress The starting physical address of the write. + @param[in,out] NumBytes On input, the number of bytes to write. On outp= ut, + the actual number of bytes written. + @param[in] Buffer The source data buffer for the write. + + @retval EFI_SUCCESS. Opertion is successful. + @retval EFI_DEVICE_ERROR If there is any device errors. + +**/ +EFI_STATUS +EFIAPI +LibFvbFlashDeviceWrite ( + IN UINTN PAddress, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ); + + +/** + Erase the block starting at PAddress. + + @param[in] PAddress The starting physical address of the region to be e= rased. + @param[in] LbaLength The length of the region to be erased. This para= meter is necessary + as the physical block size on a flash device could = be different than + the logical block size of Firmware Volume Block pro= tocol. Erase on + flash chip is always performed block by block. Ther= efore, the ERASE + operation to a logical block is converted a number = of ERASE operation + (or a partial erase) on the hardware. + + @retval EFI_SUCCESS. Opertion is successful. + @retval EFI_DEVICE_ERROR If there is any device errors. + +**/ +EFI_STATUS +EFIAPI +LibFvbFlashDeviceBlockErase ( + IN UINTN PAddress, + IN UINTN LbaLength +); + + +/** + Lock or unlock the block starting at PAddress. + + @param[in] PAddress The starting physical address of region to be (un)l= ocked. + @param[in] LbaLength The length of the region to be (un)locked. This = parameter is necessary + as the physical block size on a flash device could = be different than + the logical block size of Firmware Volume Block pro= tocol. (Un)Lock on + flash chip is always performed block by block. Ther= efore, the (Un)Lock + operation to a logical block is converted a number = of (Un)Lock operation + (or a partial erase) on the hardware. + @param[in] Lock TRUE to lock. FALSE to unlock. + + @retval EFI_SUCCESS. Opertion is successful. + +**/ +EFI_STATUS +EFIAPI +LibFvbFlashDeviceBlockLock ( + IN UINTN PAddress, + IN UINTN LbaLength, + IN BOOLEAN Lock +); + +PHYSICAL_ADDRESS +EFIAPI +LibFvbFlashDeviceMemoryMap ( +); + +#endif diff --git a/UefiPayloadPkg/Library/FlashDeviceLib/FlashDeviceLib.c b/UefiP= ayloadPkg/Library/FlashDeviceLib/FlashDeviceLib.c new file mode 100644 index 0000000000..065841bc93 --- /dev/null +++ b/UefiPayloadPkg/Library/FlashDeviceLib/FlashDeviceLib.c @@ -0,0 +1,165 @@ +/** @file + Flash Device Library based on SPI Flash library. + +Copyright (c) 2018 - 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include + +/** + Initialize spi flash device. + + @retval EFI_SUCCESS The tested spi flash device is supporte= d. + @retval EFI_UNSUPPORTED The tested spi flash device is not supp= orted. + +**/ +EFI_STATUS +EFIAPI +LibFvbFlashDeviceInit ( + VOID + ) +{ + return SpiConstructor (); +} + + +/** + Read NumBytes bytes of data from the address specified by + PAddress into Buffer. + + @param[in] PAddress The starting physical address of the read. + @param[in,out] NumBytes On input, the number of bytes to read. On = output, the number + of bytes actually read. + @param[out] Buffer The destination data buffer for the read. + + @retval EFI_SUCCESS. Opertion is successful. + @retval EFI_DEVICE_ERROR If there is any device errors. + +**/ +EFI_STATUS +EFIAPI +LibFvbFlashDeviceRead ( + IN UINTN PAddress, + IN OUT UINTN *NumBytes, + OUT UINT8 *Buffer + ) +{ + EFI_STATUS Status; + UINT32 ByteCount; + UINT32 RgnSize; + UINT32 AddrOffset; + + Status =3D SpiGetRegionAddress (FlashRegionBios, NULL, &RgnSize); + if (EFI_ERROR (Status)) { + return Status; + } + + // BIOS region offset can be calculated by (PAddress - (0x100000000 - Rg= nSize)) + // which equal (PAddress + RgnSize) here. + AddrOffset =3D (UINT32)((UINT32)PAddress + RgnSize); + ByteCount =3D (UINT32)*NumBytes; + return SpiFlashRead (FlashRegionBios, AddrOffset, ByteCount, Buffer); +} + + +/** + Write NumBytes bytes of data from Buffer to the address specified by + PAddresss. + + @param[in] PAddress The starting physical address of the wri= te. + @param[in,out] NumBytes On input, the number of bytes to write. = On output, + the actual number of bytes written. + @param[in] Buffer The source data buffer for the write. + + @retval EFI_SUCCESS. Opertion is successful. + @retval EFI_DEVICE_ERROR If there is any device errors. + +**/ +EFI_STATUS +EFIAPI +LibFvbFlashDeviceWrite ( + IN UINTN PAddress, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +{ + EFI_STATUS Status; + UINT32 ByteCount; + UINT32 RgnSize; + UINT32 AddrOffset; + + Status =3D SpiGetRegionAddress (FlashRegionBios, NULL, &RgnSize); + if (EFI_ERROR (Status)) { + return Status; + } + + // BIOS region offset can be calculated by (PAddress - (0x100000000 - Rg= nSize)) + // which equal (PAddress + RgnSize) here. + AddrOffset =3D (UINT32)((UINT32)PAddress + RgnSize); + ByteCount =3D (UINT32)*NumBytes; + return SpiFlashWrite (FlashRegionBios, AddrOffset, ByteCount, Buffer); +} + + +/** + Erase the block starting at PAddress. + + @param[in] PAddress The starting physical address of the block t= o be erased. + This library assume that caller garantee tha= t the PAddress + is at the starting address of this block. + @param[in] LbaLength The length of the logical block to be erased. + + @retval EFI_SUCCESS. Opertion is successful. + @retval EFI_DEVICE_ERROR If there is any device errors. + +**/ +EFI_STATUS +EFIAPI +LibFvbFlashDeviceBlockErase ( + IN UINTN PAddress, + IN UINTN LbaLength + ) +{ + EFI_STATUS Status; + UINT32 RgnSize; + UINT32 AddrOffset; + + Status =3D SpiGetRegionAddress (FlashRegionBios, NULL, &RgnSize); + if (EFI_ERROR (Status)) { + return Status; + } + + // BIOS region offset can be calculated by (PAddress - (0x100000000 - Rg= nSize)) + // which equal (PAddress + RgnSize) here. + AddrOffset =3D (UINT32)((UINT32)PAddress + RgnSize); + return SpiFlashErase (FlashRegionBios, AddrOffset, (UINT32)LbaLength); +} + + +/** + Lock or unlock the block starting at PAddress. + + @param[in] PAddress The starting physical address of region to b= e (un)locked. + @param[in] LbaLength The length of the logical block to be erased. + @param[in] Lock TRUE to lock. FALSE to unlock. + + @retval EFI_SUCCESS. Opertion is successful. + @retval EFI_DEVICE_ERROR If there is any device errors. + +**/ +EFI_STATUS +EFIAPI +LibFvbFlashDeviceBlockLock ( + IN UINTN PAddress, + IN UINTN LbaLength, + IN BOOLEAN Lock + ) +{ + return EFI_SUCCESS; +} + diff --git a/UefiPayloadPkg/Library/FlashDeviceLib/FlashDeviceLib.inf b/Uef= iPayloadPkg/Library/FlashDeviceLib/FlashDeviceLib.inf new file mode 100644 index 0000000000..0ad22cffba --- /dev/null +++ b/UefiPayloadPkg/Library/FlashDeviceLib/FlashDeviceLib.inf @@ -0,0 +1,38 @@ +## @file +# Library instace of Flash Device Library Class +# +# This library implement the flash device library class for the lakeport p= latform. +#@copyright +# Copyright (c) 2014 - 2021 Intel Corporation. All rights reserved +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D FlashDeviceLib + FILE_GUID =3D BA7CA537-1C65-4a90-9379-622A24A08141 + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 1.0 + LIBRARY_CLASS =3D FlashDeviceLib | DXE_SMM_DRIVER DXE_R= UNTIME_DRIVER + + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 +# + +[Sources] + FlashDeviceLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UefiPayloadPkg/UefiPayloadPkg.dec + +[LibraryClasses] + DebugLib + BaseMemoryLib + SpiFlashLib + --=20 2.32.0.windows.2 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#82535): https://edk2.groups.io/g/devel/message/82535 Mute This Topic: https://groups.io/mt/86517143/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- From nobody Sat May 4 03:30:04 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+82537+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+82537+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1634917622; cv=none; d=zohomail.com; s=zohoarc; b=YsV008AMdqD+cxfyNd/NszmdkAXtiqN3I7B/vYeSDvls8eGwg3w3fMi+T1b51yREmkrjY1qlj2NVp9R8x4xRsrxzkDQ19C1SwwG+xZMIXKTE7cDxExroK7DYnNg7+Ax40tTgdfmSIpjhX0t4YuFr09Wkp5ogrcrl0EznQbNJLPI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1634917622; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:References:Sender:Subject:To; bh=prIBtb3QM4c0gb/cNe7sxl7dMp7GYW+5gbUUNceRc68=; b=Yew3jfSjb9Ck3QymfV8MkYaVGpYXSMwSpJIyPUkvg/bkGgdTfdwpGMH8wyh85xFOnW6EcU94IeA1lD3ZaAlsnmrDJPc4tc5qJhGs/lx5mjB67SeQTHrk1SN1TwvbdUARmpDbslC3r2CoPBxY0mU5HNd8OotNlOb51uTS+I6J1vE= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+82537+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 163491762221853.610432541666455; Fri, 22 Oct 2021 08:47:02 -0700 (PDT) Return-Path: X-Received: by 127.0.0.2 with SMTP id ZlkwYY1788612xQ63hP8GyeI; Fri, 22 Oct 2021 08:47:01 -0700 X-Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by mx.groups.io with SMTP id smtpd.web10.10216.1634917618991189270 for ; Fri, 22 Oct 2021 08:46:59 -0700 X-IronPort-AV: E=McAfee;i="6200,9189,10145"; a="209428374" X-IronPort-AV: E=Sophos;i="5.87,173,1631602800"; d="scan'208";a="209428374" X-Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Oct 2021 08:46:44 -0700 X-IronPort-AV: E=Sophos;i="5.87,173,1631602800"; d="scan'208";a="445333092" X-Received: from gdong1-mobl1.amr.corp.intel.com ([10.212.41.65]) by orsmga006-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Oct 2021 08:46:43 -0700 From: "Guo Dong" To: devel@edk2.groups.io Cc: Guo Dong , Ray Ni , Maurice Ma , Benjamin You Subject: [edk2-devel] [`edk2-devel][PATCH V3 6/8] UefiPayloadPkg: Add a common FVB SMM module Date: Fri, 22 Oct 2021 08:46:25 -0700 Message-Id: <20211022154627.1607-7-guo.dong@intel.com> In-Reply-To: <20211022154627.1607-1-guo.dong@intel.com> References: <20211022154627.1607-1-guo.dong@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,guo.dong@intel.com X-Gm-Message-State: 0W2m5LJdZ82voD7ujCZ3KUQGx1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1634917621; bh=AMeWflUQWX0drJDQYCd+CO3WjFV2WKwnPCUNJvne80A=; h=Cc:Date:From:Reply-To:Subject:To; b=oCV95gUw6y5ZT2CP6vV8GuRPjHLANHC74JIf40AXuIVoOHSCOS8Nbs1vj+iWotvwBe7 B+NvEoGLiYlMUVIJDUS8R7DynJOxc6gcWzb5FwmDXcIvuW6/MSHx/CMTk7BRGM97z+gME NjrOVW2G0BEs5FsgublubnnJ7k6Sj2izCsU= X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1634917624344100023 Content-Type: text/plain; charset="utf-8" From: Guo Dong This FVB module is used to initialize NV variable region and provide SMM FVB protocol to read/write SPI variable region. This module consume HOB gNvVariableInfoGuid and depends on FlashDeviceLib for the actual SPI device operate. During FVB initialization, it will initialize the variable region if the variable region is not valid. And it support to write initial variable data from FFS file if it is found. Signed-off-by: Guo Dong Cc: Ray Ni Cc: Maurice Ma Cc: Benjamin You Reviewed-by: Ray Ni Reviewed-by: Benjamin You Reviewed-by: Benjamin You + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FVB_MEDIA_BLOCK_SIZE 0x1000 + +typedef struct { + EFI_FIRMWARE_VOLUME_HEADER FvInfo; + EFI_FV_BLOCK_MAP_ENTRY End[1]; +} EFI_FVB2_MEDIA_INFO; + +// +// This data structure contains a template of FV header which is used to r= estore +// Fv header if it's corrupted. +// +EFI_FVB2_MEDIA_INFO mFvbMediaInfo =3D { + { + {0,}, // ZeroVector[16] + EFI_SYSTEM_NV_DATA_FV_GUID, + 0, + EFI_FVH_SIGNATURE, + 0x0004feff, // check PiFirmwareVolume.h for details on EFI_FVB_ATT= RIBUTES_2 + sizeof (EFI_FIRMWARE_VOLUME_HEADER) + sizeof (EFI_FV_BLOCK_MAP_ENTRY), + 0, // CheckSum which will be calucated dynamically. + 0, // ExtHeaderOffset + {0,}, + EFI_FVH_REVISION, + { + { + 0, + FVB_MEDIA_BLOCK_SIZE, + } + } + }, + { + { + 0, + 0 + } + } +}; + +/** + Initialize the variable store + + @retval EFI_SUCCESS if initialize the store success. + +**/ +EFI_STATUS +InitVariableStore ( + VOID + ) +{ + EFI_STATUS Status; + UINT32 NvStorageBase; + UINT32 NvStorageSize; + UINT32 NvVariableSize; + UINT32 FtwWorkingSize; + UINT32 FtwSpareSize; + EFI_HOB_GUID_TYPE *GuidHob; + NV_VARIABLE_INFO *NvVariableInfo; + + // + // Find SPI flash variable hob + // + GuidHob =3D GetFirstGuidHob (&gNvVariableInfoGuid); + if (GuidHob =3D=3D NULL) { + ASSERT (FALSE); + return EFI_NOT_FOUND; + } + NvVariableInfo =3D (NV_VARIABLE_INFO *) GET_GUID_HOB_DATA (GuidHob); + + // + // Get variable region base and size. + // + NvStorageSize =3D NvVariableInfo->VariableStoreSize; + NvStorageBase =3D NvVariableInfo->VariableStoreBase; + + // + // NvStorageBase needs to be 4KB aligned, NvStorageSize needs to be 8KB = * n + // + if (((NvStorageBase & (SIZE_4KB - 1)) !=3D 0) || ((NvStorageSize & (SIZE= _8KB - 1)) !=3D 0)) { + return EFI_INVALID_PARAMETER; + } + + FtwSpareSize =3D NvStorageSize / 2; + FtwWorkingSize =3D 0x2000; + NvVariableSize =3D NvStorageSize / 2 - FtwWorkingSize; + DEBUG ((DEBUG_INFO, "NvStorageBase:0x%x, NvStorageSize:0x%x\n", NvStorag= eBase, NvStorageSize)); + + if (NvVariableSize >=3D 0x80000000) { + return EFI_INVALID_PARAMETER; + } + Status =3D PcdSet32S(PcdFlashNvStorageVariableSize, NvVariableSize); + ASSERT_EFI_ERROR (Status); + Status =3D PcdSet32S(PcdFlashNvStorageVariableBase, NvStorageBase); + ASSERT_EFI_ERROR (Status); + Status =3D PcdSet64S(PcdFlashNvStorageVariableBase64, NvStorageBase); + ASSERT_EFI_ERROR (Status); + + Status =3D PcdSet32S(PcdFlashNvStorageFtwWorkingSize, FtwWorkingSize); + ASSERT_EFI_ERROR (Status); + Status =3D PcdSet32S(PcdFlashNvStorageFtwWorkingBase, NvStorageBase + Nv= VariableSize); + ASSERT_EFI_ERROR (Status); + + Status =3D PcdSet32S(PcdFlashNvStorageFtwSpareSize, FtwSpareSize); + ASSERT_EFI_ERROR (Status); + Status =3D PcdSet32S(PcdFlashNvStorageFtwSpareBase, NvStorageBase + Ft= wSpareSize); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + + +/** + Get a heathy FV header used for variable store recovery + + @retval The FV header. + +**/ +EFI_FIRMWARE_VOLUME_HEADER * +GetFvHeaderTemplate ( + VOID + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; + UINTN FvSize; + + FvSize =3D PcdGet32(PcdFlashNvStorageFtwSpareSize) * 2; + FvHeader =3D &mFvbMediaInfo.FvInfo; + FvHeader->FvLength =3D FvSize; + FvHeader->BlockMap[0].NumBlocks =3D (UINT32) (FvSize / FvHeader->BlockMa= p[0].Length); + FvHeader->Checksum =3D 0; + FvHeader->Checksum =3D CalculateCheckSum16 ((UINT16 *) FvHeader, FvHeade= r->HeaderLength); + + return FvHeader; +} + diff --git a/UefiPayloadPkg/FvbRuntimeDxe/FvbService.c b/UefiPayloadPkg/Fvb= RuntimeDxe/FvbService.c new file mode 100644 index 0000000000..d90a39b564 --- /dev/null +++ b/UefiPayloadPkg/FvbRuntimeDxe/FvbService.c @@ -0,0 +1,1088 @@ +/** @file +Firmware Volume Block Driver to provide FVB service. + + Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "FvbService.h" + +// +// Global variable for this FVB driver which contains +// the private data of all firmware volume block instances +// +FWB_GLOBAL mFvbModuleGlobal; + +FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate =3D { + { + { + HARDWARE_DEVICE_PATH, + HW_MEMMAP_DP, + { + (UINT8)(sizeof (MEMMAP_DEVICE_PATH)), + (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8) + } + }, + EfiMemoryMappedIO, + (EFI_PHYSICAL_ADDRESS) 0, + (EFI_PHYSICAL_ADDRESS) 0, + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + END_DEVICE_PATH_LENGTH, + 0 + } + } +}; + +FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate =3D { + { + { + MEDIA_DEVICE_PATH, + MEDIA_PIWG_FW_VOL_DP, + { + (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)), + (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8) + } + }, + { 0 } + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + END_DEVICE_PATH_LENGTH, + 0 + } + } +}; + + +EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate =3D { + FVB_DEVICE_SIGNATURE, + NULL, + 0, // Instance + { + FvbProtocolGetAttributes, + FvbProtocolSetAttributes, + FvbProtocolGetPhysicalAddress, + FvbProtocolGetBlockSize, + FvbProtocolRead, + FvbProtocolWrite, + FvbProtocolEraseBlocks, + NULL + } // FwVolBlockInstance +}; + + +/** + Get the pointer to EFI_FW_VOL_INSTANCE from the buffer pointed + by mFvbModuleGlobal.FvInstance based on a index. + Each EFI_FW_VOL_INSTANCE is with variable length as + we have a block map at the end of the EFI_FIRMWARE_VOLUME_HEADER. + + @param[in] Instance The index of the EFI_FW_VOL_INSTANCE. + + @return A pointer to EFI_FW_VOL_INSTANCE. + +**/ +EFI_FW_VOL_INSTANCE * +GetFvbInstance ( + IN UINTN Instance + ) +{ + EFI_FW_VOL_INSTANCE *FwhRecord; + + if ( Instance >=3D mFvbModuleGlobal.NumFv ) { + ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER); + return NULL; + } + + // + // Find the right instance of the FVB private data + // + FwhRecord =3D mFvbModuleGlobal.FvInstance; + while ( Instance > 0 ) { + FwhRecord =3D (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhRecord) + + FwhRecord->VolumeHeader.HeaderLength + + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUM= E_HEADER))); + Instance--; + } + + return FwhRecord; + +} + + +/** + Get the EFI_FVB_ATTRIBUTES_2 of a FV. + + @param[in] Instance The index of the EFI_FW_VOL_INSTANCE. + + @retval EFI_FVB_ATTRIBUTES_2 of the FV identified by Instance. + +**/ +STATIC +EFI_FVB_ATTRIBUTES_2 +FvbGetVolumeAttributes ( + IN UINTN Instance + ) +{ + EFI_FW_VOL_INSTANCE * FwInstance; + FwInstance =3D GetFvbInstance(Instance); + ASSERT (FwInstance !=3D NULL); + + if (FwInstance =3D=3D NULL) { + return 0; + } + + return FwInstance->VolumeHeader.Attributes; +} + + + +/** + Retrieves the starting address of an LBA in an FV. It also + return a few other attribut of the FV. + + @param[in] Instance The index of the EFI_FW_VOL_INSTANCE. + @param[in] Lba The logical block address + @param[out] LbaAddress On output, contains the physical starting ad= dress + of the Lba + @param[out] LbaLength On output, contains the length of the block + @param[out] NumOfBlocks A pointer to a caller allocated UINTN in whi= ch the + number of consecutive blocks starting with L= ba is + returned. All blocks in this range have a si= ze of + BlockSize + + @retval EFI_SUCCESS Successfully returns + @retval EFI_INVALID_PARAMETER Instance not found + +**/ +STATIC +EFI_STATUS +FvbGetLbaAddress ( + IN UINTN Instance, + IN EFI_LBA Lba, + OUT UINTN *LbaAddress, + OUT UINTN *LbaLength, + OUT UINTN *NumOfBlocks + ) +{ + UINT32 NumBlocks; + UINT32 BlockLength; + UINTN Offset; + EFI_LBA StartLba; + EFI_LBA NextLba; + EFI_FW_VOL_INSTANCE *FwhInstance; + EFI_FV_BLOCK_MAP_ENTRY *BlockMap; + + // + // Find the right instance of the FVB private data + // + FwhInstance =3D GetFvbInstance (Instance); + if (FwhInstance =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + StartLba =3D 0; + Offset =3D 0; + BlockMap =3D &FwhInstance->VolumeHeader.BlockMap[0]; + ASSERT (BlockMap !=3D NULL); + + // + // Parse the blockmap of the FV to find which map entry the Lba belongs = to + // + while (TRUE) { + if ( BlockMap !=3D NULL) { + NumBlocks =3D BlockMap->NumBlocks; + BlockLength =3D BlockMap->Length; + } + + if ( NumBlocks =3D=3D 0 || BlockLength =3D=3D 0) { + return EFI_INVALID_PARAMETER; + } + + NextLba =3D StartLba + NumBlocks; + + // + // The map entry found + // + if (Lba >=3D StartLba && Lba < NextLba) { + Offset =3D Offset + (UINTN)MultU64x32((Lba - StartLba), BlockLength); + if (LbaAddress !=3D NULL) { + *LbaAddress =3D FwhInstance->FvBase + Offset; + } + + if (LbaLength !=3D NULL) { + *LbaLength =3D BlockLength; + } + + if (NumOfBlocks !=3D NULL) { + *NumOfBlocks =3D (UINTN)(NextLba - Lba); + } + return EFI_SUCCESS; + } + + StartLba =3D NextLba; + Offset =3D Offset + NumBlocks * BlockLength; + BlockMap++; + } +} + + +/** + Reads specified number of bytes into a buffer from the specified block + + @param[in] Instance The FV instance to be read from + @param[in] Lba The logical block address to be read from + @param[in] BlockOffset Offset into the block at which to begin = reading + @param[in, out] NumBytes Pointer that on input contains the total= size of + the buffer. On output, it contains the t= otal number + of bytes read + @param[in] Buffer Pointer to a caller allocated buffer tha= t will be + used to hold the data read + + + @retval EFI_SUCCESS The firmware volume was read success= fully and + contents are in Buffer + @retval EFI_BAD_BUFFER_SIZE Read attempted across a LBA boundary= . On output, + NumBytes contains the total number o= f bytes returned + in Buffer + @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDi= sabled state + @retval EFI_DEVICE_ERROR The block device is not functioning = correctly and + could not be read + @retval EFI_INVALID_PARAMETER Instance not found, or NumBytes, B= uffer are NULL + +**/ +STATIC +EFI_STATUS +FvbReadBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN UINTN BlockOffset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +{ + EFI_FVB_ATTRIBUTES_2 Attributes; + UINTN LbaAddress; + UINTN LbaLength; + EFI_STATUS Status; + EFI_STATUS ReadStatus; + + if ( (NumBytes =3D=3D NULL) || (Buffer =3D=3D NULL)) { + return (EFI_INVALID_PARAMETER); + } + if (*NumBytes =3D=3D 0) { + return (EFI_INVALID_PARAMETER); + } + + Status =3D FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NUL= L); + if (EFI_ERROR(Status)) { + return Status; + } + + Attributes =3D FvbGetVolumeAttributes (Instance); + + if ( (Attributes & EFI_FVB2_READ_STATUS) =3D=3D 0) { + return (EFI_ACCESS_DENIED); + } + + if (BlockOffset > LbaLength) { + return (EFI_INVALID_PARAMETER); + } + + if (LbaLength < ( *NumBytes + BlockOffset ) ) { + *NumBytes =3D (UINT32) (LbaLength - BlockOffset); + Status =3D EFI_BAD_BUFFER_SIZE; + } + + ReadStatus =3D LibFvbFlashDeviceRead (LbaAddress + BlockOffset, NumBytes= , Buffer); + if (EFI_ERROR(ReadStatus)) { + return ReadStatus; + } + + return Status; +} + + +/** + Writes specified number of bytes from the input buffer to the block + + @param[in] Instance The FV instance to be written to + @param[in] Lba The starting logical block index to write = to + @param[in] BlockOffset Offset into the block at which to begin wr= iting + @param[in, out] NumBytes Pointer that on input contains the total s= ize of + the buffer. On output, it contains the to= tal number + of bytes actually written + @param[in] Buffer Pointer to a caller allocated buffer that = contains + the source for the write + @retval EFI_SUCCESS The firmware volume was written successf= ully + @retval EFI_BAD_BUFFER_SIZE Write attempted across a LBA boundary. O= n output, + NumBytes contains the total number of by= tes + actually written + @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisab= led state + @retval EFI_DEVICE_ERROR The block device is not functioning corr= ectly and + could not be written + @retval EFI_INVALID_PARAMETER Instance not found, or NumBytes, Buffe= r are NULL + +**/ +EFI_STATUS +FvbWriteBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN UINTN BlockOffset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +{ + EFI_FVB_ATTRIBUTES_2 Attributes; + UINTN LbaAddress; + UINTN LbaLength; + EFI_STATUS Status; + + if ( (NumBytes =3D=3D NULL) || (Buffer =3D=3D NULL)) { + return (EFI_INVALID_PARAMETER); + } + if (*NumBytes =3D=3D 0) { + return (EFI_INVALID_PARAMETER); + } + + Status =3D FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NUL= L); + if (EFI_ERROR(Status)) { + return Status; + } + + // + // Check if the FV is write enabled + // + Attributes =3D FvbGetVolumeAttributes (Instance); + if ( (Attributes & EFI_FVB2_WRITE_STATUS) =3D=3D 0) { + return EFI_ACCESS_DENIED; + } + + // + // Perform boundary checks and adjust NumBytes + // + if (BlockOffset > LbaLength) { + return EFI_INVALID_PARAMETER; + } + + if ( LbaLength < ( *NumBytes + BlockOffset ) ) { + DEBUG ((DEBUG_ERROR, + "FvWriteBlock: Reducing Numbytes from 0x%x to 0x%x\n", + *NumBytes, (UINT32)(LbaLength - BlockOffset))); + *NumBytes =3D (UINT32) (LbaLength - BlockOffset); + return EFI_BAD_BUFFER_SIZE; + } + + LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, FALSE); + Status =3D LibFvbFlashDeviceWrite (LbaAddress + BlockOffset, NumBytes, B= uffer); + + LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, TRUE); + WriteBackInvalidateDataCacheRange ((VOID *) (LbaAddress + BlockOffset), = *NumBytes); + return Status; +} + + +/** + Erases and initializes a firmware volume block + + @param[in] Instance The FV instance to be erased + @param[in] Lba The logical block index to be erased + + @retval EFI_SUCCESS The erase request was successfully completed + @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled = state + @retval EFI_DEVICE_ERROR The block device is not functioning correctl= y and + could not be written. Firmware device may ha= ve been + partially erased + @retval EFI_INVALID_PARAMETER Instance not found + +**/ +EFI_STATUS +FvbEraseBlock ( + IN UINTN Instance, + IN EFI_LBA Lba + ) +{ + + EFI_FVB_ATTRIBUTES_2 Attributes; + UINTN LbaAddress; + UINTN LbaLength; + EFI_STATUS Status; + + // + // Check if the FV is write enabled + // + Attributes =3D FvbGetVolumeAttributes (Instance); + + if( (Attributes & EFI_FVB2_WRITE_STATUS) =3D=3D 0) { + return (EFI_ACCESS_DENIED); + } + + // + // Get the starting address of the block for erase. + // + Status =3D FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NUL= L); + if (EFI_ERROR(Status)) { + return Status; + } + + LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, FALSE); + + Status =3D LibFvbFlashDeviceBlockErase (LbaAddress, LbaLength); + + LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, TRUE); + + WriteBackInvalidateDataCacheRange ((VOID *) LbaAddress, LbaLength); + + return Status; +} + +/** + Modifies the current settings of the firmware volume according to the + input parameter, and returns the new setting of the volume + + @param[in] Instance The FV instance whose attributes is go= ing to be + modified + @param[in, out] Attributes On input, it is a pointer to EFI_FVB_A= TTRIBUTES_2 + containing the desired firmware volume= settings. + On successful return, it contains the = new settings + of the firmware volume + + @retval EFI_SUCCESS Successfully returns + @retval EFI_ACCESS_DENIED The volume setting is locked and canno= t be modified + @retval EFI_INVALID_PARAMETER Instance not found, or The attributes = requested are + in conflict with the capabilities as d= eclared in the + firmware volume header + +**/ +STATIC +EFI_STATUS +FvbSetVolumeAttributes ( + IN UINTN Instance, + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ) +{ + EFI_FW_VOL_INSTANCE *FwhInstance; + EFI_FVB_ATTRIBUTES_2 OldAttributes; + EFI_FVB_ATTRIBUTES_2 *AttribPtr; + EFI_FVB_ATTRIBUTES_2 UnchangedAttributes; + UINT32 Capabilities; + UINT32 OldStatus; + UINT32 NewStatus; + + // + // Find the right instance of the FVB private data + // + FwhInstance =3D GetFvbInstance (Instance); + if (FwhInstance =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + AttribPtr =3D (EFI_FVB_ATTRIBUTES_2 *) &(FwhInstance->VolumeHeader.Attri= butes); + ASSERT (AttribPtr !=3D NULL); + if ( AttribPtr =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + OldAttributes =3D *AttribPtr; + Capabilities =3D OldAttributes & EFI_FVB2_CAPABILITIES; + OldStatus =3D OldAttributes & EFI_FVB2_STATUS; + NewStatus =3D *Attributes & EFI_FVB2_STATUS; + + UnchangedAttributes =3D EFI_FVB2_READ_DISABLED_CAP | \ + EFI_FVB2_READ_ENABLED_CAP | \ + EFI_FVB2_WRITE_DISABLED_CAP | \ + EFI_FVB2_WRITE_ENABLED_CAP | \ + EFI_FVB2_LOCK_CAP | \ + EFI_FVB2_STICKY_WRITE | \ + EFI_FVB2_MEMORY_MAPPED | \ + EFI_FVB2_ERASE_POLARITY | \ + EFI_FVB2_READ_LOCK_CAP | \ + EFI_FVB2_WRITE_LOCK_CAP | \ + EFI_FVB2_ALIGNMENT; + + // + // Some attributes of FV is read only can *not* be set + // + if ((OldAttributes & UnchangedAttributes) ^ (*Attributes & UnchangedAttr= ibutes)) { + return EFI_INVALID_PARAMETER; + } + + // + // If firmware volume is locked, no status bit can be updated + // + if ((OldAttributes & EFI_FVB2_LOCK_STATUS) !=3D 0) { + if ((OldStatus ^ NewStatus) !=3D 0) { + return EFI_ACCESS_DENIED; + } + } + + // + // Test read disable + // + if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) =3D=3D 0) { + if ((NewStatus & EFI_FVB2_READ_STATUS) =3D=3D 0) { + return EFI_INVALID_PARAMETER; + } + } + + // + // Test read enable + // + if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) =3D=3D 0) { + if ((NewStatus & EFI_FVB2_READ_STATUS) !=3D 0) { + return EFI_INVALID_PARAMETER; + } + } + + // + // Test write disable + // + if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) =3D=3D 0) { + if ((NewStatus & EFI_FVB2_WRITE_STATUS) =3D=3D 0) { + return EFI_INVALID_PARAMETER; + } + } + + // + // Test write enable + // + if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) =3D=3D 0) { + if ((NewStatus & EFI_FVB2_WRITE_STATUS) !=3D 0) { + return EFI_INVALID_PARAMETER; + } + } + + // + // Test lock + // + if ((Capabilities & EFI_FVB2_LOCK_CAP) =3D=3D 0) { + if ((NewStatus & EFI_FVB2_LOCK_STATUS) !=3D 0) { + return EFI_INVALID_PARAMETER; + } + } + + *AttribPtr =3D (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS)); + *AttribPtr =3D (*AttribPtr) | NewStatus; + *Attributes =3D *AttribPtr; + + return EFI_SUCCESS; +} + + +/** + Retrieves the physical address of the device. + + @param[in] This A pointer to EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL. + @param[out] Address Output buffer containing the address. + + @retval EFI_SUCCESS The function always return successfully. + @retval EFI_INVALID_PARAMETER Instance not found. + +**/ +EFI_STATUS +EFIAPI +FvbProtocolGetPhysicalAddress ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_PHYSICAL_ADDRESS *Address + ) +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + EFI_FW_VOL_INSTANCE *FwhInstance; + + FvbDevice =3D FVB_DEVICE_FROM_THIS (This); + FwhInstance =3D GetFvbInstance(FvbDevice->Instance); + if (FwhInstance =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + *Address =3D FwhInstance->FvBase; + return EFI_SUCCESS; +} + + + +/** + Retrieve the size of a logical block + + @param[in] This Calling context + @param[in] Lba Indicates which block to return the size for. + @param[out] BlockSize A pointer to a caller allocated UINTN in which + the size of the block is returned + @param[out] NumOfBlocks A pointer to a caller allocated UINTN in which t= he + number of consecutive blocks starting with Lba is + returned. All blocks in this range have a size of + BlockSize + + @retval EFI_SUCCESS The function always return successfully. + +**/ +EFI_STATUS +EFIAPI +FvbProtocolGetBlockSize ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumOfBlocks + ) +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice =3D FVB_DEVICE_FROM_THIS (This); + return FvbGetLbaAddress (FvbDevice->Instance, Lba, NULL, BlockSize, NumO= fBlocks); +} + + +/** + Retrieves Volume attributes. No polarity translations are done. + + @param[in] This Calling context + @param[out] Attributes Output buffer which contains attributes + + @retval EFI_SUCCESS The function always return successfully. + +**/ +EFI_STATUS +EFIAPI +FvbProtocolGetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ) +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice =3D FVB_DEVICE_FROM_THIS (This); + *Attributes =3D FvbGetVolumeAttributes (FvbDevice->Instance); + + return EFI_SUCCESS; +} + + +/** + Sets Volume attributes. No polarity translations are done. + + @param[in] This Calling context + @param[in, out] Attributes Output buffer which contains attributes + + @retval EFI_SUCCESS The function always return successfully. + +**/ +EFI_STATUS +EFIAPI +FvbProtocolSetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ) +{ + EFI_STATUS Status; + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice =3D FVB_DEVICE_FROM_THIS (This); + Status =3D FvbSetVolumeAttributes (FvbDevice->Instance, Attributes); + return Status; +} + + + +/** + This function erases one or more blocks as denoted by the + variable argument list. The entire parameter list of blocks must be veri= fied + prior to erasing any blocks. If a block is requested that does not exist + within the associated firmware volume (it has a larger index than the la= st + block of the firmware volume), the EraseBlock() function must return + EFI_INVALID_PARAMETER without modifying the contents of the firmware vol= ume. + + @param[in] This Calling context + @param[in] ... Starting LBA followed by Number of Lba to erase. + a -1 to terminate the list. + + @retval EFI_SUCCESS The erase request was successfully completed + @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled st= ate + @retval EFI_DEVICE_ERROR The block device is not functioning correctly = and + could not be written. Firmware device may have= been + partially erased + +**/ +EFI_STATUS +EFIAPI +FvbProtocolEraseBlocks ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + ... + ) +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + EFI_FW_VOL_INSTANCE *FwhInstance; + UINTN NumOfBlocks; + VA_LIST args; + EFI_LBA StartingLba; + UINTN NumOfLba; + EFI_STATUS Status; + + FvbDevice =3D FVB_DEVICE_FROM_THIS (This); + FwhInstance =3D GetFvbInstance (FvbDevice->Instance); + if (FwhInstance =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + NumOfBlocks =3D FwhInstance->NumOfBlocks; + VA_START (args, This); + + do { + StartingLba =3D VA_ARG (args, EFI_LBA); + if ( StartingLba =3D=3D EFI_LBA_LIST_TERMINATOR ) { + break; + } + + NumOfLba =3D VA_ARG (args, UINT32); + + // + // Check input parameters + // + if (NumOfLba =3D=3D 0) { + VA_END (args); + return EFI_INVALID_PARAMETER; + } + + if ( ( StartingLba + NumOfLba ) > NumOfBlocks ) { + return EFI_INVALID_PARAMETER; + } + } while ( 1 ); + + VA_END (args); + + VA_START (args, This); + do { + StartingLba =3D VA_ARG (args, EFI_LBA); + if (StartingLba =3D=3D EFI_LBA_LIST_TERMINATOR) { + break; + } + + NumOfLba =3D VA_ARG (args, UINT32); + + while ( NumOfLba > 0 ) { + Status =3D FvbEraseBlock (FvbDevice->Instance, StartingLba); + if ( EFI_ERROR(Status)) { + VA_END (args); + return Status; + } + StartingLba++; + NumOfLba--; + } + } while ( 1 ); + + VA_END (args); + + return EFI_SUCCESS; +} + + + +/** + Writes data beginning at Lba:Offset from FV. The write terminates either + when *NumBytes of data have been written, or when a block boundary is + reached. *NumBytes is updated to reflect the actual number of bytes + written. The write opertion does not include erase. This routine will + attempt to write only the specified bytes. If the writes do not stick, + it will return an error. + + @param[in] This Calling context + @param[in] Lba Block in which to begin write + @param[in] Offset Offset in the block at which to begin write + @param[in,out] NumBytes On input, indicates the requested write size. = On + output, indicates the actual number of bytes w= ritten + @param[in] Buffer Buffer containing source data for the write. + + @retval EFI_SUCCESS The firmware volume was written successful= ly + @retval EFI_BAD_BUFFER_SIZE Write attempted across a LBA boundary. On = output, + NumBytes contains the total number of bytes + actually written + @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisable= d state + @retval EFI_DEVICE_ERROR The block device is not functioning correc= tly and + could not be written + @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL + +**/ +EFI_STATUS +EFIAPI +FvbProtocolWrite ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + EFI_STATUS Status; + + FvbDevice =3D FVB_DEVICE_FROM_THIS (This); + Status =3D FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes,= Buffer); + DEBUG((DEBUG_VERBOSE, + "FvbWrite: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x Status= :%r\n", + Lba, Offset, *NumBytes, Buffer, Status)); + + return Status; +} + + +/** + Reads data beginning at Lba:Offset from FV. The Read terminates either + when *NumBytes of data have been read, or when a block boundary is + reached. *NumBytes is updated to reflect the actual number of bytes + written. The write opertion does not include erase. This routine will + attempt to write only the specified bytes. If the writes do not stick, + it will return an error. + + @param[in] This Calling context + @param[in] Lba Block in which to begin write + @param[in] Offset Offset in the block at which to begin write + @param[in,out] NumBytes On input, indicates the requested write size. = On + output, indicates the actual number of bytes w= ritten + @param[out] Buffer Buffer containing source data for the write. + + +Returns: + @retval EFI_SUCCESS The firmware volume was read successfully = and + contents are in Buffer + @retval EFI_BAD_BUFFER_SIZE Read attempted across a LBA boundary. On o= utput, + NumBytes contains the total number of byte= s returned + in Buffer + @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled= state + @retval EFI_DEVICE_ERROR The block device is not functioning correc= tly and + could not be read + @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL + +**/ +EFI_STATUS +EFIAPI +FvbProtocolRead ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + OUT UINT8 *Buffer + ) +{ + + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + EFI_STATUS Status; + + FvbDevice =3D FVB_DEVICE_FROM_THIS (This); + Status =3D FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, = Buffer); + DEBUG((DEBUG_VERBOSE, + "FvbRead: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x, Status= :%r\n", + Lba, Offset, *NumBytes, Buffer, Status)); + + return Status; +} + +/** + Check the integrity of firmware volume header in FvBase + + @param[in] FvBase A pointer to firmware volume base address. + + @retval TRUE The firmware volume is consistent + @retval FALSE The firmware volume has corrupted. + +**/ +BOOLEAN +IsFvHeaderValid ( + IN EFI_PHYSICAL_ADDRESS FvBase + ) +{ + UINT16 Sum; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + + FwVolHeader =3D (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) FvBase; + if (FvBase =3D=3D PcdGet32(PcdFlashNvStorageVariableBase)) { + if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid,= sizeof(EFI_GUID)) !=3D 0 ) { + DEBUG((DEBUG_INFO, " --FileSystemGuid not match: %g\n", &FwVolHeade= r->FileSystemGuid)); + return FALSE; + } + } else { + if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem2= Guid, sizeof(EFI_GUID)) !=3D 0 ) { + DEBUG((DEBUG_INFO, " --not expected guid.\n")); + return FALSE; + } + } + + if ( (FwVolHeader->Revision !=3D EFI_FVH_REVISION) || + (FwVolHeader->Signature !=3D EFI_FVH_SIGNATURE) || + (FwVolHeader->FvLength =3D=3D ((UINTN) -1)) || + ((FwVolHeader->HeaderLength & 0x01 ) !=3D0) ) { + DEBUG((DEBUG_INFO, " -- >Revision =3D 0x%x, Signature =3D 0x%x\n", Fw= VolHeader->Revision, FwVolHeader->Signature )); + DEBUG((DEBUG_INFO, " -- >FvLength =3D 0x%lx, HeaderLength =3D 0x%x\n"= , FwVolHeader->FvLength, FwVolHeader->HeaderLength )); + return FALSE; + } + + Sum =3D CalculateSum16 ((UINT16 *) FwVolHeader, FwVolHeader->HeaderLengt= h); + if (Sum !=3D 0) { + DEBUG((DEBUG_INFO, "error: checksum: 0x%04X (expect 0x0)\n", Sum)); + return FALSE; + } + + return TRUE; +} + + +/** + Get intial variable data. + + @param[out] VarData Valid variable data. + @param[out] VarSize Valid variable size. + + @retval RETURN_SUCCESS Successfully found initial variable data. + @retval RETURN_NOT_FOUND Failed to find the variable data file from= FV. + @retval EFI_INVALID_PARAMETER VarData or VarSize is null. + +**/ +EFI_STATUS +GetInitialVariableData ( + OUT VOID **VarData, + OUT UINTN *VarSize + ) +{ + EFI_STATUS Status; + VOID *ImageData; + UINTN ImageSize; + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; + VARIABLE_STORE_HEADER *VariableStore; + AUTHENTICATED_VARIABLE_HEADER *Variable; + UINTN VariableSize; + UINTN VarEndAddr; + + if ((VarData =3D=3D NULL) || (VarSize =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + Status =3D GetSectionFromAnyFv (PcdGetPtr(PcdNvsDataFile), EFI_SECTION_R= AW, 0, &ImageData, &ImageSize); + if (EFI_ERROR (Status)) { + return Status; + } + + FvHeader =3D (EFI_FIRMWARE_VOLUME_HEADER *) ImageData; + VariableStore =3D (VARIABLE_STORE_HEADER *) ((UINT8 *)ImageData + FvHead= er->HeaderLength); + VarEndAddr =3D (UINTN)VariableStore + VariableStore->Size; + Variable =3D (AUTHENTICATED_VARIABLE_HEADER *) HEADER_ALIGN (Variab= leStore + 1); + *VarData =3D (VOID *)Variable; + while (((UINTN)Variable < VarEndAddr)) { + if (Variable->StartId !=3D VARIABLE_DATA) { + break; + } + VariableSize =3D sizeof (AUTHENTICATED_VARIABLE_HEADER) + Variable->Da= taSize + Variable->NameSize; + Variable =3D (AUTHENTICATED_VARIABLE_HEADER *) HEADER_ALIGN ((UINT= N) Variable + VariableSize); + } + + *VarSize =3D (UINTN)Variable - HEADER_ALIGN (VariableStore + 1); + + return EFI_SUCCESS; +} + +/** + The function does the necessary initialization work for + Firmware Volume Block Driver. + + @retval EFI_SUCCESS This funtion always return EFI_SUCCESS. + It will ASSERT on errors. + +**/ +EFI_STATUS +FvbInitialize ( + VOID + ) +{ + EFI_FW_VOL_INSTANCE *FwVolInstance; + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; + EFI_FV_BLOCK_MAP_ENTRY *BlockMap; + EFI_PHYSICAL_ADDRESS BaseAddress; + UINTN WriteAddr; + EFI_STATUS Status; + UINTN BufferSize; + UINTN Length; + VARIABLE_STORE_HEADER VariableStore; + VOID *VarData; + + InitVariableStore (); + BaseAddress =3D PcdGet32(PcdFlashNvStorageVariableBase); + FvHeader =3D (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress; + + // + // Check FV header and variable store header + // + if (!IsFvHeaderValid (BaseAddress)) { + // + // Write back a healthy FV header + // + DEBUG ((DEBUG_ERROR, "Fvb: Writing back a healthy FV header: 0x%lx\n",= BaseAddress)); + FvHeader =3D GetFvHeaderTemplate (); + LibFvbFlashDeviceBlockLock ((UINTN)BaseAddress, FvHeader->BlockMap->Le= ngth, FALSE); + + Status =3D LibFvbFlashDeviceBlockErase ((UINTN)BaseAddress, FvHeader->= BlockMap->Length); + ASSERT_EFI_ERROR(Status); + + Length =3D FvHeader->HeaderLength; + WriteAddr =3D (UINTN)BaseAddress; + Status =3D LibFvbFlashDeviceWrite (WriteAddr, &Length, (UINT8 *) FvHea= der); + WriteAddr +=3D Length; + ASSERT_EFI_ERROR(Status); + + // + // Write back variable store header + // + VariableStore.Size =3D PcdGet32(PcdFlashNvStorageVariableSize) - FvH= eader->HeaderLength; + VariableStore.Format =3D VARIABLE_STORE_FORMATTED; + VariableStore.State =3D VARIABLE_STORE_HEALTHY; + CopyGuid (&VariableStore.Signature, &gEfiAuthenticatedVariableGuid); + BufferSize =3D sizeof (VARIABLE_STORE_HEADER); + Status =3D LibFvbFlashDeviceWrite (WriteAddr, &BufferSize, (UINT8 *) &= VariableStore); + WriteAddr +=3D BufferSize; + ASSERT_EFI_ERROR(Status); + + // + // Write initial variable data if found + // + Status =3D GetInitialVariableData (&VarData, &Length); + if (!EFI_ERROR (Status)) { + Status =3D LibFvbFlashDeviceWrite (WriteAddr, &Length, (UINT8 *) Var= Data); + ASSERT_EFI_ERROR(Status); + } + + LibFvbFlashDeviceBlockLock ((UINTN)BaseAddress, FvHeader->BlockMap->Le= ngth, TRUE); + WriteBackInvalidateDataCacheRange ((VOID *) (UINTN) BaseAddress, FvHea= der->BlockMap->Length); + } + + // + // Create a new FW volume instance for NVS variable + // + BufferSize =3D FvHeader->HeaderLength + sizeof (EFI_FW_VOL_INSTANCE) = - sizeof (EFI_FIRMWARE_VOLUME_HEADER); + FwVolInstance =3D (EFI_FW_VOL_INSTANCE *) AllocateRuntimeZeroPool (Buffe= rSize); + if (FwVolInstance =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + FwVolInstance->FvBase =3D (UINTN)BaseAddress; + CopyMem (&FwVolInstance->VolumeHeader, FvHeader, FvHeader->HeaderLength); + + // + // Process the block map for each FV. Assume it has same block size. + // + FwVolInstance->NumOfBlocks =3D 0; + FvHeader =3D &FwVolInstance->VolumeHeader; + for (BlockMap =3D FvHeader->BlockMap; BlockMap->NumBlocks !=3D 0; BlockM= ap++) { + FwVolInstance->NumOfBlocks +=3D BlockMap->NumBlocks; + } + + // + // Add a FVB Protocol Instance + // + Status =3D InstallFvbProtocol (FwVolInstance, mFvbModuleGlobal.NumFv); + mFvbModuleGlobal.NumFv++; + mFvbModuleGlobal.FvInstance =3D FwVolInstance; + + return Status; +} diff --git a/UefiPayloadPkg/FvbRuntimeDxe/FvbService.h b/UefiPayloadPkg/Fvb= RuntimeDxe/FvbService.h new file mode 100644 index 0000000000..c07562cbfd --- /dev/null +++ b/UefiPayloadPkg/FvbRuntimeDxe/FvbService.h @@ -0,0 +1,187 @@ +/** @file +The header file for Firmware volume block driver. + +Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef FW_BLOCK_SERVICE_H_ +#define FW_BLOCK_SERVICE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Define two helper macro to extract the Capability field or Status field= in FVB +// bit fields +// +#define EFI_FVB2_CAPABILITIES (EFI_FVB2_READ_DISABLED_CAP | \ + EFI_FVB2_READ_ENABLED_CAP | \ + EFI_FVB2_WRITE_DISABLED_CAP | \ + EFI_FVB2_WRITE_ENABLED_CAP | \ + EFI_FVB2_LOCK_CAP \ + ) + +#define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EF= I_FVB2_LOCK_STATUS) + + +typedef struct { + UINTN FvBase; + UINTN NumOfBlocks; + // + // Note!!!: VolumeHeader must be the last element + // of the structure. + // + EFI_FIRMWARE_VOLUME_HEADER VolumeHeader; +} EFI_FW_VOL_INSTANCE; + + +typedef struct { + EFI_FW_VOL_INSTANCE *FvInstance; + UINT32 NumFv; + UINT32 Flags; +} FWB_GLOBAL; + +// +// Fvb Protocol instance data +// +#define FVB_DEVICE_FROM_THIS(a) CR(a, EFI_FW_VOL_BLOCK_DEVICE, FwVolBlockI= nstance, FVB_DEVICE_SIGNATURE) +#define FVB_EXTEND_DEVICE_FROM_THIS(a) CR(a, EFI_FW_VOL_BLOCK_DEVICE, FvbE= xtension, FVB_DEVICE_SIGNATURE) +#define FVB_DEVICE_SIGNATURE SIGNATURE_32('F','V','B','C') + +typedef struct { + MEDIA_FW_VOL_DEVICE_PATH FvDevPath; + EFI_DEVICE_PATH_PROTOCOL EndDevPath; +} FV_PIWG_DEVICE_PATH; + +typedef struct { + MEMMAP_DEVICE_PATH MemMapDevPath; + EFI_DEVICE_PATH_PROTOCOL EndDevPath; +} FV_MEMMAP_DEVICE_PATH; + +typedef struct { + UINT32 Signature; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UINTN Instance; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL FwVolBlockInstance; +} EFI_FW_VOL_BLOCK_DEVICE; + +/** + Get a heathy FV header used for variable store recovery + + @retval The FV header. + +**/ +EFI_FIRMWARE_VOLUME_HEADER * +GetFvHeaderTemplate ( + VOID + ); + +EFI_STATUS +InitVariableStore ( + VOID + ); + +// +// Protocol APIs +// +EFI_STATUS +EFIAPI +FvbProtocolGetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ); + +EFI_STATUS +EFIAPI +FvbProtocolSetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ); + +EFI_STATUS +EFIAPI +FvbProtocolGetPhysicalAddress ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_PHYSICAL_ADDRESS *Address + ); + +EFI_STATUS +EFIAPI +FvbProtocolGetBlockSize ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumOfBlocks + ); + +EFI_STATUS +EFIAPI +FvbProtocolRead ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + OUT UINT8 *Buffer + ); + +EFI_STATUS +EFIAPI +FvbProtocolWrite ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ); + +EFI_STATUS +EFIAPI +FvbProtocolEraseBlocks ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + ... + ); + +EFI_FW_VOL_INSTANCE * +GetFvbInstance ( + IN UINTN Instance + ); + +EFI_STATUS +InstallFvbProtocol ( + IN EFI_FW_VOL_INSTANCE *FwhInstance, + IN UINTN InstanceNum + ); + +EFI_STATUS +FvbInitialize ( + VOID + ); + +extern FWB_GLOBAL mFvbModuleGlobal; +extern EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate; +extern FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate; +extern FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate; + +#endif diff --git a/UefiPayloadPkg/FvbRuntimeDxe/FvbServiceSmm.c b/UefiPayloadPkg/= FvbRuntimeDxe/FvbServiceSmm.c new file mode 100644 index 0000000000..0f1f4b369c --- /dev/null +++ b/UefiPayloadPkg/FvbRuntimeDxe/FvbServiceSmm.c @@ -0,0 +1,139 @@ +/** @file + SMM Firmware Volume Block Driver. + + Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include "FvbSmmCommon.h" +#include "FvbService.h" + +/** + The function installs EFI_SMM_FIRMWARE_VOLUME_BLOCK protocol + for each FV in the system. + + @param[in] FwhInstance The pointer to a FW volume instance structure, + which contains the information about one FV. + @param[in] InstanceNum The instance number which can be used as a ID + to locate this FwhInstance in other functions. + + @retval EFI_SUCESS Installed successfully. + @retval Else Did not install successfully. + +**/ +EFI_STATUS +InstallFvbProtocol ( + IN EFI_FW_VOL_INSTANCE *FwhInstance, + IN UINTN InstanceNum + ) +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_STATUS Status; + EFI_HANDLE FvbHandle; + FV_MEMMAP_DEVICE_PATH *FvDevicePath; + VOID *TempPtr; + + FvbDevice =3D (EFI_FW_VOL_BLOCK_DEVICE *) AllocateRuntimeCopyPool ( + sizeof (EFI_FW_VOL_BLOCK_DEVIC= E), + &mFvbDeviceTemplate + ); + if (FvbDevice =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + FvbDevice->Instance =3D InstanceNum; + FwVolHeader =3D &FwhInstance->VolumeHeader; + + // + // Set up the devicepath + // + if (FwVolHeader->ExtHeaderOffset =3D=3D 0) { + // + // FV does not contains extension header, then produce MEMMAP_DEVICE_P= ATH + // + TempPtr =3D AllocateRuntimeCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH), &= mFvMemmapDevicePathTemplate); + FvbDevice->DevicePath =3D (EFI_DEVICE_PATH_PROTOCOL *) TempPtr; + if (FvbDevice->DevicePath =3D=3D NULL) { + ASSERT (FALSE); + return EFI_OUT_OF_RESOURCES; + } + FvDevicePath =3D (FV_MEMMAP_DEVICE_PATH *) FvbDevice->DevicePath; + FvDevicePath->MemMapDevPath.StartingAddress =3D FwhInstance->FvBase; + FvDevicePath->MemMapDevPath.EndingAddress =3D FwhInstance->FvBase + = FwVolHeader->FvLength - 1; + } else { + TempPtr =3D AllocateRuntimeCopyPool (sizeof (FV_PIWG_DEVICE_PATH), &mF= vPIWGDevicePathTemplate); + FvbDevice->DevicePath =3D (EFI_DEVICE_PATH_PROTOCOL *) TempPtr; + if (FvbDevice->DevicePath =3D=3D NULL) { + ASSERT (FALSE); + return EFI_OUT_OF_RESOURCES; + } + + CopyGuid ( + &((FV_PIWG_DEVICE_PATH *)FvbDevice->DevicePath)->FvDevPath.FvName, + (GUID *)(UINTN)(FwhInstance->FvBase + FwVolHeader->ExtHeaderOffset) + ); + } + + // + // Install the SMM Firmware Volume Block Protocol and Device Path Protoc= ol + // + FvbHandle =3D NULL; + Status =3D gSmst->SmmInstallProtocolInterface ( + &FvbHandle, + &gEfiSmmFirmwareVolumeBlockProtocolGuid, + EFI_NATIVE_INTERFACE, + &FvbDevice->FwVolBlockInstance + ); + ASSERT_EFI_ERROR (Status); + + Status =3D gSmst->SmmInstallProtocolInterface ( + &FvbHandle, + &gEfiDevicePathProtocolGuid, + EFI_NATIVE_INTERFACE, + FvbDevice->DevicePath + ); + ASSERT_EFI_ERROR (Status); + + // + // Notify the Fvb wrapper driver SMM fvb is ready + // + FvbHandle =3D NULL; + Status =3D gBS->InstallProtocolInterface ( + &FvbHandle, + &gEfiSmmFirmwareVolumeBlockProtocolGuid, + EFI_NATIVE_INTERFACE, + &FvbDevice->FwVolBlockInstance + ); + + return Status; +} + + +/** + The driver entry point for SMM Firmware Volume Block Driver. + + The function does the necessary initialization work + Firmware Volume Block Driver. + + @param[in] ImageHandle The firmware allocated handle for the UEFI= image. + @param[in] SystemTable A pointer to the EFI system table. + + @retval EFI_SUCCESS This funtion always return EFI_SUCCESS. + It will ASSERT on errors. + +**/ +EFI_STATUS +EFIAPI +FvbSmmInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + FvbInitialize (); + + return EFI_SUCCESS; +} diff --git a/UefiPayloadPkg/FvbRuntimeDxe/FvbSmm.inf b/UefiPayloadPkg/FvbRu= ntimeDxe/FvbSmm.inf new file mode 100644 index 0000000000..2a262076d6 --- /dev/null +++ b/UefiPayloadPkg/FvbRuntimeDxe/FvbSmm.inf @@ -0,0 +1,71 @@ +## @file +# This driver installs the EFI_SMM_FIRMWARE_VOLUMEN_PROTOCOL. +# +# +# Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D FvbSmm + FILE_GUID =3D A4EC8ADB-B7A8-47d1-8E52-EC820D0ACF6F + MODULE_TYPE =3D DXE_SMM_DRIVER + VERSION_STRING =3D 1.0 + PI_SPECIFICATION_VERSION =3D 0x0001000A + ENTRY_POINT =3D FvbSmmInitialize + +[Sources] + FvbInfo.c + FvbService.h + FvbService.c + FvbServiceSmm.c + FvbSmmCommon.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + UefiPayloadPkg/UefiPayloadPkg.dec + +[LibraryClasses] + FlashDeviceLib + PcdLib + MemoryAllocationLib + CacheMaintenanceLib + IoLib + BaseMemoryLib + DebugLib + BaseLib + UefiLib + SmmServicesTableLib + UefiBootServicesTableLib + UefiDriverEntryPoint + HobLib + DxeServicesLib + +[Guids] + gEfiFirmwareFileSystem2Guid # ALWAYS_CONSUMED + gEfiSystemNvDataFvGuid # ALWAYS_CONSUMED + gEfiAuthenticatedVariableGuid + gNvVariableInfoGuid + + [Protocols] + gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_PRODUCED + gEfiSmmFirmwareVolumeBlockProtocolGuid # PROTOCOL ALWAYS_PRODUCED + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize + + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase + gUefiPayloadPkgTokenSpaceGuid.PcdNvsDataFile + +[Depex] + TRUE diff --git a/UefiPayloadPkg/FvbRuntimeDxe/FvbSmmCommon.h b/UefiPayloadPkg/F= vbRuntimeDxe/FvbSmmCommon.h new file mode 100644 index 0000000000..5886996cd8 --- /dev/null +++ b/UefiPayloadPkg/FvbRuntimeDxe/FvbSmmCommon.h @@ -0,0 +1,69 @@ +/** @file + The common header file for SMM FVB module. + +Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef SMM_FVB_COMMON_H_ +#define SMM_FVB_COMMON_H_ + +#include + +#define EFI_FUNCTION_GET_ATTRIBUTES 1 +#define EFI_FUNCTION_SET_ATTRIBUTES 2 +#define EFI_FUNCTION_GET_PHYSICAL_ADDRESS 3 +#define EFI_FUNCTION_GET_BLOCK_SIZE 4 +#define EFI_FUNCTION_READ 5 +#define EFI_FUNCTION_WRITE 6 +#define EFI_FUNCTION_ERASE_BLOCKS 7 + +typedef struct { + UINTN Function; + EFI_STATUS ReturnStatus; + UINT8 Data[1]; +} SMM_FVB_COMMUNICATE_FUNCTION_HEADER; + + +/// +/// Size of SMM communicate header, without including the payload. +/// +#define SMM_COMMUNICATE_HEADER_SIZE (OFFSET_OF (EFI_SMM_COMMUNICATE_HEADE= R, Data)) + +/// +/// Size of SMM FVB communicate function header, without including the pay= load. +/// +#define SMM_FVB_COMMUNICATE_HEADER_SIZE (OFFSET_OF (SMM_FVB_COMMUNICATE_F= UNCTION_HEADER, Data)) + +typedef struct { + EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb; + EFI_FVB_ATTRIBUTES_2 Attributes; +} SMM_FVB_ATTRIBUTES_HEADER; + +typedef struct { + EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb; + EFI_PHYSICAL_ADDRESS Address; +} SMM_FVB_PHYSICAL_ADDRESS_HEADER; + +typedef struct { + EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb; + EFI_LBA Lba; + UINTN BlockSize; + UINTN NumOfBlocks; +} SMM_FVB_BLOCK_SIZE_HEADER; + +typedef struct { + EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb; + EFI_LBA Lba; + UINTN Offset; + UINTN NumBytes; +} SMM_FVB_READ_WRITE_HEADER; + +typedef struct { + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb; + EFI_LBA StartLba; + UINTN NumOfLba; +} SMM_FVB_BLOCKS_HEADER; + +#endif diff --git a/UefiPayloadPkg/Include/Guid/NvVariableInfoGuid.h b/UefiPayload= Pkg/Include/Guid/NvVariableInfoGuid.h new file mode 100644 index 0000000000..f22e4e6122 --- /dev/null +++ b/UefiPayloadPkg/Include/Guid/NvVariableInfoGuid.h @@ -0,0 +1,24 @@ +/** @file + This file defines the hob structure for the SPI flash variable info. + + Copyright (c) 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef NV_VARIABLE_INFO_GUID_H_ +#define NV_VARIABLE_INFO_GUID_H_ + +// +// NV variable hob info GUID +// +extern EFI_GUID gNvVariableInfoGuid; + +typedef struct { + UINT8 Revision; + UINT8 Reserved[3]; + UINT32 VariableStoreBase; + UINT32 VariableStoreSize; +} NV_VARIABLE_INFO; + +#endif diff --git a/UefiPayloadPkg/UefiPayloadPkg.dec b/UefiPayloadPkg/UefiPayload= Pkg.dec index 3ffdce550d..e385dc7219 100644 --- a/UefiPayloadPkg/UefiPayloadPkg.dec +++ b/UefiPayloadPkg/UefiPayloadPkg.dec @@ -37,6 +37,8 @@ gUefiSerialPortInfoGuid =3D { 0x6c6872fe, 0x56a9, 0x4403, { 0xbb, 0x98,= 0x95, 0x8d, 0x62, 0xde, 0x87, 0xf1 } } gLoaderMemoryMapInfoGuid =3D { 0xa1ff7424, 0x7a1a, 0x478e, { 0xa9, 0xe4,= 0x92, 0xf3, 0x57, 0xd1, 0x28, 0x32 } } =20 + # SMM variable support + gNvVariableInfoGuid =3D { 0x7a345dca, 0xc26, 0x4f2a, { 0xa8, 0x9a,= 0x57, 0xc0, 0x8d, 0xdd, 0x22, 0xee } } gSpiFlashInfoGuid =3D { 0x2d4aac1b, 0x91a5, 0x4cd5, { 0x9b, 0x5c,= 0xb4, 0x0f, 0x5d, 0x28, 0x51, 0xa1 } } gSmmRegisterInfoGuid =3D { 0xaa9bd7a7, 0xcafb, 0x4499, { 0xa4, 0xa9,= 0xb, 0x34, 0x6b, 0x40, 0xa6, 0x22 } } gS3CommunicationGuid =3D { 0x88e31ba1, 0x1856, 0x4b8b, { 0xbb, 0xdf,= 0xf8, 0x16, 0xdd, 0x94, 0xa, 0xef } } @@ -81,3 +83,7 @@ gUefiPayloadPkgTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServ= icesCode|0x80|UINT32|0x gUefiPayloadPkgTokenSpaceGuid.PcdSystemMemoryUefiRegionSize|0x02000000|UIN= T32|0x00000017 =20 gUefiPayloadPkgTokenSpaceGuid.PcdPcdDriverFile|{ 0x57, 0x72, 0xcf, 0x80, 0= xab, 0x87, 0xf9, 0x47, 0xa3, 0xfe, 0xD5, 0x0B, 0x76, 0xd8, 0x95, 0x41 }|VOI= D*|0x00000018 + +## FFS filename to find the default variable initial data file. +# @Prompt FFS Name of variable initial data file + gUefiPayloadPkgTokenSpaceGuid.PcdNvsDataFile |{ 0x1a, 0xf1, 0xb1, 0xae, 0= x42, 0xcc, 0xcf, 0x4e, 0xac, 0x60, 0xdb, 0xab, 0xf6, 0xca, 0x69, 0xe6 }|VOI= D*|0x00000025 --=20 2.32.0.windows.2 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#82537): https://edk2.groups.io/g/devel/message/82537 Mute This Topic: https://groups.io/mt/86517145/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- From nobody Sat May 4 03:30:04 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+82538+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+82538+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1634917622; cv=none; d=zohomail.com; s=zohoarc; b=Yom+sjVcNXTTr/c3u6Zxv/cyWhCsEbMH2IE1H5SzOhviTWreA35/Won4G2aXW2dBBiHQTVeJEM9fNDU/9Y+XUjW5JgX2SuQ6MU12Y0hEWgaxCzp/vvcjgH9WL2YoQwsf74ynrfT/BnMAGcM8eXe6+gvVK2fAwM62y2ipC3gb5k4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1634917622; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:References:Sender:Subject:To; bh=zK9H6QOjjJkol1w0k0QAIY6Sa7lBa/meDVroWh8sfnU=; b=LL5tJxAb/++wKAsggeTaTgo2d35G0bcLMTVN9mSF1F+4vkLutlpG4k0Y44eKrE9z5UPErRMmObjaQWCLxFtqM14aS/X8hTheKvYcXT2W/EnX1js4pW52nLGiw1DWIU7dmUl6cHlJisce4TPhug0HLkzPQX8LY9yf874VApos62I= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+82538+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 1634917622671807.7873810426819; Fri, 22 Oct 2021 08:47:02 -0700 (PDT) Return-Path: X-Received: by 127.0.0.2 with SMTP id KGC6YY1788612xgnRZNAR0SM; Fri, 22 Oct 2021 08:47:02 -0700 X-Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by mx.groups.io with SMTP id smtpd.web11.10188.1634917617623869169 for ; Fri, 22 Oct 2021 08:47:00 -0700 X-IronPort-AV: E=McAfee;i="6200,9189,10145"; a="209428380" X-IronPort-AV: E=Sophos;i="5.87,173,1631602800"; d="scan'208";a="209428380" X-Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Oct 2021 08:46:45 -0700 X-IronPort-AV: E=Sophos;i="5.87,173,1631602800"; d="scan'208";a="445333098" X-Received: from gdong1-mobl1.amr.corp.intel.com ([10.212.41.65]) by orsmga006-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Oct 2021 08:46:44 -0700 From: "Guo Dong" To: devel@edk2.groups.io Cc: Guo Dong , Ray Ni , Maurice Ma , Benjamin You Subject: [edk2-devel] [`edk2-devel][PATCH V3 7/8] UefiPayloadPkg: Add a SMM dispatch module Date: Fri, 22 Oct 2021 08:46:26 -0700 Message-Id: <20211022154627.1607-8-guo.dong@intel.com> In-Reply-To: <20211022154627.1607-1-guo.dong@intel.com> References: <20211022154627.1607-1-guo.dong@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,guo.dong@intel.com X-Gm-Message-State: ZPHGoqIxubTl1fF6VpwKK7pFx1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1634917622; bh=dEis8j5cAViEKRx546juivdaoxHB5zt4O4Ti3CekgUE=; h=Cc:Date:From:Reply-To:Subject:To; b=JeVq+dr5LDAbLo6H9Wld2JfJZ3cWrweDqhJgOOXbfh5L044jqLFTUxxSxGwbnYlgORo DTXvh+tIMftSZlkSKvYFC+b1Ys6xO1LmaQm+FNydNbFF0lq6rMKv6VWFGCLSxfRqD++Z/ ZMPv4wjmbaTfnsZmC1FhxSVEiC6Y4HLunhM= X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1634917624442100026 Content-Type: text/plain; charset="utf-8" From: Guo Dong PCH SMM module would install SMM SW dispatch2 protocol. And it supports to register SMI handlers based on SMI APM interrupt from the bootloader information gSmmRegisterInfoGuid. It is possible to extend bootloader HOB to pass other information to support more SMI sources. If this module is not required by bootloader for some reason, the bootloader could skip this HOB or build a HOB without EOS info. Signed-off-by: Guo Dong Cc: Ray Ni Cc: Maurice Ma Cc: Benjamin You Reviewed-by: Ray Ni Reviewed-by: Benjamin You Reviewed-by: Benjamin You + SPDX-License-Identifier: BSD-2-Clause-Patent + + + +**/ + +#include "PchSmiDispatchSmm.h" + +typedef struct { + UINT8 EosBitOffset; + UINT8 ApmBitOffset; + UINT32 SmiEosAddr; + UINT32 SmiApmStsAddr; +} SMM_PCH_REGISTER; + +SMM_PCH_REGISTER mSmiPchReg; + +EFI_SMM_CPU_PROTOCOL *mSmmCpuProtocol; +LIST_ENTRY mSmmSwDispatch2Queue =3D INITIALIZE_LIST_HEAD_VARIA= BLE (mSmmSwDispatch2Queue); + +/** + Find SmmSwDispatch2Context by SwSmiInputValue. + + @param[in] SwSmiInputValue The value to indentify the SmmSwDispatch= 2 context + + @return Pointer to EFI_SMM_SW_DISPATCH2_CONTEXT context +**/ +EFI_SMM_SW_DISPATCH2_CONTEXT * +FindContextBySwSmiInputValue ( + IN UINTN SwSmiInputValue + ) +{ + LIST_ENTRY *Node; + EFI_SMM_SW_DISPATCH2_CONTEXT *Dispatch2Context; + + Node =3D mSmmSwDispatch2Queue.ForwardLink; + for (; Node !=3D &mSmmSwDispatch2Queue; Node =3D Node->ForwardLink) { + Dispatch2Context =3D BASE_CR (Node, EFI_SMM_SW_DISPATCH2_CONTEXT, Link= ); + if (Dispatch2Context->SwSmiInputValue =3D=3D SwSmiInputValue) { + return Dispatch2Context; + } + } + return NULL; +} + +/** + Find SmmSwDispatch2Context by DispatchHandle. + + @param DispatchHandle The handle to indentify the SmmSwDispatch2 cont= ext + + @return Pointer to EFI_SMM_SW_DISPATCH2_CONTEXT context +**/ +EFI_SMM_SW_DISPATCH2_CONTEXT * +FindContextByDispatchHandle ( + IN EFI_HANDLE DispatchHandle + ) +{ + LIST_ENTRY *Node; + EFI_SMM_SW_DISPATCH2_CONTEXT *Dispatch2Context; + + Node =3D mSmmSwDispatch2Queue.ForwardLink; + for (; Node !=3D &mSmmSwDispatch2Queue; Node =3D Node->ForwardLink) { + Dispatch2Context =3D BASE_CR (Node, EFI_SMM_SW_DISPATCH2_CONTEXT, Link= ); + if (Dispatch2Context->DispatchHandle =3D=3D DispatchHandle) { + return Dispatch2Context; + } + } + return NULL; +} + +/** + Dispatch registered SMM handlers + + @param DispatchHandle The unique handle assigned to this handler by Sm= iHandlerRegister(). + @param RegisterContext Points to an optional handler context which was = specified when the handler was registered. + @param CommBuffer A pointer to a collection of data in memory that= will + be conveyed from a non-SMM environment into an S= MM environment. + @param CommBufferSize The size of the CommBuffer. + + @return Status Code + +**/ +EFI_STATUS +SmmSwDispatcher ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *RegisterContext, + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommBufferSize + ) +{ + EFI_STATUS Status; + EFI_SMM_SW_CONTEXT SwContext; + UINTN Index; + EFI_SMM_SW_DISPATCH2_CONTEXT *Context; + EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction; + EFI_SMM_SW_REGISTER_CONTEXT DispatchContext; + UINTN Size; + EFI_SMM_SAVE_STATE_IO_INFO IoInfo; + + // + // Construct new context + // + SwContext.SwSmiCpuIndex =3D 0; + SwContext.CommandPort =3D IoRead8 (SMM_CONTROL_PORT); + SwContext.DataPort =3D IoRead8 (SMM_DATA_PORT); + + // + // Try to find which CPU trigger SWSMI + // + for (Index =3D 0; Index < gSmst->NumberOfCpus; Index++) { + Status =3D mSmmCpuProtocol->ReadSaveState ( + mSmmCpuProtocol, + sizeof(IoInfo), + EFI_SMM_SAVE_STATE_REGISTER_IO, + Index, + &IoInfo + ); + if (EFI_ERROR (Status)) { + continue; + } + if (IoInfo.IoPort =3D=3D SMM_CONTROL_PORT) { + // + // Great! Find it. + // + SwContext.SwSmiCpuIndex =3D Index; + DEBUG ((DEBUG_VERBOSE, "CPU index =3D 0x%x/0x%x\n", Index, gSmst->Nu= mberOfCpus)); + break; + } + } + + if (SwContext.CommandPort =3D=3D 0) { + DEBUG ((DEBUG_VERBOSE, "NOT SW SMI\n")); + Status =3D EFI_SUCCESS; + goto End; + } + + // + // Search context + // + Context =3D FindContextBySwSmiInputValue (SwContext.CommandPort); + if (Context =3D=3D NULL) { + DEBUG ((DEBUG_INFO, "No handler for SMI value 0x%x\n", SwContext.Comma= ndPort)); + Status =3D EFI_SUCCESS; + goto End; + } + DEBUG ((DEBUG_VERBOSE, "Prepare to call handler for 0x%x\n", SwContext.C= ommandPort)); + + // + // Dispatch + // + DispatchContext.SwSmiInputValue =3D SwContext.CommandPort; + Size =3D sizeof(SwContext); + DispatchFunction =3D (EFI_SMM_HANDLER_ENTRY_POINT2)Context->DispatchFunc= tion; + Status =3D DispatchFunction (DispatchHandle, &DispatchContext, &SwContex= t, &Size); + +End: + // + // Clear SMI APM status + // + IoOr32 (mSmiPchReg.SmiApmStsAddr, 1 << mSmiPchReg.ApmBitOffset); + + + // + // Set EOS bit + // + IoOr32 (mSmiPchReg.SmiEosAddr, 1 << mSmiPchReg.EosBitOffset); + + return Status; +} + + +/** +Check the SwSmiInputValue is already used + +@param[in] SwSmiInputValue To indentify the SmmSwDispatch2 context + +@retval EFI_SUCCESS SwSmiInputValue could be used. +@retval EFI_INVALID_PARAMETER SwSmiInputValue is already be used. + +**/ +EFI_STATUS +SmiInputValueCheck ( + IN UINTN SwSmiInputValue + ) +{ + LIST_ENTRY *Node; + EFI_SMM_SW_DISPATCH2_CONTEXT *Dispatch2Context; + + Node =3D mSmmSwDispatch2Queue.ForwardLink; + for (; Node !=3D &mSmmSwDispatch2Queue; Node =3D Node->ForwardLink) { + Dispatch2Context =3D BASE_CR (Node, EFI_SMM_SW_DISPATCH2_CONTEXT, Link= ); + if (Dispatch2Context->SwSmiInputValue =3D=3D SwSmiInputValue) { + return EFI_INVALID_PARAMETER; + } + } + + return EFI_SUCCESS; +} + + +/** + Register a child SMI source dispatch function for the specified software= SMI. + + This service registers a function (DispatchFunction) which will be calle= d when the software + SMI source specified by RegContext->SwSmiCpuIndex is detected. On return= , DispatchHandle + contains a unique handle which may be used later to unregister the funct= ion using UnRegister(). + + @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PROTO= COL instance. + @param[in] DispatchFunction Function to register for handler when the= specified software + SMI is generated. + @param[in, out] RegContext Pointer to the dispatch function's contex= t. + The caller fills this context in before c= alling + the register function to indicate to the = register + function which Software SMI input value t= he + dispatch function should be invoked for. + @param[out] DispatchHandle Handle generated by the dispatcher to tra= ck the + function instance. + + @retval EFI_SUCCESS The dispatch function has been successful= ly + registered and the SMI source has been en= abled. + @retval EFI_DEVICE_ERROR The SW driver was unable to enable the SM= I source. + @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The SW SMI in= put value + is not within valid range. + @retval EFI_OUT_OF_RESOURCES There is not enough memory (system or SMM= ) to manage this + child. + @retval EFI_OUT_OF_RESOURCES A unique software SMI value could not be = assigned + for this dispatch. +**/ +EFI_STATUS +EFIAPI +SmmSwDispatch2Register ( + IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL *This, + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, + IN OUT EFI_SMM_SW_REGISTER_CONTEXT *RegContext, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + UINTN Index; + EFI_SMM_SW_DISPATCH2_CONTEXT *Context; + + if (RegContext->SwSmiInputValue =3D=3D (UINTN)-1) { + // + // If SwSmiInputValue is set to (UINTN) -1 then a unique value + // will be assigned and returned in the structure. + // + Status =3D EFI_NOT_FOUND; + for (Index =3D 1; Index < MAXIMUM_SWI_VALUE; Index++) { + Status =3D SmiInputValueCheck (Index); + if (!EFI_ERROR (Status)) { + RegContext->SwSmiInputValue =3D Index; + break; + } + } + if (RegContext->SwSmiInputValue =3D=3D (UINTN)-1) { + return EFI_OUT_OF_RESOURCES; + } + } + + if ((RegContext->SwSmiInputValue > MAXIMUM_SWI_VALUE) || (RegContext->Sw= SmiInputValue =3D=3D 0)) { + DEBUG ((DEBUG_ERROR, "ERROR: SMI value range (1 ~ 0x%x)\n", MAXIMUM_SW= I_VALUE)); + return EFI_INVALID_PARAMETER; + } + + // + // Register + // + Status =3D gSmst->SmmAllocatePool (EfiRuntimeServicesData, sizeof(*Conte= xt), (VOID **)&Context); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + *DispatchHandle =3D (EFI_HANDLE )Context; + Context->Signature =3D SMI_SW_HANDLER_SIGNATURE; + Context->SwSmiInputValue =3D RegContext->SwSmiInputValue; + Context->DispatchFunction =3D (UINTN)DispatchFunction; + Context->DispatchHandle =3D *DispatchHandle; + InsertTailList (&mSmmSwDispatch2Queue, &Context->Link); + + return Status; +} + + +/** + Unregister a child SMI source dispatch function for the specified softwa= re SMI. + + This service removes the handler associated with DispatchHandle so that = it will no longer be + called in response to a software SMI. + + @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PROTO= COL instance. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successful= ly unregistered. + @retval EFI_INVALID_PARAMETER The DispatchHandle was not valid. +**/ +EFI_STATUS +EFIAPI +SmmSwDispatch2UnRegister ( + IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ) +{ + EFI_SMM_SW_DISPATCH2_CONTEXT *Context; + + // + // Unregister + // + Context =3D FindContextByDispatchHandle (DispatchHandle); + ASSERT (Context !=3D NULL); + if (Context !=3D NULL) { + RemoveEntryList (&Context->Link); + gSmst->SmmFreePool (Context); + } + + return EFI_SUCCESS; +} + + +EFI_SMM_SW_DISPATCH2_PROTOCOL gSmmSwDispatch2 =3D { + SmmSwDispatch2Register, + SmmSwDispatch2UnRegister, + MAXIMUM_SWI_VALUE +}; + + +/** + Get specified SMI register based on given register ID + + @param[in] SmmRegister SMI related register array from bootloader + @param[in] Id The register ID to get. + + @retval NULL The register is not found or the format is not = expected. + @return smi register + +**/ +PLD_GENERIC_REGISTER * +GetSmmCtrlRegById ( + IN PLD_SMM_REGISTERS *SmmRegister, + IN UINT32 Id + ) +{ + UINT32 Index; + PLD_GENERIC_REGISTER *PldReg; + + PldReg =3D NULL; + for (Index =3D 0; Index < SmmRegister->Count; Index++) { + if (SmmRegister->Registers[Index].Id =3D=3D Id) { + PldReg =3D &SmmRegister->Registers[Index]; + break; + } + } + + if (PldReg =3D=3D NULL) { + DEBUG ((DEBUG_INFO, "Register %d not found.\n", Id)); + return NULL; + } + + // + // Checking the register if it is expected. + // + if ((PldReg->Address.AccessSize !=3D EFI_ACPI_3_0_DWORD) || + (PldReg->Address.Address =3D=3D 0) || + (PldReg->Address.RegisterBitWidth !=3D 1) || + (PldReg->Address.AddressSpaceId !=3D EFI_ACPI_3_0_SYSTEM_IO) || + (PldReg->Value !=3D 1)) { + DEBUG ((DEBUG_INFO, "Unexpected SMM register.\n")); + DEBUG ((DEBUG_INFO, "AddressSpaceId=3D 0x%x\n", PldReg->Address.Addres= sSpaceId)); + DEBUG ((DEBUG_INFO, "RegBitWidth =3D 0x%x\n", PldReg->Address.Regist= erBitWidth)); + DEBUG ((DEBUG_INFO, "RegBitOffset =3D 0x%x\n", PldReg->Address.Regist= erBitOffset)); + DEBUG ((DEBUG_INFO, "AccessSize =3D 0x%x\n", PldReg->Address.Access= Size)); + DEBUG ((DEBUG_INFO, "Address =3D 0x%lx\n",PldReg->Address.Addres= s )); + return NULL; + } + + return PldReg; +} + + +/** + Entry Point for this driver. + + @param[in] ImageHandle Image handle of this driver. + @param[in] SystemTable A Pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurred when executing this entry point. +**/ +EFI_STATUS +EFIAPI +PchSmiDispatchEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE DispatchHandle; + EFI_HOB_GUID_TYPE *GuidHob; + PLD_SMM_REGISTERS *SmmRegister; + PLD_GENERIC_REGISTER *SmiEosReg; + PLD_GENERIC_REGISTER *SmiApmStsReg; + + GuidHob =3D GetFirstGuidHob (&gSmmRegisterInfoGuid); + if (GuidHob =3D=3D NULL) { + return EFI_UNSUPPORTED; + } + + SmmRegister =3D (PLD_SMM_REGISTERS *) GET_GUID_HOB_DATA(GuidHob); + SmiEosReg =3D GetSmmCtrlRegById (SmmRegister, REGISTER_ID_SMI_EOS); + if (SmiEosReg =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "SMI EOS reg not found.\n")); + return EFI_NOT_FOUND; + } + mSmiPchReg.SmiEosAddr =3D (UINT32)SmiEosReg->Address.Address; + mSmiPchReg.EosBitOffset =3D SmiEosReg->Address.RegisterBitOffset; + + SmiApmStsReg =3D GetSmmCtrlRegById (SmmRegister, REGISTER_ID_SMI_APM_STS= ); + if (SmiApmStsReg =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "SMI APM status reg not found.\n")); + return EFI_NOT_FOUND; + } + mSmiPchReg.SmiApmStsAddr =3D (UINT32)SmiApmStsReg->Address.Address; + mSmiPchReg.ApmBitOffset =3D SmiApmStsReg->Address.RegisterBitOffset; + + // + // Locate PI SMM CPU protocol + // + Status =3D gSmst->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL, (VOI= D **)&mSmmCpuProtocol); + ASSERT_EFI_ERROR (Status); + + // + // Register a SMM handler to handle subsequent SW SMIs. + // + Status =3D gSmst->SmiHandlerRegister ((EFI_MM_HANDLER_ENTRY_POINT)SmmSwD= ispatcher, NULL, &DispatchHandle); + ASSERT_EFI_ERROR (Status); + + // + // Publish PI SMM SwDispatch2 Protocol + // + ImageHandle =3D NULL; + Status =3D gSmst->SmmInstallProtocolInterface ( + &ImageHandle, + &gEfiSmmSwDispatch2ProtocolGuid, + EFI_NATIVE_INTERFACE, + &gSmmSwDispatch2 + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + diff --git a/UefiPayloadPkg/PchSmiDispatchSmm/PchSmiDispatchSmm.h b/UefiPay= loadPkg/PchSmiDispatchSmm/PchSmiDispatchSmm.h new file mode 100644 index 0000000000..930f5a2158 --- /dev/null +++ b/UefiPayloadPkg/PchSmiDispatchSmm/PchSmiDispatchSmm.h @@ -0,0 +1,37 @@ +/** @file + The header file for SMM SwDispatch2 module. + + Copyright (c) 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef SMM_SW_DISPATCH2_H_ +#define SMM_SW_DISPATCH2_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SMI_SW_HANDLER_SIGNATURE SIGNATURE_32('s','s','w','h') +#define MAXIMUM_SWI_VALUE 0xFF +#define SMM_CONTROL_PORT 0xB2 +#define SMM_DATA_PORT 0xB3 + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + EFI_HANDLE DispatchHandle; + UINTN SwSmiInputValue; + UINTN DispatchFunction; +} EFI_SMM_SW_DISPATCH2_CONTEXT; + +#endif + diff --git a/UefiPayloadPkg/PchSmiDispatchSmm/PchSmiDispatchSmm.inf b/UefiP= ayloadPkg/PchSmiDispatchSmm/PchSmiDispatchSmm.inf new file mode 100644 index 0000000000..96a154e888 --- /dev/null +++ b/UefiPayloadPkg/PchSmiDispatchSmm/PchSmiDispatchSmm.inf @@ -0,0 +1,51 @@ +## @file +# PCH SMM SMI Software dispatch module. +# +# Copyright (c) 2021, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D PchSmiDispatchSmm + FILE_GUID =3D 60F343E3-2AE2-4AA7-B01E-BF9BD5C04A3B + MODULE_TYPE =3D DXE_SMM_DRIVER + VERSION_STRING =3D 1.0 + PI_SPECIFICATION_VERSION =3D 0x0001000A + ENTRY_POINT =3D PchSmiDispatchEntryPoint + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 +# + +[Sources] + PchSmiDispatchSmm.c + PchSmiDispatchSmm.h + +[Packages] + MdePkg/MdePkg.dec + UefiPayloadPkg/UefiPayloadPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + MemoryAllocationLib + DebugLib + UefiBootServicesTableLib + SmmServicesTableLib + BaseLib + IoLib + HobLib + +[Protocols] + gEfiSmmCpuProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiSmmSwDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED + +[Guids] + gSmmRegisterInfoGuid + +[Depex] + gEfiSmmCpuProtocolGuid --=20 2.32.0.windows.2 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#82538): https://edk2.groups.io/g/devel/message/82538 Mute This Topic: https://groups.io/mt/86517146/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- From nobody Sat May 4 03:30:04 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+82539+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+82539+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1634917623; cv=none; d=zohomail.com; s=zohoarc; b=Uq2OPO2d762P9eeWfkmRAos4yIQXciPksE6GDEOTCCPEh8A9GpqRLi45gHKrxOFIpUT91JgeX/u3AXcS2j4BCa2s5hl4G4WAHHSdJiY6Oz7MEp+zZcxRIBehLZySHsomGjKw6HlYiD7k3XVkvzXU3AFSOU9r14GqQAqE8NGJSBA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1634917623; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:References:Sender:Subject:To; bh=Xz8mjCT6sJSU8JvxTgBiVOdcQ85yRf883ZDq3nou9m8=; b=RPEaGvWPzqGJOHZXlVohgw+RJV/U5RRw0oCCD248ae1hLhnaU45IoAxqpRswGESq4SRL4JBsL5rgluZq6XsQjDwD94jmnjygBoRGVOUEOVpMcFPdmMwlfoxgSpg99kn/TvR8xkROAdRcm2Uk+qMl3af70Gn9rc8K9M/XM6Dq5Ss= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+82539+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 1634917623058569.4238263613287; Fri, 22 Oct 2021 08:47:03 -0700 (PDT) Return-Path: X-Received: by 127.0.0.2 with SMTP id L0B1YY1788612x34XN87CWJg; Fri, 22 Oct 2021 08:47:02 -0700 X-Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by mx.groups.io with SMTP id smtpd.web08.10360.1634917620423800129 for ; Fri, 22 Oct 2021 08:47:00 -0700 X-IronPort-AV: E=McAfee;i="6200,9189,10145"; a="209428381" X-IronPort-AV: E=Sophos;i="5.87,173,1631602800"; d="scan'208";a="209428381" X-Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Oct 2021 08:46:45 -0700 X-IronPort-AV: E=Sophos;i="5.87,173,1631602800"; d="scan'208";a="445333103" X-Received: from gdong1-mobl1.amr.corp.intel.com ([10.212.41.65]) by orsmga006-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Oct 2021 08:46:45 -0700 From: "Guo Dong" To: devel@edk2.groups.io Cc: Guo Dong , Ray Ni , Maurice Ma , Benjamin You Subject: [edk2-devel] [`edk2-devel][PATCH V3 8/8] UefiPayloadPkg: Add SMM support and SMM variable support Date: Fri, 22 Oct 2021 08:46:27 -0700 Message-Id: <20211022154627.1607-9-guo.dong@intel.com> In-Reply-To: <20211022154627.1607-1-guo.dong@intel.com> References: <20211022154627.1607-1-guo.dong@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,guo.dong@intel.com X-Gm-Message-State: t8MjCo8r65Fqumc3ccjVXkdTx1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1634917622; bh=adrGzrIHojONiN+fdOWZkFuityRmFNSknLjNOhqeD2I=; h=Cc:Date:From:Reply-To:Subject:To; b=EA4HWr5ulYwpYAsXJre66/jS9MLodC0ofEe0I6sAmo8ZoxHIAtUpy/afFrfk0nkqAJk I80sxUT8cWgRAp1/r4/YAVJ/x7iNXZ21AOvpCQfirsFCtKdWO4VYMDJC3NukYkrQ1SImT 7B0PNS85I8BKK4Ym4YdLQ8Vc8LJqvaosGJQ= X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1634917624498100028 Content-Type: text/plain; charset="utf-8" From: Guo Dong Add SMM variable support for universal UEFI payload. By default they are disabled. Signed-off-by: Guo Dong Cc: Ray Ni Cc: Maurice Ma Cc: Benjamin You Reviewed-by: Ray Ni Reviewed-by: Benjamin You Reviewed-by: Benjamin You + NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf + NULL|MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf + NULL|MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf + NULL|MdeModulePkg/Library/VarCheckPolicyLib/VarCheckPolicyLib.inf + } + + UefiPayloadPkg/FvbRuntimeDxe/FvbSmm.inf + MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf + MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf +!endif + #------------------------------ # Build the shell #------------------------------ diff --git a/UefiPayloadPkg/UefiPayloadPkg.fdf b/UefiPayloadPkg/UefiPayload= Pkg.fdf index 72e4c70467..2f5cb17f62 100644 --- a/UefiPayloadPkg/UefiPayloadPkg.fdf +++ b/UefiPayloadPkg/UefiPayloadPkg.fdf @@ -114,11 +114,29 @@ INF MdeModulePkg/Universal/MonotonicCounterRuntimeDxe= /MonotonicCounterRuntimeDxe !if $(DISABLE_RESET_SYSTEM) =3D=3D FALSE INF MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.inf !endif - INF PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe= .inf =20 -!if $(EMU_VARIABLE_ENABLE) =3D=3D TRUE -INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf +# +# SMM Support +# +!if $(SMM_SUPPORT) =3D=3D TRUE + INF UefiPayloadPkg/SmmAccessDxe/SmmAccessDxe.inf + INF UefiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.inf + INF UefiPayloadPkg/BlSupportSmm/BlSupportSmm.inf + INF MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf + INF MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf + INF UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf + INF UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf + INF UefiPayloadPkg/PchSmiDispatchSmm/PchSmiDispatchSmm.inf +!endif + +!if $(VARIABLE_SUPPORT) =3D=3D "EMU" + INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf +!elseif $(VARIABLE_SUPPORT) =3D=3D "SPI" + INF UefiPayloadPkg/FvbRuntimeDxe/FvbSmm.inf + INF MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.i= nf + INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf + INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf !endif =20 INF UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf @@ -271,6 +289,20 @@ INF ShellPkg/Application/Shell/Shell.inf UI STRING=3D"$(MODULE_NAME)" Optional VERSION STRING=3D"$(INF_VERSION)" Optional BUILD_NUM=3D$(BUILD_NUMBER) } +[Rule.Common.DXE_SMM_DRIVER] + FILE SMM =3D $(NAMED_GUID) { + SMM_DEPEX SMM_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex + PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi + UI STRING=3D"$(MODULE_NAME)" Optional + VERSION STRING=3D"$(INF_VERSION)" Optional BUILD_NUM=3D$(BUILD_NUMBE= R) + } + +[Rule.Common.SMM_CORE] + FILE SMM_CORE =3D $(NAMED_GUID) { + PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi + UI STRING=3D"$(MODULE_NAME)" Optional + VERSION STRING=3D"$(INF_VERSION)" Optional BUILD_NUM=3D$(BUILD_NUMBER) + } =20 [Rule.Common.UEFI_DRIVER] FILE DRIVER =3D $(NAMED_GUID) { --=20 2.32.0.windows.2 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#82539): https://edk2.groups.io/g/devel/message/82539 Mute This Topic: https://groups.io/mt/86517148/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-