diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-30 20:44:10 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-30 20:44:10 -0400 |
| commit | 484b002e28ca328195829ddc06fa9082c8ad41f8 (patch) | |
| tree | f407d16112b9916854e4c3a22d4d9ea8dae90048 | |
| parent | 3655b22de04e3635fe3a2d7b9529cb12609a9bd0 (diff) | |
| parent | 5187b28ff08249ab8a162e802209ed04e271ca02 (diff) | |
Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 fixes from Peter Anvin:
- Three EFI-related fixes
- Two early memory initialization fixes
- build fix for older binutils
- fix for an eager FPU performance regression -- currently we don't
allow the use of the FPU at interrupt time *at all* in eager mode,
which is clearly wrong.
* 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86: Allow FPU to be used at interrupt time even with eagerfpu
x86, crc32-pclmul: Fix build with older binutils
x86-64, init: Fix a possible wraparound bug in switchover in head_64.S
x86, range: fix missing merge during add range
x86, efi: initial the local variable of DataSize to zero
efivar: fix oops in efivar_update_sysfs_entries() caused by memory reuse
efivarfs: Never return ENOENT from firmware again
| -rw-r--r-- | arch/x86/crypto/crc32-pclmul_asm.S | 2 | ||||
| -rw-r--r-- | arch/x86/include/asm/inst.h | 74 | ||||
| -rw-r--r-- | arch/x86/kernel/head_64.S | 6 | ||||
| -rw-r--r-- | arch/x86/kernel/i387.c | 14 | ||||
| -rw-r--r-- | arch/x86/platform/efi/efi.c | 2 | ||||
| -rw-r--r-- | drivers/firmware/efi/efivars.c | 8 | ||||
| -rw-r--r-- | fs/efivarfs/file.c | 14 | ||||
| -rw-r--r-- | kernel/range.c | 8 |
8 files changed, 103 insertions, 25 deletions
diff --git a/arch/x86/crypto/crc32-pclmul_asm.S b/arch/x86/crypto/crc32-pclmul_asm.S index 94c27df8a549..f247304299a2 100644 --- a/arch/x86/crypto/crc32-pclmul_asm.S +++ b/arch/x86/crypto/crc32-pclmul_asm.S | |||
| @@ -240,7 +240,7 @@ fold_64: | |||
| 240 | pand %xmm3, %xmm1 | 240 | pand %xmm3, %xmm1 |
| 241 | PCLMULQDQ 0x00, CONSTANT, %xmm1 | 241 | PCLMULQDQ 0x00, CONSTANT, %xmm1 |
| 242 | pxor %xmm2, %xmm1 | 242 | pxor %xmm2, %xmm1 |
| 243 | pextrd $0x01, %xmm1, %eax | 243 | PEXTRD 0x01, %xmm1, %eax |
| 244 | 244 | ||
| 245 | ret | 245 | ret |
| 246 | ENDPROC(crc32_pclmul_le_16) | 246 | ENDPROC(crc32_pclmul_le_16) |
diff --git a/arch/x86/include/asm/inst.h b/arch/x86/include/asm/inst.h index 280bf7fb6aba..3e115273ed88 100644 --- a/arch/x86/include/asm/inst.h +++ b/arch/x86/include/asm/inst.h | |||
| @@ -9,12 +9,68 @@ | |||
| 9 | 9 | ||
| 10 | #define REG_NUM_INVALID 100 | 10 | #define REG_NUM_INVALID 100 |
| 11 | 11 | ||
| 12 | #define REG_TYPE_R64 0 | 12 | #define REG_TYPE_R32 0 |
| 13 | #define REG_TYPE_XMM 1 | 13 | #define REG_TYPE_R64 1 |
| 14 | #define REG_TYPE_XMM 2 | ||
| 14 | #define REG_TYPE_INVALID 100 | 15 | #define REG_TYPE_INVALID 100 |
| 15 | 16 | ||
| 17 | .macro R32_NUM opd r32 | ||
| 18 | \opd = REG_NUM_INVALID | ||
| 19 | .ifc \r32,%eax | ||
| 20 | \opd = 0 | ||
| 21 | .endif | ||
| 22 | .ifc \r32,%ecx | ||
| 23 | \opd = 1 | ||
| 24 | .endif | ||
| 25 | .ifc \r32,%edx | ||
| 26 | \opd = 2 | ||
| 27 | .endif | ||
| 28 | .ifc \r32,%ebx | ||
| 29 | \opd = 3 | ||
| 30 | .endif | ||
| 31 | .ifc \r32,%esp | ||
| 32 | \opd = 4 | ||
| 33 | .endif | ||
| 34 | .ifc \r32,%ebp | ||
| 35 | \opd = 5 | ||
| 36 | .endif | ||
| 37 | .ifc \r32,%esi | ||
| 38 | \opd = 6 | ||
| 39 | .endif | ||
| 40 | .ifc \r32,%edi | ||
| 41 | \opd = 7 | ||
| 42 | .endif | ||
| 43 | #ifdef CONFIG_X86_64 | ||
| 44 | .ifc \r32,%r8d | ||
| 45 | \opd = 8 | ||
| 46 | .endif | ||
| 47 | .ifc \r32,%r9d | ||
| 48 | \opd = 9 | ||
| 49 | .endif | ||
| 50 | .ifc \r32,%r10d | ||
| 51 | \opd = 10 | ||
| 52 | .endif | ||
| 53 | .ifc \r32,%r11d | ||
| 54 | \opd = 11 | ||
| 55 | .endif | ||
| 56 | .ifc \r32,%r12d | ||
| 57 | \opd = 12 | ||
| 58 | .endif | ||
| 59 | .ifc \r32,%r13d | ||
| 60 | \opd = 13 | ||
| 61 | .endif | ||
| 62 | .ifc \r32,%r14d | ||
| 63 | \opd = 14 | ||
| 64 | .endif | ||
| 65 | .ifc \r32,%r15d | ||
| 66 | \opd = 15 | ||
| 67 | .endif | ||
| 68 | #endif | ||
| 69 | .endm | ||
| 70 | |||
| 16 | .macro R64_NUM opd r64 | 71 | .macro R64_NUM opd r64 |
| 17 | \opd = REG_NUM_INVALID | 72 | \opd = REG_NUM_INVALID |
| 73 | #ifdef CONFIG_X86_64 | ||
| 18 | .ifc \r64,%rax | 74 | .ifc \r64,%rax |
| 19 | \opd = 0 | 75 | \opd = 0 |
| 20 | .endif | 76 | .endif |
| @@ -63,6 +119,7 @@ | |||
| 63 | .ifc \r64,%r15 | 119 | .ifc \r64,%r15 |
| 64 | \opd = 15 | 120 | \opd = 15 |
| 65 | .endif | 121 | .endif |
| 122 | #endif | ||
| 66 | .endm | 123 | .endm |
| 67 | 124 | ||
| 68 | .macro XMM_NUM opd xmm | 125 | .macro XMM_NUM opd xmm |
| @@ -118,10 +175,13 @@ | |||
| 118 | .endm | 175 | .endm |
| 119 | 176 | ||
| 120 | .macro REG_TYPE type reg | 177 | .macro REG_TYPE type reg |
| 178 | R32_NUM reg_type_r32 \reg | ||
| 121 | R64_NUM reg_type_r64 \reg | 179 | R64_NUM reg_type_r64 \reg |
| 122 | XMM_NUM reg_type_xmm \reg | 180 | XMM_NUM reg_type_xmm \reg |
| 123 | .if reg_type_r64 <> REG_NUM_INVALID | 181 | .if reg_type_r64 <> REG_NUM_INVALID |
| 124 | \type = REG_TYPE_R64 | 182 | \type = REG_TYPE_R64 |
| 183 | .elseif reg_type_r32 <> REG_NUM_INVALID | ||
| 184 | \type = REG_TYPE_R32 | ||
| 125 | .elseif reg_type_xmm <> REG_NUM_INVALID | 185 | .elseif reg_type_xmm <> REG_NUM_INVALID |
| 126 | \type = REG_TYPE_XMM | 186 | \type = REG_TYPE_XMM |
| 127 | .else | 187 | .else |
| @@ -162,6 +222,16 @@ | |||
| 162 | .byte \imm8 | 222 | .byte \imm8 |
| 163 | .endm | 223 | .endm |
| 164 | 224 | ||
| 225 | .macro PEXTRD imm8 xmm gpr | ||
| 226 | R32_NUM extrd_opd1 \gpr | ||
| 227 | XMM_NUM extrd_opd2 \xmm | ||
| 228 | PFX_OPD_SIZE | ||
| 229 | PFX_REX extrd_opd1 extrd_opd2 | ||
| 230 | .byte 0x0f, 0x3a, 0x16 | ||
| 231 | MODRM 0xc0 extrd_opd1 extrd_opd2 | ||
| 232 | .byte \imm8 | ||
| 233 | .endm | ||
| 234 | |||
| 165 | .macro AESKEYGENASSIST rcon xmm1 xmm2 | 235 | .macro AESKEYGENASSIST rcon xmm1 xmm2 |
| 166 | XMM_NUM aeskeygen_opd1 \xmm1 | 236 | XMM_NUM aeskeygen_opd1 \xmm1 |
| 167 | XMM_NUM aeskeygen_opd2 \xmm2 | 237 | XMM_NUM aeskeygen_opd2 \xmm2 |
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S index 08f7e8039099..321d65ebaffe 100644 --- a/arch/x86/kernel/head_64.S +++ b/arch/x86/kernel/head_64.S | |||
| @@ -115,8 +115,10 @@ startup_64: | |||
| 115 | movq %rdi, %rax | 115 | movq %rdi, %rax |
| 116 | shrq $PUD_SHIFT, %rax | 116 | shrq $PUD_SHIFT, %rax |
| 117 | andl $(PTRS_PER_PUD-1), %eax | 117 | andl $(PTRS_PER_PUD-1), %eax |
| 118 | movq %rdx, (4096+0)(%rbx,%rax,8) | 118 | movq %rdx, 4096(%rbx,%rax,8) |
| 119 | movq %rdx, (4096+8)(%rbx,%rax,8) | 119 | incl %eax |
| 120 | andl $(PTRS_PER_PUD-1), %eax | ||
| 121 | movq %rdx, 4096(%rbx,%rax,8) | ||
| 120 | 122 | ||
| 121 | addq $8192, %rbx | 123 | addq $8192, %rbx |
| 122 | movq %rdi, %rax | 124 | movq %rdi, %rax |
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c index 245a71db401a..cb339097b9ea 100644 --- a/arch/x86/kernel/i387.c +++ b/arch/x86/kernel/i387.c | |||
| @@ -22,23 +22,19 @@ | |||
| 22 | /* | 22 | /* |
| 23 | * Were we in an interrupt that interrupted kernel mode? | 23 | * Were we in an interrupt that interrupted kernel mode? |
| 24 | * | 24 | * |
| 25 | * For now, with eagerfpu we will return interrupted kernel FPU | ||
| 26 | * state as not-idle. TBD: Ideally we can change the return value | ||
| 27 | * to something like __thread_has_fpu(current). But we need to | ||
| 28 | * be careful of doing __thread_clear_has_fpu() before saving | ||
| 29 | * the FPU etc for supporting nested uses etc. For now, take | ||
| 30 | * the simple route! | ||
| 31 | * | ||
| 32 | * On others, we can do a kernel_fpu_begin/end() pair *ONLY* if that | 25 | * On others, we can do a kernel_fpu_begin/end() pair *ONLY* if that |
| 33 | * pair does nothing at all: the thread must not have fpu (so | 26 | * pair does nothing at all: the thread must not have fpu (so |
| 34 | * that we don't try to save the FPU state), and TS must | 27 | * that we don't try to save the FPU state), and TS must |
| 35 | * be set (so that the clts/stts pair does nothing that is | 28 | * be set (so that the clts/stts pair does nothing that is |
| 36 | * visible in the interrupted kernel thread). | 29 | * visible in the interrupted kernel thread). |
| 30 | * | ||
| 31 | * Except for the eagerfpu case when we return 1 unless we've already | ||
| 32 | * been eager and saved the state in kernel_fpu_begin(). | ||
| 37 | */ | 33 | */ |
| 38 | static inline bool interrupted_kernel_fpu_idle(void) | 34 | static inline bool interrupted_kernel_fpu_idle(void) |
| 39 | { | 35 | { |
| 40 | if (use_eager_fpu()) | 36 | if (use_eager_fpu()) |
| 41 | return 0; | 37 | return __thread_has_fpu(current); |
| 42 | 38 | ||
| 43 | return !__thread_has_fpu(current) && | 39 | return !__thread_has_fpu(current) && |
| 44 | (read_cr0() & X86_CR0_TS); | 40 | (read_cr0() & X86_CR0_TS); |
| @@ -78,8 +74,8 @@ void __kernel_fpu_begin(void) | |||
| 78 | struct task_struct *me = current; | 74 | struct task_struct *me = current; |
| 79 | 75 | ||
| 80 | if (__thread_has_fpu(me)) { | 76 | if (__thread_has_fpu(me)) { |
| 81 | __save_init_fpu(me); | ||
| 82 | __thread_clear_has_fpu(me); | 77 | __thread_clear_has_fpu(me); |
| 78 | __save_init_fpu(me); | ||
| 83 | /* We do 'stts()' in __kernel_fpu_end() */ | 79 | /* We do 'stts()' in __kernel_fpu_end() */ |
| 84 | } else if (!use_eager_fpu()) { | 80 | } else if (!use_eager_fpu()) { |
| 85 | this_cpu_write(fpu_owner_task, NULL); | 81 | this_cpu_write(fpu_owner_task, NULL); |
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 55856b2310d3..82089d8b1954 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c | |||
| @@ -206,7 +206,7 @@ static efi_status_t virt_efi_get_next_variable(unsigned long *name_size, | |||
| 206 | } | 206 | } |
| 207 | 207 | ||
| 208 | if (boot_used_size && !finished) { | 208 | if (boot_used_size && !finished) { |
| 209 | unsigned long size; | 209 | unsigned long size = 0; |
| 210 | u32 attr; | 210 | u32 attr; |
| 211 | efi_status_t s; | 211 | efi_status_t s; |
| 212 | void *tmp; | 212 | void *tmp; |
diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c index b623c599e572..8bd1bb6dbe47 100644 --- a/drivers/firmware/efi/efivars.c +++ b/drivers/firmware/efi/efivars.c | |||
| @@ -523,13 +523,11 @@ static void efivar_update_sysfs_entries(struct work_struct *work) | |||
| 523 | struct efivar_entry *entry; | 523 | struct efivar_entry *entry; |
| 524 | int err; | 524 | int err; |
| 525 | 525 | ||
| 526 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); | ||
| 527 | if (!entry) | ||
| 528 | return; | ||
| 529 | |||
| 530 | /* Add new sysfs entries */ | 526 | /* Add new sysfs entries */ |
| 531 | while (1) { | 527 | while (1) { |
| 532 | memset(entry, 0, sizeof(*entry)); | 528 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); |
| 529 | if (!entry) | ||
| 530 | return; | ||
| 533 | 531 | ||
| 534 | err = efivar_init(efivar_update_sysfs_entry, entry, | 532 | err = efivar_init(efivar_update_sysfs_entry, entry, |
| 535 | true, false, &efivar_sysfs_list); | 533 | true, false, &efivar_sysfs_list); |
diff --git a/fs/efivarfs/file.c b/fs/efivarfs/file.c index bfb531564319..8dd524f32284 100644 --- a/fs/efivarfs/file.c +++ b/fs/efivarfs/file.c | |||
| @@ -44,8 +44,11 @@ static ssize_t efivarfs_file_write(struct file *file, | |||
| 44 | 44 | ||
| 45 | bytes = efivar_entry_set_get_size(var, attributes, &datasize, | 45 | bytes = efivar_entry_set_get_size(var, attributes, &datasize, |
| 46 | data, &set); | 46 | data, &set); |
| 47 | if (!set && bytes) | 47 | if (!set && bytes) { |
| 48 | if (bytes == -ENOENT) | ||
| 49 | bytes = -EIO; | ||
| 48 | goto out; | 50 | goto out; |
| 51 | } | ||
| 49 | 52 | ||
| 50 | if (bytes == -ENOENT) { | 53 | if (bytes == -ENOENT) { |
| 51 | drop_nlink(inode); | 54 | drop_nlink(inode); |
| @@ -76,7 +79,14 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf, | |||
| 76 | int err; | 79 | int err; |
| 77 | 80 | ||
| 78 | err = efivar_entry_size(var, &datasize); | 81 | err = efivar_entry_size(var, &datasize); |
| 79 | if (err) | 82 | |
| 83 | /* | ||
| 84 | * efivarfs represents uncommitted variables with | ||
| 85 | * zero-length files. Reading them should return EOF. | ||
| 86 | */ | ||
| 87 | if (err == -ENOENT) | ||
| 88 | return 0; | ||
| 89 | else if (err) | ||
| 80 | return err; | 90 | return err; |
| 81 | 91 | ||
| 82 | data = kmalloc(datasize + sizeof(attributes), GFP_KERNEL); | 92 | data = kmalloc(datasize + sizeof(attributes), GFP_KERNEL); |
diff --git a/kernel/range.c b/kernel/range.c index 071b0ab455cb..eb911dbce267 100644 --- a/kernel/range.c +++ b/kernel/range.c | |||
| @@ -48,9 +48,11 @@ int add_range_with_merge(struct range *range, int az, int nr_range, | |||
| 48 | final_start = min(range[i].start, start); | 48 | final_start = min(range[i].start, start); |
| 49 | final_end = max(range[i].end, end); | 49 | final_end = max(range[i].end, end); |
| 50 | 50 | ||
| 51 | range[i].start = final_start; | 51 | /* clear it and add it back for further merge */ |
| 52 | range[i].end = final_end; | 52 | range[i].start = 0; |
| 53 | return nr_range; | 53 | range[i].end = 0; |
| 54 | return add_range_with_merge(range, az, nr_range, | ||
| 55 | final_start, final_end); | ||
| 54 | } | 56 | } |
| 55 | 57 | ||
| 56 | /* Need to add it: */ | 58 | /* Need to add it: */ |
