Updates for firstfloor paravirt-ops patches
Subsystems (8)
cover Updates for firstfloor paravirt-ops patches
Hi Andi,
This is a set of updates for the firstfloor patch queue.
Quick rundown:
revert-mm-x86_64-mm-account-for-module-percpu-space-separately-from-kernel-percpu.patch separate-module-percpu-space.patch
Update the module percpu accounting patch
fix-ff-allow-percpu-variables-to-be-page-aligned.patch
Make sure the percpu memory allocation is page-aligned
deflate-stack-usage-in-lib_inflate_c.patch
Fix deflate stack usage. With all the arch-fixes rolled in.
i386-gdt-cleanups-page-align-the-gdt.patch i386-convert-pda-into-the-percpu-section.patch i386-cleanups-to-help-using-per-cpu-variables-from-asm.patch percpu-define-per_cpu_offset.patch fix-uniproc-gdt-bugs.patch
Percpu and GDT fixes.
x86-map-enough-initial-memory.patch
Fix head.S to map enough memory.
cleanup-cleanup-asm-bugs_h.patch cleanup-identify_cpu-fix.patch
This is the pair I tried to post yesterday, but they got interrupted by an network outage. They basically add a little more cleanup, and move a misplaced hunk. cleanup-cleanup-asm-bugs_h.patch should go after/roll into the clean-up-asm-(i386|x86_64)-bugs_h patches, and cleanup-identify_cpu-fix.patch should go after/roll into clean-up-identify_cpu patch.
paravirt-flush-on-kunmap_atomic.patch
Flush pending lazy mmu operations on kunmap_atomic too.
paravirt-fix-paravirt_lazy.patch
Fix up an apparent mismerge: remove the #defines for PARAVIRT_LAZY_* and add _LAZY_FLUSH to the enum.
i386-sysenter-arch-pages-fix.patch i386-acpi-remove-earlyquirk-warning.patch i386-mcheck-p4-grotesque-and-needless-warning-fix.patch i386-pgd-clone-under-lock-fix.patch paravirt-kmap_atomic_pte-tidy.patch vmi-supports-compat-vdso.patch vmi-kmap_atomic_pte-fix.patch vmi-timer-update.patch buslogic-check-range-fixes.patch pte-drop-ptep_get_and_clear-paravirt-op.patch
A chunk of pages from Zach.
rename-the-parainstructions-symbols-to-be-consistent-with-the-others.patch rename-the-parainstructions-symbols-to-be-consistent-with-the-others-fix.patch
Obvious.
vmi-fix-ff.patch
Make VMI compile in the -ff patchstack.
paravirt-sched-clock-ff.patch
Updated paravirt-sched-lock for your sched_clock.
Thanks,
J
PATCH 1/28 revert account-for-module-percpu-space-separately-from-kernel-percpu
--- include/asm-i386/percpu.h | 10 ---------- 1 file changed, 10 deletions(-)
===================================================================
include/asm-i386/percpu.h +0 -10
@@ -4,16 +4,6 @@#ifndef __ASSEMBLY__#include <asm-generic/percpu.h> #else - -#ifdef CONFIG_MODULES -# define PERCPU_MODULE_RESERVE 8192 -#else -# define PERCPU_MODULE_RESERVE 0 -#endif - -#define PERCPU_ENOUGH_ROOM \ - (ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES) + \ - PERCPU_MODULE_RESERVE)/* * PER_CPU finds an address of a per-cpu variable.
PATCH 2/28 Account for module percpu space separately from kernel percpu
In reply to Jeremy FitzhardingeRather than using a single constant PERCPU_ENOUGH_ROOM, compute it as the sum of kernel_percpu + PERCPU_MODULE_RESERVE. This is now common to all architectures; if an architecture wants to set PERCPU_ENOUGH_ROOM to something special, then it may do so (ia64 is the only one which does).
--- include/asm-alpha/percpu.h | 14 -------------- include/asm-sparc64/percpu.h | 10 ---------- include/asm-x86_64/percpu.h | 10 ---------- include/linux/percpu.h | 9 ++++++++- kernel/module.c | 2 +- 5 files changed, 9 insertions(+), 36 deletions(-)
===================================================================
include/asm-alpha/percpu.h +0 -14
@@ -1,19 +1,5 @@#ifndef __ALPHA_PERCPU_H#define __ALPHA_PERCPU_H - -/* -* Increase the per cpu area for Alpha so that -* modules using percpu area can load. -*/ -#ifdef CONFIG_MODULES -# define PERCPU_MODULE_RESERVE 8192 -#else -# define PERCPU_MODULE_RESERVE 0 -#endif - -#define PERCPU_ENOUGH_ROOM \ - (ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES) + \ - PERCPU_MODULE_RESERVE)#include <asm-generic/percpu.h>
===================================================================
include/asm-sparc64/percpu.h +0 -10
@@ -4,16 +4,6 @@#include <linux/compiler.h> #ifdef CONFIG_SMP - -#ifdef CONFIG_MODULES -# define PERCPU_MODULE_RESERVE 8192 -#else -# define PERCPU_MODULE_RESERVE 0 -#endif - -#define PERCPU_ENOUGH_ROOM \ - (ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES) + \ - PERCPU_MODULE_RESERVE)extern void setup_per_cpu_areas (void );
===================================================================
include/asm-x86_64/percpu.h +0 -10
@@ -10,16 +10,6 @@#ifdef CONFIG_SMP #include <asm/pda.h> - -#ifdef CONFIG_MODULES -# define PERCPU_MODULE_RESERVE 8192 -#else -# define PERCPU_MODULE_RESERVE 0 -#endif - -#define PERCPU_ENOUGH_ROOM \ - (ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES) + \ - PERCPU_MODULE_RESERVE)#define __per_cpu_offset (cpu) (cpu_pda(cpu)->data_offset)#define __my_cpu_offset () read_pda(data_offset)
===================================================================
include/linux/percpu.h +8 -1
@@ -11,8 +11,15 @@/* Enough to cover all DEFINE_PER_CPUs in kernel, including modules. */ #ifndef PERCPU_ENOUGH_ROOM -#define PERCPU_ENOUGH_ROOM 32768 +#ifdef CONFIG_MODULES +#define PERCPU_MODULE_RESERVE 8192 +#else +#define PERCPU_MODULE_RESERVE 0#endif + +#define PERCPU_ENOUGH_ROOM \ + (__per_cpu_end - __per_cpu_start + PERCPU_MODULE_RESERVE) +#endif /* PERCPU_ENOUGH_ROOM */ /* * Must be an lvalue. Since @var must be a simple identifier,
===================================================================
kernel/module.c +1 -1
@@ -430,7 +430,7 @@ static int percpu_modinit(void) pcpu_size =kmalloc (sizeof (pcpu_size[0 ]) * pcpu_num_allocated,GFP_KERNEL );/* Static in-kernel percpu data (used). */ - pcpu_size[0 ] = -ALIGN (__per_cpu_end-__per_cpu_start,SMP_CACHE_BYTES ); + pcpu_size[0 ] = -(__per_cpu_end-__per_cpu_start);/* Free room. */ pcpu_size[1 ] =PERCPU_ENOUGH_ROOM + pcpu_size[0 ];if (pcpu_size[1 ] <0 ) {
PATCH 3/28 fix allow-percpu-variables-to-be-page-aligned.patch
In reply to Jeremy FitzhardingeMake sure allocation is page-aligned.
--- init/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
===================================================================
init/main.c +1 -1
@@ -370,7 +370,7 @@ static void __init setup_per_cpu_areas(v/* Copy section for each CPU (we discard the original) */ size =ALIGN (PERCPU_ENOUGH_ROOM ,PAGE_SIZE ); - ptr =alloc_bootmem (size * nr_possible_cpus); + ptr =alloc_bootmem_pages (size * nr_possible_cpus);for_each_possible_cpu (i) { __per_cpu_offset[i] = ptr - __per_cpu_start;
PATCH 4/28 deflate stack usage in lib/inflate.c
In reply to Jeremy Fitzhardingeinflate_fixed and huft_build together use around 2.7k of stack. When using 4k stacks, I saw stack overflows from interrupts arriving while unpacking the root initrd:
do_IRQ: stack overflow: 384
[<c0106b64>] show_trace_log_lvl+0x1a/0x30 [<c01075e6>] show_trace+0x12/0x14 [<c010763f>] dump_stack+0x16/0x18 [<c0107ca4>] do_IRQ+0x6d/0xd9 [<c010202b>] xen_evtchn_do_upcall+0x6e/0xa2 [<c0106781>] xen_hypervisor_callback+0x25/0x2c [<c010116c>] xen_restore_fl+0x27/0x29 [<c0330f63>] _spin_unlock_irqrestore+0x4a/0x50 [<c0117aab>] change_page_attr+0x577/0x584 [<c0117b45>] kernel_map_pages+0x8d/0xb4 [<c016a314>] cache_alloc_refill+0x53f/0x632 [<c016a6c2>] __kmalloc+0xc1/0x10d [<c0463d34>] malloc+0x10/0x12 [<c04641c1>] huft_build+0x2a7/0x5fa [<c04645a5>] inflate_fixed+0x91/0x136 [<c04657e2>] unpack_to_rootfs+0x5f2/0x8c1 [<c0465acf>] populate_rootfs+0x1e/0xe4
(This was under Xen, but there's no reason it couldn't happen on bare
hardware.)
This patch mallocs the local variables, thereby reducing the stack usage to sane levels.
Also, up the heap size for the kernel decompressor to deal with the extra allocation.
--- arch/alpha/boot/misc.c | 2 - arch/arm/boot/compressed/misc.c | 2 - arch/arm26/boot/compressed/misc.c | 2 - arch/i386/boot/compressed/misc.c | 2 - arch/x86_64/boot/compressed/misc.c | 2 - lib/inflate.c | 66 ++++++++++++++++++++++++++---------- 6 files changed, 54 insertions(+), 22 deletions(-)
===================================================================
arch/alpha/boot/misc.c +1 -1
@@ -98,7 +98,7 @@ static ulg free_mem_ptr;static ulg free_mem_ptr;static ulg free_mem_ptr_end; -#define HEAP_SIZE 0x2000 +#define HEAP_SIZE 0x3000#include "../../../lib/inflate.c"
===================================================================
arch/arm/boot/compressed/misc.c +1 -1
@@ -239,7 +239,7 @@ static ulg free_mem_ptr;static ulg free_mem_ptr;static ulg free_mem_ptr_end; -#define HEAP_SIZE 0x2000 +#define HEAP_SIZE 0x3000#include "../../../../lib/inflate.c"
===================================================================
arch/arm26/boot/compressed/misc.c +1 -1
@@ -182,7 +182,7 @@ static ulg free_mem_ptr;static ulg free_mem_ptr;static ulg free_mem_ptr_end; -#define HEAP_SIZE 0x2000 +#define HEAP_SIZE 0x3000#include "../../../../lib/inflate.c"
===================================================================
arch/i386/boot/compressed/misc.c +1 -1
@@ -189,7 +189,7 @@ static unsigned long free_mem_ptr;static unsigned long free_mem_ptr;static unsigned long free_mem_end_ptr; -#define HEAP_SIZE 0x3000 +#define HEAP_SIZE 0x4000static char *vidmem = (char *)0xb8000 ;static int vidport;
===================================================================
arch/x86_64/boot/compressed/misc.c +1 -1
@@ -189,7 +189,7 @@ static long free_mem_ptr;static long free_mem_ptr;static long free_mem_end_ptr; -#define HEAP_SIZE 0x6000 +#define HEAP_SIZE 0x7000static char *vidmem = (char *)0xb8000 ;static int vidport;
===================================================================
lib/inflate.c +49 -17
140 lines not on this page · raw message
PATCH 5/28 Page-align the GDT
In reply to Jeremy FitzhardingeXen wants a dedicated page for the GDT. I believe VMI likes it too. lguest, KVM and native don't care.
Simple transformation to page-aligned "struct gdt_page".
--- arch/i386/kernel/cpu/common.c | 6 +++--- arch/i386/kernel/entry.S | 2 +- arch/i386/kernel/head.S | 2 +- arch/i386/kernel/traps.c | 2 +- include/asm-i386/desc.h | 9 +++++++-- 5 files changed, 13 insertions(+), 8 deletions(-)
===================================================================
arch/i386/kernel/cpu/common.c +3 -3
@@ -22,7 +22,7 @@#include "cpu.h" -DEFINE_PER_CPU(struct desc_struct, cpu_gdt[GDT_ENTRIES]) = { +DEFINE_PER_CPU(struct gdt_page, gdt_page) = { .gdt = { [GDT_ENTRY_KERNEL_CS ] = {0x0000ffff ,0x00cf9a00 }, [GDT_ENTRY_KERNEL_DS ] = {0x0000ffff ,0x00cf9200 }, [GDT_ENTRY_DEFAULT_USER_CS ] = {0x0000ffff ,0x00cffa00 },
@@ -48,8 +48,8 @@ DEFINE_PER_CPU(struct desc_struct, cpu_g [GDT_ENTRY_ESPFIX_SS] = { 0x00000000, 0x00c09200 }, [GDT_ENTRY_PDA ] = {0x00000000 ,0x00c09200 },/* set in setup_pda */ -}; -EXPORT_PER_CPU_SYMBOL_GPL (cpu_gdt ); +} }; +EXPORT_PER_CPU_SYMBOL_GPL (gdt_page ); DEFINE_PER_CPU(struct i386_pda, _cpu_pda) = { ._pda = &per_cpu___cpu_pda,
===================================================================
arch/i386/kernel/entry.S +1 -1
@@ -558,7 +558,7 @@ END(syscall_badsys) #define FIXUP_ESPFIX_STACK \ /* since we are on a wrong stack, we cant make it a C code :( */ \ movl %fs:PDA_cpu, %ebx; \ - PER_CPU(cpu_gdt, %ebx); \ + PER_CPU(gdt_page, %ebx); \ GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah); \ addl %esp, %eax; \ pushl $__KERNEL_DS; \
===================================================================
arch/i386/kernel/head.S +1 -1
@@ -599,7 +599,7 @@ idt_descr: .word 0 # 32 bit align gdt_desc.address ENTRY(early_gdt_descr) .word GDT_ENTRIES*8-1 - .long per_cpu__cpu_gdt /* Overwritten for secondary CPUs */ + .long per_cpu__gdt_page /* Overwritten for secondary CPUs */ /* * The boot_gdt_table must mirror the equivalent in setup.S and is
===================================================================
arch/i386/kernel/traps.c +1 -1
@@ -1037,7 +1037,7 @@ fastcall unsigned long patch_espfix_descfastcall unsigned long patch_espfix_desc (unsigned long uesp,unsigned long kesp) { -struct desc_struct *gdt =__get_cpu_var (cpu_gdt); +struct desc_struct *gdt =__get_cpu_var (gdt_page).gdt;unsigned long base = (kesp - uesp) & -THREAD_SIZE ;unsigned long new_kesp = kesp - base;unsigned long lim_pages = (new_kesp | (THREAD_SIZE -1 )) >>PAGE_SHIFT ;
===================================================================
include/asm-i386/desc.h +7 -2
@@ -18,10 +18,15 @@ struct Xgt_desc_struct {unsigned short pad; } __attribute__ ((packed)); -DECLARE_PER_CPU(struct desc_struct, cpu_gdt[GDT_ENTRIES]); +struct gdt_page +{ +struct desc_struct gdt[GDT_ENTRIES ]; +} __attribute__((aligned (PAGE_SIZE ))); +DECLARE_PER_CPU(struct gdt_page, gdt_page); +static inline struct desc_struct *get_cpu_gdt_table (unsigned int cpu) { -return per_cpu (cpu_gdt, cpu); +return per_cpu (gdt_page, cpu).gdt; }extern struct Xgt_desc_struct idt_descr;
PATCH 6/28 Convert PDA into the percpu section
In reply to Jeremy FitzhardingeCurrently x86 (similar to x84-64) has a special per-cpu structure called "i386_pda" which can be easily and efficiently referenced via the %fs register. An ELF section is more flexible than a structure, allowing any piece of code to use this area. Indeed, such a section already exists: the per-cpu area.
So this patch:
(1) Removes the PDA and uses per-cpu variables for each current member.
(2) Replaces the __KERNEL_PDA segment with __KERNEL_PERCPU.
(3) Creates a per-cpu mirror of __per_cpu_offset called this_cpu_off, which can be used to calculate addresses for this CPU's variables.
(4) Simplifies startup, because %fs doesn't need to be loaded with a special segment at early boot; it can be deferred until the first percpu area is allocated (or never for UP).
The result is less code and one less x86-specific concept.
--- arch/i386/kernel/asm-offsets.c | 5 - arch/i386/kernel/cpu/common.c | 17 ----- arch/i386/kernel/entry.S | 5 - arch/i386/kernel/head.S | 31 +-------- arch/i386/kernel/i386_ksyms.c | 2 arch/i386/kernel/irq.c | 3 arch/i386/kernel/process.c | 12 ++- arch/i386/kernel/smpboot.c | 34 ++++------ arch/i386/kernel/vmi.c | 6 - arch/i386/kernel/vmlinux.lds.S | 1 include/asm-i386/current.h | 5 - include/asm-i386/irq_regs.h | 12 ++- include/asm-i386/pda.h | 99 ------------------------------ include/asm-i386/percpu.h | 132 +++++++++++++++++++++++++++++++++++++--- include/asm-i386/processor.h | 2 include/asm-i386/segment.h | 6 - include/asm-i386/smp.h | 4 - include/asm-i386/unwind.h | 2 18 files changed, 180 insertions(+), 198 deletions(-)
===================================================================
arch/i386/kernel/asm-offsets.c +0 -5
@@ -15,7 +15,6 @@#include <asm/processor.h> #include <asm/thread_info.h> #include <asm/elf.h> -#include <asm/pda.h> #define DEFINE (sym, val) \ asm volatile("\n->" #sym " %0 " #val : : "i" (val))
@@ -101,10 +100,6 @@ void foo(void)OFFSET (crypto_tfm_ctx_offset, crypto_tfm, __crt_ctx); -BLANK (); -OFFSET (PDA_cpu, i386_pda, cpu_number); -OFFSET (PDA_pcurrent, i386_pda, pcurrent); -#ifdef CONFIG_PARAVIRT BLANK ();OFFSET (PARAVIRT_enabled, paravirt_ops, paravirt_enabled);
===================================================================
arch/i386/kernel/cpu/common.c +3 -14
@@ -18,7 +18,6 @@#include <asm/apic.h> #include <mach_apic.h> #endif -#include <asm/pda.h> #include "cpu.h"
@@ -47,12 +46,9 @@ DEFINE_PER_CPU(struct gdt_page, gdt_page [GDT_ENTRY_APMBIOS_BASE+2] = { 0x0000ffff, 0x00409200 }, /* data */ [GDT_ENTRY_ESPFIX_SS] = { 0x00000000, 0x00c09200 }, - [GDT_ENTRY_PDA ] = {0x00000000 ,0x00c09200 },/* set in setup_pda */ + [GDT_ENTRY_PERCPU ] = {0x00000000 ,0x00000000 }, } };EXPORT_PER_CPU_SYMBOL_GPL (gdt_page ); - -DEFINE_PER_CPU(struct i386_pda, _cpu_pda); -EXPORT_PER_CPU_SYMBOL (_cpu_pda);static int cachesize_override__cpuinitdata =-1 ;static int disable_x86_fxsr__cpuinitdata ;
@@ -634,20 +630,13 @@ void __init early_cpu_init(void)#endif } -/* Make sure %gs is initialized properly in idle threads */ +/* Make sure %fs is initialized properly in idle threads */ struct pt_regs *__devinit idle_regs (struct pt_regs *regs) {memset (regs,0 ,sizeof (struct pt_regs )); - regs->xfs = __KERNEL_PDA; + regs->xfs = __KERNEL_PERCPU;return regs; } - -/* Initial PDA used by boot CPU */ -struct i386_pda boot_pda = { - ._pda = &boot_pda, - .cpu_number =0 , - .pcurrent = &init_task, -};/* * cpu_init() initializes state that is per-CPU. Some data is already
===================================================================
arch/i386/kernel/entry.S +2 -3
@@ -132,7 +132,7 @@ 1: movl $(__USER_DS), %edx; \ movl %edx, %ds; \ movl %edx, %es; \ - movl $(__KERNEL_PDA), %edx; \ + movl $(__KERNEL_PERCPU), %edx; \ movl %edx, %fs #define RESTORE_INT_REGS \
@@ -556,7 +556,6 @@ END(syscall_badsys) #define FIXUP_ESPFIX_STACK \ /* since we are on a wrong stack, we cant make it a C code :( */ \ - movl %fs:PDA_cpu, %ebx; \ PER_CPU(gdt_page, %ebx); \ GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah); \ addl %esp, %eax; \
@@ -681,7 +680,7 @@ error_code: pushl %fs CFI_ADJUST_CFA_OFFSET 4 /*CFI_REL_OFFSET fs, 0*/ - movl $(__KERNEL_PDA), %ecx + movl $(__KERNEL_PERCPU), %ecx movl %ecx, %fs UNWIND_ESPFIX_STACK popl %ecx
===================================================================
arch/i386/kernel/head.S +6 -25
@@ -317,12 +317,12 @@ 2: movl %cr0,%eax movl %eax,%cr0 call check_x87 - call setup_pda lgdt early_gdt_descr lidt idt_descr ljmp $(__KERNEL_CS),$1f 1: movl $(__KERNEL_DS),%eax # reload all the segment registers movl %eax,%ss # after changing gdt. + movl %eax,%fs # gets reset once there's real percpu movl $(__USER_DS),%eax # DS/ES contains default USER segment movl %eax,%ds
@@ -331,9 +331,6 @@ 1: movl $(__KERNEL_DS),%eax # reload all xorl %eax,%eax # Clear GS and LDT movl %eax,%gs lldt %ax - - movl $(__KERNEL_PDA),%eax - mov %eax,%fs cld # gcc2 wants the direction flag cleared at all times pushl $0 # fake return address for unwinder
@@ -341,7 +338,11 @@ 1: movl $(__KERNEL_DS),%eax # reload all movb ready, %cl movb $1, ready cmpb $0,%cl # the first CPU calls start_kernel - jne initialize_secondary # all other CPUs call initialize_secondary + je 1f + movl $(__KERNEL_PERCPU), %eax + movl %eax,%fs # set this cpu's percpu + jmp initialize_secondary # all other CPUs call initialize_secondary +1: #endif /* CONFIG_SMP */ jmp start_kernel
@@ -362,23 +363,6 @@ check_x87: ALIGN 1: movb $1,X86_HARD_MATH .byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */ - ret - -/* - * Point the GDT at this CPU's PDA. On boot this will be - * cpu_gdt_table and boot_pda; for secondary CPUs, these will be - * that CPU's GDT and PDA. - */ -ENTRY(setup_pda) - /* get the PDA pointer */ - movl start_pda, %eax - - /* slot the PDA address into the GDT */ - mov early_gdt_descr+2, %ecx - mov %ax, (__KERNEL_PDA+0+2)(%ecx) /* base & 0x0000ffff */ - shr $16, %eax - mov %al, (__KERNEL_PDA+4+0)(%ecx) /* base & 0x00ff0000 */ - mov %ah, (__KERNEL_PDA+4+3)(%ecx) /* base & 0xff000000 */ ret /*
@@ -553,9 +537,6 @@ ENTRY(empty_zero_page) * This starts the data section. */ .data -ENTRY(start_pda) - .long boot_pda - ENTRY(stack_start) .long init_thread_union+THREAD_SIZE .long __BOOT_DS
===================================================================
arch/i386/kernel/i386_ksyms.c +0 -2
@@ -28,5 +28,3 @@ EXPORT_SYMBOL(__read_lock_failed);#endif EXPORT_SYMBOL (csum_partial); - -EXPORT_SYMBOL (_proxy_pda);
===================================================================
arch/i386/kernel/irq.c +3 -0
@@ -23,6 +23,9 @@DEFINE_PER_CPU (irq_cpustat_t, irq_stat)____cacheline_internodealigned_in_smp ;EXPORT_PER_CPU_SYMBOL (irq_stat); + +DEFINE_PER_CPU(struct pt_regs *, irq_regs); +EXPORT_PER_CPU_SYMBOL (irq_regs);/* * 'what should we do if we get a hw irq event on an illegal vector'.
===================================================================
arch/i386/kernel/process.c +9 -3
@@ -39,6 +39,7 @@#include <linux/random.h> #include <linux/personality.h> #include <linux/tick.h> +#include <linux/percpu.h> #include <asm/uaccess.h> #include <asm/pgtable.h>
@@ -57,7 +58,6 @@#include <asm/tlbflush.h> #include <asm/cpu.h> -#include <asm/pda.h> asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
@@ -65,6 +65,12 @@ static int hlt_counter;unsigned long boot_option_idle_override =0 ;EXPORT_SYMBOL (boot_option_idle_override); + +DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task; +EXPORT_PER_CPU_SYMBOL (current_task); + +DEFINE_PER_CPU (int, cpu_number); +EXPORT_PER_CPU_SYMBOL (cpu_number);/* * Return saved PC of a blocked thread.
@@ -342,7 +348,7 @@ int kernel_thread(int (*fn)(void *), voi regs.xds = __USER_DS; regs.xes = __USER_DS; - regs.xfs = __KERNEL_PDA; + regs.xfs = __KERNEL_PERCPU; regs.orig_eax =-1 ; regs.eip = (unsigned long ) kernel_thread_helper; regs.xcs = __KERNEL_CS |get_kernel_rpl ();
@@ -711,7 +717,7 @@ struct task_struct fastcall * __switch_tif (prev->gs | next->gs)loadsegment (gs, next->gs); -write_pda (pcurrent, next_p); +x86_write_percpu (current_task, next_p);return prev_p; }
===================================================================
arch/i386/kernel/smpboot.c +16 -18
@@ -53,7 +53,6 @@#include <asm/desc.h> #include <asm/arch_hooks.h> #include <asm/nmi.h> -#include <asm/pda.h> #include <mach_apic.h> #include <mach_wakecpu.h>
@@ -98,6 +97,9 @@ EXPORT_SYMBOL(x86_cpu_to_apicid);EXPORT_SYMBOL (x86_cpu_to_apicid);u8 apicid_2_node[MAX_APICID ]; + +DEFINE_PER_CPU(unsigned long, this_cpu_off); +EXPORT_PER_CPU_SYMBOL (this_cpu_off);/* * Trampoline 80x86 program as an array.
@@ -456,7 +458,6 @@ extern struct {void * esp;unsigned short ss; } stack_start; -extern struct i386_pda *start_pda;#ifdef CONFIG_NUMA
@@ -784,20 +785,17 @@ static inline struct task_struct * alloc/* Initialize the CPU's GDT. This is either the boot CPU doing itself (still using the master per-cpu area), or a CPU doing it for a secondary which will soon come up. */ -static __cpuinit void init_gdt (int cpu,struct task_struct *idle) +static __cpuinit void init_gdt (int cpu) {struct desc_struct *gdt =get_cpu_gdt_table (cpu); -struct i386_pda *pda = &per_cpu (_cpu_pda, cpu); - -pack_descriptor ((u32 *)&gdt[GDT_ENTRY_PDA ].a, - (u32 *)&gdt[GDT_ENTRY_PDA ].b, - (unsigned long )pda,sizeof (*pda) -1 , -0x80 |DESCTYPE_S |0x2 ,0 );/* present read-write data segment */ - -memset (pda,0 ,sizeof (*pda)); - pda->_pda = pda; - pda->cpu_number = cpu; - pda->pcurrent = idle; + +pack_descriptor ((u32 *)&gdt[GDT_ENTRY_PERCPU ].a, + (u32 *)&gdt[GDT_ENTRY_PERCPU ].b, + __per_cpu_offset[cpu],0xFFFFF , +0x80 |DESCTYPE_S |0x2 ,0x8 ); + +per_cpu (this_cpu_off, cpu) = __per_cpu_offset[cpu]; +per_cpu (cpu_number, cpu) = cpu; }/* Defined in head.S */
@@ -824,9 +822,9 @@ static int __cpuinit do_boot_cpu(int apiif (IS_ERR (idle))panic ("failed fork for CPU %d" , cpu); -init_gdt (cpu, idle); +init_gdt (cpu); +per_cpu (current_task, cpu) = idle; early_gdt_descr.address = (unsigned long )get_cpu_gdt_table (cpu); - start_pda =cpu_pda (cpu); idle->thread.eip = (unsigned long ) start_secondary;/* start_eip had better be page-aligned! */
@@ -1188,14 +1186,14 @@ static inline void switch_to_new_gdt(voi gdt_descr.address = (long )get_cpu_gdt_table (smp_processor_id ()); gdt_descr.size =GDT_SIZE -1 ;load_gdt (&gdt_descr); - asmvolatile ("mov %0, %%fs" : :"r" (__KERNEL_PDA) :"memory" ); + asm("mov %0, %%fs" : :"r" (__KERNEL_PERCPU) :"memory" ); }void __init native_smp_prepare_boot_cpu (void ) {unsigned int cpu =smp_processor_id (); -init_gdt (cpu, current); +init_gdt (cpu);switch_to_new_gdt ();cpu_set (cpu, cpu_online_map);
===================================================================
arch/i386/kernel/vmi.c +1 -5
@@ -504,8 +504,6 @@ static void vmi_pmd_clear(pmd_t *pmd)#endif #ifdef CONFIG_SMP -extern void setup_pda (void ); -static void __devinit vmi_startup_ipi_hook (int phys_apicid,unsigned long start_eip,unsigned long start_esp)
@@ -530,12 +528,10 @@ vmi_startup_ipi_hook(int phys_apicid, un ap.ds = __USER_DS; ap.es = __USER_DS; - ap.fs = __KERNEL_PDA; + ap.fs = __KERNEL_PERCPU; ap.gs =0 ; ap.eflags =0 ; - -setup_pda ();#ifdef CONFIG_X86_PAE /* efer should match BSP efer. */
===================================================================
arch/i386/kernel/vmlinux.lds.S +0 -1
@@ -26,7 +26,6 @@ OUTPUT_ARCH(i386) OUTPUT_ARCH(i386) ENTRY(phys_startup_32) jiffies = jiffies_64; -_proxy_pda = 0; PHDRS { text PT_LOAD FLAGS(5); /* R_E */
===================================================================
include/asm-i386/current.h +3 -2
@@ -1,14 +1,15 @@#ifndef _I386_CURRENT_H#define _I386_CURRENT_H -#include <asm/pda.h> #include <linux/compiler.h> +#include <asm/percpu.h> struct task_struct ; +DECLARE_PER_CPU(struct task_struct *, current_task); static __always_inline struct task_struct *get_current(void) { -return read_pda (pcurrent); +return x86_read_percpu (current_task); }#define current get_current()
===================================================================
include/asm-i386/irq_regs.h +7 -5
@@ -1,25 +1,27 @@/* * Per-cpu current frame pointer - the location of the last exception frame on -* the stack, stored in the PDA. +* the stack, stored in the per-cpu area. * * Jeremy Fitzhardinge <[email protected]> */ #ifndef _ASM_I386_IRQ_REGS_H#define _ASM_I386_IRQ_REGS_H -#include <asm/pda.h> +#include <asm/percpu.h> + +DECLARE_PER_CPU(struct pt_regs *, irq_regs);static inline struct pt_regs *get_irq_regs (void ) { -return read_pda (irq_regs); +return x86_read_percpu (irq_regs); }static inline struct pt_regs *set_irq_regs (struct pt_regs *new_regs) {struct pt_regs *old_regs; - old_regs =read_pda (irq_regs); -write_pda (irq_regs, new_regs); + old_regs =get_irq_regs (); +x86_write_percpu (irq_regs, new_regs);return old_regs; }
===================================================================
include/asm-i386/pda.h deleted +0 -99
99 lines not on this page · raw message
===================================================================
include/asm-i386/percpu.h +123 -9
146 lines not on this page · raw message
===================================================================
include/asm-i386/processor.h +1 -1
@@ -377,7 +377,7 @@ struct thread_struct { .vm86_info = NULL, \ .sysenter_cs = __KERNEL_CS, \ .io_bitmap_ptr = NULL, \ - .fs = __KERNEL_PDA, \ + .fs = __KERNEL_PERCPU, \ }/*
===================================================================
include/asm-i386/segment.h +3 -3
@@ -39,7 +39,7 @@* 25 - APM BIOS support * * 26 - ESPFIX small SS -* 27 - PDA [ per-cpu private data area ] +* 27 - per-cpu [ offset to per-cpu data area ] * 28 - unused * 29 - unused * 30 - unused
@@ -74,8 +74,8 @@#define GDT_ENTRY_ESPFIX_SS (GDT_ENTRY_KERNEL_BASE + 14)#define __ESPFIX_SS (GDT_ENTRY_ESPFIX_SS * 8) -#define GDT_ENTRY_PDA (GDT_ENTRY_KERNEL_BASE + 15) -#define __KERNEL_PDA (GDT_ENTRY_PDA * 8) +#define GDT_ENTRY_PERCPU (GDT_ENTRY_KERNEL_BASE + 15) +#define __KERNEL_PERCPU (GDT_ENTRY_PERCPU * 8)#define GDT_ENTRY_DOUBLEFAULT_TSS 31
===================================================================
include/asm-i386/smp.h +2 -2
@@ -8,7 +8,6 @@#include <linux/kernel.h> #include <linux/threads.h> #include <linux/cpumask.h> -#include <asm/pda.h> #endif #if defined(CONFIG_X86_LOCAL_APIC ) && !defined(__ASSEMBLY__)
@@ -112,7 +111,8 @@ do { } while (0)* from the initial startup. We map APIC_BASE very early in page_setup(), * so this is correct in the x86 case. */ -#define raw_smp_processor_id () (read_pda(cpu_number)) +DECLARE_PER_CPU (int, cpu_number); +#define raw_smp_processor_id () (x86_read_percpu(cpu_number))extern cpumask_t cpu_callout_map;extern cpumask_t cpu_callin_map;
===================================================================
include/asm-i386/unwind.h +1 -1
@@ -71,7 +71,7 @@ static inline void arch_unw_init_blocked info->regs.xss = __KERNEL_DS; info->regs.xds = __USER_DS; info->regs.xes = __USER_DS; - info->regs.xfs = __KERNEL_PDA; + info->regs.xfs = __KERNEL_PERCPU; } extern asmlinkage int arch_unwind_init_running(struct unwind_frame_info *,
PATCH 7/28 cleanups to help using per-cpu variables from asm
In reply to Jeremy FitzhardingeThis patch does a few small cleanups:
- use PER_CPU_NAME to generate the names of per-cpu variables
- use lea to add the per_cpu offset in PER_CPU(), because it doesn't affect condition flags
- add PER_CPU_VAR which allows direct access to pre-cpu variables with the %fs: prefix on SMP.
--- include/asm-i386/percpu.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
===================================================================
include/asm-i386/percpu.h +7 -5
@@ -16,12 +16,14 @@* PER_CPU(cpu_gdt_descr, %ebx) */ #ifdef CONFIG_SMP +#define PER_CPU (var, reg) \ + movl %fs:per_cpu__##this_cpu_off, reg; \ + lea per_cpu__##var(reg), reg +#define PER_CPU_VAR (var) %fs:per_cpu__##var +#else /* ! SMP */ #define PER_CPU (var, reg) \ - movl %fs:per_cpu__this_cpu_off, reg; \ - addl $per_cpu__##var, reg -#else /* ! SMP */ -#define PER_CPU (var, reg) \ - movl $per_cpu__##var, reg; + movl $per_cpu__##var, reg +#define PER_CPU_VAR (var) per_cpu__##var#endif /* SMP */ #else /* ...!ASSEMBLY */
PATCH 8/28 Define per_cpu_offset
In reply to Jeremy FitzhardingeDefine per_cpu_offset in asm-i386/percpu.h when SMP defined, like asm-generic/percpu.h does for UP.
--- include/asm-i386/percpu.h | 2 ++ 1 file changed, 2 insertions(+)
===================================================================
include/asm-i386/percpu.h +2 -0
@@ -34,6 +34,8 @@/* This is used for other cpus to find our section. */ extern unsigned long __per_cpu_offset[]; + +#define per_cpu_offset (x) (__per_cpu_offset[x])/* Separate out the type, so (int[3], foo) works. */ #define DECLARE_PER_CPU (type, name) extern __typeof__(type) per_cpu__##name
PATCH 9/28 Fix UP gdt bugs
In reply to Jeremy FitzhardingeFixes two problems with the GDT when compiling for uniprocessor:
- There's no percpu segment, so trying to load its selector into %fs fails. Use a null selector instead.
- The real gdt needs to be loaded at some point. Do it in cpu_init().
--- arch/i386/kernel/cpu/common.c | 13 +++++++++++++ arch/i386/kernel/smpboot.c | 12 ------------ include/asm-i386/processor.h | 1 + include/asm-i386/segment.h | 4 ++++ 4 files changed, 18 insertions(+), 12 deletions(-)
===================================================================
arch/i386/kernel/cpu/common.c +13 -0
@@ -644,6 +644,18 @@ struct pt_regs * __devinit idle_regs(strreturn regs; } +/* Current gdt points %fs at the "master" per-cpu area: after this, +* it's on the real one. */ +void switch_to_new_gdt (void ) +{ +struct Xgt_desc_struct gdt_descr; + + gdt_descr.address = (long )get_cpu_gdt_table (smp_processor_id ()); + gdt_descr.size =GDT_SIZE -1 ; +load_gdt (&gdt_descr); + asm("mov %0, %%fs" : :"r" (__KERNEL_PERCPU) :"memory" ); +} +/* * cpu_init() initializes state that is per-CPU. Some data is already * initialized (naturally) in the bootstrap process, such as the GDT
@@ -674,6 +688,7 @@ void __cpuinit cpu_init(void) }load_idt (&idt_descr); +switch_to_new_gdt ();/* * Set up and load the per-CPU TSS and LDT
===================================================================
arch/i386/kernel/smpboot.c +0 -12
@@ -1176,18 +1176,6 @@ void __init native_smp_prepare_cpus(unsismp_boot_cpus (max_cpus); } -/* Current gdt points %fs at the "master" per-cpu area: after this, -* it's on the real one. */ -static inline void switch_to_new_gdt (void ) -{ -struct Xgt_desc_struct gdt_descr; - - gdt_descr.address = (long )get_cpu_gdt_table (smp_processor_id ()); - gdt_descr.size =GDT_SIZE -1 ; -load_gdt (&gdt_descr); - asm("mov %0, %%fs" : :"r" (__KERNEL_PERCPU) :"memory" ); -} -void __init native_smp_prepare_boot_cpu (void ) {unsigned int cpu =smp_processor_id ();
===================================================================
include/asm-i386/processor.h +1 -0
@@ -777,6 +777,7 @@ extern int sysenter_setup(void);extern int sysenter_setup (void );extern void cpu_set_gdt (int ); +extern void switch_to_new_gdt (void );extern void cpu_init (void );#endif /* __ASM_I386_PROCESSOR_H */
===================================================================
include/asm-i386/segment.h +4 -0
@@ -75,7 +75,11 @@#define __ESPFIX_SS (GDT_ENTRY_ESPFIX_SS * 8)#define GDT_ENTRY_PERCPU (GDT_ENTRY_KERNEL_BASE + 15) +#ifdef CONFIG_SMP #define __KERNEL_PERCPU (GDT_ENTRY_PERCPU * 8) +#else +#define __KERNEL_PERCPU 0 +#endif #define GDT_ENTRY_DOUBLEFAULT_TSS 31
PATCH 10/28 i386: map enough initial memory to create lowmem mappings
In reply to Jeremy Fitzhardingehead.S creates the very initial pagetable for the kernel. This just maps enough space for the kernel itself, and an allocation bitmap. The amount of mapped memory is rounded up to 4Mbytes, and so this typically ends up mapping 8Mbytes of memory.
When booting, pagetable_init() needs to create mappings for all lowmem, and the pagetables for these mappings are allocated from the free pages around the kernel in low memory. If the number of pagetable pages + kernel size exceeds head.S's initial mapping, it will end up faulting on an unmapped page. This will only happen with specific combinations of kernel size and memory size.
This patch makes sure that head.S also maps enough space to fit the kernel pagetables as well as the kernel itself. It ends up using an additional two pages of unreclaimable memory.
--- arch/i386/kernel/asm-offsets.c | 6 ++++++ arch/i386/kernel/head.S | 25 ++++++++++++++++++++----- 2 files changed, 26 insertions(+), 5 deletions(-)
===================================================================
arch/i386/kernel/asm-offsets.c +6 -0
@@ -11,6 +11,7 @@#include <linux/suspend.h> #include <asm/ucontext.h> #include "sigframe.h" +#include <asm/pgtable.h> #include <asm/fixmap.h> #include <asm/processor.h> #include <asm/thread_info.h>
@@ -96,6 +97,11 @@ void foo(void) sizeof(struct tss_struct));DEFINE (PAGE_SIZE_asm,PAGE_SIZE ); +DEFINE (PAGE_SHIFT_asm,PAGE_SHIFT ); +DEFINE (PTRS_PER_PTE ,PTRS_PER_PTE ); +DEFINE (PTRS_PER_PMD ,PTRS_PER_PMD ); +DEFINE (PTRS_PER_PGD ,PTRS_PER_PGD ); +DEFINE (VDSO_PRELINK_asm,VDSO_PRELINK );OFFSET (crypto_tfm_ctx_offset, crypto_tfm, __crt_ctx);
===================================================================
arch/i386/kernel/head.S +20 -5
@@ -34,17 +34,32 @@ /* * This is how much memory *in addition to the memory covered up to - * and including _end* we need mapped initially. We need one bit for - * each possible page, but only in low memory, which means - * 2^32/4096/8 = 128K worst case (4G/4G split.) + * and including _end* we need mapped initially. + * We need: + * - one bit for each possible page, but only in low memory, which means + * 2^32/4096/8 = 128K worst case (4G/4G split.) + * - enough space to map all low memory, which means + * (2^32/4096) / 1024 pages (worst case, non PAE) + * (2^32/4096) / 512 + 4 pages (worst case for PAE) + * - a few pages for allocator use before the kernel pagetable has + * been set up * * Modulo rounding, each megabyte assigned here requires a kilobyte of * memory, which is currently unreclaimed. * * This should be a multiple of a page. */ -#define INIT_MAP_BEYOND_END (128*1024) - +LOW_PAGES = 1<<(32-PAGE_SHIFT_asm) + +#if PTRS_PER_PMD > 1 +PAGE_TABLE_SIZE = (LOW_PAGES / PTRS_PER_PMD) + PTRS_PER_PGD +#else +PAGE_TABLE_SIZE = (LOW_PAGES / PTRS_PER_PGD) +#endif +BOOTBITMAP_SIZE = LOW_PAGES / 8 +ALLOCATOR_SLOP = 4 + +INIT_MAP_BEYOND_END = BOOTBITMAP_SIZE + (PAGE_TABLE_SIZE + ALLOCATOR_SLOP)*PAGE_SIZE_asm /* * 32-bit kernel entrypoint; only used by the boot CPU. On entry,
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
arch/i386/kernel/head.S line 53
Quoted 3 lines · Jeremy Fitzhardinge
arch/i386/kernel/head.S +2
-1- +LOW_PAGES = 1<<(32-PAGE_SHIFT_asm) +
Again, for debugging... it would be interesting to replace this with:
LOW_PAGES = (0x100000000-__PAGE_OFFSET) >> PAGE_SHIFT_asm
... to smoke out further problems; this will take the strict definition of "lowmem" (modulo the pci region, which someone unwisely made dynamically adjustable... which would have been fine if initramfs could live in highmem, which it can't yet.)
-hpa
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 9 lines · H. Peter Anvin
arch/i386/kernel/head.S line 53
Quoted 3 lines · Jeremy Fitzhardinge
arch/i386/kernel/head.S +2
-1- +LOW_PAGES = 1<<(32-PAGE_SHIFT_asm) +Again, for debugging... it would be interesting to replace this with:
LOW_PAGES= (0x100000000-__PAGE_OFFSET) >>PAGE_SHIFT_asm
LOW_PAGES = (0x100000000ULL - __PAGE_OFFSET) >> PAGE_SHIT_asm
Jan
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 1 line · Jan Engelhardt
LOW_PAGES= (0x100000000ULL-__PAGE_OFFSET) >>PAGE_SHIT_asm
The assembler does not now anything about ULL.
Andreas.
Signature · 4 lines
Andreas Schwab, SuSE Labs, [email protected] SuSE Linux Products GmbH, Maxfeldstraße 5, 90409 Nürnberg, Germany PGP key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5 "And now for something completely different."
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
In reply to Jeremy FitzhardingeQuoted 16 lines · Jeremy Fitzhardinge
head.Screates the very initial pagetable for the kernel. This just maps enough space for the kernel itself, and an allocation bitmap. The amount of mapped memory is rounded up to 4Mbytes, and so this typically ends up mapping 8Mbytes of memory.When booting,
pagetable_init()needs to create mappings for all lowmem, and the pagetables for these mappings are allocated from the free pages around the kernel in low memory. If the number of pagetable pages + kernel size exceeds head.S's initial mapping, it will end up faulting on an unmapped page. This will only happen with specific combinations of kernel size and memory size.This patch makes sure that
head.Salso maps enough space to fit the kernel pagetables as well as the kernel itself. It ends up using an additional two pages of unreclaimable memory.
Quoted 7 lines
Signed-off-by Jeremy Fitzhardinge <[email protected]>Acked-by "H. Peter Anvin" <[email protected]>Cc Andi Kleen <[email protected]>Cc Zachary Amsden <[email protected]>Cc Chris Wright <[email protected]>Cc "Eric W. Biederman" <[email protected]>Cc Linus Torvalds <[email protected]>,
Is some version of this going in for 2.6.21, or is it not a real problem?
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 3 lines
Is some version of this going in for 2.6.21, or is it not a real problem?
When it's only seen with Xen it's not a real problem right now.
-Andi
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 3 lines · Andi Kleen
Quoted 1 line
Is some version of this going in for 2.6.21, or is it not a real problem?
When it's only seen with Xen it's not a real problem right now.
It's not just seen only with Xen, though. It will affect all kernels in a particular range of sizes, and we have ordinary kernels covering that range (in fact, Xen hardly affects size in that way.)
-hpa
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 8 lines · On Thursday 19 April 2007 22:55:50 H. Peter Anvin wrote:
Quoted 3 lines · Andi Kleen
Quoted 1 line
Is some version of this going in for 2.6.21, or is it not a real problem?
When it's only seen with Xen it's not a real problem right now.
It's not just seen only with Xen, though. It will affect all kernels in a particular range of sizes, and we have ordinary kernels covering that range (in fact, Xen hardly affects size in that way.)
Then we would have seen reports surely?
-Andi
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 7 lines · Andi Kleen
Quoted 4 lines · On Thursday 19 April 2007 22:55:50 H. Peter Anvin wrote:
Quoted 2 lines · Andi Kleen
Quoted 1 line
Is some version of this going in for 2.6.21, or is it not a real problem?
When it's only seen with Xen it's not a real problem right now.
It's not just seen only with Xen, though. It will affect all kernels in a particular range of sizes, and we have ordinary kernels covering that range (in fact, Xen hardly affects size in that way.)
Then we would have seen reports surely?
The critical size window is relatively small, though. The size of the uncompressed kernel mod 4 MB must be above 3.75 MB or so. If you have less than 1 GB RAM, the window is even smaller. This is strictly configuration-dependent, and has nothing to do with Xen. It just so happened that the first people to detect and diagnose it (as opposed to just "it doesn't boot") were Xen people.
-hpa
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 10 lines · H. Peter Anvin
Quoted 9 lines · Andi Kleen
Quoted 7 lines · On Thursday 19 April 2007 22:55:50 H. Peter Anvin wrote:
Quoted 3 lines · Andi Kleen
Quoted 2 lines
Is some version of this going in for 2.6.21, or is it not a real problem?
When it's only seen with Xen it's not a real problem right now.
It's not just seen only with Xen, though. It will affect all kernels in a particular range of sizes, and we have ordinary kernels covering that range (in fact, Xen hardly affects size in that way.)
Quoted 8 lines
Quoted 1 line
Then we would have seen reports surely?
The critical size window is relatively small, though. The size of the uncompressed kernel mod 4 MB must be above 3.75 MB or so. If you have less than 1 GB RAM, the window is even smaller. This is strictly configuration-dependent, and has nothing to do with Xen. It just so happened that the first people to detect and diagnose it (as opposed to just "it doesn't boot") were Xen people.
I never saw a description of the symptoms of encountering this bug. Does it just hang, or what?
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 6 lines · Chuck Ebbert
Quoted 4 lines · H. Peter Anvin
Quoted 2 lines · Andi Kleen
Then we would have seen reports surely?
Yes, I would have thought so. It surprised me that such an obvious bug could be there, apparently for a long time. But it's real, and potentially affects everyone. It probably doesn't affect highly modular distros much, since the kernel itself will be relatively small.
Quoted 3 lines
I never saw a description of the symptoms of encountering this bug. Does it just hang, or what?
You get an early-fault message on-screen, assuming that's enabled; otherwise it will just appear to hang. It happens in pagetable_init, when it allocates a new pagetable above the head.S mapping (8M in my case). It will only hit if the kernel size approaches a 4M boundary, since it won't leave enough space mapped to construct the lowmem mappings.
It only affects native booting, since under Xen all those mappings have already been constructed. It happened to me with a paravirt kernel that happened to Xen compiled into it, but that was irrelevent (though misleading; the 40k difference in kernel size was enough to make it not happen in a non-Xen kernel).
J
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 23 lines · Jeremy Fitzhardinge
Quoted 6 lines · Chuck Ebbert
Quoted 4 lines · H. Peter Anvin
Quoted 2 lines · Andi Kleen
Then we would have seen reports surely?
Yes, I would have thought so. It surprised me that such an obvious bug could be there, apparently for a long time. But it's real, and potentially affects everyone. It probably doesn't affect highly modular distros much, since the kernel itself will be relatively small.
Quoted 3 lines
I never saw a description of the symptoms of encountering this bug. Does it just hang, or what?
You get an early-fault message on-screen, assuming that's enabled; otherwise it will just appear to hang. It happens in
pagetable_init, when it allocates a new pagetable above thehead.Smapping (8M in my case). It will only hit if the kernel size approaches a 4M boundary, since it won't leave enough space mapped to construct the lowmem mappings.
Quoted 5 lines
It only affects native booting, since under Xen all those mappings have already been constructed. It happened to me with a paravirt kernel that happened to Xen compiled into it, but that was irrelevent (though misleading; the 40k difference in kernel size was enough to make it not happen in a non-Xen kernel).
I happened to be looking at this stretch of code and I have realized that this is quite simply the wrong fix.
The problem is that it depends intimately on the details of alloc_bootmem_pages_low. Essentially the problem is that when we are setting up the identity mappings in paging_init we assume the identity mappings already exist.
If there are holes in the memory map or someone changes the way pages are returned from alloc_bootmem_pages_low() this code will break again.
The only way to ensure this will not happen is to do what we do on x86_64 and map the new page table page into our address space before we write to it. Assuming the page we allocate is already mapped is simply not robust.
Eric
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 4 lines · Eric W. Biederman
I happened to be looking at this stretch of code and I have realized that this is quite simply the wrong fix.
Quoted 9 lines
The problem is that it depends intimately on the details of
alloc_bootmem_pages_low. Essentially the problem is that when we are setting up the identity mappings inpaging_initwe assume the identity mappings already exist.If there are holes in the memory map or someone changes the way pages are returned from
alloc_bootmem_pages_low()this code will break again.
How would holes in the memory map affect it?
-hpa
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
In reply to Eric W. BiedermanQuoted 5 lines · Eric W. Biederman
The only way to ensure this will not happen is to do what we do on
x86_64and map the new page table page into our address space before we write to it. Assuming the page we allocate is already mapped is simply not robust.
So you mean make alloc_bootmem make sure there's a mapping for the returned page? That would be simple enough, though it might interact strangely with the actual construction of the memory mappings (what if the page alloc_bootmem just allocated for the pagetable is the page pagetable_init is actually trying to map?).
I'm not sure about the issue with holes. I assume you mean that just because head.S maps a chunk of memory, it isn't necessarily available for allocation because its a hole. But does alloc_bootmem know to avoid them anyway? Has it already parsed e820 at that point?
J
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 13 lines · Jeremy Fitzhardinge
Quoted 5 lines · Eric W. Biederman
The only way to ensure this will not happen is to do what we do on
x86_64and map the new page table page into our address space before we write to it. Assuming the page we allocate is already mapped is simply not robust.So you mean make
alloc_bootmemmake sure there's a mapping for the returned page? That would be simple enough, though it might interact strangely with the actual construction of the memory mappings (what if the pagealloc_bootmemjust allocated for the pagetable is the pagepagetable_initis actually trying to map?).
Quoted 5 lines
I'm not sure about the issue with holes. I assume you mean that just because
head.Smaps a chunk of memory, it isn't necessarily available for allocation because its a hole. But doesalloc_bootmemknow to avoid them anyway? Has it already parsed e820 at that point?
Since we allocate the maximum possible memory statically, I fail to see how holes could make the situation any worse, or better.
-hpa
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 2 lines · H. Peter Anvin
Since we allocate the maximum possible memory statically, I fail to see how holes could make the situation any worse, or better.
No, we map enough space to map 4G (~4 pages), but we don't actually map 4G. If a hole happened to start within that 4 page mapping, then the memory still wouldn't be available for allocation.
I think this is a bit of a spurious argument though, since if it were really a problem we'd have to worry about holes hitting the kernel image too. As far as I can see, that's not considered to be a problem.
I think the real point is that there's currently a subtle dependency between head.S and bootmem allocation which happens between start_kernel and pagetable_init. Your patch preventing over-mapping should make them easier to smoke out as it currently stands, but eliminating the problem by making alloc_bootmem create the mappings for itself does have appeal. There would still be the dependency on head.S to map the kernel itself and the bootmem allocator bitmap.
J
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 12 lines · Jeremy Fitzhardinge
Quoted 2 lines · H. Peter Anvin
Since we allocate the maximum possible memory statically, I fail to see how holes could make the situation any worse, or better.
No, we map enough space to map 4G (~4 pages), but we don't actually map 4G. If a hole happened to start within that 4 page mapping, then the memory still wouldn't be available for allocation.
I think this is a bit of a spurious argument though, since if it were really a problem we'd have to worry about holes hitting the kernel image too. As far as I can see, that's not considered to be a problem.
Quoted 8 lines
I think the real point is that there's currently a subtle dependency between
head.Sand bootmem allocation which happens betweenstart_kernelandpagetable_init. Your patch preventing over-mapping should make them easier to smoke out as it currently stands, but eliminating the problem by makingalloc_bootmemcreate the mappings for itself does have appeal. There would still be the dependency onhead.Sto map the kernel itself and the bootmem allocator bitmap.
Agreed. However, saying that your patch shouldn't go into the mainline kernel until that has been fixed is spurious and wrong. It fixes a real problem with minimal risk.
-hpa
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 3 lines · H. Peter Anvin
Agreed. However, saying that your patch shouldn't go into the mainline kernel until that has been fixed is spurious and wrong. It fixes a real problem with minimal risk.
For a stable and frozen kernel it is probably the best we can do.
However the code is based on confusion of what should be happening and it increases the complexity of the code and pushes us towards the edge of code that is so crufty it is impossible to maintain.
We need to simplify this mess not make it more convoluted.
Did anyone else notice that if we don't have PAE we continue to use the initial page tables 4K page mappings of the kernel?
This probably explains why experiments to 4MB align the i386 kernel to improve performance failed.
Eric
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
In reply to Jeremy FitzhardingeQuoted 11 lines · Jeremy Fitzhardinge
Quoted 2 lines · H. Peter Anvin
Since we allocate the maximum possible memory statically, I fail to see how holes could make the situation any worse, or better.
No, we map enough space to map 4G (~4 pages), but we don't actually map 4G. If a hole happened to start within that 4 page mapping, then the memory still wouldn't be available for allocation.
I think this is a bit of a spurious argument though, since if it were really a problem we'd have to worry about holes hitting the kernel image too. As far as I can see, that's not considered to be a problem.
- holes hitting the kernel image is not something we can do anything about.
- I have always believed we need to export enough information so the bootloader can verify that we don't hit a hole in the initial kernel image.
- I know of one system that had BIOS tables at 16MB I believe (and thus had a fairly low hole).
- Given that we are actually increasing (not decreasing) the number of scenarios where we boot the kernel it probably makes sense to be as robust as we can.
- If we support putting the ramdisk immediately after the kernel image in memory we will actually hit this case in practice.
Quoted 7 lines
I think the real point is that there's currently a subtle dependency between
head.Sand bootmem allocation which happens betweenstart_kernelandpagetable_init. Your patch preventing over-mapping should make them easier to smoke out as it currently stands, but eliminating the problem by makingalloc_bootmemcreate the mappings for itself does have appeal. There would still be the dependency onhead.Sto map the kernel itself and the bootmem allocator bitmap.
Agreed. However that is essentially all statically allocated memory and the best we can do at this point in time.
Eric
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 4 lines · Eric W. Biederman
- I know of one system that had BIOS tables at 16MB I believe (and thus had a fairly low hole).
Please name names, otherwise this is just rumouring. Seriously. We have enough cargo-cult programming as it is.
A lot of old ISA systems had an option to put a memory hole at 15-16 MB to support ISA video cards with linear frame buffer. It very rarely got used, since VLB took over around the same time.
-hpa
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 8 lines · H. Peter Anvin
Quoted 4 lines · Eric W. Biederman
- I know of one system that had BIOS tables at 16MB I believe (and thus had a fairly low hole).
Please name names, otherwise this is just rumouring. Seriously. We have enough cargo-cult programming as it is.
The unisys systems. I don't remember exactly where they put there ACPI tables but it was low enough that the default address for the kdump kernels conflicted with it. So this is likely 16MB or 32MB
Quoted 3 lines
A lot of old ISA systems had an option to put a memory hole at 15-16 MB to support ISA video cards with linear frame buffer. It very rarely got used, since VLB took over around the same time.
No this was a much larger and more modern system.
Eric
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
In reply to H. Peter AnvinQuoted 8 lines · On Monday 23 April 2007 19:45:41 H. Peter Anvin wrote:
Quoted 4 lines · Eric W. Biederman
- I know of one system that had BIOS tables at 16MB I believe (and thus had a fairly low hole).
Please name names, otherwise this is just rumouring. Seriously. We have enough cargo-cult programming as it is.
Unisys did this at some point in their large machines, but they fixed that in a later BIOS.
Anyways, boot up should be robust against any holes if possible.
-Andi
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
In reply to H. Peter AnvinQuoted 2 lines · H. Peter Anvin
Since we allocate the maximum possible memory statically, I fail to see how holes could make the situation any worse, or better.
Consider a memory hole of size 8M immediately after our bootmem bitmap. head.S which knows nothing of holes will map the pages of the hole into the initial page tables assuming that is where the page tables will live.
alloc_bootmem_low_pages which understands holes will skip those pages and return a higher address, which is outside of our initial mapping of pages.
As for how to fix this, we need to call boot_ioremap or better bt_ioremap on the address returned from alloc_bootmem_pages_low to force the allocated page into the page table. After we have setup the page table page we can call unmap the page to free up the scarce early mapping resource.
Eric
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 5 lines · Eric W. Biederman
Consider a memory hole of size 8M immediately after our bootmem bitmap.
head.Swhich knows nothing of holes will map the pages of the hole into the initial page tables assuming that is where the page tables will live.
Sure, but considering we're only talking about mapping an additional *2* pages, the chances are that it will affect a kernel as much as the early head.S mapping. It's well within the variability of fairly similar kernel configs.
Quoted 6 lines
As for how to fix this, we need to call
boot_ioremapor betterbt_ioremapon the address returned fromalloc_bootmem_pages_lowto force the allocated page into the page table. After we have setup the page table page we can call unmap the page to free up the scarce early mapping resource.
Would that be necessary? Is there any need to remap it? Couldn't you just do the straightforward phys->virt mapping and use the page where it lies?
J
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 11 lines · Jeremy Fitzhardinge
Quoted 5 lines · Eric W. Biederman
Consider a memory hole of size 8M immediately after our bootmem bitmap.
head.Swhich knows nothing of holes will map the pages of the hole into the initial page tables assuming that is where the page tables will live.Sure, but considering we're only talking about mapping an additional *2* pages, the chances are that it will affect a kernel as much as the early
head.Smapping. It's well within the variability of fairly similar kernel configs.
If (cpu_has_pse) it may only be an additional two pages. INIT_MAP_BEYOND is currently mapping a lot more then that.
Quoted 10 lines
Quoted 6 lines
As for how to fix this, we need to call
boot_ioremapor betterbt_ioremapon the address returned fromalloc_bootmem_pages_lowto force the allocated page into the page table. After we have setup the page table page we can call unmap the page to free up the scarce early mapping resource.Would that be necessary? Is there any need to remap it? Couldn't you just do the straightforward
phys->virtmapping and use the page where it lies?
Catch-22. If the page is not mapped yet you can't use it where it lies.
Eric
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 3 lines · Eric W. Biederman
If (
cpu_has_pse) it may only be an additional two pages.INIT_MAP_BEYONDis currently mapping a lot more then that.
Ah, yes. It allocates an extra two pages for pagetables, and then maps an extra 8MB or so.
Quoted 6 lines
Quoted 4 lines
Would that be necessary? Is there any need to remap it? Couldn't you just do the straightforward
phys->virtmapping and use the page where it lies?Catch-22. If the page is not mapped yet you can't use it where it lies.
Why not? Er, except in the case where the page is needed to map itself
- but that can be dealt with with a transient fixmap mapping.
J
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 4 lines · Jeremy Fitzhardinge
Why not? Er, except in the case where the page is needed to map itself
- but that can be dealt with with a transient fixmap mapping.
It would be *trivial* to make a certain number of page table slots available at the end of the head.S-generated map.
-hpa
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 2 lines · H. Peter Anvin
It would be *trivial* to make a certain number of page table slots available at the end of the head.S-generated map.
Or you could use a fixmap.
J
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 5 lines · Jeremy Fitzhardinge
Quoted 2 lines · H. Peter Anvin
It would be *trivial* to make a certain number of page table slots available at the end of the head.S-generated map.
Or you could use a fixmap.
That certain number of page table slots should be the fixmap slots. If you do that bt_ioremap works, we remove a boatload of special cases and the code becomes simpler.
Eric
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 10 lines · Eric W. Biederman
Quoted 4 lines · Jeremy Fitzhardinge
Quoted 2 lines · H. Peter Anvin
It would be *trivial* to make a certain number of page table slots available at the end of the head.S-generated map.
Or you could use a fixmap.
That certain number of page table slots should be the fixmap slots. If you do that
bt_ioremapworks, we remove a boatload of special cases and the code becomes simpler.
It's probably worth noting that several of the non-PC ports already do exactly this, although in a hacky way. Grep for pg0 and you'll find it.
-hpa
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
In reply to Jeremy FitzhardingeQuoted 23 lines · Jeremy Fitzhardinge
Quoted 6 lines · Chuck Ebbert
Quoted 4 lines · H. Peter Anvin
Quoted 2 lines · Andi Kleen
Then we would have seen reports surely?
Yes, I would have thought so. It surprised me that such an obvious bug could be there, apparently for a long time. But it's real, and potentially affects everyone. It probably doesn't affect highly modular distros much, since the kernel itself will be relatively small.
Quoted 3 lines
I never saw a description of the symptoms of encountering this bug. Does it just hang, or what?
You get an early-fault message on-screen, assuming that's enabled; otherwise it will just appear to hang. It happens in
pagetable_init, when it allocates a new pagetable above thehead.Smapping (8M in my case). It will only hit if the kernel size approaches a 4M boundary, since it won't leave enough space mapped to construct the lowmem mappings.
Quoted 5 lines
It only affects native booting, since under Xen all those mappings have already been constructed. It happened to me with a paravirt kernel that happened to Xen compiled into it, but that was irrelevent (though misleading; the 40k difference in kernel size was enough to make it not happen in a non-Xen kernel).
Jeremy did your kernel have PAE enabled?
It just occurred to me that we have at all of the memory below 1M (say about 512K) mapped and available to setup new mappings.
The only way I can see a page fault happening is if you were using a PAE enabled kernel (so you were not updating the current page tables) and you have more than 256M of low memory, and we don't get any much extra from always mapping 4M at a time.
Eric
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 9 lines · Eric W. Biederman
Jeremy did your kernel have PAE enabled?
It just occurred to me that we have at all of the memory below 1M (say about 512K) mapped and available to setup new mappings.
The only way I can see a page fault happening is if you were using a PAE enabled kernel (so you were not updating the current page tables) and you have more than 256M of low memory, and we don't get any much extra from always mapping 4M at a time.
Yes, that's the situation. PAE enabled, ~768MB of memory and a large kernel which mostly fills the 8M mapping.
J
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 6 lines · Jeremy Fitzhardinge
Quoted 5 lines · Eric W. Biederman
Jeremy did your kernel have PAE enabled?
It just occurred to me that we have at all of the memory below 1M (say about 512K) mapped and available to setup new mappings.
Quoted 7 lines
Quoted 4 lines
The only way I can see a page fault happening is if you were using a PAE enabled kernel (so you were not updating the current page tables) and you have more than 256M of low memory, and we don't get any much extra from always mapping 4M at a time.
Yes, that's the situation. PAE enabled, ~768MB of memory and a large kernel which mostly fills the 8M mapping.
And it just occurred to me PSE disabled, otherwise you would not have needed more than 4 pages. I supposed you were testing the Xen case.
That said I know for certain now why we have never seen this in production because all cpus that fit this configuration also support PSE.
So the way I think we should properly fix this is:
- Enable PAE early so we are updating our current page table.
- Pass a limit to the bootmem allocator so we do not get pages pass the point where we have setup page tables.
- Handle memory allocation failures.
However only the first part is necessary to solve the problem, in practice even if you are using 4K pages.
Eric
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 3 lines · Eric W. Biederman
And it just occurred to me PSE disabled, otherwise you would not have needed more than 4 pages. I supposed you were testing the Xen case.
No, actually, I wasn't. It was booting native (the Xen boot path doesn't go that way), and it should have booted like a normal native kernel despite having Xen compiled in. Hm, not sure why it wouldn't be using the PSE path.
J
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 10 lines · Jeremy Fitzhardinge
Quoted 3 lines · Eric W. Biederman
And it just occurred to me PSE disabled, otherwise you would not have needed more than 4 pages. I supposed you were testing the Xen case.
No, actually, I wasn't. It was booting native (the Xen boot path doesn't go that way), and it should have booted like a normal native kernel despite having Xen compiled in. Hm, not sure why it wouldn't be using the PSE path.
Since you have PSE disabled for Xen my hunch is that somehow that got left on for your test boot.
Eric
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 2 lines · Eric W. Biederman
Since you have PSE disabled for Xen my hunch is that somehow that got left on for your test boot.
No. Under Xen cpuid masks out PSE (and complains if you try to set it in a pte), but when booting native it will just use a plain unadorned cpuid.
J
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 6 lines · Jeremy Fitzhardinge
Quoted 2 lines · Eric W. Biederman
Since you have PSE disabled for Xen my hunch is that somehow that got left on for your test boot.
No. Under Xen cpuid masks out PSE (and complains if you try to set it in a pte), but when booting native it will just use a plain unadorned cpuid.
Then why you had to allocate enough pages to cause a failure has me stumped. Perhaps there is some other bug?
Eric
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 3 lines · Eric W. Biederman
Then why you had to allocate enough pages to cause a failure has me stumped. Perhaps there is some other bug?
Perhaps, but nothing comes to mind. I'll see what happens when I boot this kernel on real hardware (rather than kvm).
J
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 6 lines · * Jeremy Fitzhardinge ([email protected]) wrote:
Quoted 2 lines · Eric W. Biederman
Then why you had to allocate enough pages to cause a failure has me stumped. Perhaps there is some other bug?
Perhaps, but nothing comes to mind. I'll see what happens when I boot this kernel on real hardware (rather than kvm).
I was using real hardware with your .config when I reproduced it.
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 2 lines · Chris Wright
I was using real hardware with your .config when I reproduced it.
Yes, I first found it on real hardware. I haven't tested my fix on real hardware yet, but it seems OK on kvm.
J
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
In reply to Jeremy FitzhardingeQuoted 9 lines · Jeremy Fitzhardinge
Quoted 3 lines · Eric W. Biederman
And it just occurred to me PSE disabled, otherwise you would not have needed more than 4 pages. I supposed you were testing the Xen case.
No, actually, I wasn't. It was booting native (the Xen boot path doesn't go that way), and it should have booted like a normal native kernel despite having Xen compiled in. Hm, not sure why it wouldn't be using the PSE path.
Any chance you had CONFIG_DEBUG_PAGEALLOC selected?
Apparently that also disabled PSE...
Eric
Re: [PATCH 10/28] i386: map enough initial memory to create lowmem mappings
Quoted 2 lines · Eric W. Biederman
Any chance you had
CONFIG_DEBUG_PAGEALLOCselected?
Yes, that's quite likely.
J
PATCH 11/28 x86: incremental update for i386 and x86-64 check_bugs
In reply to Jeremy Fitzhardingei386 bugs.c shouldn't refer to identify_boot_cpu yet, since it doesn't get introduced until the identify_cpu patch.
Remove spurious comments, headers and keywords from x86-64 bugs.[ch].
--- arch/i386/kernel/cpu/bugs.c | 2 +- arch/x86_64/kernel/bugs.c | 9 +-------- include/asm-i386/bugs.h | 2 +- 3 files changed, 3 insertions(+), 10 deletions(-)
===================================================================
arch/i386/kernel/cpu/bugs.c +1 -1
@@ -177,7 +177,7 @@ static void __init check_config(void)void __init check_bugs (void ) { -identify_boot_cpu (); +identify_cpu (&boot_cpu_data);#ifndef CONFIG_SMP printk ("CPU: " );print_cpu_info (&boot_cpu_data);
===================================================================
arch/x86_64/kernel/bugs.c +1 -8
@@ -3,19 +3,12 @@* * Copyright (C) 1994 Linus Torvalds * Copyright (C) 2000 SuSE -* -* This is included by init/main.c to check for architecture-dependent bugs. -* -* Needs: -* void check_bugs(void); */ #include <linux/kernel.h> +#include <linux/init.h> #include <asm/alternative.h> #include <asm/processor.h> -#include <asm/i387.h> -#include <asm/msr.h> -#include <asm/pda.h> void __init check_bugs (void ) {
===================================================================
include/asm-i386/bugs.h +1 -1
@@ -7,6 +7,6 @@#ifndef _ASM_I386_BUG_H#define _ASM_I386_BUG_H -extern void __init check_bugs (void ); +void check_bugs (void );#endif /* _ASM_I386_BUG_H */
PATCH 12/28 i386: now its ok to use identify_boot_cpu
In reply to Jeremy Fitzhardinge--- arch/i386/kernel/cpu/bugs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
===================================================================
arch/i386/kernel/cpu/bugs.c +1 -1
@@ -177,7 +177,7 @@ static void __init check_config(void)void __init check_bugs (void ) { -identify_cpu (&boot_cpu_data); +identify_boot_cpu ();#ifndef CONFIG_SMP printk ("CPU: " );print_cpu_info (&boot_cpu_data);
PATCH 13/28 paravirt: flush lazy mmu updates on kunmap_atomic
In reply to Jeremy Fitzhardingekunmap_atomic should flush any pending lazy mmu updates, mainly to be consistent with kmap_atomic, and to preserve its normal behaviour.
--- arch/i386/mm/highmem.c | 1 + 1 file changed, 1 insertion(+)
===================================================================
arch/i386/mm/highmem.c +1 -0
@@ -72,6 +72,7 @@ void kunmap_atomic(void *kvaddr, enum km#endif } +arch_flush_lazy_mmu_mode ();pagefault_enable (); }
PATCH 14/28 fix paravirt-documentation
In reply to Jeremy FitzhardingeRemove #defines, add enum for PARAVIRT_LAZY_FLUSH.
--- include/asm-i386/paravirt.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-)
===================================================================
include/asm-i386/paravirt.h +1 -6
@@ -30,6 +30,7 @@ enum paravirt_lazy_mode {PARAVIRT_LAZY_NONE =0 ,PARAVIRT_LAZY_MMU =1 ,PARAVIRT_LAZY_CPU =2 , + PARAVIRT_LAZY_FLUSH = 3, };struct paravirt_ops
@@ -906,12 +907,6 @@ static inline void set_pmd(pmd_t *pmdp, }#endif /* CONFIG_X86_PAE */ -/* Lazy mode for batching updates / context switch */ -#define PARAVIRT_LAZY_NONE 0 -#define PARAVIRT_LAZY_MMU 1 -#define PARAVIRT_LAZY_CPU 2 -#define PARAVIRT_LAZY_FLUSH 3 -#define __HAVE_ARCH_ENTER_LAZY_CPU_MODEstatic inline void arch_enter_lazy_cpu_mode (void ) {
PATCH 15/28 In compat mode, the return value here was uninitialized.
In reply to Jeremy FitzhardingeFrom: Zachary Amsden <[email protected]>
--- arch/i386/kernel/sysenter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
===================================================================
arch/i386/kernel/sysenter.c +1 -1
@@ -254,7 +254,7 @@ int arch_setup_additional_pages(struct l {struct mm_struct *mm = current->mm;unsigned long addr; -int ret; +int ret =0 ;bool compat;down_write (&mm->mmap_sem);
PATCH 16/28 kRemove a warning about unused variable in !CONFIG_ACPI compilation.
In reply to Jeremy FitzhardingeFrom: Zachary Amsden <[email protected]>
--- arch/i386/kernel/acpi/earlyquirk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
===================================================================
arch/i386/kernel/acpi/earlyquirk.c +1 -1
@@ -21,8 +21,8 @@ static int __init nvidia_hpet_check(strustatic int __init check_bridge (int vendor,int device) { +#ifdef CONFIG_ACPI static int warned; -#ifdef CONFIG_ACPI /* According to Nvidia all timer overrides are bogus unless HPET is enabled. */ if (!acpi_use_timer_override && vendor ==PCI_VENDOR_ID_NVIDIA ) {
PATCH 17/28 x86: cleanup arch/i386/kernel/cpu/mcheck/p4.c
In reply to Jeremy FitzhardingeNo, just no. You do not use goto to skip a code block. You do not return an obvious variable from a singly-inlined function and give the function a return value. You don't put unexplained comments about kmalloc in code which doesn't do dynamic allocation. And you don't leave stray warnings around for no good reason.
Also, when possible, it is better to use block scoped variables because gcc can sometime generate better code.
From: Zachary Amsden <[email protected]>
--- arch/i386/kernel/cpu/mcheck/p4.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-)
===================================================================
arch/i386/kernel/cpu/mcheck/p4.c +4 -12
@@ -124,12 +124,9 @@ static void intel_init_thermal(struct cp/* P4/Xeon Extended MCE MSR retrieval, return 0 if unsupported */ -static inline int intel_get_extended_msrs (struct intel_mce_extended_msrs *r) +static inline void intel_get_extended_msrs (struct intel_mce_extended_msrs *r) {u32 h; - -if (mce_num_extended_msrs ==0 ) - goto done;rdmsr (MSR_IA32_MCG_EAX , r->eax, h);rdmsr (MSR_IA32_MCG_EBX , r->ebx, h);
@@ -141,12 +138,6 @@ static inline int intel_get_extended_msrrdmsr (MSR_IA32_MCG_ESP , r->esp, h);rdmsr (MSR_IA32_MCG_EFLAGS , r->eflags, h);rdmsr (MSR_IA32_MCG_EIP , r->eip, h); - -/* can we rely on kmalloc to do a dynamic -* allocation for the reserved registers? -*/ -done: -return mce_num_extended_msrs; } static fastcall void intel_machine_check(struct pt_regs * regs, long error_code)
@@ -155,7 +146,6 @@ static fastcall void intel_machine_checku32 alow, ahigh, high, low;u32 mcgstl, mcgsth;int i; -struct intel_mce_extended_msrs dbg;rdmsr (MSR_IA32_MCG_STATUS , mcgstl, mcgsth);if (mcgstl & (1 <<0 ))/* Recoverable ? */
@@ -164,7 +154,9 @@ static fastcall void intel_machine_checkprintk (KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x\n" ,smp_processor_id (), mcgsth, mcgstl); -if (intel_get_extended_msrs (&dbg)) { +if (mce_num_extended_msrs >0 ) { +struct intel_mce_extended_msrs dbg; +intel_get_extended_msrs (&dbg);printk (KERN_DEBUG "CPU %d: EIP: %08x EFLAGS: %08x\n" ,smp_processor_id (), dbg.eip, dbg.eflags); printk (KERN_DEBUG "\teax: %08x ebx: %08x ecx: %08x edx: %08x\n",
PATCH 18/28 Copying of the pgd range must happen under the pgd_lock
In reply to Jeremy FitzhardingeCopying of the pgd range must happen under the pgd_lock. This got broken by the paravirt changes in the -mm tree. Badness can result if you copy the pgd before being added to the list when splitting or rejoining large pages.
From: Zachary Amsden <[email protected]>
--- arch/i386/mm/pgtable.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-)
===================================================================
arch/i386/mm/pgtable.c +3 -5
@@ -241,18 +241,16 @@ void pgd_ctor(void *pgd, struct kmem_cac/* !PAE, no pagetable sharing */ memset (pgd,0 ,USER_PTRS_PER_PGD *sizeof (pgd_t)); +spin_lock_irqsave (&pgd_lock, flags); + +/* must happen under lock */ clone_pgd_range ((pgd_t *)pgd +USER_PTRS_PER_PGD , swapper_pg_dir +USER_PTRS_PER_PGD ,KERNEL_PGD_PTRS ); - -spin_lock_irqsave (&pgd_lock, flags); - -/* must happen under lock */ paravirt_alloc_pd_clone (__pa (pgd) >>PAGE_SHIFT ,__pa (swapper_pg_dir) >>PAGE_SHIFT ,USER_PTRS_PER_PGD ,KERNEL_PGD_PTRS ); -pgd_list_add (pgd);spin_unlock_irqrestore (&pgd_lock, flags); }
PATCH 19/28 Dont implement native_kmap_atomic_pte for !HIGHPTE
In reply to Jeremy FitzhardingeDon't implement native_kmap_atomic_pte for !HIGHPTE case; it is never needed, never called, and leaving it in is just plain confusing. Making it isolated to the config where it is used may help find bugs.
From: Zachary Amsden <[email protected]>
--- arch/i386/kernel/paravirt.c | 4 +--- include/asm-i386/highmem.h | 5 ----- include/asm-i386/paravirt.h | 4 ++++ 3 files changed, 5 insertions(+), 8 deletions(-)
===================================================================
arch/i386/kernel/paravirt.c +1 -3
@@ -318,9 +318,7 @@ struct paravirt_ops paravirt_ops = { .ptep_get_and_clear = native_ptep_get_and_clear,#ifdef CONFIG_HIGHPTE - .kmap_atomic_pte = native_kmap_atomic_pte, -#else - .kmap_atomic_pte = paravirt_nop, + .kmap_atomic_pte = kmap_atomic,#endif #ifdef CONFIG_X86_PAE
===================================================================
include/asm-i386/highmem.h +0 -5
@@ -74,11 +74,6 @@ void *kmap_atomic_pfn(unsigned long pfn,void *kmap_atomic_pfn (unsigned long pfn,enum km_type type);struct page *kmap_atomic_to_page (void *ptr); -static inline void *native_kmap_atomic_pte (struct page *page,enum km_type type) -{ -return kmap_atomic (page, type); -} -#ifndef CONFIG_PARAVIRT #define kmap_atomic_pte (page, type) kmap_atomic(page, type)#endif
===================================================================
include/asm-i386/paravirt.h +4 -0
@@ -190,7 +190,9 @@ struct paravirt_opspte_t (*ptep_get_and_clear)(pte_t *ptep); +#ifdef CONFIG_HIGHPTE void *(*kmap_atomic_pte)(struct page *page,enum km_type type); +#endif #ifdef CONFIG_X86_PAE void (*set_pte_atomic)(pte_t *ptep,pte_t pteval);
@@ -759,12 +761,14 @@ static inline void paravirt_release_pd(uPVOP_VCALL1 (release_pd, pfn); } +#ifdef CONFIG_HIGHPTE static inline void *kmap_atomic_pte (struct page *page,enum km_type type) {unsigned long ret; ret = PVOP_CALL2(unsigned long, kmap_atomic_pte, page, type);return (void *)ret; } +#endif static inline void pte_update (struct mm_struct *mm,unsigned long addr,pte_t *ptep)
PATCH 20/28 Now that the VDSO can be relocated, we can support it in VMI configurations.
In reply to Jeremy FitzhardingeFrom: Zachary Amsden <[email protected]>
--- arch/i386/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
===================================================================
arch/i386/Kconfig +1 -1
@@ -220,7 +220,7 @@ config PARAVIRT config VMI bool "VMI Paravirt-ops support" - depends on PARAVIRT && !COMPAT_VDSO + depends on PARAVIRT help VMI provides a paravirtualized interface to the VMware ESX server (it could be used by other hypervisors in theory too, but is not
PATCH 21/28 Implement vmi_kmap_atomic_pte
In reply to Jeremy FitzhardingeImplement vmi_kmap_atomic_pte in terms of the backend set_linear_mapping operation. The conversion is rather straighforward; call kmap_atomic and then inform the hypervisor of the page mapping.
The _flush_tlb damage is due to macros being pulled in from highmem.h.
From: Zachary Amsden <[email protected]>
--- arch/i386/kernel/vmi.c | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-)
===================================================================
arch/i386/kernel/vmi.c +24 -14
@@ -26,6 +26,7 @@#include <linux/cpu.h> #include <linux/bootmem.h> #include <linux/mm.h> +#include <linux/highmem.h> #include <asm/vmi.h> #include <asm/io.h> #include <asm/fixmap.h>
@@ -65,8 +66,8 @@ static struct {void (*release_page)(u32 ,u32 );void (*set_pte)(pte_t ,pte_t *,unsigned );void (*update_pte)(pte_t *,unsigned ); -void (*set_linear_mapping)(int ,u32 ,u32 ,u32 ); -void (*flush_tlb)(int ); +void (*set_linear_mapping)(int ,void *,u32 ,u32 ); +void (*_flush_tlb)(int );void (*set_initial_ap_state)(int ,int );void (*halt)(void );void (*set_lazy_mode)(int mode);
@@ -217,12 +218,12 @@ static void vmi_load_esp0(struct tss_strstatic void vmi_flush_tlb_user (void ) { - vmi_ops.flush_tlb (VMI_FLUSH_TLB ); + vmi_ops._flush_tlb (VMI_FLUSH_TLB ); }static void vmi_flush_tlb_kernel (void ) { - vmi_ops.flush_tlb (VMI_FLUSH_TLB |VMI_FLUSH_GLOBAL ); + vmi_ops._flush_tlb (VMI_FLUSH_TLB |VMI_FLUSH_GLOBAL ); }/* Stub to do nothing at all; used for delays and unimplemented calls */
@@ -345,8 +346,11 @@ static void vmi_check_page_type(u32 pfn,#define vmi_check_page_type (p,t) do { } while (0)#endif -static void vmi_map_pt_hook (int type,pte_t *va,u32 pfn) -{ +#ifdef CONFIG_HIGHPTE +static void *vmi_kmap_atomic_pte (struct page *page,enum km_type type) +{ +void *va =kmap_atomic (page, type); +/* * Internally, the VMI ROM must map virtual addresses to physical * addresses for processing MMU updates. By the time MMU updates
@@ -360,8 +364,11 @@ static void vmi_map_pt_hook(int type, pt* args: SLOT VA COUNT PFN */ BUG_ON (type !=KM_PTE0 && type !=KM_PTE1 ); - vmi_ops.set_linear_mapping ((type -KM_PTE0 )+1 , (u32 )va,1 , pfn); -} + vmi_ops.set_linear_mapping ((type -KM_PTE0 )+1 , va,1 ,page_to_pfn (page)); + + return va; +} +#endif static void vmi_allocate_pt (u32 pfn) {
@@ -656,7 +663,7 @@ void vmi_bringup(void) {/* We must establish the lowmem mapping for MMU ops to work */ if (vmi_ops.set_linear_mapping) - vmi_ops.set_linear_mapping (0 , __PAGE_OFFSET, max_low_pfn,0 ); + vmi_ops.set_linear_mapping (0 , (void *)__PAGE_OFFSET, max_low_pfn,0 ); }/*
@@ -793,8 +800,8 @@ static inline int __init activate_vmi(vopara_wrap (set_lazy_mode, vmi_set_lazy_mode, set_lazy_mode, SetLazyMode);/* user and kernel flush are just handled with different flags to FlushTLB */ -para_wrap (flush_tlb_user, vmi_flush_tlb_user, flush_tlb, FlushTLB); -para_wrap (flush_tlb_kernel, vmi_flush_tlb_kernel, flush_tlb, FlushTLB); +para_wrap (flush_tlb_user, vmi_flush_tlb_user, _flush_tlb, FlushTLB); +para_wrap (flush_tlb_kernel, vmi_flush_tlb_kernel, _flush_tlb, FlushTLB);para_fill (flush_tlb_single, InvalPage);/*
@@ -840,9 +847,12 @@ static inline int __init activate_vmi(vo paravirt_ops.release_pt = vmi_release_pt; paravirt_ops.release_pd = vmi_release_pd; } -#if 0 -para_wrap (map_pt_hook, vmi_map_pt_hook, set_linear_mapping, - SetLinearMapping); + +/* Set linear is needed in all cases */ + vmi_ops.set_linear_mapping =vmi_get_function (VMI_CALL_SetLinearMapping); +#ifdef CONFIG_HIGHPTE +if (vmi_ops.set_linear_mapping) + paravirt_ops.kmap_atomic_pte = vmi_kmap_atomic_pte;#endif /*
PATCH 22/28 Convert VMI timer to use clock events
In reply to Jeremy FitzhardingeConvert VMI timer to use clock events, making it properly able to use the NO_HZ infrastructure. On UP systems, with no local APIC, we just continue to route these events through the PIT. On systems with a local APIC, or SMP, we provide a single source interrupt chip which creates the local timer IRQ. It actually gets delivered by the APIC hardware, but we don't want to use the same local APIC clocksource processing, so we create our own handler here.
From: Zachary Amsden <[email protected]>
--- arch/i386/kernel/Makefile | 2 arch/i386/kernel/entry.S | 5 arch/i386/kernel/vmi.c | 26 -- arch/i386/kernel/vmiclock.c | 318 ++++++++++++++++++++++++++++ arch/i386/kernel/vmitime.c | 482 ------------------------------------------- include/asm-i386/vmi_time.h | 18 - 6 files changed, 327 insertions(+), 524 deletions(-)
===================================================================
arch/i386/kernel/Makefile +1 -1
@@ -41,7 +41,7 @@ obj-$(CONFIG_K8_NB) += k8.o obj-$(CONFIG_K8_NB) += k8.o obj-$(CONFIG_STACK_UNWIND) += unwind.o -obj-$(CONFIG_VMI) += vmi.o vmitime.o +obj-$(CONFIG_VMI) += vmi.o vmiclock.o obj-$(CONFIG_PARAVIRT) += paravirt.o obj-y += pcspeaker.o
===================================================================
arch/i386/kernel/vmi.c +6 -20
@@ -73,6 +73,9 @@ static struct {void (*set_lazy_mode)(int mode); } vmi_ops; +/* Cached VMI operations */ +struct vmi_timer_ops vmi_timer_ops; +/* * VMI patching routines. */
@@ -231,18 +234,6 @@ static void vmi_nop(void) { } -/* For NO_IDLE_HZ, we stop the clock when halting the kernel */ -static fastcall void vmi_safe_halt(void) -{ -int idle =vmi_stop_hz_timer (); - vmi_ops.halt (); -if (idle) { -local_irq_disable (); -vmi_account_time_restart_hz_timer (); -local_irq_enable (); - } -} -#ifdef CONFIG_DEBUG_PAGE_TYPE #ifdef CONFIG_X86_PAE
@@ -714,7 +705,6 @@ do { \ vmi_ops.cache = (void *)rel->eip; \ } \ }while (0 ) -/* * Activate the VMI interface and switch into paravirtualized mode
@@ -894,8 +884,8 @@ static inline int __init activate_vmi(vo paravirt_ops.get_wallclock = vmi_get_wallclock; paravirt_ops.set_wallclock = vmi_set_wallclock;#ifdef CONFIG_X86_LOCAL_APIC - paravirt_ops.setup_boot_clock = vmi_timer_setup_boot_alarm; - paravirt_ops.setup_secondary_clock = vmi_timer_setup_secondary_alarm; + paravirt_ops.setup_boot_clock = vmi_time_bsp_init; + paravirt_ops.setup_secondary_clock = vmi_time_ap_init;#endif paravirt_ops.get_scheduled_cycles = vmi_get_sched_cycles; paravirt_ops.get_cpu_khz = vmi_cpu_khz;
@@ -907,11 +897,7 @@ static inline int __init activate_vmi(vo disable_vmi_timer =1 ; } -/* No idle HZ mode only works if VMI timer and no idle is enabled */ -if (disable_noidle || disable_vmi_timer) -para_fill (safe_halt, Halt); -else -para_wrap (safe_halt, vmi_safe_halt, halt, Halt); +para_fill (safe_halt, Halt);/* * Alternative instruction rewriting doesn't happen soon enough
===================================================================
include/asm-i386/vmi_time.h +2 -16
@@ -53,22 +53,8 @@ extern unsigned long vmi_cpu_khz(void);extern unsigned long vmi_cpu_khz (void );#ifdef CONFIG_X86_LOCAL_APIC -extern void __init vmi_timer_setup_boot_alarm (void ); -extern void __devinit vmi_timer_setup_secondary_alarm (void ); -extern void apic_vmi_timer_interrupt (void ); -#endif - -#ifdef CONFIG_NO_IDLE_HZ -extern int vmi_stop_hz_timer (void ); -extern void vmi_account_time_restart_hz_timer (void ); -#else -static inline int vmi_stop_hz_timer (void ) -{ -return 0 ; -} -static inline void vmi_account_time_restart_hz_timer (void ) -{ -} +extern void __devinit vmi_time_bsp_init (void ); +extern void __devinit vmi_time_ap_init (void );#endif /*
===================================================================
arch/i386/kernel/entry.S +0 -5
@@ -637,11 +637,6 @@ ENDPROC(name) /* The include is where all of the SMP etc. interrupts come from */ #include "entry_arch.h" -/* This alternate entry is needed because we hijack the apic LVTT */ -#if defined(CONFIG_VMI) && defined(CONFIG_X86_LOCAL_APIC) -BUILD_INTERRUPT(apic_vmi_timer_interrupt,LOCAL_TIMER_VECTOR) -#endif - KPROBE_ENTRY(page_fault) RING0_EC_FRAME pushl $do_page_fault
===================================================================
arch/i386/kernel/vmiclock.c new file +318 -0
318 lines not on this page · raw message
===================================================================
arch/i386/kernel/vmitime.c deleted +0 -482
482 lines not on this page · raw message
PATCH 23/28 Fix BusLogic to stop using check_region
In reply to Jeremy FitzhardingeI got so sick of seing the check_region warnings from BusLogic.c I actually fixed it properly. Never use check region, reserve it before the probe with request region instead and check the error result; free region if setup fails. Should be functionally identical to the original except for fixing the potential race.
From: Zachary Amsden <[email protected]>
--- drivers/scsi/BusLogic.c | 73 ++++++++++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 25 deletions(-)
===================================================================
drivers/scsi/BusLogic.c +48 -25
@@ -579,17 +579,17 @@ static void __init BusLogic_InitializePr/* Append the list of standard BusLogic MultiMaster ISA I/O Addresses. */ -if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe330 :check_region (0x330 , BusLogic_MultiMasterAddressCount) ==0 ) +if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe330)BusLogic_AppendProbeAddressISA (0x330 ); -if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe334 :check_region (0x334 , BusLogic_MultiMasterAddressCount) ==0 ) +if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe334)BusLogic_AppendProbeAddressISA (0x334 ); -if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe230 :check_region (0x230 , BusLogic_MultiMasterAddressCount) ==0 ) +if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe230)BusLogic_AppendProbeAddressISA (0x230 ); -if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe234 :check_region (0x234 , BusLogic_MultiMasterAddressCount) ==0 ) +if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe234)BusLogic_AppendProbeAddressISA (0x234 ); -if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe130 :check_region (0x130 , BusLogic_MultiMasterAddressCount) ==0 ) +if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe130)BusLogic_AppendProbeAddressISA (0x130 ); -if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe134 :check_region (0x134 , BusLogic_MultiMasterAddressCount) ==0 ) +if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe134)BusLogic_AppendProbeAddressISA (0x134 ); }
@@ -795,7 +795,9 @@ static int __init BusLogic_InitializeMulhost adapters are probed. */ if (!BusLogic_ProbeOptions.NoProbeISA) -if (PrimaryProbeInfo->IO_Address ==0 && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe330 :check_region (0x330 , BusLogic_MultiMasterAddressCount) ==0 )) { +if (PrimaryProbeInfo->IO_Address ==0 && + (!BusLogic_ProbeOptions.LimitedProbeISA || + BusLogic_ProbeOptions.Probe330)) { PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster; PrimaryProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus; PrimaryProbeInfo->IO_Address =0x330 ;
@@ -805,15 +807,25 @@ static int __init BusLogic_InitializeMulomitting the Primary I/O Address which has already been handled. */ if (!BusLogic_ProbeOptions.NoProbeISA) { -if (!StandardAddressSeen[1 ] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe334 :check_region (0x334 , BusLogic_MultiMasterAddressCount) ==0 )) +if (!StandardAddressSeen[1 ] && + (!BusLogic_ProbeOptions.LimitedProbeISA || + BusLogic_ProbeOptions.Probe334))BusLogic_AppendProbeAddressISA (0x334 ); -if (!StandardAddressSeen[2 ] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe230 :check_region (0x230 , BusLogic_MultiMasterAddressCount) ==0 )) +if (!StandardAddressSeen[2 ] && + (!BusLogic_ProbeOptions.LimitedProbeISA || + BusLogic_ProbeOptions.Probe230))BusLogic_AppendProbeAddressISA (0x230 ); -if (!StandardAddressSeen[3 ] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe234 :check_region (0x234 , BusLogic_MultiMasterAddressCount) ==0 )) +if (!StandardAddressSeen[3 ] && + (!BusLogic_ProbeOptions.LimitedProbeISA || + BusLogic_ProbeOptions.Probe234))BusLogic_AppendProbeAddressISA (0x234 ); -if (!StandardAddressSeen[4 ] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe130 :check_region (0x130 , BusLogic_MultiMasterAddressCount) ==0 )) +if (!StandardAddressSeen[4 ] && + (!BusLogic_ProbeOptions.LimitedProbeISA || + BusLogic_ProbeOptions.Probe130))BusLogic_AppendProbeAddressISA (0x130 ); -if (!StandardAddressSeen[5 ] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe134 :check_region (0x134 , BusLogic_MultiMasterAddressCount) ==0 )) +if (!StandardAddressSeen[5 ] && + (!BusLogic_ProbeOptions.LimitedProbeISA || + BusLogic_ProbeOptions.Probe134))BusLogic_AppendProbeAddressISA (0x134 ); }/*
@@ -2220,22 +2232,35 @@ static int __init BusLogic_init(void) HostAdapter->PCI_Device = ProbeInfo->PCI_Device; HostAdapter->IRQ_Channel = ProbeInfo->IRQ_Channel; HostAdapter->AddressCount = BusLogic_HostAdapterAddressCount[HostAdapter->HostAdapterType]; + +/* +Make sure region is free prior to probing. +*/ +if (!request_region (HostAdapter->IO_Address, HostAdapter->AddressCount, +"BusLogic" )) +continue ;/* Probe the Host Adapter. If unsuccessful, abort further initialization. */ -if (!BusLogic_ProbeHostAdapter (HostAdapter)) +if (!BusLogic_ProbeHostAdapter (HostAdapter)) { +release_region (HostAdapter->IO_Address, HostAdapter->AddressCount);continue ; + }/* Hard Reset the Host Adapter. If unsuccessful, abort further initialization. */ -if (!BusLogic_HardwareResetHostAdapter (HostAdapter, true)) +if (!BusLogic_HardwareResetHostAdapter (HostAdapter, true)) { +release_region (HostAdapter->IO_Address, HostAdapter->AddressCount);continue ; + }/* Check the Host Adapter. If unsuccessful, abort further initialization. */ -if (!BusLogic_CheckHostAdapter (HostAdapter)) +if (!BusLogic_CheckHostAdapter (HostAdapter)) { +release_region (HostAdapter->IO_Address, HostAdapter->AddressCount);continue ; + }/* Initialize the Driver Options field if provided. */
@@ -2247,16 +2272,6 @@ static int __init BusLogic_init(void)*/ BusLogic_AnnounceDriver (HostAdapter);/* -Register usage of the I/O Address range. From this point onward, any -failure will be assumed to be due to a problem with the Host Adapter, -rather than due to having mistakenly identified this port as belonging -to a BusLogic Host Adapter. The I/O Address range will not be -released, thereby preventing it from being incorrectly identified as -any other type of Host Adapter. -*/ -if (!request_region (HostAdapter->IO_Address, HostAdapter->AddressCount,"BusLogic" )) -continue ; -/* Register the SCSI Host structure. */
@@ -2280,6 +2295,12 @@ static int __init BusLogic_init(void)Acquire the System Resources necessary to use the Host Adapter, then Create the Initial CCBs, Initialize the Host Adapter, and finally perform Target Device Inquiry. + +From this point onward, any failure will be assumed to be due to a +problem with the Host Adapter, rather than due to having mistakenly +identified this port as belonging to a BusLogic Host Adapter. The +I/O Address range will not be released, thereby preventing it from +being incorrectly identified as any other type of Host Adapter. */ if (BusLogic_ReadHostAdapterConfiguration(HostAdapter) && BusLogic_ReportHostAdapterConfiguration(HostAdapter) &&
@@ -3598,6 +3619,7 @@ static void __exit BusLogic_exit(void)__setup ("BusLogic=" , BusLogic_Setup); +#ifdef MODULE static struct pci_device_id BusLogic_pci_tbl[]__devinitdata = { {PCI_VENDOR_ID_BUSLOGIC ,PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER , PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
@@ -3607,6 +3629,7 @@ static struct pci_device_id BusLogic_pci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { } }; +#endif MODULE_DEVICE_TABLE (pci, BusLogic_pci_tbl);module_init (BusLogic_init);
PATCH 24/28 paravirt: drop unused ptep_get_and_clear
In reply to Jeremy FitzhardingeIn shadow mode hypervisors, ptep_get_and_clear achieves the desired purpose of keeping the shadows in sync by issuing a native_get_and_clear, followed by a call to pte_update, which indicates the PTE has been modified.
Direct mode hypervisors (Xen) have no need for this anyway, and will trap the update using writable pagetables.
This means no hypervisor makes use of ptep_get_and_clear; there is no reason to have it in the paravirt-ops structure. Change confusing terminology about raw vs. native functions into consistent use of native_pte_xxx for operations which do not invoke paravirt-ops.
--- arch/i386/kernel/paravirt.c | 2 -- include/asm-i386/paravirt.h | 13 +------------ include/asm-i386/pgtable.h | 4 +--- 3 files changed, 2 insertions(+), 17 deletions(-)
===================================================================
arch/i386/kernel/paravirt.c +0 -2
@@ -315,8 +315,6 @@ struct paravirt_ops paravirt_ops = { .pte_update = paravirt_nop, .pte_update_defer = paravirt_nop, - .ptep_get_and_clear = native_ptep_get_and_clear, -#ifdef CONFIG_HIGHPTE .kmap_atomic_pte = kmap_atomic,#endif
===================================================================
include/asm-i386/paravirt.h +1 -12
@@ -187,8 +187,6 @@ struct paravirt_opsvoid (*pte_update)(struct mm_struct *mm,unsigned long addr,pte_t *ptep);void (*pte_update_defer)(struct mm_struct *mm,unsigned long addr,pte_t *ptep); - -pte_t (*ptep_get_and_clear)(pte_t *ptep);#ifdef CONFIG_HIGHPTE void *(*kmap_atomic_pte)(struct page *page,enum km_type type);
@@ -859,12 +857,8 @@ static inline void pmd_clear(pmd_t *pmdpPVOP_VCALL1 (pmd_clear, pmdp); } -static inline pte_t raw_ptep_get_and_clear (pte_t *p) -{ - unsigned long long val = PVOP_CALL1(unsigned long long, ptep_get_and_clear, p); -return (pte_t ) { val, val >>32 }; -}#else /* !CONFIG_X86_PAE */ +static inline pte_t __pte (unsigned long val) { return (pte_t) { PVOP_CALL1(unsigned long, make_pte, val) };
@@ -899,11 +893,6 @@ static inline void set_pmd(pmd_t *pmdp,static inline void set_pmd (pmd_t *pmdp,pmd_t pmdval) {PVOP_VCALL2 (set_pmd, pmdp, pmdval.pud.pgd.pgd); -} - -static inline pte_t raw_ptep_get_and_clear (pte_t *p) -{ - return (pte_t) { PVOP_CALL1(unsigned long, ptep_get_and_clear, p) }; }#endif /* CONFIG_X86_PAE */
===================================================================
include/asm-i386/pgtable.h +1 -3
@@ -265,8 +265,6 @@ static inline pte_t pte_mkhuge(pte_t pte*/ #define pte_update (mm, addr, ptep) do { } while (0)#define pte_update_defer (mm, addr, ptep) do { } while (0) - -#define raw_ptep_get_and_clear (xp) native_ptep_get_and_clear(xp)#endif /*
@@ -340,7 +338,7 @@ do { \#define __HAVE_ARCH_PTEP_GET_AND_CLEARstatic inline pte_t ptep_get_and_clear (struct mm_struct *mm,unsigned long addr,pte_t *ptep) { -pte_t pte =raw_ptep_get_and_clear (ptep); +pte_t pte =native_ptep_get_and_clear (ptep);pte_update (mm, addr, ptep);return pte; }
PATCH 25/28 From: Jeremy Fitzhardinge <[email protected]>
In reply to Jeremy FitzhardingeThe other symbols used to delineate the alt-instructions sections have the form __foo/__foo_end. Rename parainstructions to match.
--- arch/i386/kernel/alternative.c | 2 +- arch/i386/kernel/vmi.c | 6 +++--- arch/i386/kernel/vmlinux.lds.S | 4 ++-- include/asm-i386/alternative.h | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-)
===================================================================
arch/i386/kernel/alternative.c +1 -1
@@ -386,6 +386,6 @@ void __init alternative_instructions(voi alternatives_smp_switch(0); }#endif -apply_paravirt (__start_parainstructions, __stop_parainstructions); +apply_paravirt (__parainstructions, __parainstructions_end);local_irq_restore (flags); }
===================================================================
arch/i386/kernel/vmi.c +3 -3
@@ -74,8 +74,8 @@ static struct { } vmi_ops;/* XXX move this to alternative.h */ -extern struct paravirt_patch __start_parainstructions[], - __stop_parainstructions[]; +extern struct paravirt_patch __parainstructions[], + __parainstructions_end[];/* Cached VMI operations */ struct vmi_timer_ops vmi_timer_ops;
@@ -909,7 +909,7 @@ static inline int __init activate_vmi(vo* to do this before IRQs get reenabled. Fortunately, it is * idempotent. */ -apply_paravirt (__start_parainstructions, __stop_parainstructions); +apply_paravirt (__parainstructions, __parainstructions_end);vmi_bringup ();
===================================================================
arch/i386/kernel/vmlinux.lds.S +2 -2
@@ -166,9 +166,9 @@ SECTIONS } . = ALIGN(4); .parainstructions : AT(ADDR(.parainstructions) - LOAD_OFFSET) { - __start_parainstructions = .; + __parainstructions = .; *(.parainstructions) - __stop_parainstructions = .; + __parainstructions_end = .; } /* .exit.text is discard at runtime, not link time, to deal with references from .altinstructions and .eh_frame */
===================================================================
include/asm-i386/alternative.h +2 -2
@@ -124,8 +124,8 @@ apply_paravirt(struct paravirt_patch_sit apply_paravirt(struct paravirt_patch_site *start, struct paravirt_patch_site *end) {} -#define __start_parainstructions NULL -#define __stop_parainstructions NULL +#define __parainstructions NULL +#define __parainstructions_end NULL #endif #endif /* _I386_ALTERNATIVE_H */
PATCH 26/28 From: Andrew Morton <[email protected]>
In reply to Jeremy Fitzhardingex86_64:
arch/x86_64/kernel/../../i386/kernel/alternative.c: In function 'alternative_instructions':arch/x86_64/kernel/../../i386/kernel/alternative.c:374: error: '__parainstructions' undeclared (first use in this function) arch/x86_64/kernel/../../i386/kernel/alternative.c:374: error: (Each undeclared identifier is reported only once arch/x86_64/kernel/../../i386/kernel/alternative.c:374: error: for each function it appears in.) arch/x86_64/kernel/../../i386/kernel/alternative.c:374: error: '__parainstructions_end' undeclared (first use in this function)
--- include/asm-x86_64/alternative.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
===================================================================
include/asm-x86_64/alternative.h renamed from include/asm-x86_64/alternative.h~rename-the-parainstructions-symbols-to-be-consistent-with-the-others-fix +2 -2
@@ -141,8 +141,8 @@ void apply_paravirt(struct paravirt_patcstatic inline void apply_paravirt (struct paravirt_patch *start,struct paravirt_patch *end) {} -#define __start_parainstructions NULL -#define __stop_parainstructions NULL +#define __parainstructions NULL +#define __parainstructions_end NULL#endif #endif /* _X86_64_ALTERNATIVE_H */
_
PATCH 27/28 paravirt: little compile fixes for vmi.c
In reply to Jeremy Fitzhardinge--- arch/i386/kernel/vmi.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-)
===================================================================
arch/i386/kernel/vmi.c +3 -7
@@ -73,10 +73,6 @@ static struct {void (*set_lazy_mode)(int mode); } vmi_ops; -/* XXX move this to alternative.h */ -extern struct paravirt_patch __parainstructions[], - __parainstructions_end[]; -/* Cached VMI operations */ struct vmi_timer_ops vmi_timer_ops;
@@ -548,9 +544,9 @@ vmi_startup_ipi_hook(int phys_apicid, un }#endif -static void vmi_set_lazy_mode (int mode) -{ - static DEFINE_PER_CPU(int, lazy_mode); +static void vmi_set_lazy_mode (enum paravirt_lazy_mode mode) +{ + static DEFINE_PER_CPU(enum paravirt_lazy_mode, lazy_mode);if (!vmi_ops.set_lazy_mode)return ;
PATCH 28/28 Add a sched_clock paravirt_op
In reply to Jeremy FitzhardingeThe tsc-based get_scheduled_cycles interface is not a good match for Xen's runstate accounting, which reports everything in nanoseconds.
This patch replaces this interface with a sched_clock interface, which matches both Xen and VMI's requirements.
In order to do this, we:
1. replace get_scheduled_cycles with sched_clock
2. hoist cycles_2_ns into a common header
3. update vmi accordingly
One thing to note: because sched_clock is implemented as a weak function in kernel/sched.c, we must define a real function in order to override this weak binding. This means the usual paravirt_ops technique of using an inline function won't work in this case.
--- arch/i386/kernel/paravirt.c | 2 - arch/i386/kernel/sched-clock.c | 43 ++++++++++++++----------------------- arch/i386/kernel/vmi.c | 2 - arch/i386/kernel/vmiclock.c | 6 ++--- include/asm-i386/paravirt.h | 7 ++++-- include/asm-i386/timer.h | 46 +++++++++++++++++++++++++++++++++++++++- include/asm-i386/vmi_time.h | 2 - 7 files changed, 73 insertions(+), 35 deletions(-)
===================================================================
arch/i386/kernel/paravirt.c +1 -1
@@ -268,7 +268,7 @@ struct paravirt_ops paravirt_ops = { .write_msr = native_write_msr_safe, .read_tsc = native_read_tsc, .read_pmc = native_read_pmc, - .get_scheduled_cycles = native_read_tsc, + .sched_clock = native_sched_clock, .get_cpu_khz = native_calculate_cpu_khz, .load_tr_desc = native_load_tr_desc, .set_ldt = native_set_ldt,
===================================================================
arch/i386/kernel/sched-clock.c +17 -26
73 lines not on this page · raw message
===================================================================
arch/i386/kernel/vmi.c +1 -1
@@ -887,7 +887,7 @@ static inline int __init activate_vmi(vo paravirt_ops.setup_boot_clock = vmi_time_bsp_init; paravirt_ops.setup_secondary_clock = vmi_time_ap_init;#endif - paravirt_ops.get_scheduled_cycles = vmi_get_sched_cycles; + paravirt_ops.sched_clock = vmi_sched_clock; paravirt_ops.get_cpu_khz = vmi_cpu_khz;/* We have true wallclock functions; disable CMOS clock sync */
===================================================================
arch/i386/kernel/vmiclock.c +3 -3
@@ -65,9 +65,9 @@ int vmi_set_wallclock(unsigned long now) }/* paravirt_ops.get_scheduled_cycles = vmi_get_sched_cycles */ -unsigned long long vmi_get_sched_cycles (void ) -{ -return vmi_timer_ops.get_cycle_counter (VMI_CYCLES_AVAILABLE ); +unsigned long long vmi_sched_clock (void ) +{ +return cycles_2_ns (vmi_timer_ops.get_cycle_counter (VMI_CYCLES_AVAILABLE )); }/* paravirt_ops.get_cpu_khz = vmi_cpu_khz */
===================================================================
include/asm-i386/paravirt.h +5 -2
@@ -116,7 +116,7 @@ struct paravirt_opsu64 (*read_tsc)(void);u64 (*read_pmc)(void); -u64 (*get_scheduled_cycles)(void); +unsigned long long (*sched_clock)(void );unsigned long (*get_cpu_khz)(void );/* Segment descriptor handling */
@@ -573,7 +573,10 @@ static inline u64 paravirt_read_tsc(void#define rdtscll (val) (val = paravirt_read_tsc()) -#define get_scheduled_cycles (val) (val = paravirt_ops.get_scheduled_cycles()) +static inline unsigned long long paravirt_sched_clock (void ) +{ + return PVOP_CALL0(unsigned long long, sched_clock); +}#define calculate_cpu_khz () (paravirt_ops.get_cpu_khz())#define write_tsc (val1,val2) wrmsr(0x10, val1, val2)
===================================================================
include/asm-i386/timer.h +45 -1
53 lines not on this page · raw message
===================================================================
include/asm-i386/vmi_time.h +1 -1
@@ -49,7 +49,7 @@ extern void __init vmi_time_init(void);extern void __init vmi_time_init (void );extern unsigned long vmi_get_wallclock (void );extern int vmi_set_wallclock (unsigned long now); -extern unsigned long long vmi_get_sched_cycles (void ); +extern unsigned long long vmi_sched_clock (void );extern unsigned long vmi_cpu_khz (void );#ifdef CONFIG_X86_LOCAL_APIC