From nobody Thu Dec 26 13:45:54 2024 Delivered-To: importer@patchew.org Received-SPF: none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) client-ip=198.145.21.10; envelope-from=edk2-devel-bounces@lists.01.org; helo=ml01.01.org; Authentication-Results: mx.zohomail.com; spf=none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) smtp.mailfrom=edk2-devel-bounces@lists.01.org Return-Path: Received: from ml01.01.org (ml01.01.org [198.145.21.10]) by mx.zohomail.com with SMTPS id 1504824114460938.3006803927899; Thu, 7 Sep 2017 15:41:54 -0700 (PDT) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id D909421CEB108; Thu, 7 Sep 2017 15:38:48 -0700 (PDT) Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 9AD5221E62BAA for ; Thu, 7 Sep 2017 15:38:46 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id CE2B1C049D7F; Thu, 7 Sep 2017 22:41:37 +0000 (UTC) Received: from lacos-laptop-7.usersys.redhat.com (ovpn-120-54.rdu2.redhat.com [10.10.120.54]) by smtp.corp.redhat.com (Postfix) with ESMTP id 896655D967; Thu, 7 Sep 2017 22:41:36 +0000 (UTC) X-Original-To: edk2-devel@lists.01.org DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com CE2B1C049D7F Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=lersek@redhat.com From: Laszlo Ersek To: edk2-devel-01 Date: Fri, 8 Sep 2017 00:41:16 +0200 Message-Id: <20170907224116.895-11-lersek@redhat.com> In-Reply-To: <20170907224116.895-1-lersek@redhat.com> References: <20170907224116.895-1-lersek@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Thu, 07 Sep 2017 22:41:38 +0000 (UTC) Subject: [edk2] [PATCH 10/10] OvmfPkg/IoMmuDxe: unmap all IOMMU mappings at ExitBootServices() X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Jiewen Yao , Brijesh Singh , Jordan Justen , Ard Biesheuvel MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" X-ZohoMail: RSF_4 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Register an ExitBootServices() callback that tears down all IOMMU mappings, without modifying the UEFI memory map. The trick is that in the ExitBootServices() callback, we don't immediately do the work; instead we signal another (private) event. Normally the dispatch order of ExitBootServices() callbacks is unspecified (within the same task priority level anyway). By queueing another function, we delay the unmapping until after all PciIo and Virtio drivers abort -- in their own ExitBootServices() callbacks -- the pending DMA operations of their respective controllers. Furthermore, the fact that IoMmuUnmapWorker() rewrites client-owned memory when it unmaps a Write or CommonBuffer bus master operation, is safe even in this context. The existence of any given "MapInfo" in "mMapInfos" implies that the client buffer pointed-to by "MapInfo->CryptedAddress" was live when ExitBootServices() was entered. And, after entering ExitBootServices(), nothing must have changed the UEFI memory map, hence the client buffer at "MapInfo->CryptedAddress" still exists. Cc: Ard Biesheuvel Cc: Brijesh Singh Cc: Jiewen Yao Cc: Jordan Justen Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Laszlo Ersek --- OvmfPkg/IoMmuDxe/AmdSevIoMmu.c | 145 ++++++++++++++++++++ 1 file changed, 145 insertions(+) diff --git a/OvmfPkg/IoMmuDxe/AmdSevIoMmu.c b/OvmfPkg/IoMmuDxe/AmdSevIoMmu.c index 34e1c6ee4a74..6b7df8d8aa3d 100644 --- a/OvmfPkg/IoMmuDxe/AmdSevIoMmu.c +++ b/OvmfPkg/IoMmuDxe/AmdSevIoMmu.c @@ -746,10 +746,111 @@ EDKII_IOMMU_PROTOCOL mAmdSev =3D { IoMmuUnmap, IoMmuAllocateBuffer, IoMmuFreeBuffer, }; =20 +/** + Notification function that is queued when gBS->ExitBootServices() signal= s the + EFI_EVENT_GROUP_EXIT_BOOT_SERVICES event group. This function signals an= other + event, received as Context, and returns. + + Signaling an event in this context is safe. The UEFI spec allows + gBS->SignalEvent() to return EFI_SUCCESS only; EFI_OUT_OF_RESOURCES is n= ot + listed, hence memory is not allocated. The edk2 implementation also does= not + release memory (and we only have to care about the edk2 implementation + because EDKII_IOMMU_PROTOCOL is edk2-specific anyway). + + @param[in] Event Event whose notification function is being inv= oked. + Event is permitted to request the queueing of = this + function at TPL_CALLBACK or TPL_NOTIFY task + priority level. + + @param[in] EventToSignal Identifies the EFI_EVENT to signal. EventToSig= nal + is permitted to request the queueing of its + notification function only at TPL_CALLBACK lev= el. +**/ +STATIC +VOID +EFIAPI +AmdSevExitBoot ( + IN EFI_EVENT Event, + IN VOID *EventToSignal + ) +{ + // + // (1) The NotifyFunctions of all the events in + // EFI_EVENT_GROUP_EXIT_BOOT_SERVICES will have been queued before + // AmdSevExitBoot() is entered. + // + // (2) AmdSevExitBoot() is executing minimally at TPL_CALLBACK. + // + // (3) AmdSevExitBoot() has been queued in unspecified order relative to= the + // NotifyFunctions of all the other events in + // EFI_EVENT_GROUP_EXIT_BOOT_SERVICES whose NotifyTpl is the same as + // Event's. + // + // Consequences: + // + // - If Event's NotifyTpl is TPL_CALLBACK, then some other NotifyFunctio= ns + // queued at TPL_CALLBACK may be invoked after AmdSevExitBoot() return= s. + // + // - If Event's NotifyTpl is TPL_NOTIFY, then some other NotifyFunctions + // queued at TPL_NOTIFY may be invoked after AmdSevExitBoot() returns;= plus + // *all* NotifyFunctions queued at TPL_CALLBACK will be invoked strict= ly + // after all NotifyFunctions queued at TPL_NOTIFY, including + // AmdSevExitBoot(), have been invoked. + // + // - By signaling EventToSignal here, whose NotifyTpl is TPL_CALLBACK, we + // queue EventToSignal's NotifyFunction after the NotifyFunctions of *= all* + // events in EFI_EVENT_GROUP_EXIT_BOOT_SERVICES. + // + DEBUG ((DEBUG_VERBOSE, "%a\n", __FUNCTION__)); + gBS->SignalEvent (EventToSignal); +} + +/** + Notification function that is queued after the notification functions of= all + events in the EFI_EVENT_GROUP_EXIT_BOOT_SERVICES event group. The same m= emory + map restrictions apply. + + This function unmaps all currently existing IOMMU mappings. + + @param[in] Event Event whose notification function is being invoked. = Event + is permitted to request the queueing of this function + only at TPL_CALLBACK task priority level. + + @param[in] Context Ignored. +**/ +STATIC +VOID +EFIAPI +AmdSevUnmapAllMappings ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + LIST_ENTRY *Node; + LIST_ENTRY *NextNode; + MAP_INFO *MapInfo; + + DEBUG ((DEBUG_VERBOSE, "%a\n", __FUNCTION__)); + + // + // All drivers that had set up IOMMU mappings have halted their respecti= ve + // controllers by now; tear down the mappings. + // + for (Node =3D GetFirstNode (&mMapInfos); Node !=3D &mMapInfos; Node =3D = NextNode) { + NextNode =3D GetNextNode (&mMapInfos, Node); + MapInfo =3D CR (Node, MAP_INFO, Link, MAP_INFO_SIG); + IoMmuUnmapWorker ( + &mAmdSev, // This + MapInfo, // Mapping + TRUE // MemoryMapLocked + ); + } +} + /** Initialize Iommu Protocol. =20 **/ EFI_STATUS @@ -757,15 +858,59 @@ EFIAPI AmdSevInstallIoMmuProtocol ( VOID ) { EFI_STATUS Status; + EFI_EVENT UnmapAllMappingsEvent; + EFI_EVENT ExitBootEvent; EFI_HANDLE Handle; =20 + // + // Create the "late" event whose notification function will tear down all + // left-over IOMMU mappings. + // + Status =3D gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, // Type + TPL_CALLBACK, // NotifyTpl + AmdSevUnmapAllMappings, // NotifyFunction + NULL, // NotifyContext + &UnmapAllMappingsEvent // Event + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Create the event whose notification function will be queued by + // gBS->ExitBootServices() and will signal the event created above. + // + Status =3D gBS->CreateEvent ( + EVT_SIGNAL_EXIT_BOOT_SERVICES, // Type + TPL_CALLBACK, // NotifyTpl + AmdSevExitBoot, // NotifyFunction + UnmapAllMappingsEvent, // NotifyContext + &ExitBootEvent // Event + ); + if (EFI_ERROR (Status)) { + goto CloseUnmapAllMappingsEvent; + } + Handle =3D NULL; Status =3D gBS->InstallMultipleProtocolInterfaces ( &Handle, &gEdkiiIoMmuProtocolGuid, &mAmdSev, NULL ); + if (EFI_ERROR (Status)) { + goto CloseExitBootEvent; + } + + return EFI_SUCCESS; + +CloseExitBootEvent: + gBS->CloseEvent (ExitBootEvent); + +CloseUnmapAllMappingsEvent: + gBS->CloseEvent (UnmapAllMappingsEvent); + return Status; } --=20 2.14.1.3.gb7cf6e02401b _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel