public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Jeff Fan <jeff.fan@intel.com>
To: edk2-devel@ml01.01.org
Cc: Michael Kinney <michael.d.kinney@intel.com>,
	Feng Tian <feng.tian@intel.com>,
	Giri P Mudusuru <giri.p.mudusuru@intel.com>,
	Laszlo Ersek <lersek@redhat.com>
Subject: [Patch v4 15/46] UefiCpuPkg/MpInitLib: Add MicrocodeDetect() and load microcode on BSP
Date: Sat, 30 Jul 2016 02:14:41 +0800	[thread overview]
Message-ID: <1469816112-8200-16-git-send-email-jeff.fan@intel.com> (raw)
In-Reply-To: <1469816112-8200-1-git-send-email-jeff.fan@intel.com>

v4:
  1. ProcessorSignature is updated to CPU_MICROCODE_PROCESSOR_SIGNATURE
     instead of UINT32.

Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
---
 UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf      |  1 +
 .../{CpuMpPei => Library/MpInitLib}/Microcode.c    | 77 +++++++++++-----------
 UefiCpuPkg/Library/MpInitLib/MpLib.c               |  5 ++
 UefiCpuPkg/Library/MpInitLib/MpLib.h               | 10 +++
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf      |  1 +
 5 files changed, 57 insertions(+), 37 deletions(-)
 copy UefiCpuPkg/{CpuMpPei => Library/MpInitLib}/Microcode.c (68%)

diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
index e9a2725..03a8994 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
@@ -39,6 +39,7 @@ [Sources.common]
   DxeMpLib.c
   MpLib.c
   MpLib.h
+  Microcode.c
 
 [Packages]
   MdePkg/MdePkg.dec
diff --git a/UefiCpuPkg/CpuMpPei/Microcode.c b/UefiCpuPkg/Library/MpInitLib/Microcode.c
similarity index 68%
copy from UefiCpuPkg/CpuMpPei/Microcode.c
copy to UefiCpuPkg/Library/MpInitLib/Microcode.c
index 4fe6f2d..0fd8e8c 100644
--- a/UefiCpuPkg/CpuMpPei/Microcode.c
+++ b/UefiCpuPkg/Library/MpInitLib/Microcode.c
@@ -12,56 +12,55 @@
 
 **/
 
-#include "CpuMpPei.h"
+#include "MpLib.h"
 
 /**
   Get microcode update signature of currently loaded microcode update.
 
   @return  Microcode signature.
-
 **/
 UINT32
 GetCurrentMicrocodeSignature (
   VOID
   )
 {
-  UINT64 Signature;
+  MSR_IA32_BIOS_SIGN_ID_REGISTER   BiosSignIdMsr;
 
-  AsmWriteMsr64 (EFI_MSR_IA32_BIOS_SIGN_ID, 0);
+  AsmWriteMsr64 (MSR_IA32_BIOS_SIGN_ID, 0);
   AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);
-  Signature = AsmReadMsr64 (EFI_MSR_IA32_BIOS_SIGN_ID);
-  return (UINT32) RShiftU64 (Signature, 32);
+  BiosSignIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_BIOS_SIGN_ID);
+  return BiosSignIdMsr.Bits.MicrocodeUpdateSignature;
 }
 
 /**
   Detect whether specified processor can find matching microcode patch and load it.
 
-  @param PeiCpuMpData        Pointer to PEI CPU MP Data
+  @param[in] PeiCpuMpData        Pointer to PEI CPU MP Data
 **/
 VOID
 MicrocodeDetect (
-  IN PEI_CPU_MP_DATA            *PeiCpuMpData
+  IN CPU_MP_DATA             *CpuMpData
   )
 {
   UINT64                                  MicrocodePatchAddress;
   UINT64                                  MicrocodePatchRegionSize;
   UINT32                                  ExtendedTableLength;
   UINT32                                  ExtendedTableCount;
-  EFI_CPU_MICROCODE_EXTENDED_TABLE        *ExtendedTable;
-  EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;
-  EFI_CPU_MICROCODE_HEADER                *MicrocodeEntryPoint;
+  CPU_MICROCODE_EXTENDED_TABLE            *ExtendedTable;
+  CPU_MICROCODE_EXTENDED_TABLE_HEADER     *ExtendedTableHeader;
+  CPU_MICROCODE_HEADER                    *MicrocodeEntryPoint;
   UINTN                                   MicrocodeEnd;
   UINTN                                   Index;
   UINT8                                   PlatformId;
-  UINT32                                  RegEax;
+  CPUID_VERSION_INFO_EAX                  Eax;
   UINT32                                  CurrentRevision;
   UINT32                                  LatestRevision;
   UINTN                                   TotalSize;
   UINT32                                  CheckSum32;
   BOOLEAN                                 CorrectMicrocode;
-  MICROCODE_INFO                          MicrocodeInfo;
+  VOID                                    *MicrocodeData;
+  MSR_IA32_PLATFORM_ID_REGISTER           PlatformIdMsr;
 
-  ZeroMem (&MicrocodeInfo, sizeof (MICROCODE_INFO));
   MicrocodePatchAddress    = PcdGet64 (PcdCpuMicrocodePatchAddress);
   MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);
   if (MicrocodePatchRegionSize == 0) {
@@ -82,18 +81,19 @@ MicrocodeDetect (
   ExtendedTableLength = 0;
   //
   // Here data of CPUID leafs have not been collected into context buffer, so
-  // GetProcessorCpuid() cannot be used here to retrieve CPUID data.
+  // GetProcessorCpuid() cannot be used here to retrieve sCPUID data.
   //
-  AsmCpuid (CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL);
+  AsmCpuid (CPUID_VERSION_INFO, &Eax.Uint32, NULL, NULL, NULL);
 
   //
   // The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID
   //
-  PlatformId = (UINT8) AsmMsrBitFieldRead64 (EFI_MSR_IA32_PLATFORM_ID, 50, 52);
+  PlatformIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_PLATFORM_ID);
+  PlatformId = (UINT8) PlatformIdMsr.Bits.PlatformId;
 
   LatestRevision = 0;
   MicrocodeEnd = (UINTN) (MicrocodePatchAddress + MicrocodePatchRegionSize);
-  MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchAddress;
+  MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchAddress;
   do {
     //
     // Check if the microcode is for the Cpu and the version is newer
@@ -106,44 +106,49 @@ MicrocodeDetect (
       // because the padding data should not include 0x00000001 and it should be the repeated
       // byte format (like 0xXYXYXYXY....).
       //
-      if (MicrocodeEntryPoint->ProcessorId == RegEax &&
+      if (MicrocodeEntryPoint->ProcessorSignature.Uint32 == Eax.Uint32 &&
           MicrocodeEntryPoint->UpdateRevision > LatestRevision &&
           (MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId))
           ) {
         if (MicrocodeEntryPoint->DataSize == 0) {
-          CheckSum32 = CalculateSum32 ((UINT32 *)MicrocodeEntryPoint, 2048);
+          CheckSum32 = CalculateSum32 ((UINT32 *) MicrocodeEntryPoint, 2048);
         } else {
-          CheckSum32 = CalculateSum32 ((UINT32 *)MicrocodeEntryPoint, MicrocodeEntryPoint->DataSize + sizeof(EFI_CPU_MICROCODE_HEADER));
+          CheckSum32 = CalculateSum32 (
+                         (UINT32 *) MicrocodeEntryPoint,
+                         MicrocodeEntryPoint->DataSize + sizeof (CPU_MICROCODE_HEADER)
+                         );
         }
         if (CheckSum32 == 0) {
           CorrectMicrocode = TRUE;
         }
       } else if ((MicrocodeEntryPoint->DataSize != 0) &&
                  (MicrocodeEntryPoint->UpdateRevision > LatestRevision)) {
-        ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize + sizeof (EFI_CPU_MICROCODE_HEADER));
+        ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize +
+                                sizeof (CPU_MICROCODE_HEADER));
         if (ExtendedTableLength != 0) {
           //
           // Extended Table exist, check if the CPU in support list
           //
-          ExtendedTableHeader = (EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *)((UINT8 *)(MicrocodeEntryPoint) + MicrocodeEntryPoint->DataSize + sizeof (EFI_CPU_MICROCODE_HEADER));
+          ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINT8 *) (MicrocodeEntryPoint)
+                                  + MicrocodeEntryPoint->DataSize + sizeof (CPU_MICROCODE_HEADER));
           //
           // Calculate Extended Checksum
           //
           if ((ExtendedTableLength % 4) == 0) {
-            CheckSum32 = CalculateSum32 ((UINT32 *)ExtendedTableHeader, ExtendedTableLength);
+            CheckSum32 = CalculateSum32 ((UINT32 *) ExtendedTableHeader, ExtendedTableLength);
             if (CheckSum32 == 0) {
               //
               // Checksum correct
               //
               ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;
-              ExtendedTable      = (EFI_CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1);
+              ExtendedTable      = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1);
               for (Index = 0; Index < ExtendedTableCount; Index ++) {
-                CheckSum32 = CalculateSum32 ((UINT32 *)ExtendedTable, sizeof(EFI_CPU_MICROCODE_EXTENDED_TABLE));
+                CheckSum32 = CalculateSum32 ((UINT32 *) ExtendedTable, sizeof(CPU_MICROCODE_EXTENDED_TABLE));
                 if (CheckSum32 == 0) {
                   //
                   // Verify Header
                   //
-                  if ((ExtendedTable->ProcessorSignature == RegEax) &&
+                  if ((ExtendedTable->ProcessorSignature.Uint32 == Eax.Uint32) &&
                       (ExtendedTable->ProcessorFlag & (1 << PlatformId)) ) {
                     //
                     // Find one
@@ -166,7 +171,7 @@ MicrocodeDetect (
       // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
       // find the next possible microcode patch header.
       //
-      MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
+      MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
       continue;
     }
     //
@@ -180,12 +185,10 @@ MicrocodeDetect (
 
     if (CorrectMicrocode) {
       LatestRevision = MicrocodeEntryPoint->UpdateRevision;
-      MicrocodeInfo.MicrocodeData = (VOID *)((UINTN)MicrocodeEntryPoint + sizeof (EFI_CPU_MICROCODE_HEADER));
-      MicrocodeInfo.MicrocodeSize = TotalSize;
-      MicrocodeInfo.ProcessorId = RegEax;
+      MicrocodeData = (VOID *) ((UINTN) MicrocodeEntryPoint + sizeof (CPU_MICROCODE_HEADER));
     }
 
-    MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);
+    MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);
   } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));
 
   if (LatestRevision > CurrentRevision) {
@@ -196,18 +199,18 @@ MicrocodeDetect (
     // revision equal to zero.
     //
     AsmWriteMsr64 (
-      EFI_MSR_IA32_BIOS_UPDT_TRIG,
-      (UINT64) (UINTN) MicrocodeInfo.MicrocodeData
-      );
+        MSR_IA32_BIOS_UPDT_TRIG,
+        (UINT64) (UINTN) MicrocodeData
+        );
     //
     // Get and check new microcode signature
     //
     CurrentRevision = GetCurrentMicrocodeSignature ();
     if (CurrentRevision != LatestRevision) {
-      AcquireSpinLock(&PeiCpuMpData->MpLock);
+      AcquireSpinLock(&CpuMpData->MpLock);
       DEBUG ((EFI_D_ERROR, "Updated microcode signature [0x%08x] does not match \
                 loaded microcode signature [0x%08x]\n", CurrentRevision, LatestRevision));
-      ReleaseSpinLock(&PeiCpuMpData->MpLock);
+      ReleaseSpinLock(&CpuMpData->MpLock);
     }
   }
 }
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index 0832228..7384f5d 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -294,6 +294,11 @@ MpInitLibInitialize (
     CpuMpData->CpuData[Index].StartupApSignal =
       (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);
   }
+  //
+  // Load Microcode on BSP
+  //
+  MicrocodeDetect (CpuMpData);
+  //
   // Store BSP's MTRR setting
   //
   MtrrGetAllMtrrs (&CpuMpData->MtrrTable);
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index a455896..42713f0 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -212,5 +212,15 @@ AsmGetAddressMap (
   OUT MP_ASSEMBLY_ADDRESS_MAP    *AddressMap
   );
 
+/**
+  Detect whether specified processor can find matching microcode patch and load it.
+
+  @param[in] PeiCpuMpData        Pointer to PEI CPU MP Data
+**/
+VOID
+MicrocodeDetect (
+  IN CPU_MP_DATA             *CpuMpData
+  );
+
 #endif
 
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
index c195a38..0c6873d 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
@@ -39,6 +39,7 @@ [Sources.common]
   PeiMpLib.c
   MpLib.c
   MpLib.h
+  Microcode.c
 
 [Packages]
   MdePkg/MdePkg.dec
-- 
2.7.4.windows.1



  parent reply	other threads:[~2016-07-29 18:15 UTC|newest]

Thread overview: 47+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-07-29 18:14 [Patch v4 00/46] MP Initialize Library Jeff Fan
2016-07-29 18:14 ` [Patch v4 01/46] UefiCpuPkg/LocalApic.h: Remove duplicated/conflicted definitions Jeff Fan
2016-07-29 18:14 ` [Patch v4 02/46] UefiCpuPkg/MpInitLib: Add microcode definitions defined in IA32 SDM Jeff Fan
2016-07-29 18:14 ` [Patch v4 03/46] UefiCpuPkg/CpuS3DataDxe: Move StartupVector allocation to EndOfDxe() Jeff Fan
2016-07-29 18:14 ` [Patch v4 04/46] UefiCpuPkg/MpInitLib: Add MP Initialize library class definition Jeff Fan
2016-07-29 18:14 ` [Patch v4 05/46] UefiCpuPkg/MpInitLib: Add two instances PeiMpInitLib and DxeMpInitLib Jeff Fan
2016-07-29 18:14 ` [Patch v4 06/46] UefiCpuPkg/MpInitLib: Add AP assembly code and MP_CPU_EXCHANGE_INFO Jeff Fan
2016-07-29 18:14 ` [Patch v4 07/46] UefiCpuPkg/MpInitLib: Fix typo and clean up the code Jeff Fan
2016-07-29 18:14 ` [Patch v4 08/46] UefiCpuPkg/MpInitLib: Add EnableExecuteDisable in MP_CPU_EXCHANGE_INFO Jeff Fan
2016-07-29 18:14 ` [Patch v4 09/46] UefiCpuPkg/MpInitLib: Add AsmRelocateApLoop() assembly code Jeff Fan
2016-07-29 18:14 ` [Patch v4 10/46] UefiCpuPkg/MpInitLib: Add MP_ASSEMBLY_ADDRESS_MAP Jeff Fan
2016-07-29 18:14 ` [Patch v4 11/46] UefiCpuPkg/MpInitLib: Get ApLoopMode and MointorFilter size Jeff Fan
2016-07-29 18:14 ` [Patch v4 12/46] UefiCpuPkg/MpInitLib: Allocate and initialize memory of MP Data buffer Jeff Fan
2016-07-29 18:14 ` [Patch v4 13/46] UefiCpuPkg/MpInitLib: Initialize CPU_AP_DATA for CPU APs Jeff Fan
2016-07-29 18:14 ` [Patch v4 14/46] UefiCpuPkg/MpInitLib: Add CPU_VOLATILE_REGISTERS & worker functions Jeff Fan
2016-07-29 18:14 ` Jeff Fan [this message]
2016-07-29 18:14 ` [Patch v4 16/46] UefiCpuPkg/MpInitLib: Save CPU MP Data pointer Jeff Fan
2016-07-29 18:14 ` [Patch v4 17/46] UefiCpuPkg/MpInitLib: Register one End of PEI callback function Jeff Fan
2016-07-29 18:14 ` [Patch v4 18/46] UefiCpuPkg/MpInitLib: Register one period event to check APs status Jeff Fan
2016-07-29 18:14 ` [Patch v4 19/46] UefiCpuPkg/MpInitLib: Allocate AP reset vector buffer under 1MB Jeff Fan
2016-07-29 18:14 ` [Patch v4 20/46] UefiCpuPkg/MpInitLib: Add ApCFunction() executed by assembly code Jeff Fan
2016-07-29 18:14 ` [Patch v4 21/46] UefiCpuPkg/MpInitLib: Fill MP_CPU_EXCHANGE_INFO fields Jeff Fan
2016-07-29 18:14 ` [Patch v4 22/46] UefiCpuPkg/MpInitLib: Add WakeUpAP() Jeff Fan
2016-07-29 18:14 ` [Patch v4 23/46] UefiCpuPkg/MpInitLib: Send INIT-SIPI-SIPI to get processor count Jeff Fan
2016-07-29 18:14 ` [Patch v4 24/46] UefiCpuPkg/MpInitLib: Enable x2APIC mode on BSP/APs Jeff Fan
2016-07-29 18:14 ` [Patch v4 25/46] UefiCpuPkg/MpInitLib: Sort processor by ascending order of APIC ID Jeff Fan
2016-07-29 18:14 ` [Patch v4 26/46] UefiCpuPkg/MpInitLib: Skip collect processor count if GUIDed HOB exist Jeff Fan
2016-07-29 18:14 ` [Patch v4 27/46] UefiCpuPkg/MpInitLib: Implementation of MpInitLibGetNumberOfProcessors() Jeff Fan
2016-07-29 18:14 ` [Patch v4 28/46] UefiCpuPkg/MpInitLib: Implementation of MpInitLibGetProcessorInfo() Jeff Fan
2016-07-29 18:14 ` [Patch v4 29/46] UefiCpuPkg/MpInitLib: Implementation of MpInitLibWhoAmI() Jeff Fan
2016-07-29 18:14 ` [Patch v4 30/46] UefiCpuPkg/MpInitLib: Implementation of MpInitLibSwitchBSP() Jeff Fan
2016-07-29 18:14 ` [Patch v4 31/46] UefiCpuPkg/MpInitLib: Implementation of MpInitLibEnableDisableAP() Jeff Fan
2016-07-29 18:14 ` [Patch v4 32/46] UefiCpuPkg/MpInitLib: Check APs Status and update APs status Jeff Fan
2016-07-29 18:14 ` [Patch v4 33/46] UefiCpuPkg/MpInitLib: Implementation of MpInitLibStartupThisAP() Jeff Fan
2016-07-29 18:15 ` [Patch v4 34/46] UefiCpuPkg/MpInitLib: Implementation of MpInitLibStartupAllAPs() Jeff Fan
2016-07-29 18:15 ` [Patch v4 35/46] UefiCpuPkg/MpInitLib: Place APs in safe loop before hand-off to OS Jeff Fan
2016-07-29 18:15 ` [Patch v4 36/46] OvmfPkg: Add MpInitLib reference in DSC files Jeff Fan
2016-07-29 18:15 ` [Patch v4 37/46] QuarkPlatformPkg: " Jeff Fan
2016-07-29 18:15 ` [Patch v4 38/46] UefiCpuPkg/CpuMpPei: Consume MpInitLib to produce CPU MP PPI services Jeff Fan
2016-07-29 18:15 ` [Patch v4 39/46] UefiCpuPkg/CpuMpPei: Remove unused files and codes Jeff Fan
2016-07-29 18:15 ` [Patch v4 40/46] UefiCpuPkg/CpuMpPei: Delete PeiMpServices.c and PeiMpServices.h Jeff Fan
2016-07-29 18:15 ` [Patch v4 41/46] UefiCpuPkg/CpuDxe: Consume MpInitLib to produce CPU MP Protocol services Jeff Fan
2016-07-29 18:15 ` [Patch v4 42/46] UefiCpuPkg/CpuDxe: Move SetMtrrsFromBuffer() location Jeff Fan
2016-07-29 18:15 ` [Patch v4 43/46] UefiCpuPkg/CpuDxe: Remove unused codes and files Jeff Fan
2016-07-29 18:15 ` [Patch v4 44/46] MdePkg/MpService.h: Fixed typo in function header to match PI spec Jeff Fan
2016-07-29 18:15 ` [Patch v4 45/46] MdePkg/MpService.h: Trim whitespace at end of line Jeff Fan
2016-07-29 18:15 ` [Patch v4 46/46] UefiCpuPkg/CpuDxe: Fixed typo in function header to match PI spec Jeff Fan

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=1469816112-8200-16-git-send-email-jeff.fan@intel.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