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