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