-
Notifications
You must be signed in to change notification settings - Fork 39
RFC: Runtime Service Module Support #877
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,161 @@ | ||||||
| # RFC: Runtime Services Support | ||||||
|
|
||||||
| This RFC proposes a roadmap for Runtime Services and runtime module support for the | ||||||
| Patina project. Runtime modules and services must exist in separate memory regions | ||||||
| from the monolithic Patina core and so present problems for using the existing core | ||||||
| and infrastructure to support. This RFC proposes that a new runtime module be spun | ||||||
| up from the existing Rust code and to defer other future support. This RFC leaves open | ||||||
| the possibility that this module be extended in the future. | ||||||
|
|
||||||
| ## Change Log | ||||||
|
|
||||||
| - 10-14-25: Initial RFC created. | ||||||
|
|
||||||
| ## Motivation | ||||||
|
|
||||||
| Runtime services present a unique challenge for the monolithic binary model that | ||||||
| Patina uses. Runtime services must exist after boot services have been unloaded, | ||||||
| and so it is not possible for the runtime services to exist as part of the | ||||||
| monolithic binary, at least without very specialized handling. Runtime services | ||||||
| must have a focused roadmap to align with the goals and development models of | ||||||
| Patina to be clear about expected investments. | ||||||
|
|
||||||
| ## Technology Background | ||||||
|
|
||||||
| Currently the EDKII implementation dispatches runtime modules as part of DXE phase, | ||||||
| most notably RuntimeDxe which provides core services such as `SetVirtualAddressMap` | ||||||
| and other modules to implement more platform specific runtime services. The original | ||||||
| implementation on Patina provided an implementation of `SetVirtualAddressMap` within | ||||||
| the monolithic core, but this results in some problems on Windows boot as we will | ||||||
| leverage boot services memory in `SetVirtualAddressMap` which is a runtime service | ||||||
| and executes after ExitBootServices. Generally, this makes assumptions about OS | ||||||
| behavior which may not be sustainable. These were resolved in the following PRs. | ||||||
|
|
||||||
| - [dxe_core: Move runtime event handling into runtime module](https://github.com/OpenDevicePartnership/patina/pull/738) | ||||||
| - [patina_dxe_core: Switch to use external RuntimeDxe implementation](https://github.com/OpenDevicePartnership/patina/pull/769) | ||||||
|
|
||||||
| The approach that has been taken in the interim is to remove the Patina | ||||||
| implementation for now and to ask platforms to go back to the EDKII RuntimeDxe. | ||||||
|
|
||||||
| ## Goals | ||||||
|
|
||||||
| 1. Set short term support plan for runtime services/modules. | ||||||
| 2. Enumerate expansion plans for runtime services in the future. | ||||||
|
|
||||||
| ## Requirements | ||||||
|
|
||||||
| 1. Runtime services must continue to operate as expected for short term. | ||||||
| 2. Runtime modules must exist purely in runtime service memory. | ||||||
| 3. Long term goals should remove dependence on EDKII runtime code. | ||||||
|
|
||||||
| ## Unresolved Questions | ||||||
|
|
||||||
| - Is there a suitable type of dynamic linking that may make other options suitable | ||||||
| without excessive one-off infrastructure? | ||||||
|
|
||||||
| ## Prior Art (Existing PI C Implementation) | ||||||
|
|
||||||
| The current C implementation consists of one primary runtime module, usually | ||||||
| RuntimeDxe and a variable amount of additional runtime modules. These modules are | ||||||
| dispatched by DXE, but will be loaded in runtime memory. The primary runtime module | ||||||
| should produce the runtime architecture protocol, defined in the PI spec section | ||||||
| 12.8. This protocol allows for the core to fill in critical information for the | ||||||
| runtime module to implement SetVirtualAddressMap. This includes the image list of | ||||||
| runtime modules, events registered for virtualizing memory, and memory map | ||||||
| information that is not currently used. When `SetVirtualAddressMap` is called, the | ||||||
| runtime DXE module will use the information from the protocol it published and the | ||||||
| core filled to re-relocate the images, virtualizing their execution, and call all | ||||||
| events registered to allow drivers/libraries to virtualize any stored pointers. | ||||||
|
|
||||||
| ## Alternatives | ||||||
|
|
||||||
| ### Create new interface for runtime architectural information | ||||||
|
|
||||||
| Instead of using runtime architectural protocol for the chosen driver model, a new | ||||||
| protocol or interface could be invented that would allow safer parsing. For example, | ||||||
| for the event and image lists, these could be instead maintained in a vector and | ||||||
| the slices provided through a protocol. This would prevent the need for unsafe logic | ||||||
| in walking a raw pointer based linked list. However, this would be creating a new | ||||||
| set of rust-to-rust interfaces that do not exist within the monolithically compiled | ||||||
| binaries. This both complicates the interoperability story with existing code, and | ||||||
| will only be applicable to this one off scenario for the time being. | ||||||
|
|
||||||
| ### Dynamic Module Linking | ||||||
|
|
||||||
| An alternative to leveraging the protocol communication would be to allow dynamic | ||||||
| linking and direct invocation of the runtime module. This would prevent the need | ||||||
| for secondary structures and callbacks. However, this raises many questions and | ||||||
| potential toolchain problems such as support between GCC and MSVC tool chains for | ||||||
| dynamic linking. This would also invent additional infrastructure needed only for | ||||||
| runtime services. | ||||||
|
|
||||||
| ### Runtime Service Removal | ||||||
|
|
||||||
| The long term goal of runtime services, instead of replacing them, should be to | ||||||
| remove them. Most runtime services are superfluous on modern machines. The only | ||||||
| runtime service that is typically invoked at runtime that cannot be replaced with | ||||||
| other existing mechanisms is variable services. Even so, variable services are nearly | ||||||
| always a simple wrapper around calls to the implementation executing in either SMM | ||||||
| or TrustZone. An alternative to re-implementing runtime services for Patina, would | ||||||
| be to simply not support runtime services at runtime, but instead provide a | ||||||
| specification defined interface to access variable services directly through SMM | ||||||
| and TrustZone. | ||||||
|
|
||||||
| However, this is not feasible in the short term. Any solution here would require | ||||||
| updates both to the UEFI specifications to support them as well as specification | ||||||
| of the new SMM/TrustZone interfaces, not to mention OS support. While removal of | ||||||
| runtime services is a desirable long term goal it does not satisfy the immediate | ||||||
| goals of this RFC. | ||||||
cfernald marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
|
||||||
| ### Defer Runtime Module Support | ||||||
|
|
||||||
| Another solution is to defer implementation of any Rust runtime module until DXE | ||||||
| and MM are solved and a more clear interfacing model appears, and continue to use | ||||||
| the EDKII implementation of RuntimeDxe in the interim. The EDKII implementation | ||||||
| would either be replaced by a more robust implementation of a Patina runtime or | ||||||
| removed in the future if runtime services are no longer required in the future. | ||||||
| However, as explained above a more robust solution in this space is filled with | ||||||
| complications and is unlikely to occur in the near future. Additionally, runtime | ||||||
| service removal will be a long process of standardization and OS support. Deferring | ||||||
| until a more complete solution may not be feasible. | ||||||
|
|
||||||
| ## Rust Code Design | ||||||
|
|
||||||
| Patina should continue to use separate runtime modules which interface using the | ||||||
| UEFI and PI defined interfaces. This includes the system architectural protocol for | ||||||
| resources from the core as well as boot services for allocations and other DXE | ||||||
| phase calls. | ||||||
|
|
||||||
| However, as a stepping stone to replacement RuntimeDxe should be implementation of a | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| Rust driver leveraging the original code removed in the above PRs. This driver would | ||||||
| be implemented in the Rust driver infrastructure developed for EDKII and located in | ||||||
| the PatinaPkg. This module would use all existing UEFI/PI interfaces to access boot | ||||||
| services and communicate runtime image and event data. The responsibilities of each | ||||||
| module in this model are detailed below. | ||||||
|
|
||||||
| ### Patina DXE Core | ||||||
|
|
||||||
| The Patina DXE core will continue to listen for the registration of the runtime | ||||||
| architectural protocol, and register event and image data to the protocol. This | ||||||
| will be updated whenever a new runtime image is loaded or a new `SetVirtualAddressMap` | ||||||
| callback is registered. | ||||||
|
|
||||||
| ### Patina Runtime (new) | ||||||
|
|
||||||
| A new module compiled as a Rust driver in an EDKII environment, provides a | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know this has been discussed, but from my point of view, I'm not sure how much value this adds. I know we have the Rust code that was originally part of Patina that could be used, but, as evidenced it already had design issues and would have to be refactored into an EDKII Rust driver, which is a model we have decided has major drawbacks. From my point of view, I would just keep to using EDKII's RuntimeDxe until we have a comprehensive solution in Patina, whether it is the dynamic linking approach or removal approach. But I worry that we promote a model we don't want to promote and that we open ourselves up for bugs in a place where we want to remove support entirely. As we've noted, Rust in a single driver may only add minimal improvement (particularly a heavily protocol reliant driver such as this) and it adds risk by introducing a new implementation. My two cents would be to not incur this risk for RuntimeDxe, it doesn't feel like a valuable investment of resources. Certainly open to other opinions.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I've also been having this internal debate. There are a few benefits of using a rust runtime DXE.
That being said, it is an investment and whether those benefits are worth the cost is debatable. @makubacki should weigh in on this as well.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The other issue is torn state with Patina DXE Core. The Patina DXE Core produces Boot Services which includes struct _EFI_RUNTIME_ARCH_PROTOCOL {
EFI_LIST_ENTRY ImageHead; ///< A list of type EFI_RUNTIME_IMAGE_ENTRY.
EFI_LIST_ENTRY EventHead; ///< A list of type EFI_RUNTIME_EVENT_ENTRY.
UINTN MemoryDescriptorSize; ///< Size of a memory descriptor that is returned by GetMemoryMap().
UINT32 MemoryDesciptorVersion; ///< Version of a memory descriptor that is returned by GetMemoryMap().
UINTN MemoryMapSize; ///< Size of the memory map in bytes contained in MemoryMapPhysical and MemoryMapVirtual.
EFI_MEMORY_DESCRIPTOR *MemoryMapPhysical; ///< Pointer to a runtime buffer that contains a copy of
///< the memory map returned via GetMemoryMap().
EFI_MEMORY_DESCRIPTOR *MemoryMapVirtual; ///< Pointer to MemoryMapPhysical that is updated to virtual mode after SetVirtualAddressMap().
BOOLEAN VirtualMode; ///< Boolean that is TRUE if SetVirtualAddressMap() has been called.
BOOLEAN AtRuntime; ///< Boolean that is TRUE if ExitBootServices () has been called.
};Now, we have an interface produced in
Regardless of That said, the runtime services logic is relatively minimal and I'd prefer to be written in a memory safe lanuage with full unit test coverage, the ability for integration level testing, and using the same underlying dependencies used by the Patina DXE Core for consistency. We don't have a universal rule that separate .efi binaries are bad (at least while co-existing in today's PI platforms). When code can be built as a single binary and we can better leverage static safety mechanisms, we should do so, but I don't see it as extending beyond that. We simply can't do so here, right now. So, I don't see it in opposition to our stance for a single monolithic DXE Core binary, it's just the rationale doesn't apply here. Just like we'll need to build a separate monolithic MM Core binary becuse it doesn't apply there either. All that said, for practical reasons, most people are going to use the well-known
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For what it's worth, we aren't actually filling any of the memory map fields today as they are not actually used. The only information we are providing is the image and event lists. Overall, I agree that switching to a rust implementation of RuntimeDxe seems reasonable, and I think its fine to put as the point of record with this RFC, though I'm not concerned with this being accomplished in any immediate timeframe and the cost/reward seems limited. |
||||||
| compatible implementation as RuntimeDxe to implement core functions, i.e. | ||||||
| `SetVirtualAddressMap` & `ConvertPointer`. This driver will install the runtime | ||||||
| architectural protocol. On `SetVirtualAddressMap` the module will be responsible for | ||||||
| re-relocating images and invoking all appropriate events filled in the | ||||||
| architectural protocol. | ||||||
|
|
||||||
| ### Refactoring Relocation Logic (optional) | ||||||
|
|
||||||
| The logic necessary to relocate the PE is currently split across multiple modules | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| in patina_dxe_core. To reduce code duplication, it may be desirable to refactor the | ||||||
| PE loader logic into a standalone crate, e.g. `patina_loader`. Without this, | ||||||
| relocation and PE parsing logic may need to be duplicated. | ||||||
|
|
||||||
| ## Guide-Level Explanation | ||||||
|
|
||||||
| Does not change any consumable rust APIs. | ||||||
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.
I may have missed it, but what is the current proposed solution versus listing of alternatives?
Uh oh!
There was an error while loading. Please reload this page.
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.
I'll make the plan more clear in the summary