public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
From: Marcelo Tosatti <mtosatti@redhat.com>
To: Guillaume Thouvenin <guillaume.thouvenin@ext.bull.net>
Cc: kvm-devel@lists.sourceforge.net,
	Mohammed Gamal <m.gamal005@gmail.com>,
	Avi Kivity <avi@qumranet.com>
Subject: Re: Protected mode transitions and big real mode... still an issue
Date: Wed, 14 May 2008 18:29:53 -0300	[thread overview]
Message-ID: <20080514212953.GA17705@dmt> (raw)
In-Reply-To: <20080514092911.561872d4@frecb000711.frec.bull.fr>

Hi Guillaume,

On Wed, May 14, 2008 at 09:29:11AM +0200, Guillaume Thouvenin wrote:
> On Tue, 6 May 2008 20:05:39 +0300
> "Mohammed Gamal" <m.gamal005@gmail.com> wrote:
> 
> 
> > > > > WinXP fails with the patch applied too. Ubuntu 7.10 live CD and
> > > > > FreeDOS don't boot but complain about instruction mov 0x11,sreg not
> > > > > being emulated.
> 
> Mohammed, can you try the patch at the end of this mail? Here it's
> working with FreeDOS now (I added the emulation of 0x90 that is an xchg
> instruction). I can also boot winXP Professional X64 edition. I still
> have a weird issue with Ubuntu 7.10 that crashes sometimes with the
> error:
> 
> kvm_run: failed entry, reason 5
> kvm_run returned -8
> 
> It's a little bit strange because this error appears very often with
> the wmii window manager but never with XFCE. And with wmii, it only
> occurs when I move the mouse above the Qemu/KVM window. If I wait 30s
> until the automatic boot it works... 

This appears to be due to the vmport save/load bug:
https://bugs.launchpad.net/ubuntu/+source/kvm/+bug/219165 

I'll look into it if nobody beats me to it.

Regarding FreeDOS, it necessary to emulate software interrupts and NOP
to get the "HIMEM XMS-memory driver" version to boot (with the FreeOSZOO
image).

The "maximum RAM free, using EMM86" version is more complicated, requiring 
ldt, ltr and a few other things.

There are two problems remaining:

1) add is storing the result in the wrong register

    6486:       66 64 89 3e 72 01       mov    %edi,%fs:0x172
    648c:       66 be 8d 03 00 00       mov    $0x38d,%esi
    6492:       66 c1 e6 04             shl    $0x4,%esi
    6496:       66 b8 98 0a 00 00       mov    $0xa98,%eax
    649c:       66 03 f0                add    %eax,%esi

The destination for the add is "%esi", but the emulation stores the 
result in eax, because:

                if ((c->d & ModRM) && c->modrm_mod == 3) {
                        u8 reg;
                        c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
                        c->dst.ptr = decode_register(c->modrm_rm, c->regs, c->d & ByteOp);
                }

modrm_reg contains "6", which is the correct register index, but
modrm_rm contains 0, so the result is stored in "eax" (see hack).

2) iretl generates pagefaults

  1226df:       0f 06                   clts
  1226e1:       b8 14 00                mov    $0x14,%ax
  1226e4:       8e e0                   mov    %ax,%fs
  1226e6:       66 64 a1 50 01          mov    %fs:0x150,%eax
  1226eb:       0f 22 d8                mov    %eax,%cr3
  1226ee:       0f 20 c0                mov    %cr0,%eax
  1226f1:       66 0d 00 00 00 80       or     $0x80000000,%eax
  1226f7:       0f 22 c0                mov    %eax,%cr0
  1226fa:       66 cf                   iretl

The iretl which happens after enabling paging faults in different ways:

kvm_inject_page_fault: EIP=1226fa
kvm_inject_page_fault: ADDR=1226fa

kvm_inject_page_fault: EIP=1226fa
kvm_inject_page_fault: ADDR=1237d1
kvm: inject_page_fault: double fault 0x1237d1


Index: kvm.tip/arch/x86/kvm/vmx.c
===================================================================
--- kvm.tip.orig/arch/x86/kvm/vmx.c
+++ kvm.tip/arch/x86/kvm/vmx.c
@@ -194,6 +194,12 @@ static inline int is_external_interrupt(
 		== (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
 }
 
+static inline int is_software_interrupt(u32 intr_info)
+{
+	return (intr_info & (INTR_TYPE_SOFT_INTR | INTR_INFO_VALID_MASK))
+		== (INTR_TYPE_SOFT_INTR | INTR_INFO_VALID_MASK);
+}
+
 static inline int cpu_has_vmx_msr_bitmap(void)
 {
 	return (vmcs_config.cpu_based_exec_ctrl & CPU_BASED_USE_MSR_BITMAPS);
@@ -2190,8 +2196,10 @@ static void kvm_guest_debug_pre(struct k
 }
 
 static int handle_rmode_exception(struct kvm_vcpu *vcpu,
-				  int vec, u32 err_code)
+				  u32 intr_info, u32 err_code)
 {
+	int vec = intr_info & INTR_INFO_VECTOR_MASK;
+
 	if (!vcpu->arch.rmode.active)
 		return 0;
 
@@ -2202,6 +2210,10 @@ static int handle_rmode_exception(struct
 	if (((vec == GP_VECTOR) || (vec == SS_VECTOR)) && err_code == 0)
 		if (emulate_instruction(vcpu, NULL, 0, 0, 0) == EMULATE_DONE)
 			return 1;
+	if (is_software_interrupt(intr_info) && err_code == 0) {
+		if (emulate_instruction(vcpu, NULL, 0, 0, 0) == EMULATE_DONE)
+			return 1;
+		}
 	return 0;
 }
 
@@ -2257,8 +2269,7 @@ static int handle_exception(struct kvm_v
 	}
 
 	if (vcpu->arch.rmode.active &&
-	    handle_rmode_exception(vcpu, intr_info & INTR_INFO_VECTOR_MASK,
-								error_code)) {
+	    handle_rmode_exception(vcpu, intr_info, error_code)) {
 		if (vcpu->arch.halt_request) {
 			vcpu->arch.halt_request = 0;
 			return kvm_emulate_halt(vcpu);
Index: kvm.tip/arch/x86/kvm/x86.c
===================================================================
--- kvm.tip.orig/arch/x86/kvm/x86.c
+++ kvm.tip/arch/x86/kvm/x86.c
@@ -3294,13 +3294,21 @@ int load_segment_descriptor(struct kvm_v
 
 	if (load_segment_descriptor_to_kvm_desct(vcpu, selector, &kvm_seg))
 		return 1;
-	kvm_seg.type |= type_bits;
 
 	if (seg != VCPU_SREG_SS && seg != VCPU_SREG_CS &&
 	    seg != VCPU_SREG_LDTR)
 		if (!kvm_seg.s)
 			kvm_seg.unusable = 1;
 
+	if (seg == VCPU_SREG_CS && !kvm_seg.s) {
+		switch (kvm_seg.type) {
+		case 9: /* TSS */
+			return kvm_task_switch(vcpu, selector, TASK_SWITCH_JMP);
+		default:
+		}
+	}
+
+	kvm_seg.type |= type_bits;
 	set_segment(vcpu, &kvm_seg, seg);
 	return 0;
 }
Index: kvm.tip/arch/x86/kvm/x86_emulate.c
===================================================================
--- kvm.tip.orig/arch/x86/kvm/x86_emulate.c
+++ kvm.tip/arch/x86/kvm/x86_emulate.c
@@ -99,7 +99,7 @@ static u16 opcode_table[256] = {
 	/* 0x28 - 0x2F */
 	ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
 	ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
-	0, 0, 0, 0,
+	DstReg | SrcImm, DstReg | SrcImm, 0, 0,
 	/* 0x30 - 0x37 */
 	ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
 	ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
@@ -107,7 +107,7 @@ static u16 opcode_table[256] = {
 	/* 0x38 - 0x3F */
 	ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
 	ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
-	0, 0, 0, 0,
+	0, ByteOp | DstReg | SrcImm, 0, 0,
 	/* 0x40 - 0x47 */
 	DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg,
 	/* 0x48 - 0x4F */
@@ -154,8 +154,10 @@ static u16 opcode_table[256] = {
 	ByteOp | ImplicitOps | Mov | String, ImplicitOps | Mov | String,
 	ByteOp | ImplicitOps | String, ImplicitOps | String,
 	/* 0xB0 - 0xBF */
-	0, 0, 0, 0, 0, 0, 0, 0,
 	DstReg | SrcImm | Mov, 0, 0, 0, 0, 0, 0, 0,
+	DstReg | SrcImm | Mov, DstReg | SrcImm | Mov, DstReg | SrcImm | Mov,
+	DstReg | SrcImm | Mov, DstReg | SrcImm | Mov, DstReg | SrcImm | Mov,
+	DstReg | SrcImm | Mov, DstReg | SrcImm | Mov,
 	/* 0xC0 - 0xC7 */
 	ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM,
 	0, ImplicitOps | Stack, 0, 0,
@@ -169,7 +171,7 @@ static u16 opcode_table[256] = {
 	/* 0xD8 - 0xDF */
 	0, 0, 0, 0, 0, 0, 0, 0,
 	/* 0xE0 - 0xE7 */
-	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, SrcImmByte, 0, 0, 0, 0, 0,
 	/* 0xE8 - 0xEF */
 	ImplicitOps | Stack, SrcImm | ImplicitOps, ImplicitOps, SrcImmByte | ImplicitOps,
 	0, 0, 0, 0,
@@ -183,7 +185,8 @@ static u16 opcode_table[256] = {
 
 static u16 twobyte_table[256] = {
 	/* 0x00 - 0x0F */
-	0, Group | GroupDual | Group7, 0, 0, 0, 0, ImplicitOps, 0,
+	SrcReg|SrcMem16|ModRM,
+	Group | GroupDual | Group7, 0, 0, 0, 0, ImplicitOps, 0,
 	ImplicitOps, ImplicitOps, 0, 0, 0, ImplicitOps | ModRM, 0, 0,
 	/* 0x10 - 0x1F */
 	0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0, 0, 0, 0, 0, 0,
@@ -275,7 +278,8 @@ static u16 group_table[] = {
 	0, 0, 0, 0, 0, 0,
 	[Group5*8] =
 	DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM, 0, 0,
-	SrcMem | ModRM, 0, SrcMem | ModRM | Stack, 0,
+	SrcMem | ModRM, ImplicitOps | ModRM, SrcMem | ModRM | Stack, 0,
+
 	[Group7*8] =
 	0, 0, ModRM | SrcMem, ModRM | SrcMem,
 	SrcNone | ModRM | DstMem | Mov, 0,
@@ -951,8 +955,8 @@ done_prefixes:
 	}
 
 	/* Unrecognised? */
-	if (c->d == 0) {
-		DPRINTF("Cannot emulate %02x\n", c->b);
+	if (c->d == 0 && (c->b != 0xcc) && (c->b != 0x90) && (c->b != 0xf)) {
+		DPRINTF("Cannot emulate %02x %x\n", c->b, c->eip);
 		return -1;
 	}
 
@@ -1359,8 +1363,15 @@ special_insn:
 	case 0x00 ... 0x05:
 	      add:		/* add */
 		if ((c->d & ModRM) && c->modrm_mod == 3) {
+			u8 reg;
 			c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
-			c->dst.ptr =  decode_register(c->modrm_rm, c->regs, c->d & ByteOp);
+
+			if (ctxt->cs_base + c->eip == 0x649f)
+				reg = c->modrm_rm|c->modrm_reg;
+			else
+				reg = c->modrm_rm;
+
+			c->dst.ptr =  decode_register(reg, c->regs, c->d & ByteOp);
 		}
 		emulate_2op_SrcV("add", c->src, c->dst, ctxt->eflags);
 		break;
@@ -1616,8 +1627,14 @@ special_insn:
 		if (rc != 0)
 			goto done;
 		break;
-	case 0xb8: /* mov r, imm */
-		goto mov;
+	case 0xb8 ... 0xbf: /* mov r, imm */
+		{
+			int reg = c->b & 0x7;
+			c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX + reg];
+			goto mov;
+		}
+	case 0x90: /* nop */
+		break;
 	case 0x9c: /* pushf */
 		c->src.val =  (unsigned long) ctxt->eflags;
 		emulate_push(ctxt);
@@ -1732,6 +1749,11 @@ special_insn:
 	mov:
 		c->dst.val = c->src.val;
 		break;
+	case 0xcc ... 0xcd: /* int */
+		/* FIXME: do a proper jump through idt */
+		if (ctxt->mode == X86EMUL_MODE_REAL) {
+		}
+		break;
 	case 0xd0 ... 0xd1:	/* Grp2 */
 		c->src.val = 1;
 		emulate_grp2(ctxt);
@@ -1740,6 +1762,12 @@ special_insn:
 		c->src.val = c->regs[VCPU_REGS_RCX];
 		emulate_grp2(ctxt);
 		break;
+	case 0xe2:		/* loop */
+		c->regs[VCPU_REGS_RCX]--;
+		if (c->regs[VCPU_REGS_RCX])
+			c->eip = c->eip + c->src.val;
+		c->dst.type = OP_NONE;
+		break;
 	case 0xe8: /* call (near) */ {
 		long int rel;
 		switch (c->op_bytes) {
@@ -1763,13 +1791,38 @@ special_insn:
 		jmp_rel(c, c->src.val);
 		c->dst.type = OP_NONE; /* Disable writeback. */
 		break;
-	case 0xea: /* jmp far */ {
+	case 0xea:
+	jmpfar: /* jmp far */ {
 		uint32_t eip;
 		uint16_t sel;
 
 		/* enable switch_perso */
 		switch_perso = 1;
 
+		if (c->b == 0xff) {
+			rc = ops->read_emulated(c->modrm_ea, &eip, 
+						c->op_bytes, ctxt->vcpu);
+			if (rc != 0)
+				goto cannot_emulate;
+
+			c->modrm_ea += c->op_bytes;
+			rc = ops->read_emulated(c->modrm_ea, &sel, 
+						2, ctxt->vcpu);
+			if (rc != 0)
+				goto cannot_emulate;
+
+			c->eip = eip;
+			if (load_segment_descriptor(ctxt->vcpu, sel, 9,
+			    VCPU_SREG_CS) < 0) {
+				printk("failed to load cs!\n");
+				goto cannot_emulate;
+			}
+			goto done;
+			/* FIXME: if this is not a TSS jump need to
+ 			 * perform register writeback.
+ 			 * break;
+ 			 */
+		}
 		switch (c->op_bytes) {
 		case 2:
 			eip = insn_fetch(u16, 2, c->eip);
@@ -1823,6 +1876,8 @@ special_insn:
 		c->dst.type = OP_NONE;	/* Disable writeback. */
 		break;
 	case 0xfe ... 0xff:	/* Grp4/Grp5 */
+		if (c->modrm_reg == 5)
+			goto jmpfar;
 		rc = emulate_grp45(ctxt, ops);
 		if (rc != 0)
 			goto done;
@@ -1847,6 +1902,22 @@ done:
 
 twobyte_insn:
 	switch (c->b) {
+	case 0x0:
+		switch (c->modrm_reg) {
+		case 2: /* ldt */
+			if (load_segment_descriptor(ctxt->vcpu, c->src.val,
+						    0, VCPU_SREG_LDTR))
+				goto cannot_emulate;
+			break;
+		case 3: /* ltr */
+			if (load_segment_descriptor(ctxt->vcpu, c->src.val, 
+						    1, VCPU_SREG_TR))
+				goto cannot_emulate;
+			break;
+		default:
+			goto cannot_emulate;
+		}
+		break;
 	case 0x01: /* lgdt, lidt, lmsw */
 		switch (c->modrm_reg) {
 			u16 size;

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft 
Defy all challenges. Microsoft(R) Visual Studio 2008. 
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

  reply	other threads:[~2008-05-14 21:29 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-04-29 13:02 Protected mode transitions and big real mode... still an issue Guillaume Thouvenin
2008-04-29 16:41 ` Anthony Liguori
2008-04-29 17:09   ` Laurent Vivier
2008-04-29 17:22     ` Laurent Vivier
2008-04-29 23:20       ` Avi Kivity
2008-04-29 18:17     ` Anthony Liguori
2008-04-29 16:56 ` David Mair
2008-04-29 18:16 ` Anthony Liguori
2008-05-01 19:13 ` Marcelo Tosatti
2008-05-03  8:26   ` Balaji Rao
2008-05-05 12:40     ` Guillaume Thouvenin
2008-05-05 12:44       ` Balaji Rao
2008-05-05 12:57       ` Anthony Liguori
2008-05-05 13:29         ` Mohammed Gamal
2008-05-06 13:38           ` Guillaume Thouvenin
2008-05-06 14:30             ` Anthony Liguori
2008-05-06 17:05               ` Mohammed Gamal
2008-05-14  7:29                 ` Guillaume Thouvenin
2008-05-14 21:29                   ` Marcelo Tosatti [this message]
2008-05-15  7:33                     ` Avi Kivity
2008-05-15  7:49                       ` Guillaume Thouvenin
2008-05-15 18:07                   ` Mohammed Gamal
2008-05-07  5:57               ` Guillaume Thouvenin
2008-05-05  6:27   ` Guillaume Thouvenin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080514212953.GA17705@dmt \
    --to=mtosatti@redhat.com \
    --cc=avi@qumranet.com \
    --cc=guillaume.thouvenin@ext.bull.net \
    --cc=kvm-devel@lists.sourceforge.net \
    --cc=m.gamal005@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox