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_LZ4) := lz4
|
||||
|
||||
RUN_SIZE = $(shell objdump -h vmlinux | \
|
||||
perl $(srctree)/arch/x86/tools/calc_run_size.pl)
|
||||
quiet_cmd_mkpiggy = MKPIGGY $@
|
||||
cmd_mkpiggy = $(obj)/mkpiggy $< > $@ || ( rm -f $@ ; false )
|
||||
cmd_mkpiggy = $(obj)/mkpiggy $< $(RUN_SIZE) > $@ || ( rm -f $@ ; false )
|
||||
|
||||
targets += piggy.S
|
||||
$(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..
|
||||
*/
|
||||
/* 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
|
||||
pushl %ebp /* output address */
|
||||
pushl $z_input_len /* input_len */
|
||||
|
@ -217,7 +218,7 @@ relocated:
|
|||
pushl %eax /* heap area */
|
||||
pushl %esi /* real mode pointer */
|
||||
call decompress_kernel /* returns kernel location in %eax */
|
||||
addl $24, %esp
|
||||
addl $28, %esp
|
||||
|
||||
/*
|
||||
* Jump to the decompressed kernel.
|
||||
|
|
|
@ -402,13 +402,16 @@ relocated:
|
|||
* Do the decompression, and jump to the new kernel..
|
||||
*/
|
||||
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 */
|
||||
leaq boot_heap(%rip), %rsi /* malloc area for uncompression */
|
||||
leaq input_data(%rip), %rdx /* input_data */
|
||||
movl $z_input_len, %ecx /* input_len */
|
||||
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 */
|
||||
popq %r9
|
||||
popq %rsi
|
||||
|
||||
/*
|
||||
|
|
|
@ -358,7 +358,8 @@ asmlinkage __visible void *decompress_kernel(void *rmode, memptr heap,
|
|||
unsigned char *input_data,
|
||||
unsigned long input_len,
|
||||
unsigned char *output,
|
||||
unsigned long output_len)
|
||||
unsigned long output_len,
|
||||
unsigned long run_size)
|
||||
{
|
||||
real_mode = rmode;
|
||||
|
||||
|
@ -381,8 +382,14 @@ asmlinkage __visible void *decompress_kernel(void *rmode, memptr heap,
|
|||
free_mem_ptr = heap; /* Heap */
|
||||
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. */
|
||||
if ((unsigned long)output & (MIN_KERNEL_ALIGN - 1))
|
||||
|
|
|
@ -36,11 +36,13 @@ int main(int argc, char *argv[])
|
|||
uint32_t olen;
|
||||
long ilen;
|
||||
unsigned long offs;
|
||||
unsigned long run_size;
|
||||
FILE *f = NULL;
|
||||
int retval = 1;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Usage: %s compressed_file\n", argv[0]);
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "Usage: %s compressed_file run_size\n",
|
||||
argv[0]);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
|
@ -74,6 +76,7 @@ int main(int argc, char *argv[])
|
|||
offs += olen >> 12; /* Add 8 bytes for each 32K block */
|
||||
offs += 64*1024 + 128; /* Add 64K + 128 bytes slack */
|
||||
offs = (offs+4095) & ~4095; /* Round to a 4K boundary */
|
||||
run_size = atoi(argv[2]);
|
||||
|
||||
printf(".section \".rodata..compressed\",\"a\",@progbits\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 */
|
||||
printf(".globl z_extract_offset_negative\n");
|
||||
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("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_die_common(unsigned int cpu);
|
||||
void native_smp_prepare_boot_cpu(void);
|
||||
void native_smp_prepare_cpus(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
|
||||
* 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;
|
||||
size_t *cont_sz;
|
||||
u32 *header;
|
||||
u8 *data, **cont;
|
||||
u8 (*patch)[PATCH_MAX_SIZE];
|
||||
u16 eq_id = 0;
|
||||
int offset, left;
|
||||
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);
|
||||
cont_sz = (size_t *)__pa_nodebug(&container_size);
|
||||
cont = (u8 **)__pa_nodebug(&container);
|
||||
patch = (u8 (*)[PATCH_MAX_SIZE])__pa_nodebug(&amd_ucode_patch);
|
||||
#else
|
||||
new_rev = &ucode_new_rev;
|
||||
cont_sz = &container_size;
|
||||
cont = &container;
|
||||
patch = &amd_ucode_patch;
|
||||
#endif
|
||||
|
||||
data = ucode;
|
||||
|
@ -213,9 +216,9 @@ static void apply_ucode_in_initrd(void *ucode, size_t size)
|
|||
rev = mc->hdr.patch_id;
|
||||
*new_rev = rev;
|
||||
|
||||
/* save ucode patch */
|
||||
memcpy(amd_ucode_patch, mc,
|
||||
min_t(u32, header[1], PATCH_MAX_SIZE));
|
||||
if (save_patch)
|
||||
memcpy(patch, mc,
|
||||
min_t(u32, header[1], PATCH_MAX_SIZE));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -246,7 +249,7 @@ void __init load_ucode_amd_bsp(void)
|
|||
*data = cp.data;
|
||||
*size = cp.size;
|
||||
|
||||
apply_ucode_in_initrd(cp.data, cp.size);
|
||||
apply_ucode_in_initrd(cp.data, cp.size, true);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
|
@ -263,7 +266,7 @@ void load_ucode_amd_ap(void)
|
|||
size_t *usize;
|
||||
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) {
|
||||
__apply_microcode_amd(mc);
|
||||
return;
|
||||
|
@ -275,7 +278,7 @@ void load_ucode_amd_ap(void)
|
|||
if (!*ucode || !*usize)
|
||||
return;
|
||||
|
||||
apply_ucode_in_initrd(*ucode, *usize);
|
||||
apply_ucode_in_initrd(*ucode, *usize, false);
|
||||
}
|
||||
|
||||
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
|
||||
* 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
|
||||
|
@ -347,7 +350,9 @@ void load_ucode_amd_ap(void)
|
|||
int __init save_microcode_in_initrd_amd(void)
|
||||
{
|
||||
unsigned long cont;
|
||||
int retval = 0;
|
||||
enum ucode_state ret;
|
||||
u8 *cont_va;
|
||||
u32 eax;
|
||||
|
||||
if (!container)
|
||||
|
@ -355,13 +360,15 @@ int __init save_microcode_in_initrd_amd(void)
|
|||
|
||||
#ifdef CONFIG_X86_32
|
||||
get_bsp_sig();
|
||||
cont = (unsigned long)container;
|
||||
cont = (unsigned long)container;
|
||||
cont_va = __va(container);
|
||||
#else
|
||||
/*
|
||||
* We need the physical address of the container for both bitness since
|
||||
* boot_params.hdr.ramdisk_image is a physical address.
|
||||
*/
|
||||
cont = __pa(container);
|
||||
cont = __pa(container);
|
||||
cont_va = container;
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -372,6 +379,8 @@ int __init save_microcode_in_initrd_amd(void)
|
|||
if (relocated_ramdisk)
|
||||
container = (u8 *)(__va(relocated_ramdisk) +
|
||||
(cont - boot_params.hdr.ramdisk_image));
|
||||
else
|
||||
container = cont_va;
|
||||
|
||||
if (ucode_new_rev)
|
||||
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);
|
||||
if (ret != UCODE_OK)
|
||||
return -EINVAL;
|
||||
retval = -EINVAL;
|
||||
|
||||
/*
|
||||
* 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_size = 0;
|
||||
|
||||
return 0;
|
||||
return retval;
|
||||
}
|
||||
|
|
|
@ -124,7 +124,7 @@ void __init load_ucode_bsp(void)
|
|||
static bool check_loader_disabled_ap(void)
|
||||
{
|
||||
#ifdef CONFIG_X86_32
|
||||
return __pa_nodebug(dis_ucode_ldr);
|
||||
return *((bool *)__pa_nodebug(&dis_ucode_ldr));
|
||||
#else
|
||||
return dis_ucode_ldr;
|
||||
#endif
|
||||
|
|
|
@ -1303,10 +1303,14 @@ static void __ref remove_cpu_from_maps(int cpu)
|
|||
numa_remove_cpu(cpu);
|
||||
}
|
||||
|
||||
static DEFINE_PER_CPU(struct completion, die_complete);
|
||||
|
||||
void cpu_disable_common(void)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
|
||||
init_completion(&per_cpu(die_complete, smp_processor_id()));
|
||||
|
||||
remove_siblinginfo(cpu);
|
||||
|
||||
/* It's now safe to remove this processor from the online map */
|
||||
|
@ -1316,8 +1320,6 @@ void cpu_disable_common(void)
|
|||
fixup_irqs();
|
||||
}
|
||||
|
||||
static DEFINE_PER_CPU(struct completion, die_complete);
|
||||
|
||||
int native_cpu_disable(void)
|
||||
{
|
||||
int ret;
|
||||
|
@ -1327,16 +1329,21 @@ int native_cpu_disable(void)
|
|||
return ret;
|
||||
|
||||
clear_local_APIC();
|
||||
init_completion(&per_cpu(die_complete, smp_processor_id()));
|
||||
cpu_disable_common();
|
||||
|
||||
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)
|
||||
{
|
||||
/* 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 */
|
||||
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;
|
||||
schedule_timeout(HZ/10);
|
||||
}
|
||||
|
||||
cpu_die_common(cpu);
|
||||
|
||||
xen_smp_intr_free(cpu);
|
||||
xen_uninit_lock_cpu(cpu);
|
||||
xen_teardown_timer(cpu);
|
||||
|
|
Loading…
Reference in a new issue