/* * Input in %rax, MSR number in %ecx * * %edx is set up to match %rax >> 32 like the native stub * is expected to do * * Change xen_do_write_msr to return a true value if * the MSR access should be executed natively (or vice versa, * if you prefer.) * * bool xen_do_write_msr(uint32_t msr, uint64_t value) * * Let the native pattern look like: * * 48 89 c2 mov %rax,%rdx * 48 c1 ea 20 shr $32,%rdx * 3e 0f 30 ds wrmsr <--- trap point * * ... which can be replaced with ... * 48 89 c2 mov %rax,%rdx * 48 c1 ea 20 shr $32,%rdx * 0f 01 c6 wrmsrns <--- trap point * * FOR XEN, replace the FIRST SEVEN BYTES with: * e8 xx xx xx xx call asm_xen_write_msr * 74 03 jz .+5 * * If ZF=0 then this will fall down to the actual native WRMSR[NS] * instruction. * * This also removes the need for Xen to maintain different safe and * unsafe MSR routines, as the difference is handled by the same * trap handler as is used natively. */ SYM_FUNC_START(asm_xen_write_msr) FRAME_BEGIN push %rax /* Save in case of native fallback */ push %rcx push %rsi push %rdi push %r8 push %r9 push %r10 push %r11 mov %ecx,%edi /* MSR number */ mov %rax,%rsi /* MSR data */ call xen_do_write_msr test %al,%al /* ZF=1 means we are done */ pop %r11 pop %r10 pop %r9 pop %r8 pop %rdi pop %rsi pop %rcx mov 4(%rsp),%edx /* Set up %edx for native execution */ pop %rax FRAME_END RET SYM_FUNC_END(asm_xen_write_msr) /* * RDMSR code. It isn't quite as clean; it requires a new trap handler * type: * * case EX_TYPE_UPLEVEL: { * /* Let reg hold the unsigned number of machine * * words to pop off the stack before the return * * address, and imm the signed offset from the * * return address to the desired trap point. * * * * pointer in units of machine words, and imm the * * signed offset from this stack word... * * / * unsigned long *sp = (unsigned long *)regs->sp + reg; * regs->ip = *sp++ + (int16_t)imm; * regs->sp = (unsigned long)sp; * goto again; /* Loop back to the beginning * / * } * * The prototype of the Xen C code: * struct { uint64_t val, bool native } xen_do_read_msr(uint32_t msr) * * Native code: * 0f 32 rdmsr <--- trap point * 48 c1 e2 20 shl $0x20,%rdx * 48 09 d0 or %rdx,%rax * * Xen code (cs rex is just for padding) * 2e 40 e8 xx xx xx xx cs rex call asm_xen_read_msr */ SYM_FUNC_START(asm_xen_read_msr) FRAME_BEGIN push %rcx push %rsi push %rdi push %r8 push %r9 push %r10 push %r11 mov %ecx,%edi /* MSR number */ call xen_do_read_msr test %dl,%dl /* ZF=1 means we are done */ pop %r11 pop %r10 pop %r9 pop %r8 pop %rdi pop %rsi pop %rcx jz 2f 1: rdmsr _ASM_EXTABLE_TYPE(1b, 2f, \ EX_TYPE_UPLEVEL|EX_DATA_IMM(-7)|EX_DATA_REG(0)) shl $32,%rdx or %rdx,%rax /* * The top of the stack points directly at the return address; * back up by 7 bytes from the return address. */ 2: FRAME_END RET SYM_FUNC_END(asm_xen_read_msr)