VOID InstallFeatureControlCallback ( VOID ) { EFI_STATUS Status; FIRMWARE_CONFIG_ITEM FwCfgItem; UINTN FwCfgSize; Status = QemuFwCfgFindFile ("etc/msr_feature_control", &FwCfgItem, &FwCfgSize); if (EFI_ERROR (Status) || FwCfgSize != sizeof mFeatureControlValue) { // // Nothing to do. // return; } QemuFwCfgSelectItem (FwCfgItem); QemuFwCfgReadBytes (sizeof mFeatureControlValue, &mFeatureControlValue); Status = PeiServicesNotifyPpi (&mMpServicesNotify); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "%a: failed to set up MP Services callback: %r\n", __FUNCTION__, Status)); } }
/** Locates and extracts the QEMU SMBIOS data if present in fw_cfg @return Address of extracted QEMU SMBIOS data **/ UINT8 * GetQemuSmbiosTables ( VOID ) { EFI_STATUS Status; FIRMWARE_CONFIG_ITEM Tables; UINTN TablesSize; UINT8 *QemuTables; if (!PcdGetBool (PcdQemuSmbiosValidated)) { return NULL; } Status = QemuFwCfgFindFile ("etc/smbios/smbios-tables", &Tables, &TablesSize); ASSERT_EFI_ERROR (Status); ASSERT (TablesSize > 0); QemuTables = AllocatePool (TablesSize); if (QemuTables == NULL) { return NULL; } QemuFwCfgSelectItem (Tables); QemuFwCfgReadBytes (TablesSize, QemuTables); return QemuTables; }
/** Locates and extracts the QEMU SMBIOS data if present in fw_cfg @return Address of extracted QEMU SMBIOS data **/ UINT8 * GetQemuSmbiosTables ( VOID ) { SMBIOS_TABLE_ENTRY_POINT QemuAnchor; FIRMWARE_CONFIG_ITEM Anchor, Tables; UINTN AnchorSize, TablesSize; UINT8 *QemuTables; if (EFI_ERROR (QemuFwCfgFindFile ( "etc/smbios/smbios-anchor", &Anchor, &AnchorSize)) || EFI_ERROR (QemuFwCfgFindFile ( "etc/smbios/smbios-tables", &Tables, &TablesSize)) || AnchorSize != sizeof (QemuAnchor) || TablesSize == 0) { return NULL; } // // We copy the entry point structure to perform some additional checks, // but discard it upon return. // QemuFwCfgSelectItem (Anchor); QemuFwCfgReadBytes (AnchorSize, &QemuAnchor); if (AsciiStrnCmp ((CHAR8 *)QemuAnchor.AnchorString, "_SM_", 4) || AsciiStrnCmp ((CHAR8 *)QemuAnchor.IntermediateAnchorString, "_DMI_", 5) || TablesSize != QemuAnchor.TableLength) { return NULL; } QemuTables = AllocatePool (TablesSize); if (QemuTables == NULL) { return NULL; } QemuFwCfgSelectItem (Tables); QemuFwCfgReadBytes (TablesSize, QemuTables); return QemuTables; }
EFI_STATUS GetNamedFwCfgBoolean ( IN CHAR8 *FwCfgFileName, OUT BOOLEAN *Setting ) { EFI_STATUS Status; FIRMWARE_CONFIG_ITEM FwCfgItem; UINTN FwCfgSize; UINT8 Value[3]; Status = QemuFwCfgFindFile (FwCfgFileName, &FwCfgItem, &FwCfgSize); if (EFI_ERROR (Status)) { return Status; } if (FwCfgSize > sizeof Value) { return EFI_BAD_BUFFER_SIZE; } QemuFwCfgSelectItem (FwCfgItem); QemuFwCfgReadBytes (FwCfgSize, Value); if ((FwCfgSize == 1) || (FwCfgSize == 2 && Value[1] == '\n') || (FwCfgSize == 3 && Value[1] == '\r' && Value[2] == '\n')) { switch (Value[0]) { case '0': case 'n': case 'N': *Setting = FALSE; return EFI_SUCCESS; case '1': case 'y': case 'Y': *Setting = TRUE; return EFI_SUCCESS; default: break; } } return EFI_PROTOCOL_ERROR; }
/** Set the boot order based on configuration retrieved from QEMU. Attempt to retrieve the "bootorder" fw_cfg file from QEMU. Translate the OpenFirmware device paths therein to UEFI device path fragments. Match the translated fragments against BootOptionList, and rewrite the BootOrder NvVar so that it corresponds to the order described in fw_cfg. @param[in] BootOptionList A boot option list, created with BdsLibEnumerateAllBootOption (). @retval RETURN_SUCCESS BootOrder NvVar rewritten. @retval RETURN_UNSUPPORTED QEMU's fw_cfg is not supported. @retval RETURN_NOT_FOUND Empty or nonexistent "bootorder" fw_cfg file, or no match found between the "bootorder" fw_cfg file and BootOptionList. @retval RETURN_INVALID_PARAMETER Parse error in the "bootorder" fw_cfg file. @retval RETURN_OUT_OF_RESOURCES Memory allocation failed. @return Values returned by gBS->LocateProtocol () or gRT->SetVariable (). **/ RETURN_STATUS SetBootOrderFromQemu ( IN CONST LIST_ENTRY *BootOptionList ) { RETURN_STATUS Status; FIRMWARE_CONFIG_ITEM FwCfgItem; UINTN FwCfgSize; CHAR8 *FwCfg; CONST CHAR8 *FwCfgPtr; BOOT_ORDER BootOrder; ACTIVE_OPTION *ActiveOption; UINTN ActiveCount; UINTN TranslatedSize; CHAR16 Translated[TRANSLATION_OUTPUT_SIZE]; Status = QemuFwCfgFindFile ("bootorder", &FwCfgItem, &FwCfgSize); if (Status != RETURN_SUCCESS) { return Status; } if (FwCfgSize == 0) { return RETURN_NOT_FOUND; } FwCfg = AllocatePool (FwCfgSize); if (FwCfg == NULL) { return RETURN_OUT_OF_RESOURCES; } QemuFwCfgSelectItem (FwCfgItem); QemuFwCfgReadBytes (FwCfgSize, FwCfg); if (FwCfg[FwCfgSize - 1] != '\0') { Status = RETURN_INVALID_PARAMETER; goto ErrorFreeFwCfg; } DEBUG ((DEBUG_VERBOSE, "%a: FwCfg:\n", __FUNCTION__)); DEBUG ((DEBUG_VERBOSE, "%a\n", FwCfg)); DEBUG ((DEBUG_VERBOSE, "%a: FwCfg: <end>\n", __FUNCTION__)); FwCfgPtr = FwCfg; BootOrder.Produced = 0; BootOrder.Allocated = 1; BootOrder.Data = AllocatePool ( BootOrder.Allocated * sizeof (*BootOrder.Data) ); if (BootOrder.Data == NULL) { Status = RETURN_OUT_OF_RESOURCES; goto ErrorFreeFwCfg; } Status = CollectActiveOptions (BootOptionList, &ActiveOption, &ActiveCount); if (RETURN_ERROR (Status)) { goto ErrorFreeBootOrder; } // // translate each OpenFirmware path // TranslatedSize = sizeof (Translated) / sizeof (Translated[0]); Status = TranslateOfwPath (&FwCfgPtr, Translated, &TranslatedSize); while (Status == RETURN_SUCCESS || Status == RETURN_UNSUPPORTED || Status == RETURN_BUFFER_TOO_SMALL) { if (Status == RETURN_SUCCESS) { UINTN Idx; // // match translated OpenFirmware path against all active boot options // for (Idx = 0; Idx < ActiveCount; ++Idx) { if (Match ( Translated, TranslatedSize, // contains length, not size, in CHAR16's here ActiveOption[Idx].BootOption->DevicePath ) ) { // // match found, store ID and continue with next OpenFirmware path // Status = BootOrderAppend (&BootOrder, &ActiveOption[Idx]); if (Status != RETURN_SUCCESS) { goto ErrorFreeActiveOption; } break; } } // scanned all active boot options } // translation successful TranslatedSize = sizeof (Translated) / sizeof (Translated[0]); Status = TranslateOfwPath (&FwCfgPtr, Translated, &TranslatedSize); } // scanning of OpenFirmware paths done if (Status == RETURN_NOT_FOUND && BootOrder.Produced > 0) { // // No more OpenFirmware paths, some matches found: rewrite BootOrder NvVar. // Some of the active boot options that have not been selected over fw_cfg // should be preserved at the end of the boot order. // Status = BootOrderComplete (&BootOrder, ActiveOption, ActiveCount); if (RETURN_ERROR (Status)) { goto ErrorFreeActiveOption; } // // See Table 10 in the UEFI Spec 2.3.1 with Errata C for the required // attributes. // Status = gRT->SetVariable ( L"BootOrder", &gEfiGlobalVariableGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, BootOrder.Produced * sizeof (*BootOrder.Data), BootOrder.Data ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a: setting BootOrder: %r\n", __FUNCTION__, Status)); goto ErrorFreeActiveOption; } DEBUG ((DEBUG_INFO, "%a: setting BootOrder: success\n", __FUNCTION__)); PruneBootVariables (ActiveOption, ActiveCount); } ErrorFreeActiveOption: FreePool (ActiveOption); ErrorFreeBootOrder: FreePool (BootOrder.Data); ErrorFreeFwCfg: FreePool (FwCfg); return Status; }
/** Download, process, and install ACPI table data from the QEMU loader interface. @param[in] AcpiProtocol The ACPI table protocol used to install tables. @retval EFI_UNSUPPORTED Firmware configuration is unavailable, or QEMU loader command with unsupported parameters has been found. @retval EFI_NOT_FOUND The host doesn't export the required fw_cfg files. @retval EFI_OUT_OF_RESOURCES Memory allocation failed, or more than INSTALLED_TABLES_MAX tables found. @retval EFI_PROTOCOL_ERROR Found invalid fw_cfg contents. @return Status codes returned by AcpiProtocol->InstallAcpiTable(). **/ EFI_STATUS EFIAPI InstallQemuFwCfgTables ( IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol ) { EFI_STATUS Status; FIRMWARE_CONFIG_ITEM FwCfgItem; UINTN FwCfgSize; QEMU_LOADER_ENTRY *LoaderStart; CONST QEMU_LOADER_ENTRY *LoaderEntry, *LoaderEnd; ORIGINAL_ATTRIBUTES *OriginalPciAttributes; UINTN OriginalPciAttributesCount; ORDERED_COLLECTION *Tracker; UINTN *InstalledKey; INT32 Installed; ORDERED_COLLECTION_ENTRY *TrackerEntry, *TrackerEntry2; Status = QemuFwCfgFindFile ("etc/table-loader", &FwCfgItem, &FwCfgSize); if (EFI_ERROR (Status)) { return Status; } if (FwCfgSize % sizeof *LoaderEntry != 0) { DEBUG ((EFI_D_ERROR, "%a: \"etc/table-loader\" has invalid size 0x%Lx\n", __FUNCTION__, (UINT64)FwCfgSize)); return EFI_PROTOCOL_ERROR; } LoaderStart = AllocatePool (FwCfgSize); if (LoaderStart == NULL) { return EFI_OUT_OF_RESOURCES; } EnablePciDecoding (&OriginalPciAttributes, &OriginalPciAttributesCount); QemuFwCfgSelectItem (FwCfgItem); QemuFwCfgReadBytes (FwCfgSize, LoaderStart); RestorePciDecoding (OriginalPciAttributes, OriginalPciAttributesCount); LoaderEnd = LoaderStart + FwCfgSize / sizeof *LoaderEntry; Tracker = OrderedCollectionInit (BlobCompare, BlobKeyCompare); if (Tracker == NULL) { Status = EFI_OUT_OF_RESOURCES; goto FreeLoader; } // // first pass: process the commands // for (LoaderEntry = LoaderStart; LoaderEntry < LoaderEnd; ++LoaderEntry) { switch (LoaderEntry->Type) { case QemuLoaderCmdAllocate: Status = ProcessCmdAllocate (&LoaderEntry->Command.Allocate, Tracker); break; case QemuLoaderCmdAddPointer: Status = ProcessCmdAddPointer (&LoaderEntry->Command.AddPointer, Tracker); break; case QemuLoaderCmdAddChecksum: Status = ProcessCmdAddChecksum (&LoaderEntry->Command.AddChecksum, Tracker); break; default: DEBUG ((EFI_D_VERBOSE, "%a: unknown loader command: 0x%x\n", __FUNCTION__, LoaderEntry->Type)); break; } if (EFI_ERROR (Status)) { goto FreeTracker; } } InstalledKey = AllocatePool (INSTALLED_TABLES_MAX * sizeof *InstalledKey); if (InstalledKey == NULL) { Status = EFI_OUT_OF_RESOURCES; goto FreeTracker; } // // second pass: identify and install ACPI tables // Installed = 0; for (LoaderEntry = LoaderStart; LoaderEntry < LoaderEnd; ++LoaderEntry) { if (LoaderEntry->Type == QemuLoaderCmdAddPointer) { Status = Process2ndPassCmdAddPointer (&LoaderEntry->Command.AddPointer, Tracker, AcpiProtocol, InstalledKey, &Installed); if (EFI_ERROR (Status)) { break; } } } if (EFI_ERROR (Status)) { // // roll back partial installation // while (Installed > 0) { --Installed; AcpiProtocol->UninstallAcpiTable (AcpiProtocol, InstalledKey[Installed]); } } else { DEBUG ((EFI_D_INFO, "%a: installed %d tables\n", __FUNCTION__, Installed)); } FreePool (InstalledKey); FreeTracker: // // Tear down the tracker infrastructure. Each fw_cfg blob will be left in // place only if we're exiting with success and the blob hosts data that is // not directly part of some ACPI table. // for (TrackerEntry = OrderedCollectionMin (Tracker); TrackerEntry != NULL; TrackerEntry = TrackerEntry2) { VOID *UserStruct; BLOB *Blob; TrackerEntry2 = OrderedCollectionNext (TrackerEntry); OrderedCollectionDelete (Tracker, TrackerEntry, &UserStruct); Blob = UserStruct; if (EFI_ERROR (Status) || Blob->HostsOnlyTableData) { DEBUG ((EFI_D_VERBOSE, "%a: freeing \"%a\"\n", __FUNCTION__, Blob->File)); gBS->FreePages ((UINTN)Blob->Base, EFI_SIZE_TO_PAGES (Blob->Size)); } FreePool (Blob); } OrderedCollectionUninit (Tracker); FreeLoader: FreePool (LoaderStart); return Status; }
/** Process a QEMU_LOADER_ALLOCATE command. @param[in] Allocate The QEMU_LOADER_ALLOCATE command to process. @param[in,out] Tracker The ORDERED_COLLECTION tracking the BLOB user structures created thus far. @retval EFI_SUCCESS An area of whole AcpiNVS pages has been allocated for the blob contents, and the contents have been saved. A BLOB object (user structure) has been allocated from pool memory, referencing the blob contents. The BLOB user structure has been linked into Tracker. @retval EFI_PROTOCOL_ERROR Malformed fw_cfg file name has been found in Allocate, or the Allocate command references a file that is already known by Tracker. @retval EFI_UNSUPPORTED Unsupported alignment request has been found in Allocate. @retval EFI_OUT_OF_RESOURCES Pool allocation failed. @return Error codes from QemuFwCfgFindFile() and gBS->AllocatePages(). **/ STATIC EFI_STATUS EFIAPI ProcessCmdAllocate ( IN CONST QEMU_LOADER_ALLOCATE *Allocate, IN OUT ORDERED_COLLECTION *Tracker ) { FIRMWARE_CONFIG_ITEM FwCfgItem; UINTN FwCfgSize; EFI_STATUS Status; UINTN NumPages; EFI_PHYSICAL_ADDRESS Address; BLOB *Blob; if (Allocate->File[QEMU_LOADER_FNAME_SIZE - 1] != '\0') { DEBUG ((EFI_D_ERROR, "%a: malformed file name\n", __FUNCTION__)); return EFI_PROTOCOL_ERROR; } if (Allocate->Alignment > EFI_PAGE_SIZE) { DEBUG ((EFI_D_ERROR, "%a: unsupported alignment 0x%x\n", __FUNCTION__, Allocate->Alignment)); return EFI_UNSUPPORTED; } Status = QemuFwCfgFindFile ((CHAR8 *)Allocate->File, &FwCfgItem, &FwCfgSize); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "%a: QemuFwCfgFindFile(\"%a\"): %r\n", __FUNCTION__, Allocate->File, Status)); return Status; } NumPages = EFI_SIZE_TO_PAGES (FwCfgSize); Address = 0xFFFFFFFF; Status = gBS->AllocatePages (AllocateMaxAddress, EfiACPIMemoryNVS, NumPages, &Address); if (EFI_ERROR (Status)) { return Status; } Blob = AllocatePool (sizeof *Blob); if (Blob == NULL) { Status = EFI_OUT_OF_RESOURCES; goto FreePages; } CopyMem (Blob->File, Allocate->File, QEMU_LOADER_FNAME_SIZE); Blob->Size = FwCfgSize; Blob->Base = (VOID *)(UINTN)Address; Blob->HostsOnlyTableData = TRUE; Status = OrderedCollectionInsert (Tracker, NULL, Blob); if (Status == RETURN_ALREADY_STARTED) { DEBUG ((EFI_D_ERROR, "%a: duplicated file \"%a\"\n", __FUNCTION__, Allocate->File)); Status = EFI_PROTOCOL_ERROR; } if (EFI_ERROR (Status)) { goto FreeBlob; } QemuFwCfgSelectItem (FwCfgItem); QemuFwCfgReadBytes (FwCfgSize, Blob->Base); ZeroMem (Blob->Base + Blob->Size, EFI_PAGES_TO_SIZE (NumPages) - Blob->Size); DEBUG ((EFI_D_VERBOSE, "%a: File=\"%a\" Alignment=0x%x Zone=%d Size=0x%Lx " "Address=0x%Lx\n", __FUNCTION__, Allocate->File, Allocate->Alignment, Allocate->Zone, (UINT64)Blob->Size, (UINT64)(UINTN)Blob->Base)); return EFI_SUCCESS; FreeBlob: FreePool (Blob); FreePages: gBS->FreePages (Address, NumPages); return Status; }
EFIAPI PciHostBridgeGetRootBridges ( UINTN *Count ) { EFI_STATUS Status; FIRMWARE_CONFIG_ITEM FwCfgItem; UINTN FwCfgSize; UINT64 ExtraRootBridges; PCI_ROOT_BRIDGE *Bridges; UINTN Initialized; UINTN LastRootBridgeNumber; UINTN RootBridgeNumber; *Count = 0; // // QEMU provides the number of extra root buses, shortening the exhaustive // search below. If there is no hint, the feature is missing. // Status = QemuFwCfgFindFile ("etc/extra-pci-roots", &FwCfgItem, &FwCfgSize); if (EFI_ERROR (Status) || FwCfgSize != sizeof ExtraRootBridges) { ExtraRootBridges = 0; } else { QemuFwCfgSelectItem (FwCfgItem); QemuFwCfgReadBytes (FwCfgSize, &ExtraRootBridges); if (ExtraRootBridges > PCI_MAX_BUS) { DEBUG ((EFI_D_ERROR, "%a: invalid count of extra root buses (%Lu) " "reported by QEMU\n", __FUNCTION__, ExtraRootBridges)); return NULL; } DEBUG ((EFI_D_INFO, "%a: %Lu extra root buses reported by QEMU\n", __FUNCTION__, ExtraRootBridges)); } // // Allocate the "main" root bridge, and any extra root bridges. // Bridges = AllocatePool ((1 + (UINTN)ExtraRootBridges) * sizeof *Bridges); if (Bridges == NULL) { DEBUG ((EFI_D_ERROR, "%a: %r\n", __FUNCTION__, EFI_OUT_OF_RESOURCES)); return NULL; } Initialized = 0; // // The "main" root bus is always there. // LastRootBridgeNumber = 0; // // Scan all other root buses. If function 0 of any device on a bus returns a // VendorId register value different from all-bits-one, then that bus is // alive. // for (RootBridgeNumber = 1; RootBridgeNumber <= PCI_MAX_BUS && Initialized < ExtraRootBridges; ++RootBridgeNumber) { UINTN Device; for (Device = 0; Device <= PCI_MAX_DEVICE; ++Device) { if (PciRead16 (PCI_LIB_ADDRESS (RootBridgeNumber, Device, 0, PCI_VENDOR_ID_OFFSET)) != MAX_UINT16) { break; } } if (Device <= PCI_MAX_DEVICE) { // // Found the next root bus. We can now install the *previous* one, // because now we know how big a bus number range *that* one has, for any // subordinate buses that might exist behind PCI bridges hanging off it. // Status = InitRootBridge ((UINT8)LastRootBridgeNumber, (UINT8)(RootBridgeNumber - 1), &Bridges[Initialized]); if (EFI_ERROR (Status)) { goto FreeBridges; } ++Initialized; LastRootBridgeNumber = RootBridgeNumber; } } // // Install the last root bus (which might be the only, ie. main, root bus, if // we've found no extra root buses). // Status = InitRootBridge ((UINT8)LastRootBridgeNumber, PCI_MAX_BUS, &Bridges[Initialized]); if (EFI_ERROR (Status)) { goto FreeBridges; } ++Initialized; *Count = Initialized; return Bridges; FreeBridges: while (Initialized > 0) { --Initialized; UninitRootBridge (&Bridges[Initialized]); } FreePool (Bridges); return NULL; }
EFI_STATUS EFIAPI InitializeQemuRamfb ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_DEVICE_PATH_PROTOCOL *RamfbDevicePath; EFI_DEVICE_PATH_PROTOCOL *GopDevicePath; VOID *DevicePath; VENDOR_DEVICE_PATH VendorDeviceNode; ACPI_ADR_DEVICE_PATH AcpiDeviceNode; EFI_STATUS Status; EFI_PHYSICAL_ADDRESS FbBase; UINTN FbSize, MaxFbSize, Pages; UINTN FwCfgSize; UINTN Index; if (!QemuFwCfgIsAvailable ()) { DEBUG ((DEBUG_INFO, "Ramfb: no FwCfg\n")); return EFI_NOT_FOUND; } Status = QemuFwCfgFindFile ("etc/ramfb", &mRamfbFwCfgItem, &FwCfgSize); if (EFI_ERROR (Status)) { return EFI_NOT_FOUND; } if (FwCfgSize != sizeof (RAMFB_CONFIG)) { DEBUG ((DEBUG_ERROR, "Ramfb: FwCfg size mismatch (expected %lu, got %lu)\n", (UINT64)sizeof (RAMFB_CONFIG), (UINT64)FwCfgSize)); return EFI_PROTOCOL_ERROR; } MaxFbSize = 0; for (Index = 0; Index < ARRAY_SIZE (mQemuRamfbModeInfo); Index++) { mQemuRamfbModeInfo[Index].PixelsPerScanLine = mQemuRamfbModeInfo[Index].HorizontalResolution; mQemuRamfbModeInfo[Index].PixelFormat = PixelBlueGreenRedReserved8BitPerColor; FbSize = RAMFB_BPP * mQemuRamfbModeInfo[Index].HorizontalResolution * mQemuRamfbModeInfo[Index].VerticalResolution; if (MaxFbSize < FbSize) { MaxFbSize = FbSize; } DEBUG ((DEBUG_INFO, "Ramfb: Mode %lu: %ux%u, %lu kB\n", (UINT64)Index, mQemuRamfbModeInfo[Index].HorizontalResolution, mQemuRamfbModeInfo[Index].VerticalResolution, (UINT64)(FbSize / 1024))); } Pages = EFI_SIZE_TO_PAGES (MaxFbSize); MaxFbSize = EFI_PAGES_TO_SIZE (Pages); FbBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateReservedPages (Pages); if (FbBase == 0) { DEBUG ((DEBUG_ERROR, "Ramfb: memory allocation failed\n")); return EFI_OUT_OF_RESOURCES; } DEBUG ((DEBUG_INFO, "Ramfb: Framebuffer at 0x%lx, %lu kB, %lu pages\n", (UINT64)FbBase, (UINT64)(MaxFbSize / 1024), (UINT64)Pages)); mQemuRamfbMode.FrameBufferSize = MaxFbSize; mQemuRamfbMode.FrameBufferBase = FbBase; // // 800 x 600 // QemuRamfbGraphicsOutputSetMode (&mQemuRamfbGraphicsOutput, 1); // // ramfb vendor devpath // VendorDeviceNode.Header.Type = HARDWARE_DEVICE_PATH; VendorDeviceNode.Header.SubType = HW_VENDOR_DP; CopyGuid (&VendorDeviceNode.Guid, &gQemuRamfbGuid); SetDevicePathNodeLength (&VendorDeviceNode.Header, sizeof (VENDOR_DEVICE_PATH)); RamfbDevicePath = AppendDevicePathNode (NULL, (EFI_DEVICE_PATH_PROTOCOL *) &VendorDeviceNode); if (RamfbDevicePath == NULL) { Status = EFI_OUT_OF_RESOURCES; goto FreeFramebuffer; } Status = gBS->InstallMultipleProtocolInterfaces ( &mRamfbHandle, &gEfiDevicePathProtocolGuid, RamfbDevicePath, NULL ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Ramfb: install Ramfb Vendor DevicePath failed: %r\n", Status)); goto FreeRamfbDevicePath; } // // gop devpath + protocol // AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH; AcpiDeviceNode.Header.SubType = ACPI_ADR_DP; AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR ( 1, // DeviceIdScheme 0, // HeadId 0, // NonVgaOutput 1, // BiosCanDetect 0, // VendorInfo ACPI_ADR_DISPLAY_TYPE_EXTERNAL_DIGITAL, // Type 0, // Port 0 // Index ); SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH)); GopDevicePath = AppendDevicePathNode (RamfbDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode); if (GopDevicePath == NULL) { Status = EFI_OUT_OF_RESOURCES; goto FreeRamfbHandle; } Status = gBS->InstallMultipleProtocolInterfaces ( &mGopHandle, &gEfiDevicePathProtocolGuid, GopDevicePath, &gEfiGraphicsOutputProtocolGuid, &mQemuRamfbGraphicsOutput, NULL ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Ramfb: install GOP DevicePath failed: %r\n", Status)); goto FreeGopDevicePath; } Status = gBS->OpenProtocol ( mRamfbHandle, &gEfiDevicePathProtocolGuid, &DevicePath, gImageHandle, mGopHandle, EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Ramfb: OpenProtocol failed: %r\n", Status)); goto FreeGopHandle; } return EFI_SUCCESS; FreeGopHandle: gBS->UninstallMultipleProtocolInterfaces ( mGopHandle, &gEfiDevicePathProtocolGuid, GopDevicePath, &gEfiGraphicsOutputProtocolGuid, &mQemuRamfbGraphicsOutput, NULL ); FreeGopDevicePath: FreePool (GopDevicePath); FreeRamfbHandle: gBS->UninstallMultipleProtocolInterfaces ( mRamfbHandle, &gEfiDevicePathProtocolGuid, RamfbDevicePath, NULL ); FreeRamfbDevicePath: FreePool (RamfbDevicePath); FreeFramebuffer: FreePages ((VOID*)(UINTN)mQemuRamfbMode.FrameBufferBase, Pages); return Status; }