From: Laszlo Ersek <lersek@redhat.com>
To: edk2-devel@lists.01.org
Cc: "Anthony Perard" <anthony.perard@citrix.com>,
"Ard Biesheuvel" <ard.biesheuvel@linaro.org>,
"Jordan Justen" <jordan.l.justen@intel.com>,
"Julien Grall" <julien.grall@linaro.org>,
"Philippe Mathieu-Daudé" <philmd@redhat.com>,
yuchenlin <yuchenlin@synology.com>
Subject: [PATCH 3/4] Reapply "OvmfPkg/QemuVideoDxe: VMWare SVGA device support"
Date: Fri, 9 Nov 2018 20:44:18 +0100 [thread overview]
Message-ID: <20181109194419.24750-4-lersek@redhat.com> (raw)
In-Reply-To: <20181109194419.24750-1-lersek@redhat.com>
This reverts commit 98856a724c2acdc0094220d4de615a557dad0f88, reapplying
c137d95081690d4877fbeb5f1856972e84ac32f2.
Note that the commit now being reverted is technically correct; the only
reason we're reverting it is because it should not have been pushed past
the Soft Feature Freeze for the edk2-stable201811 tag.
Cc: Anthony Perard <anthony.perard@citrix.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Julien Grall <julien.grall@linaro.org>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Cc: yuchenlin <yuchenlin@synology.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1319
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
OvmfPkg/QemuVideoDxe/Qemu.h | 29 ++++
OvmfPkg/QemuVideoDxe/Driver.c | 135 ++++++++++++++++-
OvmfPkg/QemuVideoDxe/Gop.c | 65 +++++++-
OvmfPkg/QemuVideoDxe/Initialize.c | 157 ++++++++++++++++++++
4 files changed, 379 insertions(+), 7 deletions(-)
diff --git a/OvmfPkg/QemuVideoDxe/Qemu.h b/OvmfPkg/QemuVideoDxe/Qemu.h
index d7da761705a1..bc49f867a4ff 100644
--- a/OvmfPkg/QemuVideoDxe/Qemu.h
+++ b/OvmfPkg/QemuVideoDxe/Qemu.h
@@ -92,6 +92,7 @@ typedef enum {
QEMU_VIDEO_CIRRUS_5446,
QEMU_VIDEO_BOCHS,
QEMU_VIDEO_BOCHS_MMIO,
+ QEMU_VIDEO_VMWARE_SVGA,
} QEMU_VIDEO_VARIANT;
typedef struct {
@@ -116,10 +117,13 @@ typedef struct {
//
UINTN MaxMode;
QEMU_VIDEO_MODE_DATA *ModeData;
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *VmwareSvgaModeInfo;
QEMU_VIDEO_VARIANT Variant;
FRAME_BUFFER_CONFIGURE *FrameBufferBltConfigure;
UINTN FrameBufferBltConfigureSize;
+ UINT8 FrameBufferVramBarIndex;
+ UINT16 VmwareSvgaBasePort;
} QEMU_VIDEO_PRIVATE_DATA;
///
@@ -503,9 +507,34 @@ QemuVideoBochsModeSetup (
BOOLEAN IsQxl
);
+EFI_STATUS
+QemuVideoVmwareSvgaModeSetup (
+ QEMU_VIDEO_PRIVATE_DATA *Private
+ );
+
VOID
InstallVbeShim (
IN CONST CHAR16 *CardName,
IN EFI_PHYSICAL_ADDRESS FrameBufferBase
);
+
+VOID
+VmwareSvgaWrite (
+ QEMU_VIDEO_PRIVATE_DATA *Private,
+ UINT16 Register,
+ UINT32 Value
+ );
+
+UINT32
+VmwareSvgaRead (
+ QEMU_VIDEO_PRIVATE_DATA *Private,
+ UINT16 Register
+ );
+
+VOID
+InitializeVmwareSvgaGraphicsMode (
+ QEMU_VIDEO_PRIVATE_DATA *Private,
+ QEMU_VIDEO_BOCHS_MODES *ModeData
+ );
+
#endif
diff --git a/OvmfPkg/QemuVideoDxe/Driver.c b/OvmfPkg/QemuVideoDxe/Driver.c
index 2304afd1e686..73eb2cad0584 100644
--- a/OvmfPkg/QemuVideoDxe/Driver.c
+++ b/OvmfPkg/QemuVideoDxe/Driver.c
@@ -14,8 +14,10 @@
**/
-#include "Qemu.h"
+#include <IndustryStandard/VmwareSvga.h>
#include <IndustryStandard/Acpi.h>
+#include "Qemu.h"
+#include "UnalignedIoInternal.h"
EFI_DRIVER_BINDING_PROTOCOL gQemuVideoDriverBinding = {
QemuVideoControllerDriverSupported,
@@ -69,6 +71,12 @@ QEMU_VIDEO_CARD gQemuVideoCardList[] = {
0x1050,
QEMU_VIDEO_BOCHS_MMIO,
L"QEMU VirtIO VGA"
+ },{
+ PCI_CLASS_DISPLAY_VGA,
+ VMWARE_PCI_VENDOR_ID_VMWARE,
+ VMWARE_PCI_DEVICE_ID_VMWARE_SVGA2,
+ QEMU_VIDEO_VMWARE_SVGA,
+ L"QEMU VMWare SVGA"
},{
0 /* end of list */
}
@@ -256,6 +264,7 @@ QemuVideoControllerDriverStart (
goto ClosePciIo;
}
Private->Variant = Card->Variant;
+ Private->FrameBufferVramBarIndex = PCI_BAR_IDX0;
//
// IsQxl is based on the detected Card->Variant, which at a later point might
@@ -330,6 +339,58 @@ QemuVideoControllerDriverStart (
}
}
+ //
+ // Check if accessing Vmware SVGA interface works
+ //
+ if (Private->Variant == QEMU_VIDEO_VMWARE_SVGA) {
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *IoDesc;
+ UINT32 TargetId;
+ UINT32 SvgaIdRead;
+
+ IoDesc = NULL;
+ Status = Private->PciIo->GetBarAttributes (
+ Private->PciIo,
+ PCI_BAR_IDX0,
+ NULL,
+ (VOID**) &IoDesc
+ );
+ if (EFI_ERROR (Status) ||
+ IoDesc->ResType != ACPI_ADDRESS_SPACE_TYPE_IO ||
+ IoDesc->AddrRangeMin > MAX_UINT16 + 1 - (VMWARE_SVGA_VALUE_PORT + 4)) {
+ if (IoDesc != NULL) {
+ FreePool (IoDesc);
+ }
+ Status = EFI_DEVICE_ERROR;
+ goto RestoreAttributes;
+ }
+ Private->VmwareSvgaBasePort = (UINT16) IoDesc->AddrRangeMin;
+ FreePool (IoDesc);
+
+ TargetId = VMWARE_SVGA_ID_2;
+ while (TRUE) {
+ VmwareSvgaWrite (Private, VmwareSvgaRegId, TargetId);
+ SvgaIdRead = VmwareSvgaRead (Private, VmwareSvgaRegId);
+ if ((SvgaIdRead == TargetId) || (TargetId <= VMWARE_SVGA_ID_0)) {
+ break;
+ }
+ TargetId--;
+ }
+
+ if (SvgaIdRead != TargetId) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "QemuVideo: QEMU_VIDEO_VMWARE_SVGA ID mismatch "
+ "(got 0x%x, base address 0x%x)\n",
+ SvgaIdRead,
+ Private->VmwareSvgaBasePort
+ ));
+ Status = EFI_DEVICE_ERROR;
+ goto RestoreAttributes;
+ }
+
+ Private->FrameBufferVramBarIndex = PCI_BAR_IDX1;
+ }
+
//
// Get ParentDevicePath
//
@@ -385,6 +446,9 @@ QemuVideoControllerDriverStart (
case QEMU_VIDEO_BOCHS:
Status = QemuVideoBochsModeSetup (Private, IsQxl);
break;
+ case QEMU_VIDEO_VMWARE_SVGA:
+ Status = QemuVideoVmwareSvgaModeSetup (Private);
+ break;
default:
ASSERT (FALSE);
Status = EFI_DEVICE_ERROR;
@@ -446,6 +510,9 @@ DestructQemuVideoGraphics:
FreeModeData:
FreePool (Private->ModeData);
+ if (Private->VmwareSvgaModeInfo != NULL) {
+ FreePool (Private->VmwareSvgaModeInfo);
+ }
UninstallGopDevicePath:
gBS->UninstallProtocolInterface (Private->Handle,
@@ -567,6 +634,9 @@ QemuVideoControllerDriverStop (
);
FreePool (Private->ModeData);
+ if (Private->VmwareSvgaModeInfo != NULL) {
+ FreePool (Private->VmwareSvgaModeInfo);
+ }
gBS->UninstallProtocolInterface (Private->Handle,
&gEfiDevicePathProtocolGuid, Private->GopDevicePath);
FreePool (Private->GopDevicePath);
@@ -764,7 +834,7 @@ ClearScreen (
Private->PciIo->Mem.Write (
Private->PciIo,
EfiPciIoWidthFillUint32,
- 0,
+ Private->FrameBufferVramBarIndex,
0,
0x400000 >> 2,
&Color
@@ -901,6 +971,38 @@ BochsRead (
return Data;
}
+VOID
+VmwareSvgaWrite (
+ QEMU_VIDEO_PRIVATE_DATA *Private,
+ UINT16 Register,
+ UINT32 Value
+ )
+{
+ UnalignedIoWrite32 (
+ Private->VmwareSvgaBasePort + VMWARE_SVGA_INDEX_PORT,
+ Register
+ );
+ UnalignedIoWrite32 (
+ Private->VmwareSvgaBasePort + VMWARE_SVGA_VALUE_PORT,
+ Value
+ );
+}
+
+UINT32
+VmwareSvgaRead (
+ QEMU_VIDEO_PRIVATE_DATA *Private,
+ UINT16 Register
+ )
+{
+ UnalignedIoWrite32 (
+ Private->VmwareSvgaBasePort + VMWARE_SVGA_INDEX_PORT,
+ Register
+ );
+ return UnalignedIoRead32 (
+ Private->VmwareSvgaBasePort + VMWARE_SVGA_VALUE_PORT
+ );
+}
+
VOID
VgaOutb (
QEMU_VIDEO_PRIVATE_DATA *Private,
@@ -955,6 +1057,35 @@ InitializeBochsGraphicsMode (
ClearScreen (Private);
}
+VOID
+InitializeVmwareSvgaGraphicsMode (
+ QEMU_VIDEO_PRIVATE_DATA *Private,
+ QEMU_VIDEO_BOCHS_MODES *ModeData
+ )
+{
+ UINT32 Capabilities;
+
+ VmwareSvgaWrite (Private, VmwareSvgaRegWidth, ModeData->Width);
+ VmwareSvgaWrite (Private, VmwareSvgaRegHeight, ModeData->Height);
+
+ Capabilities = VmwareSvgaRead (
+ Private,
+ VmwareSvgaRegCapabilities
+ );
+ if ((Capabilities & VMWARE_SVGA_CAP_8BIT_EMULATION) != 0) {
+ VmwareSvgaWrite (
+ Private,
+ VmwareSvgaRegBitsPerPixel,
+ ModeData->ColorDepth
+ );
+ }
+
+ VmwareSvgaWrite (Private, VmwareSvgaRegEnable, 1);
+
+ SetDefaultPalette (Private);
+ ClearScreen (Private);
+}
+
EFI_STATUS
EFIAPI
InitializeQemuVideo (
diff --git a/OvmfPkg/QemuVideoDxe/Gop.c b/OvmfPkg/QemuVideoDxe/Gop.c
index d490fa7a2e6f..c9941ef138bd 100644
--- a/OvmfPkg/QemuVideoDxe/Gop.c
+++ b/OvmfPkg/QemuVideoDxe/Gop.c
@@ -13,6 +13,7 @@
**/
+#include <IndustryStandard/VmwareSvga.h>
#include "Qemu.h"
STATIC
@@ -78,6 +79,46 @@ QemuVideoCompleteModeData (
return EFI_SUCCESS;
}
+STATIC
+EFI_STATUS
+QemuVideoVmwareSvgaCompleteModeData (
+ IN QEMU_VIDEO_PRIVATE_DATA *Private,
+ OUT EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode
+ )
+{
+ EFI_STATUS Status;
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *FrameBufDesc;
+ UINT32 BytesPerLine, FbOffset, BytesPerPixel;
+
+ Info = Mode->Info;
+ CopyMem (Info, &Private->VmwareSvgaModeInfo[Mode->Mode], sizeof (*Info));
+ BytesPerPixel = Private->ModeData[Mode->Mode].ColorDepth / 8;
+ BytesPerLine = Info->PixelsPerScanLine * BytesPerPixel;
+
+ FbOffset = VmwareSvgaRead (Private, VmwareSvgaRegFbOffset);
+
+ Status = Private->PciIo->GetBarAttributes (
+ Private->PciIo,
+ PCI_BAR_IDX1,
+ NULL,
+ (VOID**) &FrameBufDesc
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Mode->FrameBufferBase = FrameBufDesc->AddrRangeMin + FbOffset;
+ Mode->FrameBufferSize = BytesPerLine * Info->VerticalResolution;
+ Mode->FrameBufferSize = EFI_PAGES_TO_SIZE (
+ EFI_SIZE_TO_PAGES (Mode->FrameBufferSize)
+ );
+
+ FreePool (FrameBufDesc);
+ return Status;
+}
+
+
//
// Graphics Output Protocol Member Functions
//
@@ -126,10 +167,14 @@ Routine Description:
*SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
- ModeData = &Private->ModeData[ModeNumber];
- (*Info)->HorizontalResolution = ModeData->HorizontalResolution;
- (*Info)->VerticalResolution = ModeData->VerticalResolution;
- QemuVideoCompleteModeInfo (ModeData, *Info);
+ if (Private->Variant == QEMU_VIDEO_VMWARE_SVGA) {
+ CopyMem (*Info, &Private->VmwareSvgaModeInfo[ModeNumber], sizeof (**Info));
+ } else {
+ ModeData = &Private->ModeData[ModeNumber];
+ (*Info)->HorizontalResolution = ModeData->HorizontalResolution;
+ (*Info)->VerticalResolution = ModeData->VerticalResolution;
+ QemuVideoCompleteModeInfo (ModeData, *Info);
+ }
return EFI_SUCCESS;
}
@@ -179,6 +224,12 @@ Routine Description:
case QEMU_VIDEO_BOCHS:
InitializeBochsGraphicsMode (Private, &QemuVideoBochsModes[ModeData->InternalModeIndex]);
break;
+ case QEMU_VIDEO_VMWARE_SVGA:
+ InitializeVmwareSvgaGraphicsMode (
+ Private,
+ &QemuVideoBochsModes[ModeData->InternalModeIndex]
+ );
+ break;
default:
ASSERT (FALSE);
return EFI_DEVICE_ERROR;
@@ -189,7 +240,11 @@ Routine Description:
This->Mode->Info->VerticalResolution = ModeData->VerticalResolution;
This->Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
- QemuVideoCompleteModeData (Private, This->Mode);
+ if (Private->Variant == QEMU_VIDEO_VMWARE_SVGA) {
+ QemuVideoVmwareSvgaCompleteModeData (Private, This->Mode);
+ } else {
+ QemuVideoCompleteModeData (Private, This->Mode);
+ }
//
// Re-initialize the frame buffer configure when mode changes.
diff --git a/OvmfPkg/QemuVideoDxe/Initialize.c b/OvmfPkg/QemuVideoDxe/Initialize.c
index d5d8cfef9661..357124d628e7 100644
--- a/OvmfPkg/QemuVideoDxe/Initialize.c
+++ b/OvmfPkg/QemuVideoDxe/Initialize.c
@@ -13,6 +13,7 @@
**/
+#include <IndustryStandard/VmwareSvga.h>
#include "Qemu.h"
@@ -346,3 +347,159 @@ QemuVideoBochsModeSetup (
return EFI_SUCCESS;
}
+EFI_STATUS
+QemuVideoVmwareSvgaModeSetup (
+ QEMU_VIDEO_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+ UINT32 FbSize;
+ UINT32 MaxWidth, MaxHeight;
+ UINT32 Capabilities;
+ UINT32 BitsPerPixel;
+ UINT32 Index;
+ QEMU_VIDEO_MODE_DATA *ModeData;
+ QEMU_VIDEO_BOCHS_MODES *VideoMode;
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *ModeInfo;
+
+ VmwareSvgaWrite (Private, VmwareSvgaRegEnable, 0);
+
+ Private->ModeData =
+ AllocatePool (sizeof (Private->ModeData[0]) * QEMU_VIDEO_BOCHS_MODE_COUNT);
+ if (Private->ModeData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ModeDataAllocError;
+ }
+
+ Private->VmwareSvgaModeInfo =
+ AllocatePool (
+ sizeof (Private->VmwareSvgaModeInfo[0]) * QEMU_VIDEO_BOCHS_MODE_COUNT
+ );
+ if (Private->VmwareSvgaModeInfo == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ModeInfoAllocError;
+ }
+
+ FbSize = VmwareSvgaRead (Private, VmwareSvgaRegFbSize);
+ MaxWidth = VmwareSvgaRead (Private, VmwareSvgaRegMaxWidth);
+ MaxHeight = VmwareSvgaRead (Private, VmwareSvgaRegMaxHeight);
+ Capabilities = VmwareSvgaRead (Private, VmwareSvgaRegCapabilities);
+ if ((Capabilities & VMWARE_SVGA_CAP_8BIT_EMULATION) != 0) {
+ BitsPerPixel = VmwareSvgaRead (
+ Private,
+ VmwareSvgaRegHostBitsPerPixel
+ );
+ VmwareSvgaWrite (
+ Private,
+ VmwareSvgaRegBitsPerPixel,
+ BitsPerPixel
+ );
+ } else {
+ BitsPerPixel = VmwareSvgaRead (
+ Private,
+ VmwareSvgaRegBitsPerPixel
+ );
+ }
+
+ if (FbSize == 0 ||
+ MaxWidth == 0 ||
+ MaxHeight == 0 ||
+ BitsPerPixel == 0 ||
+ BitsPerPixel % 8 != 0) {
+ Status = EFI_DEVICE_ERROR;
+ goto Rollback;
+ }
+
+ ModeData = Private->ModeData;
+ ModeInfo = Private->VmwareSvgaModeInfo;
+ VideoMode = &QemuVideoBochsModes[0];
+ for (Index = 0; Index < QEMU_VIDEO_BOCHS_MODE_COUNT; Index++) {
+ UINTN RequiredFbSize;
+
+ RequiredFbSize = (UINTN) VideoMode->Width * VideoMode->Height *
+ (BitsPerPixel / 8);
+ if (RequiredFbSize <= FbSize &&
+ VideoMode->Width <= MaxWidth &&
+ VideoMode->Height <= MaxHeight) {
+ UINT32 BytesPerLine;
+ UINT32 RedMask, GreenMask, BlueMask, PixelMask;
+
+ VmwareSvgaWrite (
+ Private,
+ VmwareSvgaRegWidth,
+ VideoMode->Width
+ );
+ VmwareSvgaWrite (
+ Private,
+ VmwareSvgaRegHeight,
+ VideoMode->Height
+ );
+
+ ModeData->InternalModeIndex = Index;
+ ModeData->HorizontalResolution = VideoMode->Width;
+ ModeData->VerticalResolution = VideoMode->Height;
+ ModeData->ColorDepth = BitsPerPixel;
+
+ //
+ // Setting VmwareSvgaRegWidth/VmwareSvgaRegHeight actually changes
+ // the device's display mode, so we save all properties of each mode up
+ // front to avoid inadvertent mode changes later.
+ //
+ ModeInfo->Version = 0;
+ ModeInfo->HorizontalResolution = ModeData->HorizontalResolution;
+ ModeInfo->VerticalResolution = ModeData->VerticalResolution;
+
+ ModeInfo->PixelFormat = PixelBitMask;
+
+ RedMask = VmwareSvgaRead (Private, VmwareSvgaRegRedMask);
+ ModeInfo->PixelInformation.RedMask = RedMask;
+
+ GreenMask = VmwareSvgaRead (Private, VmwareSvgaRegGreenMask);
+ ModeInfo->PixelInformation.GreenMask = GreenMask;
+
+ BlueMask = VmwareSvgaRead (Private, VmwareSvgaRegBlueMask);
+ ModeInfo->PixelInformation.BlueMask = BlueMask;
+
+ //
+ // Reserved mask is whatever bits in the pixel not containing RGB data,
+ // so start with binary 1s for every bit in the pixel, then mask off
+ // bits already used for RGB. Special case 32 to avoid undefined
+ // behaviour in the shift.
+ //
+ if (BitsPerPixel == 32) {
+ if (BlueMask == 0xff && GreenMask == 0xff00 && RedMask == 0xff0000) {
+ ModeInfo->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
+ } else if (BlueMask == 0xff0000 &&
+ GreenMask == 0xff00 &&
+ RedMask == 0xff) {
+ ModeInfo->PixelFormat = PixelRedGreenBlueReserved8BitPerColor;
+ }
+ PixelMask = MAX_UINT32;
+ } else {
+ PixelMask = (1u << BitsPerPixel) - 1;
+ }
+ ModeInfo->PixelInformation.ReservedMask =
+ PixelMask & ~(RedMask | GreenMask | BlueMask);
+
+ BytesPerLine = VmwareSvgaRead (Private, VmwareSvgaRegBytesPerLine);
+ ModeInfo->PixelsPerScanLine = BytesPerLine / (BitsPerPixel / 8);
+
+ ModeData++;
+ ModeInfo++;
+ }
+ VideoMode++;
+ }
+ Private->MaxMode = ModeData - Private->ModeData;
+ return EFI_SUCCESS;
+
+Rollback:
+ FreePool (Private->VmwareSvgaModeInfo);
+ Private->VmwareSvgaModeInfo = NULL;
+
+ModeInfoAllocError:
+ FreePool (Private->ModeData);
+ Private->ModeData = NULL;
+
+ModeDataAllocError:
+ return Status;
+}
--
2.19.1.3.g30247aa5d201
next prev parent reply other threads:[~2018-11-09 19:44 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-11-09 19:44 [PATCH 0/4] OvmfPkg: revert some untimely pushed VMW SVGA reverts Laszlo Ersek
2018-11-09 19:44 ` [PATCH 1/4] Reapply "OvmfPkg: VMWare SVGA display device register definitions" Laszlo Ersek
2018-11-09 19:44 ` [PATCH 2/4] Reapply "OvmfPkg/QemuVideoDxe: Helper functions for unaligned port I/O." Laszlo Ersek
2018-11-09 19:44 ` Laszlo Ersek [this message]
2018-11-09 19:44 ` [PATCH 4/4] Reapply "OvmfPkg/QemuVideoDxe: list "UnalignedIoInternal.h" in the INF file" Laszlo Ersek
2018-11-09 20:07 ` [PATCH 0/4] OvmfPkg: revert some untimely pushed VMW SVGA reverts Philippe Mathieu-Daudé
2018-11-09 20:31 ` Ard Biesheuvel
2018-11-10 0:33 ` yuchenlin
2018-11-12 11:36 ` Laszlo Ersek
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20181109194419.24750-4-lersek@redhat.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox