Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

+363 -265
+1 -2
arch/x86/boot/compressed/eboot.c
··· 1087 1087 hdr->type_of_loader = 0x21; 1088 1088 1089 1089 /* Convert unicode cmdline to ascii */ 1090 - cmdline_ptr = efi_convert_cmdline_to_ascii(sys_table, image, 1091 - &options_size); 1090 + cmdline_ptr = efi_convert_cmdline(sys_table, image, &options_size); 1092 1091 if (!cmdline_ptr) 1093 1092 goto fail; 1094 1093 hdr->cmd_line_ptr = (unsigned long)cmdline_ptr;
+1 -1
arch/x86/boot/compressed/head_64.S
··· 452 452 .global efi64_config 453 453 efi64_config: 454 454 .fill 11,8,0 455 - .quad efi_call6 455 + .quad efi_call 456 456 .byte 1 457 457 #endif /* CONFIG_EFI_STUB */ 458 458
+31 -63
arch/x86/include/asm/efi.h
··· 1 1 #ifndef _ASM_X86_EFI_H 2 2 #define _ASM_X86_EFI_H 3 3 4 + #include <asm/i387.h> 4 5 /* 5 6 * We map the EFI regions needed for runtime services non-contiguously, 6 7 * with preserved alignment on virtual addresses starting from -4G down ··· 28 27 29 28 extern unsigned long asmlinkage efi_call_phys(void *, ...); 30 29 31 - #define efi_call_phys0(f) efi_call_phys(f) 32 - #define efi_call_phys1(f, a1) efi_call_phys(f, a1) 33 - #define efi_call_phys2(f, a1, a2) efi_call_phys(f, a1, a2) 34 - #define efi_call_phys3(f, a1, a2, a3) efi_call_phys(f, a1, a2, a3) 35 - #define efi_call_phys4(f, a1, a2, a3, a4) \ 36 - efi_call_phys(f, a1, a2, a3, a4) 37 - #define efi_call_phys5(f, a1, a2, a3, a4, a5) \ 38 - efi_call_phys(f, a1, a2, a3, a4, a5) 39 - #define efi_call_phys6(f, a1, a2, a3, a4, a5, a6) \ 40 - efi_call_phys(f, a1, a2, a3, a4, a5, a6) 41 30 /* 42 31 * Wrap all the virtual calls in a way that forces the parameters on the stack. 43 32 */ 44 33 34 + /* Use this macro if your virtual returns a non-void value */ 45 35 #define efi_call_virt(f, args...) \ 46 - ((efi_##f##_t __attribute__((regparm(0)))*)efi.systab->runtime->f)(args) 36 + ({ \ 37 + efi_status_t __s; \ 38 + kernel_fpu_begin(); \ 39 + __s = ((efi_##f##_t __attribute__((regparm(0)))*) \ 40 + efi.systab->runtime->f)(args); \ 41 + kernel_fpu_end(); \ 42 + __s; \ 43 + }) 47 44 48 - #define efi_call_virt0(f) efi_call_virt(f) 49 - #define efi_call_virt1(f, a1) efi_call_virt(f, a1) 50 - #define efi_call_virt2(f, a1, a2) efi_call_virt(f, a1, a2) 51 - #define efi_call_virt3(f, a1, a2, a3) efi_call_virt(f, a1, a2, a3) 52 - #define efi_call_virt4(f, a1, a2, a3, a4) \ 53 - efi_call_virt(f, a1, a2, a3, a4) 54 - #define efi_call_virt5(f, a1, a2, a3, a4, a5) \ 55 - efi_call_virt(f, a1, a2, a3, a4, a5) 56 - #define efi_call_virt6(f, a1, a2, a3, a4, a5, a6) \ 57 - efi_call_virt(f, a1, a2, a3, a4, a5, a6) 45 + /* Use this macro if your virtual call does not return any value */ 46 + #define __efi_call_virt(f, args...) \ 47 + ({ \ 48 + kernel_fpu_begin(); \ 49 + ((efi_##f##_t __attribute__((regparm(0)))*) \ 50 + efi.systab->runtime->f)(args); \ 51 + kernel_fpu_end(); \ 52 + }) 58 53 59 54 #define efi_ioremap(addr, size, type, attr) ioremap_cache(addr, size) 60 55 61 56 #else /* !CONFIG_X86_32 */ 62 57 63 - extern u64 efi_call0(void *fp); 64 - extern u64 efi_call1(void *fp, u64 arg1); 65 - extern u64 efi_call2(void *fp, u64 arg1, u64 arg2); 66 - extern u64 efi_call3(void *fp, u64 arg1, u64 arg2, u64 arg3); 67 - extern u64 efi_call4(void *fp, u64 arg1, u64 arg2, u64 arg3, u64 arg4); 68 - extern u64 efi_call5(void *fp, u64 arg1, u64 arg2, u64 arg3, 69 - u64 arg4, u64 arg5); 70 - extern u64 efi_call6(void *fp, u64 arg1, u64 arg2, u64 arg3, 71 - u64 arg4, u64 arg5, u64 arg6); 58 + #define EFI_LOADER_SIGNATURE "EL64" 72 59 73 - #define efi_call_phys0(f) \ 74 - efi_call0((f)) 75 - #define efi_call_phys1(f, a1) \ 76 - efi_call1((f), (u64)(a1)) 77 - #define efi_call_phys2(f, a1, a2) \ 78 - efi_call2((f), (u64)(a1), (u64)(a2)) 79 - #define efi_call_phys3(f, a1, a2, a3) \ 80 - efi_call3((f), (u64)(a1), (u64)(a2), (u64)(a3)) 81 - #define efi_call_phys4(f, a1, a2, a3, a4) \ 82 - efi_call4((f), (u64)(a1), (u64)(a2), (u64)(a3), \ 83 - (u64)(a4)) 84 - #define efi_call_phys5(f, a1, a2, a3, a4, a5) \ 85 - efi_call5((f), (u64)(a1), (u64)(a2), (u64)(a3), \ 86 - (u64)(a4), (u64)(a5)) 87 - #define efi_call_phys6(f, a1, a2, a3, a4, a5, a6) \ 88 - efi_call6((f), (u64)(a1), (u64)(a2), (u64)(a3), \ 89 - (u64)(a4), (u64)(a5), (u64)(a6)) 60 + extern u64 asmlinkage efi_call(void *fp, ...); 90 61 91 - #define _efi_call_virtX(x, f, ...) \ 62 + #define efi_call_phys(f, args...) efi_call((f), args) 63 + 64 + #define efi_call_virt(f, ...) \ 92 65 ({ \ 93 66 efi_status_t __s; \ 94 67 \ 95 68 efi_sync_low_kernel_mappings(); \ 96 69 preempt_disable(); \ 97 - __s = efi_call##x((void *)efi.systab->runtime->f, __VA_ARGS__); \ 70 + __kernel_fpu_begin(); \ 71 + __s = efi_call((void *)efi.systab->runtime->f, __VA_ARGS__); \ 72 + __kernel_fpu_end(); \ 98 73 preempt_enable(); \ 99 74 __s; \ 100 75 }) 101 76 102 - #define efi_call_virt0(f) \ 103 - _efi_call_virtX(0, f) 104 - #define efi_call_virt1(f, a1) \ 105 - _efi_call_virtX(1, f, (u64)(a1)) 106 - #define efi_call_virt2(f, a1, a2) \ 107 - _efi_call_virtX(2, f, (u64)(a1), (u64)(a2)) 108 - #define efi_call_virt3(f, a1, a2, a3) \ 109 - _efi_call_virtX(3, f, (u64)(a1), (u64)(a2), (u64)(a3)) 110 - #define efi_call_virt4(f, a1, a2, a3, a4) \ 111 - _efi_call_virtX(4, f, (u64)(a1), (u64)(a2), (u64)(a3), (u64)(a4)) 112 - #define efi_call_virt5(f, a1, a2, a3, a4, a5) \ 113 - _efi_call_virtX(5, f, (u64)(a1), (u64)(a2), (u64)(a3), (u64)(a4), (u64)(a5)) 114 - #define efi_call_virt6(f, a1, a2, a3, a4, a5, a6) \ 115 - _efi_call_virtX(6, f, (u64)(a1), (u64)(a2), (u64)(a3), (u64)(a4), (u64)(a5), (u64)(a6)) 77 + /* 78 + * All X86_64 virt calls return non-void values. Thus, use non-void call for 79 + * virt calls that would be void on X86_32. 80 + */ 81 + #define __efi_call_virt(f, args...) efi_call_virt(f, args) 116 82 117 83 extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size, 118 84 u32 type, u64 attribute);
+5 -5
arch/x86/include/asm/fpu-internal.h
··· 87 87 88 88 static __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 93 93 static __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 98 98 static __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 103 103 static __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 108 108 static inline void fx_finit(struct i387_fxsave_struct *fx) ··· 293 293 /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception 294 294 is pending. Clear the x87 state here by setting it to fixed 295 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 297 asm volatile( 298 298 "fnclex\n\t" 299 299 "emms\n\t"
+23 -25
arch/x86/platform/efi/efi.c
··· 110 110 efi_status_t status; 111 111 112 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 114 spin_unlock_irqrestore(&rtc_lock, flags); 115 115 return status; 116 116 } ··· 121 121 efi_status_t status; 122 122 123 123 spin_lock_irqsave(&rtc_lock, flags); 124 - status = efi_call_virt1(set_time, tm); 124 + status = efi_call_virt(set_time, tm); 125 125 spin_unlock_irqrestore(&rtc_lock, flags); 126 126 return status; 127 127 } ··· 134 134 efi_status_t status; 135 135 136 136 spin_lock_irqsave(&rtc_lock, flags); 137 - status = efi_call_virt3(get_wakeup_time, 138 - enabled, pending, tm); 137 + status = efi_call_virt(get_wakeup_time, enabled, pending, tm); 139 138 spin_unlock_irqrestore(&rtc_lock, flags); 140 139 return status; 141 140 } ··· 145 146 efi_status_t status; 146 147 147 148 spin_lock_irqsave(&rtc_lock, flags); 148 - status = efi_call_virt2(set_wakeup_time, 149 - enabled, tm); 149 + status = efi_call_virt(set_wakeup_time, enabled, tm); 150 150 spin_unlock_irqrestore(&rtc_lock, flags); 151 151 return status; 152 152 } ··· 156 158 unsigned long *data_size, 157 159 void *data) 158 160 { 159 - return efi_call_virt5(get_variable, 160 - name, vendor, attr, 161 - data_size, data); 161 + return efi_call_virt(get_variable, 162 + name, vendor, attr, 163 + data_size, data); 162 164 } 163 165 164 166 static efi_status_t virt_efi_get_next_variable(unsigned long *name_size, 165 167 efi_char16_t *name, 166 168 efi_guid_t *vendor) 167 169 { 168 - return efi_call_virt3(get_next_variable, 169 - name_size, name, vendor); 170 + return efi_call_virt(get_next_variable, 171 + name_size, name, vendor); 170 172 } 171 173 172 174 static efi_status_t virt_efi_set_variable(efi_char16_t *name, ··· 175 177 unsigned long data_size, 176 178 void *data) 177 179 { 178 - return efi_call_virt5(set_variable, 179 - name, vendor, attr, 180 - data_size, data); 180 + return efi_call_virt(set_variable, 181 + name, vendor, attr, 182 + data_size, data); 181 183 } 182 184 183 185 static efi_status_t virt_efi_query_variable_info(u32 attr, ··· 188 190 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 189 191 return EFI_UNSUPPORTED; 190 192 191 - return efi_call_virt4(query_variable_info, attr, storage_space, 192 - remaining_space, max_variable_size); 193 + return efi_call_virt(query_variable_info, attr, storage_space, 194 + remaining_space, max_variable_size); 193 195 } 194 196 195 197 static efi_status_t virt_efi_get_next_high_mono_count(u32 *count) 196 198 { 197 - return efi_call_virt1(get_next_high_mono_count, count); 199 + return efi_call_virt(get_next_high_mono_count, count); 198 200 } 199 201 200 202 static void virt_efi_reset_system(int reset_type, ··· 202 204 unsigned long data_size, 203 205 efi_char16_t *data) 204 206 { 205 - efi_call_virt4(reset_system, reset_type, status, 206 - data_size, data); 207 + __efi_call_virt(reset_system, reset_type, status, 208 + data_size, data); 207 209 } 208 210 209 211 static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules, ··· 213 215 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 214 216 return EFI_UNSUPPORTED; 215 217 216 - return efi_call_virt3(update_capsule, capsules, count, sg_list); 218 + return efi_call_virt(update_capsule, capsules, count, sg_list); 217 219 } 218 220 219 221 static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, ··· 224 226 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 225 227 return EFI_UNSUPPORTED; 226 228 227 - return efi_call_virt4(query_capsule_caps, capsules, count, max_size, 228 - reset_type); 229 + return efi_call_virt(query_capsule_caps, capsules, count, max_size, 230 + reset_type); 229 231 } 230 232 231 233 static efi_status_t __init phys_efi_set_virtual_address_map( ··· 237 239 efi_status_t status; 238 240 239 241 efi_call_phys_prelog(); 240 - status = efi_call_phys4(efi_phys.set_virtual_address_map, 241 - memory_map_size, descriptor_size, 242 - descriptor_version, virtual_map); 242 + status = efi_call_phys(efi_phys.set_virtual_address_map, 243 + memory_map_size, descriptor_size, 244 + descriptor_version, virtual_map); 243 245 efi_call_phys_epilog(); 244 246 return status; 245 247 }
+2 -79
arch/x86/platform/efi/efi_stub_64.S
··· 73 73 2: 74 74 .endm 75 75 76 - ENTRY(efi_call0) 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 85 - ENDPROC(efi_call0) 86 - 87 - ENTRY(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 97 - ENDPROC(efi_call1) 98 - 99 - ENTRY(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 109 - ENDPROC(efi_call2) 110 - 111 - ENTRY(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 122 - ENDPROC(efi_call3) 123 - 124 - ENTRY(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 136 - ENDPROC(efi_call4) 137 - 138 - ENTRY(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 151 - ENDPROC(efi_call5) 152 - 153 - ENTRY(efi_call6) 76 + ENTRY(efi_call) 154 77 SAVE_XMM 155 78 mov (%rsp), %rax 156 79 mov 8(%rax), %rax ··· 89 166 addq $48, %rsp 90 167 RESTORE_XMM 91 168 ret 92 - ENDPROC(efi_call6) 169 + ENDPROC(efi_call) 93 170 94 171 #ifdef CONFIG_EFI_MIXED 95 172
+1 -1
arch/x86/platform/uv/bios_uv.c
··· 39 39 */ 40 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 43 a1, a2, a3, a4, a5); 44 44 return ret; 45 45 }
+107 -37
drivers/firmware/efi/efi-stub-helper.c
··· 11 11 */ 12 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 + 14 18 struct file_info { 15 19 efi_file_handle_t *handle; 16 20 u64 size; ··· 36 32 efi_char16_printk(sys_table_arg, ch); 37 33 } 38 34 } 35 + 36 + #define pr_efi(sys_table, msg) efi_printk(sys_table, "EFI stub: "msg) 37 + #define pr_efi_err(sys_table, msg) efi_printk(sys_table, "EFI stub: ERROR: "msg) 39 38 40 39 41 40 static efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg, ··· 85 78 fail: 86 79 *map = m; 87 80 return status; 81 + } 82 + 83 + 84 + static unsigned long __init get_dram_base(efi_system_table_t *sys_table_arg) 85 + { 86 + efi_status_t status; 87 + unsigned long map_size; 88 + unsigned long membase = EFI_ERROR; 89 + struct efi_memory_map map; 90 + efi_memory_desc_t *md; 91 + 92 + status = efi_get_memory_map(sys_table_arg, (efi_memory_desc_t **)&map.map, 93 + &map_size, &map.desc_size, NULL, NULL); 94 + if (status != EFI_SUCCESS) 95 + return membase; 96 + 97 + map.map_end = map.map + map_size; 98 + 99 + for_each_efi_memory_desc(&map, md) 100 + if (md->attribute & EFI_MEMORY_WB) 101 + if (membase > md->phys_addr) 102 + membase = md->phys_addr; 103 + 104 + efi_call_early(free_pool, map.map); 105 + 106 + return membase; 88 107 } 89 108 90 109 /* ··· 300 267 struct file_info *files; 301 268 unsigned long file_addr; 302 269 u64 file_size_total; 303 - efi_file_handle_t *fh; 270 + efi_file_handle_t *fh = NULL; 304 271 efi_status_t status; 305 272 int nr_files; 306 273 char *str; ··· 343 310 status = efi_call_early(allocate_pool, EFI_LOADER_DATA, 344 311 nr_files * sizeof(*files), (void **)&files); 345 312 if (status != EFI_SUCCESS) { 346 - efi_printk(sys_table_arg, "Failed to alloc mem for file handle list\n"); 313 + pr_efi_err(sys_table_arg, "Failed to alloc mem for file handle list\n"); 347 314 goto fail; 348 315 } 349 316 ··· 407 374 status = efi_high_alloc(sys_table_arg, file_size_total, 0x1000, 408 375 &file_addr, max_addr); 409 376 if (status != EFI_SUCCESS) { 410 - efi_printk(sys_table_arg, "Failed to alloc highmem for files\n"); 377 + pr_efi_err(sys_table_arg, "Failed to alloc highmem for files\n"); 411 378 goto close_handles; 412 379 } 413 380 414 381 /* We've run out of free low memory. */ 415 382 if (file_addr > max_addr) { 416 - efi_printk(sys_table_arg, "We've run out of free low memory\n"); 383 + pr_efi_err(sys_table_arg, "We've run out of free low memory\n"); 417 384 status = EFI_INVALID_PARAMETER; 418 385 goto free_file_total; 419 386 } ··· 434 401 &chunksize, 435 402 (void *)addr); 436 403 if (status != EFI_SUCCESS) { 437 - efi_printk(sys_table_arg, "Failed to read file\n"); 404 + pr_efi_err(sys_table_arg, "Failed to read file\n"); 438 405 goto free_file_total; 439 406 } 440 407 addr += chunksize; ··· 519 486 &new_addr); 520 487 } 521 488 if (status != EFI_SUCCESS) { 522 - efi_printk(sys_table_arg, "ERROR: Failed to allocate usable memory for kernel.\n"); 489 + pr_efi_err(sys_table_arg, "Failed to allocate usable memory for kernel.\n"); 523 490 return status; 524 491 } 525 492 ··· 536 503 } 537 504 538 505 /* 506 + * Get the number of UTF-8 bytes corresponding to an UTF-16 character. 507 + * This overestimates for surrogates, but that is okay. 508 + */ 509 + static int efi_utf8_bytes(u16 c) 510 + { 511 + return 1 + (c >= 0x80) + (c >= 0x800); 512 + } 513 + 514 + /* 515 + * Convert an UTF-16 string, not necessarily null terminated, to UTF-8. 516 + */ 517 + static u8 *efi_utf16_to_utf8(u8 *dst, const u16 *src, int n) 518 + { 519 + unsigned int c; 520 + 521 + while (n--) { 522 + c = *src++; 523 + if (n && c >= 0xd800 && c <= 0xdbff && 524 + *src >= 0xdc00 && *src <= 0xdfff) { 525 + c = 0x10000 + ((c & 0x3ff) << 10) + (*src & 0x3ff); 526 + src++; 527 + n--; 528 + } 529 + if (c >= 0xd800 && c <= 0xdfff) 530 + c = 0xfffd; /* Unmatched surrogate */ 531 + if (c < 0x80) { 532 + *dst++ = c; 533 + continue; 534 + } 535 + if (c < 0x800) { 536 + *dst++ = 0xc0 + (c >> 6); 537 + goto t1; 538 + } 539 + if (c < 0x10000) { 540 + *dst++ = 0xe0 + (c >> 12); 541 + goto t2; 542 + } 543 + *dst++ = 0xf0 + (c >> 18); 544 + *dst++ = 0x80 + ((c >> 12) & 0x3f); 545 + t2: 546 + *dst++ = 0x80 + ((c >> 6) & 0x3f); 547 + t1: 548 + *dst++ = 0x80 + (c & 0x3f); 549 + } 550 + 551 + return dst; 552 + } 553 + 554 + /* 539 555 * Convert the unicode UEFI command line to ASCII to pass to kernel. 540 556 * Size of memory allocated return in *cmd_line_len. 541 557 * Returns NULL on error. 542 558 */ 543 - static char *efi_convert_cmdline_to_ascii(efi_system_table_t *sys_table_arg, 544 - efi_loaded_image_t *image, 545 - int *cmd_line_len) 559 + static char *efi_convert_cmdline(efi_system_table_t *sys_table_arg, 560 + efi_loaded_image_t *image, 561 + int *cmd_line_len) 546 562 { 547 - u16 *s2; 563 + const u16 *s2; 548 564 u8 *s1 = NULL; 549 565 unsigned long cmdline_addr = 0; 550 - int load_options_size = image->load_options_size / 2; /* ASCII */ 551 - void *options = image->load_options; 552 - int options_size = 0; 566 + int load_options_chars = image->load_options_size / 2; /* UTF-16 */ 567 + const u16 *options = image->load_options; 568 + int options_bytes = 0; /* UTF-8 bytes */ 569 + int options_chars = 0; /* UTF-16 chars */ 553 570 efi_status_t status; 554 - int i; 555 571 u16 zero = 0; 556 572 557 573 if (options) { 558 574 s2 = options; 559 - while (*s2 && *s2 != '\n' && options_size < load_options_size) { 560 - s2++; 561 - options_size++; 575 + while (*s2 && *s2 != '\n' 576 + && options_chars < load_options_chars) { 577 + options_bytes += efi_utf8_bytes(*s2++); 578 + options_chars++; 562 579 } 563 580 } 564 581 565 - if (options_size == 0) { 582 + if (!options_chars) { 566 583 /* No command line options, so return empty string*/ 567 - options_size = 1; 568 584 options = &zero; 569 585 } 570 586 571 - options_size++; /* NUL termination */ 572 - #ifdef CONFIG_ARM 573 - /* 574 - * For ARM, allocate at a high address to avoid reserved 575 - * regions at low addresses that we don't know the specfics of 576 - * at the time we are processing the command line. 577 - */ 578 - status = efi_high_alloc(sys_table_arg, options_size, 0, 579 - &cmdline_addr, 0xfffff000); 580 - #else 581 - status = efi_low_alloc(sys_table_arg, options_size, 0, 582 - &cmdline_addr); 583 - #endif 587 + options_bytes++; /* NUL termination */ 588 + 589 + status = efi_low_alloc(sys_table_arg, options_bytes, 0, &cmdline_addr); 584 590 if (status != EFI_SUCCESS) 585 591 return NULL; 586 592 587 593 s1 = (u8 *)cmdline_addr; 588 - s2 = (u16 *)options; 594 + s2 = (const u16 *)options; 589 595 590 - for (i = 0; i < options_size - 1; i++) 591 - *s1++ = *s2++; 592 - 596 + s1 = efi_utf16_to_utf8(s1, s2, options_chars); 593 597 *s1 = '\0'; 594 598 595 - *cmd_line_len = options_size; 599 + *cmd_line_len = options_bytes; 596 600 return (char *)cmdline_addr; 597 601 }
+167 -35
drivers/firmware/efi/efivars.c
··· 69 69 #include <linux/module.h> 70 70 #include <linux/slab.h> 71 71 #include <linux/ucs2_string.h> 72 + #include <linux/compat.h> 72 73 73 74 #define EFIVARS_VERSION "0.08" 74 75 #define EFIVARS_DATE "2004-May-17" ··· 86 85 87 86 static struct bin_attribute *efivars_new_var; 88 87 static struct bin_attribute *efivars_del_var; 88 + 89 + struct compat_efi_variable { 90 + efi_char16_t VariableName[EFI_VAR_NAME_LEN/sizeof(efi_char16_t)]; 91 + efi_guid_t VendorGuid; 92 + __u32 DataSize; 93 + __u8 Data[1024]; 94 + __u32 Status; 95 + __u32 Attributes; 96 + } __packed; 89 97 90 98 struct efivar_attribute { 91 99 struct attribute attr; ··· 199 189 memcpy(buf, var->Data, var->DataSize); 200 190 return var->DataSize; 201 191 } 192 + 193 + static inline int 194 + sanity_check(struct efi_variable *var, efi_char16_t *name, efi_guid_t vendor, 195 + unsigned long size, u32 attributes, u8 *data) 196 + { 197 + /* 198 + * If only updating the variable data, then the name 199 + * and guid should remain the same 200 + */ 201 + if (memcmp(name, var->VariableName, sizeof(var->VariableName)) || 202 + efi_guidcmp(vendor, var->VendorGuid)) { 203 + printk(KERN_ERR "efivars: Cannot edit the wrong variable!\n"); 204 + return -EINVAL; 205 + } 206 + 207 + if ((size <= 0) || (attributes == 0)){ 208 + printk(KERN_ERR "efivars: DataSize & Attributes must be valid!\n"); 209 + return -EINVAL; 210 + } 211 + 212 + if ((attributes & ~EFI_VARIABLE_MASK) != 0 || 213 + efivar_validate(name, data, size) == false) { 214 + printk(KERN_ERR "efivars: Malformed variable content\n"); 215 + return -EINVAL; 216 + } 217 + 218 + return 0; 219 + } 220 + 221 + static inline bool is_compat(void) 222 + { 223 + if (IS_ENABLED(CONFIG_COMPAT) && is_compat_task()) 224 + return true; 225 + 226 + return false; 227 + } 228 + 229 + static void 230 + copy_out_compat(struct efi_variable *dst, struct compat_efi_variable *src) 231 + { 232 + memcpy(dst->VariableName, src->VariableName, EFI_VAR_NAME_LEN); 233 + memcpy(dst->Data, src->Data, sizeof(src->Data)); 234 + 235 + dst->VendorGuid = src->VendorGuid; 236 + dst->DataSize = src->DataSize; 237 + dst->Attributes = src->Attributes; 238 + } 239 + 202 240 /* 203 241 * We allow each variable to be edited via rewriting the 204 242 * entire efi variable structure. ··· 255 197 efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count) 256 198 { 257 199 struct efi_variable *new_var, *var = &entry->var; 200 + efi_char16_t *name; 201 + unsigned long size; 202 + efi_guid_t vendor; 203 + u32 attributes; 204 + u8 *data; 258 205 int err; 259 206 260 - if (count != sizeof(struct efi_variable)) 261 - return -EINVAL; 207 + if (is_compat()) { 208 + struct compat_efi_variable *compat; 262 209 263 - new_var = (struct efi_variable *)buf; 264 - /* 265 - * If only updating the variable data, then the name 266 - * and guid should remain the same 267 - */ 268 - if (memcmp(new_var->VariableName, var->VariableName, sizeof(var->VariableName)) || 269 - efi_guidcmp(new_var->VendorGuid, var->VendorGuid)) { 270 - printk(KERN_ERR "efivars: Cannot edit the wrong variable!\n"); 271 - return -EINVAL; 210 + if (count != sizeof(*compat)) 211 + return -EINVAL; 212 + 213 + compat = (struct compat_efi_variable *)buf; 214 + attributes = compat->Attributes; 215 + vendor = compat->VendorGuid; 216 + name = compat->VariableName; 217 + size = compat->DataSize; 218 + data = compat->Data; 219 + 220 + err = sanity_check(var, name, vendor, size, attributes, data); 221 + if (err) 222 + return err; 223 + 224 + copy_out_compat(&entry->var, compat); 225 + } else { 226 + if (count != sizeof(struct efi_variable)) 227 + return -EINVAL; 228 + 229 + new_var = (struct efi_variable *)buf; 230 + 231 + attributes = new_var->Attributes; 232 + vendor = new_var->VendorGuid; 233 + name = new_var->VariableName; 234 + size = new_var->DataSize; 235 + data = new_var->Data; 236 + 237 + err = sanity_check(var, name, vendor, size, attributes, data); 238 + if (err) 239 + return err; 240 + 241 + memcpy(&entry->var, new_var, count); 272 242 } 273 243 274 - if ((new_var->DataSize <= 0) || (new_var->Attributes == 0)){ 275 - printk(KERN_ERR "efivars: DataSize & Attributes must be valid!\n"); 276 - return -EINVAL; 277 - } 278 - 279 - if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || 280 - efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) { 281 - printk(KERN_ERR "efivars: Malformed variable content\n"); 282 - return -EINVAL; 283 - } 284 - 285 - memcpy(&entry->var, new_var, count); 286 - 287 - err = efivar_entry_set(entry, new_var->Attributes, 288 - new_var->DataSize, new_var->Data, NULL); 244 + err = efivar_entry_set(entry, attributes, size, data, NULL); 289 245 if (err) { 290 246 printk(KERN_WARNING "efivars: set_variable() failed: status=%d\n", err); 291 247 return -EIO; ··· 312 240 efivar_show_raw(struct efivar_entry *entry, char *buf) 313 241 { 314 242 struct efi_variable *var = &entry->var; 243 + struct compat_efi_variable *compat; 244 + size_t size; 315 245 316 246 if (!entry || !buf) 317 247 return 0; ··· 323 249 &entry->var.DataSize, entry->var.Data)) 324 250 return -EIO; 325 251 326 - memcpy(buf, var, sizeof(*var)); 252 + if (is_compat()) { 253 + compat = (struct compat_efi_variable *)buf; 327 254 328 - return sizeof(*var); 255 + size = sizeof(*compat); 256 + memcpy(compat->VariableName, var->VariableName, 257 + EFI_VAR_NAME_LEN); 258 + memcpy(compat->Data, var->Data, sizeof(compat->Data)); 259 + 260 + compat->VendorGuid = var->VendorGuid; 261 + compat->DataSize = var->DataSize; 262 + compat->Attributes = var->Attributes; 263 + } else { 264 + size = sizeof(*var); 265 + memcpy(buf, var, size); 266 + } 267 + 268 + return size; 329 269 } 330 270 331 271 /* ··· 414 326 struct bin_attribute *bin_attr, 415 327 char *buf, loff_t pos, size_t count) 416 328 { 329 + struct compat_efi_variable *compat = (struct compat_efi_variable *)buf; 417 330 struct efi_variable *new_var = (struct efi_variable *)buf; 418 331 struct efivar_entry *new_entry; 332 + bool need_compat = is_compat(); 333 + efi_char16_t *name; 334 + unsigned long size; 335 + u32 attributes; 336 + u8 *data; 419 337 int err; 420 338 421 339 if (!capable(CAP_SYS_ADMIN)) 422 340 return -EACCES; 423 341 424 - if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || 425 - efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) { 342 + if (need_compat) { 343 + if (count != sizeof(*compat)) 344 + return -EINVAL; 345 + 346 + attributes = compat->Attributes; 347 + name = compat->VariableName; 348 + size = compat->DataSize; 349 + data = compat->Data; 350 + } else { 351 + if (count != sizeof(*new_var)) 352 + return -EINVAL; 353 + 354 + attributes = new_var->Attributes; 355 + name = new_var->VariableName; 356 + size = new_var->DataSize; 357 + data = new_var->Data; 358 + } 359 + 360 + if ((attributes & ~EFI_VARIABLE_MASK) != 0 || 361 + efivar_validate(name, data, size) == false) { 426 362 printk(KERN_ERR "efivars: Malformed variable content\n"); 427 363 return -EINVAL; 428 364 } ··· 455 343 if (!new_entry) 456 344 return -ENOMEM; 457 345 458 - memcpy(&new_entry->var, new_var, sizeof(*new_var)); 346 + if (need_compat) 347 + copy_out_compat(&new_entry->var, compat); 348 + else 349 + memcpy(&new_entry->var, new_var, sizeof(*new_var)); 459 350 460 - err = efivar_entry_set(new_entry, new_var->Attributes, new_var->DataSize, 461 - new_var->Data, &efivar_sysfs_list); 351 + err = efivar_entry_set(new_entry, attributes, size, 352 + data, &efivar_sysfs_list); 462 353 if (err) { 463 354 if (err == -EEXIST) 464 355 err = -EINVAL; ··· 484 369 char *buf, loff_t pos, size_t count) 485 370 { 486 371 struct efi_variable *del_var = (struct efi_variable *)buf; 372 + struct compat_efi_variable *compat; 487 373 struct efivar_entry *entry; 374 + efi_char16_t *name; 375 + efi_guid_t vendor; 488 376 int err = 0; 489 377 490 378 if (!capable(CAP_SYS_ADMIN)) 491 379 return -EACCES; 492 380 381 + if (is_compat()) { 382 + if (count != sizeof(*compat)) 383 + return -EINVAL; 384 + 385 + compat = (struct compat_efi_variable *)buf; 386 + name = compat->VariableName; 387 + vendor = compat->VendorGuid; 388 + } else { 389 + if (count != sizeof(*del_var)) 390 + return -EINVAL; 391 + 392 + name = del_var->VariableName; 393 + vendor = del_var->VendorGuid; 394 + } 395 + 493 396 efivar_entry_iter_begin(); 494 - entry = efivar_entry_find(del_var->VariableName, del_var->VendorGuid, 495 - &efivar_sysfs_list, true); 397 + entry = efivar_entry_find(name, vendor, &efivar_sysfs_list, true); 496 398 if (!entry) 497 399 err = -EINVAL; 498 400 else if (__efivar_entry_delete(entry))
+15 -15
drivers/firmware/efi/vars.c
··· 42 42 EXPORT_SYMBOL_GPL(efivar_work); 43 43 44 44 static bool 45 - validate_device_path(struct efi_variable *var, int match, u8 *buffer, 45 + validate_device_path(efi_char16_t *var_name, int match, u8 *buffer, 46 46 unsigned long len) 47 47 { 48 48 struct efi_generic_dev_path *node; ··· 75 75 } 76 76 77 77 static bool 78 - validate_boot_order(struct efi_variable *var, int match, u8 *buffer, 78 + validate_boot_order(efi_char16_t *var_name, int match, u8 *buffer, 79 79 unsigned long len) 80 80 { 81 81 /* An array of 16-bit integers */ ··· 86 86 } 87 87 88 88 static bool 89 - validate_load_option(struct efi_variable *var, int match, u8 *buffer, 89 + validate_load_option(efi_char16_t *var_name, int match, u8 *buffer, 90 90 unsigned long len) 91 91 { 92 92 u16 filepathlength; 93 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 97 /* Either "Boot" or "Driver" followed by four digits of hex */ 98 98 for (i = match; i < match+4; i++) { 99 - if (var->VariableName[i] > 127 || 100 - hex_to_bin(var->VariableName[i] & 0xff) < 0) 99 + if (var_name[i] > 127 || 100 + hex_to_bin(var_name[i] & 0xff) < 0) 101 101 return true; 102 102 } 103 103 ··· 132 132 /* 133 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 136 filepathlength); 137 137 } 138 138 139 139 static bool 140 - validate_uint16(struct efi_variable *var, int match, u8 *buffer, 140 + validate_uint16(efi_char16_t *var_name, int match, u8 *buffer, 141 141 unsigned long len) 142 142 { 143 143 /* A single 16-bit integer */ ··· 148 148 } 149 149 150 150 static bool 151 - validate_ascii_string(struct efi_variable *var, int match, u8 *buffer, 151 + validate_ascii_string(efi_char16_t *var_name, int match, u8 *buffer, 152 152 unsigned long len) 153 153 { 154 154 int i; ··· 166 166 167 167 struct variable_validate { 168 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 170 unsigned long len); 171 171 }; 172 172 ··· 189 189 }; 190 190 191 191 bool 192 - efivar_validate(struct efi_variable *var, u8 *data, unsigned long len) 192 + efivar_validate(efi_char16_t *var_name, u8 *data, unsigned long len) 193 193 { 194 194 int i; 195 - u16 *unicode_name = var->VariableName; 195 + u16 *unicode_name = var_name; 196 196 197 197 for (i = 0; variable_validate[i].validate != NULL; i++) { 198 198 const char *name = variable_validate[i].name; ··· 208 208 209 209 /* Wildcard in the matching name means we've matched */ 210 210 if (c == '*') 211 - return variable_validate[i].validate(var, 211 + return variable_validate[i].validate(var_name, 212 212 match, data, len); 213 213 214 214 /* Case sensitive match */ ··· 217 217 218 218 /* Reached the end of the string while matching */ 219 219 if (!c) 220 - return variable_validate[i].validate(var, 220 + return variable_validate[i].validate(var_name, 221 221 match, data, len); 222 222 } 223 223 } ··· 805 805 806 806 *set = false; 807 807 808 - if (efivar_validate(&entry->var, data, *size) == false) 808 + if (efivar_validate(name, data, *size) == false) 809 809 return -EINVAL; 810 810 811 811 /*
+10 -2
include/linux/efi.h
··· 863 863 extern void efi_reserve_boot_services(void); 864 864 extern 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 873 * efi_range_is_wc - check the WC bit on an address range 868 874 * @start: starting kvirt address ··· 1039 1033 * and we use a page for reading/writing. 1040 1034 */ 1041 1035 1036 + #define EFI_VAR_NAME_LEN 1024 1037 + 1042 1038 struct efi_variable { 1043 - efi_char16_t VariableName[1024/sizeof(efi_char16_t)]; 1039 + efi_char16_t VariableName[EFI_VAR_NAME_LEN/sizeof(efi_char16_t)]; 1044 1040 efi_guid_t VendorGuid; 1045 1041 unsigned long DataSize; 1046 1042 __u8 Data[1024]; ··· 1124 1116 struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid, 1125 1117 struct list_head *head, bool remove); 1126 1118 1127 - bool efivar_validate(struct efi_variable *var, u8 *data, unsigned long len); 1119 + bool efivar_validate(efi_char16_t *var_name, u8 *data, unsigned long len); 1128 1120 1129 1121 extern struct work_struct efivar_work; 1130 1122 void efivar_run_worker(void);