Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Leap:42.2:Update
efibootmgr
MARM-add-m-and-M-options.diff
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File MARM-add-m-and-M-options.diff of Package efibootmgr
From f6f14847e1f37ed3b5e05ef830b3db5ea122aa17 Mon Sep 17 00:00:00 2001 From: "Luck, Tony" <tony.luck@intel.com> Date: Tue, 9 Jun 2015 10:14:58 -0700 Subject: [PATCH] Add -m and -M options to support address range mirror BIOS and OS pass messages for address range mirror using a pair of UEFI variables: MirrorCurrent: Written by BIOS to tell the OS that the platform supports address range mirror and to say whether mirroring was set up using the desired parameters MirrorRequest: Written by OS to tell BIOS new paramters to use on next boot This is documented in the RAS validation guide for memory address range mirroring for the Xeon E7-v3 family: https://software.intel.com/sites/default/files/managed/43/6a/Memory%20Address%20Range%20Mirroring%20Validation%20Guide.pdf Signed-off-by: Tony Luck <tony.luck@intel.com> --- src/efibootmgr/efibootmgr.c | 146 +++++++++++++++++++++++++++++++++++++++++++- src/include/efi.h | 14 +++++ src/include/efibootmgr.h | 4 ++ 3 files changed, 163 insertions(+), 1 deletion(-) diff --git a/src/efibootmgr/efibootmgr.c b/src/efibootmgr/efibootmgr.c index a5b5bf9..886f98c 100644 --- a/src/efibootmgr/efibootmgr.c +++ b/src/efibootmgr/efibootmgr.c @@ -878,9 +878,124 @@ set_active_state() return EFI_NOT_FOUND; } +static int +get_mirror(int which, int *below4g, int *above4g, int *mirrorstatus) +{ + int rc; + ADDRESS_RANGE_MIRROR_VARIABLE_DATA *abm; + char *name, name_guid[PATH_MAX]; + efi_guid_t guid; + char text_guid[40]; + efi_variable_t *var; + + if (which) + name = ADDRESS_RANGE_MIRROR_VARIABLE_REQUEST; + else + name = ADDRESS_RANGE_MIRROR_VARIABLE_CURRENT; + + var = malloc(sizeof(var_entry_t)); + guid = ADDRESS_RANGE_MIRROR_VARIABLE_GUID; + efi_guid_unparse(&guid, text_guid); + snprintf(name_guid, sizeof(name_guid), "%s-%s", name, text_guid); + rc = read_variable(name_guid, var); + if (rc == 0) { + abm = (ADDRESS_RANGE_MIRROR_VARIABLE_DATA *) var->Data; + if (!which && abm->mirror_version != MIRROR_VERSION) { + fprintf(stderr, "** Warning ** : unrecognised version for memory mirror i/f\n"); + return 2; + } + *below4g = abm->mirror_memory_below_4gb; + *above4g = abm->mirror_amount_above_4gb; + *mirrorstatus = abm->mirror_status; + } + efichar_from_char(var->VariableName, name, 1024); + return rc; +} + +static int +set_mirror(int below4g, int above4g) +{ + int s, status, rc; + ADDRESS_RANGE_MIRROR_VARIABLE_DATA abm; + int oldbelow4g, oldabove4g; + efi_variable_t *var; + char *name; + + if ((s = get_mirror(0, &oldbelow4g, &oldabove4g, &status)) == 0) { + if (oldbelow4g == below4g && oldabove4g == above4g) + return 0; + } else { + fprintf(stderr, "** Warning ** : platform does not support memory mirror\n"); + return s; + } + + var = malloc(sizeof(var_entry_t)); + memset(var, 0, sizeof(efi_variable_t)); + var->DataSize = sizeof (abm); + memcpy(&(var->Data), (uint8_t *)&abm, var->DataSize); + var->Attributes = EFI_VARIABLE_NON_VOLATILE + | EFI_VARIABLE_BOOTSERVICE_ACCESS + | EFI_VARIABLE_RUNTIME_ACCESS; + + abm.mirror_version = MIRROR_VERSION; + abm.mirror_amount_above_4gb = opts.set_mirror_hi ? above4g : oldabove4g; + abm.mirror_memory_below_4gb = opts.set_mirror_lo ? below4g : oldbelow4g; + abm.mirror_status = 0; + memcpy(&(var->Data), (uint8_t *)&abm, var->DataSize); + var->VendorGuid = ADDRESS_RANGE_MIRROR_VARIABLE_GUID; + name = ADDRESS_RANGE_MIRROR_VARIABLE_REQUEST; + efichar_from_char(var->VariableName, name, 1024); + rc = create_or_edit_variable(var); + return rc; +} + +static void +show_mirror(void) +{ + int status; + int below4g, above4g; + int rbelow4g, rabove4g; + + if (get_mirror(0, &below4g, &above4g, &status) == 0) { + if (status == 0) { + printf("MirroredPercentageAbove4G: %d.%.2d\n", above4g/100, above4g%100); + printf("MirrorMemoryBelow4GB: %s\n", below4g ? "true" : "false"); + } else { + printf("MirrorStatus: "); + switch (status) { + case 1: + printf("Platform does not support address range mirror\n"); + break; + case 2: + printf("Invalid version number\n"); + break; + case 3: + printf("MirroredMemoryAbove4GB > 50.00%%\n"); + break; + case 4: + printf("DIMM configuration does not allow mirror\n"); + break; + case 5: + printf("OEM specific method\n"); + break; + default: + printf("%u\n", status); + break; + } + printf("DesiredMirroredPercentageAbove4G: %d.%.2d\n", above4g/100, above4g%100); + printf("DesiredMirrorMemoryBelow4GB: %s\n", below4g ? "true" : "false"); + } + } + if ((get_mirror(1, &rbelow4g, &rabove4g, &status) == 0) && + (above4g != rabove4g || below4g != rbelow4g)) { + printf("RequestMirroredPercentageAbove4G: %d.%.2d\n", rabove4g/100, rabove4g%100); + printf("RequestMirrorMemoryBelow4GB: %s\n", rbelow4g ? "true" : "false"); + } +} + static void usage() { @@ -901,6 +1010,8 @@ usage() printf("\t-i | --iface name create a netboot entry for the named interface\n"); printf("\t-l | --loader name (defaults to \""DEFAULT_LOADER"\")\n"); printf("\t-L | --label label Boot manager display label (defaults to \"Linux\")\n"); + printf("\t-m | --mirror-below-4G t|f mirror memory below 4GB\n"); + printf("\t-M | --mirror-above-4G X percentage memory to mirror above 4GB\n"); printf("\t-n | --bootnext XXXX set BootNext to XXXX (hex)\n"); printf("\t-N | --delete-bootnext delete BootNext\n"); printf("\t-o | --bootorder XXXX,YYYY,ZZZZ,... explicitly set BootOrder (hex)\n"); @@ -943,6 +1054,7 @@ parse_opts(int argc, char **argv) { int c, num, rc; int option_index = 0; + float fnum; while (1) { @@ -963,6 +1055,8 @@ parse_opts(int argc, char **argv) {"gpt", no_argument, 0, 'g'}, {"loader", required_argument, 0, 'l'}, {"label", required_argument, 0, 'L'}, + {"mirror-below-4G", required_argument, 0, 'm'}, + {"mirror-above-4G", required_argument, 0, 'M'}, {"bootnext", required_argument, 0, 'n'}, {"delete-bootnext", no_argument, 0, 'N'}, {"bootorder", required_argument, 0, 'o'}, @@ -984,7 +1002,7 @@ parse_opts(int argc, char **argv) }; c = getopt_long (argc, argv, - "AaBb:cCd:e:E:gH:i:l:L:n:N" + "AaBb:cCd:e:E:gH:i:l:L:M:m:n:N" "o:Op:P:qt:TuU:v::Vw@:", long_options, &option_index); if (c == -1) @@ -1058,6 +1172,31 @@ parse_opts(int argc, char **argv) case 'L': opts.label = optarg; break; + case 'm': + opts.set_mirror_lo = 1; + switch (optarg[0]) { + case '1': case 'y': case 't': + opts.below4g = 1; + break; + case '0': case 'n': case 'f': + opts.below4g = 0; + break; + default: + fprintf (stderr,"invalid boolean value %s\n",optarg); + exit(1); + } + break; + case 'M': + opts.set_mirror_hi = 1; + rc = sscanf(optarg, "%f", &fnum); + if (rc == 1 && fnum <= 50) { + opts.above4g = fnum * 100; /* percent to basis points */ + } + else { + fprintf (stderr,"invalid numeric value %s\n",optarg); + exit(1); + } + break; case 'N': opts.delete_bootnext = 1; break; @@ -1271,6 +1310,10 @@ main(int argc, char **argv) ret=set_boot_u16("Timeout", opts.timeout); } + if (opts.set_mirror_lo || opts.set_mirror_hi) { + ret=set_mirror(opts.below4g, opts.above4g); + } + if (!opts.quiet && ret == 0) { num = read_boot_u16("BootNext"); if (num != -1 ) { @@ -1286,6 +1429,7 @@ main(int argc, char **argv) } show_boot_order(); show_boot_vars(); + show_mirror(); } else if (ret > 1) { /* only print efi_status_t values as others already have a message! */ fprintf (stderr,"\n\nrequested operation failed: status=%lx\n\n", ret); diff --git a/src/include/efi.h b/src/include/efi.h index b8d3b12..b1e760e 100644 --- a/src/include/efi.h +++ b/src/include/efi.h @@ -83,6 +83,8 @@ EFI_GUID( 0x47c7b227, 0xc42a, 0x11d2, 0x8e, 0x57, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) #define ESP_UNKNOWN_GUID \ EFI_GUID( 0x47c7b226, 0xc42a, 0x11d2, 0x8e, 0x57, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) +#define ADDRESS_RANGE_MIRROR_VARIABLE_GUID \ +EFI_GUID( 0x7b9be2e0, 0xe28a, 0x4197, 0xad, 0x3e, 0x32, 0xf0, 0x62, 0xf9, 0x46, 0x2c) static inline int efi_guidcmp(efi_guid_t left, efi_guid_t right) @@ -369,4 +369,16 @@ extern ssize_t make_linux_load_option(uint8_t **data, size_t *data_size, extern int variable_to_name(efi_variable_t *var, char *name); extern int var_name_to_path(const char *name, char *path); +typedef struct { + uint8_t mirror_version; + uint8_t mirror_memory_below_4gb; + uint16_t mirror_amount_above_4gb; + uint8_t mirror_status; +} __attribute__((packed)) ADDRESS_RANGE_MIRROR_VARIABLE_DATA; + +#define MIRROR_VERSION 1 + +#define ADDRESS_RANGE_MIRROR_VARIABLE_CURRENT "MirrorCurrent" +#define ADDRESS_RANGE_MIRROR_VARIABLE_REQUEST "MirrorRequest" + #endif /* EFI_H */ diff --git a/src/include/efibootmgr.h b/src/include/efibootmgr.h index f5738b3..10a6701 100644 --- a/src/include/efibootmgr.h +++ b/src/include/efibootmgr.h @@ -40,6 +40,8 @@ typedef struct { int bootnext; int verbose; int active; + int below4g; + int above4g; int delete; uint32_t acpi_hid; uint32_t acpi_uid; @@ -54,6 +56,8 @@ typedef struct { unsigned int forcegpt:1; unsigned int set_timeout:1; unsigned int delete_timeout:1; + unsigned int set_mirror_lo:1; + unsigned int set_mirror_hi:1; unsigned short int timeout; } efibootmgr_opt_t;
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor