-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
MdeModulePkg/DxeCore: Call BeforeExitBootServices event group only once #6481
Conversation
cc @deeglaze |
LGTM, thanks Ard. Happy thanksgiving. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A related topic I have been discussing and impemented in other environments is disallowing alloc/free during BeforeEBS and EBS handlers. For anything non-runtime memory, that memory is about to be forfeit anyway to the OS, for runtime types it is suspicious that it is being allocated or freed during EBS. Any alloc/free will change the memory map of course and fail EBS, but depending on what happens, it can be a persistent failure. We have a recent case where a platform had frees during an EBS handler and Linux couldn’t boot afterwards because grub only allocates 8 extra memory map entries for possible changes across EBS (Windows allocates double the memory map entry count). The memory map changed by more than 8 entries and thus Linux could never boot. So we’ve taken the approach that allocs should be explicitly rejected during EBS and frees should silently fail (i.e. just return success) unless they are a runtime type, then an assert and explicit failure seems worthwhile to amend those drivers. Anyway, this is just a thought related to this PR, I don’t think this PR needs to change as a result, but it could come later as a stronger statement towards not changing the memory map during EBS, because even with this we can still fail to boot an OS based on memory map changes during EBS.
This suggestion would break the use case that led me to add this event group signaling support for in the first place: accepting unaccepted memory if the OS doesn’t use a certain protocol to indicate that it supports the new kind of memory map entry. |
Is there a public example of that? In this case, os the unaccepted memory allocated or just changed type? |
Indeed. Alloc/free are already disallowed during EFI_EVENT_GROUP_EXIT_BOOT_SERVICES, and I guess we could police that by failing any calls to the memory services when |
https://github.com/tianocore/edk2/blob/master/OvmfPkg/AmdSevDxe/AmdSevDxe.c I don’t think it’s possible to simply change type without removing and adding, which can allocate memory IIRC |
Well, that last part being the problem :). Grub only allocating 8 extra entries can be tight. Grub should probably be updated to allocate more, but then you also run into the problem of distros carrying 6+ years old shim/grub and not updating. I do agree this patchmakes the prospect a lot better. I think this reduces the number of failures for Windows to almost none. |
GRUB has no business calling ExitBootServices() on a modern system - that should be left up to the EFI stub in Linux (or whatever OS and loader is in use). If Linux is problematic in the same way, we should fix it.
To be honest, I wasn't aware that EFI_EVENT_GROUP_BEFORE_EXIT_BOOT_SERVICES is that widely used. But I ended up looking into this because Lenovo Snapdragon laptops (which are built to boot Windows but being repurposed for Linux) are experiencing persistent failures of ExitBootServices(), and it seems like these callbacks may be the culprit (although I fail to understand why only Linux would be affected by this) |
This may be my misremembering the bug report, so it may be the Linux EFI stub and not grub that only allocates 8 extra entries. This is for a modern Linux distro. That may factor into what you are seeing. I cannot update Linux or look at the source code, due to some restrictions for other projects I am working on. Like I said, we are seeing persistent failures for ExitBootServices for Linux and not Windows, because of Linux only allocating 8 extra entries and failing if the memory map changes more than that. I would encourage you to follow up on the Linux side and confirm what our Linux team reported to me. Definitely it is also an issue that drivers don’t close their BeforeEBS callbacks and so get called more than once, your current patch obviously fixes that. |
Indeed - it's the Linux EFI stub that allocates spare entries. But re-reading the spec, it seems that it is permitted to free the memory map and re-allocate it using boot services, rather than bend over backwards to avoid updating the memory map. |
@lgao4 any thoughts? |
Is there any info from UEFI Spec on the required behavior here? |
Yes. As Oliver pointed out, UEFI spec 2.10 errata A section 7.4.6 |
I did not see that specific spec reference in the PR or the commit message. That should be the main reason for this change. I recommend updating the PR description and commit message with that specific spec reference and that the reason for the change is to follow the spec. |
3fb479e
to
a5bccb6
Compare
According to UEFI spec 2.10 errata A section 7.4.6 "All events from the EFI_EVENT_GROUP_BEFORE_EXIT_BOOT_SERVICES and EFI_EVENT_GROUP_EXIT_BOOT_SERVICES event notification groups as well as events of type EVT_SIGNAL_EXIT_BOOT_SERVICES must be signaled before ExitBootServices() returns EFI_SUCCESS. The events are only signaled once even if ExitBootServices() is called multiple times." So keep track of whether ExitBootServices() has been called, and signal the event group EFI_EVENT_GROUP_BEFORE_EXIT_BOOT_SERVICES only the first time around. EFI_EVENT_GROUP_EXIT_BOOT_SERVICES will only be signalled if ExitBootServices() is going to run to [successful] completion, after which calling it a second time is not possible anyway. So for this case, no special handling is needed. Signed-off-by: Ard Biesheuvel <[email protected]>
a5bccb6
to
e27dfbe
Compare
Done |
According to UEFI spec 2.10 errata A section 7.4.6
"All events from the EFI_EVENT_GROUP_BEFORE_EXIT_BOOT_SERVICES and
EFI_EVENT_GROUP_EXIT_BOOT_SERVICES event notification groups as well
as events of type EVT_SIGNAL_EXIT_BOOT_SERVICES must be signaled
before ExitBootServices() returns EFI_SUCCESS. The events are only
signaled once even if ExitBootServices() is called multiple times."
So keep track of whether ExitBootServices() has been called, and signal
the event group EFI_EVENT_GROUP_BEFORE_EXIT_BOOT_SERVICES only the first
time around.
EFI_EVENT_GROUP_EXIT_BOOT_SERVICES will only be signalled if
ExitBootServices() is going to run to [successful] completion, after
which calling it a second time is not possible anyway. So for this case,
no special handling is needed.