1 /** @file
2 *
3 *  Copyright (c) 2011-2015, ARM Limited. All rights reserved.
4 *
5 *  SPDX-License-Identifier: BSD-2-Clause-Patent
6 *
7 **/
8 
9 #include <PiPei.h>
10 
11 #include <Library/ArmMmuLib.h>
12 #include <Library/ArmPlatformLib.h>
13 #include <Library/DebugLib.h>
14 #include <Library/HobLib.h>
15 #include <Library/MemoryAllocationLib.h>
16 #include <Library/PcdLib.h>
17 
18 VOID
19 BuildMemoryTypeInformationHob (
20   VOID
21   );
22 
23 STATIC
24 VOID
InitMmu(IN ARM_MEMORY_REGION_DESCRIPTOR * MemoryTable)25 InitMmu (
26   IN ARM_MEMORY_REGION_DESCRIPTOR  *MemoryTable
27   )
28 {
29 
30   VOID                          *TranslationTableBase;
31   UINTN                         TranslationTableSize;
32   RETURN_STATUS                 Status;
33 
34   //Note: Because we called PeiServicesInstallPeiMemory() before to call InitMmu() the MMU Page Table resides in
35   //      DRAM (even at the top of DRAM as it is the first permanent memory allocation)
36   Status = ArmConfigureMmu (MemoryTable, &TranslationTableBase, &TranslationTableSize);
37   if (EFI_ERROR (Status)) {
38     DEBUG ((EFI_D_ERROR, "Error: Failed to enable MMU\n"));
39   }
40 }
41 
42 /*++
43 
44 Routine Description:
45 
46 
47 
48 Arguments:
49 
50   FileHandle  - Handle of the file being invoked.
51   PeiServices - Describes the list of possible PEI Services.
52 
53 Returns:
54 
55   Status -  EFI_SUCCESS if the boot mode could be set
56 
57 --*/
58 EFI_STATUS
59 EFIAPI
MemoryPeim(IN EFI_PHYSICAL_ADDRESS UefiMemoryBase,IN UINT64 UefiMemorySize)60 MemoryPeim (
61   IN EFI_PHYSICAL_ADDRESS               UefiMemoryBase,
62   IN UINT64                             UefiMemorySize
63   )
64 {
65   ARM_MEMORY_REGION_DESCRIPTOR *MemoryTable;
66   EFI_RESOURCE_ATTRIBUTE_TYPE  ResourceAttributes;
67   UINT64                       ResourceLength;
68   EFI_PEI_HOB_POINTERS         NextHob;
69   EFI_PHYSICAL_ADDRESS         FdTop;
70   EFI_PHYSICAL_ADDRESS         SystemMemoryTop;
71   EFI_PHYSICAL_ADDRESS         ResourceTop;
72   BOOLEAN                      Found;
73 
74   // Get Virtual Memory Map from the Platform Library
75   ArmPlatformGetVirtualMemoryMap (&MemoryTable);
76 
77   // Ensure PcdSystemMemorySize has been set
78   ASSERT (PcdGet64 (PcdSystemMemorySize) != 0);
79 
80   //
81   // Now, the permanent memory has been installed, we can call AllocatePages()
82   //
83   ResourceAttributes = (
84       EFI_RESOURCE_ATTRIBUTE_PRESENT |
85       EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
86       EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
87       EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
88       EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
89       EFI_RESOURCE_ATTRIBUTE_TESTED
90   );
91 
92   //
93   // Check if the resource for the main system memory has been declared
94   //
95   Found = FALSE;
96   NextHob.Raw = GetHobList ();
97   while ((NextHob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, NextHob.Raw)) != NULL) {
98     if ((NextHob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&
99         (PcdGet64 (PcdSystemMemoryBase) >= NextHob.ResourceDescriptor->PhysicalStart) &&
100         (NextHob.ResourceDescriptor->PhysicalStart + NextHob.ResourceDescriptor->ResourceLength <= PcdGet64 (PcdSystemMemoryBase) + PcdGet64 (PcdSystemMemorySize)))
101     {
102       Found = TRUE;
103       break;
104     }
105     NextHob.Raw = GET_NEXT_HOB (NextHob);
106   }
107 
108   if (!Found) {
109     // Reserved the memory space occupied by the firmware volume
110     BuildResourceDescriptorHob (
111         EFI_RESOURCE_SYSTEM_MEMORY,
112         ResourceAttributes,
113         PcdGet64 (PcdSystemMemoryBase),
114         PcdGet64 (PcdSystemMemorySize)
115     );
116   }
117 
118   //
119   // Reserved the memory space occupied by the firmware volume
120   //
121 
122   SystemMemoryTop = (EFI_PHYSICAL_ADDRESS)PcdGet64 (PcdSystemMemoryBase) + (EFI_PHYSICAL_ADDRESS)PcdGet64 (PcdSystemMemorySize);
123   FdTop = (EFI_PHYSICAL_ADDRESS)PcdGet64 (PcdFdBaseAddress) + (EFI_PHYSICAL_ADDRESS)PcdGet32 (PcdFdSize);
124 
125   // EDK2 does not have the concept of boot firmware copied into DRAM. To avoid the DXE
126   // core to overwrite this area we must create a memory allocation HOB for the region,
127   // but this only works if we split off the underlying resource descriptor as well.
128   if ((PcdGet64 (PcdFdBaseAddress) >= PcdGet64 (PcdSystemMemoryBase)) && (FdTop <= SystemMemoryTop)) {
129     Found = FALSE;
130 
131     // Search for System Memory Hob that contains the firmware
132     NextHob.Raw = GetHobList ();
133     while ((NextHob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, NextHob.Raw)) != NULL) {
134       if ((NextHob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&
135           (PcdGet64 (PcdFdBaseAddress) >= NextHob.ResourceDescriptor->PhysicalStart) &&
136           (FdTop <= NextHob.ResourceDescriptor->PhysicalStart + NextHob.ResourceDescriptor->ResourceLength))
137       {
138         ResourceAttributes = NextHob.ResourceDescriptor->ResourceAttribute;
139         ResourceLength = NextHob.ResourceDescriptor->ResourceLength;
140         ResourceTop = NextHob.ResourceDescriptor->PhysicalStart + ResourceLength;
141 
142         if (PcdGet64 (PcdFdBaseAddress) == NextHob.ResourceDescriptor->PhysicalStart) {
143           if (SystemMemoryTop != FdTop) {
144             // Create the System Memory HOB for the firmware
145             BuildResourceDescriptorHob (EFI_RESOURCE_SYSTEM_MEMORY,
146                                         ResourceAttributes,
147                                         PcdGet64 (PcdFdBaseAddress),
148                                         PcdGet32 (PcdFdSize));
149 
150             // Top of the FD is system memory available for UEFI
151             NextHob.ResourceDescriptor->PhysicalStart += PcdGet32(PcdFdSize);
152             NextHob.ResourceDescriptor->ResourceLength -= PcdGet32(PcdFdSize);
153           }
154         } else {
155           // Create the System Memory HOB for the firmware
156           BuildResourceDescriptorHob (EFI_RESOURCE_SYSTEM_MEMORY,
157                                       ResourceAttributes,
158                                       PcdGet64 (PcdFdBaseAddress),
159                                       PcdGet32 (PcdFdSize));
160 
161           // Update the HOB
162           NextHob.ResourceDescriptor->ResourceLength = PcdGet64 (PcdFdBaseAddress) - NextHob.ResourceDescriptor->PhysicalStart;
163 
164           // If there is some memory available on the top of the FD then create a HOB
165           if (FdTop < NextHob.ResourceDescriptor->PhysicalStart + ResourceLength) {
166             // Create the System Memory HOB for the remaining region (top of the FD)
167             BuildResourceDescriptorHob (EFI_RESOURCE_SYSTEM_MEMORY,
168                                         ResourceAttributes,
169                                         FdTop,
170                                         ResourceTop - FdTop);
171           }
172         }
173 
174         // Mark the memory covering the Firmware Device as boot services data
175         BuildMemoryAllocationHob (PcdGet64 (PcdFdBaseAddress),
176                                   PcdGet32 (PcdFdSize),
177                                   EfiBootServicesData);
178 
179         Found = TRUE;
180         break;
181       }
182       NextHob.Raw = GET_NEXT_HOB (NextHob);
183     }
184 
185     ASSERT(Found);
186   }
187 
188   // Build Memory Allocation Hob
189   InitMmu (MemoryTable);
190 
191   if (FeaturePcdGet (PcdPrePiProduceMemoryTypeInformationHob)) {
192     // Optional feature that helps prevent EFI memory map fragmentation.
193     BuildMemoryTypeInformationHob ();
194   }
195 
196   return EFI_SUCCESS;
197 }
198