summaryrefslogtreecommitdiff
path: root/Library/Memory.c
blob: 387474f65012986818dae1b74d058a9f29ee1761 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
//*************************************************************************
//*************************************************************************
//**                                                                     **
//**        (C)Copyright 1985-2011, American Megatrends, Inc.            **
//**                                                                     **
//**                       All Rights Reserved.                          **
//**                                                                     **
//**      5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093           **
//**                                                                     **
//**                       Phone: (770)-246-8600                         **
//**                                                                     **
//*************************************************************************
//*************************************************************************

//*************************************************************************
// $Header: /Alaska/SOURCE/Core/Library/Memory.c 10    1/19/12 5:00p Markw $
//
// $Revision: 10 $
//
// $Date: 1/19/12 5:00p $
//*************************************************************************
// Revision History
// ----------------
// $Log: /Alaska/SOURCE/Core/Library/Memory.c $
// 
// 10    1/19/12 5:00p Markw
// [TAG]  		EIP81447
// [Category]  	Improvement
// [Description]  	Update page tables to use only 2 MB page tables below 4
// GB.
// Vista/Win7/Win2008 server doesn't parse 1 GB page tables correctly.
// [Files]  		memory.c
// 
// 9     4/26/11 10:45p Markw
// [TAG]  		EIP58991
// [Category]  	Improvement
// [Description]  	Support 1 GB page table size in 64-bit mode in DXE.
// [Files]  		memory.c
// 
// 8     7/10/09 3:49p Felixp
// Function headers added
// 
// 7     5/02/08 9:57a Felixp
// Bug fix in FillPageTable (Systems with x64 firmware and more than 4GB
// of memory were resetting during transition to DXE)
// 
// 6     4/17/08 3:27p Markw
// Add paging functions.
// 
// 5     8/24/06 9:26a Felixp
// Preliminary x64 support (work in progress):
// 1. Processor architecture specific functions moved to a processor
// library
// 2. Makefile removed (AmiLib files are build by the AmiPeiLib and
// AmeDxeLib makefile)
// 3. Tokens.c added
// 
// 4     6/22/05 12:52p Felixp
// MemSet changes: bug fix (problem with Counter<4); comments added
// 
// 3     3/04/05 10:50a Mandal
// 
//*************************************************************************
//<AMI_FHDR_START>
//
// Name: Memory.c
//
// Description: 
//  Contains memory related library functions.
//
//<AMI_FHDR_END>
//*************************************************************************
#include <efi.h>
#include <AmiLib.h>

//*************************************************************************
//<AMI_GHDR_START>
//
// Name: Memory_Functions
//
// Description:
//  Memory functions defined in the AMI library.  Note some may only be
// available in DXE.
//
// Fields: Header Function Description
// ------------------------------------------------------------------
// AmiLib    MemSet   Fills a buffer with a user provided value. 
// AmiLib    MemCmp   Compare two buffers for equality.
// AmiLIb    MemCpy   Copy a buffer into another buffer.
// AmiDxeLib Malloc   Allocate memory from EfiBootServicesData.
// AmiDxeLib MallocZ  Allocate memory from EfiBootServicesData that has been cleared with zeros.
//
// Notes:
//  Header details which header file contains the function prototype for
// the above functions.  Append .h to the given name.
//  
//<AMI_GHDR_END>
//*************************************************************************

VOID CPULib_CpuID(IN UINT32 CpuIDIndex, OUT UINT32 *RegEAX, OUT UINT32 *RegEBX, 
  IN OUT UINT32 *RegECX, OUT UINT32 *RegEDX);

//*************************************************************************
//<AMI_PHDR_START>
//
// Name: MemCmp
//
// Description:	
//  INTN MemCmp(IN VOID* pDestination, IN VOID* pSource, IN UINTN Count)
// compares Length bytes of pDestination to Length bytes of pSource.  If all
// Length bytes of the two buffers are identical, then 0 is returned.
// Otherwise, the value returned is the first mismatched byte in pSource
// subtracted from the first mismatched byte in pDestination.
//
// Input:
//  IN VOID* pDestination
// Pointer to the first buffer to compare.
//
//  IN VOID* pSource
// Pointer to the second buffer to compare.
//
//  IN UINTN Count
// Number of bytes to compare.
//
// Output:
//  INTN value of first mismatched byte in pSource subtracted from the first
// mismatched byte in pDestination (pDestination - pSource). Returns 0 if
// both buffers are the same. 
//
// Modified:
//
// Referrals:
// 
// Notes:	
//          
//<AMI_PHDR_END>
//*************************************************************************
INTN MemCmp(VOID* pDestination, VOID* pSource, UINTN Count){
    INT8 *d = (UINT8*)pDestination, *s = (UINT8*)pSource;
    INT8 *end=d+Count;
    UINTN r;
////////////////////////////////////////////////////////////
// NOTE: in order to increase the comparison speed we will
// compare sizeof(UINTN) bytes at a time if possible.
// Once inequality is found, we will go to the last while loop
// to do a byte by byte comparison to get proper results.
// We have to do it because of the following:
// Let's say we are trying to compare values: 0x1234 and 0x4321:
// If we compare them as double words the second value will be greater.
// If we compare them byte by byte the first value wiill be greater
// (because of little endian architecture of x86)
////////////////////////////////////////////////////////////
    if (Count >= sizeof(UINTN)){
        r = (UINTN)d & (sizeof(UINTN)-1);
        if (r && r== ((UINTN)s & (sizeof(UINTN)-1))){
            r = sizeof(UINTN)-r;
            Count-=r;
            for(;r;r--) 
                if (*d==*s){d++;s++;}
                //the values are not equal 
                //let's break to do a byte by byte comparison 
                //to figure out which one is greater
                else break;
        }
        while(d<=end-sizeof(UINTN)) 
            if (*(UINTN*)d==*(UINTN*)s){
                d+=sizeof(UINTN);s+=sizeof(UINTN);
            }
            //the values are not equal 
            //let's break to do a byte by byte comparison 
            //to figure out which one is greater
            else break; 
    }
    while(d<end)
        if (*d==*s){d++;s++;}
        else return *d-*s;
    return 0;
}

//*************************************************************************
//<AMI_PHDR_START>
//
// Name: GetPageTableNumPages
//
// Description:
//  UINT32 GetPageTableNumPages(IN UINT8 NumberMemoryBits) gets the number
// of pages to allocate for paging.
// Unlimited if 1 GB page tables is supported. Otherwise, limit 512 MB address space.
//
// Input:
//  IN UINT8 NumberMemoryBits
// Number of memory bits to map.
//
// Output:
//  UINT32 number of pages.
//
// Modified:
//
// Referrals:
//  Shl64
//  CPULib_CpuID
// 
// Notes:	
//          
//<AMI_PHDR_END>
//*************************************************************************
UINT32 GetPageTableNumPages(
    IN UINT8 NumberMemoryBits
)
{
    BOOLEAN GigPageSupport;
    UINT32 RegEax, RegEbx, RegEcx, RegEdx;
    UINT32 NumPages;

    CPULib_CpuID(0x80000001, &RegEax, &RegEbx, &RegEcx, &RegEdx);
    GigPageSupport = !!(RegEdx & BIT26);

    //Limit number of memory bits to 39 (512 GB) if no support for GB page-tables.
    if (!GigPageSupport && NumberMemoryBits > 39) NumberMemoryBits = 39;

    if (GigPageSupport) {
    	//1 page for PML4E Table.
        //4 page for for Directory. First 4GB of 2MB pages.
        //1 Page for Page-Table Entries for 1st 2MB of 4k pages.        
        NumPages = 6;

        //Allocate pages for directory pointers.
        NumPages += 1 << (NumberMemoryBits > 39 ? NumberMemoryBits - 39 : 0);
   } else {
    	//Allocate at least 7 pages to cover Identity Mapping for 32 bits.
    	//1 page for PML4E Table
    	//1 page for Page-Directory Pointer
        //Pages for Directory allocated later--one for each directory.
        //1 page for Page-Table Entries for 1st 2MB. This must be 4k blocks.
        NumPages = 3;
    
        //Allocate pages for page directories.
        NumPages += 1 << (NumberMemoryBits - 30);
    }
    return NumPages;
}

//*************************************************************************
//<AMI_PHDR_START>
//
// Name: FillPageTable
//
// Description:
//  VOID FillPageTable(IN UINT8 NumberMemoryBits, IN VOID *PageTable) fills a
// provided page table with an identity map.
//
// Input:
//  IN UINT8 NumberMemoryBits
// Number of memory bits to map.
//
//  IN VOID *PageTable
// Page table to fill.
//
// Output:
//  VOID.
//
// Modified:
//
// Referrals:
//  Shl64
//  MemSet
//  CPULib_CpuID
// 
// Notes:	
//          
//<AMI_PHDR_END>
//*************************************************************************
VOID FillPageTable(
    IN UINT8  NumberMemoryBits,
    IN VOID   *PageTable
)
{
    BOOLEAN GigPageSupport;
    UINT32 RegEax, RegEbx, RegEcx, RegEdx;
    UINT64 *Pml4eTable = (UINT64*)PageTable;
	UINT64 *PdpTable   = (UINT64*)((UINT8*)PageTable + 0x1000);
	UINT64 *PDir;
    UINT64 *PTableEntry;
    UINT32 NumPml4Entries;
    UINT32 NumPgDirPtrEntries;
    UINT32 NumPgDirEntries;
    UINT32 i;

    CPULib_CpuID(0x80000001, &RegEax, &RegEbx, &RegEcx, &RegEdx);
    GigPageSupport = !!(RegEdx & BIT26);

    //Limit number of memory bits to 39 (512 GB) if no support for GB page-tables.
    if (!GigPageSupport && NumberMemoryBits > 39) NumberMemoryBits = 39;

	// Update Page-Map Level-4 tables.
    NumPml4Entries =  1 << (NumberMemoryBits > 39 ? NumberMemoryBits - 39 : 0);
    for (i = 0; i < NumPml4Entries; ++i) Pml4eTable[i] = BIT0 + BIT1 + (i << 12) + (UINT64)(UINTN)PdpTable;
	MemSet(Pml4eTable + i, 4096 - 8 * i, 0);	//Clear unused entries.

	//Update Page Pointer Directories.
    NumPgDirPtrEntries = 1 << (NumberMemoryBits - 30);
    PDir = PdpTable + (NumPgDirPtrEntries <= 512 ? 512 : NumPgDirPtrEntries);
    if (GigPageSupport) {
        //1st 4 pages must point to a Page directory
        PdpTable[0] = BIT0 + BIT1 + (0 << 12) + (UINT64)(UINTN)PDir;
        PdpTable[1] = BIT0 + BIT1 + (1 << 12) + (UINT64)(UINTN)PDir;
        PdpTable[2] = BIT0 + BIT1 + (2 << 12) + (UINT64)(UINTN)PDir;
        PdpTable[3] = BIT0 + BIT1 + (3 << 12) + (UINT64)(UINTN)PDir;
        for (i = 4; i <  NumPgDirPtrEntries; ++i)
            PdpTable[i] = BIT0 + BIT1 + BIT7 + Shl64(i, 30);
    } else {
        for (i = 0; i <  NumPgDirPtrEntries; ++i)
            PdpTable[i] = BIT0 + BIT1 + (i << 12) + (UINT64)(UINTN)PDir;
    }
    if (i < 512) MemSet(PdpTable + i, 4096 - 8 * i, 0);	//Clear unused entries.

	//Initialize Page Directores.
    if (GigPageSupport) NumPgDirEntries = 2048;  //First 4 GB
    else NumPgDirEntries = 1 << (NumberMemoryBits - 21); //Number of 2MB pages.
    PTableEntry = PDir + NumPgDirEntries;
    PDir[0] = BIT0 + BIT1 + (UINT64)(UINTN)PTableEntry;  //4K Page Table for first 2MB.
	for(i = 1; i < NumPgDirEntries; ++i) PDir[i] = 0x83 + Shl64(i, 21); 

    //Initialize 4k page entries for first 2MB.
    for(i = 0; i < 512; ++i) PTableEntry[i] = BIT0 + BIT1 + (i << 12);
}

//*************************************************************************
//*************************************************************************
//**                                                                     **
//**        (C)Copyright 1985-2011, American Megatrends, Inc.            **
//**                                                                     **
//**                       All Rights Reserved.                          **
//**                                                                     **
//**      5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093           **
//**                                                                     **
//**                       Phone: (770)-246-8600                         **
//**                                                                     **
//*************************************************************************
//*************************************************************************