Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 fixes from Ingo Molnar: "Microcode fixes, a Xen fix and a KASLR boot loading fix with certain memory layouts" * 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86, microcode, AMD: Fix ucode patch stashing on 32-bit x86/core, x86/xen/smp: Use 'die_complete' completion when taking CPU down x86, microcode: Fix accessing dis_ucode_ldr on 32-bit x86, kaslr: Prevent .bss from overlaping initrd x86, microcode, AMD: Fix early ucode loading on 32-bit
This commit is contained in:
commit
de55bbbff2
11 changed files with 94 additions and 26 deletions
|
@ -76,8 +76,10 @@ suffix-$(CONFIG_KERNEL_XZ) := xz
|
||||||
suffix-$(CONFIG_KERNEL_LZO) := lzo
|
suffix-$(CONFIG_KERNEL_LZO) := lzo
|
||||||
suffix-$(CONFIG_KERNEL_LZ4) := lz4
|
suffix-$(CONFIG_KERNEL_LZ4) := lz4
|
||||||
|
|
||||||
|
RUN_SIZE = $(shell objdump -h vmlinux | \
|
||||||
|
perl $(srctree)/arch/x86/tools/calc_run_size.pl)
|
||||||
quiet_cmd_mkpiggy = MKPIGGY $@
|
quiet_cmd_mkpiggy = MKPIGGY $@
|
||||||
cmd_mkpiggy = $(obj)/mkpiggy $< > $@ || ( rm -f $@ ; false )
|
cmd_mkpiggy = $(obj)/mkpiggy $< $(RUN_SIZE) > $@ || ( rm -f $@ ; false )
|
||||||
|
|
||||||
targets += piggy.S
|
targets += piggy.S
|
||||||
$(obj)/piggy.S: $(obj)/vmlinux.bin.$(suffix-y) $(obj)/mkpiggy FORCE
|
$(obj)/piggy.S: $(obj)/vmlinux.bin.$(suffix-y) $(obj)/mkpiggy FORCE
|
||||||
|
|
|
@ -207,7 +207,8 @@ relocated:
|
||||||
* Do the decompression, and jump to the new kernel..
|
* Do the decompression, and jump to the new kernel..
|
||||||
*/
|
*/
|
||||||
/* push arguments for decompress_kernel: */
|
/* push arguments for decompress_kernel: */
|
||||||
pushl $z_output_len /* decompressed length */
|
pushl $z_run_size /* size of kernel with .bss and .brk */
|
||||||
|
pushl $z_output_len /* decompressed length, end of relocs */
|
||||||
leal z_extract_offset_negative(%ebx), %ebp
|
leal z_extract_offset_negative(%ebx), %ebp
|
||||||
pushl %ebp /* output address */
|
pushl %ebp /* output address */
|
||||||
pushl $z_input_len /* input_len */
|
pushl $z_input_len /* input_len */
|
||||||
|
@ -217,7 +218,7 @@ relocated:
|
||||||
pushl %eax /* heap area */
|
pushl %eax /* heap area */
|
||||||
pushl %esi /* real mode pointer */
|
pushl %esi /* real mode pointer */
|
||||||
call decompress_kernel /* returns kernel location in %eax */
|
call decompress_kernel /* returns kernel location in %eax */
|
||||||
addl $24, %esp
|
addl $28, %esp
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Jump to the decompressed kernel.
|
* Jump to the decompressed kernel.
|
||||||
|
|
|
@ -402,13 +402,16 @@ relocated:
|
||||||
* Do the decompression, and jump to the new kernel..
|
* Do the decompression, and jump to the new kernel..
|
||||||
*/
|
*/
|
||||||
pushq %rsi /* Save the real mode argument */
|
pushq %rsi /* Save the real mode argument */
|
||||||
|
movq $z_run_size, %r9 /* size of kernel with .bss and .brk */
|
||||||
|
pushq %r9
|
||||||
movq %rsi, %rdi /* real mode address */
|
movq %rsi, %rdi /* real mode address */
|
||||||
leaq boot_heap(%rip), %rsi /* malloc area for uncompression */
|
leaq boot_heap(%rip), %rsi /* malloc area for uncompression */
|
||||||
leaq input_data(%rip), %rdx /* input_data */
|
leaq input_data(%rip), %rdx /* input_data */
|
||||||
movl $z_input_len, %ecx /* input_len */
|
movl $z_input_len, %ecx /* input_len */
|
||||||
movq %rbp, %r8 /* output target address */
|
movq %rbp, %r8 /* output target address */
|
||||||
movq $z_output_len, %r9 /* decompressed length */
|
movq $z_output_len, %r9 /* decompressed length, end of relocs */
|
||||||
call decompress_kernel /* returns kernel location in %rax */
|
call decompress_kernel /* returns kernel location in %rax */
|
||||||
|
popq %r9
|
||||||
popq %rsi
|
popq %rsi
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -358,7 +358,8 @@ asmlinkage __visible void *decompress_kernel(void *rmode, memptr heap,
|
||||||
unsigned char *input_data,
|
unsigned char *input_data,
|
||||||
unsigned long input_len,
|
unsigned long input_len,
|
||||||
unsigned char *output,
|
unsigned char *output,
|
||||||
unsigned long output_len)
|
unsigned long output_len,
|
||||||
|
unsigned long run_size)
|
||||||
{
|
{
|
||||||
real_mode = rmode;
|
real_mode = rmode;
|
||||||
|
|
||||||
|
@ -381,8 +382,14 @@ asmlinkage __visible void *decompress_kernel(void *rmode, memptr heap,
|
||||||
free_mem_ptr = heap; /* Heap */
|
free_mem_ptr = heap; /* Heap */
|
||||||
free_mem_end_ptr = heap + BOOT_HEAP_SIZE;
|
free_mem_end_ptr = heap + BOOT_HEAP_SIZE;
|
||||||
|
|
||||||
output = choose_kernel_location(input_data, input_len,
|
/*
|
||||||
output, output_len);
|
* The memory hole needed for the kernel is the larger of either
|
||||||
|
* the entire decompressed kernel plus relocation table, or the
|
||||||
|
* entire decompressed kernel plus .bss and .brk sections.
|
||||||
|
*/
|
||||||
|
output = choose_kernel_location(input_data, input_len, output,
|
||||||
|
output_len > run_size ? output_len
|
||||||
|
: run_size);
|
||||||
|
|
||||||
/* Validate memory location choices. */
|
/* Validate memory location choices. */
|
||||||
if ((unsigned long)output & (MIN_KERNEL_ALIGN - 1))
|
if ((unsigned long)output & (MIN_KERNEL_ALIGN - 1))
|
||||||
|
|
|
@ -36,11 +36,13 @@ int main(int argc, char *argv[])
|
||||||
uint32_t olen;
|
uint32_t olen;
|
||||||
long ilen;
|
long ilen;
|
||||||
unsigned long offs;
|
unsigned long offs;
|
||||||
|
unsigned long run_size;
|
||||||
FILE *f = NULL;
|
FILE *f = NULL;
|
||||||
int retval = 1;
|
int retval = 1;
|
||||||
|
|
||||||
if (argc < 2) {
|
if (argc < 3) {
|
||||||
fprintf(stderr, "Usage: %s compressed_file\n", argv[0]);
|
fprintf(stderr, "Usage: %s compressed_file run_size\n",
|
||||||
|
argv[0]);
|
||||||
goto bail;
|
goto bail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,6 +76,7 @@ int main(int argc, char *argv[])
|
||||||
offs += olen >> 12; /* Add 8 bytes for each 32K block */
|
offs += olen >> 12; /* Add 8 bytes for each 32K block */
|
||||||
offs += 64*1024 + 128; /* Add 64K + 128 bytes slack */
|
offs += 64*1024 + 128; /* Add 64K + 128 bytes slack */
|
||||||
offs = (offs+4095) & ~4095; /* Round to a 4K boundary */
|
offs = (offs+4095) & ~4095; /* Round to a 4K boundary */
|
||||||
|
run_size = atoi(argv[2]);
|
||||||
|
|
||||||
printf(".section \".rodata..compressed\",\"a\",@progbits\n");
|
printf(".section \".rodata..compressed\",\"a\",@progbits\n");
|
||||||
printf(".globl z_input_len\n");
|
printf(".globl z_input_len\n");
|
||||||
|
@ -85,6 +88,8 @@ int main(int argc, char *argv[])
|
||||||
/* z_extract_offset_negative allows simplification of head_32.S */
|
/* z_extract_offset_negative allows simplification of head_32.S */
|
||||||
printf(".globl z_extract_offset_negative\n");
|
printf(".globl z_extract_offset_negative\n");
|
||||||
printf("z_extract_offset_negative = -0x%lx\n", offs);
|
printf("z_extract_offset_negative = -0x%lx\n", offs);
|
||||||
|
printf(".globl z_run_size\n");
|
||||||
|
printf("z_run_size = %lu\n", run_size);
|
||||||
|
|
||||||
printf(".globl input_data, input_data_end\n");
|
printf(".globl input_data, input_data_end\n");
|
||||||
printf("input_data:\n");
|
printf("input_data:\n");
|
||||||
|
|
|
@ -150,6 +150,7 @@ static inline void arch_send_call_function_ipi_mask(const struct cpumask *mask)
|
||||||
}
|
}
|
||||||
|
|
||||||
void cpu_disable_common(void);
|
void cpu_disable_common(void);
|
||||||
|
void cpu_die_common(unsigned int cpu);
|
||||||
void native_smp_prepare_boot_cpu(void);
|
void native_smp_prepare_boot_cpu(void);
|
||||||
void native_smp_prepare_cpus(unsigned int max_cpus);
|
void native_smp_prepare_cpus(unsigned int max_cpus);
|
||||||
void native_smp_cpus_done(unsigned int max_cpus);
|
void native_smp_cpus_done(unsigned int max_cpus);
|
||||||
|
|
|
@ -108,12 +108,13 @@ static size_t compute_container_size(u8 *data, u32 total_size)
|
||||||
* load_microcode_amd() to save equivalent cpu table and microcode patches in
|
* load_microcode_amd() to save equivalent cpu table and microcode patches in
|
||||||
* kernel heap memory.
|
* kernel heap memory.
|
||||||
*/
|
*/
|
||||||
static void apply_ucode_in_initrd(void *ucode, size_t size)
|
static void apply_ucode_in_initrd(void *ucode, size_t size, bool save_patch)
|
||||||
{
|
{
|
||||||
struct equiv_cpu_entry *eq;
|
struct equiv_cpu_entry *eq;
|
||||||
size_t *cont_sz;
|
size_t *cont_sz;
|
||||||
u32 *header;
|
u32 *header;
|
||||||
u8 *data, **cont;
|
u8 *data, **cont;
|
||||||
|
u8 (*patch)[PATCH_MAX_SIZE];
|
||||||
u16 eq_id = 0;
|
u16 eq_id = 0;
|
||||||
int offset, left;
|
int offset, left;
|
||||||
u32 rev, eax, ebx, ecx, edx;
|
u32 rev, eax, ebx, ecx, edx;
|
||||||
|
@ -123,10 +124,12 @@ static void apply_ucode_in_initrd(void *ucode, size_t size)
|
||||||
new_rev = (u32 *)__pa_nodebug(&ucode_new_rev);
|
new_rev = (u32 *)__pa_nodebug(&ucode_new_rev);
|
||||||
cont_sz = (size_t *)__pa_nodebug(&container_size);
|
cont_sz = (size_t *)__pa_nodebug(&container_size);
|
||||||
cont = (u8 **)__pa_nodebug(&container);
|
cont = (u8 **)__pa_nodebug(&container);
|
||||||
|
patch = (u8 (*)[PATCH_MAX_SIZE])__pa_nodebug(&amd_ucode_patch);
|
||||||
#else
|
#else
|
||||||
new_rev = &ucode_new_rev;
|
new_rev = &ucode_new_rev;
|
||||||
cont_sz = &container_size;
|
cont_sz = &container_size;
|
||||||
cont = &container;
|
cont = &container;
|
||||||
|
patch = &amd_ucode_patch;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
data = ucode;
|
data = ucode;
|
||||||
|
@ -213,8 +216,8 @@ static void apply_ucode_in_initrd(void *ucode, size_t size)
|
||||||
rev = mc->hdr.patch_id;
|
rev = mc->hdr.patch_id;
|
||||||
*new_rev = rev;
|
*new_rev = rev;
|
||||||
|
|
||||||
/* save ucode patch */
|
if (save_patch)
|
||||||
memcpy(amd_ucode_patch, mc,
|
memcpy(patch, mc,
|
||||||
min_t(u32, header[1], PATCH_MAX_SIZE));
|
min_t(u32, header[1], PATCH_MAX_SIZE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -246,7 +249,7 @@ void __init load_ucode_amd_bsp(void)
|
||||||
*data = cp.data;
|
*data = cp.data;
|
||||||
*size = cp.size;
|
*size = cp.size;
|
||||||
|
|
||||||
apply_ucode_in_initrd(cp.data, cp.size);
|
apply_ucode_in_initrd(cp.data, cp.size, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_32
|
||||||
|
@ -263,7 +266,7 @@ void load_ucode_amd_ap(void)
|
||||||
size_t *usize;
|
size_t *usize;
|
||||||
void **ucode;
|
void **ucode;
|
||||||
|
|
||||||
mc = (struct microcode_amd *)__pa(amd_ucode_patch);
|
mc = (struct microcode_amd *)__pa_nodebug(amd_ucode_patch);
|
||||||
if (mc->hdr.patch_id && mc->hdr.processor_rev_id) {
|
if (mc->hdr.patch_id && mc->hdr.processor_rev_id) {
|
||||||
__apply_microcode_amd(mc);
|
__apply_microcode_amd(mc);
|
||||||
return;
|
return;
|
||||||
|
@ -275,7 +278,7 @@ void load_ucode_amd_ap(void)
|
||||||
if (!*ucode || !*usize)
|
if (!*ucode || !*usize)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
apply_ucode_in_initrd(*ucode, *usize);
|
apply_ucode_in_initrd(*ucode, *usize, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __init collect_cpu_sig_on_bsp(void *arg)
|
static void __init collect_cpu_sig_on_bsp(void *arg)
|
||||||
|
@ -339,7 +342,7 @@ void load_ucode_amd_ap(void)
|
||||||
* AP has a different equivalence ID than BSP, looks like
|
* AP has a different equivalence ID than BSP, looks like
|
||||||
* mixed-steppings silicon so go through the ucode blob anew.
|
* mixed-steppings silicon so go through the ucode blob anew.
|
||||||
*/
|
*/
|
||||||
apply_ucode_in_initrd(ucode_cpio.data, ucode_cpio.size);
|
apply_ucode_in_initrd(ucode_cpio.data, ucode_cpio.size, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -347,7 +350,9 @@ void load_ucode_amd_ap(void)
|
||||||
int __init save_microcode_in_initrd_amd(void)
|
int __init save_microcode_in_initrd_amd(void)
|
||||||
{
|
{
|
||||||
unsigned long cont;
|
unsigned long cont;
|
||||||
|
int retval = 0;
|
||||||
enum ucode_state ret;
|
enum ucode_state ret;
|
||||||
|
u8 *cont_va;
|
||||||
u32 eax;
|
u32 eax;
|
||||||
|
|
||||||
if (!container)
|
if (!container)
|
||||||
|
@ -356,12 +361,14 @@ int __init save_microcode_in_initrd_amd(void)
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_32
|
||||||
get_bsp_sig();
|
get_bsp_sig();
|
||||||
cont = (unsigned long)container;
|
cont = (unsigned long)container;
|
||||||
|
cont_va = __va(container);
|
||||||
#else
|
#else
|
||||||
/*
|
/*
|
||||||
* We need the physical address of the container for both bitness since
|
* We need the physical address of the container for both bitness since
|
||||||
* boot_params.hdr.ramdisk_image is a physical address.
|
* boot_params.hdr.ramdisk_image is a physical address.
|
||||||
*/
|
*/
|
||||||
cont = __pa(container);
|
cont = __pa(container);
|
||||||
|
cont_va = container;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -372,6 +379,8 @@ int __init save_microcode_in_initrd_amd(void)
|
||||||
if (relocated_ramdisk)
|
if (relocated_ramdisk)
|
||||||
container = (u8 *)(__va(relocated_ramdisk) +
|
container = (u8 *)(__va(relocated_ramdisk) +
|
||||||
(cont - boot_params.hdr.ramdisk_image));
|
(cont - boot_params.hdr.ramdisk_image));
|
||||||
|
else
|
||||||
|
container = cont_va;
|
||||||
|
|
||||||
if (ucode_new_rev)
|
if (ucode_new_rev)
|
||||||
pr_info("microcode: updated early to new patch_level=0x%08x\n",
|
pr_info("microcode: updated early to new patch_level=0x%08x\n",
|
||||||
|
@ -382,7 +391,7 @@ int __init save_microcode_in_initrd_amd(void)
|
||||||
|
|
||||||
ret = load_microcode_amd(eax, container, container_size);
|
ret = load_microcode_amd(eax, container, container_size);
|
||||||
if (ret != UCODE_OK)
|
if (ret != UCODE_OK)
|
||||||
return -EINVAL;
|
retval = -EINVAL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This will be freed any msec now, stash patches for the current
|
* This will be freed any msec now, stash patches for the current
|
||||||
|
@ -391,5 +400,5 @@ int __init save_microcode_in_initrd_amd(void)
|
||||||
container = NULL;
|
container = NULL;
|
||||||
container_size = 0;
|
container_size = 0;
|
||||||
|
|
||||||
return 0;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,7 +124,7 @@ void __init load_ucode_bsp(void)
|
||||||
static bool check_loader_disabled_ap(void)
|
static bool check_loader_disabled_ap(void)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_32
|
||||||
return __pa_nodebug(dis_ucode_ldr);
|
return *((bool *)__pa_nodebug(&dis_ucode_ldr));
|
||||||
#else
|
#else
|
||||||
return dis_ucode_ldr;
|
return dis_ucode_ldr;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1303,10 +1303,14 @@ static void __ref remove_cpu_from_maps(int cpu)
|
||||||
numa_remove_cpu(cpu);
|
numa_remove_cpu(cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DEFINE_PER_CPU(struct completion, die_complete);
|
||||||
|
|
||||||
void cpu_disable_common(void)
|
void cpu_disable_common(void)
|
||||||
{
|
{
|
||||||
int cpu = smp_processor_id();
|
int cpu = smp_processor_id();
|
||||||
|
|
||||||
|
init_completion(&per_cpu(die_complete, smp_processor_id()));
|
||||||
|
|
||||||
remove_siblinginfo(cpu);
|
remove_siblinginfo(cpu);
|
||||||
|
|
||||||
/* It's now safe to remove this processor from the online map */
|
/* It's now safe to remove this processor from the online map */
|
||||||
|
@ -1316,8 +1320,6 @@ void cpu_disable_common(void)
|
||||||
fixup_irqs();
|
fixup_irqs();
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEFINE_PER_CPU(struct completion, die_complete);
|
|
||||||
|
|
||||||
int native_cpu_disable(void)
|
int native_cpu_disable(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -1327,16 +1329,21 @@ int native_cpu_disable(void)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
clear_local_APIC();
|
clear_local_APIC();
|
||||||
init_completion(&per_cpu(die_complete, smp_processor_id()));
|
|
||||||
cpu_disable_common();
|
cpu_disable_common();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cpu_die_common(unsigned int cpu)
|
||||||
|
{
|
||||||
|
wait_for_completion_timeout(&per_cpu(die_complete, cpu), HZ);
|
||||||
|
}
|
||||||
|
|
||||||
void native_cpu_die(unsigned int cpu)
|
void native_cpu_die(unsigned int cpu)
|
||||||
{
|
{
|
||||||
/* We don't do anything here: idle task is faking death itself. */
|
/* We don't do anything here: idle task is faking death itself. */
|
||||||
wait_for_completion_timeout(&per_cpu(die_complete, cpu), HZ);
|
|
||||||
|
cpu_die_common(cpu);
|
||||||
|
|
||||||
/* They ack this in play_dead() by setting CPU_DEAD */
|
/* They ack this in play_dead() by setting CPU_DEAD */
|
||||||
if (per_cpu(cpu_state, cpu) == CPU_DEAD) {
|
if (per_cpu(cpu_state, cpu) == CPU_DEAD) {
|
||||||
|
|
30
arch/x86/tools/calc_run_size.pl
Normal file
30
arch/x86/tools/calc_run_size.pl
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
#
|
||||||
|
# Calculate the amount of space needed to run the kernel, including room for
|
||||||
|
# the .bss and .brk sections.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# objdump -h a.out | perl calc_run_size.pl
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
my $mem_size = 0;
|
||||||
|
my $file_offset = 0;
|
||||||
|
|
||||||
|
my $sections=" *[0-9]+ \.(?:bss|brk) +";
|
||||||
|
while (<>) {
|
||||||
|
if (/^$sections([0-9a-f]+) +(?:[0-9a-f]+ +){2}([0-9a-f]+)/) {
|
||||||
|
my $size = hex($1);
|
||||||
|
my $offset = hex($2);
|
||||||
|
$mem_size += $size;
|
||||||
|
if ($file_offset == 0) {
|
||||||
|
$file_offset = $offset;
|
||||||
|
} elsif ($file_offset != $offset) {
|
||||||
|
die ".bss and .brk lack common file offset\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($file_offset == 0) {
|
||||||
|
die "Never found .bss or .brk file offset\n";
|
||||||
|
}
|
||||||
|
printf("%d\n", $mem_size + $file_offset);
|
|
@ -510,6 +510,9 @@ static void xen_cpu_die(unsigned int cpu)
|
||||||
current->state = TASK_UNINTERRUPTIBLE;
|
current->state = TASK_UNINTERRUPTIBLE;
|
||||||
schedule_timeout(HZ/10);
|
schedule_timeout(HZ/10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cpu_die_common(cpu);
|
||||||
|
|
||||||
xen_smp_intr_free(cpu);
|
xen_smp_intr_free(cpu);
|
||||||
xen_uninit_lock_cpu(cpu);
|
xen_uninit_lock_cpu(cpu);
|
||||||
xen_teardown_timer(cpu);
|
xen_teardown_timer(cpu);
|
||||||
|
|
Loading…
Reference in a new issue