/** Selects a firmware configuration item for reading. Following this call, any data read from this item will start from the beginning of the configuration item's data. @param[in] QemuFwCfgItem Firmware Configuration item to read **/ VOID EFIAPI QemuFwCfgSelectItem ( IN FIRMWARE_CONFIG_ITEM QemuFwCfgItem ) { if (QemuFwCfgIsAvailable ()) { MmioWrite16 (mFwCfgSelectorAddress, SwapBytes16 ((UINT16)QemuFwCfgItem)); } }
BOOLEAN QemuDetected ( VOID ) { if (!QemuFwCfgIsAvailable ()) { return FALSE; } return TRUE; }
RETURN_STATUS EFIAPI QemuFwCfgInitialize ( VOID ) { EFI_STATUS Status; FDT_CLIENT_PROTOCOL *FdtClient; CONST UINT64 *Reg; UINT32 RegSize; UINTN AddressCells, SizeCells; UINT64 FwCfgSelectorAddress; UINT64 FwCfgSelectorSize; UINT64 FwCfgDataAddress; UINT64 FwCfgDataSize; UINT64 FwCfgDmaAddress; UINT64 FwCfgDmaSize; Status = gBS->LocateProtocol (&gFdtClientProtocolGuid, NULL, (VOID **)&FdtClient); ASSERT_EFI_ERROR (Status); Status = FdtClient->FindCompatibleNodeReg (FdtClient, "qemu,fw-cfg-mmio", (CONST VOID **)&Reg, &AddressCells, &SizeCells, &RegSize); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_WARN, "%a: No 'qemu,fw-cfg-mmio' compatible DT node found (Status == %r)\n", __FUNCTION__, Status)); return EFI_SUCCESS; } ASSERT (AddressCells == 2); ASSERT (SizeCells == 2); ASSERT (RegSize == 2 * sizeof (UINT64)); FwCfgDataAddress = SwapBytes64 (Reg[0]); FwCfgDataSize = 8; FwCfgSelectorAddress = FwCfgDataAddress + FwCfgDataSize; FwCfgSelectorSize = 2; // // The following ASSERT()s express // // Address + Size - 1 <= MAX_UINTN // // for both registers, that is, that the last byte in each MMIO range is // expressible as a MAX_UINTN. The form below is mathematically // equivalent, and it also prevents any unsigned overflow before the // comparison. // ASSERT (FwCfgSelectorAddress <= MAX_UINTN - FwCfgSelectorSize + 1); ASSERT (FwCfgDataAddress <= MAX_UINTN - FwCfgDataSize + 1); mFwCfgSelectorAddress = FwCfgSelectorAddress; mFwCfgDataAddress = FwCfgDataAddress; DEBUG ((EFI_D_INFO, "Found FwCfg @ 0x%Lx/0x%Lx\n", FwCfgSelectorAddress, FwCfgDataAddress)); if (SwapBytes64 (Reg[1]) >= 0x18) { FwCfgDmaAddress = FwCfgDataAddress + 0x10; FwCfgDmaSize = 0x08; // // See explanation above. // ASSERT (FwCfgDmaAddress <= MAX_UINTN - FwCfgDmaSize + 1); DEBUG ((EFI_D_INFO, "Found FwCfg DMA @ 0x%Lx\n", FwCfgDmaAddress)); } else { FwCfgDmaAddress = 0; } if (QemuFwCfgIsAvailable ()) { UINT32 Signature; QemuFwCfgSelectItem (QemuFwCfgItemSignature); Signature = QemuFwCfgRead32 (); if (Signature == SIGNATURE_32 ('Q', 'E', 'M', 'U')) { // // For DMA support, we require the DTB to advertise the register, and the // feature bitmap (which we read without DMA) to confirm the feature. // if (FwCfgDmaAddress != 0) { UINT32 Features; QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion); Features = QemuFwCfgRead32 (); if ((Features & FW_CFG_F_DMA) != 0) { mFwCfgDmaAddress = FwCfgDmaAddress; InternalQemuFwCfgReadBytes = DmaReadBytes; } } } else { mFwCfgSelectorAddress = 0; mFwCfgDataAddress = 0; } } return RETURN_SUCCESS; }
EFI_STATUS TryRunningQemuKernel ( VOID ) { EFI_STATUS Status; UINTN KernelSize; UINTN KernelInitialSize; VOID *KernelBuf; UINTN SetupSize; VOID *SetupBuf; UINTN CommandLineSize; CHAR8 *CommandLine; UINTN InitrdSize; VOID* InitrdData; SetupBuf = NULL; SetupSize = 0; KernelBuf = NULL; KernelInitialSize = 0; CommandLine = NULL; CommandLineSize = 0; InitrdData = NULL; InitrdSize = 0; if (!QemuFwCfgIsAvailable ()) { return EFI_NOT_FOUND; } QemuFwCfgSelectItem (QemuFwCfgItemKernelSize); KernelSize = (UINTN) QemuFwCfgRead64 (); QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupSize); SetupSize = (UINTN) QemuFwCfgRead64 (); if (KernelSize == 0 || SetupSize == 0) { DEBUG ((EFI_D_INFO, "qemu -kernel was not used.\n")); return EFI_NOT_FOUND; } SetupBuf = LoadLinuxAllocateKernelSetupPages (EFI_SIZE_TO_PAGES (SetupSize)); if (SetupBuf == NULL) { DEBUG ((EFI_D_ERROR, "Unable to allocate memory for kernel setup!\n")); return EFI_OUT_OF_RESOURCES; } DEBUG ((EFI_D_INFO, "Setup size: 0x%x\n", (UINT32) SetupSize)); DEBUG ((EFI_D_INFO, "Reading kernel setup image ...")); QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupData); QemuFwCfgReadBytes (SetupSize, SetupBuf); DEBUG ((EFI_D_INFO, " [done]\n")); Status = LoadLinuxCheckKernelSetup (SetupBuf, SetupSize); if (EFI_ERROR (Status)) { goto FreeAndReturn; } Status = LoadLinuxInitializeKernelSetup (SetupBuf); if (EFI_ERROR (Status)) { goto FreeAndReturn; } KernelInitialSize = LoadLinuxGetKernelSize (SetupBuf, KernelSize); if (KernelInitialSize == 0) { Status = EFI_UNSUPPORTED; goto FreeAndReturn; } KernelBuf = LoadLinuxAllocateKernelPages ( SetupBuf, EFI_SIZE_TO_PAGES (KernelInitialSize)); if (KernelBuf == NULL) { DEBUG ((EFI_D_ERROR, "Unable to allocate memory for kernel!\n")); Status = EFI_OUT_OF_RESOURCES; goto FreeAndReturn; } DEBUG ((EFI_D_INFO, "Kernel size: 0x%x\n", (UINT32) KernelSize)); DEBUG ((EFI_D_INFO, "Reading kernel image ...")); QemuFwCfgSelectItem (QemuFwCfgItemKernelData); QemuFwCfgReadBytes (KernelSize, KernelBuf); DEBUG ((EFI_D_INFO, " [done]\n")); QemuFwCfgSelectItem (QemuFwCfgItemCommandLineSize); CommandLineSize = (UINTN) QemuFwCfgRead64 (); if (CommandLineSize > 0) { CommandLine = LoadLinuxAllocateCommandLinePages ( EFI_SIZE_TO_PAGES (CommandLineSize)); QemuFwCfgSelectItem (QemuFwCfgItemCommandLineData); QemuFwCfgReadBytes (CommandLineSize, CommandLine); } else { CommandLine = NULL; } Status = LoadLinuxSetCommandLine (SetupBuf, CommandLine); if (EFI_ERROR (Status)) { goto FreeAndReturn; } QemuFwCfgSelectItem (QemuFwCfgItemInitrdSize); InitrdSize = (UINTN) QemuFwCfgRead64 (); if (InitrdSize > 0) { InitrdData = LoadLinuxAllocateInitrdPages ( SetupBuf, EFI_SIZE_TO_PAGES (InitrdSize) ); DEBUG ((EFI_D_INFO, "Initrd size: 0x%x\n", (UINT32) InitrdSize)); DEBUG ((EFI_D_INFO, "Reading initrd image ...")); QemuFwCfgSelectItem (QemuFwCfgItemInitrdData); QemuFwCfgReadBytes (InitrdSize, InitrdData); DEBUG ((EFI_D_INFO, " [done]\n")); } else { InitrdData = NULL; } Status = LoadLinuxSetInitrd (SetupBuf, InitrdData, InitrdSize); if (EFI_ERROR (Status)) { goto FreeAndReturn; } Status = LoadLinux (KernelBuf, SetupBuf); FreeAndReturn: if (SetupBuf != NULL) { FreePages (SetupBuf, EFI_SIZE_TO_PAGES (SetupSize)); } if (KernelBuf != NULL) { FreePages (KernelBuf, EFI_SIZE_TO_PAGES (KernelInitialSize)); } if (CommandLine != NULL) { FreePages (CommandLine, EFI_SIZE_TO_PAGES (CommandLineSize)); } if (InitrdData != NULL) { FreePages (InitrdData, EFI_SIZE_TO_PAGES (InitrdSize)); } return Status; }
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; }