diff options
author | Matt Fleming <matt.fleming@intel.com> | 2013-04-30 06:30:24 -0400 |
---|---|---|
committer | Matt Fleming <matt.fleming@intel.com> | 2013-04-30 06:42:13 -0400 |
commit | a614e1923d5389d01f3545ee4a90e39a04d0c90d (patch) | |
tree | e8e32dba12a66ffd26d78f015a142ac28e19ad8e /arch/x86/platform | |
parent | f53f292eeaa234615c31a1306babe703fc4263f2 (diff) | |
parent | c1be5a5b1b355d40e6cf79cc979eb66dafa24ad1 (diff) |
Merge tag 'v3.9' into efi-for-tip2
Resolve conflicts for Ingo.
Conflicts:
drivers/firmware/Kconfig
drivers/firmware/efivars.c
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
Diffstat (limited to 'arch/x86/platform')
-rw-r--r-- | arch/x86/platform/efi/efi.c | 168 |
1 files changed, 163 insertions, 5 deletions
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index fff986da6239..012b3f6a9bd6 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/io.h> | 41 | #include <linux/io.h> |
42 | #include <linux/reboot.h> | 42 | #include <linux/reboot.h> |
43 | #include <linux/bcd.h> | 43 | #include <linux/bcd.h> |
44 | #include <linux/ucs2_string.h> | ||
44 | 45 | ||
45 | #include <asm/setup.h> | 46 | #include <asm/setup.h> |
46 | #include <asm/efi.h> | 47 | #include <asm/efi.h> |
@@ -51,6 +52,13 @@ | |||
51 | 52 | ||
52 | #define EFI_DEBUG 1 | 53 | #define EFI_DEBUG 1 |
53 | 54 | ||
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 | |||
54 | struct efi __read_mostly efi = { | 62 | struct efi __read_mostly efi = { |
55 | .mps = EFI_INVALID_TABLE_ADDR, | 63 | .mps = EFI_INVALID_TABLE_ADDR, |
56 | .acpi = EFI_INVALID_TABLE_ADDR, | 64 | .acpi = EFI_INVALID_TABLE_ADDR, |
@@ -69,6 +77,13 @@ struct efi_memory_map memmap; | |||
69 | static struct efi efi_phys __initdata; | 77 | static struct efi efi_phys __initdata; |
70 | static efi_system_table_t efi_systab __initdata; | 78 | static efi_system_table_t efi_systab __initdata; |
71 | 79 | ||
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 | |||
72 | unsigned long x86_efi_facility; | 87 | unsigned long x86_efi_facility; |
73 | 88 | ||
74 | /* | 89 | /* |
@@ -98,6 +113,15 @@ static int __init setup_add_efi_memmap(char *arg) | |||
98 | } | 113 | } |
99 | early_param("add_efi_memmap", setup_add_efi_memmap); | 114 | early_param("add_efi_memmap", setup_add_efi_memmap); |
100 | 115 | ||
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 | |||
101 | 125 | ||
102 | static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) | 126 | static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) |
103 | { | 127 | { |
@@ -162,8 +186,53 @@ static efi_status_t virt_efi_get_next_variable(unsigned long *name_size, | |||
162 | efi_char16_t *name, | 186 | efi_char16_t *name, |
163 | efi_guid_t *vendor) | 187 | efi_guid_t *vendor) |
164 | { | 188 | { |
165 | return efi_call_virt3(get_next_variable, | 189 | efi_status_t status; |
166 | name_size, name, vendor); | 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; | ||
167 | } | 236 | } |
168 | 237 | ||
169 | static efi_status_t virt_efi_set_variable(efi_char16_t *name, | 238 | 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, | |||
172 | unsigned long data_size, | 241 | unsigned long data_size, |
173 | void *data) | 242 | void *data) |
174 | { | 243 | { |
175 | return efi_call_virt5(set_variable, | 244 | efi_status_t status; |
176 | name, vendor, attr, | 245 | u32 orig_attr = 0; |
177 | data_size, data); | 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; | ||
178 | } | 272 | } |
179 | 273 | ||
180 | static efi_status_t virt_efi_query_variable_info(u32 attr, | 274 | static efi_status_t virt_efi_query_variable_info(u32 attr, |
@@ -683,6 +777,9 @@ void __init efi_init(void) | |||
683 | char vendor[100] = "unknown"; | 777 | char vendor[100] = "unknown"; |
684 | int i = 0; | 778 | int i = 0; |
685 | void *tmp; | 779 | void *tmp; |
780 | struct setup_data *data; | ||
781 | struct efi_var_bootdata *efi_var_data; | ||
782 | u64 pa_data; | ||
686 | 783 | ||
687 | #ifdef CONFIG_X86_32 | 784 | #ifdef CONFIG_X86_32 |
688 | if (boot_params.efi_info.efi_systab_hi || | 785 | if (boot_params.efi_info.efi_systab_hi || |
@@ -700,6 +797,22 @@ void __init efi_init(void) | |||
700 | if (efi_systab_init(efi_phys.systab)) | 797 | if (efi_systab_init(efi_phys.systab)) |
701 | return; | 798 | return; |
702 | 799 | ||
800 | pa_data = boot_params.hdr.setup_data; | ||
801 | while (pa_data) { | ||
802 | data = early_ioremap(pa_data, sizeof(*efi_var_data)); | ||
803 | if (data->type == SETUP_EFI_VARS) { | ||
804 | efi_var_data = (struct efi_var_bootdata *)data; | ||
805 | |||
806 | efi_var_store_size = efi_var_data->store_size; | ||
807 | efi_var_remaining_size = efi_var_data->remaining_size; | ||
808 | efi_var_max_var_size = efi_var_data->max_var_size; | ||
809 | } | ||
810 | pa_data = data->next; | ||
811 | early_iounmap(data, sizeof(*efi_var_data)); | ||
812 | } | ||
813 | |||
814 | boot_used_size = efi_var_store_size - efi_var_remaining_size; | ||
815 | |||
703 | set_bit(EFI_SYSTEM_TABLES, &x86_efi_facility); | 816 | set_bit(EFI_SYSTEM_TABLES, &x86_efi_facility); |
704 | 817 | ||
705 | /* | 818 | /* |
@@ -1000,3 +1113,48 @@ u64 efi_mem_attributes(unsigned long phys_addr) | |||
1000 | } | 1113 | } |
1001 | return 0; | 1114 | return 0; |
1002 | } | 1115 | } |
1116 | |||
1117 | /* | ||
1118 | * Some firmware has serious problems when using more than 50% of the EFI | ||
1119 | * variable store, i.e. it triggers bugs that can brick machines. Ensure that | ||
1120 | * we never use more than this safe limit. | ||
1121 | * | ||
1122 | * Return EFI_SUCCESS if it is safe to write 'size' bytes to the variable | ||
1123 | * store. | ||
1124 | */ | ||
1125 | efi_status_t efi_query_variable_store(u32 attributes, unsigned long size) | ||
1126 | { | ||
1127 | efi_status_t status; | ||
1128 | u64 storage_size, remaining_size, max_size; | ||
1129 | |||
1130 | status = efi.query_variable_info(attributes, &storage_size, | ||
1131 | &remaining_size, &max_size); | ||
1132 | if (status != EFI_SUCCESS) | ||
1133 | return status; | ||
1134 | |||
1135 | if (!max_size && remaining_size > size) | ||
1136 | printk_once(KERN_ERR FW_BUG "Broken EFI implementation" | ||
1137 | " is returning MaxVariableSize=0\n"); | ||
1138 | /* | ||
1139 | * Some firmware implementations refuse to boot if there's insufficient | ||
1140 | * space in the variable store. We account for that by refusing the | ||
1141 | * write if permitting it would reduce the available space to under | ||
1142 | * 50%. However, some firmware won't reclaim variable space until | ||
1143 | * after the used (not merely the actively used) space drops below | ||
1144 | * a threshold. We can approximate that case with the value calculated | ||
1145 | * above. If both the firmware and our calculations indicate that the | ||
1146 | * available space would drop below 50%, refuse the write. | ||
1147 | */ | ||
1148 | |||
1149 | if (!storage_size || size > remaining_size || | ||
1150 | (max_size && size > max_size)) | ||
1151 | return EFI_OUT_OF_RESOURCES; | ||
1152 | |||
1153 | if (!efi_no_storage_paranoia && | ||
1154 | ((active_size + size + VAR_METADATA_SIZE > storage_size / 2) && | ||
1155 | (remaining_size - size < storage_size / 2))) | ||
1156 | return EFI_OUT_OF_RESOURCES; | ||
1157 | |||
1158 | return EFI_SUCCESS; | ||
1159 | } | ||
1160 | EXPORT_SYMBOL_GPL(efi_query_variable_store); | ||