2 Locate, get and update PE/COFF permissions during Standalone MM
3 Foundation Entry point on ARM platforms.
5 Copyright (c) 2017 - 2021, Arm Ltd. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
14 #include <Guid/MmramMemoryReserve.h>
15 #include <Guid/MpInformation.h>
17 #include <Library/AArch64/StandaloneMmCoreEntryPoint.h>
18 #include <Library/ArmMmuLib.h>
19 #include <Library/ArmSvcLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/HobLib.h>
22 #include <Library/BaseLib.h>
23 #include <Library/BaseMemoryLib.h>
24 #include <Library/SerialPortLib.h>
26 #include <IndustryStandard/ArmStdSmc.h>
29 Privileged firmware assigns RO & Executable attributes to all memory occupied
30 by the Boot Firmware Volume. This function sets the correct permissions of
31 sections in the Standalone MM Core module to be able to access RO and RW data
32 and make further progress in the boot process.
34 @param [in] ImageContext Pointer to PE/COFF image context
35 @param [in] ImageBase Base of image in memory
36 @param [in] SectionHeaderOffset Offset of PE/COFF image section header
37 @param [in] NumberOfSections Number of Sections
38 @param [in] TextUpdater Function to change code permissions
39 @param [in] ReadOnlyUpdater Function to change RO permissions
40 @param [in] ReadWriteUpdater Function to change RW permissions
45 UpdateMmFoundationPeCoffPermissions (
46 IN CONST PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
47 IN EFI_PHYSICAL_ADDRESS ImageBase
,
48 IN UINT32 SectionHeaderOffset
,
49 IN CONST UINT16 NumberOfSections
,
50 IN REGION_PERMISSION_UPDATE_FUNC TextUpdater
,
51 IN REGION_PERMISSION_UPDATE_FUNC ReadOnlyUpdater
,
52 IN REGION_PERMISSION_UPDATE_FUNC ReadWriteUpdater
55 EFI_IMAGE_SECTION_HEADER SectionHeader
;
57 EFI_PHYSICAL_ADDRESS Base
;
62 ASSERT (ImageContext
!= NULL
);
65 // Iterate over the sections
67 for (Index
= 0; Index
< NumberOfSections
; Index
++) {
69 // Read section header from file
71 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
73 Status
= ImageContext
->ImageRead (
80 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
82 "%a: ImageContext->ImageRead () failed (Status = %r)\n",
83 __FUNCTION__
, Status
));
88 "%a: Section %d of image at 0x%lx has 0x%x permissions\n",
89 __FUNCTION__
, Index
, ImageContext
->ImageAddress
, SectionHeader
.Characteristics
));
91 "%a: Section %d of image at 0x%lx has %a name\n",
92 __FUNCTION__
, Index
, ImageContext
->ImageAddress
, SectionHeader
.Name
));
94 "%a: Section %d of image at 0x%lx has 0x%x address\n",
95 __FUNCTION__
, Index
, ImageContext
->ImageAddress
,
96 ImageContext
->ImageAddress
+ SectionHeader
.VirtualAddress
));
98 "%a: Section %d of image at 0x%lx has 0x%x data\n",
99 __FUNCTION__
, Index
, ImageContext
->ImageAddress
, SectionHeader
.PointerToRawData
));
102 // If the section is marked as XN then remove the X attribute. Furthermore,
103 // if it is a writeable section then mark it appropriately as well.
105 if ((SectionHeader
.Characteristics
& EFI_IMAGE_SCN_MEM_EXECUTE
) == 0) {
106 Base
= ImageBase
+ SectionHeader
.VirtualAddress
;
108 TextUpdater (Base
, SectionHeader
.Misc
.VirtualSize
);
110 if ((SectionHeader
.Characteristics
& EFI_IMAGE_SCN_MEM_WRITE
) != 0) {
111 ReadWriteUpdater (Base
, SectionHeader
.Misc
.VirtualSize
);
113 "%a: Mapping section %d of image at 0x%lx with RW-XN permissions\n",
114 __FUNCTION__
, Index
, ImageContext
->ImageAddress
));
117 "%a: Mapping section %d of image at 0x%lx with RO-XN permissions\n",
118 __FUNCTION__
, Index
, ImageContext
->ImageAddress
));
122 "%a: Ignoring section %d of image at 0x%lx with 0x%x permissions\n",
123 __FUNCTION__
, Index
, ImageContext
->ImageAddress
, SectionHeader
.Characteristics
));
125 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
128 return RETURN_SUCCESS
;
132 Privileged firmware assigns RO & Executable attributes to all memory occupied
133 by the Boot Firmware Volume. This function locates the Standalone MM Core
134 module PE/COFF image in the BFV and returns this information.
136 @param [in] BfvAddress Base Address of Boot Firmware Volume
137 @param [in, out] TeData Pointer to address for allocating memory
138 for PE/COFF image data
139 @param [in, out] TeDataSize Pointer to size of PE/COFF image data
144 LocateStandaloneMmCorePeCoffData (
145 IN EFI_FIRMWARE_VOLUME_HEADER
*BfvAddress
,
146 IN OUT VOID
**TeData
,
147 IN OUT UINTN
*TeDataSize
150 EFI_FFS_FILE_HEADER
*FileHeader
;
154 Status
= FfsFindNextFile (
155 EFI_FV_FILETYPE_SECURITY_CORE
,
160 if (EFI_ERROR (Status
)) {
161 DEBUG ((DEBUG_ERROR
, "Unable to locate Standalone MM FFS file - 0x%x\n",
166 Status
= FfsFindSectionData (EFI_SECTION_PE32
, FileHeader
, TeData
, TeDataSize
);
167 if (EFI_ERROR (Status
)) {
168 Status
= FfsFindSectionData (EFI_SECTION_TE
, FileHeader
, TeData
, TeDataSize
);
169 if (EFI_ERROR (Status
)) {
170 DEBUG ((DEBUG_ERROR
, "Unable to locate Standalone MM Section data - %r\n",
176 DEBUG ((DEBUG_INFO
, "Found Standalone MM PE data - 0x%x\n", *TeData
));
181 Returns the PC COFF section information.
183 @param [in, out] ImageContext Pointer to PE/COFF image context
184 @param [out] ImageBase Base of image in memory
185 @param [out] SectionHeaderOffset Offset of PE/COFF image section header
186 @param [out] NumberOfSections Number of Sections
191 GetPeCoffSectionInformation (
192 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
193 OUT EFI_PHYSICAL_ADDRESS
*ImageBase
,
194 OUT UINT32
*SectionHeaderOffset
,
195 OUT UINT16
*NumberOfSections
198 RETURN_STATUS Status
;
199 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
200 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData
;
204 ASSERT (ImageContext
!= NULL
);
205 ASSERT (SectionHeaderOffset
!= NULL
);
206 ASSERT (NumberOfSections
!= NULL
);
208 Status
= PeCoffLoaderGetImageInfo (ImageContext
);
209 if (RETURN_ERROR (Status
)) {
211 "%a: PeCoffLoaderGetImageInfo () failed (Status == %r)\n",
212 __FUNCTION__
, Status
));
216 if (ImageContext
->SectionAlignment
< EFI_PAGE_SIZE
) {
218 // The sections need to be at least 4 KB aligned, since that is the
219 // granularity at which we can tighten permissions.
221 if (!ImageContext
->IsTeImage
) {
223 "%a: non-TE Image at 0x%lx has SectionAlignment < 4 KB (%lu)\n",
224 __FUNCTION__
, ImageContext
->ImageAddress
, ImageContext
->SectionAlignment
));
225 return RETURN_UNSUPPORTED
;
227 ImageContext
->SectionAlignment
= EFI_PAGE_SIZE
;
231 // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much
232 // data, but that should not hurt anything. Hdr.Pe32->OptionalHeader.Magic
233 // determines if this is a PE32 or PE32+ image. The magic is in the same
234 // location in both images.
236 Hdr
.Union
= &HdrData
;
237 Size
= sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION
);
239 Status
= ImageContext
->ImageRead (
240 ImageContext
->Handle
,
241 ImageContext
->PeCoffHeaderOffset
,
246 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
248 "%a: TmpContext->ImageRead () failed (Status = %r)\n",
249 __FUNCTION__
, Status
));
253 *ImageBase
= ImageContext
->ImageAddress
;
254 if (!ImageContext
->IsTeImage
) {
255 ASSERT (Hdr
.Pe32
->Signature
== EFI_IMAGE_NT_SIGNATURE
);
257 *SectionHeaderOffset
= ImageContext
->PeCoffHeaderOffset
+ sizeof (UINT32
) +
258 sizeof (EFI_IMAGE_FILE_HEADER
);
259 *NumberOfSections
= Hdr
.Pe32
->FileHeader
.NumberOfSections
;
261 switch (Hdr
.Pe32
->OptionalHeader
.Magic
) {
262 case EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
:
263 *SectionHeaderOffset
+= Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
;
265 case EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
:
266 *SectionHeaderOffset
+= Hdr
.Pe32Plus
->FileHeader
.SizeOfOptionalHeader
;
272 *SectionHeaderOffset
= (UINTN
)(sizeof (EFI_TE_IMAGE_HEADER
));
273 *NumberOfSections
= Hdr
.Te
->NumberOfSections
;
274 *ImageBase
-= (UINT32
)Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
);
276 return RETURN_SUCCESS
;
280 Privileged firmware assigns RO & Executable attributes to all memory occupied
281 by the Boot Firmware Volume. This function locates the section information of
282 the Standalone MM Core module to be able to change permissions of the
283 individual sections later in the boot process.
285 @param [in] TeData Pointer to PE/COFF image data
286 @param [in, out] ImageContext Pointer to PE/COFF image context
287 @param [out] ImageBase Pointer to ImageBase variable
288 @param [in, out] SectionHeaderOffset Offset of PE/COFF image section header
289 @param [in, out] NumberOfSections Number of Sections
294 GetStandaloneMmCorePeCoffSections (
296 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
297 OUT EFI_PHYSICAL_ADDRESS
*ImageBase
,
298 IN OUT UINT32
*SectionHeaderOffset
,
299 IN OUT UINT16
*NumberOfSections
304 // Initialize the Image Context
305 ZeroMem (ImageContext
, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT
));
306 ImageContext
->Handle
= TeData
;
307 ImageContext
->ImageRead
= PeCoffLoaderImageReadFromMemory
;
309 DEBUG ((DEBUG_INFO
, "Found Standalone MM PE data - 0x%x\n", TeData
));
311 Status
= GetPeCoffSectionInformation (ImageContext
, ImageBase
,
312 SectionHeaderOffset
, NumberOfSections
);
313 if (EFI_ERROR (Status
)) {
314 DEBUG ((DEBUG_ERROR
, "Unable to locate Standalone MM Core PE-COFF Section information - %r\n", Status
));
318 DEBUG ((DEBUG_INFO
, "Standalone MM Core PE-COFF SectionHeaderOffset - 0x%x, NumberOfSections - %d\n",
319 *SectionHeaderOffset
, *NumberOfSections
));