]> git.proxmox.com Git - mirror_edk2.git/blob - StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/SetPermissions.c
StandaloneMmPkg: Add option to use FF-A calls for getting SPM version
[mirror_edk2.git] / StandaloneMmPkg / Library / StandaloneMmCoreEntryPoint / AArch64 / SetPermissions.c
1 /** @file
2 Locate, get and update PE/COFF permissions during Standalone MM
3 Foundation Entry point on ARM platforms.
4
5 Copyright (c) 2017 - 2021, Arm Ltd. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10
11 #include <PiMm.h>
12
13 #include <PiPei.h>
14 #include <Guid/MmramMemoryReserve.h>
15 #include <Guid/MpInformation.h>
16
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>
25
26 #include <IndustryStandard/ArmStdSmc.h>
27
28 /**
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.
33
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
41
42 **/
43 EFI_STATUS
44 EFIAPI
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
53 )
54 {
55 EFI_IMAGE_SECTION_HEADER SectionHeader;
56 RETURN_STATUS Status;
57 EFI_PHYSICAL_ADDRESS Base;
58 UINTN Size;
59 UINTN ReadSize;
60 UINTN Index;
61
62 ASSERT (ImageContext != NULL);
63
64 //
65 // Iterate over the sections
66 //
67 for (Index = 0; Index < NumberOfSections; Index++) {
68 //
69 // Read section header from file
70 //
71 Size = sizeof (EFI_IMAGE_SECTION_HEADER);
72 ReadSize = Size;
73 Status = ImageContext->ImageRead (
74 ImageContext->Handle,
75 SectionHeaderOffset,
76 &Size,
77 &SectionHeader
78 );
79
80 if (RETURN_ERROR (Status) || (Size != ReadSize)) {
81 DEBUG ((DEBUG_ERROR,
82 "%a: ImageContext->ImageRead () failed (Status = %r)\n",
83 __FUNCTION__, Status));
84 return Status;
85 }
86
87 DEBUG ((DEBUG_INFO,
88 "%a: Section %d of image at 0x%lx has 0x%x permissions\n",
89 __FUNCTION__, Index, ImageContext->ImageAddress, SectionHeader.Characteristics));
90 DEBUG ((DEBUG_INFO,
91 "%a: Section %d of image at 0x%lx has %a name\n",
92 __FUNCTION__, Index, ImageContext->ImageAddress, SectionHeader.Name));
93 DEBUG ((DEBUG_INFO,
94 "%a: Section %d of image at 0x%lx has 0x%x address\n",
95 __FUNCTION__, Index, ImageContext->ImageAddress,
96 ImageContext->ImageAddress + SectionHeader.VirtualAddress));
97 DEBUG ((DEBUG_INFO,
98 "%a: Section %d of image at 0x%lx has 0x%x data\n",
99 __FUNCTION__, Index, ImageContext->ImageAddress, SectionHeader.PointerToRawData));
100
101 //
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.
104 //
105 if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) == 0) {
106 Base = ImageBase + SectionHeader.VirtualAddress;
107
108 TextUpdater (Base, SectionHeader.Misc.VirtualSize);
109
110 if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_WRITE) != 0) {
111 ReadWriteUpdater (Base, SectionHeader.Misc.VirtualSize);
112 DEBUG ((DEBUG_INFO,
113 "%a: Mapping section %d of image at 0x%lx with RW-XN permissions\n",
114 __FUNCTION__, Index, ImageContext->ImageAddress));
115 } else {
116 DEBUG ((DEBUG_INFO,
117 "%a: Mapping section %d of image at 0x%lx with RO-XN permissions\n",
118 __FUNCTION__, Index, ImageContext->ImageAddress));
119 }
120 } else {
121 DEBUG ((DEBUG_INFO,
122 "%a: Ignoring section %d of image at 0x%lx with 0x%x permissions\n",
123 __FUNCTION__, Index, ImageContext->ImageAddress, SectionHeader.Characteristics));
124 }
125 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
126 }
127
128 return RETURN_SUCCESS;
129 }
130
131 /**
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.
135
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
140
141 **/
142 EFI_STATUS
143 EFIAPI
144 LocateStandaloneMmCorePeCoffData (
145 IN EFI_FIRMWARE_VOLUME_HEADER *BfvAddress,
146 IN OUT VOID **TeData,
147 IN OUT UINTN *TeDataSize
148 )
149 {
150 EFI_FFS_FILE_HEADER *FileHeader;
151 EFI_STATUS Status;
152
153 FileHeader = NULL;
154 Status = FfsFindNextFile (
155 EFI_FV_FILETYPE_SECURITY_CORE,
156 BfvAddress,
157 &FileHeader
158 );
159
160 if (EFI_ERROR (Status)) {
161 DEBUG ((DEBUG_ERROR, "Unable to locate Standalone MM FFS file - 0x%x\n",
162 Status));
163 return Status;
164 }
165
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",
171 Status));
172 return Status;
173 }
174 }
175
176 DEBUG ((DEBUG_INFO, "Found Standalone MM PE data - 0x%x\n", *TeData));
177 return Status;
178 }
179
180 /**
181 Returns the PC COFF section information.
182
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
187
188 **/
189 STATIC
190 EFI_STATUS
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
196 )
197 {
198 RETURN_STATUS Status;
199 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
200 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;
201 UINTN Size;
202 UINTN ReadSize;
203
204 ASSERT (ImageContext != NULL);
205 ASSERT (SectionHeaderOffset != NULL);
206 ASSERT (NumberOfSections != NULL);
207
208 Status = PeCoffLoaderGetImageInfo (ImageContext);
209 if (RETURN_ERROR (Status)) {
210 DEBUG ((DEBUG_ERROR,
211 "%a: PeCoffLoaderGetImageInfo () failed (Status == %r)\n",
212 __FUNCTION__, Status));
213 return Status;
214 }
215
216 if (ImageContext->SectionAlignment < EFI_PAGE_SIZE) {
217 //
218 // The sections need to be at least 4 KB aligned, since that is the
219 // granularity at which we can tighten permissions.
220 //
221 if (!ImageContext->IsTeImage) {
222 DEBUG ((DEBUG_WARN,
223 "%a: non-TE Image at 0x%lx has SectionAlignment < 4 KB (%lu)\n",
224 __FUNCTION__, ImageContext->ImageAddress, ImageContext->SectionAlignment));
225 return RETURN_UNSUPPORTED;
226 }
227 ImageContext->SectionAlignment = EFI_PAGE_SIZE;
228 }
229
230 //
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.
235 //
236 Hdr.Union = &HdrData;
237 Size = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
238 ReadSize = Size;
239 Status = ImageContext->ImageRead (
240 ImageContext->Handle,
241 ImageContext->PeCoffHeaderOffset,
242 &Size,
243 Hdr.Pe32
244 );
245
246 if (RETURN_ERROR (Status) || (Size != ReadSize)) {
247 DEBUG ((DEBUG_ERROR,
248 "%a: TmpContext->ImageRead () failed (Status = %r)\n",
249 __FUNCTION__, Status));
250 return Status;
251 }
252
253 *ImageBase = ImageContext->ImageAddress;
254 if (!ImageContext->IsTeImage) {
255 ASSERT (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE);
256
257 *SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + sizeof (UINT32) +
258 sizeof (EFI_IMAGE_FILE_HEADER);
259 *NumberOfSections = Hdr.Pe32->FileHeader.NumberOfSections;
260
261 switch (Hdr.Pe32->OptionalHeader.Magic) {
262 case EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC:
263 *SectionHeaderOffset += Hdr.Pe32->FileHeader.SizeOfOptionalHeader;
264 break;
265 case EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC:
266 *SectionHeaderOffset += Hdr.Pe32Plus->FileHeader.SizeOfOptionalHeader;
267 break;
268 default:
269 ASSERT (FALSE);
270 }
271 } else {
272 *SectionHeaderOffset = (UINTN)(sizeof (EFI_TE_IMAGE_HEADER));
273 *NumberOfSections = Hdr.Te->NumberOfSections;
274 *ImageBase -= (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
275 }
276 return RETURN_SUCCESS;
277 }
278
279 /**
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.
284
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
290
291 **/
292 EFI_STATUS
293 EFIAPI
294 GetStandaloneMmCorePeCoffSections (
295 IN VOID *TeData,
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
300 )
301 {
302 EFI_STATUS Status;
303
304 // Initialize the Image Context
305 ZeroMem (ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
306 ImageContext->Handle = TeData;
307 ImageContext->ImageRead = PeCoffLoaderImageReadFromMemory;
308
309 DEBUG ((DEBUG_INFO, "Found Standalone MM PE data - 0x%x\n", TeData));
310
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));
315 return Status;
316 }
317
318 DEBUG ((DEBUG_INFO, "Standalone MM Core PE-COFF SectionHeaderOffset - 0x%x, NumberOfSections - %d\n",
319 *SectionHeaderOffset, *NumberOfSections));
320
321 return Status;
322 }