Blame SOURCES/0028-Add-m-and-M-options-to-support-address-range-mirror.patch

38ab4d
From 745b6244b2b81d7698520646089657ff9f121da2 Mon Sep 17 00:00:00 2001
38ab4d
From: "Luck, Tony" <tony.luck@intel.com>
38ab4d
Date: Tue, 9 Jun 2015 10:14:58 -0700
38ab4d
Subject: [PATCH 28/31] Add -m and -M options to support address range mirror
38ab4d
38ab4d
BIOS and OS pass messages for address range mirror using a pair of
38ab4d
UEFI variables:
38ab4d
38ab4d
   MirrorCurrent: Written by BIOS to tell the OS that the platform supports
38ab4d
	address range mirror and to say whether mirroring was set up using
38ab4d
	the desired parameters
38ab4d
   MirrorRequest: Written by OS to tell BIOS new paramters to use on next boot
38ab4d
38ab4d
This is documented in the RAS validation guide for memory address range
38ab4d
mirroring for the Xeon E7-v3 family:
38ab4d
38ab4d
  https://software.intel.com/sites/default/files/managed/43/6a/Memory%20Address%20Range%20Mirroring%20Validation%20Guide.pdf
38ab4d
38ab4d
Signed-off-by: Tony Luck <tony.luck@intel.com>
38ab4d
---
38ab4d
 src/efibootmgr/efibootmgr.c | 143 +++++++++++++++++++++++++++++++++++++++++++-
38ab4d
 src/include/efi.h           |  15 +++++
38ab4d
 src/include/efibootmgr.h    |   5 ++
38ab4d
 3 files changed, 162 insertions(+), 1 deletion(-)
38ab4d
38ab4d
diff --git a/src/efibootmgr/efibootmgr.c b/src/efibootmgr/efibootmgr.c
38ab4d
index 73faffa..7cb87fa 100644
38ab4d
--- a/src/efibootmgr/efibootmgr.c
38ab4d
+++ b/src/efibootmgr/efibootmgr.c
38ab4d
@@ -948,8 +948,114 @@ set_active_state()
38ab4d
 	return -1;
38ab4d
 }
38ab4d
 
38ab4d
+static int
38ab4d
+get_mirror(int which, int *below4g, int *above4g, int *mirrorstatus)
38ab4d
+{
38ab4d
+	int rc;
38ab4d
+	uint8_t *data;
38ab4d
+	ADDRESS_RANGE_MIRROR_VARIABLE_DATA *abm;
38ab4d
+	size_t data_size;
38ab4d
+	uint32_t attributes;
38ab4d
+	char *name;
38ab4d
 
38ab4d
+	if (which)
38ab4d
+		name = ADDRESS_RANGE_MIRROR_VARIABLE_REQUEST;
38ab4d
+	else
38ab4d
+		name = ADDRESS_RANGE_MIRROR_VARIABLE_CURRENT;
38ab4d
+
38ab4d
+	rc = efi_get_variable(ADDRESS_RANGE_MIRROR_VARIABLE_GUID, name,
38ab4d
+				&data, &data_size, &attributes);
38ab4d
+	if (rc == 0) {
38ab4d
+		abm = (ADDRESS_RANGE_MIRROR_VARIABLE_DATA *)data;
38ab4d
+		if (!which && abm->mirror_version != MIRROR_VERSION) {
38ab4d
+			fprintf(stderr, "** Warning ** : unrecognised version for memory mirror i/f\n");
38ab4d
+			return 2;
38ab4d
+		}
38ab4d
+		*below4g = abm->mirror_memory_below_4gb;
38ab4d
+		*above4g = abm->mirror_amount_above_4gb;
38ab4d
+		*mirrorstatus = abm->mirror_status;
38ab4d
+	}
38ab4d
+	return rc;
38ab4d
+}
38ab4d
 
38ab4d
+static int
38ab4d
+set_mirror(int below4g, int above4g)
38ab4d
+{
38ab4d
+	int s, status, rc;
38ab4d
+	uint8_t *data;
38ab4d
+	ADDRESS_RANGE_MIRROR_VARIABLE_DATA abm;
38ab4d
+	size_t data_size;
38ab4d
+	uint32_t attributes;
38ab4d
+	int oldbelow4g, oldabove4g;
38ab4d
+
38ab4d
+	if ((s = get_mirror(0, &oldbelow4g, &oldabove4g, &status)) == 0) {
38ab4d
+		if (oldbelow4g == below4g && oldabove4g == above4g)
38ab4d
+			return 0;
38ab4d
+	} else {
38ab4d
+		fprintf(stderr, "** Warning ** : platform does not support memory mirror\n");
38ab4d
+		return s;
38ab4d
+	}
38ab4d
+
38ab4d
+	data = (uint8_t *)&abm;
38ab4d
+	data_size = sizeof (abm);
38ab4d
+	attributes = EFI_VARIABLE_NON_VOLATILE
38ab4d
+		| EFI_VARIABLE_BOOTSERVICE_ACCESS
38ab4d
+		| EFI_VARIABLE_RUNTIME_ACCESS;
38ab4d
+
38ab4d
+	abm.mirror_version = MIRROR_VERSION;
38ab4d
+	abm.mirror_amount_above_4gb = opts.set_mirror_hi ? above4g : oldabove4g;
38ab4d
+	abm.mirror_memory_below_4gb = opts.set_mirror_lo ? below4g : oldbelow4g;
38ab4d
+	abm.mirror_status = 0;
38ab4d
+	data = (uint8_t *)&abm;
38ab4d
+	rc = efi_set_variable(ADDRESS_RANGE_MIRROR_VARIABLE_GUID,
38ab4d
+			      ADDRESS_RANGE_MIRROR_VARIABLE_REQUEST, data,
38ab4d
+				data_size, attributes);
38ab4d
+	return rc;
38ab4d
+}
38ab4d
+
38ab4d
+static void
38ab4d
+show_mirror(void)
38ab4d
+{
38ab4d
+	int status;
38ab4d
+	int below4g, above4g;
38ab4d
+	int rbelow4g, rabove4g;
38ab4d
+
38ab4d
+	if (get_mirror(0, &below4g, &above4g, &status) == 0) {
38ab4d
+		if (status == 0) {
38ab4d
+			printf("MirroredPercentageAbove4G: %d.%.2d\n", above4g/100, above4g%100);
38ab4d
+			printf("MirrorMemoryBelow4GB: %s\n", below4g ? "true" : "false");
38ab4d
+		} else {
38ab4d
+			printf("MirrorStatus: ");
38ab4d
+			switch (status) {
38ab4d
+			case 1:
38ab4d
+				printf("Platform does not support address range mirror\n");
38ab4d
+				break;
38ab4d
+			case 2:
38ab4d
+				printf("Invalid version number\n");
38ab4d
+				break;
38ab4d
+			case 3:
38ab4d
+				printf("MirroredMemoryAbove4GB > 50.00%%\n");
38ab4d
+				break;
38ab4d
+			case 4:
38ab4d
+				printf("DIMM configuration does not allow mirror\n");
38ab4d
+				break;
38ab4d
+			case 5:
38ab4d
+				printf("OEM specific method\n");
38ab4d
+				break;
38ab4d
+			default:
38ab4d
+				printf("%u\n", status);
38ab4d
+				break;
38ab4d
+			}
38ab4d
+			printf("DesiredMirroredPercentageAbove4G: %d.%.2d\n", above4g/100, above4g%100);
38ab4d
+			printf("DesiredMirrorMemoryBelow4GB: %s\n", below4g ? "true" : "false");
38ab4d
+		}
38ab4d
+	}
38ab4d
+	if ((get_mirror(1, &rbelow4g, &rabove4g, &status) == 0) &&
38ab4d
+		(above4g != rabove4g || below4g != rbelow4g)) {
38ab4d
+		printf("RequestMirroredPercentageAbove4G: %d.%.2d\n", rabove4g/100, rabove4g%100);
38ab4d
+		printf("RequestMirrorMemoryBelow4GB: %s\n", rbelow4g ? "true" : "false");
38ab4d
+	}
38ab4d
+}
38ab4d
 
38ab4d
 static void
38ab4d
 usage()
38ab4d
@@ -970,6 +1076,8 @@ usage()
38ab4d
 	printf("\t-i | --iface name     create a netboot entry for the named interface\n");
38ab4d
 	printf("\t-l | --loader name     (defaults to \\EFI\\redhat\\shim.efi)\n");
38ab4d
 	printf("\t-L | --label label     Boot manager display label (defaults to \"Linux\")\n");
38ab4d
+	printf("\t-m | --mirror-below-4G t|f mirror memory below 4GB\n");
38ab4d
+	printf("\t-M | --mirror-above-4G X percentage memory to mirror above 4GB\n");
38ab4d
 	printf("\t-n | --bootnext XXXX   set BootNext to XXXX (hex)\n");
38ab4d
 	printf("\t-N | --delete-bootnext delete BootNext\n");
38ab4d
 	printf("\t-o | --bootorder XXXX,YYYY,ZZZZ,...     explicitly set BootOrder (hex)\n");
38ab4d
@@ -1010,6 +1118,7 @@ parse_opts(int argc, char **argv)
38ab4d
 {
38ab4d
 	int c, rc;
38ab4d
 	unsigned int num;
38ab4d
+	float fnum;
38ab4d
 	int option_index = 0;
38ab4d
 
38ab4d
 	while (1)
38ab4d
@@ -1032,6 +1141,8 @@ parse_opts(int argc, char **argv)
38ab4d
 			{"keep",                   no_argument, 0, 'k'},
38ab4d
 			{"loader",           required_argument, 0, 'l'},
38ab4d
 			{"label",            required_argument, 0, 'L'},
38ab4d
+			{"mirror-below-4G",  required_argument, 0, 'm'},
38ab4d
+			{"mirror-above-4G",  required_argument, 0, 'M'},
38ab4d
 			{"bootnext",         required_argument, 0, 'n'},
38ab4d
 			{"delete-bootnext",        no_argument, 0, 'N'},
38ab4d
 			{"bootorder",        required_argument, 0, 'o'},
38ab4d
@@ -1052,7 +1163,7 @@ parse_opts(int argc, char **argv)
38ab4d
 		};
38ab4d
 
38ab4d
 		c = getopt_long (argc, argv,
38ab4d
-				 "AaBb:cDd:e:E:gH:i:l:L:n:No:Op:qt:TuU:v::Vw"
38ab4d
+				 "AaBb:cDd:e:E:gH:i:l:L:M:m:n:No:Op:qt:TuU:v::Vw"
38ab4d
 				 "@:h",
38ab4d
 				 long_options, &option_index);
38ab4d
 		if (c == -1)
38ab4d
@@ -1158,6 +1269,31 @@ parse_opts(int argc, char **argv)
38ab4d
 		case 'L':
38ab4d
 			opts.label = optarg;
38ab4d
 			break;
38ab4d
+		case 'm':
38ab4d
+			opts.set_mirror_lo = 1;
38ab4d
+			switch (optarg[0]) {
38ab4d
+			case '1': case 'y': case 't':
38ab4d
+				opts.below4g = 1;
38ab4d
+				break;
38ab4d
+			case '0': case 'n': case 'f':
38ab4d
+				opts.below4g = 0;
38ab4d
+				break;
38ab4d
+			default:
38ab4d
+				fprintf (stderr,"invalid boolean value %s\n",optarg);
38ab4d
+				exit(1);
38ab4d
+			}
38ab4d
+			break;
38ab4d
+		case 'M':
38ab4d
+			opts.set_mirror_hi = 1;
38ab4d
+			rc = sscanf(optarg, "%f", &fnum);
38ab4d
+			if (rc == 1 && fnum <= 50) {
38ab4d
+				opts.above4g = fnum * 100; /* percent to basis points */
38ab4d
+			}
38ab4d
+			else {
38ab4d
+				fprintf (stderr,"invalid numeric value %s\n",optarg);
38ab4d
+				exit(1);
38ab4d
+			}
38ab4d
+			break;
38ab4d
 		case 'N':
38ab4d
 			opts.delete_bootnext = 1;
38ab4d
 			break;
38ab4d
@@ -1370,6 +1506,10 @@ main(int argc, char **argv)
38ab4d
 			err(14, "Could not set Timeout");
38ab4d
 	}
38ab4d
 
38ab4d
+	if (opts.set_mirror_lo || opts.set_mirror_hi) {
38ab4d
+		ret=set_mirror(opts.below4g, opts.above4g);
38ab4d
+	}
38ab4d
+
38ab4d
 	if (!opts.quiet && ret == 0) {
38ab4d
 		num = read_boot_u16("BootNext");
38ab4d
 		if (num != -1 ) {
38ab4d
@@ -1385,6 +1525,7 @@ main(int argc, char **argv)
38ab4d
 		}
38ab4d
 		show_boot_order();
38ab4d
 		show_boot_vars();
38ab4d
+		show_mirror();
38ab4d
 	}
38ab4d
 	free_vars(&boot_entry_list);
38ab4d
 	free_array(boot_names);
38ab4d
diff --git a/src/include/efi.h b/src/include/efi.h
38ab4d
index ec25be9..d95bf4e 100644
38ab4d
--- a/src/include/efi.h
38ab4d
+++ b/src/include/efi.h
38ab4d
@@ -309,6 +309,9 @@ typedef struct {
38ab4d
 /* Used for ACPI _HID */
38ab4d
 #define EISAID_PNP0A03 0xa0341d0
38ab4d
 
38ab4d
+#define ADDRESS_RANGE_MIRROR_VARIABLE_GUID \
38ab4d
+EFI_GUID( 0x7b9be2e0, 0xe28a, 0x4197, 0xad3e, 0x32, 0xf0, 0x62, 0xf9, 0x46, 0x2c)
38ab4d
+
38ab4d
 /* Exported functions */
38ab4d
 
38ab4d
 extern EFI_DEVICE_PATH *load_option_path(EFI_LOAD_OPTION *option);
38ab4d
@@ -318,4 +321,16 @@ extern ssize_t make_linux_load_option(uint8_t **data, size_t *data_size);
38ab4d
 extern int append_extra_args(uint8_t **data, size_t *data_size);
38ab4d
 
38ab4d
 
38ab4d
+typedef struct {
38ab4d
+	uint8_t		mirror_version;
38ab4d
+	uint8_t		mirror_memory_below_4gb;
38ab4d
+	uint16_t	mirror_amount_above_4gb;
38ab4d
+	uint8_t		mirror_status;
38ab4d
+} __attribute__((packed)) ADDRESS_RANGE_MIRROR_VARIABLE_DATA;
38ab4d
+
38ab4d
+#define        MIRROR_VERSION  1
38ab4d
+
38ab4d
+#define ADDRESS_RANGE_MIRROR_VARIABLE_CURRENT "MirrorCurrent"
38ab4d
+#define ADDRESS_RANGE_MIRROR_VARIABLE_REQUEST "MirrorRequest"
38ab4d
+
38ab4d
 #endif /* EFI_H */
38ab4d
diff --git a/src/include/efibootmgr.h b/src/include/efibootmgr.h
38ab4d
index b978caf..6196b75 100644
38ab4d
--- a/src/include/efibootmgr.h
38ab4d
+++ b/src/include/efibootmgr.h
38ab4d
@@ -40,6 +40,8 @@ typedef struct {
38ab4d
 	int bootnext;
38ab4d
 	int verbose;
38ab4d
 	int active;
38ab4d
+	int below4g;
38ab4d
+	int above4g;
38ab4d
 	int deduplicate;
38ab4d
 	int64_t acpi_hid;
38ab4d
 	int64_t acpi_uid;
38ab4d
@@ -54,6 +56,9 @@ typedef struct {
38ab4d
 	unsigned int forcegpt:1;
38ab4d
 	unsigned int set_timeout:1;
38ab4d
 	unsigned int delete_timeout:1;
38ab4d
+	unsigned int set_mirror_lo:1;
38ab4d
+	unsigned int set_mirror_hi:1;
38ab4d
+	unsigned int no_boot_order:1;
38ab4d
 	unsigned short int timeout;
38ab4d
 } efibootmgr_opt_t;
38ab4d
 
38ab4d
-- 
38ab4d
2.7.4
38ab4d