]> git.proxmox.com Git - mirror_edk2.git/blob - StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/AArch64/StandaloneMmPeCoffExtraActionLib.c
StandaloneMmPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / StandaloneMmPkg / Library / StandaloneMmPeCoffExtraActionLib / AArch64 / StandaloneMmPeCoffExtraActionLib.c
1 /**@file
2
3 Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
4 Portions copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
5 Portions copyright (c) 2011 - 2018, ARM Ltd. All rights reserved.<BR>
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11 #include <PiDxe.h>
12
13 #include <Library/ArmMmuLib.h>
14 #include <Library/BaseLib.h>
15 #include <Library/BaseMemoryLib.h>
16 #include <Library/DebugLib.h>
17 #include <Library/PcdLib.h>
18 #include <Library/PeCoffLib.h>
19 #include <Library/PeCoffExtraActionLib.h>
20
21 typedef RETURN_STATUS (*REGION_PERMISSION_UPDATE_FUNC) (
22 IN EFI_PHYSICAL_ADDRESS BaseAddress,
23 IN UINT64 Length
24 );
25
26 STATIC
27 RETURN_STATUS
28 UpdatePeCoffPermissions (
29 IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
30 IN REGION_PERMISSION_UPDATE_FUNC NoExecUpdater,
31 IN REGION_PERMISSION_UPDATE_FUNC ReadOnlyUpdater
32 )
33 {
34 RETURN_STATUS Status;
35 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
36 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;
37 UINTN Size;
38 UINTN ReadSize;
39 UINT32 SectionHeaderOffset;
40 UINTN NumberOfSections;
41 UINTN Index;
42 EFI_IMAGE_SECTION_HEADER SectionHeader;
43 PE_COFF_LOADER_IMAGE_CONTEXT TmpContext;
44 EFI_PHYSICAL_ADDRESS Base;
45
46 //
47 // We need to copy ImageContext since PeCoffLoaderGetImageInfo ()
48 // will mangle the ImageAddress field
49 //
50 CopyMem (&TmpContext, ImageContext, sizeof (TmpContext));
51
52 if (TmpContext.PeCoffHeaderOffset == 0) {
53 Status = PeCoffLoaderGetImageInfo (&TmpContext);
54 if (RETURN_ERROR (Status)) {
55 DEBUG ((DEBUG_ERROR,
56 "%a: PeCoffLoaderGetImageInfo () failed (Status = %r)\n",
57 __FUNCTION__, Status));
58 return Status;
59 }
60 }
61
62 if (TmpContext.IsTeImage &&
63 TmpContext.ImageAddress == ImageContext->ImageAddress) {
64 DEBUG ((DEBUG_INFO, "%a: ignoring XIP TE image at 0x%lx\n", __FUNCTION__,
65 ImageContext->ImageAddress));
66 return RETURN_SUCCESS;
67 }
68
69 if (TmpContext.SectionAlignment < EFI_PAGE_SIZE) {
70 //
71 // The sections need to be at least 4 KB aligned, since that is the
72 // granularity at which we can tighten permissions. So just clear the
73 // noexec permissions on the entire region.
74 //
75 if (!TmpContext.IsTeImage) {
76 DEBUG ((DEBUG_WARN,
77 "%a: non-TE Image at 0x%lx has SectionAlignment < 4 KB (%lu)\n",
78 __FUNCTION__, ImageContext->ImageAddress, TmpContext.SectionAlignment));
79 }
80 Base = ImageContext->ImageAddress & ~(EFI_PAGE_SIZE - 1);
81 Size = ImageContext->ImageAddress - Base + ImageContext->ImageSize;
82 return NoExecUpdater (Base, ALIGN_VALUE (Size, EFI_PAGE_SIZE));
83 }
84
85 //
86 // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much
87 // data, but that should not hurt anything. Hdr.Pe32->OptionalHeader.Magic
88 // determines if this is a PE32 or PE32+ image. The magic is in the same
89 // location in both images.
90 //
91 Hdr.Union = &HdrData;
92 Size = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
93 ReadSize = Size;
94 Status = TmpContext.ImageRead (TmpContext.Handle,
95 TmpContext.PeCoffHeaderOffset, &Size, Hdr.Pe32);
96 if (RETURN_ERROR (Status) || (Size != ReadSize)) {
97 DEBUG ((DEBUG_ERROR,
98 "%a: TmpContext.ImageRead () failed (Status = %r)\n",
99 __FUNCTION__, Status));
100 return Status;
101 }
102
103 ASSERT (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE);
104
105 SectionHeaderOffset = TmpContext.PeCoffHeaderOffset + sizeof (UINT32) +
106 sizeof (EFI_IMAGE_FILE_HEADER);
107 NumberOfSections = (UINTN)(Hdr.Pe32->FileHeader.NumberOfSections);
108
109 switch (Hdr.Pe32->OptionalHeader.Magic) {
110 case EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC:
111 SectionHeaderOffset += Hdr.Pe32->FileHeader.SizeOfOptionalHeader;
112 break;
113 case EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC:
114 SectionHeaderOffset += Hdr.Pe32Plus->FileHeader.SizeOfOptionalHeader;
115 break;
116 default:
117 ASSERT (FALSE);
118 }
119
120 //
121 // Iterate over the sections
122 //
123 for (Index = 0; Index < NumberOfSections; Index++) {
124 //
125 // Read section header from file
126 //
127 Size = sizeof (EFI_IMAGE_SECTION_HEADER);
128 ReadSize = Size;
129 Status = TmpContext.ImageRead (TmpContext.Handle, SectionHeaderOffset,
130 &Size, &SectionHeader);
131 if (RETURN_ERROR (Status) || (Size != ReadSize)) {
132 DEBUG ((DEBUG_ERROR,
133 "%a: TmpContext.ImageRead () failed (Status = %r)\n",
134 __FUNCTION__, Status));
135 return Status;
136 }
137
138 Base = TmpContext.ImageAddress + SectionHeader.VirtualAddress;
139
140 if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) == 0) {
141
142 if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_WRITE) == 0) {
143
144 DEBUG ((DEBUG_INFO,
145 "%a: Mapping section %d of image at 0x%lx with RO-XN permissions and size 0x%x\n",
146 __FUNCTION__, Index, Base, SectionHeader.Misc.VirtualSize));
147 ReadOnlyUpdater (Base, SectionHeader.Misc.VirtualSize);
148 } else {
149 DEBUG ((DEBUG_WARN,
150 "%a: Mapping section %d of image at 0x%lx with RW-XN permissions and size 0x%x\n",
151 __FUNCTION__, Index, Base, SectionHeader.Misc.VirtualSize));
152 }
153 } else {
154 DEBUG ((DEBUG_INFO,
155 "%a: Mapping section %d of image at 0x%lx with RO-X permissions and size 0x%x\n",
156 __FUNCTION__, Index, Base, SectionHeader.Misc.VirtualSize));
157 ReadOnlyUpdater (Base, SectionHeader.Misc.VirtualSize);
158 NoExecUpdater (Base, SectionHeader.Misc.VirtualSize);
159 }
160
161 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
162 }
163 return RETURN_SUCCESS;
164 }
165
166 /**
167 Performs additional actions after a PE/COFF image has been loaded and relocated.
168
169 If ImageContext is NULL, then ASSERT().
170
171 @param ImageContext Pointer to the image context structure that describes the
172 PE/COFF image that has already been loaded and relocated.
173
174 **/
175 VOID
176 EFIAPI
177 PeCoffLoaderRelocateImageExtraAction (
178 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
179 )
180 {
181 UpdatePeCoffPermissions (
182 ImageContext,
183 ArmClearMemoryRegionNoExec,
184 ArmSetMemoryRegionReadOnly
185 );
186 }
187
188
189
190 /**
191 Performs additional actions just before a PE/COFF image is unloaded. Any resources
192 that were allocated by PeCoffLoaderRelocateImageExtraAction() must be freed.
193
194 If ImageContext is NULL, then ASSERT().
195
196 @param ImageContext Pointer to the image context structure that describes the
197 PE/COFF image that is being unloaded.
198
199 **/
200 VOID
201 EFIAPI
202 PeCoffLoaderUnloadImageExtraAction (
203 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
204 )
205 {
206 UpdatePeCoffPermissions (
207 ImageContext,
208 ArmSetMemoryRegionNoExec,
209 ArmClearMemoryRegionReadOnly
210 );
211 }