1 /** @file
2
3 Copyright (c) 2006 - 2015, 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 #include <IndustryStandard/Pci.h>
18
19 #define BOOT_LEGACY_OS 0
20 #define BOOT_EFI_OS 1
21 #define BOOT_UNCONVENTIONAL_DEVICE 2
22
23 UINT32 mLoadOptionsSize = 0;
24 UINTN mBootMode = BOOT_LEGACY_OS;
25 VOID *mLoadOptions = NULL;
26 BBS_BBS_DEVICE_PATH *mBbsDevicePathPtr = NULL;
27 BBS_BBS_DEVICE_PATH mBbsDevicePathNode;
28 UDC_ATTRIBUTES mAttributes = { 0, 0, 0, 0 };
29 UINTN mBbsEntry = 0;
30 VOID *mBeerData = NULL;
31 VOID *mServiceAreaData = NULL;
32 UINT64 mLowWater = 0xffffffffffffffffULL;
33
34 extern BBS_TABLE *mBbsTable;
35
36 extern VOID *mRuntimeSmbiosEntryPoint;
37 extern EFI_PHYSICAL_ADDRESS mReserveSmbiosEntryPoint;
38 extern EFI_PHYSICAL_ADDRESS mStructureTableAddress;
39
40 /**
41 Print the BBS Table.
42
43 @param BbsTable The BBS table.
44
45
46 **/
47 VOID
PrintBbsTable(IN BBS_TABLE * BbsTable)48 PrintBbsTable (
49 IN BBS_TABLE *BbsTable
50 )
51 {
52 UINT16 Index;
53 UINT16 SubIndex;
54 CHAR8 *String;
55
56 DEBUG ((EFI_D_INFO, "\n"));
57 DEBUG ((EFI_D_INFO, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs mfgs:mfgo dess:deso\n"));
58 DEBUG ((EFI_D_INFO, "=================================================================\n"));
59 for (Index = 0; Index < MAX_BBS_ENTRIES; Index++) {
60 //
61 // Filter
62 //
63 if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {
64 continue;
65 }
66
67 DEBUG ((
68 EFI_D_INFO,
69 " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x",
70 (UINTN) Index,
71 (UINTN) BbsTable[Index].BootPriority,
72 (UINTN) BbsTable[Index].Bus,
73 (UINTN) BbsTable[Index].Device,
74 (UINTN) BbsTable[Index].Function,
75 (UINTN) BbsTable[Index].Class,
76 (UINTN) BbsTable[Index].SubClass,
77 (UINTN) BbsTable[Index].DeviceType,
78 (UINTN) * (UINT16 *) &BbsTable[Index].StatusFlags
79 ));
80 DEBUG ((
81 EFI_D_INFO,
82 " %04x:%04x %04x:%04x %04x:%04x",
83 (UINTN) BbsTable[Index].BootHandlerSegment,
84 (UINTN) BbsTable[Index].BootHandlerOffset,
85 (UINTN) BbsTable[Index].MfgStringSegment,
86 (UINTN) BbsTable[Index].MfgStringOffset,
87 (UINTN) BbsTable[Index].DescStringSegment,
88 (UINTN) BbsTable[Index].DescStringOffset
89 ));
90
91 //
92 // Print DescString
93 //
94 String = (CHAR8 *)(UINTN)((BbsTable[Index].DescStringSegment << 4) + BbsTable[Index].DescStringOffset);
95 if (String != NULL) {
96 DEBUG ((EFI_D_INFO," ("));
97 for (SubIndex = 0; String[SubIndex] != 0; SubIndex++) {
98 DEBUG ((EFI_D_INFO, "%c", String[SubIndex]));
99 }
100 DEBUG ((EFI_D_INFO,")"));
101 }
102 DEBUG ((EFI_D_INFO,"\n"));
103 }
104
105 DEBUG ((EFI_D_INFO, "\n"));
106
107 return ;
108 }
109
110 /**
111 Print the BBS Table.
112
113 @param HddInfo The HddInfo table.
114
115
116 **/
117 VOID
PrintHddInfo(IN HDD_INFO * HddInfo)118 PrintHddInfo (
119 IN HDD_INFO *HddInfo
120 )
121 {
122 UINTN Index;
123
124 DEBUG ((EFI_D_INFO, "\n"));
125 for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) {
126 DEBUG ((EFI_D_INFO, "Index - %04x\n", Index));
127 DEBUG ((EFI_D_INFO, " Status - %04x\n", (UINTN)HddInfo[Index].Status));
128 DEBUG ((EFI_D_INFO, " B/D/F - %02x/%02x/%02x\n", (UINTN)HddInfo[Index].Bus, (UINTN)HddInfo[Index].Device, (UINTN)HddInfo[Index].Function));
129 DEBUG ((EFI_D_INFO, " Command - %04x\n", HddInfo[Index].CommandBaseAddress));
130 DEBUG ((EFI_D_INFO, " Control - %04x\n", HddInfo[Index].ControlBaseAddress));
131 DEBUG ((EFI_D_INFO, " BusMaster - %04x\n", HddInfo[Index].BusMasterAddress));
132 DEBUG ((EFI_D_INFO, " HddIrq - %02x\n", HddInfo[Index].HddIrq));
133 DEBUG ((EFI_D_INFO, " IdentifyDrive[0].Raw[0] - %x\n", HddInfo[Index].IdentifyDrive[0].Raw[0]));
134 DEBUG ((EFI_D_INFO, " IdentifyDrive[1].Raw[0] - %x\n", HddInfo[Index].IdentifyDrive[1].Raw[0]));
135 }
136
137 DEBUG ((EFI_D_INFO, "\n"));
138
139 return ;
140 }
141
142 /**
143 Print the PCI Interrupt Line and Interrupt Pin registers.
144 **/
145 VOID
PrintPciInterruptRegister(VOID)146 PrintPciInterruptRegister (
147 VOID
148 )
149 {
150 EFI_STATUS Status;
151 UINTN Index;
152 EFI_HANDLE *Handles;
153 UINTN HandleNum;
154 EFI_PCI_IO_PROTOCOL *PciIo;
155 UINT8 Interrupt[2];
156 UINTN Segment;
157 UINTN Bus;
158 UINTN Device;
159 UINTN Function;
160
161 gBS->LocateHandleBuffer (
162 ByProtocol,
163 &gEfiPciIoProtocolGuid,
164 NULL,
165 &HandleNum,
166 &Handles
167 );
168
169 Bus = 0;
170 Device = 0;
171 Function = 0;
172
173 DEBUG ((EFI_D_INFO, "\n"));
174 DEBUG ((EFI_D_INFO, " bb/dd/ff interrupt line interrupt pin\n"));
175 DEBUG ((EFI_D_INFO, "======================================\n"));
176 for (Index = 0; Index < HandleNum; Index++) {
177 Status = gBS->HandleProtocol (Handles[Index], &gEfiPciIoProtocolGuid, (VOID **) &PciIo);
178 if (!EFI_ERROR (Status)) {
179 Status = PciIo->Pci.Read (
180 PciIo,
181 EfiPciIoWidthUint8,
182 PCI_INT_LINE_OFFSET,
183 2,
184 Interrupt
185 );
186 }
187 if (!EFI_ERROR (Status)) {
188 Status = PciIo->GetLocation (
189 PciIo,
190 &Segment,
191 &Bus,
192 &Device,
193 &Function
194 );
195 }
196 if (!EFI_ERROR (Status)) {
197 DEBUG ((EFI_D_INFO, " %02x/%02x/%02x 0x%02x 0x%02x\n",
198 Bus, Device, Function, Interrupt[0], Interrupt[1]));
199 }
200 }
201 DEBUG ((EFI_D_INFO, "\n"));
202
203 if (Handles != NULL) {
204 FreePool (Handles);
205 }
206 }
207
208 /**
209 Identify drive data must be updated to actual parameters before boot.
210
211 @param IdentifyDriveData ATA Identify Data
212
213 **/
214 VOID
215 UpdateIdentifyDriveData (
216 IN UINT8 *IdentifyDriveData
217 );
218
219 /**
220 Update SIO data.
221
222 @param Private Legacy BIOS Instance data
223
224 @retval EFI_SUCCESS Removable media not present
225
226 **/
227 EFI_STATUS
UpdateSioData(IN LEGACY_BIOS_INSTANCE * Private)228 UpdateSioData (
229 IN LEGACY_BIOS_INSTANCE *Private
230 )
231 {
232 EFI_STATUS Status;
233 UINTN Index;
234 UINTN Index1;
235 UINT8 LegacyInterrupts[16];
236 EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable;
237 UINTN RoutingTableEntries;
238 EFI_LEGACY_IRQ_PRIORITY_TABLE_ENTRY *IrqPriorityTable;
239 UINTN NumberPriorityEntries;
240 EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
241 UINT8 HddIrq;
242 UINT16 LegacyInt;
243 UINT16 LegMask;
244 UINT32 Register;
245 UINTN HandleCount;
246 EFI_HANDLE *HandleBuffer;
247 EFI_ISA_IO_PROTOCOL *IsaIo;
248
249 LegacyInt = 0;
250 HandleBuffer = NULL;
251
252 EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
253 LegacyBiosBuildSioData (Private);
254 SetMem (LegacyInterrupts, sizeof (LegacyInterrupts), 0);
255
256 //
257 // Create list of legacy interrupts.
258 //
259 for (Index = 0; Index < 4; Index++) {
260 LegacyInterrupts[Index] = EfiToLegacy16BootTable->SioData.Serial[Index].Irq;
261 }
262
263 for (Index = 4; Index < 7; Index++) {
264 LegacyInterrupts[Index] = EfiToLegacy16BootTable->SioData.Parallel[Index - 4].Irq;
265 }
266
267 LegacyInterrupts[7] = EfiToLegacy16BootTable->SioData.Floppy.Irq;
268
269 //
270 // Get Legacy Hdd IRQs. If native mode treat as PCI
271 //
272 for (Index = 0; Index < 2; Index++) {
273 HddIrq = EfiToLegacy16BootTable->HddInfo[Index].HddIrq;
274 if ((HddIrq != 0) && ((HddIrq == 15) || (HddIrq == 14))) {
275 LegacyInterrupts[Index + 8] = HddIrq;
276 }
277 }
278
279 Private->LegacyBiosPlatform->GetRoutingTable (
280 Private->LegacyBiosPlatform,
281 (VOID *) &RoutingTable,
282 &RoutingTableEntries,
283 NULL,
284 NULL,
285 (VOID **) &IrqPriorityTable,
286 &NumberPriorityEntries
287 );
288 //
289 // Remove legacy interrupts from the list of PCI interrupts available.
290 //
291 for (Index = 0; Index <= 0x0b; Index++) {
292 for (Index1 = 0; Index1 <= NumberPriorityEntries; Index1++) {
293 if (LegacyInterrupts[Index] != 0) {
294 LegacyInt = (UINT16) (LegacyInt | (1 << LegacyInterrupts[Index]));
295 if (LegacyInterrupts[Index] == IrqPriorityTable[Index1].Irq) {
296 IrqPriorityTable[Index1].Used = LEGACY_USED;
297 }
298 }
299 }
300 }
301
302 Private->Legacy8259->GetMask (
303 Private->Legacy8259,
304 &LegMask,
305 NULL,
306 NULL,
307 NULL
308 );
309
310 //
311 // Set SIO interrupts and disable mouse. Let mouse driver
312 // re-enable it.
313 //
314 LegMask = (UINT16) ((LegMask &~LegacyInt) | 0x1000);
315 Private->Legacy8259->SetMask (
316 Private->Legacy8259,
317 &LegMask,
318 NULL,
319 NULL,
320 NULL
321 );
322
323 //
324 // Disable mouse in keyboard controller
325 //
326 Register = 0xA7;
327 Status = gBS->LocateHandleBuffer (
328 ByProtocol,
329 &gEfiIsaIoProtocolGuid,
330 NULL,
331 &HandleCount,
332 &HandleBuffer
333 );
334 if (EFI_ERROR (Status)) {
335 return Status;
336 }
337
338 for (Index = 0; Index < HandleCount; Index++) {
339 Status = gBS->HandleProtocol (
340 HandleBuffer[Index],
341 &gEfiIsaIoProtocolGuid,
342 (VOID **) &IsaIo
343 );
344 ASSERT_EFI_ERROR (Status);
345 IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, 0x64, 1, &Register);
346
347 }
348
349 if (HandleBuffer != NULL) {
350 FreePool (HandleBuffer);
351 }
352
353 return EFI_SUCCESS;
354
355 }
356
357 /**
358 Identify drive data must be updated to actual parameters before boot.
359 This requires updating the checksum, if it exists.
360
361 @param IdentifyDriveData ATA Identify Data
362 @param Checksum checksum of the ATA Identify Data
363
364 @retval EFI_SUCCESS checksum calculated
365 @retval EFI_SECURITY_VIOLATION IdentifyData invalid
366
367 **/
368 EFI_STATUS
CalculateIdentifyDriveChecksum(IN UINT8 * IdentifyDriveData,OUT UINT8 * Checksum)369 CalculateIdentifyDriveChecksum (
370 IN UINT8 *IdentifyDriveData,
371 OUT UINT8 *Checksum
372 )
373 {
374 UINTN Index;
375 UINT8 LocalChecksum;
376 LocalChecksum = 0;
377 *Checksum = 0;
378 if (IdentifyDriveData[510] != 0xA5) {
379 return EFI_SECURITY_VIOLATION;
380 }
381
382 for (Index = 0; Index < 512; Index++) {
383 LocalChecksum = (UINT8) (LocalChecksum + IdentifyDriveData[Index]);
384 }
385
386 *Checksum = LocalChecksum;
387 return EFI_SUCCESS;
388 }
389
390
391 /**
392 Identify drive data must be updated to actual parameters before boot.
393
394 @param IdentifyDriveData ATA Identify Data
395
396
397 **/
398 VOID
UpdateIdentifyDriveData(IN UINT8 * IdentifyDriveData)399 UpdateIdentifyDriveData (
400 IN UINT8 *IdentifyDriveData
401 )
402 {
403 UINT16 NumberCylinders;
404 UINT16 NumberHeads;
405 UINT16 NumberSectorsTrack;
406 UINT32 CapacityInSectors;
407 UINT8 OriginalChecksum;
408 UINT8 FinalChecksum;
409 EFI_STATUS Status;
410 ATAPI_IDENTIFY *ReadInfo;
411
412 //
413 // Status indicates if Integrity byte is correct. Checksum should be
414 // 0 if valid.
415 //
416 ReadInfo = (ATAPI_IDENTIFY *) IdentifyDriveData;
417 Status = CalculateIdentifyDriveChecksum (IdentifyDriveData, &OriginalChecksum);
418 if (OriginalChecksum != 0) {
419 Status = EFI_SECURITY_VIOLATION;
420 }
421 //
422 // If NumberCylinders = 0 then do data(Controller present but don drive attached).
423 //
424 NumberCylinders = ReadInfo->Raw[1];
425 if (NumberCylinders != 0) {
426 ReadInfo->Raw[54] = NumberCylinders;
427
428 NumberHeads = ReadInfo->Raw[3];
429 ReadInfo->Raw[55] = NumberHeads;
430
431 NumberSectorsTrack = ReadInfo->Raw[6];
432 ReadInfo->Raw[56] = NumberSectorsTrack;
433
434 //
435 // Copy Multisector info and set valid bit.
436 //
437 ReadInfo->Raw[59] = (UINT16) (ReadInfo->Raw[47] + 0x100);
438 CapacityInSectors = (UINT32) ((UINT32) (NumberCylinders) * (UINT32) (NumberHeads) * (UINT32) (NumberSectorsTrack));
439 ReadInfo->Raw[57] = (UINT16) (CapacityInSectors >> 16);
440 ReadInfo->Raw[58] = (UINT16) (CapacityInSectors & 0xffff);
441 if (Status == EFI_SUCCESS) {
442 //
443 // Forece checksum byte to 0 and get new checksum.
444 //
445 ReadInfo->Raw[255] &= 0xff;
446 CalculateIdentifyDriveChecksum (IdentifyDriveData, &FinalChecksum);
447
448 //
449 // Force new checksum such that sum is 0.
450 //
451 FinalChecksum = (UINT8) ((UINT8)0 - FinalChecksum);
452 ReadInfo->Raw[255] = (UINT16) (ReadInfo->Raw[255] | (FinalChecksum << 8));
453 }
454 }
455 }
456
457 /**
458 Identify drive data must be updated to actual parameters before boot.
459 Do for all drives.
460
461 @param Private Legacy BIOS Instance data
462
463
464 **/
465 VOID
UpdateAllIdentifyDriveData(IN LEGACY_BIOS_INSTANCE * Private)466 UpdateAllIdentifyDriveData (
467 IN LEGACY_BIOS_INSTANCE *Private
468 )
469 {
470 UINTN Index;
471 HDD_INFO *HddInfo;
472
473 HddInfo = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo[0];
474
475 for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) {
476 //
477 // Each controller can have 2 devices. Update for each device
478 //
479 if ((HddInfo[Index].Status & HDD_MASTER_IDE) != 0) {
480 UpdateIdentifyDriveData ((UINT8 *) (&HddInfo[Index].IdentifyDrive[0].Raw[0]));
481 }
482
483 if ((HddInfo[Index].Status & HDD_SLAVE_IDE) != 0) {
484 UpdateIdentifyDriveData ((UINT8 *) (&HddInfo[Index].IdentifyDrive[1].Raw[0]));
485 }
486 }
487 }
488
489 /**
490 Enable ide controller. This gets disabled when LegacyBoot.c is about
491 to run the Option ROMs.
492
493 @param Private Legacy BIOS Instance data
494
495
496 **/
497 VOID
EnableIdeController(IN LEGACY_BIOS_INSTANCE * Private)498 EnableIdeController (
499 IN LEGACY_BIOS_INSTANCE *Private
500 )
501 {
502 EFI_PCI_IO_PROTOCOL *PciIo;
503 EFI_STATUS Status;
504 EFI_HANDLE IdeController;
505 UINT8 ByteBuffer;
506 UINTN HandleCount;
507 EFI_HANDLE *HandleBuffer;
508
509 Status = Private->LegacyBiosPlatform->GetPlatformHandle (
510 Private->LegacyBiosPlatform,
511 EfiGetPlatformIdeHandle,
512 0,
513 &HandleBuffer,
514 &HandleCount,
515 NULL
516 );
517 if (!EFI_ERROR (Status)) {
518 IdeController = HandleBuffer[0];
519 Status = gBS->HandleProtocol (
520 IdeController,
521 &gEfiPciIoProtocolGuid,
522 (VOID **) &PciIo
523 );
524 ByteBuffer = 0x1f;
525 if (!EFI_ERROR (Status)) {
526 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x04, 1, &ByteBuffer);
527 }
528 }
529 }
530
531
532 /**
533 Enable ide controller. This gets disabled when LegacyBoot.c is about
534 to run the Option ROMs.
535
536 @param Private Legacy BIOS Instance data
537
538
539 **/
540 VOID
EnableAllControllers(IN LEGACY_BIOS_INSTANCE * Private)541 EnableAllControllers (
542 IN LEGACY_BIOS_INSTANCE *Private
543 )
544 {
545 UINTN HandleCount;
546 EFI_HANDLE *HandleBuffer;
547 UINTN Index;
548 EFI_PCI_IO_PROTOCOL *PciIo;
549 PCI_TYPE01 PciConfigHeader;
550 EFI_STATUS Status;
551
552 //
553 //
554 //
555 EnableIdeController (Private);
556
557 //
558 // Assumption is table is built from low bus to high bus numbers.
559 //
560 Status = gBS->LocateHandleBuffer (
561 ByProtocol,
562 &gEfiPciIoProtocolGuid,
563 NULL,
564 &HandleCount,
565 &HandleBuffer
566 );
567 ASSERT_EFI_ERROR (Status);
568
569 for (Index = 0; Index < HandleCount; Index++) {
570 Status = gBS->HandleProtocol (
571 HandleBuffer[Index],
572 &gEfiPciIoProtocolGuid,
573 (VOID **) &PciIo
574 );
575 ASSERT_EFI_ERROR (Status);
576
577 PciIo->Pci.Read (
578 PciIo,
579 EfiPciIoWidthUint32,
580 0,
581 sizeof (PciConfigHeader) / sizeof (UINT32),
582 &PciConfigHeader
583 );
584
585 //
586 // We do not enable PPB here. This is for HotPlug Consideration.
587 // The Platform HotPlug Driver is responsible for Padding enough hot plug
588 // resources. It is also responsible for enable this bridge. If it
589 // does not pad it. It will cause some early Windows fail to installation.
590 // If the platform driver does not pad resource for PPB, PPB should be in
591 // un-enabled state to let Windows know that this PPB is not configured by
592 // BIOS. So Windows will allocate default resource for PPB.
593 //
594 // The reason for why we enable the command register is:
595 // The CSM will use the IO bar to detect some IRQ status, if the command
596 // is disabled, the IO resource will be out of scope.
597 // For example:
598 // We installed a legacy IRQ handle for a PCI IDE controller. When IRQ
599 // comes up, the handle will check the IO space to identify is the
600 // controller generated the IRQ source.
601 // If the IO command is not enabled, the IRQ handler will has wrong
602 // information. It will cause IRQ storm when the correctly IRQ handler fails
603 // to run.
604 //
605 if (!(IS_PCI_VGA (&PciConfigHeader) ||
606 IS_PCI_OLD_VGA (&PciConfigHeader) ||
607 IS_PCI_IDE (&PciConfigHeader) ||
608 IS_PCI_P2P (&PciConfigHeader) ||
609 IS_PCI_P2P_SUB (&PciConfigHeader) ||
610 IS_PCI_LPC (&PciConfigHeader) )) {
611
612 PciConfigHeader.Hdr.Command |= 0x1f;
613
614 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 4, 1, &PciConfigHeader.Hdr.Command);
615 }
616 }
617 }
618
619 /**
620 The following routines are identical in operation, so combine
621 for code compaction:
622 EfiGetPlatformBinaryGetMpTable
623 EfiGetPlatformBinaryGetOemIntData
624 EfiGetPlatformBinaryGetOem32Data
625 EfiGetPlatformBinaryGetOem16Data
626
627 @param This Protocol instance pointer.
628 @param Id Table/Data identifier
629
630 @retval EFI_SUCCESS Success
631 @retval EFI_INVALID_PARAMETER Invalid ID
632 @retval EFI_OUT_OF_RESOURCES no resource to get data or table
633
634 **/
635 EFI_STATUS
LegacyGetDataOrTable(IN EFI_LEGACY_BIOS_PROTOCOL * This,IN EFI_GET_PLATFORM_INFO_MODE Id)636 LegacyGetDataOrTable (
637 IN EFI_LEGACY_BIOS_PROTOCOL *This,
638 IN EFI_GET_PLATFORM_INFO_MODE Id
639 )
640 {
641 VOID *Table;
642 UINT32 TablePtr;
643 UINTN TableSize;
644 UINTN Alignment;
645 UINTN Location;
646 EFI_STATUS Status;
647 EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;
648 EFI_COMPATIBILITY16_TABLE *Legacy16Table;
649 EFI_IA32_REGISTER_SET Regs;
650 LEGACY_BIOS_INSTANCE *Private;
651
652 Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
653
654 LegacyBiosPlatform = Private->LegacyBiosPlatform;
655 Legacy16Table = Private->Legacy16Table;
656
657 //
658 // Phase 1 - get an address allocated in 16-bit code
659 //
660 while (TRUE) {
661 switch (Id) {
662 case EfiGetPlatformBinaryMpTable:
663 case EfiGetPlatformBinaryOemIntData:
664 case EfiGetPlatformBinaryOem32Data:
665 case EfiGetPlatformBinaryOem16Data:
666 {
667 Status = LegacyBiosPlatform->GetPlatformInfo (
668 LegacyBiosPlatform,
669 Id,
670 (VOID *) &Table,
671 &TableSize,
672 &Location,
673 &Alignment,
674 0,
675 0
676 );
677 DEBUG ((EFI_D_INFO, "LegacyGetDataOrTable - ID: %x, %r\n", (UINTN)Id, Status));
678 DEBUG ((EFI_D_INFO, " Table - %x, Size - %x, Location - %x, Alignment - %x\n", (UINTN)Table, (UINTN)TableSize, (UINTN)Location, (UINTN)Alignment));
679 break;
680 }
681
682 default:
683 {
684 return EFI_INVALID_PARAMETER;
685 }
686 }
687
688 if (EFI_ERROR (Status)) {
689 return Status;
690 }
691
692 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
693 Regs.X.AX = Legacy16GetTableAddress;
694 Regs.X.CX = (UINT16) TableSize;
695 Regs.X.BX = (UINT16) Location;
696 Regs.X.DX = (UINT16) Alignment;
697 Private->LegacyBios.FarCall86 (
698 This,
699 Private->Legacy16CallSegment,
700 Private->Legacy16CallOffset,
701 &Regs,
702 NULL,
703 0
704 );
705
706 if (Regs.X.AX != 0) {
707 DEBUG ((EFI_D_ERROR, "Table ID %x length insufficient\n", Id));
708 return EFI_OUT_OF_RESOURCES;
709 } else {
710 break;
711 }
712 }
713 //
714 // Phase 2 Call routine second time with address to allow address adjustment
715 //
716 Status = LegacyBiosPlatform->GetPlatformInfo (
717 LegacyBiosPlatform,
718 Id,
719 (VOID *) &Table,
720 &TableSize,
721 &Location,
722 &Alignment,
723 Regs.X.DS,
724 Regs.X.BX
725 );
726 switch (Id) {
727 case EfiGetPlatformBinaryMpTable:
728 {
729 Legacy16Table->MpTablePtr = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
730 Legacy16Table->MpTableLength = (UINT32)TableSize;
731 DEBUG ((EFI_D_INFO, "MP table in legacy region - %x\n", (UINTN)Legacy16Table->MpTablePtr));
732 break;
733 }
734
735 case EfiGetPlatformBinaryOemIntData:
736 {
737
738 Legacy16Table->OemIntSegment = Regs.X.DS;
739 Legacy16Table->OemIntOffset = Regs.X.BX;
740 DEBUG ((EFI_D_INFO, "OemInt table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->OemIntSegment, (UINTN)Legacy16Table->OemIntOffset));
741 break;
742 }
743
744 case EfiGetPlatformBinaryOem32Data:
745 {
746 Legacy16Table->Oem32Segment = Regs.X.DS;
747 Legacy16Table->Oem32Offset = Regs.X.BX;
748 DEBUG ((EFI_D_INFO, "Oem32 table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->Oem32Segment, (UINTN)Legacy16Table->Oem32Offset));
749 break;
750 }
751
752 case EfiGetPlatformBinaryOem16Data:
753 {
754 //
755 // Legacy16Table->Oem16Segment = Regs.X.DS;
756 // Legacy16Table->Oem16Offset = Regs.X.BX;
757 DEBUG ((EFI_D_INFO, "Oem16 table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->Oem16Segment, (UINTN)Legacy16Table->Oem16Offset));
758 break;
759 }
760
761 default:
762 {
763 return EFI_INVALID_PARAMETER;
764 }
765 }
766
767 if (EFI_ERROR (Status)) {
768 return Status;
769 }
770 //
771 // Phase 3 Copy table to final location
772 //
773 TablePtr = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
774
775 CopyMem (
776 (VOID *) (UINTN)TablePtr,
777 Table,
778 TableSize
779 );
780
781 return EFI_SUCCESS;
782 }
783
784 /**
785 Copy SMBIOS table to EfiReservedMemoryType of memory for legacy boot.
786
787 **/
788 VOID
CreateSmbiosTableInReservedMemory(VOID)789 CreateSmbiosTableInReservedMemory (
790 VOID
791 )
792 {
793 SMBIOS_TABLE_ENTRY_POINT *EntryPointStructure;
794
795 if ((mRuntimeSmbiosEntryPoint == NULL) ||
796 (mReserveSmbiosEntryPoint == 0) ||
797 (mStructureTableAddress == 0)) {
798 return;
799 }
800
801 EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *) mRuntimeSmbiosEntryPoint;
802
803 //
804 // Copy SMBIOS Entry Point Structure
805 //
806 CopyMem (
807 (VOID *)(UINTN) mReserveSmbiosEntryPoint,
808 EntryPointStructure,
809 EntryPointStructure->EntryPointLength
810 );
811
812 //
813 // Copy SMBIOS Structure Table into EfiReservedMemoryType memory
814 //
815 CopyMem (
816 (VOID *)(UINTN) mStructureTableAddress,
817 (VOID *)(UINTN) EntryPointStructure->TableAddress,
818 EntryPointStructure->TableLength
819 );
820
821 //
822 // Update TableAddress in Entry Point Structure
823 //
824 EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *)(UINTN) mReserveSmbiosEntryPoint;
825 EntryPointStructure->TableAddress = (UINT32)(UINTN) mStructureTableAddress;
826
827 //
828 // Fixup checksums in the Entry Point Structure
829 //
830 EntryPointStructure->IntermediateChecksum = 0;
831 EntryPointStructure->EntryPointStructureChecksum = 0;
832
833 EntryPointStructure->IntermediateChecksum =
834 CalculateCheckSum8 (
835 (UINT8 *) EntryPointStructure + OFFSET_OF (SMBIOS_TABLE_ENTRY_POINT, IntermediateAnchorString),
836 EntryPointStructure->EntryPointLength - OFFSET_OF (SMBIOS_TABLE_ENTRY_POINT, IntermediateAnchorString)
837 );
838 EntryPointStructure->EntryPointStructureChecksum =
839 CalculateCheckSum8 ((UINT8 *) EntryPointStructure, EntryPointStructure->EntryPointLength);
840 }
841
842 /**
843 Assign drive number to legacy HDD drives prior to booting an EFI
844 aware OS so the OS can access drives without an EFI driver.
845 Note: BBS compliant drives ARE NOT available until this call by
846 either shell or EFI.
847
848 @param This Protocol instance pointer.
849
850 @retval EFI_SUCCESS Drive numbers assigned
851
852 **/
853 EFI_STATUS
GenericLegacyBoot(IN EFI_LEGACY_BIOS_PROTOCOL * This)854 GenericLegacyBoot (
855 IN EFI_LEGACY_BIOS_PROTOCOL *This
856 )
857 {
858 EFI_STATUS Status;
859 LEGACY_BIOS_INSTANCE *Private;
860 EFI_IA32_REGISTER_SET Regs;
861 EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
862 EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;
863 UINTN CopySize;
864 VOID *AcpiPtr;
865 HDD_INFO *HddInfo;
866 HDD_INFO *LocalHddInfo;
867 UINTN Index;
868 EFI_COMPATIBILITY16_TABLE *Legacy16Table;
869 UINT32 *BdaPtr;
870 UINT16 HddCount;
871 UINT16 BbsCount;
872 BBS_TABLE *LocalBbsTable;
873 UINT32 *BaseVectorMaster;
874 EFI_TIME BootTime;
875 UINT32 LocalTime;
876 EFI_HANDLE IdeController;
877 UINTN HandleCount;
878 EFI_HANDLE *HandleBuffer;
879 VOID *AcpiTable;
880 UINTN ShadowAddress;
881 UINT32 Granularity;
882
883 LocalHddInfo = NULL;
884 HddCount = 0;
885 BbsCount = 0;
886 LocalBbsTable = NULL;
887
888 Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
889 DEBUG_CODE (
890 DEBUG ((EFI_D_ERROR, "Start of legacy boot\n"));
891 );
892
893 Legacy16Table = Private->Legacy16Table;
894 EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
895 HddInfo = &EfiToLegacy16BootTable->HddInfo[0];
896
897 LegacyBiosPlatform = Private->LegacyBiosPlatform;
898
899 EfiToLegacy16BootTable->MajorVersion = EFI_TO_LEGACY_MAJOR_VERSION;
900 EfiToLegacy16BootTable->MinorVersion = EFI_TO_LEGACY_MINOR_VERSION;
901
902 //
903 // If booting to a legacy OS then force HDD drives to the appropriate
904 // boot mode by calling GetIdeHandle.
905 // A reconnect -r can force all HDDs back to native mode.
906 //
907 IdeController = NULL;
908 if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
909 Status = LegacyBiosPlatform->GetPlatformHandle (
910 Private->LegacyBiosPlatform,
911 EfiGetPlatformIdeHandle,
912 0,
913 &HandleBuffer,
914 &HandleCount,
915 NULL
916 );
917 if (!EFI_ERROR (Status)) {
918 IdeController = HandleBuffer[0];
919 }
920 }
921 //
922 // Unlock the Legacy BIOS region
923 //
924 Private->LegacyRegion->UnLock (
925 Private->LegacyRegion,
926 0xE0000,
927 0x20000,
928 &Granularity
929 );
930
931 //
932 // Reconstruct the Legacy16 boot memory map
933 //
934 LegacyBiosBuildE820 (Private, &CopySize);
935 if (CopySize > Private->Legacy16Table->E820Length) {
936 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
937 Regs.X.AX = Legacy16GetTableAddress;
938 Regs.X.CX = (UINT16) CopySize;
939 Private->LegacyBios.FarCall86 (
940 &Private->LegacyBios,
941 Private->Legacy16Table->Compatibility16CallSegment,
942 Private->Legacy16Table->Compatibility16CallOffset,
943 &Regs,
944 NULL,
945 0
946 );
947
948 Private->Legacy16Table->E820Pointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
949 Private->Legacy16Table->E820Length = (UINT32) CopySize;
950 if (Regs.X.AX != 0) {
951 DEBUG ((EFI_D_ERROR, "Legacy16 E820 length insufficient\n"));
952 } else {
953 CopyMem (
954 (VOID *)(UINTN) Private->Legacy16Table->E820Pointer,
955 Private->E820Table,
956 CopySize
957 );
958 }
959 } else {
960 CopyMem (
961 (VOID *)(UINTN) Private->Legacy16Table->E820Pointer,
962 Private->E820Table,
963 CopySize
964 );
965 Private->Legacy16Table->E820Length = (UINT32) CopySize;
966 }
967
968 //
969 // We do not ASSERT if SmbiosTable not found. It is possbile that a platform does not produce SmbiosTable.
970 //
971 if (mReserveSmbiosEntryPoint == 0) {
972 DEBUG ((EFI_D_INFO, "Smbios table is not found!\n"));
973 }
974 CreateSmbiosTableInReservedMemory ();
975 EfiToLegacy16BootTable->SmbiosTable = (UINT32)(UINTN)mReserveSmbiosEntryPoint;
976
977 AcpiTable = NULL;
978 Status = EfiGetSystemConfigurationTable (
979 &gEfiAcpi20TableGuid,
980 &AcpiTable
981 );
982 if (EFI_ERROR (Status)) {
983 Status = EfiGetSystemConfigurationTable (
984 &gEfiAcpi10TableGuid,
985 &AcpiTable
986 );
987 }
988 //
989 // We do not ASSERT if AcpiTable not found. It is possbile that a platform does not produce AcpiTable.
990 //
991 if (AcpiTable == NULL) {
992 DEBUG ((EFI_D_INFO, "ACPI table is not found!\n"));
993 }
994 EfiToLegacy16BootTable->AcpiTable = (UINT32)(UINTN)AcpiTable;
995
996 //
997 // Get RSD Ptr table rev at offset 15 decimal
998 // Rev = 0 Length is 20 decimal
999 // Rev != 0 Length is UINT32 at offset 20 decimal
1000 //
1001 if (AcpiTable != NULL) {
1002
1003 AcpiPtr = AcpiTable;
1004 if (*((UINT8 *) AcpiPtr + 15) == 0) {
1005 CopySize = 20;
1006 } else {
1007 AcpiPtr = ((UINT8 *) AcpiPtr + 20);
1008 CopySize = (*(UINT32 *) AcpiPtr);
1009 }
1010
1011 CopyMem (
1012 (VOID *)(UINTN) Private->Legacy16Table->AcpiRsdPtrPointer,
1013 AcpiTable,
1014 CopySize
1015 );
1016 }
1017 //
1018 // Make sure all PCI Interrupt Line register are programmed to match 8259
1019 //
1020 PciProgramAllInterruptLineRegisters (Private);
1021
1022 //
1023 // Unlock the Legacy BIOS region as PciProgramAllInterruptLineRegisters
1024 // can lock it.
1025 //
1026 Private->LegacyRegion->UnLock (
1027 Private->LegacyRegion,
1028 Private->BiosStart,
1029 Private->LegacyBiosImageSize,
1030 &Granularity
1031 );
1032
1033 //
1034 // Configure Legacy Device Magic
1035 //
1036 // Only do this code if booting legacy OS
1037 //
1038 if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
1039 UpdateSioData (Private);
1040 }
1041 //
1042 // Setup BDA and EBDA standard areas before Legacy Boot
1043 //
1044 LegacyBiosCompleteBdaBeforeBoot (Private);
1045 LegacyBiosCompleteStandardCmosBeforeBoot (Private);
1046
1047 //
1048 // We must build IDE data, if it hasn't been done, before PciShadowRoms
1049 // to insure EFI drivers are connected.
1050 //
1051 LegacyBiosBuildIdeData (Private, &HddInfo, 1);
1052 UpdateAllIdentifyDriveData (Private);
1053
1054 //
1055 // Clear IO BAR, if IDE controller in legacy mode.
1056 //
1057 InitLegacyIdeController (IdeController);
1058
1059 //
1060 // Generate number of ticks since midnight for BDA. DOS requires this
1061 // for its time. We have to make assumptions as to how long following
1062 // code takes since after PciShadowRoms PciIo is gone. Place result in
1063 // 40:6C-6F
1064 //
1065 // Adjust value by 1 second.
1066 //
1067 gRT->GetTime (&BootTime, NULL);
1068 LocalTime = BootTime.Hour * 3600 + BootTime.Minute * 60 + BootTime.Second;
1069 LocalTime += 1;
1070
1071 //
1072 // Multiply result by 18.2 for number of ticks since midnight.
1073 // Use 182/10 to avoid floating point math.
1074 //
1075 LocalTime = (LocalTime * 182) / 10;
1076 BdaPtr = (UINT32 *) (UINTN)0x46C;
1077 *BdaPtr = LocalTime;
1078
1079 //
1080 // Shadow PCI ROMs. We must do this near the end since this will kick
1081 // of Native EFI drivers that may be needed to collect info for Legacy16
1082 //
1083 // WARNING: PciIo is gone after this call.
1084 //
1085 PciShadowRoms (Private);
1086
1087 //
1088 // Shadow PXE base code, BIS etc.
1089 //
1090 Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xc0000, 0x40000, &Granularity);
1091 ShadowAddress = Private->OptionRom;
1092 Private->LegacyBiosPlatform->PlatformHooks (
1093 Private->LegacyBiosPlatform,
1094 EfiPlatformHookShadowServiceRoms,
1095 0,
1096 0,
1097 &ShadowAddress,
1098 Legacy16Table,
1099 NULL
1100 );
1101 Private->OptionRom = (UINT32)ShadowAddress;
1102 //
1103 // Register Legacy SMI Handler
1104 //
1105 LegacyBiosPlatform->SmmInit (
1106 LegacyBiosPlatform,
1107 EfiToLegacy16BootTable
1108 );
1109
1110 //
1111 // Let platform code know the boot options
1112 //
1113 LegacyBiosGetBbsInfo (
1114 This,
1115 &HddCount,
1116 &LocalHddInfo,
1117 &BbsCount,
1118 &LocalBbsTable
1119 );
1120
1121 DEBUG_CODE (
1122 PrintPciInterruptRegister ();
1123 PrintBbsTable (LocalBbsTable);
1124 PrintHddInfo (LocalHddInfo);
1125 );
1126 //
1127 // If drive wasn't spun up then BuildIdeData may have found new drives.
1128 // Need to update BBS boot priority.
1129 //
1130 for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) {
1131 if ((LocalHddInfo[Index].IdentifyDrive[0].Raw[0] != 0) &&
1132 (LocalBbsTable[2 * Index + 1].BootPriority == BBS_IGNORE_ENTRY)
1133 ) {
1134 LocalBbsTable[2 * Index + 1].BootPriority = BBS_UNPRIORITIZED_ENTRY;
1135 }
1136
1137 if ((LocalHddInfo[Index].IdentifyDrive[1].Raw[0] != 0) &&
1138 (LocalBbsTable[2 * Index + 2].BootPriority == BBS_IGNORE_ENTRY)
1139 ) {
1140 LocalBbsTable[2 * Index + 2].BootPriority = BBS_UNPRIORITIZED_ENTRY;
1141 }
1142 }
1143
1144 Private->LegacyRegion->UnLock (
1145 Private->LegacyRegion,
1146 0xc0000,
1147 0x40000,
1148 &Granularity
1149 );
1150
1151 LegacyBiosPlatform->PrepareToBoot (
1152 LegacyBiosPlatform,
1153 mBbsDevicePathPtr,
1154 mBbsTable,
1155 mLoadOptionsSize,
1156 mLoadOptions,
1157 (VOID *) &Private->IntThunk->EfiToLegacy16BootTable
1158 );
1159
1160 //
1161 // If no boot device return to BDS
1162 //
1163 if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
1164 for (Index = 0; Index < BbsCount; Index++){
1165 if ((LocalBbsTable[Index].BootPriority != BBS_DO_NOT_BOOT_FROM) &&
1166 (LocalBbsTable[Index].BootPriority != BBS_UNPRIORITIZED_ENTRY) &&
1167 (LocalBbsTable[Index].BootPriority != BBS_IGNORE_ENTRY)) {
1168 break;
1169 }
1170 }
1171 if (Index == BbsCount) {
1172 return EFI_DEVICE_ERROR;
1173 }
1174 }
1175 //
1176 // Let the Legacy16 code know the device path type for legacy boot
1177 //
1178 EfiToLegacy16BootTable->DevicePathType = mBbsDevicePathPtr->DeviceType;
1179
1180 //
1181 // Copy MP table, if it exists.
1182 //
1183 LegacyGetDataOrTable (This, EfiGetPlatformBinaryMpTable);
1184
1185 if (!Private->LegacyBootEntered) {
1186 //
1187 // Copy OEM INT Data, if it exists. Note: This code treats any data
1188 // as a bag of bits and knows nothing of the contents nor cares.
1189 // Contents are IBV specific.
1190 //
1191 LegacyGetDataOrTable (This, EfiGetPlatformBinaryOemIntData);
1192
1193 //
1194 // Copy OEM16 Data, if it exists.Note: This code treats any data
1195 // as a bag of bits and knows nothing of the contents nor cares.
1196 // Contents are IBV specific.
1197 //
1198 LegacyGetDataOrTable (This, EfiGetPlatformBinaryOem16Data);
1199
1200 //
1201 // Copy OEM32 Data, if it exists.Note: This code treats any data
1202 // as a bag of bits and knows nothing of the contents nor cares.
1203 // Contents are IBV specific.
1204 //
1205 LegacyGetDataOrTable (This, EfiGetPlatformBinaryOem32Data);
1206 }
1207
1208 //
1209 // Call into Legacy16 code to prepare for INT 19h
1210 //
1211 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
1212 Regs.X.AX = Legacy16PrepareToBoot;
1213
1214 //
1215 // Pass in handoff data
1216 //
1217 Regs.X.ES = NORMALIZE_EFI_SEGMENT ((UINTN)EfiToLegacy16BootTable);
1218 Regs.X.BX = NORMALIZE_EFI_OFFSET ((UINTN)EfiToLegacy16BootTable);
1219
1220 Private->LegacyBios.FarCall86 (
1221 This,
1222 Private->Legacy16CallSegment,
1223 Private->Legacy16CallOffset,
1224 &Regs,
1225 NULL,
1226 0
1227 );
1228
1229 if (Regs.X.AX != 0) {
1230 return EFI_DEVICE_ERROR;
1231 }
1232 //
1233 // Lock the Legacy BIOS region
1234 //
1235 Private->LegacyRegion->Lock (
1236 Private->LegacyRegion,
1237 0xc0000,
1238 0x40000,
1239 &Granularity
1240 );
1241
1242 if ((Private->Legacy16Table->TableLength >= OFFSET_OF (EFI_COMPATIBILITY16_TABLE, HiPermanentMemoryAddress)) &&
1243 ((Private->Legacy16Table->UmaAddress != 0) && (Private->Legacy16Table->UmaSize != 0))) {
1244 //
1245 // Here we could reduce UmaAddress down as far as Private->OptionRom, taking into
1246 // account the granularity of the access control.
1247 //
1248 DEBUG((EFI_D_INFO, "Unlocking UMB RAM region 0x%x-0x%x\n", Private->Legacy16Table->UmaAddress,
1249 Private->Legacy16Table->UmaAddress + Private->Legacy16Table->UmaSize));
1250
1251 Private->LegacyRegion->UnLock (
1252 Private->LegacyRegion,
1253 Private->Legacy16Table->UmaAddress,
1254 Private->Legacy16Table->UmaSize,
1255 &Granularity
1256 );
1257 }
1258
1259 //
1260 // Lock attributes of the Legacy Region if chipset supports
1261 //
1262 Private->LegacyRegion->BootLock (
1263 Private->LegacyRegion,
1264 0xc0000,
1265 0x40000,
1266 &Granularity
1267 );
1268
1269 //
1270 // Call into Legacy16 code to do the INT 19h
1271 //
1272 EnableAllControllers (Private);
1273 if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
1274
1275 //
1276 // Signal all the events that are waiting on EVT_SIGNAL_LEGACY_BOOT
1277 //
1278 EfiSignalEventLegacyBoot ();
1279
1280 //
1281 // Report Status Code to indicate legacy boot event was signalled
1282 //
1283 REPORT_STATUS_CODE (
1284 EFI_PROGRESS_CODE,
1285 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_LEGACY_BOOT_EVENT)
1286 );
1287
1288 DEBUG ((EFI_D_INFO, "Legacy INT19 Boot...\n"));
1289
1290 //
1291 // Disable DXE Timer while executing in real mode
1292 //
1293 Private->Timer->SetTimerPeriod (Private->Timer, 0);
1294
1295 //
1296 // Save and disable interrupt of debug timer
1297 //
1298 SaveAndSetDebugTimerInterrupt (FALSE);
1299
1300
1301 //
1302 // Put the 8259 into its legacy mode by reprogramming the vector bases
1303 //
1304 Private->Legacy8259->SetVectorBase (Private->Legacy8259, LEGACY_MODE_BASE_VECTOR_MASTER, LEGACY_MODE_BASE_VECTOR_SLAVE);
1305 //
1306 // PC History
1307 // The original PC used INT8-F for master PIC. Since these mapped over
1308 // processor exceptions TIANO moved the master PIC to INT68-6F.
1309 // We need to set these back to the Legacy16 unexpected interrupt(saved
1310 // in LegacyBios.c) since some OS see that these have values different from
1311 // what is expected and invoke them. Since the legacy OS corrupts EFI
1312 // memory, there is no handler for these interrupts and OS blows up.
1313 //
1314 // We need to save the TIANO values for the rare case that the Legacy16
1315 // code cannot boot but knows memory hasn't been destroyed.
1316 //
1317 // To compound the problem, video takes over one of these INTS and must be
1318 // be left.
1319 // @bug - determine if video hooks INT(in which case we must find new
1320 // set of TIANO vectors) or takes it over.
1321 //
1322 //
1323 BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);
1324 for (Index = 0; Index < 8; Index++) {
1325 Private->ThunkSavedInt[Index] = BaseVectorMaster[Index];
1326 if (Private->ThunkSeg == (UINT16) (BaseVectorMaster[Index] >> 16)) {
1327 BaseVectorMaster[Index] = (UINT32) (Private->BiosUnexpectedInt);
1328 }
1329 }
1330
1331 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
1332 Regs.X.AX = Legacy16Boot;
1333
1334 Private->LegacyBios.FarCall86 (
1335 This,
1336 Private->Legacy16CallSegment,
1337 Private->Legacy16CallOffset,
1338 &Regs,
1339 NULL,
1340 0
1341 );
1342
1343 BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);
1344 for (Index = 0; Index < 8; Index++) {
1345 BaseVectorMaster[Index] = Private->ThunkSavedInt[Index];
1346 }
1347 }
1348 Private->LegacyBootEntered = TRUE;
1349 if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
1350 //
1351 // Should never return unless never passed control to 0:7c00(first stage
1352 // OS loader) and only then if no bootable device found.
1353 //
1354 return EFI_DEVICE_ERROR;
1355 } else {
1356 //
1357 // If boot to EFI then expect to return to caller
1358 //
1359 return EFI_SUCCESS;
1360 }
1361 }
1362
1363
1364 /**
1365 Assign drive number to legacy HDD drives prior to booting an EFI
1366 aware OS so the OS can access drives without an EFI driver.
1367 Note: BBS compliant drives ARE NOT available until this call by
1368 either shell or EFI.
1369
1370 @param This Protocol instance pointer.
1371 @param BbsCount Number of BBS_TABLE structures
1372 @param BbsTable List BBS entries
1373
1374 @retval EFI_SUCCESS Drive numbers assigned
1375
1376 **/
1377 EFI_STATUS
1378 EFIAPI
LegacyBiosPrepareToBootEfi(IN EFI_LEGACY_BIOS_PROTOCOL * This,OUT UINT16 * BbsCount,OUT BBS_TABLE ** BbsTable)1379 LegacyBiosPrepareToBootEfi (
1380 IN EFI_LEGACY_BIOS_PROTOCOL *This,
1381 OUT UINT16 *BbsCount,
1382 OUT BBS_TABLE **BbsTable
1383 )
1384 {
1385 EFI_STATUS Status;
1386 EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
1387 LEGACY_BIOS_INSTANCE *Private;
1388
1389 Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
1390 EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
1391 mBootMode = BOOT_EFI_OS;
1392 mBbsDevicePathPtr = NULL;
1393 Status = GenericLegacyBoot (This);
1394 *BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable;
1395 *BbsCount = (UINT16) (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE));
1396 return Status;
1397 }
1398
1399 /**
1400 To boot from an unconventional device like parties and/or execute HDD diagnostics.
1401
1402 @param This Protocol instance pointer.
1403 @param Attributes How to interpret the other input parameters
1404 @param BbsEntry The 0-based index into the BbsTable for the parent
1405 device.
1406 @param BeerData Pointer to the 128 bytes of ram BEER data.
1407 @param ServiceAreaData Pointer to the 64 bytes of raw Service Area data. The
1408 caller must provide a pointer to the specific Service
1409 Area and not the start all Service Areas.
1410
1411 @retval EFI_INVALID_PARAMETER if error. Does NOT return if no error.
1412
1413 ***/
1414 EFI_STATUS
1415 EFIAPI
LegacyBiosBootUnconventionalDevice(IN EFI_LEGACY_BIOS_PROTOCOL * This,IN UDC_ATTRIBUTES Attributes,IN UINTN BbsEntry,IN VOID * BeerData,IN VOID * ServiceAreaData)1416 LegacyBiosBootUnconventionalDevice (
1417 IN EFI_LEGACY_BIOS_PROTOCOL *This,
1418 IN UDC_ATTRIBUTES Attributes,
1419 IN UINTN BbsEntry,
1420 IN VOID *BeerData,
1421 IN VOID *ServiceAreaData
1422 )
1423 {
1424 EFI_STATUS Status;
1425 EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
1426 LEGACY_BIOS_INSTANCE *Private;
1427 UD_TABLE *UcdTable;
1428 UINTN Index;
1429 UINT16 BootPriority;
1430 BBS_TABLE *BbsTable;
1431
1432 BootPriority = 0;
1433 Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
1434 mBootMode = BOOT_UNCONVENTIONAL_DEVICE;
1435 mBbsDevicePathPtr = &mBbsDevicePathNode;
1436 mAttributes = Attributes;
1437 mBbsEntry = BbsEntry;
1438 mBeerData = BeerData, mServiceAreaData = ServiceAreaData;
1439
1440 EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
1441
1442 //
1443 // Do input parameter checking
1444 //
1445 if ((Attributes.DirectoryServiceValidity == 0) &&
1446 (Attributes.RabcaUsedFlag == 0) &&
1447 (Attributes.ExecuteHddDiagnosticsFlag == 0)
1448 ) {
1449 return EFI_INVALID_PARAMETER;
1450 }
1451
1452 if (((Attributes.DirectoryServiceValidity != 0) && (ServiceAreaData == NULL)) ||
1453 (((Attributes.DirectoryServiceValidity | Attributes.RabcaUsedFlag) != 0) && (BeerData == NULL))
1454 ) {
1455 return EFI_INVALID_PARAMETER;
1456 }
1457
1458 UcdTable = (UD_TABLE *) AllocatePool (
1459 sizeof (UD_TABLE)
1460 );
1461 if (NULL == UcdTable) {
1462 return EFI_OUT_OF_RESOURCES;
1463 }
1464
1465 EfiToLegacy16BootTable->UnconventionalDeviceTable = (UINT32)(UINTN)UcdTable;
1466 UcdTable->Attributes = Attributes;
1467 UcdTable->BbsTableEntryNumberForParentDevice = (UINT8) BbsEntry;
1468 //
1469 // Force all existing BBS entries to DoNotBoot. This allows 16-bit CSM
1470 // to assign drive numbers but bot boot from. Only newly created entries
1471 // will be valid.
1472 //
1473 BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable;
1474 for (Index = 0; Index < EfiToLegacy16BootTable->NumberBbsEntries; Index++) {
1475 BbsTable[Index].BootPriority = BBS_DO_NOT_BOOT_FROM;
1476 }
1477 //
1478 // If parent is onboard IDE then assign controller & device number
1479 // else they are 0.
1480 //
1481 if (BbsEntry < MAX_IDE_CONTROLLER * 2) {
1482 UcdTable->DeviceNumber = (UINT8) ((BbsEntry - 1) % 2);
1483 }
1484
1485 if (BeerData != NULL) {
1486 CopyMem (
1487 (VOID *) UcdTable->BeerData,
1488 BeerData,
1489 (UINTN) 128
1490 );
1491 }
1492
1493 if (ServiceAreaData != NULL) {
1494 CopyMem (
1495 (VOID *) UcdTable->ServiceAreaData,
1496 ServiceAreaData,
1497 (UINTN) 64
1498 );
1499 }
1500 //
1501 // For each new entry do the following:
1502 // 1. Increment current number of BBS entries
1503 // 2. Copy parent entry to new entry.
1504 // 3. Zero out BootHandler Offset & segment
1505 // 4. Set appropriate device type. BEV(0x80) for HDD diagnostics
1506 // and Floppy(0x01) for PARTIES boot.
1507 // 5. Assign new priority.
1508 //
1509 if ((Attributes.ExecuteHddDiagnosticsFlag) != 0) {
1510 EfiToLegacy16BootTable->NumberBbsEntries += 1;
1511
1512 CopyMem (
1513 (VOID *) &BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority,
1514 (VOID *) &BbsTable[BbsEntry].BootPriority,
1515 sizeof (BBS_TABLE)
1516 );
1517
1518 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerOffset = 0;
1519 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerSegment = 0;
1520 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].DeviceType = 0x80;
1521
1522 UcdTable->BbsTableEntryNumberForHddDiag = (UINT8) (EfiToLegacy16BootTable->NumberBbsEntries - 1);
1523
1524 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority = BootPriority;
1525 BootPriority += 1;
1526
1527 //
1528 // Set device type as BBS_TYPE_DEV for PARTIES diagnostic
1529 //
1530 mBbsDevicePathNode.DeviceType = BBS_TYPE_BEV;
1531 }
1532
1533 if (((Attributes.DirectoryServiceValidity | Attributes.RabcaUsedFlag)) != 0) {
1534 EfiToLegacy16BootTable->NumberBbsEntries += 1;
1535 CopyMem (
1536 (VOID *) &BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority,
1537 (VOID *) &BbsTable[BbsEntry].BootPriority,
1538 sizeof (BBS_TABLE)
1539 );
1540
1541 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerOffset = 0;
1542 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerSegment = 0;
1543 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].DeviceType = 0x01;
1544 UcdTable->BbsTableEntryNumberForBoot = (UINT8) (EfiToLegacy16BootTable->NumberBbsEntries - 1);
1545 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority = BootPriority;
1546
1547 //
1548 // Set device type as BBS_TYPE_FLOPPY for PARTIES boot as floppy
1549 //
1550 mBbsDevicePathNode.DeviceType = BBS_TYPE_FLOPPY;
1551 }
1552 //
1553 // Build the BBS Device Path for this boot selection
1554 //
1555 mBbsDevicePathNode.Header.Type = BBS_DEVICE_PATH;
1556 mBbsDevicePathNode.Header.SubType = BBS_BBS_DP;
1557 SetDevicePathNodeLength (&mBbsDevicePathNode.Header, sizeof (BBS_BBS_DEVICE_PATH));
1558 mBbsDevicePathNode.StatusFlag = 0;
1559 mBbsDevicePathNode.String[0] = 0;
1560
1561 Status = GenericLegacyBoot (This);
1562 return Status;
1563 }
1564
1565 /**
1566 Attempt to legacy boot the BootOption. If the EFI contexted has been
1567 compromised this function will not return.
1568
1569 @param This Protocol instance pointer.
1570 @param BbsDevicePath EFI Device Path from BootXXXX variable.
1571 @param LoadOptionsSize Size of LoadOption in size.
1572 @param LoadOptions LoadOption from BootXXXX variable
1573
1574 @retval EFI_SUCCESS Removable media not present
1575
1576 **/
1577 EFI_STATUS
1578 EFIAPI
LegacyBiosLegacyBoot(IN EFI_LEGACY_BIOS_PROTOCOL * This,IN BBS_BBS_DEVICE_PATH * BbsDevicePath,IN UINT32 LoadOptionsSize,IN VOID * LoadOptions)1579 LegacyBiosLegacyBoot (
1580 IN EFI_LEGACY_BIOS_PROTOCOL *This,
1581 IN BBS_BBS_DEVICE_PATH *BbsDevicePath,
1582 IN UINT32 LoadOptionsSize,
1583 IN VOID *LoadOptions
1584 )
1585 {
1586 EFI_STATUS Status;
1587
1588 mBbsDevicePathPtr = BbsDevicePath;
1589 mLoadOptionsSize = LoadOptionsSize;
1590 mLoadOptions = LoadOptions;
1591 mBootMode = BOOT_LEGACY_OS;
1592 Status = GenericLegacyBoot (This);
1593
1594 return Status;
1595 }
1596
1597 /**
1598 Convert EFI Memory Type to E820 Memory Type.
1599
1600 @param Type EFI Memory Type
1601
1602 @return ACPI Memory Type for EFI Memory Type
1603
1604 **/
1605 EFI_ACPI_MEMORY_TYPE
EfiMemoryTypeToE820Type(IN UINT32 Type)1606 EfiMemoryTypeToE820Type (
1607 IN UINT32 Type
1608 )
1609 {
1610 switch (Type) {
1611 case EfiLoaderCode:
1612 case EfiLoaderData:
1613 case EfiBootServicesCode:
1614 case EfiBootServicesData:
1615 case EfiConventionalMemory:
1616 //
1617 // The memory of EfiRuntimeServicesCode and EfiRuntimeServicesData are
1618 // usable memory for legacy OS, because legacy OS is not aware of EFI runtime concept.
1619 // In ACPI specification, EfiRuntimeServiceCode and EfiRuntimeServiceData
1620 // should be mapped to AddressRangeReserved. This statement is for UEFI OS, not for legacy OS.
1621 //
1622 case EfiRuntimeServicesCode:
1623 case EfiRuntimeServicesData:
1624 return EfiAcpiAddressRangeMemory;
1625
1626 case EfiPersistentMemory:
1627 return EfiAddressRangePersistentMemory;
1628
1629 case EfiACPIReclaimMemory:
1630 return EfiAcpiAddressRangeACPI;
1631
1632 case EfiACPIMemoryNVS:
1633 return EfiAcpiAddressRangeNVS;
1634
1635 //
1636 // All other types map to reserved.
1637 // Adding the code just waists FLASH space.
1638 //
1639 // case EfiReservedMemoryType:
1640 // case EfiUnusableMemory:
1641 // case EfiMemoryMappedIO:
1642 // case EfiMemoryMappedIOPortSpace:
1643 // case EfiPalCode:
1644 //
1645 default:
1646 return EfiAcpiAddressRangeReserved;
1647 }
1648 }
1649
1650 /**
1651 Build the E820 table.
1652
1653 @param Private Legacy BIOS Instance data
1654 @param Size Size of E820 Table
1655
1656 @retval EFI_SUCCESS It should always work.
1657
1658 **/
1659 EFI_STATUS
LegacyBiosBuildE820(IN LEGACY_BIOS_INSTANCE * Private,OUT UINTN * Size)1660 LegacyBiosBuildE820 (
1661 IN LEGACY_BIOS_INSTANCE *Private,
1662 OUT UINTN *Size
1663 )
1664 {
1665 EFI_STATUS Status;
1666 EFI_E820_ENTRY64 *E820Table;
1667 EFI_MEMORY_DESCRIPTOR *EfiMemoryMap;
1668 EFI_MEMORY_DESCRIPTOR *EfiMemoryMapEnd;
1669 EFI_MEMORY_DESCRIPTOR *EfiEntry;
1670 EFI_MEMORY_DESCRIPTOR *NextEfiEntry;
1671 EFI_MEMORY_DESCRIPTOR TempEfiEntry;
1672 UINTN EfiMemoryMapSize;
1673 UINTN EfiMapKey;
1674 UINTN EfiDescriptorSize;
1675 UINT32 EfiDescriptorVersion;
1676 UINTN Index;
1677 EFI_PEI_HOB_POINTERS Hob;
1678 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
1679 UINTN TempIndex;
1680 UINTN IndexSort;
1681 UINTN TempNextIndex;
1682 EFI_E820_ENTRY64 TempE820;
1683 EFI_ACPI_MEMORY_TYPE TempType;
1684 BOOLEAN ChangedFlag;
1685 UINTN Above1MIndex;
1686 UINT64 MemoryBlockLength;
1687
1688 E820Table = (EFI_E820_ENTRY64 *) Private->E820Table;
1689
1690 //
1691 // Get the EFI memory map.
1692 //
1693 EfiMemoryMapSize = 0;
1694 EfiMemoryMap = NULL;
1695 Status = gBS->GetMemoryMap (
1696 &EfiMemoryMapSize,
1697 EfiMemoryMap,
1698 &EfiMapKey,
1699 &EfiDescriptorSize,
1700 &EfiDescriptorVersion
1701 );
1702 ASSERT (Status == EFI_BUFFER_TOO_SMALL);
1703
1704 do {
1705 //
1706 // Use size returned back plus 1 descriptor for the AllocatePool.
1707 // We don't just multiply by 2 since the "for" loop below terminates on
1708 // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwize
1709 // we process bogus entries and create bogus E820 entries.
1710 //
1711 EfiMemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (EfiMemoryMapSize);
1712 ASSERT (EfiMemoryMap != NULL);
1713 Status = gBS->GetMemoryMap (
1714 &EfiMemoryMapSize,
1715 EfiMemoryMap,
1716 &EfiMapKey,
1717 &EfiDescriptorSize,
1718 &EfiDescriptorVersion
1719 );
1720 if (EFI_ERROR (Status)) {
1721 FreePool (EfiMemoryMap);
1722 }
1723 } while (Status == EFI_BUFFER_TOO_SMALL);
1724
1725 ASSERT_EFI_ERROR (Status);
1726
1727 //
1728 // Punch in the E820 table for memory less than 1 MB.
1729 // Assume ZeroMem () has been done on data structure.
1730 //
1731 //
1732 // First entry is 0 to (640k - EBDA)
1733 //
1734 E820Table[0].BaseAddr = 0;
1735 E820Table[0].Length = (UINT64) ((*(UINT16 *) (UINTN)0x40E) << 4);
1736 E820Table[0].Type = EfiAcpiAddressRangeMemory;
1737
1738 //
1739 // Second entry is (640k - EBDA) to 640k
1740 //
1741 E820Table[1].BaseAddr = E820Table[0].Length;
1742 E820Table[1].Length = (UINT64) ((640 * 1024) - E820Table[0].Length);
1743 E820Table[1].Type = EfiAcpiAddressRangeReserved;
1744
1745 //
1746 // Third Entry is legacy BIOS
1747 // DO NOT CLAIM region from 0xA0000-0xDFFFF. OS can use free areas
1748 // to page in memory under 1MB.
1749 // Omit region from 0xE0000 to start of BIOS, if any. This can be
1750 // used for a multiple reasons including OPROMS.
1751 //
1752
1753 //
1754 // The CSM binary image size is not the actually size that CSM binary used,
1755 // to avoid memory corrupt, we declare the 0E0000 - 0FFFFF is used by CSM binary.
1756 //
1757 E820Table[2].BaseAddr = 0xE0000;
1758 E820Table[2].Length = 0x20000;
1759 E820Table[2].Type = EfiAcpiAddressRangeReserved;
1760
1761 Above1MIndex = 2;
1762
1763 //
1764 // Process the EFI map to produce E820 map;
1765 //
1766
1767 //
1768 // Sort memory map from low to high
1769 //
1770 EfiEntry = EfiMemoryMap;
1771 NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
1772 EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);
1773 while (EfiEntry < EfiMemoryMapEnd) {
1774 while (NextEfiEntry < EfiMemoryMapEnd) {
1775 if (EfiEntry->PhysicalStart > NextEfiEntry->PhysicalStart) {
1776 CopyMem (&TempEfiEntry, EfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
1777 CopyMem (EfiEntry, NextEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
1778 CopyMem (NextEfiEntry, &TempEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
1779 }
1780
1781 NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (NextEfiEntry, EfiDescriptorSize);
1782 }
1783
1784 EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
1785 NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
1786 }
1787
1788 EfiEntry = EfiMemoryMap;
1789 EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);
1790 for (Index = Above1MIndex; (EfiEntry < EfiMemoryMapEnd) && (Index < EFI_MAX_E820_ENTRY - 1); ) {
1791 MemoryBlockLength = (UINT64) (LShiftU64 (EfiEntry->NumberOfPages, 12));
1792 if ((EfiEntry->PhysicalStart + MemoryBlockLength) < 0x100000) {
1793 //
1794 // Skip the memory block is under 1MB
1795 //
1796 } else {
1797 if (EfiEntry->PhysicalStart < 0x100000) {
1798 //
1799 // When the memory block spans below 1MB, ensure the memory block start address is at least 1MB
1800 //
1801 MemoryBlockLength -= 0x100000 - EfiEntry->PhysicalStart;
1802 EfiEntry->PhysicalStart = 0x100000;
1803 }
1804
1805 //
1806 // Convert memory type to E820 type
1807 //
1808 TempType = EfiMemoryTypeToE820Type (EfiEntry->Type);
1809
1810 if ((E820Table[Index].Type == TempType) && (EfiEntry->PhysicalStart == (E820Table[Index].BaseAddr + E820Table[Index].Length))) {
1811 //
1812 // Grow an existing entry
1813 //
1814 E820Table[Index].Length += MemoryBlockLength;
1815 } else {
1816 //
1817 // Make a new entry
1818 //
1819 ++Index;
1820 E820Table[Index].BaseAddr = EfiEntry->PhysicalStart;
1821 E820Table[Index].Length = MemoryBlockLength;
1822 E820Table[Index].Type = TempType;
1823 }
1824 }
1825 EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
1826 }
1827
1828 FreePool (EfiMemoryMap);
1829
1830 //
1831 // Process the reserved memory map to produce E820 map ;
1832 //
1833 for (Hob.Raw = GetHobList (); !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
1834 if (Hob.Raw != NULL && GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
1835 ResourceHob = Hob.ResourceDescriptor;
1836 if (((ResourceHob->ResourceType == EFI_RESOURCE_MEMORY_MAPPED_IO) ||
1837 (ResourceHob->ResourceType == EFI_RESOURCE_FIRMWARE_DEVICE) ||
1838 (ResourceHob->ResourceType == EFI_RESOURCE_MEMORY_RESERVED) ) &&
1839 (ResourceHob->PhysicalStart > 0x100000) &&
1840 (Index < EFI_MAX_E820_ENTRY - 1)) {
1841 ++Index;
1842 E820Table[Index].BaseAddr = ResourceHob->PhysicalStart;
1843 E820Table[Index].Length = ResourceHob->ResourceLength;
1844 E820Table[Index].Type = EfiAcpiAddressRangeReserved;
1845 }
1846 }
1847 }
1848
1849 Index ++;
1850 Private->IntThunk->EfiToLegacy16InitTable.NumberE820Entries = (UINT32)Index;
1851 Private->IntThunk->EfiToLegacy16BootTable.NumberE820Entries = (UINT32)Index;
1852 Private->NumberE820Entries = (UINT32)Index;
1853 *Size = (UINTN) (Index * sizeof (EFI_E820_ENTRY64));
1854
1855 //
1856 // Sort E820Table from low to high
1857 //
1858 for (TempIndex = 0; TempIndex < Index; TempIndex++) {
1859 ChangedFlag = FALSE;
1860 for (TempNextIndex = 1; TempNextIndex < Index - TempIndex; TempNextIndex++) {
1861 if (E820Table[TempNextIndex - 1].BaseAddr > E820Table[TempNextIndex].BaseAddr) {
1862 ChangedFlag = TRUE;
1863 TempE820.BaseAddr = E820Table[TempNextIndex - 1].BaseAddr;
1864 TempE820.Length = E820Table[TempNextIndex - 1].Length;
1865 TempE820.Type = E820Table[TempNextIndex - 1].Type;
1866
1867 E820Table[TempNextIndex - 1].BaseAddr = E820Table[TempNextIndex].BaseAddr;
1868 E820Table[TempNextIndex - 1].Length = E820Table[TempNextIndex].Length;
1869 E820Table[TempNextIndex - 1].Type = E820Table[TempNextIndex].Type;
1870
1871 E820Table[TempNextIndex].BaseAddr = TempE820.BaseAddr;
1872 E820Table[TempNextIndex].Length = TempE820.Length;
1873 E820Table[TempNextIndex].Type = TempE820.Type;
1874 }
1875 }
1876
1877 if (!ChangedFlag) {
1878 break;
1879 }
1880 }
1881
1882 //
1883 // Remove the overlap range
1884 //
1885 for (TempIndex = 1; TempIndex < Index; TempIndex++) {
1886 if (E820Table[TempIndex - 1].BaseAddr <= E820Table[TempIndex].BaseAddr &&
1887 ((E820Table[TempIndex - 1].BaseAddr + E820Table[TempIndex - 1].Length) >=
1888 (E820Table[TempIndex].BaseAddr +E820Table[TempIndex].Length))) {
1889 //
1890 //Overlap range is found
1891 //
1892 ASSERT (E820Table[TempIndex - 1].Type == E820Table[TempIndex].Type);
1893
1894 if (TempIndex == Index - 1) {
1895 E820Table[TempIndex].BaseAddr = 0;
1896 E820Table[TempIndex].Length = 0;
1897 E820Table[TempIndex].Type = (EFI_ACPI_MEMORY_TYPE) 0;
1898 Index--;
1899 break;
1900 } else {
1901 for (IndexSort = TempIndex; IndexSort < Index - 1; IndexSort ++) {
1902 E820Table[IndexSort].BaseAddr = E820Table[IndexSort + 1].BaseAddr;
1903 E820Table[IndexSort].Length = E820Table[IndexSort + 1].Length;
1904 E820Table[IndexSort].Type = E820Table[IndexSort + 1].Type;
1905 }
1906 Index--;
1907 }
1908 }
1909 }
1910
1911
1912
1913 Private->IntThunk->EfiToLegacy16InitTable.NumberE820Entries = (UINT32)Index;
1914 Private->IntThunk->EfiToLegacy16BootTable.NumberE820Entries = (UINT32)Index;
1915 Private->NumberE820Entries = (UINT32)Index;
1916 *Size = (UINTN) (Index * sizeof (EFI_E820_ENTRY64));
1917
1918 //
1919 // Determine OS usable memory above 1Mb
1920 //
1921 Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb = 0x0000;
1922 for (TempIndex = Above1MIndex; TempIndex < Index; TempIndex++) {
1923 if (E820Table[TempIndex].BaseAddr >= 0x100000 && E820Table[TempIndex].BaseAddr < 0x100000000ULL) { // not include above 4G memory
1924 //
1925 // ACPIReclaimMemory is also usable memory for ACPI OS, after OS dumps all ACPI tables.
1926 //
1927 if ((E820Table[TempIndex].Type == EfiAcpiAddressRangeMemory) || (E820Table[TempIndex].Type == EfiAcpiAddressRangeACPI)) {
1928 Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb += (UINT32) (E820Table[TempIndex].Length);
1929 } else {
1930 break; // break at first not normal memory, because SMM may use reserved memory.
1931 }
1932 }
1933 }
1934
1935 Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb = Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb;
1936
1937 //
1938 // Print DEBUG information
1939 //
1940 for (TempIndex = 0; TempIndex < Index; TempIndex++) {
1941 DEBUG((EFI_D_INFO, "E820[%2d]: 0x%16lx ---- 0x%16lx, Type = 0x%x \n",
1942 TempIndex,
1943 E820Table[TempIndex].BaseAddr,
1944 (E820Table[TempIndex].BaseAddr + E820Table[TempIndex].Length),
1945 E820Table[TempIndex].Type
1946 ));
1947 }
1948
1949 return EFI_SUCCESS;
1950 }
1951
1952
1953 /**
1954 Fill in the standard BDA and EBDA stuff prior to legacy Boot
1955
1956 @param Private Legacy BIOS Instance data
1957
1958 @retval EFI_SUCCESS It should always work.
1959
1960 **/
1961 EFI_STATUS
LegacyBiosCompleteBdaBeforeBoot(IN LEGACY_BIOS_INSTANCE * Private)1962 LegacyBiosCompleteBdaBeforeBoot (
1963 IN LEGACY_BIOS_INSTANCE *Private
1964 )
1965 {
1966 BDA_STRUC *Bda;
1967 UINT16 MachineConfig;
1968 DEVICE_PRODUCER_DATA_HEADER *SioPtr;
1969
1970 Bda = (BDA_STRUC *) ((UINTN) 0x400);
1971 MachineConfig = 0;
1972
1973 SioPtr = &(Private->IntThunk->EfiToLegacy16BootTable.SioData);
1974 Bda->Com1 = SioPtr->Serial[0].Address;
1975 Bda->Com2 = SioPtr->Serial[1].Address;
1976 Bda->Com3 = SioPtr->Serial[2].Address;
1977 Bda->Com4 = SioPtr->Serial[3].Address;
1978
1979 if (SioPtr->Serial[0].Address != 0x00) {
1980 MachineConfig += 0x200;
1981 }
1982
1983 if (SioPtr->Serial[1].Address != 0x00) {
1984 MachineConfig += 0x200;
1985 }
1986
1987 if (SioPtr->Serial[2].Address != 0x00) {
1988 MachineConfig += 0x200;
1989 }
1990
1991 if (SioPtr->Serial[3].Address != 0x00) {
1992 MachineConfig += 0x200;
1993 }
1994
1995 Bda->Lpt1 = SioPtr->Parallel[0].Address;
1996 Bda->Lpt2 = SioPtr->Parallel[1].Address;
1997 Bda->Lpt3 = SioPtr->Parallel[2].Address;
1998
1999 if (SioPtr->Parallel[0].Address != 0x00) {
2000 MachineConfig += 0x4000;
2001 }
2002
2003 if (SioPtr->Parallel[1].Address != 0x00) {
2004 MachineConfig += 0x4000;
2005 }
2006
2007 if (SioPtr->Parallel[2].Address != 0x00) {
2008 MachineConfig += 0x4000;
2009 }
2010
2011 Bda->NumberOfDrives = (UINT8) (Bda->NumberOfDrives + Private->IdeDriveCount);
2012 if (SioPtr->Floppy.NumberOfFloppy != 0x00) {
2013 MachineConfig = (UINT16) (MachineConfig + 0x01 + (SioPtr->Floppy.NumberOfFloppy - 1) * 0x40);
2014 Bda->FloppyXRate = 0x07;
2015 }
2016
2017 Bda->Lpt1_2Timeout = 0x1414;
2018 Bda->Lpt3_4Timeout = 0x1414;
2019 Bda->Com1_2Timeout = 0x0101;
2020 Bda->Com3_4Timeout = 0x0101;
2021
2022 //
2023 // Force VGA and Coprocessor, indicate 101/102 keyboard
2024 //
2025 MachineConfig = (UINT16) (MachineConfig + 0x00 + 0x02 + (SioPtr->MousePresent * 0x04));
2026 Bda->MachineConfig = MachineConfig;
2027
2028 return EFI_SUCCESS;
2029 }
2030
2031 /**
2032 Fill in the standard BDA for Keyboard LEDs
2033
2034 @param This Protocol instance pointer.
2035 @param Leds Current LED status
2036
2037 @retval EFI_SUCCESS It should always work.
2038
2039 **/
2040 EFI_STATUS
2041 EFIAPI
LegacyBiosUpdateKeyboardLedStatus(IN EFI_LEGACY_BIOS_PROTOCOL * This,IN UINT8 Leds)2042 LegacyBiosUpdateKeyboardLedStatus (
2043 IN EFI_LEGACY_BIOS_PROTOCOL *This,
2044 IN UINT8 Leds
2045 )
2046 {
2047 LEGACY_BIOS_INSTANCE *Private;
2048 BDA_STRUC *Bda;
2049 UINT8 LocalLeds;
2050 EFI_IA32_REGISTER_SET Regs;
2051
2052 Bda = (BDA_STRUC *) ((UINTN) 0x400);
2053
2054 Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
2055 LocalLeds = Leds;
2056 Bda->LedStatus = (UINT8) ((Bda->LedStatus &~0x07) | LocalLeds);
2057 LocalLeds = (UINT8) (LocalLeds << 4);
2058 Bda->ShiftStatus = (UINT8) ((Bda->ShiftStatus &~0x70) | LocalLeds);
2059 LocalLeds = (UINT8) (Leds & 0x20);
2060 Bda->KeyboardStatus = (UINT8) ((Bda->KeyboardStatus &~0x20) | LocalLeds);
2061 //
2062 // Call into Legacy16 code to allow it to do any processing
2063 //
2064 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
2065 Regs.X.AX = Legacy16SetKeyboardLeds;
2066 Regs.H.CL = Leds;
2067
2068 Private->LegacyBios.FarCall86 (
2069 &Private->LegacyBios,
2070 Private->Legacy16Table->Compatibility16CallSegment,
2071 Private->Legacy16Table->Compatibility16CallOffset,
2072 &Regs,
2073 NULL,
2074 0
2075 );
2076
2077 return EFI_SUCCESS;
2078 }
2079
2080
2081 /**
2082 Fill in the standard CMOS stuff prior to legacy Boot
2083
2084 @param Private Legacy BIOS Instance data
2085
2086 @retval EFI_SUCCESS It should always work.
2087
2088 **/
2089 EFI_STATUS
LegacyBiosCompleteStandardCmosBeforeBoot(IN LEGACY_BIOS_INSTANCE * Private)2090 LegacyBiosCompleteStandardCmosBeforeBoot (
2091 IN LEGACY_BIOS_INSTANCE *Private
2092 )
2093 {
2094 UINT8 Bda;
2095 UINT8 Floppy;
2096 UINT32 Size;
2097
2098 //
2099 // Update CMOS locations
2100 // 10 floppy
2101 // 12,19,1A - ignore as OS don't use them and there is no standard due
2102 // to large capacity drives
2103 // CMOS 14 = BDA 40:10 plus bit 3(display enabled)
2104 //
2105 Bda = (UINT8)(*((UINT8 *)((UINTN)0x410)) | BIT3);
2106
2107 //
2108 // Force display enabled
2109 //
2110 Floppy = 0x00;
2111 if ((Bda & BIT0) != 0) {
2112 Floppy = BIT6;
2113 }
2114
2115 //
2116 // Check if 2.88MB floppy set
2117 //
2118 if ((Bda & (BIT7 | BIT6)) != 0) {
2119 Floppy = (UINT8)(Floppy | BIT1);
2120 }
2121
2122 LegacyWriteStandardCmos (CMOS_10, Floppy);
2123 LegacyWriteStandardCmos (CMOS_14, Bda);
2124
2125 //
2126 // Force Status Register A to set rate selection bits and divider
2127 //
2128 LegacyWriteStandardCmos (CMOS_0A, 0x26);
2129
2130 //
2131 // redo memory size since it can change
2132 //
2133 Size = (15 * SIZE_1MB) >> 10;
2134 if (Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb < (15 * SIZE_1MB)) {
2135 Size = Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb >> 10;
2136 }
2137
2138 LegacyWriteStandardCmos (CMOS_17, (UINT8)(Size & 0xFF));
2139 LegacyWriteStandardCmos (CMOS_30, (UINT8)(Size & 0xFF));
2140 LegacyWriteStandardCmos (CMOS_18, (UINT8)(Size >> 8));
2141 LegacyWriteStandardCmos (CMOS_31, (UINT8)(Size >> 8));
2142
2143 LegacyCalculateWriteStandardCmosChecksum ();
2144
2145 return EFI_SUCCESS;
2146 }
2147
2148 /**
2149 Relocate this image under 4G memory for IPF.
2150
2151 @param ImageHandle Handle of driver image.
2152 @param SystemTable Pointer to system table.
2153
2154 @retval EFI_SUCCESS Image successfully relocated.
2155 @retval EFI_ABORTED Failed to relocate image.
2156
2157 **/
2158 EFI_STATUS
RelocateImageUnder4GIfNeeded(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)2159 RelocateImageUnder4GIfNeeded (
2160 IN EFI_HANDLE ImageHandle,
2161 IN EFI_SYSTEM_TABLE *SystemTable
2162 )
2163 {
2164 return EFI_SUCCESS;
2165 }
2166