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