1 /** @file
2   This module sets default policy for attributes of EfiACPIMemoryNVS and EfiReservedMemoryType.
3 
4   This module sets EFI_MEMORY_XP for attributes of EfiACPIMemoryNVS and EfiReservedMemoryType
5   in UEFI memory map, if and only of PropertiesTable is published and has BIT0 set.
6 
7 Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
8 This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution.  The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
12 
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 
16 **/
17 
18 #include <Uefi.h>
19 #include <Library/DebugLib.h>
20 #include <Library/UefiBootServicesTableLib.h>
21 #include <Library/DxeServicesTableLib.h>
22 #include <Library/UefiLib.h>
23 #include <Library/MemoryAllocationLib.h>
24 #include <Guid/EventGroup.h>
25 #include <Guid/PropertiesTable.h>
26 
27 /**
28   Converts a number of EFI_PAGEs to a size in bytes.
29 
30   NOTE: Do not use EFI_PAGES_TO_SIZE because it handles UINTN only.
31 
32   @param  Pages     The number of EFI_PAGES.
33 
34   @return  The number of bytes associated with the number of EFI_PAGEs specified
35            by Pages.
36 **/
37 UINT64
EfiPagesToSize(IN UINT64 Pages)38 EfiPagesToSize (
39   IN UINT64 Pages
40   )
41 {
42   return LShiftU64 (Pages, EFI_PAGE_SHIFT);
43 }
44 
45 /**
46   Set memory attributes according to default policy.
47 
48   @param  MemoryMap        A pointer to the buffer in which firmware places the current memory map.
49   @param  MemoryMapSize    Size, in bytes, of the MemoryMap buffer.
50   @param  DescriptorSize   size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
51 **/
52 VOID
SetMemorySpaceAttributesDefault(IN EFI_MEMORY_DESCRIPTOR * MemoryMap,IN UINTN MemoryMapSize,IN UINTN DescriptorSize)53 SetMemorySpaceAttributesDefault (
54   IN EFI_MEMORY_DESCRIPTOR  *MemoryMap,
55   IN UINTN                  MemoryMapSize,
56   IN UINTN                  DescriptorSize
57   )
58 {
59   EFI_MEMORY_DESCRIPTOR       *MemoryMapEntry;
60   EFI_MEMORY_DESCRIPTOR       *MemoryMapEnd;
61   EFI_STATUS                  Status;
62 
63   DEBUG ((EFI_D_INFO, "SetMemorySpaceAttributesDefault\n"));
64 
65   MemoryMapEntry = MemoryMap;
66   MemoryMapEnd   = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);
67   while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
68     if (MemoryMapEntry->PhysicalStart < BASE_1MB) {
69       //
70       // Do not touch memory space below 1MB
71       //
72       MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
73       continue;
74     }
75     switch (MemoryMapEntry->Type) {
76     case EfiRuntimeServicesCode:
77     case EfiRuntimeServicesData:
78       //
79       // should be handled later;
80       //
81       break;
82     case EfiReservedMemoryType:
83     case EfiACPIMemoryNVS:
84       //
85       // Handle EfiReservedMemoryType and EfiACPIMemoryNVS, because there might be firmware executable there.
86       //
87       DEBUG ((EFI_D_INFO, "SetMemorySpaceAttributes - %016lx - %016lx (%016lx) ...\n",
88         MemoryMapEntry->PhysicalStart,
89         MemoryMapEntry->PhysicalStart + EfiPagesToSize (MemoryMapEntry->NumberOfPages),
90         MemoryMapEntry->Attribute
91         ));
92       Status = gDS->SetMemorySpaceCapabilities (
93                       MemoryMapEntry->PhysicalStart,
94                       EfiPagesToSize (MemoryMapEntry->NumberOfPages),
95                       MemoryMapEntry->Attribute | EFI_MEMORY_XP
96                       );
97       DEBUG ((EFI_D_INFO, "SetMemorySpaceCapabilities - %r\n", Status));
98       break;
99     }
100 
101     MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
102   }
103 
104   return ;
105 }
106 
107 /**
108   Update memory attributes according to default policy.
109 
110   @param[in]  Event     The Event this notify function registered to.
111   @param[in]  Context   Pointer to the context data registered to the Event.
112 **/
113 VOID
114 EFIAPI
UpdateMemoryAttributesDefault(EFI_EVENT Event,VOID * Context)115 UpdateMemoryAttributesDefault (
116   EFI_EVENT                               Event,
117   VOID                                    *Context
118   )
119 {
120   EFI_STATUS                  Status;
121   EFI_MEMORY_DESCRIPTOR       *MemoryMap;
122   UINTN                       MemoryMapSize;
123   UINTN                       MapKey;
124   UINTN                       DescriptorSize;
125   UINT32                      DescriptorVersion;
126   EFI_PROPERTIES_TABLE        *PropertiesTable;
127 
128   DEBUG ((EFI_D_INFO, "UpdateMemoryAttributesDefault\n"));
129   Status = EfiGetSystemConfigurationTable (&gEfiPropertiesTableGuid, (VOID **) &PropertiesTable);
130   if (EFI_ERROR (Status)) {
131     goto Done;
132   }
133 
134   ASSERT (PropertiesTable != NULL);
135 
136   DEBUG ((EFI_D_INFO, "MemoryProtectionAttribute - 0x%016lx\n", PropertiesTable->MemoryProtectionAttribute));
137   if ((PropertiesTable->MemoryProtectionAttribute & EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) == 0) {
138     goto Done;
139   }
140 
141   //
142   // Get the EFI memory map.
143   //
144   MemoryMapSize  = 0;
145   MemoryMap      = NULL;
146   Status = gBS->GetMemoryMap (
147                   &MemoryMapSize,
148                   MemoryMap,
149                   &MapKey,
150                   &DescriptorSize,
151                   &DescriptorVersion
152                   );
153   ASSERT (Status == EFI_BUFFER_TOO_SMALL);
154   do {
155     MemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (MemoryMapSize);
156     ASSERT (MemoryMap != NULL);
157     Status = gBS->GetMemoryMap (
158                     &MemoryMapSize,
159                     MemoryMap,
160                     &MapKey,
161                     &DescriptorSize,
162                     &DescriptorVersion
163                     );
164     if (EFI_ERROR (Status)) {
165       FreePool (MemoryMap);
166     }
167   } while (Status == EFI_BUFFER_TOO_SMALL);
168   ASSERT_EFI_ERROR (Status);
169 
170   SetMemorySpaceAttributesDefault (MemoryMap, MemoryMapSize, DescriptorSize);
171 
172 Done:
173   gBS->CloseEvent (Event);
174 
175   return ;
176 }
177 
178 /**
179   The entrypoint of properties table attribute driver.
180 
181   @param  ImageHandle    The firmware allocated handle for the EFI image.
182   @param  SystemTable    A pointer to the EFI System Table.
183 
184   @retval EFI_SUCCESS    It always returns EFI_SUCCESS.
185 
186 **/
187 EFI_STATUS
188 EFIAPI
InitializePropertiesTableAttributesDxe(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)189 InitializePropertiesTableAttributesDxe (
190   IN EFI_HANDLE        ImageHandle,
191   IN EFI_SYSTEM_TABLE  *SystemTable
192   )
193 {
194   EFI_STATUS  Status;
195   EFI_EVENT   ReadyToBootEvent;
196 
197   Status = gBS->CreateEventEx (
198                   EVT_NOTIFY_SIGNAL,
199                   TPL_CALLBACK,
200                   UpdateMemoryAttributesDefault,
201                   NULL,
202                   &gEfiEventReadyToBootGuid,
203                   &ReadyToBootEvent
204                   );
205   ASSERT_EFI_ERROR (Status);
206 
207   return EFI_SUCCESS;
208 }
209