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