aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/boot/compressed/eboot.c
diff options
context:
space:
mode:
authorZach Bobroff <zacharyb@ami.com>2013-06-07 08:02:50 -0400
committerMatt Fleming <matt.fleming@intel.com>2013-06-11 02:51:54 -0400
commitd3768d885c6ccbf8a137276843177d76c49033a7 (patch)
treea50eb1b4b1b0ff59a55633562b7096bc091889af /arch/x86/boot/compressed/eboot.c
parent43ab0476a648053e5998bf081f47f215375a4502 (diff)
x86, efi: retry ExitBootServices() on failure
ExitBootServices is absolutely supposed to return a failure if any ExitBootServices event handler changes the memory map. Basically the get_map loop should run again if ExitBootServices returns an error the first time. I would say it would be fair that if ExitBootServices gives an error the second time then Linux would be fine in returning control back to BIOS. The second change is the following line: again: size += sizeof(*mem_map) * 2; Originally you were incrementing it by the size of one memory map entry. The issue here is all related to the low_alloc routine you are using. In this routine you are making allocations to get the memory map itself. Doing this allocation or allocations can affect the memory map by more than one record. [ mfleming - changelog, code style ] Signed-off-by: Zach Bobroff <zacharyb@ami.com> Cc: <stable@vger.kernel.org> Signed-off-by: Matt Fleming <matt.fleming@intel.com>
Diffstat (limited to 'arch/x86/boot/compressed/eboot.c')
-rw-r--r--arch/x86/boot/compressed/eboot.c20
1 files changed, 17 insertions, 3 deletions
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index 35ee62fccf98..7c6e5d957cc5 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -1037,18 +1037,20 @@ static efi_status_t exit_boot(struct boot_params *boot_params,
1037 efi_memory_desc_t *mem_map; 1037 efi_memory_desc_t *mem_map;
1038 efi_status_t status; 1038 efi_status_t status;
1039 __u32 desc_version; 1039 __u32 desc_version;
1040 bool called_exit = false;
1040 u8 nr_entries; 1041 u8 nr_entries;
1041 int i; 1042 int i;
1042 1043
1043 size = sizeof(*mem_map) * 32; 1044 size = sizeof(*mem_map) * 32;
1044 1045
1045again: 1046again:
1046 size += sizeof(*mem_map); 1047 size += sizeof(*mem_map) * 2;
1047 _size = size; 1048 _size = size;
1048 status = low_alloc(size, 1, (unsigned long *)&mem_map); 1049 status = low_alloc(size, 1, (unsigned long *)&mem_map);
1049 if (status != EFI_SUCCESS) 1050 if (status != EFI_SUCCESS)
1050 return status; 1051 return status;
1051 1052
1053get_map:
1052 status = efi_call_phys5(sys_table->boottime->get_memory_map, &size, 1054 status = efi_call_phys5(sys_table->boottime->get_memory_map, &size,
1053 mem_map, &key, &desc_size, &desc_version); 1055 mem_map, &key, &desc_size, &desc_version);
1054 if (status == EFI_BUFFER_TOO_SMALL) { 1056 if (status == EFI_BUFFER_TOO_SMALL) {
@@ -1074,8 +1076,20 @@ again:
1074 /* Might as well exit boot services now */ 1076 /* Might as well exit boot services now */
1075 status = efi_call_phys2(sys_table->boottime->exit_boot_services, 1077 status = efi_call_phys2(sys_table->boottime->exit_boot_services,
1076 handle, key); 1078 handle, key);
1077 if (status != EFI_SUCCESS) 1079 if (status != EFI_SUCCESS) {
1078 goto free_mem_map; 1080 /*
1081 * ExitBootServices() will fail if any of the event
1082 * handlers change the memory map. In which case, we
1083 * must be prepared to retry, but only once so that
1084 * we're guaranteed to exit on repeated failures instead
1085 * of spinning forever.
1086 */
1087 if (called_exit)
1088 goto free_mem_map;
1089
1090 called_exit = true;
1091 goto get_map;
1092 }
1079 1093
1080 /* Historic? */ 1094 /* Historic? */
1081 boot_params->alt_mem_k = 32 * 1024; 1095 boot_params->alt_mem_k = 32 * 1024;