]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBios.c
Remove hard code value and create new PCDs for OpROM reserved range in CSM module.
[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 EFI_PHYSICAL_ADDRESS EbdaReservedBaseAddress;
686 VOID *MemoryPtr;
687 EFI_PHYSICAL_ADDRESS MemoryAddressUnder1MB;
688 UINTN Index;
689 UINT32 *BaseVectorMaster;
690 EFI_PHYSICAL_ADDRESS StartAddress;
691 UINT32 *ClearPtr;
692 EFI_PHYSICAL_ADDRESS MemStart;
693 UINT32 IntRedirCode;
694 UINT32 Granularity;
695 BOOLEAN DecodeOn;
696 UINT32 MemorySize;
697 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
698 UINT64 Length;
699 UINT8 *SecureBoot;
700
701 //
702 // Load this driver's image to memory
703 //
704 Status = RelocateImageUnder4GIfNeeded (ImageHandle, SystemTable);
705 if (EFI_ERROR (Status)) {
706 return Status;
707 }
708
709 //
710 // When UEFI Secure Boot is enabled, CSM module will not start any more.
711 //
712 SecureBoot = NULL;
713 GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&SecureBoot, NULL);
714 if ((SecureBoot != NULL) && (*SecureBoot == SECURE_BOOT_MODE_ENABLE)) {
715 FreePool (SecureBoot);
716 return EFI_SECURITY_VIOLATION;
717 }
718
719 if (SecureBoot != NULL) {
720 FreePool (SecureBoot);
721 }
722
723 Private = &mPrivateData;
724 ZeroMem (Private, sizeof (LEGACY_BIOS_INSTANCE));
725
726 //
727 // Grab a copy of all the protocols we depend on. Any error would
728 // be a dispatcher bug!.
729 //
730 Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &Private->Cpu);
731 ASSERT_EFI_ERROR (Status);
732
733 Status = gBS->LocateProtocol (&gEfiTimerArchProtocolGuid, NULL, (VOID **) &Private->Timer);
734 ASSERT_EFI_ERROR (Status);
735
736 Status = gBS->LocateProtocol (&gEfiLegacyRegion2ProtocolGuid, NULL, (VOID **) &Private->LegacyRegion);
737 ASSERT_EFI_ERROR (Status);
738
739 Status = gBS->LocateProtocol (&gEfiLegacyBiosPlatformProtocolGuid, NULL, (VOID **) &Private->LegacyBiosPlatform);
740 ASSERT_EFI_ERROR (Status);
741
742 Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **) &Private->Legacy8259);
743 ASSERT_EFI_ERROR (Status);
744
745 Status = gBS->LocateProtocol (&gEfiLegacyInterruptProtocolGuid, NULL, (VOID **) &Private->LegacyInterrupt);
746 ASSERT_EFI_ERROR (Status);
747
748 //
749 // Locate Memory Test Protocol if exists
750 //
751 Status = gBS->LocateProtocol (
752 &gEfiGenericMemTestProtocolGuid,
753 NULL,
754 (VOID **) &Private->GenericMemoryTest
755 );
756 ASSERT_EFI_ERROR (Status);
757
758 //
759 // Make sure all memory from 0-640K is tested
760 //
761 for (StartAddress = 0; StartAddress < 0xa0000; ) {
762 gDS->GetMemorySpaceDescriptor (StartAddress, &Descriptor);
763 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) {
764 StartAddress = Descriptor.BaseAddress + Descriptor.Length;
765 continue;
766 }
767 Length = MIN (Descriptor.Length, 0xa0000 - StartAddress);
768 Private->GenericMemoryTest->CompatibleRangeTest (
769 Private->GenericMemoryTest,
770 StartAddress,
771 Length
772 );
773 StartAddress = StartAddress + Length;
774 }
775 //
776 // Make sure all memory from 1MB to 16MB is tested and added to memory map
777 //
778 for (StartAddress = BASE_1MB; StartAddress < BASE_16MB; ) {
779 gDS->GetMemorySpaceDescriptor (StartAddress, &Descriptor);
780 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) {
781 StartAddress = Descriptor.BaseAddress + Descriptor.Length;
782 continue;
783 }
784 Length = MIN (Descriptor.Length, BASE_16MB - StartAddress);
785 Private->GenericMemoryTest->CompatibleRangeTest (
786 Private->GenericMemoryTest,
787 StartAddress,
788 Length
789 );
790 StartAddress = StartAddress + Length;
791 }
792
793 Private->Signature = LEGACY_BIOS_INSTANCE_SIGNATURE;
794
795 Private->LegacyBios.Int86 = LegacyBiosInt86;
796 Private->LegacyBios.FarCall86 = LegacyBiosFarCall86;
797 Private->LegacyBios.CheckPciRom = LegacyBiosCheckPciRom;
798 Private->LegacyBios.InstallPciRom = LegacyBiosInstallPciRom;
799 Private->LegacyBios.LegacyBoot = LegacyBiosLegacyBoot;
800 Private->LegacyBios.UpdateKeyboardLedStatus = LegacyBiosUpdateKeyboardLedStatus;
801 Private->LegacyBios.GetBbsInfo = LegacyBiosGetBbsInfo;
802 Private->LegacyBios.ShadowAllLegacyOproms = LegacyBiosShadowAllLegacyOproms;
803 Private->LegacyBios.PrepareToBootEfi = LegacyBiosPrepareToBootEfi;
804 Private->LegacyBios.GetLegacyRegion = LegacyBiosGetLegacyRegion;
805 Private->LegacyBios.CopyLegacyRegion = LegacyBiosCopyLegacyRegion;
806 Private->LegacyBios.BootUnconventionalDevice = LegacyBiosBootUnconventionalDevice;
807
808 Private->ImageHandle = ImageHandle;
809
810 //
811 // Enable read attribute of legacy region.
812 //
813 DecodeOn = TRUE;
814 Private->LegacyRegion->Decode (
815 Private->LegacyRegion,
816 0xc0000,
817 0x40000,
818 &Granularity,
819 &DecodeOn
820 );
821 //
822 // Set Cachebility for legacy region
823 // BUGBUG: Comments about this legacy region cacheability setting
824 // This setting will make D865GCHProduction CSM Unhappy
825 //
826 if (PcdGetBool (PcdLegacyBiosCacheLegacyRegion)) {
827 gDS->SetMemorySpaceAttributes (
828 0x0,
829 0xA0000,
830 EFI_MEMORY_WB
831 );
832 gDS->SetMemorySpaceAttributes (
833 0xc0000,
834 0x40000,
835 EFI_MEMORY_WB
836 );
837 }
838
839 gDS->SetMemorySpaceAttributes (
840 0xA0000,
841 0x20000,
842 EFI_MEMORY_UC
843 );
844
845 //
846 // Allocate 0 - 4K for real mode interupt vectors and BDA.
847 //
848 AllocateLegacyMemory (
849 AllocateAddress,
850 0,
851 1,
852 &MemoryAddress
853 );
854 ASSERT (MemoryAddress == 0x000000000);
855
856 ClearPtr = (VOID *) ((UINTN) 0x0000);
857
858 //
859 // Initialize region from 0x0000 to 4k. This initializes interrupt vector
860 // range.
861 //
862 gBS->SetMem ((VOID *) ClearPtr, 0x400, INITIAL_VALUE_BELOW_1K);
863 ZeroMem ((VOID *) ((UINTN)ClearPtr + 0x400), 0xC00);
864
865 //
866 // Allocate pages for OPROM usage
867 //
868 MemorySize = PcdGet32 (PcdEbdaReservedMemorySize);
869 ASSERT ((MemorySize & 0xFFF) == 0);
870
871 Status = AllocateLegacyMemory (
872 AllocateAddress,
873 CONVENTIONAL_MEMORY_TOP - MemorySize,
874 EFI_SIZE_TO_PAGES (MemorySize),
875 &MemoryAddress
876 );
877 ASSERT_EFI_ERROR (Status);
878
879 ZeroMem ((VOID *) ((UINTN) MemoryAddress), MemorySize);
880
881 //
882 // Allocate all 32k chunks from 0x60000 ~ 0x88000 for Legacy OPROMs that
883 // don't use PMM but look for zeroed memory. Note that various non-BBS
884 // OpROMs expect different areas to be free
885 //
886 EbdaReservedBaseAddress = MemoryAddress;
887 MemoryAddress = PcdGet32 (PcdOpromReservedMemoryBase);
888 MemorySize = PcdGet32 (PcdOpromReservedMemorySize);
889 //
890 // Check if base address and size for reserved memory are 4KB aligned.
891 //
892 ASSERT ((MemoryAddress & 0xFFF) == 0);
893 ASSERT ((MemorySize & 0xFFF) == 0);
894 //
895 // Check if the reserved memory is below EBDA reserved range.
896 //
897 ASSERT ((MemoryAddress < EbdaReservedBaseAddress) && ((MemoryAddress + MemorySize - 1) < EbdaReservedBaseAddress));
898 for (MemStart = MemoryAddress; MemStart < MemoryAddress + MemorySize; MemStart += 0x1000) {
899 Status = AllocateLegacyMemory (
900 AllocateAddress,
901 MemStart,
902 1,
903 &MemoryAddress
904 );
905 if (!EFI_ERROR (Status)) {
906 MemoryPtr = (VOID *) ((UINTN) MemoryAddress);
907 ZeroMem (MemoryPtr, 0x1000);
908 } else {
909 DEBUG ((EFI_D_ERROR, "WARNING: Allocate legacy memory fail for SCSI card - %x\n", MemStart));
910 }
911 }
912
913 //
914 // Allocate low PMM memory and zero it out
915 //
916 MemorySize = PcdGet32 (PcdLowPmmMemorySize);
917 ASSERT ((MemorySize & 0xFFF) == 0);
918 Status = AllocateLegacyMemory (
919 AllocateMaxAddress,
920 CONVENTIONAL_MEMORY_TOP,
921 EFI_SIZE_TO_PAGES (MemorySize),
922 &MemoryAddressUnder1MB
923 );
924 ASSERT_EFI_ERROR (Status);
925
926 ZeroMem ((VOID *) ((UINTN) MemoryAddressUnder1MB), MemorySize);
927
928 //
929 // Allocate space for thunker and Init Thunker
930 //
931 Status = AllocateLegacyMemory (
932 AllocateMaxAddress,
933 CONVENTIONAL_MEMORY_TOP,
934 (sizeof (LOW_MEMORY_THUNK) / EFI_PAGE_SIZE) + 2,
935 &MemoryAddress
936 );
937 ASSERT_EFI_ERROR (Status);
938 Private->IntThunk = (LOW_MEMORY_THUNK *) (UINTN) MemoryAddress;
939 EfiToLegacy16InitTable = &Private->IntThunk->EfiToLegacy16InitTable;
940 EfiToLegacy16InitTable->ThunkStart = (UINT32) (EFI_PHYSICAL_ADDRESS) (UINTN) MemoryAddress;
941 EfiToLegacy16InitTable->ThunkSizeInBytes = (UINT32) (sizeof (LOW_MEMORY_THUNK));
942
943 Status = LegacyBiosInitializeThunk (Private);
944 ASSERT_EFI_ERROR (Status);
945
946 //
947 // Init the legacy memory map in memory < 1 MB.
948 //
949 EfiToLegacy16InitTable->BiosLessThan1MB = (UINT32) MemoryAddressUnder1MB;
950 EfiToLegacy16InitTable->LowPmmMemory = (UINT32) MemoryAddressUnder1MB;
951 EfiToLegacy16InitTable->LowPmmMemorySizeInBytes = MemorySize;
952
953 MemorySize = PcdGet32 (PcdHighPmmMemorySize);
954 ASSERT ((MemorySize & 0xFFF) == 0);
955 //
956 // Allocate high PMM Memory under 16 MB
957 //
958 Status = AllocateLegacyMemory (
959 AllocateMaxAddress,
960 0x1000000,
961 EFI_SIZE_TO_PAGES (MemorySize),
962 &MemoryAddress
963 );
964 if (EFI_ERROR (Status)) {
965 //
966 // If it fails, allocate high PMM Memory under 4GB
967 //
968 Status = AllocateLegacyMemory (
969 AllocateMaxAddress,
970 0xFFFFFFFF,
971 EFI_SIZE_TO_PAGES (MemorySize),
972 &MemoryAddress
973 );
974 }
975 if (!EFI_ERROR (Status)) {
976 EfiToLegacy16InitTable->HiPmmMemory = (UINT32) (EFI_PHYSICAL_ADDRESS) (UINTN) MemoryAddress;
977 EfiToLegacy16InitTable->HiPmmMemorySizeInBytes = MemorySize;
978 }
979
980 //
981 // ShutdownAPs();
982 //
983 // Start the Legacy BIOS;
984 //
985 Status = ShadowAndStartLegacy16 (Private);
986 if (EFI_ERROR (Status)) {
987 return Status;
988 }
989 //
990 // Initialize interrupt redirection code and entries;
991 // IDT Vectors 0x68-0x6f must be redirected to IDT Vectors 0x08-0x0f.
992 //
993 CopyMem (
994 Private->IntThunk->InterruptRedirectionCode,
995 (VOID *) (UINTN) InterruptRedirectionTemplate,
996 sizeof (Private->IntThunk->InterruptRedirectionCode)
997 );
998
999 //
1000 // Save Unexpected interrupt vector so can restore it just prior to boot
1001 //
1002 BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);
1003 Private->BiosUnexpectedInt = BaseVectorMaster[0];
1004 IntRedirCode = (UINT32) (UINTN) Private->IntThunk->InterruptRedirectionCode;
1005 for (Index = 0; Index < 8; Index++) {
1006 BaseVectorMaster[Index] = (EFI_SEGMENT (IntRedirCode + Index * 4) << 16) | EFI_OFFSET (IntRedirCode + Index * 4);
1007 }
1008 //
1009 // Save EFI value
1010 //
1011 Private->ThunkSeg = (UINT16) (EFI_SEGMENT (IntRedirCode));
1012
1013 //
1014 // Make a new handle and install the protocol
1015 //
1016 Private->Handle = NULL;
1017 Status = gBS->InstallProtocolInterface (
1018 &Private->Handle,
1019 &gEfiLegacyBiosProtocolGuid,
1020 EFI_NATIVE_INTERFACE,
1021 &Private->LegacyBios
1022 );
1023 Private->Csm16PciInterfaceVersion = GetPciInterfaceVersion (Private);
1024
1025 DEBUG ((EFI_D_INFO, "CSM16 PCI BIOS Interface Version: %02x.%02x\n",
1026 (UINT8) (Private->Csm16PciInterfaceVersion >> 8),
1027 (UINT8) Private->Csm16PciInterfaceVersion
1028 ));
1029 ASSERT (Private->Csm16PciInterfaceVersion != 0);
1030 return Status;
1031 }