📄 paravirt.h
字号:
#ifndef __ASM_PARAVIRT_H#define __ASM_PARAVIRT_H/* Various instructions on x86 need to be replaced for * para-virtualization: those hooks are defined here. */#ifdef CONFIG_PARAVIRT#include <asm/page.h>/* Bitmask of what can be clobbered: usually at least eax. */#define CLBR_NONE 0x0#define CLBR_EAX 0x1#define CLBR_ECX 0x2#define CLBR_EDX 0x4#define CLBR_ANY 0x7#ifndef __ASSEMBLY__#include <linux/types.h>#include <linux/cpumask.h>#include <asm/kmap_types.h>struct page;struct thread_struct;struct Xgt_desc_struct;struct tss_struct;struct mm_struct;struct desc_struct;/* general info */struct pv_info { unsigned int kernel_rpl; int shared_kernel_pmd; int paravirt_enabled; const char *name;};struct pv_init_ops { /* * Patch may replace one of the defined code sequences with * arbitrary code, subject to the same register constraints. * This generally means the code is not free to clobber any * registers other than EAX. The patch function should return * the number of bytes of code generated, as we nop pad the * rest in generic code. */ unsigned (*patch)(u8 type, u16 clobber, void *insnbuf, unsigned long addr, unsigned len); /* Basic arch-specific setup */ void (*arch_setup)(void); char *(*memory_setup)(void); void (*post_allocator_init)(void); /* Print a banner to identify the environment */ void (*banner)(void);};struct pv_lazy_ops { /* Set deferred update mode, used for batching operations. */ void (*enter)(void); void (*leave)(void);};struct pv_time_ops { void (*time_init)(void); /* Set and set time of day */ unsigned long (*get_wallclock)(void); int (*set_wallclock)(unsigned long); unsigned long long (*sched_clock)(void); unsigned long (*get_cpu_khz)(void);};struct pv_cpu_ops { /* hooks for various privileged instructions */ unsigned long (*get_debugreg)(int regno); void (*set_debugreg)(int regno, unsigned long value); void (*clts)(void); unsigned long (*read_cr0)(void); void (*write_cr0)(unsigned long); unsigned long (*read_cr4_safe)(void); unsigned long (*read_cr4)(void); void (*write_cr4)(unsigned long); /* Segment descriptor handling */ void (*load_tr_desc)(void); void (*load_gdt)(const struct Xgt_desc_struct *); void (*load_idt)(const struct Xgt_desc_struct *); void (*store_gdt)(struct Xgt_desc_struct *); void (*store_idt)(struct Xgt_desc_struct *); void (*set_ldt)(const void *desc, unsigned entries); unsigned long (*store_tr)(void); void (*load_tls)(struct thread_struct *t, unsigned int cpu); void (*write_ldt_entry)(struct desc_struct *, int entrynum, u32 low, u32 high); void (*write_gdt_entry)(struct desc_struct *, int entrynum, u32 low, u32 high); void (*write_idt_entry)(struct desc_struct *, int entrynum, u32 low, u32 high); void (*load_esp0)(struct tss_struct *tss, struct thread_struct *t); void (*set_iopl_mask)(unsigned mask); void (*wbinvd)(void); void (*io_delay)(void); /* cpuid emulation, mostly so that caps bits can be disabled */ void (*cpuid)(unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx); /* MSR, PMC and TSR operations. err = 0/-EFAULT. wrmsr returns 0/-EFAULT. */ u64 (*read_msr)(unsigned int msr, int *err); int (*write_msr)(unsigned int msr, u64 val); u64 (*read_tsc)(void); u64 (*read_pmc)(void); /* These two are jmp to, not actually called. */ void (*irq_enable_sysexit)(void); void (*iret)(void); struct pv_lazy_ops lazy_mode;};struct pv_irq_ops { void (*init_IRQ)(void); /* * Get/set interrupt state. save_fl and restore_fl are only * expected to use X86_EFLAGS_IF; all other bits * returned from save_fl are undefined, and may be ignored by * restore_fl. */ unsigned long (*save_fl)(void); void (*restore_fl)(unsigned long); void (*irq_disable)(void); void (*irq_enable)(void); void (*safe_halt)(void); void (*halt)(void);};struct pv_apic_ops {#ifdef CONFIG_X86_LOCAL_APIC /* * Direct APIC operations, principally for VMI. Ideally * these shouldn't be in this interface. */ void (*apic_write)(unsigned long reg, unsigned long v); void (*apic_write_atomic)(unsigned long reg, unsigned long v); unsigned long (*apic_read)(unsigned long reg); void (*setup_boot_clock)(void); void (*setup_secondary_clock)(void); void (*startup_ipi_hook)(int phys_apicid, unsigned long start_eip, unsigned long start_esp);#endif};struct pv_mmu_ops { /* * Called before/after init_mm pagetable setup. setup_start * may reset %cr3, and may pre-install parts of the pagetable; * pagetable setup is expected to preserve any existing * mapping. */ void (*pagetable_setup_start)(pgd_t *pgd_base); void (*pagetable_setup_done)(pgd_t *pgd_base); unsigned long (*read_cr2)(void); void (*write_cr2)(unsigned long); unsigned long (*read_cr3)(void); void (*write_cr3)(unsigned long); /* * Hooks for intercepting the creation/use/destruction of an * mm_struct. */ void (*activate_mm)(struct mm_struct *prev, struct mm_struct *next); void (*dup_mmap)(struct mm_struct *oldmm, struct mm_struct *mm); void (*exit_mmap)(struct mm_struct *mm); /* TLB operations */ void (*flush_tlb_user)(void); void (*flush_tlb_kernel)(void); void (*flush_tlb_single)(unsigned long addr); void (*flush_tlb_others)(const cpumask_t *cpus, struct mm_struct *mm, unsigned long va); /* Hooks for allocating/releasing pagetable pages */ void (*alloc_pt)(struct mm_struct *mm, u32 pfn); void (*alloc_pd)(u32 pfn); void (*alloc_pd_clone)(u32 pfn, u32 clonepfn, u32 start, u32 count); void (*release_pt)(u32 pfn); void (*release_pd)(u32 pfn); /* Pagetable manipulation functions */ void (*set_pte)(pte_t *ptep, pte_t pteval); void (*set_pte_at)(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pteval); void (*set_pmd)(pmd_t *pmdp, pmd_t pmdval); void (*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);#ifdef CONFIG_X86_PAE void (*set_pte_atomic)(pte_t *ptep, pte_t pteval); void (*set_pte_present)(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte); void (*set_pud)(pud_t *pudp, pud_t pudval); void (*pte_clear)(struct mm_struct *mm, unsigned long addr, pte_t *ptep); void (*pmd_clear)(pmd_t *pmdp); unsigned long long (*pte_val)(pte_t); unsigned long long (*pmd_val)(pmd_t); unsigned long long (*pgd_val)(pgd_t); pte_t (*make_pte)(unsigned long long pte); pmd_t (*make_pmd)(unsigned long long pmd); pgd_t (*make_pgd)(unsigned long long pgd);#else unsigned long (*pte_val)(pte_t); unsigned long (*pgd_val)(pgd_t); pte_t (*make_pte)(unsigned long pte); pgd_t (*make_pgd)(unsigned long pgd);#endif#ifdef CONFIG_HIGHPTE void *(*kmap_atomic_pte)(struct page *page, enum km_type type);#endif struct pv_lazy_ops lazy_mode;};/* This contains all the paravirt structures: we get a convenient * number for each function using the offset which we use to indicate * what to patch. */struct paravirt_patch_template{ struct pv_init_ops pv_init_ops; struct pv_time_ops pv_time_ops; struct pv_cpu_ops pv_cpu_ops; struct pv_irq_ops pv_irq_ops; struct pv_apic_ops pv_apic_ops; struct pv_mmu_ops pv_mmu_ops;};extern struct pv_info pv_info;extern struct pv_init_ops pv_init_ops;extern struct pv_time_ops pv_time_ops;extern struct pv_cpu_ops pv_cpu_ops;extern struct pv_irq_ops pv_irq_ops;extern struct pv_apic_ops pv_apic_ops;extern struct pv_mmu_ops pv_mmu_ops;#define PARAVIRT_PATCH(x) \ (offsetof(struct paravirt_patch_template, x) / sizeof(void *))#define paravirt_type(op) \ [paravirt_typenum] "i" (PARAVIRT_PATCH(op)), \ [paravirt_opptr] "m" (op)#define paravirt_clobber(clobber) \ [paravirt_clobber] "i" (clobber)/* * Generate some code, and mark it as patchable by the * apply_paravirt() alternate instruction patcher. */#define _paravirt_alt(insn_string, type, clobber) \ "771:\n\t" insn_string "\n" "772:\n" \ ".pushsection .parainstructions,\"a\"\n" \ " .long 771b\n" \ " .byte " type "\n" \ " .byte 772b-771b\n" \ " .short " clobber "\n" \ ".popsection\n"/* Generate patchable code, with the default asm parameters. */#define paravirt_alt(insn_string) \ _paravirt_alt(insn_string, "%c[paravirt_typenum]", "%c[paravirt_clobber]")unsigned paravirt_patch_nop(void);unsigned paravirt_patch_ignore(unsigned len);unsigned paravirt_patch_call(void *insnbuf, const void *target, u16 tgt_clobbers, unsigned long addr, u16 site_clobbers, unsigned len);unsigned paravirt_patch_jmp(void *insnbuf, const void *target, unsigned long addr, unsigned len);unsigned paravirt_patch_default(u8 type, u16 clobbers, void *insnbuf, unsigned long addr, unsigned len);unsigned paravirt_patch_insns(void *insnbuf, unsigned len, const char *start, const char *end);int paravirt_disable_iospace(void);/* * This generates an indirect call based on the operation type number. * The type number, computed in PARAVIRT_PATCH, is derived from the * offset into the paravirt_patch_template structure, and can therefore be * freely converted back into a structure offset. */#define PARAVIRT_CALL "call *%[paravirt_opptr];"/* * These macros are intended to wrap calls through one of the paravirt * ops structs, so that they can be later identified and patched at * runtime. * * Normally, a call to a pv_op function is a simple indirect call: * (paravirt_ops.operations)(args...). * * Unfortunately, this is a relatively slow operation for modern CPUs, * because it cannot necessarily determine what the destination * address is. In this case, the address is a runtime constant, so at * the very least we can patch the call to e a simple direct call, or * ideally, patch an inline implementation into the callsite. (Direct * calls are essentially free, because the call and return addresses * are completely predictable.) * * These macros rely on the standard gcc "regparm(3)" calling * convention, in which the first three arguments are placed in %eax, * %edx, %ecx (in that order), and the remaining arguments are placed * on the stack. All caller-save registers (eax,edx,ecx) are expected * to be modified (either clobbered or used for return values). * * The call instruction itself is marked by placing its start address * and size into the .parainstructions section, so that * apply_paravirt() in arch/i386/kernel/alternative.c can do the * appropriate patching under the control of the backend pv_init_ops * implementation. * * Unfortunately there's no way to get gcc to generate the args setup * for the call, and then allow the call itself to be generated by an * inline asm. Because of this, we must do the complete arg setup and * return value handling from within these macros. This is fairly * cumbersome. * * There are 5 sets of PVOP_* macros for dealing with 0-4 arguments. * It could be extended to more arguments, but there would be little * to be gained from that. For each number of arguments, there are * the two VCALL and CALL variants for void and non-void functions. * * When there is a return value, the invoker of the macro must specify * the return type. The macro then uses sizeof() on that type to * determine whether its a 32 or 64 bit value, and places the return * in the right register(s) (just %eax for 32-bit, and %edx:%eax for * 64-bit). * * 64-bit arguments are passed as a pair of adjacent 32-bit arguments * in low,high order. * * Small structures are passed and returned in registers. The macro * calling convention can't directly deal with this, so the wrapper * functions must do this. * * These PVOP_* macros are only defined within this header. This * means that all uses must be wrapped in inline functions. This also * makes sure the incoming and outgoing types are always correct. */#define __PVOP_CALL(rettype, op, pre, post, ...) \ ({ \ rettype __ret; \ unsigned long __eax, __edx, __ecx; \ if (sizeof(rettype) > sizeof(unsigned long)) { \ asm volatile(pre \ paravirt_alt(PARAVIRT_CALL) \ post \ : "=a" (__eax), "=d" (__edx), \ "=c" (__ecx) \ : paravirt_type(op), \ paravirt_clobber(CLBR_ANY), \ ##__VA_ARGS__ \ : "memory", "cc"); \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -