diff options
Diffstat (limited to 'arch/x86/kvm/emulate.c')
| -rw-r--r-- | arch/x86/kvm/emulate.c | 76 | 
1 files changed, 39 insertions, 37 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index b3705ae52824..4c4f4263420c 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -812,6 +812,19 @@ static inline int jmp_rel(struct x86_emulate_ctxt *ctxt, int rel)  	return assign_eip_near(ctxt, ctxt->_eip + rel);  } +static int linear_read_system(struct x86_emulate_ctxt *ctxt, ulong linear, +			      void *data, unsigned size) +{ +	return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception, true); +} + +static int linear_write_system(struct x86_emulate_ctxt *ctxt, +			       ulong linear, void *data, +			       unsigned int size) +{ +	return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception, true); +} +  static int segmented_read_std(struct x86_emulate_ctxt *ctxt,  			      struct segmented_address addr,  			      void *data, @@ -823,7 +836,7 @@ static int segmented_read_std(struct x86_emulate_ctxt *ctxt,  	rc = linearize(ctxt, addr, size, false, &linear);  	if (rc != X86EMUL_CONTINUE)  		return rc; -	return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception); +	return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception, false);  }  static int segmented_write_std(struct x86_emulate_ctxt *ctxt, @@ -837,7 +850,7 @@ static int segmented_write_std(struct x86_emulate_ctxt *ctxt,  	rc = linearize(ctxt, addr, size, true, &linear);  	if (rc != X86EMUL_CONTINUE)  		return rc; -	return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception); +	return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception, false);  }  /* @@ -1496,8 +1509,7 @@ static int read_interrupt_descriptor(struct x86_emulate_ctxt *ctxt,  		return emulate_gp(ctxt, index << 3 | 0x2);  	addr = dt.address + index * 8; -	return ctxt->ops->read_std(ctxt, addr, desc, sizeof *desc, -				   &ctxt->exception); +	return linear_read_system(ctxt, addr, desc, sizeof *desc);  }  static void get_descriptor_table_ptr(struct x86_emulate_ctxt *ctxt, @@ -1560,8 +1572,7 @@ static int read_segment_descriptor(struct x86_emulate_ctxt *ctxt,  	if (rc != X86EMUL_CONTINUE)  		return rc; -	return ctxt->ops->read_std(ctxt, *desc_addr_p, desc, sizeof(*desc), -				   &ctxt->exception); +	return linear_read_system(ctxt, *desc_addr_p, desc, sizeof(*desc));  }  /* allowed just for 8 bytes segments */ @@ -1575,8 +1586,7 @@ static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt,  	if (rc != X86EMUL_CONTINUE)  		return rc; -	return ctxt->ops->write_std(ctxt, addr, desc, sizeof *desc, -				    &ctxt->exception); +	return linear_write_system(ctxt, addr, desc, sizeof *desc);  }  static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt, @@ -1737,8 +1747,7 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt,  				return ret;  		}  	} else if (ctxt->mode == X86EMUL_MODE_PROT64) { -		ret = ctxt->ops->read_std(ctxt, desc_addr+8, &base3, -				sizeof(base3), &ctxt->exception); +		ret = linear_read_system(ctxt, desc_addr+8, &base3, sizeof(base3));  		if (ret != X86EMUL_CONTINUE)  			return ret;  		if (emul_is_noncanonical_address(get_desc_base(&seg_desc) | @@ -2051,11 +2060,11 @@ static int __emulate_int_real(struct x86_emulate_ctxt *ctxt, int irq)  	eip_addr = dt.address + (irq << 2);  	cs_addr = dt.address + (irq << 2) + 2; -	rc = ops->read_std(ctxt, cs_addr, &cs, 2, &ctxt->exception); +	rc = linear_read_system(ctxt, cs_addr, &cs, 2);  	if (rc != X86EMUL_CONTINUE)  		return rc; -	rc = ops->read_std(ctxt, eip_addr, &eip, 2, &ctxt->exception); +	rc = linear_read_system(ctxt, eip_addr, &eip, 2);  	if (rc != X86EMUL_CONTINUE)  		return rc; @@ -2919,12 +2928,12 @@ static bool emulator_io_port_access_allowed(struct x86_emulate_ctxt *ctxt,  #ifdef CONFIG_X86_64  	base |= ((u64)base3) << 32;  #endif -	r = ops->read_std(ctxt, base + 102, &io_bitmap_ptr, 2, NULL); +	r = ops->read_std(ctxt, base + 102, &io_bitmap_ptr, 2, NULL, true);  	if (r != X86EMUL_CONTINUE)  		return false;  	if (io_bitmap_ptr + port/8 > desc_limit_scaled(&tr_seg))  		return false; -	r = ops->read_std(ctxt, base + io_bitmap_ptr + port/8, &perm, 2, NULL); +	r = ops->read_std(ctxt, base + io_bitmap_ptr + port/8, &perm, 2, NULL, true);  	if (r != X86EMUL_CONTINUE)  		return false;  	if ((perm >> bit_idx) & mask) @@ -3053,35 +3062,30 @@ static int task_switch_16(struct x86_emulate_ctxt *ctxt,  			  u16 tss_selector, u16 old_tss_sel,  			  ulong old_tss_base, struct desc_struct *new_desc)  { -	const struct x86_emulate_ops *ops = ctxt->ops;  	struct tss_segment_16 tss_seg;  	int ret;  	u32 new_tss_base = get_desc_base(new_desc); -	ret = ops->read_std(ctxt, old_tss_base, &tss_seg, sizeof tss_seg, -			    &ctxt->exception); +	ret = linear_read_system(ctxt, old_tss_base, &tss_seg, sizeof tss_seg);  	if (ret != X86EMUL_CONTINUE)  		return ret;  	save_state_to_tss16(ctxt, &tss_seg); -	ret = ops->write_std(ctxt, old_tss_base, &tss_seg, sizeof tss_seg, -			     &ctxt->exception); +	ret = linear_write_system(ctxt, old_tss_base, &tss_seg, sizeof tss_seg);  	if (ret != X86EMUL_CONTINUE)  		return ret; -	ret = ops->read_std(ctxt, new_tss_base, &tss_seg, sizeof tss_seg, -			    &ctxt->exception); +	ret = linear_read_system(ctxt, new_tss_base, &tss_seg, sizeof tss_seg);  	if (ret != X86EMUL_CONTINUE)  		return ret;  	if (old_tss_sel != 0xffff) {  		tss_seg.prev_task_link = old_tss_sel; -		ret = ops->write_std(ctxt, new_tss_base, -				     &tss_seg.prev_task_link, -				     sizeof tss_seg.prev_task_link, -				     &ctxt->exception); +		ret = linear_write_system(ctxt, new_tss_base, +					  &tss_seg.prev_task_link, +					  sizeof tss_seg.prev_task_link);  		if (ret != X86EMUL_CONTINUE)  			return ret;  	} @@ -3197,38 +3201,34 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt,  			  u16 tss_selector, u16 old_tss_sel,  			  ulong old_tss_base, struct desc_struct *new_desc)  { -	const struct x86_emulate_ops *ops = ctxt->ops;  	struct tss_segment_32 tss_seg;  	int ret;  	u32 new_tss_base = get_desc_base(new_desc);  	u32 eip_offset = offsetof(struct tss_segment_32, eip);  	u32 ldt_sel_offset = offsetof(struct tss_segment_32, ldt_selector); -	ret = ops->read_std(ctxt, old_tss_base, &tss_seg, sizeof tss_seg, -			    &ctxt->exception); +	ret = linear_read_system(ctxt, old_tss_base, &tss_seg, sizeof tss_seg);  	if (ret != X86EMUL_CONTINUE)  		return ret;  	save_state_to_tss32(ctxt, &tss_seg);  	/* Only GP registers and segment selectors are saved */ -	ret = ops->write_std(ctxt, old_tss_base + eip_offset, &tss_seg.eip, -			     ldt_sel_offset - eip_offset, &ctxt->exception); +	ret = linear_write_system(ctxt, old_tss_base + eip_offset, &tss_seg.eip, +				  ldt_sel_offset - eip_offset);  	if (ret != X86EMUL_CONTINUE)  		return ret; -	ret = ops->read_std(ctxt, new_tss_base, &tss_seg, sizeof tss_seg, -			    &ctxt->exception); +	ret = linear_read_system(ctxt, new_tss_base, &tss_seg, sizeof tss_seg);  	if (ret != X86EMUL_CONTINUE)  		return ret;  	if (old_tss_sel != 0xffff) {  		tss_seg.prev_task_link = old_tss_sel; -		ret = ops->write_std(ctxt, new_tss_base, -				     &tss_seg.prev_task_link, -				     sizeof tss_seg.prev_task_link, -				     &ctxt->exception); +		ret = linear_write_system(ctxt, new_tss_base, +					  &tss_seg.prev_task_link, +					  sizeof tss_seg.prev_task_link);  		if (ret != X86EMUL_CONTINUE)  			return ret;  	} @@ -4189,7 +4189,9 @@ static int check_cr_write(struct x86_emulate_ctxt *ctxt)  				maxphyaddr = eax & 0xff;  			else  				maxphyaddr = 36; -			rsvd = rsvd_bits(maxphyaddr, 62); +			rsvd = rsvd_bits(maxphyaddr, 63); +			if (ctxt->ops->get_cr(ctxt, 4) & X86_CR4_PCIDE) +				rsvd &= ~CR3_PCID_INVD;  		}  		if (new_val & rsvd)  |