[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH for-next v3 02/22] x86/traps: move gate op emulation code
The code is moved to pv/emulate.c. Export emulate_gate_op in pv/traps.h. Delete the now unused read_descriptor in x86/traps.c. Duplicate instruction_done in pv/traps.c. No functional change. Signed-off-by: Wei Liu <wei.liu2@xxxxxxxxxx> --- xen/arch/x86/pv/emulate.c | 403 +++++++++++++++++++++++++++++++++++++ xen/arch/x86/traps.c | 441 ----------------------------------------- xen/include/asm-x86/pv/traps.h | 2 + 3 files changed, 405 insertions(+), 441 deletions(-) diff --git a/xen/arch/x86/pv/emulate.c b/xen/arch/x86/pv/emulate.c index fb0d066a3b..6d096b74b2 100644 --- a/xen/arch/x86/pv/emulate.c +++ b/xen/arch/x86/pv/emulate.c @@ -45,6 +45,17 @@ * Helper functions */ +static void instruction_done(struct cpu_user_regs *regs, unsigned long rip) +{ + regs->rip = rip; + regs->eflags &= ~X86_EFLAGS_RF; + if ( regs->eflags & X86_EFLAGS_TF ) + { + current->arch.debugreg[6] |= DR_STEP | DR_STATUS_RESERVED_ONE; + pv_inject_hw_exception(TRAP_debug, X86_EVENT_NO_EC); + } +} + static int read_descriptor(unsigned int sel, const struct vcpu *v, unsigned long *base, @@ -1459,6 +1470,398 @@ int emulate_privileged_op(struct cpu_user_regs *regs) return 0; } +/******************* + * Gate OP emulation + */ + + +static int read_gate_descriptor(unsigned int gate_sel, + const struct vcpu *v, + unsigned int *sel, + unsigned long *off, + unsigned int *ar) +{ + struct desc_struct desc; + const struct desc_struct *pdesc; + + + pdesc = (const struct desc_struct *) + (!(gate_sel & 4) ? GDT_VIRT_START(v) : LDT_VIRT_START(v)) + + (gate_sel >> 3); + if ( (gate_sel < 4) || + ((gate_sel >= FIRST_RESERVED_GDT_BYTE) && !(gate_sel & 4)) || + __get_user(desc, pdesc) ) + return 0; + + *sel = (desc.a >> 16) & 0x0000fffc; + *off = (desc.a & 0x0000ffff) | (desc.b & 0xffff0000); + *ar = desc.b & 0x0000ffff; + + /* + * check_descriptor() clears the DPL field and stores the + * guest requested DPL in the selector's RPL field. + */ + if ( *ar & _SEGMENT_DPL ) + return 0; + *ar |= (desc.a >> (16 - 13)) & _SEGMENT_DPL; + + if ( !is_pv_32bit_vcpu(v) ) + { + if ( (*ar & 0x1f00) != 0x0c00 || + (gate_sel >= FIRST_RESERVED_GDT_BYTE - 8 && !(gate_sel & 4)) || + __get_user(desc, pdesc + 1) || + (desc.b & 0x1f00) ) + return 0; + + *off |= (unsigned long)desc.a << 32; + return 1; + } + + switch ( *ar & 0x1f00 ) + { + case 0x0400: + *off &= 0xffff; + break; + case 0x0c00: + break; + default: + return 0; + } + + return 1; +} + +static inline int check_stack_limit(unsigned int ar, unsigned int limit, + unsigned int esp, unsigned int decr) +{ + return (((esp - decr) < (esp - 1)) && + (!(ar & _SEGMENT_EC) ? (esp - 1) <= limit : (esp - decr) > limit)); +} + +struct gate_op_ctxt { + struct x86_emulate_ctxt ctxt; + struct { + unsigned long base, limit; + } cs; + bool insn_fetch; +}; + +static int gate_op_read( + enum x86_segment seg, + unsigned long offset, + void *p_data, + unsigned int bytes, + struct x86_emulate_ctxt *ctxt) +{ + const struct gate_op_ctxt *goc = + container_of(ctxt, struct gate_op_ctxt, ctxt); + unsigned int rc = bytes, sel = 0; + unsigned long addr = offset, limit = 0; + + switch ( seg ) + { + case x86_seg_cs: + addr += goc->cs.base; + limit = goc->cs.limit; + break; + case x86_seg_ds: + sel = read_sreg(ds); + break; + case x86_seg_es: + sel = read_sreg(es); + break; + case x86_seg_fs: + sel = read_sreg(fs); + break; + case x86_seg_gs: + sel = read_sreg(gs); + break; + case x86_seg_ss: + sel = ctxt->regs->ss; + break; + default: + return X86EMUL_UNHANDLEABLE; + } + if ( sel ) + { + unsigned int ar; + + ASSERT(!goc->insn_fetch); + if ( !read_descriptor(sel, current, &addr, &limit, &ar, 0) || + !(ar & _SEGMENT_S) || + !(ar & _SEGMENT_P) || + ((ar & _SEGMENT_CODE) && !(ar & _SEGMENT_WR)) ) + return X86EMUL_UNHANDLEABLE; + addr += offset; + } + else if ( seg != x86_seg_cs ) + return X86EMUL_UNHANDLEABLE; + + /* We don't mean to emulate any branches. */ + if ( limit < bytes - 1 || offset > limit - bytes + 1 ) + return X86EMUL_UNHANDLEABLE; + + addr = (uint32_t)addr; + + if ( (rc = __copy_from_user(p_data, (void *)addr, bytes)) ) + { + /* + * TODO: This should report PFEC_insn_fetch when goc->insn_fetch && + * cpu_has_nx, but we'd then need a "fetch" variant of + * __copy_from_user() respecting NX, SMEP, and protection keys. + */ + x86_emul_pagefault(0, addr + bytes - rc, ctxt); + return X86EMUL_EXCEPTION; + } + + return X86EMUL_OKAY; +} + +void emulate_gate_op(struct cpu_user_regs *regs) +{ + struct vcpu *v = current; + unsigned int sel, ar, dpl, nparm, insn_len; + struct gate_op_ctxt ctxt = { .ctxt.regs = regs, .insn_fetch = true }; + struct x86_emulate_state *state; + unsigned long off, base, limit; + uint16_t opnd_sel = 0; + int jump = -1, rc = X86EMUL_OKAY; + + /* Check whether this fault is due to the use of a call gate. */ + if ( !read_gate_descriptor(regs->error_code, v, &sel, &off, &ar) || + (((ar >> 13) & 3) < (regs->cs & 3)) || + ((ar & _SEGMENT_TYPE) != 0xc00) ) + { + pv_inject_hw_exception(TRAP_gp_fault, regs->error_code); + return; + } + if ( !(ar & _SEGMENT_P) ) + { + pv_inject_hw_exception(TRAP_no_segment, regs->error_code); + return; + } + dpl = (ar >> 13) & 3; + nparm = ar & 0x1f; + + /* + * Decode instruction (and perhaps operand) to determine RPL, + * whether this is a jump or a call, and the call return offset. + */ + if ( !read_descriptor(regs->cs, v, &ctxt.cs.base, &ctxt.cs.limit, + &ar, 0) || + !(ar & _SEGMENT_S) || + !(ar & _SEGMENT_P) || + !(ar & _SEGMENT_CODE) ) + { + pv_inject_hw_exception(TRAP_gp_fault, regs->error_code); + return; + } + + ctxt.ctxt.addr_size = ar & _SEGMENT_DB ? 32 : 16; + /* Leave zero in ctxt.ctxt.sp_size, as it's not needed for decoding. */ + state = x86_decode_insn(&ctxt.ctxt, gate_op_read); + ctxt.insn_fetch = false; + if ( IS_ERR_OR_NULL(state) ) + { + if ( PTR_ERR(state) == -X86EMUL_EXCEPTION ) + pv_inject_event(&ctxt.ctxt.event); + else + pv_inject_hw_exception(TRAP_gp_fault, regs->error_code); + return; + } + + switch ( ctxt.ctxt.opcode ) + { + unsigned int modrm_345; + + case 0xea: + ++jump; + /* fall through */ + case 0x9a: + ++jump; + opnd_sel = x86_insn_immediate(state, 1); + break; + case 0xff: + if ( x86_insn_modrm(state, NULL, &modrm_345) >= 3 ) + break; + switch ( modrm_345 & 7 ) + { + enum x86_segment seg; + + case 5: + ++jump; + /* fall through */ + case 3: + ++jump; + base = x86_insn_operand_ea(state, &seg); + rc = gate_op_read(seg, + base + (x86_insn_opsize(state) >> 3), + &opnd_sel, sizeof(opnd_sel), &ctxt.ctxt); + break; + } + break; + } + + insn_len = x86_insn_length(state, &ctxt.ctxt); + x86_emulate_free_state(state); + + if ( rc == X86EMUL_EXCEPTION ) + { + pv_inject_event(&ctxt.ctxt.event); + return; + } + + if ( rc != X86EMUL_OKAY || + jump < 0 || + (opnd_sel & ~3) != regs->error_code || + dpl < (opnd_sel & 3) ) + { + pv_inject_hw_exception(TRAP_gp_fault, regs->error_code); + return; + } + + if ( !read_descriptor(sel, v, &base, &limit, &ar, 0) || + !(ar & _SEGMENT_S) || + !(ar & _SEGMENT_CODE) || + (!jump || (ar & _SEGMENT_EC) ? + ((ar >> 13) & 3) > (regs->cs & 3) : + ((ar >> 13) & 3) != (regs->cs & 3)) ) + { + pv_inject_hw_exception(TRAP_gp_fault, sel); + return; + } + if ( !(ar & _SEGMENT_P) ) + { + pv_inject_hw_exception(TRAP_no_segment, sel); + return; + } + if ( off > limit ) + { + pv_inject_hw_exception(TRAP_gp_fault, 0); + return; + } + + if ( !jump ) + { + unsigned int ss, esp, *stkp; + int rc; +#define push(item) do \ + { \ + --stkp; \ + esp -= 4; \ + rc = __put_user(item, stkp); \ + if ( rc ) \ + { \ + pv_inject_page_fault(PFEC_write_access, \ + (unsigned long)(stkp + 1) - rc); \ + return; \ + } \ + } while ( 0 ) + + if ( ((ar >> 13) & 3) < (regs->cs & 3) ) + { + sel |= (ar >> 13) & 3; + /* Inner stack known only for kernel ring. */ + if ( (sel & 3) != GUEST_KERNEL_RPL(v->domain) ) + { + pv_inject_hw_exception(TRAP_gp_fault, regs->error_code); + return; + } + esp = v->arch.pv_vcpu.kernel_sp; + ss = v->arch.pv_vcpu.kernel_ss; + if ( (ss & 3) != (sel & 3) || + !read_descriptor(ss, v, &base, &limit, &ar, 0) || + ((ar >> 13) & 3) != (sel & 3) || + !(ar & _SEGMENT_S) || + (ar & _SEGMENT_CODE) || + !(ar & _SEGMENT_WR) ) + { + pv_inject_hw_exception(TRAP_invalid_tss, ss & ~3); + return; + } + if ( !(ar & _SEGMENT_P) || + !check_stack_limit(ar, limit, esp, (4 + nparm) * 4) ) + { + pv_inject_hw_exception(TRAP_stack_error, ss & ~3); + return; + } + stkp = (unsigned int *)(unsigned long)((unsigned int)base + esp); + if ( !compat_access_ok(stkp - 4 - nparm, (4 + nparm) * 4) ) + { + pv_inject_hw_exception(TRAP_gp_fault, regs->error_code); + return; + } + push(regs->ss); + push(regs->rsp); + if ( nparm ) + { + const unsigned int *ustkp; + + if ( !read_descriptor(regs->ss, v, &base, &limit, &ar, 0) || + ((ar >> 13) & 3) != (regs->cs & 3) || + !(ar & _SEGMENT_S) || + (ar & _SEGMENT_CODE) || + !(ar & _SEGMENT_WR) || + !check_stack_limit(ar, limit, esp + nparm * 4, nparm * 4) ) + return pv_inject_hw_exception(TRAP_gp_fault, regs->error_code); + ustkp = (unsigned int *)(unsigned long) + ((unsigned int)base + regs->esp + nparm * 4); + if ( !compat_access_ok(ustkp - nparm, nparm * 4) ) + { + pv_inject_hw_exception(TRAP_gp_fault, regs->error_code); + return; + } + do + { + unsigned int parm; + + --ustkp; + rc = __get_user(parm, ustkp); + if ( rc ) + { + pv_inject_page_fault(0, (unsigned long)(ustkp + 1) - rc); + return; + } + push(parm); + } while ( --nparm ); + } + } + else + { + sel |= (regs->cs & 3); + esp = regs->rsp; + ss = regs->ss; + if ( !read_descriptor(ss, v, &base, &limit, &ar, 0) || + ((ar >> 13) & 3) != (sel & 3) ) + { + pv_inject_hw_exception(TRAP_gp_fault, regs->error_code); + return; + } + if ( !check_stack_limit(ar, limit, esp, 2 * 4) ) + { + pv_inject_hw_exception(TRAP_stack_error, 0); + return; + } + stkp = (unsigned int *)(unsigned long)((unsigned int)base + esp); + if ( !compat_access_ok(stkp - 2, 2 * 4) ) + { + pv_inject_hw_exception(TRAP_gp_fault, regs->error_code); + return; + } + } + push(regs->cs); + push(regs->rip + insn_len); +#undef push + regs->rsp = esp; + regs->ss = ss; + } + else + sel |= (regs->cs & 3); + + regs->cs = sel; + instruction_done(regs, off); +} + /* * Local variables: * mode: C diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index cd43e9f44c..b55c425071 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -1590,447 +1590,6 @@ long do_fpu_taskswitch(int set) return 0; } -static int read_descriptor(unsigned int sel, - const struct vcpu *v, - unsigned long *base, - unsigned long *limit, - unsigned int *ar, - bool_t insn_fetch) -{ - struct desc_struct desc; - - if ( sel < 4) - desc.b = desc.a = 0; - else if ( __get_user(desc, - (const struct desc_struct *)(!(sel & 4) - ? GDT_VIRT_START(v) - : LDT_VIRT_START(v)) - + (sel >> 3)) ) - return 0; - if ( !insn_fetch ) - desc.b &= ~_SEGMENT_L; - - *ar = desc.b & 0x00f0ff00; - if ( !(desc.b & _SEGMENT_L) ) - { - *base = ((desc.a >> 16) + ((desc.b & 0xff) << 16) + - (desc.b & 0xff000000)); - *limit = (desc.a & 0xffff) | (desc.b & 0x000f0000); - if ( desc.b & _SEGMENT_G ) - *limit = ((*limit + 1) << 12) - 1; -#ifndef NDEBUG - if ( sel > 3 ) - { - unsigned int a, l; - unsigned char valid; - - asm volatile ( - "larl %2,%0 ; setz %1" - : "=r" (a), "=qm" (valid) : "rm" (sel)); - BUG_ON(valid && ((a & 0x00f0ff00) != *ar)); - asm volatile ( - "lsll %2,%0 ; setz %1" - : "=r" (l), "=qm" (valid) : "rm" (sel)); - BUG_ON(valid && (l != *limit)); - } -#endif - } - else - { - *base = 0UL; - *limit = ~0UL; - } - - return 1; -} - -static int read_gate_descriptor(unsigned int gate_sel, - const struct vcpu *v, - unsigned int *sel, - unsigned long *off, - unsigned int *ar) -{ - struct desc_struct desc; - const struct desc_struct *pdesc; - - - pdesc = (const struct desc_struct *) - (!(gate_sel & 4) ? GDT_VIRT_START(v) : LDT_VIRT_START(v)) - + (gate_sel >> 3); - if ( (gate_sel < 4) || - ((gate_sel >= FIRST_RESERVED_GDT_BYTE) && !(gate_sel & 4)) || - __get_user(desc, pdesc) ) - return 0; - - *sel = (desc.a >> 16) & 0x0000fffc; - *off = (desc.a & 0x0000ffff) | (desc.b & 0xffff0000); - *ar = desc.b & 0x0000ffff; - - /* - * check_descriptor() clears the DPL field and stores the - * guest requested DPL in the selector's RPL field. - */ - if ( *ar & _SEGMENT_DPL ) - return 0; - *ar |= (desc.a >> (16 - 13)) & _SEGMENT_DPL; - - if ( !is_pv_32bit_vcpu(v) ) - { - if ( (*ar & 0x1f00) != 0x0c00 || - (gate_sel >= FIRST_RESERVED_GDT_BYTE - 8 && !(gate_sel & 4)) || - __get_user(desc, pdesc + 1) || - (desc.b & 0x1f00) ) - return 0; - - *off |= (unsigned long)desc.a << 32; - return 1; - } - - switch ( *ar & 0x1f00 ) - { - case 0x0400: - *off &= 0xffff; - break; - case 0x0c00: - break; - default: - return 0; - } - - return 1; -} - -static inline int check_stack_limit(unsigned int ar, unsigned int limit, - unsigned int esp, unsigned int decr) -{ - return (((esp - decr) < (esp - 1)) && - (!(ar & _SEGMENT_EC) ? (esp - 1) <= limit : (esp - decr) > limit)); -} - -struct gate_op_ctxt { - struct x86_emulate_ctxt ctxt; - struct { - unsigned long base, limit; - } cs; - bool insn_fetch; -}; - -static int gate_op_read( - enum x86_segment seg, - unsigned long offset, - void *p_data, - unsigned int bytes, - struct x86_emulate_ctxt *ctxt) -{ - const struct gate_op_ctxt *goc = - container_of(ctxt, struct gate_op_ctxt, ctxt); - unsigned int rc = bytes, sel = 0; - unsigned long addr = offset, limit = 0; - - switch ( seg ) - { - case x86_seg_cs: - addr += goc->cs.base; - limit = goc->cs.limit; - break; - case x86_seg_ds: - sel = read_sreg(ds); - break; - case x86_seg_es: - sel = read_sreg(es); - break; - case x86_seg_fs: - sel = read_sreg(fs); - break; - case x86_seg_gs: - sel = read_sreg(gs); - break; - case x86_seg_ss: - sel = ctxt->regs->ss; - break; - default: - return X86EMUL_UNHANDLEABLE; - } - if ( sel ) - { - unsigned int ar; - - ASSERT(!goc->insn_fetch); - if ( !read_descriptor(sel, current, &addr, &limit, &ar, 0) || - !(ar & _SEGMENT_S) || - !(ar & _SEGMENT_P) || - ((ar & _SEGMENT_CODE) && !(ar & _SEGMENT_WR)) ) - return X86EMUL_UNHANDLEABLE; - addr += offset; - } - else if ( seg != x86_seg_cs ) - return X86EMUL_UNHANDLEABLE; - - /* We don't mean to emulate any branches. */ - if ( limit < bytes - 1 || offset > limit - bytes + 1 ) - return X86EMUL_UNHANDLEABLE; - - addr = (uint32_t)addr; - - if ( (rc = __copy_from_user(p_data, (void *)addr, bytes)) ) - { - /* - * TODO: This should report PFEC_insn_fetch when goc->insn_fetch && - * cpu_has_nx, but we'd then need a "fetch" variant of - * __copy_from_user() respecting NX, SMEP, and protection keys. - */ - x86_emul_pagefault(0, addr + bytes - rc, ctxt); - return X86EMUL_EXCEPTION; - } - - return X86EMUL_OKAY; -} - -static void emulate_gate_op(struct cpu_user_regs *regs) -{ - struct vcpu *v = current; - unsigned int sel, ar, dpl, nparm, insn_len; - struct gate_op_ctxt ctxt = { .ctxt.regs = regs, .insn_fetch = true }; - struct x86_emulate_state *state; - unsigned long off, base, limit; - uint16_t opnd_sel = 0; - int jump = -1, rc = X86EMUL_OKAY; - - /* Check whether this fault is due to the use of a call gate. */ - if ( !read_gate_descriptor(regs->error_code, v, &sel, &off, &ar) || - (((ar >> 13) & 3) < (regs->cs & 3)) || - ((ar & _SEGMENT_TYPE) != 0xc00) ) - { - pv_inject_hw_exception(TRAP_gp_fault, regs->error_code); - return; - } - if ( !(ar & _SEGMENT_P) ) - { - pv_inject_hw_exception(TRAP_no_segment, regs->error_code); - return; - } - dpl = (ar >> 13) & 3; - nparm = ar & 0x1f; - - /* - * Decode instruction (and perhaps operand) to determine RPL, - * whether this is a jump or a call, and the call return offset. - */ - if ( !read_descriptor(regs->cs, v, &ctxt.cs.base, &ctxt.cs.limit, - &ar, 0) || - !(ar & _SEGMENT_S) || - !(ar & _SEGMENT_P) || - !(ar & _SEGMENT_CODE) ) - { - pv_inject_hw_exception(TRAP_gp_fault, regs->error_code); - return; - } - - ctxt.ctxt.addr_size = ar & _SEGMENT_DB ? 32 : 16; - /* Leave zero in ctxt.ctxt.sp_size, as it's not needed for decoding. */ - state = x86_decode_insn(&ctxt.ctxt, gate_op_read); - ctxt.insn_fetch = false; - if ( IS_ERR_OR_NULL(state) ) - { - if ( PTR_ERR(state) == -X86EMUL_EXCEPTION ) - pv_inject_event(&ctxt.ctxt.event); - else - pv_inject_hw_exception(TRAP_gp_fault, regs->error_code); - return; - } - - switch ( ctxt.ctxt.opcode ) - { - unsigned int modrm_345; - - case 0xea: - ++jump; - /* fall through */ - case 0x9a: - ++jump; - opnd_sel = x86_insn_immediate(state, 1); - break; - case 0xff: - if ( x86_insn_modrm(state, NULL, &modrm_345) >= 3 ) - break; - switch ( modrm_345 & 7 ) - { - enum x86_segment seg; - - case 5: - ++jump; - /* fall through */ - case 3: - ++jump; - base = x86_insn_operand_ea(state, &seg); - rc = gate_op_read(seg, - base + (x86_insn_opsize(state) >> 3), - &opnd_sel, sizeof(opnd_sel), &ctxt.ctxt); - break; - } - break; - } - - insn_len = x86_insn_length(state, &ctxt.ctxt); - x86_emulate_free_state(state); - - if ( rc == X86EMUL_EXCEPTION ) - { - pv_inject_event(&ctxt.ctxt.event); - return; - } - - if ( rc != X86EMUL_OKAY || - jump < 0 || - (opnd_sel & ~3) != regs->error_code || - dpl < (opnd_sel & 3) ) - { - pv_inject_hw_exception(TRAP_gp_fault, regs->error_code); - return; - } - - if ( !read_descriptor(sel, v, &base, &limit, &ar, 0) || - !(ar & _SEGMENT_S) || - !(ar & _SEGMENT_CODE) || - (!jump || (ar & _SEGMENT_EC) ? - ((ar >> 13) & 3) > (regs->cs & 3) : - ((ar >> 13) & 3) != (regs->cs & 3)) ) - { - pv_inject_hw_exception(TRAP_gp_fault, sel); - return; - } - if ( !(ar & _SEGMENT_P) ) - { - pv_inject_hw_exception(TRAP_no_segment, sel); - return; - } - if ( off > limit ) - { - pv_inject_hw_exception(TRAP_gp_fault, 0); - return; - } - - if ( !jump ) - { - unsigned int ss, esp, *stkp; - int rc; -#define push(item) do \ - { \ - --stkp; \ - esp -= 4; \ - rc = __put_user(item, stkp); \ - if ( rc ) \ - { \ - pv_inject_page_fault(PFEC_write_access, \ - (unsigned long)(stkp + 1) - rc); \ - return; \ - } \ - } while ( 0 ) - - if ( ((ar >> 13) & 3) < (regs->cs & 3) ) - { - sel |= (ar >> 13) & 3; - /* Inner stack known only for kernel ring. */ - if ( (sel & 3) != GUEST_KERNEL_RPL(v->domain) ) - { - pv_inject_hw_exception(TRAP_gp_fault, regs->error_code); - return; - } - esp = v->arch.pv_vcpu.kernel_sp; - ss = v->arch.pv_vcpu.kernel_ss; - if ( (ss & 3) != (sel & 3) || - !read_descriptor(ss, v, &base, &limit, &ar, 0) || - ((ar >> 13) & 3) != (sel & 3) || - !(ar & _SEGMENT_S) || - (ar & _SEGMENT_CODE) || - !(ar & _SEGMENT_WR) ) - { - pv_inject_hw_exception(TRAP_invalid_tss, ss & ~3); - return; - } - if ( !(ar & _SEGMENT_P) || - !check_stack_limit(ar, limit, esp, (4 + nparm) * 4) ) - { - pv_inject_hw_exception(TRAP_stack_error, ss & ~3); - return; - } - stkp = (unsigned int *)(unsigned long)((unsigned int)base + esp); - if ( !compat_access_ok(stkp - 4 - nparm, (4 + nparm) * 4) ) - { - pv_inject_hw_exception(TRAP_gp_fault, regs->error_code); - return; - } - push(regs->ss); - push(regs->rsp); - if ( nparm ) - { - const unsigned int *ustkp; - - if ( !read_descriptor(regs->ss, v, &base, &limit, &ar, 0) || - ((ar >> 13) & 3) != (regs->cs & 3) || - !(ar & _SEGMENT_S) || - (ar & _SEGMENT_CODE) || - !(ar & _SEGMENT_WR) || - !check_stack_limit(ar, limit, esp + nparm * 4, nparm * 4) ) - return pv_inject_hw_exception(TRAP_gp_fault, regs->error_code); - ustkp = (unsigned int *)(unsigned long) - ((unsigned int)base + regs->esp + nparm * 4); - if ( !compat_access_ok(ustkp - nparm, nparm * 4) ) - { - pv_inject_hw_exception(TRAP_gp_fault, regs->error_code); - return; - } - do - { - unsigned int parm; - - --ustkp; - rc = __get_user(parm, ustkp); - if ( rc ) - { - pv_inject_page_fault(0, (unsigned long)(ustkp + 1) - rc); - return; - } - push(parm); - } while ( --nparm ); - } - } - else - { - sel |= (regs->cs & 3); - esp = regs->rsp; - ss = regs->ss; - if ( !read_descriptor(ss, v, &base, &limit, &ar, 0) || - ((ar >> 13) & 3) != (sel & 3) ) - { - pv_inject_hw_exception(TRAP_gp_fault, regs->error_code); - return; - } - if ( !check_stack_limit(ar, limit, esp, 2 * 4) ) - { - pv_inject_hw_exception(TRAP_stack_error, 0); - return; - } - stkp = (unsigned int *)(unsigned long)((unsigned int)base + esp); - if ( !compat_access_ok(stkp - 2, 2 * 4) ) - { - pv_inject_hw_exception(TRAP_gp_fault, regs->error_code); - return; - } - } - push(regs->cs); - push(regs->rip + insn_len); -#undef push - regs->rsp = esp; - regs->ss = ss; - } - else - sel |= (regs->cs & 3); - - regs->cs = sel; - instruction_done(regs, off); -} - void do_general_protection(struct cpu_user_regs *regs) { struct vcpu *v = current; diff --git a/xen/include/asm-x86/pv/traps.h b/xen/include/asm-x86/pv/traps.h index 32c7bac587..2d9f23dbde 100644 --- a/xen/include/asm-x86/pv/traps.h +++ b/xen/include/asm-x86/pv/traps.h @@ -26,12 +26,14 @@ #include <public/xen.h> int emulate_privileged_op(struct cpu_user_regs *regs); +void emulate_gate_op(struct cpu_user_regs *regs); #else /* !CONFIG_PV */ #include <xen/errno.h> int emulate_privileged_op(struct cpu_user_regs *regs) { return -EOPNOTSUPP; } +void emulate_gate_op(struct cpu_user_regs *regs) {} #endif /* CONFIG_PV */ -- 2.11.0 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |