Viewing file: asm-x86-linux-rdmsr-paravirt.c (5.39 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/* Adapted from Linux: arch/x86/include/asm/paravirt.h */
/* { dg-do compile { target x86_64-pc-linux-gnu } } */ /* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } { "" } } */ /* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
/* Adapted/reduced from linux kernel (GPL-2.0). */
#include "../analyzer-decls.h"
typedef unsigned char u8; typedef unsigned __INT32_TYPE__ u32; typedef unsigned __INT64_TYPE__ u64; typedef __SIZE_TYPE__ size_t;
#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER)
#define __stringify_1(x...) #x #define __stringify(x...) __stringify_1(x)
# define __ASM_FORM(x, ...) " " __stringify(x,##__VA_ARGS__) " " # define __ASM_FORM_RAW(x, ...) __stringify(x,##__VA_ARGS__)
#ifndef __x86_64__ /* 32 bit */ # define __ASM_SEL(a,b) __ASM_FORM(a) # define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(a) #else /* 64 bit */ # define __ASM_SEL(a,b) __ASM_FORM(b) # define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(b) #endif
#define __ASM_REG(reg) __ASM_SEL_RAW(e##reg, r##reg)
#define _ASM_PTR __ASM_SEL(.long, .quad) #define _ASM_ALIGN __ASM_SEL(.balign 4, .balign 8)
#define _ASM_SP __ASM_REG(sp)
register unsigned long current_stack_pointer asm(_ASM_SP); #define ASM_CALL_CONSTRAINT "+r" (current_stack_pointer)
#define ANNOTATE_RETPOLINE_SAFE \ "999:\n\t" \ ".pushsection .discard.retpoline_safe\n\t" \ _ASM_PTR " 999b\n\t" \ ".popsection\n\t"
/* Adapted from Linux arch/x86/include/asm/paravirt.h */
/* snip */
/* ./arch/x86/include/asm/paravirt.h I think; was: PVOP_VCALL4(cpu.cpuid, eax, ebx, ecx, edx);
*/
#ifndef __x86_64__ #define CLBR_ANY ((1 << 4) - 1) #else #define CLBR_ANY ((1 << 9) - 1) #endif /* X86_64 */
struct pv_cpu_ops { /* snip */ u64 (*read_msr_safe)(unsigned int msr, int *err); /* snip */ };
struct paravirt_patch_template { struct pv_cpu_ops cpu; /* snip */ }; extern struct paravirt_patch_template pv_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] "i" (&(pv_ops.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" \ _ASM_ALIGN "\n" \ _ASM_PTR " 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]")
#define PARAVIRT_CALL \ ANNOTATE_RETPOLINE_SAFE \ "call *%c[paravirt_opptr];"
#ifndef __x86_64__
/* 32-bit. */
#define PVOP_CALL_ARGS \ unsigned long __eax = __eax, __edx = __edx, __ecx = __ecx;
#define PVOP_CALL_ARG1(x) "a" ((unsigned long)(x)) #define PVOP_CALL_ARG2(x) "d" ((unsigned long)(x))
#define PVOP_VCALL_CLOBBERS "=a" (__eax), "=d" (__edx), \ "=c" (__ecx) #define PVOP_CALL_CLOBBERS PVOP_VCALL_CLOBBERS
#define PVOP_VCALLEE_CLOBBERS "=a" (__eax), "=d" (__edx) #define PVOP_CALLEE_CLOBBERS PVOP_VCALLEE_CLOBBERS
#define EXTRA_CLOBBERS
#else
/* 64-bit. */
/* [re]ax isn't an arg, but the return val */ #define PVOP_CALL_ARGS \ unsigned long __edi = __edi, __esi = __esi, \ __edx = __edx, __ecx = __ecx, __eax = __eax;
#define PVOP_CALL_ARG1(x) "D" ((unsigned long)(x)) #define PVOP_CALL_ARG2(x) "S" ((unsigned long)(x))
#define PVOP_VCALL_CLOBBERS "=D" (__edi), \ "=S" (__esi), "=d" (__edx), \ "=c" (__ecx) #define PVOP_CALL_CLOBBERS PVOP_VCALL_CLOBBERS, "=a" (__eax) #define PVOP_VCALLEE_CLOBBERS "=a" (__eax) #define PVOP_CALLEE_CLOBBERS PVOP_VCALLEE_CLOBBERS
#define EXTRA_CLOBBERS , "r8", "r9", "r10", "r11" #endif /* CONFIG_X86_32 */
#define PVOP_TEST_NULL(op) ((void)pv_ops.op)
#define PVOP_RETVAL(rettype) \ ({ unsigned long __mask = ~0UL; \ switch (sizeof(rettype)) { \ case 1: __mask = 0xffUL; break; \ case 2: __mask = 0xffffUL; break; \ case 4: __mask = 0xffffffffUL; break; \ default: break; \ } \ __mask & __eax; \ })
#define ____PVOP_CALL(ret, op, clbr, call_clbr, extra_clbr, ...) \ ({ \ PVOP_CALL_ARGS; \ PVOP_TEST_NULL(op); \ asm volatile(paravirt_alt(PARAVIRT_CALL) \ : call_clbr, ASM_CALL_CONSTRAINT \ : paravirt_type(op), \ paravirt_clobber(clbr), \ ##__VA_ARGS__ \ : "memory", "cc" extra_clbr); \ ret; \ })
#define __PVOP_CALL(rettype, op, ...) \ ____PVOP_CALL(PVOP_RETVAL(rettype), op, CLBR_ANY, \ PVOP_CALL_CLOBBERS, EXTRA_CLOBBERS, ##__VA_ARGS__)
#define PVOP_CALL2(rettype, op, arg1, arg2) \ __PVOP_CALL(rettype, op, PVOP_CALL_ARG1(arg1), PVOP_CALL_ARG2(arg2))
static inline u64 paravirt_read_msr_safe(unsigned msr, int *err) { return PVOP_CALL2(u64, cpu.read_msr_safe, msr, err); }
#define rdmsr_safe(msr, a, b) \ ({ \ int _err; \ u64 _l = paravirt_read_msr_safe(msr, &_err); \ (*a) = (u32)_l; \ (*b) = _l >> 32; \ _err; \ })
void check_init_int(int); void check_init_u32(u32);
void test(void) { int err; u32 eax, edx; err = rdmsr_safe(0, &eax, &edx); check_init_int(err); check_init_u32(eax); check_init_u32(edx); }
|