ia64/xen-unstable

changeset 10307:1dab198509a9

[VMXASSIST] Extensions to vmxassist to handle additional mode switch cases.

Extends vmxassist to handle two cases related to mode switching found
while experimenting with different boot loaders.

The first case is use of the JMP instruction with memory location
operands to complete a switch to protected mode. This patch adds
emulation for this form of the JMP instruction to vmxassist.

The second case is where boot loader code does not save/restore a
non-zero SS register across a protected mode traversal.
Zeroing the SS register in vmxassist results in all sorts of problems
in the domU after returning back to real mode. This patch stores
segment register values before entering protected mode and correctly
restores the old values (instead of an incorrect zero value) when
reentering real mode.

Signed-off-by: Kevin Tronkowski <ktronkowski@virtualiron.com>
author kaf24@firebug.cl.cam.ac.uk
date Mon Jun 05 15:18:13 2006 +0100 (2006-06-05)
parents 9f50b8c2de0a
children 50db8c95e65d
files tools/firmware/vmxassist/vm86.c
line diff
     1.1 --- a/tools/firmware/vmxassist/vm86.c	Mon Jun 05 15:14:58 2006 +0100
     1.2 +++ b/tools/firmware/vmxassist/vm86.c	Mon Jun 05 15:18:13 2006 +0100
     1.3 @@ -37,6 +37,8 @@
     1.4  static unsigned prev_eip = 0;
     1.5  enum vm86_mode mode = 0;
     1.6  
     1.7 +static struct regs saved_rm_regs;
     1.8 +
     1.9  #ifdef DEBUG
    1.10  int traceset = 0;
    1.11  
    1.12 @@ -795,6 +797,8 @@ protected_mode(struct regs *regs)
    1.13  	oldctx.esp = regs->uesp;
    1.14  	oldctx.eflags = regs->eflags;
    1.15  
    1.16 +	memset(&saved_rm_regs, 0, sizeof(struct regs));
    1.17 +
    1.18  	/* reload all segment registers */
    1.19  	if (!load_seg(regs->cs, &oldctx.cs_base,
    1.20  				&oldctx.cs_limit, &oldctx.cs_arbytes))
    1.21 @@ -808,6 +812,7 @@ protected_mode(struct regs *regs)
    1.22  		load_seg(0, &oldctx.es_base,
    1.23  			    &oldctx.es_limit, &oldctx.es_arbytes);
    1.24  		oldctx.es_sel = 0;
    1.25 +		saved_rm_regs.ves = regs->ves;
    1.26  	}
    1.27  
    1.28  	if (load_seg(regs->uss, &oldctx.ss_base,
    1.29 @@ -817,6 +822,7 @@ protected_mode(struct regs *regs)
    1.30  		load_seg(0, &oldctx.ss_base,
    1.31  			    &oldctx.ss_limit, &oldctx.ss_arbytes);
    1.32  		oldctx.ss_sel = 0;
    1.33 +		saved_rm_regs.uss = regs->uss;
    1.34  	}
    1.35  
    1.36  	if (load_seg(regs->vds, &oldctx.ds_base,
    1.37 @@ -826,6 +832,7 @@ protected_mode(struct regs *regs)
    1.38  		load_seg(0, &oldctx.ds_base,
    1.39  			    &oldctx.ds_limit, &oldctx.ds_arbytes);
    1.40  		oldctx.ds_sel = 0;
    1.41 +		saved_rm_regs.vds = regs->vds;
    1.42  	}
    1.43  
    1.44  	if (load_seg(regs->vfs, &oldctx.fs_base,
    1.45 @@ -835,6 +842,7 @@ protected_mode(struct regs *regs)
    1.46  		load_seg(0, &oldctx.fs_base,
    1.47  			    &oldctx.fs_limit, &oldctx.fs_arbytes);
    1.48  		oldctx.fs_sel = 0;
    1.49 +		saved_rm_regs.vfs = regs->vfs;
    1.50  	}
    1.51  
    1.52  	if (load_seg(regs->vgs, &oldctx.gs_base,
    1.53 @@ -844,6 +852,7 @@ protected_mode(struct regs *regs)
    1.54  		load_seg(0, &oldctx.gs_base,
    1.55  			    &oldctx.gs_limit, &oldctx.gs_arbytes);
    1.56  		oldctx.gs_sel = 0;
    1.57 +		saved_rm_regs.vgs = regs->vgs;
    1.58  	}
    1.59  
    1.60  	/* initialize jump environment to warp back to protected mode */
    1.61 @@ -880,16 +889,22 @@ real_mode(struct regs *regs)
    1.62  		if (regs->uss >= HIGHMEM)
    1.63  			panic("%%ss 0x%lx higher than 1MB", regs->uss);
    1.64  		regs->uss = address(regs, regs->uss, 0) >> 4;
    1.65 +	} else {
    1.66 +	  regs->uss = saved_rm_regs.uss;
    1.67  	}
    1.68  	if (regs->vds != 0) {
    1.69  		if (regs->vds >= HIGHMEM)
    1.70  			panic("%%ds 0x%lx higher than 1MB", regs->vds);
    1.71  		regs->vds = address(regs, regs->vds, 0) >> 4;
    1.72 +	} else {
    1.73 +	  regs->vds = saved_rm_regs.vds;
    1.74  	}
    1.75  	if (regs->ves != 0) {
    1.76  		if (regs->ves >= HIGHMEM)
    1.77  			panic("%%es 0x%lx higher than 1MB", regs->ves);
    1.78  		regs->ves = address(regs, regs->ves, 0) >> 4;
    1.79 +	} else {
    1.80 +	  regs->ves = saved_rm_regs.ves;
    1.81  	}
    1.82  
    1.83  	/* this should get us into 16-bit mode */
    1.84 @@ -982,6 +997,39 @@ jmpl(struct regs *regs, int prefix)
    1.85  }
    1.86  
    1.87  static void
    1.88 +jmpl_indirect(struct regs *regs, int prefix, unsigned modrm)
    1.89 +{
    1.90 +	unsigned n = regs->eip;
    1.91 +	unsigned cs, eip;
    1.92 +	unsigned addr;
    1.93 +
    1.94 +	addr  = operand(prefix, regs, modrm);
    1.95 +
    1.96 +	if (mode == VM86_REAL_TO_PROTECTED) { /* jump to protected mode */
    1.97 +		eip = (prefix & DATA32) ? read32(addr) : read16(addr);
    1.98 +		addr += (prefix & DATA32) ? 4 : 2;
    1.99 +		cs = read16(addr);
   1.100 +
   1.101 +		TRACE((regs, (regs->eip - n) + 1, "jmpl 0x%x:0x%x", cs, eip));
   1.102 +
   1.103 +                regs->cs = cs;
   1.104 +                regs->eip = eip;
   1.105 +		set_mode(regs, VM86_PROTECTED);
   1.106 +	} else if (mode == VM86_PROTECTED_TO_REAL) { /* jump to real mode */
   1.107 +		eip = (prefix & DATA32) ? read32(addr) : read16(addr);
   1.108 +		addr += (prefix & DATA32) ? 4 : 2;
   1.109 +		cs = read16(addr);
   1.110 +
   1.111 +		TRACE((regs, (regs->eip - n) + 1, "jmpl 0x%x:0x%x", cs, eip));
   1.112 +
   1.113 +                regs->cs = cs;
   1.114 +                regs->eip = eip;
   1.115 +		set_mode(regs, VM86_REAL);
   1.116 +	} else
   1.117 +		panic("jmpl");
   1.118 +}
   1.119 +
   1.120 +static void
   1.121  retl(struct regs *regs, int prefix)
   1.122  {
   1.123  	unsigned cs, eip;
   1.124 @@ -1306,6 +1354,23 @@ opcode(struct regs *regs)
   1.125  			}
   1.126  			goto invalid;
   1.127  
   1.128 +		case 0xFF: /* jmpl (indirect) */
   1.129 +			if ((mode == VM86_REAL_TO_PROTECTED) ||
   1.130 +			    (mode == VM86_PROTECTED_TO_REAL)) {
   1.131 +			 	unsigned modrm = fetch8(regs);
   1.132 +				
   1.133 +				switch((modrm >> 3) & 7) {
   1.134 +				case 5:
   1.135 +				  jmpl_indirect(regs, prefix, modrm);
   1.136 +				  return OPC_INVALID;
   1.137 +
   1.138 +				default:
   1.139 +				  break;
   1.140 +				}
   1.141 +
   1.142 +			}
   1.143 +			goto invalid;
   1.144 +
   1.145  		case 0xEB: /* short jump */
   1.146  			if ((mode == VM86_REAL_TO_PROTECTED) ||
   1.147  			    (mode == VM86_PROTECTED_TO_REAL)) {