]>
Commit | Line | Data |
---|---|---|
d2cb6e67 MK |
1 | # **Platform Runtime Mechanism**\r |
2 | \r | |
3 | Platform Runtime Mechanism (PRM) introduces the capability of moving platform-specific code out of SMM and into a\r | |
4 | code module that executes within the OS context. Moving this firmware to the OS context provides better transparency\r | |
5 | and mitigates the negative system impact currently accompanied with SMM solutions. Futhermore, the PRM code is\r | |
6 | packaged into modules with well-defined entry points, each representing a specific PRM functionality.\r | |
7 | \r | |
deea4e58 MK |
8 | For more details on PRM, refer to the [Platform Runtime Mechanism Specification on uefi.org](https://uefi.org/sites/default/files/resources/Platform%20Runtime%20Mechanism%20-%20with%20legal%20notice.pdf).\r |
9 | \r | |
d2cb6e67 MK |
10 | The `PrmPkg` maintained in this branch provides a single cohesive set of generic PRM functionality that is intended\r |
11 | to be leveraged by platform firmware with minimal overhead to integrate PRM functionality in the firmware.\r | |
12 | \r | |
f8e68587 MK |
13 | > By default, the build makes use of a new ACPI OperationRegion type specifically introduced for PRM called\r |
14 | `PlatformRtMechanism`. Support for this OperationRegion is planned for the next release of the ACPI specification.\r | |
15 | However, support for `PlatformRtMechanism` is already included in the iASL Compiler/Disassembler for early prototyping\r | |
16 | (i.e. this package). If you would like the default build to work and/or to use PRM handlers that are invoked\r | |
17 | through ACPI, iASL compiler [20200528](https://acpica.org/node/181) or greater must be used. If you are only\r | |
18 | interested in compiling the code and/or using direct call style PRM handlers, you can simply remove\r | |
19 | `PrmSsdtInstallDxe` from `PrmPkg.dsc`.\r | |
20 | \r | |
f3c11224 MK |
21 | The changes in the ACPI Specification include two elements:\r |
22 | \r | |
23 | 1. `BIT20` in Platform-Wide _OSC Capabilities DWORD2 will be used by an OS to indicate support for PRM\r | |
24 | 2. A new Operation Region Address Space Identifier Value is defined as `0xB` for `PlatformRtMechanism`\r | |
25 | \r | |
d2cb6e67 | 26 | ## How to Build PrmPkg\r |
f3c11224 | 27 | \r |
d2cb6e67 MK |
28 | As noted earlier, resources in `PrmPkg` are intended to be referenced by a platform firmware so it can adopt support\r |
29 | for PRM. In that case, the platform firmware should add the `PrmConfigDxe` and `PrmLoaderDxe` drivers to its DSC and\r | |
30 | FDF files so they are built in the platform firmware build and dispatched during its runtime. All that is left is to\r | |
31 | add individual PRM modules to the DSC and FDF. These can be built from source or included as binaries into the platform\r | |
32 | firmware flash map.\r | |
33 | \r | |
34 | ### PrmPkg Standalone Build\r | |
d2cb6e67 MK |
35 | \r |
36 | To build `PrmPkg` as a standalone package:\r | |
f3c11224 | 37 | \r |
d2cb6e67 MK |
38 | 1. If new to EDK II, follow the directions in [Getting Started with EDK II](https://github.com/tianocore/tianocore.github.io/wiki/Getting-Started-with-EDK-II)\r |
39 | \r | |
40 | 2. Clone the *master* branch on the edk2 repository locally \\r | |
41 | ``git clone https://github.com/tianocore/edk2.git``\r | |
42 | \r | |
f3c11224 | 43 | 3. Change to the edk2 workspace directory \\r |
d2cb6e67 MK |
44 | ``cd edk2``\r |
45 | \r | |
f3c11224 | 46 | 4. Run *edksetup* to set local environment variables needed for build\r |
d2cb6e67 MK |
47 | * Windows:\r |
48 | * ``edksetup.bat``\r | |
49 | * Linux:\r | |
50 | * If you have not already built BaseTools:\r | |
51 | * ``make -C BaseTools``\r | |
52 | * ``. edksetup.sh``\r | |
53 | \r | |
f3c11224 | 54 | 5. Build PrmPkg \\r |
d2cb6e67 | 55 | ``build -p PrmPkg/PrmPkg.dsc -a IA32 -a X64``\r |
f3c11224 MK |
56 | > ***Note***: Due to the way PRM modules are compiled with exports, **only building on Visual Studio compiler tool\r |
57 | chains has been tested**.\r | |
d2cb6e67 | 58 | \r |
f3c11224 | 59 | > ***Note***: \\r |
f8e68587 MK |
60 | > This package has been used without modification in several environments including client, server,\r |
61 | > and virtual systems.\r | |
62 | >\r | |
f8e68587 MK |
63 | > You can add your own PRM modules into the build and check them with the `PrmInfo` UEFI application described\r |
64 | > later in this document and dump the PRMT table in the OS to check if your PRM module is represented as expected.\r | |
65 | \r | |
c040831c | 66 | ### PRM Platform GUID\r |
c040831c | 67 | \r |
f3c11224 MK |
68 | **IMPORTANT** PRM has a concept of a "Platform GUID" which associates a specific platform with a set of PRM modules\r |
69 | built for that platform. This GUID is used to ensure system compatibility for a given collection of PRM modules.\r | |
4a4aeaa4 MK |
70 | \r |
71 | Therefore, each PRM module must only target a single platform and each platform must have a unique GUID. Even if a\r | |
72 | PRM module is unchanged between two different platforms now, there is no guarantee that will remain the case so always\r | |
73 | assign a unique Platform GUID for each platform.\r | |
c040831c | 74 | \r |
4a4aeaa4 MK |
75 | The PRM Platform GUID is primarily used during PRM module runtime updates in the OS to ensure that the Platform GUID\r |
76 | in the system's ACPI table (PRMT) matches the Platform GUID of the module requested for update. Even if runtime\r | |
77 | updates are not a planned feature for a given platform, still assign a unique Platform GUID for binary module\r | |
78 | identification (the Platform GUID is in the module's export descriptor) and to ensure such updates can be seamlessly\r | |
79 | supported in the future if needed.\r | |
c040831c | 80 | \r |
4a4aeaa4 MK |
81 | In the `PrmPkg` implementation, the Platform GUID is automatically derived from the PLATFORM_GUID in the DSC file of\r |
82 | the package being built.\r | |
c040831c | 83 | \r |
f3c11224 MK |
84 | ### Build Output\r |
85 | \r | |
86 | Like a typical EDK II package, the PrmPkg binary build output can be found in the Build directory in the edk2\r | |
87 | workspace. The organization in that directory follows the same layout as other EDK II packages.\r | |
88 | \r | |
89 | For example, that path to PRM module sample binaries for a DEBUG VS2017 X64 build is: \\r | |
90 | ``edk2/Build/Prm/DEBUG_VS2017/X64/PrmPkg/Samples``\r | |
91 | \r | |
d2cb6e67 | 92 | ## Overview\r |
f3c11224 | 93 | \r |
d2cb6e67 MK |
94 | At a high-level, PRM can be viewed from three levels of granularity:\r |
95 | \r | |
f3c11224 | 96 | 1. `PRM interface` - Encompassing the entirety of firmware functionalities and data provided to OS runtime. Most\r |
d2cb6e67 | 97 | information is provided through ACPI tables to be agnostic to a UEFI implementation.\r |
f3c11224 | 98 | 2. `PRM module` - An independently updatable package of PRM handlers. The PRM interface will be composed of multiple\r |
d2cb6e67 MK |
99 | PRM modules. This requirement allows for the separation of OEM and IHV PRM code, each of which can be serviced\r |
100 | independently.\r | |
f3c11224 | 101 | 3. `PRM handler` - The implementation/callback of a single PRM functionality as identified by a GUID.\r |
d2cb6e67 MK |
102 | \r |
103 | ## Firmware Design\r | |
f3c11224 | 104 | \r |
d2cb6e67 MK |
105 | The firmware has three key generic drivers to support PRM:\r |
106 | \r | |
f3c11224 | 107 | 1. A `PRM Loader driver` - Functionality is split across three phases:\r |
d2cb6e67 MK |
108 | 1. Discover - Find all PRM modules in the firmware image made available by the platform firmware author.\r |
109 | * This phase includes verifying authenticity/integrity of the image, the image executable type, the export\r | |
110 | table is present and the PRM Export Module Descriptor is present and valid.\r | |
111 | 2. Process - Convert PRM handler GUID to name mappings in the PRM Module Export Descriptor to PRM handler Name\r | |
112 | to physical address mappings required to construct the PRM ACPI table.\r | |
113 | 3. Publish - Publish the PRM ACPI table using the information from the Process phase.\r | |
114 | \r | |
f3c11224 | 115 | 2. A `PRM Configuration driver` - A generic driver responsible for processing PRM module configuration information\r |
d2cb6e67 MK |
116 | consumed through a `PRM_CONFIG_PROTOCOL` per PRM module instance. Therefore, the `PRM_CONFIG_PROTOCOL` serves\r |
117 | as the dynamic interface for this driver to process PRM module resources and prepare the module's data to be\r | |
118 | configured properly for OS runtime.\r | |
119 | \r | |
f3c11224 | 120 | 3. A `PRM Module` - Not a single driver but a user written PE/COFF image that follows the PRM module authoring process.\r |
d2cb6e67 MK |
121 | A PRM module groups together cohesive sets of PRM functionality into functions referred to as "PRM handlers".\r |
122 | \r | |
123 | ## PrmPkg Code Organization\r | |
f3c11224 | 124 | \r |
d2cb6e67 MK |
125 | The package follows a standard EDK II style package format. The list below contains some notable areas to\r |
126 | explore in the package:\r | |
127 | \r | |
128 | * [ACPI Table Definitions](PrmPkg/PrmLoaderDxe/PrmAcpiTable.h)\r | |
129 | * [Common Interface Definitions](PrmPkg/Include)\r | |
130 | * [PRM Config Driver](PrmPkg/PrmConfigDxe)\r | |
131 | * [PRM Loader Driver](PrmPkg/PrmLoaderDxe)\r | |
132 | * [Sample PRM Modules](PrmPkg/Samples)\r | |
133 | \r | |
134 | While the package does provide sample PRM modules to be used as a reference, actual PRM modules should not be\r | |
135 | maintained in PrmPkg. It is intended to only contain PRM infrastructure code and a few samples of how to use\r | |
136 | that infrastructure. The PrmPkg is meant to be used as-is by firmware that supports PRM. Any shortcomings that\r | |
137 | prevent the package from being used as-is should be addressed directly in PrmPkg.\r | |
138 | \r | |
4348c72a | 139 | ## PRM Information UEFI Application\r |
f3c11224 MK |
140 | \r |
141 | A UEFI application is provided in this package called `PrmInfo` that allows a user to display and test PRM\r | |
4348c72a MK |
142 | modules on their system.\r |
143 | \r | |
144 | [Link to application source code](PrmPkg/Application/PrmInfo).\r | |
145 | \r | |
146 | This application is intended to be helpful during PRM enabling by allowing the user to:\r | |
f3c11224 | 147 | \r |
4348c72a MK |
148 | 1. Confirm that their firmware port of the PRM infrastructure implemented in this package is functioning correctly.\r |
149 | 2. Quickly get information about what PRM modules and handlers that are present on a given system.\r | |
150 | 3. Quickly test PRM handlers without booting into a full operating system.\r | |
151 | 4. Develop and exercise PRM handlers prior to the availability of an operating system that is PRM aware.\r | |
152 | \r | |
153 | Execute the application help command for detailed usage instructions and examples of how to use the application: \\r | |
154 | ``PrmInfo -?``\r | |
155 | \r | |
156 | *Example Usage:*\r | |
157 | \r | |
f3c11224 | 158 | ![PrmInfo Usage Example](https://raw.githubusercontent.com/tianocore/edk2-staging/PlatformRuntimeMechanism/PrmPkg/Application/PrmInfo/PrmInfo_Usage_Example.gif)\r |
4348c72a | 159 | \r |
d2cb6e67 MK |
160 | ## PRM Module\r |
161 | \r | |
f3c11224 | 162 | > ***Note***: You can find simple examples of PRM modules in the Samples directory of this package.\r |
d10b8dc5 MK |
163 | > [Samples/Readme.md](PrmPkg/Samples/Readme.md) has more information.\r |
164 | \r | |
d2cb6e67 | 165 | By default, the EDK II implementation of UEFI does not allow images with the subsystem type\r |
f3c11224 | 166 | `IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER` to be built with exports.\r |
d2cb6e67 | 167 | \r |
f3c11224 | 168 | ```txt\r |
d2cb6e67 MK |
169 | ERROR - Linker #1294 from LINK : fatal exports and import libraries are not supported with /SUBSYSTEM:EFI_RUNTIME_DRIVER\r |
170 | ```\r | |
f3c11224 | 171 | \r |
d2cb6e67 MK |
172 | This can adjusted in the MSVC linker options.\r |
173 | \r | |
f3c11224 MK |
174 | The subsystem type is changed in the firmware build to allow the export table to be added but the subsystem type in the\r |
175 | final image is still `0xC` (`EFI Runtime Driver`). This is important to allow the DXE dispatcher to use its standard\r | |
176 | image verification and loading algorithms to load the image into permanent memory during the DXE execution phase.\r | |
d2cb6e67 | 177 | \r |
f3c11224 | 178 | All firmware-loaded PRM modules are loaded into a memory buffer of type `EfiRuntimeServicesCode`. This means the\r |
d2cb6e67 MK |
179 | operating system must preserve all PRM handler code and the buffer will be reflected in the UEFI memory map. The\r |
180 | execution for invoking PRM handlers is the same as that required for UEFI Runtime Services, notably 4KiB or more of\r | |
f3c11224 | 181 | available stack space must be provided and the stack must be 16-byte aligned.\r |
d2cb6e67 | 182 | \r |
f3c11224 | 183 | ***Note:*** Long term it is possible to similarly load the modules into a `EfiRuntimeServicesCode` buffer and perform\r |
d2cb6e67 MK |
184 | relocation fixups with a new EFI module type for PRM if desired. It was simply not done since it is not essential\r |
185 | for this POC.\r | |
186 | \r | |
187 | Where possible, PRM module information is stored and generated using industry compiler tool chains. This is a key\r | |
188 | motivation behind using PE/COFF export tables to expose PRM module information and using a single PRM module binary\r | |
189 | definition consistent between firmware and OS load.\r | |
190 | \r | |
191 | ### PRM Module Exports\r | |
f3c11224 | 192 | \r |
a409f4b6 MK |
193 | A PRM module must contain at least two exports: A PRM Module Export Descriptor and at least one PRM handler. Here's\r |
194 | an example of an export table from a PRM module that has a single PRM handler:\r | |
d2cb6e67 | 195 | \r |
f3c11224 | 196 | ```txt\r |
a409f4b6 MK |
197 | 0000000000005000: 00 00 00 00 FF FF FF FF 00 00 00 00 3C 50 00 00 ............<P..\r |
198 | 0000000000005010: 01 00 00 00 02 00 00 00 02 00 00 00 28 50 00 00 ............(P..\r | |
199 | 0000000000005020: 30 50 00 00 38 50 00 00 78 13 00 00 20 40 00 00 0P..8P..x... @..\r | |
200 | 0000000000005030: 5D 50 00 00 7C 50 00 00 00 00 01 00 50 72 6D 53 ]P..|P......PrmS\r | |
201 | 0000000000005040: 61 6D 70 6C 65 43 6F 6E 74 65 78 74 42 75 66 66 ampleContextBuff\r | |
202 | 0000000000005050: 65 72 4D 6F 64 75 6C 65 2E 64 6C 6C 00 44 75 6D erModule.dll.Dum\r | |
203 | 0000000000005060: 70 53 74 61 74 69 63 44 61 74 61 42 75 66 66 65 pStaticDataBuffe\r | |
204 | 0000000000005070: 72 50 72 6D 48 61 6E 64 6C 65 72 00 50 72 6D 4D rPrmHandler.PrmM\r | |
205 | 0000000000005080: 6F 64 75 6C 65 45 78 70 6F 72 74 44 65 73 63 72 oduleExportDescr\r | |
206 | 0000000000005090: 69 70 74 6F 72 00 iptor.\r | |
d2cb6e67 MK |
207 | \r |
208 | 00000000 characteristics\r | |
209 | FFFFFFFF time date stamp\r | |
a409f4b6 | 210 | 0.00 version\r |
d2cb6e67 | 211 | 1 ordinal base\r |
a409f4b6 MK |
212 | 2 number of functions\r |
213 | 2 number of names\r | |
d2cb6e67 MK |
214 | \r |
215 | ordinal hint RVA name\r | |
a409f4b6 | 216 | \r |
d2cb6e67 | 217 | 1 0 00001378 DumpStaticDataBufferPrmHandler\r |
a409f4b6 MK |
218 | 2 1 00004020 PrmModuleExportDescriptor\r |
219 | \r | |
d2cb6e67 | 220 | ```\r |
f3c11224 | 221 | \r |
d2cb6e67 | 222 | ### PRM Image Format\r |
f3c11224 | 223 | \r |
d2cb6e67 MK |
224 | PRM modules are ultimately PE/COFF images. However, when packaged in firmware the PE/COFF image is placed into a\r |
225 | Firmware File System (FFS) file. This is transparent to the operating system but done to better align with the typical\r | |
226 | packaging of PE32(+) images managed in the firmware binary image. In the dump of the PRM FV binary image shown earlier,\r | |
227 | the FFS sections placed by EDK II build tools ("DXE dependency", "User interface", "Version") that reside alongside the\r | |
228 | PE/COFF binary are shown. A PRM module can be placed into a firmware image as a pre-built PE/COFF binary or built\r | |
229 | during the firmware build process. In either case, the PE/COFF section is contained in a FFS file as shown in that\r | |
230 | image.\r | |
231 | \r | |
232 | ### PRM Module Implementation\r | |
f3c11224 | 233 | \r |
d2cb6e67 MK |
234 | To simplify building the PRM Module Export Descriptor, a PRM module implementation can use the following macros to mark\r |
235 | functions as PRM handlers. In this example, a PRM module registers three functions by name as PRM handlers with the\r | |
236 | associated GUIDs.\r | |
237 | \r | |
f3c11224 | 238 | ```c\r |
d2cb6e67 MK |
239 | //\r |
240 | // Register the PRM export information for this PRM Module\r | |
241 | //\r | |
242 | PRM_MODULE_EXPORT (\r | |
243 | PRM_HANDLER_EXPORT_ENTRY (PRM_HANDLER_1_GUID, PrmHandler1),\r | |
244 | PRM_HANDLER_EXPORT_ENTRY (PRM_HANDLER_2_GUID, PrmHandler2),\r | |
245 | PRM_HANDLER_EXPORT_ENTRY (PRM_HANDLER_N_GUID, PrmHandlerN)\r | |
246 | );\r | |
247 | ```\r | |
248 | \r | |
249 | `PRM_MODULE_EXPORT` take a variable-length argument list of `PRM_HANDLER_EXPORT_ENTRY` entries that each describe an\r | |
250 | individual PRM handler being exported for the module. Ultimately, this information is used to define the structure\r | |
251 | necessary to statically allocate the PRM Module Export Descriptor Structure (and its PRM Handler Export Descriptor\r | |
252 | substructures) in the image.\r | |
253 | \r | |
254 | Another required export for PRM modules is automatically provided in `PrmModule.h`, a header file that pulls together\r | |
255 | all the includes needed to author a PRM module. This export is `PRM_MODULE_UPDATE_LOCK_EXPORT`. By including,\r | |
256 | `PrmModule.h`, a PRM module has the `PRM_MODULE_UPDATE_LOCK_DESCRIPTOR` automatically exported.\r | |
257 | \r | |
258 | ## PRM Handler Constraints\r | |
f3c11224 | 259 | \r |
d2cb6e67 MK |
260 | At this time, PRM handlers are restricted to a maximum identifier length of 128 characters. This is checked when using\r |
261 | the `PRM_HANDLER_EXPORT` macro by using a static assert that reports a violation at build-time.\r | |
262 | \r | |
263 | PRM handlers are **not** allowed to use UEFI Runtime Services and should not rely upon any UEFI constructs. For the\r | |
264 | purposes of this POC, this is currently not explicitly enforced but should be in the final changes.\r |