]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBios.c
IntelFrameworkModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / IntelFrameworkModulePkg / Csm / LegacyBiosDxe / LegacyBios.c
CommitLineData
bcecde14 1/** @file\r
2\r
b22a62be 3Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
bcecde14 4\r
c0a00b14 5SPDX-License-Identifier: BSD-2-Clause-Patent\r
bcecde14 6\r
7**/\r
8\r
9#include "LegacyBiosInterface.h"\r
10\r
11#define PHYSICAL_ADDRESS_TO_POINTER(Address) ((VOID *) ((UINTN) Address))\r
12\r
13//\r
14// define maximum number of HDD system supports\r
15//\r
16#define MAX_HDD_ENTRIES 0x30\r
17\r
18//\r
19// Module Global:\r
20// Since this driver will only ever produce one instance of the Private Data\r
21// protocol you are not required to dynamically allocate the PrivateData.\r
22//\r
23LEGACY_BIOS_INSTANCE mPrivateData;\r
24\r
b6823730
EL
25//\r
26// The SMBIOS table in EfiRuntimeServicesData memory\r
27//\r
28VOID *mRuntimeSmbiosEntryPoint = NULL;\r
29\r
30//\r
31// The SMBIOS table in EfiReservedMemoryType memory\r
32//\r
33EFI_PHYSICAL_ADDRESS mReserveSmbiosEntryPoint = 0;\r
34EFI_PHYSICAL_ADDRESS mStructureTableAddress = 0;\r
35UINTN mStructureTablePages = 0;\r
d057d8c4 36BOOLEAN mEndOfDxe = FALSE;\r
b6823730 37\r
bcecde14 38/**\r
cd25509b 39 Allocate memory for legacy usage. The memory is executable.\r
bcecde14 40\r
b22a62be
RN
41 @param AllocateType The type of allocation to perform.\r
42 @param MemoryType The type of memory to allocate.\r
bcecde14 43 @param StartPageAddress Start address of range\r
44 @param Pages Number of pages to allocate\r
45 @param Result Result of allocation\r
46\r
cd25509b
RN
47 @retval EFI_SUCCESS Legacy memory is allocated successfully.\r
48 @retval Other Legacy memory is not allocated.\r
bcecde14 49\r
50**/\r
51EFI_STATUS\r
52AllocateLegacyMemory (\r
53 IN EFI_ALLOCATE_TYPE AllocateType,\r
b22a62be 54 IN EFI_MEMORY_TYPE MemoryType,\r
bcecde14 55 IN EFI_PHYSICAL_ADDRESS StartPageAddress,\r
56 IN UINTN Pages,\r
57 OUT EFI_PHYSICAL_ADDRESS *Result\r
58 )\r
59{\r
cd25509b
RN
60 EFI_STATUS Status;\r
61 EFI_PHYSICAL_ADDRESS MemPage;\r
62 EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemDesc;\r
bcecde14 63\r
64 //\r
65 // Allocate Pages of memory less <= StartPageAddress\r
66 //\r
67 MemPage = (EFI_PHYSICAL_ADDRESS) (UINTN) StartPageAddress;\r
68 Status = gBS->AllocatePages (\r
69 AllocateType,\r
b22a62be 70 MemoryType,\r
bcecde14 71 Pages,\r
72 &MemPage\r
73 );\r
74 //\r
75 // Do not ASSERT on Status error but let caller decide since some cases\r
76 // memory is already taken but that is ok.\r
77 //\r
cd25509b
RN
78 if (!EFI_ERROR (Status)) {\r
79 if (MemoryType != EfiBootServicesCode) {\r
80 //\r
81 // Make sure that the buffer can be used to store code.\r
82 //\r
83 Status = gDS->GetMemorySpaceDescriptor (MemPage, &MemDesc);\r
84 if (!EFI_ERROR (Status) && (MemDesc.Attributes & EFI_MEMORY_XP) != 0) {\r
85 Status = gDS->SetMemorySpaceAttributes (\r
86 MemPage,\r
87 EFI_PAGES_TO_SIZE (Pages),\r
88 MemDesc.Attributes & (~EFI_MEMORY_XP)\r
89 );\r
90 }\r
91 if (EFI_ERROR (Status)) {\r
92 gBS->FreePages (MemPage, Pages);\r
93 }\r
94 }\r
95 }\r
96\r
bcecde14 97 if (!EFI_ERROR (Status)) {\r
98 *Result = (EFI_PHYSICAL_ADDRESS) (UINTN) MemPage;\r
99 }\r
cd25509b 100\r
bcecde14 101 return Status;\r
102}\r
103\r
104\r
105/**\r
106 This function is called when EFI needs to reserve an area in the 0xE0000 or 0xF0000\r
107 64 KB blocks.\r
108\r
109 Note: inconsistency with the Framework CSM spec. Per the spec, this function may be\r
110 invoked only once. This limitation is relaxed to allow multiple calls in this implemenation.\r
111\r
112 @param This Protocol instance pointer.\r
113 @param LegacyMemorySize Size of required region\r
114 @param Region Region to use. 00 = Either 0xE0000 or 0xF0000\r
115 block Bit0 = 1 0xF0000 block Bit1 = 1 0xE0000\r
116 block\r
117 @param Alignment Address alignment. Bit mapped. First non-zero\r
118 bit from right is alignment.\r
119 @param LegacyMemoryAddress Region Assigned\r
120\r
121 @retval EFI_SUCCESS Region assigned\r
122 @retval EFI_ACCESS_DENIED Procedure previously invoked\r
123 @retval Other Region not assigned\r
124\r
125**/\r
126EFI_STATUS\r
127EFIAPI\r
128LegacyBiosGetLegacyRegion (\r
129 IN EFI_LEGACY_BIOS_PROTOCOL *This,\r
130 IN UINTN LegacyMemorySize,\r
131 IN UINTN Region,\r
132 IN UINTN Alignment,\r
133 OUT VOID **LegacyMemoryAddress\r
134 )\r
135{\r
136\r
137 LEGACY_BIOS_INSTANCE *Private;\r
138 EFI_IA32_REGISTER_SET Regs;\r
139 EFI_STATUS Status;\r
140 UINT32 Granularity;\r
141\r
142 Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r
143 Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);\r
144\r
145 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
146 Regs.X.AX = Legacy16GetTableAddress;\r
147 Regs.X.BX = (UINT16) Region;\r
148 Regs.X.CX = (UINT16) LegacyMemorySize;\r
149 Regs.X.DX = (UINT16) Alignment;\r
150 Private->LegacyBios.FarCall86 (\r
151 &Private->LegacyBios,\r
152 Private->Legacy16CallSegment,\r
153 Private->Legacy16CallOffset,\r
154 &Regs,\r
155 NULL,\r
156 0\r
157 );\r
158\r
159 if (Regs.X.AX == 0) {\r
aa5f60ae 160 *LegacyMemoryAddress = (VOID *) (((UINTN) Regs.X.DS << 4) + Regs.X.BX);\r
bcecde14 161 Status = EFI_SUCCESS;\r
162 } else {\r
163 Status = EFI_OUT_OF_RESOURCES;\r
164 }\r
165\r
166 Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);\r
167 Private->LegacyRegion->Lock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);\r
168\r
169 return Status;\r
170}\r
171\r
172\r
173/**\r
174 This function is called when copying data to the region assigned by\r
175 EFI_LEGACY_BIOS_PROTOCOL.GetLegacyRegion().\r
176\r
177 @param This Protocol instance pointer.\r
178 @param LegacyMemorySize Size of data to copy\r
179 @param LegacyMemoryAddress Legacy Region destination address Note: must\r
180 be in region assigned by\r
181 LegacyBiosGetLegacyRegion\r
182 @param LegacyMemorySourceAddress Source of data\r
183\r
184 @retval EFI_SUCCESS The data was copied successfully.\r
185 @retval EFI_ACCESS_DENIED Either the starting or ending address is out of bounds.\r
186**/\r
187EFI_STATUS\r
188EFIAPI\r
189LegacyBiosCopyLegacyRegion (\r
190 IN EFI_LEGACY_BIOS_PROTOCOL *This,\r
191 IN UINTN LegacyMemorySize,\r
192 IN VOID *LegacyMemoryAddress,\r
193 IN VOID *LegacyMemorySourceAddress\r
194 )\r
195{\r
196\r
197 LEGACY_BIOS_INSTANCE *Private;\r
198 UINT32 Granularity;\r
199\r
200 if ((LegacyMemoryAddress < (VOID *)(UINTN)0xE0000 ) ||\r
201 ((UINTN) LegacyMemoryAddress + LegacyMemorySize > (UINTN) 0x100000)\r
202 ) {\r
203 return EFI_ACCESS_DENIED;\r
204 }\r
205 //\r
206 // There is no protection from writes over lapping if this function is\r
207 // called multiple times.\r
208 //\r
209 Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r
210 Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);\r
211 CopyMem (LegacyMemoryAddress, LegacyMemorySourceAddress, LegacyMemorySize);\r
212\r
213 Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);\r
214 Private->LegacyRegion->Lock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);\r
215\r
216 return EFI_SUCCESS;\r
217}\r
218\r
219\r
220/**\r
221 Find Legacy16 BIOS image in the FLASH device and shadow it into memory. Find\r
222 the $EFI table in the shadow area. Thunk into the Legacy16 code after it had\r
223 been shadowed.\r
224\r
225 @param Private Legacy BIOS context data\r
226\r
227 @retval EFI_SUCCESS Legacy16 code loaded\r
228 @retval Other No protocol installed, unload driver.\r
229\r
230**/\r
231EFI_STATUS\r
232ShadowAndStartLegacy16 (\r
233 IN LEGACY_BIOS_INSTANCE *Private\r
234 )\r
235{\r
236 EFI_STATUS Status;\r
237 UINT8 *Ptr;\r
238 UINT8 *PtrEnd;\r
239 BOOLEAN Done;\r
240 EFI_COMPATIBILITY16_TABLE *Table;\r
241 UINT8 CheckSum;\r
242 EFI_IA32_REGISTER_SET Regs;\r
243 EFI_TO_COMPATIBILITY16_INIT_TABLE *EfiToLegacy16InitTable;\r
244 EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;\r
245 VOID *LegacyBiosImage;\r
246 UINTN LegacyBiosImageSize;\r
247 UINTN E820Size;\r
248 UINT32 *ClearPtr;\r
249 BBS_TABLE *BbsTable;\r
250 LEGACY_EFI_HDD_TABLE *LegacyEfiHddTable;\r
251 UINTN Index;\r
252 UINT32 TpmPointer;\r
253 VOID *TpmBinaryImage;\r
254 UINTN TpmBinaryImageSize;\r
255 UINTN Location;\r
256 UINTN Alignment;\r
257 UINTN TempData;\r
258 EFI_PHYSICAL_ADDRESS Address;\r
259 UINT16 OldMask;\r
260 UINT16 NewMask;\r
261 UINT32 Granularity;\r
262 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;\r
263\r
264 Location = 0;\r
265 Alignment = 0;\r
266\r
267 //\r
268 // we allocate the C/D/E/F segment as RT code so no one will use it any more.\r
269 //\r
270 Address = 0xC0000;\r
271 gDS->GetMemorySpaceDescriptor (Address, &Descriptor);\r
272 if (Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) {\r
273 //\r
274 // If it is already reserved, we should be safe, or else we allocate it.\r
275 //\r
276 Status = gBS->AllocatePages (\r
277 AllocateAddress,\r
278 EfiRuntimeServicesCode,\r
279 0x40000/EFI_PAGE_SIZE,\r
280 &Address\r
281 );\r
282 if (EFI_ERROR (Status)) {\r
283 //\r
284 // Bugbug: need to figure out whether C/D/E/F segment should be marked as reserved memory.\r
0a6f4824 285 //\r
bcecde14 286 DEBUG ((DEBUG_ERROR, "Failed to allocate the C/D/E/F segment Status = %r", Status));\r
287 }\r
288 }\r
289\r
290 //\r
291 // start testtest\r
292 // GetTimerValue (&Ticker);\r
293 //\r
294 // gRT->SetVariable (L"StartLegacy",\r
295 // &gEfiGlobalVariableGuid,\r
296 // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
297 // sizeof (UINT64),\r
298 // (VOID *)&Ticker\r
299 // );\r
300 // end testtest\r
301 //\r
302 EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;\r
303 Status = Private->LegacyBiosPlatform->GetPlatformInfo (\r
304 Private->LegacyBiosPlatform,\r
305 EfiGetPlatformBinarySystemRom,\r
306 &LegacyBiosImage,\r
307 &LegacyBiosImageSize,\r
308 &Location,\r
309 &Alignment,\r
310 0,\r
311 0\r
312 );\r
313 if (EFI_ERROR (Status)) {\r
314 return Status;\r
315 }\r
316\r
317 Private->BiosStart = (UINT32) (0x100000 - LegacyBiosImageSize);\r
318 Private->OptionRom = 0xc0000;\r
319 Private->LegacyBiosImageSize = (UINT32) LegacyBiosImageSize;\r
320\r
321 //\r
322 // Can only shadow into memory allocated for legacy useage.\r
323 //\r
324 ASSERT (Private->BiosStart > Private->OptionRom);\r
325\r
326 //\r
327 // Shadow Legacy BIOS. Turn on memory and copy image\r
328 //\r
329 Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xc0000, 0x40000, &Granularity);\r
330\r
331 ClearPtr = (VOID *) ((UINTN) 0xc0000);\r
332\r
333 //\r
334 // Initialize region from 0xc0000 to start of BIOS to all ffs. This allows unused\r
335 // regions to be used by EMM386 etc.\r
336 //\r
337 SetMem ((VOID *) ClearPtr, (UINTN) (0x40000 - LegacyBiosImageSize), 0xff);\r
338\r
339 TempData = Private->BiosStart;\r
340\r
341 CopyMem (\r
342 (VOID *) TempData,\r
343 LegacyBiosImage,\r
344 (UINTN) LegacyBiosImageSize\r
345 );\r
346\r
347 Private->Cpu->FlushDataCache (Private->Cpu, 0xc0000, 0x40000, EfiCpuFlushTypeWriteBackInvalidate);\r
348\r
349 //\r
350 // Search for Legacy16 table in Shadowed ROM\r
351 //\r
352 Done = FALSE;\r
353 Table = NULL;\r
354 for (Ptr = (UINT8 *) TempData; Ptr < (UINT8 *) ((UINTN) 0x100000) && !Done; Ptr += 0x10) {\r
355 if (*(UINT32 *) Ptr == SIGNATURE_32 ('I', 'F', 'E', '$')) {\r
356 Table = (EFI_COMPATIBILITY16_TABLE *) Ptr;\r
357 PtrEnd = Ptr + Table->TableLength;\r
358 for (CheckSum = 0; Ptr < PtrEnd; Ptr++) {\r
359 CheckSum = (UINT8) (CheckSum +*Ptr);\r
360 }\r
361\r
362 Done = TRUE;\r
363 }\r
364 }\r
365\r
366 if (Table == NULL) {\r
367 DEBUG ((EFI_D_ERROR, "No Legacy16 table found\n"));\r
368 return EFI_NOT_FOUND;\r
369 }\r
370\r
371 if (!Done) {\r
372 //\r
373 // Legacy16 table header checksum error.\r
374 //\r
375 DEBUG ((EFI_D_ERROR, "Legacy16 table found with bad talbe header checksum\n"));\r
376 }\r
377\r
378 //\r
379 // Remember location of the Legacy16 table\r
380 //\r
381 Private->Legacy16Table = Table;\r
382 Private->Legacy16CallSegment = Table->Compatibility16CallSegment;\r
383 Private->Legacy16CallOffset = Table->Compatibility16CallOffset;\r
384 EfiToLegacy16InitTable = &Private->IntThunk->EfiToLegacy16InitTable;\r
385 Private->Legacy16InitPtr = EfiToLegacy16InitTable;\r
386 Private->Legacy16BootPtr = &Private->IntThunk->EfiToLegacy16BootTable;\r
387 Private->InternalIrqRoutingTable = NULL;\r
388 Private->NumberIrqRoutingEntries = 0;\r
389 Private->BbsTablePtr = NULL;\r
390 Private->LegacyEfiHddTable = NULL;\r
391 Private->DiskEnd = 0;\r
392 Private->Disk4075 = 0;\r
393 Private->HddTablePtr = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo;\r
394 Private->NumberHddControllers = MAX_IDE_CONTROLLER;\r
395 Private->Dump[0] = 'D';\r
396 Private->Dump[1] = 'U';\r
397 Private->Dump[2] = 'M';\r
398 Private->Dump[3] = 'P';\r
399\r
400 ZeroMem (\r
401 Private->Legacy16BootPtr,\r
402 sizeof (EFI_TO_COMPATIBILITY16_BOOT_TABLE)\r
403 );\r
404\r
405 //\r
406 // Store away a copy of the EFI System Table\r
407 //\r
408 Table->EfiSystemTable = (UINT32) (UINTN) gST;\r
409\r
bcecde14 410 //\r
411 // IPF CSM integration -Bug\r
412 //\r
413 // Construct the Legacy16 boot memory map. This sets up number of\r
414 // E820 entries.\r
415 //\r
416 LegacyBiosBuildE820 (Private, &E820Size);\r
417 //\r
418 // Initialize BDA and EBDA standard values needed to load Legacy16 code\r
419 //\r
420 LegacyBiosInitBda (Private);\r
421 LegacyBiosInitCmos (Private);\r
422\r
423 //\r
424 // All legacy interrupt should be masked when do initialization work from legacy 16 code.\r
425 //\r
426 Private->Legacy8259->GetMask(Private->Legacy8259, &OldMask, NULL, NULL, NULL);\r
427 NewMask = 0xFFFF;\r
428 Private->Legacy8259->SetMask(Private->Legacy8259, &NewMask, NULL, NULL, NULL);\r
0a6f4824 429\r
bcecde14 430 //\r
431 // Call into Legacy16 code to do an INIT\r
432 //\r
433 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
434 Regs.X.AX = Legacy16InitializeYourself;\r
435 Regs.X.ES = EFI_SEGMENT (*((UINT32 *) &EfiToLegacy16InitTable));\r
436 Regs.X.BX = EFI_OFFSET (*((UINT32 *) &EfiToLegacy16InitTable));\r
437\r
438 Private->LegacyBios.FarCall86 (\r
439 &Private->LegacyBios,\r
440 Table->Compatibility16CallSegment,\r
441 Table->Compatibility16CallOffset,\r
442 &Regs,\r
443 NULL,\r
444 0\r
445 );\r
446\r
447 //\r
448 // Restore original legacy interrupt mask value\r
449 //\r
450 Private->Legacy8259->SetMask(Private->Legacy8259, &OldMask, NULL, NULL, NULL);\r
0a6f4824 451\r
bcecde14 452 if (Regs.X.AX != 0) {\r
453 return EFI_DEVICE_ERROR;\r
454 }\r
455\r
456 //\r
457 // start testtest\r
458 // GetTimerValue (&Ticker);\r
459 //\r
460 // gRT->SetVariable (L"BackFromInitYourself",\r
461 // &gEfiGlobalVariableGuid,\r
462 // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
463 // sizeof (UINT64),\r
464 // (VOID *)&Ticker\r
465 // );\r
466 // end testtest\r
467 //\r
468 // Copy E820 table after InitializeYourself is completed\r
469 //\r
470 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
471 Regs.X.AX = Legacy16GetTableAddress;\r
472 Regs.X.CX = (UINT16) E820Size;\r
473 Regs.X.DX = 1;\r
474 Private->LegacyBios.FarCall86 (\r
475 &Private->LegacyBios,\r
476 Table->Compatibility16CallSegment,\r
477 Table->Compatibility16CallOffset,\r
478 &Regs,\r
479 NULL,\r
480 0\r
481 );\r
482\r
483 Table->E820Pointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);\r
484 Table->E820Length = (UINT32) E820Size;\r
485 if (Regs.X.AX != 0) {\r
486 DEBUG ((EFI_D_ERROR, "Legacy16 E820 length insufficient\n"));\r
487 } else {\r
488 TempData = Table->E820Pointer;\r
489 CopyMem ((VOID *) TempData, Private->E820Table, E820Size);\r
490 }\r
491 //\r
492 // Get PnPInstallationCheck Info.\r
493 //\r
494 Private->PnPInstallationCheckSegment = Table->PnPInstallationCheckSegment;\r
495 Private->PnPInstallationCheckOffset = Table->PnPInstallationCheckOffset;\r
496\r
497 //\r
498 // Check if PCI Express is supported. If yes, Save base address.\r
499 //\r
500 Status = Private->LegacyBiosPlatform->GetPlatformInfo (\r
501 Private->LegacyBiosPlatform,\r
502 EfiGetPlatformPciExpressBase,\r
503 NULL,\r
504 NULL,\r
505 &Location,\r
506 &Alignment,\r
507 0,\r
508 0\r
509 );\r
510 if (!EFI_ERROR (Status)) {\r
511 Private->Legacy16Table->PciExpressBase = (UINT32)Location;\r
512 Location = 0;\r
513 }\r
514 //\r
515 // Check if TPM is supported. If yes get a region in E0000,F0000 to copy it\r
516 // into, copy it and update pointer to binary image. This needs to be\r
517 // done prior to any OPROM for security purposes.\r
518 //\r
519 Status = Private->LegacyBiosPlatform->GetPlatformInfo (\r
520 Private->LegacyBiosPlatform,\r
521 EfiGetPlatformBinaryTpmBinary,\r
522 &TpmBinaryImage,\r
523 &TpmBinaryImageSize,\r
524 &Location,\r
525 &Alignment,\r
526 0,\r
527 0\r
528 );\r
529 if (!EFI_ERROR (Status)) {\r
530\r
531 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
532 Regs.X.AX = Legacy16GetTableAddress;\r
533 Regs.X.CX = (UINT16) TpmBinaryImageSize;\r
534 Regs.X.DX = 1;\r
535 Private->LegacyBios.FarCall86 (\r
536 &Private->LegacyBios,\r
537 Table->Compatibility16CallSegment,\r
538 Table->Compatibility16CallOffset,\r
539 &Regs,\r
540 NULL,\r
541 0\r
542 );\r
543\r
544 TpmPointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);\r
545 if (Regs.X.AX != 0) {\r
546 DEBUG ((EFI_D_ERROR, "TPM cannot be loaded\n"));\r
547 } else {\r
548 CopyMem ((VOID *) (UINTN)TpmPointer, TpmBinaryImage, TpmBinaryImageSize);\r
549 Table->TpmSegment = Regs.X.DS;\r
550 Table->TpmOffset = Regs.X.BX;\r
551\r
552 }\r
553 }\r
554 //\r
555 // Lock the Legacy BIOS region\r
556 //\r
557 Private->Cpu->FlushDataCache (Private->Cpu, Private->BiosStart, (UINT32) LegacyBiosImageSize, EfiCpuFlushTypeWriteBackInvalidate);\r
558 Private->LegacyRegion->Lock (Private->LegacyRegion, Private->BiosStart, (UINT32) LegacyBiosImageSize, &Granularity);\r
559\r
560 //\r
561 // Get the BbsTable from LOW_MEMORY_THUNK\r
562 //\r
563 BbsTable = (BBS_TABLE *)(UINTN)Private->IntThunk->BbsTable;\r
564 ZeroMem ((VOID *)BbsTable, sizeof (Private->IntThunk->BbsTable));\r
565\r
566 EfiToLegacy16BootTable->BbsTable = (UINT32)(UINTN)BbsTable;\r
567 Private->BbsTablePtr = (VOID *) BbsTable;\r
568 //\r
569 // Skip Floppy and possible onboard IDE drives\r
570 //\r
571 EfiToLegacy16BootTable->NumberBbsEntries = 1 + 2 * MAX_IDE_CONTROLLER;\r
572\r
573 for (Index = 0; Index < (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE)); Index++) {\r
574 BbsTable[Index].BootPriority = BBS_IGNORE_ENTRY;\r
575 }\r
576 //\r
577 // Allocate space for Legacy HDD table\r
578 //\r
579 LegacyEfiHddTable = (LEGACY_EFI_HDD_TABLE *) AllocateZeroPool ((UINTN) MAX_HDD_ENTRIES * sizeof (LEGACY_EFI_HDD_TABLE));\r
580 ASSERT (LegacyEfiHddTable);\r
581\r
582 Private->LegacyEfiHddTable = LegacyEfiHddTable;\r
583 Private->LegacyEfiHddTableIndex = 0x00;\r
584\r
585 //\r
586 // start testtest\r
587 // GetTimerValue (&Ticker);\r
588 //\r
589 // gRT->SetVariable (L"EndOfLoadFv",\r
590 // &gEfiGlobalVariableGuid,\r
591 // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
592 // sizeof (UINT64),\r
593 // (VOID *)&Ticker\r
594 // );\r
595 // end testtest\r
596 //\r
597 return EFI_SUCCESS;\r
598}\r
599\r
600/**\r
601 Shadow all legacy16 OPROMs that haven't been shadowed.\r
602 Warning: Use this with caution. This routine disconnects all EFI\r
603 drivers. If used externally then caller must re-connect EFI\r
604 drivers.\r
605\r
606 @param This Protocol instance pointer.\r
607\r
608 @retval EFI_SUCCESS OPROMs shadowed\r
609\r
610**/\r
611EFI_STATUS\r
612EFIAPI\r
613LegacyBiosShadowAllLegacyOproms (\r
614 IN EFI_LEGACY_BIOS_PROTOCOL *This\r
615 )\r
616{\r
617 LEGACY_BIOS_INSTANCE *Private;\r
618\r
619 //\r
620 // EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;\r
621 // EFI_LEGACY16_TABLE *Legacy16Table;\r
622 //\r
623 Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r
624\r
625 //\r
626 // LegacyBiosPlatform = Private->LegacyBiosPlatform;\r
627 // Legacy16Table = Private->Legacy16Table;\r
628 //\r
629 // Shadow PCI ROMs. We must do this near the end since this will kick\r
630 // of Native EFI drivers that may be needed to collect info for Legacy16\r
631 //\r
632 // WARNING: PciIo is gone after this call.\r
633 //\r
634 PciProgramAllInterruptLineRegisters (Private);\r
635\r
636 PciShadowRoms (Private);\r
637\r
638 //\r
639 // Shadow PXE base code, BIS etc.\r
640 //\r
641 // LegacyBiosPlatform->ShadowServiceRoms (LegacyBiosPlatform,\r
642 // &Private->OptionRom,\r
643 // Legacy16Table);\r
644 //\r
645 return EFI_SUCCESS;\r
646}\r
647\r
648/**\r
649 Get the PCI BIOS interface version.\r
650\r
651 @param Private Driver private data.\r
652\r
653 @return The PCI interface version number in Binary Coded Decimal (BCD) format.\r
654 E.g.: 0x0210 indicates 2.10, 0x0300 indicates 3.00\r
655\r
656**/\r
657UINT16\r
658GetPciInterfaceVersion (\r
659 IN LEGACY_BIOS_INSTANCE *Private\r
660 )\r
661{\r
662 EFI_IA32_REGISTER_SET Reg;\r
663 BOOLEAN ThunkFailed;\r
664 UINT16 PciInterfaceVersion;\r
665\r
666 PciInterfaceVersion = 0;\r
0a6f4824 667\r
bcecde14 668 Reg.X.AX = 0xB101;\r
669 Reg.E.EDI = 0;\r
670\r
671 ThunkFailed = Private->LegacyBios.Int86 (&Private->LegacyBios, 0x1A, &Reg);\r
672 if (!ThunkFailed) {\r
673 //\r
674 // From PCI Firmware 3.0 Specification:\r
675 // If the CARRY FLAG [CF] is cleared and AH is set to 00h, it is still necessary to examine the\r
676 // contents of [EDX] for the presence of the string "PCI" + (trailing space) to fully validate the\r
677 // presence of the PCI function set. [BX] will further indicate the version level, with enough\r
678 // granularity to allow for incremental changes in the code that don't affect the function interface.\r
679 // Version numbers are stored as Binary Coded Decimal (BCD) values. For example, Version 2.10\r
680 // would be returned as a 02h in the [BH] registers and 10h in the [BL] registers.\r
681 //\r
682 if ((Reg.X.Flags.CF == 0) && (Reg.H.AH == 0) && (Reg.E.EDX == SIGNATURE_32 ('P', 'C', 'I', ' '))) {\r
683 PciInterfaceVersion = Reg.X.BX;\r
684 }\r
685 }\r
686 return PciInterfaceVersion;\r
687}\r
688\r
b6823730
EL
689/**\r
690 Callback function to calculate SMBIOS table size, and allocate memory for SMBIOS table.\r
691 SMBIOS table will be copied into EfiReservedMemoryType memory in legacy boot path.\r
692\r
693 @param Event Event whose notification function is being invoked.\r
694 @param Context The pointer to the notification function's context,\r
695 which is implementation-dependent.\r
696\r
697**/\r
698VOID\r
699EFIAPI\r
700InstallSmbiosEventCallback (\r
701 IN EFI_EVENT Event,\r
702 IN VOID *Context\r
703 )\r
704{\r
705 EFI_STATUS Status;\r
706 SMBIOS_TABLE_ENTRY_POINT *EntryPointStructure;\r
0a6f4824 707\r
b6823730
EL
708 //\r
709 // Get SMBIOS table from EFI configuration table\r
710 //\r
711 Status = EfiGetSystemConfigurationTable (\r
712 &gEfiSmbiosTableGuid,\r
713 &mRuntimeSmbiosEntryPoint\r
714 );\r
ad793176 715 if ((EFI_ERROR (Status)) || (mRuntimeSmbiosEntryPoint == NULL)) {\r
b6823730
EL
716 return;\r
717 }\r
0a6f4824 718\r
b6823730
EL
719 EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *) mRuntimeSmbiosEntryPoint;\r
720\r
721 //\r
722 // Allocate memory for SMBIOS Entry Point Structure.\r
723 // CSM framework spec requires SMBIOS table below 4GB in EFI_TO_COMPATIBILITY16_BOOT_TABLE.\r
724 //\r
725 if (mReserveSmbiosEntryPoint == 0) {\r
726 //\r
727 // Entrypoint structure with fixed size is allocated only once.\r
728 //\r
729 mReserveSmbiosEntryPoint = SIZE_4GB - 1;\r
730 Status = gBS->AllocatePages (\r
731 AllocateMaxAddress,\r
732 EfiReservedMemoryType,\r
733 EFI_SIZE_TO_PAGES ((UINTN) (EntryPointStructure->EntryPointLength)),\r
734 &mReserveSmbiosEntryPoint\r
735 );\r
736 if (EFI_ERROR (Status)) {\r
737 mReserveSmbiosEntryPoint = 0;\r
738 return;\r
739 }\r
740 DEBUG ((EFI_D_INFO, "Allocate memory for Smbios Entry Point Structure\n"));\r
741 }\r
0a6f4824
LG
742\r
743 if ((mStructureTableAddress != 0) &&\r
aa5f60ae 744 (mStructureTablePages < EFI_SIZE_TO_PAGES ((UINT32)EntryPointStructure->TableLength))) {\r
b6823730
EL
745 //\r
746 // If original buffer is not enough for the new SMBIOS table, free original buffer and re-allocate\r
747 //\r
748 gBS->FreePages (mStructureTableAddress, mStructureTablePages);\r
749 mStructureTableAddress = 0;\r
750 mStructureTablePages = 0;\r
751 DEBUG ((EFI_D_INFO, "Original size is not enough. Re-allocate the memory.\n"));\r
752 }\r
0a6f4824 753\r
b6823730
EL
754 if (mStructureTableAddress == 0) {\r
755 //\r
756 // Allocate reserved memory below 4GB.\r
757 // Smbios spec requires the structure table is below 4GB.\r
758 //\r
759 mStructureTableAddress = SIZE_4GB - 1;\r
760 mStructureTablePages = EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength);\r
761 Status = gBS->AllocatePages (\r
762 AllocateMaxAddress,\r
763 EfiReservedMemoryType,\r
764 mStructureTablePages,\r
765 &mStructureTableAddress\r
766 );\r
767 if (EFI_ERROR (Status)) {\r
768 gBS->FreePages (\r
0a6f4824 769 mReserveSmbiosEntryPoint,\r
b6823730
EL
770 EFI_SIZE_TO_PAGES ((UINTN) (EntryPointStructure->EntryPointLength))\r
771 );\r
772 mReserveSmbiosEntryPoint = 0;\r
773 mStructureTableAddress = 0;\r
774 mStructureTablePages = 0;\r
775 return;\r
776 }\r
777 DEBUG ((EFI_D_INFO, "Allocate memory for Smbios Structure Table\n"));\r
778 }\r
779}\r
780\r
d057d8c4
JW
781/**\r
782 Callback function to toggle EndOfDxe status. NULL pointer detection needs\r
783 this status to decide if it's necessary to change attributes of page 0.\r
784\r
785 @param Event Event whose notification function is being invoked.\r
786 @param Context The pointer to the notification function's context,\r
787 which is implementation-dependent.\r
788\r
789**/\r
790VOID\r
791EFIAPI\r
792ToggleEndOfDxeStatus (\r
793 IN EFI_EVENT Event,\r
794 IN VOID *Context\r
795 )\r
796{\r
797 mEndOfDxe = TRUE;\r
798 return;\r
799}\r
800\r
bcecde14 801/**\r
802 Install Driver to produce Legacy BIOS protocol.\r
803\r
804 @param ImageHandle Handle of driver image.\r
805 @param SystemTable Pointer to system table.\r
806\r
807 @retval EFI_SUCCESS Legacy BIOS protocol installed\r
808 @retval No protocol installed, unload driver.\r
809\r
810**/\r
811EFI_STATUS\r
812EFIAPI\r
813LegacyBiosInstall (\r
814 IN EFI_HANDLE ImageHandle,\r
815 IN EFI_SYSTEM_TABLE *SystemTable\r
816 )\r
817{\r
818 EFI_STATUS Status;\r
819 LEGACY_BIOS_INSTANCE *Private;\r
820 EFI_TO_COMPATIBILITY16_INIT_TABLE *EfiToLegacy16InitTable;\r
821 EFI_PHYSICAL_ADDRESS MemoryAddress;\r
3e5eb447 822 EFI_PHYSICAL_ADDRESS EbdaReservedBaseAddress;\r
bcecde14 823 VOID *MemoryPtr;\r
824 EFI_PHYSICAL_ADDRESS MemoryAddressUnder1MB;\r
825 UINTN Index;\r
826 UINT32 *BaseVectorMaster;\r
827 EFI_PHYSICAL_ADDRESS StartAddress;\r
828 UINT32 *ClearPtr;\r
829 EFI_PHYSICAL_ADDRESS MemStart;\r
830 UINT32 IntRedirCode;\r
831 UINT32 Granularity;\r
832 BOOLEAN DecodeOn;\r
833 UINT32 MemorySize;\r
834 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;\r
835 UINT64 Length;\r
0f8b0298 836 UINT8 *SecureBoot;\r
b6823730 837 EFI_EVENT InstallSmbiosEvent;\r
d057d8c4 838 EFI_EVENT EndOfDxeEvent;\r
bcecde14 839\r
840 //\r
841 // Load this driver's image to memory\r
842 //\r
843 Status = RelocateImageUnder4GIfNeeded (ImageHandle, SystemTable);\r
844 if (EFI_ERROR (Status)) {\r
845 return Status;\r
846 }\r
847\r
0f8b0298 848 //\r
849 // When UEFI Secure Boot is enabled, CSM module will not start any more.\r
850 //\r
851 SecureBoot = NULL;\r
852 GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&SecureBoot, NULL);\r
853 if ((SecureBoot != NULL) && (*SecureBoot == SECURE_BOOT_MODE_ENABLE)) {\r
854 FreePool (SecureBoot);\r
855 return EFI_SECURITY_VIOLATION;\r
856 }\r
0a6f4824 857\r
0f8b0298 858 if (SecureBoot != NULL) {\r
859 FreePool (SecureBoot);\r
860 }\r
861\r
bcecde14 862 Private = &mPrivateData;\r
863 ZeroMem (Private, sizeof (LEGACY_BIOS_INSTANCE));\r
864\r
865 //\r
866 // Grab a copy of all the protocols we depend on. Any error would\r
867 // be a dispatcher bug!.\r
868 //\r
869 Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &Private->Cpu);\r
870 ASSERT_EFI_ERROR (Status);\r
871\r
f767f990 872 Status = gBS->LocateProtocol (&gEfiTimerArchProtocolGuid, NULL, (VOID **) &Private->Timer);\r
873 ASSERT_EFI_ERROR (Status);\r
874\r
bcecde14 875 Status = gBS->LocateProtocol (&gEfiLegacyRegion2ProtocolGuid, NULL, (VOID **) &Private->LegacyRegion);\r
876 ASSERT_EFI_ERROR (Status);\r
877\r
878 Status = gBS->LocateProtocol (&gEfiLegacyBiosPlatformProtocolGuid, NULL, (VOID **) &Private->LegacyBiosPlatform);\r
879 ASSERT_EFI_ERROR (Status);\r
880\r
881 Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **) &Private->Legacy8259);\r
882 ASSERT_EFI_ERROR (Status);\r
883\r
884 Status = gBS->LocateProtocol (&gEfiLegacyInterruptProtocolGuid, NULL, (VOID **) &Private->LegacyInterrupt);\r
885 ASSERT_EFI_ERROR (Status);\r
886\r
887 //\r
888 // Locate Memory Test Protocol if exists\r
889 //\r
890 Status = gBS->LocateProtocol (\r
891 &gEfiGenericMemTestProtocolGuid,\r
892 NULL,\r
893 (VOID **) &Private->GenericMemoryTest\r
894 );\r
895 ASSERT_EFI_ERROR (Status);\r
896\r
897 //\r
898 // Make sure all memory from 0-640K is tested\r
899 //\r
900 for (StartAddress = 0; StartAddress < 0xa0000; ) {\r
901 gDS->GetMemorySpaceDescriptor (StartAddress, &Descriptor);\r
902 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) {\r
903 StartAddress = Descriptor.BaseAddress + Descriptor.Length;\r
904 continue;\r
905 }\r
906 Length = MIN (Descriptor.Length, 0xa0000 - StartAddress);\r
907 Private->GenericMemoryTest->CompatibleRangeTest (\r
908 Private->GenericMemoryTest,\r
909 StartAddress,\r
910 Length\r
911 );\r
912 StartAddress = StartAddress + Length;\r
913 }\r
914 //\r
915 // Make sure all memory from 1MB to 16MB is tested and added to memory map\r
916 //\r
917 for (StartAddress = BASE_1MB; StartAddress < BASE_16MB; ) {\r
918 gDS->GetMemorySpaceDescriptor (StartAddress, &Descriptor);\r
919 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) {\r
920 StartAddress = Descriptor.BaseAddress + Descriptor.Length;\r
921 continue;\r
922 }\r
923 Length = MIN (Descriptor.Length, BASE_16MB - StartAddress);\r
924 Private->GenericMemoryTest->CompatibleRangeTest (\r
925 Private->GenericMemoryTest,\r
926 StartAddress,\r
927 Length\r
928 );\r
929 StartAddress = StartAddress + Length;\r
930 }\r
931\r
932 Private->Signature = LEGACY_BIOS_INSTANCE_SIGNATURE;\r
933\r
934 Private->LegacyBios.Int86 = LegacyBiosInt86;\r
935 Private->LegacyBios.FarCall86 = LegacyBiosFarCall86;\r
936 Private->LegacyBios.CheckPciRom = LegacyBiosCheckPciRom;\r
937 Private->LegacyBios.InstallPciRom = LegacyBiosInstallPciRom;\r
938 Private->LegacyBios.LegacyBoot = LegacyBiosLegacyBoot;\r
939 Private->LegacyBios.UpdateKeyboardLedStatus = LegacyBiosUpdateKeyboardLedStatus;\r
940 Private->LegacyBios.GetBbsInfo = LegacyBiosGetBbsInfo;\r
941 Private->LegacyBios.ShadowAllLegacyOproms = LegacyBiosShadowAllLegacyOproms;\r
942 Private->LegacyBios.PrepareToBootEfi = LegacyBiosPrepareToBootEfi;\r
943 Private->LegacyBios.GetLegacyRegion = LegacyBiosGetLegacyRegion;\r
944 Private->LegacyBios.CopyLegacyRegion = LegacyBiosCopyLegacyRegion;\r
945 Private->LegacyBios.BootUnconventionalDevice = LegacyBiosBootUnconventionalDevice;\r
946\r
947 Private->ImageHandle = ImageHandle;\r
948\r
949 //\r
950 // Enable read attribute of legacy region.\r
951 //\r
952 DecodeOn = TRUE;\r
953 Private->LegacyRegion->Decode (\r
954 Private->LegacyRegion,\r
955 0xc0000,\r
956 0x40000,\r
957 &Granularity,\r
958 &DecodeOn\r
959 );\r
960 //\r
961 // Set Cachebility for legacy region\r
962 // BUGBUG: Comments about this legacy region cacheability setting\r
963 // This setting will make D865GCHProduction CSM Unhappy\r
964 //\r
965 if (PcdGetBool (PcdLegacyBiosCacheLegacyRegion)) {\r
966 gDS->SetMemorySpaceAttributes (\r
967 0x0,\r
968 0xA0000,\r
969 EFI_MEMORY_WB\r
970 );\r
971 gDS->SetMemorySpaceAttributes (\r
972 0xc0000,\r
973 0x40000,\r
974 EFI_MEMORY_WB\r
975 );\r
976 }\r
977\r
978 gDS->SetMemorySpaceAttributes (\r
979 0xA0000,\r
980 0x20000,\r
981 EFI_MEMORY_UC\r
982 );\r
983\r
984 //\r
985 // Allocate 0 - 4K for real mode interupt vectors and BDA.\r
986 //\r
987 AllocateLegacyMemory (\r
988 AllocateAddress,\r
b22a62be 989 EfiReservedMemoryType,\r
bcecde14 990 0,\r
991 1,\r
992 &MemoryAddress\r
993 );\r
994 ASSERT (MemoryAddress == 0x000000000);\r
995\r
996 ClearPtr = (VOID *) ((UINTN) 0x0000);\r
997\r
998 //\r
999 // Initialize region from 0x0000 to 4k. This initializes interrupt vector\r
1000 // range.\r
1001 //\r
2ea3576e
JW
1002 ACCESS_PAGE0_CODE (\r
1003 gBS->SetMem ((VOID *) ClearPtr, 0x400, INITIAL_VALUE_BELOW_1K);\r
1004 ZeroMem ((VOID *) ((UINTN)ClearPtr + 0x400), 0xC00);\r
1005 );\r
bcecde14 1006\r
1007 //\r
1008 // Allocate pages for OPROM usage\r
1009 //\r
1010 MemorySize = PcdGet32 (PcdEbdaReservedMemorySize);\r
1011 ASSERT ((MemorySize & 0xFFF) == 0);\r
1012\r
1013 Status = AllocateLegacyMemory (\r
1014 AllocateAddress,\r
b22a62be 1015 EfiReservedMemoryType,\r
bcecde14 1016 CONVENTIONAL_MEMORY_TOP - MemorySize,\r
1017 EFI_SIZE_TO_PAGES (MemorySize),\r
1018 &MemoryAddress\r
1019 );\r
1020 ASSERT_EFI_ERROR (Status);\r
1021\r
1022 ZeroMem ((VOID *) ((UINTN) MemoryAddress), MemorySize);\r
1023\r
1024 //\r
1025 // Allocate all 32k chunks from 0x60000 ~ 0x88000 for Legacy OPROMs that\r
1026 // don't use PMM but look for zeroed memory. Note that various non-BBS\r
3e5eb447 1027 // OpROMs expect different areas to be free\r
bcecde14 1028 //\r
3e5eb447 1029 EbdaReservedBaseAddress = MemoryAddress;\r
1030 MemoryAddress = PcdGet32 (PcdOpromReservedMemoryBase);\r
1031 MemorySize = PcdGet32 (PcdOpromReservedMemorySize);\r
1032 //\r
1033 // Check if base address and size for reserved memory are 4KB aligned.\r
1034 //\r
1035 ASSERT ((MemoryAddress & 0xFFF) == 0);\r
1036 ASSERT ((MemorySize & 0xFFF) == 0);\r
1037 //\r
1038 // Check if the reserved memory is below EBDA reserved range.\r
1039 //\r
1040 ASSERT ((MemoryAddress < EbdaReservedBaseAddress) && ((MemoryAddress + MemorySize - 1) < EbdaReservedBaseAddress));\r
1041 for (MemStart = MemoryAddress; MemStart < MemoryAddress + MemorySize; MemStart += 0x1000) {\r
bcecde14 1042 Status = AllocateLegacyMemory (\r
1043 AllocateAddress,\r
b22a62be 1044 EfiBootServicesCode,\r
bcecde14 1045 MemStart,\r
1046 1,\r
79966a6f 1047 &StartAddress\r
bcecde14 1048 );\r
1049 if (!EFI_ERROR (Status)) {\r
79966a6f 1050 MemoryPtr = (VOID *) ((UINTN) StartAddress);\r
bcecde14 1051 ZeroMem (MemoryPtr, 0x1000);\r
1052 } else {\r
1053 DEBUG ((EFI_D_ERROR, "WARNING: Allocate legacy memory fail for SCSI card - %x\n", MemStart));\r
1054 }\r
1055 }\r
1056\r
1057 //\r
befbc4f3 1058 // Allocate low PMM memory and zero it out\r
bcecde14 1059 //\r
befbc4f3 1060 MemorySize = PcdGet32 (PcdLowPmmMemorySize);\r
0a6f4824 1061 ASSERT ((MemorySize & 0xFFF) == 0);\r
bcecde14 1062 Status = AllocateLegacyMemory (\r
1063 AllocateMaxAddress,\r
b22a62be 1064 EfiBootServicesCode,\r
bcecde14 1065 CONVENTIONAL_MEMORY_TOP,\r
befbc4f3 1066 EFI_SIZE_TO_PAGES (MemorySize),\r
bcecde14 1067 &MemoryAddressUnder1MB\r
1068 );\r
1069 ASSERT_EFI_ERROR (Status);\r
1070\r
befbc4f3 1071 ZeroMem ((VOID *) ((UINTN) MemoryAddressUnder1MB), MemorySize);\r
bcecde14 1072\r
1073 //\r
1074 // Allocate space for thunker and Init Thunker\r
1075 //\r
1076 Status = AllocateLegacyMemory (\r
1077 AllocateMaxAddress,\r
b22a62be 1078 EfiReservedMemoryType,\r
bcecde14 1079 CONVENTIONAL_MEMORY_TOP,\r
1080 (sizeof (LOW_MEMORY_THUNK) / EFI_PAGE_SIZE) + 2,\r
1081 &MemoryAddress\r
1082 );\r
1083 ASSERT_EFI_ERROR (Status);\r
1084 Private->IntThunk = (LOW_MEMORY_THUNK *) (UINTN) MemoryAddress;\r
1085 EfiToLegacy16InitTable = &Private->IntThunk->EfiToLegacy16InitTable;\r
1086 EfiToLegacy16InitTable->ThunkStart = (UINT32) (EFI_PHYSICAL_ADDRESS) (UINTN) MemoryAddress;\r
1087 EfiToLegacy16InitTable->ThunkSizeInBytes = (UINT32) (sizeof (LOW_MEMORY_THUNK));\r
1088\r
1089 Status = LegacyBiosInitializeThunk (Private);\r
1090 ASSERT_EFI_ERROR (Status);\r
1091\r
1092 //\r
1093 // Init the legacy memory map in memory < 1 MB.\r
1094 //\r
1095 EfiToLegacy16InitTable->BiosLessThan1MB = (UINT32) MemoryAddressUnder1MB;\r
1096 EfiToLegacy16InitTable->LowPmmMemory = (UINT32) MemoryAddressUnder1MB;\r
befbc4f3 1097 EfiToLegacy16InitTable->LowPmmMemorySizeInBytes = MemorySize;\r
bcecde14 1098\r
74dee931 1099 MemorySize = PcdGet32 (PcdHighPmmMemorySize);\r
1100 ASSERT ((MemorySize & 0xFFF) == 0);\r
bcecde14 1101 //\r
befbc4f3 1102 // Allocate high PMM Memory under 16 MB\r
0a6f4824 1103 //\r
bcecde14 1104 Status = AllocateLegacyMemory (\r
1105 AllocateMaxAddress,\r
b22a62be 1106 EfiBootServicesCode,\r
bcecde14 1107 0x1000000,\r
befbc4f3 1108 EFI_SIZE_TO_PAGES (MemorySize),\r
bcecde14 1109 &MemoryAddress\r
1110 );\r
74dee931 1111 if (EFI_ERROR (Status)) {\r
1112 //\r
1113 // If it fails, allocate high PMM Memory under 4GB\r
0a6f4824 1114 //\r
74dee931 1115 Status = AllocateLegacyMemory (\r
1116 AllocateMaxAddress,\r
b22a62be 1117 EfiBootServicesCode,\r
74dee931 1118 0xFFFFFFFF,\r
1119 EFI_SIZE_TO_PAGES (MemorySize),\r
1120 &MemoryAddress\r
0a6f4824 1121 );\r
74dee931 1122 }\r
bcecde14 1123 if (!EFI_ERROR (Status)) {\r
1124 EfiToLegacy16InitTable->HiPmmMemory = (UINT32) (EFI_PHYSICAL_ADDRESS) (UINTN) MemoryAddress;\r
befbc4f3 1125 EfiToLegacy16InitTable->HiPmmMemorySizeInBytes = MemorySize;\r
0a6f4824 1126 }\r
bcecde14 1127\r
1128 //\r
1129 // ShutdownAPs();\r
1130 //\r
1131 // Start the Legacy BIOS;\r
1132 //\r
1133 Status = ShadowAndStartLegacy16 (Private);\r
1134 if (EFI_ERROR (Status)) {\r
1135 return Status;\r
1136 }\r
1137 //\r
1138 // Initialize interrupt redirection code and entries;\r
1139 // IDT Vectors 0x68-0x6f must be redirected to IDT Vectors 0x08-0x0f.\r
1140 //\r
1141 CopyMem (\r
1142 Private->IntThunk->InterruptRedirectionCode,\r
1143 (VOID *) (UINTN) InterruptRedirectionTemplate,\r
1144 sizeof (Private->IntThunk->InterruptRedirectionCode)\r
1145 );\r
1146\r
1147 //\r
1148 // Save Unexpected interrupt vector so can restore it just prior to boot\r
1149 //\r
2ea3576e
JW
1150 ACCESS_PAGE0_CODE (\r
1151 BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);\r
1152 Private->BiosUnexpectedInt = BaseVectorMaster[0];\r
1153 IntRedirCode = (UINT32) (UINTN) Private->IntThunk->InterruptRedirectionCode;\r
1154 for (Index = 0; Index < 8; Index++) {\r
1155 BaseVectorMaster[Index] = (EFI_SEGMENT (IntRedirCode + Index * 4) << 16) | EFI_OFFSET (IntRedirCode + Index * 4);\r
1156 }\r
1157 );\r
d057d8c4 1158\r
bcecde14 1159 //\r
1160 // Save EFI value\r
1161 //\r
1162 Private->ThunkSeg = (UINT16) (EFI_SEGMENT (IntRedirCode));\r
0a6f4824 1163\r
b6823730
EL
1164 //\r
1165 // Allocate reserved memory for SMBIOS table used in legacy boot if SMBIOS table exists\r
1166 //\r
1167 InstallSmbiosEventCallback (NULL, NULL);\r
1168\r
1169 //\r
1170 // Create callback function to update the size of reserved memory after LegacyBiosDxe starts\r
1171 //\r
1172 Status = gBS->CreateEventEx (\r
1173 EVT_NOTIFY_SIGNAL,\r
1174 TPL_NOTIFY,\r
1175 InstallSmbiosEventCallback,\r
1176 NULL,\r
1177 &gEfiSmbiosTableGuid,\r
1178 &InstallSmbiosEvent\r
1179 );\r
0a6f4824 1180 ASSERT_EFI_ERROR (Status);\r
bcecde14 1181\r
d057d8c4
JW
1182 //\r
1183 // Create callback to update status of EndOfDxe, which is needed by NULL\r
1184 // pointer detection\r
1185 //\r
1186 Status = gBS->CreateEventEx (\r
1187 EVT_NOTIFY_SIGNAL,\r
1188 TPL_NOTIFY,\r
1189 ToggleEndOfDxeStatus,\r
1190 NULL,\r
1191 &gEfiEndOfDxeEventGroupGuid,\r
1192 &EndOfDxeEvent\r
1193 );\r
1194 ASSERT_EFI_ERROR (Status);\r
1195\r
bcecde14 1196 //\r
1197 // Make a new handle and install the protocol\r
1198 //\r
1199 Private->Handle = NULL;\r
1200 Status = gBS->InstallProtocolInterface (\r
1201 &Private->Handle,\r
1202 &gEfiLegacyBiosProtocolGuid,\r
1203 EFI_NATIVE_INTERFACE,\r
1204 &Private->LegacyBios\r
1205 );\r
1206 Private->Csm16PciInterfaceVersion = GetPciInterfaceVersion (Private);\r
0a6f4824
LG
1207\r
1208 DEBUG ((EFI_D_INFO, "CSM16 PCI BIOS Interface Version: %02x.%02x\n",\r
1209 (UINT8) (Private->Csm16PciInterfaceVersion >> 8),\r
bcecde14 1210 (UINT8) Private->Csm16PciInterfaceVersion\r
1211 ));\r
1212 ASSERT (Private->Csm16PciInterfaceVersion != 0);\r
1213 return Status;\r
1214}\r