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