/** @file ;****************************************************************************** ;* Copyright (c) 2012 - 2021, Insyde Software Corporation. All Rights Reserved. ;* ;* You may not reproduce, distribute, publish, display, perform, modify, adapt, ;* transmit, broadcast, present, recite, release, license or otherwise exploit ;* any part of this publication in any form, by any means, without the prior ;* written permission of Insyde Software Corporation. ;* ;****************************************************************************** */ #include "LegacyBiosInterface.h" #include #include #include #define BOOT_LEGACY_OS 0 #define BOOT_EFI_OS 1 #define BOOT_UNCONVENTIONAL_DEVICE 2 UINT32 mLoadOptionsSize = 0; UINTN mBootMode = BOOT_LEGACY_OS; VOID *mLoadOptions = NULL; BBS_BBS_DEVICE_PATH *mBbsDevicePathPtr = NULL; BBS_BBS_DEVICE_PATH mBbsDevicePathNode; UDC_ATTRIBUTES mAttributes = { 0, 0, 0, 0 }; UINTN mBbsEntry = 0; VOID *mBeerData = NULL; VOID *mServiceAreaData = NULL; UINT64 mLowWater = 0xffffffffffffffffULL; extern BBS_TABLE *mBbsTable; /** Print the BBS Table. @param BbsTable The BBS table. **/ VOID PrintBbsTable ( IN BBS_TABLE *BbsTable ) { UINT16 Index; UINT16 SubIndex; CHAR8 *String; DEBUG ((EFI_D_INFO, "\n")); DEBUG ((EFI_D_INFO, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs mfgs:mfgo dess:deso\n")); DEBUG ((EFI_D_INFO, "=================================================================\n")); for (Index = 0; Index < MAX_BBS_ENTRIES; Index++) { // // Filter // if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) { continue; } DEBUG (( EFI_D_INFO, " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x", (UINTN) Index, (UINTN) BbsTable[Index].BootPriority, (UINTN) BbsTable[Index].Bus, (UINTN) BbsTable[Index].Device, (UINTN) BbsTable[Index].Function, (UINTN) BbsTable[Index].Class, (UINTN) BbsTable[Index].SubClass, (UINTN) BbsTable[Index].DeviceType, (UINTN) * (UINT16 *) &BbsTable[Index].StatusFlags )); DEBUG (( EFI_D_INFO, " %04x:%04x %04x:%04x %04x:%04x", (UINTN) BbsTable[Index].BootHandlerSegment, (UINTN) BbsTable[Index].BootHandlerOffset, (UINTN) BbsTable[Index].MfgStringSegment, (UINTN) BbsTable[Index].MfgStringOffset, (UINTN) BbsTable[Index].DescStringSegment, (UINTN) BbsTable[Index].DescStringOffset )); // // Print DescString // String = (CHAR8 *)(UINTN)((BbsTable[Index].DescStringSegment << 4) + BbsTable[Index].DescStringOffset); if (String != NULL) { DEBUG ((EFI_D_INFO," (")); for (SubIndex = 0; String[SubIndex] != 0; SubIndex++) { DEBUG ((EFI_D_INFO, "%c", String[SubIndex])); } DEBUG ((EFI_D_INFO,")")); } DEBUG ((EFI_D_INFO,"\n")); } DEBUG ((EFI_D_INFO, "\n")); return ; } /** Print the BBS Table. @param HddInfo The HddInfo table. **/ VOID PrintHddInfo ( IN HDD_INFO *HddInfo ) { UINTN Index; DEBUG ((EFI_D_INFO, "\n")); for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) { DEBUG ((EFI_D_INFO, "Index - %04x\n", Index)); DEBUG ((EFI_D_INFO, " Status - %04x\n", (UINTN)HddInfo[Index].Status)); DEBUG ((EFI_D_INFO, " B/D/F - %02x/%02x/%02x\n", (UINTN)HddInfo[Index].Bus, (UINTN)HddInfo[Index].Device, (UINTN)HddInfo[Index].Function)); DEBUG ((EFI_D_INFO, " Command - %04x\n", HddInfo[Index].CommandBaseAddress)); DEBUG ((EFI_D_INFO, " Control - %04x\n", HddInfo[Index].ControlBaseAddress)); DEBUG ((EFI_D_INFO, " BusMaster - %04x\n", HddInfo[Index].BusMasterAddress)); DEBUG ((EFI_D_INFO, " HddIrq - %02x\n", HddInfo[Index].HddIrq)); DEBUG ((EFI_D_INFO, " IdentifyDrive[0].Raw[0] - %x\n", HddInfo[Index].IdentifyDrive[0].Raw[0])); DEBUG ((EFI_D_INFO, " IdentifyDrive[1].Raw[0] - %x\n", HddInfo[Index].IdentifyDrive[1].Raw[0])); } DEBUG ((EFI_D_INFO, "\n")); return ; } /** Print the PCI Interrupt Line and Interrupt Pin registers. **/ VOID PrintPciInterruptRegister ( VOID ) { EFI_STATUS Status; UINTN Index; EFI_HANDLE *Handles; UINTN HandleNum; EFI_PCI_IO_PROTOCOL *PciIo; UINT8 Interrupt[2]; UINTN Segment; UINTN Bus; UINTN Device; UINTN Function; gBS->LocateHandleBuffer ( ByProtocol, &gEfiPciIoProtocolGuid, NULL, &HandleNum, &Handles ); Bus = 0; Device = 0; Function = 0; DEBUG ((EFI_D_INFO, "\n")); DEBUG ((EFI_D_INFO, " bb/dd/ff interrupt line interrupt pin\n")); DEBUG ((EFI_D_INFO, "======================================\n")); for (Index = 0; Index < HandleNum; Index++) { Status = gBS->HandleProtocol (Handles[Index], &gEfiPciIoProtocolGuid, (VOID **) &PciIo); if (!EFI_ERROR (Status)) { Status = PciIo->Pci.Read ( PciIo, EfiPciIoWidthUint8, PCI_INT_LINE_OFFSET, 2, Interrupt ); } if (!EFI_ERROR (Status)) { Status = PciIo->GetLocation ( PciIo, &Segment, &Bus, &Device, &Function ); } if (!EFI_ERROR (Status)) { DEBUG ((EFI_D_INFO, " %02x/%02x/%02x 0x%02x 0x%02x\n", Bus, Device, Function, Interrupt[0], Interrupt[1])); } } DEBUG ((EFI_D_INFO, "\n")); if (Handles != NULL) { FreePool (Handles); } } /** Identify drive data must be updated to actual parameters before boot. @param IdentifyDriveData ATA Identify Data **/ VOID UpdateIdentifyDriveData ( IN UINT8 *IdentifyDriveData ); /** Update SIO data. @param Private Legacy BIOS Instance data @retval EFI_SUCCESS Removable media not present **/ EFI_STATUS UpdateSioData ( IN LEGACY_BIOS_INSTANCE *Private ) { EFI_STATUS Status; UINTN Index; UINTN Index1; UINT8 LegacyInterrupts[16]; EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable; UINTN RoutingTableEntries; EFI_LEGACY_IRQ_PRIORITY_TABLE_ENTRY *IrqPriorityTable; UINTN NumberPriorityEntries; EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable; UINT8 HddIrq; UINT16 LegacyInt; UINT16 LegMask; UINT32 Register; UINTN HandleCount; EFI_HANDLE *HandleBuffer; EFI_ISA_IO_PROTOCOL *IsaIo; LegacyInt = 0; HandleBuffer = NULL; EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable; LegacyBiosBuildSioData (Private); SetMem (LegacyInterrupts, sizeof (LegacyInterrupts), 0); // // Create list of legacy interrupts. // for (Index = 0; Index < 4; Index++) { LegacyInterrupts[Index] = EfiToLegacy16BootTable->SioData.Serial[Index].Irq; } for (Index = 4; Index < 7; Index++) { LegacyInterrupts[Index] = EfiToLegacy16BootTable->SioData.Parallel[Index - 4].Irq; } LegacyInterrupts[7] = EfiToLegacy16BootTable->SioData.Floppy.Irq; // // Get Legacy Hdd IRQs. If native mode treat as PCI // for (Index = 0; Index < 2; Index++) { HddIrq = EfiToLegacy16BootTable->HddInfo[Index].HddIrq; if ((HddIrq != 0) && ((HddIrq == 15) || (HddIrq == 14))) { LegacyInterrupts[Index + 8] = HddIrq; } } Private->LegacyBiosPlatform->GetRoutingTable ( Private->LegacyBiosPlatform, (VOID *) &RoutingTable, &RoutingTableEntries, NULL, NULL, (VOID **) &IrqPriorityTable, &NumberPriorityEntries ); // // Remove legacy interrupts from the list of PCI interrupts available. // for (Index = 0; Index <= 0x0b; Index++) { for (Index1 = 0; Index1 <= NumberPriorityEntries; Index1++) { if (LegacyInterrupts[Index] != 0) { LegacyInt = (UINT16) (LegacyInt | (1 << LegacyInterrupts[Index])); if (LegacyInterrupts[Index] == IrqPriorityTable[Index1].Irq) { IrqPriorityTable[Index1].Used = LEGACY_USED; } } } } Private->Legacy8259->GetMask ( Private->Legacy8259, &LegMask, NULL, NULL, NULL ); // // Set SIO interrupts and disable mouse. Let mouse driver // re-enable it. // LegMask = (UINT16) ((LegMask &~LegacyInt) | 0x1000); Private->Legacy8259->SetMask ( Private->Legacy8259, &LegMask, NULL, NULL, NULL ); // // Disable mouse in keyboard controller // Register = 0xA7; Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiIsaIoProtocolGuid, NULL, &HandleCount, &HandleBuffer ); if (EFI_ERROR (Status)) { return Status; } for (Index = 0; Index < HandleCount; Index++) { Status = gBS->HandleProtocol ( HandleBuffer[Index], &gEfiIsaIoProtocolGuid, (VOID **) &IsaIo ); ASSERT_EFI_ERROR (Status); IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, 0x64, 1, &Register); } if (HandleBuffer != NULL) { FreePool (HandleBuffer); } return EFI_SUCCESS; } /** Identify drive data must be updated to actual parameters before boot. This requires updating the checksum, if it exists. @param IdentifyDriveData ATA Identify Data @param Checksum checksum of the ATA Identify Data @retval EFI_SUCCESS checksum calculated @retval EFI_SECURITY_VIOLATION IdentifyData invalid **/ EFI_STATUS CalculateIdentifyDriveChecksum ( IN UINT8 *IdentifyDriveData, OUT UINT8 *Checksum ) { UINTN Index; UINT8 LocalChecksum; LocalChecksum = 0; *Checksum = 0; if (IdentifyDriveData[510] != 0xA5) { return EFI_SECURITY_VIOLATION; } for (Index = 0; Index < 512; Index++) { LocalChecksum = (UINT8) (LocalChecksum + IdentifyDriveData[Index]); } *Checksum = LocalChecksum; return EFI_SUCCESS; } /** Identify drive data must be updated to actual parameters before boot. @param IdentifyDriveData ATA Identify Data **/ VOID UpdateIdentifyDriveData ( IN UINT8 *IdentifyDriveData ) { UINT16 NumberCylinders; UINT16 NumberHeads; UINT16 NumberSectorsTrack; UINT32 CapacityInSectors; UINT8 OriginalChecksum; UINT8 FinalChecksum; EFI_STATUS Status; ATAPI_IDENTIFY *ReadInfo; // // Status indicates if Integrity byte is correct. Checksum should be // 0 if valid. // ReadInfo = (ATAPI_IDENTIFY *) IdentifyDriveData; Status = CalculateIdentifyDriveChecksum (IdentifyDriveData, &OriginalChecksum); if (OriginalChecksum != 0) { Status = EFI_SECURITY_VIOLATION; } // // If NumberCylinders = 0 then do data(Controller present but don drive attached). // NumberCylinders = ReadInfo->Raw[1]; if (NumberCylinders != 0) { ReadInfo->Raw[54] = NumberCylinders; NumberHeads = ReadInfo->Raw[3]; ReadInfo->Raw[55] = NumberHeads; NumberSectorsTrack = ReadInfo->Raw[6]; ReadInfo->Raw[56] = NumberSectorsTrack; // // Copy Multisector info and set valid bit. // ReadInfo->Raw[59] = (UINT16) (ReadInfo->Raw[47] + 0x100); CapacityInSectors = (UINT32) ((UINT32) (NumberCylinders) * (UINT32) (NumberHeads) * (UINT32) (NumberSectorsTrack)); ReadInfo->Raw[57] = (UINT16) (CapacityInSectors >> 16); ReadInfo->Raw[58] = (UINT16) (CapacityInSectors & 0xffff); if (Status == EFI_SUCCESS) { // // Forece checksum byte to 0 and get new checksum. // ReadInfo->Raw[255] &= 0xff; CalculateIdentifyDriveChecksum (IdentifyDriveData, &FinalChecksum); // // Force new checksum such that sum is 0. // FinalChecksum = (UINT8) ((UINT8)0 - FinalChecksum); ReadInfo->Raw[255] = (UINT16) (ReadInfo->Raw[255] | (FinalChecksum << 8)); } } } /** Identify drive data must be updated to actual parameters before boot. Do for all drives. @param Private Legacy BIOS Instance data **/ VOID UpdateAllIdentifyDriveData ( IN LEGACY_BIOS_INSTANCE *Private ) { UINTN Index; HDD_INFO *HddInfo; HddInfo = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo[0]; for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) { // // Each controller can have 2 devices. Update for each device // if ((HddInfo[Index].Status & HDD_MASTER_IDE) != 0) { UpdateIdentifyDriveData ((UINT8 *) (&HddInfo[Index].IdentifyDrive[0].Raw[0])); } if ((HddInfo[Index].Status & HDD_SLAVE_IDE) != 0) { UpdateIdentifyDriveData ((UINT8 *) (&HddInfo[Index].IdentifyDrive[1].Raw[0])); } } } /** Enable ide controller. This gets disabled when LegacyBoot.c is about to run the Option ROMs. @param Private Legacy BIOS Instance data **/ VOID EnableIdeController ( IN LEGACY_BIOS_INSTANCE *Private ) { EFI_PCI_IO_PROTOCOL *PciIo; EFI_STATUS Status; EFI_HANDLE IdeController; UINT8 ByteBuffer; UINTN HandleCount; EFI_HANDLE *HandleBuffer; Status = Private->LegacyBiosPlatform->GetPlatformHandle ( Private->LegacyBiosPlatform, EfiGetPlatformIdeHandle, 0, &HandleBuffer, &HandleCount, NULL ); if (!EFI_ERROR (Status)) { IdeController = HandleBuffer[0]; Status = gBS->HandleProtocol ( IdeController, &gEfiPciIoProtocolGuid, (VOID **) &PciIo ); ByteBuffer = 0x1f; if (!EFI_ERROR (Status)) { PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x04, 1, &ByteBuffer); } } } /** Enable ide controller. This gets disabled when LegacyBoot.c is about to run the Option ROMs. @param Private Legacy BIOS Instance data **/ VOID EnableAllControllers ( IN LEGACY_BIOS_INSTANCE *Private ) { UINTN HandleCount; EFI_HANDLE *HandleBuffer; UINTN Index; EFI_PCI_IO_PROTOCOL *PciIo; PCI_TYPE01 PciConfigHeader; EFI_STATUS Status; // // // EnableIdeController (Private); // // Assumption is table is built from low bus to high bus numbers. // Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiPciIoProtocolGuid, NULL, &HandleCount, &HandleBuffer ); ASSERT_EFI_ERROR (Status); for (Index = 0; Index < HandleCount; Index++) { Status = gBS->HandleProtocol ( HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID **) &PciIo ); ASSERT_EFI_ERROR (Status); PciIo->Pci.Read ( PciIo, EfiPciIoWidthUint32, 0, sizeof (PciConfigHeader) / sizeof (UINT32), &PciConfigHeader ); // // We do not enable PPB here. This is for HotPlug Consideration. // The Platform HotPlug Driver is responsible for Padding enough hot plug // resources. It is also responsible for enable this bridge. If it // does not pad it. It will cause some early Windows fail to installation. // If the platform driver does not pad resource for PPB, PPB should be in // un-enabled state to let Windows know that this PPB is not configured by // BIOS. So Windows will allocate default resource for PPB. // // The reason for why we enable the command register is: // The CSM will use the IO bar to detect some IRQ status, if the command // is disabled, the IO resource will be out of scope. // For example: // We installed a legacy IRQ handle for a PCI IDE controller. When IRQ // comes up, the handle will check the IO space to identify is the // controller generated the IRQ source. // If the IO command is not enabled, the IRQ handler will has wrong // information. It will cause IRQ storm when the correctly IRQ handler fails // to run. // if (!(IS_PCI_VGA (&PciConfigHeader) || IS_PCI_OLD_VGA (&PciConfigHeader) || IS_PCI_IDE (&PciConfigHeader) || IS_PCI_P2P (&PciConfigHeader) || IS_PCI_P2P_SUB (&PciConfigHeader) || IS_PCI_LPC (&PciConfigHeader) )) { PciConfigHeader.Hdr.Command |= 0x1f; PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 4, 1, &PciConfigHeader.Hdr.Command); } } } /** The following routines are identical in operation, so combine for code compaction: EfiGetPlatformBinaryGetMpTable EfiGetPlatformBinaryGetOemIntData EfiGetPlatformBinaryGetOem32Data EfiGetPlatformBinaryGetOem16Data @param This Protocol instance pointer. @param Id Table/Data identifier @retval EFI_SUCCESS Success @retval EFI_INVALID_PARAMETER Invalid ID @retval EFI_OUT_OF_RESOURCES no resource to get data or table **/ EFI_STATUS LegacyGetDataOrTable ( IN EFI_LEGACY_BIOS_PROTOCOL *This, IN EFI_GET_PLATFORM_INFO_MODE Id ) { VOID *Table; UINT32 TablePtr; UINTN TableSize; UINTN Alignment; UINTN Location; EFI_STATUS Status; EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform; EFI_COMPATIBILITY16_TABLE *Legacy16Table; EFI_IA32_REGISTER_SET Regs; LEGACY_BIOS_INSTANCE *Private; Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); LegacyBiosPlatform = Private->LegacyBiosPlatform; Legacy16Table = Private->Legacy16Table; if (Id != EfiGetPlatformBinaryMpTable && Id != EfiGetPlatformBinaryOemIntData && Id != EfiGetPlatformBinaryOem32Data && Id != EfiGetPlatformBinaryOem16Data) { return EFI_INVALID_PARAMETER; } // // Phase 1 - get an address allocated in 16-bit code // Status = LegacyBiosPlatform->GetPlatformInfo ( LegacyBiosPlatform, Id, (VOID *) &Table, &TableSize, &Location, &Alignment, 0, 0 ); DEBUG ((EFI_D_INFO, "LegacyGetDataOrTable - ID: %x, %r\n", (UINTN)Id, Status)); DEBUG ((EFI_D_INFO, " Table - %x, Size - %x, Location - %x, Alignment - %x\n", (UINTN)Table, (UINTN)TableSize, (UINTN)Location, (UINTN)Alignment)); if (EFI_ERROR (Status)) { return Status; } ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); Regs.X.AX = Legacy16GetTableAddress; Regs.X.CX = (UINT16) TableSize; Regs.X.BX = (UINT16) Location; Regs.X.DX = (UINT16) Alignment; Private->LegacyBios.FarCall86 ( This, Private->Legacy16CallSegment, Private->Legacy16CallOffset, &Regs, NULL, 0 ); if (Regs.X.AX != 0) { DEBUG ((EFI_D_ERROR, "Table ID %x length insufficient\n", Id)); return EFI_OUT_OF_RESOURCES; } // // Phase 2 Call routine second time with address to allow address adjustment // Status = LegacyBiosPlatform->GetPlatformInfo ( LegacyBiosPlatform, Id, (VOID *) &Table, &TableSize, &Location, &Alignment, Regs.X.DS, Regs.X.BX ); if (Id == EfiGetPlatformBinaryMpTable) { Legacy16Table->MpTablePtr = (UINT32) (Regs.X.DS * 16 + Regs.X.BX); Legacy16Table->MpTableLength = (UINT32)TableSize; DEBUG ((EFI_D_INFO, "MP table in legacy region - %x\n", (UINTN)Legacy16Table->MpTablePtr)); } else if (Id == EfiGetPlatformBinaryOemIntData) { Legacy16Table->OemIntSegment = Regs.X.DS; Legacy16Table->OemIntOffset = Regs.X.BX; DEBUG ((EFI_D_INFO, "OemInt table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->OemIntSegment, (UINTN)Legacy16Table->OemIntOffset)); } else if (Id == EfiGetPlatformBinaryOem32Data) { Legacy16Table->Oem32Segment = Regs.X.DS; Legacy16Table->Oem32Offset = Regs.X.BX; DEBUG ((EFI_D_INFO, "Oem32 table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->Oem32Segment, (UINTN)Legacy16Table->Oem32Offset)); } else if (Id == EfiGetPlatformBinaryOem16Data) { // // Legacy16Table->Oem16Segment = Regs.X.DS; // Legacy16Table->Oem16Offset = Regs.X.BX; DEBUG ((EFI_D_INFO, "Oem16 table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->Oem16Segment, (UINTN)Legacy16Table->Oem16Offset)); } if (EFI_ERROR (Status)) { return Status; } // // Phase 3 Copy table to final location // TablePtr = (UINT32) (Regs.X.DS * 16 + Regs.X.BX); CopyMem ( (VOID *) (UINTN)TablePtr, Table, TableSize ); return EFI_SUCCESS; } /** Search string in Smbios table by Type @param Type SMBIOS structure type @param Handle SMBIOS structure handle @param StrOffset String offset in the header of this SMBIOS structure type @param Location Return pointer to the string @param Size The returned string size @retval EFI_SUCCESS Success @retval EFI_NOT_FOUND Smbios table not found **/ EFI_STATUS LocateSmbiosStringByType ( IN UINT8 Type, IN UINT16 *Handle, OPTIONAL IN UINT16 StrOffset, OUT VOID **Location, OUT UINT32 *Size ) { SMBIOS_TABLE_ENTRY_POINT *SmbiosTableEntryPoint; SMBIOS_TABLE_3_0_ENTRY_POINT *Smbios3TableEntryPoint; SMBIOS_STRUCTURE *SmbiosTable; SMBIOS_STRUCTURE *NextTable; EFI_STATUS Status; UINT8 *Temp; UINT8 *StringAddress; UINT8 StrNum; UINT8 StrCount; UINT8 *StrStart; UINTN TableEndAddr; SmbiosTableEntryPoint = NULL; Smbios3TableEntryPoint= NULL; SmbiosTable = NULL; NextTable = NULL; // // Get SMBIOS and ACPI table pointers // Status = EfiGetSystemConfigurationTable ( &gEfiSmbiosTableGuid, (VOID **)&SmbiosTableEntryPoint ); EfiGetSystemConfigurationTable ( &gEfiSmbios3TableGuid, (VOID **)&Smbios3TableEntryPoint ); if (SmbiosTableEntryPoint != NULL){ SmbiosTable = (SMBIOS_STRUCTURE *)(UINTN)SmbiosTableEntryPoint->TableAddress; TableEndAddr = (UINTN)SmbiosTable + (UINTN)SmbiosTableEntryPoint->TableLength; } else if (Smbios3TableEntryPoint != NULL) { SmbiosTable = (SMBIOS_STRUCTURE *)(UINTN)Smbios3TableEntryPoint->TableAddress; TableEndAddr = (UINTN)SmbiosTable + (UINTN)Smbios3TableEntryPoint->TableMaximumSize; } else { return EFI_NOT_FOUND; } while ((UINTN)SmbiosTable < TableEndAddr){ // // Get the next handle // Temp = (UINT8*)SmbiosTable + SmbiosTable->Length; while (TRUE) { // // The ending of a handle is '00' '00' // if ((*Temp == 0x00) && (*(Temp + 1) == 0x00)) { Temp = Temp + 2; NextTable = (SMBIOS_STRUCTURE*)Temp; break; } else { Temp++; } } if ((SmbiosTable->Type == Type) && (Handle == NULL || (SmbiosTable->Handle == *Handle))) { // // Check string number. If string number is zero, it means no reference string. // Temp = (UINT8 *) SmbiosTable + StrOffset; StrNum = *Temp; if (StrNum != 0) { StrStart = (UINT8 *) SmbiosTable + SmbiosTable->Length; StrCount = 1; for (StringAddress = StrStart; StringAddress < (UINT8 *) NextTable; StringAddress++) { if (*StringAddress == 0x00) { if (StrCount == StrNum) { StringAddress++; break; } else { StrCount++; StrStart = StringAddress + 1; } } } // // If success to get string by this structure, update output data. Otherwise, keep searching. // if (StringAddress < (UINT8 *) NextTable) { *Location = (VOID *) StrStart; *Size = (UINT16) (StringAddress - StrStart); return EFI_SUCCESS; } } } SmbiosTable = NextTable; } return EFI_NOT_FOUND; } /** HCT will check 0xFFFF5 for BIOS Release Date And CSM already define 0xFFFF5 for bios date Just update the 0xFFFF5 to current bios date from SMBIOS @param This Protocol instance pointer. @retval EFI_SUCCESS Success @retval EFI_NOT_FOUND Dmi String not found **/ EFI_STATUS UpdateBiosReleaseDate ( IN EFI_LEGACY_BIOS_PROTOCOL *This ) { EFI_STATUS Status; VOID *Table; UINT32 TablePtr; UINTN TableSize; VOID *DmiLocation; UINT32 DmiSize; CHAR8 ReleaseDate[10]; // // Read Dmi String (STR_MISC_BIOS_RELEASE_DATE) // Status = LocateSmbiosStringByType (0, NULL ,0x8, &DmiLocation, &DmiSize); ASSERT_EFI_ERROR (Status); if (EFI_ERROR(Status)) { return Status; } CopyMem ((UINT8 *)ReleaseDate, (UINT8 *)DmiLocation, DmiSize); ReleaseDate[6] = ReleaseDate[8]; ReleaseDate[7] = ReleaseDate[9]; ReleaseDate[8] = 0; ReleaseDate[9] = 0; // // Update SystemBiosDate // TablePtr = 0x000FFFF5; Table=(VOID *)ReleaseDate; TableSize= 0x08; CopyMem ((VOID *)(UINTN)TablePtr, Table, TableSize); return EFI_SUCCESS; } /** Internal function to initalize H2O_BDS_CP_LEGACY_PREPARE_TO_BOOT_BEFORE_DATA data and trigger gH2OBdsCpLegacyPrepareToBootBeforeGuid checkpoint. @retval The checkpoint status value. **/ STATIC UINT32 TriggerCpLegacyPrepareToBootBefore ( VOID ) { H2O_BDS_CP_LEGACY_PREPARE_TO_BOOT_BEFORE_DATA BdsLegacyPrepareBootBeforeData; EFI_STATUS Status; BdsLegacyPrepareBootBeforeData.Size = sizeof (H2O_BDS_CP_LEGACY_PREPARE_TO_BOOT_BEFORE_DATA); BdsLegacyPrepareBootBeforeData.Status = H2O_CP_TASK_NORMAL; DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpLegacyPrepareToBootBeforeGuid)); Status = H2OCpTrigger (&gH2OBdsCpLegacyPrepareToBootBeforeGuid, &BdsLegacyPrepareBootBeforeData); DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", BdsLegacyPrepareBootBeforeData.Status)); return BdsLegacyPrepareBootBeforeData.Status; } /** Internal function to initalize H2O_BDS_CP_LEGACY_PREPARE_TO_BOOT_AFTER_DATA data and trigger gH2OBdsCpLegacyPrepareToBootAfterGuid checkpoint. @retval EFI_SUCCESS Trigger gH2OBdsCpLegacyPrepareToBootAfterGuid checkpoint successfully. @return Other Other error occurred while triggering gH2OBdsCpLegacyPrepareToBootAfterGuid checkpoint. **/ STATIC EFI_STATUS TriggerCpLegacyPrepareToBootAfter ( VOID ) { H2O_BDS_CP_LEGACY_PREPARE_TO_BOOT_AFTER_DATA BdsLegacyPrepareBootAfterData; EFI_STATUS Status; BdsLegacyPrepareBootAfterData.Size = sizeof (H2O_BDS_CP_LEGACY_PREPARE_TO_BOOT_AFTER_DATA); BdsLegacyPrepareBootAfterData.Status = H2O_CP_TASK_NORMAL; DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpLegacyPrepareToBootAfterGuid)); Status = H2OCpTrigger (&gH2OBdsCpLegacyPrepareToBootAfterGuid, &BdsLegacyPrepareBootAfterData); DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", BdsLegacyPrepareBootAfterData.Status)); return Status; } /** Internal function to initalize H2O_BDS_CP_LEGACY_BOOT_BEFORE_DATA data and trigger gH2OBdsCpLegacyBootBeforeGuid checkpoint. @retval EFI_SUCCESS Trigger gH2OBdsCpLegacyBootBeforeGuid checkpoint successfully. @retval EFI_OUT_OF_RESOURCES Allocate memory to initialize checkpoint data failed. @return Other Other error occurred while triggering gH2OBdsCpLegacyBootBeforeGuid checkpoint. **/ STATIC EFI_STATUS TriggerCpLegacyBootBefore ( VOID ) { H2O_BDS_CP_LEGACY_BOOT_BEFORE_DATA BdsLegacyBootBeforeData; EFI_STATUS Status; BdsLegacyBootBeforeData.Size = sizeof (H2O_BDS_CP_LEGACY_BOOT_BEFORE_DATA); BdsLegacyBootBeforeData.Status = H2O_CP_TASK_NORMAL; DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpLegacyBootBeforeGuid)); Status = H2OCpTrigger (&gH2OBdsCpLegacyBootBeforeGuid, &BdsLegacyBootBeforeData); DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", BdsLegacyBootBeforeData.Status)); return Status; } /** Internal function to initalize H2O_BDS_CP_LEGACY_BOOT_AFTER_DATA data and trigger gH2OBdsCpLegacyBootAfterGuid checkpoint. @retval EFI_SUCCESS Trigger gH2OBdsCpLegacyBootAfterGuid checkpoint successfully. @retval EFI_OUT_OF_RESOURCES Allocate memory to initialize checkpoint data failed. @return Other Other error occurred while triggering gH2OBdsCpLegacyBootAfterGuid checkpoint. **/ STATIC EFI_STATUS TriggerCpLegacyBootAfter ( VOID ) { H2O_BDS_CP_LEGACY_BOOT_AFTER_DATA BdsLegacyBootAfterData; EFI_STATUS Status; BdsLegacyBootAfterData.Size = sizeof (H2O_BDS_CP_LEGACY_BOOT_AFTER_DATA); BdsLegacyBootAfterData.Status = H2O_CP_TASK_NORMAL; DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpLegacyBootAfterGuid)); Status = H2OCpTrigger (&gH2OBdsCpLegacyBootAfterGuid, &BdsLegacyBootAfterData); DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", BdsLegacyBootAfterData.Status)); return Status; } /** Assign drive number to legacy HDD drives prior to booting an EFI aware OS so the OS can access drives without an EFI driver. Note: BBS compliant drives ARE NOT available until this call by either shell or EFI. @param This Protocol instance pointer. @retval EFI_SUCCESS Drive numbers assigned **/ EFI_STATUS GenericLegacyBoot ( IN EFI_LEGACY_BIOS_PROTOCOL *This ) { EFI_STATUS Status; LEGACY_BIOS_INSTANCE *Private; EFI_IA32_REGISTER_SET Regs; EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable; EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform; UINTN CopySize; VOID *AcpiPtr; HDD_INFO *HddInfo; HDD_INFO *LocalHddInfo; UINTN Index; EFI_COMPATIBILITY16_TABLE *Legacy16Table; UINT32 *BdaPtr; UINT16 HddCount; UINT16 BbsCount; BBS_TABLE *LocalBbsTable; UINT32 *BaseVectorMaster; EFI_TIME BootTime; UINT32 LocalTime; EFI_HANDLE IdeController; UINTN HandleCount; EFI_HANDLE *HandleBuffer; SMBIOS_TABLE_ENTRY_POINT *SmbiosTable; SMBIOS_TABLE_3_0_ENTRY_POINT *SmbiosTable64Bit; SMBIOS_TABLE_3_0_ENTRY_POINT *Smbios30TablePtr; EFI_PHYSICAL_ADDRESS ReAllocSmbios30Table; EFI_PHYSICAL_ADDRESS ReAllocSmbios30TableHeader; VOID *AcpiTable; UINTN ShadowAddress; UINT32 Granularity; EFI_E820_ENTRY64 *E820; UINT32 HeaderSize; BOOLEAN DoPrepareToBoot; LocalHddInfo = NULL; HddCount = 0; BbsCount = 0; LocalBbsTable = NULL; Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); DEBUG_CODE ( DEBUG ((EFI_D_INFO, "Start of legacy boot\n")); ); Legacy16Table = Private->Legacy16Table; EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable; HddInfo = &EfiToLegacy16BootTable->HddInfo[0]; LegacyBiosPlatform = Private->LegacyBiosPlatform; EfiToLegacy16BootTable->MajorVersion = EFI_TO_LEGACY_MAJOR_VERSION; EfiToLegacy16BootTable->MinorVersion = EFI_TO_LEGACY_MINOR_VERSION; // // If booting to a legacy OS then force HDD drives to the appropriate // boot mode by calling GetIdeHandle. // A reconnect -r can force all HDDs back to native mode. // IdeController = NULL; if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) { // // In case the GetPlatformHandle returns error in Non-IDE system, // Make the error checking to prevent gBS->HandleProtocol crash // HandleCount = 0; Status = LegacyBiosPlatform->GetPlatformHandle ( Private->LegacyBiosPlatform, EfiGetPlatformIdeHandle, 0, &HandleBuffer, &HandleCount, NULL ); if (!EFI_ERROR (Status) && HandleCount > 0) { IdeController = HandleBuffer[0]; } } // // Unlock the Legacy BIOS region // Private->LegacyRegion->UnLock ( Private->LegacyRegion, 0xE0000, 0x20000, &Granularity ); // // Reconstruct the Legacy16 boot memory map // LegacyBiosBuildE820 (Private, &CopySize); if (CopySize > Private->Legacy16Table->E820Length) { ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); Regs.X.AX = Legacy16GetTableAddress; Regs.X.CX = (UINT16) CopySize; Private->LegacyBios.FarCall86 ( &Private->LegacyBios, Private->Legacy16Table->Compatibility16CallSegment, Private->Legacy16Table->Compatibility16CallOffset, &Regs, NULL, 0 ); Private->Legacy16Table->E820Pointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX); Private->Legacy16Table->E820Length = (UINT32) CopySize; if (Regs.X.AX != 0) { DEBUG ((EFI_D_ERROR, "Legacy16 E820 length insufficient\n")); } else { CopyMem ( (VOID *)(UINTN) Private->Legacy16Table->E820Pointer, Private->E820Table, CopySize ); } } else { CopyMem ( (VOID *)(UINTN) Private->Legacy16Table->E820Pointer, Private->E820Table, CopySize ); Private->Legacy16Table->E820Length = (UINT32) CopySize; } // // Get SMBIOS and ACPI table pointers // SmbiosTable = NULL; EfiGetSystemConfigurationTable ( &gEfiSmbiosTableGuid, (VOID **)&SmbiosTable ); // // We do not ASSERT if SmbiosTable not found. It is possbile that a platform does not produce SmbiosTable. // if (SmbiosTable == NULL) { DEBUG ((EFI_D_ERROR, "Smbios table is not found!\n")); } EfiToLegacy16BootTable->SmbiosTable = (UINT32)(UINTN)SmbiosTable; // // SMBIOS 3.0 // SmbiosTable64Bit = NULL; EfiGetSystemConfigurationTable ( &gEfiSmbios3TableGuid, (VOID **)&SmbiosTable64Bit ); // // We do not ASSERT if SmbiosTable not found. It is possbile that a platform does not produce SmbiosTable. // if (SmbiosTable64Bit == NULL) { DEBUG ((EFI_D_ERROR, "Smbios table 3.0 is not found!\n")); } ReAllocSmbios30TableHeader = 0; // Cascade Smbios 2.x & 3.0 header if (SmbiosTable64Bit != NULL) { HeaderSize = (SmbiosTable == NULL) ? sizeof(SMBIOS_TABLE_3_0_ENTRY_POINT) : sizeof(SMBIOS_TABLE_3_0_ENTRY_POINT) + sizeof (SMBIOS_TABLE_ENTRY_POINT) + 1; ReAllocSmbios30TableHeader = BASE_4GB - BASE_64KB; Status = gBS->AllocatePages ( AllocateMaxAddress, EfiBootServicesData, EFI_SIZE_TO_PAGES(HeaderSize), &ReAllocSmbios30TableHeader ); if (!EFI_ERROR (Status)){ // Preserved 32 bytes space for 31 bytes long Smbios 2.x header if (HeaderSize == sizeof(SMBIOS_TABLE_3_0_ENTRY_POINT) + sizeof (SMBIOS_TABLE_ENTRY_POINT) + 1) { CopyMem ((VOID*)(UINTN) ReAllocSmbios30TableHeader, (VOID*) SmbiosTable, sizeof(SMBIOS_TABLE_ENTRY_POINT)); CopyMem ((VOID*)(UINTN) (ReAllocSmbios30TableHeader + sizeof (SMBIOS_TABLE_ENTRY_POINT) + 1), (VOID*) SmbiosTable64Bit, sizeof(SMBIOS_TABLE_3_0_ENTRY_POINT)); } else { CopyMem ((VOID*)(UINTN) ReAllocSmbios30TableHeader, (VOID*)SmbiosTable64Bit, sizeof(SMBIOS_TABLE_3_0_ENTRY_POINT)); } // point to the cascaded header EfiToLegacy16BootTable->SmbiosTable = (UINT32)(UINTN)ReAllocSmbios30TableHeader; } else { ReAllocSmbios30TableHeader = 0; } } // // Item TableAddress of smbios 30 header point to smbios 2.x body // if ((SmbiosTable64Bit != NULL) && (ReAllocSmbios30TableHeader != 0)) { if (SmbiosTable != NULL){ Smbios30TablePtr = (SMBIOS_TABLE_3_0_ENTRY_POINT*)(UINTN)(ReAllocSmbios30TableHeader + sizeof (SMBIOS_TABLE_ENTRY_POINT) + 1); Smbios30TablePtr->TableAddress = SmbiosTable->TableAddress; } else if (SmbiosTable64Bit->TableAddress + SmbiosTable64Bit->TableMaximumSize > BASE_4GB){ ReAllocSmbios30Table = BASE_4GB - SmbiosTable64Bit->TableMaximumSize; Status = gBS->AllocatePages ( AllocateMaxAddress, EfiBootServicesData, EFI_SIZE_TO_PAGES (SmbiosTable64Bit->TableMaximumSize), &ReAllocSmbios30Table ); if (!EFI_ERROR (Status)){ CopyMem ((VOID*)(UINTN)ReAllocSmbios30Table, (VOID*)(UINTN)SmbiosTable64Bit->TableAddress, SmbiosTable64Bit->TableMaximumSize); Smbios30TablePtr = (SMBIOS_TABLE_3_0_ENTRY_POINT*)(UINTN)(ReAllocSmbios30TableHeader); Smbios30TablePtr->TableAddress = (UINT64) ReAllocSmbios30Table; } } } AcpiTable = NULL; Status = EfiGetSystemConfigurationTable ( &gEfiAcpi20TableGuid, (VOID **)&AcpiTable ); if (EFI_ERROR (Status)) { Status = EfiGetSystemConfigurationTable ( &gEfiAcpi10TableGuid, (VOID **)&AcpiTable ); } // // We do not ASSERT if AcpiTable not found. It is possbile that a platform does not produce AcpiTable. // if (AcpiTable == NULL) { DEBUG ((EFI_D_ERROR, "ACPI table is not found!\n")); } EfiToLegacy16BootTable->AcpiTable = (UINT32)(UINTN)AcpiTable; // // Get RSD Ptr table rev at offset 15 decimal // Rev = 0 Length is 20 decimal // Rev != 0 Length is UINT32 at offset 20 decimal // if (AcpiTable != NULL) { AcpiPtr = AcpiTable; if (*((UINT8 *) AcpiPtr + 15) == 0) { CopySize = 20; } else { AcpiPtr = ((UINT8 *) AcpiPtr + 20); CopySize = (*(UINT32 *) AcpiPtr); } CopyMem ( (VOID *)(UINTN) Private->Legacy16Table->AcpiRsdPtrPointer, AcpiTable, CopySize ); } // // Make sure all PCI Interrupt Line register are programmed to match 8259 // PciProgramAllInterruptLineRegisters (Private); // // Unlock the Legacy BIOS region as PciProgramAllInterruptLineRegisters // can lock it. // Private->LegacyRegion->UnLock ( Private->LegacyRegion, Private->BiosStart, Private->LegacyBiosImageSize, &Granularity ); // // Configure Legacy Device Magic // // Only do this code if booting legacy OS // if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) { UpdateSioData (Private); } // // Setup BDA and EBDA standard areas before Legacy Boot // ACCESS_PAGE0_CODE ( LegacyBiosCompleteBdaBeforeBoot (Private); ); LegacyBiosCompleteStandardCmosBeforeBoot (Private); UpdateAllIdentifyDriveData (Private); // // Clear IO BAR, if IDE controller in legacy mode. // InitLegacyIdeController (IdeController); // // Generate number of ticks since midnight for BDA. DOS requires this // for its time. We have to make assumptions as to how long following // code takes since after PciShadowRoms PciIo is gone. Place result in // 40:6C-6F // // Adjust value by 1 second. // gRT->GetTime (&BootTime, NULL); LocalTime = BootTime.Hour * 3600 + BootTime.Minute * 60 + BootTime.Second; LocalTime += 1; // // Multiply result by 18.2 for number of ticks since midnight. // Use 182/10 to avoid floating point math. // LocalTime = (LocalTime * 182) / 10; ACCESS_PAGE0_CODE ( BdaPtr = (UINT32 *) (UINTN)0x46C; *BdaPtr = LocalTime; ); // // Shadow PCI ROMs. We must do this near the end since this will kick // of Native EFI drivers that may be needed to collect info for Legacy16 // // WARNING: PciIo is gone after this call. // PciShadowRoms (Private); // // Shadow PXE base code, BIS etc. // Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xc0000, 0x40000, &Granularity); ShadowAddress = Private->OptionRom; Private->LegacyBiosPlatform->PlatformHooks ( Private->LegacyBiosPlatform, EfiPlatformHookShadowServiceRoms, 0, 0, &ShadowAddress, Legacy16Table, NULL ); Private->OptionRom = (UINT32)ShadowAddress; // // Let platform code know the boot options // LegacyBiosGetBbsInfo ( This, &HddCount, &LocalHddInfo, &BbsCount, &LocalBbsTable ); DEBUG_CODE ( PrintPciInterruptRegister (); PrintBbsTable (LocalBbsTable); PrintHddInfo (LocalHddInfo); ); Private->LegacyRegion->UnLock ( Private->LegacyRegion, 0xc0000, 0x40000, &Granularity ); DoPrepareToBoot = TRUE; if (FeaturePcdGet (PcdH2OBdsCpLegacyPrepareToBootBeforeSupported)) { if (TriggerCpLegacyPrepareToBootBefore () == H2O_CP_TASK_SKIP) { DoPrepareToBoot = FALSE; } } if (DoPrepareToBoot) { LegacyBiosPlatform->PrepareToBoot ( LegacyBiosPlatform, mBbsDevicePathPtr, mBbsTable, mLoadOptionsSize, mLoadOptions, (VOID *) &Private->IntThunk->EfiToLegacy16BootTable ); if (FeaturePcdGet (PcdH2OBdsCpLegacyPrepareToBootAfterSupported)) { TriggerCpLegacyPrepareToBootAfter (); } } // // If no boot device return to BDS // if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) { for (Index = 0; Index < BbsCount; Index++){ if ((LocalBbsTable[Index].BootPriority != BBS_DO_NOT_BOOT_FROM) && (LocalBbsTable[Index].BootPriority != BBS_UNPRIORITIZED_ENTRY) && (LocalBbsTable[Index].BootPriority != BBS_IGNORE_ENTRY)) { break; } } if (Index == BbsCount) { return EFI_DEVICE_ERROR; } } // // Let the Legacy16 code know the device path type for legacy boot // EfiToLegacy16BootTable->DevicePathType = mBbsDevicePathPtr->DeviceType; Status = UpdateBiosReleaseDate(This); // // Copy MP table, if it exists. // CreateMpTable (Private); if (!Private->LegacyBootEntered) { // // Copy OEM INT Data, if it exists. Note: This code treats any data // as a bag of bits and knows nothing of the contents nor cares. // Contents are IBV specific. // LegacyGetDataOrTable (This, EfiGetPlatformBinaryOemIntData); // // Copy OEM16 Data, if it exists.Note: This code treats any data // as a bag of bits and knows nothing of the contents nor cares. // Contents are IBV specific. // LegacyGetDataOrTable (This, EfiGetPlatformBinaryOem16Data); // // Copy OEM32 Data, if it exists.Note: This code treats any data // as a bag of bits and knows nothing of the contents nor cares. // Contents are IBV specific. // LegacyGetDataOrTable (This, EfiGetPlatformBinaryOem32Data); } // // Call into Legacy16 code to prepare for INT 19h // ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); Regs.X.AX = Legacy16PrepareToBoot; POST_CODE (BDS_LEGACY16_PREPARE_TO_BOOT); //PostCode = 0x31, Prepare to Boot to Legacy OS // // Pass in handoff data // Regs.X.ES = NORMALIZE_EFI_SEGMENT ((UINTN)EfiToLegacy16BootTable); Regs.X.BX = NORMALIZE_EFI_OFFSET ((UINTN)EfiToLegacy16BootTable); Private->LegacyBios.FarCall86 ( This, Private->Legacy16CallSegment, Private->Legacy16CallOffset, &Regs, NULL, 0 ); if (Regs.X.AX != 0) { return EFI_DEVICE_ERROR; } // // Re-update E820 table // E820 = (EFI_E820_ENTRY64 *) Private->E820Table; // // Update First entry from BDA // E820[0].Length = (UINT64) ((UINTN)(*(UINT16 *) (UINTN)0x40E) << 4); // // Second entry is (640k - EBDA) to 640k // E820[1].BaseAddr = E820[0].Length; E820[1].Length = (UINT64) ((640 * 1024) - E820[0].Length); CopyMem ( (VOID *) (UINTN) Private->Legacy16Table->E820Pointer, Private->E820Table, sizeof (EFI_E820_ENTRY64) * 2 ); // // Lock the Legacy BIOS region // Private->LegacyRegion->Lock ( Private->LegacyRegion, 0xc0000, 0x40000, &Granularity ); // // Lock attributes of the Legacy Region if chipset supports // Private->LegacyRegion->BootLock ( Private->LegacyRegion, 0xc0000, 0x40000, &Granularity ); // // Call into Legacy16 code to do the INT 19h // EnableAllControllers (Private); if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) { // // Disable DXE Timer before signal legacy boot event // to preventing DXE services from called in timer handler // Private->Timer->SetTimerPeriod (Private->Timer, 0); if (FeaturePcdGet (PcdH2OBdsCpLegacyBootBeforeSupported)) { TriggerCpLegacyBootBefore (); } POST_CODE (BDS_LEGACY_BOOT_EVENT); //PostCode = 0x33, Last Chipset initial before boot to Legacy OS // // Signal all the events that are waiting on EVT_SIGNAL_LEGACY_BOOT // EfiSignalEventLegacyBoot (); DEBUG ((EFI_D_INFO, "Legacy INT19 Boot...\n")); // // Report Status Code to indicate legacy boot event was signalled // REPORT_STATUS_CODE ( EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_LEGACY_BOOT_EVENT) ); if (FeaturePcdGet (PcdH2OBdsCpLegacyBootAfterSupported)) { TriggerCpLegacyBootAfter (); } // // Save and disable interrupt of debug timer // SaveAndSetDebugTimerInterrupt (FALSE); // // Put the 8259 into its legacy mode by reprogramming the vector bases // Private->Legacy8259->SetVectorBase (Private->Legacy8259, LEGACY_MODE_BASE_VECTOR_MASTER, LEGACY_MODE_BASE_VECTOR_SLAVE); // // PC History // The original PC used INT8-F for master PIC. Since these mapped over // processor exceptions TIANO moved the master PIC to INT68-6F. // We need to set these back to the Legacy16 unexpected interrupt(saved // in LegacyBios.c) since some OS see that these have values different from // what is expected and invoke them. Since the legacy OS corrupts EFI // memory, there is no handler for these interrupts and OS blows up. // // We need to save the TIANO values for the rare case that the Legacy16 // code cannot boot but knows memory hasn't been destroyed. // // To compound the problem, video takes over one of these INTS and must be // be left. // @bug - determine if video hooks INT(in which case we must find new // set of TIANO vectors) or takes it over. // // ACCESS_PAGE0_CODE ( BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER); for (Index = 0; Index < 8; Index++) { Private->ThunkSavedInt[Index] = BaseVectorMaster[Index]; if (Private->ThunkSeg == (UINT16) (BaseVectorMaster[Index] >> 16)) { BaseVectorMaster[Index] = (UINT32) (Private->BiosUnexpectedInt); } } ); POST_CODE (BDS_ENTER_LEGACY_16_BOOT); //PostCode = 0x34, Ready to Boot Legacy OS ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); Regs.X.AX = Legacy16Boot; Private->LegacyBios.FarCall86 ( This, Private->Legacy16CallSegment, Private->Legacy16CallOffset, &Regs, NULL, 0 ); ACCESS_PAGE0_CODE ( BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER); for (Index = 0; Index < 8; Index++) { BaseVectorMaster[Index] = Private->ThunkSavedInt[Index]; } ); } Private->LegacyBootEntered = TRUE; if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) { // // Should never return unless never passed control to 0:7c00(first stage // OS loader) and only then if no bootable device found. // return EFI_DEVICE_ERROR; } else { // // If boot to EFI then expect to return to caller // return EFI_SUCCESS; } } /** Assign drive number to legacy HDD drives prior to booting an EFI aware OS so the OS can access drives without an EFI driver. Note: BBS compliant drives ARE NOT available until this call by either shell or EFI. @param This Protocol instance pointer. @param BbsCount Number of BBS_TABLE structures @param BbsTable List BBS entries @retval EFI_SUCCESS Drive numbers assigned **/ EFI_STATUS EFIAPI LegacyBiosPrepareToBootEfi ( IN EFI_LEGACY_BIOS_PROTOCOL *This, OUT UINT16 *BbsCount, OUT BBS_TABLE **BbsTable ) { EFI_STATUS Status; EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable; LEGACY_BIOS_INSTANCE *Private; Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable; mBootMode = BOOT_EFI_OS; mBbsDevicePathPtr = NULL; Status = GenericLegacyBoot (This); *BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable; *BbsCount = (UINT16) (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE)); return Status; } /** To boot from an unconventional device like parties and/or execute HDD diagnostics. @param This Protocol instance pointer. @param Attributes How to interpret the other input parameters @param BbsEntry The 0-based index into the BbsTable for the parent device. @param BeerData Pointer to the 128 bytes of ram BEER data. @param ServiceAreaData Pointer to the 64 bytes of raw Service Area data. The caller must provide a pointer to the specific Service Area and not the start all Service Areas. @retval EFI_INVALID_PARAMETER if error. Does NOT return if no error. ***/ EFI_STATUS EFIAPI LegacyBiosBootUnconventionalDevice ( IN EFI_LEGACY_BIOS_PROTOCOL *This, IN UDC_ATTRIBUTES Attributes, IN UINTN BbsEntry, IN VOID *BeerData, IN VOID *ServiceAreaData ) { EFI_STATUS Status; EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable; LEGACY_BIOS_INSTANCE *Private; UD_TABLE *UcdTable; UINTN Index; UINT16 BootPriority; BBS_TABLE *BbsTable; BootPriority = 0; Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); mBootMode = BOOT_UNCONVENTIONAL_DEVICE; mBbsDevicePathPtr = &mBbsDevicePathNode; mAttributes = Attributes; mBbsEntry = BbsEntry; mBeerData = BeerData, mServiceAreaData = ServiceAreaData; EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable; // // Do input parameter checking // if ((Attributes.DirectoryServiceValidity == 0) && (Attributes.RabcaUsedFlag == 0) && (Attributes.ExecuteHddDiagnosticsFlag == 0) ) { return EFI_INVALID_PARAMETER; } if (((Attributes.DirectoryServiceValidity != 0) && (ServiceAreaData == NULL)) || (((Attributes.DirectoryServiceValidity | Attributes.RabcaUsedFlag) != 0) && (BeerData == NULL)) ) { return EFI_INVALID_PARAMETER; } UcdTable = (UD_TABLE *) AllocatePool ( sizeof (UD_TABLE) ); if (NULL == UcdTable) { return EFI_OUT_OF_RESOURCES; } EfiToLegacy16BootTable->UnconventionalDeviceTable = (UINT32)(UINTN)UcdTable; UcdTable->Attributes = Attributes; UcdTable->BbsTableEntryNumberForParentDevice = (UINT8) BbsEntry; // // Force all existing BBS entries to DoNotBoot. This allows 16-bit CSM // to assign drive numbers but bot boot from. Only newly created entries // will be valid. // BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable; for (Index = 0; Index < EfiToLegacy16BootTable->NumberBbsEntries; Index++) { BbsTable[Index].BootPriority = BBS_DO_NOT_BOOT_FROM; } // // If parent is onboard IDE then assign controller & device number // else they are 0. // if (BbsEntry < MAX_IDE_CONTROLLER * 2) { UcdTable->DeviceNumber = (UINT8) ((BbsEntry - 1) % 2); } if (BeerData != NULL) { CopyMem ( (VOID *) UcdTable->BeerData, BeerData, (UINTN) 128 ); } if (ServiceAreaData != NULL) { CopyMem ( (VOID *) UcdTable->ServiceAreaData, ServiceAreaData, (UINTN) 64 ); } // // For each new entry do the following: // 1. Increment current number of BBS entries // 2. Copy parent entry to new entry. // 3. Zero out BootHandler Offset & segment // 4. Set appropriate device type. BEV(0x80) for HDD diagnostics // and Floppy(0x01) for PARTIES boot. // 5. Assign new priority. // if ((Attributes.ExecuteHddDiagnosticsFlag) != 0) { EfiToLegacy16BootTable->NumberBbsEntries += 1; CopyMem ( (VOID *) &BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority, (VOID *) &BbsTable[BbsEntry].BootPriority, sizeof (BBS_TABLE) ); BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerOffset = 0; BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerSegment = 0; BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].DeviceType = 0x80; UcdTable->BbsTableEntryNumberForHddDiag = (UINT8) (EfiToLegacy16BootTable->NumberBbsEntries - 1); BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority = BootPriority; BootPriority += 1; // // Set device type as BBS_TYPE_BEV for PARTIES diagnostic // mBbsDevicePathNode.DeviceType = BBS_TYPE_BEV; } if (((Attributes.DirectoryServiceValidity | Attributes.RabcaUsedFlag)) != 0) { EfiToLegacy16BootTable->NumberBbsEntries += 1; CopyMem ( (VOID *) &BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority, (VOID *) &BbsTable[BbsEntry].BootPriority, sizeof (BBS_TABLE) ); BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerOffset = 0; BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerSegment = 0; BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].DeviceType = 0x01; UcdTable->BbsTableEntryNumberForBoot = (UINT8) (EfiToLegacy16BootTable->NumberBbsEntries - 1); BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority = BootPriority; // // Set device type as BBS_TYPE_FLOPPY for PARTIES boot as floppy // mBbsDevicePathNode.DeviceType = BBS_TYPE_FLOPPY; } // // Build the BBS Device Path for this boot selection // mBbsDevicePathNode.Header.Type = BBS_DEVICE_PATH; mBbsDevicePathNode.Header.SubType = BBS_BBS_DP; SetDevicePathNodeLength (&mBbsDevicePathNode.Header, sizeof (BBS_BBS_DEVICE_PATH)); mBbsDevicePathNode.StatusFlag = 0; mBbsDevicePathNode.String[0] = 0; Status = GenericLegacyBoot (This); return Status; } /** Attempt to legacy boot the BootOption. If the EFI contexted has been compromised this function will not return. @param This Protocol instance pointer. @param BbsDevicePath EFI Device Path from BootXXXX variable. @param LoadOptionsSize Size of LoadOption in size. @param LoadOptions LoadOption from BootXXXX variable @retval EFI_SUCCESS Removable media not present **/ EFI_STATUS EFIAPI LegacyBiosLegacyBoot ( IN EFI_LEGACY_BIOS_PROTOCOL *This, IN BBS_BBS_DEVICE_PATH *BbsDevicePath, IN UINT32 LoadOptionsSize, IN VOID *LoadOptions ) { EFI_STATUS Status; mBbsDevicePathPtr = BbsDevicePath; mLoadOptionsSize = LoadOptionsSize; mLoadOptions = LoadOptions; mBootMode = BOOT_LEGACY_OS; Status = GenericLegacyBoot (This); return Status; } /** Convert EFI Memory Type to E820 Memory Type. @param Type EFI Memory Type @return ACPI Memory Type for EFI Memory Type **/ EFI_ACPI_MEMORY_TYPE EfiMemoryTypeToE820Type ( IN UINT32 Type ) { switch (Type) { case EfiLoaderCode: case EfiLoaderData: case EfiBootServicesCode: case EfiBootServicesData: case EfiConventionalMemory: return EfiAcpiAddressRangeMemory; case EfiPersistentMemory: return EfiAddressRangePersistentMemory; case EfiACPIReclaimMemory: return EfiAcpiAddressRangeACPI; case EfiACPIMemoryNVS: return EfiAcpiAddressRangeNVS; // // All other types map to reserved. // Adding the code just waists FLASH space. // // case EfiReservedMemoryType: // case EfiRuntimeServicesCode: // case EfiRuntimeServicesData: // case EfiUnusableMemory: // case EfiMemoryMappedIO: // case EfiMemoryMappedIOPortSpace: // case EfiPalCode: // default: return EfiAcpiAddressRangeReserved; } } /** Adjust the E820 table. @param E820 Pointer of E820 Table @param Index Counts of E820 Table @retval Index Counts of E820 Table after Adjust. **/ UINTN AdjustE820Table ( IN EFI_E820_ENTRY64 *E820, IN UINTN Index ) { UINTN TempIndex; BOOLEAN ChangedFlag; UINTN TempNextIndex; EFI_E820_ENTRY64 TempE820; UINTN IndexSort; for (TempIndex = 0; TempIndex < Index; TempIndex++) { ChangedFlag = FALSE; for (TempNextIndex = 1; TempNextIndex < Index - TempIndex; TempNextIndex++) { // // Sort E820Table from low to high // if (E820[TempNextIndex - 1].BaseAddr > E820[TempNextIndex].BaseAddr) { ChangedFlag = TRUE; TempE820.BaseAddr = E820[TempNextIndex - 1].BaseAddr; TempE820.Length = E820[TempNextIndex - 1].Length; TempE820.Type = E820[TempNextIndex - 1].Type; TempE820.ExtAttributes = E820[TempNextIndex - 1].ExtAttributes; E820[TempNextIndex - 1].BaseAddr = E820[TempNextIndex].BaseAddr; E820[TempNextIndex - 1].Length = E820[TempNextIndex].Length; E820[TempNextIndex - 1].Type = E820[TempNextIndex].Type; E820[TempNextIndex - 1].ExtAttributes = E820[TempNextIndex].ExtAttributes; E820[TempNextIndex].BaseAddr = TempE820.BaseAddr; E820[TempNextIndex].Length = TempE820.Length; E820[TempNextIndex].Type = TempE820.Type; E820[TempNextIndex].ExtAttributes = TempE820.ExtAttributes; } else if ((E820[TempNextIndex - 1].Type == E820[TempNextIndex].Type) && (E820[TempNextIndex - 1].ExtAttributes == E820[TempNextIndex].ExtAttributes) && (E820[TempNextIndex - 1].BaseAddr == E820[TempNextIndex].BaseAddr)) { if (E820[TempNextIndex - 1].Length < E820[TempNextIndex].Length) { E820[TempNextIndex - 1].Length = E820[TempNextIndex].Length; } // // Filter the same type / base / length / ExtAttributes // E820[TempNextIndex].BaseAddr = 0; E820[TempNextIndex].Length = 0; E820[TempNextIndex].Type = 0; E820[TempNextIndex].ExtAttributes = 0; for (IndexSort = TempNextIndex; IndexSort < Index ; IndexSort ++) { E820[IndexSort].BaseAddr = E820[IndexSort + 1].BaseAddr; E820[IndexSort].Length = E820[IndexSort + 1].Length; E820[IndexSort].Type = E820[IndexSort + 1].Type; E820[IndexSort].ExtAttributes = E820[IndexSort + 1].ExtAttributes; } TempNextIndex--; Index--; } } if (!ChangedFlag) { break; } } // // Remove the overlap range // for (TempIndex = 1; TempIndex < Index; TempIndex++) { if (E820[TempIndex - 1].BaseAddr <= E820[TempIndex].BaseAddr && ((E820[TempIndex - 1].BaseAddr + E820[TempIndex - 1].Length) >= (E820[TempIndex].BaseAddr + E820[TempIndex].Length))) { // // Overlap range is found // ASSERT (E820[TempIndex - 1].Type == E820[TempIndex].Type); if (TempIndex == Index - 1) { E820[TempIndex].BaseAddr = 0; E820[TempIndex].Length = 0; E820[TempIndex].Type = 0; E820[TempIndex].ExtAttributes = 0; Index--; break; } else { for (IndexSort = TempIndex; IndexSort < Index; IndexSort ++) { E820[IndexSort].BaseAddr = E820[IndexSort + 1].BaseAddr; E820[IndexSort].Length = E820[IndexSort + 1].Length; E820[IndexSort].Type = E820[IndexSort + 1].Type; E820[IndexSort].ExtAttributes = E820[IndexSort + 1].ExtAttributes; } TempIndex--; Index--; } } } for (TempIndex = 1; TempIndex < Index; TempIndex++) { // // Merge the same type and contiguous memory // if ((E820[TempIndex - 1].Type == E820[TempIndex].Type) && (E820[TempIndex - 1].ExtAttributes == E820[TempIndex].ExtAttributes) && ((E820[TempIndex - 1].BaseAddr + E820[TempIndex - 1].Length) == E820[TempIndex].BaseAddr )) { E820[TempIndex - 1].Length = E820[TempIndex - 1].Length + E820[TempIndex].Length; for (IndexSort = TempIndex; IndexSort < Index ; IndexSort ++) { E820[IndexSort].BaseAddr = E820[IndexSort + 1].BaseAddr; E820[IndexSort].Length = E820[IndexSort + 1].Length; E820[IndexSort].Type = E820[IndexSort + 1].Type; E820[IndexSort].ExtAttributes = E820[IndexSort + 1].ExtAttributes; } TempIndex--; Index--; } // // Filter the same type/base/length // if ((E820[TempIndex - 1].Type == E820[TempIndex].Type) && (E820[TempIndex - 1].ExtAttributes == E820[TempIndex].ExtAttributes) && (E820[TempIndex - 1].BaseAddr == E820[TempIndex].BaseAddr) && (E820[TempIndex - 1].Length == E820[TempIndex].Length)) { E820[TempIndex].BaseAddr = 0; E820[TempIndex].Length = 0; E820[TempIndex].Type = 0; E820[TempIndex].ExtAttributes = 0; for (IndexSort = TempIndex; IndexSort < Index ; IndexSort ++) { E820[IndexSort].BaseAddr = E820[IndexSort + 1].BaseAddr; E820[IndexSort].Length = E820[IndexSort + 1].Length; E820[IndexSort].Type = E820[IndexSort + 1].Type; E820[IndexSort].ExtAttributes = E820[IndexSort + 1].ExtAttributes; } TempIndex--; Index--; } } return Index; } /** Build the E820 table. @param Private Legacy BIOS Instance data @param Size Size of E820 Table @retval EFI_SUCCESS It should always work. **/ EFI_STATUS LegacyBiosBuildE820 ( IN LEGACY_BIOS_INSTANCE *Private, OUT UINTN *Size ) { EFI_STATUS Status; EFI_E820_ENTRY64 *E820; EFI_MEMORY_DESCRIPTOR *EfiMemoryMap; EFI_MEMORY_DESCRIPTOR *EfiMemoryMapEnd; EFI_MEMORY_DESCRIPTOR *EfiEntry; EFI_MEMORY_DESCRIPTOR *NextEfiEntry; EFI_MEMORY_DESCRIPTOR TempEfiEntry; UINTN EfiMemoryMapSize; UINTN EfiMapKey; UINTN EfiDescriptorSize; UINT32 EfiDescriptorVersion; UINTN Index; EFI_PEI_HOB_POINTERS Hob; EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob; UINTN TempIndex; EFI_ACPI_MEMORY_TYPE TempType; UINTN Above1MIndex; UINT64 MemoryBlockLength; E820 = (EFI_E820_ENTRY64 *) Private->E820Table; // // Get the EFI memory map. // EfiMemoryMapSize = 0; EfiMemoryMap = NULL; Status = gBS->GetMemoryMap ( &EfiMemoryMapSize, EfiMemoryMap, &EfiMapKey, &EfiDescriptorSize, &EfiDescriptorVersion ); while (Status == EFI_BUFFER_TOO_SMALL) { // // Use size returned back plus 1 descriptor for the AllocatePool. // We don't just multiply by 2 since the "for" loop below terminates on // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwize // we process bogus entries and create bogus E820 entries. // EfiMemoryMap = AllocatePool (EfiMemoryMapSize); if (EfiMemoryMap == NULL) { return EFI_OUT_OF_RESOURCES; } Status = gBS->GetMemoryMap ( &EfiMemoryMapSize, EfiMemoryMap, &EfiMapKey, &EfiDescriptorSize, &EfiDescriptorVersion ); if (EFI_ERROR (Status)) { FreePool (EfiMemoryMap); } } ASSERT_EFI_ERROR (Status); if(EfiMemoryMap == NULL) { return EFI_OUT_OF_RESOURCES; } // // Punch in the E820 table for memory less than 1 MB. // Assume ZeroMem () has been done on data structure. // // // First entry is 0 to (640k - EBDA) // ACCESS_PAGE0_CODE ( E820[0].BaseAddr = 0; E820[0].Length = (UINT64) ((UINTN)(*(UINT16 *) (UINTN)0x40E) << 4); E820[0].Type = EfiAcpiAddressRangeMemory; E820[0].ExtAttributes = AddressRangeEnabled; ); // // Second entry is (640k - EBDA) to 640k // E820[1].BaseAddr = E820[0].Length; E820[1].Length = (UINT64) ((640 * 1024) - E820[0].Length); E820[1].Type = EfiAcpiAddressRangeReserved; E820[1].ExtAttributes = AddressRangeEnabled; // // Third Entry is legacy BIOS // DO NOT CLAIM region from 0xA0000-0xDFFFF. OS can use free areas // to page in memory under 1MB. // Omit region from 0xE0000 to start of BIOS, if any. This can be // used for a multiple reasons including OPROMS. // // // The CSM binary image size is not the actually size that CSM binary used, // to avoid memory corrupt, we declare the 0E0000 - 0FFFFF is used by CSM binary. // E820[2].BaseAddr = 0xE0000; E820[2].Length = 0x20000; E820[2].Type = EfiAcpiAddressRangeReserved; E820[2].ExtAttributes = AddressRangeEnabled; Above1MIndex = 2; // // Process the EFI map to produce E820 map; // // // Sort memory map from low to high // EfiEntry = EfiMemoryMap; NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize); EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize); while (EfiEntry < EfiMemoryMapEnd) { while (NextEfiEntry < EfiMemoryMapEnd) { if (EfiEntry->PhysicalStart > NextEfiEntry->PhysicalStart) { CopyMem (&TempEfiEntry, EfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR)); CopyMem (EfiEntry, NextEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR)); CopyMem (NextEfiEntry, &TempEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR)); } NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (NextEfiEntry, EfiDescriptorSize); } EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize); NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize); } EfiEntry = EfiMemoryMap; EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize); for (Index = Above1MIndex; (EfiEntry < EfiMemoryMapEnd) && (Index < EFI_MAX_E820_ENTRY - 1); ) { MemoryBlockLength = (UINT64) (LShiftU64 (EfiEntry->NumberOfPages, 12)); if ((EfiEntry->PhysicalStart + MemoryBlockLength) < 0x100000) { // // Skip the memory block is under 1MB // } else { if (EfiEntry->PhysicalStart < 0x100000) { // // When the memory block spans below 1MB, ensure the memory block start address is at least 1MB // MemoryBlockLength -= 0x100000 - EfiEntry->PhysicalStart; EfiEntry->PhysicalStart = 0x100000; } // // Convert memory type to E820 type // TempType = EfiMemoryTypeToE820Type (EfiEntry->Type); if (FeaturePcdGet(PcdE820TableNetBsdSupported)) { // // Win98 SE and NetBSD have a problem with intermixed E820 types 1,3,4. If type // 1 is 1 page it walks into the next type. If see a type 1 above // a type 3 or 4 then force type 1 to type 3. // if ((TempType == EfiAcpiAddressRangeMemory) && (EfiEntry->PhysicalStart > mLowWater)) { TempType = EfiAcpiAddressRangeACPI; } else { if (((TempType == EfiAcpiAddressRangeACPI) || (TempType == EfiAcpiAddressRangeNVS)) && (EfiEntry->PhysicalStart < mLowWater)) { mLowWater = EfiEntry->PhysicalStart; } } } if ((E820[Index].Type == TempType) && (EfiEntry->PhysicalStart == (E820[Index].BaseAddr + E820[Index].Length))) { // // Grow an existing entry // E820[Index].Length += MemoryBlockLength; } else { // // Make a new entry // ++Index; E820[Index].BaseAddr = EfiEntry->PhysicalStart; E820[Index].Length = MemoryBlockLength; E820[Index].Type = TempType; E820[Index].ExtAttributes = AddressRangeEnabled; } } EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize); } FreePool (EfiMemoryMap); // // Process the reserved memory map to produce E820 map ; // for (Hob.Raw = GetHobList (); !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) { if (Hob.Raw == NULL) { break; } if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { ResourceHob = Hob.ResourceDescriptor; if (((ResourceHob->ResourceType == EFI_RESOURCE_MEMORY_MAPPED_IO) || (ResourceHob->ResourceType == EFI_RESOURCE_FIRMWARE_DEVICE) || (ResourceHob->ResourceType == EFI_RESOURCE_MEMORY_RESERVED)) && (ResourceHob->PhysicalStart > 0x100000) && (Index < EFI_MAX_E820_ENTRY - 1)) { ++Index; E820[Index].BaseAddr = ResourceHob->PhysicalStart; E820[Index].Length = ResourceHob->ResourceLength; E820[Index].Type = EfiAcpiAddressRangeReserved; } } } if (Index == EFI_MAX_E820_ENTRY - 1) { return EFI_OUT_OF_RESOURCES; } Index ++; // // Sort / Merge / Remove the overlap range // Index = AdjustE820Table (E820, Index); // // If set, the Address Range Descriptor represents non-volatile memory, this address // is remapped System BIOS at end of address space. // if ((E820[Index].BaseAddr + E820[Index].Length) == 0x100000000) { E820[Index].ExtAttributes |= AddressRangeNonVolatile; } Private->IntThunk->EfiToLegacy16InitTable.NumberE820Entries = (UINT32)Index; Private->IntThunk->EfiToLegacy16BootTable.NumberE820Entries = (UINT32)Index; Private->NumberE820Entries = (UINT32)Index; *Size = (UINTN) (Index * sizeof (EFI_E820_ENTRY64)); if (FeaturePcdGet(PcdE820TableNetBsdSupported)) { for (TempIndex = Above1MIndex; TempIndex < Index; TempIndex++) { if ((E820[TempIndex].Type == EfiAcpiAddressRangeMemory) && (E820[TempIndex].BaseAddr > mLowWater)) { E820[TempIndex].Type = EfiAcpiAddressRangeACPI; } } } // // Determine OS usable memory above 1Mb // Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb = 0x0000; for (TempIndex = Above1MIndex; TempIndex < Index; TempIndex++) { if (E820[TempIndex].BaseAddr >= 0x100000) { // // ACPIReclaimMemory is also usable memory for ACPI OS, after OS dumps all ACPI tables. // if ((E820[TempIndex].Type == EfiAcpiAddressRangeMemory) || (E820[TempIndex].Type == EfiAcpiAddressRangeACPI)) { Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb += (UINT32) (E820[TempIndex].Length); } else { continue; } } } Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb = Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb; // // Print DEBUG information // for (TempIndex = 0; TempIndex < Index; TempIndex++) { DEBUG((EFI_D_INFO, "E820[%2d]: 0x%16lx ---- 0x%16lx, Type = 0x%x, ExtAttributes = 0x%x\n", TempIndex, E820[TempIndex].BaseAddr, (E820[TempIndex].BaseAddr + E820[TempIndex].Length), E820[TempIndex].Type, E820[TempIndex].ExtAttributes )); } return EFI_SUCCESS; } /** Fill in the standard BDA and EBDA stuff prior to legacy Boot @param Private Legacy BIOS Instance data @retval EFI_SUCCESS It should always work. **/ EFI_STATUS LegacyBiosCompleteBdaBeforeBoot ( IN LEGACY_BIOS_INSTANCE *Private ) { BDA_STRUC *Bda; UINT16 MachineConfig; DEVICE_PRODUCER_DATA_HEADER *SioPtr; Bda = (BDA_STRUC *) ((UINTN) 0x400); MachineConfig = 0; SioPtr = &(Private->IntThunk->EfiToLegacy16BootTable.SioData); Bda->Com1 = SioPtr->Serial[0].Address; Bda->Com2 = SioPtr->Serial[1].Address; Bda->Com3 = SioPtr->Serial[2].Address; Bda->Com4 = SioPtr->Serial[3].Address; if (SioPtr->Serial[0].Address != 0x00) { MachineConfig += 0x200; } if (SioPtr->Serial[1].Address != 0x00) { MachineConfig += 0x200; } if (SioPtr->Serial[2].Address != 0x00) { MachineConfig += 0x200; } if (SioPtr->Serial[3].Address != 0x00) { MachineConfig += 0x200; } Bda->Lpt1 = SioPtr->Parallel[0].Address; Bda->Lpt2 = SioPtr->Parallel[1].Address; Bda->Lpt3 = SioPtr->Parallel[2].Address; if (SioPtr->Parallel[0].Address != 0x00) { MachineConfig += 0x4000; } if (SioPtr->Parallel[1].Address != 0x00) { MachineConfig += 0x4000; } if (SioPtr->Parallel[2].Address != 0x00) { MachineConfig += 0x4000; } Bda->NumberOfDrives = (UINT8) (Bda->NumberOfDrives + Private->IdeDriveCount); if (SioPtr->Floppy.NumberOfFloppy != 0x00) { MachineConfig = (UINT16) (MachineConfig + 0x01 + (SioPtr->Floppy.NumberOfFloppy - 1) * 0x40); Bda->FloppyXRate = 0x07; } Bda->Lpt1_2Timeout = 0x1414; Bda->Lpt3_4Timeout = 0x1414; Bda->Com1_2Timeout = 0x0101; Bda->Com3_4Timeout = 0x0101; // // Force VGA and Coprocessor, indicate 101/102 keyboard // MachineConfig = (UINT16) (MachineConfig + 0x00 + 0x02 + (SioPtr->MousePresent * 0x04)); Bda->MachineConfig = MachineConfig; return EFI_SUCCESS; } /** Fill in the standard BDA for Keyboard LEDs @param This Protocol instance pointer. @param Leds Current LED status @retval EFI_SUCCESS It should always work. **/ EFI_STATUS EFIAPI LegacyBiosUpdateKeyboardLedStatus ( IN EFI_LEGACY_BIOS_PROTOCOL *This, IN UINT8 Leds ) { LEGACY_BIOS_INSTANCE *Private; BDA_STRUC *Bda; UINT8 LocalLeds; EFI_IA32_REGISTER_SET Regs; Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); ACCESS_PAGE0_CODE ( Bda = (BDA_STRUC *) ((UINTN) 0x400); LocalLeds = Leds; Bda->LedStatus = (UINT8) ((Bda->LedStatus &~0x07) | LocalLeds); LocalLeds = (UINT8) (LocalLeds << 4); Bda->ShiftStatus = (UINT8) ((Bda->ShiftStatus &~0x70) | LocalLeds); LocalLeds = (UINT8) (Leds & 0x20); Bda->KeyboardStatus = (UINT8) ((Bda->KeyboardStatus &~0x20) | LocalLeds); ); // // Call into Legacy16 code to allow it to do any processing // ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); Regs.X.AX = Legacy16SetKeyboardLeds; Regs.H.CL = Leds; Private->LegacyBios.FarCall86 ( &Private->LegacyBios, Private->Legacy16Table->Compatibility16CallSegment, Private->Legacy16Table->Compatibility16CallOffset, &Regs, NULL, 0 ); return EFI_SUCCESS; } /** Fill in the standard CMOS stuff prior to legacy Boot @param Private Legacy BIOS Instance data @retval EFI_SUCCESS It should always work. **/ EFI_STATUS LegacyBiosCompleteStandardCmosBeforeBoot ( IN LEGACY_BIOS_INSTANCE *Private ) { UINT8 Bda; UINT8 Floppy; UINT32 Size; UINT8 Temp; UINT8 Temp1; // // Update CMOS locations // 10 floppy // 12,19,1A - ignore as OS don't use them and there is no standard due // to large capacity drives // CMOS 14 = BDA 40:10 plus bit 3(display enabled) // ACCESS_PAGE0_CODE ( Bda = (UINT8)(*((UINT8 *)((UINTN)0x410)) | BIT3); ); // // Force display enabled // Floppy = 0x00; if ((Bda & BIT0) != 0) { Floppy = BIT6; } // // Check if 2.88MB floppy set // if ((Bda & (BIT7 | BIT6)) != 0) { Floppy = (UINT8)(Floppy | BIT1); } LegacyWriteStandardCmos (CMOS_10, Floppy); LegacyWriteStandardCmos (CMOS_14, Bda); // // Force Status Register A to set rate selection bits and divider // LegacyWriteStandardCmos (CMOS_0A, 0x26); // // redo memory size since it can change // Size = 63 * SIZE_1MB; Temp = 0x00; Temp1 = 0xFC; if (Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb < (63 * SIZE_1MB)) { Size = Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb >> 10; Temp = (UINT8) (Size & 0xFF); Temp1 = (UINT8) (Size >> 8); } LegacyWriteStandardCmos (CMOS_17, Temp); LegacyWriteStandardCmos (CMOS_30, Temp); LegacyWriteStandardCmos (CMOS_18, Temp1); LegacyWriteStandardCmos (CMOS_31, Temp1); LegacyCalculateWriteStandardCmosChecksum (); return EFI_SUCCESS; } /** Relocate this image under 4G memory for IPF. @param ImageHandle Handle of driver image. @param SystemTable Pointer to system table. @retval EFI_SUCCESS Image successfully relocated. @retval EFI_ABORTED Failed to relocate image. **/ EFI_STATUS RelocateImageUnder4GIfNeeded ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { return EFI_SUCCESS; }