Skip to content

Commit 0389075

Browse files
committed
Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 fixes from Ingo Molnar: "This is unusually large, partly due to the EFI fixes that prevent accidental deletion of EFI variables through efivarfs that may brick machines. These fixes are somewhat involved to maintain compatibility with existing install methods and other usage modes, while trying to turn off the 'rm -rf' bricking vector. Other fixes are for large page ioremap()s and for non-temporal user-memcpy()s" * 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/mm: Fix vmalloc_fault() to handle large pages properly hpet: Drop stale URLs x86/uaccess/64: Handle the caching of 4-byte nocache copies properly in __copy_user_nocache() x86/uaccess/64: Make the __copy_user_nocache() assembly code more readable lib/ucs2_string: Correct ucs2 -> utf8 conversion efi: Add pstore variables to the deletion whitelist efi: Make efivarfs entries immutable by default efi: Make our variable validation list include the guid efi: Do variable name validation tests in utf8 efi: Use ucs2_as_utf8 in efivarfs instead of open coding a bad version lib/ucs2_string: Add ucs2 -> utf8 helper functions
2 parents 06b74c6 + f4eafd8 commit 0389075

File tree

17 files changed

+500
-134
lines changed

17 files changed

+500
-134
lines changed

Documentation/filesystems/efivarfs.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,10 @@ filesystem.
1414
efivarfs is typically mounted like this,
1515

1616
mount -t efivarfs none /sys/firmware/efi/efivars
17+
18+
Due to the presence of numerous firmware bugs where removing non-standard
19+
UEFI variables causes the system firmware to fail to POST, efivarfs
20+
files that are not well-known standardized variables are created
21+
as immutable files. This doesn't prevent removal - "chattr -i" will work -
22+
but it does prevent this kind of failure from being accomplished
23+
accidentally.

Documentation/timers/hpet.txt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
High Precision Event Timer Driver for Linux
22

33
The High Precision Event Timer (HPET) hardware follows a specification
4-
by Intel and Microsoft which can be found at
5-
6-
http://www.intel.com/hardwaredesign/hpetspec_1.pdf
4+
by Intel and Microsoft, revision 1.
75

86
Each HPET has one fixed-rate counter (at 10+ MHz, hence "High Precision")
97
and up to 32 comparators. Normally three or more comparators are provided,

arch/x86/Kconfig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -778,8 +778,8 @@ config HPET_TIMER
778778
HPET is the next generation timer replacing legacy 8254s.
779779
The HPET provides a stable time base on SMP
780780
systems, unlike the TSC, but it is more expensive to access,
781-
as it is off-chip. You can find the HPET spec at
782-
<http://www.intel.com/hardwaredesign/hpetspec_1.pdf>.
781+
as it is off-chip. The interface used is documented
782+
in the HPET spec, revision 1.
783783

784784
You can safely choose Y here. However, HPET will only be
785785
activated if the platform and the BIOS support this feature.

arch/x86/lib/copy_user_64.S

Lines changed: 101 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -232,17 +232,31 @@ ENDPROC(copy_user_enhanced_fast_string)
232232

233233
/*
234234
* copy_user_nocache - Uncached memory copy with exception handling
235-
* This will force destination/source out of cache for more performance.
235+
* This will force destination out of cache for more performance.
236+
*
237+
* Note: Cached memory copy is used when destination or size is not
238+
* naturally aligned. That is:
239+
* - Require 8-byte alignment when size is 8 bytes or larger.
240+
* - Require 4-byte alignment when size is 4 bytes.
236241
*/
237242
ENTRY(__copy_user_nocache)
238243
ASM_STAC
244+
245+
/* If size is less than 8 bytes, go to 4-byte copy */
239246
cmpl $8,%edx
240-
jb 20f /* less then 8 bytes, go to byte copy loop */
247+
jb .L_4b_nocache_copy_entry
248+
249+
/* If destination is not 8-byte aligned, "cache" copy to align it */
241250
ALIGN_DESTINATION
251+
252+
/* Set 4x8-byte copy count and remainder */
242253
movl %edx,%ecx
243254
andl $63,%edx
244255
shrl $6,%ecx
245-
jz 17f
256+
jz .L_8b_nocache_copy_entry /* jump if count is 0 */
257+
258+
/* Perform 4x8-byte nocache loop-copy */
259+
.L_4x8b_nocache_copy_loop:
246260
1: movq (%rsi),%r8
247261
2: movq 1*8(%rsi),%r9
248262
3: movq 2*8(%rsi),%r10
@@ -262,60 +276,106 @@ ENTRY(__copy_user_nocache)
262276
leaq 64(%rsi),%rsi
263277
leaq 64(%rdi),%rdi
264278
decl %ecx
265-
jnz 1b
266-
17: movl %edx,%ecx
279+
jnz .L_4x8b_nocache_copy_loop
280+
281+
/* Set 8-byte copy count and remainder */
282+
.L_8b_nocache_copy_entry:
283+
movl %edx,%ecx
267284
andl $7,%edx
268285
shrl $3,%ecx
269-
jz 20f
270-
18: movq (%rsi),%r8
271-
19: movnti %r8,(%rdi)
286+
jz .L_4b_nocache_copy_entry /* jump if count is 0 */
287+
288+
/* Perform 8-byte nocache loop-copy */
289+
.L_8b_nocache_copy_loop:
290+
20: movq (%rsi),%r8
291+
21: movnti %r8,(%rdi)
272292
leaq 8(%rsi),%rsi
273293
leaq 8(%rdi),%rdi
274294
decl %ecx
275-
jnz 18b
276-
20: andl %edx,%edx
277-
jz 23f
295+
jnz .L_8b_nocache_copy_loop
296+
297+
/* If no byte left, we're done */
298+
.L_4b_nocache_copy_entry:
299+
andl %edx,%edx
300+
jz .L_finish_copy
301+
302+
/* If destination is not 4-byte aligned, go to byte copy: */
303+
movl %edi,%ecx
304+
andl $3,%ecx
305+
jnz .L_1b_cache_copy_entry
306+
307+
/* Set 4-byte copy count (1 or 0) and remainder */
278308
movl %edx,%ecx
279-
21: movb (%rsi),%al
280-
22: movb %al,(%rdi)
309+
andl $3,%edx
310+
shrl $2,%ecx
311+
jz .L_1b_cache_copy_entry /* jump if count is 0 */
312+
313+
/* Perform 4-byte nocache copy: */
314+
30: movl (%rsi),%r8d
315+
31: movnti %r8d,(%rdi)
316+
leaq 4(%rsi),%rsi
317+
leaq 4(%rdi),%rdi
318+
319+
/* If no bytes left, we're done: */
320+
andl %edx,%edx
321+
jz .L_finish_copy
322+
323+
/* Perform byte "cache" loop-copy for the remainder */
324+
.L_1b_cache_copy_entry:
325+
movl %edx,%ecx
326+
.L_1b_cache_copy_loop:
327+
40: movb (%rsi),%al
328+
41: movb %al,(%rdi)
281329
incq %rsi
282330
incq %rdi
283331
decl %ecx
284-
jnz 21b
285-
23: xorl %eax,%eax
332+
jnz .L_1b_cache_copy_loop
333+
334+
/* Finished copying; fence the prior stores */
335+
.L_finish_copy:
336+
xorl %eax,%eax
286337
ASM_CLAC
287338
sfence
288339
ret
289340

290341
.section .fixup,"ax"
291-
30: shll $6,%ecx
342+
.L_fixup_4x8b_copy:
343+
shll $6,%ecx
292344
addl %ecx,%edx
293-
jmp 60f
294-
40: lea (%rdx,%rcx,8),%rdx
295-
jmp 60f
296-
50: movl %ecx,%edx
297-
60: sfence
345+
jmp .L_fixup_handle_tail
346+
.L_fixup_8b_copy:
347+
lea (%rdx,%rcx,8),%rdx
348+
jmp .L_fixup_handle_tail
349+
.L_fixup_4b_copy:
350+
lea (%rdx,%rcx,4),%rdx
351+
jmp .L_fixup_handle_tail
352+
.L_fixup_1b_copy:
353+
movl %ecx,%edx
354+
.L_fixup_handle_tail:
355+
sfence
298356
jmp copy_user_handle_tail
299357
.previous
300358

301-
_ASM_EXTABLE(1b,30b)
302-
_ASM_EXTABLE(2b,30b)
303-
_ASM_EXTABLE(3b,30b)
304-
_ASM_EXTABLE(4b,30b)
305-
_ASM_EXTABLE(5b,30b)
306-
_ASM_EXTABLE(6b,30b)
307-
_ASM_EXTABLE(7b,30b)
308-
_ASM_EXTABLE(8b,30b)
309-
_ASM_EXTABLE(9b,30b)
310-
_ASM_EXTABLE(10b,30b)
311-
_ASM_EXTABLE(11b,30b)
312-
_ASM_EXTABLE(12b,30b)
313-
_ASM_EXTABLE(13b,30b)
314-
_ASM_EXTABLE(14b,30b)
315-
_ASM_EXTABLE(15b,30b)
316-
_ASM_EXTABLE(16b,30b)
317-
_ASM_EXTABLE(18b,40b)
318-
_ASM_EXTABLE(19b,40b)
319-
_ASM_EXTABLE(21b,50b)
320-
_ASM_EXTABLE(22b,50b)
359+
_ASM_EXTABLE(1b,.L_fixup_4x8b_copy)
360+
_ASM_EXTABLE(2b,.L_fixup_4x8b_copy)
361+
_ASM_EXTABLE(3b,.L_fixup_4x8b_copy)
362+
_ASM_EXTABLE(4b,.L_fixup_4x8b_copy)
363+
_ASM_EXTABLE(5b,.L_fixup_4x8b_copy)
364+
_ASM_EXTABLE(6b,.L_fixup_4x8b_copy)
365+
_ASM_EXTABLE(7b,.L_fixup_4x8b_copy)
366+
_ASM_EXTABLE(8b,.L_fixup_4x8b_copy)
367+
_ASM_EXTABLE(9b,.L_fixup_4x8b_copy)
368+
_ASM_EXTABLE(10b,.L_fixup_4x8b_copy)
369+
_ASM_EXTABLE(11b,.L_fixup_4x8b_copy)
370+
_ASM_EXTABLE(12b,.L_fixup_4x8b_copy)
371+
_ASM_EXTABLE(13b,.L_fixup_4x8b_copy)
372+
_ASM_EXTABLE(14b,.L_fixup_4x8b_copy)
373+
_ASM_EXTABLE(15b,.L_fixup_4x8b_copy)
374+
_ASM_EXTABLE(16b,.L_fixup_4x8b_copy)
375+
_ASM_EXTABLE(20b,.L_fixup_8b_copy)
376+
_ASM_EXTABLE(21b,.L_fixup_8b_copy)
377+
_ASM_EXTABLE(30b,.L_fixup_4b_copy)
378+
_ASM_EXTABLE(31b,.L_fixup_4b_copy)
379+
_ASM_EXTABLE(40b,.L_fixup_1b_copy)
380+
_ASM_EXTABLE(41b,.L_fixup_1b_copy)
321381
ENDPROC(__copy_user_nocache)

arch/x86/mm/fault.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,9 @@ static noinline int vmalloc_fault(unsigned long address)
287287
if (!pmd_k)
288288
return -1;
289289

290+
if (pmd_huge(*pmd_k))
291+
return 0;
292+
290293
pte_k = pte_offset_kernel(pmd_k, address);
291294
if (!pte_present(*pte_k))
292295
return -1;
@@ -360,8 +363,6 @@ void vmalloc_sync_all(void)
360363
* 64-bit:
361364
*
362365
* Handle a fault on the vmalloc area
363-
*
364-
* This assumes no large pages in there.
365366
*/
366367
static noinline int vmalloc_fault(unsigned long address)
367368
{
@@ -403,17 +404,23 @@ static noinline int vmalloc_fault(unsigned long address)
403404
if (pud_none(*pud_ref))
404405
return -1;
405406

406-
if (pud_none(*pud) || pud_page_vaddr(*pud) != pud_page_vaddr(*pud_ref))
407+
if (pud_none(*pud) || pud_pfn(*pud) != pud_pfn(*pud_ref))
407408
BUG();
408409

410+
if (pud_huge(*pud))
411+
return 0;
412+
409413
pmd = pmd_offset(pud, address);
410414
pmd_ref = pmd_offset(pud_ref, address);
411415
if (pmd_none(*pmd_ref))
412416
return -1;
413417

414-
if (pmd_none(*pmd) || pmd_page(*pmd) != pmd_page(*pmd_ref))
418+
if (pmd_none(*pmd) || pmd_pfn(*pmd) != pmd_pfn(*pmd_ref))
415419
BUG();
416420

421+
if (pmd_huge(*pmd))
422+
return 0;
423+
417424
pte_ref = pte_offset_kernel(pmd_ref, address);
418425
if (!pte_present(*pte_ref))
419426
return -1;

drivers/char/hpet.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
/*
4343
* The High Precision Event Timer driver.
4444
* This driver is closely modelled after the rtc.c driver.
45-
* http://www.intel.com/hardwaredesign/hpetspec_1.pdf
45+
* See HPET spec revision 1.
4646
*/
4747
#define HPET_USER_FREQ (64)
4848
#define HPET_DRIFT (500)

drivers/firmware/efi/efivars.c

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ sanity_check(struct efi_variable *var, efi_char16_t *name, efi_guid_t vendor,
221221
}
222222

223223
if ((attributes & ~EFI_VARIABLE_MASK) != 0 ||
224-
efivar_validate(name, data, size) == false) {
224+
efivar_validate(vendor, name, data, size) == false) {
225225
printk(KERN_ERR "efivars: Malformed variable content\n");
226226
return -EINVAL;
227227
}
@@ -447,7 +447,8 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
447447
}
448448

449449
if ((attributes & ~EFI_VARIABLE_MASK) != 0 ||
450-
efivar_validate(name, data, size) == false) {
450+
efivar_validate(new_var->VendorGuid, name, data,
451+
size) == false) {
451452
printk(KERN_ERR "efivars: Malformed variable content\n");
452453
return -EINVAL;
453454
}
@@ -540,38 +541,30 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
540541
static int
541542
efivar_create_sysfs_entry(struct efivar_entry *new_var)
542543
{
543-
int i, short_name_size;
544+
int short_name_size;
544545
char *short_name;
545-
unsigned long variable_name_size;
546-
efi_char16_t *variable_name;
546+
unsigned long utf8_name_size;
547+
efi_char16_t *variable_name = new_var->var.VariableName;
547548
int ret;
548549

549-
variable_name = new_var->var.VariableName;
550-
variable_name_size = ucs2_strlen(variable_name) * sizeof(efi_char16_t);
551-
552550
/*
553-
* Length of the variable bytes in ASCII, plus the '-' separator,
551+
* Length of the variable bytes in UTF8, plus the '-' separator,
554552
* plus the GUID, plus trailing NUL
555553
*/
556-
short_name_size = variable_name_size / sizeof(efi_char16_t)
557-
+ 1 + EFI_VARIABLE_GUID_LEN + 1;
558-
559-
short_name = kzalloc(short_name_size, GFP_KERNEL);
554+
utf8_name_size = ucs2_utf8size(variable_name);
555+
short_name_size = utf8_name_size + 1 + EFI_VARIABLE_GUID_LEN + 1;
560556

557+
short_name = kmalloc(short_name_size, GFP_KERNEL);
561558
if (!short_name)
562559
return -ENOMEM;
563560

564-
/* Convert Unicode to normal chars (assume top bits are 0),
565-
ala UTF-8 */
566-
for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) {
567-
short_name[i] = variable_name[i] & 0xFF;
568-
}
561+
ucs2_as_utf8(short_name, variable_name, short_name_size);
562+
569563
/* This is ugly, but necessary to separate one vendor's
570564
private variables from another's. */
571-
572-
*(short_name + strlen(short_name)) = '-';
565+
short_name[utf8_name_size] = '-';
573566
efi_guid_to_str(&new_var->var.VendorGuid,
574-
short_name + strlen(short_name));
567+
short_name + utf8_name_size + 1);
575568

576569
new_var->kobj.kset = efivars_kset;
577570

0 commit comments

Comments
 (0)