Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c0a9f45

Browse files
author
H. Peter Anvin
committed
Merge remote-tracking branch 'efi/urgent' into x86/urgent
Matt Fleming (1): x86, efivars: firmware bug workarounds should be in platform code Matthew Garrett (3): Move utf16 functions to kernel core and rename efi: Pass boot services variable info to runtime code efi: Distinguish between "remaining space" and actually used space Richard Weinberger (2): x86,efi: Check max_size only if it is non-zero. x86,efi: Implement efi_no_storage_paranoia parameter Sergey Vlasov (2): x86/Kconfig: Make EFI select UCS2_STRING efi: Export efi_query_variable_store() for efivars.ko Signed-off-by: H. Peter Anvin <[email protected]>
2 parents 74c3e3f + 8c58bf3 commit c0a9f45

File tree

13 files changed

+325
-83
lines changed

13 files changed

+325
-83
lines changed

Documentation/kernel-parameters.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
788788
edd= [EDD]
789789
Format: {"off" | "on" | "skip[mbr]"}
790790

791+
efi_no_storage_paranoia [EFI; X86]
792+
Using this parameter you can use more than 50% of
793+
your efi variable storage. Use this parameter only if
794+
you are really sure that your UEFI does sane gc and
795+
fulfills the spec otherwise your board may brick.
796+
791797
eisa_irq_edge= [PARISC,HW]
792798
See header of drivers/parisc/eisa.c.
793799

arch/x86/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1549,6 +1549,7 @@ config X86_SMAP
15491549
config EFI
15501550
bool "EFI runtime service support"
15511551
depends on ACPI
1552+
select UCS2_STRING
15521553
---help---
15531554
This enables the kernel to use EFI runtime services that are
15541555
available (such as the EFI variable services).

arch/x86/boot/compressed/eboot.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,51 @@ static void find_bits(unsigned long mask, u8 *pos, u8 *size)
251251
*size = len;
252252
}
253253

254+
static efi_status_t setup_efi_vars(struct boot_params *params)
255+
{
256+
struct setup_data *data;
257+
struct efi_var_bootdata *efidata;
258+
u64 store_size, remaining_size, var_size;
259+
efi_status_t status;
260+
261+
if (!sys_table->runtime->query_variable_info)
262+
return EFI_UNSUPPORTED;
263+
264+
data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
265+
266+
while (data && data->next)
267+
data = (struct setup_data *)(unsigned long)data->next;
268+
269+
status = efi_call_phys4(sys_table->runtime->query_variable_info,
270+
EFI_VARIABLE_NON_VOLATILE |
271+
EFI_VARIABLE_BOOTSERVICE_ACCESS |
272+
EFI_VARIABLE_RUNTIME_ACCESS, &store_size,
273+
&remaining_size, &var_size);
274+
275+
if (status != EFI_SUCCESS)
276+
return status;
277+
278+
status = efi_call_phys3(sys_table->boottime->allocate_pool,
279+
EFI_LOADER_DATA, sizeof(*efidata), &efidata);
280+
281+
if (status != EFI_SUCCESS)
282+
return status;
283+
284+
efidata->data.type = SETUP_EFI_VARS;
285+
efidata->data.len = sizeof(struct efi_var_bootdata) -
286+
sizeof(struct setup_data);
287+
efidata->data.next = 0;
288+
efidata->store_size = store_size;
289+
efidata->remaining_size = remaining_size;
290+
efidata->max_var_size = var_size;
291+
292+
if (data)
293+
data->next = (unsigned long)efidata;
294+
else
295+
params->hdr.setup_data = (unsigned long)efidata;
296+
297+
}
298+
254299
static efi_status_t setup_efi_pci(struct boot_params *params)
255300
{
256301
efi_pci_io_protocol *pci;
@@ -1157,6 +1202,8 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
11571202

11581203
setup_graphics(boot_params);
11591204

1205+
setup_efi_vars(boot_params);
1206+
11601207
setup_efi_pci(boot_params);
11611208

11621209
status = efi_call_phys3(sys_table->boottime->allocate_pool,

arch/x86/include/asm/efi.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,13 @@ extern void efi_call_phys_epilog(void);
102102
extern void efi_unmap_memmap(void);
103103
extern void efi_memory_uc(u64 addr, unsigned long size);
104104

105+
struct efi_var_bootdata {
106+
struct setup_data data;
107+
u64 store_size;
108+
u64 remaining_size;
109+
u64 max_var_size;
110+
};
111+
105112
#ifdef CONFIG_EFI
106113

107114
static inline bool efi_is_native(void)

arch/x86/include/uapi/asm/bootparam.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#define SETUP_E820_EXT 1
77
#define SETUP_DTB 2
88
#define SETUP_PCI 3
9+
#define SETUP_EFI_VARS 4
910

1011
/* ram_size flags */
1112
#define RAMDISK_IMAGE_START_MASK 0x07FF

arch/x86/platform/efi/efi.c

Lines changed: 163 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include <linux/io.h>
4242
#include <linux/reboot.h>
4343
#include <linux/bcd.h>
44+
#include <linux/ucs2_string.h>
4445

4546
#include <asm/setup.h>
4647
#include <asm/efi.h>
@@ -51,6 +52,13 @@
5152

5253
#define EFI_DEBUG 1
5354

55+
/*
56+
* There's some additional metadata associated with each
57+
* variable. Intel's reference implementation is 60 bytes - bump that
58+
* to account for potential alignment constraints
59+
*/
60+
#define VAR_METADATA_SIZE 64
61+
5462
struct efi __read_mostly efi = {
5563
.mps = EFI_INVALID_TABLE_ADDR,
5664
.acpi = EFI_INVALID_TABLE_ADDR,
@@ -69,6 +77,13 @@ struct efi_memory_map memmap;
6977
static struct efi efi_phys __initdata;
7078
static efi_system_table_t efi_systab __initdata;
7179

80+
static u64 efi_var_store_size;
81+
static u64 efi_var_remaining_size;
82+
static u64 efi_var_max_var_size;
83+
static u64 boot_used_size;
84+
static u64 boot_var_size;
85+
static u64 active_size;
86+
7287
unsigned long x86_efi_facility;
7388

7489
/*
@@ -98,6 +113,15 @@ static int __init setup_add_efi_memmap(char *arg)
98113
}
99114
early_param("add_efi_memmap", setup_add_efi_memmap);
100115

116+
static bool efi_no_storage_paranoia;
117+
118+
static int __init setup_storage_paranoia(char *arg)
119+
{
120+
efi_no_storage_paranoia = true;
121+
return 0;
122+
}
123+
early_param("efi_no_storage_paranoia", setup_storage_paranoia);
124+
101125

102126
static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
103127
{
@@ -162,8 +186,53 @@ static efi_status_t virt_efi_get_next_variable(unsigned long *name_size,
162186
efi_char16_t *name,
163187
efi_guid_t *vendor)
164188
{
165-
return efi_call_virt3(get_next_variable,
166-
name_size, name, vendor);
189+
efi_status_t status;
190+
static bool finished = false;
191+
static u64 var_size;
192+
193+
status = efi_call_virt3(get_next_variable,
194+
name_size, name, vendor);
195+
196+
if (status == EFI_NOT_FOUND) {
197+
finished = true;
198+
if (var_size < boot_used_size) {
199+
boot_var_size = boot_used_size - var_size;
200+
active_size += boot_var_size;
201+
} else {
202+
printk(KERN_WARNING FW_BUG "efi: Inconsistent initial sizes\n");
203+
}
204+
}
205+
206+
if (boot_used_size && !finished) {
207+
unsigned long size;
208+
u32 attr;
209+
efi_status_t s;
210+
void *tmp;
211+
212+
s = virt_efi_get_variable(name, vendor, &attr, &size, NULL);
213+
214+
if (s != EFI_BUFFER_TOO_SMALL || !size)
215+
return status;
216+
217+
tmp = kmalloc(size, GFP_ATOMIC);
218+
219+
if (!tmp)
220+
return status;
221+
222+
s = virt_efi_get_variable(name, vendor, &attr, &size, tmp);
223+
224+
if (s == EFI_SUCCESS && (attr & EFI_VARIABLE_NON_VOLATILE)) {
225+
var_size += size;
226+
var_size += ucs2_strsize(name, 1024);
227+
active_size += size;
228+
active_size += VAR_METADATA_SIZE;
229+
active_size += ucs2_strsize(name, 1024);
230+
}
231+
232+
kfree(tmp);
233+
}
234+
235+
return status;
167236
}
168237

169238
static efi_status_t virt_efi_set_variable(efi_char16_t *name,
@@ -172,9 +241,34 @@ static efi_status_t virt_efi_set_variable(efi_char16_t *name,
172241
unsigned long data_size,
173242
void *data)
174243
{
175-
return efi_call_virt5(set_variable,
176-
name, vendor, attr,
177-
data_size, data);
244+
efi_status_t status;
245+
u32 orig_attr = 0;
246+
unsigned long orig_size = 0;
247+
248+
status = virt_efi_get_variable(name, vendor, &orig_attr, &orig_size,
249+
NULL);
250+
251+
if (status != EFI_BUFFER_TOO_SMALL)
252+
orig_size = 0;
253+
254+
status = efi_call_virt5(set_variable,
255+
name, vendor, attr,
256+
data_size, data);
257+
258+
if (status == EFI_SUCCESS) {
259+
if (orig_size) {
260+
active_size -= orig_size;
261+
active_size -= ucs2_strsize(name, 1024);
262+
active_size -= VAR_METADATA_SIZE;
263+
}
264+
if (data_size) {
265+
active_size += data_size;
266+
active_size += ucs2_strsize(name, 1024);
267+
active_size += VAR_METADATA_SIZE;
268+
}
269+
}
270+
271+
return status;
178272
}
179273

180274
static efi_status_t virt_efi_query_variable_info(u32 attr,
@@ -682,6 +776,9 @@ void __init efi_init(void)
682776
char vendor[100] = "unknown";
683777
int i = 0;
684778
void *tmp;
779+
struct setup_data *data;
780+
struct efi_var_bootdata *efi_var_data;
781+
u64 pa_data;
685782

686783
#ifdef CONFIG_X86_32
687784
if (boot_params.efi_info.efi_systab_hi ||
@@ -699,6 +796,22 @@ void __init efi_init(void)
699796
if (efi_systab_init(efi_phys.systab))
700797
return;
701798

799+
pa_data = boot_params.hdr.setup_data;
800+
while (pa_data) {
801+
data = early_ioremap(pa_data, sizeof(*efi_var_data));
802+
if (data->type == SETUP_EFI_VARS) {
803+
efi_var_data = (struct efi_var_bootdata *)data;
804+
805+
efi_var_store_size = efi_var_data->store_size;
806+
efi_var_remaining_size = efi_var_data->remaining_size;
807+
efi_var_max_var_size = efi_var_data->max_var_size;
808+
}
809+
pa_data = data->next;
810+
early_iounmap(data, sizeof(*efi_var_data));
811+
}
812+
813+
boot_used_size = efi_var_store_size - efi_var_remaining_size;
814+
702815
set_bit(EFI_SYSTEM_TABLES, &x86_efi_facility);
703816

704817
/*
@@ -999,3 +1112,48 @@ u64 efi_mem_attributes(unsigned long phys_addr)
9991112
}
10001113
return 0;
10011114
}
1115+
1116+
/*
1117+
* Some firmware has serious problems when using more than 50% of the EFI
1118+
* variable store, i.e. it triggers bugs that can brick machines. Ensure that
1119+
* we never use more than this safe limit.
1120+
*
1121+
* Return EFI_SUCCESS if it is safe to write 'size' bytes to the variable
1122+
* store.
1123+
*/
1124+
efi_status_t efi_query_variable_store(u32 attributes, unsigned long size)
1125+
{
1126+
efi_status_t status;
1127+
u64 storage_size, remaining_size, max_size;
1128+
1129+
status = efi.query_variable_info(attributes, &storage_size,
1130+
&remaining_size, &max_size);
1131+
if (status != EFI_SUCCESS)
1132+
return status;
1133+
1134+
if (!max_size && remaining_size > size)
1135+
printk_once(KERN_ERR FW_BUG "Broken EFI implementation"
1136+
" is returning MaxVariableSize=0\n");
1137+
/*
1138+
* Some firmware implementations refuse to boot if there's insufficient
1139+
* space in the variable store. We account for that by refusing the
1140+
* write if permitting it would reduce the available space to under
1141+
* 50%. However, some firmware won't reclaim variable space until
1142+
* after the used (not merely the actively used) space drops below
1143+
* a threshold. We can approximate that case with the value calculated
1144+
* above. If both the firmware and our calculations indicate that the
1145+
* available space would drop below 50%, refuse the write.
1146+
*/
1147+
1148+
if (!storage_size || size > remaining_size ||
1149+
(max_size && size > max_size))
1150+
return EFI_OUT_OF_RESOURCES;
1151+
1152+
if (!efi_no_storage_paranoia &&
1153+
((active_size + size + VAR_METADATA_SIZE > storage_size / 2) &&
1154+
(remaining_size - size < storage_size / 2)))
1155+
return EFI_OUT_OF_RESOURCES;
1156+
1157+
return EFI_SUCCESS;
1158+
}
1159+
EXPORT_SYMBOL_GPL(efi_query_variable_store);

drivers/firmware/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ config FIRMWARE_MEMMAP
3939
config EFI_VARS
4040
tristate "EFI Variable Support via sysfs"
4141
depends on EFI
42+
select UCS2_STRING
4243
default n
4344
help
4445
If you say Y here, you are able to get EFI (Extensible Firmware

0 commit comments

Comments
 (0)