1 /* 2 Everyone else is writing i80x86 virtual machines, why not me too? 3 -- rkeene [010719991500] rkeene@suspend.net 4 rkeene (Roy Keene), rkeene@suspend.net 5 help from, saurik (Jay Freeman), saurik@saurik.com 6 and #asm on the IRC network of EFnet. 7 8 Lets see.. 9 10 doopcodereal() Used to execute an opcode (or group of opcodes) in real mode. 11 opcode*() Used to execute a specific opcode. 12 13 writemembyte() Used to write to an area of memmory. 14 readmembyte() Used to read an area of memmory. 15 changeval() Change two parts of a register. 16 getval() Put two parts of a register together. 17 changevalext() Change three parts of a register. 18 19 Partially implemented opcodes [opcode*()]: 20 0x00, 0x0f, 0xe4 21 22 Fully implemented opcodes [opcode*()]: 23 0x04, 0x05, 0x06, 0x14, 0x15, 0x24, 0x25, 0x27, 0x2f, 0x37, 0x3f, 0x50, 0x8b, 24 0x98, 0xb8, 0xbe, 0xbf, 0xd4, 0xd5, 0xf3, 0xf5, 0xf7, 0xf8, 0xfc 25 26 */ 27 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <math.h> 31 #define VERSION "0.01" 32 /* 33 Default to 4.0megs of RAM. 34 */ 35 #ifndef RAMSIZE 36 #define RAMSIZE 4194304 37 #endif 38 39 /* General Purpose regs */ 40 unsigned char ah=0; 41 unsigned char bh=0; 42 unsigned char ch=0; 43 unsigned char dh=0; 44 unsigned char al=0; 45 unsigned char bl=0; 46 unsigned char cl=0; 47 unsigned char dl=0; 48 int ip=0; 49 int si=0; 50 int di=0; 51 int bp=0; 52 int sp=0; 53 int ax=0; 54 int bx=0; 55 int cx=0; 56 int dx=0; 57 long eax=0; 58 long ebx=0; 59 long ecx=0; 60 long edx=0; 61 long esi=0; 62 long edi=0; 63 long ebp=0; 64 long esp=0; 65 long eip=0; 66 67 /* Flags */ 68 int af=0; 69 int cf=0; 70 int df=0; 71 int IF=0; 72 int eflags= 0x00000000; 73 int eflags_reset= 0x00000002; 74 int eflags_id= 0x00200000; 75 int eflags_vip= 0x00100000; 76 int eflags_vif= 0x00080000; 77 int eflags_ac= 0x00040000; 78 int eflags_vm= 0x00020000; 79 int eflags_rf= 0x00010000; 80 int eflags_nt= 0x00004000; 81 int eflags_iopl3= 0x00003000; 82 int eflags_iopl2= 0x00002000; 83 int eflags_iopl1= 0x00001000; 84 int eflags_iopl0= 0x00000000; 85 int eflags_of= 0x00000800; 86 int eflags_di= 0x00000400; 87 int eflags_if= 0x00000200; 88 int eflags_tf= 0x00000100; 89 int eflags_sf= 0x00000080; 90 int eflags_zf= 0x00000040; 91 int eflags_af= 0x00000010; 92 int eflags_pf= 0x00000004; 93 int eflags_cf= 0x00000001; 94 95 /* Segment Regs */ 96 long cs=0; 97 long ss=0; 98 long ds=0; 99 long es=0; 100 long fs=0; 101 long gs=0; 102 103 /* Table Regs */ 104 int gdtr=0; 105 int idtr=0; 106 int ldtr=0; 107 int tr=0; 108 109 /* Control regs */ 110 int cr0=0; 111 int cr1=0; 112 int cr2=0; 113 int cr3=0; 114 int cr4=0; 115 int cr5=0; 116 int cr6=0; 117 int cr7=0; 118 119 /* Debug Regs */ 120 int dr0=0; 121 int dr1=0; 122 int dr2=0; 123 int dr3=0; 124 int dr4=0; 125 int dr5=0; 126 int dr6=0; 127 int dr7=0; 128 129 /* Program Variables */ 130 long *retptr[8][3]; 131 #if (defined GO32) || (defined WIN32) 132 char biosfile[255]="bios.ram"; 133 #else 134 char biosfile[255]="io/VGABIOS-elpin-2.20"; 135 #endif 136 #if (USEFILE==1) 137 FILE *memfd; 138 char memfile[255]="io/vmi586.mem"; 139 #else 140 unsigned char memarray[RAMSIZE]; 141 #endif 142 int stack[8192]; 143 void (*(regs[255]))(); 144 unsigned long absaddr; 145 #ifdef CHECK_INSTRUCTIONS 146 char INSTRUCTION[256]={1,0,0,0,1,1,1,0,0,0,0, 147 0,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0, 148 0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0, 149 0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 150 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0, 151 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 152 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 153 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0, 154 0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 155 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1, 156 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 157 0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0, 158 0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,1,0,0, 159 0,1,0,0,0}; 160 #endif 161 162 163 /* 164 Remember to pass the locations to ext, high, and low. 165 mesh==1 if setting ax,ah,al 166 mesh==0 if setting eax 167 */ 168 void changevalext(unsigned long *ext, int *high, int *low, unsigned int nval, int mesh) 169 { 170 unsigned int tmpv=0; 171 #if (DEBUG>=1) 172 printf("changeval(%i, %i, %i, %i)\n called",(unsigned int) *ext,*high,*low,nval); 173 #endif 174 tmpv=nval; 175 tmpv-=((tmpv>>16)<<16); 176 *high=tmpv>>8; 177 tmpv-=(*high<<8); 178 *low=tmpv; 179 if (mesh==0) { *ext=nval; } else { *ext=((*ext>>16)<<16)+(*high<<8)+(*low); } 180 return; 181 } 182 183 /* 184 Pass memlocs. 185 */ 186 void changeval(int *high, int *low, int nv) 187 { 188 unsigned int tmpv=0; 189 #if (DEBUG>=1) 190 printf("changeval(%i, %i, %i)\n called",*high,*low,nv); 191 #endif 192 tmpv=nv; 193 *high=tmpv>>8; 194 tmpv-=(*high<<8); 195 *low=tmpv; 196 return; 197 } 198 199 /* 200 Assemble high and low bytes into a word. 201 */ 202 int getval(int high, int low) 203 { 204 return((high<<8)+(low)); 205 } 206 207 /* 208 A standard interface to memmory, very slow for now (1byte at a time). 209 Probably will be changed later, joy. 210 */ 211 void writemembyte(unsigned long location, int value) 212 { 213 #if (DEBUG>=3) 214 printf("Writing %c(%i) to %i\n",value,value,(unsigned int) location); 215 #endif 216 #if (USEFILE==1) 217 fseek(memfd,location,SEEK_SET); 218 fputc(value,memfd); 219 #else 220 memarray[location]=value; 221 #endif 222 } 223 224 /* 225 Read memmory the standard way. 226 */ 227 unsigned int readmembyte(unsigned long location) 228 { 229 #if (DEBUG>=3) 230 printf("Reading byte from %i, ",(unsigned int) location); 231 #endif 232 #if (USEFILE==1) 233 fseek(memfd,location,SEEK_SET); 234 #if (DEBUG>=3) 235 printf("(%i)\n",fgetc(memfd)); 236 fseek(memfd,location,SEEK_SET); 237 #endif 238 return(fgetc(memfd)); 239 #else 240 #if (DEBUG>=3) 241 printf("(%i)\n",memarray[location]); 242 #endif 243 return (memarray[location]); 244 #endif 245 } 246 247 void doopcodereal(unsigned int bcs, unsigned long offset, long length) 248 { 249 unsigned int opcodeval=0; 250 cs=bcs; 251 for (ip=offset;ip<length;ip++) 252 { 253 absaddr=((cs<<16)+ip); 254 opcodeval=readmembyte(absaddr); 255 #ifdef CHECK_INSTRUCTIONS 256 if (INSTRUCTION[opcodeval]!=1) { 257 #if (DEBUG>=1) 258 printf("Opcode not implemented (%i)\n",opcodeval); 259 #endif 260 } else { 261 (regs[opcodeval])(); 262 } 263 #else 264 (regs[opcodeval])(); 265 #endif 266 } 267 } 268 269 /* 270 #de 0 divide error 271 #db 1 debug 272 #bp 3 breakpoint 273 #of 4 overflow 274 #br 5 BOUND overflow 275 #ud 6 undefined opcode 276 #nm 7 no math coprossor 277 #df 8 double fault 278 #ts 10 invlaid ts 279 #np 11 segment not present 280 #ss 12 stack segfault 281 #gp 13 general protection 282 #pf 14 page fault 283 #mf 16 math fault 284 #ac 17 alignment check 285 #mc 19 machine check 286 */ 287 void callint(int intpt) { 288 int intloc; 289 intloc=readmembyte(intpt*4); 290 #if (DEBUG>=2) 291 printf("Interrupt %i called. Running segment %i\n", intpt, intloc); 292 #endif 293 doopcodereal(intloc,0,65535); 294 return; 295 } 296 297 298 299 void opcode00(void) { 300 writemembyte((bx+si),al+readmembyte(bx+si)); ip+=1; 301 #if (DEBUG>=2) 302 printf("00 add [%i],%i\n",(bx+si),al); 303 #endif 304 } 305 void opcode04(void) { 306 ip++; 307 al+=readmembyte(absaddr+1); 308 ax=(((ax>>8)<<8)+al); 309 eax=(((eax>>8)<<8)+al); 310 #if (DEBUG>=2) 311 printf("04 add\n"); 312 #endif 313 } 314 void opcode05(void) { 315 if ((cr0 & 1)==0) { 316 ip+=2; 317 ax+=((readmembyte(absaddr+2)<<8)+readmembyte(absaddr+1)); 318 eax=((eax>>16)<<16)+ax; 319 ah=(ax>>8); 320 al=(ax-(ah<<8)); 321 #if (DEBUG>=2) 322 printf("05 add\n"); 323 #endif 324 return; 325 } else { 326 ip+=4; 327 eax+=(readmembyte(absaddr+4)<<24)+(readmembyte(absaddr+3)<<16)+(readmembyte(absaddr+2)<<8)+readmembyte(absaddr+1); 328 ax=((eax<<16)>>16); 329 ah=(ax>>8); 330 al=(ax-(ah<<8)); 331 #if (DEBUG>=2) 332 printf("05 add\n"); 333 #endif 334 return; 335 } 336 } 337 void opcode06(void) { 338 stack[sp]=es>>8; stack[sp+1]=es-((es>>8)<<8); sp=sp+2; 339 #if (DEBUG>=2) 340 printf("06 push es\n"); 341 #endif 342 } 343 void opcode0f(void) { 344 int tmpA; 345 tmpA=(readmembyte(absaddr+1)); 346 if (tmpA>=0xc8) { 347 ip+=4; 348 *retptr[tmpA][3]=((*retptr[tmpA][3])>>24)+((*retptr[tmpA][3] & 0xFF)<<24)+((*retptr[tmpA][3] & 0x0000FF00)<<8)+((*retptr[tmpA][3] & 0x00FF0000)>>8); 349 *retptr[tmpA][2]=(*retptr[tmpA][3] & 0xFFFF); 350 if (tmpA>4) { 351 *retptr[tmpA][0]=(*retptr[tmpA][2] & 0xFF); 352 *retptr[tmpA][1]=(*retptr[tmpA][2] & 0xFF00); 353 } 354 #if (DEBUG>=2) 355 printf("0FC8 bswap %i\n", tmpA+65); 356 #endif 357 return; 358 } 359 if (tmpA==0xa3) { 360 /* 361 Need to write BT sometime... 362 */ 363 return; 364 } 365 if (tmpA==0x06) { 366 #if (DEBUG>=2) 367 printf("0F06 CLTS\n"); 368 #endif 369 } 370 if (tmpA==0xa2) { 371 if (eax==0) { 372 eax=1; ax=1; ah=0; al=1; 373 bl=0x47; bh=0x65; bx=0x6547; ebx=0x756e6547; 374 cl=0x6e; ch=0x74; cx=0x746e; ecx=0x6c65746e; 375 dl=0x69; dh=0x6e; dx=0x6e69; edx=0x49656e69; 376 } 377 #if (DEBUG>=2) 378 printf("0FA2 CPUId\n"); 379 #endif 380 } 381 #if (DEBUG>=2) 382 printf("Unksupported form of 0x0F, %i\n",tmpA); 383 #endif 384 } 385 void opcode14(void) { 386 ip++; 387 al+=readmembyte(absaddr+1)+cf; 388 ax=(ah<<8)+(al); 389 eax=((eax>>16)<<16)+ax; 390 #if (DEBUG>=2) 391 printf("14 adc al,...\n"); 392 #endif 393 } 394 void opcode15(void) { 395 if ((cr0 & 1)==0) { 396 ip+=2; 397 ax+=((readmembyte(absaddr+2)<<8)+readmembyte(absaddr+1))+cf; 398 eax=((eax>>16)<<16)+ax; 399 ah=(ax>>8); 400 al=(ax-(ah<<8)); 401 #if (DEBUG>=2) 402 printf("15 adc ax,...\n"); 403 #endif 404 return; 405 } else { 406 ip+=4; 407 eax+=(readmembyte(absaddr+4)<<24)+(readmembyte(absaddr+3)<<16)+(readmembyte(absaddr+2)<<8)+readmembyte(absaddr+1)+cf; 408 ax=((eax<<16)>>16); 409 ah=(ax>>8); 410 al=(ax-(ah<<8)); 411 #if (DEBUG>=2) 412 printf("15 adc eax,...\n"); 413 #endif 414 return; 415 } 416 } 417 void opcode24(void) { 418 ip++; 419 al=(al & readmembyte(absaddr+1)); 420 #if (DEBUG>=2) 421 printf("24 and al,...\n"); 422 #endif 423 } 424 void opcode25(void) { 425 if ((cr0 & 1)==0) { 426 ip+=2; 427 ax=(ax & ((readmembyte(absaddr+2)<<8)+readmembyte(absaddr+1))); 428 eax=((eax>>16)<<16)+ax; 429 ah=(ax>>8); 430 al=(ax-(ah<<8)); 431 #if (DEBUG>=2) 432 printf("25 and ax,...\n"); 433 #endif 434 return; 435 } else { 436 ip+=4; 437 eax=(eax & ((readmembyte(absaddr+4)<<24)+(readmembyte(absaddr+3)<<16)+(readmembyte(absaddr+2)<<8)+readmembyte(absaddr+1))); 438 ax=((eax<<16)>>16); 439 ah=(ax>>8); 440 al=(ax-(ah<<8)); 441 #if (DEBUG>=2) 442 printf("25 and eax,...\n"); 443 #endif 444 return; 445 } 446 } 447 void opcode27(void) { 448 if (((al & 0x0f)>9) || af==1) { 449 al+=6; 450 af=1; 451 } else { 452 af=0; 453 } 454 if (((al & 0xf0)>0x90) || cf==1) { 455 al+=0x60; 456 cf=1; 457 } else { 458 cf=0; 459 } 460 #if (DEBUG>=2) 461 printf("27 daa\n"); 462 #endif 463 } 464 void opcode2f(void) { 465 if (((al & 0xf)>9) || af==1) { 466 al-=6; 467 af=1; 468 } else { af=0; } 469 if ((al>0x9f) || cf==1) { 470 al-=0x60; 471 cf=1; 472 } else { cf=0; } 473 474 } 475 void opcode37(void) 476 { 477 if (((al & 0x0f) > 9) || (af==1)) { 478 al+=6; 479 ah+=1; 480 af=1; cf=1; 481 } else { 482 af=0; cf=0; 483 } 484 al=(al & 0x0f); 485 #if (DEBUG>=2) 486 printf("37 aaa\n"); 487 #endif 488 } 489 void opcode3f(void) { 490 if (((al & 0x0f)>9) || (af==1)) { 491 al-=6; 492 ah-=1; 493 af=1;cf=1; 494 } else { 495 af=0;cf=0; 496 } 497 al=(al & 0x0f); 498 #if (DEBUG>=2) 499 printf("3F aas\n"); 500 #endif 501 } 502 void opcode50(void) 503 { 504 stack[sp]=ah; stack[sp+1]=al; sp=sp+2; 505 #if (DEBUG>=2) 506 printf("50 push ax\n"); 507 #endif 508 } 509 void opcode8b(void) 510 { 511 cx=si; 512 ip++; 513 #if (DEBUG>=2) 514 printf("8BCE mov cx,si\n"); 515 #endif 516 } 517 void opcode98(void) { 518 if ((cr0 & 1)==0) { 519 if ((al>7)==1) { ah=255; } else { ah=0; } 520 ax=(ah<<8)+(al); 521 eax=((eax>>16)<<16)+ax; 522 #if (DEBUG>=2) 523 printf("98 CBW\n"); 524 #endif 525 return; 526 } else { 527 if ((ax>>15)==1) { eax=((65535<<16)+ax); } else { eax=ax; } 528 #if (DEBUG>=2) 529 printf("98 CDWE\n"); 530 #endif 531 } 532 } 533 void opcodeb8(void) 534 { 535 ax=(readmembyte(absaddr+2)<<8)+(readmembyte(absaddr+1)); 536 ah=ax>>8; 537 al=(ax-((ax>>8)<<8)); 538 eax=((eax>>16)<<16)+ax; 539 ip+=2; 540 #if (DEBUG>=2) 541 printf("B8 mov ax,%i\n",ax); 542 #endif 543 } 544 void opcodebe(void) 545 { 546 si=(readmembyte(absaddr+2)<<8)+(readmembyte(absaddr+1)); 547 esi=((esi>>16)<<16)+si; 548 ip+=2; 549 #if (DEBUG>=2) 550 printf("BE mov si,%i\n",si); 551 #endif 552 } 553 void opcodebf(void) 554 { 555 di=(readmembyte(absaddr+2)<<8)+(readmembyte(absaddr+1)); 556 edi=((edi>>16)<<16)+di; 557 ip+=2; 558 #if (DEBUG>=2) 559 printf("BF mov di,%i\n",di); 560 #endif 561 } 562 void opcoded4(void) { 563 int tmpA,tmpB; 564 ip++; 565 tmpA=al; tmpB=readmembyte(absaddr+1); 566 if (tmpB==0) { callint(0); return; } /* Divide overflow. */ 567 ah=tmpA/tmpB; 568 al=tmpA % tmpB; 569 #if (DEBUG>=2) 570 printf("D4 aam\n"); 571 #endif 572 } 573 void opcoded5(void) { 574 ip++; 575 ah=0; 576 al=((al+ah+readmembyte(absaddr+1)) & 0xff); 577 ax=getval(ah,al); 578 eax=((eax>>16)<<16)+ax; 579 #if (DEBUG>=2) 580 printf("D5 aad\n"); 581 #endif 582 } 583 584 void opcodee4(void) { 585 int tmpA; 586 tmpA=readmembyte(absaddr+1); 587 ip+=1; 588 589 #if (DEBUG>=2) 590 printf("E4 in"); 591 #endif 592 } 593 594 void opcodef3(void) 595 { 596 #if (DEBUG>=1) 597 printf("F3 repz --- NOT SUPPORTED\n"); 598 #endif 599 } 600 void opcodef5(void) { 601 cf=(cf*-1)+1; 602 #if (DEBUG>=2) 603 printf("F5 cfc\n"); 604 #endif 605 } 606 void opcodef7(void) 607 { 608 cx=(cx^0xffff)+1; 609 ip++; 610 #if (DEBUG>=2) 611 printf("F7D9 neg cx\n"); 612 #endif 613 } 614 void opcodef8(void) { 615 cf=0; 616 #if (DEBUG>=2) 617 printf("F8 clc\n"); 618 #endif 619 } 620 void opcodefc(void) 621 { 622 df=0; 623 #if (DEBUG>=1) 624 printf("FC cld\n"); 625 #endif 626 } 627 628 629 630 void make_regs_and_ops(void) { 631 regs[0x00]=opcode00; 632 regs[0x04]=opcode04; 633 regs[0x05]=opcode05; 634 regs[0x06]=opcode06; 635 regs[0x0f]=opcode0f; 636 regs[0x14]=opcode14; 637 regs[0x15]=opcode15; 638 regs[0x24]=opcode24; 639 regs[0x25]=opcode25; 640 regs[0x27]=opcode27; 641 regs[0x2f]=opcode2f; 642 regs[0x37]=opcode37; 643 regs[0x3f]=opcode3f; 644 regs[0x50]=opcode50; 645 regs[0x8b]=opcode8b; 646 regs[0x98]=opcode98; 647 regs[0xb8]=opcodeb8; 648 regs[0xbe]=opcodebe; 649 regs[0xbf]=opcodebf; 650 regs[0xd4]=opcoded4; 651 regs[0xd5]=opcoded5; 652 regs[0xe4]=opcodee4; 653 regs[0xf3]=opcodef3; 654 regs[0xf5]=opcodef5; 655 regs[0xf7]=opcodef7; 656 regs[0xf8]=opcodef8; 657 regs[0xfc]=opcodefc; 658 659 /* Setup pointers to registers in the standard way. */ 660 retptr[0][0]=(long *) &al; 661 retptr[1][0]=(long *) &cl; 662 retptr[2][0]=(long *) &dl; 663 retptr[3][0]=(long *) &bl; 664 retptr[0][1]=(long *) &al; 665 retptr[1][1]=(long *) &cl; 666 retptr[2][1]=(long *) &dl; 667 retptr[3][1]=(long *) &bl; 668 retptr[0][2]=(long *) &ax; 669 retptr[1][2]=(long *) &cx; 670 retptr[2][2]=(long *) &dx; 671 retptr[3][2]=(long *) &bx; 672 retptr[4][2]=(long *) &sp; 673 retptr[5][2]=(long *) &bp; 674 retptr[6][2]=(long *) &si; 675 retptr[7][2]=(long *) &di; 676 retptr[0][3]=(long *) &eax; 677 retptr[1][3]=(long *) &ecx; 678 retptr[2][3]=(long *) &edx; 679 retptr[3][3]=(long *) &ebx; 680 retptr[4][3]=(long *) &esp; 681 retptr[5][3]=(long *) &ebp; 682 retptr[6][3]=(long *) &esi; 683 retptr[7][3]=(long *) &edi; 684 685 } 686 687 int main(void) 688 { 689 FILE *biosId; 690 int i; 691 printf("Creating virtual memmory using a"); 692 #if (USEFILE==1) 693 memfd=fopen(memfile,"w+"); 694 printf(" file"); 695 #else 696 printf("n array"); 697 #endif 698 printf(", %ikb\nLoading startup program %s\n",RAMSIZE/1024,biosfile); 699 make_regs_and_ops(); 700 biosId=fopen(biosfile,"r"); 701 for (i=0;i<32768;i++) 702 { 703 writemembyte(((1<<16)+i),fgetc(biosId)); 704 } 705 doopcodereal(1,0,32768); 706 return(0); 707 } main.c is the source. |