From mboxrd@z Thu Jan 1 00:00:00 1970 From: "Jan Beulich" Subject: [PATCH 11/17] x86/PV: split out dealing with CRn from privileged instruction handling Date: Thu, 08 Sep 2016 07:17:02 -0600 Message-ID: <57D180EE020000780010D197@prv-mh.provo.novell.com> References: <57D17C78020000780010D127@prv-mh.provo.novell.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=__Part5462DFDE.1__=" Return-path: Received: from mail6.bemta6.messagelabs.com ([193.109.254.103]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1bhzCY-0001Sg-CW for xen-devel@lists.xenproject.org; Thu, 08 Sep 2016 13:17:10 +0000 In-Reply-To: <57D17C78020000780010D127@prv-mh.provo.novell.com> List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" To: xen-devel Cc: Andrew Cooper List-Id: xen-devel@lists.xenproject.org This is a MIME message. If you are reading this text, you may want to consider changing to a mail reader or gateway that understands how to properly handle MIME multipart messages. --=__Part5462DFDE.1__= Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: quoted-printable Content-Disposition: inline This is in preparation for using the generic emulator here. Signed-off-by: Jan Beulich --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -2242,6 +2242,107 @@ unsigned long guest_to_host_gpr_switch(u =20 void (*pv_post_outb_hook)(unsigned int port, u8 value); =20 +static int priv_op_read_cr(unsigned int reg, unsigned long *val, + struct x86_emulate_ctxt *ctxt) +{ + const struct vcpu *curr =3D current; + + switch ( reg ) + { + case 0: /* Read CR0 */ + *val =3D (read_cr0() & ~X86_CR0_TS) | curr->arch.pv_vcpu.ctrlreg[0= ]; + return X86EMUL_OKAY; + + case 2: /* Read CR2 */ + case 4: /* Read CR4 */ + *val =3D curr->arch.pv_vcpu.ctrlreg[reg]; + return X86EMUL_OKAY; + + case 3: /* Read CR3 */ + { + const struct domain *currd =3D curr->domain; + unsigned long mfn; + + if ( !is_pv_32bit_domain(currd) ) + { + mfn =3D pagetable_get_pfn(curr->arch.guest_table); + *val =3D xen_pfn_to_cr3(mfn_to_gmfn(currd, mfn)); + } + else + { + l4_pgentry_t *pl4e =3D + map_domain_page(_mfn(pagetable_get_pfn(curr->arch.guest_ta= ble))); + + mfn =3D l4e_get_pfn(*pl4e); + unmap_domain_page(pl4e); + *val =3D compat_pfn_to_cr3(mfn_to_gmfn(currd, mfn)); + } + /* PTs should not be shared */ + BUG_ON(page_get_owner(mfn_to_page(mfn)) =3D=3D dom_cow); + return X86EMUL_OKAY; + } + } + + return X86EMUL_UNHANDLEABLE; +} + +static int priv_op_write_cr(unsigned int reg, unsigned long val, + struct x86_emulate_ctxt *ctxt) +{ + struct vcpu *curr =3D current; + + switch ( reg ) + { + case 0: /* Write CR0 */ + if ( (val ^ read_cr0()) & ~X86_CR0_TS ) + { + gdprintk(XENLOG_WARNING, + "Attempt to change unmodifiable CR0 flags\n"); + break; + } + do_fpu_taskswitch(!!(val & X86_CR0_TS)); + return X86EMUL_OKAY; + + case 2: /* Write CR2 */ + curr->arch.pv_vcpu.ctrlreg[2] =3D val; + arch_set_cr2(curr, val); + return X86EMUL_OKAY; + + case 3: /* Write CR3 */ + { + struct domain *currd =3D curr->domain; + unsigned long gfn; + struct page_info *page; + int rc; + + gfn =3D !is_pv_32bit_domain(currd) + ? xen_cr3_to_pfn(val) : compat_cr3_to_pfn(val); + page =3D get_page_from_gfn(currd, gfn, NULL, P2M_ALLOC); + if ( !page ) + break; + rc =3D new_guest_cr3(page_to_mfn(page)); + put_page(page); + + switch ( rc ) + { + case 0: + return X86EMUL_OKAY; + case -ERESTART: /* retry after preemption */ + return X86EMUL_RETRY; + } + break; + } + + case 4: /* Write CR4 */ + curr->arch.pv_vcpu.ctrlreg[4] =3D pv_guest_cr4_fixup(curr, val); + write_cr4(pv_guest_cr4_to_real_cr4(curr)); + ctxt_switch_levelling(curr); + return X86EMUL_OKAY; + } + + return X86EMUL_UNHANDLEABLE; +} + static inline uint64_t guest_misc_enable(uint64_t val) { val &=3D ~(MSR_IA32_MISC_ENABLE_PERF_AVAIL | @@ -2654,48 +2755,9 @@ static int emulate_privileged_op(struct goto fail; modrm_reg +=3D ((opcode >> 3) & 7) + (lock << 3); modrm_rm |=3D (opcode >> 0) & 7; - reg =3D decode_register(modrm_rm, regs, 0); - switch ( modrm_reg ) - { - case 0: /* Read CR0 */ - *reg =3D (read_cr0() & ~X86_CR0_TS) | - v->arch.pv_vcpu.ctrlreg[0]; - break; - - case 2: /* Read CR2 */ - *reg =3D v->arch.pv_vcpu.ctrlreg[2]; - break; - =20 - case 3: /* Read CR3 */ - { - unsigned long mfn; - =20 - if ( !is_pv_32bit_domain(currd) ) - { - mfn =3D pagetable_get_pfn(v->arch.guest_table); - *reg =3D xen_pfn_to_cr3(mfn_to_gmfn(currd, mfn)); - } - else - { - l4_pgentry_t *pl4e =3D - map_domain_page(_mfn(pagetable_get_pfn(v->arch.guest_t= able))); - - mfn =3D l4e_get_pfn(*pl4e); - unmap_domain_page(pl4e); - *reg =3D compat_pfn_to_cr3(mfn_to_gmfn(currd, mfn)); - } - /* PTs should not be shared */ - BUG_ON(page_get_owner(mfn_to_page(mfn)) =3D=3D dom_cow); - } - break; - - case 4: /* Read CR4 */ - *reg =3D v->arch.pv_vcpu.ctrlreg[4]; - break; - - default: + if ( priv_op_read_cr(modrm_reg, decode_register(modrm_rm, regs, = 0), + NULL) !=3D X86EMUL_OKAY ) goto fail; - } break; =20 case 0x21: /* MOV DR?, */ { @@ -2719,56 +2781,12 @@ static int emulate_privileged_op(struct modrm_reg +=3D ((opcode >> 3) & 7) + (lock << 3); modrm_rm |=3D (opcode >> 0) & 7; reg =3D decode_register(modrm_rm, regs, 0); - switch ( modrm_reg ) + switch ( priv_op_write_cr(modrm_reg, *reg, NULL) ) { - case 0: /* Write CR0 */ - if ( (*reg ^ read_cr0()) & ~X86_CR0_TS ) - { - gdprintk(XENLOG_WARNING, - "Attempt to change unmodifiable CR0 flags.\n"); - goto fail; - } - (void)do_fpu_taskswitch(!!(*reg & X86_CR0_TS)); - break; - - case 2: /* Write CR2 */ - v->arch.pv_vcpu.ctrlreg[2] =3D *reg; - arch_set_cr2(v, *reg); - break; - - case 3: {/* Write CR3 */ - unsigned long gfn; - struct page_info *page; - - gfn =3D !is_pv_32bit_domain(currd) - ? xen_cr3_to_pfn(*reg) : compat_cr3_to_pfn(*reg); - page =3D get_page_from_gfn(currd, gfn, NULL, P2M_ALLOC); - if ( page ) - { - rc =3D new_guest_cr3(page_to_mfn(page)); - put_page(page); - } - else - rc =3D -EINVAL; - - switch ( rc ) - { - case 0: - break; - case -ERESTART: /* retry after preemption */ - goto skip; - default: /* not okay */ - goto fail; - } + case X86EMUL_OKAY: break; - } - - case 4: /* Write CR4 */ - v->arch.pv_vcpu.ctrlreg[4] =3D pv_guest_cr4_fixup(v, *reg); - write_cr4(pv_guest_cr4_to_real_cr4(v)); - ctxt_switch_levelling(v); - break; - + case X86EMUL_RETRY: /* retry after preemption */ + goto skip; default: goto fail; } --=__Part5462DFDE.1__= Content-Type: text/plain; name="x86-PV-priv-op-split-CR.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="x86-PV-priv-op-split-CR.patch" x86/PV: split out dealing with CRn from privileged instruction handling=0A= =0AThis is in preparation for using the generic emulator here.=0A=0ASigned-= off-by: Jan Beulich =0A=0A--- a/xen/arch/x86/traps.c=0A+= ++ b/xen/arch/x86/traps.c=0A@@ -2242,6 +2242,107 @@ unsigned long = guest_to_host_gpr_switch(u=0A =0A void (*pv_post_outb_hook)(unsigned int = port, u8 value);=0A =0A+static int priv_op_read_cr(unsigned int reg, = unsigned long *val,=0A+ struct x86_emulate_ctxt = *ctxt)=0A+{=0A+ const struct vcpu *curr =3D current;=0A+=0A+ switch = ( reg )=0A+ {=0A+ case 0: /* Read CR0 */=0A+ *val =3D = (read_cr0() & ~X86_CR0_TS) | curr->arch.pv_vcpu.ctrlreg[0];=0A+ = return X86EMUL_OKAY;=0A+=0A+ case 2: /* Read CR2 */=0A+ case 4: /* = Read CR4 */=0A+ *val =3D curr->arch.pv_vcpu.ctrlreg[reg];=0A+ = return X86EMUL_OKAY;=0A+=0A+ case 3: /* Read CR3 */=0A+ {=0A+ = const struct domain *currd =3D curr->domain;=0A+ unsigned long = mfn;=0A+=0A+ if ( !is_pv_32bit_domain(currd) )=0A+ {=0A+ = mfn =3D pagetable_get_pfn(curr->arch.guest_table);=0A+ = *val =3D xen_pfn_to_cr3(mfn_to_gmfn(currd, mfn));=0A+ }=0A+ = else=0A+ {=0A+ l4_pgentry_t *pl4e =3D=0A+ = map_domain_page(_mfn(pagetable_get_pfn(curr->arch.guest_table)));=0A+=0A+ = mfn =3D l4e_get_pfn(*pl4e);=0A+ unmap_domain_page(pl4e= );=0A+ *val =3D compat_pfn_to_cr3(mfn_to_gmfn(currd, mfn));=0A+ = }=0A+ /* PTs should not be shared */=0A+ BUG_ON(page_g= et_owner(mfn_to_page(mfn)) =3D=3D dom_cow);=0A+ return X86EMUL_OKAY;= =0A+ }=0A+ }=0A+=0A+ return X86EMUL_UNHANDLEABLE;=0A+}=0A+=0A+stat= ic int priv_op_write_cr(unsigned int reg, unsigned long val,=0A+ = struct x86_emulate_ctxt *ctxt)=0A+{=0A+ struct vcpu = *curr =3D current;=0A+=0A+ switch ( reg )=0A+ {=0A+ case 0: /* = Write CR0 */=0A+ if ( (val ^ read_cr0()) & ~X86_CR0_TS )=0A+ = {=0A+ gdprintk(XENLOG_WARNING,=0A+ "Attempt = to change unmodifiable CR0 flags\n");=0A+ break;=0A+ = }=0A+ do_fpu_taskswitch(!!(val & X86_CR0_TS));=0A+ return = X86EMUL_OKAY;=0A+=0A+ case 2: /* Write CR2 */=0A+ curr->arch.pv_v= cpu.ctrlreg[2] =3D val;=0A+ arch_set_cr2(curr, val);=0A+ = return X86EMUL_OKAY;=0A+=0A+ case 3: /* Write CR3 */=0A+ {=0A+ = struct domain *currd =3D curr->domain;=0A+ unsigned long gfn;=0A+ = struct page_info *page;=0A+ int rc;=0A+=0A+ gfn =3D = !is_pv_32bit_domain(currd)=0A+ ? xen_cr3_to_pfn(val) : = compat_cr3_to_pfn(val);=0A+ page =3D get_page_from_gfn(currd, gfn, = NULL, P2M_ALLOC);=0A+ if ( !page )=0A+ break;=0A+ = rc =3D new_guest_cr3(page_to_mfn(page));=0A+ put_page(page);=0A+=0A+= switch ( rc )=0A+ {=0A+ case 0:=0A+ = return X86EMUL_OKAY;=0A+ case -ERESTART: /* retry after preemption = */=0A+ return X86EMUL_RETRY;=0A+ }=0A+ break;=0A+ = }=0A+=0A+ case 4: /* Write CR4 */=0A+ curr->arch.pv_vcpu.ctrlr= eg[4] =3D pv_guest_cr4_fixup(curr, val);=0A+ write_cr4(pv_guest_cr4_= to_real_cr4(curr));=0A+ ctxt_switch_levelling(curr);=0A+ = return X86EMUL_OKAY;=0A+ }=0A+=0A+ return X86EMUL_UNHANDLEABLE;=0A+}= =0A+=0A static inline uint64_t guest_misc_enable(uint64_t val)=0A {=0A = val &=3D ~(MSR_IA32_MISC_ENABLE_PERF_AVAIL |=0A@@ -2654,48 +2755,9 @@ = static int emulate_privileged_op(struct=0A goto fail;=0A = modrm_reg +=3D ((opcode >> 3) & 7) + (lock << 3);=0A modrm_rm = |=3D (opcode >> 0) & 7;=0A- reg =3D decode_register(modrm_rm, regs, = 0);=0A- switch ( modrm_reg )=0A- {=0A- case 0: /* = Read CR0 */=0A- *reg =3D (read_cr0() & ~X86_CR0_TS) |=0A- = v->arch.pv_vcpu.ctrlreg[0];=0A- break;=0A-=0A- = case 2: /* Read CR2 */=0A- *reg =3D v->arch.pv_vcpu.ctrlreg[2];= =0A- break;=0A- =0A- case 3: /* Read CR3 = */=0A- {=0A- unsigned long mfn;=0A- =0A- = if ( !is_pv_32bit_domain(currd) )=0A- {=0A- = mfn =3D pagetable_get_pfn(v->arch.guest_table);=0A- *reg = =3D xen_pfn_to_cr3(mfn_to_gmfn(currd, mfn));=0A- }=0A- = else=0A- {=0A- l4_pgentry_t *pl4e =3D=0A- = map_domain_page(_mfn(pagetable_get_pfn(v->arch.guest_table)))= ;=0A-=0A- mfn =3D l4e_get_pfn(*pl4e);=0A- = unmap_domain_page(pl4e);=0A- *reg =3D compat_pfn_to_cr3(mfn_= to_gmfn(currd, mfn));=0A- }=0A- /* PTs should not be = shared */=0A- BUG_ON(page_get_owner(mfn_to_page(mfn)) =3D=3D = dom_cow);=0A- }=0A- break;=0A-=0A- case 4: /* Read = CR4 */=0A- *reg =3D v->arch.pv_vcpu.ctrlreg[4];=0A- = break;=0A-=0A- default:=0A+ if ( priv_op_read_cr(modrm_reg, = decode_register(modrm_rm, regs, 0),=0A+ NULL) = !=3D X86EMUL_OKAY )=0A goto fail;=0A- }=0A = break;=0A =0A case 0x21: /* MOV DR?, */ {=0A@@ -2719,56 +2781,12 = @@ static int emulate_privileged_op(struct=0A modrm_reg +=3D = ((opcode >> 3) & 7) + (lock << 3);=0A modrm_rm |=3D (opcode >> 0) = & 7;=0A reg =3D decode_register(modrm_rm, regs, 0);=0A- = switch ( modrm_reg )=0A+ switch ( priv_op_write_cr(modrm_reg, *reg, = NULL) )=0A {=0A- case 0: /* Write CR0 */=0A- if = ( (*reg ^ read_cr0()) & ~X86_CR0_TS )=0A- {=0A- = gdprintk(XENLOG_WARNING,=0A- "Attempt to change = unmodifiable CR0 flags.\n");=0A- goto fail;=0A- = }=0A- (void)do_fpu_taskswitch(!!(*reg & X86_CR0_TS));=0A- = break;=0A-=0A- case 2: /* Write CR2 */=0A- = v->arch.pv_vcpu.ctrlreg[2] =3D *reg;=0A- arch_set_cr2(v, = *reg);=0A- break;=0A-=0A- case 3: {/* Write CR3 */=0A- = unsigned long gfn;=0A- struct page_info *page;=0A-=0A- = gfn =3D !is_pv_32bit_domain(currd)=0A- ? = xen_cr3_to_pfn(*reg) : compat_cr3_to_pfn(*reg);=0A- page =3D = get_page_from_gfn(currd, gfn, NULL, P2M_ALLOC);=0A- if ( page = )=0A- {=0A- rc =3D new_guest_cr3(page_to_mfn(page= ));=0A- put_page(page);=0A- }=0A- = else=0A- rc =3D -EINVAL;=0A-=0A- switch ( rc = )=0A- {=0A- case 0:=0A- break;=0A- = case -ERESTART: /* retry after preemption */=0A- = goto skip;=0A- default: /* not okay */=0A- = goto fail;=0A- }=0A+ case X86EMUL_OKAY:=0A = break;=0A- }=0A-=0A- case 4: /* Write CR4 */=0A- = v->arch.pv_vcpu.ctrlreg[4] =3D pv_guest_cr4_fixup(v, *reg);=0A- = write_cr4(pv_guest_cr4_to_real_cr4(v));=0A- ctxt_switch_levellin= g(v);=0A- break;=0A-=0A+ case X86EMUL_RETRY: /* retry = after preemption */=0A+ goto skip;=0A default:=0A = goto fail;=0A }=0A --=__Part5462DFDE.1__= Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: base64 Content-Disposition: inline X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18KWGVuLWRldmVs IG1haWxpbmcgbGlzdApYZW4tZGV2ZWxAbGlzdHMueGVuLm9yZwpodHRwczovL2xpc3RzLnhlbi5v cmcveGVuLWRldmVsCg== --=__Part5462DFDE.1__=--