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