aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-06-05 11:16:29 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-06-05 11:16:29 -0400
commit046f153343e33dcad1be7f6249ea6ff1c6fd9b58 (patch)
tree46da03ea84e1a4fe8eff53891332e715cbf31f3e
parenta0abcf2e8f8017051830f738ac1bf5ef42703243 (diff)
parente33655a386ed3b26ad36fb97a47ebb1c2ca1e928 (diff)
Merge branch 'x86-efi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip into next
Pull x86 EFI updates from Peter Anvin: "A collection of EFI changes. The perhaps most important one is to fully save and restore the FPU state around each invocation of EFI runtime, and to not choke on non-ASCII characters in the boot stub" * 'x86-efi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: efivars: Add compatibility code for compat tasks efivars: Refactor sanity checking code into separate function efivars: Stop passing a struct argument to efivar_validate() efivars: Check size of user object efivars: Use local variables instead of a pointer dereference x86/efi: Save and restore FPU context around efi_calls (i386) x86/efi: Save and restore FPU context around efi_calls (x86_64) x86/efi: Implement a __efi_call_virt macro x86, fpu: Extend the use of static_cpu_has_safe x86/efi: Delete most of the efi_call* macros efi: x86: Handle arbitrary Unicode characters efi: Add get_dram_base() helper function efi: Add shared printk wrapper for consistent prefixing efi: create memory map iteration helper efi: efi-stub-helper cleanup
-rw-r--r--arch/x86/boot/compressed/eboot.c3
-rw-r--r--arch/x86/boot/compressed/head_64.S2
-rw-r--r--arch/x86/include/asm/efi.h100
-rw-r--r--arch/x86/include/asm/fpu-internal.h10
-rw-r--r--arch/x86/platform/efi/efi.c48
-rw-r--r--arch/x86/platform/efi/efi_stub_64.S81
-rw-r--r--arch/x86/platform/uv/bios_uv.c2
-rw-r--r--drivers/firmware/efi/efi-stub-helper.c144
-rw-r--r--drivers/firmware/efi/efivars.c192
-rw-r--r--drivers/firmware/efi/vars.c30
-rw-r--r--include/linux/efi.h12
11 files changed, 361 insertions, 263 deletions
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index 4703a6c4b8e3..0331d765c2bb 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -1087,8 +1087,7 @@ struct boot_params *make_boot_params(struct efi_config *c)
1087 hdr->type_of_loader = 0x21; 1087 hdr->type_of_loader = 0x21;
1088 1088
1089 /* Convert unicode cmdline to ascii */ 1089 /* Convert unicode cmdline to ascii */
1090 cmdline_ptr = efi_convert_cmdline_to_ascii(sys_table, image, 1090 cmdline_ptr = efi_convert_cmdline(sys_table, image, &options_size);
1091 &options_size);
1092 if (!cmdline_ptr) 1091 if (!cmdline_ptr)
1093 goto fail; 1092 goto fail;
1094 hdr->cmd_line_ptr = (unsigned long)cmdline_ptr; 1093 hdr->cmd_line_ptr = (unsigned long)cmdline_ptr;
diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
index 0d558ee899ae..2884e0c3e8a5 100644
--- a/arch/x86/boot/compressed/head_64.S
+++ b/arch/x86/boot/compressed/head_64.S
@@ -452,7 +452,7 @@ efi32_config:
452 .global efi64_config 452 .global efi64_config
453efi64_config: 453efi64_config:
454 .fill 11,8,0 454 .fill 11,8,0
455 .quad efi_call6 455 .quad efi_call
456 .byte 1 456 .byte 1
457#endif /* CONFIG_EFI_STUB */ 457#endif /* CONFIG_EFI_STUB */
458 458
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 0869434eaf72..1eb5f6433ad8 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -1,6 +1,7 @@
1#ifndef _ASM_X86_EFI_H 1#ifndef _ASM_X86_EFI_H
2#define _ASM_X86_EFI_H 2#define _ASM_X86_EFI_H
3 3
4#include <asm/i387.h>
4/* 5/*
5 * We map the EFI regions needed for runtime services non-contiguously, 6 * We map the EFI regions needed for runtime services non-contiguously,
6 * with preserved alignment on virtual addresses starting from -4G down 7 * with preserved alignment on virtual addresses starting from -4G down
@@ -27,91 +28,58 @@
27 28
28extern unsigned long asmlinkage efi_call_phys(void *, ...); 29extern unsigned long asmlinkage efi_call_phys(void *, ...);
29 30
30#define efi_call_phys0(f) efi_call_phys(f)
31#define efi_call_phys1(f, a1) efi_call_phys(f, a1)
32#define efi_call_phys2(f, a1, a2) efi_call_phys(f, a1, a2)
33#define efi_call_phys3(f, a1, a2, a3) efi_call_phys(f, a1, a2, a3)
34#define efi_call_phys4(f, a1, a2, a3, a4) \
35 efi_call_phys(f, a1, a2, a3, a4)
36#define efi_call_phys5(f, a1, a2, a3, a4, a5) \
37 efi_call_phys(f, a1, a2, a3, a4, a5)
38#define efi_call_phys6(f, a1, a2, a3, a4, a5, a6) \
39 efi_call_phys(f, a1, a2, a3, a4, a5, a6)
40/* 31/*
41 * Wrap all the virtual calls in a way that forces the parameters on the stack. 32 * Wrap all the virtual calls in a way that forces the parameters on the stack.
42 */ 33 */
43 34
35/* Use this macro if your virtual returns a non-void value */
44#define efi_call_virt(f, args...) \ 36#define efi_call_virt(f, args...) \
45 ((efi_##f##_t __attribute__((regparm(0)))*)efi.systab->runtime->f)(args) 37({ \
46 38 efi_status_t __s; \
47#define efi_call_virt0(f) efi_call_virt(f) 39 kernel_fpu_begin(); \
48#define efi_call_virt1(f, a1) efi_call_virt(f, a1) 40 __s = ((efi_##f##_t __attribute__((regparm(0)))*) \
49#define efi_call_virt2(f, a1, a2) efi_call_virt(f, a1, a2) 41 efi.systab->runtime->f)(args); \
50#define efi_call_virt3(f, a1, a2, a3) efi_call_virt(f, a1, a2, a3) 42 kernel_fpu_end(); \
51#define efi_call_virt4(f, a1, a2, a3, a4) \ 43 __s; \
52 efi_call_virt(f, a1, a2, a3, a4) 44})
53#define efi_call_virt5(f, a1, a2, a3, a4, a5) \ 45
54 efi_call_virt(f, a1, a2, a3, a4, a5) 46/* Use this macro if your virtual call does not return any value */
55#define efi_call_virt6(f, a1, a2, a3, a4, a5, a6) \ 47#define __efi_call_virt(f, args...) \
56 efi_call_virt(f, a1, a2, a3, a4, a5, a6) 48({ \
49 kernel_fpu_begin(); \
50 ((efi_##f##_t __attribute__((regparm(0)))*) \
51 efi.systab->runtime->f)(args); \
52 kernel_fpu_end(); \
53})
57 54
58#define efi_ioremap(addr, size, type, attr) ioremap_cache(addr, size) 55#define efi_ioremap(addr, size, type, attr) ioremap_cache(addr, size)
59 56
60#else /* !CONFIG_X86_32 */ 57#else /* !CONFIG_X86_32 */
61 58
62extern u64 efi_call0(void *fp); 59#define EFI_LOADER_SIGNATURE "EL64"
63extern u64 efi_call1(void *fp, u64 arg1); 60
64extern u64 efi_call2(void *fp, u64 arg1, u64 arg2); 61extern u64 asmlinkage efi_call(void *fp, ...);
65extern u64 efi_call3(void *fp, u64 arg1, u64 arg2, u64 arg3); 62
66extern u64 efi_call4(void *fp, u64 arg1, u64 arg2, u64 arg3, u64 arg4); 63#define efi_call_phys(f, args...) efi_call((f), args)
67extern u64 efi_call5(void *fp, u64 arg1, u64 arg2, u64 arg3, 64
68 u64 arg4, u64 arg5); 65#define efi_call_virt(f, ...) \
69extern u64 efi_call6(void *fp, u64 arg1, u64 arg2, u64 arg3,
70 u64 arg4, u64 arg5, u64 arg6);
71
72#define efi_call_phys0(f) \
73 efi_call0((f))
74#define efi_call_phys1(f, a1) \
75 efi_call1((f), (u64)(a1))
76#define efi_call_phys2(f, a1, a2) \
77 efi_call2((f), (u64)(a1), (u64)(a2))
78#define efi_call_phys3(f, a1, a2, a3) \
79 efi_call3((f), (u64)(a1), (u64)(a2), (u64)(a3))
80#define efi_call_phys4(f, a1, a2, a3, a4) \
81 efi_call4((f), (u64)(a1), (u64)(a2), (u64)(a3), \
82 (u64)(a4))
83#define efi_call_phys5(f, a1, a2, a3, a4, a5) \
84 efi_call5((f), (u64)(a1), (u64)(a2), (u64)(a3), \
85 (u64)(a4), (u64)(a5))
86#define efi_call_phys6(f, a1, a2, a3, a4, a5, a6) \
87 efi_call6((f), (u64)(a1), (u64)(a2), (u64)(a3), \
88 (u64)(a4), (u64)(a5), (u64)(a6))
89
90#define _efi_call_virtX(x, f, ...) \
91({ \ 66({ \
92 efi_status_t __s; \ 67 efi_status_t __s; \
93 \ 68 \
94 efi_sync_low_kernel_mappings(); \ 69 efi_sync_low_kernel_mappings(); \
95 preempt_disable(); \ 70 preempt_disable(); \
96 __s = efi_call##x((void *)efi.systab->runtime->f, __VA_ARGS__); \ 71 __kernel_fpu_begin(); \
72 __s = efi_call((void *)efi.systab->runtime->f, __VA_ARGS__); \
73 __kernel_fpu_end(); \
97 preempt_enable(); \ 74 preempt_enable(); \
98 __s; \ 75 __s; \
99}) 76})
100 77
101#define efi_call_virt0(f) \ 78/*
102 _efi_call_virtX(0, f) 79 * All X86_64 virt calls return non-void values. Thus, use non-void call for
103#define efi_call_virt1(f, a1) \ 80 * virt calls that would be void on X86_32.
104 _efi_call_virtX(1, f, (u64)(a1)) 81 */
105#define efi_call_virt2(f, a1, a2) \ 82#define __efi_call_virt(f, args...) efi_call_virt(f, args)
106 _efi_call_virtX(2, f, (u64)(a1), (u64)(a2))
107#define efi_call_virt3(f, a1, a2, a3) \
108 _efi_call_virtX(3, f, (u64)(a1), (u64)(a2), (u64)(a3))
109#define efi_call_virt4(f, a1, a2, a3, a4) \
110 _efi_call_virtX(4, f, (u64)(a1), (u64)(a2), (u64)(a3), (u64)(a4))
111#define efi_call_virt5(f, a1, a2, a3, a4, a5) \
112 _efi_call_virtX(5, f, (u64)(a1), (u64)(a2), (u64)(a3), (u64)(a4), (u64)(a5))
113#define efi_call_virt6(f, a1, a2, a3, a4, a5, a6) \
114 _efi_call_virtX(6, f, (u64)(a1), (u64)(a2), (u64)(a3), (u64)(a4), (u64)(a5), (u64)(a6))
115 83
116extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size, 84extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size,
117 u32 type, u64 attribute); 85 u32 type, u64 attribute);
diff --git a/arch/x86/include/asm/fpu-internal.h b/arch/x86/include/asm/fpu-internal.h
index cea1c76d49bf..115e3689cd53 100644
--- a/arch/x86/include/asm/fpu-internal.h
+++ b/arch/x86/include/asm/fpu-internal.h
@@ -87,22 +87,22 @@ static inline int is_x32_frame(void)
87 87
88static __always_inline __pure bool use_eager_fpu(void) 88static __always_inline __pure bool use_eager_fpu(void)
89{ 89{
90 return static_cpu_has(X86_FEATURE_EAGER_FPU); 90 return static_cpu_has_safe(X86_FEATURE_EAGER_FPU);
91} 91}
92 92
93static __always_inline __pure bool use_xsaveopt(void) 93static __always_inline __pure bool use_xsaveopt(void)
94{ 94{
95 return static_cpu_has(X86_FEATURE_XSAVEOPT); 95 return static_cpu_has_safe(X86_FEATURE_XSAVEOPT);
96} 96}
97 97
98static __always_inline __pure bool use_xsave(void) 98static __always_inline __pure bool use_xsave(void)
99{ 99{
100 return static_cpu_has(X86_FEATURE_XSAVE); 100 return static_cpu_has_safe(X86_FEATURE_XSAVE);
101} 101}
102 102
103static __always_inline __pure bool use_fxsr(void) 103static __always_inline __pure bool use_fxsr(void)
104{ 104{
105 return static_cpu_has(X86_FEATURE_FXSR); 105 return static_cpu_has_safe(X86_FEATURE_FXSR);
106} 106}
107 107
108static inline void fx_finit(struct i387_fxsave_struct *fx) 108static inline void fx_finit(struct i387_fxsave_struct *fx)
@@ -293,7 +293,7 @@ static inline int restore_fpu_checking(struct task_struct *tsk)
293 /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception 293 /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception
294 is pending. Clear the x87 state here by setting it to fixed 294 is pending. Clear the x87 state here by setting it to fixed
295 values. "m" is a random variable that should be in L1 */ 295 values. "m" is a random variable that should be in L1 */
296 if (unlikely(static_cpu_has(X86_FEATURE_FXSAVE_LEAK))) { 296 if (unlikely(static_cpu_has_safe(X86_FEATURE_FXSAVE_LEAK))) {
297 asm volatile( 297 asm volatile(
298 "fnclex\n\t" 298 "fnclex\n\t"
299 "emms\n\t" 299 "emms\n\t"
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 3781dd39e8bd..835b24820eaa 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -110,7 +110,7 @@ static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
110 efi_status_t status; 110 efi_status_t status;
111 111
112 spin_lock_irqsave(&rtc_lock, flags); 112 spin_lock_irqsave(&rtc_lock, flags);
113 status = efi_call_virt2(get_time, tm, tc); 113 status = efi_call_virt(get_time, tm, tc);
114 spin_unlock_irqrestore(&rtc_lock, flags); 114 spin_unlock_irqrestore(&rtc_lock, flags);
115 return status; 115 return status;
116} 116}
@@ -121,7 +121,7 @@ static efi_status_t virt_efi_set_time(efi_time_t *tm)
121 efi_status_t status; 121 efi_status_t status;
122 122
123 spin_lock_irqsave(&rtc_lock, flags); 123 spin_lock_irqsave(&rtc_lock, flags);
124 status = efi_call_virt1(set_time, tm); 124 status = efi_call_virt(set_time, tm);
125 spin_unlock_irqrestore(&rtc_lock, flags); 125 spin_unlock_irqrestore(&rtc_lock, flags);
126 return status; 126 return status;
127} 127}
@@ -134,8 +134,7 @@ static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled,
134 efi_status_t status; 134 efi_status_t status;
135 135
136 spin_lock_irqsave(&rtc_lock, flags); 136 spin_lock_irqsave(&rtc_lock, flags);
137 status = efi_call_virt3(get_wakeup_time, 137 status = efi_call_virt(get_wakeup_time, enabled, pending, tm);
138 enabled, pending, tm);
139 spin_unlock_irqrestore(&rtc_lock, flags); 138 spin_unlock_irqrestore(&rtc_lock, flags);
140 return status; 139 return status;
141} 140}
@@ -146,8 +145,7 @@ static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
146 efi_status_t status; 145 efi_status_t status;
147 146
148 spin_lock_irqsave(&rtc_lock, flags); 147 spin_lock_irqsave(&rtc_lock, flags);
149 status = efi_call_virt2(set_wakeup_time, 148 status = efi_call_virt(set_wakeup_time, enabled, tm);
150 enabled, tm);
151 spin_unlock_irqrestore(&rtc_lock, flags); 149 spin_unlock_irqrestore(&rtc_lock, flags);
152 return status; 150 return status;
153} 151}
@@ -158,17 +156,17 @@ static efi_status_t virt_efi_get_variable(efi_char16_t *name,
158 unsigned long *data_size, 156 unsigned long *data_size,
159 void *data) 157 void *data)
160{ 158{
161 return efi_call_virt5(get_variable, 159 return efi_call_virt(get_variable,
162 name, vendor, attr, 160 name, vendor, attr,
163 data_size, data); 161 data_size, data);
164} 162}
165 163
166static efi_status_t virt_efi_get_next_variable(unsigned long *name_size, 164static efi_status_t virt_efi_get_next_variable(unsigned long *name_size,
167 efi_char16_t *name, 165 efi_char16_t *name,
168 efi_guid_t *vendor) 166 efi_guid_t *vendor)
169{ 167{
170 return efi_call_virt3(get_next_variable, 168 return efi_call_virt(get_next_variable,
171 name_size, name, vendor); 169 name_size, name, vendor);
172} 170}
173 171
174static efi_status_t virt_efi_set_variable(efi_char16_t *name, 172static efi_status_t virt_efi_set_variable(efi_char16_t *name,
@@ -177,9 +175,9 @@ static efi_status_t virt_efi_set_variable(efi_char16_t *name,
177 unsigned long data_size, 175 unsigned long data_size,
178 void *data) 176 void *data)
179{ 177{
180 return efi_call_virt5(set_variable, 178 return efi_call_virt(set_variable,
181 name, vendor, attr, 179 name, vendor, attr,
182 data_size, data); 180 data_size, data);
183} 181}
184 182
185static efi_status_t virt_efi_query_variable_info(u32 attr, 183static efi_status_t virt_efi_query_variable_info(u32 attr,
@@ -190,13 +188,13 @@ static efi_status_t virt_efi_query_variable_info(u32 attr,
190 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 188 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
191 return EFI_UNSUPPORTED; 189 return EFI_UNSUPPORTED;
192 190
193 return efi_call_virt4(query_variable_info, attr, storage_space, 191 return efi_call_virt(query_variable_info, attr, storage_space,
194 remaining_space, max_variable_size); 192 remaining_space, max_variable_size);
195} 193}
196 194
197static efi_status_t virt_efi_get_next_high_mono_count(u32 *count) 195static efi_status_t virt_efi_get_next_high_mono_count(u32 *count)
198{ 196{
199 return efi_call_virt1(get_next_high_mono_count, count); 197 return efi_call_virt(get_next_high_mono_count, count);
200} 198}
201 199
202static void virt_efi_reset_system(int reset_type, 200static void virt_efi_reset_system(int reset_type,
@@ -204,8 +202,8 @@ static void virt_efi_reset_system(int reset_type,
204 unsigned long data_size, 202 unsigned long data_size,
205 efi_char16_t *data) 203 efi_char16_t *data)
206{ 204{
207 efi_call_virt4(reset_system, reset_type, status, 205 __efi_call_virt(reset_system, reset_type, status,
208 data_size, data); 206 data_size, data);
209} 207}
210 208
211static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules, 209static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules,
@@ -215,7 +213,7 @@ static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules,
215 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 213 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
216 return EFI_UNSUPPORTED; 214 return EFI_UNSUPPORTED;
217 215
218 return efi_call_virt3(update_capsule, capsules, count, sg_list); 216 return efi_call_virt(update_capsule, capsules, count, sg_list);
219} 217}
220 218
221static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, 219static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules,
@@ -226,8 +224,8 @@ static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules,
226 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 224 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
227 return EFI_UNSUPPORTED; 225 return EFI_UNSUPPORTED;
228 226
229 return efi_call_virt4(query_capsule_caps, capsules, count, max_size, 227 return efi_call_virt(query_capsule_caps, capsules, count, max_size,
230 reset_type); 228 reset_type);
231} 229}
232 230
233static efi_status_t __init phys_efi_set_virtual_address_map( 231static efi_status_t __init phys_efi_set_virtual_address_map(
@@ -239,9 +237,9 @@ static efi_status_t __init phys_efi_set_virtual_address_map(
239 efi_status_t status; 237 efi_status_t status;
240 238
241 efi_call_phys_prelog(); 239 efi_call_phys_prelog();
242 status = efi_call_phys4(efi_phys.set_virtual_address_map, 240 status = efi_call_phys(efi_phys.set_virtual_address_map,
243 memory_map_size, descriptor_size, 241 memory_map_size, descriptor_size,
244 descriptor_version, virtual_map); 242 descriptor_version, virtual_map);
245 efi_call_phys_epilog(); 243 efi_call_phys_epilog();
246 return status; 244 return status;
247} 245}
diff --git a/arch/x86/platform/efi/efi_stub_64.S b/arch/x86/platform/efi/efi_stub_64.S
index e0984ef0374b..5fcda7272550 100644
--- a/arch/x86/platform/efi/efi_stub_64.S
+++ b/arch/x86/platform/efi/efi_stub_64.S
@@ -73,84 +73,7 @@
73 2: 73 2:
74 .endm 74 .endm
75 75
76ENTRY(efi_call0) 76ENTRY(efi_call)
77 SAVE_XMM
78 subq $32, %rsp
79 SWITCH_PGT
80 call *%rdi
81 RESTORE_PGT
82 addq $32, %rsp
83 RESTORE_XMM
84 ret
85ENDPROC(efi_call0)
86
87ENTRY(efi_call1)
88 SAVE_XMM
89 subq $32, %rsp
90 mov %rsi, %rcx
91 SWITCH_PGT
92 call *%rdi
93 RESTORE_PGT
94 addq $32, %rsp
95 RESTORE_XMM
96 ret
97ENDPROC(efi_call1)
98
99ENTRY(efi_call2)
100 SAVE_XMM
101 subq $32, %rsp
102 mov %rsi, %rcx
103 SWITCH_PGT
104 call *%rdi
105 RESTORE_PGT
106 addq $32, %rsp
107 RESTORE_XMM
108 ret
109ENDPROC(efi_call2)
110
111ENTRY(efi_call3)
112 SAVE_XMM
113 subq $32, %rsp
114 mov %rcx, %r8
115 mov %rsi, %rcx
116 SWITCH_PGT
117 call *%rdi
118 RESTORE_PGT
119 addq $32, %rsp
120 RESTORE_XMM
121 ret
122ENDPROC(efi_call3)
123
124ENTRY(efi_call4)
125 SAVE_XMM
126 subq $32, %rsp
127 mov %r8, %r9
128 mov %rcx, %r8
129 mov %rsi, %rcx
130 SWITCH_PGT
131 call *%rdi
132 RESTORE_PGT
133 addq $32, %rsp
134 RESTORE_XMM
135 ret
136ENDPROC(efi_call4)
137
138ENTRY(efi_call5)
139 SAVE_XMM
140 subq $48, %rsp
141 mov %r9, 32(%rsp)
142 mov %r8, %r9
143 mov %rcx, %r8
144 mov %rsi, %rcx
145 SWITCH_PGT
146 call *%rdi
147 RESTORE_PGT
148 addq $48, %rsp
149 RESTORE_XMM
150 ret
151ENDPROC(efi_call5)
152
153ENTRY(efi_call6)
154 SAVE_XMM 77 SAVE_XMM
155 mov (%rsp), %rax 78 mov (%rsp), %rax
156 mov 8(%rax), %rax 79 mov 8(%rax), %rax
@@ -166,7 +89,7 @@ ENTRY(efi_call6)
166 addq $48, %rsp 89 addq $48, %rsp
167 RESTORE_XMM 90 RESTORE_XMM
168 ret 91 ret
169ENDPROC(efi_call6) 92ENDPROC(efi_call)
170 93
171#ifdef CONFIG_EFI_MIXED 94#ifdef CONFIG_EFI_MIXED
172 95
diff --git a/arch/x86/platform/uv/bios_uv.c b/arch/x86/platform/uv/bios_uv.c
index 766612137a62..1584cbed0dce 100644
--- a/arch/x86/platform/uv/bios_uv.c
+++ b/arch/x86/platform/uv/bios_uv.c
@@ -39,7 +39,7 @@ s64 uv_bios_call(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, u64 a4, u64 a5)
39 */ 39 */
40 return BIOS_STATUS_UNIMPLEMENTED; 40 return BIOS_STATUS_UNIMPLEMENTED;
41 41
42 ret = efi_call6((void *)__va(tab->function), (u64)which, 42 ret = efi_call((void *)__va(tab->function), (u64)which,
43 a1, a2, a3, a4, a5); 43 a1, a2, a3, a4, a5);
44 return ret; 44 return ret;
45} 45}
diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
index 2c41eaece2c1..eb6d4be9e722 100644
--- a/drivers/firmware/efi/efi-stub-helper.c
+++ b/drivers/firmware/efi/efi-stub-helper.c
@@ -11,6 +11,10 @@
11 */ 11 */
12#define EFI_READ_CHUNK_SIZE (1024 * 1024) 12#define EFI_READ_CHUNK_SIZE (1024 * 1024)
13 13
14/* error code which can't be mistaken for valid address */
15#define EFI_ERROR (~0UL)
16
17
14struct file_info { 18struct file_info {
15 efi_file_handle_t *handle; 19 efi_file_handle_t *handle;
16 u64 size; 20 u64 size;
@@ -33,6 +37,9 @@ static void efi_printk(efi_system_table_t *sys_table_arg, char *str)
33 } 37 }
34} 38}
35 39
40#define pr_efi(sys_table, msg) efi_printk(sys_table, "EFI stub: "msg)
41#define pr_efi_err(sys_table, msg) efi_printk(sys_table, "EFI stub: ERROR: "msg)
42
36 43
37static efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg, 44static efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg,
38 efi_memory_desc_t **map, 45 efi_memory_desc_t **map,
@@ -80,6 +87,32 @@ fail:
80 return status; 87 return status;
81} 88}
82 89
90
91static unsigned long __init get_dram_base(efi_system_table_t *sys_table_arg)
92{
93 efi_status_t status;
94 unsigned long map_size;
95 unsigned long membase = EFI_ERROR;
96 struct efi_memory_map map;
97 efi_memory_desc_t *md;
98
99 status = efi_get_memory_map(sys_table_arg, (efi_memory_desc_t **)&map.map,
100 &map_size, &map.desc_size, NULL, NULL);
101 if (status != EFI_SUCCESS)
102 return membase;
103
104 map.map_end = map.map + map_size;
105
106 for_each_efi_memory_desc(&map, md)
107 if (md->attribute & EFI_MEMORY_WB)
108 if (membase > md->phys_addr)
109 membase = md->phys_addr;
110
111 efi_call_early(free_pool, map.map);
112
113 return membase;
114}
115
83/* 116/*
84 * Allocate at the highest possible address that is not above 'max'. 117 * Allocate at the highest possible address that is not above 'max'.
85 */ 118 */
@@ -267,7 +300,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
267 struct file_info *files; 300 struct file_info *files;
268 unsigned long file_addr; 301 unsigned long file_addr;
269 u64 file_size_total; 302 u64 file_size_total;
270 efi_file_handle_t *fh; 303 efi_file_handle_t *fh = NULL;
271 efi_status_t status; 304 efi_status_t status;
272 int nr_files; 305 int nr_files;
273 char *str; 306 char *str;
@@ -310,7 +343,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
310 status = efi_call_early(allocate_pool, EFI_LOADER_DATA, 343 status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
311 nr_files * sizeof(*files), (void **)&files); 344 nr_files * sizeof(*files), (void **)&files);
312 if (status != EFI_SUCCESS) { 345 if (status != EFI_SUCCESS) {
313 efi_printk(sys_table_arg, "Failed to alloc mem for file handle list\n"); 346 pr_efi_err(sys_table_arg, "Failed to alloc mem for file handle list\n");
314 goto fail; 347 goto fail;
315 } 348 }
316 349
@@ -374,13 +407,13 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
374 status = efi_high_alloc(sys_table_arg, file_size_total, 0x1000, 407 status = efi_high_alloc(sys_table_arg, file_size_total, 0x1000,
375 &file_addr, max_addr); 408 &file_addr, max_addr);
376 if (status != EFI_SUCCESS) { 409 if (status != EFI_SUCCESS) {
377 efi_printk(sys_table_arg, "Failed to alloc highmem for files\n"); 410 pr_efi_err(sys_table_arg, "Failed to alloc highmem for files\n");
378 goto close_handles; 411 goto close_handles;
379 } 412 }
380 413
381 /* We've run out of free low memory. */ 414 /* We've run out of free low memory. */
382 if (file_addr > max_addr) { 415 if (file_addr > max_addr) {
383 efi_printk(sys_table_arg, "We've run out of free low memory\n"); 416 pr_efi_err(sys_table_arg, "We've run out of free low memory\n");
384 status = EFI_INVALID_PARAMETER; 417 status = EFI_INVALID_PARAMETER;
385 goto free_file_total; 418 goto free_file_total;
386 } 419 }
@@ -401,7 +434,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
401 &chunksize, 434 &chunksize,
402 (void *)addr); 435 (void *)addr);
403 if (status != EFI_SUCCESS) { 436 if (status != EFI_SUCCESS) {
404 efi_printk(sys_table_arg, "Failed to read file\n"); 437 pr_efi_err(sys_table_arg, "Failed to read file\n");
405 goto free_file_total; 438 goto free_file_total;
406 } 439 }
407 addr += chunksize; 440 addr += chunksize;
@@ -486,7 +519,7 @@ static efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg,
486 &new_addr); 519 &new_addr);
487 } 520 }
488 if (status != EFI_SUCCESS) { 521 if (status != EFI_SUCCESS) {
489 efi_printk(sys_table_arg, "ERROR: Failed to allocate usable memory for kernel.\n"); 522 pr_efi_err(sys_table_arg, "Failed to allocate usable memory for kernel.\n");
490 return status; 523 return status;
491 } 524 }
492 525
@@ -503,62 +536,99 @@ static efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg,
503} 536}
504 537
505/* 538/*
539 * Get the number of UTF-8 bytes corresponding to an UTF-16 character.
540 * This overestimates for surrogates, but that is okay.
541 */
542static int efi_utf8_bytes(u16 c)
543{
544 return 1 + (c >= 0x80) + (c >= 0x800);
545}
546
547/*
548 * Convert an UTF-16 string, not necessarily null terminated, to UTF-8.
549 */
550static u8 *efi_utf16_to_utf8(u8 *dst, const u16 *src, int n)
551{
552 unsigned int c;
553
554 while (n--) {
555 c = *src++;
556 if (n && c >= 0xd800 && c <= 0xdbff &&
557 *src >= 0xdc00 && *src <= 0xdfff) {
558 c = 0x10000 + ((c & 0x3ff) << 10) + (*src & 0x3ff);
559 src++;
560 n--;
561 }
562 if (c >= 0xd800 && c <= 0xdfff)
563 c = 0xfffd; /* Unmatched surrogate */
564 if (c < 0x80) {
565 *dst++ = c;
566 continue;
567 }
568 if (c < 0x800) {
569 *dst++ = 0xc0 + (c >> 6);
570 goto t1;
571 }
572 if (c < 0x10000) {
573 *dst++ = 0xe0 + (c >> 12);
574 goto t2;
575 }
576 *dst++ = 0xf0 + (c >> 18);
577 *dst++ = 0x80 + ((c >> 12) & 0x3f);
578 t2:
579 *dst++ = 0x80 + ((c >> 6) & 0x3f);
580 t1:
581 *dst++ = 0x80 + (c & 0x3f);
582 }
583
584 return dst;
585}
586
587/*
506 * Convert the unicode UEFI command line to ASCII to pass to kernel. 588 * Convert the unicode UEFI command line to ASCII to pass to kernel.
507 * Size of memory allocated return in *cmd_line_len. 589 * Size of memory allocated return in *cmd_line_len.
508 * Returns NULL on error. 590 * Returns NULL on error.
509 */ 591 */
510static char *efi_convert_cmdline_to_ascii(efi_system_table_t *sys_table_arg, 592static char *efi_convert_cmdline(efi_system_table_t *sys_table_arg,
511 efi_loaded_image_t *image, 593 efi_loaded_image_t *image,
512 int *cmd_line_len) 594 int *cmd_line_len)
513{ 595{
514 u16 *s2; 596 const u16 *s2;
515 u8 *s1 = NULL; 597 u8 *s1 = NULL;
516 unsigned long cmdline_addr = 0; 598 unsigned long cmdline_addr = 0;
517 int load_options_size = image->load_options_size / 2; /* ASCII */ 599 int load_options_chars = image->load_options_size / 2; /* UTF-16 */
518 void *options = image->load_options; 600 const u16 *options = image->load_options;
519 int options_size = 0; 601 int options_bytes = 0; /* UTF-8 bytes */
602 int options_chars = 0; /* UTF-16 chars */
520 efi_status_t status; 603 efi_status_t status;
521 int i;
522 u16 zero = 0; 604 u16 zero = 0;
523 605
524 if (options) { 606 if (options) {
525 s2 = options; 607 s2 = options;
526 while (*s2 && *s2 != '\n' && options_size < load_options_size) { 608 while (*s2 && *s2 != '\n'
527 s2++; 609 && options_chars < load_options_chars) {
528 options_size++; 610 options_bytes += efi_utf8_bytes(*s2++);
611 options_chars++;
529 } 612 }
530 } 613 }
531 614
532 if (options_size == 0) { 615 if (!options_chars) {
533 /* No command line options, so return empty string*/ 616 /* No command line options, so return empty string*/
534 options_size = 1;
535 options = &zero; 617 options = &zero;
536 } 618 }
537 619
538 options_size++; /* NUL termination */ 620 options_bytes++; /* NUL termination */
539#ifdef CONFIG_ARM 621
540 /* 622 status = efi_low_alloc(sys_table_arg, options_bytes, 0, &cmdline_addr);
541 * For ARM, allocate at a high address to avoid reserved
542 * regions at low addresses that we don't know the specfics of
543 * at the time we are processing the command line.
544 */
545 status = efi_high_alloc(sys_table_arg, options_size, 0,
546 &cmdline_addr, 0xfffff000);
547#else
548 status = efi_low_alloc(sys_table_arg, options_size, 0,
549 &cmdline_addr);
550#endif
551 if (status != EFI_SUCCESS) 623 if (status != EFI_SUCCESS)
552 return NULL; 624 return NULL;
553 625
554 s1 = (u8 *)cmdline_addr; 626 s1 = (u8 *)cmdline_addr;
555 s2 = (u16 *)options; 627 s2 = (const u16 *)options;
556
557 for (i = 0; i < options_size - 1; i++)
558 *s1++ = *s2++;
559 628
629 s1 = efi_utf16_to_utf8(s1, s2, options_chars);
560 *s1 = '\0'; 630 *s1 = '\0';
561 631
562 *cmd_line_len = options_size; 632 *cmd_line_len = options_bytes;
563 return (char *)cmdline_addr; 633 return (char *)cmdline_addr;
564} 634}
diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c
index 50ea412a25e6..463c56545ae8 100644
--- a/drivers/firmware/efi/efivars.c
+++ b/drivers/firmware/efi/efivars.c
@@ -69,6 +69,7 @@
69#include <linux/module.h> 69#include <linux/module.h>
70#include <linux/slab.h> 70#include <linux/slab.h>
71#include <linux/ucs2_string.h> 71#include <linux/ucs2_string.h>
72#include <linux/compat.h>
72 73
73#define EFIVARS_VERSION "0.08" 74#define EFIVARS_VERSION "0.08"
74#define EFIVARS_DATE "2004-May-17" 75#define EFIVARS_DATE "2004-May-17"
@@ -86,6 +87,15 @@ static struct kset *efivars_kset;
86static struct bin_attribute *efivars_new_var; 87static struct bin_attribute *efivars_new_var;
87static struct bin_attribute *efivars_del_var; 88static struct bin_attribute *efivars_del_var;
88 89
90struct compat_efi_variable {
91 efi_char16_t VariableName[EFI_VAR_NAME_LEN/sizeof(efi_char16_t)];
92 efi_guid_t VendorGuid;
93 __u32 DataSize;
94 __u8 Data[1024];
95 __u32 Status;
96 __u32 Attributes;
97} __packed;
98
89struct efivar_attribute { 99struct efivar_attribute {
90 struct attribute attr; 100 struct attribute attr;
91 ssize_t (*show) (struct efivar_entry *entry, char *buf); 101 ssize_t (*show) (struct efivar_entry *entry, char *buf);
@@ -189,45 +199,107 @@ efivar_data_read(struct efivar_entry *entry, char *buf)
189 memcpy(buf, var->Data, var->DataSize); 199 memcpy(buf, var->Data, var->DataSize);
190 return var->DataSize; 200 return var->DataSize;
191} 201}
192/*
193 * We allow each variable to be edited via rewriting the
194 * entire efi variable structure.
195 */
196static ssize_t
197efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
198{
199 struct efi_variable *new_var, *var = &entry->var;
200 int err;
201 202
202 if (count != sizeof(struct efi_variable)) 203static inline int
203 return -EINVAL; 204sanity_check(struct efi_variable *var, efi_char16_t *name, efi_guid_t vendor,
204 205 unsigned long size, u32 attributes, u8 *data)
205 new_var = (struct efi_variable *)buf; 206{
206 /* 207 /*
207 * If only updating the variable data, then the name 208 * If only updating the variable data, then the name
208 * and guid should remain the same 209 * and guid should remain the same
209 */ 210 */
210 if (memcmp(new_var->VariableName, var->VariableName, sizeof(var->VariableName)) || 211 if (memcmp(name, var->VariableName, sizeof(var->VariableName)) ||
211 efi_guidcmp(new_var->VendorGuid, var->VendorGuid)) { 212 efi_guidcmp(vendor, var->VendorGuid)) {
212 printk(KERN_ERR "efivars: Cannot edit the wrong variable!\n"); 213 printk(KERN_ERR "efivars: Cannot edit the wrong variable!\n");
213 return -EINVAL; 214 return -EINVAL;
214 } 215 }
215 216
216 if ((new_var->DataSize <= 0) || (new_var->Attributes == 0)){ 217 if ((size <= 0) || (attributes == 0)){
217 printk(KERN_ERR "efivars: DataSize & Attributes must be valid!\n"); 218 printk(KERN_ERR "efivars: DataSize & Attributes must be valid!\n");
218 return -EINVAL; 219 return -EINVAL;
219 } 220 }
220 221
221 if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || 222 if ((attributes & ~EFI_VARIABLE_MASK) != 0 ||
222 efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) { 223 efivar_validate(name, data, size) == false) {
223 printk(KERN_ERR "efivars: Malformed variable content\n"); 224 printk(KERN_ERR "efivars: Malformed variable content\n");
224 return -EINVAL; 225 return -EINVAL;
225 } 226 }
226 227
227 memcpy(&entry->var, new_var, count); 228 return 0;
229}
230
231static inline bool is_compat(void)
232{
233 if (IS_ENABLED(CONFIG_COMPAT) && is_compat_task())
234 return true;
235
236 return false;
237}
238
239static void
240copy_out_compat(struct efi_variable *dst, struct compat_efi_variable *src)
241{
242 memcpy(dst->VariableName, src->VariableName, EFI_VAR_NAME_LEN);
243 memcpy(dst->Data, src->Data, sizeof(src->Data));
244
245 dst->VendorGuid = src->VendorGuid;
246 dst->DataSize = src->DataSize;
247 dst->Attributes = src->Attributes;
248}
249
250/*
251 * We allow each variable to be edited via rewriting the
252 * entire efi variable structure.
253 */
254static ssize_t
255efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
256{
257 struct efi_variable *new_var, *var = &entry->var;
258 efi_char16_t *name;
259 unsigned long size;
260 efi_guid_t vendor;
261 u32 attributes;
262 u8 *data;
263 int err;
264
265 if (is_compat()) {
266 struct compat_efi_variable *compat;
267
268 if (count != sizeof(*compat))
269 return -EINVAL;
270
271 compat = (struct compat_efi_variable *)buf;
272 attributes = compat->Attributes;
273 vendor = compat->VendorGuid;
274 name = compat->VariableName;
275 size = compat->DataSize;
276 data = compat->Data;
277
278 err = sanity_check(var, name, vendor, size, attributes, data);
279 if (err)
280 return err;
281
282 copy_out_compat(&entry->var, compat);
283 } else {
284 if (count != sizeof(struct efi_variable))
285 return -EINVAL;
286
287 new_var = (struct efi_variable *)buf;
228 288
229 err = efivar_entry_set(entry, new_var->Attributes, 289 attributes = new_var->Attributes;
230 new_var->DataSize, new_var->Data, NULL); 290 vendor = new_var->VendorGuid;
291 name = new_var->VariableName;
292 size = new_var->DataSize;
293 data = new_var->Data;
294
295 err = sanity_check(var, name, vendor, size, attributes, data);
296 if (err)
297 return err;
298
299 memcpy(&entry->var, new_var, count);
300 }
301
302 err = efivar_entry_set(entry, attributes, size, data, NULL);
231 if (err) { 303 if (err) {
232 printk(KERN_WARNING "efivars: set_variable() failed: status=%d\n", err); 304 printk(KERN_WARNING "efivars: set_variable() failed: status=%d\n", err);
233 return -EIO; 305 return -EIO;
@@ -240,6 +312,8 @@ static ssize_t
240efivar_show_raw(struct efivar_entry *entry, char *buf) 312efivar_show_raw(struct efivar_entry *entry, char *buf)
241{ 313{
242 struct efi_variable *var = &entry->var; 314 struct efi_variable *var = &entry->var;
315 struct compat_efi_variable *compat;
316 size_t size;
243 317
244 if (!entry || !buf) 318 if (!entry || !buf)
245 return 0; 319 return 0;
@@ -249,9 +323,23 @@ efivar_show_raw(struct efivar_entry *entry, char *buf)
249 &entry->var.DataSize, entry->var.Data)) 323 &entry->var.DataSize, entry->var.Data))
250 return -EIO; 324 return -EIO;
251 325
252 memcpy(buf, var, sizeof(*var)); 326 if (is_compat()) {
327 compat = (struct compat_efi_variable *)buf;
328
329 size = sizeof(*compat);
330 memcpy(compat->VariableName, var->VariableName,
331 EFI_VAR_NAME_LEN);
332 memcpy(compat->Data, var->Data, sizeof(compat->Data));
333
334 compat->VendorGuid = var->VendorGuid;
335 compat->DataSize = var->DataSize;
336 compat->Attributes = var->Attributes;
337 } else {
338 size = sizeof(*var);
339 memcpy(buf, var, size);
340 }
253 341
254 return sizeof(*var); 342 return size;
255} 343}
256 344
257/* 345/*
@@ -326,15 +414,39 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
326 struct bin_attribute *bin_attr, 414 struct bin_attribute *bin_attr,
327 char *buf, loff_t pos, size_t count) 415 char *buf, loff_t pos, size_t count)
328{ 416{
417 struct compat_efi_variable *compat = (struct compat_efi_variable *)buf;
329 struct efi_variable *new_var = (struct efi_variable *)buf; 418 struct efi_variable *new_var = (struct efi_variable *)buf;
330 struct efivar_entry *new_entry; 419 struct efivar_entry *new_entry;
420 bool need_compat = is_compat();
421 efi_char16_t *name;
422 unsigned long size;
423 u32 attributes;
424 u8 *data;
331 int err; 425 int err;
332 426
333 if (!capable(CAP_SYS_ADMIN)) 427 if (!capable(CAP_SYS_ADMIN))
334 return -EACCES; 428 return -EACCES;
335 429
336 if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || 430 if (need_compat) {
337 efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) { 431 if (count != sizeof(*compat))
432 return -EINVAL;
433
434 attributes = compat->Attributes;
435 name = compat->VariableName;
436 size = compat->DataSize;
437 data = compat->Data;
438 } else {
439 if (count != sizeof(*new_var))
440 return -EINVAL;
441
442 attributes = new_var->Attributes;
443 name = new_var->VariableName;
444 size = new_var->DataSize;
445 data = new_var->Data;
446 }
447
448 if ((attributes & ~EFI_VARIABLE_MASK) != 0 ||
449 efivar_validate(name, data, size) == false) {
338 printk(KERN_ERR "efivars: Malformed variable content\n"); 450 printk(KERN_ERR "efivars: Malformed variable content\n");
339 return -EINVAL; 451 return -EINVAL;
340 } 452 }
@@ -343,10 +455,13 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
343 if (!new_entry) 455 if (!new_entry)
344 return -ENOMEM; 456 return -ENOMEM;
345 457
346 memcpy(&new_entry->var, new_var, sizeof(*new_var)); 458 if (need_compat)
459 copy_out_compat(&new_entry->var, compat);
460 else
461 memcpy(&new_entry->var, new_var, sizeof(*new_var));
347 462
348 err = efivar_entry_set(new_entry, new_var->Attributes, new_var->DataSize, 463 err = efivar_entry_set(new_entry, attributes, size,
349 new_var->Data, &efivar_sysfs_list); 464 data, &efivar_sysfs_list);
350 if (err) { 465 if (err) {
351 if (err == -EEXIST) 466 if (err == -EEXIST)
352 err = -EINVAL; 467 err = -EINVAL;
@@ -369,15 +484,32 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
369 char *buf, loff_t pos, size_t count) 484 char *buf, loff_t pos, size_t count)
370{ 485{
371 struct efi_variable *del_var = (struct efi_variable *)buf; 486 struct efi_variable *del_var = (struct efi_variable *)buf;
487 struct compat_efi_variable *compat;
372 struct efivar_entry *entry; 488 struct efivar_entry *entry;
489 efi_char16_t *name;
490 efi_guid_t vendor;
373 int err = 0; 491 int err = 0;
374 492
375 if (!capable(CAP_SYS_ADMIN)) 493 if (!capable(CAP_SYS_ADMIN))
376 return -EACCES; 494 return -EACCES;
377 495
496 if (is_compat()) {
497 if (count != sizeof(*compat))
498 return -EINVAL;
499
500 compat = (struct compat_efi_variable *)buf;
501 name = compat->VariableName;
502 vendor = compat->VendorGuid;
503 } else {
504 if (count != sizeof(*del_var))
505 return -EINVAL;
506
507 name = del_var->VariableName;
508 vendor = del_var->VendorGuid;
509 }
510
378 efivar_entry_iter_begin(); 511 efivar_entry_iter_begin();
379 entry = efivar_entry_find(del_var->VariableName, del_var->VendorGuid, 512 entry = efivar_entry_find(name, vendor, &efivar_sysfs_list, true);
380 &efivar_sysfs_list, true);
381 if (!entry) 513 if (!entry)
382 err = -EINVAL; 514 err = -EINVAL;
383 else if (__efivar_entry_delete(entry)) 515 else if (__efivar_entry_delete(entry))
diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c
index b22659cccca4..f0a43646a2f3 100644
--- a/drivers/firmware/efi/vars.c
+++ b/drivers/firmware/efi/vars.c
@@ -42,7 +42,7 @@ DECLARE_WORK(efivar_work, NULL);
42EXPORT_SYMBOL_GPL(efivar_work); 42EXPORT_SYMBOL_GPL(efivar_work);
43 43
44static bool 44static bool
45validate_device_path(struct efi_variable *var, int match, u8 *buffer, 45validate_device_path(efi_char16_t *var_name, int match, u8 *buffer,
46 unsigned long len) 46 unsigned long len)
47{ 47{
48 struct efi_generic_dev_path *node; 48 struct efi_generic_dev_path *node;
@@ -75,7 +75,7 @@ validate_device_path(struct efi_variable *var, int match, u8 *buffer,
75} 75}
76 76
77static bool 77static bool
78validate_boot_order(struct efi_variable *var, int match, u8 *buffer, 78validate_boot_order(efi_char16_t *var_name, int match, u8 *buffer,
79 unsigned long len) 79 unsigned long len)
80{ 80{
81 /* An array of 16-bit integers */ 81 /* An array of 16-bit integers */
@@ -86,18 +86,18 @@ validate_boot_order(struct efi_variable *var, int match, u8 *buffer,
86} 86}
87 87
88static bool 88static bool
89validate_load_option(struct efi_variable *var, int match, u8 *buffer, 89validate_load_option(efi_char16_t *var_name, int match, u8 *buffer,
90 unsigned long len) 90 unsigned long len)
91{ 91{
92 u16 filepathlength; 92 u16 filepathlength;
93 int i, desclength = 0, namelen; 93 int i, desclength = 0, namelen;
94 94
95 namelen = ucs2_strnlen(var->VariableName, sizeof(var->VariableName)); 95 namelen = ucs2_strnlen(var_name, EFI_VAR_NAME_LEN);
96 96
97 /* Either "Boot" or "Driver" followed by four digits of hex */ 97 /* Either "Boot" or "Driver" followed by four digits of hex */
98 for (i = match; i < match+4; i++) { 98 for (i = match; i < match+4; i++) {
99 if (var->VariableName[i] > 127 || 99 if (var_name[i] > 127 ||
100 hex_to_bin(var->VariableName[i] & 0xff) < 0) 100 hex_to_bin(var_name[i] & 0xff) < 0)
101 return true; 101 return true;
102 } 102 }
103 103
@@ -132,12 +132,12 @@ validate_load_option(struct efi_variable *var, int match, u8 *buffer,
132 /* 132 /*
133 * And, finally, check the filepath 133 * And, finally, check the filepath
134 */ 134 */
135 return validate_device_path(var, match, buffer + desclength + 6, 135 return validate_device_path(var_name, match, buffer + desclength + 6,
136 filepathlength); 136 filepathlength);
137} 137}
138 138
139static bool 139static bool
140validate_uint16(struct efi_variable *var, int match, u8 *buffer, 140validate_uint16(efi_char16_t *var_name, int match, u8 *buffer,
141 unsigned long len) 141 unsigned long len)
142{ 142{
143 /* A single 16-bit integer */ 143 /* A single 16-bit integer */
@@ -148,7 +148,7 @@ validate_uint16(struct efi_variable *var, int match, u8 *buffer,
148} 148}
149 149
150static bool 150static bool
151validate_ascii_string(struct efi_variable *var, int match, u8 *buffer, 151validate_ascii_string(efi_char16_t *var_name, int match, u8 *buffer,
152 unsigned long len) 152 unsigned long len)
153{ 153{
154 int i; 154 int i;
@@ -166,7 +166,7 @@ validate_ascii_string(struct efi_variable *var, int match, u8 *buffer,
166 166
167struct variable_validate { 167struct variable_validate {
168 char *name; 168 char *name;
169 bool (*validate)(struct efi_variable *var, int match, u8 *data, 169 bool (*validate)(efi_char16_t *var_name, int match, u8 *data,
170 unsigned long len); 170 unsigned long len);
171}; 171};
172 172
@@ -189,10 +189,10 @@ static const struct variable_validate variable_validate[] = {
189}; 189};
190 190
191bool 191bool
192efivar_validate(struct efi_variable *var, u8 *data, unsigned long len) 192efivar_validate(efi_char16_t *var_name, u8 *data, unsigned long len)
193{ 193{
194 int i; 194 int i;
195 u16 *unicode_name = var->VariableName; 195 u16 *unicode_name = var_name;
196 196
197 for (i = 0; variable_validate[i].validate != NULL; i++) { 197 for (i = 0; variable_validate[i].validate != NULL; i++) {
198 const char *name = variable_validate[i].name; 198 const char *name = variable_validate[i].name;
@@ -208,7 +208,7 @@ efivar_validate(struct efi_variable *var, u8 *data, unsigned long len)
208 208
209 /* Wildcard in the matching name means we've matched */ 209 /* Wildcard in the matching name means we've matched */
210 if (c == '*') 210 if (c == '*')
211 return variable_validate[i].validate(var, 211 return variable_validate[i].validate(var_name,
212 match, data, len); 212 match, data, len);
213 213
214 /* Case sensitive match */ 214 /* Case sensitive match */
@@ -217,7 +217,7 @@ efivar_validate(struct efi_variable *var, u8 *data, unsigned long len)
217 217
218 /* Reached the end of the string while matching */ 218 /* Reached the end of the string while matching */
219 if (!c) 219 if (!c)
220 return variable_validate[i].validate(var, 220 return variable_validate[i].validate(var_name,
221 match, data, len); 221 match, data, len);
222 } 222 }
223 } 223 }
@@ -805,7 +805,7 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
805 805
806 *set = false; 806 *set = false;
807 807
808 if (efivar_validate(&entry->var, data, *size) == false) 808 if (efivar_validate(name, data, *size) == false)
809 return -EINVAL; 809 return -EINVAL;
810 810
811 /* 811 /*
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 6c100ff0cae4..6a4d8e27d1d7 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -863,6 +863,12 @@ extern int efi_set_rtc_mmss(const struct timespec *now);
863extern void efi_reserve_boot_services(void); 863extern void efi_reserve_boot_services(void);
864extern struct efi_memory_map memmap; 864extern struct efi_memory_map memmap;
865 865
866/* Iterate through an efi_memory_map */
867#define for_each_efi_memory_desc(m, md) \
868 for ((md) = (m)->map; \
869 (md) <= (efi_memory_desc_t *)((m)->map_end - (m)->desc_size); \
870 (md) = (void *)(md) + (m)->desc_size)
871
866/** 872/**
867 * efi_range_is_wc - check the WC bit on an address range 873 * efi_range_is_wc - check the WC bit on an address range
868 * @start: starting kvirt address 874 * @start: starting kvirt address
@@ -1033,8 +1039,10 @@ struct efivars {
1033 * and we use a page for reading/writing. 1039 * and we use a page for reading/writing.
1034 */ 1040 */
1035 1041
1042#define EFI_VAR_NAME_LEN 1024
1043
1036struct efi_variable { 1044struct efi_variable {
1037 efi_char16_t VariableName[1024/sizeof(efi_char16_t)]; 1045 efi_char16_t VariableName[EFI_VAR_NAME_LEN/sizeof(efi_char16_t)];
1038 efi_guid_t VendorGuid; 1046 efi_guid_t VendorGuid;
1039 unsigned long DataSize; 1047 unsigned long DataSize;
1040 __u8 Data[1024]; 1048 __u8 Data[1024];
@@ -1116,7 +1124,7 @@ int efivar_entry_iter(int (*func)(struct efivar_entry *, void *),
1116struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid, 1124struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid,
1117 struct list_head *head, bool remove); 1125 struct list_head *head, bool remove);
1118 1126
1119bool efivar_validate(struct efi_variable *var, u8 *data, unsigned long len); 1127bool efivar_validate(efi_char16_t *var_name, u8 *data, unsigned long len);
1120 1128
1121extern struct work_struct efivar_work; 1129extern struct work_struct efivar_work;
1122void efivar_run_worker(void); 1130void efivar_run_worker(void);