linux_vm86.c (8868B)
1 #ifdef HAVE_XORG_CONFIG_H 2 #include <xorg-config.h> 3 #endif 4 5 #include <errno.h> 6 #include <string.h> 7 8 #include "xf86.h" 9 #include "xf86_OSproc.h" 10 #include "xf86Pci.h" 11 #include "compiler.h" 12 #define _INT10_PRIVATE 13 #include "xf86int10.h" 14 15 #define REG pInt 16 17 #ifdef _VM86_LINUX 18 #include "int10Defines.h" 19 20 static int vm86_rep(struct vm86_struct *ptr); 21 static struct vm86_struct vm86_s; 22 23 Bool 24 xf86Int10ExecSetup(xf86Int10InfoPtr pInt) 25 { 26 #define VM86S ((struct vm86_struct *)pInt->cpuRegs) 27 28 pInt->cpuRegs = &vm86_s; 29 VM86S->flags = 0; 30 VM86S->screen_bitmap = 0; 31 VM86S->cpu_type = CPU_586; 32 memset(&VM86S->int_revectored, 0xff, sizeof(VM86S->int_revectored)); 33 memset(&VM86S->int21_revectored, 0xff, sizeof(VM86S->int21_revectored)); 34 return TRUE; 35 } 36 37 /* get the linear address */ 38 #define LIN_PREF_SI ((pref_seg << 4) + X86_SI) 39 #define LWECX ((prefix66 ^ prefix67) ? X86_ECX : X86_CX) 40 #define LWECX_ZERO {if (prefix66 ^ prefix67) X86_ECX = 0; else X86_CX = 0;} 41 #define DF (1 << 10) 42 43 /* vm86 fault handling */ 44 static Bool 45 vm86_GP_fault(xf86Int10InfoPtr pInt) 46 { 47 unsigned char *csp, *lina; 48 CARD32 org_eip; 49 int pref_seg; 50 int done, is_rep, prefix66, prefix67; 51 52 csp = lina = SEG_ADR((unsigned char *), X86_CS, IP); 53 54 is_rep = 0; 55 prefix66 = prefix67 = 0; 56 pref_seg = -1; 57 58 /* eat up prefixes */ 59 done = 0; 60 do { 61 switch (MEM_RB(pInt, (int) csp++)) { 62 case 0x66: /* operand prefix */ 63 prefix66 = 1; 64 break; 65 case 0x67: /* address prefix */ 66 prefix67 = 1; 67 break; 68 case 0x2e: /* CS */ 69 pref_seg = X86_CS; 70 break; 71 case 0x3e: /* DS */ 72 pref_seg = X86_DS; 73 break; 74 case 0x26: /* ES */ 75 pref_seg = X86_ES; 76 break; 77 case 0x36: /* SS */ 78 pref_seg = X86_SS; 79 break; 80 case 0x65: /* GS */ 81 pref_seg = X86_GS; 82 break; 83 case 0x64: /* FS */ 84 pref_seg = X86_FS; 85 break; 86 case 0xf0: /* lock */ 87 break; 88 case 0xf2: /* repnz */ 89 case 0xf3: /* rep */ 90 is_rep = 1; 91 break; 92 default: 93 done = 1; 94 } 95 } while (!done); 96 csp--; /* oops one too many */ 97 org_eip = X86_EIP; 98 X86_IP += (csp - lina); 99 100 switch (MEM_RB(pInt, (int) csp)) { 101 case 0x6c: /* insb */ 102 /* NOTE: ES can't be overwritten; prefixes 66,67 should use esi,edi,ecx 103 * but is anyone using extended regs in real mode? */ 104 /* WARNING: no test for DI wrapping! */ 105 X86_EDI += port_rep_inb(pInt, X86_DX, SEG_EADR((CARD32), X86_ES, DI), 106 X86_FLAGS & DF, is_rep ? LWECX : 1); 107 if (is_rep) 108 LWECX_ZERO; 109 X86_IP++; 110 break; 111 112 case 0x6d: /* (rep) insw / insd */ 113 /* NOTE: ES can't be overwritten */ 114 /* WARNING: no test for _DI wrapping! */ 115 if (prefix66) { 116 X86_DI += port_rep_inl(pInt, X86_DX, SEG_ADR((CARD32), X86_ES, DI), 117 X86_EFLAGS & DF, is_rep ? LWECX : 1); 118 } 119 else { 120 X86_DI += port_rep_inw(pInt, X86_DX, SEG_ADR((CARD32), X86_ES, DI), 121 X86_FLAGS & DF, is_rep ? LWECX : 1); 122 } 123 if (is_rep) 124 LWECX_ZERO; 125 X86_IP++; 126 break; 127 128 case 0x6e: /* (rep) outsb */ 129 if (pref_seg < 0) 130 pref_seg = X86_DS; 131 /* WARNING: no test for _SI wrapping! */ 132 X86_SI += port_rep_outb(pInt, X86_DX, (CARD32) LIN_PREF_SI, 133 X86_FLAGS & DF, is_rep ? LWECX : 1); 134 if (is_rep) 135 LWECX_ZERO; 136 X86_IP++; 137 break; 138 139 case 0x6f: /* (rep) outsw / outsd */ 140 if (pref_seg < 0) 141 pref_seg = X86_DS; 142 /* WARNING: no test for _SI wrapping! */ 143 if (prefix66) { 144 X86_SI += port_rep_outl(pInt, X86_DX, (CARD32) LIN_PREF_SI, 145 X86_EFLAGS & DF, is_rep ? LWECX : 1); 146 } 147 else { 148 X86_SI += port_rep_outw(pInt, X86_DX, (CARD32) LIN_PREF_SI, 149 X86_FLAGS & DF, is_rep ? LWECX : 1); 150 } 151 if (is_rep) 152 LWECX_ZERO; 153 X86_IP++; 154 break; 155 156 case 0xe5: /* inw xx, inl xx */ 157 if (prefix66) 158 X86_EAX = x_inl(csp[1]); 159 else 160 X86_AX = x_inw(csp[1]); 161 X86_IP += 2; 162 break; 163 164 case 0xe4: /* inb xx */ 165 X86_AL = x_inb(csp[1]); 166 X86_IP += 2; 167 break; 168 169 case 0xed: /* inw dx, inl dx */ 170 if (prefix66) 171 X86_EAX = x_inl(X86_DX); 172 else 173 X86_AX = x_inw(X86_DX); 174 X86_IP += 1; 175 break; 176 177 case 0xec: /* inb dx */ 178 X86_AL = x_inb(X86_DX); 179 X86_IP += 1; 180 break; 181 182 case 0xe7: /* outw xx */ 183 if (prefix66) 184 x_outl(csp[1], X86_EAX); 185 else 186 x_outw(csp[1], X86_AX); 187 X86_IP += 2; 188 break; 189 190 case 0xe6: /* outb xx */ 191 x_outb(csp[1], X86_AL); 192 X86_IP += 2; 193 break; 194 195 case 0xef: /* outw dx */ 196 if (prefix66) 197 x_outl(X86_DX, X86_EAX); 198 else 199 x_outw(X86_DX, X86_AX); 200 X86_IP += 1; 201 break; 202 203 case 0xee: /* outb dx */ 204 x_outb(X86_DX, X86_AL); 205 X86_IP += 1; 206 break; 207 208 case 0xf4: 209 DebugF("hlt at %p\n", lina); 210 return FALSE; 211 212 case 0x0f: 213 xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR, 214 "CPU 0x0f Trap at CS:EIP=0x%4.4x:0x%8.8lx\n", X86_CS, 215 X86_EIP); 216 goto op0ferr; 217 218 default: 219 xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR, "unknown reason for exception\n"); 220 221 op0ferr: 222 dump_registers(pInt); 223 stack_trace(pInt); 224 dump_code(pInt); 225 xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR, "cannot continue\n"); 226 return FALSE; 227 } /* end of switch() */ 228 return TRUE; 229 } 230 231 static int 232 do_vm86(xf86Int10InfoPtr pInt) 233 { 234 int retval; 235 236 retval = vm86_rep(VM86S); 237 238 switch (VM86_TYPE(retval)) { 239 case VM86_UNKNOWN: 240 if (!vm86_GP_fault(pInt)) 241 return 0; 242 break; 243 case VM86_STI: 244 xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR, "vm86_sti :-((\n"); 245 dump_registers(pInt); 246 dump_code(pInt); 247 stack_trace(pInt); 248 return 0; 249 case VM86_INTx: 250 pInt->num = VM86_ARG(retval); 251 if (!int_handler(pInt)) { 252 xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR, 253 "Unknown vm86_int: 0x%X\n\n", VM86_ARG(retval)); 254 dump_registers(pInt); 255 dump_code(pInt); 256 stack_trace(pInt); 257 return 0; 258 } 259 /* I'm not sure yet what to do if we can handle ints */ 260 break; 261 case VM86_SIGNAL: 262 return 1; 263 /* 264 * we used to warn here and bail out - but now the sigio stuff 265 * always fires signals at us. So we just ignore them for now. 266 */ 267 xf86DrvMsg(pInt->pScrn->scrnIndex, X_WARNING, "received signal\n"); 268 return 0; 269 default: 270 xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR, "unknown type(0x%x)=0x%x\n", 271 VM86_ARG(retval), VM86_TYPE(retval)); 272 dump_registers(pInt); 273 dump_code(pInt); 274 stack_trace(pInt); 275 return 0; 276 } 277 278 return 1; 279 } 280 281 void 282 xf86ExecX86int10(xf86Int10InfoPtr pInt) 283 { 284 int sig = setup_int(pInt); 285 286 if (int_handler(pInt)) 287 while (do_vm86(pInt)) { 288 }; 289 290 finish_int(pInt, sig); 291 } 292 293 static int 294 vm86_rep(struct vm86_struct *ptr) 295 { 296 int __res; 297 298 #ifdef __PIC__ 299 /* When compiling with -fPIC, we can't use asm constraint "b" because 300 %ebx is already taken by gcc. */ 301 __asm__ __volatile__("pushl %%ebx\n\t" 302 "push %%gs\n\t" 303 "movl %2,%%ebx\n\t" 304 "movl %1,%%eax\n\t" 305 "int $0x80\n\t" "pop %%gs\n\t" "popl %%ebx":"=a"(__res) 306 :"n"((int) 113), "r"((struct vm86_struct *) ptr)); 307 #else 308 __asm__ __volatile__("push %%gs\n\t" 309 "int $0x80\n\t" 310 "pop %%gs":"=a"(__res):"a"((int) 113), 311 "b"((struct vm86_struct *) ptr)); 312 #endif 313 314 if (__res < 0) { 315 errno = -__res; 316 __res = -1; 317 } 318 else 319 errno = 0; 320 return __res; 321 } 322 323 #endif