Skip to content

Commit

Permalink
Merge branch 'x86/paravirt' into x86/apic
Browse files Browse the repository at this point in the history
Conflicts:
	arch/x86/mach-voyager/voyager_smp.c
  • Loading branch information
Ingo Molnar committed Feb 9, 2009
2 parents 54a353a + e4d0407 commit eca217b
Show file tree
Hide file tree
Showing 27 changed files with 1,399 additions and 1,167 deletions.
435 changes: 301 additions & 134 deletions arch/x86/include/asm/paravirt.h

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion arch/x86/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -768,7 +768,8 @@ extern int sysenter_setup(void);
extern struct desc_ptr early_gdt_descr;

extern void cpu_set_gdt(int);
extern void switch_to_new_gdt(void);
extern void switch_to_new_gdt(int);
extern void load_percpu_segment(int);
extern void cpu_init(void);

static inline unsigned long get_debugctlmsr(void)
Expand Down
25 changes: 15 additions & 10 deletions arch/x86/kernel/cpu/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,23 +296,28 @@ static char __cpuinit *table_lookup_model(struct cpuinfo_x86 *c)

__u32 cleared_cpu_caps[NCAPINTS] __cpuinitdata;

void load_percpu_segment(int cpu)
{
#ifdef CONFIG_X86_32
loadsegment(fs, __KERNEL_PERCPU);
#else
loadsegment(gs, 0);
wrmsrl(MSR_GS_BASE, (unsigned long)per_cpu(irq_stack_union.gs_base, cpu));
#endif
}

/* Current gdt points %fs at the "master" per-cpu area: after this,
* it's on the real one. */
void switch_to_new_gdt(void)
void switch_to_new_gdt(int cpu)
{
struct desc_ptr gdt_descr;
int cpu = smp_processor_id();

gdt_descr.address = (long)get_cpu_gdt_table(cpu);
gdt_descr.size = GDT_SIZE - 1;
load_gdt(&gdt_descr);
/* Reload the per-cpu base */
#ifdef CONFIG_X86_32
loadsegment(fs, __KERNEL_PERCPU);
#else
loadsegment(gs, 0);
wrmsrl(MSR_GS_BASE, (unsigned long)per_cpu(irq_stack_union.gs_base, cpu));
#endif

load_percpu_segment(cpu);
}

static struct cpu_dev *cpu_devs[X86_VENDOR_NUM] = {};
Expand Down Expand Up @@ -1029,7 +1034,7 @@ void __cpuinit cpu_init(void)
* and set up the GDT descriptor:
*/

switch_to_new_gdt();
switch_to_new_gdt(cpu);
loadsegment(fs, 0);

load_idt((const struct desc_ptr *)&idt_descr);
Expand Down Expand Up @@ -1131,7 +1136,7 @@ void __cpuinit cpu_init(void)
clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);

load_idt(&idt_descr);
switch_to_new_gdt();
switch_to_new_gdt(cpu);

/*
* Set up and load the per-CPU TSS and LDT
Expand Down
2 changes: 1 addition & 1 deletion arch/x86/kernel/entry_64.S
Original file line number Diff line number Diff line change
Expand Up @@ -1143,7 +1143,7 @@ ENTRY(native_load_gs_index)
CFI_STARTPROC
pushf
CFI_ADJUST_CFA_OFFSET 8
DISABLE_INTERRUPTS(CLBR_ANY | ~(CLBR_RDI))
DISABLE_INTERRUPTS(CLBR_ANY & ~CLBR_RDI)
SWAPGS
gs_change:
movl %edi,%gs
Expand Down
54 changes: 41 additions & 13 deletions arch/x86/kernel/paravirt.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,17 @@ void _paravirt_nop(void)
{
}

/* identity function, which can be inlined */
u32 _paravirt_ident_32(u32 x)
{
return x;
}

u64 _paravirt_ident_64(u64 x)
{
return x;
}

static void __init default_banner(void)
{
printk(KERN_INFO "Booting paravirtualized kernel on %s\n",
Expand Down Expand Up @@ -138,9 +149,16 @@ unsigned paravirt_patch_default(u8 type, u16 clobbers, void *insnbuf,
if (opfunc == NULL)
/* If there's no function, patch it with a ud2a (BUG) */
ret = paravirt_patch_insns(insnbuf, len, ud2a, ud2a+sizeof(ud2a));
else if (opfunc == paravirt_nop)
else if (opfunc == _paravirt_nop)
/* If the operation is a nop, then nop the callsite */
ret = paravirt_patch_nop();

/* identity functions just return their single argument */
else if (opfunc == _paravirt_ident_32)
ret = paravirt_patch_ident_32(insnbuf, len);
else if (opfunc == _paravirt_ident_64)
ret = paravirt_patch_ident_64(insnbuf, len);

else if (type == PARAVIRT_PATCH(pv_cpu_ops.iret) ||
type == PARAVIRT_PATCH(pv_cpu_ops.irq_enable_sysexit) ||
type == PARAVIRT_PATCH(pv_cpu_ops.usergs_sysret32) ||
Expand Down Expand Up @@ -292,10 +310,10 @@ struct pv_time_ops pv_time_ops = {

struct pv_irq_ops pv_irq_ops = {
.init_IRQ = native_init_IRQ,
.save_fl = native_save_fl,
.restore_fl = native_restore_fl,
.irq_disable = native_irq_disable,
.irq_enable = native_irq_enable,
.save_fl = __PV_IS_CALLEE_SAVE(native_save_fl),
.restore_fl = __PV_IS_CALLEE_SAVE(native_restore_fl),
.irq_disable = __PV_IS_CALLEE_SAVE(native_irq_disable),
.irq_enable = __PV_IS_CALLEE_SAVE(native_irq_enable),
.safe_halt = native_safe_halt,
.halt = native_halt,
#ifdef CONFIG_X86_64
Expand Down Expand Up @@ -373,6 +391,14 @@ struct pv_apic_ops pv_apic_ops = {
#endif
};

#if defined(CONFIG_X86_32) && !defined(CONFIG_X86_PAE)
/* 32-bit pagetable entries */
#define PTE_IDENT __PV_IS_CALLEE_SAVE(_paravirt_ident_32)
#else
/* 64-bit pagetable entries */
#define PTE_IDENT __PV_IS_CALLEE_SAVE(_paravirt_ident_64)
#endif

struct pv_mmu_ops pv_mmu_ops = {
#ifndef CONFIG_X86_64
.pagetable_setup_start = native_pagetable_setup_start,
Expand Down Expand Up @@ -424,21 +450,23 @@ struct pv_mmu_ops pv_mmu_ops = {
.pmd_clear = native_pmd_clear,
#endif
.set_pud = native_set_pud,
.pmd_val = native_pmd_val,
.make_pmd = native_make_pmd,

.pmd_val = PTE_IDENT,
.make_pmd = PTE_IDENT,

#if PAGETABLE_LEVELS == 4
.pud_val = native_pud_val,
.make_pud = native_make_pud,
.pud_val = PTE_IDENT,
.make_pud = PTE_IDENT,

.set_pgd = native_set_pgd,
#endif
#endif /* PAGETABLE_LEVELS >= 3 */

.pte_val = native_pte_val,
.pgd_val = native_pgd_val,
.pte_val = PTE_IDENT,
.pgd_val = PTE_IDENT,

.make_pte = native_make_pte,
.make_pgd = native_make_pgd,
.make_pte = PTE_IDENT,
.make_pgd = PTE_IDENT,

.dup_mmap = paravirt_nop,
.exit_mmap = paravirt_nop,
Expand Down
12 changes: 12 additions & 0 deletions arch/x86/kernel/paravirt_patch_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@ DEF_NATIVE(pv_mmu_ops, read_cr3, "mov %cr3, %eax");
DEF_NATIVE(pv_cpu_ops, clts, "clts");
DEF_NATIVE(pv_cpu_ops, read_tsc, "rdtsc");

unsigned paravirt_patch_ident_32(void *insnbuf, unsigned len)
{
/* arg in %eax, return in %eax */
return 0;
}

unsigned paravirt_patch_ident_64(void *insnbuf, unsigned len)
{
/* arg in %edx:%eax, return in %edx:%eax */
return 0;
}

unsigned native_patch(u8 type, u16 clobbers, void *ibuf,
unsigned long addr, unsigned len)
{
Expand Down
15 changes: 15 additions & 0 deletions arch/x86/kernel/paravirt_patch_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,21 @@ DEF_NATIVE(pv_cpu_ops, usergs_sysret64, "swapgs; sysretq");
DEF_NATIVE(pv_cpu_ops, usergs_sysret32, "swapgs; sysretl");
DEF_NATIVE(pv_cpu_ops, swapgs, "swapgs");

DEF_NATIVE(, mov32, "mov %edi, %eax");
DEF_NATIVE(, mov64, "mov %rdi, %rax");

unsigned paravirt_patch_ident_32(void *insnbuf, unsigned len)
{
return paravirt_patch_insns(insnbuf, len,
start__mov32, end__mov32);
}

unsigned paravirt_patch_ident_64(void *insnbuf, unsigned len)
{
return paravirt_patch_insns(insnbuf, len,
start__mov64, end__mov64);
}

unsigned native_patch(u8 type, u16 clobbers, void *ibuf,
unsigned long addr, unsigned len)
{
Expand Down
2 changes: 1 addition & 1 deletion arch/x86/kernel/setup_percpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ void __init setup_per_cpu_areas(void)
* area. Reload any changed state for the boot CPU.
*/
if (cpu == boot_cpu_id)
switch_to_new_gdt();
switch_to_new_gdt(cpu);

DBG("PERCPU: cpu %4d %p\n", cpu, ptr);
}
Expand Down
2 changes: 1 addition & 1 deletion arch/x86/kernel/smpboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -1188,7 +1188,7 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
void __init native_smp_prepare_boot_cpu(void)
{
int me = smp_processor_id();
switch_to_new_gdt();
switch_to_new_gdt(me);
/* already set me in cpu_online_mask in boot_cpu_init() */
cpumask_set_cpu(me, cpu_callout_mask);
per_cpu(cpu_state, me) = CPU_ONLINE;
Expand Down
2 changes: 1 addition & 1 deletion arch/x86/kernel/tlb_uv.c
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ const struct cpumask *uv_flush_send_and_wait(int cpu, int this_blade,
* the cpu's, all of which are still in the mask.
*/
__get_cpu_var(ptcstats).ptc_i++;
return 0;
return flush_mask;
}

/*
Expand Down
9 changes: 5 additions & 4 deletions arch/x86/kernel/vmi_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -670,10 +670,11 @@ static inline int __init activate_vmi(void)
para_fill(pv_mmu_ops.write_cr2, SetCR2);
para_fill(pv_mmu_ops.write_cr3, SetCR3);
para_fill(pv_cpu_ops.write_cr4, SetCR4);
para_fill(pv_irq_ops.save_fl, GetInterruptMask);
para_fill(pv_irq_ops.restore_fl, SetInterruptMask);
para_fill(pv_irq_ops.irq_disable, DisableInterrupts);
para_fill(pv_irq_ops.irq_enable, EnableInterrupts);

para_fill(pv_irq_ops.save_fl.func, GetInterruptMask);
para_fill(pv_irq_ops.restore_fl.func, SetInterruptMask);
para_fill(pv_irq_ops.irq_disable.func, DisableInterrupts);
para_fill(pv_irq_ops.irq_enable.func, EnableInterrupts);

para_fill(pv_cpu_ops.wbinvd, WBINVD);
para_fill(pv_cpu_ops.read_tsc, RDTSC);
Expand Down
5 changes: 3 additions & 2 deletions arch/x86/kernel/vmlinux_64.lds.S
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ PHDRS {
#ifdef CONFIG_SMP
percpu PT_LOAD FLAGS(7); /* RWE */
#endif
data.init2 PT_LOAD FLAGS(7); /* RWE */
note PT_NOTE FLAGS(0); /* ___ */
}
SECTIONS
Expand Down Expand Up @@ -215,7 +216,7 @@ SECTIONS
/*
* percpu offsets are zero-based on SMP. PERCPU_VADDR() changes the
* output PHDR, so the next output section - __data_nosave - should
* switch it back to data.init. Also, pda should be at the head of
* start another section data.init2. Also, pda should be at the head of
* percpu area. Preallocate it and define the percpu offset symbol
* so that it can be accessed as a percpu variable.
*/
Expand All @@ -232,7 +233,7 @@ SECTIONS
__nosave_begin = .;
.data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) {
*(.data.nosave)
} :data.init /* switch back to data.init, see PERCPU_VADDR() above */
} :data.init2 /* use another section data.init2, see PERCPU_VADDR() above */
. = ALIGN(PAGE_SIZE);
__nosave_end = .;

Expand Down
12 changes: 8 additions & 4 deletions arch/x86/kernel/vsmp_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ static unsigned long vsmp_save_fl(void)
flags &= ~X86_EFLAGS_IF;
return flags;
}
PV_CALLEE_SAVE_REGS_THUNK(vsmp_save_fl);

static void vsmp_restore_fl(unsigned long flags)
{
Expand All @@ -46,20 +47,23 @@ static void vsmp_restore_fl(unsigned long flags)
flags |= X86_EFLAGS_AC;
native_restore_fl(flags);
}
PV_CALLEE_SAVE_REGS_THUNK(vsmp_restore_fl);

static void vsmp_irq_disable(void)
{
unsigned long flags = native_save_fl();

native_restore_fl((flags & ~X86_EFLAGS_IF) | X86_EFLAGS_AC);
}
PV_CALLEE_SAVE_REGS_THUNK(vsmp_irq_disable);

static void vsmp_irq_enable(void)
{
unsigned long flags = native_save_fl();

native_restore_fl((flags | X86_EFLAGS_IF) & (~X86_EFLAGS_AC));
}
PV_CALLEE_SAVE_REGS_THUNK(vsmp_irq_enable);

static unsigned __init_or_module vsmp_patch(u8 type, u16 clobbers, void *ibuf,
unsigned long addr, unsigned len)
Expand Down Expand Up @@ -90,10 +94,10 @@ static void __init set_vsmp_pv_ops(void)
cap, ctl);
if (cap & ctl & (1 << 4)) {
/* Setup irq ops and turn on vSMP IRQ fastpath handling */
pv_irq_ops.irq_disable = vsmp_irq_disable;
pv_irq_ops.irq_enable = vsmp_irq_enable;
pv_irq_ops.save_fl = vsmp_save_fl;
pv_irq_ops.restore_fl = vsmp_restore_fl;
pv_irq_ops.irq_disable = PV_CALLEE_SAVE(vsmp_irq_disable);
pv_irq_ops.irq_enable = PV_CALLEE_SAVE(vsmp_irq_enable);
pv_irq_ops.save_fl = PV_CALLEE_SAVE(vsmp_save_fl);
pv_irq_ops.restore_fl = PV_CALLEE_SAVE(vsmp_restore_fl);
pv_init_ops.patch = vsmp_patch;

ctl &= ~(1 << 4);
Expand Down
13 changes: 9 additions & 4 deletions arch/x86/lguest/boot.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,24 +173,29 @@ static unsigned long save_fl(void)
{
return lguest_data.irq_enabled;
}
PV_CALLEE_SAVE_REGS_THUNK(save_fl);

/* restore_flags() just sets the flags back to the value given. */
static void restore_fl(unsigned long flags)
{
lguest_data.irq_enabled = flags;
}
PV_CALLEE_SAVE_REGS_THUNK(restore_fl);

/* Interrupts go off... */
static void irq_disable(void)
{
lguest_data.irq_enabled = 0;
}
PV_CALLEE_SAVE_REGS_THUNK(irq_disable);

/* Interrupts go on... */
static void irq_enable(void)
{
lguest_data.irq_enabled = X86_EFLAGS_IF;
}
PV_CALLEE_SAVE_REGS_THUNK(irq_enable);

/*:*/
/*M:003 Note that we don't check for outstanding interrupts when we re-enable
* them (or when we unmask an interrupt). This seems to work for the moment,
Expand Down Expand Up @@ -984,10 +989,10 @@ __init void lguest_init(void)

/* interrupt-related operations */
pv_irq_ops.init_IRQ = lguest_init_IRQ;
pv_irq_ops.save_fl = save_fl;
pv_irq_ops.restore_fl = restore_fl;
pv_irq_ops.irq_disable = irq_disable;
pv_irq_ops.irq_enable = irq_enable;
pv_irq_ops.save_fl = PV_CALLEE_SAVE(save_fl);
pv_irq_ops.restore_fl = PV_CALLEE_SAVE(restore_fl);
pv_irq_ops.irq_disable = PV_CALLEE_SAVE(irq_disable);
pv_irq_ops.irq_enable = PV_CALLEE_SAVE(irq_enable);
pv_irq_ops.safe_halt = lguest_safe_halt;

/* init-time operations */
Expand Down
4 changes: 2 additions & 2 deletions arch/x86/mach-voyager/voyager_smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1744,13 +1744,13 @@ static void __init voyager_smp_prepare_cpus(unsigned int max_cpus)

static void __cpuinit voyager_smp_prepare_boot_cpu(void)
{
switch_to_new_gdt();
int cpu = smp_processor_id();
switch_to_new_gdt(cpu);

cpu_online_map = cpumask_of_cpu(smp_processor_id());
cpu_callout_map = cpumask_of_cpu(smp_processor_id());
cpu_callin_map = CPU_MASK_NONE;
cpu_present_map = cpumask_of_cpu(smp_processor_id());

}

static int __cpuinit voyager_cpu_up(unsigned int cpu)
Expand Down
Loading

0 comments on commit eca217b

Please sign in to comment.