public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Brijesh Singh <brijesh.singh@amd.com>
To: Laszlo Ersek <lersek@redhat.com>, edk2-devel@lists.01.org
Cc: brijesh.singh@amd.com, Jordan Justen <jordan.l.justen@intel.com>,
	Tom Lendacky <thomas.lendacky@amd.com>,
	Ard Biesheuvel <ard.biesheuvel@linaro.org>
Subject: Re: [PATCH v2 17/23] OvmfPkg/VirtioBlkDxe: map host address to device address
Date: Tue, 22 Aug 2017 09:29:47 -0500	[thread overview]
Message-ID: <26532a70-01fb-ddc8-766a-2a0df672f97b@amd.com> (raw)
In-Reply-To: <1387174d-0040-0072-5e36-c133fd7ec934@redhat.com>

Hi Laszlo,

On 08/22/2017 06:14 AM, Laszlo Ersek wrote:

> 
>> So the question: is it possible that we may get called from both
>> ExitBootService notify and device uninit functions ?
> 
> This is a valid problem statement / question, and I verified your code
> with regard to it, in the patches that I reviewed.
> 
> Let's use VirtioBlkDxe as an example:
> 
> (1) The VirtioBlkDriverBindingStart() function calls VirtioBlkInit().
> 
> (2) If, and only if, VirtioBlkInit() returns with success, then the ring
> has been mapped.
> 
> (3) If, and only if, VirtioBlkInit() has returned with success, then we
> create the Dev->ExitBoot event (EVT_SIGNAL_EXIT_BOOT_SERVICES) in
> VirtioBlkDriverBindingStart(), the notification function being
> VirtioBlkExitBoot(). The task priority level at which the notification
> function will be enqueued is TPL_CALLBACK (just above TPL_APPLICATION).
> 
> (4) If the protocol interface installation fails in
> VirtioBlkDriverBindingStart(), then the Dev->ExitBoot is closed first
> (which unregisters the notification function), and VirtioBlkUninit() is
> called second (more on this below).
> 
> (5) Side topic:
> 
> According to "Table 23. TPL Restrictions" in the UEFI spec v2.7,
> ExitBootServices() may only be called at TPL_APPLICATION. This means
> that the notification function will actually be executed before
> ExitBootServices() returns.
> 
> I'm only mentioning this because in some cases the installation of a
> protocol interface has to be done very carefully. Some other module may
> have set up a protocol notify e.g. at TPL_CALLBACK. If the driver
> installs the protocol interface at TPL_APPLICATION (the default), the
> protocol notify in the other driver may be invoked immediately, and that
> driver might call back into the first driver, in order to use the
> just-installed protocol. This requires that the first driver either
> raise the TPL temporarily (so that the protocol installation not result
> in an immediate notification in the other driver), or make sure that the
> protocol being installed be immediately usable.
> 
> With regard to ExitBootServices() however, this is irrelevant. Any
> protocol install notification function invoked like above runs at
> TPL_CALLBACK, or at a higher task priority level. Therefore it *must
> not* call ExitBootServices().
> 
> Which, ultimately, guarantees that our BlockIo installation in
> VirtioBlkDriverBindingStart() will never result in a direct callback to
> VirtioBlkExitBoot().
> 
> (6) Now consider VirtioBlkUninit(). With the feature in place,
> VirtioBlkUninit() both unmaps and frees the ring. It is called from two
> contexts: (a) when we get "far enough" in VirtioBlkDriverBindingStart()
> but then fail ultimately (see point (4), and the label "UninitDev"), and
> (b) when the binding succeeds just fine, and then later the driver is
> asked to unbind (disconnect from) the device -- in
> VirtioBlkDriverBindingStop().
> 
> In VirtioBlkDriverBindingStop(), we close Dev->ExitBoot, before we call
> VirtioBlkUninit() and unmap the vring. Closing the event deregisters the
> notification function, and also clears any invocations for the notify
> function originally enqueued via this event.
> 
> (FWIW, I don't see how any such invocations could be pending here,
> because that would imply that some agent called *both*
> ExitBootServices() and our VirtioBlkDriverBindingStop() at a TPL higher
> than TPL_APPLICATION -- it would be totally invalid. Nonetheless, this
> is how closing an event works.)
> 
> 
> The upshot is that three scenarios are possible:
> 
> - VirtioBlkDriverBindingStart() fails. On return from that function, the
> vring is not mapped, and the exit-boot-services callback does not exit.
> 
> - VirtioBlkDriverBindingStart() succeeds. On return from the function,
> the vring is mapped, and the exit-boot-services callback is live. Then,
> the driver is requested to unbind the device
> (VirtioBlkDriverBindingStop()). The callback is removed, and the vring
> is unmapped in VirtioBlkUninit(). If ExitBootServices() is called
> sometime after this, then the callback is not there any longer.
> 
> - VirtioBlkDriverBindingStart() succeeds. On return from the function,
> the vring is mapped, and the exit-boot-services callback is live. Then,
> ExitBootServices() is called. VirtioBlkExitBoot() runs, resetting the
> virtio device, and unmapping its vring. VirtioBlkDriverBindingStop() may
> never be called after this point, because boot services will have been
> exited after all the callbacks run and ExitBootServices() returns.
> 
> 
> In general ExitBootServices() notify functions behave very differently
> from BindingStop() functions. The latter tear down all the structures
> nicely, in reverse order of construction, freeing memory, uninitializing
> devices, and so on. In comparison, the former *must not* free memory,
> only abort in-flight transfers and de-configure devices surgically,
> "in-place", so that they forget previous system memory references. These
> two are exclusive.
> 
> When people first write UEFI drivers that follow the UEFI driver model,
> they are tempted to call (or imitate) the full BindingStop() logic in
> the ExitBootServices() notify function. That's wrong. Those contexts are
> different with regard to system memory ownership. In BindingStop(), the
> memory is owned by the driver. In the ExitBootServices() callback, the
> memory is already owned by the OS (sort of), it is only on "loan" to the
> driver -- after which a call to BindingStop() is impossible.
> 
> 
> Therefore the answer to your question is, "no, that is not possible".
> 
>> If so, then we will
>> have issue because now we will end up calling Unmap() twice (once from
>> ExitBootServices then device uninit). In my debug statement I saw the
>> call to ExitBootServices but was never able to trigger code path where
>> the device uninit is called.
> 
> If you had been able to trigger such a sequence (exit-boot-services
> callback followed by BindingStop), that would imply a huge problem in edk2.
> 
>> I am wondering if you know any method to
>> trigger the device uninit code flow so that I can verify both the path.
> 
> Testing repeated BindingStart / BindingStop calls is indeed a good idea
> -- sort of necessary -- for any UEFI driver that follows the UEFI driver
> model. It's easiest to do with the CONNECT, DISCONNECT and RECONNECT
> commands in the UEFI shell. (Please see their documentation in the UEFI
> shell spec.)
> 
> In order to find suitable handles for testing (driver and device
> handles), I recommend the DEVICES / DRIVERS / DEVTREE / DH commands.
> Personally I find DH the most useful, in particular with the "-d -v" and
> "-p" options.
> 
> For example, "dh -d -v -p BlockIo" should give you a detailed list of
> handles with BlockIo protocol interfaces on them, and the output should
> help you find the ones installed by VirtioBlkDxe.
> 
> Sorry about the length of this email (I realize a shorter email might
> have been more to the point). I hope it helps a little.
> 


Thanks for detail explanation, I was trying driver unload and reload from
the UEFI shell but that did not trigger the BindStop hence I was not sure
how it all works. But your explanation makes sense. I will try connect and
disconnect to trigger the code path and make sure that all logical code path
have been tested before we commit the patch :)

-Brijesh



  parent reply	other threads:[~2017-08-22 14:27 UTC|newest]

Thread overview: 51+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-08-14 11:36 [PATCH v2 00/21] OvmfPkg/Virtio: introduce IOMMU-like member functions Brijesh Singh
2017-08-14 11:36 ` [PATCH v2 01/23] OvmfPkg/VirtioPciDeviceDxe: supply missing BUS_MASTER attribute Brijesh Singh
2017-08-16  0:34   ` Laszlo Ersek
2017-08-14 11:36 ` [PATCH v2 02/23] OvmfPkg/Virtio10Dxe: " Brijesh Singh
2017-08-16  0:36   ` Laszlo Ersek
2017-08-14 11:36 ` [PATCH v2 03/23] OvmfPkg/VirtioPciDeviceDxe: add missing IN and OUT decoration Brijesh Singh
2017-08-16  0:36   ` Laszlo Ersek
2017-08-14 11:36 ` [PATCH v2 04/23] OvmfPkg/VirtioMmioDeviceLib: " Brijesh Singh
2017-08-16  0:37   ` Laszlo Ersek
2017-08-14 11:36 ` [PATCH v2 05/23] OvmfPkg/Virtio: fix comment style Brijesh Singh
2017-08-16  0:41   ` Laszlo Ersek
2017-08-14 11:36 ` [PATCH v2 06/23] OvmfPkg/Virtio: introduce IOMMU-like member functions to VIRTIO_DEVICE_PROTOCOL Brijesh Singh
2017-08-16 14:37   ` Laszlo Ersek
2017-08-16 15:58     ` Brijesh Singh
2017-08-14 11:36 ` [PATCH v2 07/23] OvmfPkg/Virtio10Dxe: implement IOMMU-like member functions Brijesh Singh
2017-08-16 14:59   ` Laszlo Ersek
2017-08-14 11:36 ` [PATCH v2 08/23] OvmfPkg/VirtioPciDeviceDxe: " Brijesh Singh
2017-08-16 15:32   ` Laszlo Ersek
2017-08-16 15:53     ` Brijesh Singh
2017-08-14 11:36 ` [PATCH v2 09/23] OvmfPkg/VirtioMmioDeviceLib: " Brijesh Singh
2017-08-16 15:58   ` Laszlo Ersek
2017-08-14 11:36 ` [PATCH v2 10/23] OvmfPkg/VirtioLib: add VirtioMapAllBytesInSharedBuffer() helper function Brijesh Singh
2017-08-16 16:47   ` Laszlo Ersek
2017-08-14 11:36 ` [PATCH v2 11/23] OvmfPkg/VirtioLib: take VirtIo instance in VirtioRingInit/VirtioRingUninit Brijesh Singh
2017-08-16 16:53   ` Laszlo Ersek
2017-08-14 11:36 ` [PATCH v2 12/23] OvmfPkg/VirtioLib: add functions to map/unmap VRING Brijesh Singh
2017-08-16 20:56   ` Laszlo Ersek
2017-08-14 11:36 ` [PATCH v2 13/23] OvmfPkg/Virtio: take RingBaseShift in VirtioSetQueueAddress() Brijesh Singh
2017-08-16 21:43   ` Laszlo Ersek
2017-08-16 21:51     ` Laszlo Ersek
2017-08-14 11:36 ` [PATCH v2 14/23] OvmfPkg/Virtio10Dxe: add the RingBaseShift offset Brijesh Singh
2017-08-16 21:57   ` Laszlo Ersek
2017-08-14 11:36 ` [PATCH v2 15/23] OvmfPkg/VirtioLib: alloc vring buffer with AllocateSharedPages() Brijesh Singh
2017-08-16 22:18   ` Laszlo Ersek
2017-08-14 11:36 ` [PATCH v2 16/23] OvmfPkg/VirtioRngDxe: map host address to device address Brijesh Singh
2017-08-21 14:05   ` Laszlo Ersek
2017-08-22 15:44     ` Brijesh Singh
2017-08-22 16:28       ` Laszlo Ersek
2017-08-14 11:36 ` [PATCH v2 17/23] OvmfPkg/VirtioBlkDxe: " Brijesh Singh
2017-08-21 15:24   ` Laszlo Ersek
2017-08-22  1:42     ` Brijesh Singh
     [not found]       ` <1387174d-0040-0072-5e36-c133fd7ec934@redhat.com>
2017-08-22 14:29         ` Brijesh Singh [this message]
2017-08-22 15:53           ` Laszlo Ersek
2017-08-14 11:36 ` [PATCH v2 18/23] OvmfPkg/VirtioScsiDxe: Use DeviceAddresses in vring descriptors Brijesh Singh
2017-08-21 19:08   ` Laszlo Ersek
2017-08-14 11:36 ` [PATCH v2 19/23] OvmfPkg/VirtioNetDxe: alloc Tx and Rx rings using AllocateSharedPage() Brijesh Singh
2017-08-14 11:36 ` [PATCH v2 20/23] OvmfPkg/VirtioNetDxe: alloc RxBuf using AllocateSharedPages() Brijesh Singh
2017-08-14 11:36 ` [PATCH v2 21/23] OvmfPkg/VirtioNetDxe: dynamically alloc transmit header Brijesh Singh
2017-08-14 11:36 ` [PATCH v2 22/23] OvmfPkg/VirtioNetDxe: map transmit buffer host address to device address Brijesh Singh
2017-08-14 11:36 ` [PATCH v2 23/23] OvmfPkg/Virtio: define VIRITO_F_IOMMU_PLATFORM feature bit Brijesh Singh
2017-08-21 15:40   ` Laszlo Ersek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=26532a70-01fb-ddc8-766a-2a0df672f97b@amd.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox