public inbox for linux-efi@vger.kernel.org
 help / color / mirror / Atom feed
From: Dave Young <dyoung-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
To: linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Cc: mjg59-1xO5oi07KQx4cg9Nei1l7Q@public.gmane.org,
	msalter-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org,
	linux-efi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	toshi.kani-VXdhtT5mjnY@public.gmane.org,
	matt-HNK1S37rvNbeXh+fF434Mdi2O/JbrIOy@public.gmane.org,
	greg-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org,
	x86-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
	kexec-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	leif.lindholm-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org,
	James.Bottomley-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org,
	horms-/R6kz+dDXgpPR4JQBCEnsQ@public.gmane.org,
	bp-Gina5bIWoIWzQB+pC5nmwQ@public.gmane.org,
	ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org,
	hpa-YMNOUZJC4hwAvxtiuMwx3w@public.gmane.org,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org,
	mingo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
	vgoyal-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org
Subject: [PATCH v6 09/14] efi: passing kexec necessary efi data via setup_data
Date: Mon, 16 Dec 2013 17:30:30 +0800	[thread overview]
Message-ID: <1387186235-15972-10-git-send-email-dyoung@redhat.com> (raw)
In-Reply-To: <1387186235-15972-1-git-send-email-dyoung-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>

Add a new setup_data type SETUP_EFI for kexec use.
Passing the saved fw_vendor, runtime, config tables and efi runtime mappings.

When entering virtual mode, directly mapping the efi runtime ragions which
we passed in previously. And skip the step to call SetVirtualAddressMap.

Specially for HP z420 workstation we need save the smbios physical address.
The kernel boot sequence proceeds in the following order.  Step 2
requires efi.smbios to be the physical address.  However, I found that on
HP z420 EFI system table has a virtual address of SMBIOS in step 1.  Hence,
we need set it back to the physical address with the smbios in
efi_setup_data.  (When it is still the physical address, it simply sets
the same value.)

1. efi_init() - Set efi.smbios from EFI system table
2. dmi_scan_machine() - Temporary map efi.smbios to access SMBIOS table
3. efi_enter_virtual_mode() - Map EFI ranges

Tested on ovmf+qemu, lenovo thinkpad, a dell laptop and an
HP z420 workstation.

v2: refresh based on previous patch changes, code cleanup.
v3: use ioremap instead of phys_to_virt for efi_setup
v5: improve some code structure per comments from Matt
    Boris: improve code structure, spell fix, etc.
    Improve changelog from Toshi.
    change the variable efi_setup to the physical address of efi setup_data
    instead of the ioremapped virt address
v6: Boris: Documentation fixes
           move parse_efi_setup to efi_$(BITS).c
    Matt: check return value of efi_reuse_config

Signed-off-by: Dave Young <dyoung-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
 arch/x86/include/asm/efi.h            |  12 +++
 arch/x86/include/uapi/asm/bootparam.h |   1 +
 arch/x86/kernel/setup.c               |   3 +
 arch/x86/platform/efi/efi.c           | 192 +++++++++++++++++++++++++++++-----
 arch/x86/platform/efi/efi_32.c        |   1 +
 arch/x86/platform/efi/efi_64.c        |   5 +
 6 files changed, 190 insertions(+), 24 deletions(-)

diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 9fbaeb2..4f81328 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -133,6 +133,18 @@ extern void efi_sync_low_kernel_mappings(void);
 extern void efi_setup_page_tables(void);
 extern void __init old_map_region(efi_memory_desc_t *md);
 
+struct efi_setup_data {
+	u64 fw_vendor;
+	u64 runtime;
+	u64 tables;
+	u64 smbios;
+	u64 reserved[8];
+	efi_memory_desc_t map[0];
+};
+
+extern u64 efi_setup;
+extern void parse_efi_setup(u64 phys_addr);
+
 #ifdef CONFIG_EFI
 
 static inline bool efi_is_native(void)
diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
index 9c3733c..64fe421 100644
--- a/arch/x86/include/uapi/asm/bootparam.h
+++ b/arch/x86/include/uapi/asm/bootparam.h
@@ -6,6 +6,7 @@
 #define SETUP_E820_EXT			1
 #define SETUP_DTB			2
 #define SETUP_PCI			3
+#define SETUP_EFI			4
 
 /* ram_size flags */
 #define RAMDISK_IMAGE_START_MASK	0x07FF
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index cb233bc..b2b54cd 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -447,6 +447,9 @@ static void __init parse_setup_data(void)
 		case SETUP_DTB:
 			add_dtb(pa_data);
 			break;
+		case SETUP_EFI:
+			parse_efi_setup(pa_data);
+			break;
 		default:
 			break;
 		}
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 11b110f9..e8739aa 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -78,6 +78,7 @@ static __initdata efi_config_table_type_t arch_tables[] = {
 
 static void *efi_runtime_map;
 static int nr_efi_runtime_map;
+u64 efi_setup; /* efi setup_data physical address */
 
 /*
  * Returns 1 if 'facility' is enabled, 0 otherwise.
@@ -115,7 +116,6 @@ static int __init setup_storage_paranoia(char *arg)
 }
 early_param("efi_no_storage_paranoia", setup_storage_paranoia);
 
-
 static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
 {
 	unsigned long flags;
@@ -494,18 +494,28 @@ static int __init efi_systab_init(void *phys)
 {
 	if (efi_enabled(EFI_64BIT)) {
 		efi_system_table_64_t *systab64;
+		struct efi_setup_data *data = NULL;
 		u64 tmp = 0;
 
+		if (efi_setup) {
+			data = early_memremap(efi_setup, sizeof(*data));
+			if (!data)
+				return -ENOMEM;
+		}
 		systab64 = early_memremap((unsigned long)phys,
 					 sizeof(*systab64));
 		if (systab64 == NULL) {
 			pr_err("Couldn't map the system table!\n");
+			if (data)
+				early_memunmap(data, sizeof(*data));
 			return -ENOMEM;
 		}
 
 		efi_systab.hdr = systab64->hdr;
-		efi_systab.fw_vendor = systab64->fw_vendor;
-		tmp |= systab64->fw_vendor;
+
+		efi_systab.fw_vendor = data ? (unsigned long)data->fw_vendor :
+					      systab64->fw_vendor;
+		tmp |= efi_systab.fw_vendor;
 		efi_systab.fw_revision = systab64->fw_revision;
 		efi_systab.con_in_handle = systab64->con_in_handle;
 		tmp |= systab64->con_in_handle;
@@ -519,15 +529,20 @@ static int __init efi_systab_init(void *phys)
 		tmp |= systab64->stderr_handle;
 		efi_systab.stderr = systab64->stderr;
 		tmp |= systab64->stderr;
-		efi_systab.runtime = (void *)(unsigned long)systab64->runtime;
-		tmp |= systab64->runtime;
+		efi_systab.runtime = data ?
+				     (void *)(unsigned long)data->runtime :
+				     (void *)(unsigned long)systab64->runtime;
+		tmp |= (unsigned long)efi_systab.runtime;
 		efi_systab.boottime = (void *)(unsigned long)systab64->boottime;
 		tmp |= systab64->boottime;
 		efi_systab.nr_tables = systab64->nr_tables;
-		efi_systab.tables = systab64->tables;
-		tmp |= systab64->tables;
+		efi_systab.tables = data ? (unsigned long)data->tables :
+					   systab64->tables;
+		tmp |= efi_systab.tables;
 
 		early_memunmap(systab64, sizeof(*systab64));
+		if (data)
+			early_memunmap(data, sizeof(*data));
 #ifdef CONFIG_X86_32
 		if (tmp >> 32) {
 			pr_err("EFI data located above 4GB, disabling EFI.\n");
@@ -631,6 +646,81 @@ static int __init efi_memmap_init(void)
 	return 0;
 }
 
+/*
+ * A number of config table entries get remapped to virtual addresses
+ * after entering EFI virtual mode. However, the kexec kernel requires
+ * their physical addresses therefore we pass them via setup_data and
+ * correct those entries to their respective physical addresses here.
+ *
+ * Currently only handles smbios which is necessary for some firmware
+ * implementation.
+ */
+static int __init efi_reuse_config(u64 tables, int nr_tables)
+{
+	int i, sz, ret = 0;
+	void *p, *tablep;
+	struct efi_setup_data *data;
+
+	if (!efi_setup)
+		return 0;
+
+	if (!efi_enabled(EFI_64BIT))
+		return 0;
+
+	data = early_memremap(efi_setup, sizeof(*data));
+	if (!data) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	if (!data->smbios)
+		goto out_memremap;
+
+	sz = sizeof(efi_config_table_64_t);
+
+	p = tablep = early_memremap(tables, nr_tables * sz);
+	if (!p) {
+		pr_err("Could not map Configuration table!\n");
+		ret = -ENOMEM;
+		goto out_memremap;
+	}
+
+	for (i = 0; i < efi.systab->nr_tables; i++) {
+		efi_guid_t guid;
+
+		guid = ((efi_config_table_64_t *)p)->guid;
+
+		if (!efi_guidcmp(guid, SMBIOS_TABLE_GUID))
+			((efi_config_table_64_t *)p)->table = data->smbios;
+		p += sz;
+	}
+	early_memunmap(tablep, nr_tables * sz);
+
+out_memremap:
+	early_memunmap(data, sizeof(*data));
+out:
+	return ret;
+}
+
+static void __init efi_setup_init(void)
+{
+	struct setup_data *sd;
+
+	if (!efi_setup)
+		return;
+
+	sd = early_memremap(efi_setup, sizeof(struct setup_data));
+	if (!sd) {
+		pr_warn("early_memremap setup_data failed\n");
+		efi_setup = 0;
+		return;
+	}
+	efi_setup += sizeof(struct setup_data);
+	nr_efi_runtime_map = (sd->len - sizeof(struct efi_setup_data)) /
+			     sizeof(efi_memory_desc_t);
+	early_memunmap(sd, sizeof(struct setup_data));
+}
+
 void __init efi_init(void)
 {
 	efi_char16_t *c16;
@@ -638,6 +728,7 @@ void __init efi_init(void)
 	int i = 0;
 	void *tmp;
 
+	efi_setup_init();
 #ifdef CONFIG_X86_32
 	if (boot_params.efi_info.efi_systab_hi ||
 	    boot_params.efi_info.efi_memmap_hi) {
@@ -676,6 +767,9 @@ void __init efi_init(void)
 		efi.systab->hdr.revision >> 16,
 		efi.systab->hdr.revision & 0xffff, vendor);
 
+	if (efi_reuse_config(efi.systab->tables, efi.systab->nr_tables))
+		return;
+
 	if (efi_config_init(arch_tables))
 		return;
 
@@ -887,6 +981,43 @@ out:
 }
 
 /*
+ * Map efi regions which were passed via setup_data. The virt_addr is a fixed
+ * addr which was used in first kernel of a kexec boot.
+ */
+static int __init map_regions_fixed(void)
+{
+	int i, s, ret = 0;
+	u64 end, systab;
+	unsigned long size;
+	efi_memory_desc_t *md;
+	struct efi_setup_data *data;
+
+	s = sizeof(*data) + nr_efi_runtime_map * sizeof(data->map[0]);
+	data = early_memremap(efi_setup, s);
+	if (!data)
+		return -ENOMEM;
+
+	for (i = 0, md = data->map; i < nr_efi_runtime_map; i++, md++) {
+		efi_map_region_fixed(md); /* FIXME: add error handling */
+		size = md->num_pages << PAGE_SHIFT;
+		end = md->phys_addr + size;
+
+		systab = (u64) (unsigned long) efi_phys.systab;
+		if (md->phys_addr <= systab && systab < end) {
+			systab += md->virt_addr - md->phys_addr;
+			efi.systab = (efi_system_table_t *)(unsigned long)systab;
+		}
+		ret = save_runtime_map(md, i);
+		if (ret)
+			goto out;
+	}
+
+out:
+	early_memunmap(data, s);
+	return ret;
+}
+
+/*
  * This function will switch the EFI runtime services to virtual mode.
  * Essentially, we look through the EFI memmap and map every region that
  * has the runtime attribute bit set in its memory descriptor into the
@@ -902,12 +1033,16 @@ out:
  * so that we're in a different address space when calling a runtime
  * function. For function arguments passing we do copy the PGDs of the
  * kernel page table into ->trampoline_pgd prior to each call.
+ *
+ * Specially for kexec boot, efi runtime maps in previous kernel should
+ * be passed in via setup_data. In that case runtime ranges will be mapped
+ * to the same virtual addresses as the first kernel.
  */
 void __init efi_enter_virtual_mode(void)
 {
 	efi_status_t status;
 	void *new_memmap = NULL;
-	int count = 0;
+	int err, count = 0;
 
 	efi.systab = NULL;
 
@@ -920,12 +1055,19 @@ void __init efi_enter_virtual_mode(void)
 		return;
 	}
 
-	efi_merge_regions();
-
-	new_memmap = efi_map_regions(&count);
-	if (!new_memmap) {
-		pr_err("Error reallocating memory, EFI runtime non-functional!\n");
-		return;
+	if (efi_setup) {
+		err = map_regions_fixed();
+		if (err) {
+			pr_err("Error mapping runtime services, EFI runtime non-functional!\n");
+			return;
+		}
+	} else {
+		efi_merge_regions();
+		new_memmap = efi_map_regions(&count);
+		if (!new_memmap) {
+			pr_err("Error reallocating memory, EFI runtime non-functional!\n");
+			return;
+		}
 	}
 
 #ifdef CONFIG_EFI_RUNTIME_MAP
@@ -938,16 +1080,18 @@ void __init efi_enter_virtual_mode(void)
 	efi_setup_page_tables();
 	efi_sync_low_kernel_mappings();
 
-	status = phys_efi_set_virtual_address_map(
-		memmap.desc_size * count,
-		memmap.desc_size,
-		memmap.desc_version,
-		(efi_memory_desc_t *)__pa(new_memmap));
-
-	if (status != EFI_SUCCESS) {
-		pr_alert("Unable to switch EFI into virtual mode "
-			 "(status=%lx)!\n", status);
-		panic("EFI call to SetVirtualAddressMap() failed!");
+	if (!efi_setup) {
+		status = phys_efi_set_virtual_address_map(
+			memmap.desc_size * count,
+			memmap.desc_size,
+			memmap.desc_version,
+			(efi_memory_desc_t *)__pa(new_memmap));
+
+		if (status != EFI_SUCCESS) {
+			pr_alert("Unable to switch EFI into virtual mode (status=%lx)!\n",
+				 status);
+			panic("EFI call to SetVirtualAddressMap() failed!");
+		}
 	}
 
 	/*
diff --git a/arch/x86/platform/efi/efi_32.c b/arch/x86/platform/efi/efi_32.c
index 7b3ec6e..cb84fef 100644
--- a/arch/x86/platform/efi/efi_32.c
+++ b/arch/x86/platform/efi/efi_32.c
@@ -48,6 +48,7 @@ void __init efi_map_region(efi_memory_desc_t *md)
 }
 
 void __init efi_map_region_fixed(efi_memory_desc_t *md) {}
+void __init parse_efi_setup(u64 phys_addr) {}
 
 void efi_call_phys_prelog(void)
 {
diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c
index ff08cb1..1d6835a 100644
--- a/arch/x86/platform/efi/efi_64.c
+++ b/arch/x86/platform/efi/efi_64.c
@@ -228,3 +228,8 @@ void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size,
 
 	return (void __iomem *)__va(phys_addr);
 }
+
+void __init parse_efi_setup(u64 phys_addr)
+{
+	efi_setup = phys_addr;
+}
-- 
1.8.3.1

  parent reply	other threads:[~2013-12-16  9:30 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-12-16  9:30 [PATCH v6 00/14] kexec kernel efi runtime support Dave Young
2013-12-16  9:30 ` [PATCH v6 01/14] x86/mm: sparse warning fix for early_memremap Dave Young
2013-12-16  9:30 ` [PATCH v6 02/14] efi: Use early_memremap and early_memunmap to fix sparse warnings Dave Young
2013-12-16  9:30 ` [PATCH v6 03/14] efi: remove unused variables in __map_region Dave Young
2013-12-16  9:30 ` [PATCH v6 04/14] efi: add a wrapper function efi_map_region_fixed Dave Young
2013-12-16  9:30 ` [PATCH v6 05/14] efi: reserve boot service fix Dave Young
2013-12-16  9:30 ` [PATCH v6 08/14] efi: export efi runtime memory mapping to sysfs Dave Young
     [not found]   ` <1387186235-15972-9-git-send-email-dyoung-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-12-16 15:09     ` Matt Fleming
     [not found]       ` <20131216150929.GA3873-HNK1S37rvNbeXh+fF434Mdi2O/JbrIOy@public.gmane.org>
2013-12-17  6:13         ` Dave Young
2013-12-17  8:00     ` [PATCH v7 " Dave Young
     [not found] ` <1387186235-15972-1-git-send-email-dyoung-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-12-16  9:30   ` [PATCH v6 06/14] efi: cleanup efi_enter_virtual_mode function Dave Young
2013-12-16  9:30   ` [PATCH v6 07/14] efi: export more efi table variable to sysfs Dave Young
2013-12-16  9:30   ` Dave Young [this message]
     [not found]     ` <1387186235-15972-10-git-send-email-dyoung-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-12-17  8:01       ` [PATCH v7 09/14] efi: passing kexec necessary efi data via setup_data Dave Young
     [not found]         ` <20131217080140.GB12621-je1gSBvt1TcFLmT5oZ11vB/sF2h8X+2i0E9HWUfgJXw@public.gmane.org>
2013-12-17  8:08           ` Dave Young
2013-12-16  9:30   ` [PATCH v6 10/14] efi: only print saved efi runtime maps instead of all memmap ranges for kexec Dave Young
     [not found]     ` <1387186235-15972-11-git-send-email-dyoung-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-12-19 16:41       ` Matt Fleming
     [not found]         ` <20131219164144.GG3145-HNK1S37rvNbeXh+fF434Mdi2O/JbrIOy@public.gmane.org>
2013-12-20  1:35           ` Dave Young
     [not found]             ` <20131220013508.GA3795-je1gSBvt1TcFLmT5oZ11vB/sF2h8X+2i0E9HWUfgJXw@public.gmane.org>
2013-12-20  1:57               ` Dave Young
2013-12-16  9:30   ` [PATCH v6 11/14] x86: add xloadflags bit for efi runtime support on kexec Dave Young
2013-12-16  9:30   ` [PATCH v6 12/14] x86: export x86 boot_params to sysfs Dave Young
2013-12-16  9:30   ` [PATCH v6 13/14] x86: reserve setup_data ranges late after parsing memmap cmdline Dave Young
2013-12-16  9:30   ` [PATCH v6 14/14] x86: kdebugfs do not use __va for getting setup_data virt addr Dave Young
     [not found]     ` <1387186235-15972-15-git-send-email-dyoung-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-12-16 16:35       ` Matt Fleming
     [not found]         ` <20131216163501.GB3873-HNK1S37rvNbeXh+fF434Mdi2O/JbrIOy@public.gmane.org>
2013-12-17  6:24           ` Dave Young
     [not found]             ` <20131217062417.GE6751-je1gSBvt1TcFLmT5oZ11vB/sF2h8X+2i0E9HWUfgJXw@public.gmane.org>
2013-12-17  6:53               ` Dave Young
     [not found]                 ` <20131217065346.GG6751-je1gSBvt1TcFLmT5oZ11vB/sF2h8X+2i0E9HWUfgJXw@public.gmane.org>
2013-12-17 11:24                   ` Matt Fleming
     [not found]                     ` <20131217112452.GA3145-HNK1S37rvNbeXh+fF434Mdi2O/JbrIOy@public.gmane.org>
2013-12-18  9:29                       ` Dave Young

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-all 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=1387186235-15972-10-git-send-email-dyoung@redhat.com \
    --to=dyoung-h+wxahxf7alqt0dzr+alfa@public.gmane.org \
    --cc=James.Bottomley-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org \
    --cc=akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org \
    --cc=bp-Gina5bIWoIWzQB+pC5nmwQ@public.gmane.org \
    --cc=ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org \
    --cc=greg-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org \
    --cc=horms-/R6kz+dDXgpPR4JQBCEnsQ@public.gmane.org \
    --cc=hpa-YMNOUZJC4hwAvxtiuMwx3w@public.gmane.org \
    --cc=kexec-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org \
    --cc=leif.lindholm-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \
    --cc=linux-efi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=matt-HNK1S37rvNbeXh+fF434Mdi2O/JbrIOy@public.gmane.org \
    --cc=mingo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org \
    --cc=mjg59-1xO5oi07KQx4cg9Nei1l7Q@public.gmane.org \
    --cc=msalter-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org \
    --cc=toshi.kani-VXdhtT5mjnY@public.gmane.org \
    --cc=vgoyal-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org \
    --cc=x86-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org \
    /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