paravirt_ops x86_64 , take 2
Subsystems (2)
PATCH 1/1 paravirt_ops x86_64 , take 2
Hello all,
Here's a new version of the paravirt_ops x86_64 patch. With this message, I'm sending an incremental patch. The complete patches can be found , from now on, at http://et.redhat.com/~gcosta/paravirt_ops/
The main aim of this new update, is to fix a critical bug, namely, Rusty's name. However, I took the opportunity to write some new less important pieces of code, highlighting:
* proper casts in places in which macros were replaced by functions, and the arguments happened to mismatch types.
* calling paravirt_ops functions from .S files (I lacked this last time)
* addition of the startup_paravirt function, to kick off guests (not tested)
* fixed problems with patching
* added a new field, vsyscall_page in the paravirt_ops struct, which allows the kernel to map a vsyscall_page on its own
* fixed vsyscall functions to avoid calling paravirt_ops functions. __vsyscall_0 is the page to be mapped for the host. (set and get cpu not yet tested.)
* fixed cpuid calls.
* added substitute for the swapgs instruction. (Notice that I'm not saying it works ;-) )
In my TODO list, you can find:
* putting swapgs to work
* making sure legacy mode binaries work
* merging in valuable commentaries from all you ;-)
Signature · 3 lines
Glauber de Oliveira Costa Red Hat Inc. "Free as in Freedom"
arch/i386/kernel/alternative.c +0 -2
@@ -431,9 +431,7 @@ void __init alternative_instructions(voi }#endif #ifdef CONFIG_PARAVIRT -#ifndef CONFIG_X86_64 /* Not working properly yet */ apply_paravirt (__start_parainstructions, __stop_parainstructions); -#endif #endif local_irq_restore (flags); }
arch/x86_64/ia32/syscall32.c +1 -1
@@ -104,5 +104,5 @@ void syscall32_cpu_init(void)checking_wrmsrl (MSR_IA32_SYSENTER_ESP ,0ULL );checking_wrmsrl (MSR_IA32_SYSENTER_EIP , (u64 )ia32_sysenter_target); -wrmsrl (MSR_CSTAR , ia32_cstar_target); +wrmsrl (MSR_CSTAR , (u64 )ia32_cstar_target); }
arch/x86_64/kernel/asm-offsets.c +3 -2
@@ -79,9 +79,10 @@ int main(void)ENTRY (paravirt_enabled);ENTRY (irq_disable);ENTRY (irq_enable); -ENTRY (irq_enable_sysexit); +ENTRY (sysret);ENTRY (iret); -ENTRY (read_cr0); +ENTRY (read_cr2); +ENTRY (swapgs);#endif return 0 ;
arch/x86_64/kernel/entry.S +52 -43
275 lines not on this page · raw message
arch/x86_64/kernel/head64.c +1 -1
@@ -62,7 +62,7 @@ void __init x86_64_start_kernel(char * rfor (i =0 ; i <IDT_ENTRIES ; i++)set_intr_gate (i, early_idt_handler); - asmvolatile ("lidt %0" ::"m" (idt_descr)); +load_idt ((const struct desc_struct *)&idt_descr);early_printk ("Kernel alive\n" );
arch/x86_64/kernel/head.S +59 -2
87 lines not on this page · raw message
arch/x86_64/kernel/paravirt.c +28 -9
@@ -1,6 +1,6 @@/* Paravirtualization interfaces Copyright (C) 2007 Glauber de Oliveira Costa, Red Hat Inc. -Based on i386 work by Rusty Russel. +Based on i386 work by Rusty Russell. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
@@ -59,11 +59,14 @@ void memory_setup(void) asm("start_" #name ": " code "; end_" #name ":")DEF_NATIVE (cli,"cli" );DEF_NATIVE (sti,"sti" ); -DEF_NATIVE (popfq,"pushq %rax; popfq" ); +/* We push rdi , and pop in rda. This is due to x86_64 calling conventions +* Recall that we are patching a function call */ +DEF_NATIVE (popfq,"pushq %rdi; popfq" );DEF_NATIVE (pushfq,"pushfq; popq %rax" );DEF_NATIVE (pushfq_cli,"pushfq; popq %rax; cli" ); -DEF_NATIVE (iret,"iret" ); -DEF_NATIVE (sti_sysretq,"sti; sysretq" ); +DEF_NATIVE (iret,"iretq" ); +DEF_NATIVE (sysretq,"sysretq" ); +DEF_NATIVE (swapgs,"swapgs" ); static const struct native_insns {
@@ -75,7 +78,8 @@ static const struct native_insns [PARAVIRT_SAVE_FLAGS] = { start_pushfq, end_pushfq }, [PARAVIRT_SAVE_FLAGS_IRQ_DISABLE] = { start_pushfq_cli, end_pushfq_cli }, [PARAVIRT_INTERRUPT_RETURN] = { start_iret, end_iret }, - [PARAVIRT_STI_SYSRETQ] = { start_sti_sysretq, end_sti_sysretq }, + [PARAVIRT_SYSRETQ] = { start_sysretq, end_sysretq }, + [PARAVIRT_SWAPGS] = { start_swapgs, end_swapgs }, };static unsigned native_patch (u8 type,u16 clobbers,void *insns,unsigned len)
@@ -88,7 +92,6 @@ static unsigned native_patch(u8 type, u1 insn_len = native_insns[type].end - native_insns[type].start; -/* Similarly if we can't fit replacement. */ if (len < insn_len)return len;
@@ -243,7 +246,7 @@ static void native_wbinvd(void) asmvolatile ("wbinvd" : : :"memory" ); } -static unsigned long native_read_msr (unsigned int msr,int *err) +static u64 native_read_msr (unsigned int msr,int *err) {unsigned long val;
@@ -287,6 +290,13 @@ static u64 native_read_tsc(void)return val; } +static u64 native_read_tscp (int *aux) +{ +u64 val; + asmvolatile ("rdtscp" :"=A" (val),"=c" (aux)); +return val; +} +static u64 native_read_pmc (void ) {unsigned long val;
@@ -463,7 +473,8 @@ void native_pmd_clear(pmd_t *pmd)/* These are in entry.S */ extern void native_iret (void ); -extern void native_irq_enable_sysexit (void ); +extern void native_sysret (void ); +extern void native_swapgs (void );static int __init print_banner (void ) {
@@ -475,12 +486,18 @@ core_initcall(print_banner);/* We simply declare start_kernel to be the paravirt probe of last resort. */ paravirt_probe (start_kernel); +extern unsigned long __vsyscall_0;struct paravirt_ops paravirt_ops = { .name ="bare hardware" , .paravirt_enabled =0 , .kernel_rpl =0 , .pgd_alignment =sizeof (pgd_t) *PTRS_PER_PGD , + .swapgs = { + .ret =0 , + .fn = native_swapgs, + }, + .vsyscall_page = &__vsyscall_0, .patch = native_patch, .banner = default_banner, .arch_setup = native_nop,
@@ -512,6 +529,7 @@ struct paravirt_ops paravirt_ops = { .read_msr = native_read_msr, .write_msr = native_write_msr, .read_tsc = native_read_tsc, + .read_tscp = native_read_tscp, .read_pmc = native_read_pmc, .load_tr_desc = native_load_tr_desc, .set_ldt = native_set_ldt,
@@ -571,7 +589,7 @@ struct paravirt_ops paravirt_ops = { .make_pud = native_make_pud, .make_pgd = native_make_pgd, - .irq_enable_sysexit = native_irq_enable_sysexit, + .sysret = native_sysret, .iret = native_iret, .dup_mmap = (void *)native_nop,
@@ -580,4 +598,5 @@ struct paravirt_ops paravirt_ops = { .startup_ipi_hook = (void *)native_nop, }; +EXPORT_SYMBOL (paravirt_ops);
arch/x86_64/kernel/setup64.c +4 -4
@@ -123,7 +123,7 @@ void pda_init(int cpu) asmvolatile ("movl %0,%%fs ; movl %0,%%gs" ::"r" (0 ));/* Memory clobbers used to order PDA accessed */ mb (); -wrmsrl (MSR_GS_BASE , pda); +wrmsrl (MSR_GS_BASE , (u64 )pda);mb (); pda->cpunumber = cpu;
@@ -160,7 +160,7 @@ void syscall_init(void)* but only a 32bit target. LSTAR sets the 64bit rip. */ wrmsrl (MSR_STAR , ((u64 )__USER32_CS)<<48 | ((u64 )__KERNEL_CS)<<32 ); -wrmsrl (MSR_LSTAR , system_call); +wrmsrl (MSR_LSTAR , (u64 )system_call);#ifdef CONFIG_IA32_EMULATION syscall32_cpu_init ();
@@ -223,8 +223,8 @@ void __cpuinit cpu_init (void)memcpy (cpu_gdt (cpu), cpu_gdt_table,GDT_SIZE ); cpu_gdt_descr[cpu].size =GDT_SIZE ; - asmvolatile ("lgdt %0" ::"m" (cpu_gdt_descr[cpu])); - asmvolatile ("lidt %0" ::"m" (idt_descr)); +load_gdt ((const struct desc_struct *)&cpu_gdt_descr[cpu]); +load_idt ((const struct desc_struct *)&idt_descr);memset (me->thread.tls_array,0 ,GDT_ENTRY_TLS_ENTRIES *8 );syscall_init ();
arch/x86_64/kernel/setup.c +6 -6
@@ -341,6 +341,12 @@ static void discover_ebda(void) ebda_size =64 *1024 ; } +/* Overridden in paravirt.c if CONFIG_PARAVIRT */ +void __attribute__((weak))memory_setup (void ) +{ +return setup_memory_region (); +} +void __init setup_arch (char **cmdline_p) {printk (KERN_INFO "Command line: %s\n" , saved_command_line);
@@ -561,12 +567,6 @@ static int __cpuinit get_model_name(strureturn 1 ; } -/* Overridden in paravirt.c if CONFIG_PARAVIRT */ -void __attribute__((weak))memory_setup (void ) -{ -return setup_memory_region (); -} -static void __cpuinit display_cacheinfo (struct cpuinfo_x86 *c) {unsigned int n, dummy, eax, ebx, ecx, edx;
arch/x86_64/kernel/vsyscall.c +22 -6
@@ -73,7 +73,7 @@ static __always_inline void do_vgettimeo usec = __xtime.tv_nsec /1000 ;if (__vxtime.mode !=VXTIME_HPET ) { - t =get_cycles_sync (); + t =vget_cycles_sync ();if (t < __vxtime.last_tsc) t = __vxtime.last_tsc; usec += ((t - __vxtime.last_tsc) *
@@ -147,8 +147,8 @@ time_t __vsyscall(1) vtime(time_t *t) long __vsyscall(2) vgetcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache) { -unsigned int dummy, p; -unsigned long j =0 ; +unsigned int p; +unsigned long dummy, j =0 ;/* Fast cache - only recompute value once per jiffies and avoid relatively costly rdtscp/cpuid otherwise.
@@ -162,7 +162,8 @@ vgetcpu(unsigned *cpu, unsigned *node, s p = tcache->blob[1 ]; }else if (__vgetcpu_mode ==VGETCPU_RDTSCP ) {/* Load per CPU data from RDTSCP */ -rdtscp (dummy, dummy, p); +/* rdtscp() cannot be called due to the paravirt indirection */ + asm("rdtscp" :"=A" (dummy),"=c" (p)); }else {/* Load per CPU data from GDT */ asm("lsl %1,%0" :"=r" (p) :"r" (__PER_CPU_SEG));
@@ -257,7 +258,11 @@ static void __cpuinit vsyscall_set_cpu(i node = cpu_to_node[cpu];#endif if (cpu_has (&cpu_data[cpu],X86_FEATURE_RDTSCP )) -write_rdtscp_aux ((node <<12 ) | cpu); +/* This is write_rdtscp_aux. It cannot be called directly +* due to the paravirt indirection */ + asm("wrmsr" :/* no output */ + :"d" (0 ), +"a" ((node <<12 ) | cpu),"c" (0xc0000103 ));/* Store cpu number in limit so that it can be loaded quickly in user space in vgetcpu.
@@ -286,8 +291,12 @@ cpu_vsyscall_notifier(struct notifier_blstatic void __init map_vsyscall (void ) { +#ifndef CONFIG_PARAVIRT extern char __vsyscall_0;unsigned long physaddr_page0 =__pa_symbol (&__vsyscall_0); +#else +unsigned long physaddr_page0 =__pa_symbol (paravirt_ops.vsyscall_page); +#endif /* Note that VSYSCALL_MAPPED_PAGES must agree with the code below. */ __set_fixmap (VSYSCALL_FIRST_PAGE , physaddr_page0,PAGE_KERNEL_VSYSCALL );
@@ -300,7 +309,14 @@ static int __init vsyscall_init(void)BUG_ON ((unsigned long ) &vtime !=VSYSCALL_ADDR (__NR_vtime));BUG_ON ((VSYSCALL_ADDR (0 ) !=__fix_to_virt (VSYSCALL_FIRST_PAGE )));BUG_ON ((unsigned long ) &vgetcpu !=VSYSCALL_ADDR (__NR_vgetcpu)); -map_vsyscall (); +#ifdef CONFIG_PARAVIRT + if (paravirt_ops.vsyscall_page) +#endif +map_vsyscall (); +#ifdef CONFIG_PARAVIRT + else + __sysctl_vsyscall =0 ; +#endif #ifdef CONFIG_SYSCTL register_sysctl_table (kernel_root_table2,0 );#endif
arch/x86_64/mm/pageattr.c +1 -1
@@ -81,7 +81,7 @@ static void flush_kernel_map(void *arg)void *adr =page_address (pg);if (cpu_has_clflush)cache_flush_page (adr); -__flush_tlb_one (adr); +__flush_tlb_one ((u64 )adr); } }
include/asm-x86_64/alternative.h +4 -1
@@ -134,8 +134,10 @@ static inline void alternatives_smp_swit#define LOCK_PREFIX ""#endif -struct paravirt_patch ; + +#ifdef CONFIG_PARAVIRT +struct paravirt_patch ;void apply_paravirt (struct paravirt_patch *start,struct paravirt_patch *end);#else static inline void
@@ -145,4 +147,5 @@ apply_paravirt(struct paravirt_patch *st#define __stop_parainstructions NULL#endif +#endif /* _X86_64_ALTERNATIVE_H */
include/asm-x86_64/irqflags.h +0 -1
@@ -18,7 +18,6 @@ static inline int raw_irqs_disabled_flag {return !(flags & (1 <<9 )); } -#else /*
include/asm-x86_64/msr.h +5 -9
@@ -105,15 +105,6 @@ static inline void native_cpuid(unsigned#endif /* CONFIG_PARAVIRT */ -#define rdtscp (low,high,aux) \ - asm volatile (".byte 0x0f,0x01,0xf9" : "=a" (low), "=d" (high), "=c" (aux)) - -#define rdtscpll (val, aux) do { \ - unsigned long __a, __d; \ - asm volatile (".byte 0x0f,0x01,0xf9" : "=a" (__a), "=d" (__d), "=c" (aux)); \ - (val) = (__d << 32) | __a; \ -} while (0) -#define checking_wrmsrl (msr,val) wrmsr_safe(msr,(u32)(val),(u32)((val)>>32))#define write_tsc (val1,val2) wrmsr(0x10, val1, val2)
@@ -125,6 +116,7 @@ static inline void cpuid(unsigned int op *eax = op;__cpuid (eax, ebx, ecx, edx); } +/* Some CPUID calls want 'count' to be placed in ecx */ static inline void cpuid_count (int op,int count,int *eax,int *ebx,int *ecx,int *edx)
@@ -140,24 +132,28 @@ static inline void cpuid_count(int op, istatic inline unsigned int cpuid_eax (unsigned int op) {unsigned int eax, ebx, ecx, edx; + eax = op;__cpuid (&eax, &ebx, &ecx, &edx);return eax; }static inline unsigned int cpuid_ebx (unsigned int op) {unsigned int eax, ebx, ecx, edx; + eax = op;__cpuid (&eax, &ebx, &ecx, &edx);return ebx; }static inline unsigned int cpuid_ecx (unsigned int op) {unsigned int eax, ebx, ecx, edx; + eax = op;__cpuid (&eax, &ebx, &ecx, &edx);return ecx; }static inline unsigned int cpuid_edx (unsigned int op) {unsigned int eax, ebx, ecx, edx; + eax = op;__cpuid (&eax, &ebx, &ecx, &edx);return edx; }
include/asm-x86_64/paravirt.h +50 -33
172 lines not on this page · raw message
include/asm-x86_64/timex.h +17 -2
@@ -31,14 +31,29 @@ static __always_inline cycles_t get_cycl {unsigned long long ret;unsigned eax; +unsigned int (*fn)(unsigned int ) = &cpuid_eax;/* Don't do an additional sync on CPUs where we know RDTSC is already synchronous. */ -alternative_io ("cpuid" ,ASM_NOP2 ,X86_FEATURE_SYNC_RDTSC , - "=a" (eax), "0" (1) : "ebx","ecx","edx","memory"); +alternative_io ("call *%3" ,ASM_NOP2 ,X86_FEATURE_SYNC_RDTSC , +"=a" (eax) ,"D" (1 ) ,"m" (fn));rdtscll (ret);return ret; } +/* Inside a vsyscall, we cannot call paravirt functions. (like rdtsc +* and cpuid). For the host, use this function instead */ +static __always_inline cycles_t vget_cycles_sync(void) +{ +unsigned long ret; +unsigned eax; +/* Don't do an additional sync on CPUs where we know +RDTSC is already synchronous. */ +alternative_io ("cpuid" ,ASM_NOP2 ,X86_FEATURE_SYNC_RDTSC , + "=a" (eax), "0" (1) : "ebx","ecx","edx","memory"); + + asmvolatile ("rdtsc" :"=A" (ret)); +return ret; +}extern unsigned int cpu_khz;extern int read_current_timer (unsigned long *timer_value);
_______________________________________________
Virtualization mailing list
[email protected]
https://lists.osdl.org/mailman/listinfo/virtualization