|
|
1.1 ! root 1: /* ! 2: MS-DOS Player for Win32 console ! 3: ! 4: Author : Takeda.Toshiya ! 5: Date : 2009.11.09- ! 6: */ ! 7: ! 8: #include "msdos.h" ! 9: ! 10: #ifdef _MSC_VER ! 11: #pragma warning( disable : 4018 ) ! 12: #pragma warning( disable : 4065 ) ! 13: #pragma warning( disable : 4146 ) ! 14: #pragma warning( disable : 4244 ) ! 15: #pragma warning( disable : 4267 ) ! 16: #endif ! 17: ! 18: #define my_strchr(str, chr) (char *)_mbschr((unsigned char *)(str), (unsigned int)(chr)) ! 19: #define my_strtok(tok, del) (char *)_mbstok((unsigned char *)(tok), (const unsigned char *)(del)) ! 20: #define my_strupr(str) (char *)_mbsupr((unsigned char *)(str)) ! 21: ! 22: #define fatalerror(...) { \ ! 23: fprintf(stderr, __VA_ARGS__); \ ! 24: exit(1); \ ! 25: } ! 26: #define error(...) fprintf(stderr, "error: " __VA_ARGS__) ! 27: ! 28: /* ---------------------------------------------------------------------------- ! 29: MAME i386 ! 30: ---------------------------------------------------------------------------- */ ! 31: ! 32: //#define SUPPORT_DISASSEMBLER ! 33: ! 34: #define CPU_MODEL i386 ! 35: //#define CPU_MODEL i486 ! 36: //#define CPU_MODEL pentium ! 37: //#define CPU_MODEL mediagx ! 38: //#define CPU_MODEL pentium_pro ! 39: //#define CPU_MODEL pentium_mmx ! 40: //#define CPU_MODEL pentium2 ! 41: //#define CPU_MODEL pentium3 ! 42: //#define CPU_MODEL pentium4 ! 43: ! 44: #define LSB_FIRST ! 45: ! 46: #ifndef INLINE ! 47: #define INLINE inline ! 48: #endif ! 49: #define U64(v) UINT64(v) ! 50: ! 51: //#define logerror(...) fprintf(stderr, __VA_ARGS__) ! 52: #define logerror(...) ! 53: //#define popmessage(...) fprintf(stderr, __VA_ARGS__) ! 54: #define popmessage(...) ! 55: ! 56: /*****************************************************************************/ ! 57: /* src/emu/diexec.h */ ! 58: ! 59: // I/O line states ! 60: enum line_state ! 61: { ! 62: CLEAR_LINE = 0, // clear (a fired or held) line ! 63: ASSERT_LINE, // assert an interrupt immediately ! 64: HOLD_LINE, // hold interrupt line until acknowledged ! 65: PULSE_LINE // pulse interrupt line instantaneously (only for NMI, RESET) ! 66: }; ! 67: ! 68: // I/O line definitions ! 69: enum ! 70: { ! 71: INPUT_LINE_IRQ = 0, ! 72: INPUT_LINE_NMI ! 73: }; ! 74: ! 75: /*****************************************************************************/ ! 76: /* src/emu/devcpu.h */ ! 77: ! 78: // CPU interface functions ! 79: #define CPU_INIT_NAME(name) cpu_init_##name ! 80: #define CPU_INIT(name) void* CPU_INIT_NAME(name)() ! 81: #define CPU_INIT_CALL(name) CPU_INIT_NAME(name)() ! 82: ! 83: #define CPU_RESET_NAME(name) cpu_reset_##name ! 84: #define CPU_RESET(name) void CPU_RESET_NAME(name)(i386_state *cpustate) ! 85: #define CPU_RESET_CALL(name) CPU_RESET_NAME(name)(cpustate) ! 86: ! 87: #define CPU_EXECUTE_NAME(name) cpu_execute_##name ! 88: #define CPU_EXECUTE(name) void CPU_EXECUTE_NAME(name)(i386_state *cpustate) ! 89: #define CPU_EXECUTE_CALL(name) CPU_EXECUTE_NAME(name)(cpustate) ! 90: ! 91: #define CPU_DISASSEMBLE_NAME(name) cpu_disassemble_##name ! 92: #define CPU_DISASSEMBLE(name) int CPU_DISASSEMBLE_NAME(name)(char *buffer, offs_t eip, const UINT8 *oprom) ! 93: #define CPU_DISASSEMBLE_CALL(name) CPU_DISASSEMBLE_NAME(name)(buffer, eip, oprom) ! 94: ! 95: /*****************************************************************************/ ! 96: /* src/emu/memory.h */ ! 97: ! 98: // offsets and addresses are 32-bit (for now...) ! 99: typedef UINT32 offs_t; ! 100: ! 101: // read accessors ! 102: UINT8 read_byte(offs_t byteaddress) ! 103: { ! 104: if(byteaddress < MAX_MEM) { ! 105: return mem[byteaddress]; ! 106: } else if((byteaddress & 0xfffffff0) == 0xfffffff0) { ! 107: return read_byte(byteaddress & 0xfffff); ! 108: } ! 109: return 0; ! 110: } ! 111: ! 112: UINT16 read_word(offs_t byteaddress) ! 113: { ! 114: if(byteaddress < MAX_MEM - 1) { ! 115: return *(UINT16 *)(mem + byteaddress); ! 116: } else if((byteaddress & 0xfffffff0) == 0xfffffff0) { ! 117: return read_word(byteaddress & 0xfffff); ! 118: } ! 119: return 0; ! 120: } ! 121: ! 122: UINT32 read_dword(offs_t byteaddress) ! 123: { ! 124: if(byteaddress < MAX_MEM - 3) { ! 125: return *(UINT32 *)(mem + byteaddress); ! 126: } else if((byteaddress & 0xfffffff0) == 0xfffffff0) { ! 127: return read_dword(byteaddress & 0xfffff); ! 128: } ! 129: return 0; ! 130: } ! 131: ! 132: // write accessors ! 133: void write_byte(offs_t byteaddress, UINT8 data) ! 134: { ! 135: if(byteaddress < MAX_MEM) { ! 136: if(byteaddress >= tvram_base_address && byteaddress < tvram_base_address + 4000) { ! 137: if(int_10h_feh_called && !int_10h_ffh_called && mem[byteaddress] != data) { ! 138: COORD co; ! 139: DWORD num; ! 140: ! 141: co.X = ((byteaddress - tvram_base_address) >> 1) % 80; ! 142: co.Y = ((byteaddress - tvram_base_address) >> 1) / 80; ! 143: ! 144: if(byteaddress & 1) { ! 145: scr_attr[0] = data; ! 146: WriteConsoleOutputAttribute(hStdout, scr_attr, 1, co, &num); ! 147: } else { ! 148: scr_char[0] = data; ! 149: WriteConsoleOutputCharacter(hStdout, scr_char, 1, co, &num); ! 150: } ! 151: } ! 152: } ! 153: mem[byteaddress] = data; ! 154: } ! 155: } ! 156: ! 157: void write_word(offs_t byteaddress, UINT16 data) ! 158: { ! 159: if(byteaddress < MAX_MEM - 1) { ! 160: if(byteaddress >= tvram_base_address && byteaddress < tvram_base_address + 4000) { ! 161: if(int_10h_feh_called && !int_10h_ffh_called && *(UINT16 *)(mem + byteaddress) != data) { ! 162: if(byteaddress & 1) { ! 163: write_byte(byteaddress , data ); ! 164: write_byte(byteaddress + 1, data >> 8); ! 165: } else { ! 166: COORD co; ! 167: DWORD num; ! 168: ! 169: co.X = ((byteaddress - tvram_base_address) >> 1) % 80; ! 170: co.Y = ((byteaddress - tvram_base_address) >> 1) / 80; ! 171: ! 172: scr_char[0] = data; ! 173: scr_attr[0] = data >> 8; ! 174: ! 175: WriteConsoleOutputCharacter(hStdout, scr_char, 1, co, &num); ! 176: WriteConsoleOutputAttribute(hStdout, scr_attr, 1, co, &num); ! 177: } ! 178: return; ! 179: } ! 180: } ! 181: *(UINT16 *)(mem + byteaddress) = data; ! 182: } ! 183: } ! 184: ! 185: void write_dword(offs_t byteaddress, UINT32 data) ! 186: { ! 187: if(byteaddress < MAX_MEM - 3) { ! 188: if(byteaddress >= tvram_base_address && byteaddress < tvram_base_address + 4000) { ! 189: if(int_10h_feh_called && !int_10h_ffh_called && *(UINT32 *)(mem + byteaddress) != data) { ! 190: if(byteaddress & 1) { ! 191: write_byte(byteaddress , data ); ! 192: write_byte(byteaddress + 1, data >> 8); ! 193: write_byte(byteaddress + 2, data >> 16); ! 194: write_byte(byteaddress + 3, data >> 24); ! 195: } else { ! 196: COORD co; ! 197: DWORD num; ! 198: ! 199: co.X = ((byteaddress - tvram_base_address) >> 1) % 80; ! 200: co.Y = ((byteaddress - tvram_base_address) >> 1) / 80; ! 201: ! 202: scr_char[0] = data; ! 203: scr_attr[0] = data >> 8; ! 204: scr_char[1] = data >> 16; ! 205: scr_attr[1] = data >> 24; ! 206: ! 207: WriteConsoleOutputCharacter(hStdout, scr_char, 2, co, &num); ! 208: WriteConsoleOutputAttribute(hStdout, scr_attr, 2, co, &num); ! 209: } ! 210: return; ! 211: } ! 212: } ! 213: *(UINT32 *)(mem + byteaddress) = data; ! 214: } ! 215: } ! 216: ! 217: // accessor methods for reading decrypted data ! 218: #define read_decrypted_byte read_byte ! 219: #define read_decrypted_word read_word ! 220: #define read_decrypted_dword read_dword ! 221: ! 222: UINT8 read_io_byte(offs_t byteaddress); ! 223: UINT16 read_io_word(offs_t byteaddress); ! 224: UINT32 read_io_dword(offs_t byteaddress); ! 225: ! 226: void write_io_byte(offs_t byteaddress, UINT8 data); ! 227: void write_io_word(offs_t byteaddress, UINT16 data); ! 228: void write_io_dword(offs_t byteaddress, UINT32 data); ! 229: ! 230: /*****************************************************************************/ ! 231: /* src/emu/emucore.h */ ! 232: ! 233: // constants for expression endianness ! 234: enum endianness_t ! 235: { ! 236: ENDIANNESS_LITTLE, ! 237: ENDIANNESS_BIG ! 238: }; ! 239: ! 240: // declare native endianness to be one or the other ! 241: #ifdef LSB_FIRST ! 242: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_LITTLE; ! 243: #else ! 244: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_BIG; ! 245: #endif ! 246: ! 247: // endian-based value: first value is if 'endian' is little-endian, second is if 'endian' is big-endian ! 248: #define ENDIAN_VALUE_LE_BE(endian,leval,beval) (((endian) == ENDIANNESS_LITTLE) ? (leval) : (beval)) ! 249: ! 250: // endian-based value: first value is if native endianness is little-endian, second is if native is big-endian ! 251: #define NATIVE_ENDIAN_VALUE_LE_BE(leval,beval) ENDIAN_VALUE_LE_BE(ENDIANNESS_NATIVE, leval, beval) ! 252: ! 253: // endian-based value: first value is if 'endian' matches native, second is if 'endian' doesn't match native ! 254: #define ENDIAN_VALUE_NE_NNE(endian,leval,beval) (((endian) == ENDIANNESS_NATIVE) ? (neval) : (nneval)) ! 255: ! 256: /*****************************************************************************/ ! 257: /* src/emu/didisasm.h */ ! 258: ! 259: // Disassembler constants ! 260: const UINT32 DASMFLAG_SUPPORTED = 0x80000000; // are disassembly flags supported? ! 261: const UINT32 DASMFLAG_STEP_OUT = 0x40000000; // this instruction should be the end of a step out sequence ! 262: const UINT32 DASMFLAG_STEP_OVER = 0x20000000; // this instruction should be stepped over by setting a breakpoint afterwards ! 263: const UINT32 DASMFLAG_OVERINSTMASK = 0x18000000; // number of extra instructions to skip when stepping over ! 264: const UINT32 DASMFLAG_OVERINSTSHIFT = 27; // bits to shift after masking to get the value ! 265: const UINT32 DASMFLAG_LENGTHMASK = 0x0000ffff; // the low 16-bits contain the actual length ! 266: ! 267: /*****************************************************************************/ ! 268: /* src/osd/osdcomm.h */ ! 269: ! 270: /* Highly useful macro for compile-time knowledge of an array size */ ! 271: #define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0])) ! 272: ! 273: #include "softfloat/softfloat.c" ! 274: #include "i386/i386.c" ! 275: #ifdef SUPPORT_DISASSEMBLER ! 276: #include "i386/i386dasm.c" ! 277: bool dasm = false; ! 278: #endif ! 279: ! 280: i386_state *cpustate; ! 281: int cpu_type, cpu_step; ! 282: ! 283: void i386_jmp_far(UINT16 selector, UINT32 address) ! 284: { ! 285: if(PROTECTED_MODE && !V8086_MODE) { ! 286: i386_protected_mode_jump(cpustate, selector, address, 1, cpustate->operand_size); ! 287: } else { ! 288: cpustate->sreg[CS].selector = selector; ! 289: cpustate->performed_intersegment_jump = 1; ! 290: i386_load_segment_descriptor(cpustate, CS); ! 291: cpustate->eip = address; ! 292: CHANGE_PC(cpustate, cpustate->eip); ! 293: } ! 294: } ! 295: ! 296: /* ---------------------------------------------------------------------------- ! 297: main ! 298: ---------------------------------------------------------------------------- */ ! 299: ! 300: int main(int argc, char *argv[], char *envp[]) ! 301: { ! 302: int standard_env = (argc > 1 && _stricmp(argv[1], "-e") == 0); ! 303: ! 304: if(argc < 2 + standard_env) { ! 305: #ifdef _WIN64 ! 306: fprintf(stderr, "MS-DOS Player for Win32-x64 console\n\n"); ! 307: #else ! 308: fprintf(stderr, "MS-DOS Player for Win32 console\n\n"); ! 309: #endif ! 310: fprintf(stderr, "Usage: MSDOS [-e] (command file) [opions]\n"); ! 311: return(EXIT_FAILURE); ! 312: } ! 313: ! 314: CONSOLE_SCREEN_BUFFER_INFO csbi; ! 315: hStdin = GetStdHandle(STD_INPUT_HANDLE); ! 316: hStdout = GetStdHandle(STD_OUTPUT_HANDLE); ! 317: GetConsoleScreenBufferInfo(hStdout, &csbi); ! 318: ! 319: for(int y = 0; y < SCR_BUF_SIZE; y++) { ! 320: for(int x = 0; x < 80; x++) { ! 321: scr_buf[y][x].Char.AsciiChar = ' '; ! 322: scr_buf[y][x].Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; ! 323: } ! 324: } ! 325: scr_buf_size.X = 80; ! 326: scr_buf_size.Y = SCR_BUF_SIZE; ! 327: scr_buf_pos.X = scr_buf_pos.Y = 0; ! 328: scr_width = csbi.dwSize.X; ! 329: scr_height = csbi.dwSize.Y; ! 330: cursor_moved = false; ! 331: ! 332: key_buf_char = new FIFO(); ! 333: key_buf_scan = new FIFO(); ! 334: ! 335: hardware_init(); ! 336: ! 337: if(msdos_init(argc - (standard_env + 1), argv + (standard_env + 1), envp, standard_env)) { ! 338: retval = EXIT_FAILURE; ! 339: } else { ! 340: timeBeginPeriod(1); ! 341: hardware_run(); ! 342: msdos_finish(); ! 343: timeEndPeriod(1); ! 344: } ! 345: hardware_finish(); ! 346: ! 347: delete key_buf_char; ! 348: delete key_buf_scan; ! 349: ! 350: SetConsoleTextAttribute(hStdout, csbi.wAttributes); ! 351: ! 352: return(retval); ! 353: } ! 354: ! 355: /* ---------------------------------------------------------------------------- ! 356: MS-DOS virtual machine ! 357: ---------------------------------------------------------------------------- */ ! 358: ! 359: void update_key_buffer() ! 360: { ! 361: DWORD dwRead; ! 362: INPUT_RECORD ir[16]; ! 363: ! 364: if(ReadConsoleInputA(hStdin, ir, 16, &dwRead)) { ! 365: for(int i = 0; i < dwRead; i++) { ! 366: if((ir[i].EventType & KEY_EVENT) && ir[i].Event.KeyEvent.bKeyDown) { ! 367: if(ir[i].Event.KeyEvent.uChar.AsciiChar == 0) { ! 368: // ignore shift, ctrl and alt keys ! 369: if(ir[i].Event.KeyEvent.wVirtualScanCode != 0x1d && ! 370: ir[i].Event.KeyEvent.wVirtualScanCode != 0x2a && ! 371: ir[i].Event.KeyEvent.wVirtualScanCode != 0x36 && ! 372: ir[i].Event.KeyEvent.wVirtualScanCode != 0x38) { ! 373: key_buf_char->write(0x00); ! 374: key_buf_scan->write(ir[i].Event.KeyEvent.dwControlKeyState & ENHANCED_KEY ? 0xe0 : 0x00); ! 375: key_buf_char->write(0x00); ! 376: key_buf_scan->write(ir[i].Event.KeyEvent.wVirtualScanCode & 0xff); ! 377: } ! 378: } else { ! 379: key_buf_char->write(ir[i].Event.KeyEvent.uChar.AsciiChar & 0xff); ! 380: key_buf_scan->write(ir[i].Event.KeyEvent.wVirtualScanCode & 0xff); ! 381: } ! 382: } ! 383: } ! 384: } ! 385: if(key_buf_char->count() == 0) { ! 386: Sleep(10); ! 387: } ! 388: } ! 389: ! 390: // process info ! 391: ! 392: process_t *msdos_process_info_create(UINT16 psp_seg) ! 393: { ! 394: for(int i = 0; i < MAX_PROCESS; i++) { ! 395: if(process[i].psp == 0 || process[i].psp == psp_seg) { ! 396: memset(&process[i], 0, sizeof(process_t)); ! 397: process[i].psp = psp_seg; ! 398: return(&process[i]); ! 399: } ! 400: } ! 401: fatalerror("too many processes\n"); ! 402: return(NULL); ! 403: } ! 404: ! 405: process_t *msdos_process_info_get(UINT16 psp_seg) ! 406: { ! 407: for(int i = 0; i < MAX_PROCESS; i++) { ! 408: if(process[i].psp == psp_seg) { ! 409: return(&process[i]); ! 410: } ! 411: } ! 412: fatalerror("invalid psp address\n"); ! 413: return(NULL); ! 414: } ! 415: ! 416: void msdos_cds_update(int drv) ! 417: { ! 418: cds_t *cds = (cds_t *)(mem + CDS_TOP); ! 419: ! 420: memset(mem + CDS_TOP, 0, CDS_SIZE); ! 421: sprintf(cds->path_name, "%c:\\", 'A' + drv); ! 422: cds->drive_attrib = 0x4000; // physical drive ! 423: cds->physical_drive_number = drv; ! 424: } ! 425: ! 426: // dbcs ! 427: ! 428: void msdos_dbcs_table_update() ! 429: { ! 430: UINT8 dbcs_data[DBCS_SIZE]; ! 431: memset(dbcs_data, 0, sizeof(dbcs_data)); ! 432: ! 433: CPINFO info; ! 434: GetCPInfo(active_code_page, &info); ! 435: ! 436: if(info.MaxCharSize != 1) { ! 437: for(int i = 0;; i += 2) { ! 438: UINT8 lo = info.LeadByte[i + 0]; ! 439: UINT8 hi = info.LeadByte[i + 1]; ! 440: dbcs_data[2 + i + 0] = lo; ! 441: dbcs_data[2 + i + 1] = hi; ! 442: if(lo == 0 && hi == 0) { ! 443: dbcs_data[0] = i + 2; ! 444: break; ! 445: } ! 446: } ! 447: } else { ! 448: dbcs_data[0] = 2; // ??? ! 449: } ! 450: memcpy(mem + DBCS_TOP, dbcs_data, sizeof(dbcs_data)); ! 451: } ! 452: ! 453: void msdos_dbcs_table_init() ! 454: { ! 455: system_code_page = active_code_page = _getmbcp(); ! 456: msdos_dbcs_table_update(); ! 457: } ! 458: ! 459: void msdos_dbcs_table_finish() ! 460: { ! 461: if(active_code_page != system_code_page) { ! 462: _setmbcp(system_code_page); ! 463: } ! 464: } ! 465: ! 466: int msdos_lead_byte_check(UINT8 code) ! 467: { ! 468: UINT8 *dbcs_table = mem + DBCS_TABLE; ! 469: ! 470: for(int i = 0;; i += 2) { ! 471: UINT8 lo = dbcs_table[i + 0]; ! 472: UINT8 hi = dbcs_table[i + 1]; ! 473: if(lo == 0 && hi == 0) { ! 474: break; ! 475: } ! 476: if(lo <= code && code <= hi) { ! 477: return(1); ! 478: } ! 479: } ! 480: return(0); ! 481: } ! 482: ! 483: // file control ! 484: ! 485: char *msdos_trimmed_path(char *path, int lfn) ! 486: { ! 487: static char tmp[MAX_PATH]; ! 488: ! 489: if(lfn) { ! 490: strcpy(tmp, path); ! 491: } else { ! 492: // remove space in the path ! 493: char *src = path, *dst = tmp; ! 494: ! 495: while(*src != '\0') { ! 496: if(msdos_lead_byte_check(*src)) { ! 497: *dst++ = *src++; ! 498: *dst++ = *src++; ! 499: } else if(*src != ' ') { ! 500: *dst++ = *src++; ! 501: } else { ! 502: src++; // skip space ! 503: } ! 504: } ! 505: *dst = '\0'; ! 506: } ! 507: return(tmp); ! 508: } ! 509: ! 510: bool match(char *text, char *pattern) ! 511: { ! 512: //http://www.prefield.com/algorithm/string/wildcard.html ! 513: switch (*pattern) { ! 514: case '\0': ! 515: return !*text; ! 516: case '*': ! 517: return match(text, pattern + 1) || *text && match(text + 1, pattern); ! 518: case '?': ! 519: return *text && match(text + 1, pattern + 1); ! 520: default: ! 521: return (*text == *pattern) && match(text + 1, pattern + 1); ! 522: } ! 523: } ! 524: ! 525: bool msdos_match_volume_label(char *path, char *volume) ! 526: { ! 527: char *p; ! 528: ! 529: if((p = my_strchr(path, ':')) != NULL) { ! 530: return msdos_match_volume_label(p + 1, volume); ! 531: } else if((p = my_strchr(path, '\\')) != NULL) { ! 532: return msdos_match_volume_label(p + 1, volume); ! 533: } else if((p = my_strchr(path, '.')) != NULL) { ! 534: *p = '\0'; ! 535: bool result = match(volume, path); ! 536: *p = '.'; ! 537: return result; ! 538: } else { ! 539: return match(volume, path); ! 540: } ! 541: } ! 542: ! 543: char *msdos_fcb_path(fcb_t *fcb) ! 544: { ! 545: static char tmp[MAX_PATH]; ! 546: char name[9], ext[4]; ! 547: ! 548: memset(name, 0, sizeof(name)); ! 549: memcpy(name, fcb->file_name, 8); ! 550: strcpy(name, msdos_trimmed_path(name, 0)); ! 551: ! 552: memset(ext, 0, sizeof(ext)); ! 553: memcpy(ext, fcb->file_name + 8, 3); ! 554: strcpy(ext, msdos_trimmed_path(ext, 0)); ! 555: ! 556: if(name[0] == '\0' || strcmp(name, "????????") == 0) { ! 557: strcpy(name, "*"); ! 558: } ! 559: if(ext[0] == '\0') { ! 560: strcpy(tmp, name); ! 561: } else { ! 562: if(strcmp(ext, "???") == 0) { ! 563: strcpy(ext, "*"); ! 564: } ! 565: sprintf(tmp, "%s.%s", name, ext); ! 566: } ! 567: return(tmp); ! 568: } ! 569: ! 570: void msdos_set_fcb_path(fcb_t *fcb, char *path) ! 571: { ! 572: char *ext = my_strchr(path, '.'); ! 573: ! 574: memset(fcb->file_name, 0x20, 8 + 3); ! 575: if(ext != NULL && path[0] != '.') { ! 576: *ext = '\0'; ! 577: memcpy(fcb->file_name + 8, ext + 1, strlen(ext + 1)); ! 578: } ! 579: memcpy(fcb->file_name, path, strlen(path)); ! 580: } ! 581: ! 582: char *msdos_short_path(char *path) ! 583: { ! 584: static char tmp[MAX_PATH]; ! 585: ! 586: GetShortPathName(path, tmp, MAX_PATH); ! 587: my_strupr(tmp); ! 588: return(tmp); ! 589: } ! 590: ! 591: char *msdos_short_full_path(char *path) ! 592: { ! 593: static char tmp[MAX_PATH]; ! 594: char full[MAX_PATH], *name; ! 595: ! 596: GetFullPathName(path, MAX_PATH, full, &name); ! 597: GetShortPathName(full, tmp, MAX_PATH); ! 598: my_strupr(tmp); ! 599: return(tmp); ! 600: } ! 601: ! 602: char *msdos_short_full_dir(char *path) ! 603: { ! 604: static char tmp[MAX_PATH]; ! 605: char full[MAX_PATH], *name; ! 606: ! 607: GetFullPathName(path, MAX_PATH, full, &name); ! 608: name[-1] = '\0'; ! 609: GetShortPathName(full, tmp, MAX_PATH); ! 610: my_strupr(tmp); ! 611: return(tmp); ! 612: } ! 613: ! 614: char *msdos_local_file_path(char *path, int lfn) ! 615: { ! 616: char *trimmed = msdos_trimmed_path(path, lfn); ! 617: ! 618: if(_access(trimmed, 0) != 0) { ! 619: process_t *process = msdos_process_info_get(current_psp); ! 620: static char tmp[MAX_PATH]; ! 621: ! 622: sprintf(tmp, "%s\\%s", process->module_dir, trimmed); ! 623: if(_access(tmp, 0) == 0) { ! 624: return(tmp); ! 625: } ! 626: } ! 627: return(trimmed); ! 628: } ! 629: ! 630: int msdos_drive_number(char *path) ! 631: { ! 632: char tmp[MAX_PATH], *name; ! 633: ! 634: GetFullPathName(path, MAX_PATH, tmp, &name); ! 635: if(tmp[0] >= 'a' && tmp[0] <= 'z') { ! 636: return(tmp[0] - 'a'); ! 637: } else { ! 638: return(tmp[0] - 'A'); ! 639: } ! 640: } ! 641: ! 642: char *msdos_volume_label(char *path) ! 643: { ! 644: static char tmp[MAX_PATH]; ! 645: char volume[] = "A:\\"; ! 646: ! 647: if(path[1] == ':') { ! 648: volume[0] = path[0]; ! 649: } else { ! 650: volume[0] = 'A' + _getdrive() - 1; ! 651: } ! 652: if(!GetVolumeInformation(volume, tmp, MAX_PATH, NULL, NULL, NULL, NULL, 0)) { ! 653: memset(tmp, 0, sizeof(tmp)); ! 654: } ! 655: return(tmp); ! 656: } ! 657: ! 658: char *msdos_short_volume_label(char *label) ! 659: { ! 660: static char tmp[(8 + 1 + 3) + 1]; ! 661: char *src = label; ! 662: int remain = strlen(label); ! 663: char *dst_n = tmp; ! 664: char *dst_e = tmp + 9; ! 665: ! 666: strcpy(tmp, " . "); ! 667: for(int i = 0; i < 8 && remain > 0; i++) { ! 668: if(msdos_lead_byte_check(*src)) { ! 669: if(++i == 8) { ! 670: break; ! 671: } ! 672: *dst_n++ = *src++; ! 673: remain--; ! 674: } ! 675: *dst_n++ = *src++; ! 676: remain--; ! 677: } ! 678: if(remain > 0) { ! 679: for(int i = 0; i < 3 && remain > 0; i++) { ! 680: if(msdos_lead_byte_check(*src)) { ! 681: if(++i == 3) { ! 682: break; ! 683: } ! 684: *dst_e++ = *src++; ! 685: remain--; ! 686: } ! 687: *dst_e++ = *src++; ! 688: remain--; ! 689: } ! 690: *dst_e = '\0'; ! 691: } else { ! 692: *dst_n = '\0'; ! 693: } ! 694: my_strupr(tmp); ! 695: return(tmp); ! 696: } ! 697: ! 698: void msdos_file_handler_open(int fd, char *path, int atty, int mode, UINT16 info, UINT16 psp_seg) ! 699: { ! 700: static int id = 0; ! 701: char full[MAX_PATH], *name; ! 702: ! 703: if(psp_seg && fd < 20) { ! 704: psp_t *psp = (psp_t *)(mem + (psp_seg << 4)); ! 705: psp->file_table[fd] = fd; ! 706: } ! 707: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) { ! 708: strcpy(file_handler[fd].path, full); ! 709: } else { ! 710: strcpy(file_handler[fd].path, path); ! 711: } ! 712: file_handler[fd].valid = 1; ! 713: file_handler[fd].id = id++; // dummy id for int 21h ax=71a6h ! 714: file_handler[fd].atty = atty; ! 715: file_handler[fd].mode = mode; ! 716: file_handler[fd].info = info; ! 717: file_handler[fd].psp = psp_seg; ! 718: } ! 719: ! 720: void msdos_file_handler_dup(int dst, int src, UINT16 psp_seg) ! 721: { ! 722: if(psp_seg && dst < 20) { ! 723: psp_t *psp = (psp_t *)(mem + (psp_seg << 4)); ! 724: psp->file_table[dst] = dst; ! 725: } ! 726: strcpy(file_handler[dst].path, file_handler[src].path); ! 727: file_handler[dst].valid = 1; ! 728: file_handler[dst].id = file_handler[src].id; ! 729: file_handler[dst].atty = file_handler[src].atty; ! 730: file_handler[dst].mode = file_handler[src].mode; ! 731: file_handler[dst].info = file_handler[src].info; ! 732: file_handler[dst].psp = psp_seg; ! 733: } ! 734: ! 735: void msdos_file_handler_close(int fd, UINT16 psp_seg) ! 736: { ! 737: if(psp_seg && fd < 20) { ! 738: psp_t *psp = (psp_t *)(mem + (psp_seg << 4)); ! 739: psp->file_table[fd] = 0xff; ! 740: } ! 741: file_handler[fd].valid = 0; ! 742: } ! 743: ! 744: int msdos_file_attribute_create(UINT16 new_attr) ! 745: { ! 746: int attr = 0; ! 747: ! 748: if(REG16(CX) & 0x01) { ! 749: attr |= FILE_ATTRIBUTE_READONLY; ! 750: } ! 751: if(REG16(CX) & 0x02) { ! 752: attr |= FILE_ATTRIBUTE_HIDDEN; ! 753: } ! 754: if(REG16(CX) & 0x04) { ! 755: attr |= FILE_ATTRIBUTE_SYSTEM; ! 756: } ! 757: if(REG16(CX) & 0x20) { ! 758: attr |= FILE_ATTRIBUTE_ARCHIVE; ! 759: } ! 760: return(attr); ! 761: } ! 762: ! 763: // find file ! 764: ! 765: int msdos_find_file_check_attribute(int attribute, int allowed_mask, int required_mask) ! 766: { ! 767: if((allowed_mask & 0x08) && !(attribute & FILE_ATTRIBUTE_DIRECTORY)) { ! 768: return(0); // search directory only !!! ! 769: } else if(!(allowed_mask & 0x02) && (attribute & FILE_ATTRIBUTE_HIDDEN)) { ! 770: return(0); ! 771: } else if(!(allowed_mask & 0x04) && (attribute & FILE_ATTRIBUTE_SYSTEM)) { ! 772: return(0); ! 773: } else if(!(allowed_mask & 0x10) && (attribute & FILE_ATTRIBUTE_DIRECTORY)) { ! 774: return(0); ! 775: } else if((attribute & required_mask) != required_mask) { ! 776: return(0); ! 777: } else { ! 778: return(1); ! 779: } ! 780: } ! 781: ! 782: void msdos_find_file_conv_local_time(WIN32_FIND_DATA *fd) ! 783: { ! 784: FILETIME local; ! 785: ! 786: FileTimeToLocalFileTime(&fd->ftCreationTime, &local); ! 787: fd->ftCreationTime.dwLowDateTime = local.dwLowDateTime; ! 788: fd->ftCreationTime.dwHighDateTime = local.dwHighDateTime; ! 789: ! 790: FileTimeToLocalFileTime(&fd->ftLastAccessTime, &local); ! 791: fd->ftLastAccessTime.dwLowDateTime = local.dwLowDateTime; ! 792: fd->ftLastAccessTime.dwHighDateTime = local.dwHighDateTime; ! 793: ! 794: FileTimeToLocalFileTime(&fd->ftLastWriteTime, &local); ! 795: fd->ftLastWriteTime.dwLowDateTime = local.dwLowDateTime; ! 796: fd->ftLastWriteTime.dwHighDateTime = local.dwHighDateTime; ! 797: } ! 798: ! 799: // i/o ! 800: ! 801: void msdos_putch(UINT8 data); ! 802: ! 803: void msdos_stdio_reopen() ! 804: { ! 805: if(!file_handler[0].valid) { ! 806: _dup2(DUP_STDIN, 0); ! 807: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0); ! 808: } ! 809: if(!file_handler[1].valid) { ! 810: _dup2(DUP_STDOUT, 1); ! 811: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0); ! 812: } ! 813: if(!file_handler[2].valid) { ! 814: _dup2(DUP_STDERR, 2); ! 815: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0); ! 816: } ! 817: } ! 818: ! 819: int msdos_kbhit() ! 820: { ! 821: msdos_stdio_reopen(); ! 822: ! 823: if(!file_handler[0].atty) { ! 824: // stdin is redirected to file ! 825: return(eof(0) == 0); ! 826: } ! 827: ! 828: // check keyboard status ! 829: if(key_buf_char->count() != 0) { ! 830: return(1); ! 831: } else { ! 832: return(_kbhit()); ! 833: } ! 834: } ! 835: ! 836: int msdos_getch_ex(int echo) ! 837: { ! 838: static char prev = 0; ! 839: ! 840: msdos_stdio_reopen(); ! 841: ! 842: if(!file_handler[0].atty) { ! 843: // stdin is redirected to file ! 844: retry: ! 845: char data; ! 846: if(_read(0, &data, 1) == 1) { ! 847: char tmp = data; ! 848: if(data == 0x0a) { ! 849: if(prev == 0x0d) { ! 850: goto retry; // CRLF -> skip LF ! 851: } else { ! 852: data = 0x0d; // LF only -> CR ! 853: } ! 854: } ! 855: prev = tmp; ! 856: return(data); ! 857: } ! 858: return(EOF); ! 859: } ! 860: ! 861: // input from console ! 862: while(key_buf_char->count() == 0) { ! 863: update_key_buffer(); ! 864: } ! 865: int key_char = key_buf_char->read(); ! 866: int key_scan = key_buf_scan->read(); ! 867: ! 868: if(echo && key_char) { ! 869: msdos_putch(key_char); ! 870: } ! 871: return key_char ? key_char : (key_scan != 0xe0) ? key_scan : 0; ! 872: } ! 873: ! 874: inline int msdos_getch() ! 875: { ! 876: return(msdos_getch_ex(0)); ! 877: } ! 878: ! 879: inline int msdos_getche() ! 880: { ! 881: return(msdos_getch_ex(1)); ! 882: } ! 883: ! 884: int msdos_write(int fd, const void *buffer, unsigned int count) ! 885: { ! 886: static int is_cr = 0; ! 887: ! 888: if(fd == 1 && !file_handler[1].atty) { ! 889: // CR+LF -> LF ! 890: UINT8 *buf = (UINT8 *)buffer; ! 891: for(unsigned int i = 0; i < count; i++) { ! 892: UINT8 data = buf[i]; ! 893: if(is_cr) { ! 894: if(data != 0x0a) { ! 895: UINT8 tmp = 0x0d; ! 896: _write(1, &tmp, 1); ! 897: } ! 898: _write(1, &data, 1); ! 899: is_cr = 0; ! 900: } else if(data == 0x0d) { ! 901: is_cr = 1; ! 902: } else { ! 903: _write(1, &data, 1); ! 904: } ! 905: } ! 906: return(count); ! 907: } ! 908: return(_write(fd, buffer, count)); ! 909: } ! 910: ! 911: void msdos_putch(UINT8 data) ! 912: { ! 913: static int p = 0; ! 914: static int is_kanji = 0; ! 915: static int is_esc = 0; ! 916: static int stored_x; ! 917: static int stored_y; ! 918: static WORD stored_a; ! 919: static char tmp[64]; ! 920: ! 921: msdos_stdio_reopen(); ! 922: ! 923: if(!file_handler[1].atty) { ! 924: // stdout is redirected to file ! 925: msdos_write(1, &data, 1); ! 926: return; ! 927: } ! 928: ! 929: // output to console ! 930: tmp[p++] = data; ! 931: ! 932: if(is_kanji) { ! 933: // kanji character ! 934: is_kanji = 0; ! 935: } else if(is_esc) { ! 936: // escape sequense ! 937: if((tmp[1] == ')' || tmp[1] == '(') && p == 3) { ! 938: p = is_esc = 0; ! 939: } else if(tmp[1] == '=' && p == 4) { ! 940: COORD co; ! 941: co.X = tmp[3] - 0x20; ! 942: co.Y = tmp[2] - 0x20; ! 943: SetConsoleCursorPosition(hStdout, co); ! 944: mem[0x450 + mem[0x462] * 2] = co.X; ! 945: mem[0x451 + mem[0x462] * 2] = co.Y; ! 946: cursor_moved = false; ! 947: p = is_esc = 0; ! 948: } else if((data >= 'a' && data <= 'z') || (data >= 'A' && data <= 'Z') || data == '*') { ! 949: CONSOLE_SCREEN_BUFFER_INFO csbi; ! 950: COORD co; ! 951: GetConsoleScreenBufferInfo(hStdout, &csbi); ! 952: co.X = csbi.dwCursorPosition.X; ! 953: co.Y = csbi.dwCursorPosition.Y; ! 954: WORD wAttributes = csbi.wAttributes; ! 955: ! 956: if(tmp[1] == 'D') { ! 957: co.Y++; ! 958: } else if(tmp[1] == 'E') { ! 959: co.X = 0; ! 960: co.Y++; ! 961: } else if(tmp[1] == 'M') { ! 962: co.Y--; ! 963: } else if(tmp[1] == '*') { ! 964: SMALL_RECT rect; ! 965: SET_RECT(rect, 0, 0, csbi.dwSize.X - 1, csbi.dwSize.Y - 1); ! 966: WriteConsoleOutput(hStdout, &scr_buf[0][0], scr_buf_size, scr_buf_pos, &rect); ! 967: co.X = co.Y = 0; ! 968: } else if(tmp[1] == '[') { ! 969: int param[256], params = 0; ! 970: memset(param, 0, sizeof(param)); ! 971: for(int i = 2; i < p; i++) { ! 972: if(tmp[i] >= '0' && tmp[i] <= '9') { ! 973: param[params] *= 10; ! 974: param[params] += tmp[i] - '0'; ! 975: } else { ! 976: params++; ! 977: } ! 978: } ! 979: if(data == 'A') { ! 980: co.Y -= param[0]; ! 981: } else if(data == 'B') { ! 982: co.Y += param[0]; ! 983: } else if(data == 'C') { ! 984: co.X += param[0]; ! 985: } else if(data == 'D') { ! 986: co.X -= param[0]; ! 987: } else if(data == 'H' || data == 'f') { ! 988: co.X = param[1] - 1; ! 989: co.Y = param[0] - 1; ! 990: } else if(data == 'J') { ! 991: SMALL_RECT rect; ! 992: if(param[0] == 0) { ! 993: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y); ! 994: WriteConsoleOutput(hStdout, &scr_buf[0][0], scr_buf_size, scr_buf_pos, &rect); ! 995: if(co.Y < csbi.dwSize.Y - 1) { ! 996: SET_RECT(rect, 0, co.Y + 1, csbi.dwSize.X - 1, csbi.dwSize.Y - 1); ! 997: WriteConsoleOutput(hStdout, &scr_buf[0][0], scr_buf_size, scr_buf_pos, &rect); ! 998: } ! 999: } else if(param[0] == 1) { ! 1000: if(co.Y > 0) { ! 1001: SET_RECT(rect, 0, 0, csbi.dwSize.X - 1, co.Y - 1); ! 1002: WriteConsoleOutput(hStdout, &scr_buf[0][0], scr_buf_size, scr_buf_pos, &rect); ! 1003: } ! 1004: SET_RECT(rect, 0, co.Y, co.X, co.Y); ! 1005: WriteConsoleOutput(hStdout, &scr_buf[0][0], scr_buf_size, scr_buf_pos, &rect); ! 1006: } else if(param[0] == 2) { ! 1007: SET_RECT(rect, 0, 0, csbi.dwSize.X - 1, csbi.dwSize.Y - 1); ! 1008: WriteConsoleOutput(hStdout, &scr_buf[0][0], scr_buf_size, scr_buf_pos, &rect); ! 1009: co.X = co.Y = 0; ! 1010: } ! 1011: } else if(data == 'K') { ! 1012: SMALL_RECT rect; ! 1013: if(param[0] == 0) { ! 1014: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y); ! 1015: WriteConsoleOutput(hStdout, &scr_buf[0][0], scr_buf_size, scr_buf_pos, &rect); ! 1016: } else if(param[0] == 1) { ! 1017: SET_RECT(rect, 0, co.Y, co.X, co.Y); ! 1018: WriteConsoleOutput(hStdout, &scr_buf[0][0], scr_buf_size, scr_buf_pos, &rect); ! 1019: } else if(param[0] == 2) { ! 1020: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y); ! 1021: WriteConsoleOutput(hStdout, &scr_buf[0][0], scr_buf_size, scr_buf_pos, &rect); ! 1022: } ! 1023: } else if(data == 'L') { ! 1024: SMALL_RECT rect; ! 1025: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.dwSize.Y - 1); ! 1026: ReadConsoleOutput(hStdout, &scr_buf[0][0], scr_buf_size, scr_buf_pos, &rect); ! 1027: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.dwSize.Y - 1); ! 1028: WriteConsoleOutput(hStdout, &scr_buf[0][0], scr_buf_size, scr_buf_pos, &rect); ! 1029: // clear buffer ! 1030: for(int y = 0; y < SCR_BUF_SIZE; y++) { ! 1031: for(int x = 0; x < 80; x++) { ! 1032: scr_buf[y][x].Char.AsciiChar = ' '; ! 1033: scr_buf[y][x].Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; ! 1034: } ! 1035: } ! 1036: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y + param[0] - 1); ! 1037: WriteConsoleOutput(hStdout, &scr_buf[0][0], scr_buf_size, scr_buf_pos, &rect); ! 1038: co.X = 0; ! 1039: } else if(data == 'M') { ! 1040: SMALL_RECT rect; ! 1041: if(co.Y + param[0] > csbi.dwSize.Y - 1) { ! 1042: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.dwSize.Y - 1); ! 1043: WriteConsoleOutput(hStdout, &scr_buf[0][0], scr_buf_size, scr_buf_pos, &rect); ! 1044: } else { ! 1045: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.dwSize.Y - 1); ! 1046: ReadConsoleOutput(hStdout, &scr_buf[0][0], scr_buf_size, scr_buf_pos, &rect); ! 1047: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.dwSize.Y - 1); ! 1048: WriteConsoleOutput(hStdout, &scr_buf[0][0], scr_buf_size, scr_buf_pos, &rect); ! 1049: // clear buffer ! 1050: for(int y = 0; y < SCR_BUF_SIZE; y++) { ! 1051: for(int x = 0; x < 80; x++) { ! 1052: scr_buf[y][x].Char.AsciiChar = ' '; ! 1053: scr_buf[y][x].Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; ! 1054: } ! 1055: } ! 1056: } ! 1057: co.X = 0; ! 1058: } else if(data == 'h') { ! 1059: if(tmp[2] == '>' && tmp[3] == '5') { ! 1060: CONSOLE_CURSOR_INFO cur; ! 1061: GetConsoleCursorInfo(hStdout, &cur); ! 1062: if(cur.bVisible) { ! 1063: cur.bVisible = FALSE; ! 1064: GetConsoleCursorInfo(hStdout, &cur); ! 1065: } ! 1066: } ! 1067: } else if(data == 'l') { ! 1068: if(tmp[2] == '>' && tmp[3] == '5') { ! 1069: CONSOLE_CURSOR_INFO cur; ! 1070: GetConsoleCursorInfo(hStdout, &cur); ! 1071: if(!cur.bVisible) { ! 1072: cur.bVisible = TRUE; ! 1073: GetConsoleCursorInfo(hStdout, &cur); ! 1074: } ! 1075: } ! 1076: } else if(data == 'm') { ! 1077: wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; ! 1078: int reverse = 0, hidden = 0; ! 1079: for(int i = 0; i < params; i++) { ! 1080: if(param[i] == 1) { ! 1081: wAttributes |= FOREGROUND_INTENSITY; ! 1082: } else if(param[i] == 4) { ! 1083: wAttributes |= COMMON_LVB_UNDERSCORE; ! 1084: } else if(param[i] == 7) { ! 1085: reverse = 1; ! 1086: } else if(param[i] == 8 || param[i] == 16) { ! 1087: hidden = 1; ! 1088: } else if((param[i] >= 17 && param[i] <= 23) || (param[i] >= 30 && param[i] <= 37)) { ! 1089: wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); ! 1090: if(param[i] >= 17 && param[i] <= 23) { ! 1091: param[i] -= 16; ! 1092: } else { ! 1093: param[i] -= 30; ! 1094: } ! 1095: if(param[i] & 1) { ! 1096: wAttributes |= FOREGROUND_RED; ! 1097: } ! 1098: if(param[i] & 2) { ! 1099: wAttributes |= FOREGROUND_GREEN; ! 1100: } ! 1101: if(param[i] & 4) { ! 1102: wAttributes |= FOREGROUND_BLUE; ! 1103: } ! 1104: } else if(param[i] >= 40 && param[i] <= 47) { ! 1105: wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); ! 1106: if((param[i] - 40) & 1) { ! 1107: wAttributes |= BACKGROUND_RED; ! 1108: } ! 1109: if((param[i] - 40) & 2) { ! 1110: wAttributes |= BACKGROUND_GREEN; ! 1111: } ! 1112: if((param[i] - 40) & 4) { ! 1113: wAttributes |= BACKGROUND_BLUE; ! 1114: } ! 1115: } ! 1116: } ! 1117: if(reverse) { ! 1118: wAttributes &= ~0xff; ! 1119: wAttributes |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; ! 1120: } ! 1121: if(hidden) { ! 1122: wAttributes &= ~0x0f; ! 1123: wAttributes |= (wAttributes >> 4) & 0x0f; ! 1124: } ! 1125: } else if(data == 'n') { ! 1126: if(param[0] == 6) { ! 1127: char tmp[16]; ! 1128: sprintf(tmp, "\x1b[%d;%dR", co.Y + 1, co.X + 1); ! 1129: int len = strlen(tmp); ! 1130: for(int i = 0; i < len; i++) { ! 1131: key_buf_char->write(tmp[i]); ! 1132: key_buf_scan->write(0x00); ! 1133: } ! 1134: } ! 1135: } else if(data == 's') { ! 1136: stored_x = co.X; ! 1137: stored_y = co.Y; ! 1138: stored_a = wAttributes; ! 1139: } else if(data == 'u') { ! 1140: co.X = stored_x; ! 1141: co.Y = stored_y; ! 1142: wAttributes = stored_a; ! 1143: } ! 1144: } ! 1145: if(co.X < 0) { ! 1146: co.X = 0; ! 1147: } else if(co.X >= csbi.dwSize.X) { ! 1148: co.X = csbi.dwSize.X - 1; ! 1149: } ! 1150: if(co.Y < 0) { ! 1151: co.Y = 0; ! 1152: } else if(co.Y >= csbi.dwSize.Y) { ! 1153: co.Y = csbi.dwSize.Y - 1; ! 1154: } ! 1155: if(co.X != csbi.dwCursorPosition.X || co.Y != csbi.dwCursorPosition.Y) { ! 1156: SetConsoleCursorPosition(hStdout, co); ! 1157: mem[0x450 + mem[0x462] * 2] = co.X; ! 1158: mem[0x451 + mem[0x462] * 2] = co.Y; ! 1159: cursor_moved = false; ! 1160: } ! 1161: if(wAttributes != csbi.wAttributes) { ! 1162: SetConsoleTextAttribute(hStdout, wAttributes); ! 1163: } ! 1164: p = is_esc = 0; ! 1165: } ! 1166: return; ! 1167: } else { ! 1168: if(msdos_lead_byte_check(data)) { ! 1169: is_kanji = 1; ! 1170: return; ! 1171: } else if(data == 0x1b) { ! 1172: is_esc = 1; ! 1173: return; ! 1174: } ! 1175: } ! 1176: tmp[p++] = '\0'; ! 1177: p = 0; ! 1178: printf("%s", tmp); ! 1179: cursor_moved = true; ! 1180: } ! 1181: ! 1182: int msdos_aux_in() ! 1183: { ! 1184: #ifdef SUPPORT_AUX_PRN ! 1185: if(file_handler[3].valid && !eof(3)) { ! 1186: char data = 0; ! 1187: _read(3, &data, 1); ! 1188: return(data); ! 1189: } else { ! 1190: return(EOF); ! 1191: } ! 1192: #else ! 1193: return(0); ! 1194: #endif ! 1195: } ! 1196: ! 1197: void msdos_aux_out(char data) ! 1198: { ! 1199: #ifdef SUPPORT_AUX_PRN ! 1200: if(file_handler[3].valid) { ! 1201: msdos_write(3, &data, 1); ! 1202: } ! 1203: #endif ! 1204: } ! 1205: ! 1206: void msdos_prn_out(char data) ! 1207: { ! 1208: #ifdef SUPPORT_AUX_PRN ! 1209: if(file_handler[4].valid) { ! 1210: msdos_write(4, &data, 1); ! 1211: } ! 1212: #endif ! 1213: } ! 1214: ! 1215: // memory control ! 1216: ! 1217: mcb_t *msdos_mcb_create(int mcb_seg, UINT8 mz, UINT16 psp, UINT16 paragraphs) ! 1218: { ! 1219: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4)); ! 1220: ! 1221: mcb->mz = mz; ! 1222: mcb->psp = psp; ! 1223: mcb->paragraphs = paragraphs; ! 1224: return(mcb); ! 1225: } ! 1226: ! 1227: void msdos_mcb_check(mcb_t *mcb) ! 1228: { ! 1229: if(!(mcb->mz == 'M' || mcb->mz == 'Z')) { ! 1230: fatalerror("broken mcb\n"); ! 1231: } ! 1232: } ! 1233: ! 1234: int msdos_mem_split(int seg, int paragraphs) ! 1235: { ! 1236: int mcb_seg = seg - 1; ! 1237: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4)); ! 1238: msdos_mcb_check(mcb); ! 1239: ! 1240: if(mcb->paragraphs > paragraphs) { ! 1241: int new_seg = mcb_seg + 1 + paragraphs; ! 1242: int new_paragraphs = mcb->paragraphs - paragraphs - 1; ! 1243: ! 1244: msdos_mcb_create(new_seg, mcb->mz, 0, new_paragraphs); ! 1245: mcb->mz = 'M'; ! 1246: mcb->paragraphs = paragraphs; ! 1247: return(0); ! 1248: } ! 1249: return(-1); ! 1250: } ! 1251: ! 1252: void msdos_mem_merge(int seg) ! 1253: { ! 1254: int mcb_seg = seg - 1; ! 1255: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4)); ! 1256: msdos_mcb_check(mcb); ! 1257: ! 1258: while(1) { ! 1259: if(mcb->mz == 'Z') { ! 1260: break; ! 1261: } ! 1262: int next_seg = mcb_seg + 1 + mcb->paragraphs; ! 1263: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4)); ! 1264: msdos_mcb_check(next_mcb); ! 1265: ! 1266: if(next_mcb->psp != 0) { ! 1267: break; ! 1268: } ! 1269: mcb->mz = next_mcb->mz; ! 1270: mcb->paragraphs += 1 + next_mcb->paragraphs; ! 1271: } ! 1272: } ! 1273: ! 1274: int msdos_mem_alloc(int paragraphs, int new_process) ! 1275: { ! 1276: int mcb_seg = current_psp - 1; ! 1277: ! 1278: while(1) { ! 1279: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4)); ! 1280: msdos_mcb_check(mcb); ! 1281: ! 1282: if(!new_process || mcb->mz == 'Z') { ! 1283: if(mcb->psp == 0 && mcb->paragraphs >= paragraphs) { ! 1284: msdos_mem_split(mcb_seg + 1, paragraphs); ! 1285: mcb->psp = current_psp; ! 1286: return(mcb_seg + 1); ! 1287: } ! 1288: } ! 1289: if(mcb->mz == 'Z') { ! 1290: break; ! 1291: } ! 1292: mcb_seg += 1 + mcb->paragraphs; ! 1293: } ! 1294: return(-1); ! 1295: } ! 1296: ! 1297: int msdos_mem_realloc(int seg, int paragraphs, int *max_paragraphs) ! 1298: { ! 1299: int mcb_seg = seg - 1; ! 1300: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4)); ! 1301: msdos_mcb_check(mcb); ! 1302: int current_paragraphs = mcb->paragraphs; ! 1303: ! 1304: msdos_mem_merge(seg); ! 1305: if(paragraphs > mcb->paragraphs) { ! 1306: *max_paragraphs = mcb->paragraphs; ! 1307: msdos_mem_split(seg, current_paragraphs); ! 1308: return(-1); ! 1309: } ! 1310: msdos_mem_split(seg, paragraphs); ! 1311: return(0); ! 1312: } ! 1313: ! 1314: void msdos_mem_free(int seg) ! 1315: { ! 1316: int mcb_seg = seg - 1; ! 1317: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4)); ! 1318: msdos_mcb_check(mcb); ! 1319: ! 1320: mcb->psp = 0; ! 1321: msdos_mem_merge(seg); ! 1322: } ! 1323: ! 1324: int msdos_mem_get_free(int new_process) ! 1325: { ! 1326: int mcb_seg = current_psp - 1; ! 1327: int max_paragraphs = 0; ! 1328: ! 1329: while(1) { ! 1330: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4)); ! 1331: msdos_mcb_check(mcb); ! 1332: ! 1333: if(!new_process || mcb->mz == 'Z') { ! 1334: if(mcb->psp == 0 && mcb->paragraphs > max_paragraphs) { ! 1335: max_paragraphs = mcb->paragraphs; ! 1336: } ! 1337: } ! 1338: if(mcb->mz == 'Z') { ! 1339: break; ! 1340: } ! 1341: mcb_seg += 1 + mcb->paragraphs; ! 1342: } ! 1343: return(max_paragraphs); ! 1344: } ! 1345: ! 1346: // environment ! 1347: ! 1348: void msdos_env_set_argv(int env_seg, char *argv) ! 1349: { ! 1350: char *dst = (char *)(mem + (env_seg << 4)); ! 1351: ! 1352: while(1) { ! 1353: if(dst[0] == 0) { ! 1354: break; ! 1355: } ! 1356: dst += strlen(dst) + 1; ! 1357: } ! 1358: *dst++ = 0; // end of environment ! 1359: *dst++ = 1; // top of argv[0] ! 1360: *dst++ = 0; ! 1361: memcpy(dst, argv, strlen(argv)); ! 1362: dst += strlen(argv); ! 1363: *dst++ = 0; ! 1364: *dst++ = 0; ! 1365: } ! 1366: ! 1367: char *msdos_env_get_argv(int env_seg) ! 1368: { ! 1369: static char env[ENV_SIZE]; ! 1370: char *src = env; ! 1371: ! 1372: memcpy(src, mem + (env_seg << 4), ENV_SIZE); ! 1373: while(1) { ! 1374: if(src[0] == 0) { ! 1375: if(src[1] == 1) { ! 1376: return(src + 3); ! 1377: } ! 1378: break; ! 1379: } ! 1380: src += strlen(src) + 1; ! 1381: } ! 1382: return(NULL); ! 1383: } ! 1384: ! 1385: char *msdos_env_get(int env_seg, const char *name) ! 1386: { ! 1387: static char env[ENV_SIZE]; ! 1388: char *src = env; ! 1389: ! 1390: memcpy(src, mem + (env_seg << 4), ENV_SIZE); ! 1391: while(1) { ! 1392: if(src[0] == 0) { ! 1393: break; ! 1394: } ! 1395: int len = strlen(src); ! 1396: char *n = my_strtok(src, "="); ! 1397: char *v = src + strlen(n) + 1; ! 1398: ! 1399: if(_stricmp(name, n) == 0) { ! 1400: return(v); ! 1401: } ! 1402: src += len + 1; ! 1403: } ! 1404: return(NULL); ! 1405: } ! 1406: ! 1407: void msdos_env_set(int env_seg, char *name, char *value) ! 1408: { ! 1409: char env[ENV_SIZE]; ! 1410: char *src = env; ! 1411: char *dst = (char *)(mem + (env_seg << 4)); ! 1412: char *argv = msdos_env_get_argv(env_seg); ! 1413: int done = 0; ! 1414: ! 1415: memcpy(src, dst, ENV_SIZE); ! 1416: memset(dst, 0, ENV_SIZE); ! 1417: while(1) { ! 1418: if(src[0] == 0) { ! 1419: break; ! 1420: } ! 1421: int len = strlen(src); ! 1422: char *n = my_strtok(src, "="); ! 1423: char *v = src + strlen(n) + 1; ! 1424: char tmp[1024]; ! 1425: ! 1426: if(_stricmp(name, n) == 0) { ! 1427: sprintf(tmp, "%s=%s", n, value); ! 1428: done = 1; ! 1429: } else { ! 1430: sprintf(tmp, "%s=%s", n, v); ! 1431: } ! 1432: memcpy(dst, tmp, strlen(tmp)); ! 1433: dst += strlen(tmp) + 1; ! 1434: src += len + 1; ! 1435: } ! 1436: if(!done) { ! 1437: char tmp[1024]; ! 1438: ! 1439: sprintf(tmp, "%s=%s", name, value); ! 1440: memcpy(dst, tmp, strlen(tmp)); ! 1441: dst += strlen(tmp) + 1; ! 1442: } ! 1443: if(argv) { ! 1444: *dst++ = 0; // end of environment ! 1445: *dst++ = 1; // top of argv[0] ! 1446: *dst++ = 0; ! 1447: memcpy(dst, argv, strlen(argv)); ! 1448: dst += strlen(argv); ! 1449: *dst++ = 0; ! 1450: *dst++ = 0; ! 1451: } ! 1452: } ! 1453: ! 1454: // process ! 1455: ! 1456: psp_t *msdos_psp_create(int psp_seg, UINT16 first_mcb, UINT16 parent_psp, UINT16 env_seg) ! 1457: { ! 1458: psp_t *psp = (psp_t *)(mem + (psp_seg << 4)); ! 1459: ! 1460: memset(psp, 0, PSP_SIZE); ! 1461: psp->exit[0] = 0xcd; ! 1462: psp->exit[1] = 0x20; ! 1463: psp->first_mcb = first_mcb; ! 1464: psp->far_call = 0xea; ! 1465: psp->cpm_entry.w.l = 0xfff1; // int 21h, retf ! 1466: psp->cpm_entry.w.h = 0xf000; ! 1467: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22); ! 1468: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23); ! 1469: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24); ! 1470: psp->parent_psp = parent_psp; ! 1471: for(int i = 0; i < 20; i++) { ! 1472: if(file_handler[i].valid) { ! 1473: psp->file_table[i] = i; ! 1474: } else { ! 1475: psp->file_table[i] = 0xff; ! 1476: } ! 1477: } ! 1478: psp->env_seg = env_seg; ! 1479: psp->stack.w.l = REG16(SP); ! 1480: psp->stack.w.h = cpustate->sreg[SS].selector; ! 1481: psp->service[0] = 0xcd; ! 1482: psp->service[1] = 0x21; ! 1483: psp->service[2] = 0xcb; ! 1484: return(psp); ! 1485: } ! 1486: ! 1487: int msdos_process_exec(char *cmd, param_block_t *param, UINT8 al) ! 1488: { ! 1489: // load command file ! 1490: int fd = -1; ! 1491: int dos_command = 0; ! 1492: char command[MAX_PATH], path[MAX_PATH], opt[MAX_PATH], *name; ! 1493: ! 1494: strcpy(command, cmd); ! 1495: int opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l; ! 1496: int opt_len = mem[opt_ofs]; ! 1497: memset(opt, 0, sizeof(opt)); ! 1498: memcpy(opt, mem + opt_ofs + 1, opt_len); ! 1499: ! 1500: // check command.com ! 1501: GetFullPathName(command, MAX_PATH, path, &name); ! 1502: if(_stricmp(name, "COMMAND.COM") == 0 || _stricmp(name, "CMD.EXE") == 0) { ! 1503: for(int i = 0; i < opt_len; i++) { ! 1504: if(opt[i] == ' ') { ! 1505: continue; ! 1506: } ! 1507: if(opt[i] == '/' && (opt[i + 1] == 'c' || opt[i + 1] == 'C') && opt[i + 2] == ' ') { ! 1508: dos_command = 1; ! 1509: for(int j = i + 3; j < opt_len; j++) { ! 1510: if(opt[j] == ' ') { ! 1511: continue; ! 1512: } ! 1513: char *token = my_strtok(opt + j, " "); ! 1514: strcpy(command, token); ! 1515: char tmp[MAX_PATH]; ! 1516: strcpy(tmp, token + strlen(token) + 1); ! 1517: strcpy(opt, tmp); ! 1518: opt_len = strlen(opt); ! 1519: mem[opt_ofs] = opt_len; ! 1520: strcpy((char *)(mem + opt_ofs + 1), opt); ! 1521: break; ! 1522: } ! 1523: } ! 1524: break; ! 1525: } ! 1526: } ! 1527: ! 1528: // load command file ! 1529: strcpy(path, command); ! 1530: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) { ! 1531: sprintf(path, "%s.COM", command); ! 1532: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) { ! 1533: sprintf(path, "%s.EXE", command); ! 1534: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) { ! 1535: // search path in parent environments ! 1536: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4)); ! 1537: char *env = msdos_env_get(parent_psp->env_seg, "PATH"); ! 1538: ! 1539: if(env != NULL) { ! 1540: char env_path[1024]; ! 1541: strcpy(env_path, env); ! 1542: char *token = my_strtok(env_path, ";"); ! 1543: ! 1544: while(token != NULL) { ! 1545: sprintf(path, "%s\\%s", token, command); ! 1546: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) { ! 1547: break; ! 1548: } ! 1549: sprintf(path, "%s\\%s.COM", token, command); ! 1550: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) { ! 1551: break; ! 1552: } ! 1553: sprintf(path, "%s\\%s.EXE", token, command); ! 1554: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) { ! 1555: break; ! 1556: } ! 1557: token = my_strtok(NULL, ";"); ! 1558: } ! 1559: } ! 1560: } ! 1561: } ! 1562: } ! 1563: if(fd == -1) { ! 1564: if(dos_command) { ! 1565: // may be dos command ! 1566: char tmp[MAX_PATH]; ! 1567: sprintf(tmp, "%s %s", command, opt); ! 1568: system(tmp); ! 1569: return(0); ! 1570: } else { ! 1571: return(-1); ! 1572: } ! 1573: } ! 1574: _read(fd, file_buffer, sizeof(file_buffer)); ! 1575: _close(fd); ! 1576: ! 1577: // copy environment ! 1578: int env_seg, psp_seg; ! 1579: ! 1580: if((env_seg = msdos_mem_alloc(ENV_SIZE >> 4, 1)) == -1) { ! 1581: return(-1); ! 1582: } ! 1583: if(param->env_seg == 0) { ! 1584: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4)); ! 1585: memcpy(mem + (env_seg << 4), mem + (parent_psp->env_seg << 4), ENV_SIZE); ! 1586: } else { ! 1587: memcpy(mem + (env_seg << 4), mem + (param->env_seg << 4), ENV_SIZE); ! 1588: } ! 1589: msdos_env_set_argv(env_seg, msdos_short_full_path(path)); ! 1590: ! 1591: // check exe header ! 1592: exe_header_t *header = (exe_header_t *)file_buffer; ! 1593: int paragraphs, free_paragraphs = msdos_mem_get_free(1); ! 1594: UINT16 cs, ss, ip, sp; ! 1595: ! 1596: if(header->mz == 0x4d5a || header->mz == 0x5a4d) { ! 1597: // memory allocation ! 1598: int header_size = header->header_size * 16; ! 1599: int load_size = header->pages * 512 - header_size; ! 1600: if(header_size + load_size < 512) { ! 1601: load_size = 512 - header_size; ! 1602: } ! 1603: paragraphs = (PSP_SIZE + load_size) >> 4; ! 1604: if(paragraphs + header->min_alloc > free_paragraphs) { ! 1605: msdos_mem_free(env_seg); ! 1606: return(-1); ! 1607: } ! 1608: paragraphs += header->max_alloc ? header->max_alloc : header->min_alloc; ! 1609: if(paragraphs > free_paragraphs) { ! 1610: paragraphs = free_paragraphs; ! 1611: } ! 1612: if((psp_seg = msdos_mem_alloc(paragraphs, 1)) == -1) { ! 1613: msdos_mem_free(env_seg); ! 1614: return(-1); ! 1615: } ! 1616: // relocation ! 1617: int start_seg = psp_seg + (PSP_SIZE >> 4); ! 1618: for(int i = 0; i < header->relocations; i++) { ! 1619: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0); ! 1620: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2); ! 1621: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg; ! 1622: } ! 1623: memcpy(mem + (start_seg << 4), file_buffer + header_size, load_size); ! 1624: // segments ! 1625: cs = header->init_cs + start_seg; ! 1626: ss = header->init_ss + start_seg; ! 1627: ip = header->init_ip; ! 1628: sp = header->init_sp - 2; // for symdeb ! 1629: } else { ! 1630: // memory allocation ! 1631: paragraphs = free_paragraphs; ! 1632: if((psp_seg = msdos_mem_alloc(paragraphs, 1)) == -1) { ! 1633: msdos_mem_free(env_seg); ! 1634: return(-1); ! 1635: } ! 1636: int start_seg = psp_seg + (PSP_SIZE >> 4); ! 1637: memcpy(mem + (start_seg << 4), file_buffer, 0x10000 - PSP_SIZE); ! 1638: // segments ! 1639: cs = ss = psp_seg; ! 1640: ip = 0x100; ! 1641: sp = 0xfffe; ! 1642: } ! 1643: ! 1644: // create psp ! 1645: *(UINT16 *)(mem + 4 * 0x22 + 0) = cpustate->eip; ! 1646: *(UINT16 *)(mem + 4 * 0x22 + 2) = cpustate->sreg[CS].selector; ! 1647: psp_t *psp = msdos_psp_create(psp_seg, psp_seg + paragraphs, current_psp, env_seg); ! 1648: memcpy(psp->fcb1, mem + (param->fcb1.w.h << 4) + param->fcb1.w.l, sizeof(psp->fcb1)); ! 1649: memcpy(psp->fcb2, mem + (param->fcb2.w.h << 4) + param->fcb2.w.l, sizeof(psp->fcb2)); ! 1650: memcpy(psp->buffer, mem + (param->cmd_line.w.h << 4) + param->cmd_line.w.l, sizeof(psp->buffer)); ! 1651: ! 1652: mcb_t *mcb_env = (mcb_t *)(mem + ((env_seg - 1) << 4)); ! 1653: mcb_t *mcb_psp = (mcb_t *)(mem + ((psp_seg - 1) << 4)); ! 1654: mcb_psp->psp = mcb_env->psp = psp_seg; ! 1655: ! 1656: // process info ! 1657: process_t *process = msdos_process_info_create(psp_seg); ! 1658: strcpy(process->module_dir, msdos_short_full_dir(path)); ! 1659: process->dta.w.l = 0x80; ! 1660: process->dta.w.h = psp_seg; ! 1661: process->switchar = '/'; ! 1662: process->max_files = 20; ! 1663: process->find_handle = INVALID_HANDLE_VALUE; ! 1664: process->parent_int_10h_feh_called = int_10h_feh_called; ! 1665: process->parent_int_10h_ffh_called = int_10h_ffh_called; ! 1666: ! 1667: current_psp = psp_seg; ! 1668: ! 1669: if(al == 0x00) { ! 1670: int_10h_feh_called = int_10h_ffh_called = false; ! 1671: ! 1672: // registers and segments ! 1673: REG16(AX) = REG16(BX) = 0x00; ! 1674: REG16(CX) = 0xff; ! 1675: REG16(DX) = psp_seg; ! 1676: REG16(SI) = ip; ! 1677: REG16(DI) = sp; ! 1678: REG16(SP) = sp; ! 1679: cpustate->sreg[DS].selector = cpustate->sreg[ES].selector = psp_seg; ! 1680: cpustate->sreg[SS].selector = ss; ! 1681: i386_load_segment_descriptor(cpustate, DS); ! 1682: i386_load_segment_descriptor(cpustate, ES); ! 1683: i386_load_segment_descriptor(cpustate, SS); ! 1684: ! 1685: *(UINT16 *)(mem + (ss << 4) + sp) = 0; ! 1686: i386_jmp_far(cs, ip); ! 1687: } else if(al == 0x01) { ! 1688: // copy ss:sp and cs:ip to param block ! 1689: param->sp = sp; ! 1690: param->ss = ss; ! 1691: param->ip = ip; ! 1692: param->cs = cs; ! 1693: } ! 1694: return(0); ! 1695: } ! 1696: ! 1697: void msdos_process_terminate(int psp_seg, int ret, int mem_free) ! 1698: { ! 1699: psp_t *psp = (psp_t *)(mem + (psp_seg << 4)); ! 1700: ! 1701: *(UINT32 *)(mem + 4 * 0x22) = psp->int_22h.dw; ! 1702: *(UINT32 *)(mem + 4 * 0x23) = psp->int_23h.dw; ! 1703: *(UINT32 *)(mem + 4 * 0x24) = psp->int_24h.dw; ! 1704: ! 1705: cpustate->sreg[SS].selector = psp->stack.w.h; ! 1706: i386_load_segment_descriptor(cpustate, SS); ! 1707: REG16(SP) = psp->stack.w.l; ! 1708: i386_jmp_far(psp->int_22h.w.h, psp->int_22h.w.l); ! 1709: ! 1710: process_t *process = msdos_process_info_get(psp_seg); ! 1711: int_10h_feh_called = process->parent_int_10h_feh_called; ! 1712: int_10h_ffh_called = process->parent_int_10h_ffh_called; ! 1713: ! 1714: if(mem_free) { ! 1715: int mcb_seg = psp->env_seg - 1; ! 1716: msdos_mcb_create(mcb_seg, 'Z', 0, (MEMORY_END >> 4) - mcb_seg - 1); ! 1717: ! 1718: for(int i = 0; i < MAX_FILES; i++) { ! 1719: if(file_handler[i].valid && file_handler[i].psp == psp_seg) { ! 1720: _close(i); ! 1721: msdos_file_handler_close(i, psp_seg); ! 1722: } ! 1723: } ! 1724: msdos_stdio_reopen(); ! 1725: ! 1726: if(process->find_handle != INVALID_HANDLE_VALUE) { ! 1727: FindClose(process->find_handle); ! 1728: process->find_handle = INVALID_HANDLE_VALUE; ! 1729: } ! 1730: } ! 1731: ! 1732: memset(process, 0, sizeof(process_t)); ! 1733: ! 1734: current_psp = psp->parent_psp; ! 1735: retval = ret; ! 1736: } ! 1737: ! 1738: // drive ! 1739: ! 1740: int msdos_drive_param_block_update(int drive_num, UINT16 *seg, UINT16 *ofs, int force_update) ! 1741: { ! 1742: *seg = DPB_TOP >> 4; ! 1743: *ofs = sizeof(dpb_t) * drive_num; ! 1744: dpb_t *dpb = (dpb_t *)(mem + (*seg << 4) + *ofs); ! 1745: ! 1746: if(!force_update && dpb->free_clusters != 0) { ! 1747: return(dpb->bytes_per_sector ? 1 : 0); ! 1748: } ! 1749: memset(dpb, 0, sizeof(dpb_t)); ! 1750: ! 1751: int res = 0; ! 1752: char dev[64]; ! 1753: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num); ! 1754: ! 1755: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); ! 1756: if(hFile != INVALID_HANDLE_VALUE) { ! 1757: DISK_GEOMETRY geo; ! 1758: DWORD dwSize; ! 1759: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) { ! 1760: dpb->bytes_per_sector = (UINT16)geo.BytesPerSector; ! 1761: dpb->highest_sector_num = (UINT8)(geo.SectorsPerTrack - 1); ! 1762: dpb->highest_cluster_num = (UINT16)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1); ! 1763: switch(geo.MediaType) { ! 1764: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K) ! 1765: dpb->media_type = 0xff; ! 1766: break; ! 1767: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K) ! 1768: dpb->media_type = 0xfe; ! 1769: break; ! 1770: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K) ! 1771: dpb->media_type = 0xfd; ! 1772: break; ! 1773: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K) ! 1774: dpb->media_type = 0xfc; ! 1775: break; ! 1776: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M) ! 1777: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5") ! 1778: dpb->media_type = 0xf9; ! 1779: break; ! 1780: case FixedMedia: // hard disk ! 1781: case RemovableMedia: ! 1782: dpb->media_type = 0xf8; ! 1783: break; ! 1784: default: ! 1785: dpb->media_type = 0xf0; ! 1786: break; ! 1787: } ! 1788: res = 1; ! 1789: } ! 1790: dpb->drive_num = drive_num; ! 1791: dpb->unit_num = drive_num; ! 1792: dpb->next_dpb_ofs = *ofs + sizeof(dpb_t); ! 1793: dpb->next_dpb_seg = *seg; ! 1794: dpb->free_clusters = 0xffff; ! 1795: CloseHandle(hFile); ! 1796: } ! 1797: return(res); ! 1798: } ! 1799: ! 1800: // pc bios ! 1801: ! 1802: int get_tvram_address(int page) ! 1803: { ! 1804: if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) { ! 1805: return TVRAM_TOP; ! 1806: } else { ! 1807: return TVRAM_TOP + 0x1000 * (page & 7); ! 1808: } ! 1809: } ! 1810: ! 1811: inline int get_tvram_address(int page, int x, int y) ! 1812: { ! 1813: return get_tvram_address(page) + (x + y * 80) * 2; ! 1814: } ! 1815: ! 1816: inline void pcbios_int_10h_00h() ! 1817: { ! 1818: mem[0x449] = REG8(AL) & 0x7f; ! 1819: tvram_base_address = get_tvram_address(mem[0x462]); ! 1820: ! 1821: if(REG8(AL) & 0x80) { ! 1822: mem[0x487] |= 0x80; ! 1823: } else { ! 1824: for(int y = 0, ofs = get_tvram_address(mem[0x462]); y < 25; y++) { ! 1825: for(int x = 0; x < 80; x++) { ! 1826: scr_buf[y][x].Char.AsciiChar = ' '; ! 1827: scr_buf[y][x].Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; ! 1828: mem[ofs++] = 0x20; ! 1829: mem[ofs++] = 0x07; ! 1830: } ! 1831: } ! 1832: SMALL_RECT rect; ! 1833: SET_RECT(rect, 0, 0, 79, 24); ! 1834: WriteConsoleOutput(hStdout, &scr_buf[0][0], scr_buf_size, scr_buf_pos, &rect); ! 1835: mem[0x487] &= ~0x80; ! 1836: } ! 1837: } ! 1838: ! 1839: inline void pcbios_int_10h_01h() ! 1840: { ! 1841: mem[0x460] = REG8(CL); ! 1842: mem[0x461] = REG8(CH); ! 1843: } ! 1844: ! 1845: inline void pcbios_int_10h_02h() ! 1846: { ! 1847: if(mem[0x462] == REG8(BH)) { ! 1848: COORD co; ! 1849: co.X = REG8(DL); ! 1850: co.Y = REG8(DH); ! 1851: SetConsoleCursorPosition(hStdout, co); ! 1852: } ! 1853: mem[0x450 + (REG8(BH) & 7) * 2] = REG8(DL); ! 1854: mem[0x451 + (REG8(BH) & 7) * 2] = REG8(DH); ! 1855: } ! 1856: ! 1857: inline void pcbios_int_10h_03h() ! 1858: { ! 1859: REG8(DL) = mem[0x450 + (REG8(BH) & 7) * 2]; ! 1860: REG8(DH) = mem[0x451 + (REG8(BH) & 7) * 2]; ! 1861: REG8(CL) = mem[0x460]; ! 1862: REG8(CH) = mem[0x461]; ! 1863: } ! 1864: ! 1865: inline void pcbios_int_10h_05h() ! 1866: { ! 1867: if(mem[0x462] != REG8(BH)) { ! 1868: SMALL_RECT rect; ! 1869: SET_RECT(rect, 0, 0, 79, 24); ! 1870: ReadConsoleOutput(hStdout, &scr_buf[0][0], scr_buf_size, scr_buf_pos, &rect); ! 1871: ! 1872: for(int y = 0, ofs = get_tvram_address(mem[0x462]); y < 25; y++) { ! 1873: for(int x = 0; x < 80; x++) { ! 1874: mem[ofs++] = scr_buf[y][x].Char.AsciiChar; ! 1875: mem[ofs++] = scr_buf[y][x].Attributes; ! 1876: } ! 1877: } ! 1878: for(int y = 0, ofs = get_tvram_address(REG8(BH)); y < 25; y++) { ! 1879: for(int x = 0; x < 80; x++) { ! 1880: scr_buf[y][x].Char.AsciiChar = mem[ofs++]; ! 1881: scr_buf[y][x].Attributes = mem[ofs++]; ! 1882: } ! 1883: } ! 1884: WriteConsoleOutput(hStdout, &scr_buf[0][0], scr_buf_size, scr_buf_pos, &rect); ! 1885: ! 1886: COORD co; ! 1887: co.X = mem[0x450 + (REG8(BH) & 7) * 2]; ! 1888: co.Y = mem[0x451 + (REG8(BH) & 7) * 2]; ! 1889: SetConsoleCursorPosition(hStdout, co); ! 1890: } ! 1891: mem[0x462] = REG8(BH) & 7; ! 1892: mem[0x44e] = 0; ! 1893: mem[0x44f] = REG8(BH) << 4; ! 1894: tvram_base_address = get_tvram_address(mem[0x462]); ! 1895: } ! 1896: ! 1897: inline void pcbios_int_10h_06h() ! 1898: { ! 1899: SMALL_RECT rect; ! 1900: SET_RECT(rect, 0, 0, 79, 24); ! 1901: ReadConsoleOutput(hStdout, &scr_buf[0][0], scr_buf_size, scr_buf_pos, &rect); ! 1902: ! 1903: if(REG8(AL) == 0) { ! 1904: for(int y = REG8(CH); y <= REG8(DH); y++) { ! 1905: for(int x = REG8(CL), ofs = get_tvram_address(mem[0x462], REG8(CL), y); x <= REG8(DL); x++) { ! 1906: scr_buf[y][x].Char.AsciiChar = ' '; ! 1907: scr_buf[y][x].Attributes = REG8(BH); ! 1908: mem[ofs++] = scr_buf[y][x].Char.AsciiChar; ! 1909: mem[ofs++] = scr_buf[y][x].Attributes; ! 1910: } ! 1911: } ! 1912: } else { ! 1913: ReadConsoleOutput(hStdout, &scr_buf[0][0], scr_buf_size, scr_buf_pos, &rect); ! 1914: for(int y = REG8(CH), y2 = REG8(CH) + REG8(AL); y <= REG8(DH); y++, y2++) { ! 1915: for(int x = REG8(CL), ofs = get_tvram_address(mem[0x462], REG8(CL), y); x <= REG8(DL); x++) { ! 1916: if(y2 <= REG8(DH) && y2 >= 0 && y2 < SCR_BUF_SIZE) { ! 1917: scr_buf[y][x] = scr_buf[y2][x]; ! 1918: } else { ! 1919: scr_buf[y][x].Char.AsciiChar = ' '; ! 1920: scr_buf[y][x].Attributes = REG8(BH); ! 1921: } ! 1922: mem[ofs++] = scr_buf[y][x].Char.AsciiChar; ! 1923: mem[ofs++] = scr_buf[y][x].Attributes; ! 1924: } ! 1925: } ! 1926: } ! 1927: WriteConsoleOutput(hStdout, &scr_buf[0][0], scr_buf_size, scr_buf_pos, &rect); ! 1928: } ! 1929: ! 1930: inline void pcbios_int_10h_07h() ! 1931: { ! 1932: SMALL_RECT rect; ! 1933: SET_RECT(rect, 0, 0, 79, 24); ! 1934: ReadConsoleOutput(hStdout, &scr_buf[0][0], scr_buf_size, scr_buf_pos, &rect); ! 1935: ! 1936: if(REG8(AL) == 0) { ! 1937: for(int y = REG8(CH); y <= REG8(DH); y++) { ! 1938: for(int x = REG8(CL), ofs = get_tvram_address(mem[0x462], REG8(CL), y); x <= REG8(DL); x++) { ! 1939: scr_buf[y][x].Char.AsciiChar = ' '; ! 1940: scr_buf[y][x].Attributes = REG8(BH); ! 1941: mem[ofs++] = scr_buf[y][x].Char.AsciiChar; ! 1942: mem[ofs++] = scr_buf[y][x].Attributes; ! 1943: } ! 1944: } ! 1945: } else { ! 1946: ReadConsoleOutput(hStdout, &scr_buf[0][0], scr_buf_size, scr_buf_pos, &rect); ! 1947: for(int y = REG8(DH), y2 = REG8(DH) - REG8(AL); y >= REG8(CH); y--, y2--) { ! 1948: for(int x = REG8(CL), ofs = get_tvram_address(mem[0x462], REG8(CL), y); x <= REG8(DL); x++) { ! 1949: if(y2 >= REG8(CH) && y2 >= 0 && y2 < SCR_BUF_SIZE) { ! 1950: scr_buf[y][x] = scr_buf[y2][x]; ! 1951: } else { ! 1952: scr_buf[y][x].Char.AsciiChar = ' '; ! 1953: scr_buf[y][x].Attributes = REG8(BH); ! 1954: } ! 1955: mem[ofs++] = scr_buf[y][x].Char.AsciiChar; ! 1956: mem[ofs++] = scr_buf[y][x].Attributes; ! 1957: } ! 1958: } ! 1959: } ! 1960: WriteConsoleOutput(hStdout, &scr_buf[0][0], scr_buf_size, scr_buf_pos, &rect); ! 1961: } ! 1962: ! 1963: inline void pcbios_int_10h_08h() ! 1964: { ! 1965: COORD co; ! 1966: DWORD num; ! 1967: ! 1968: co.X = mem[0x450 + (REG8(BH) & 7) * 2]; ! 1969: co.Y = mem[0x451 + (REG8(BH) & 7) * 2]; ! 1970: ! 1971: if(mem[0x462] == REG8(BH)) { ! 1972: ReadConsoleOutputCharacter(hStdout, scr_char, 1, co, &num); ! 1973: ReadConsoleOutputAttribute(hStdout, scr_attr, 1, co, &num); ! 1974: REG8(AL) = scr_char[0]; ! 1975: REG8(AH) = scr_attr[0]; ! 1976: } else { ! 1977: REG16(AX) = *(UINT16 *)(mem + get_tvram_address(REG8(BH), co.X, co.Y)); ! 1978: } ! 1979: } ! 1980: ! 1981: inline void pcbios_int_10h_09h() ! 1982: { ! 1983: COORD co; ! 1984: DWORD num; ! 1985: ! 1986: co.X = mem[0x450 + (REG8(BH) & 7) * 2]; ! 1987: co.Y = mem[0x451 + (REG8(BH) & 7) * 2]; ! 1988: ! 1989: if(mem[0x462] == REG8(BH)) { ! 1990: for(int i = 0; i < REG16(CX) && i < 80 * 25; i++) { ! 1991: scr_char[i] = REG8(AL); ! 1992: scr_attr[i] = REG8(BL); ! 1993: } ! 1994: WriteConsoleOutputCharacter(hStdout, scr_char, REG16(CX), co, &num); ! 1995: WriteConsoleOutputAttribute(hStdout, scr_attr, REG16(CX), co, &num); ! 1996: } else { ! 1997: for(int i = 0, dest = get_tvram_address(REG8(BH), co.X, co.Y); i < REG16(CX); i++) { ! 1998: mem[dest++] = REG8(AL); ! 1999: mem[dest++] = REG8(BL); ! 2000: if(++co.X == 80) { ! 2001: if(++co.Y == 25) { ! 2002: break; ! 2003: } ! 2004: co.X = 0; ! 2005: } ! 2006: } ! 2007: } ! 2008: } ! 2009: ! 2010: inline void pcbios_int_10h_0ah() ! 2011: { ! 2012: COORD co; ! 2013: DWORD num; ! 2014: ! 2015: co.X = mem[0x450 + (REG8(BH) & 7) * 2]; ! 2016: co.Y = mem[0x451 + (REG8(BH) & 7) * 2]; ! 2017: ! 2018: if(mem[0x462] == REG8(BH)) { ! 2019: for(int i = 0; i < REG16(CX) && i < 80 * 25; i++) { ! 2020: scr_char[i] = REG8(AL); ! 2021: // scr_attr[i] = REG8(BL); ! 2022: } ! 2023: WriteConsoleOutputCharacter(hStdout, scr_char, REG16(CX), co, &num); ! 2024: // WriteConsoleOutputAttribute(hStdout, scr_attr, REG16(CX), co, &num); ! 2025: } else { ! 2026: for(int i = 0, dest = get_tvram_address(REG8(BH), co.X, co.Y); i < REG16(CX); i++) { ! 2027: mem[dest++] = REG8(AL); ! 2028: // mem[dest++] = REG8(BL); ! 2029: dest++; ! 2030: if(++co.X == 80) { ! 2031: if(++co.Y == 25) { ! 2032: break; ! 2033: } ! 2034: co.X = 0; ! 2035: } ! 2036: } ! 2037: } ! 2038: } ! 2039: ! 2040: inline void pcbios_int_10h_0eh() ! 2041: { ! 2042: msdos_putch(REG8(AL)); ! 2043: } ! 2044: ! 2045: inline void pcbios_int_10h_0fh() ! 2046: { ! 2047: REG8(AL) = mem[0x449]; ! 2048: REG8(AH) = mem[0x44a]; ! 2049: REG8(BH) = mem[0x462]; ! 2050: } ! 2051: ! 2052: inline void pcbios_int_10h_13h() ! 2053: { ! 2054: int ofs = cpustate->sreg[ES].base + REG16(BP); ! 2055: COORD co; ! 2056: DWORD num; ! 2057: ! 2058: co.X = REG8(DL); ! 2059: co.Y = REG8(DH); ! 2060: ! 2061: switch(REG8(AL)) { ! 2062: case 0x00: ! 2063: case 0x01: ! 2064: if(mem[0x462] == REG8(BH)) { ! 2065: CONSOLE_SCREEN_BUFFER_INFO csbi; ! 2066: GetConsoleScreenBufferInfo(hStdout, &csbi); ! 2067: SetConsoleCursorPosition(hStdout, co); ! 2068: ! 2069: if(csbi.wAttributes != REG8(BL)) { ! 2070: SetConsoleTextAttribute(hStdout, REG8(BL)); ! 2071: } ! 2072: for(int i = 0; i < REG16(CX); i++) { ! 2073: msdos_putch(mem[ofs++]); ! 2074: } ! 2075: if(csbi.wAttributes != REG8(BL)) { ! 2076: SetConsoleTextAttribute(hStdout, csbi.wAttributes); ! 2077: } ! 2078: if(REG8(AL) == 0x00) { ! 2079: co.X = mem[0x450 + (REG8(BH) & 7) * 2]; ! 2080: co.Y = mem[0x451 + (REG8(BH) & 7) * 2]; ! 2081: SetConsoleCursorPosition(hStdout, co); ! 2082: } else { ! 2083: cursor_moved = true; ! 2084: } ! 2085: } else { ! 2086: cpustate->CF = 1; ! 2087: } ! 2088: break; ! 2089: case 0x02: ! 2090: case 0x03: ! 2091: if(mem[0x462] == REG8(BH)) { ! 2092: CONSOLE_SCREEN_BUFFER_INFO csbi; ! 2093: GetConsoleScreenBufferInfo(hStdout, &csbi); ! 2094: SetConsoleCursorPosition(hStdout, co); ! 2095: ! 2096: WORD wAttributes = csbi.wAttributes; ! 2097: for(int i = 0; i < REG16(CX); i++, ofs += 2) { ! 2098: if(wAttributes != mem[ofs + 1]) { ! 2099: SetConsoleTextAttribute(hStdout, mem[ofs + 1]); ! 2100: wAttributes = mem[ofs + 1]; ! 2101: } ! 2102: msdos_putch(mem[ofs]); ! 2103: } ! 2104: if(csbi.wAttributes != wAttributes) { ! 2105: SetConsoleTextAttribute(hStdout, csbi.wAttributes); ! 2106: } ! 2107: if(REG8(AL) == 0x02) { ! 2108: co.X = mem[0x450 + (REG8(BH) & 7) * 2]; ! 2109: co.Y = mem[0x451 + (REG8(BH) & 7) * 2]; ! 2110: SetConsoleCursorPosition(hStdout, co); ! 2111: } else { ! 2112: cursor_moved = true; ! 2113: } ! 2114: } else { ! 2115: cpustate->CF = 1; ! 2116: } ! 2117: break; ! 2118: case 0x10: ! 2119: case 0x11: ! 2120: if(mem[0x462] == REG8(BH)) { ! 2121: ReadConsoleOutputCharacter(hStdout, scr_char, REG16(CX), co, &num); ! 2122: ReadConsoleOutputAttribute(hStdout, scr_attr, REG16(CX), co, &num); ! 2123: for(int i = 0; i < num; i++) { ! 2124: mem[ofs++] = scr_char[i]; ! 2125: mem[ofs++] = scr_attr[i]; ! 2126: if(REG8(AL) == 0x11) { ! 2127: mem[ofs++] = 0; ! 2128: mem[ofs++] = 0; ! 2129: } ! 2130: } ! 2131: } else { ! 2132: for(int i = 0, src = get_tvram_address(REG8(BH), co.X, co.Y); i < REG16(CX); i++) { ! 2133: mem[ofs++] = mem[src++]; ! 2134: mem[ofs++] = mem[src++]; ! 2135: if(REG8(AL) == 0x11) { ! 2136: mem[ofs++] = 0; ! 2137: mem[ofs++] = 0; ! 2138: } ! 2139: if(++co.X == 80) { ! 2140: if(++co.Y == 25) { ! 2141: break; ! 2142: } ! 2143: co.X = 0; ! 2144: } ! 2145: } ! 2146: } ! 2147: break; ! 2148: case 0x20: ! 2149: case 0x21: ! 2150: if(mem[0x462] == REG8(BH)) { ! 2151: for(int i = 0; i < REG16(CX) && i < 80 * 25; i++) { ! 2152: scr_char[i] = mem[ofs++]; ! 2153: scr_attr[i] = mem[ofs++]; ! 2154: if(REG8(AL) == 0x21) { ! 2155: ofs += 2; ! 2156: } ! 2157: } ! 2158: WriteConsoleOutputCharacter(hStdout, scr_char, REG16(CX), co, &num); ! 2159: WriteConsoleOutputAttribute(hStdout, scr_attr, REG16(CX), co, &num); ! 2160: } else { ! 2161: for(int i = 0, dest = get_tvram_address(REG8(BH), co.X, co.Y); i < REG16(CX); i++) { ! 2162: mem[dest++] = mem[ofs++]; ! 2163: mem[dest++] = mem[ofs++]; ! 2164: if(REG8(AL) == 0x21) { ! 2165: ofs += 2; ! 2166: } ! 2167: if(++co.X == 80) { ! 2168: if(++co.Y == 25) { ! 2169: break; ! 2170: } ! 2171: co.X = 0; ! 2172: } ! 2173: } ! 2174: } ! 2175: break; ! 2176: default: ! 2177: cpustate->CF = 1; ! 2178: break; ! 2179: } ! 2180: } ! 2181: ! 2182: inline void pcbios_int_10h_1dh() ! 2183: { ! 2184: switch(REG8(AL)) { ! 2185: case 0x01: ! 2186: break; ! 2187: case 0x02: ! 2188: REG16(BX) = 0; ! 2189: break; ! 2190: default: ! 2191: cpustate->CF = 1; ! 2192: break; ! 2193: } ! 2194: } ! 2195: ! 2196: inline void pcbios_int_10h_82h() ! 2197: { ! 2198: static UINT8 mode = 0; ! 2199: ! 2200: switch(REG8(AL)) { ! 2201: case 0: ! 2202: if(REG8(BL) != 0xff) { ! 2203: mode = REG8(BL); ! 2204: } ! 2205: REG8(AL) = mode; ! 2206: break; ! 2207: default: ! 2208: cpustate->CF = 1; ! 2209: break; ! 2210: } ! 2211: } ! 2212: ! 2213: inline void pcbios_int_10h_feh() ! 2214: { ! 2215: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) { ! 2216: cpustate->sreg[ES].selector = (TVRAM_TOP >> 4); ! 2217: i386_load_segment_descriptor(cpustate, ES); ! 2218: REG16(DI) = (TVRAM_TOP & 0x0f); ! 2219: } ! 2220: int_10h_feh_called = true; ! 2221: } ! 2222: ! 2223: inline void pcbios_int_10h_ffh() ! 2224: { ! 2225: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) { ! 2226: COORD co; ! 2227: DWORD num; ! 2228: ! 2229: co.X = (REG16(DI) >> 1) % 80; ! 2230: co.Y = (REG16(DI) >> 1) / 80; ! 2231: for(int i = 0, ofs = get_tvram_address(0, co.X, co.Y); i < REG16(CX) && i < 80 * 25; i++) { ! 2232: scr_char[i] = mem[ofs++]; ! 2233: scr_attr[i] = mem[ofs++]; ! 2234: } ! 2235: WriteConsoleOutputCharacter(hStdout, scr_char, REG16(CX), co, &num); ! 2236: WriteConsoleOutputAttribute(hStdout, scr_attr, REG16(CX), co, &num); ! 2237: } ! 2238: int_10h_ffh_called = true; ! 2239: } ! 2240: ! 2241: inline void pcbios_int_15h_23h() ! 2242: { ! 2243: switch(REG8(AL)) { ! 2244: case 0: ! 2245: REG8(CL) = cmos[0x2d]; ! 2246: REG8(CH) = cmos[0x2e]; ! 2247: break; ! 2248: case 1: ! 2249: cmos[0x2d] = REG8(CL); ! 2250: cmos[0x2e] = REG8(CH); ! 2251: break; ! 2252: default: ! 2253: REG8(AH) = 0x86; ! 2254: cpustate->CF = 1; ! 2255: break; ! 2256: } ! 2257: } ! 2258: ! 2259: inline void pcbios_int_15h_24h() ! 2260: { ! 2261: switch(REG8(AL)) { ! 2262: case 0: ! 2263: i386_set_a20_line(cpustate, 0); ! 2264: REG8(AH) = 0; ! 2265: break; ! 2266: case 1: ! 2267: i386_set_a20_line(cpustate, 1); ! 2268: REG8(AH) = 0; ! 2269: break; ! 2270: case 2: ! 2271: REG8(AH) = 0; ! 2272: REG8(AL) = (cpustate->a20_mask >> 20) & 1; ! 2273: REG16(CX) = 0; ! 2274: break; ! 2275: case 3: ! 2276: REG16(AX) = 0; ! 2277: REG16(BX) = 0; ! 2278: break; ! 2279: } ! 2280: } ! 2281: ! 2282: inline void pcbios_int_15h_49h() ! 2283: { ! 2284: REG8(AL) = 0; ! 2285: REG8(BL) = 0; // DOS/V; ! 2286: } ! 2287: ! 2288: inline void pcbios_int_15h_86h() ! 2289: { ! 2290: UINT32 usec = (REG16(CX) << 16) | REG16(DX); ! 2291: Sleep(usec / 1000); ! 2292: } ! 2293: ! 2294: inline void pcbios_int_15h_87h() ! 2295: { ! 2296: #if 1 ! 2297: // copy extended memory (from DOSBox) ! 2298: int len = REG16(CX) * 2; ! 2299: int ofs = cpustate->sreg[ES].base + REG16(SI); ! 2300: int src = (*(UINT32 *)(mem + ofs + 0x12) & 0xffffff); // + (mem[ofs + 0x16] << 24); ! 2301: int dst = (*(UINT32 *)(mem + ofs + 0x1a) & 0xffffff); // + (mem[ofs + 0x1e] << 24); ! 2302: memcpy(mem + dst, mem + src, len); ! 2303: REG16(AX) = 0x00; ! 2304: #else ! 2305: REG8(AH) = 0x86; ! 2306: cpustate->CF = 1; ! 2307: #endif ! 2308: } ! 2309: ! 2310: inline void pcbios_int_15h_88h() ! 2311: { ! 2312: REG16(AX) = ((min(MAX_MEM, 0x1000000) - 0x100000) >> 10); ! 2313: } ! 2314: ! 2315: inline void pcbios_int_15h_89h() ! 2316: { ! 2317: #if 1 ! 2318: // switch to protected mode (from DOSBox) ! 2319: write_io_byte(0x20, 0x10); ! 2320: write_io_byte(0x21, REG8(BH)); ! 2321: write_io_byte(0x21, 0x00); ! 2322: write_io_byte(0xa0, 0x10); ! 2323: write_io_byte(0xa1, REG8(BL)); ! 2324: write_io_byte(0xa1, 0x00); ! 2325: i386_set_a20_line(cpustate, 1); ! 2326: int ofs = cpustate->sreg[ES].base + REG16(SI); ! 2327: cpustate->gdtr.limit = *(UINT16 *)(mem + ofs + 0x08); ! 2328: cpustate->gdtr.base = *(UINT32 *)(mem + ofs + 0x08 + 0x02) & 0xffffff; ! 2329: cpustate->idtr.limit = *(UINT16 *)(mem + ofs + 0x10); ! 2330: cpustate->idtr.base = *(UINT32 *)(mem + ofs + 0x10 + 0x02) & 0xffffff; ! 2331: cpustate->cr[0] |= 1; ! 2332: cpustate->sreg[DS].selector = 0x18; ! 2333: cpustate->sreg[ES].selector = 0x20; ! 2334: cpustate->sreg[SS].selector = 0x28; ! 2335: i386_load_segment_descriptor(cpustate, DS); ! 2336: i386_load_segment_descriptor(cpustate, ES); ! 2337: i386_load_segment_descriptor(cpustate, SS); ! 2338: REG16(SP) += 6; ! 2339: set_flags(cpustate, 0); // ??? ! 2340: REG16(AX) = 0x00; ! 2341: i386_jmp_far(0x30, REG16(CX)); ! 2342: #else ! 2343: REG8(AH) = 0x86; ! 2344: cpustate->CF = 1; ! 2345: #endif ! 2346: } ! 2347: ! 2348: inline void pcbios_int_15h_c9h() ! 2349: { ! 2350: REG8(AH) = 0x00; ! 2351: REG8(CH) = cpu_type; ! 2352: REG8(CL) = cpu_step; ! 2353: } ! 2354: ! 2355: inline void pcbios_int_15h_cah() ! 2356: { ! 2357: switch(REG8(AL)) { ! 2358: case 0: ! 2359: if(REG8(BL) > 0x3f) { ! 2360: REG8(AH) = 0x03; ! 2361: cpustate->CF = 1; ! 2362: } else if(REG8(BL) < 0x0e) { ! 2363: REG8(AH) = 0x04; ! 2364: cpustate->CF = 1; ! 2365: } else { ! 2366: REG8(CL) = cmos[REG8(BL)]; ! 2367: } ! 2368: break; ! 2369: case 1: ! 2370: if(REG8(BL) > 0x3f) { ! 2371: REG8(AH) = 0x03; ! 2372: cpustate->CF = 1; ! 2373: } else if(REG8(BL) < 0x0e) { ! 2374: REG8(AH) = 0x04; ! 2375: cpustate->CF = 1; ! 2376: } else { ! 2377: cmos[REG8(BL)] = REG8(CL); ! 2378: } ! 2379: break; ! 2380: default: ! 2381: REG8(AH) = 0x86; ! 2382: cpustate->CF = 1; ! 2383: break; ! 2384: } ! 2385: } ! 2386: ! 2387: UINT32 get_key_code(bool clear_buffer) ! 2388: { ! 2389: UINT32 code = 0; ! 2390: ! 2391: if(key_buf_char->count() == 0) { ! 2392: update_key_buffer(); ! 2393: } ! 2394: if(!clear_buffer) { ! 2395: key_buf_char->store_buffer(); ! 2396: key_buf_scan->store_buffer(); ! 2397: } ! 2398: if(key_buf_char->count() != 0) { ! 2399: code = key_buf_char->read() | (key_buf_scan->read() << 8); ! 2400: } ! 2401: if(key_buf_char->count() != 0) { ! 2402: code |= (key_buf_char->read() << 16) | (key_buf_scan->read() << 24); ! 2403: } ! 2404: if(!clear_buffer) { ! 2405: key_buf_char->restore_buffer(); ! 2406: key_buf_scan->restore_buffer(); ! 2407: } ! 2408: return code; ! 2409: } ! 2410: ! 2411: inline void pcbios_int_16h_00h() ! 2412: { ! 2413: static UINT32 key_code = 0; ! 2414: ! 2415: while(key_code == 0) { ! 2416: key_code = get_key_code(true); ! 2417: } ! 2418: if((key_code & 0xffff) == 0x0000 || (key_code & 0xffff) == 0xe000) { ! 2419: if(REG8(AH) == 0x10) { ! 2420: key_code = ((key_code >> 8) & 0xff) | ((key_code >> 16) & 0xff00); ! 2421: } else { ! 2422: key_code = ((key_code >> 16) & 0xff00); ! 2423: } ! 2424: } ! 2425: REG16(AX) = key_code & 0xffff; ! 2426: key_code >>= 16; ! 2427: } ! 2428: ! 2429: inline void pcbios_int_16h_01h() ! 2430: { ! 2431: UINT32 key_code = get_key_code(false); ! 2432: ! 2433: if(key_code != 0) { ! 2434: if((key_code & 0xffff) == 0x0000 || (key_code & 0xffff) == 0xe000) { ! 2435: if(REG8(AH) == 0x11) { ! 2436: key_code = ((key_code >> 8) & 0xff) | ((key_code >> 16) & 0xff00); ! 2437: } else { ! 2438: key_code = ((key_code >> 16) & 0xff00); ! 2439: } ! 2440: } ! 2441: } ! 2442: if(key_code != 0) { ! 2443: REG16(AX) = key_code & 0xffff; ! 2444: } ! 2445: cpustate->ZF = (key_code == 0); ! 2446: } ! 2447: ! 2448: inline void pcbios_int_16h_02h() ! 2449: { ! 2450: REG8(AL) = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0; ! 2451: REG8(AL) |= (GetAsyncKeyState(VK_CAPITAL) & 0x0001) ? 0x40 : 0; ! 2452: REG8(AL) |= (GetAsyncKeyState(VK_NUMLOCK) & 0x0001) ? 0x20 : 0; ! 2453: REG8(AL) |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0; ! 2454: REG8(AL) |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0; ! 2455: REG8(AL) |= (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? 0x04 : 0; ! 2456: REG8(AL) |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0; ! 2457: REG8(AL) |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0; ! 2458: } ! 2459: ! 2460: inline void pcbios_int_16h_03h() ! 2461: { ! 2462: static UINT16 status = 0; ! 2463: ! 2464: switch(REG8(AL)) { ! 2465: case 0x05: ! 2466: status = REG16(BX); ! 2467: break; ! 2468: case 0x06: ! 2469: REG16(BX) = status; ! 2470: break; ! 2471: default: ! 2472: cpustate->CF = 1; ! 2473: break; ! 2474: } ! 2475: } ! 2476: ! 2477: inline void pcbios_int_16h_05h() ! 2478: { ! 2479: _ungetch(REG8(CL)); ! 2480: REG8(AL) = 0x00; ! 2481: } ! 2482: ! 2483: inline void pcbios_int_16h_12h() ! 2484: { ! 2485: pcbios_int_16h_02h(); ! 2486: ! 2487: REG8(AH) = 0;//(GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x80 : 0; ! 2488: REG8(AH) |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0; ! 2489: REG8(AH) |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0; ! 2490: REG8(AH) |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0; ! 2491: REG8(AH) |= (GetAsyncKeyState(VK_RMENU ) & 0x8000) ? 0x08 : 0; ! 2492: REG8(AH) |= (GetAsyncKeyState(VK_RCONTROL) & 0x8000) ? 0x04 : 0; ! 2493: REG8(AH) |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0; ! 2494: REG8(AH) |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0; ! 2495: } ! 2496: ! 2497: inline void pcbios_int_16h_13h() ! 2498: { ! 2499: static UINT16 status = 0; ! 2500: ! 2501: switch(REG8(AL)) { ! 2502: case 0x00: ! 2503: status = REG16(DX); ! 2504: break; ! 2505: case 0x01: ! 2506: REG16(DX) = status; ! 2507: break; ! 2508: default: ! 2509: cpustate->CF = 1; ! 2510: break; ! 2511: } ! 2512: } ! 2513: ! 2514: inline void pcbios_int_16h_14h() ! 2515: { ! 2516: static UINT8 status = 0; ! 2517: ! 2518: switch(REG8(AL)) { ! 2519: case 0x00: ! 2520: case 0x01: ! 2521: status = REG8(AL); ! 2522: break; ! 2523: case 0x02: ! 2524: REG8(AL) = status; ! 2525: break; ! 2526: default: ! 2527: cpustate->CF = 1; ! 2528: break; ! 2529: } ! 2530: } ! 2531: ! 2532: inline void pcbios_int_1ah_00h() ! 2533: { ! 2534: static WORD prev_day = 0; ! 2535: SYSTEMTIME time; ! 2536: ! 2537: GetLocalTime(&time); ! 2538: unsigned __int64 msec = ((time.wHour * 60 + time.wMinute) * 60 + time.wSecond) * 1000 + time.wMilliseconds; ! 2539: unsigned __int64 tick = msec * 0x1800b0 / 24 / 60 / 60 / 1000; ! 2540: REG16(CX) = (tick >> 16) & 0xffff; ! 2541: REG16(DX) = (tick ) & 0xffff; ! 2542: REG8(AL) = (prev_day != 0 && prev_day != time.wDay) ? 1 : 0; ! 2543: prev_day = time.wDay; ! 2544: } ! 2545: ! 2546: inline int to_bcd(int t) ! 2547: { ! 2548: int u = (t % 100) / 10; ! 2549: return (u << 4) | (t % 10); ! 2550: } ! 2551: ! 2552: inline void pcbios_int_1ah_02h() ! 2553: { ! 2554: SYSTEMTIME time; ! 2555: ! 2556: GetLocalTime(&time); ! 2557: REG8(CH) = to_bcd(time.wHour); ! 2558: REG8(CL) = to_bcd(time.wMinute); ! 2559: REG8(DH) = to_bcd(time.wSecond); ! 2560: REG8(DL) = 0x00; ! 2561: } ! 2562: ! 2563: inline void pcbios_int_1ah_04h() ! 2564: { ! 2565: SYSTEMTIME time; ! 2566: ! 2567: GetLocalTime(&time); ! 2568: REG8(CH) = to_bcd(time.wYear / 100); ! 2569: REG8(CL) = to_bcd(time.wYear); ! 2570: REG8(DH) = to_bcd(time.wMonth); ! 2571: REG8(DL) = to_bcd(time.wDay); ! 2572: } ! 2573: ! 2574: inline void pcbios_int_1ah_0ah() ! 2575: { ! 2576: SYSTEMTIME time; ! 2577: FILETIME file_time; ! 2578: WORD dos_date, dos_time; ! 2579: ! 2580: GetLocalTime(&time); ! 2581: SystemTimeToFileTime(&time, &file_time); ! 2582: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time); ! 2583: REG16(CX) = dos_date; ! 2584: } ! 2585: ! 2586: // msdos system call ! 2587: ! 2588: inline void msdos_int_21h_00h() ! 2589: { ! 2590: msdos_process_terminate(cpustate->sreg[CS].selector, retval, 1); ! 2591: } ! 2592: ! 2593: inline void msdos_int_21h_01h() ! 2594: { ! 2595: REG8(AL) = msdos_getche(); ! 2596: #ifdef SUPPORT_HARDWARE ! 2597: hardware_update(); ! 2598: #endif ! 2599: } ! 2600: ! 2601: inline void msdos_int_21h_02h() ! 2602: { ! 2603: msdos_putch(REG8(DL)); ! 2604: } ! 2605: ! 2606: inline void msdos_int_21h_03h() ! 2607: { ! 2608: REG8(AL) = msdos_aux_in(); ! 2609: } ! 2610: ! 2611: inline void msdos_int_21h_04h() ! 2612: { ! 2613: msdos_aux_out(REG8(DL)); ! 2614: } ! 2615: ! 2616: inline void msdos_int_21h_05h() ! 2617: { ! 2618: msdos_prn_out(REG8(DL)); ! 2619: } ! 2620: ! 2621: inline void msdos_int_21h_06h() ! 2622: { ! 2623: if(REG8(DL) == 0xff) { ! 2624: if(msdos_kbhit()) { ! 2625: REG8(AL) = msdos_getch(); ! 2626: cpustate->ZF = 0; ! 2627: } else { ! 2628: REG8(AL) = 0; ! 2629: cpustate->ZF = 1; ! 2630: Sleep(10); ! 2631: } ! 2632: } else { ! 2633: msdos_putch(REG8(DL)); ! 2634: } ! 2635: } ! 2636: ! 2637: inline void msdos_int_21h_07h() ! 2638: { ! 2639: REG8(AL) = msdos_getch(); ! 2640: #ifdef SUPPORT_HARDWARE ! 2641: hardware_update(); ! 2642: #endif ! 2643: } ! 2644: ! 2645: inline void msdos_int_21h_08h() ! 2646: { ! 2647: REG8(AL) = msdos_getch(); ! 2648: #ifdef SUPPORT_HARDWARE ! 2649: hardware_update(); ! 2650: #endif ! 2651: } ! 2652: ! 2653: inline void msdos_int_21h_09h() ! 2654: { ! 2655: char tmp[0x10000]; ! 2656: memcpy(tmp, mem + cpustate->sreg[DS].base + REG16(DX), sizeof(tmp)); ! 2657: tmp[sizeof(tmp) - 1] = '\0'; ! 2658: int len = strlen(my_strtok(tmp, "$")); ! 2659: ! 2660: if(file_handler[1].valid && !file_handler[1].atty) { ! 2661: // stdout is redirected to file ! 2662: msdos_write(1, tmp, len); ! 2663: } else { ! 2664: for(int i = 0; i < len; i++) { ! 2665: msdos_putch(tmp[i]); ! 2666: } ! 2667: } ! 2668: } ! 2669: ! 2670: inline void msdos_int_21h_0ah() ! 2671: { ! 2672: int ofs = cpustate->sreg[DS].base + REG16(DX); ! 2673: int max = mem[ofs] - 1; ! 2674: UINT8 *buf = mem + ofs + 2; ! 2675: int chr, p = 0; ! 2676: ! 2677: while((chr = msdos_getch()) != 0x0d) { ! 2678: if(chr == 0x00) { ! 2679: // skip 2nd byte ! 2680: msdos_getch(); ! 2681: } else if(chr == 0x08) { ! 2682: // back space ! 2683: if(p > 0) { ! 2684: p--; ! 2685: msdos_putch(chr); ! 2686: msdos_putch(' '); ! 2687: msdos_putch(chr); ! 2688: } ! 2689: } else if(p < max) { ! 2690: buf[p++] = chr; ! 2691: msdos_putch(chr); ! 2692: } ! 2693: } ! 2694: buf[p] = 0x0d; ! 2695: mem[ofs + 1] = p; ! 2696: #ifdef SUPPORT_HARDWARE ! 2697: hardware_update(); ! 2698: #endif ! 2699: } ! 2700: ! 2701: inline void msdos_int_21h_0bh() ! 2702: { ! 2703: if(msdos_kbhit()) { ! 2704: REG8(AL) = 0xff; ! 2705: } else { ! 2706: REG8(AL) = 0x00; ! 2707: Sleep(10); ! 2708: } ! 2709: } ! 2710: ! 2711: inline void msdos_int_21h_0ch() ! 2712: { ! 2713: // clear key buffer ! 2714: if(file_handler[0].valid && !file_handler[0].atty) { ! 2715: // stdin is redirected to file ! 2716: } else { ! 2717: while(msdos_kbhit()) { ! 2718: msdos_getch(); ! 2719: } ! 2720: } ! 2721: ! 2722: switch(REG8(AL)) { ! 2723: case 0x01: ! 2724: msdos_int_21h_01h(); ! 2725: break; ! 2726: case 0x06: ! 2727: msdos_int_21h_06h(); ! 2728: break; ! 2729: case 0x07: ! 2730: msdos_int_21h_07h(); ! 2731: break; ! 2732: case 0x08: ! 2733: msdos_int_21h_08h(); ! 2734: break; ! 2735: case 0x0a: ! 2736: msdos_int_21h_0ah(); ! 2737: break; ! 2738: default: ! 2739: REG16(AX) = 0x01; ! 2740: cpustate->CF = 1; ! 2741: break; ! 2742: } ! 2743: } ! 2744: ! 2745: inline void msdos_int_21h_0dh() ! 2746: { ! 2747: } ! 2748: ! 2749: inline void msdos_int_21h_0eh() ! 2750: { ! 2751: if(REG8(DL) < 26) { ! 2752: _chdrive(REG8(DL) + 1); ! 2753: msdos_cds_update(REG8(DL)); ! 2754: } ! 2755: REG8(AL) = 26; // zdrive ! 2756: } ! 2757: ! 2758: inline void msdos_int_21h_11h() ! 2759: { ! 2760: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + cpustate->sreg[DS].base + REG16(DX)); ! 2761: fcb_t *fcb = (fcb_t *)(mem + cpustate->sreg[DS].base + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0)); ! 2762: ! 2763: process_t *process = msdos_process_info_get(current_psp); ! 2764: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + (process->dta.w.h << 4) + process->dta.w.l); ! 2765: find_fcb_t *find = (find_fcb_t *)(mem + (process->dta.w.h << 4) + process->dta.w.l + (ext_fcb->flag == 0xff ? 7 : 0)); ! 2766: char *path = msdos_fcb_path(fcb); ! 2767: WIN32_FIND_DATA fd; ! 2768: ! 2769: if(process->find_handle != INVALID_HANDLE_VALUE) { ! 2770: FindClose(process->find_handle); ! 2771: process->find_handle = INVALID_HANDLE_VALUE; ! 2772: } ! 2773: strcpy(process->volume_label, msdos_volume_label(path)); ! 2774: process->allowable_mask = (ext_fcb->flag == 0xff) ? ext_fcb->attribute : 0x20; ! 2775: ! 2776: if((process->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) { ! 2777: process->allowable_mask &= ~8; ! 2778: } ! 2779: if((process->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) { ! 2780: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, process->allowable_mask, 0)) { ! 2781: if(!FindNextFile(process->find_handle, &fd)) { ! 2782: FindClose(process->find_handle); ! 2783: process->find_handle = INVALID_HANDLE_VALUE; ! 2784: break; ! 2785: } ! 2786: } ! 2787: } ! 2788: if(process->find_handle != INVALID_HANDLE_VALUE) { ! 2789: if(ext_fcb->flag == 0xff) { ! 2790: ext_find->flag = 0xff; ! 2791: memset(ext_find->reserved, 0, 5); ! 2792: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f); ! 2793: } ! 2794: find->drive = _getdrive(); ! 2795: msdos_set_fcb_path((fcb_t *)find, msdos_short_path(fd.cFileName)); ! 2796: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f); ! 2797: find->nt_res = 0; ! 2798: msdos_find_file_conv_local_time(&fd); ! 2799: find->create_time_ms = 0; ! 2800: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time); ! 2801: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time); ! 2802: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time); ! 2803: find->cluster_hi = find->cluster_lo = 0; ! 2804: find->file_size = fd.nFileSizeLow; ! 2805: REG8(AL) = 0x00; ! 2806: } else if(process->allowable_mask & 8) { ! 2807: if(ext_fcb->flag == 0xff) { ! 2808: ext_find->flag = 0xff; ! 2809: memset(ext_find->reserved, 0, 5); ! 2810: ext_find->attribute = 8; ! 2811: } ! 2812: find->drive = _getdrive(); ! 2813: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label)); ! 2814: find->attribute = 8; ! 2815: find->nt_res = 0; ! 2816: msdos_find_file_conv_local_time(&fd); ! 2817: find->create_time_ms = 0; ! 2818: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time); ! 2819: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time); ! 2820: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time); ! 2821: find->cluster_hi = find->cluster_lo = 0; ! 2822: find->file_size = 0; ! 2823: process->allowable_mask &= ~8; ! 2824: REG8(AL) = 0x00; ! 2825: } else { ! 2826: REG8(AL) = 0xff; ! 2827: } ! 2828: } ! 2829: ! 2830: inline void msdos_int_21h_12h() ! 2831: { ! 2832: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + cpustate->sreg[DS].base + REG16(DX)); ! 2833: fcb_t *fcb = (fcb_t *)(mem + cpustate->sreg[DS].base + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0)); ! 2834: ! 2835: process_t *process = msdos_process_info_get(current_psp); ! 2836: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + (process->dta.w.h << 4) + process->dta.w.l); ! 2837: find_fcb_t *find = (find_fcb_t *)(mem + (process->dta.w.h << 4) + process->dta.w.l + (ext_fcb->flag == 0xff ? 7 : 0)); ! 2838: WIN32_FIND_DATA fd; ! 2839: ! 2840: if(process->find_handle != INVALID_HANDLE_VALUE) { ! 2841: if(FindNextFile(process->find_handle, &fd)) { ! 2842: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, process->allowable_mask, 0)) { ! 2843: if(!FindNextFile(process->find_handle, &fd)) { ! 2844: FindClose(process->find_handle); ! 2845: process->find_handle = INVALID_HANDLE_VALUE; ! 2846: break; ! 2847: } ! 2848: } ! 2849: } else { ! 2850: FindClose(process->find_handle); ! 2851: process->find_handle = INVALID_HANDLE_VALUE; ! 2852: } ! 2853: } ! 2854: if(process->find_handle != INVALID_HANDLE_VALUE) { ! 2855: if(ext_fcb->flag == 0xff) { ! 2856: ext_find->flag = 0xff; ! 2857: memset(ext_find->reserved, 0, 5); ! 2858: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f); ! 2859: } ! 2860: find->drive = _getdrive(); ! 2861: msdos_set_fcb_path((fcb_t *)find, msdos_short_path(fd.cFileName)); ! 2862: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f); ! 2863: find->nt_res = 0; ! 2864: msdos_find_file_conv_local_time(&fd); ! 2865: find->create_time_ms = 0; ! 2866: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time); ! 2867: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time); ! 2868: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time); ! 2869: find->cluster_hi = find->cluster_lo = 0; ! 2870: find->file_size = fd.nFileSizeLow; ! 2871: REG8(AL) = 0x00; ! 2872: } else if(process->allowable_mask & 8) { ! 2873: if(ext_fcb->flag == 0xff) { ! 2874: ext_find->flag = 0xff; ! 2875: memset(ext_find->reserved, 0, 5); ! 2876: ext_find->attribute = 8; ! 2877: } ! 2878: find->drive = _getdrive(); ! 2879: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label)); ! 2880: find->attribute = 8; ! 2881: find->nt_res = 0; ! 2882: msdos_find_file_conv_local_time(&fd); ! 2883: find->create_time_ms = 0; ! 2884: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time); ! 2885: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time); ! 2886: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time); ! 2887: find->cluster_hi = find->cluster_lo = 0; ! 2888: find->file_size = 0; ! 2889: process->allowable_mask &= ~8; ! 2890: REG8(AL) = 0x00; ! 2891: } else { ! 2892: REG8(AL) = 0xff; ! 2893: } ! 2894: } ! 2895: ! 2896: inline void msdos_int_21h_13h() ! 2897: { ! 2898: if(remove(msdos_fcb_path((fcb_t *)(mem + cpustate->sreg[DS].base + REG16(DX))))) { ! 2899: REG8(AL) = 0xff; ! 2900: } else { ! 2901: REG8(AL) = 0x00; ! 2902: } ! 2903: } ! 2904: ! 2905: inline void msdos_int_21h_18h() ! 2906: { ! 2907: REG8(AL) = 0x00; ! 2908: } ! 2909: ! 2910: inline void msdos_int_21h_19h() ! 2911: { ! 2912: REG8(AL) = _getdrive() - 1; ! 2913: } ! 2914: ! 2915: inline void msdos_int_21h_1ah() ! 2916: { ! 2917: process_t *process = msdos_process_info_get(current_psp); ! 2918: ! 2919: process->dta.w.l = REG16(DX); ! 2920: process->dta.w.h = cpustate->sreg[DS].selector; ! 2921: } ! 2922: ! 2923: inline void msdos_int_21h_1bh() ! 2924: { ! 2925: int drive_num = _getdrive() - 1; ! 2926: UINT16 seg, ofs; ! 2927: ! 2928: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) { ! 2929: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs); ! 2930: REG8(AL) = dpb->highest_sector_num + 1; ! 2931: REG16(CX) = dpb->bytes_per_sector; ! 2932: REG16(DX) = dpb->highest_cluster_num - 1; ! 2933: *(UINT8 *)(mem + cpustate->sreg[DS].base + REG16(BX)) = dpb->media_type; ! 2934: } else { ! 2935: REG8(AL) = 0xff; ! 2936: cpustate->CF = 1; ! 2937: } ! 2938: ! 2939: } ! 2940: ! 2941: inline void msdos_int_21h_1ch() ! 2942: { ! 2943: int drive_num = REG8(DL) ? (REG8(DL) - 1) : (_getdrive() - 1); ! 2944: UINT16 seg, ofs; ! 2945: ! 2946: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) { ! 2947: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs); ! 2948: REG8(AL) = dpb->highest_sector_num + 1; ! 2949: REG16(CX) = dpb->bytes_per_sector; ! 2950: REG16(DX) = dpb->highest_cluster_num - 1; ! 2951: *(UINT8 *)(mem + cpustate->sreg[DS].base + REG16(BX)) = dpb->media_type; ! 2952: } else { ! 2953: REG8(AL) = 0xff; ! 2954: cpustate->CF = 1; ! 2955: } ! 2956: ! 2957: } ! 2958: ! 2959: inline void msdos_int_21h_1dh() ! 2960: { ! 2961: REG8(AL) = 0; ! 2962: } ! 2963: ! 2964: inline void msdos_int_21h_1eh() ! 2965: { ! 2966: REG8(AL) = 0; ! 2967: } ! 2968: ! 2969: inline void msdos_int_21h_1fh() ! 2970: { ! 2971: int drive_num = _getdrive() - 1; ! 2972: UINT16 seg, ofs; ! 2973: ! 2974: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) { ! 2975: REG8(AL) = 0; ! 2976: cpustate->sreg[DS].selector = seg; ! 2977: i386_load_segment_descriptor(cpustate, DS); ! 2978: REG16(BX) = ofs; ! 2979: } else { ! 2980: REG8(AL) = 0xff; ! 2981: cpustate->CF = 1; ! 2982: } ! 2983: } ! 2984: ! 2985: inline void msdos_int_21h_20h() ! 2986: { ! 2987: REG8(AL) = 0; ! 2988: } ! 2989: ! 2990: inline void msdos_int_21h_25h() ! 2991: { ! 2992: *(UINT16 *)(mem + 4 * REG8(AL) + 0) = REG16(DX); ! 2993: *(UINT16 *)(mem + 4 * REG8(AL) + 2) = cpustate->sreg[DS].selector; ! 2994: } ! 2995: ! 2996: inline void msdos_int_21h_26h() ! 2997: { ! 2998: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4)); ! 2999: ! 3000: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t)); ! 3001: psp->first_mcb = REG16(DX) + 16; ! 3002: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22); ! 3003: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23); ! 3004: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24); ! 3005: psp->parent_psp = 0; ! 3006: } ! 3007: ! 3008: inline void msdos_int_21h_29h() ! 3009: { ! 3010: int ofs = cpustate->sreg[DS].base + REG16(SI); ! 3011: char name[MAX_PATH], ext[MAX_PATH]; ! 3012: UINT8 drv = 0; ! 3013: char sep_chars[] = ":.;,=+"; ! 3014: char end_chars[] = "\\<>|/\"[]"; ! 3015: char spc_chars[] = " \t"; ! 3016: ! 3017: if(REG8(AL) & 1) { ! 3018: ofs += strspn((char *)&mem[ofs], spc_chars); ! 3019: if(my_strchr(sep_chars, mem[ofs]) && mem[ofs] != '\0') { ! 3020: ofs++; ! 3021: } ! 3022: } ! 3023: ofs += strspn((char *)&mem[ofs], spc_chars); ! 3024: ! 3025: if(mem[ofs + 1] == ':') { ! 3026: UINT8 c = mem[ofs]; ! 3027: if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) { ! 3028: ; // invalid drive letter ! 3029: } else { ! 3030: if(c >= 'a' && c <= 'z') { ! 3031: drv = c - 'a' + 1; ! 3032: } else { ! 3033: drv = c - 'A' + 1; ! 3034: } ! 3035: ofs += 2; ! 3036: } ! 3037: } ! 3038: memset(name, 0x20, sizeof(name)); ! 3039: memset(ext, 0x20, sizeof(ext)); ! 3040: for(int i = 0; i < MAX_PATH; i++) { ! 3041: UINT8 c = mem[ofs]; ! 3042: if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) { ! 3043: break; ! 3044: } else if(c >= 'a' && c <= 'z') { ! 3045: c -= 0x20; ! 3046: } ! 3047: ofs++; ! 3048: name[i] = c; ! 3049: } ! 3050: if(mem[ofs] == '.') { ! 3051: ofs++; ! 3052: for(int i = 0; i < MAX_PATH; i++) { ! 3053: UINT8 c = mem[ofs]; ! 3054: if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) { ! 3055: break; ! 3056: } else if(c >= 'a' && c <= 'z') { ! 3057: c -= 0x20; ! 3058: } ! 3059: ofs++; ! 3060: ext[i] = c; ! 3061: } ! 3062: } ! 3063: int si = ofs - cpustate->sreg[DS].base; ! 3064: int ds = cpustate->sreg[DS].selector; ! 3065: while(si > 0xffff) { ! 3066: si -= 0x10; ! 3067: ds++; ! 3068: } ! 3069: REG16(SI) = si; ! 3070: cpustate->sreg[DS].selector = ds; ! 3071: i386_load_segment_descriptor(cpustate, DS); ! 3072: ! 3073: UINT8 *fcb = mem + cpustate->sreg[ES].base + REG16(DI); ! 3074: fcb[0] = drv; ! 3075: memcpy(fcb + 1, name, 8); ! 3076: int found_star = 0; ! 3077: for(int i = 1; i < 1 + 8; i++) { ! 3078: if(fcb[i] == '*') { ! 3079: found_star = 1; ! 3080: } ! 3081: if(found_star) { ! 3082: fcb[i] = '?'; ! 3083: } ! 3084: } ! 3085: memcpy(fcb + 9, ext, 3); ! 3086: found_star = 0; ! 3087: for(int i = 9; i < 9 + 3; i++) { ! 3088: if(fcb[i] == '*') { ! 3089: found_star = 1; ! 3090: } ! 3091: if(found_star) { ! 3092: fcb[i] = '?'; ! 3093: } ! 3094: } ! 3095: ! 3096: REG8(AL) = 0x00; ! 3097: if(drv == 0 || (drv > 0 && drv <= 26 && (GetLogicalDrives() & ( 1 << (drv - 1) )))) { ! 3098: if(memchr(fcb + 1, '?', 8 + 3)) { ! 3099: REG8(AL) = 0x01; ! 3100: } ! 3101: } else { ! 3102: REG8(AL) = 0xff; ! 3103: } ! 3104: } ! 3105: ! 3106: inline void msdos_int_21h_2ah() ! 3107: { ! 3108: SYSTEMTIME sTime; ! 3109: ! 3110: GetLocalTime(&sTime); ! 3111: REG16(CX) = sTime.wYear; ! 3112: REG8(DH) = (UINT8)sTime.wMonth; ! 3113: REG8(DL) = (UINT8)sTime.wDay; ! 3114: REG8(AL) = (UINT8)sTime.wDayOfWeek; ! 3115: } ! 3116: ! 3117: inline void msdos_int_21h_2bh() ! 3118: { ! 3119: REG8(AL) = 0x00; ! 3120: } ! 3121: ! 3122: inline void msdos_int_21h_2ch() ! 3123: { ! 3124: SYSTEMTIME sTime; ! 3125: ! 3126: GetLocalTime(&sTime); ! 3127: REG8(CH) = (UINT8)sTime.wHour; ! 3128: REG8(CL) = (UINT8)sTime.wMinute; ! 3129: REG8(DH) = (UINT8)sTime.wSecond; ! 3130: } ! 3131: ! 3132: inline void msdos_int_21h_2dh() ! 3133: { ! 3134: REG8(AL) = 0x00; ! 3135: } ! 3136: ! 3137: inline void msdos_int_21h_2eh() ! 3138: { ! 3139: process_t *process = msdos_process_info_get(current_psp); ! 3140: ! 3141: process->verify = REG8(AL); ! 3142: } ! 3143: ! 3144: inline void msdos_int_21h_2fh() ! 3145: { ! 3146: process_t *process = msdos_process_info_get(current_psp); ! 3147: ! 3148: REG16(BX) = process->dta.w.l; ! 3149: cpustate->sreg[ES].selector = process->dta.w.h; ! 3150: i386_load_segment_descriptor(cpustate, ES); ! 3151: } ! 3152: ! 3153: inline void msdos_int_21h_30h() ! 3154: { ! 3155: // Version Flag / OEM ! 3156: if(REG8(AL) == 1) { ! 3157: REG8(BH) = 0x00; // not in ROM ! 3158: } else { ! 3159: REG8(BH) = 0xff; // OEM = Microsoft ! 3160: } ! 3161: // MS-DOS version (7.10) ! 3162: REG8(AL) = 7; ! 3163: REG8(AH) = 10; ! 3164: } ! 3165: ! 3166: inline void msdos_int_21h_31h() ! 3167: { ! 3168: int mcb_seg = current_psp - 1; ! 3169: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4)); ! 3170: ! 3171: mcb->paragraphs = REG16(DX); ! 3172: mcb_seg += mcb->paragraphs + 1; ! 3173: msdos_mcb_create(mcb_seg, 'Z', 0, (MEMORY_END >> 4) - mcb_seg - 1); ! 3174: ! 3175: msdos_process_terminate(current_psp, REG8(AL) | 0x300, 0); ! 3176: } ! 3177: ! 3178: inline void msdos_int_21h_32h() ! 3179: { ! 3180: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1); ! 3181: UINT16 seg, ofs; ! 3182: ! 3183: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) { ! 3184: REG8(AL) = 0; ! 3185: cpustate->sreg[DS].selector = seg; ! 3186: i386_load_segment_descriptor(cpustate, DS); ! 3187: REG16(BX) = ofs; ! 3188: } else { ! 3189: REG8(AL) = 0xff; ! 3190: cpustate->CF = 1; ! 3191: } ! 3192: } ! 3193: ! 3194: inline void msdos_int_21h_33h() ! 3195: { ! 3196: static UINT8 state = 0x00; ! 3197: char path[MAX_PATH]; ! 3198: ! 3199: switch(REG8(AL)) { ! 3200: case 0x00: ! 3201: REG8(DL) = state; ! 3202: break; ! 3203: case 0x01: ! 3204: state = REG8(DL); ! 3205: break; ! 3206: case 0x05: ! 3207: GetSystemDirectory(path, MAX_PATH); ! 3208: if(path[0] >= 'a' && path[0] <= 'z') { ! 3209: REG8(DL) = path[0] - 'a' + 1; ! 3210: } else { ! 3211: REG8(DL) = path[0] - 'A' + 1; ! 3212: } ! 3213: break; ! 3214: case 0x06: ! 3215: // MS-DOS version (7.00) ! 3216: REG8(BL) = 7; ! 3217: REG8(BH) = 0; ! 3218: REG8(DL) = 0; ! 3219: REG8(DH) = 0x10; // in HMA ! 3220: break; ! 3221: default: ! 3222: REG16(AX) = 0x01; ! 3223: cpustate->CF = 1; ! 3224: break; ! 3225: } ! 3226: } ! 3227: ! 3228: inline void msdos_int_21h_35h() ! 3229: { ! 3230: REG16(BX) = *(UINT16 *)(mem + 4 * REG8(AL) + 0); ! 3231: cpustate->sreg[ES].selector = *(UINT16 *)(mem + 4 * REG8(AL) + 2); ! 3232: i386_load_segment_descriptor(cpustate, ES); ! 3233: } ! 3234: ! 3235: inline void msdos_int_21h_36h() ! 3236: { ! 3237: struct _diskfree_t df = {0}; ! 3238: ! 3239: if(_getdiskfree(REG8(DL), &df) == 0) { ! 3240: REG16(AX) = (UINT16)df.sectors_per_cluster; ! 3241: REG16(CX) = (UINT16)df.bytes_per_sector; ! 3242: REG16(BX) = (UINT16)df.avail_clusters; ! 3243: REG16(DX) = (UINT16)df.total_clusters; ! 3244: } else { ! 3245: REG16(AX) = 0xffff; ! 3246: } ! 3247: } ! 3248: ! 3249: inline void msdos_int_21h_37h() ! 3250: { ! 3251: process_t *process = msdos_process_info_get(current_psp); ! 3252: ! 3253: switch(REG8(AL)) { ! 3254: case 0x00: ! 3255: REG8(AL) = 0x00; ! 3256: REG8(DL) = process->switchar; ! 3257: break; ! 3258: case 0x01: ! 3259: REG8(AL) = 0x00; ! 3260: process->switchar = REG8(DL); ! 3261: break; ! 3262: default: ! 3263: REG16(AX) = 1; ! 3264: break; ! 3265: } ! 3266: } ! 3267: ! 3268: inline void msdos_int_21h_39h(int lfn) ! 3269: { ! 3270: if(_mkdir(msdos_trimmed_path((char *)(mem + cpustate->sreg[DS].base + REG16(DX)), lfn))) { ! 3271: REG16(AX) = errno; ! 3272: cpustate->CF = 1; ! 3273: } ! 3274: } ! 3275: ! 3276: inline void msdos_int_21h_3ah(int lfn) ! 3277: { ! 3278: if(_rmdir(msdos_trimmed_path((char *)(mem + cpustate->sreg[DS].base + REG16(DX)), lfn))) { ! 3279: REG16(AX) = errno; ! 3280: cpustate->CF = 1; ! 3281: } ! 3282: } ! 3283: ! 3284: inline void msdos_int_21h_3bh(int lfn) ! 3285: { ! 3286: if(_chdir(msdos_trimmed_path((char *)(mem + cpustate->sreg[DS].base + REG16(DX)), lfn))) { ! 3287: REG16(AX) = errno; ! 3288: cpustate->CF = 1; ! 3289: } ! 3290: } ! 3291: ! 3292: inline void msdos_int_21h_3ch() ! 3293: { ! 3294: char *path = msdos_local_file_path((char *)(mem + cpustate->sreg[DS].base + REG16(DX)), 0); ! 3295: int attr = GetFileAttributes(path); ! 3296: int fd = -1; ! 3297: ! 3298: if(_stricmp(path, "CON") == 0) { ! 3299: fd = _open(path, _O_WRONLY | _O_BINARY); ! 3300: } else { ! 3301: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE); ! 3302: } ! 3303: if(fd != -1) { ! 3304: if(attr == -1) { ! 3305: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY; ! 3306: } ! 3307: SetFileAttributes(path, attr); ! 3308: REG16(AX) = fd; ! 3309: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp); ! 3310: } else { ! 3311: REG16(AX) = errno; ! 3312: cpustate->CF = 1; ! 3313: } ! 3314: } ! 3315: ! 3316: inline void msdos_int_21h_3dh() ! 3317: { ! 3318: char *path = msdos_local_file_path((char *)(mem + cpustate->sreg[DS].base + REG16(DX)), 0); ! 3319: int mode = REG8(AL) & 0x03; ! 3320: ! 3321: if(mode < 0x03) { ! 3322: int fd = _open(path, file_mode[mode].mode); ! 3323: ! 3324: if(fd != -1) { ! 3325: REG16(AX) = fd; ! 3326: msdos_file_handler_open(fd, path, _isatty(fd), mode, msdos_drive_number(path), current_psp); ! 3327: } else { ! 3328: REG16(AX) = errno; ! 3329: cpustate->CF = 1; ! 3330: } ! 3331: } else { ! 3332: REG16(AX) = 0x0c; ! 3333: cpustate->CF = 1; ! 3334: } ! 3335: } ! 3336: ! 3337: inline void msdos_int_21h_3eh() ! 3338: { ! 3339: process_t *process = msdos_process_info_get(current_psp); ! 3340: ! 3341: if(REG16(BX) < process->max_files && file_handler[REG16(BX)].valid) { ! 3342: _close(REG16(BX)); ! 3343: msdos_file_handler_close(REG16(BX), current_psp); ! 3344: } else { ! 3345: REG16(AX) = 0x06; ! 3346: cpustate->CF = 1; ! 3347: } ! 3348: } ! 3349: ! 3350: inline void msdos_int_21h_3fh() ! 3351: { ! 3352: process_t *process = msdos_process_info_get(current_psp); ! 3353: ! 3354: if(REG16(BX) < process->max_files && file_handler[REG16(BX)].valid) { ! 3355: if(file_mode[file_handler[REG16(BX)].mode].in) { ! 3356: if(file_handler[REG16(BX)].atty) { ! 3357: // BX is stdin or is redirected to stdin ! 3358: UINT8 *buf = mem + cpustate->sreg[DS].base + REG16(DX); ! 3359: int max = REG16(CX); ! 3360: int p = 0; ! 3361: ! 3362: while(max > p) { ! 3363: int chr = msdos_getch(); ! 3364: ! 3365: if(chr == 0x00) { ! 3366: // skip 2nd byte ! 3367: msdos_getch(); ! 3368: } else if(chr == 0x0d) { ! 3369: // carriage return ! 3370: buf[p++] = 0x0d; ! 3371: if(max > p) { ! 3372: buf[p++] = 0x0a; ! 3373: } ! 3374: break; ! 3375: } else if(chr == 0x08) { ! 3376: // back space ! 3377: if(p > 0) { ! 3378: p--; ! 3379: msdos_putch(chr); ! 3380: msdos_putch(' '); ! 3381: msdos_putch(chr); ! 3382: } ! 3383: } else { ! 3384: buf[p++] = chr; ! 3385: msdos_putch(chr); ! 3386: } ! 3387: } ! 3388: REG16(AX) = p; ! 3389: #ifdef SUPPORT_HARDWARE ! 3390: hardware_update(); ! 3391: #endif ! 3392: } else { ! 3393: REG16(AX) = _read(REG16(BX), mem + cpustate->sreg[DS].base + REG16(DX), REG16(CX)); ! 3394: } ! 3395: } else { ! 3396: REG16(AX) = 0x05; ! 3397: cpustate->CF = 1; ! 3398: } ! 3399: } else { ! 3400: REG16(AX) = 0x06; ! 3401: cpustate->CF = 1; ! 3402: } ! 3403: } ! 3404: ! 3405: inline void msdos_int_21h_40h() ! 3406: { ! 3407: process_t *process = msdos_process_info_get(current_psp); ! 3408: ! 3409: if(REG16(BX) < process->max_files && file_handler[REG16(BX)].valid) { ! 3410: if(file_mode[file_handler[REG16(BX)].mode].out) { ! 3411: if(REG16(CX)) { ! 3412: if(file_handler[REG16(BX)].atty) { ! 3413: // BX is stdout/stderr or is redirected to stdout ! 3414: for(int i = 0; i < REG16(CX); i++) { ! 3415: msdos_putch(mem[cpustate->sreg[DS].base + REG16(DX) + i]); ! 3416: } ! 3417: REG16(AX) = REG16(CX); ! 3418: } else { ! 3419: REG16(AX) = msdos_write(REG16(BX), mem + cpustate->sreg[DS].base + REG16(DX), REG16(CX)); ! 3420: } ! 3421: } else { ! 3422: UINT32 pos = _tell(REG16(BX)); ! 3423: _lseek(REG16(BX), 0, SEEK_END); ! 3424: UINT32 size = _tell(REG16(BX)); ! 3425: REG16(AX) = 0; ! 3426: for(UINT32 i = size; i < pos; i++) { ! 3427: UINT8 tmp = 0; ! 3428: REG16(AX) += msdos_write(REG16(BX), &tmp, 1); ! 3429: } ! 3430: _lseek(REG16(BX), pos, SEEK_SET); ! 3431: } ! 3432: } else { ! 3433: REG16(AX) = 0x05; ! 3434: cpustate->CF = 1; ! 3435: } ! 3436: } else { ! 3437: REG16(AX) = 0x06; ! 3438: cpustate->CF = 1; ! 3439: } ! 3440: } ! 3441: ! 3442: inline void msdos_int_21h_41h(int lfn) ! 3443: { ! 3444: if(remove(msdos_trimmed_path((char *)(mem + cpustate->sreg[DS].base + REG16(DX)), lfn))) { ! 3445: REG16(AX) = errno; ! 3446: cpustate->CF = 1; ! 3447: } ! 3448: } ! 3449: ! 3450: inline void msdos_int_21h_42h() ! 3451: { ! 3452: process_t *process = msdos_process_info_get(current_psp); ! 3453: ! 3454: if(REG16(BX) < process->max_files && file_handler[REG16(BX)].valid) { ! 3455: if(REG8(AL) < 0x03) { ! 3456: static int ptrname[] = { SEEK_SET, SEEK_CUR, SEEK_END }; ! 3457: _lseek(REG16(BX), (REG16(CX) << 16) | REG16(DX), ptrname[REG8(AL)]); ! 3458: UINT32 pos = _tell(REG16(BX)); ! 3459: REG16(AX) = pos & 0xffff; ! 3460: REG16(DX) = (pos >> 16); ! 3461: } else { ! 3462: REG16(AX) = 0x01; ! 3463: cpustate->CF = 1; ! 3464: } ! 3465: } else { ! 3466: REG16(AX) = 0x06; ! 3467: cpustate->CF = 1; ! 3468: } ! 3469: } ! 3470: ! 3471: inline void msdos_int_21h_43h(int lfn) ! 3472: { ! 3473: char *path = msdos_local_file_path((char *)(mem + cpustate->sreg[DS].base + REG16(DX)), lfn); ! 3474: int attr; ! 3475: ! 3476: switch(REG8(AL)) { ! 3477: case 0x00: ! 3478: if((attr = GetFileAttributes(path)) != -1) { ! 3479: REG16(CX) = 0; ! 3480: if(attr & FILE_ATTRIBUTE_READONLY) { ! 3481: REG16(CX) |= 0x01; ! 3482: } ! 3483: if(attr & FILE_ATTRIBUTE_HIDDEN) { ! 3484: REG16(CX) |= 0x02; ! 3485: } ! 3486: if(attr & FILE_ATTRIBUTE_SYSTEM) { ! 3487: REG16(CX) |= 0x04; ! 3488: } ! 3489: if(attr & FILE_ATTRIBUTE_ARCHIVE) { ! 3490: REG16(CX) |= 0x20; ! 3491: } ! 3492: } else { ! 3493: REG16(AX) = (UINT16)GetLastError(); ! 3494: cpustate->CF = 1; ! 3495: } ! 3496: break; ! 3497: case 0x01: ! 3498: if(SetFileAttributes(path, msdos_file_attribute_create(REG16(CX))) != 0) { ! 3499: REG16(AX) = (UINT16)GetLastError(); ! 3500: cpustate->CF = 1; ! 3501: } ! 3502: break; ! 3503: case 0x02: ! 3504: break; ! 3505: case 0x03: ! 3506: REG16(CX) = 0x00; ! 3507: break; ! 3508: default: ! 3509: REG16(AX) = 0x01; ! 3510: cpustate->CF = 1; ! 3511: break; ! 3512: } ! 3513: } ! 3514: ! 3515: inline void msdos_int_21h_44h() ! 3516: { ! 3517: switch(REG8(AL)) { ! 3518: case 0x00: // get ioctrl data ! 3519: REG16(DX) = file_handler[REG16(BX)].info; ! 3520: break; ! 3521: case 0x01: // set ioctrl data ! 3522: file_handler[REG16(BX)].info |= REG8(DL); ! 3523: break; ! 3524: case 0x02: // recv from character device ! 3525: case 0x03: // send to character device ! 3526: REG16(AX) = 0x06; ! 3527: cpustate->CF = 1; ! 3528: break; ! 3529: case 0x04: // recv from block device ! 3530: case 0x05: // send to block device ! 3531: REG16(AX) = 0x05; ! 3532: cpustate->CF = 1; ! 3533: break; ! 3534: case 0x06: // get read status ! 3535: { ! 3536: process_t *process = msdos_process_info_get(current_psp); ! 3537: ! 3538: if(REG16(BX) < process->max_files && file_handler[REG16(BX)].valid) { ! 3539: if(file_mode[file_handler[REG16(BX)].mode].in) { ! 3540: if(file_handler[REG16(BX)].atty) { ! 3541: REG8(AL) = msdos_kbhit() ? 0xff : 0x00; ! 3542: } else { ! 3543: REG8(AL) = eof(REG16(BX)) ? 0x00 : 0xff; ! 3544: } ! 3545: } else { ! 3546: REG8(AL) = 0x00; ! 3547: } ! 3548: } else { ! 3549: REG16(AX) = 0x06; ! 3550: cpustate->CF = 1; ! 3551: } ! 3552: } ! 3553: break; ! 3554: case 0x07: // get write status ! 3555: { ! 3556: process_t *process = msdos_process_info_get(current_psp); ! 3557: ! 3558: if(REG16(BX) < process->max_files && file_handler[REG16(BX)].valid) { ! 3559: if(file_mode[file_handler[REG16(BX)].mode].out) { ! 3560: REG8(AL) = 0xff; ! 3561: } else { ! 3562: REG8(AL) = 0x00; ! 3563: } ! 3564: } else { ! 3565: REG16(AX) = 0x06; ! 3566: cpustate->CF = 1; ! 3567: } ! 3568: } ! 3569: break; ! 3570: case 0x08: // check removable drive ! 3571: if(REG8(BL) < ('Z' - 'A' + 1)) { ! 3572: UINT32 val; ! 3573: if(REG8(BL) == 0) { ! 3574: val = GetDriveType(NULL); ! 3575: } else if(REG8(BL) < ('Z' - 'A' + 1)) { ! 3576: char tmp[8]; ! 3577: sprintf(tmp, "%c:\\", 'A' + REG8(BL) - 1); ! 3578: val = GetDriveType(tmp); ! 3579: } ! 3580: if(val == DRIVE_NO_ROOT_DIR) { ! 3581: // no drive ! 3582: REG16(AX) = 0x0f; ! 3583: cpustate->CF = 1; ! 3584: } else if(val == DRIVE_REMOVABLE || val == DRIVE_CDROM) { ! 3585: // removable drive ! 3586: REG16(AX) = 0x00; ! 3587: } else { ! 3588: // fixed drive ! 3589: REG16(AX) = 0x01; ! 3590: } ! 3591: } else { ! 3592: // invalid drive number ! 3593: REG16(AX) = 0x0f; ! 3594: cpustate->CF = 1; ! 3595: } ! 3596: break; ! 3597: case 0x09: // check remote drive ! 3598: if(REG8(BL) < ('Z' - 'A' + 1)) { ! 3599: UINT32 val; ! 3600: if(REG8(BL) == 0) { ! 3601: val = GetDriveType(NULL); ! 3602: } else if(REG8(BL) < ('Z' - 'A' + 1)) { ! 3603: char tmp[8]; ! 3604: sprintf(tmp, "%c:\\", 'A' + REG8(BL) - 1); ! 3605: val = GetDriveType(tmp); ! 3606: } ! 3607: if(val == DRIVE_NO_ROOT_DIR) { ! 3608: // no drive ! 3609: REG16(AX) = 0x0f; ! 3610: cpustate->CF = 1; ! 3611: } else if(val == DRIVE_REMOTE) { ! 3612: // remote drive ! 3613: REG16(DX) = 0x1000; ! 3614: } else { ! 3615: // local drive ! 3616: REG16(DX) = 0x00; ! 3617: } ! 3618: } else { ! 3619: // invalid drive number ! 3620: REG16(AX) = 0x0f; ! 3621: cpustate->CF = 1; ! 3622: } ! 3623: break; ! 3624: case 0x0b: // set retry count ! 3625: break; ! 3626: default: ! 3627: REG16(AX) = 0x01; ! 3628: cpustate->CF = 1; ! 3629: break; ! 3630: } ! 3631: } ! 3632: ! 3633: inline void msdos_int_21h_45h() ! 3634: { ! 3635: process_t *process = msdos_process_info_get(current_psp); ! 3636: ! 3637: if(REG16(BX) < process->max_files && file_handler[REG16(BX)].valid) { ! 3638: int fd = _dup(REG16(BX)); ! 3639: if(fd != -1) { ! 3640: REG16(AX) = fd; ! 3641: msdos_file_handler_dup(REG16(AX), REG16(BX), current_psp); ! 3642: } else { ! 3643: REG16(AX) = errno; ! 3644: cpustate->CF = 1; ! 3645: } ! 3646: } else { ! 3647: REG16(AX) = 0x06; ! 3648: cpustate->CF = 1; ! 3649: } ! 3650: } ! 3651: ! 3652: inline void msdos_int_21h_46h() ! 3653: { ! 3654: process_t *process = msdos_process_info_get(current_psp); ! 3655: ! 3656: if(REG16(BX) < process->max_files && REG16(CX) < process->max_files && file_handler[REG16(BX)].valid) { ! 3657: if(_dup2(REG16(BX), REG16(CX)) != -1) { ! 3658: msdos_file_handler_dup(REG16(CX), REG16(BX), current_psp); ! 3659: } else { ! 3660: REG16(AX) = errno; ! 3661: cpustate->CF = 1; ! 3662: } ! 3663: } else { ! 3664: REG16(AX) = 0x06; ! 3665: cpustate->CF = 1; ! 3666: } ! 3667: } ! 3668: ! 3669: inline void msdos_int_21h_47h(int lfn) ! 3670: { ! 3671: char path[MAX_PATH]; ! 3672: ! 3673: if(_getdcwd(REG8(DL), path, MAX_PATH) != NULL) { ! 3674: if(path[1] == ':') { ! 3675: // the returned path does not include a drive or the initial backslash ! 3676: strcpy((char *)(mem + cpustate->sreg[DS].base + REG16(SI)), (lfn ? path : msdos_short_path(path)) + 3); ! 3677: } else { ! 3678: strcpy((char *)(mem + cpustate->sreg[DS].base + REG16(SI)), lfn ? path : msdos_short_path(path)); ! 3679: } ! 3680: } else { ! 3681: REG16(AX) = errno; ! 3682: cpustate->CF = 1; ! 3683: } ! 3684: } ! 3685: ! 3686: inline void msdos_int_21h_48h() ! 3687: { ! 3688: int seg; ! 3689: ! 3690: if((seg = msdos_mem_alloc(REG16(BX), 0)) != -1) { ! 3691: REG16(AX) = seg; ! 3692: } else { ! 3693: REG16(AX) = 0x08; ! 3694: REG16(BX) = msdos_mem_get_free(0); ! 3695: cpustate->CF = 1; ! 3696: } ! 3697: } ! 3698: ! 3699: inline void msdos_int_21h_49h() ! 3700: { ! 3701: msdos_mem_free(cpustate->sreg[ES].selector); ! 3702: } ! 3703: ! 3704: inline void msdos_int_21h_4ah() ! 3705: { ! 3706: int max_paragraphs; ! 3707: ! 3708: if(msdos_mem_realloc(cpustate->sreg[ES].selector, REG16(BX), &max_paragraphs)) { ! 3709: REG16(AX) = 0x08; ! 3710: REG16(BX) = max_paragraphs; ! 3711: cpustate->CF = 1; ! 3712: } ! 3713: } ! 3714: ! 3715: inline void msdos_int_21h_4bh() ! 3716: { ! 3717: char *command = (char *)(mem + cpustate->sreg[DS].base + REG16(DX)); ! 3718: param_block_t *param = (param_block_t *)(mem + cpustate->sreg[ES].base + REG16(BX)); ! 3719: ! 3720: switch(REG8(AL)) { ! 3721: case 0x00: ! 3722: case 0x01: ! 3723: if(msdos_process_exec(command, param, REG8(AL))) { ! 3724: REG16(AX) = 0x02; ! 3725: cpustate->CF = 1; ! 3726: } ! 3727: break; ! 3728: default: ! 3729: REG16(AX) = 0x01; ! 3730: cpustate->CF = 1; ! 3731: break; ! 3732: } ! 3733: } ! 3734: ! 3735: inline void msdos_int_21h_4ch() ! 3736: { ! 3737: msdos_process_terminate(current_psp, REG8(AL), 1); ! 3738: } ! 3739: ! 3740: inline void msdos_int_21h_4dh() ! 3741: { ! 3742: REG16(AX) = retval; ! 3743: } ! 3744: ! 3745: inline void msdos_int_21h_4eh() ! 3746: { ! 3747: process_t *process = msdos_process_info_get(current_psp); ! 3748: find_t *find = (find_t *)(mem + (process->dta.w.h << 4) + process->dta.w.l); ! 3749: char *path = msdos_trimmed_path((char *)(mem + cpustate->sreg[DS].base + REG16(DX)), 0); ! 3750: WIN32_FIND_DATA fd; ! 3751: ! 3752: if(process->find_handle != INVALID_HANDLE_VALUE) { ! 3753: FindClose(process->find_handle); ! 3754: process->find_handle = INVALID_HANDLE_VALUE; ! 3755: } ! 3756: strcpy(process->volume_label, msdos_volume_label(path)); ! 3757: process->allowable_mask = REG8(CL); ! 3758: ! 3759: if((process->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) { ! 3760: process->allowable_mask &= ~8; ! 3761: } ! 3762: if((process->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) { ! 3763: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, process->allowable_mask, 0)) { ! 3764: if(!FindNextFile(process->find_handle, &fd)) { ! 3765: FindClose(process->find_handle); ! 3766: process->find_handle = INVALID_HANDLE_VALUE; ! 3767: break; ! 3768: } ! 3769: } ! 3770: } ! 3771: if(process->find_handle != INVALID_HANDLE_VALUE) { ! 3772: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f); ! 3773: msdos_find_file_conv_local_time(&fd); ! 3774: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time); ! 3775: find->size = fd.nFileSizeLow; ! 3776: strcpy(find->name, msdos_short_path(fd.cFileName)); ! 3777: REG16(AX) = 0; ! 3778: } else if(process->allowable_mask & 8) { ! 3779: find->attrib = 8; ! 3780: find->size = 0; ! 3781: strcpy(find->name, msdos_short_volume_label(process->volume_label)); ! 3782: process->allowable_mask &= ~8; ! 3783: REG16(AX) = 0; ! 3784: } else { ! 3785: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid ! 3786: cpustate->CF = 1; ! 3787: } ! 3788: } ! 3789: ! 3790: inline void msdos_int_21h_4fh() ! 3791: { ! 3792: process_t *process = msdos_process_info_get(current_psp); ! 3793: find_t *find = (find_t *)(mem + (process->dta.w.h << 4) + process->dta.w.l); ! 3794: WIN32_FIND_DATA fd; ! 3795: ! 3796: if(process->find_handle != INVALID_HANDLE_VALUE) { ! 3797: if(FindNextFile(process->find_handle, &fd)) { ! 3798: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, process->allowable_mask, 0)) { ! 3799: if(!FindNextFile(process->find_handle, &fd)) { ! 3800: FindClose(process->find_handle); ! 3801: process->find_handle = INVALID_HANDLE_VALUE; ! 3802: break; ! 3803: } ! 3804: } ! 3805: } else { ! 3806: FindClose(process->find_handle); ! 3807: process->find_handle = INVALID_HANDLE_VALUE; ! 3808: } ! 3809: } ! 3810: if(process->find_handle != INVALID_HANDLE_VALUE) { ! 3811: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f); ! 3812: msdos_find_file_conv_local_time(&fd); ! 3813: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time); ! 3814: find->size = fd.nFileSizeLow; ! 3815: strcpy(find->name, msdos_short_path(fd.cFileName)); ! 3816: REG16(AX) = 0; ! 3817: } else if(process->allowable_mask & 8) { ! 3818: find->attrib = 8; ! 3819: find->size = 0; ! 3820: strcpy(find->name, msdos_short_volume_label(process->volume_label)); ! 3821: process->allowable_mask &= ~8; ! 3822: REG16(AX) = 0; ! 3823: } else { ! 3824: REG16(AX) = 0x12; ! 3825: cpustate->CF = 1; ! 3826: } ! 3827: } ! 3828: ! 3829: inline void msdos_int_21h_50h() ! 3830: { ! 3831: current_psp = REG16(BX); ! 3832: } ! 3833: ! 3834: inline void msdos_int_21h_51h() ! 3835: { ! 3836: REG16(BX) = current_psp; ! 3837: } ! 3838: ! 3839: inline void msdos_int_21h_52h() ! 3840: { ! 3841: cpustate->sreg[ES].selector = (DOS_INFO_BASE >> 4); ! 3842: i386_load_segment_descriptor(cpustate, ES); ! 3843: REG16(BX) = (DOS_INFO_BASE & 0x0f); ! 3844: } ! 3845: ! 3846: inline void msdos_int_21h_54h() ! 3847: { ! 3848: process_t *process = msdos_process_info_get(current_psp); ! 3849: ! 3850: REG8(AL) = process->verify; ! 3851: } ! 3852: ! 3853: inline void msdos_int_21h_55h() ! 3854: { ! 3855: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4)); ! 3856: ! 3857: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t)); ! 3858: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22); ! 3859: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23); ! 3860: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24); ! 3861: psp->parent_psp = current_psp; ! 3862: } ! 3863: ! 3864: inline void msdos_int_21h_56h(int lfn) ! 3865: { ! 3866: char src[MAX_PATH], dst[MAX_PATH]; ! 3867: strcpy(src, msdos_trimmed_path((char *)(mem + cpustate->sreg[DS].base + REG16(DX)), lfn)); ! 3868: strcpy(dst, msdos_trimmed_path((char *)(mem + cpustate->sreg[ES].base + REG16(DI)), lfn)); ! 3869: ! 3870: if(rename(src, dst)) { ! 3871: REG16(AX) = errno; ! 3872: cpustate->CF = 1; ! 3873: } ! 3874: } ! 3875: ! 3876: inline void msdos_int_21h_57h() ! 3877: { ! 3878: FILETIME time, local; ! 3879: ! 3880: switch(REG8(AL)) { ! 3881: case 0x00: ! 3882: if(GetFileTime((HANDLE)_get_osfhandle(REG16(BX)), NULL, NULL, &time)) { ! 3883: FileTimeToLocalFileTime(&time, &local); ! 3884: FileTimeToDosDateTime(&local, ®16(DX), ®16(CX)); ! 3885: } else { ! 3886: REG16(AX) = (UINT16)GetLastError(); ! 3887: cpustate->CF = 1; ! 3888: } ! 3889: break; ! 3890: case 0x01: ! 3891: DosDateTimeToFileTime(REG16(DX), REG16(CX), &local); ! 3892: LocalFileTimeToFileTime(&local, &time); ! 3893: if(!SetFileTime((HANDLE)_get_osfhandle(REG16(BX)), NULL, NULL, &time)) { ! 3894: REG16(AX) = (UINT16)GetLastError(); ! 3895: cpustate->CF = 1; ! 3896: } ! 3897: break; ! 3898: default: ! 3899: REG16(AX) = 0x01; ! 3900: cpustate->CF = 1; ! 3901: break; ! 3902: } ! 3903: } ! 3904: ! 3905: inline void msdos_int_21h_58h() ! 3906: { ! 3907: switch(REG8(AL)) { ! 3908: case 0x00: ! 3909: REG16(AX) = 0x00; ! 3910: break; ! 3911: default: ! 3912: REG16(AX) = 0x01; ! 3913: cpustate->CF = 1; ! 3914: break; ! 3915: } ! 3916: } ! 3917: ! 3918: inline void msdos_int_21h_59h() ! 3919: { ! 3920: REG16(AX) = error_code; ! 3921: switch(error_code) { ! 3922: case 4: // Too many open files ! 3923: case 8: // Insufficient memory ! 3924: REG8(BH) = 1; // Out of resource ! 3925: break; ! 3926: case 5: // Access denied ! 3927: REG8(BH) = 3; // Authorization ! 3928: break; ! 3929: case 7: // Memory control block destroyed ! 3930: REG8(BH) = 4; // Internal ! 3931: break; ! 3932: case 2: // File not found ! 3933: case 3: // Path not found ! 3934: case 15: // Invaid drive specified ! 3935: case 18: // No more files ! 3936: REG8(BH) = 8; // Not found ! 3937: break; ! 3938: case 32: // Sharing violation ! 3939: case 33: // Lock violation ! 3940: REG8(BH) = 10; // Locked ! 3941: break; ! 3942: // case 16: // Removal of current directory attempted ! 3943: case 19: // Attempted write on protected disk ! 3944: case 21: // Drive not ready ! 3945: // case 29: // Write failure ! 3946: // case 30: // Read failure ! 3947: // case 82: // Cannot create subdirectory ! 3948: REG8(BH) = 11; // Media ! 3949: break; ! 3950: case 80: // File already exists ! 3951: REG8(BH) = 12; // Already exist ! 3952: break; ! 3953: default: ! 3954: REG8(BH) = 13; // Unknown ! 3955: break; ! 3956: } ! 3957: REG8(BL) = 1; // Retry ! 3958: REG8(CH) = 1; // Unknown ! 3959: } ! 3960: ! 3961: inline void msdos_int_21h_5ah() ! 3962: { ! 3963: char *path = (char *)(mem + cpustate->sreg[DS].base + REG16(DX)); ! 3964: int len = strlen(path); ! 3965: char tmp[MAX_PATH]; ! 3966: ! 3967: if(GetTempFileName(path, "TMP", 0, tmp)) { ! 3968: int fd = _open(tmp, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE); ! 3969: ! 3970: SetFileAttributes(tmp, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY); ! 3971: REG16(AX) = fd; ! 3972: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp); ! 3973: ! 3974: strcpy(path, tmp); ! 3975: int dx = REG16(DX) + len; ! 3976: int ds = cpustate->sreg[DS].selector; ! 3977: while(dx > 0xffff) { ! 3978: dx -= 0x10; ! 3979: ds++; ! 3980: } ! 3981: REG16(DX) = dx; ! 3982: cpustate->sreg[DS].selector = ds; ! 3983: i386_load_segment_descriptor(cpustate, DS); ! 3984: } else { ! 3985: REG16(AX) = (UINT16)GetLastError(); ! 3986: cpustate->CF = 1; ! 3987: } ! 3988: } ! 3989: ! 3990: inline void msdos_int_21h_5bh() ! 3991: { ! 3992: char *path = msdos_local_file_path((char *)(mem + cpustate->sreg[DS].base + REG16(DX)), 0); ! 3993: ! 3994: if(_access(path, 0) == 0) { ! 3995: // already exists ! 3996: REG16(AX) = 0x50; ! 3997: cpustate->CF = 1; ! 3998: } else { ! 3999: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE); ! 4000: ! 4001: if(fd != -1) { ! 4002: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY); ! 4003: REG16(AX) = fd; ! 4004: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp); ! 4005: } else { ! 4006: REG16(AX) = errno; ! 4007: cpustate->CF = 1; ! 4008: } ! 4009: } ! 4010: } ! 4011: ! 4012: inline void msdos_int_21h_5ch() ! 4013: { ! 4014: process_t *process = msdos_process_info_get(current_psp); ! 4015: ! 4016: if(REG16(BX) < process->max_files && file_handler[REG16(BX)].valid) { ! 4017: if(REG8(AL) == 0 || REG8(AL) == 1) { ! 4018: static int modes[2] = {_LK_LOCK, _LK_UNLCK}; ! 4019: UINT32 pos = _tell(REG16(BX)); ! 4020: _lseek(REG16(BX), (REG16(CX) << 16) | REG16(DX), SEEK_SET); ! 4021: if(_locking(REG16(BX), modes[REG8(AL)], (REG16(SI) << 16) | REG16(DI))) { ! 4022: REG16(AX) = errno; ! 4023: cpustate->CF = 1; ! 4024: } ! 4025: _lseek(REG16(BX), pos, SEEK_SET); ! 4026: #ifdef SUPPORT_HARDWARE ! 4027: // some seconds may be passed in _locking() ! 4028: hardware_update(); ! 4029: #endif ! 4030: } else { ! 4031: REG16(AX) = 0x01; ! 4032: cpustate->CF = 1; ! 4033: } ! 4034: } else { ! 4035: REG16(AX) = 0x06; ! 4036: cpustate->CF = 1; ! 4037: } ! 4038: } ! 4039: ! 4040: inline void msdos_int_21h_60h(int lfn) ! 4041: { ! 4042: if(lfn) { ! 4043: char full[MAX_PATH], *name; ! 4044: GetFullPathName((char *)(mem + cpustate->sreg[DS].base + REG16(SI)), MAX_PATH, full, &name); ! 4045: strcpy((char *)(mem + cpustate->sreg[ES].base + REG16(DI)), full); ! 4046: } else { ! 4047: strcpy((char *)(mem + cpustate->sreg[ES].base + REG16(DI)), msdos_short_full_path((char *)(mem + cpustate->sreg[DS].base + REG16(SI)))); ! 4048: } ! 4049: } ! 4050: ! 4051: inline void msdos_int_21h_61h() ! 4052: { ! 4053: REG8(AL) = 0; ! 4054: } ! 4055: ! 4056: inline void msdos_int_21h_62h() ! 4057: { ! 4058: REG16(BX) = current_psp; ! 4059: } ! 4060: ! 4061: inline void msdos_int_21h_63h() ! 4062: { ! 4063: switch(REG8(AL)) { ! 4064: case 0x00: ! 4065: cpustate->sreg[DS].selector = (DBCS_TABLE >> 4); ! 4066: i386_load_segment_descriptor(cpustate, DS); ! 4067: REG16(SI) = (DBCS_TABLE & 0x0f); ! 4068: REG8(AL) = 0x00; ! 4069: break; ! 4070: default: ! 4071: REG16(AX) = 0x01; ! 4072: cpustate->CF = 1; ! 4073: break; ! 4074: } ! 4075: } ! 4076: ! 4077: inline void msdos_int_21h_65h() ! 4078: { ! 4079: char tmp[0x10000]; ! 4080: ! 4081: switch(REG8(AL)) { ! 4082: case 0x07: ! 4083: *(UINT8 *)(mem + cpustate->sreg[ES].base + REG16(DI) + 0) = 0x07; ! 4084: *(UINT16 *)(mem + cpustate->sreg[ES].base + REG16(DI) + 1) = (DBCS_TOP & 0x0f); ! 4085: *(UINT16 *)(mem + cpustate->sreg[ES].base + REG16(DI) + 3) = (DBCS_TOP >> 4); ! 4086: REG16(CX) = 0x05; ! 4087: break; ! 4088: case 0x20: ! 4089: sprintf(tmp, "%c", REG8(DL)); ! 4090: my_strupr(tmp); ! 4091: REG8(DL) = tmp[0]; ! 4092: break; ! 4093: case 0x21: ! 4094: memset(tmp, 0, sizeof(tmp)); ! 4095: memcpy(tmp, mem + cpustate->sreg[DS].base + REG16(DX), REG16(CX)); ! 4096: my_strupr(tmp); ! 4097: memcpy(mem + cpustate->sreg[DS].base + REG16(DX), tmp, REG16(CX)); ! 4098: break; ! 4099: case 0x22: ! 4100: my_strupr((char *)(mem + cpustate->sreg[DS].base + REG16(DX))); ! 4101: break; ! 4102: default: ! 4103: REG16(AX) = 0x01; ! 4104: cpustate->CF = 1; ! 4105: break; ! 4106: } ! 4107: } ! 4108: ! 4109: inline void msdos_int_21h_66h() ! 4110: { ! 4111: switch(REG8(AL)) { ! 4112: case 0x01: ! 4113: REG16(BX) = active_code_page; ! 4114: REG16(DX) = system_code_page; ! 4115: break; ! 4116: case 0x02: ! 4117: if(active_code_page == REG16(BX)) { ! 4118: REG16(AX) = 0xeb41; ! 4119: } else if(_setmbcp(REG16(BX)) == 0) { ! 4120: active_code_page = REG16(BX); ! 4121: msdos_dbcs_table_update(); ! 4122: REG16(AX) = 0xeb41; ! 4123: } else { ! 4124: REG16(AX) = 0x25; ! 4125: cpustate->CF = 1; ! 4126: } ! 4127: break; ! 4128: default: ! 4129: REG16(AX) = 0x01; ! 4130: cpustate->CF = 1; ! 4131: break; ! 4132: } ! 4133: } ! 4134: ! 4135: inline void msdos_int_21h_67h() ! 4136: { ! 4137: process_t *process = msdos_process_info_get(current_psp); ! 4138: ! 4139: if(REG16(BX) <= MAX_FILES) { ! 4140: process->max_files = max(REG16(BX), 20); ! 4141: } else { ! 4142: REG16(AX) = 0x08; ! 4143: cpustate->CF = 1; ! 4144: } ! 4145: } ! 4146: ! 4147: inline void msdos_int_21h_68h() ! 4148: { ! 4149: process_t *process = msdos_process_info_get(current_psp); ! 4150: ! 4151: if(REG16(BX) < process->max_files && file_handler[REG16(BX)].valid) { ! 4152: // fflush(_fdopen(REG16(BX), "")); ! 4153: } else { ! 4154: REG16(AX) = 0x06; ! 4155: cpustate->CF = 1; ! 4156: } ! 4157: } ! 4158: ! 4159: inline void msdos_int_21h_69h() ! 4160: { ! 4161: drive_info_t *info = (drive_info_t *)(mem + cpustate->sreg[DS].base + REG16(DX)); ! 4162: char path[] = "A:\\"; ! 4163: char volume_label[MAX_PATH]; ! 4164: DWORD serial_number = 0; ! 4165: char file_system[MAX_PATH]; ! 4166: ! 4167: if(REG8(BL) == 0) { ! 4168: path[0] = 'A' + _getdrive() - 1; ! 4169: } else { ! 4170: path[0] = 'A' + REG8(BL) - 1; ! 4171: } ! 4172: ! 4173: switch(REG8(AL)) { ! 4174: case 0x00: ! 4175: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) { ! 4176: info->info_level = 0; ! 4177: info->serial_number = serial_number; ! 4178: memset(info->volume_label, 0x20, 11); ! 4179: memcpy(info->volume_label, volume_label, min(strlen(volume_label), 11)); ! 4180: memset(info->file_system, 0x20, 8); ! 4181: memcpy(info->file_system, file_system, min(strlen(file_system), 8)); ! 4182: } else { ! 4183: REG16(AX) = errno; ! 4184: cpustate->CF = 1; ! 4185: } ! 4186: break; ! 4187: case 0x01: ! 4188: REG16(AX) = 0x03; ! 4189: cpustate->CF = 1; ! 4190: } ! 4191: } ! 4192: ! 4193: inline void msdos_int_21h_6ah() ! 4194: { ! 4195: REG8(AH) = 0x68; ! 4196: msdos_int_21h_68h(); ! 4197: } ! 4198: ! 4199: inline void msdos_int_21h_6bh() ! 4200: { ! 4201: REG8(AL) = 0; ! 4202: } ! 4203: ! 4204: inline void msdos_int_21h_6ch(int lfn) ! 4205: { ! 4206: char *path = msdos_local_file_path((char *)(mem + cpustate->sreg[DS].base + REG16(SI)), lfn); ! 4207: int mode = REG8(BL) & 0x03; ! 4208: ! 4209: if(mode < 0x03) { ! 4210: if(_access(path, 0) == 0) { ! 4211: // file exists ! 4212: if(REG8(DL) & 1) { ! 4213: int fd = _open(path, file_mode[mode].mode); ! 4214: ! 4215: if(fd != -1) { ! 4216: REG16(AX) = fd; ! 4217: REG16(CX) = 1; ! 4218: msdos_file_handler_open(fd, path, _isatty(fd), mode, msdos_drive_number(path), current_psp); ! 4219: } else { ! 4220: REG16(AX) = errno; ! 4221: cpustate->CF = 1; ! 4222: } ! 4223: } else if(REG8(DL) & 2) { ! 4224: int attr = GetFileAttributes(path); ! 4225: int fd = -1; ! 4226: ! 4227: if(_stricmp(path, "CON") == 0) { ! 4228: fd = _open(path, file_mode[mode].mode); ! 4229: } else { ! 4230: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE); ! 4231: } ! 4232: if(fd != -1) { ! 4233: if(attr == -1) { ! 4234: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY; ! 4235: } ! 4236: SetFileAttributes(path, attr); ! 4237: REG16(AX) = fd; ! 4238: REG16(CX) = 3; ! 4239: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp); ! 4240: } else { ! 4241: REG16(AX) = errno; ! 4242: cpustate->CF = 1; ! 4243: } ! 4244: } else { ! 4245: REG16(AX) = 0x50; ! 4246: cpustate->CF = 1; ! 4247: } ! 4248: } else { ! 4249: // file not exists ! 4250: if(REG8(DL) & 0x10) { ! 4251: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE); ! 4252: ! 4253: if(fd != -1) { ! 4254: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY); ! 4255: REG16(AX) = fd; ! 4256: REG16(CX) = 2; ! 4257: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp); ! 4258: } else { ! 4259: REG16(AX) = errno; ! 4260: cpustate->CF = 1; ! 4261: } ! 4262: } else { ! 4263: REG16(AX) = 0x02; ! 4264: cpustate->CF = 1; ! 4265: } ! 4266: } ! 4267: } else { ! 4268: REG16(AX) = 0x0c; ! 4269: cpustate->CF = 1; ! 4270: } ! 4271: } ! 4272: ! 4273: inline void msdos_int_21h_710dh() ! 4274: { ! 4275: // reset drive ! 4276: } ! 4277: ! 4278: inline void msdos_int_21h_714eh() ! 4279: { ! 4280: process_t *process = msdos_process_info_get(current_psp); ! 4281: find_lfn_t *find = (find_lfn_t *)(mem + cpustate->sreg[ES].base + REG16(DI)); ! 4282: char *path = (char *)(mem + cpustate->sreg[DS].base + REG16(DX)); ! 4283: WIN32_FIND_DATA fd; ! 4284: ! 4285: if(process->find_handle != INVALID_HANDLE_VALUE) { ! 4286: FindClose(process->find_handle); ! 4287: process->find_handle = INVALID_HANDLE_VALUE; ! 4288: } ! 4289: strcpy(process->volume_label, msdos_volume_label(path)); ! 4290: process->allowable_mask = REG8(CL); ! 4291: process->required_mask = REG8(CH); ! 4292: ! 4293: if((process->allowable_mask & 8) && !msdos_match_volume_label(path, process->volume_label) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) { ! 4294: process->allowable_mask &= ~8; ! 4295: } ! 4296: if((process->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) { ! 4297: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, process->allowable_mask, process->required_mask)) { ! 4298: if(!FindNextFile(process->find_handle, &fd)) { ! 4299: FindClose(process->find_handle); ! 4300: process->find_handle = INVALID_HANDLE_VALUE; ! 4301: break; ! 4302: } ! 4303: } ! 4304: } ! 4305: if(process->find_handle != INVALID_HANDLE_VALUE) { ! 4306: find->attrib = fd.dwFileAttributes; ! 4307: msdos_find_file_conv_local_time(&fd); ! 4308: if(REG16(SI) == 0) { ! 4309: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime; ! 4310: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime; ! 4311: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime; ! 4312: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime; ! 4313: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime; ! 4314: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime; ! 4315: } else { ! 4316: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l); ! 4317: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l); ! 4318: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l); ! 4319: } ! 4320: find->size_hi = fd.nFileSizeHigh; ! 4321: find->size_lo = fd.nFileSizeLow; ! 4322: strcpy(find->full_name, fd.cFileName); ! 4323: strcpy(find->short_name, msdos_short_path(fd.cFileName)); ! 4324: } else if(process->allowable_mask & 8) { ! 4325: // volume label ! 4326: find->attrib = 8; ! 4327: find->size_hi = find->size_lo = 0; ! 4328: strcpy(find->full_name, process->volume_label); ! 4329: strcpy(find->short_name, msdos_short_volume_label(process->volume_label)); ! 4330: process->allowable_mask &= ~8; ! 4331: } else { ! 4332: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid ! 4333: cpustate->CF = 1; ! 4334: } ! 4335: } ! 4336: ! 4337: inline void msdos_int_21h_714fh() ! 4338: { ! 4339: process_t *process = msdos_process_info_get(current_psp); ! 4340: find_lfn_t *find = (find_lfn_t *)(mem + cpustate->sreg[ES].base + REG16(DI)); ! 4341: WIN32_FIND_DATA fd; ! 4342: ! 4343: if(process->find_handle != INVALID_HANDLE_VALUE) { ! 4344: if(FindNextFile(process->find_handle, &fd)) { ! 4345: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, process->allowable_mask, process->required_mask)) { ! 4346: if(!FindNextFile(process->find_handle, &fd)) { ! 4347: FindClose(process->find_handle); ! 4348: process->find_handle = INVALID_HANDLE_VALUE; ! 4349: break; ! 4350: } ! 4351: } ! 4352: } else { ! 4353: FindClose(process->find_handle); ! 4354: process->find_handle = INVALID_HANDLE_VALUE; ! 4355: } ! 4356: } ! 4357: if(process->find_handle != INVALID_HANDLE_VALUE) { ! 4358: find->attrib = fd.dwFileAttributes; ! 4359: msdos_find_file_conv_local_time(&fd); ! 4360: if(REG16(SI) == 0) { ! 4361: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime; ! 4362: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime; ! 4363: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime; ! 4364: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime; ! 4365: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime; ! 4366: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime; ! 4367: } else { ! 4368: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l); ! 4369: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l); ! 4370: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l); ! 4371: } ! 4372: find->size_hi = fd.nFileSizeHigh; ! 4373: find->size_lo = fd.nFileSizeLow; ! 4374: strcpy(find->full_name, fd.cFileName); ! 4375: strcpy(find->short_name, msdos_short_path(fd.cFileName)); ! 4376: } else if(process->allowable_mask & 8) { ! 4377: // volume label ! 4378: find->attrib = 8; ! 4379: find->size_hi = find->size_lo = 0; ! 4380: strcpy(find->full_name, process->volume_label); ! 4381: strcpy(find->short_name, msdos_short_volume_label(process->volume_label)); ! 4382: process->allowable_mask &= ~8; ! 4383: } else { ! 4384: REG16(AX) = 0x12; ! 4385: cpustate->CF = 1; ! 4386: } ! 4387: } ! 4388: ! 4389: inline void msdos_int_21h_71a0h() ! 4390: { ! 4391: DWORD max_component_len, file_sys_flag; ! 4392: ! 4393: if(GetVolumeInformation((char *)(mem + cpustate->sreg[DS].base + REG16(DX)), NULL, 0, NULL, &max_component_len, &file_sys_flag, (char *)(mem + cpustate->sreg[ES].base + REG16(DI)), REG16(CX))) { ! 4394: REG16(BX) = (UINT16)file_sys_flag; ! 4395: REG16(CX) = (UINT16)max_component_len; // 255 ! 4396: REG16(DX) = (UINT16)max_component_len + 5; // 260 ! 4397: } else { ! 4398: REG16(AX) = (UINT16)GetLastError(); ! 4399: cpustate->CF = 1; ! 4400: } ! 4401: } ! 4402: ! 4403: inline void msdos_int_21h_71a1h() ! 4404: { ! 4405: process_t *process = msdos_process_info_get(current_psp); ! 4406: find_t *find = (find_t *)(mem + (process->dta.w.h << 4) + process->dta.w.l); ! 4407: ! 4408: if(process->find_handle != INVALID_HANDLE_VALUE) { ! 4409: FindClose(process->find_handle); ! 4410: process->find_handle = INVALID_HANDLE_VALUE; ! 4411: } ! 4412: } ! 4413: ! 4414: inline void msdos_int_21h_71a6h() ! 4415: { ! 4416: process_t *process = msdos_process_info_get(current_psp); ! 4417: UINT8 *buffer = (UINT8 *)(mem + cpustate->sreg[DS].base + REG16(DX)); ! 4418: struct _stat64 status; ! 4419: DWORD serial_number = 0; ! 4420: ! 4421: if(REG16(BX) < process->max_files && file_handler[REG16(BX)].valid) { ! 4422: if(_fstat64(REG16(BX), &status) == 0) { ! 4423: if(file_handler[REG16(BX)].path[1] == ':') { ! 4424: // NOTE: we need to consider the network file path "\\host\share\" ! 4425: char volume[] = "A:\\"; ! 4426: volume[0] = file_handler[REG16(BX)].path[1]; ! 4427: GetVolumeInformation(volume, NULL, 0, &serial_number, NULL, NULL, NULL, 0); ! 4428: } ! 4429: *(UINT32 *)(buffer + 0x00) = GetFileAttributes(file_handler[REG16(BX)].path); ! 4430: *(UINT32 *)(buffer + 0x04) = (UINT32)(status.st_ctime & 0xffffffff); ! 4431: *(UINT32 *)(buffer + 0x08) = (UINT32)((status.st_ctime >> 32) & 0xffffffff); ! 4432: *(UINT32 *)(buffer + 0x0c) = (UINT32)(status.st_atime & 0xffffffff); ! 4433: *(UINT32 *)(buffer + 0x10) = (UINT32)((status.st_atime >> 32) & 0xffffffff); ! 4434: *(UINT32 *)(buffer + 0x14) = (UINT32)(status.st_mtime & 0xffffffff); ! 4435: *(UINT32 *)(buffer + 0x18) = (UINT32)((status.st_mtime >> 32) & 0xffffffff); ! 4436: *(UINT32 *)(buffer + 0x1c) = serial_number; ! 4437: *(UINT32 *)(buffer + 0x20) = (UINT32)((status.st_size >> 32) & 0xffffffff); ! 4438: *(UINT32 *)(buffer + 0x24) = (UINT32)(status.st_size & 0xffffffff); ! 4439: *(UINT32 *)(buffer + 0x28) = status.st_nlink; ! 4440: // this is dummy id and it will be changed when it is reopend... ! 4441: *(UINT32 *)(buffer + 0x2c) = 0; ! 4442: *(UINT32 *)(buffer + 0x30) = file_handler[REG16(BX)].id; ! 4443: } else { ! 4444: REG16(AX) = errno; ! 4445: cpustate->CF = 1; ! 4446: } ! 4447: } else { ! 4448: REG16(AX) = 0x06; ! 4449: cpustate->CF = 1; ! 4450: } ! 4451: } ! 4452: ! 4453: inline void msdos_int_21h_71a7h() ! 4454: { ! 4455: switch(REG8(BL)) { ! 4456: case 0x00: ! 4457: if(!FileTimeToDosDateTime((FILETIME *)(mem + cpustate->sreg[DS].base + REG16(SI)), ®16(DX), ®16(CX))) { ! 4458: REG16(AX) = (UINT16)GetLastError(); ! 4459: cpustate->CF = 1; ! 4460: } ! 4461: break; ! 4462: case 0x01: ! 4463: // NOTE: we need to check BH that shows 10-millisecond untils past time in CX ! 4464: if(!DosDateTimeToFileTime(REG16(DX), REG16(CX), (FILETIME *)(mem + cpustate->sreg[ES].base + REG16(DI)))) { ! 4465: REG16(AX) = (UINT16)GetLastError(); ! 4466: cpustate->CF = 1; ! 4467: } ! 4468: break; ! 4469: default: ! 4470: REG16(AX) = 0x01; ! 4471: cpustate->CF = 1; ! 4472: break; ! 4473: } ! 4474: } ! 4475: ! 4476: inline void msdos_int_21h_71a8h() ! 4477: { ! 4478: if(REG8(DH) == 0) { ! 4479: char tmp[MAX_PATH], fcb[MAX_PATH]; ! 4480: strcpy(tmp, msdos_short_path((char *)(mem + cpustate->sreg[DS].base + REG16(SI)))); ! 4481: memset(fcb, 0x20, sizeof(fcb)); ! 4482: int len = strlen(tmp); ! 4483: int pos = 0; ! 4484: for(int i = 0; i < len; i++) { ! 4485: if(tmp[i] == '.') { ! 4486: pos = 8; ! 4487: } else { ! 4488: if(msdos_lead_byte_check(tmp[i])) { ! 4489: fcb[pos++] = tmp[i++]; ! 4490: } ! 4491: fcb[pos++] = tmp[i]; ! 4492: } ! 4493: } ! 4494: memcpy((char *)(mem + cpustate->sreg[ES].base + REG16(DI)), fcb, 11); ! 4495: } else { ! 4496: strcpy((char *)(mem + cpustate->sreg[ES].base + REG16(DI)), msdos_short_path((char *)(mem + cpustate->sreg[DS].base + REG16(SI)))); ! 4497: } ! 4498: } ! 4499: ! 4500: inline void msdos_int_21h_7303h() ! 4501: { ! 4502: char *path = (char *)(mem + cpustate->sreg[DS].base + REG16(DX)); ! 4503: ext_space_info_t *info = (ext_space_info_t *)(mem + cpustate->sreg[ES].base + REG16(DI)); ! 4504: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters; ! 4505: ! 4506: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) { ! 4507: info->size_of_structure = sizeof(ext_space_info_t); ! 4508: info->structure_version = 0; ! 4509: info->sectors_per_cluster = sectors_per_cluster; ! 4510: info->bytes_per_sector = bytes_per_sector; ! 4511: info->available_clusters_on_drive = free_clusters; ! 4512: info->total_clusters_on_drive = total_clusters; ! 4513: info->available_sectors_on_drive = sectors_per_cluster * free_clusters; ! 4514: info->total_sectors_on_drive = sectors_per_cluster * total_clusters; ! 4515: info->available_allocation_units = free_clusters; // ??? ! 4516: info->total_allocation_units = total_clusters; // ??? ! 4517: } else { ! 4518: REG16(AX) = errno; ! 4519: cpustate->CF = 1; ! 4520: } ! 4521: } ! 4522: ! 4523: inline void msdos_int_25h() ! 4524: { ! 4525: UINT16 seg, ofs; ! 4526: DWORD dwSize; ! 4527: ! 4528: I386OP(pushf)(cpustate); ! 4529: ! 4530: if(!(REG8(AL) < 26)) { ! 4531: REG8(AL) = 0x01; // unit unknown ! 4532: cpustate->CF = 1; ! 4533: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) { ! 4534: REG8(AL) = 0x02; // drive not ready ! 4535: cpustate->CF = 1; ! 4536: } else { ! 4537: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs); ! 4538: char dev[64]; ! 4539: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL)); ! 4540: ! 4541: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL); ! 4542: if(hFile == INVALID_HANDLE_VALUE) { ! 4543: REG8(AL) = 0x02; // drive not ready ! 4544: cpustate->CF = 1; ! 4545: } else { ! 4546: if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) { ! 4547: REG8(AL) = 0x02; // drive not ready ! 4548: cpustate->CF = 1; ! 4549: } else if(SetFilePointer(hFile, REG16(DX) * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { ! 4550: REG8(AL) = 0x08; // sector not found ! 4551: cpustate->CF = 1; ! 4552: } else if(ReadFile(hFile, mem + cpustate->sreg[DS].base + REG16(BX), REG16(CX) * dpb->bytes_per_sector, &dwSize, NULL) == 0) { ! 4553: REG8(AL) = 0x0b; // read error ! 4554: cpustate->CF = 1; ! 4555: } ! 4556: CloseHandle(hFile); ! 4557: } ! 4558: } ! 4559: } ! 4560: ! 4561: inline void msdos_int_26h() ! 4562: { ! 4563: // this operation may cause serious damage for drives, so always returns error... ! 4564: UINT16 seg, ofs; ! 4565: DWORD dwSize; ! 4566: ! 4567: I386OP(pushf)(cpustate); ! 4568: ! 4569: if(!(REG8(AL) < 26)) { ! 4570: REG8(AL) = 0x01; // unit unknown ! 4571: cpustate->CF = 1; ! 4572: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) { ! 4573: REG8(AL) = 0x02; // drive not ready ! 4574: cpustate->CF = 1; ! 4575: } else { ! 4576: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs); ! 4577: char dev[64]; ! 4578: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL)); ! 4579: ! 4580: if(dpb->media_type == 0xf8) { ! 4581: // this drive is not a floppy ! 4582: REG8(AL) = 0x02; // drive not ready ! 4583: cpustate->CF = 1; ! 4584: } else { ! 4585: HANDLE hFile = CreateFile(dev, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL); ! 4586: if(hFile == INVALID_HANDLE_VALUE) { ! 4587: REG8(AL) = 0x02; // drive not ready ! 4588: cpustate->CF = 1; ! 4589: } else { ! 4590: if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) { ! 4591: REG8(AL) = 0x02; // drive not ready ! 4592: cpustate->CF = 1; ! 4593: } else if(SetFilePointer(hFile, REG16(DX) * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { ! 4594: REG8(AL) = 0x08; // sector not found ! 4595: cpustate->CF = 1; ! 4596: } else if(WriteFile(hFile, mem + cpustate->sreg[DS].base + REG16(BX), REG16(CX) * dpb->bytes_per_sector, &dwSize, NULL) == 0) { ! 4597: REG8(AL) = 0x0a; // write error ! 4598: cpustate->CF = 1; ! 4599: } ! 4600: CloseHandle(hFile); ! 4601: } ! 4602: } ! 4603: } ! 4604: } ! 4605: ! 4606: inline void msdos_int_27h() ! 4607: { ! 4608: int mcb_seg = cpustate->sreg[CS].selector - 1; ! 4609: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4)); ! 4610: ! 4611: mcb->paragraphs = (REG16(DX) >> 4); ! 4612: mcb_seg += mcb->paragraphs + 1; ! 4613: msdos_mcb_create(mcb_seg, 'Z', 0, (MEMORY_END >> 4) - mcb_seg - 1); ! 4614: ! 4615: msdos_process_terminate(cpustate->sreg[CS].selector, retval | 0x300, 0); ! 4616: } ! 4617: ! 4618: inline void msdos_int_29h() ! 4619: { ! 4620: msdos_putch(REG8(AL)); ! 4621: } ! 4622: ! 4623: inline void msdos_int_2eh() ! 4624: { ! 4625: char tmp[MAX_PATH], command[MAX_PATH], opt[MAX_PATH]; ! 4626: memset(tmp, 0, sizeof(tmp)); ! 4627: strcpy(tmp, (char *)(mem + cpustate->sreg[DS].base + REG16(SI))); ! 4628: char *token = my_strtok(tmp, " "); ! 4629: strcpy(command, token); ! 4630: strcpy(opt, token + strlen(token) + 1); ! 4631: ! 4632: param_block_t *param = (param_block_t *)(mem + WORK_TOP); ! 4633: param->env_seg = 0; ! 4634: param->cmd_line.w.l = 44; ! 4635: param->cmd_line.w.h = (WORK_TOP >> 4); ! 4636: param->fcb1.w.l = 24; ! 4637: param->fcb1.w.h = (WORK_TOP >> 4); ! 4638: param->fcb2.w.l = 24; ! 4639: param->fcb2.w.h = (WORK_TOP >> 4); ! 4640: ! 4641: memset(mem + WORK_TOP + 24, 0x20, 20); ! 4642: ! 4643: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44); ! 4644: cmd_line->len = strlen(opt); ! 4645: strcpy(cmd_line->cmd, opt); ! 4646: cmd_line->cmd[cmd_line->len] = 0x0d; ! 4647: ! 4648: msdos_process_exec(command, param, 0); ! 4649: REG8(AL) = 0; ! 4650: } ! 4651: ! 4652: inline void msdos_int_2fh_16h() ! 4653: { ! 4654: switch(REG8(AL)) { ! 4655: case 0x00: ! 4656: { ! 4657: OSVERSIONINFO osvi; ! 4658: ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); ! 4659: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); ! 4660: GetVersionEx(&osvi); ! 4661: REG8(AL) = osvi.dwMajorVersion; ! 4662: REG8(AH) = osvi.dwMinorVersion; ! 4663: } ! 4664: break; ! 4665: default: ! 4666: REG16(AX) = 0x01; ! 4667: cpustate->CF = 1; ! 4668: break; ! 4669: } ! 4670: } ! 4671: ! 4672: inline void msdos_int_2fh_1ah() ! 4673: { ! 4674: switch(REG8(AL)) { ! 4675: case 0x00: ! 4676: // ansi.sys is installed ! 4677: REG8(AL) = 0xff; ! 4678: break; ! 4679: default: ! 4680: REG16(AX) = 0x01; ! 4681: cpustate->CF = 1; ! 4682: break; ! 4683: } ! 4684: } ! 4685: ! 4686: inline void msdos_int_2fh_43h() ! 4687: { ! 4688: switch(REG8(AL)) { ! 4689: case 0x00: ! 4690: // xms is not installed ! 4691: REG8(AL) = 0; ! 4692: break; ! 4693: default: ! 4694: REG16(AX) = 0x01; ! 4695: cpustate->CF = 1; ! 4696: break; ! 4697: } ! 4698: } ! 4699: ! 4700: inline void msdos_int_2fh_4ah() ! 4701: { ! 4702: switch(REG8(AL)) { ! 4703: case 0x01: ! 4704: case 0x02: ! 4705: // hma is not installed ! 4706: REG16(BX) = 0; ! 4707: cpustate->sreg[ES].selector = 0xffff; ! 4708: i386_load_segment_descriptor(cpustate, ES); ! 4709: REG16(DI) = 0xffff; ! 4710: break; ! 4711: default: ! 4712: REG16(AX) = 0x01; ! 4713: cpustate->CF = 1; ! 4714: break; ! 4715: } ! 4716: } ! 4717: ! 4718: inline void msdos_int_2fh_4fh() ! 4719: { ! 4720: switch(REG8(AL)) { ! 4721: case 0x00: ! 4722: REG16(AX) = 0; ! 4723: REG8(DL) = 1; // major version ! 4724: REG8(DH) = 0; // minor version ! 4725: break; ! 4726: case 0x01: ! 4727: REG16(AX) = 0; ! 4728: REG16(BX) = active_code_page; ! 4729: break; ! 4730: default: ! 4731: REG16(AX) = 0x01; ! 4732: cpustate->CF = 1; ! 4733: break; ! 4734: } ! 4735: } ! 4736: ! 4737: inline void msdos_int_2fh_aeh() ! 4738: { ! 4739: switch(REG8(AL)) { ! 4740: case 0x00: ! 4741: REG8(AL) = 0; ! 4742: break; ! 4743: case 0x01: ! 4744: { ! 4745: char command[MAX_PATH]; ! 4746: memset(command, 0, sizeof(command)); ! 4747: memcpy(command, mem + cpustate->sreg[DS].base + REG16(SI) + 1, mem[cpustate->sreg[DS].base + REG16(SI)]); ! 4748: ! 4749: param_block_t *param = (param_block_t *)(mem + WORK_TOP); ! 4750: param->env_seg = 0; ! 4751: param->cmd_line.w.l = 44; ! 4752: param->cmd_line.w.h = (WORK_TOP >> 4); ! 4753: param->fcb1.w.l = 24; ! 4754: param->fcb1.w.h = (WORK_TOP >> 4); ! 4755: param->fcb2.w.l = 24; ! 4756: param->fcb2.w.h = (WORK_TOP >> 4); ! 4757: ! 4758: memset(mem + WORK_TOP + 24, 0x20, 20); ! 4759: ! 4760: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44); ! 4761: cmd_line->len = mem[cpustate->sreg[DS].base + REG16(BX) + 1]; ! 4762: memcpy(cmd_line->cmd, mem + cpustate->sreg[DS].base + REG16(BX) + 2, cmd_line->len); ! 4763: cmd_line->cmd[cmd_line->len] = 0x0d; ! 4764: ! 4765: if(msdos_process_exec(command, param, 0)) { ! 4766: REG16(AX) = 0x02; ! 4767: cpustate->CF = 1; ! 4768: } ! 4769: } ! 4770: break; ! 4771: default: ! 4772: REG16(AX) = 0x01; ! 4773: cpustate->CF = 1; ! 4774: break; ! 4775: } ! 4776: } ! 4777: ! 4778: inline void msdos_int_2fh_b7h() ! 4779: { ! 4780: switch(REG8(AL)) { ! 4781: case 0x00: ! 4782: // append is not installed ! 4783: REG8(AL) = 0; ! 4784: break; ! 4785: default: ! 4786: REG16(AX) = 0x01; ! 4787: cpustate->CF = 1; ! 4788: break; ! 4789: } ! 4790: } ! 4791: ! 4792: void msdos_syscall(unsigned num) ! 4793: { ! 4794: switch(num) { ! 4795: case 0x00: ! 4796: error("division by zero\n"); ! 4797: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1); ! 4798: break; ! 4799: case 0x04: ! 4800: error("overflow\n"); ! 4801: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1); ! 4802: break; ! 4803: case 0x06: ! 4804: // NOTE: ish.com has illegal instruction... ! 4805: // error("illegal instruction\n"); ! 4806: // msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1); ! 4807: break; ! 4808: case 0x10: ! 4809: // PC BIOS - Video ! 4810: if(scr_width != 80 || scr_height != 25) { ! 4811: CONSOLE_SCREEN_BUFFER_INFO csbi; ! 4812: SMALL_RECT rect; ! 4813: COORD co; ! 4814: ! 4815: GetConsoleScreenBufferInfo(hStdout, &csbi); ! 4816: if(csbi.dwCursorPosition.Y > 24) { ! 4817: SET_RECT(rect, 0, 0, scr_width - 1, scr_height - 1); ! 4818: ReadConsoleOutput(hStdout, &scr_buf[0][0], scr_buf_size, scr_buf_pos, &rect); ! 4819: for(int y = 0, y2 = csbi.dwCursorPosition.Y - 24; y < 25; y++, y2++) { ! 4820: for(int x = 0; x < 80; x++) { ! 4821: scr_buf[y][x] = scr_buf[y2][x]; ! 4822: } ! 4823: } ! 4824: WriteConsoleOutput(hStdout, &scr_buf[0][0], scr_buf_size, scr_buf_pos, &rect); ! 4825: ! 4826: co.X = csbi.dwCursorPosition.X; ! 4827: co.Y = 24; ! 4828: SetConsoleCursorPosition(hStdout, co); ! 4829: cursor_moved = true; ! 4830: } ! 4831: SET_RECT(rect, 0, 0, 79, 24); ! 4832: co.X = 80; ! 4833: co.Y = 25; ! 4834: SetConsoleWindowInfo(hStdout, TRUE, &rect); ! 4835: SetConsoleScreenBufferSize(hStdout, co); ! 4836: scr_width = 80; ! 4837: scr_height = 25; ! 4838: } ! 4839: cpustate->CF = 0; ! 4840: switch(REG8(AH)) { ! 4841: case 0x00: pcbios_int_10h_00h(); break; ! 4842: case 0x01: pcbios_int_10h_01h(); break; ! 4843: case 0x02: pcbios_int_10h_02h(); break; ! 4844: case 0x03: pcbios_int_10h_03h(); break; ! 4845: case 0x05: pcbios_int_10h_05h(); break; ! 4846: case 0x06: pcbios_int_10h_06h(); break; ! 4847: case 0x07: pcbios_int_10h_07h(); break; ! 4848: case 0x08: pcbios_int_10h_08h(); break; ! 4849: case 0x09: pcbios_int_10h_09h(); break; ! 4850: case 0x0a: pcbios_int_10h_0ah(); break; ! 4851: case 0x0b: break; ! 4852: case 0x0c: break; ! 4853: case 0x0d: break; ! 4854: case 0x0e: pcbios_int_10h_0eh(); break; ! 4855: case 0x0f: pcbios_int_10h_0fh(); break; ! 4856: case 0x10: break; ! 4857: case 0x11: break; ! 4858: case 0x12: REG8(AL) = 0x00; break; ! 4859: case 0x13: pcbios_int_10h_13h(); break; ! 4860: case 0x18: REG8(AL) = 0x86; break; ! 4861: case 0x1a: REG8(AL) = 0x00; break; ! 4862: case 0x1c: REG8(AL) = 0x00; break; ! 4863: case 0x1d: pcbios_int_10h_1dh(); break; ! 4864: case 0x82: pcbios_int_10h_82h(); break; ! 4865: case 0xfe: pcbios_int_10h_feh(); break; ! 4866: case 0xff: pcbios_int_10h_ffh(); break; ! 4867: default: ! 4868: fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX)); ! 4869: break; ! 4870: } ! 4871: break; ! 4872: case 0x11: ! 4873: // PC BIOS - Get Equipment List ! 4874: REG16(AX) = 0x20; ! 4875: break; ! 4876: case 0x12: ! 4877: // PC BIOS - Get Memory Size ! 4878: REG16(AX) = MEMORY_END / 1024; ! 4879: break; ! 4880: case 0x13: ! 4881: // PC BIOS - Disk ! 4882: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX)); ! 4883: REG8(AH) = 0xff; ! 4884: cpustate->CF = 1; ! 4885: break; ! 4886: case 0x14: ! 4887: // PC BIOS - Serial I/O ! 4888: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX)); ! 4889: REG8(AH) = 0xff; ! 4890: cpustate->CF = 1; ! 4891: break; ! 4892: case 0x15: ! 4893: // PC BIOS ! 4894: cpustate->CF = 0; ! 4895: switch(REG8(AH)) { ! 4896: case 0x23: pcbios_int_15h_23h(); break; ! 4897: case 0x24: pcbios_int_15h_24h(); break; ! 4898: case 0x49: pcbios_int_15h_49h(); break; ! 4899: case 0x86: pcbios_int_15h_86h(); break; ! 4900: case 0x87: pcbios_int_15h_87h(); break; ! 4901: case 0x88: pcbios_int_15h_88h(); break; ! 4902: case 0x89: pcbios_int_15h_89h(); break; ! 4903: case 0xc9: pcbios_int_15h_c9h(); break; ! 4904: case 0xca: pcbios_int_15h_cah(); break; ! 4905: default: ! 4906: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX)); ! 4907: REG8(AH)=0x86; ! 4908: cpustate->CF = 1; ! 4909: break; ! 4910: } ! 4911: break; ! 4912: case 0x16: ! 4913: // PC BIOS - Keyboard ! 4914: cpustate->CF = 0; ! 4915: switch(REG8(AH)) { ! 4916: case 0x00: pcbios_int_16h_00h(); break; ! 4917: case 0x01: pcbios_int_16h_01h(); break; ! 4918: case 0x02: pcbios_int_16h_02h(); break; ! 4919: case 0x03: pcbios_int_16h_03h(); break; ! 4920: case 0x05: pcbios_int_16h_05h(); break; ! 4921: case 0x10: pcbios_int_16h_00h(); break; ! 4922: case 0x11: pcbios_int_16h_01h(); break; ! 4923: case 0x12: pcbios_int_16h_12h(); break; ! 4924: case 0x13: pcbios_int_16h_13h(); break; ! 4925: case 0x14: pcbios_int_16h_14h(); break; ! 4926: default: ! 4927: fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX)); ! 4928: break; ! 4929: } ! 4930: break; ! 4931: case 0x17: ! 4932: // PC BIOS - Printer ! 4933: fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX)); ! 4934: break; ! 4935: case 0x1a: ! 4936: // PC BIOS - Timer ! 4937: cpustate->CF = 0; ! 4938: switch(REG8(AH)) { ! 4939: case 0x00: pcbios_int_1ah_00h(); break; ! 4940: case 0x01: break; ! 4941: case 0x02: pcbios_int_1ah_02h(); break; ! 4942: case 0x03: break; ! 4943: case 0x04: pcbios_int_1ah_04h(); break; ! 4944: case 0x05: break; ! 4945: case 0x0a: pcbios_int_1ah_0ah(); break; ! 4946: case 0x0b: break; ! 4947: default: ! 4948: fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX)); ! 4949: break; ! 4950: } ! 4951: break; ! 4952: case 0x20: ! 4953: msdos_process_terminate(cpustate->sreg[CS].selector, retval, 1); ! 4954: break; ! 4955: case 0x21: ! 4956: // MS-DOS System Call ! 4957: cpustate->CF = 0; ! 4958: switch(REG8(AH)) { ! 4959: case 0x00: msdos_int_21h_00h(); break; ! 4960: case 0x01: msdos_int_21h_01h(); break; ! 4961: case 0x02: msdos_int_21h_02h(); break; ! 4962: case 0x03: msdos_int_21h_03h(); break; ! 4963: case 0x04: msdos_int_21h_04h(); break; ! 4964: case 0x05: msdos_int_21h_05h(); break; ! 4965: case 0x06: msdos_int_21h_06h(); break; ! 4966: case 0x07: msdos_int_21h_07h(); break; ! 4967: case 0x08: msdos_int_21h_08h(); break; ! 4968: case 0x09: msdos_int_21h_09h(); break; ! 4969: case 0x0a: msdos_int_21h_0ah(); break; ! 4970: case 0x0b: msdos_int_21h_0bh(); break; ! 4971: case 0x0c: msdos_int_21h_0ch(); break; ! 4972: case 0x0d: msdos_int_21h_0dh(); break; ! 4973: case 0x0e: msdos_int_21h_0eh(); break; ! 4974: // 0x0f: open file with fcb ! 4975: // 0x10: close file with fcb ! 4976: case 0x11: msdos_int_21h_11h(); break; ! 4977: case 0x12: msdos_int_21h_12h(); break; ! 4978: case 0x13: msdos_int_21h_13h(); break; ! 4979: // 0x14: sequential read with fcb ! 4980: // 0x15: sequential write with fcb ! 4981: // 0x16: create new file with fcb ! 4982: // 0x17: rename file with fcb ! 4983: case 0x18: msdos_int_21h_18h(); break; ! 4984: case 0x19: msdos_int_21h_19h(); break; ! 4985: case 0x1a: msdos_int_21h_1ah(); break; ! 4986: case 0x1b: msdos_int_21h_1bh(); break; ! 4987: case 0x1c: msdos_int_21h_1ch(); break; ! 4988: case 0x1d: msdos_int_21h_1dh(); break; ! 4989: case 0x1e: msdos_int_21h_1eh(); break; ! 4990: case 0x1f: msdos_int_21h_1fh(); break; ! 4991: case 0x20: msdos_int_21h_20h(); break; ! 4992: // 0x21: random read with fcb ! 4993: // 0x22: randome write with fcb ! 4994: // 0x23: get file size with fcb ! 4995: // 0x24: set relative record field with fcb ! 4996: case 0x25: msdos_int_21h_25h(); break; ! 4997: case 0x26: msdos_int_21h_26h(); break; ! 4998: // 0x27: random block read with fcb ! 4999: // 0x28: random block write with fcb ! 5000: case 0x29: msdos_int_21h_29h(); break; ! 5001: case 0x2a: msdos_int_21h_2ah(); break; ! 5002: case 0x2b: msdos_int_21h_2bh(); break; ! 5003: case 0x2c: msdos_int_21h_2ch(); break; ! 5004: case 0x2d: msdos_int_21h_2dh(); break; ! 5005: case 0x2e: msdos_int_21h_2eh(); break; ! 5006: case 0x2f: msdos_int_21h_2fh(); break; ! 5007: case 0x30: msdos_int_21h_30h(); break; ! 5008: case 0x31: msdos_int_21h_31h(); break; ! 5009: case 0x32: msdos_int_21h_32h(); break; ! 5010: case 0x33: msdos_int_21h_33h(); break; ! 5011: // 0x34: get address of indos flag ! 5012: case 0x35: msdos_int_21h_35h(); break; ! 5013: case 0x36: msdos_int_21h_36h(); break; ! 5014: case 0x37: msdos_int_21h_37h(); break; ! 5015: // 0x38: get country-specific information ! 5016: case 0x39: msdos_int_21h_39h(0); break; ! 5017: case 0x3a: msdos_int_21h_3ah(0); break; ! 5018: case 0x3b: msdos_int_21h_3bh(0); break; ! 5019: case 0x3c: msdos_int_21h_3ch(); break; ! 5020: case 0x3d: msdos_int_21h_3dh(); break; ! 5021: case 0x3e: msdos_int_21h_3eh(); break; ! 5022: case 0x3f: msdos_int_21h_3fh(); break; ! 5023: case 0x40: msdos_int_21h_40h(); break; ! 5024: case 0x41: msdos_int_21h_41h(0); break; ! 5025: case 0x42: msdos_int_21h_42h(); break; ! 5026: case 0x43: msdos_int_21h_43h(0); break; ! 5027: case 0x44: msdos_int_21h_44h(); break; ! 5028: case 0x45: msdos_int_21h_45h(); break; ! 5029: case 0x46: msdos_int_21h_46h(); break; ! 5030: case 0x47: msdos_int_21h_47h(0); break; ! 5031: case 0x48: msdos_int_21h_48h(); break; ! 5032: case 0x49: msdos_int_21h_49h(); break; ! 5033: case 0x4a: msdos_int_21h_4ah(); break; ! 5034: case 0x4b: msdos_int_21h_4bh(); break; ! 5035: case 0x4c: msdos_int_21h_4ch(); break; ! 5036: case 0x4d: msdos_int_21h_4dh(); break; ! 5037: case 0x4e: msdos_int_21h_4eh(); break; ! 5038: case 0x4f: msdos_int_21h_4fh(); break; ! 5039: case 0x50: msdos_int_21h_50h(); break; ! 5040: case 0x51: msdos_int_21h_51h(); break; ! 5041: case 0x52: msdos_int_21h_52h(); break; ! 5042: // 0x53: translate bios parameter block to drive param bock ! 5043: case 0x54: msdos_int_21h_54h(); break; ! 5044: case 0x55: msdos_int_21h_55h(); break; ! 5045: case 0x56: msdos_int_21h_56h(0); break; ! 5046: case 0x57: msdos_int_21h_57h(); break; ! 5047: case 0x58: msdos_int_21h_58h(); break; ! 5048: case 0x59: msdos_int_21h_59h(); break; ! 5049: case 0x5a: msdos_int_21h_5ah(); break; ! 5050: case 0x5b: msdos_int_21h_5bh(); break; ! 5051: case 0x5c: msdos_int_21h_5ch(); break; ! 5052: // 0x5e: ms-network ! 5053: // 0x5f: ms-network ! 5054: case 0x60: msdos_int_21h_60h(0); break; ! 5055: case 0x61: msdos_int_21h_61h(); break; ! 5056: case 0x62: msdos_int_21h_62h(); break; ! 5057: case 0x63: msdos_int_21h_63h(); break; ! 5058: // 0x64: set device driver lockahead flag ! 5059: case 0x65: msdos_int_21h_65h(); break; ! 5060: case 0x66: msdos_int_21h_66h(); break; ! 5061: case 0x67: msdos_int_21h_67h(); break; ! 5062: case 0x68: msdos_int_21h_68h(); break; ! 5063: case 0x69: msdos_int_21h_69h(); break; ! 5064: case 0x6a: msdos_int_21h_6ah(); break; ! 5065: case 0x6b: msdos_int_21h_6bh(); break; ! 5066: case 0x6c: msdos_int_21h_6ch(0); break; ! 5067: // 0x6d: find first rom program ! 5068: // 0x6e: find next rom program ! 5069: // 0x6f: get/set rom scan start address ! 5070: // 0x70: windows95 get/set internationalization information ! 5071: case 0x71: ! 5072: // windows95 long filename functions ! 5073: switch(REG8(AL)) { ! 5074: case 0x0d: msdos_int_21h_710dh(); break; ! 5075: case 0x39: msdos_int_21h_39h(1); break; ! 5076: case 0x3a: msdos_int_21h_3ah(1); break; ! 5077: case 0x3b: msdos_int_21h_3bh(1); break; ! 5078: case 0x41: msdos_int_21h_41h(1); break; ! 5079: case 0x43: msdos_int_21h_43h(1); break; ! 5080: case 0x47: msdos_int_21h_47h(1); break; ! 5081: case 0x4e: msdos_int_21h_714eh(); break; ! 5082: case 0x4f: msdos_int_21h_714fh(); break; ! 5083: case 0x56: msdos_int_21h_56h(1); break; ! 5084: case 0x60: msdos_int_21h_60h(1); break; ! 5085: case 0x6c: msdos_int_21h_6ch(1); break; ! 5086: case 0xa0: msdos_int_21h_71a0h(); break; ! 5087: case 0xa1: msdos_int_21h_71a1h(); break; ! 5088: case 0xa6: msdos_int_21h_71a6h(); break; ! 5089: case 0xa7: msdos_int_21h_71a7h(); break; ! 5090: case 0xa8: msdos_int_21h_71a8h(); break; ! 5091: // 0xa9: server create/open file ! 5092: // 0xaa: create/terminate SUBST ! 5093: default: ! 5094: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX)); ! 5095: REG16(AX) = 0x7100; ! 5096: cpustate->CF = 1; ! 5097: break; ! 5098: } ! 5099: break; ! 5100: // 0x72: Windows95 beta - LFN FindClose ! 5101: case 0x73: ! 5102: // windows95 fat32 functions ! 5103: switch(REG8(AL)) { ! 5104: // 0x00: drive locking ??? ! 5105: // 0x01: drive locking ??? ! 5106: // 0x02: get extended dpb ! 5107: case 0x03: msdos_int_21h_7303h(); break; ! 5108: // 0x04: set dpb to use for formatting ! 5109: default: ! 5110: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX)); ! 5111: REG16(AX) = 0x7300; ! 5112: cpustate->CF = 1; ! 5113: break; ! 5114: } ! 5115: break; ! 5116: default: ! 5117: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX)); ! 5118: REG16(AX) = 0x01; ! 5119: cpustate->CF = 1; ! 5120: break; ! 5121: } ! 5122: if(cpustate->CF) { ! 5123: error_code = REG16(AX); ! 5124: } ! 5125: break; ! 5126: case 0x22: ! 5127: fatalerror("int 22h (terminate address)\n"); ! 5128: case 0x23: ! 5129: msdos_process_terminate(current_psp, (retval & 0xff) | 0x100, 1); ! 5130: break; ! 5131: case 0x24: ! 5132: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1); ! 5133: break; ! 5134: case 0x25: ! 5135: msdos_int_25h(); ! 5136: break; ! 5137: case 0x26: ! 5138: msdos_int_26h(); ! 5139: break; ! 5140: case 0x27: ! 5141: msdos_int_27h(); ! 5142: break; ! 5143: case 0x28: ! 5144: Sleep(10); ! 5145: break; ! 5146: case 0x29: ! 5147: msdos_int_29h(); ! 5148: break; ! 5149: case 0x2e: ! 5150: msdos_int_2eh(); ! 5151: break; ! 5152: case 0x2f: ! 5153: // multiplex interrupt ! 5154: cpustate->CF = 0; ! 5155: switch(REG8(AH)) { ! 5156: case 0x16: msdos_int_2fh_16h(); break; ! 5157: case 0x1a: msdos_int_2fh_1ah(); break; ! 5158: case 0x43: msdos_int_2fh_43h(); break; ! 5159: case 0x4a: msdos_int_2fh_4ah(); break; ! 5160: case 0x4f: msdos_int_2fh_4fh(); break; ! 5161: case 0xae: msdos_int_2fh_aeh(); break; ! 5162: case 0xb7: msdos_int_2fh_b7h(); break; ! 5163: default: ! 5164: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX)); ! 5165: REG16(AX) = 0x01; // ??? ! 5166: cpustate->CF = 1; ! 5167: break; ! 5168: } ! 5169: if(cpustate->CF) { ! 5170: error_code = REG16(AX); ! 5171: } ! 5172: break; ! 5173: default: ! 5174: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX)); ! 5175: break; ! 5176: } ! 5177: ! 5178: // update cursor position ! 5179: if(cursor_moved) { ! 5180: CONSOLE_SCREEN_BUFFER_INFO csbi; ! 5181: GetConsoleScreenBufferInfo(hStdout, &csbi); ! 5182: mem[0x450 + mem[0x462] * 2] = csbi.dwCursorPosition.X; ! 5183: mem[0x451 + mem[0x462] * 2] = csbi.dwCursorPosition.Y; ! 5184: cursor_moved = false; ! 5185: } ! 5186: } ! 5187: ! 5188: // init ! 5189: ! 5190: int msdos_init(int argc, char *argv[], char *envp[], int standard_env) ! 5191: { ! 5192: // init file handler ! 5193: memset(file_handler, 0, sizeof(file_handler)); ! 5194: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0); ! 5195: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0); ! 5196: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0); ! 5197: #ifdef SUPPORT_AUX_PRN ! 5198: if(_open("stdaux.txt", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) { ! 5199: msdos_file_handler_open(3, 0, 2, 0x80c0, 0); ! 5200: } ! 5201: if(_open("stdprn.txt", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) { ! 5202: msdos_file_handler_open(4, 0, 1, 0xa8c0, 0); ! 5203: } ! 5204: #endif ! 5205: _dup2(0, DUP_STDIN); ! 5206: _dup2(1, DUP_STDOUT); ! 5207: _dup2(2, DUP_STDERR); ! 5208: ! 5209: // init process ! 5210: memset(process, 0, sizeof(process)); ! 5211: ! 5212: // init memory ! 5213: memset(mem, 0, sizeof(mem)); ! 5214: for(int i = 0; i < 0x100; i++) { ! 5215: *(UINT16 *)(mem + 4 * i + 0) = i; ! 5216: *(UINT16 *)(mem + 4 * i + 2) = (IRET_TOP >> 4); ! 5217: } ! 5218: *(UINT16 *)(mem + 4 * 0x22 + 0) = 0xfff0; ! 5219: *(UINT16 *)(mem + 4 * 0x22 + 2) = 0xf000; ! 5220: memset(mem + IRET_TOP, 0xcf, IRET_SIZE); ! 5221: ! 5222: // bios data area ! 5223: CONSOLE_SCREEN_BUFFER_INFO csbi; ! 5224: GetConsoleScreenBufferInfo(hStdout, &csbi); ! 5225: ! 5226: *(UINT8 *)(mem + 0x411) = 0x20; ! 5227: *(UINT16 *)(mem + 0x410) = 0x20; ! 5228: *(UINT16 *)(mem + 0x413) = MEMORY_END / 1024; ! 5229: *(UINT8 *)(mem + 0x449) = 0x03;//0x73; ! 5230: *(UINT16 *)(mem + 0x44a) = 80; ! 5231: *(UINT16 *)(mem + 0x44c) = 4096; ! 5232: *(UINT16 *)(mem + 0x44e) = 0; ! 5233: *(UINT8 *)(mem + 0x450) = csbi.dwCursorPosition.X; ! 5234: *(UINT8 *)(mem + 0x451) = csbi.dwCursorPosition.Y; ! 5235: *(UINT8 *)(mem + 0x460) = 7; ! 5236: *(UINT8 *)(mem + 0x461) = 7; ! 5237: *(UINT8 *)(mem + 0x462) = 0; ! 5238: *(UINT16 *)(mem + 0x463) = 0x3d4; ! 5239: *(UINT8 *)(mem + 0x484) = 24; ! 5240: *(UINT8 *)(mem + 0x485) = 19; ! 5241: *(UINT8 *)(mem + 0x487) = 0; // is this okay? ! 5242: ! 5243: // dos info ! 5244: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP); ! 5245: dos_info->first_mcb = MEMORY_TOP >> 4; ! 5246: dos_info->first_dpb.w.l = 0; ! 5247: dos_info->first_dpb.w.h = DPB_TOP >> 4; ! 5248: dos_info->first_sft.w.l = 0; ! 5249: dos_info->first_sft.w.h = FILE_TABLE_TOP >> 4; ! 5250: dos_info->cds.w.l = 0; ! 5251: dos_info->cds.w.h = CDS_TOP >> 4; ! 5252: dos_info->fcb_table.w.l = 0; ! 5253: dos_info->fcb_table.w.h = FCB_TABLE_TOP >> 4; ! 5254: dos_info->last_drive = 'Z' - 'A' + 1; ! 5255: dos_info->buffers_x = 20; ! 5256: dos_info->buffers_y = 0; ! 5257: char *env; ! 5258: if((env = getenv("LASTDRIVE")) != NULL) { ! 5259: if(env[0] >= 'A' && env[0] <= 'Z') { ! 5260: dos_info->last_drive = env[0] - 'A' + 1; ! 5261: } else if(env[0] >= 'a' && env[0] <= 'z') { ! 5262: dos_info->last_drive = env[0] - 'a' + 1; ! 5263: } ! 5264: } ! 5265: if((env = getenv("windir")) != NULL) { ! 5266: if(env[0] >= 'A' && env[0] <= 'Z') { ! 5267: dos_info->boot_drive = env[0] - 'A' + 1; ! 5268: } else if(env[0] >= 'a' && env[0] <= 'z') { ! 5269: dos_info->boot_drive = env[0] - 'a' + 1; ! 5270: } ! 5271: } ! 5272: dos_info->i386_or_later = 1; ! 5273: dos_info->ext_mem_size = (MAX_MEM - 0x100000) >> 10; ! 5274: ! 5275: // environment ! 5276: int seg = MEMORY_TOP >> 4; ! 5277: msdos_mcb_create(seg++, 'M', -1, ENV_SIZE >> 4); ! 5278: int env_seg = seg; ! 5279: int ofs = 0; ! 5280: ! 5281: for(char **p = envp; p != NULL && *p != NULL; p++) { ! 5282: // lower to upper ! 5283: char tmp[ENV_SIZE], name[ENV_SIZE], value[ENV_SIZE]; ! 5284: int value_pos = 0; ! 5285: strcpy(tmp, *p); ! 5286: for(int i = 0;; i++) { ! 5287: if(tmp[i] == '=') { ! 5288: tmp[i] = '\0'; ! 5289: sprintf(name, ";%s;", tmp); ! 5290: strcpy(value, tmp + (value_pos = i + 1)); ! 5291: tmp[i] = '='; ! 5292: break; ! 5293: } else if(tmp[i] >= 'a' && tmp[i] <= 'z') { ! 5294: tmp[i] = tmp[i] - 'a' + 'A'; ! 5295: } ! 5296: } ! 5297: if(!(standard_env && strstr(";COMSPEC;INCLUDE;LIB;PATH;PROMPT;TEMP;TMP;TZ;", name) == NULL)) { ! 5298: if(strncmp(tmp, "COMSPEC=", 8) == 0) { ! 5299: char full_path[MAX_PATH], short_path[MAX_PATH], *file_name; ! 5300: GetFullPathName(argv[0], MAX_PATH, full_path, &file_name); ! 5301: if(_stricmp(file_name, "COMMAND.COM") == 0 || _stricmp(file_name, "COMMAND") == 0) { ! 5302: sprintf(file_name, "COMMAND.COM"); ! 5303: if(_access(full_path, 0) == 0) { ! 5304: GetShortPathName(full_path, short_path, MAX_PATH); ! 5305: my_strupr(short_path); ! 5306: sprintf(tmp, "COMSPEC=%s", short_path); ! 5307: } ! 5308: } ! 5309: } else if(strncmp(tmp, "PATH=", 5) == 0 || strncmp(tmp, "TEMP=", 5) == 0 || strncmp(tmp, "TMP=", 4) == 0) { ! 5310: tmp[value_pos] = '\0'; ! 5311: char *token = my_strtok(value, ";"); ! 5312: while(token != NULL) { ! 5313: if(strlen(token) != 0) { ! 5314: char path[MAX_PATH], short_path[MAX_PATH]; ! 5315: if(token[0] == '"' && token[strlen(token) - 1] == '"') { ! 5316: memset(path, 0, sizeof(path)); ! 5317: memcpy(path, token + 1, strlen(token) - 2); ! 5318: } else { ! 5319: sprintf(path, token); ! 5320: } ! 5321: GetShortPathName(path, short_path, MAX_PATH); ! 5322: strcat(tmp, short_path); ! 5323: strcat(tmp, ";"); ! 5324: } ! 5325: token = my_strtok(NULL, ";"); ! 5326: } ! 5327: tmp[strlen(tmp) - 1] = '\0'; ! 5328: my_strupr(tmp); ! 5329: } ! 5330: int len = strlen(tmp); ! 5331: if (ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) { ! 5332: fatalerror("too many environments\n"); ! 5333: } ! 5334: memcpy(mem + (seg << 4) + ofs, tmp, len); ! 5335: ofs += len + 1; ! 5336: } ! 5337: } ! 5338: seg += (ENV_SIZE >> 4); ! 5339: ! 5340: // psp ! 5341: msdos_mcb_create(seg++, 'M', -1, PSP_SIZE >> 4); ! 5342: current_psp = seg; ! 5343: psp_t *psp = msdos_psp_create(seg, seg + (PSP_SIZE >> 4), -1, env_seg); ! 5344: seg += (PSP_SIZE >> 4); ! 5345: ! 5346: // first mcb ! 5347: msdos_mcb_create(seg, 'Z', 0, (MEMORY_END >> 4) - seg - 1); ! 5348: ! 5349: // boot ! 5350: mem[0xffff0] = 0xf4; // halt ! 5351: mem[0xffff1] = 0xcd; // int 21h ! 5352: mem[0xffff2] = 0x21; ! 5353: mem[0xffff3] = 0xcb; // retf ! 5354: ! 5355: // param block ! 5356: // + 0: param block (22bytes) ! 5357: // +24: fcb1/2 (20bytes) ! 5358: // +44: command tail (128bytes) ! 5359: param_block_t *param = (param_block_t *)(mem + WORK_TOP); ! 5360: param->env_seg = 0; ! 5361: param->cmd_line.w.l = 44; ! 5362: param->cmd_line.w.h = (WORK_TOP >> 4); ! 5363: param->fcb1.w.l = 24; ! 5364: param->fcb1.w.h = (WORK_TOP >> 4); ! 5365: param->fcb2.w.l = 24; ! 5366: param->fcb2.w.h = (WORK_TOP >> 4); ! 5367: ! 5368: memset(mem + WORK_TOP + 24, 0x20, 20); ! 5369: ! 5370: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44); ! 5371: if(argc > 1) { ! 5372: sprintf(cmd_line->cmd, " %s", argv[1]); ! 5373: for(int i = 2; i < argc; i++) { ! 5374: char tmp[128]; ! 5375: sprintf(tmp, "%s %s", cmd_line->cmd, argv[i]); ! 5376: strcpy(cmd_line->cmd, tmp); ! 5377: } ! 5378: cmd_line->len = (UINT8)strlen(cmd_line->cmd); ! 5379: } else { ! 5380: cmd_line->len = 0; ! 5381: } ! 5382: cmd_line->cmd[cmd_line->len] = 0x0d; ! 5383: ! 5384: // system file table ! 5385: *(UINT16 *)(mem + FILE_TABLE_TOP + 0) = 6; ! 5386: *(UINT16 *)(mem + FILE_TABLE_TOP + 2) = FILE_TABLE_TOP >> 4; ! 5387: *(UINT16 *)(mem + FILE_TABLE_TOP + 4) = 100; ! 5388: *(UINT32 *)(mem + FILE_TABLE_TOP + 6) = 0xffffffff; ! 5389: *(UINT16 *)(mem + FILE_TABLE_TOP + 10) = 100; ! 5390: ! 5391: // current directory structure ! 5392: msdos_cds_update(_getdrive() - 1); ! 5393: ! 5394: // fcb table ! 5395: *(UINT32 *)(mem + FCB_TABLE_TOP + 0) = 0xffffffff; ! 5396: *(UINT16 *)(mem + FCB_TABLE_TOP + 4) = 100; ! 5397: ! 5398: // dbcs table ! 5399: msdos_dbcs_table_init(); ! 5400: ! 5401: // execute command ! 5402: if(msdos_process_exec(argv[0], param, 0)) { ! 5403: fatalerror("'%s' not found\n", argv[0]); ! 5404: } ! 5405: retval = 0; ! 5406: return(0); ! 5407: } ! 5408: ! 5409: #define remove_std_file(path) { \ ! 5410: int fd = _open(path, _O_RDONLY | _O_BINARY); \ ! 5411: if(fd != -1) { \ ! 5412: _lseek(fd, 0, SEEK_END); \ ! 5413: int size = _tell(fd); \ ! 5414: _close(fd); \ ! 5415: if(size == 0) { \ ! 5416: remove(path); \ ! 5417: } \ ! 5418: } \ ! 5419: } ! 5420: ! 5421: void msdos_finish() ! 5422: { ! 5423: for(int i = 0; i < MAX_FILES; i++) { ! 5424: if(file_handler[i].valid) { ! 5425: _close(i); ! 5426: } ! 5427: } ! 5428: #ifdef SUPPORT_AUX_PRN ! 5429: remove_std_file("stdaux.txt"); ! 5430: remove_std_file("stdprn.txt"); ! 5431: #endif ! 5432: msdos_dbcs_table_finish(); ! 5433: } ! 5434: ! 5435: /* ---------------------------------------------------------------------------- ! 5436: PC/AT hardware emulation ! 5437: ---------------------------------------------------------------------------- */ ! 5438: ! 5439: void hardware_init() ! 5440: { ! 5441: cpustate = (i386_state *)CPU_INIT_CALL(CPU_MODEL); ! 5442: CPU_RESET_CALL(CPU_MODEL); ! 5443: cpu_type = (REG32(EDX) >> 8) & 0x0f; ! 5444: cpu_step = (REG32(EDX) >> 0) & 0x0f; ! 5445: i386_set_a20_line(cpustate, 0); ! 5446: #ifdef SUPPORT_HARDWARE ! 5447: pic_init(); ! 5448: //pit_init(); ! 5449: pit_active = 0; ! 5450: #endif ! 5451: } ! 5452: ! 5453: void hardware_finish() ! 5454: { ! 5455: free(cpustate); ! 5456: } ! 5457: ! 5458: void hardware_run() ! 5459: { ! 5460: int ops = 0; ! 5461: ! 5462: while(!cpustate->halted) { ! 5463: #ifdef SUPPORT_DISASSEMBLER ! 5464: if(dasm) { ! 5465: char buffer[256]; ! 5466: UINT64 eip = cpustate->eip; ! 5467: UINT8 *oprom = mem + cpustate->sreg[CS].base + cpustate->eip; ! 5468: ! 5469: if(cpustate->operand_size) { ! 5470: CPU_DISASSEMBLE_CALL(x86_32); ! 5471: } else { ! 5472: CPU_DISASSEMBLE_CALL(x86_16); ! 5473: } ! 5474: fprintf(stderr, "%04x:%04x\t%s\n", cpustate->sreg[CS].selector, cpustate->eip, buffer); ! 5475: } ! 5476: #endif ! 5477: cpustate->cycles = 1; ! 5478: CPU_EXECUTE_CALL(i386); ! 5479: #ifdef SUPPORT_HARDWARE ! 5480: if(++ops == 1024) { ! 5481: hardware_update(); ! 5482: ops = 0; ! 5483: } ! 5484: #endif ! 5485: } ! 5486: } ! 5487: ! 5488: #ifdef SUPPORT_HARDWARE ! 5489: void hardware_update() ! 5490: { ! 5491: if(pit_active) { ! 5492: pit_run(); ! 5493: } ! 5494: } ! 5495: #endif ! 5496: ! 5497: // pic ! 5498: ! 5499: void pic_init() ! 5500: { ! 5501: for(int c = 0; c < 2; c++) { ! 5502: pic[c].imr = 0xff; ! 5503: pic[c].irr = pic[c].isr = pic[c].prio = 0; ! 5504: pic[c].icw1 = pic[c].icw2 = pic[c].icw3 = pic[c].icw4 = 0; ! 5505: pic[c].ocw3 = 0; ! 5506: pic[c].icw2_r = pic[c].icw3_r = pic[c].icw4_r = 0; ! 5507: } ! 5508: ! 5509: // from bochs bios ! 5510: pic_write(0, 0, 0x11); // icw1 = 11h ! 5511: pic_write(0, 1, 0x08); // icw2 = 08h ! 5512: pic_write(0, 1, 0x04); // icw3 = 04h ! 5513: pic_write(0, 1, 0x01); // icw4 = 01h ! 5514: pic_write(0, 1, 0xb8); // ocw1 = b8h ! 5515: pic_write(1, 0, 0x11); // icw1 = 11h ! 5516: pic_write(1, 1, 0x70); // icw2 = 70h ! 5517: pic_write(1, 1, 0x02); // icw3 = 02h ! 5518: pic_write(1, 1, 0x01); // icw4 = 01h ! 5519: } ! 5520: ! 5521: void pic_write(int c, UINT32 addr, UINT8 data) ! 5522: { ! 5523: if(addr & 1) { ! 5524: if(pic[c].icw2_r) { ! 5525: // icw2 ! 5526: pic[c].icw2 = data; ! 5527: pic[c].icw2_r = 0; ! 5528: } else if(pic[c].icw3_r) { ! 5529: // icw3 ! 5530: pic[c].icw3 = data; ! 5531: pic[c].icw3_r = 0; ! 5532: } else if(pic[c].icw4_r) { ! 5533: // icw4 ! 5534: pic[c].icw4 = data; ! 5535: pic[c].icw4_r = 0; ! 5536: } else { ! 5537: // ocw1 ! 5538: pic[c].imr = data; ! 5539: } ! 5540: } else { ! 5541: if(data & 0x10) { ! 5542: // icw1 ! 5543: pic[c].icw1 = data; ! 5544: pic[c].icw2_r = 1; ! 5545: pic[c].icw3_r = (data & 2) ? 0 : 1; ! 5546: pic[c].icw4_r = data & 1; ! 5547: ! 5548: pic[c].irr = 0; ! 5549: pic[c].isr = 0; ! 5550: pic[c].imr = 0; ! 5551: pic[c].prio = 0; ! 5552: if(!(pic[c].icw1 & 1)) { ! 5553: pic[c].icw4 = 0; ! 5554: } ! 5555: pic[c].ocw3 = 0; ! 5556: } else if(data & 8) { ! 5557: // ocw3 ! 5558: if(!(data & 2)) { ! 5559: data = (data & ~1) | (pic[c].ocw3 & 1); ! 5560: } ! 5561: if(!(data & 0x40)) { ! 5562: data = (data & ~0x20) | (pic[c].ocw3 & 0x20); ! 5563: } ! 5564: pic[c].ocw3 = data; ! 5565: } else { ! 5566: // ocw2 ! 5567: int level = 0; ! 5568: if(data & 0x40) { ! 5569: level = data & 7; ! 5570: } else { ! 5571: if(!pic[c].isr) { ! 5572: return; ! 5573: } ! 5574: level = pic[c].prio; ! 5575: while(!(pic[c].isr & (1 << level))) { ! 5576: level = (level + 1) & 7; ! 5577: } ! 5578: } ! 5579: if(data & 0x80) { ! 5580: pic[c].prio = (level + 1) & 7; ! 5581: } ! 5582: if(data & 0x20) { ! 5583: pic[c].isr &= ~(1 << level); ! 5584: } ! 5585: } ! 5586: } ! 5587: pic_update(); ! 5588: } ! 5589: ! 5590: UINT8 pic_read(int c, UINT32 addr) ! 5591: { ! 5592: if(addr & 1) { ! 5593: return(pic[c].imr); ! 5594: } else { ! 5595: // polling mode is not supported... ! 5596: //if(pic[c].ocw3 & 4) { ! 5597: // return ???; ! 5598: //} ! 5599: if(pic[c].ocw3 & 1) { ! 5600: return(pic[c].isr); ! 5601: } else { ! 5602: return(pic[c].irr); ! 5603: } ! 5604: } ! 5605: } ! 5606: ! 5607: void pic_req(int c, int level, int signal) ! 5608: { ! 5609: if(signal) { ! 5610: pic[c].irr |= (1 << level); ! 5611: } else { ! 5612: pic[c].irr &= ~(1 << level); ! 5613: } ! 5614: pic_update(); ! 5615: } ! 5616: ! 5617: int pic_ack() ! 5618: { ! 5619: // ack (INTA=L) ! 5620: pic[pic_req_chip].isr |= pic_req_bit; ! 5621: pic[pic_req_chip].irr &= ~pic_req_bit; ! 5622: if(pic_req_chip > 0) { ! 5623: // update isr and irr of master ! 5624: UINT8 slave = 1 << (pic[pic_req_chip].icw3 & 7); ! 5625: pic[pic_req_chip - 1].isr |= slave; ! 5626: pic[pic_req_chip - 1].irr &= ~slave; ! 5627: } ! 5628: //if(pic[pic_req_chip].icw4 & 1) { ! 5629: // 8086 mode ! 5630: int vector = (pic[pic_req_chip].icw2 & 0xf8) | pic_req_level; ! 5631: //} else { ! 5632: // // 8080 mode ! 5633: // UINT16 addr = (UINT16)pic[pic_req_chip].icw2 << 8; ! 5634: // if(pic[pic_req_chip].icw1 & 4) { ! 5635: // addr |= (pic[pic_req_chip].icw1 & 0xe0) | (pic_req_level << 2); ! 5636: // } else { ! 5637: // addr |= (pic[pic_req_chip].icw1 & 0xc0) | (pic_req_level << 3); ! 5638: // } ! 5639: // vector = 0xcd | (addr << 8); ! 5640: //} ! 5641: if(pic[pic_req_chip].icw4 & 2) { ! 5642: // auto eoi ! 5643: pic[pic_req_chip].isr &= ~pic_req_bit; ! 5644: } ! 5645: return(vector); ! 5646: } ! 5647: ! 5648: void pic_update() ! 5649: { ! 5650: for(int c = 0; c < 2; c++) { ! 5651: UINT8 irr = pic[c].irr; ! 5652: if(c + 1 < 2) { ! 5653: // this is master ! 5654: if(pic[c + 1].irr & (~pic[c + 1].imr)) { ! 5655: // request from slave ! 5656: irr |= 1 << (pic[c + 1].icw3 & 7); ! 5657: } ! 5658: } ! 5659: irr &= (~pic[c].imr); ! 5660: if(!irr) { ! 5661: break; ! 5662: } ! 5663: if(!(pic[c].ocw3 & 0x20)) { ! 5664: irr |= pic[c].isr; ! 5665: } ! 5666: int level = pic[c].prio; ! 5667: UINT8 bit = 1 << level; ! 5668: while(!(irr & bit)) { ! 5669: level = (level + 1) & 7; ! 5670: bit = 1 << level; ! 5671: } ! 5672: if((c + 1 < 2) && (pic[c].icw3 & bit)) { ! 5673: // check slave ! 5674: continue; ! 5675: } ! 5676: if(pic[c].isr & bit) { ! 5677: break; ! 5678: } ! 5679: // interrupt request ! 5680: pic_req_chip = c; ! 5681: pic_req_level = level; ! 5682: pic_req_bit = bit; ! 5683: i386_set_irq_line(cpustate, INPUT_LINE_IRQ, HOLD_LINE); ! 5684: return; ! 5685: } ! 5686: i386_set_irq_line(cpustate, INPUT_LINE_IRQ, CLEAR_LINE); ! 5687: }; ! 5688: ! 5689: // pit ! 5690: ! 5691: #define PIT_FREQ 1193182 ! 5692: #define PIT_COUNT_VALUE(n) ((pit[n].count_reg == 0) ? 0x10000 : (pit[n].mode == 3 && pit[n].count_reg == 1) ? 0x10001 : pit[n].count_reg) ! 5693: ! 5694: void pit_init() ! 5695: { ! 5696: for(int ch = 0; ch < 3; ch++) { ! 5697: pit[ch].prev_out = 1; ! 5698: //pit[ch].gate = 1; ! 5699: pit[ch].count = 0x10000; ! 5700: pit[ch].count_reg = 0; ! 5701: pit[ch].ctrl_reg = 0x34; ! 5702: pit[ch].mode = 3; ! 5703: pit[ch].count_latched = 0; ! 5704: pit[ch].low_read = pit[ch].high_read = 0; ! 5705: pit[ch].low_write = pit[ch].high_write = 0; ! 5706: pit[ch].delay = 0; ! 5707: pit[ch].start = 0; ! 5708: pit[ch].null_count = 1; ! 5709: pit[ch].status_latched = 0; ! 5710: } ! 5711: ! 5712: // from bochs bios ! 5713: pit_write(3, 0x34); ! 5714: pit_write(0, 0x00); ! 5715: pit_write(0, 0x00); ! 5716: } ! 5717: ! 5718: void pit_write(int ch, UINT8 val) ! 5719: { ! 5720: if(!pit_active) { ! 5721: pit_active = 1; ! 5722: pit_init(); ! 5723: } ! 5724: ! 5725: switch(ch) { ! 5726: case 0: ! 5727: case 1: ! 5728: case 2: ! 5729: // write count register ! 5730: if(!pit[ch].low_write && !pit[ch].high_write) { ! 5731: if(pit[ch].ctrl_reg & 0x10) { ! 5732: pit[ch].low_write = 1; ! 5733: } ! 5734: if(pit[ch].ctrl_reg & 0x20) { ! 5735: pit[ch].high_write = 1; ! 5736: } ! 5737: } ! 5738: if(pit[ch].low_write) { ! 5739: pit[ch].count_reg = val; ! 5740: pit[ch].low_write = 0; ! 5741: } else if(pit[ch].high_write) { ! 5742: if((pit[ch].ctrl_reg & 0x30) == 0x20) { ! 5743: pit[ch].count_reg = val << 8; ! 5744: } else { ! 5745: pit[ch].count_reg |= val << 8; ! 5746: } ! 5747: pit[ch].high_write = 0; ! 5748: } ! 5749: pit[ch].null_count = 1; ! 5750: // set signal ! 5751: if(pit[ch].mode == 0) { ! 5752: pit_set_signal(ch, 0); ! 5753: } else { ! 5754: pit_set_signal(ch, 1); ! 5755: } ! 5756: // start count ! 5757: if(pit[ch].mode == 0 || pit[ch].mode == 4) { ! 5758: // restart with new count ! 5759: pit_stop_count(ch); ! 5760: pit[ch].delay = 1; ! 5761: pit_start_count(ch); ! 5762: } else if(pit[ch].mode == 2 || pit[ch].mode == 3) { ! 5763: // start with new pit after the current count is finished ! 5764: if(!pit[ch].start) { ! 5765: pit[ch].delay = 1; ! 5766: pit_start_count(ch); ! 5767: } ! 5768: } ! 5769: break; ! 5770: case 3: // ctrl reg ! 5771: if((val & 0xc0) == 0xc0) { ! 5772: // i8254 read-back command ! 5773: for(ch = 0; ch < 3; ch++) { ! 5774: UINT8 bit = 2 << ch; ! 5775: if(!(val & 0x10) && !pit[ch].status_latched) { ! 5776: pit[ch].status = pit[ch].ctrl_reg & 0x3f; ! 5777: if(pit[ch].prev_out) { ! 5778: pit[ch].status |= 0x80; ! 5779: } ! 5780: if(pit[ch].null_count) { ! 5781: pit[ch].status |= 0x40; ! 5782: } ! 5783: pit[ch].status_latched = 1; ! 5784: } ! 5785: if(!(val & 0x20) && !pit[ch].count_latched) { ! 5786: pit_latch_count(ch); ! 5787: } ! 5788: } ! 5789: break; ! 5790: } ! 5791: ch = (val >> 6) & 3; ! 5792: if(val & 0x30) { ! 5793: static int modes[8] = {0, 1, 2, 3, 4, 5, 2, 3}; ! 5794: pit[ch].mode = modes[(val >> 1) & 7]; ! 5795: pit[ch].count_latched = 0; ! 5796: pit[ch].low_read = pit[ch].high_read = 0; ! 5797: pit[ch].low_write = pit[ch].high_write = 0; ! 5798: pit[ch].ctrl_reg = val; ! 5799: // set signal ! 5800: if(pit[ch].mode == 0) { ! 5801: pit_set_signal(ch, 0); ! 5802: } else { ! 5803: pit_set_signal(ch, 1); ! 5804: } ! 5805: // stop count ! 5806: pit_stop_count(ch); ! 5807: pit[ch].count_reg = 0; ! 5808: pit[ch].null_count = 1; ! 5809: } else if(!pit[ch].count_latched) { ! 5810: pit_latch_count(ch); ! 5811: } ! 5812: break; ! 5813: } ! 5814: } ! 5815: ! 5816: UINT8 pit_read(int ch) ! 5817: { ! 5818: if(!pit_active) { ! 5819: pit_active = 1; ! 5820: pit_init(); ! 5821: } ! 5822: ! 5823: switch(ch) { ! 5824: case 0: ! 5825: case 1: ! 5826: case 2: ! 5827: if(pit[ch].status_latched) { ! 5828: pit[ch].status_latched = 0; ! 5829: return(pit[ch].status); ! 5830: } ! 5831: // if not latched, through current count ! 5832: if(!pit[ch].count_latched) { ! 5833: if(!pit[ch].low_read && !pit[ch].high_read) { ! 5834: pit_latch_count(ch); ! 5835: } ! 5836: } ! 5837: // return latched count ! 5838: if(pit[ch].low_read) { ! 5839: pit[ch].low_read = 0; ! 5840: if(!pit[ch].high_read) { ! 5841: pit[ch].count_latched = 0; ! 5842: } ! 5843: return(pit[ch].latch & 0xff); ! 5844: } else if(pit[ch].high_read) { ! 5845: pit[ch].high_read = 0; ! 5846: pit[ch].count_latched = 0; ! 5847: return((pit[ch].latch >> 8) & 0xff); ! 5848: } ! 5849: } ! 5850: return(0xff); ! 5851: } ! 5852: ! 5853: void pit_run() ! 5854: { ! 5855: static UINT32 prev_time = 0; ! 5856: UINT32 cur_time = timeGetTime(); ! 5857: ! 5858: if(prev_time == cur_time) { ! 5859: return; ! 5860: } ! 5861: prev_time = cur_time; ! 5862: ! 5863: for(int ch = 0; ch < 3; ch++) { ! 5864: if(pit[ch].start && cur_time >= pit[ch].expired_time) { ! 5865: pit_input_clock(ch, pit[ch].input_clk); ! 5866: ! 5867: // next expired time ! 5868: if(pit[ch].start) { ! 5869: pit[ch].input_clk = pit[ch].delay ? 1 : pit_get_next_count(ch); ! 5870: pit[ch].prev_time = pit[ch].expired_time; ! 5871: pit[ch].expired_time += pit_get_expired_time(pit[ch].input_clk); ! 5872: if(pit[ch].expired_time <= cur_time) { ! 5873: pit[ch].prev_time = cur_time; ! 5874: pit[ch].expired_time = cur_time + pit_get_expired_time(pit[ch].input_clk); ! 5875: } ! 5876: } ! 5877: } ! 5878: } ! 5879: } ! 5880: ! 5881: void pit_input_clock(int ch, int clock) ! 5882: { ! 5883: if(!(pit[ch].start && clock)) { ! 5884: return; ! 5885: } ! 5886: if(pit[ch].delay) { ! 5887: clock -= 1; ! 5888: pit[ch].delay = 0; ! 5889: pit[ch].count = PIT_COUNT_VALUE(ch); ! 5890: pit[ch].null_count = 0; ! 5891: } ! 5892: ! 5893: // update pit ! 5894: pit[ch].count -= clock; ! 5895: INT32 tmp = PIT_COUNT_VALUE(ch); ! 5896: loop: ! 5897: if(pit[ch].mode == 3) { ! 5898: INT32 half = tmp >> 1; ! 5899: if(pit[ch].count > half) { ! 5900: pit_set_signal(ch, 1); ! 5901: } else { ! 5902: pit_set_signal(ch, 0); ! 5903: } ! 5904: } else { ! 5905: if(pit[ch].count <= 1) { ! 5906: if(pit[ch].mode == 2 || pit[ch].mode == 4 || pit[ch].mode == 5) { ! 5907: pit_set_signal(ch, 0); ! 5908: } ! 5909: } ! 5910: if(pit[ch].count <= 0) { ! 5911: pit_set_signal(ch, 1); ! 5912: } ! 5913: } ! 5914: if(pit[ch].count <= 0) { ! 5915: if(pit[ch].mode == 0 || pit[ch].mode == 2 || pit[ch].mode == 3) { ! 5916: pit[ch].count += tmp; ! 5917: pit[ch].null_count = 0; ! 5918: goto loop; ! 5919: } else { ! 5920: pit[ch].start = 0; ! 5921: pit[ch].count = 0x10000; ! 5922: } ! 5923: } ! 5924: } ! 5925: ! 5926: void pit_start_count(int ch) ! 5927: { ! 5928: if(pit[ch].low_write || pit[ch].high_write) { ! 5929: return; ! 5930: } ! 5931: //if(!pit[ch].gate) { ! 5932: // return; ! 5933: //} ! 5934: pit[ch].start = 1; ! 5935: ! 5936: // next expired time ! 5937: pit[ch].input_clk = pit[ch].delay ? 1 : pit_get_next_count(ch); ! 5938: UINT32 cur_time = timeGetTime(); ! 5939: pit[ch].prev_time = cur_time; ! 5940: pit[ch].expired_time = cur_time + pit_get_expired_time(pit[ch].input_clk); ! 5941: } ! 5942: ! 5943: void pit_stop_count(int ch) ! 5944: { ! 5945: pit[ch].start = 0; ! 5946: } ! 5947: ! 5948: void pit_latch_count(int ch) ! 5949: { ! 5950: if(pit[ch].start) { ! 5951: // update pit ! 5952: UINT32 cur_time = timeGetTime(); ! 5953: if(cur_time > pit[ch].prev_time) { ! 5954: UINT32 input = PIT_FREQ * (cur_time - pit[ch].prev_time) / 1000; ! 5955: pit_input_clock(ch, input); ! 5956: ! 5957: if(pit[ch].input_clk <= input) { ! 5958: // next expired time ! 5959: if(pit[ch].start) { ! 5960: pit[ch].input_clk = pit[ch].delay ? 1 : pit_get_next_count(ch); ! 5961: pit[ch].prev_time = pit[ch].expired_time; ! 5962: pit[ch].expired_time += pit_get_expired_time(pit[ch].input_clk); ! 5963: if(pit[ch].expired_time <= cur_time) { ! 5964: pit[ch].prev_time = cur_time; ! 5965: pit[ch].expired_time = cur_time + pit_get_expired_time(pit[ch].input_clk); ! 5966: } ! 5967: } ! 5968: } else { ! 5969: pit[ch].input_clk -= input; ! 5970: pit[ch].prev_time = cur_time; ! 5971: } ! 5972: } ! 5973: } ! 5974: // latch pit ! 5975: pit[ch].latch = (UINT16)pit[ch].count; ! 5976: pit[ch].count_latched = 1; ! 5977: if((pit[ch].ctrl_reg & 0x30) == 0x10) { ! 5978: // lower byte ! 5979: pit[ch].low_read = 1; ! 5980: pit[ch].high_read = 0; ! 5981: } else if((pit[ch].ctrl_reg & 0x30) == 0x20) { ! 5982: // upper byte ! 5983: pit[ch].low_read = 0; ! 5984: pit[ch].high_read = 1; ! 5985: } else { ! 5986: // lower -> upper ! 5987: pit[ch].low_read = pit[ch].low_read = 1; ! 5988: } ! 5989: } ! 5990: ! 5991: void pit_set_signal(int ch, int signal) ! 5992: { ! 5993: int prev = pit[ch].prev_out; ! 5994: pit[ch].prev_out = signal; ! 5995: ! 5996: if(prev && !signal) { ! 5997: // H->L ! 5998: if(ch == 0) { ! 5999: pic_req(0, 0, 0); ! 6000: } ! 6001: } else if(!prev && signal) { ! 6002: // L->H ! 6003: if(ch == 0) { ! 6004: pic_req(0, 0, 1); ! 6005: } ! 6006: } ! 6007: } ! 6008: ! 6009: int pit_get_next_count(int ch) ! 6010: { ! 6011: if(pit[ch].mode == 2 || pit[ch].mode == 4 || pit[ch].mode == 5) { ! 6012: if(pit[ch].count > 1) { ! 6013: return(pit[ch].count - 1); ! 6014: } else { ! 6015: return(1); ! 6016: } ! 6017: } ! 6018: if(pit[ch].mode == 3) { ! 6019: INT32 half = PIT_COUNT_VALUE(ch) >> 1; ! 6020: if(pit[ch].count > half) { ! 6021: return(pit[ch].count - half); ! 6022: } else { ! 6023: return(pit[ch].count); ! 6024: } ! 6025: } ! 6026: return(pit[ch].count); ! 6027: } ! 6028: ! 6029: int pit_get_expired_time(int clock) ! 6030: { ! 6031: UINT32 val = 1000 * clock / PIT_FREQ; ! 6032: ! 6033: if(val > 0) { ! 6034: return(val); ! 6035: } else { ! 6036: return(1); ! 6037: } ! 6038: } ! 6039: ! 6040: // i/o bus ! 6041: ! 6042: UINT8 read_io_byte(offs_t addr) ! 6043: { ! 6044: switch(addr) { ! 6045: #ifdef SUPPORT_HARDWARE ! 6046: case 0x20: ! 6047: case 0x21: ! 6048: return(pic_read(0, addr)); ! 6049: case 0x40: ! 6050: case 0x41: ! 6051: case 0x42: ! 6052: case 0x43: ! 6053: return(pit_read(addr & 0x03)); ! 6054: #endif ! 6055: case 0x71: ! 6056: return(cmos[cmos_addr & 0x7f]); ! 6057: case 0x92: ! 6058: return((cpustate->a20_mask >> 19) & 2); ! 6059: #ifdef SUPPORT_HARDWARE ! 6060: case 0xa0: ! 6061: case 0xa1: ! 6062: return(pic_read(1, addr)); ! 6063: #endif ! 6064: default: ! 6065: // error("inb %4x\n", addr); ! 6066: break; ! 6067: } ! 6068: return(0xff); ! 6069: } ! 6070: ! 6071: UINT16 read_io_word(offs_t addr) ! 6072: { ! 6073: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8)); ! 6074: } ! 6075: ! 6076: UINT32 read_io_dword(offs_t addr) ! 6077: { ! 6078: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8) | (read_io_byte(addr + 2) << 16) | (read_io_byte(addr + 3) << 24)); ! 6079: } ! 6080: ! 6081: void write_io_byte(offs_t addr, UINT8 val) ! 6082: { ! 6083: switch(addr) { ! 6084: #ifdef SUPPORT_HARDWARE ! 6085: case 0x20: ! 6086: case 0x21: ! 6087: pic_write(0, addr, val); ! 6088: break; ! 6089: case 0x40: ! 6090: case 0x41: ! 6091: case 0x42: ! 6092: case 0x43: ! 6093: pit_write(addr & 0x03, val); ! 6094: break; ! 6095: #endif ! 6096: case 0x64: ! 6097: if(val == 0xfe) { ! 6098: if(cmos[0x0f] == 5) { ! 6099: // reset pic ! 6100: pic_init(); ! 6101: pic[0].irr = pic[1].irr = 0x00; ! 6102: pic[0].imr = pic[1].imr = 0xff; ! 6103: } ! 6104: CPU_RESET_CALL(CPU_MODEL); ! 6105: i386_jmp_far(0x40, 0x67); ! 6106: } ! 6107: break; ! 6108: case 0x70: ! 6109: cmos_addr = val; ! 6110: break; ! 6111: case 0x71: ! 6112: cmos[cmos_addr & 7] = val; ! 6113: break; ! 6114: case 0x92: ! 6115: i386_set_a20_line(cpustate, val & 2); ! 6116: break; ! 6117: #ifdef SUPPORT_HARDWARE ! 6118: case 0xa0: ! 6119: case 0xa1: ! 6120: pic_write(1, addr, val); ! 6121: break; ! 6122: #endif ! 6123: default: ! 6124: // error("outb %4x,%2x\n", addr, val); ! 6125: break; ! 6126: } ! 6127: } ! 6128: ! 6129: void write_io_word(offs_t addr, UINT16 val) ! 6130: { ! 6131: write_io_byte(addr + 0, (val >> 0) & 0xff); ! 6132: write_io_byte(addr + 1, (val >> 8) & 0xff); ! 6133: } ! 6134: ! 6135: void write_io_dword(offs_t addr, UINT32 val) ! 6136: { ! 6137: write_io_byte(addr + 0, (val >> 0) & 0xff); ! 6138: write_io_byte(addr + 1, (val >> 8) & 0xff); ! 6139: write_io_byte(addr + 2, (val >> 16) & 0xff); ! 6140: write_io_byte(addr + 3, (val >> 24) & 0xff); ! 6141: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.