|
|
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 |
|