From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) by mx.groups.io with SMTP id smtpd.web12.4079.1601572241664988112 for ; Thu, 01 Oct 2020 10:10:41 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=J2MSzZyV; spf=pass (domain: redhat.com, ip: 216.205.24.124, mailfrom: lersek@redhat.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1601572240; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=zPeCeq/PiFR6rgEA7bq08vUP6VWMsQv76Jqgc5Ay3+0=; b=J2MSzZyVe0ycrbaThwgHfwCHH7wlkgGS1B/qYFxz8ZOKO806as+aW9CJZJcD3O+acr4qSP OCrqFddgytBh9Qyzj1OhvIoBZoBCh9yUuSEABTs89USF1TwbqqVac7wSpiFawyHr1XAndp uuPfPjJf9WhnJcFXeQb6jFwrHv1LWs0= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-243-BKA_-IihPVSk7wJGo__11w-1; Thu, 01 Oct 2020 13:10:39 -0400 X-MC-Unique: BKA_-IihPVSk7wJGo__11w-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id AF0071019627; Thu, 1 Oct 2020 17:10:37 +0000 (UTC) Received: from lacos-laptop-7.usersys.redhat.com (ovpn-113-110.ams2.redhat.com [10.36.113.110]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3E9F373683; Thu, 1 Oct 2020 17:10:36 +0000 (UTC) Subject: Re: [edk2-discuss] SmmSwDispatch2Protocol - Registering an SMI - Can't find protocol with OVMF To: Simon McMillan References: <3w3S.1601382760397314103.HxxZ@groups.io> From: "Laszlo Ersek" Cc: discuss@edk2.groups.io, Jiewen Yao , Michael Kinney , edk2-devel-groups-io Message-ID: <8062cf92-e721-9dd3-41a3-0ed794e92f0b@redhat.com> Date: Thu, 1 Oct 2020 19:10:35 +0200 MIME-Version: 1.0 In-Reply-To: <3w3S.1601382760397314103.HxxZ@groups.io> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=lersek@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 7bit Hi, (cross-posting to edk2-devel, comments below) On 09/29/20 14:32, Simon McMillan wrote: > Trying to register a SMI in my custom SMM module I'm running into > issues. > > Before registering the SMI, the code looks for the specific protocol > this way: > Status = gSmst->SmmLocateProtocol( > &gEfiSmmSwDispatch2ProtocolGuid, > NULL, > (VOID**)&SwDispatch > ); > DEBUG ( (EFI_D_INFO, "SmmSwDispatch2Protocol Status: 0x%x\n", Status) ); > ASSERT_EFI_ERROR(Status); > > Unfortunately, while starting OVMF, boot hangs and the following > message appears: > SmmSwDispatch2Protocol Status: 0xE > ASSERT_EFI_ERROR (Status = Not Found) > > Adding gEfiSmmSwDispatch2ProtocolGuid to the Depex section of my INF > file doesn't solve the issue, in fact it prevents the custom code from > being loaded at all. > > For info in OVMF, I simply added a reference to the inf file in the > DSC file, so that my custom code is built along OVMF: > > custom_code/custom_code.inf > > OVMF is built with the following options: > build -DSMM_REQUIRE > > Then the SMM module is converted to the right format and injected > manually with UEFITool. > > Would anyone be of help with this situation? Or could give me an > advice of what would be wrong or missing? OVMF does not contain an implementation of the EFI_MM_SW_DISPATCH_PROTOCOL. While OVMF does handle a particular software MMI, that handling occurs via a root MMI handler (in "OvmfPkg/CpuHotplugSmm") that watches out for a particular command port value. When I reviewed using a root MMI handler vs. EFI_MM_SW_DISPATCH_PROTOCOL in last October, the latter seemed like a needless complication to me. Mike, Jiewen and others provided many helpful explanations, and I decided that EFI_MM_SW_DISPATCH_PROTOCOL was unjustified for OVMF. Below, I'll try to rehash and extend parts of those discussions. Considering EFI_MM_SW_DISPATCH_PROTOCOL, OVMF would have had to produce that protocol from a chipset (aka "silicon") driver. And for actually handling the CPU hotplug MMI, OVMF would have to consume EFI_MM_SW_DISPATCH_PROTOCOL in a different -- not silicon, but "platform" -- driver, and register an MMI handler through EFI_MM_SW_DISPATCH_PROTOCOL. However, for OVMF and QEMU, there is no practical distinction between "chipset" (= "silicon") and "platform". The EFI_MM_SW_DISPATCH_PROTOCOL implementation would be a thick wrapper on top of IO port 0xB2, providing a more or less useless software abstraction. - The only small advantage would be that EFI_MM_SW_DISPATCH_PROTOCOL would permit the caller to ask for a new (previously not agreed-upon) "SwMmiInputValue" (via ((UINTN)-1)), eliminating the need for coordination wrt. the 0xB2 IO port values. This was not a compelling feature, as upstream OVMF was about to get its first own MMI handler. Additionally, the command port value was going to have to be agreed upon between the OS (QEMU would generate the ACPI payload for the OS, for triggering the MMI) and the firmware. For such "public" MMIs, the generation of "SwMmiInputValue" by EFI_MM_SW_DISPATCH_PROTOCOL.Register() is not useful anyway. - Furthermore, there was a *big* disadvantage -- the registered "DispatchFunction" would have to be called back with EFI_MM_SW_CONTEXT. And filling in EFI_MM_SW_CONTEXT.SwMmiCpuIndex -- "the 0-based index of the CPU which generated the software MMI" -- is both quite useless [*], and very challenging on OVMF / QEMU [**]. [*] It might tell us what VCPU was executing the ACPI GPE handler in the OS's AML interpreter (ultimately raising the VCPU hotplug MMI), but what is that knowledge good for? [**] To refer forward to the QncSmmDispatcher module as an example: in that driver, "SwSmiCpuIndex" is laboriously determined in SwGetBuffer(), by checking which CPU's save state map indicates that *that* CPU was interrupted in the particular IO port write instruction that triggered the SMI. But on QEMU/KVM, this kind of information is not even available. The SmmCpuFeaturesReadSaveStateRegister() function in "OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c" returns constant EFI_NOT_FOUND, for EFI_SMM_SAVE_STATE_REGISTER_IO. QEMU/KVM does not describe the interrupted OUT instruction in the save state map, and so the method seen in Quark's SwGetBuffer() couldn't work. So, quite a few complications, for little use. In the edk2-platforms tree, the directory Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher contains a driver that produces EFI_MM_SW_DISPATCH_PROTOCOL (still using the older / original name EFI_SMM_SW_DISPATCH2_PROTOCOL). When I reviewed this driver, I formed the opinion that it wasn't really "silicon-specific" -- I felt that it should be turned into a "universal" IA32/X64 driver. The responsibilities of the driver (in relation to EFI_MM_SW_DISPATCH_PROTOCOL) seem to be: (1) It has to install a root MMI handler with gMmst->MmiHandlerRegister(). (2) It must fetch the Command and Data port values from the *same* chipset registers that the EFI_MM_CONTROL_PROTOCOL.Trigger() function writes. The location and nature of this register block is about the only "silicon-specific" bit, IMO. (3) In the root MMI handler, the driver must look up the fetched Command value against the dictionary that is managed by Register() / UnRegister(). (4) Upon a match, the driver must call the callback associated with Command, and also pass Data to it (coming from EFI_MM_CONTROL_PROTOCOL.Trigger() via IO port 0xB3). (5) EFI_MM_SW_DISPATCH_PROTOCOL.Register() must never hand out such a Command value (a.k.a. "SwMmiInputValue"), for ((UINTN)-1), that equals the value that EFI_MM_CONTROL_PROTOCOL.Trigger() stores for (CommandPort==NULL). Otherwise, a Communicate request could be mistaken for *that* SW MMI, when SmmEntryPoint() [MdeModulePkg/Core/PiSmmCore/PiSmmCore.c] invokes the root MMI handler registered in (1), after processing the Communicate request. This (ie., the agreement between EFI_MM_CONTROL_PROTOCOL and EFI_MM_SW_DISPATCH_PROTOCOL) is maybe the 2nd silicon-specific point that the EFI_MM_SW_DISPATCH_PROTOCOL driver has to take into account. If such a generic driver existed, then we could perhaps include it verbatim in the OVMF platform DSC / FDF files. If someone really needed EFI_MM_SW_DISPATCH_PROTOCOL specifically. Until then, I suggest registering another root MMI handler with gMmst->MmiHandlerRegister(), like "OvmfPkg/CpuHotplugSmm" does. In the handler, filter for a command port value that is strictly greater than ICH9_APM_CNT_CPU_HOTPLUG (4). See commit 17efae27acaf ("OvmfPkg/CpuHotplugSmm: introduce skeleton for CPU Hotplug SMM driver", 2020-03-04). Manual arbitration between the various values for command port 0xB2 is necessary, accordingly. In practice this should not be a problem, as OVMF is open source; just be prepared that new Command values upstreamed to OVMF in the future might require you to pick a different Command value for your out-of-tree driver. Picking a value greater than ICH9_APM_CNT_CPU_HOTPLUG (4) will also ensure that your root MMI handler filter out the "default" command port value (namely zero) that OvmfPkg/SmmControl2Dxe uses in the Trigger() implementation, when SmmCommunicationCommunicate() [MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c] invokes Trigger() with (Command==NULL), for submitting a Communicate request. Thanks Laszlo