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