1 /*++
2 
3 Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution.  The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8 
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11 
12 Module Name:
13   Support.c
14 
15 Abstract:
16 
17 Revision History:
18 
19 --*/
20 #include "EfiLdr.h"
21 
22 EFI_STATUS
EfiAddMemoryDescriptor(UINTN * NoDesc,EFI_MEMORY_DESCRIPTOR * Desc,EFI_MEMORY_TYPE Type,EFI_PHYSICAL_ADDRESS BaseAddress,UINT64 NoPages,UINT64 Attribute)23 EfiAddMemoryDescriptor(
24   UINTN                 *NoDesc,
25   EFI_MEMORY_DESCRIPTOR *Desc,
26   EFI_MEMORY_TYPE       Type,
27   EFI_PHYSICAL_ADDRESS  BaseAddress,
28   UINT64                NoPages,
29   UINT64                Attribute
30   )
31 {
32   UINTN  NumberOfDesc;
33   UINT64 Temp;
34   UINTN  Index;
35 
36   if (NoPages == 0) {
37     return EFI_SUCCESS;
38   }
39 
40   //
41   // See if the new memory descriptor needs to be carved out of an existing memory descriptor
42   //
43 
44   NumberOfDesc = *NoDesc;
45   for (Index = 0; Index < NumberOfDesc; Index++) {
46 
47     if (Desc[Index].Type == EfiConventionalMemory) {
48 
49       Temp = DivU64x32 ((BaseAddress - Desc[Index].PhysicalStart), EFI_PAGE_SIZE) + NoPages;
50 
51       if ((Desc[Index].PhysicalStart < BaseAddress) && (Desc[Index].NumberOfPages >= Temp)) {
52         if (Desc[Index].NumberOfPages > Temp) {
53           Desc[*NoDesc].Type          = EfiConventionalMemory;
54           Desc[*NoDesc].PhysicalStart = BaseAddress + MultU64x32 (NoPages, EFI_PAGE_SIZE);
55           Desc[*NoDesc].NumberOfPages = Desc[Index].NumberOfPages - Temp;
56           Desc[*NoDesc].VirtualStart  = 0;
57           Desc[*NoDesc].Attribute     = Desc[Index].Attribute;
58           *NoDesc = *NoDesc + 1;
59         }
60         Desc[Index].NumberOfPages = Temp - NoPages;
61       }
62 
63       if ((Desc[Index].PhysicalStart == BaseAddress) && (Desc[Index].NumberOfPages == NoPages)) {
64         Desc[Index].Type      = Type;
65         Desc[Index].Attribute = Attribute;
66         return EFI_SUCCESS;
67       }
68 
69       if ((Desc[Index].PhysicalStart == BaseAddress) && (Desc[Index].NumberOfPages > NoPages)) {
70         Desc[Index].NumberOfPages -= NoPages;
71         Desc[Index].PhysicalStart += MultU64x32 (NoPages, EFI_PAGE_SIZE);
72       }
73     }
74   }
75 
76   //
77   // Add the new memory descriptor
78   //
79 
80   Desc[*NoDesc].Type          = Type;
81   Desc[*NoDesc].PhysicalStart = BaseAddress;
82   Desc[*NoDesc].NumberOfPages = NoPages;
83   Desc[*NoDesc].VirtualStart  = 0;
84   Desc[*NoDesc].Attribute     = Attribute;
85   *NoDesc = *NoDesc + 1;
86 
87   return EFI_SUCCESS;
88 }
89 
90 UINTN
FindSpace(UINTN NoPages,IN UINTN * NumberOfMemoryMapEntries,IN EFI_MEMORY_DESCRIPTOR * EfiMemoryDescriptor,EFI_MEMORY_TYPE Type,UINT64 Attribute)91 FindSpace (
92   UINTN                       NoPages,
93   IN UINTN                    *NumberOfMemoryMapEntries,
94   IN EFI_MEMORY_DESCRIPTOR    *EfiMemoryDescriptor,
95   EFI_MEMORY_TYPE             Type,
96   UINT64                      Attribute
97   )
98 {
99   EFI_PHYSICAL_ADDRESS        MaxPhysicalStart;
100   UINT64                      MaxNoPages;
101   UINTN                       Index;
102   EFI_MEMORY_DESCRIPTOR       *CurrentMemoryDescriptor;
103 
104   MaxPhysicalStart = 0;
105   MaxNoPages       = 0;
106   CurrentMemoryDescriptor = NULL;
107   for (Index = 0; Index < *NumberOfMemoryMapEntries; Index++) {
108     if (EfiMemoryDescriptor[Index].PhysicalStart + LShiftU64(EfiMemoryDescriptor[Index].NumberOfPages, EFI_PAGE_SHIFT) <= 0x100000) {
109       continue;
110     }
111     if ((EfiMemoryDescriptor[Index].Type == EfiConventionalMemory) &&
112         (EfiMemoryDescriptor[Index].NumberOfPages >= NoPages)) {
113       if (EfiMemoryDescriptor[Index].PhysicalStart > MaxPhysicalStart) {
114         if (EfiMemoryDescriptor[Index].PhysicalStart + LShiftU64(EfiMemoryDescriptor[Index].NumberOfPages, EFI_PAGE_SHIFT) <= 0x100000000ULL) {
115           MaxPhysicalStart = EfiMemoryDescriptor[Index].PhysicalStart;
116           MaxNoPages       = EfiMemoryDescriptor[Index].NumberOfPages;
117           CurrentMemoryDescriptor = &EfiMemoryDescriptor[Index];
118         }
119       }
120     }
121     if ((EfiMemoryDescriptor[Index].Type == EfiReservedMemoryType) ||
122         (EfiMemoryDescriptor[Index].Type >= EfiACPIReclaimMemory) ) {
123       continue;
124     }
125     if ((EfiMemoryDescriptor[Index].Type == EfiRuntimeServicesCode) ||
126         (EfiMemoryDescriptor[Index].Type == EfiRuntimeServicesData)) {
127       break;
128     }
129   }
130 
131   if (MaxPhysicalStart == 0) {
132     return 0;
133   }
134 
135   if (MaxNoPages != NoPages) {
136     CurrentMemoryDescriptor->NumberOfPages = MaxNoPages - NoPages;
137     EfiMemoryDescriptor[*NumberOfMemoryMapEntries].Type          = Type;
138     EfiMemoryDescriptor[*NumberOfMemoryMapEntries].PhysicalStart = MaxPhysicalStart + LShiftU64(MaxNoPages - NoPages, EFI_PAGE_SHIFT);
139     EfiMemoryDescriptor[*NumberOfMemoryMapEntries].NumberOfPages = NoPages;
140     EfiMemoryDescriptor[*NumberOfMemoryMapEntries].VirtualStart  = 0;
141     EfiMemoryDescriptor[*NumberOfMemoryMapEntries].Attribute     = Attribute;
142     *NumberOfMemoryMapEntries = *NumberOfMemoryMapEntries + 1;
143   } else {
144     CurrentMemoryDescriptor->Type      = Type;
145     CurrentMemoryDescriptor->Attribute = Attribute;
146   }
147 
148   return (UINTN)(MaxPhysicalStart + LShiftU64(MaxNoPages - NoPages, EFI_PAGE_SHIFT));
149 }
150 
151 VOID
GenMemoryMap(UINTN * NumberOfMemoryMapEntries,EFI_MEMORY_DESCRIPTOR * EfiMemoryDescriptor,BIOS_MEMORY_MAP * BiosMemoryMap)152 GenMemoryMap (
153   UINTN                 *NumberOfMemoryMapEntries,
154   EFI_MEMORY_DESCRIPTOR *EfiMemoryDescriptor,
155   BIOS_MEMORY_MAP       *BiosMemoryMap
156   )
157 {
158   UINT64                BaseAddress;
159   UINT64                Length;
160   EFI_MEMORY_TYPE       Type;
161   UINTN                 Index;
162   UINTN                 Attr;
163   UINT64                Ceiling;
164 
165   Ceiling = 0xFFFFFFFF;
166   for (Index = 0; Index < BiosMemoryMap->MemoryMapSize / sizeof(BIOS_MEMORY_MAP_ENTRY); Index++) {
167 
168     switch (BiosMemoryMap->MemoryMapEntry[Index].Type) {
169     case (INT15_E820_AddressRangeMemory):
170       Type = EfiConventionalMemory;
171       Attr = EFI_MEMORY_WB;
172       break;
173     case (INT15_E820_AddressRangeReserved):
174       Type = EfiReservedMemoryType;
175       Attr = EFI_MEMORY_UC;
176       break;
177     case (INT15_E820_AddressRangeACPI):
178       Type = EfiACPIReclaimMemory;
179       Attr = EFI_MEMORY_WB;
180       break;
181     case (INT15_E820_AddressRangeNVS):
182       Type = EfiACPIMemoryNVS;
183       Attr = EFI_MEMORY_UC;
184       break;
185     default:
186       // We should not get here, according to ACPI 2.0 Spec.
187       // BIOS behaviour of the Int15h, E820h
188       Type = EfiReservedMemoryType;
189       Attr = EFI_MEMORY_UC;
190       break;
191     }
192     if (Type == EfiConventionalMemory) {
193       BaseAddress = BiosMemoryMap->MemoryMapEntry[Index].BaseAddress;
194       Length      = BiosMemoryMap->MemoryMapEntry[Index].Length;
195       if (BaseAddress & EFI_PAGE_MASK) {
196         Length      = Length + (BaseAddress & EFI_PAGE_MASK) - EFI_PAGE_SIZE;
197         BaseAddress = LShiftU64 (RShiftU64 (BaseAddress, EFI_PAGE_SHIFT) + 1, EFI_PAGE_SHIFT);
198       }
199     } else {
200       BaseAddress = BiosMemoryMap->MemoryMapEntry[Index].BaseAddress;
201       Length      = BiosMemoryMap->MemoryMapEntry[Index].Length + (BaseAddress & EFI_PAGE_MASK);
202       BaseAddress = LShiftU64 (RShiftU64 (BaseAddress, EFI_PAGE_SHIFT), EFI_PAGE_SHIFT);
203       if (Length & EFI_PAGE_MASK) {
204         Length = LShiftU64 (RShiftU64 (Length, EFI_PAGE_SHIFT) + 1, EFI_PAGE_SHIFT);
205       }
206       //
207       // Update Memory Ceiling
208       //
209       if ((BaseAddress >= 0x100000) && (BaseAddress < 0x100000000ULL)) {
210         if (Ceiling > BaseAddress) {
211           Ceiling = BaseAddress;
212         }
213       }
214     }
215     EfiAddMemoryDescriptor (
216       NumberOfMemoryMapEntries,
217       EfiMemoryDescriptor,
218       Type,
219       (EFI_PHYSICAL_ADDRESS)BaseAddress,
220       RShiftU64 (Length, EFI_PAGE_SHIFT),
221       Attr
222       );
223   }
224 
225   //
226   // Update MemoryMap according to Ceiling
227   //
228   for (Index = 0; Index < *NumberOfMemoryMapEntries; Index++) {
229     if ((EfiMemoryDescriptor[Index].Type == EfiConventionalMemory) &&
230         (EfiMemoryDescriptor[Index].PhysicalStart > 0x100000) &&
231         (EfiMemoryDescriptor[Index].PhysicalStart < 0x100000000ULL)) {
232       if (EfiMemoryDescriptor[Index].PhysicalStart >= Ceiling) {
233         EfiMemoryDescriptor[Index].Type = EfiReservedMemoryType;
234       }
235     }
236   }
237 }
238