|
|
1.1.1.67! 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: void exit_handler(); ! 11: ! 12: #define fatalerror(...) { \ ! 13: fprintf(stderr, __VA_ARGS__); \ ! 14: exit_handler(); \ ! 15: exit(1); \ ! 16: } ! 17: #define error(...) fprintf(stderr, "error: " __VA_ARGS__) ! 18: #define nolog(...) ! 19: ! 20: //#define ENABLE_DEBUG_LOG ! 21: #ifdef ENABLE_DEBUG_LOG ! 22: #define EXPORT_DEBUG_TO_FILE ! 23: #define ENABLE_DEBUG_SYSCALL ! 24: #define ENABLE_DEBUG_UNIMPLEMENTED ! 25: #define ENABLE_DEBUG_IOPORT ! 26: ! 27: #ifdef EXPORT_DEBUG_TO_FILE ! 28: FILE* fp_debug_log = NULL; ! 29: #else ! 30: #define fp_debug_log stderr ! 31: #endif ! 32: #ifdef ENABLE_DEBUG_UNIMPLEMENTED ! 33: #define unimplemented_10h fatalerror ! 34: #define unimplemented_13h fatalerror ! 35: #define unimplemented_14h fatalerror ! 36: #define unimplemented_15h fatalerror ! 37: #define unimplemented_16h fatalerror ! 38: #define unimplemented_17h fatalerror ! 39: #define unimplemented_1ah fatalerror ! 40: #define unimplemented_21h fatalerror ! 41: #define unimplemented_2fh fatalerror ! 42: #define unimplemented_33h fatalerror ! 43: #define unimplemented_67h fatalerror ! 44: #define unimplemented_xms fatalerror ! 45: #endif ! 46: #endif ! 47: #ifndef unimplemented_10h ! 48: #define unimplemented_10h nolog ! 49: #endif ! 50: #ifndef unimplemented_13h ! 51: #define unimplemented_13h nolog ! 52: #endif ! 53: #ifndef unimplemented_14h ! 54: #define unimplemented_14h nolog ! 55: #endif ! 56: #ifndef unimplemented_15h ! 57: #define unimplemented_15h nolog ! 58: #endif ! 59: #ifndef unimplemented_16h ! 60: #define unimplemented_16h nolog ! 61: #endif ! 62: #ifndef unimplemented_17h ! 63: #define unimplemented_17h nolog ! 64: #endif ! 65: #ifndef unimplemented_1ah ! 66: #define unimplemented_1ah nolog ! 67: #endif ! 68: #ifndef unimplemented_21h ! 69: #define unimplemented_21h nolog ! 70: #endif ! 71: #ifndef unimplemented_2fh ! 72: #define unimplemented_2fh nolog ! 73: #endif ! 74: #ifndef unimplemented_33h ! 75: #define unimplemented_33h nolog ! 76: #endif ! 77: #ifndef unimplemented_67h ! 78: #define unimplemented_67h nolog ! 79: #endif ! 80: #ifndef unimplemented_xms ! 81: #define unimplemented_xms nolog ! 82: #endif ! 83: ! 84: #ifdef _MBCS ! 85: inline char *my_strchr(char *str, int chr) ! 86: { ! 87: return (char *)_mbschr((unsigned char *)(str), (unsigned int)(chr)); ! 88: } ! 89: inline const char *my_strchr(const char *str, int chr) ! 90: { ! 91: return (const char *)_mbschr((const unsigned char *)(str), (unsigned int)(chr)); ! 92: } ! 93: inline char *my_strrchr(char *str, int chr) ! 94: { ! 95: return (char *)_mbsrchr((unsigned char *)(str), (unsigned int)(chr)); ! 96: } ! 97: inline const char *my_strrchr(const char *str, int chr) ! 98: { ! 99: return (const char *)_mbsrchr((const unsigned char *)(str), (unsigned int)(chr)); ! 100: } ! 101: inline char *my_strtok(char *tok, const char *del) ! 102: { ! 103: return (char *)_mbstok((unsigned char *)(tok), (const unsigned char *)(del)); ! 104: } ! 105: inline char *my_strupr(char *str) ! 106: { ! 107: return (char *)_mbsupr((unsigned char *)(str)); ! 108: } ! 109: #else ! 110: #define my_strchr(str, chr) strchr((str), (chr)) ! 111: #define my_strrchr(str, chr) strrchr((str), (chr)) ! 112: #define my_strtok(tok, del) strtok((tok), (del)) ! 113: #define my_strupr(str) _strupr((str)) ! 114: #endif ! 115: #define array_length(array) (sizeof(array) / sizeof(array[0])) ! 116: ! 117: #if defined(__MINGW32__) ! 118: extern "C" int _CRT_glob = 0; ! 119: #endif ! 120: ! 121: /* ! 122: kludge for "more-standardized" C++ ! 123: */ ! 124: #if !defined(_MSC_VER) ! 125: inline int kludge_min(int a, int b) { return (a<b ? a:b); } ! 126: inline int kludge_max(int a, int b) { return (a>b ? a:b); } ! 127: #define min(a,b) kludge_min(a,b) ! 128: #define max(a,b) kludge_max(a,b) ! 129: #elif _MSC_VER >= 1400 ! 130: void ignore_invalid_parameters(const wchar_t *, const wchar_t *, const wchar_t *, unsigned int, uintptr_t) ! 131: { ! 132: } ! 133: #endif ! 134: ! 135: #define USE_VRAM_THREAD ! 136: ! 137: #ifdef USE_VRAM_THREAD ! 138: static CRITICAL_SECTION vram_crit_sect; ! 139: #else ! 140: #define vram_flush() ! 141: #endif ! 142: ! 143: #define VIDEO_REGEN *(UINT16 *)(mem + 0x44c) ! 144: #define SCR_BUF(y,x) scr_buf[(y) * scr_buf_size.X + (x)] ! 145: ! 146: void change_console_size(int width, int height); ! 147: void clear_scr_buffer(WORD attr); ! 148: ! 149: static UINT32 vram_length_char = 0, vram_length_attr = 0; ! 150: static UINT32 vram_last_length_char = 0, vram_last_length_attr = 0; ! 151: static COORD vram_coord_char, vram_coord_attr; ! 152: ! 153: char temp_file_path[MAX_PATH]; ! 154: bool temp_file_created = false; ! 155: ! 156: bool ignore_illegal_insn = false; ! 157: bool limit_max_memory = false; ! 158: bool no_windows = false; ! 159: bool stay_busy = false; ! 160: bool support_ems = false; ! 161: #ifdef SUPPORT_XMS ! 162: bool support_xms = false; ! 163: #endif ! 164: int sio_port_number[4] = {0, 0, 0, 0}; ! 165: ! 166: BOOL is_winxp_or_later; ! 167: BOOL is_xp_64_or_later; ! 168: BOOL is_vista_or_later; ! 169: ! 170: #define UPDATE_OPS 16384 ! 171: #define REQUEST_HARDWRE_UPDATE() { \ ! 172: update_ops = UPDATE_OPS - 1; \ ! 173: } ! 174: UINT32 update_ops = 0; ! 175: UINT32 idle_ops = 0; ! 176: ! 177: inline BOOL is_sse2_ready() ! 178: { ! 179: static int result = -1; ! 180: int cpu_info[4]; ! 181: ! 182: if(result == -1) { ! 183: result = 0; ! 184: __cpuid(cpu_info, 0); ! 185: if(cpu_info[0] >= 1){ ! 186: __cpuid(cpu_info, 1); ! 187: if(cpu_info[3] & (1 << 26)) { ! 188: result = 1; ! 189: } ! 190: } ! 191: } ! 192: return(result == 1); ! 193: } ! 194: ! 195: inline void maybe_idle() ! 196: { ! 197: // if it appears to be in a tight loop, assume waiting for input ! 198: // allow for one updated video character, for a spinning cursor ! 199: if(!stay_busy && idle_ops < 1024 && vram_length_char <= 1 && vram_length_attr <= 1) { ! 200: if(is_sse2_ready()) { ! 201: _mm_pause(); // SSE2 pause ! 202: } else if(is_xp_64_or_later) { ! 203: Sleep(0); // switch to other thread that is ready to run, without checking priority ! 204: } else { ! 205: Sleep(1); ! 206: REQUEST_HARDWRE_UPDATE(); ! 207: } ! 208: } ! 209: idle_ops = 0; ! 210: } ! 211: ! 212: /* ---------------------------------------------------------------------------- ! 213: MAME i86/i386 ! 214: ---------------------------------------------------------------------------- */ ! 215: ! 216: #ifndef __BIG_ENDIAN__ ! 217: #define LSB_FIRST ! 218: #endif ! 219: ! 220: #ifndef INLINE ! 221: #define INLINE inline ! 222: #endif ! 223: #define U64(v) UINT64(v) ! 224: ! 225: //#define logerror(...) fprintf(stderr, __VA_ARGS__) ! 226: #define logerror(...) ! 227: //#define popmessage(...) fprintf(stderr, __VA_ARGS__) ! 228: #define popmessage(...) ! 229: ! 230: /*****************************************************************************/ ! 231: /* src/emu/devcpu.h */ ! 232: ! 233: // CPU interface functions ! 234: #define CPU_INIT_NAME(name) cpu_init_##name ! 235: #define CPU_INIT(name) void CPU_INIT_NAME(name)() ! 236: #define CPU_INIT_CALL(name) CPU_INIT_NAME(name)() ! 237: ! 238: #define CPU_RESET_NAME(name) cpu_reset_##name ! 239: #define CPU_RESET(name) void CPU_RESET_NAME(name)() ! 240: #define CPU_RESET_CALL(name) CPU_RESET_NAME(name)() ! 241: ! 242: #define CPU_EXECUTE_NAME(name) cpu_execute_##name ! 243: #define CPU_EXECUTE(name) void CPU_EXECUTE_NAME(name)() ! 244: #define CPU_EXECUTE_CALL(name) CPU_EXECUTE_NAME(name)() ! 245: ! 246: #define CPU_TRANSLATE_NAME(name) cpu_translate_##name ! 247: #define CPU_TRANSLATE(name) int CPU_TRANSLATE_NAME(name)(address_spacenum space, int intention, offs_t *address) ! 248: #define CPU_TRANSLATE_CALL(name) CPU_TRANSLATE_NAME(name)(space, intention, address) ! 249: ! 250: #define CPU_DISASSEMBLE_NAME(name) cpu_disassemble_##name ! 251: #define CPU_DISASSEMBLE(name) int CPU_DISASSEMBLE_NAME(name)(char *buffer, offs_t eip, const UINT8 *oprom) ! 252: #define CPU_DISASSEMBLE_CALL(name) CPU_DISASSEMBLE_NAME(name)(buffer, eip, oprom) ! 253: ! 254: #define CPU_MODEL_STR(name) #name ! 255: #define CPU_MODEL_NAME(name) CPU_MODEL_STR(name) ! 256: ! 257: /*****************************************************************************/ ! 258: /* src/emu/didisasm.h */ ! 259: ! 260: // Disassembler constants ! 261: const UINT32 DASMFLAG_SUPPORTED = 0x80000000; // are disassembly flags supported? ! 262: const UINT32 DASMFLAG_STEP_OUT = 0x40000000; // this instruction should be the end of a step out sequence ! 263: const UINT32 DASMFLAG_STEP_OVER = 0x20000000; // this instruction should be stepped over by setting a breakpoint afterwards ! 264: const UINT32 DASMFLAG_OVERINSTMASK = 0x18000000; // number of extra instructions to skip when stepping over ! 265: const UINT32 DASMFLAG_OVERINSTSHIFT = 27; // bits to shift after masking to get the value ! 266: const UINT32 DASMFLAG_LENGTHMASK = 0x0000ffff; // the low 16-bits contain the actual length ! 267: ! 268: /*****************************************************************************/ ! 269: /* src/emu/diexec.h */ ! 270: ! 271: // I/O line states ! 272: enum line_state ! 273: { ! 274: CLEAR_LINE = 0, // clear (a fired or held) line ! 275: ASSERT_LINE, // assert an interrupt immediately ! 276: HOLD_LINE, // hold interrupt line until acknowledged ! 277: PULSE_LINE // pulse interrupt line instantaneously (only for NMI, RESET) ! 278: }; ! 279: ! 280: // I/O line definitions ! 281: enum ! 282: { ! 283: INPUT_LINE_IRQ = 0, ! 284: INPUT_LINE_NMI ! 285: }; ! 286: ! 287: /*****************************************************************************/ ! 288: /* src/emu/dimemory.h */ ! 289: ! 290: // Translation intentions ! 291: const int TRANSLATE_TYPE_MASK = 0x03; // read write or fetch ! 292: const int TRANSLATE_USER_MASK = 0x04; // user mode or fully privileged ! 293: const int TRANSLATE_DEBUG_MASK = 0x08; // debug mode (no side effects) ! 294: ! 295: const int TRANSLATE_READ = 0; // translate for read ! 296: const int TRANSLATE_WRITE = 1; // translate for write ! 297: const int TRANSLATE_FETCH = 2; // translate for instruction fetch ! 298: const int TRANSLATE_READ_USER = (TRANSLATE_READ | TRANSLATE_USER_MASK); ! 299: const int TRANSLATE_WRITE_USER = (TRANSLATE_WRITE | TRANSLATE_USER_MASK); ! 300: const int TRANSLATE_FETCH_USER = (TRANSLATE_FETCH | TRANSLATE_USER_MASK); ! 301: const int TRANSLATE_READ_DEBUG = (TRANSLATE_READ | TRANSLATE_DEBUG_MASK); ! 302: const int TRANSLATE_WRITE_DEBUG = (TRANSLATE_WRITE | TRANSLATE_DEBUG_MASK); ! 303: const int TRANSLATE_FETCH_DEBUG = (TRANSLATE_FETCH | TRANSLATE_DEBUG_MASK); ! 304: ! 305: /*****************************************************************************/ ! 306: /* src/emu/emucore.h */ ! 307: ! 308: // constants for expression endianness ! 309: enum endianness_t ! 310: { ! 311: ENDIANNESS_LITTLE, ! 312: ENDIANNESS_BIG ! 313: }; ! 314: ! 315: // declare native endianness to be one or the other ! 316: #ifdef LSB_FIRST ! 317: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_LITTLE; ! 318: #else ! 319: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_BIG; ! 320: #endif ! 321: ! 322: // endian-based value: first value is if 'endian' is little-endian, second is if 'endian' is big-endian ! 323: #define ENDIAN_VALUE_LE_BE(endian,leval,beval) (((endian) == ENDIANNESS_LITTLE) ? (leval) : (beval)) ! 324: ! 325: // endian-based value: first value is if native endianness is little-endian, second is if native is big-endian ! 326: #define NATIVE_ENDIAN_VALUE_LE_BE(leval,beval) ENDIAN_VALUE_LE_BE(ENDIANNESS_NATIVE, leval, beval) ! 327: ! 328: // endian-based value: first value is if 'endian' matches native, second is if 'endian' doesn't match native ! 329: #define ENDIAN_VALUE_NE_NNE(endian,leval,beval) (((endian) == ENDIANNESS_NATIVE) ? (neval) : (nneval)) ! 330: ! 331: /*****************************************************************************/ ! 332: /* src/emu/emumem.h */ ! 333: ! 334: // helpers for checking address alignment ! 335: #define WORD_ALIGNED(a) (((a) & 1) == 0) ! 336: #define DWORD_ALIGNED(a) (((a) & 3) == 0) ! 337: #define QWORD_ALIGNED(a) (((a) & 7) == 0) ! 338: ! 339: /*****************************************************************************/ ! 340: /* src/emu/memory.h */ ! 341: ! 342: // address spaces ! 343: enum address_spacenum ! 344: { ! 345: AS_0, // first address space ! 346: AS_1, // second address space ! 347: AS_2, // third address space ! 348: AS_3, // fourth address space ! 349: ADDRESS_SPACES, // maximum number of address spaces ! 350: ! 351: // alternate address space names for common use ! 352: AS_PROGRAM = AS_0, // program address space ! 353: AS_DATA = AS_1, // data address space ! 354: AS_IO = AS_2 // I/O address space ! 355: }; ! 356: ! 357: // offsets and addresses are 32-bit (for now...) ! 358: //typedef UINT32 offs_t; ! 359: ! 360: // read accessors ! 361: UINT8 read_byte(offs_t byteaddress) ! 362: #ifdef USE_DEBUGGER ! 363: { ! 364: if(now_debugging) { ! 365: for(int i = 0; i < MAX_BREAK_POINTS; i++) { ! 366: if(rd_break_point.table[i].status == 1) { ! 367: if(byteaddress == rd_break_point.table[i].addr) { ! 368: rd_break_point.hit = i + 1; ! 369: now_suspended = true; ! 370: break; ! 371: } ! 372: } ! 373: } ! 374: } ! 375: return(debugger_read_byte(byteaddress)); ! 376: } ! 377: UINT8 debugger_read_byte(offs_t byteaddress) ! 378: #endif ! 379: { ! 380: #if defined(HAS_I386) ! 381: if(byteaddress < MAX_MEM) { ! 382: return mem[byteaddress]; ! 383: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) { ! 384: // return read_byte(byteaddress & 0xfffff); ! 385: } ! 386: return 0; ! 387: #else ! 388: return mem[byteaddress]; ! 389: #endif ! 390: } ! 391: ! 392: UINT16 read_word(offs_t byteaddress) ! 393: #ifdef USE_DEBUGGER ! 394: { ! 395: if(now_debugging) { ! 396: for(int i = 0; i < MAX_BREAK_POINTS; i++) { ! 397: if(rd_break_point.table[i].status == 1) { ! 398: if(byteaddress >= rd_break_point.table[i].addr && byteaddress < rd_break_point.table[i].addr + 2) { ! 399: rd_break_point.hit = i + 1; ! 400: now_suspended = true; ! 401: break; ! 402: } ! 403: } ! 404: } ! 405: } ! 406: return(debugger_read_word(byteaddress)); ! 407: } ! 408: UINT16 debugger_read_word(offs_t byteaddress) ! 409: #endif ! 410: { ! 411: if(byteaddress == 0x41c) { ! 412: // pointer to first free slot in keyboard buffer ! 413: if(key_buf_char != NULL && key_buf_scan != NULL) { ! 414: #ifdef USE_SERVICE_THREAD ! 415: EnterCriticalSection(&key_buf_crit_sect); ! 416: #endif ! 417: bool empty = pcbios_is_key_buffer_empty(); ! 418: #ifdef USE_SERVICE_THREAD ! 419: LeaveCriticalSection(&key_buf_crit_sect); ! 420: #endif ! 421: if(empty) maybe_idle(); ! 422: } ! 423: } ! 424: #if defined(HAS_I386) ! 425: if(byteaddress < MAX_MEM - 1) { ! 426: return *(UINT16 *)(mem + byteaddress); ! 427: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) { ! 428: // return read_word(byteaddress & 0xfffff); ! 429: } ! 430: return 0; ! 431: #else ! 432: return *(UINT16 *)(mem + byteaddress); ! 433: #endif ! 434: } ! 435: ! 436: UINT32 read_dword(offs_t byteaddress) ! 437: #ifdef USE_DEBUGGER ! 438: { ! 439: if(now_debugging) { ! 440: for(int i = 0; i < MAX_BREAK_POINTS; i++) { ! 441: if(rd_break_point.table[i].status == 1) { ! 442: if(byteaddress >= rd_break_point.table[i].addr && byteaddress < rd_break_point.table[i].addr + 4) { ! 443: rd_break_point.hit = i + 1; ! 444: now_suspended = true; ! 445: break; ! 446: } ! 447: } ! 448: } ! 449: } ! 450: return(debugger_read_dword(byteaddress)); ! 451: } ! 452: UINT32 debugger_read_dword(offs_t byteaddress) ! 453: #endif ! 454: { ! 455: #if defined(HAS_I386) ! 456: if(byteaddress < MAX_MEM - 3) { ! 457: return *(UINT32 *)(mem + byteaddress); ! 458: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) { ! 459: // return read_dword(byteaddress & 0xfffff); ! 460: } ! 461: return 0; ! 462: #else ! 463: return *(UINT32 *)(mem + byteaddress); ! 464: #endif ! 465: } ! 466: ! 467: // write accessors ! 468: #ifdef USE_VRAM_THREAD ! 469: void vram_flush_char() ! 470: { ! 471: if(vram_length_char != 0) { ! 472: DWORD num; ! 473: WriteConsoleOutputCharacterA(GetStdHandle(STD_OUTPUT_HANDLE), scr_char, vram_length_char, vram_coord_char, &num); ! 474: vram_length_char = vram_last_length_char = 0; ! 475: } ! 476: } ! 477: ! 478: void vram_flush_attr() ! 479: { ! 480: if(vram_length_attr != 0) { ! 481: DWORD num; ! 482: WriteConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), scr_attr, vram_length_attr, vram_coord_attr, &num); ! 483: vram_length_attr = vram_last_length_attr = 0; ! 484: } ! 485: } ! 486: ! 487: void vram_flush() ! 488: { ! 489: if(vram_length_char != 0 || vram_length_attr != 0) { ! 490: EnterCriticalSection(&vram_crit_sect); ! 491: vram_flush_char(); ! 492: vram_flush_attr(); ! 493: LeaveCriticalSection(&vram_crit_sect); ! 494: } ! 495: } ! 496: #endif ! 497: ! 498: void write_text_vram_char(offs_t offset, UINT8 data) ! 499: { ! 500: #ifdef USE_VRAM_THREAD ! 501: static offs_t first_offset_char, last_offset_char; ! 502: ! 503: if(vram_length_char != 0) { ! 504: if(offset <= last_offset_char && offset >= first_offset_char) { ! 505: scr_char[(offset - first_offset_char) >> 1] = data; ! 506: return; ! 507: } ! 508: if(offset != last_offset_char + 2) { ! 509: vram_flush_char(); ! 510: } ! 511: } ! 512: if(vram_length_char == 0) { ! 513: first_offset_char = offset; ! 514: vram_coord_char.X = (offset >> 1) % scr_width; ! 515: vram_coord_char.Y = (offset >> 1) / scr_width + scr_top; ! 516: } ! 517: scr_char[vram_length_char++] = data; ! 518: last_offset_char = offset; ! 519: #else ! 520: COORD co; ! 521: DWORD num; ! 522: ! 523: co.X = (offset >> 1) % scr_width; ! 524: co.Y = (offset >> 1) / scr_width; ! 525: scr_char[0] = data; ! 526: WriteConsoleOutputCharacterA(GetStdHandle(STD_OUTPUT_HANDLE), scr_char, 1, co, &num); ! 527: #endif ! 528: } ! 529: ! 530: void write_text_vram_attr(offs_t offset, UINT8 data) ! 531: { ! 532: #ifdef USE_VRAM_THREAD ! 533: static offs_t first_offset_attr, last_offset_attr; ! 534: ! 535: if(vram_length_attr != 0) { ! 536: if(offset <= last_offset_attr && offset >= first_offset_attr) { ! 537: scr_attr[(offset - first_offset_attr) >> 1] = data; ! 538: return; ! 539: } ! 540: if(offset != last_offset_attr + 2) { ! 541: vram_flush_attr(); ! 542: } ! 543: } ! 544: if(vram_length_attr == 0) { ! 545: first_offset_attr = offset; ! 546: vram_coord_attr.X = (offset >> 1) % scr_width; ! 547: vram_coord_attr.Y = (offset >> 1) / scr_width + scr_top; ! 548: } ! 549: scr_attr[vram_length_attr++] = data; ! 550: last_offset_attr = offset; ! 551: #else ! 552: COORD co; ! 553: DWORD num; ! 554: ! 555: co.X = (offset >> 1) % scr_width; ! 556: co.Y = (offset >> 1) / scr_width; ! 557: scr_attr[0] = data; ! 558: WriteConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), scr_attr, 1, co, &num); ! 559: #endif ! 560: } ! 561: ! 562: void write_text_vram_byte(offs_t offset, UINT8 data) ! 563: { ! 564: #ifdef USE_VRAM_THREAD ! 565: EnterCriticalSection(&vram_crit_sect); ! 566: #endif ! 567: if(offset & 1) { ! 568: write_text_vram_attr(offset, data); ! 569: } else { ! 570: write_text_vram_char(offset, data); ! 571: } ! 572: #ifdef USE_VRAM_THREAD ! 573: LeaveCriticalSection(&vram_crit_sect); ! 574: #endif ! 575: } ! 576: ! 577: void write_text_vram_word(offs_t offset, UINT16 data) ! 578: { ! 579: #ifdef USE_VRAM_THREAD ! 580: EnterCriticalSection(&vram_crit_sect); ! 581: #endif ! 582: if(offset & 1) { ! 583: write_text_vram_attr(offset , (data ) & 0xff); ! 584: write_text_vram_char(offset + 1, (data >> 8) & 0xff); ! 585: } else { ! 586: write_text_vram_char(offset , (data ) & 0xff); ! 587: write_text_vram_attr(offset + 1, (data >> 8) & 0xff); ! 588: } ! 589: #ifdef USE_VRAM_THREAD ! 590: LeaveCriticalSection(&vram_crit_sect); ! 591: #endif ! 592: } ! 593: ! 594: void write_text_vram_dword(offs_t offset, UINT32 data) ! 595: { ! 596: #ifdef USE_VRAM_THREAD ! 597: EnterCriticalSection(&vram_crit_sect); ! 598: #endif ! 599: if(offset & 1) { ! 600: write_text_vram_attr(offset , (data ) & 0xff); ! 601: write_text_vram_char(offset + 1, (data >> 8) & 0xff); ! 602: write_text_vram_attr(offset + 2, (data >> 16) & 0xff); ! 603: write_text_vram_char(offset + 3, (data >> 24) & 0xff); ! 604: } else { ! 605: write_text_vram_char(offset , (data ) & 0xff); ! 606: write_text_vram_attr(offset + 1, (data >> 8) & 0xff); ! 607: write_text_vram_char(offset + 2, (data >> 16) & 0xff); ! 608: write_text_vram_attr(offset + 3, (data >> 24) & 0xff); ! 609: } ! 610: #ifdef USE_VRAM_THREAD ! 611: LeaveCriticalSection(&vram_crit_sect); ! 612: #endif ! 613: } ! 614: ! 615: void write_byte(offs_t byteaddress, UINT8 data) ! 616: #ifdef USE_DEBUGGER ! 617: { ! 618: if(now_debugging) { ! 619: for(int i = 0; i < MAX_BREAK_POINTS; i++) { ! 620: if(wr_break_point.table[i].status == 1) { ! 621: if(byteaddress == wr_break_point.table[i].addr) { ! 622: wr_break_point.hit = i + 1; ! 623: now_suspended = true; ! 624: break; ! 625: } ! 626: } ! 627: } ! 628: } ! 629: debugger_write_byte(byteaddress, data); ! 630: } ! 631: void debugger_write_byte(offs_t byteaddress, UINT8 data) ! 632: #endif ! 633: { ! 634: if(byteaddress < MEMORY_END) { ! 635: mem[byteaddress] = data; ! 636: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) { ! 637: if(!restore_console_on_exit) { ! 638: change_console_size(scr_width, scr_height); ! 639: } ! 640: write_text_vram_byte(byteaddress - text_vram_top_address, data); ! 641: mem[byteaddress] = data; ! 642: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) { ! 643: if(int_10h_feh_called && !int_10h_ffh_called) { ! 644: write_text_vram_byte(byteaddress - shadow_buffer_top_address, data); ! 645: } ! 646: mem[byteaddress] = data; ! 647: #if defined(HAS_I386) ! 648: } else if(byteaddress < MAX_MEM) { ! 649: #else ! 650: } else { ! 651: #endif ! 652: mem[byteaddress] = data; ! 653: } ! 654: } ! 655: ! 656: void write_word(offs_t byteaddress, UINT16 data) ! 657: #ifdef USE_DEBUGGER ! 658: { ! 659: if(now_debugging) { ! 660: for(int i = 0; i < MAX_BREAK_POINTS; i++) { ! 661: if(wr_break_point.table[i].status == 1) { ! 662: if(byteaddress >= wr_break_point.table[i].addr && byteaddress < wr_break_point.table[i].addr + 2) { ! 663: wr_break_point.hit = i + 1; ! 664: now_suspended = true; ! 665: break; ! 666: } ! 667: } ! 668: } ! 669: } ! 670: debugger_write_word(byteaddress, data); ! 671: } ! 672: void debugger_write_word(offs_t byteaddress, UINT16 data) ! 673: #endif ! 674: { ! 675: if(byteaddress < MEMORY_END) { ! 676: if(byteaddress == cursor_position_address) { ! 677: if(*(UINT16 *)(mem + byteaddress) != data) { ! 678: COORD co; ! 679: co.X = data & 0xff; ! 680: co.Y = (data >> 8) + scr_top; ! 681: SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), co); ! 682: cursor_moved = false; ! 683: cursor_moved_by_crtc = false; ! 684: } ! 685: } ! 686: *(UINT16 *)(mem + byteaddress) = data; ! 687: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) { ! 688: if(!restore_console_on_exit) { ! 689: change_console_size(scr_width, scr_height); ! 690: } ! 691: write_text_vram_word(byteaddress - text_vram_top_address, data); ! 692: *(UINT16 *)(mem + byteaddress) = data; ! 693: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) { ! 694: if(int_10h_feh_called && !int_10h_ffh_called) { ! 695: write_text_vram_word(byteaddress - shadow_buffer_top_address, data); ! 696: } ! 697: *(UINT16 *)(mem + byteaddress) = data; ! 698: #if defined(HAS_I386) ! 699: } else if(byteaddress < MAX_MEM - 1) { ! 700: #else ! 701: } else { ! 702: #endif ! 703: *(UINT16 *)(mem + byteaddress) = data; ! 704: } ! 705: } ! 706: ! 707: void write_dword(offs_t byteaddress, UINT32 data) ! 708: #ifdef USE_DEBUGGER ! 709: { ! 710: if(now_debugging) { ! 711: for(int i = 0; i < MAX_BREAK_POINTS; i++) { ! 712: if(wr_break_point.table[i].status == 1) { ! 713: if(byteaddress >= wr_break_point.table[i].addr && byteaddress < wr_break_point.table[i].addr + 4) { ! 714: wr_break_point.hit = i + 1; ! 715: now_suspended = true; ! 716: break; ! 717: } ! 718: } ! 719: } ! 720: } ! 721: debugger_write_dword(byteaddress, data); ! 722: } ! 723: void debugger_write_dword(offs_t byteaddress, UINT32 data) ! 724: #endif ! 725: { ! 726: if(byteaddress < MEMORY_END) { ! 727: *(UINT32 *)(mem + byteaddress) = data; ! 728: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) { ! 729: if(!restore_console_on_exit) { ! 730: change_console_size(scr_width, scr_height); ! 731: } ! 732: write_text_vram_dword(byteaddress - text_vram_top_address, data); ! 733: *(UINT32 *)(mem + byteaddress) = data; ! 734: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) { ! 735: if(int_10h_feh_called && !int_10h_ffh_called) { ! 736: write_text_vram_dword(byteaddress - shadow_buffer_top_address, data); ! 737: } ! 738: *(UINT32 *)(mem + byteaddress) = data; ! 739: #if defined(HAS_I386) ! 740: } else if(byteaddress < MAX_MEM - 3) { ! 741: #else ! 742: } else { ! 743: #endif ! 744: *(UINT32 *)(mem + byteaddress) = data; ! 745: } ! 746: } ! 747: ! 748: #define read_decrypted_byte read_byte ! 749: #define read_decrypted_word read_word ! 750: #define read_decrypted_dword read_dword ! 751: ! 752: #define read_raw_byte read_byte ! 753: #define write_raw_byte write_byte ! 754: ! 755: #define read_word_unaligned read_word ! 756: #define write_word_unaligned write_word ! 757: ! 758: #define read_io_word_unaligned read_io_word ! 759: #define write_io_word_unaligned write_io_word ! 760: ! 761: UINT8 read_io_byte(offs_t byteaddress); ! 762: UINT16 read_io_word(offs_t byteaddress); ! 763: UINT32 read_io_dword(offs_t byteaddress); ! 764: ! 765: void write_io_byte(offs_t byteaddress, UINT8 data); ! 766: void write_io_word(offs_t byteaddress, UINT16 data); ! 767: void write_io_dword(offs_t byteaddress, UINT32 data); ! 768: ! 769: /*****************************************************************************/ ! 770: /* src/osd/osdcomm.h */ ! 771: ! 772: /* Highly useful macro for compile-time knowledge of an array size */ ! 773: #define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0])) ! 774: ! 775: // flag to exit MS-DOS Player ! 776: // this is set when the first process is terminated and jump to FFFF:0000 HALT ! 777: int m_exit = 0; ! 778: ! 779: #if defined(HAS_I386) ! 780: static CPU_TRANSLATE(i386); ! 781: #include "mame/lib/softfloat/softfloat.c" ! 782: #include "mame/lib/softfloat/fsincos.c" ! 783: #include "mame/emu/cpu/i386/i386.c" ! 784: #include "mame/emu/cpu/vtlb.c" ! 785: #elif defined(HAS_I286) ! 786: #include "mame/emu/cpu/i86/i286.c" ! 787: #else ! 788: #include "mame/emu/cpu/i86/i86.c" ! 789: #endif ! 790: #ifdef USE_DEBUGGER ! 791: #include "mame/emu/cpu/i386/i386dasm.c" ! 792: #endif ! 793: ! 794: #if defined(HAS_I386) ! 795: #define SREG(x) m_sreg[x].selector ! 796: #define SREG_BASE(x) m_sreg[x].base ! 797: int cpu_type, cpu_step; ! 798: #define i386_get_flags() get_flags() ! 799: #define i386_set_flags(x) set_flags(x) ! 800: #else ! 801: #define REG8(x) m_regs.b[x] ! 802: #define REG16(x) m_regs.w[x] ! 803: #define SREG(x) m_sregs[x] ! 804: #define SREG_BASE(x) m_base[x] ! 805: #define m_eip (m_pc - m_base[CS]) ! 806: #define m_CF m_CarryVal ! 807: #define m_a20_mask AMASK ! 808: #define i386_load_segment_descriptor(x) m_base[x] = SegBase(x) ! 809: void i386_sreg_load(UINT16 selector, UINT8 reg, bool *fault) ! 810: { ! 811: #if defined(HAS_I286) ! 812: i80286_data_descriptor(reg, selector); ! 813: #else ! 814: m_sregs[reg] = selector; ! 815: m_base[reg] = SegBase(reg); ! 816: #endif ! 817: } ! 818: #define i386_get_flags() CompressFlags() ! 819: #define i386_set_flags(x) ExpandFlags(x) ! 820: #if defined(HAS_I286) ! 821: #define i386_set_a20_line(x) i80286_set_a20_line(x) ! 822: #else ! 823: #define i386_set_a20_line(x) ! 824: #endif ! 825: #define i386_set_irq_line(x, y) set_irq_line(x, y) ! 826: #endif ! 827: ! 828: void i386_jmp_far(UINT16 selector, UINT32 address) ! 829: { ! 830: #if defined(HAS_I386) ! 831: if(PROTECTED_MODE && !V8086_MODE) { ! 832: i386_protected_mode_jump(selector, address, 1, m_operand_size); ! 833: } else { ! 834: SREG(CS) = selector; ! 835: m_performed_intersegment_jump = 1; ! 836: i386_load_segment_descriptor(CS); ! 837: m_eip = address; ! 838: CHANGE_PC(m_eip); ! 839: } ! 840: #elif defined(HAS_I286) ! 841: i80286_code_descriptor(selector, address, 1); ! 842: #else ! 843: SREG(CS) = selector; ! 844: i386_load_segment_descriptor(CS); ! 845: m_pc = (SREG_BASE(CS) + address) & m_a20_mask; ! 846: #endif ! 847: } ! 848: ! 849: void i386_call_far(UINT16 selector, UINT32 address) ! 850: { ! 851: #if defined(HAS_I386) ! 852: if(PROTECTED_MODE && !V8086_MODE) { ! 853: i386_protected_mode_call(selector, address, 1, m_operand_size); ! 854: } else { ! 855: PUSH16(SREG(CS)); ! 856: PUSH16(m_eip); ! 857: SREG(CS) = selector; ! 858: m_performed_intersegment_jump = 1; ! 859: i386_load_segment_descriptor(CS); ! 860: m_eip = address; ! 861: CHANGE_PC(m_eip); ! 862: } ! 863: #else ! 864: UINT16 ip = m_pc - SREG_BASE(CS); ! 865: UINT16 cs = SREG(CS); ! 866: #if defined(HAS_I286) ! 867: i80286_code_descriptor(selector, address, 2); ! 868: #else ! 869: SREG(CS) = selector; ! 870: i386_load_segment_descriptor(CS); ! 871: m_pc = (SREG_BASE(CS) + address) & m_a20_mask; ! 872: #endif ! 873: PUSH(cs); ! 874: PUSH(ip); ! 875: CHANGE_PC(m_pc); ! 876: #endif ! 877: } ! 878: ! 879: void i386_push16(UINT16 value) ! 880: { ! 881: #if defined(HAS_I386) ! 882: PUSH16(value); ! 883: #else ! 884: PUSH(value); ! 885: #endif ! 886: } ! 887: ! 888: UINT16 i386_pop16() ! 889: { ! 890: #if defined(HAS_I386) ! 891: return POP16(); ! 892: #else ! 893: UINT16 value; ! 894: POP(value); ! 895: return value; ! 896: #endif ! 897: } ! 898: ! 899: UINT16 i386_read_stack() ! 900: { ! 901: #if defined(HAS_I386) ! 902: UINT32 ea, new_esp; ! 903: if( STACK_32BIT ) { ! 904: new_esp = REG32(ESP) + 2; ! 905: ea = i386_translate(SS, new_esp - 2, 0, 2); ! 906: } else { ! 907: new_esp = REG16(SP) + 2; ! 908: ea = i386_translate(SS, (new_esp - 2) & 0xffff, 0, 2); ! 909: } ! 910: return READ16(ea); ! 911: #else ! 912: UINT16 sp = m_regs.w[SP] + 2; ! 913: return ReadWord(((m_base[SS] + ((sp - 2) & 0xffff)) & AMASK)); ! 914: #endif ! 915: } ! 916: ! 917: void i386_write_stack(UINT16 value) ! 918: { ! 919: #if defined(HAS_I386) ! 920: UINT32 ea, new_esp; ! 921: if( STACK_32BIT ) { ! 922: new_esp = REG32(ESP) + 2; ! 923: ea = i386_translate(SS, new_esp - 2, 0, 2); ! 924: } else { ! 925: new_esp = REG16(SP) + 2; ! 926: ea = i386_translate(SS, (new_esp - 2) & 0xffff, 0, 2); ! 927: } ! 928: WRITE16(ea, value); ! 929: #else ! 930: UINT16 sp = m_regs.w[SP] + 2; ! 931: WriteWord(((m_base[SS] + ((sp - 2) & 0xffff)) & AMASK), value); ! 932: #endif ! 933: } ! 934: ! 935: /* ---------------------------------------------------------------------------- ! 936: debugger ! 937: ---------------------------------------------------------------------------- */ ! 938: ! 939: #ifdef USE_DEBUGGER ! 940: #define TELNET_BLUE 0x0004 // text color contains blue. ! 941: #define TELNET_GREEN 0x0002 // text color contains green. ! 942: #define TELNET_RED 0x0001 // text color contains red. ! 943: #define TELNET_INTENSITY 0x0008 // text color is intensified. ! 944: ! 945: int svr_socket = 0; ! 946: int cli_socket = 0; ! 947: ! 948: process_t *msdos_process_info_get(UINT16 psp_seg, bool show_error); ! 949: ! 950: void debugger_init() ! 951: { ! 952: now_debugging = false; ! 953: now_going = false; ! 954: now_suspended = false; ! 955: force_suspend = false; ! 956: ! 957: memset(&break_point, 0, sizeof(break_point_t)); ! 958: memset(&rd_break_point, 0, sizeof(break_point_t)); ! 959: memset(&wr_break_point, 0, sizeof(break_point_t)); ! 960: memset(&in_break_point, 0, sizeof(break_point_t)); ! 961: memset(&out_break_point, 0, sizeof(break_point_t)); ! 962: memset(&int_break_point, 0, sizeof(int_break_point_t)); ! 963: } ! 964: ! 965: void telnet_send(const char *string) ! 966: { ! 967: char buffer[8192], *ptr; ! 968: strcpy(buffer, string); ! 969: while((ptr = strstr(buffer, "\n")) != NULL) { ! 970: char tmp[8192]; ! 971: *ptr = '\0'; ! 972: sprintf(tmp, "%s\033E%s", buffer, ptr + 1); ! 973: strcpy(buffer, tmp); ! 974: } ! 975: ! 976: int len = strlen(buffer), res; ! 977: ptr = buffer; ! 978: while(len > 0) { ! 979: if((res = send(cli_socket, ptr, len, 0)) > 0) { ! 980: len -= res; ! 981: ptr += res; ! 982: } ! 983: } ! 984: } ! 985: ! 986: void telnet_command(const char *format, ...) ! 987: { ! 988: char buffer[1024]; ! 989: va_list ap; ! 990: va_start(ap, format); ! 991: vsprintf(buffer, format, ap); ! 992: va_end(ap); ! 993: ! 994: telnet_send(buffer); ! 995: } ! 996: ! 997: void telnet_printf(const char *format, ...) ! 998: { ! 999: char buffer[1024]; ! 1000: va_list ap; ! 1001: va_start(ap, format); ! 1002: vsprintf(buffer, format, ap); ! 1003: va_end(ap); ! 1004: ! 1005: if(fp_debugger != NULL) { ! 1006: fprintf(fp_debugger, "%s", buffer); ! 1007: } ! 1008: telnet_send(buffer); ! 1009: } ! 1010: ! 1011: bool telnet_gets(char *str, int n) ! 1012: { ! 1013: char buffer[1024]; ! 1014: int ptr = 0; ! 1015: ! 1016: telnet_command("\033[12l"); // local echo on ! 1017: telnet_command("\033[2l"); // key unlock ! 1018: ! 1019: while(!m_exit) { ! 1020: int len = recv(cli_socket, buffer, sizeof(buffer), 0); ! 1021: ! 1022: if(len > 0 && buffer[0] != 0xff) { ! 1023: for(int i = 0; i < len; i++) { ! 1024: if(buffer[i] == 0x0d || buffer[i] == 0x0a) { ! 1025: str[ptr] = 0; ! 1026: telnet_command("\033[2h"); // key lock ! 1027: telnet_command("\033[12h"); // local echo off ! 1028: return(!m_exit); ! 1029: } else if(buffer[i] == 0x08) { ! 1030: if(ptr > 0) { ! 1031: telnet_command("\033[0K"); // erase from cursor position ! 1032: ptr--; ! 1033: } else { ! 1034: telnet_command("\033[1C"); // move cursor forward ! 1035: } ! 1036: } else if(ptr < n - 1) { ! 1037: if(buffer[i] >= 0x20 && buffer[i] <= 0x7e) { ! 1038: str[ptr++] = buffer[i]; ! 1039: } ! 1040: } else { ! 1041: telnet_command("\033[1D\033[0K"); // move cursor backward and erase from cursor position ! 1042: } ! 1043: } ! 1044: } else if(len == -1) { ! 1045: if(WSAGetLastError() != WSAEWOULDBLOCK) { ! 1046: return(false); ! 1047: } ! 1048: } else if(len == 0) { ! 1049: return(false); ! 1050: } ! 1051: Sleep(10); ! 1052: } ! 1053: return(!m_exit); ! 1054: } ! 1055: ! 1056: bool telnet_kbhit() ! 1057: { ! 1058: char buffer[1024]; ! 1059: ! 1060: if(!m_exit) { ! 1061: int len = recv(cli_socket, buffer, sizeof(buffer), 0); ! 1062: ! 1063: if(len > 0) { ! 1064: for(int i = 0; i < len; i++) { ! 1065: if(buffer[i] == 0x0d || buffer[i] == 0x0a) { ! 1066: return(true); ! 1067: } ! 1068: } ! 1069: } else if(len == 0) { ! 1070: return(true); // disconnected ! 1071: } ! 1072: } ! 1073: return(false); ! 1074: } ! 1075: ! 1076: bool telnet_disconnected() ! 1077: { ! 1078: char buffer[1024]; ! 1079: int len = recv(cli_socket, buffer, sizeof(buffer), 0); ! 1080: ! 1081: if(len == 0) { ! 1082: return(true); ! 1083: } else if(len == -1) { ! 1084: if(WSAGetLastError() != WSAEWOULDBLOCK) { ! 1085: return(true); ! 1086: } ! 1087: } ! 1088: return(false); ! 1089: } ! 1090: ! 1091: void telnet_set_color(int color) ! 1092: { ! 1093: telnet_command("\033[%dm\033[3%dm", (color >> 3) & 1, (color & 7)); ! 1094: } ! 1095: ! 1096: int debugger_dasm(char *buffer, UINT32 cs, UINT32 eip) ! 1097: { ! 1098: // UINT8 *oprom = mem + (((cs << 4) + eip) & (MAX_MEM - 1)); ! 1099: UINT8 ops[16]; ! 1100: for(int i = 0; i < 16; i++) { ! 1101: ops[i] = debugger_read_byte(((cs << 4) + (eip + i)) & ADDR_MASK); ! 1102: } ! 1103: UINT8 *oprom = ops; ! 1104: ! 1105: #if defined(HAS_I386) ! 1106: if(m_operand_size) { ! 1107: return(CPU_DISASSEMBLE_CALL(x86_32) & DASMFLAG_LENGTHMASK); ! 1108: } else ! 1109: #endif ! 1110: return(CPU_DISASSEMBLE_CALL(x86_16) & DASMFLAG_LENGTHMASK); ! 1111: } ! 1112: ! 1113: void debugger_regs_info(char *buffer) ! 1114: { ! 1115: UINT32 flags = i386_get_flags(); ! 1116: ! 1117: #if defined(HAS_I386) ! 1118: if(m_operand_size) { ! 1119: sprintf(buffer, "EAX=%08X EBX=%08X ECX=%08X EDX=%08X\nESP=%08X EBP=%08X ESI=%08X EDI=%08X\nEIP=%08X DS=%04X ES=%04X SS=%04X CS=%04X FLAG=[%c %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c]\n", ! 1120: REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SP), REG16(BP), REG16(SI), REG16(DI), m_eip, SREG(DS), SREG(ES), SREG(SS), SREG(CS), ! 1121: PROTECTED_MODE ? "PE" : "--", ! 1122: (flags & 0x40000) ? 'A' : '-', ! 1123: (flags & 0x20000) ? 'V' : '-', ! 1124: (flags & 0x10000) ? 'R' : '-', ! 1125: (flags & 0x04000) ? 'N' : '-', ! 1126: (flags & 0x02000) ? '1' : '0', ! 1127: (flags & 0x01000) ? '1' : '0', ! 1128: (flags & 0x00800) ? 'O' : '-', ! 1129: (flags & 0x00400) ? 'D' : '-', ! 1130: (flags & 0x00200) ? 'I' : '-', ! 1131: (flags & 0x00100) ? 'T' : '-', ! 1132: (flags & 0x00080) ? 'S' : '-', ! 1133: (flags & 0x00040) ? 'Z' : '-', ! 1134: (flags & 0x00010) ? 'A' : '-', ! 1135: (flags & 0x00004) ? 'P' : '-', ! 1136: (flags & 0x00001) ? 'C' : '-'); ! 1137: } else { ! 1138: #endif ! 1139: sprintf(buffer, "AX=%04X BX=%04X CX=%04X DX=%04X SP=%04X BP=%04X SI=%04X DI=%04X\nIP=%04X DS=%04X ES=%04X SS=%04X CS=%04X FLAG=[%c %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c]\n", ! 1140: REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SP), REG16(BP), REG16(SI), REG16(DI), m_eip, SREG(DS), SREG(ES), SREG(SS), SREG(CS), ! 1141: #if defined(HAS_I386) ! 1142: PROTECTED_MODE ? "PE" : "--", ! 1143: #else ! 1144: "--", ! 1145: #endif ! 1146: (flags & 0x40000) ? 'A' : '-', ! 1147: (flags & 0x20000) ? 'V' : '-', ! 1148: (flags & 0x10000) ? 'R' : '-', ! 1149: (flags & 0x04000) ? 'N' : '-', ! 1150: (flags & 0x02000) ? '1' : '0', ! 1151: (flags & 0x01000) ? '1' : '0', ! 1152: (flags & 0x00800) ? 'O' : '-', ! 1153: (flags & 0x00400) ? 'D' : '-', ! 1154: (flags & 0x00200) ? 'I' : '-', ! 1155: (flags & 0x00100) ? 'T' : '-', ! 1156: (flags & 0x00080) ? 'S' : '-', ! 1157: (flags & 0x00040) ? 'Z' : '-', ! 1158: (flags & 0x00010) ? 'A' : '-', ! 1159: (flags & 0x00004) ? 'P' : '-', ! 1160: (flags & 0x00001) ? 'C' : '-'); ! 1161: #if defined(HAS_I386) ! 1162: } ! 1163: #endif ! 1164: } ! 1165: ! 1166: void debugger_process_info(char *buffer) ! 1167: { ! 1168: UINT16 psp_seg = current_psp; ! 1169: process_t *process; ! 1170: bool check[0x10000] = {0}; ! 1171: ! 1172: buffer[0] = '\0'; ! 1173: ! 1174: while(!check[psp_seg] && (process = msdos_process_info_get(psp_seg, false)) != NULL) { ! 1175: psp_t *psp = (psp_t *)(mem + (psp_seg << 4)); ! 1176: char *file = process->module_path, *s; ! 1177: char tmp[8192]; ! 1178: ! 1179: while((s = strstr(file, "\\")) != NULL) { ! 1180: file = s + 1; ! 1181: } ! 1182: sprintf(tmp, "PSP=%04X ENV=%04X RETURN=%04X:%04X PROGRAM=%s\n", psp_seg, psp->env_seg, psp->int_22h.w.h, psp->int_22h.w.l, my_strupr(file)); ! 1183: strcat(tmp, buffer); ! 1184: strcpy(buffer, tmp); ! 1185: ! 1186: check[psp_seg] = true; ! 1187: psp_seg = psp->parent_psp; ! 1188: } ! 1189: } ! 1190: ! 1191: UINT32 debugger_get_val(const char *str) ! 1192: { ! 1193: char tmp[1024]; ! 1194: ! 1195: if(str == NULL || strlen(str) == 0) { ! 1196: return(0); ! 1197: } ! 1198: strcpy(tmp, str); ! 1199: ! 1200: if(strlen(tmp) == 3 && tmp[0] == '\'' && tmp[2] == '\'') { ! 1201: // ank ! 1202: return(tmp[1] & 0xff); ! 1203: } else if(tmp[0] == '%') { ! 1204: // decimal ! 1205: return(strtoul(tmp + 1, NULL, 10)); ! 1206: } ! 1207: return(strtoul(tmp, NULL, 16)); ! 1208: } ! 1209: ! 1210: UINT32 debugger_get_seg(const char *str, UINT32 val) ! 1211: { ! 1212: char tmp[1024], *s; ! 1213: ! 1214: if(str == NULL || strlen(str) == 0) { ! 1215: return(val); ! 1216: } ! 1217: strcpy(tmp, str); ! 1218: ! 1219: if((s = strstr(tmp, ":")) != NULL) { ! 1220: // 0000:0000 ! 1221: *s = '\0'; ! 1222: return(debugger_get_val(tmp)); ! 1223: } ! 1224: return(val); ! 1225: } ! 1226: ! 1227: UINT32 debugger_get_ofs(const char *str) ! 1228: { ! 1229: char tmp[1024], *s; ! 1230: ! 1231: if(str == NULL || strlen(str) == 0) { ! 1232: return(0); ! 1233: } ! 1234: strcpy(tmp, str); ! 1235: ! 1236: if((s = strstr(tmp, ":")) != NULL) { ! 1237: // 0000:0000 ! 1238: return(debugger_get_val(s + 1)); ! 1239: } ! 1240: return(debugger_get_val(tmp)); ! 1241: } ! 1242: ! 1243: void debugger_main() ! 1244: { ! 1245: telnet_command("\033[20h"); // cr-lf ! 1246: ! 1247: force_suspend = true; ! 1248: now_going = false; ! 1249: now_debugging = true; ! 1250: Sleep(100); ! 1251: ! 1252: if(!m_exit && !now_suspended) { ! 1253: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY); ! 1254: telnet_printf("waiting until cpu is suspended...\n"); ! 1255: } ! 1256: while(!m_exit && !now_suspended) { ! 1257: if(telnet_disconnected()) { ! 1258: break; ! 1259: } ! 1260: Sleep(10); ! 1261: } ! 1262: ! 1263: char buffer[8192]; ! 1264: ! 1265: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY); ! 1266: debugger_process_info(buffer); ! 1267: telnet_printf("%s", buffer); ! 1268: debugger_regs_info(buffer); ! 1269: telnet_printf("%s", buffer); ! 1270: telnet_set_color(TELNET_RED | TELNET_INTENSITY); ! 1271: telnet_printf("breaked at %04X:%04X\n", SREG(CS), m_eip); ! 1272: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY); ! 1273: debugger_dasm(buffer, SREG(CS), m_eip); ! 1274: telnet_printf("next\t%04X:%04X %s\n", SREG(CS), m_eip, buffer); ! 1275: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY); ! 1276: ! 1277: #define MAX_COMMAND_LEN 64 ! 1278: ! 1279: char command[MAX_COMMAND_LEN + 1]; ! 1280: char prev_command[MAX_COMMAND_LEN + 1] = {0}; ! 1281: ! 1282: UINT32 data_seg = SREG(DS); ! 1283: UINT32 data_ofs = 0; ! 1284: UINT32 dasm_seg = SREG(CS); ! 1285: UINT32 dasm_ofs = m_eip; ! 1286: ! 1287: while(!m_exit) { ! 1288: telnet_printf("- "); ! 1289: command[0] = '\0'; ! 1290: ! 1291: if(fi_debugger != NULL) { ! 1292: while(command[0] == '\0') { ! 1293: if(fgets(command, sizeof(command), fi_debugger) == NULL) { ! 1294: break; ! 1295: } ! 1296: while(strlen(command) > 0 && (command[strlen(command) - 1] == 0x0d || command[strlen(command) - 1] == 0x0a)) { ! 1297: command[strlen(command) - 1] = '\0'; ! 1298: } ! 1299: } ! 1300: if(command[0] != '\0') { ! 1301: telnet_command("%s\n", command); ! 1302: } ! 1303: } ! 1304: if(command[0] == '\0') { ! 1305: if(!telnet_gets(command, sizeof(command))) { ! 1306: break; ! 1307: } ! 1308: } ! 1309: if(command[0] == '\0') { ! 1310: strcpy(command, prev_command); ! 1311: } else { ! 1312: strcpy(prev_command, command); ! 1313: } ! 1314: if(fp_debugger != NULL) { ! 1315: fprintf(fp_debugger, "%s\n", command); ! 1316: } ! 1317: ! 1318: if(!m_exit && command[0] != 0) { ! 1319: char *params[32], *token = NULL; ! 1320: int num = 0; ! 1321: ! 1322: if((token = strtok(command, " ")) != NULL) { ! 1323: params[num++] = token; ! 1324: while(num < 32 && (token = strtok(NULL, " ")) != NULL) { ! 1325: params[num++] = token; ! 1326: } ! 1327: } ! 1328: if(stricmp(params[0], "D") == 0) { ! 1329: if(num <= 3) { ! 1330: if(num >= 2) { ! 1331: data_seg = debugger_get_seg(params[1], data_seg); ! 1332: data_ofs = debugger_get_ofs(params[1]); ! 1333: } ! 1334: UINT32 end_seg = data_seg; ! 1335: UINT32 end_ofs = data_ofs + 8 * 16 - 1; ! 1336: if(num == 3) { ! 1337: end_seg = debugger_get_seg(params[2], data_seg); ! 1338: end_ofs = debugger_get_ofs(params[2]); ! 1339: } ! 1340: UINT64 start_addr = (data_seg << 4) + data_ofs; ! 1341: UINT64 end_addr = (end_seg << 4) + end_ofs; ! 1342: // bool is_sjis = false; ! 1343: ! 1344: for(UINT64 addr = (start_addr & ~0x0f); addr <= (end_addr | 0x0f); addr++) { ! 1345: if((addr & 0x0f) == 0) { ! 1346: if((data_ofs = addr - (data_seg << 4)) > 0xffff) { ! 1347: data_seg += 0x1000; ! 1348: data_ofs -= 0x10000; ! 1349: } ! 1350: telnet_printf("%06X:%04X ", data_seg, data_ofs); ! 1351: memset(buffer, 0, sizeof(buffer)); ! 1352: } ! 1353: if(addr < start_addr || addr > end_addr) { ! 1354: telnet_printf(" "); ! 1355: buffer[addr & 0x0f] = ' '; ! 1356: } else { ! 1357: UINT8 data = debugger_read_byte(addr & ADDR_MASK); ! 1358: telnet_printf(" %02X", data); ! 1359: // if(is_sjis) { ! 1360: // buffer[addr & 0x0f] = data; ! 1361: // is_sjis = false; ! 1362: // } else if(((data >= 0x81 && data <= 0x9f) || (data >= 0xe0 && data <= 0xef)) && (addr & 0x0f) < 0x0f) { ! 1363: // buffer[addr & 0x0f] = data; ! 1364: // is_sjis = true; ! 1365: // } else ! 1366: if((data >= 0x20 && data <= 0x7e)/* || (data >= 0xa1 && data <= 0xdf)*/) { ! 1367: buffer[addr & 0x0f] = data; ! 1368: } else { ! 1369: buffer[addr & 0x0f] = '.'; ! 1370: } ! 1371: } ! 1372: if((addr & 0x0f) == 0x0f) { ! 1373: telnet_printf(" %s\n", buffer); ! 1374: } ! 1375: } ! 1376: if((data_ofs = (end_addr + 1) - (data_seg << 4)) > 0xffff) { ! 1377: data_seg += 0x1000; ! 1378: data_ofs -= 0x10000; ! 1379: } ! 1380: prev_command[1] = '\0'; // remove parameters to dump continuously ! 1381: } else { ! 1382: telnet_printf("invalid parameter number\n"); ! 1383: } ! 1384: } else if(stricmp(params[0], "E") == 0 || stricmp(params[0], "EB") == 0) { ! 1385: if(num >= 3) { ! 1386: UINT32 seg = debugger_get_seg(params[1], data_seg); ! 1387: UINT32 ofs = debugger_get_ofs(params[1]); ! 1388: for(int i = 2, j = 0; i < num; i++, j++) { ! 1389: debugger_write_byte(((seg << 4) + (ofs + j)) & ADDR_MASK, debugger_get_val(params[i]) & 0xff); ! 1390: } ! 1391: } else { ! 1392: telnet_printf("invalid parameter number\n"); ! 1393: } ! 1394: } else if(stricmp(params[0], "EW") == 0) { ! 1395: if(num >= 3) { ! 1396: UINT32 seg = debugger_get_seg(params[1], data_seg); ! 1397: UINT32 ofs = debugger_get_ofs(params[1]); ! 1398: for(int i = 2, j = 0; i < num; i++, j += 2) { ! 1399: debugger_write_word(((seg << 4) + (ofs + j)) & ADDR_MASK, debugger_get_val(params[i]) & 0xffff); ! 1400: } ! 1401: } else { ! 1402: telnet_printf("invalid parameter number\n"); ! 1403: } ! 1404: } else if(stricmp(params[0], "ED") == 0) { ! 1405: if(num >= 3) { ! 1406: UINT32 seg = debugger_get_seg(params[1], data_seg); ! 1407: UINT32 ofs = debugger_get_ofs(params[1]); ! 1408: for(int i = 2, j = 0; i < num; i++, j += 4) { ! 1409: debugger_write_dword(((seg << 4) + (ofs + j)) & ADDR_MASK, debugger_get_val(params[i])); ! 1410: } ! 1411: } else { ! 1412: telnet_printf("invalid parameter number\n"); ! 1413: } ! 1414: } else if(stricmp(params[0], "EA") == 0) { ! 1415: if(num >= 3) { ! 1416: UINT32 seg = debugger_get_seg(params[1], data_seg); ! 1417: UINT32 ofs = debugger_get_ofs(params[1]); ! 1418: strcpy(buffer, prev_command); ! 1419: if((token = strtok(buffer, "\"")) != NULL && (token = strtok(NULL, "\"")) != NULL) { ! 1420: int len = strlen(token); ! 1421: for(int i = 0; i < len; i++) { ! 1422: debugger_write_byte(((seg << 4) + (ofs + i)) & ADDR_MASK, token[i] & 0xff); ! 1423: } ! 1424: } else { ! 1425: telnet_printf("invalid parameter\n"); ! 1426: } ! 1427: } else { ! 1428: telnet_printf("invalid parameter number\n"); ! 1429: } ! 1430: } else if(stricmp(params[0], "I") == 0 || stricmp(params[0], "IB") == 0) { ! 1431: if(num == 2) { ! 1432: telnet_printf("%02X\n", debugger_read_io_byte(debugger_get_val(params[1])) & 0xff); ! 1433: } else { ! 1434: telnet_printf("invalid parameter number\n"); ! 1435: } ! 1436: } else if(stricmp(params[0], "IW") == 0) { ! 1437: if(num == 2) { ! 1438: telnet_printf("%04X\n", debugger_read_io_word(debugger_get_val(params[1])) & 0xffff); ! 1439: } else { ! 1440: telnet_printf("invalid parameter number\n"); ! 1441: } ! 1442: } else if(stricmp(params[0], "ID") == 0) { ! 1443: if(num == 2) { ! 1444: telnet_printf("%08X\n", debugger_read_io_dword(debugger_get_val(params[1]))); ! 1445: } else { ! 1446: telnet_printf("invalid parameter number\n"); ! 1447: } ! 1448: } else if(stricmp(params[0], "O") == 0 || stricmp(params[0], "OB") == 0) { ! 1449: if(num == 3) { ! 1450: debugger_write_io_byte(debugger_get_val(params[1]), debugger_get_val(params[2]) & 0xff); ! 1451: } else { ! 1452: telnet_printf("invalid parameter number\n"); ! 1453: } ! 1454: } else if(stricmp(params[0], "OW") == 0) { ! 1455: if(num == 3) { ! 1456: debugger_write_io_word(debugger_get_val(params[1]), debugger_get_val(params[2]) & 0xffff); ! 1457: } else { ! 1458: telnet_printf("invalid parameter number\n"); ! 1459: } ! 1460: } else if(stricmp(params[0], "OD") == 0) { ! 1461: if(num == 3) { ! 1462: debugger_write_io_dword(debugger_get_val(params[1]), debugger_get_val(params[2])); ! 1463: } else { ! 1464: telnet_printf("invalid parameter number\n"); ! 1465: } ! 1466: } else if(stricmp(params[0], "R") == 0) { ! 1467: if(num == 1) { ! 1468: debugger_regs_info(buffer); ! 1469: telnet_printf("%s", buffer); ! 1470: } else if(num == 3) { ! 1471: #if defined(HAS_I386) ! 1472: if(stricmp(params[1], "EAX") == 0) { ! 1473: REG32(EAX) = debugger_get_val(params[2]); ! 1474: } else if(stricmp(params[1], "EBX") == 0) { ! 1475: REG32(EBX) = debugger_get_val(params[2]); ! 1476: } else if(stricmp(params[1], "ECX") == 0) { ! 1477: REG32(ECX) = debugger_get_val(params[2]); ! 1478: } else if(stricmp(params[1], "EDX") == 0) { ! 1479: REG32(EDX) = debugger_get_val(params[2]); ! 1480: } else if(stricmp(params[1], "ESP") == 0) { ! 1481: REG32(ESP) = debugger_get_val(params[2]); ! 1482: } else if(stricmp(params[1], "EBP") == 0) { ! 1483: REG32(EBP) = debugger_get_val(params[2]); ! 1484: } else if(stricmp(params[1], "ESI") == 0) { ! 1485: REG32(ESI) = debugger_get_val(params[2]); ! 1486: } else if(stricmp(params[1], "EDI") == 0) { ! 1487: REG32(EDI) = debugger_get_val(params[2]); ! 1488: } else ! 1489: #endif ! 1490: if(stricmp(params[1], "AX") == 0) { ! 1491: REG16(AX) = debugger_get_val(params[2]); ! 1492: } else if(stricmp(params[1], "BX") == 0) { ! 1493: REG16(BX) = debugger_get_val(params[2]); ! 1494: } else if(stricmp(params[1], "CX") == 0) { ! 1495: REG16(CX) = debugger_get_val(params[2]); ! 1496: } else if(stricmp(params[1], "DX") == 0) { ! 1497: REG16(DX) = debugger_get_val(params[2]); ! 1498: } else if(stricmp(params[1], "SP") == 0) { ! 1499: REG16(SP) = debugger_get_val(params[2]); ! 1500: } else if(stricmp(params[1], "BP") == 0) { ! 1501: REG16(BP) = debugger_get_val(params[2]); ! 1502: } else if(stricmp(params[1], "SI") == 0) { ! 1503: REG16(SI) = debugger_get_val(params[2]); ! 1504: } else if(stricmp(params[1], "DI") == 0) { ! 1505: REG16(DI) = debugger_get_val(params[2]); ! 1506: } else if(stricmp(params[1], "IP") == 0 || stricmp(params[1], "EIP") == 0) { ! 1507: #if defined(HAS_I386) ! 1508: if(m_operand_size) { ! 1509: m_eip = debugger_get_val(params[2]); ! 1510: } else { ! 1511: m_eip = debugger_get_val(params[2]) & 0xffff; ! 1512: } ! 1513: CHANGE_PC(m_eip); ! 1514: #else ! 1515: m_pc = (SREG_BASE(CS) + (debugger_get_val(params[2]) & 0xffff)) & ADDR_MASK; ! 1516: CHANGE_PC(m_pc); ! 1517: #endif ! 1518: } else if(stricmp(params[1], "AL") == 0) { ! 1519: REG8(AL) = debugger_get_val(params[2]); ! 1520: } else if(stricmp(params[1], "AH") == 0) { ! 1521: REG8(AH) = debugger_get_val(params[2]); ! 1522: } else if(stricmp(params[1], "BL") == 0) { ! 1523: REG8(BL) = debugger_get_val(params[2]); ! 1524: } else if(stricmp(params[1], "BH") == 0) { ! 1525: REG8(BH) = debugger_get_val(params[2]); ! 1526: } else if(stricmp(params[1], "CL") == 0) { ! 1527: REG8(CL) = debugger_get_val(params[2]); ! 1528: } else if(stricmp(params[1], "CH") == 0) { ! 1529: REG8(CH) = debugger_get_val(params[2]); ! 1530: } else if(stricmp(params[1], "DL") == 0) { ! 1531: REG8(DL) = debugger_get_val(params[2]); ! 1532: } else if(stricmp(params[1], "DH") == 0) { ! 1533: REG8(DH) = debugger_get_val(params[2]); ! 1534: } else { ! 1535: telnet_printf("unknown register %s\n", params[1]); ! 1536: } ! 1537: } else { ! 1538: telnet_printf("invalid parameter number\n"); ! 1539: } ! 1540: } else if(stricmp(params[0], "S") == 0) { ! 1541: if(num >= 4) { ! 1542: UINT32 cur_seg = debugger_get_seg(params[1], data_seg); ! 1543: UINT32 cur_ofs = debugger_get_ofs(params[1]); ! 1544: UINT32 end_seg = debugger_get_seg(params[2], cur_seg); ! 1545: UINT32 end_ofs = debugger_get_ofs(params[2]); ! 1546: UINT8 list[32]; ! 1547: ! 1548: for(int i = 3, j = 0; i < num && j < 32; i++, j++) { ! 1549: list[j] = debugger_get_val(params[i]); ! 1550: } ! 1551: while((cur_seg << 4) + cur_ofs <= (end_seg << 4) + end_ofs) { ! 1552: bool found = true; ! 1553: for(int i = 3, j = 0; i < num && j < 32; i++, j++) { ! 1554: if(debugger_read_byte(((cur_seg << 4) + (cur_ofs + j)) & ADDR_MASK) != list[j]) { ! 1555: found = false; ! 1556: break; ! 1557: } ! 1558: } ! 1559: if(found) { ! 1560: telnet_printf("%04X:%04X\n", cur_seg, cur_ofs); ! 1561: } ! 1562: if((cur_ofs += 1) > 0xffff) { ! 1563: cur_seg += 0x1000; ! 1564: cur_ofs -= 0x10000; ! 1565: } ! 1566: } ! 1567: } else { ! 1568: telnet_printf("invalid parameter number\n"); ! 1569: } ! 1570: } else if(stricmp(params[0], "U") == 0) { ! 1571: if(num <= 3) { ! 1572: if(num >= 2) { ! 1573: dasm_seg = debugger_get_seg(params[1], dasm_seg); ! 1574: dasm_ofs = debugger_get_ofs(params[1]); ! 1575: } ! 1576: if(num == 3) { ! 1577: UINT32 end_seg = debugger_get_seg(params[2], dasm_seg); ! 1578: UINT32 end_ofs = debugger_get_ofs(params[2]); ! 1579: ! 1580: while((dasm_seg << 4) + dasm_ofs <= (end_seg << 4) + end_ofs) { ! 1581: int len = debugger_dasm(buffer, dasm_seg, dasm_ofs); ! 1582: telnet_printf("%04X:%04X ", dasm_seg, dasm_ofs); ! 1583: for(int i = 0; i < len; i++) { ! 1584: telnet_printf("%02X", debugger_read_byte(((dasm_seg << 4) + (dasm_ofs + i)) & ADDR_MASK)); ! 1585: } ! 1586: for(int i = len; i < 8; i++) { ! 1587: telnet_printf(" "); ! 1588: } ! 1589: telnet_printf(" %s\n", buffer); ! 1590: if((dasm_ofs += len) > 0xffff) { ! 1591: dasm_seg += 0x1000; ! 1592: dasm_ofs -= 0x10000; ! 1593: } ! 1594: } ! 1595: } else { ! 1596: for(int i = 0; i < 16; i++) { ! 1597: int len = debugger_dasm(buffer, dasm_seg, dasm_ofs); ! 1598: telnet_printf("%04X:%04X ", dasm_seg, dasm_ofs); ! 1599: for(int i = 0; i < len; i++) { ! 1600: telnet_printf("%02X", debugger_read_byte(((dasm_seg << 4) + (dasm_ofs + i)) & ADDR_MASK)); ! 1601: } ! 1602: for(int i = len; i < 8; i++) { ! 1603: telnet_printf(" "); ! 1604: } ! 1605: telnet_printf(" %s\n", buffer); ! 1606: if((dasm_ofs += len) > 0xffff) { ! 1607: dasm_seg += 0x1000; ! 1608: dasm_ofs -= 0x10000; ! 1609: } ! 1610: } ! 1611: } ! 1612: prev_command[1] = '\0'; // remove parameters to disassemble continuously ! 1613: } else { ! 1614: telnet_printf("invalid parameter number\n"); ! 1615: } ! 1616: } else if(stricmp(params[0], "H") == 0) { ! 1617: if(num == 3) { ! 1618: UINT32 l = debugger_get_val(params[1]); ! 1619: UINT32 r = debugger_get_val(params[2]); ! 1620: telnet_printf("%08X %08X\n", l + r, l - r); ! 1621: } else { ! 1622: telnet_printf("invalid parameter number\n"); ! 1623: } ! 1624: } else if(stricmp(params[0], "BP") == 0 || stricmp(params[0], "RBP") == 0 || stricmp(params[0], "WBP") == 0) { ! 1625: break_point_t *break_point_ptr; ! 1626: #define GET_BREAK_POINT_PTR() { \ ! 1627: if(params[0][0] == 'R' || params[0][0] == 'r') { \ ! 1628: break_point_ptr = &rd_break_point; \ ! 1629: } else if(params[0][0] == 'W' || params[0][0] == 'w') { \ ! 1630: break_point_ptr = &wr_break_point; \ ! 1631: } else if(params[0][0] == 'I' || params[0][0] == 'i') { \ ! 1632: break_point_ptr = &in_break_point; \ ! 1633: } else if(params[0][0] == 'O' || params[0][0] == 'o') { \ ! 1634: break_point_ptr = &out_break_point; \ ! 1635: } else { \ ! 1636: break_point_ptr = &break_point; \ ! 1637: } \ ! 1638: } ! 1639: GET_BREAK_POINT_PTR(); ! 1640: if(num == 2) { ! 1641: UINT32 seg = 0; ! 1642: if(params[0][0] == 'R' || params[0][0] == 'r' || params[0][0] == 'W' || params[0][0] == 'w') { ! 1643: seg = debugger_get_seg(params[1], data_seg); ! 1644: } else { ! 1645: seg = debugger_get_seg(params[1], SREG(CS)); ! 1646: } ! 1647: UINT32 ofs = debugger_get_ofs(params[1]); ! 1648: bool found = false; ! 1649: for(int i = 0; i < MAX_BREAK_POINTS && !found; i++) { ! 1650: if(break_point_ptr->table[i].status == 0 || break_point_ptr->table[i].addr == ((seg << 4) + ofs)) { ! 1651: break_point_ptr->table[i].addr = (seg << 4) + ofs; ! 1652: break_point_ptr->table[i].seg = seg; ! 1653: break_point_ptr->table[i].ofs = ofs; ! 1654: break_point_ptr->table[i].status = 1; ! 1655: found = true; ! 1656: } ! 1657: } ! 1658: if(!found) { ! 1659: telnet_printf("too many break points\n"); ! 1660: } ! 1661: } else { ! 1662: telnet_printf("invalid parameter number\n"); ! 1663: } ! 1664: } else if(stricmp(params[0], "IBP") == 0 || stricmp(params[0], "OBP") == 0) { ! 1665: break_point_t *break_point_ptr; ! 1666: GET_BREAK_POINT_PTR(); ! 1667: if(num == 2) { ! 1668: UINT32 addr = debugger_get_val(params[1]); ! 1669: bool found = false; ! 1670: for(int i = 0; i < MAX_BREAK_POINTS && !found; i++) { ! 1671: if(break_point_ptr->table[i].status == 0 || break_point_ptr->table[i].addr == addr) { ! 1672: break_point_ptr->table[i].addr = addr; ! 1673: break_point_ptr->table[i].status = 1; ! 1674: found = true; ! 1675: } ! 1676: } ! 1677: if(!found) { ! 1678: telnet_printf("too many break points\n"); ! 1679: } ! 1680: } else { ! 1681: telnet_printf("invalid parameter number\n"); ! 1682: } ! 1683: } else if(stricmp(params[0], "BC") == 0 || stricmp(params[0], "RBC") == 0 || stricmp(params[0], "WBC") == 0 || stricmp(params[0], "IBC") == 0 || stricmp(params[0], "OBC") == 0) { ! 1684: break_point_t *break_point_ptr; ! 1685: GET_BREAK_POINT_PTR(); ! 1686: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) { ! 1687: memset(break_point_ptr, 0, sizeof(break_point_t)); ! 1688: } else if(num >= 2) { ! 1689: for(int i = 1; i < num; i++) { ! 1690: int index = debugger_get_val(params[i]); ! 1691: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) { ! 1692: telnet_printf("invalid index %x\n", index); ! 1693: } else { ! 1694: break_point_ptr->table[index - 1].addr = 0; ! 1695: break_point_ptr->table[index - 1].seg = 0; ! 1696: break_point_ptr->table[index - 1].ofs = 0; ! 1697: break_point_ptr->table[index - 1].status = 0; ! 1698: } ! 1699: } ! 1700: } else { ! 1701: telnet_printf("invalid parameter number\n"); ! 1702: } ! 1703: } else if(stricmp(params[0], "BD") == 0 || stricmp(params[0], "RBD") == 0 || stricmp(params[0], "WBD") == 0 || stricmp(params[0], "IBD") == 0 || stricmp(params[0], "OBD") == 0 || ! 1704: stricmp(params[0], "BE") == 0 || stricmp(params[0], "RBE") == 0 || stricmp(params[0], "WBE") == 0 || stricmp(params[0], "IBE") == 0 || stricmp(params[0], "OBE") == 0) { ! 1705: break_point_t *break_point_ptr; ! 1706: GET_BREAK_POINT_PTR(); ! 1707: bool enabled = (params[0][strlen(params[0]) - 1] == 'E' || params[0][strlen(params[0]) - 1] == 'e'); ! 1708: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) { ! 1709: for(int i = 0; i < MAX_BREAK_POINTS; i++) { ! 1710: if(break_point_ptr->table[i].status != 0) { ! 1711: break_point_ptr->table[i].status = enabled ? 1 : -1; ! 1712: } ! 1713: } ! 1714: } else if(num >= 2) { ! 1715: for(int i = 1; i < num; i++) { ! 1716: int index = debugger_get_val(params[i]); ! 1717: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) { ! 1718: telnet_printf("invalid index %x\n", index); ! 1719: } else if(break_point_ptr->table[index - 1].status == 0) { ! 1720: telnet_printf("break point %x is null\n", index); ! 1721: } else { ! 1722: break_point_ptr->table[index - 1].status = enabled ? 1 : -1; ! 1723: } ! 1724: } ! 1725: } else { ! 1726: telnet_printf("invalid parameter number\n"); ! 1727: } ! 1728: } else if(stricmp(params[0], "BL") == 0 || stricmp(params[0], "RBL") == 0 || stricmp(params[0], "WBL") == 0) { ! 1729: break_point_t *break_point_ptr; ! 1730: GET_BREAK_POINT_PTR(); ! 1731: if(num == 1) { ! 1732: for(int i = 0; i < MAX_BREAK_POINTS; i++) { ! 1733: if(break_point_ptr->table[i].status) { ! 1734: telnet_printf("%d %c %04X:%04X\n", i + 1, break_point_ptr->table[i].status == 1 ? 'e' : 'd', break_point_ptr->table[i].seg, break_point_ptr->table[i].ofs); ! 1735: } ! 1736: } ! 1737: } else { ! 1738: telnet_printf("invalid parameter number\n"); ! 1739: } ! 1740: } else if(stricmp(params[0], "IBL") == 0 || stricmp(params[0], "OBL") == 0) { ! 1741: break_point_t *break_point_ptr; ! 1742: GET_BREAK_POINT_PTR(); ! 1743: if(num == 1) { ! 1744: for(int i = 0; i < MAX_BREAK_POINTS; i++) { ! 1745: if(break_point_ptr->table[i].status) { ! 1746: telnet_printf("%d %c %04X\n", i + 1, break_point_ptr->table[i].status == 1 ? 'e' : 'd', break_point_ptr->table[i].addr); ! 1747: } ! 1748: } ! 1749: } else { ! 1750: telnet_printf("invalid parameter number\n"); ! 1751: } ! 1752: } else if(stricmp(params[0], "INTBP") == 0) { ! 1753: if(num >= 2 && num <= 4) { ! 1754: int int_num = debugger_get_val(params[1]); ! 1755: UINT8 ah = 0, ah_registered = 0; ! 1756: UINT8 al = 0, al_registered = 0; ! 1757: if(num >= 3) { ! 1758: ah = debugger_get_val(params[2]); ! 1759: ah_registered = 1; ! 1760: } ! 1761: if(num == 4) { ! 1762: al = debugger_get_val(params[3]); ! 1763: al_registered = 1; ! 1764: } ! 1765: bool found = false; ! 1766: for(int i = 0; i < MAX_BREAK_POINTS && !found; i++) { ! 1767: if(int_break_point.table[i].status == 0 || ( ! 1768: int_break_point.table[i].int_num == int_num && ! 1769: int_break_point.table[i].ah == ah && int_break_point.table[i].ah_registered == ah_registered && ! 1770: int_break_point.table[i].al == al && int_break_point.table[i].al_registered == al_registered)) { ! 1771: int_break_point.table[i].int_num = int_num; ! 1772: int_break_point.table[i].ah = ah; ! 1773: int_break_point.table[i].ah_registered = ah_registered; ! 1774: int_break_point.table[i].al = al; ! 1775: int_break_point.table[i].al_registered = al_registered; ! 1776: int_break_point.table[i].status = 1; ! 1777: found = true; ! 1778: } ! 1779: } ! 1780: if(!found) { ! 1781: telnet_printf("too many break points\n"); ! 1782: } ! 1783: } else { ! 1784: telnet_printf("invalid parameter number\n"); ! 1785: } ! 1786: } else if(stricmp(params[0], "INTBC") == 0) { ! 1787: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) { ! 1788: memset(&int_break_point, 0, sizeof(int_break_point_t)); ! 1789: } else if(num >= 2) { ! 1790: for(int i = 1; i < num; i++) { ! 1791: int index = debugger_get_val(params[i]); ! 1792: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) { ! 1793: telnet_printf("invalid index %x\n", index); ! 1794: } else { ! 1795: int_break_point.table[index - 1].int_num = 0; ! 1796: int_break_point.table[index - 1].ah = 0; ! 1797: int_break_point.table[index - 1].ah_registered = 0; ! 1798: int_break_point.table[index - 1].al = 0; ! 1799: int_break_point.table[index - 1].al_registered = 0; ! 1800: int_break_point.table[index - 1].status = 0; ! 1801: } ! 1802: } ! 1803: } else { ! 1804: telnet_printf("invalid parameter number\n"); ! 1805: } ! 1806: } else if(stricmp(params[0], "INTBD") == 0 || stricmp(params[0], "INTBE") == 0) { ! 1807: bool enabled = (params[0][strlen(params[0]) - 1] == 'E' || params[0][strlen(params[0]) - 1] == 'e'); ! 1808: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) { ! 1809: for(int i = 0; i < MAX_BREAK_POINTS; i++) { ! 1810: if(int_break_point.table[i].status != 0) { ! 1811: int_break_point.table[i].status = enabled ? 1 : -1; ! 1812: } ! 1813: } ! 1814: } else if(num >= 2) { ! 1815: for(int i = 1; i < num; i++) { ! 1816: int index = debugger_get_val(params[i]); ! 1817: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) { ! 1818: telnet_printf("invalid index %x\n", index); ! 1819: } else if(int_break_point.table[index - 1].status == 0) { ! 1820: telnet_printf("break point %x is null\n", index); ! 1821: } else { ! 1822: int_break_point.table[index - 1].status = enabled ? 1 : -1; ! 1823: } ! 1824: } ! 1825: } else { ! 1826: telnet_printf("invalid parameter number\n"); ! 1827: } ! 1828: } else if(stricmp(params[0], "INTBL") == 0) { ! 1829: if(num == 1) { ! 1830: for(int i = 0; i < MAX_BREAK_POINTS; i++) { ! 1831: if(int_break_point.table[i].status) { ! 1832: telnet_printf("%d %c %02X", i + 1, int_break_point.table[i].status == 1 ? 'e' : 'd', int_break_point.table[i].int_num); ! 1833: if(int_break_point.table[i].ah_registered) { ! 1834: telnet_printf(" %02X", int_break_point.table[i].ah); ! 1835: } ! 1836: if(int_break_point.table[i].al_registered) { ! 1837: telnet_printf(" %02X", int_break_point.table[i].al); ! 1838: } ! 1839: telnet_printf("\n"); ! 1840: } ! 1841: } ! 1842: } else { ! 1843: telnet_printf("invalid parameter number\n"); ! 1844: } ! 1845: } else if(stricmp(params[0], "G") == 0 || stricmp(params[0], "P") == 0) { ! 1846: if(num == 1 || num == 2) { ! 1847: break_point_t break_point_stored; ! 1848: bool break_points_stored = false; ! 1849: ! 1850: if(stricmp(params[0], "P") == 0) { ! 1851: memcpy(&break_point_stored, &break_point, sizeof(break_point_t)); ! 1852: memset(&break_point, 0, sizeof(break_point_t)); ! 1853: break_points_stored = true; ! 1854: ! 1855: break_point.table[0].addr = (SREG(CS) << 4) + m_eip + debugger_dasm(buffer, SREG(CS), m_eip); ! 1856: break_point.table[0].status = 1; ! 1857: } else if(num >= 2) { ! 1858: memcpy(&break_point_stored, &break_point, sizeof(break_point_t)); ! 1859: memset(&break_point, 0, sizeof(break_point_t)); ! 1860: break_points_stored = true; ! 1861: ! 1862: UINT32 seg = debugger_get_seg(params[1], SREG(CS)); ! 1863: UINT32 ofs = debugger_get_ofs(params[1]); ! 1864: break_point.table[0].addr = (seg << 4) + ofs; ! 1865: break_point.table[0].seg = seg; ! 1866: break_point.table[0].ofs = ofs; ! 1867: break_point.table[0].status = 1; ! 1868: } ! 1869: break_point.hit = rd_break_point.hit = wr_break_point.hit = in_break_point.hit = out_break_point.hit = int_break_point.hit = 0; ! 1870: now_going = true; ! 1871: now_suspended = false; ! 1872: ! 1873: telnet_command("\033[2l"); // key unlock ! 1874: while(!m_exit && !now_suspended) { ! 1875: if(telnet_kbhit()) { ! 1876: break; ! 1877: } ! 1878: Sleep(10); ! 1879: } ! 1880: now_going = false; ! 1881: telnet_command("\033[2h"); // key lock ! 1882: ! 1883: if(!(break_point.hit || rd_break_point.hit || wr_break_point.hit || in_break_point.hit || out_break_point.hit || int_break_point.hit)) { ! 1884: Sleep(100); ! 1885: if(!m_exit && !now_suspended) { ! 1886: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY); ! 1887: telnet_printf("waiting until cpu is suspended...\n"); ! 1888: } ! 1889: } ! 1890: while(!m_exit && !now_suspended) { ! 1891: if(telnet_disconnected()) { ! 1892: break; ! 1893: } ! 1894: Sleep(10); ! 1895: } ! 1896: dasm_seg = SREG(CS); ! 1897: dasm_ofs = m_eip; ! 1898: ! 1899: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY); ! 1900: debugger_dasm(buffer, m_prev_cs, m_prev_eip); ! 1901: telnet_printf("done\t%04X:%04X %s\n", m_prev_cs, m_prev_eip, buffer); ! 1902: ! 1903: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY); ! 1904: debugger_regs_info(buffer); ! 1905: telnet_printf("%s", buffer); ! 1906: ! 1907: if(break_point.hit) { ! 1908: if(stricmp(params[0], "G") == 0 && num == 1) { ! 1909: telnet_set_color(TELNET_RED | TELNET_INTENSITY); ! 1910: telnet_printf("breaked at %04X:%04X: break point is hit\n", SREG(CS), m_eip); ! 1911: } ! 1912: } else if(rd_break_point.hit) { ! 1913: telnet_set_color(TELNET_RED | TELNET_INTENSITY); ! 1914: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was read at %04X:%04X\n", SREG(CS), m_eip, ! 1915: rd_break_point.table[rd_break_point.hit - 1].seg, rd_break_point.table[rd_break_point.hit - 1].ofs, ! 1916: m_prev_cs, m_prev_eip); ! 1917: } else if(wr_break_point.hit) { ! 1918: telnet_set_color(TELNET_RED | TELNET_INTENSITY); ! 1919: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was written at %04X:%04X\n", SREG(CS), m_eip, ! 1920: wr_break_point.table[wr_break_point.hit - 1].seg, wr_break_point.table[wr_break_point.hit - 1].ofs, ! 1921: m_prev_cs, m_prev_eip); ! 1922: } else if(in_break_point.hit) { ! 1923: telnet_set_color(TELNET_RED | TELNET_INTENSITY); ! 1924: telnet_printf("breaked at %04X:%04X: port %04X was read at %04X:%04X\n", SREG(CS), m_eip, ! 1925: in_break_point.table[in_break_point.hit - 1].addr, ! 1926: m_prev_cs, m_prev_eip); ! 1927: } else if(out_break_point.hit) { ! 1928: telnet_set_color(TELNET_RED | TELNET_INTENSITY); ! 1929: telnet_printf("breaked at %04X:%04X: port %04X was written at %04X:%04X\n", SREG(CS), m_eip, ! 1930: out_break_point.table[out_break_point.hit - 1].addr, ! 1931: m_prev_cs, m_prev_eip); ! 1932: } else if(int_break_point.hit) { ! 1933: telnet_set_color(TELNET_RED | TELNET_INTENSITY); ! 1934: telnet_printf("breaked at %04X:%04X: INT %02x", SREG(CS), m_eip, int_break_point.table[int_break_point.hit - 1].int_num); ! 1935: if(int_break_point.table[int_break_point.hit - 1].ah_registered) { ! 1936: telnet_printf(" AH=%02x", int_break_point.table[int_break_point.hit - 1].ah); ! 1937: } ! 1938: if(int_break_point.table[int_break_point.hit - 1].al_registered) { ! 1939: telnet_printf(" AL=%02x", int_break_point.table[int_break_point.hit - 1].al); ! 1940: } ! 1941: telnet_printf(" is raised at %04X:%04X\n", m_prev_cs, m_prev_eip); ! 1942: } else { ! 1943: telnet_set_color(TELNET_RED | TELNET_INTENSITY); ! 1944: telnet_printf("breaked at %04X:%04X: enter key was pressed\n", SREG(CS), m_eip); ! 1945: } ! 1946: if(break_points_stored) { ! 1947: memcpy(&break_point, &break_point_stored, sizeof(break_point_t)); ! 1948: } ! 1949: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY); ! 1950: debugger_dasm(buffer, SREG(CS), m_eip); ! 1951: telnet_printf("next\t%04X:%04X %s\n", SREG(CS), m_eip, buffer); ! 1952: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY); ! 1953: } else { ! 1954: telnet_printf("invalid parameter number\n"); ! 1955: } ! 1956: } else if(stricmp(params[0], "T") == 0) { ! 1957: if(num == 1 || num == 2) { ! 1958: int steps = 1; ! 1959: if(num >= 2) { ! 1960: steps = debugger_get_val(params[1]); ! 1961: } ! 1962: ! 1963: telnet_command("\033[2l"); // key unlock ! 1964: while(steps-- > 0) { ! 1965: break_point.hit = rd_break_point.hit = wr_break_point.hit = in_break_point.hit = out_break_point.hit = int_break_point.hit = 0; ! 1966: now_going = false; ! 1967: now_suspended = false; ! 1968: ! 1969: while(!m_exit && !now_suspended) { ! 1970: if(telnet_disconnected()) { ! 1971: break; ! 1972: } ! 1973: Sleep(10); ! 1974: } ! 1975: dasm_seg = SREG(CS); ! 1976: dasm_ofs = m_eip; ! 1977: ! 1978: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY); ! 1979: debugger_dasm(buffer, m_prev_cs, m_prev_eip); ! 1980: telnet_printf("done\t%04X:%04X %s\n", m_prev_cs, m_prev_eip, buffer); ! 1981: ! 1982: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY); ! 1983: debugger_regs_info(buffer); ! 1984: telnet_printf("%s", buffer); ! 1985: ! 1986: if(break_point.hit || rd_break_point.hit || wr_break_point.hit || in_break_point.hit || out_break_point.hit || int_break_point.hit || telnet_kbhit()) { ! 1987: break; ! 1988: } ! 1989: } ! 1990: telnet_command("\033[2h"); // key lock ! 1991: ! 1992: if(!(break_point.hit || rd_break_point.hit || wr_break_point.hit || in_break_point.hit || out_break_point.hit || int_break_point.hit)) { ! 1993: Sleep(100); ! 1994: if(!m_exit && !now_suspended) { ! 1995: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY); ! 1996: telnet_printf("waiting until cpu is suspended...\n"); ! 1997: } ! 1998: } ! 1999: while(!m_exit && !now_suspended) { ! 2000: if(telnet_disconnected()) { ! 2001: break; ! 2002: } ! 2003: Sleep(10); ! 2004: } ! 2005: if(break_point.hit) { ! 2006: telnet_set_color(TELNET_RED | TELNET_INTENSITY); ! 2007: telnet_printf("breaked at %04X:%04X: break point is hit\n", SREG(CS), m_eip); ! 2008: } else if(rd_break_point.hit) { ! 2009: telnet_set_color(TELNET_RED | TELNET_INTENSITY); ! 2010: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was read at %04X:%04X\n", SREG(CS), m_eip, ! 2011: rd_break_point.table[rd_break_point.hit - 1].seg, rd_break_point.table[rd_break_point.hit - 1].ofs, ! 2012: m_prev_cs, m_prev_eip); ! 2013: } else if(wr_break_point.hit) { ! 2014: telnet_set_color(TELNET_RED | TELNET_INTENSITY); ! 2015: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was written at %04X:%04X\n", SREG(CS), m_eip, ! 2016: wr_break_point.table[wr_break_point.hit - 1].seg, wr_break_point.table[wr_break_point.hit - 1].ofs, ! 2017: m_prev_cs, m_prev_eip); ! 2018: } else if(in_break_point.hit) { ! 2019: telnet_set_color(TELNET_RED | TELNET_INTENSITY); ! 2020: telnet_printf("breaked at %04X:%04X: port %04X was read at %04X:%04X\n", SREG(CS), m_eip, ! 2021: in_break_point.table[in_break_point.hit - 1].addr, ! 2022: m_prev_cs, m_prev_eip); ! 2023: } else if(out_break_point.hit) { ! 2024: telnet_set_color(TELNET_RED | TELNET_INTENSITY); ! 2025: telnet_printf("breaked at %04X:%04X: port %04X was written at %04X:%04X\n", SREG(CS), m_eip, ! 2026: out_break_point.table[out_break_point.hit - 1].addr, ! 2027: m_prev_cs, m_prev_eip); ! 2028: } else if(int_break_point.hit) { ! 2029: telnet_set_color(TELNET_RED | TELNET_INTENSITY); ! 2030: telnet_printf("breaked at %04X:%04X: INT %02x", SREG(CS), m_eip, int_break_point.table[int_break_point.hit - 1].int_num); ! 2031: if(int_break_point.table[int_break_point.hit - 1].ah_registered) { ! 2032: telnet_printf(" AH=%02x", int_break_point.table[int_break_point.hit - 1].ah); ! 2033: } ! 2034: if(int_break_point.table[int_break_point.hit - 1].al_registered) { ! 2035: telnet_printf(" AL=%02x", int_break_point.table[int_break_point.hit - 1].al); ! 2036: } ! 2037: telnet_printf(" is raised at %04X:%04X\n", m_prev_cs, m_prev_eip); ! 2038: } else if(steps > 0) { ! 2039: telnet_set_color(TELNET_RED | TELNET_INTENSITY); ! 2040: telnet_printf("breaked at %04X:%04X: enter key was pressed\n", SREG(CS), m_eip); ! 2041: } ! 2042: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY); ! 2043: debugger_dasm(buffer, SREG(CS), m_eip); ! 2044: telnet_printf("next\t%04X:%04X %s\n", SREG(CS), m_eip, buffer); ! 2045: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY); ! 2046: } else { ! 2047: telnet_printf("invalid parameter number\n"); ! 2048: } ! 2049: } else if(stricmp(params[0], "Q") == 0) { ! 2050: break; ! 2051: } else if(stricmp(params[0], "X") == 0) { ! 2052: debugger_process_info(buffer); ! 2053: telnet_printf("%s", buffer); ! 2054: } else if(stricmp(params[0], ">") == 0) { ! 2055: if(num == 2) { ! 2056: if(fp_debugger != NULL) { ! 2057: fclose(fp_debugger); ! 2058: fp_debugger = NULL; ! 2059: } ! 2060: fp_debugger = fopen(params[1], "w"); ! 2061: } else { ! 2062: telnet_printf("invalid parameter number\n"); ! 2063: } ! 2064: } else if(stricmp(params[0], "<") == 0) { ! 2065: if(num == 2) { ! 2066: if(fi_debugger != NULL) { ! 2067: fclose(fi_debugger); ! 2068: fi_debugger = NULL; ! 2069: } ! 2070: fi_debugger = fopen(params[1], "r"); ! 2071: } else { ! 2072: telnet_printf("invalid parameter number\n"); ! 2073: } ! 2074: } else if(stricmp(params[0], "?") == 0) { ! 2075: telnet_printf("D [<start> [<end>]] - dump memory\n"); ! 2076: telnet_printf("E[{B,W,D}] <address> <list> - edit memory (byte,word,dword)\n"); ! 2077: telnet_printf("EA <address> \"<value>\" - edit memory (ascii)\n"); ! 2078: telnet_printf("I[{B,W,D}] <port> - input port (byte,word,dword)\n"); ! 2079: telnet_printf("O[{B,W,D}] <port> <value> - output port (byte,word,dword)\n"); ! 2080: ! 2081: telnet_printf("R - show registers\n"); ! 2082: telnet_printf("R <reg> <value> - edit register\n"); ! 2083: telnet_printf("S <start> <end> <list> - search\n"); ! 2084: telnet_printf("U [<start> [<end>]] - unassemble\n"); ! 2085: ! 2086: telnet_printf("H <value> <value> - hexadd\n"); ! 2087: ! 2088: telnet_printf("BP <address> - set breakpoint\n"); ! 2089: telnet_printf("{R,W}BP <address> - set breakpoint (break at memory access)\n"); ! 2090: telnet_printf("{I,O}BP <port> - set breakpoint (break at i/o access)\n"); ! 2091: telnet_printf("INTBP <num> [<ah> [<al>]]- set breakpoint (break at interrupt)\n"); ! 2092: telnet_printf("[{R,W,I,O,INT}]B{C,D,E} {*,<list>} - clear/disable/enable breakpoint(s)\n"); ! 2093: telnet_printf("[{R,W,I,O,INT}]BL - list breakpoint(s)\n"); ! 2094: ! 2095: telnet_printf("G - go (press enter key to break)\n"); ! 2096: telnet_printf("G <address> - go and break at address\n"); ! 2097: telnet_printf("P - trace one opcode (step over)\n"); ! 2098: telnet_printf("T [<count>] - trace (step in)\n"); ! 2099: telnet_printf("Q - quit\n"); ! 2100: telnet_printf("X - show dos process info\n"); ! 2101: ! 2102: telnet_printf("> <filename> - output logfile\n"); ! 2103: telnet_printf("< <filename> - input commands from file\n"); ! 2104: ! 2105: telnet_printf("<value> - hexa, decimal(%%d), ascii('a')\n"); ! 2106: telnet_printf("<list> - <value> [<value> [<value> [...]]]\n"); ! 2107: } else { ! 2108: telnet_printf("unknown command %s\n", params[0]); ! 2109: } ! 2110: } ! 2111: } ! 2112: if(fp_debugger != NULL) { ! 2113: fclose(fp_debugger); ! 2114: fp_debugger = NULL; ! 2115: } ! 2116: if(fi_debugger != NULL) { ! 2117: fclose(fi_debugger); ! 2118: fi_debugger = NULL; ! 2119: } ! 2120: now_debugging = now_going = now_suspended = force_suspend = false; ! 2121: closesocket(cli_socket); ! 2122: } ! 2123: ! 2124: const char *debugger_get_ttermpro_path() ! 2125: { ! 2126: static char path[MAX_PATH] = {0}; ! 2127: ! 2128: if(getenv("ProgramFiles")) { ! 2129: sprintf(path, "%s\\teraterm\\ttermpro.exe", getenv("ProgramFiles")); ! 2130: } ! 2131: return(path); ! 2132: } ! 2133: ! 2134: const char *debugger_get_ttermpro_x86_path() ! 2135: { ! 2136: static char path[MAX_PATH] = {0}; ! 2137: ! 2138: if(getenv("ProgramFiles(x86)")) { ! 2139: sprintf(path, "%s\\teraterm\\ttermpro.exe", getenv("ProgramFiles(x86)")); ! 2140: } ! 2141: return(path); ! 2142: } ! 2143: ! 2144: const char *debugger_get_putty_path() ! 2145: { ! 2146: static char path[MAX_PATH] = {0}; ! 2147: ! 2148: if(getenv("ProgramFiles")) { ! 2149: sprintf(path, "%s\\PuTTY\\putty.exe", getenv("ProgramFiles")); ! 2150: } ! 2151: return(path); ! 2152: } ! 2153: ! 2154: const char *debugger_get_putty_x86_path() ! 2155: { ! 2156: static char path[MAX_PATH] = {0}; ! 2157: ! 2158: if(getenv("ProgramFiles(x86)")) { ! 2159: sprintf(path, "%s\\PuTTY\\putty.exe", getenv("ProgramFiles(x86)")); ! 2160: } ! 2161: return(path); ! 2162: } ! 2163: ! 2164: const char *debugger_get_telnet_path() ! 2165: { ! 2166: // NOTE: When you run 32bit version of msdos.exe on Windows x64, ! 2167: // C:\Windows\System32\telnet.exe is redirected to telnet.exe in SysWOW64. ! 2168: // But 32bit version of telnet.exe will not be installed in SysWOW64 ! 2169: // and 64bit version of telnet.exe will be installed in System32. ! 2170: static char path[MAX_PATH] = {0}; ! 2171: ! 2172: if(getenv("windir") != NULL) { ! 2173: sprintf(path, "%s\\System32\\telnet.exe", getenv("windir")); ! 2174: } ! 2175: return(path); ! 2176: } ! 2177: ! 2178: DWORD WINAPI debugger_thread(LPVOID) ! 2179: { ! 2180: WSADATA was_data; ! 2181: struct sockaddr_in svr_addr; ! 2182: struct sockaddr_in cli_addr; ! 2183: int cli_addr_len = sizeof(cli_addr); ! 2184: int port = 23; ! 2185: int bind_stat = SOCKET_ERROR; ! 2186: struct timeval timeout; ! 2187: ! 2188: WSAStartup(MAKEWORD(2,0), &was_data); ! 2189: ! 2190: if((svr_socket = socket(AF_INET, SOCK_STREAM, 0)) != INVALID_SOCKET) { ! 2191: memset(&svr_addr, 0, sizeof(svr_addr)); ! 2192: svr_addr.sin_family = AF_INET; ! 2193: svr_addr.sin_addr.s_addr = htonl(INADDR_ANY); ! 2194: ! 2195: while(!m_exit && port < 10000) { ! 2196: svr_addr.sin_port = htons(port); ! 2197: if((bind_stat = bind(svr_socket, (struct sockaddr *)&svr_addr, sizeof(svr_addr))) == 0) { ! 2198: break; ! 2199: } else { ! 2200: port = (port == 23) ? 9000 : (port + 1); ! 2201: } ! 2202: } ! 2203: if(bind_stat == 0) { ! 2204: timeout.tv_sec = 1; ! 2205: timeout.tv_usec = 0; ! 2206: setsockopt(svr_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)); ! 2207: ! 2208: listen(svr_socket, 1); ! 2209: ! 2210: char command[MAX_PATH] = {0}; ! 2211: STARTUPINFOA si; ! 2212: PROCESS_INFORMATION pi; ! 2213: ! 2214: if(_access(debugger_get_ttermpro_path(), 0) == 0) { ! 2215: sprintf(command, "%s localhost:%d /T=1", debugger_get_ttermpro_path(), port); ! 2216: } else if(_access(debugger_get_ttermpro_x86_path(), 0) == 0) { ! 2217: sprintf(command, "%s localhost:%d /T=1", debugger_get_ttermpro_x86_path(), port); ! 2218: } else if(_access(debugger_get_putty_path(), 0) == 0) { ! 2219: sprintf(command, "%s -telnet localhost %d", debugger_get_putty_path(), port); ! 2220: } else if(_access(debugger_get_putty_x86_path(), 0) == 0) { ! 2221: sprintf(command, "%s -telnet localhost %d", debugger_get_putty_x86_path(), port); ! 2222: } else if(_access(debugger_get_telnet_path(), 0) == 0) { ! 2223: sprintf(command, "%s -t vt100 localhost %d", debugger_get_telnet_path(), port); ! 2224: } ! 2225: if(command[0] != '\0') { ! 2226: memset(&si, 0, sizeof(STARTUPINFOA)); ! 2227: memset(&pi, 0, sizeof(PROCESS_INFORMATION)); ! 2228: CreateProcessA(NULL, command, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi); ! 2229: } ! 2230: ! 2231: while(!m_exit) { ! 2232: if((cli_socket = accept(svr_socket, (struct sockaddr *) &cli_addr, &cli_addr_len)) != INVALID_SOCKET) { ! 2233: u_long val = 1; ! 2234: ioctlsocket(cli_socket, FIONBIO, &val); ! 2235: debugger_main(); ! 2236: } ! 2237: } ! 2238: } ! 2239: } ! 2240: WSACleanup(); ! 2241: return(0); ! 2242: } ! 2243: #endif ! 2244: ! 2245: /* ---------------------------------------------------------------------------- ! 2246: main ! 2247: ---------------------------------------------------------------------------- */ ! 2248: ! 2249: BOOL WINAPI ctrl_handler(DWORD dwCtrlType) ! 2250: { ! 2251: if(dwCtrlType == CTRL_BREAK_EVENT) { ! 2252: if(key_buf_char != NULL && key_buf_scan != NULL) { ! 2253: #ifdef USE_SERVICE_THREAD ! 2254: EnterCriticalSection(&key_buf_crit_sect); ! 2255: #endif ! 2256: pcbios_clear_key_buffer(); ! 2257: #ifdef USE_SERVICE_THREAD ! 2258: LeaveCriticalSection(&key_buf_crit_sect); ! 2259: #endif ! 2260: } ! 2261: // key_code = key_recv = 0; ! 2262: return TRUE; ! 2263: } else if(dwCtrlType == CTRL_C_EVENT) { ! 2264: return TRUE; ! 2265: } else if(dwCtrlType == CTRL_CLOSE_EVENT) { ! 2266: // this program will be terminated abnormally, do minimum end process ! 2267: exit_handler(); ! 2268: exit(1); ! 2269: } ! 2270: return FALSE; ! 2271: } ! 2272: ! 2273: void exit_handler() ! 2274: { ! 2275: if(temp_file_created) { ! 2276: DeleteFileA(temp_file_path); ! 2277: temp_file_created = false; ! 2278: } ! 2279: if(key_buf_char != NULL) { ! 2280: key_buf_char->release(); ! 2281: delete key_buf_char; ! 2282: key_buf_char = NULL; ! 2283: } ! 2284: if(key_buf_scan != NULL) { ! 2285: key_buf_scan->release(); ! 2286: delete key_buf_scan; ! 2287: key_buf_scan = NULL; ! 2288: } ! 2289: if(key_buf_data != NULL) { ! 2290: key_buf_data->release(); ! 2291: delete key_buf_data; ! 2292: key_buf_data = NULL; ! 2293: } ! 2294: #ifdef SUPPORT_XMS ! 2295: msdos_xms_release(); ! 2296: #endif ! 2297: hardware_release(); ! 2298: } ! 2299: ! 2300: #ifdef USE_VRAM_THREAD ! 2301: DWORD WINAPI vram_thread(LPVOID) ! 2302: { ! 2303: while(!m_exit) { ! 2304: EnterCriticalSection(&vram_crit_sect); ! 2305: if(vram_length_char != 0 && vram_length_char == vram_last_length_char) { ! 2306: vram_flush_char(); ! 2307: } ! 2308: if(vram_length_attr != 0 && vram_length_attr == vram_last_length_attr) { ! 2309: vram_flush_attr(); ! 2310: } ! 2311: vram_last_length_char = vram_length_char; ! 2312: vram_last_length_attr = vram_length_attr; ! 2313: LeaveCriticalSection(&vram_crit_sect); ! 2314: // this is about half the maximum keyboard repeat rate - any ! 2315: // lower tends to be jerky, any higher misses updates ! 2316: Sleep(15); ! 2317: } ! 2318: return 0; ! 2319: } ! 2320: #endif ! 2321: ! 2322: long get_section_in_exec_file(FILE *fp, const char *name) ! 2323: { ! 2324: UINT8 header[0x400]; ! 2325: ! 2326: long position = ftell(fp); ! 2327: fseek(fp, 0, SEEK_SET); ! 2328: fread(header, sizeof(header), 1, fp); ! 2329: fseek(fp, position, SEEK_SET); ! 2330: ! 2331: try { ! 2332: _IMAGE_DOS_HEADER *dosHeader = (_IMAGE_DOS_HEADER *)(header + 0); ! 2333: DWORD dwTopOfSignature = dosHeader->e_lfanew; ! 2334: DWORD dwTopOfCoffHeader = dwTopOfSignature + 4; ! 2335: _IMAGE_FILE_HEADER *coffHeader = (_IMAGE_FILE_HEADER *)(header + dwTopOfCoffHeader); ! 2336: DWORD dwTopOfOptionalHeader = dwTopOfCoffHeader + sizeof(_IMAGE_FILE_HEADER); ! 2337: DWORD dwTopOfFirstSectionHeader = dwTopOfOptionalHeader + coffHeader->SizeOfOptionalHeader; ! 2338: ! 2339: for(int i = 0; i < coffHeader->NumberOfSections; i++) { ! 2340: _IMAGE_SECTION_HEADER *sectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * i); ! 2341: if(memcmp(sectionHeader->Name, name, strlen(name)) == 0) { ! 2342: return(sectionHeader->PointerToRawData); ! 2343: } ! 2344: } ! 2345: } catch(...) { ! 2346: } ! 2347: return(0); ! 2348: } ! 2349: ! 2350: bool is_started_from_command_prompt() ! 2351: { ! 2352: bool result = false; ! 2353: HMODULE hLibrary = LoadLibraryA("Kernel32.dll"); ! 2354: ! 2355: if(hLibrary) { ! 2356: typedef DWORD (WINAPI *GetConsoleProcessListFunction)(__out LPDWORD lpdwProcessList, __in DWORD dwProcessCount); ! 2357: GetConsoleProcessListFunction lpfnGetConsoleProcessList; ! 2358: lpfnGetConsoleProcessList = reinterpret_cast<GetConsoleProcessListFunction>(::GetProcAddress(hLibrary, "GetConsoleProcessList")); ! 2359: if(lpfnGetConsoleProcessList) { // Windows XP or later ! 2360: DWORD pl; ! 2361: result = (lpfnGetConsoleProcessList(&pl, 1) > 1); ! 2362: FreeLibrary(hLibrary); ! 2363: return(result); ! 2364: } ! 2365: FreeLibrary(hLibrary); ! 2366: } ! 2367: ! 2368: HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); ! 2369: if(hSnapshot != INVALID_HANDLE_VALUE) { ! 2370: DWORD dwParentProcessID = 0; ! 2371: PROCESSENTRY32 pe32; ! 2372: pe32.dwSize = sizeof(PROCESSENTRY32); ! 2373: if(Process32First(hSnapshot, &pe32)) { ! 2374: do { ! 2375: if(pe32.th32ProcessID == GetCurrentProcessId()) { ! 2376: dwParentProcessID = pe32.th32ParentProcessID; ! 2377: break; ! 2378: } ! 2379: } while(Process32Next(hSnapshot, &pe32)); ! 2380: } ! 2381: CloseHandle(hSnapshot); ! 2382: if(dwParentProcessID != 0) { ! 2383: HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwParentProcessID); ! 2384: if(hProcess != NULL) { ! 2385: HMODULE hMod; ! 2386: DWORD cbNeeded; ! 2387: if(EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) { ! 2388: char module_name[MAX_PATH]; ! 2389: if(GetModuleBaseNameA(hProcess, hMod, module_name, sizeof(module_name))) { ! 2390: result = (_strnicmp(module_name, "cmd.exe", 7) == 0); ! 2391: } ! 2392: } ! 2393: CloseHandle(hProcess); ! 2394: } ! 2395: } ! 2396: } ! 2397: return(result); ! 2398: } ! 2399: ! 2400: BOOL is_greater_windows_version(DWORD dwMajorVersion, DWORD dwMinorVersion, WORD wServicePackMajor, WORD wServicePackMinor) ! 2401: { ! 2402: HMODULE hLibrary = LoadLibraryA("Kernel32.dll"); ! 2403: ! 2404: if(hLibrary) { ! 2405: typedef ULONGLONG (WINAPI* VerSetConditionMaskFunction)(ULONGLONG, DWORD, BYTE); ! 2406: typedef BOOL(WINAPI* VerifyVersionInfoFunction)(LPOSVERSIONINFOEXA, DWORD, DWORDLONG); ! 2407: ! 2408: VerSetConditionMaskFunction lpfnVerSetConditionMask = reinterpret_cast<VerSetConditionMaskFunction>(::GetProcAddress(hLibrary, "VerSetConditionMask")); ! 2409: VerifyVersionInfoFunction lpfnVerifyVersionInfo = reinterpret_cast<VerifyVersionInfoFunction>(::GetProcAddress(hLibrary, "VerifyVersionInfoA")); ! 2410: ! 2411: if(lpfnVerSetConditionMask && lpfnVerifyVersionInfo) { // Windows 2000 or later ! 2412: // https://msdn.microsoft.com/en-us/library/windows/desktop/ms725491(v=vs.85).aspx ! 2413: OSVERSIONINFOEXA osvi; ! 2414: DWORDLONG dwlConditionMask = 0; ! 2415: int op = VER_GREATER_EQUAL; ! 2416: ! 2417: // Initialize the OSVERSIONINFOEXA structure. ! 2418: ZeroMemory(&osvi, sizeof(OSVERSIONINFOEXA)); ! 2419: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXA); ! 2420: osvi.dwMajorVersion = dwMajorVersion; ! 2421: osvi.dwMinorVersion = dwMinorVersion; ! 2422: osvi.wServicePackMajor = wServicePackMajor; ! 2423: osvi.wServicePackMinor = wServicePackMinor; ! 2424: ! 2425: // Initialize the condition mask. ! 2426: #define MY_VER_SET_CONDITION(_m_,_t_,_c_) ((_m_)=lpfnVerSetConditionMask((_m_),(_t_),(_c_))) ! 2427: ! 2428: MY_VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, op ); ! 2429: MY_VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, op ); ! 2430: MY_VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, op ); ! 2431: MY_VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMINOR, op ); ! 2432: ! 2433: // Perform the test. ! 2434: BOOL result = lpfnVerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, dwlConditionMask); ! 2435: FreeLibrary(hLibrary); ! 2436: return(result); ! 2437: } ! 2438: FreeLibrary(hLibrary); ! 2439: } ! 2440: ! 2441: OSVERSIONINFOA osvi; ! 2442: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); ! 2443: ! 2444: if(GetVersionExA((LPOSVERSIONINFOA)&osvi)) { ! 2445: if(osvi.dwPlatformId != VER_PLATFORM_WIN32_NT) { ! 2446: return(false); ! 2447: } else if(osvi.dwMajorVersion > dwMajorVersion) { ! 2448: return(true); ! 2449: } else if(osvi.dwMajorVersion < dwMajorVersion) { ! 2450: return(false); ! 2451: } else if(osvi.dwMinorVersion > dwMinorVersion) { ! 2452: return(true); ! 2453: } else if(osvi.dwMinorVersion < dwMinorVersion) { ! 2454: return(false); ! 2455: } ! 2456: // FIXME: check wServicePackMajor and wServicePackMinor :-( ! 2457: return(true); ! 2458: } ! 2459: return(false); ! 2460: } ! 2461: ! 2462: HWND get_console_window_handle() ! 2463: { ! 2464: static HWND hwndFound = 0; ! 2465: ! 2466: if(hwndFound == 0) { ! 2467: // https://support.microsoft.com/en-us/help/124103/how-to-obtain-a-console-window-handle-hwnd ! 2468: char pszNewWindowTitle[1024]; ! 2469: char pszOldWindowTitle[1024]; ! 2470: ! 2471: GetConsoleTitleA(pszOldWindowTitle, 1024); ! 2472: wsprintfA(pszNewWindowTitle, "%d/%d", GetTickCount(), GetCurrentProcessId()); ! 2473: SetConsoleTitleA(pszNewWindowTitle); ! 2474: Sleep(100); ! 2475: hwndFound = FindWindowA(NULL, pszNewWindowTitle); ! 2476: SetConsoleTitleA(pszOldWindowTitle); ! 2477: } ! 2478: return hwndFound; ! 2479: } ! 2480: ! 2481: HDC get_console_window_device_context() ! 2482: { ! 2483: return GetDC(get_console_window_handle()); ! 2484: } ! 2485: ! 2486: bool get_console_font_size(int *width, int *height) ! 2487: { ! 2488: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); ! 2489: bool result = false; ! 2490: ! 2491: if(is_winxp_or_later) { ! 2492: HMODULE hLibrary = LoadLibraryA("Kernel32.dll"); ! 2493: if(hLibrary) { ! 2494: typedef BOOL (WINAPI* GetCurrentConsoleFontFunction)(HANDLE, BOOL, PCONSOLE_FONT_INFO); ! 2495: GetCurrentConsoleFontFunction lpfnGetCurrentConsoleFont = reinterpret_cast<GetCurrentConsoleFontFunction>(::GetProcAddress(hLibrary, "GetCurrentConsoleFont")); ! 2496: if(lpfnGetCurrentConsoleFont) { // Windows XP or later ! 2497: CONSOLE_FONT_INFO fi; ! 2498: if(lpfnGetCurrentConsoleFont(hStdout, FALSE, &fi) != 0) { ! 2499: *width = fi.dwFontSize.X; ! 2500: *height = fi.dwFontSize.Y; ! 2501: result = true; ! 2502: } ! 2503: } ! 2504: FreeLibrary(hLibrary); ! 2505: } ! 2506: } else { ! 2507: CONSOLE_SCREEN_BUFFER_INFO csbi; ! 2508: RECT rect; ! 2509: if(GetConsoleScreenBufferInfo(hStdout, &csbi) && GetClientRect(get_console_window_handle(), &rect)) { ! 2510: int cols = csbi.srWindow.Right - csbi.srWindow.Left + 1; ! 2511: int rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; ! 2512: *width = rect.right / cols; ! 2513: *height = rect.bottom / rows; ! 2514: result = true; ! 2515: } ! 2516: } ! 2517: return(result); ! 2518: } ! 2519: ! 2520: bool set_console_font_size(int width, int height) ! 2521: { ! 2522: // http://d.hatena.ne.jp/aharisu/20090427/1240852598 ! 2523: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); ! 2524: bool result = false; ! 2525: HMODULE hLibrary = LoadLibraryA("Kernel32.dll"); ! 2526: ! 2527: if(hLibrary) { ! 2528: CONSOLE_SCREEN_BUFFER_INFO csbi; ! 2529: RECT rect; ! 2530: GetConsoleScreenBufferInfo(hStdout, &csbi); ! 2531: int cols = csbi.srWindow.Right - csbi.srWindow.Left + 1; ! 2532: int rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; ! 2533: ! 2534: typedef BOOL (WINAPI* GetConsoleFontInfoFunction)(HANDLE, BOOL, DWORD, PCONSOLE_FONT_INFO); ! 2535: typedef DWORD (WINAPI* GetNumberOfConsoleFontsFunction)(VOID); ! 2536: typedef COORD (WINAPI* GetConsoleFontSizeFunction)(HANDLE, DWORD); ! 2537: typedef BOOL (WINAPI* SetConsoleFontFunction)(HANDLE, DWORD); ! 2538: typedef BOOL (WINAPI* GetCurrentConsoleFontFunction)(HANDLE, BOOL, PCONSOLE_FONT_INFO); ! 2539: typedef BOOL (WINAPI* GetCurrentConsoleFontExFunction)(HANDLE, BOOL, PCONSOLE_FONT_INFOEX); ! 2540: typedef BOOL (WINAPI* SetCurrentConsoleFontExFunction)(HANDLE, BOOL, PCONSOLE_FONT_INFOEX); ! 2541: ! 2542: GetConsoleFontInfoFunction lpfnGetConsoleFontInfo = reinterpret_cast<GetConsoleFontInfoFunction>(::GetProcAddress(hLibrary, "GetConsoleFontInfo")); ! 2543: GetNumberOfConsoleFontsFunction lpfnGetNumberOfConsoleFonts = reinterpret_cast<GetNumberOfConsoleFontsFunction>(::GetProcAddress(hLibrary, "GetNumberOfConsoleFonts")); ! 2544: GetConsoleFontSizeFunction lpfnGetConsoleFontSize = reinterpret_cast<GetConsoleFontSizeFunction>(::GetProcAddress(hLibrary, "GetConsoleFontSize")); ! 2545: SetConsoleFontFunction lpfnSetConsoleFont = reinterpret_cast<SetConsoleFontFunction>(::GetProcAddress(hLibrary, "SetConsoleFont")); ! 2546: GetCurrentConsoleFontFunction lpfnGetCurrentConsoleFont = reinterpret_cast<GetCurrentConsoleFontFunction>(::GetProcAddress(hLibrary, "GetCurrentConsoleFont")); ! 2547: GetCurrentConsoleFontExFunction lpfnGetCurrentConsoleFontEx = reinterpret_cast<GetCurrentConsoleFontExFunction>(::GetProcAddress(hLibrary, "GetCurrentConsoleFontEx")); ! 2548: SetCurrentConsoleFontExFunction lpfnSetCurrentConsoleFontEx = reinterpret_cast<SetCurrentConsoleFontExFunction>(::GetProcAddress(hLibrary, "SetCurrentConsoleFontEx")); ! 2549: ! 2550: if(lpfnGetConsoleFontInfo && lpfnGetNumberOfConsoleFonts && lpfnSetConsoleFont) { // Windows 2000 or later ! 2551: DWORD dwFontNum = lpfnGetNumberOfConsoleFonts(); ! 2552: if(dwFontNum) { ! 2553: CONSOLE_FONT_INFO* fonts = (CONSOLE_FONT_INFO*)malloc(sizeof(CONSOLE_FONT_INFO) * dwFontNum); ! 2554: lpfnGetConsoleFontInfo(hStdout, FALSE, dwFontNum, fonts); ! 2555: for(int i = 0; i < dwFontNum; i++) { ! 2556: fonts[i].dwFontSize = lpfnGetConsoleFontSize(hStdout, fonts[i].nFont); ! 2557: if(fonts[i].dwFontSize.X == width && fonts[i].dwFontSize.Y == height) { ! 2558: if(lpfnSetConsoleFont(hStdout, fonts[i].nFont)) { ! 2559: if(is_winxp_or_later && lpfnGetCurrentConsoleFont) { // Windows XP or later ! 2560: CONSOLE_FONT_INFO fi; ! 2561: if(lpfnGetCurrentConsoleFont(hStdout, FALSE, &fi)) { ! 2562: if(fonts[i].dwFontSize.X == fi.dwFontSize.X && fonts[i].dwFontSize.Y == fi.dwFontSize.Y) { ! 2563: result = true; ! 2564: break; ! 2565: } ! 2566: } ! 2567: } else { ! 2568: Sleep(10); ! 2569: if(GetClientRect(get_console_window_handle(), &rect)) { ! 2570: if(fonts[i].dwFontSize.X * cols == rect.right && fonts[i].dwFontSize.Y * rows == rect.bottom) { ! 2571: result = true; ! 2572: break; ! 2573: } ! 2574: } ! 2575: } ! 2576: } ! 2577: } ! 2578: } ! 2579: free(fonts); ! 2580: } else if(lpfnGetCurrentConsoleFontEx && lpfnSetCurrentConsoleFontEx) { ! 2581: // for Windows10 enhanced command prompt ! 2582: CONSOLE_FONT_INFOEX fi_old, fi_new; ! 2583: fi_old.cbSize = sizeof(CONSOLE_FONT_INFOEX); ! 2584: if(lpfnGetCurrentConsoleFontEx(hStdout, FALSE, &fi_old)) { ! 2585: fi_new = fi_old; ! 2586: fi_new.dwFontSize.X = width; ! 2587: fi_new.dwFontSize.Y = height; ! 2588: if(lpfnSetCurrentConsoleFontEx(hStdout, FALSE, &fi_new)) { ! 2589: lpfnGetCurrentConsoleFontEx(hStdout, FALSE, &fi_new); ! 2590: if(fi_new.dwFontSize.X == width && fi_new.dwFontSize.Y == height) { ! 2591: result = true; ! 2592: } else { ! 2593: lpfnSetCurrentConsoleFontEx(hStdout, FALSE, &fi_old); ! 2594: } ! 2595: } ! 2596: } ! 2597: } ! 2598: } ! 2599: FreeLibrary(hLibrary); ! 2600: } ! 2601: return(result); ! 2602: } ! 2603: ! 2604: bool is_cursor_blink_off() ! 2605: { ! 2606: static int result = -1; ! 2607: HKEY hKey; ! 2608: char chData[64]; ! 2609: DWORD dwSize = sizeof(chData); ! 2610: ! 2611: if(result == -1) { ! 2612: result = 0; ! 2613: if(RegOpenKeyExA(HKEY_CURRENT_USER, "Control Panel\\Desktop", 0, KEY_READ, &hKey) == ERROR_SUCCESS) { ! 2614: if(RegQueryValueExA(hKey, "CursorBlinkRate", NULL, NULL, (LPBYTE)chData, &dwSize) == ERROR_SUCCESS) { ! 2615: if(strncmp(chData, "-1", 2) == 0) { ! 2616: result = 1; ! 2617: } ! 2618: } ! 2619: RegCloseKey(hKey); ! 2620: } ! 2621: } ! 2622: return(result != 0); ! 2623: } ! 2624: ! 2625: void get_sio_port_numbers() ! 2626: { ! 2627: SP_DEVINFO_DATA DeviceInfoData = {sizeof(SP_DEVINFO_DATA)}; ! 2628: HDEVINFO hDevInfo = 0; ! 2629: HKEY hKey = 0; ! 2630: if((hDevInfo = SetupDiGetClassDevsA(&GUID_DEVINTERFACE_COMPORT, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE))) != 0) { ! 2631: for(int i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData); i++) { ! 2632: if((hKey = SetupDiOpenDevRegKey(hDevInfo, &DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE)) != INVALID_HANDLE_VALUE) { ! 2633: char chData[256]; ! 2634: DWORD dwType = 0; ! 2635: DWORD dwSize = sizeof(chData); ! 2636: int port_number = 0; ! 2637: ! 2638: if(RegQueryValueExA(hKey, "PortName", NULL, &dwType, (BYTE *)chData, &dwSize) == ERROR_SUCCESS) { ! 2639: if(_strnicmp(chData, "COM", 3) == 0) { ! 2640: port_number = atoi(chData + 3); ! 2641: } ! 2642: } ! 2643: RegCloseKey(hKey); ! 2644: ! 2645: if(sio_port_number[0] == port_number || sio_port_number[1] == port_number || sio_port_number[2] == port_number || sio_port_number[3] == port_number) { ! 2646: continue; ! 2647: } ! 2648: if(sio_port_number[0] == 0) { ! 2649: sio_port_number[0] = port_number; ! 2650: } else if(sio_port_number[1] == 0) { ! 2651: sio_port_number[1] = port_number; ! 2652: } else if(sio_port_number[2] == 0) { ! 2653: sio_port_number[2] = port_number; ! 2654: } else if(sio_port_number[3] == 0) { ! 2655: sio_port_number[3] = port_number; ! 2656: } ! 2657: if(sio_port_number[0] != 0 && sio_port_number[1] != 0 && sio_port_number[2] != 0 && sio_port_number[3] != 0) { ! 2658: break; ! 2659: } ! 2660: } ! 2661: } ! 2662: } ! 2663: } ! 2664: ! 2665: #define IS_NUMERIC(c) ((c) >= '0' && (c) <= '9') ! 2666: ! 2667: int main(int argc, char *argv[], char *envp[]) ! 2668: { ! 2669: int arg_offset = 0; ! 2670: int standard_env = 0; ! 2671: int buf_width = 0, buf_height = 0; ! 2672: bool get_console_info_success = false; ! 2673: bool get_console_font_success = false; ! 2674: bool screen_size_changed = false; ! 2675: ! 2676: char path[MAX_PATH], full[MAX_PATH], *name = NULL; ! 2677: GetModuleFileNameA(NULL, path, MAX_PATH); ! 2678: GetFullPathNameA(path, MAX_PATH, full, &name); ! 2679: ! 2680: char dummy_argv_0[] = "msdos.exe"; ! 2681: char dummy_argv_1[MAX_PATH]; ! 2682: char *dummy_argv[256] = {dummy_argv_0, dummy_argv_1, 0}; ! 2683: char new_exec_file[MAX_PATH]; ! 2684: bool convert_cmd_file = false; ! 2685: unsigned int code_page = 0; ! 2686: ! 2687: if(name != NULL && stricmp(name, "msdos.exe") != 0) { ! 2688: // check if command file is embedded to this execution file ! 2689: // if this execution file name is msdos.exe, don't check ! 2690: FILE* fp = fopen(full, "rb"); ! 2691: long offset = get_section_in_exec_file(fp, ".msdos"); ! 2692: if(offset != 0) { ! 2693: UINT8 buffer[16]; ! 2694: fseek(fp, offset, SEEK_SET); ! 2695: fread(buffer, sizeof(buffer), 1, fp); ! 2696: ! 2697: // restore flags ! 2698: stay_busy = ((buffer[0] & 0x01) != 0); ! 2699: no_windows = ((buffer[0] & 0x02) != 0); ! 2700: standard_env = ((buffer[0] & 0x04) != 0); ! 2701: ignore_illegal_insn = ((buffer[0] & 0x08) != 0); ! 2702: limit_max_memory = ((buffer[0] & 0x10) != 0); ! 2703: if((buffer[0] & 0x20) != 0) { ! 2704: get_sio_port_numbers(); ! 2705: } ! 2706: if((buffer[0] & 0x40) != 0) { ! 2707: UMB_TOP = EMS_TOP + EMS_SIZE; ! 2708: support_ems = true; ! 2709: } ! 2710: #ifdef SUPPORT_XMS ! 2711: if((buffer[0] & 0x80) != 0) { ! 2712: support_xms = true; ! 2713: } ! 2714: #endif ! 2715: if((buffer[1] != 0 || buffer[2] != 0) && (buffer[3] != 0 || buffer[4] != 0)) { ! 2716: buf_width = buffer[1] | (buffer[2] << 8); ! 2717: buf_height = buffer[3] | (buffer[4] << 8); ! 2718: } ! 2719: if(buffer[5] != 0) { ! 2720: dos_major_version = buffer[5]; ! 2721: dos_minor_version = buffer[6]; ! 2722: } ! 2723: if(buffer[7] != 0) { ! 2724: win_major_version = buffer[7]; ! 2725: win_minor_version = buffer[8]; ! 2726: } ! 2727: if((code_page = buffer[9] | (buffer[10] << 8)) != 0) { ! 2728: SetConsoleCP(code_page); ! 2729: SetConsoleOutputCP(code_page); ! 2730: } ! 2731: int name_len = buffer[11]; ! 2732: int file_len = buffer[12] | (buffer[13] << 8) | (buffer[14] << 16) | (buffer[15] << 24); ! 2733: ! 2734: // restore command file name ! 2735: memset(dummy_argv_1, 0, sizeof(dummy_argv_1)); ! 2736: fread(dummy_argv_1, name_len, 1, fp); ! 2737: ! 2738: if(name_len != 0 && _access(dummy_argv_1, 0) == 0) { ! 2739: // if original command file exists, create a temporary file name ! 2740: if(GetTempFileNameA(".", "DOS", 0, dummy_argv_1) != 0) { ! 2741: // create a temporary command file in the current director ! 2742: DeleteFileA(dummy_argv_1); ! 2743: } else { ! 2744: // create a temporary command file in the temporary folder ! 2745: GetTempPathA(MAX_PATH, path); ! 2746: if(GetTempFileNameA(path, "DOS", 0, dummy_argv_1) != 0) { ! 2747: DeleteFileA(dummy_argv_1); ! 2748: } else { ! 2749: sprintf(dummy_argv_1, "%s$DOSPRG$.TMP", path); ! 2750: } ! 2751: } ! 2752: // check the command file type ! 2753: fread(buffer, 2, 1, fp); ! 2754: fseek(fp, -2, SEEK_CUR); ! 2755: if(memcmp(buffer, "MZ", 2) != 0) { ! 2756: memcpy(dummy_argv_1 + strlen(dummy_argv_1) - 4, ".COM", 4); ! 2757: } else { ! 2758: memcpy(dummy_argv_1 + strlen(dummy_argv_1) - 4, ".EXE", 4); ! 2759: } ! 2760: } ! 2761: ! 2762: // restore command file ! 2763: FILE* fo = fopen(dummy_argv_1, "wb"); ! 2764: for(int i = 0; i < file_len; i++) { ! 2765: fputc(fgetc(fp), fo); ! 2766: } ! 2767: fclose(fo); ! 2768: ! 2769: GetFullPathNameA(dummy_argv_1, MAX_PATH, temp_file_path, NULL); ! 2770: temp_file_created = true; ! 2771: SetFileAttributesA(temp_file_path, FILE_ATTRIBUTE_HIDDEN); ! 2772: ! 2773: // adjust argc/argv ! 2774: for(int i = 1; i < argc && (i + 1) < 256; i++) { ! 2775: dummy_argv[i + 1] = argv[i]; ! 2776: } ! 2777: argc++; ! 2778: argv = dummy_argv; ! 2779: } ! 2780: fclose(fp); ! 2781: } ! 2782: for(int i = 1; i < argc; i++) { ! 2783: if(_strnicmp(argv[i], "-b", 2) == 0) { ! 2784: stay_busy = true; ! 2785: arg_offset++; ! 2786: } else if(_strnicmp(argv[i], "-c", 2) == 0) { ! 2787: if(argv[i][2] != '\0') { ! 2788: strcpy(new_exec_file, &argv[i][2]); ! 2789: } else { ! 2790: strcpy(new_exec_file, "new_exec_file.exe"); ! 2791: } ! 2792: convert_cmd_file = true; ! 2793: arg_offset++; ! 2794: } else if(_strnicmp(argv[i], "-p", 2) == 0) { ! 2795: if(IS_NUMERIC(argv[i][2])) { ! 2796: code_page = atoi(&argv[i][2]); ! 2797: } else { ! 2798: code_page = GetConsoleCP(); ! 2799: } ! 2800: arg_offset++; ! 2801: } else if(_strnicmp(argv[i], "-d", 2) == 0) { ! 2802: no_windows = true; ! 2803: arg_offset++; ! 2804: } else if(_strnicmp(argv[i], "-e", 2) == 0) { ! 2805: standard_env = 1; ! 2806: arg_offset++; ! 2807: } else if(_strnicmp(argv[i], "-i", 2) == 0) { ! 2808: ignore_illegal_insn = true; ! 2809: arg_offset++; ! 2810: } else if(_strnicmp(argv[i], "-m", 2) == 0) { ! 2811: limit_max_memory = true; ! 2812: arg_offset++; ! 2813: } else if(_strnicmp(argv[i], "-n", 2) == 0) { ! 2814: int result = sscanf(argv[i] + 2, "%d,%d", &buf_height, &buf_width); ! 2815: if(result == 1) { ! 2816: buf_width = 0; ! 2817: } else if(result != 2) { ! 2818: buf_width = buf_height = 0; ! 2819: } ! 2820: if(buf_width <= 0 || buf_width > 0x7fff) { ! 2821: buf_width = 80; ! 2822: } ! 2823: if(buf_height <= 0 || buf_height > 0x7fff) { ! 2824: buf_height = 25; ! 2825: } ! 2826: arg_offset++; ! 2827: } else if(_strnicmp(argv[i], "-s", 2) == 0) { ! 2828: if(IS_NUMERIC(argv[i][2])) { ! 2829: char *p0 = &argv[i][2], *p1, *p2, *p3; ! 2830: if((p1 = strchr(p0, ',')) != NULL && IS_NUMERIC(p1[1])) { ! 2831: sio_port_number[1] = atoi(p1 + 1); ! 2832: if((p2 = strchr(p1, ',')) != NULL && IS_NUMERIC(p2[1])) { ! 2833: sio_port_number[2] = atoi(p2 + 1); ! 2834: if((p3 = strchr(p2, ',')) != NULL && IS_NUMERIC(p3[1])) { ! 2835: sio_port_number[3] = atoi(p3 + 1); ! 2836: } ! 2837: } ! 2838: } ! 2839: sio_port_number[0] = atoi(p0); ! 2840: } ! 2841: if(sio_port_number[0] == 0 || sio_port_number[1] == 0 || sio_port_number[2] == 0 || sio_port_number[3] == 0) { ! 2842: get_sio_port_numbers(); ! 2843: } ! 2844: arg_offset++; ! 2845: } else if(_strnicmp(argv[i], "-v", 2) == 0) { ! 2846: if(strlen(argv[i]) >= 5 && IS_NUMERIC(argv[i][2]) && argv[i][3] == '.' && IS_NUMERIC(argv[i][4]) && (argv[i][5] == '\0' || IS_NUMERIC(argv[i][5]))) { ! 2847: dos_major_version = argv[i][2] - '0'; ! 2848: dos_minor_version = (argv[i][4] - '0') * 10 + (argv[i][5] ? (argv[i][5] - '0') : 0); ! 2849: } ! 2850: arg_offset++; ! 2851: } else if(_strnicmp(argv[i], "-w", 2) == 0) { ! 2852: if(strlen(argv[i]) >= 5 && IS_NUMERIC(argv[i][2]) && argv[i][3] == '.' && IS_NUMERIC(argv[i][4]) && (argv[i][5] == '\0' || IS_NUMERIC(argv[i][5]))) { ! 2853: win_major_version = argv[i][2] - '0'; ! 2854: win_minor_version = (argv[i][4] - '0') * 10 + (argv[i][5] ? (argv[i][5] - '0') : 0); ! 2855: } ! 2856: arg_offset++; ! 2857: } else if(_strnicmp(argv[i], "-x", 2) == 0) { ! 2858: UMB_TOP = EMS_TOP + EMS_SIZE; ! 2859: support_ems = true; ! 2860: #ifdef SUPPORT_XMS ! 2861: support_xms = true; ! 2862: #endif ! 2863: arg_offset++; ! 2864: } else { ! 2865: break; ! 2866: } ! 2867: } ! 2868: if(argc < 2 + arg_offset) { ! 2869: #ifdef _WIN64 ! 2870: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32-x64 console\n\n"); ! 2871: #else ! 2872: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32 console\n\n"); ! 2873: #endif ! 2874: fprintf(stderr, ! 2875: "Usage: MSDOS [-b] [-c[(new exec file)] [-p[P]]] [-d] [-e] [-i] [-m] [-n[L[,C]]]\n" ! 2876: " [-s[P1[,P2[,P3[,P4]]]]] [-vX.XX] [-wX.XX] [-x] (command) [options]\n" ! 2877: "\n" ! 2878: "\t-b\tstay busy during keyboard polling\n" ! 2879: #ifdef _WIN64 ! 2880: "\t-c\tconvert command file to 64bit execution file\n" ! 2881: #else ! 2882: "\t-c\tconvert command file to 32bit execution file\n" ! 2883: #endif ! 2884: "\t-p\trecord current code page when convert command file\n" ! 2885: "\t-d\tpretend running under straight DOS, not Windows\n" ! 2886: "\t-e\tuse a reduced environment block\n" ! 2887: "\t-i\tignore invalid instructions\n" ! 2888: "\t-m\trestrict free memory to 0x7FFF paragraphs\n" ! 2889: "\t-n\tcreate a new buffer (25 lines, 80 columns by default)\n" ! 2890: "\t-s\tenable serial I/O and set host's COM port numbers\n" ! 2891: "\t-v\tset the DOS version\n" ! 2892: "\t-w\tset the Windows version\n" ! 2893: #if defined(SUPPORT_VCPI) ! 2894: "\t-x\tenable LIM EMS, VCPI, and XMS\n" ! 2895: #elif defined(SUPPORT_XMS) ! 2896: "\t-x\tenable LIM EMS and XMS\n" ! 2897: #else ! 2898: "\t-x\tenable LIM EMS\n" ! 2899: #endif ! 2900: ); ! 2901: ! 2902: if(!is_started_from_command_prompt()) { ! 2903: fprintf(stderr, "\nStart this program from a command prompt!\n\nHit any key to quit..."); ! 2904: while(!_kbhit()) { ! 2905: Sleep(10); ! 2906: } ! 2907: } ! 2908: #ifdef _DEBUG ! 2909: _CrtDumpMemoryLeaks(); ! 2910: #endif ! 2911: return(EXIT_FAILURE); ! 2912: } ! 2913: if(convert_cmd_file) { ! 2914: retval = EXIT_FAILURE; ! 2915: if(name != NULL/* && stricmp(name, "msdos.exe") == 0*/) { ! 2916: FILE *fp = NULL, *fs = NULL, *fo = NULL; ! 2917: int len = strlen(argv[arg_offset + 1]), data; ! 2918: ! 2919: if(!(len > 4 && (stricmp(argv[arg_offset + 1] + len - 4, ".COM") == 0 || stricmp(argv[arg_offset + 1] + len - 4, ".EXE") == 0))) { ! 2920: fprintf(stderr, "Specify command file with extenstion (.COM or .EXE)\n"); ! 2921: } else if((fp = fopen(full, "rb")) == NULL) { ! 2922: fprintf(stderr, "Can't open '%s'\n", name); ! 2923: } else { ! 2924: long offset = get_section_in_exec_file(fp, ".msdos"); ! 2925: if(offset != 0) { ! 2926: UINT8 buffer[14]; ! 2927: fseek(fp, offset, SEEK_SET); ! 2928: fread(buffer, sizeof(buffer), 1, fp); ! 2929: memset(path, 0, sizeof(path)); ! 2930: fread(path, buffer[9], 1, fp); ! 2931: fprintf(stderr, "Command file '%s' was already embedded to '%s'\n", path, name); ! 2932: } else if((fs = fopen(argv[arg_offset + 1], "rb")) == NULL) { ! 2933: fprintf(stderr, "Can't open '%s'\n", argv[arg_offset + 1]); ! 2934: } else if((fo = fopen(new_exec_file, "wb")) == NULL) { ! 2935: fprintf(stderr, "Can't open '%s'\n", new_exec_file); ! 2936: } else { ! 2937: // read pe header of msdos.exe ! 2938: UINT8 header[0x400]; ! 2939: fseek(fp, 0, SEEK_SET); ! 2940: fread(header, sizeof(header), 1, fp); ! 2941: ! 2942: _IMAGE_DOS_HEADER *dosHeader = (_IMAGE_DOS_HEADER *)(header + 0); ! 2943: DWORD dwTopOfSignature = dosHeader->e_lfanew; ! 2944: DWORD dwTopOfCoffHeader = dwTopOfSignature + 4; ! 2945: _IMAGE_FILE_HEADER *coffHeader = (_IMAGE_FILE_HEADER *)(header + dwTopOfCoffHeader); ! 2946: DWORD dwTopOfOptionalHeader = dwTopOfCoffHeader + sizeof(_IMAGE_FILE_HEADER); ! 2947: _IMAGE_OPTIONAL_HEADER *optionalHeader = (_IMAGE_OPTIONAL_HEADER *)(header + dwTopOfOptionalHeader); ! 2948: DWORD dwTopOfFirstSectionHeader = dwTopOfOptionalHeader + coffHeader->SizeOfOptionalHeader; ! 2949: ! 2950: _IMAGE_SECTION_HEADER *lastSectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * (coffHeader->NumberOfSections - 1)); ! 2951: DWORD dwEndOfFile = lastSectionHeader->PointerToRawData + lastSectionHeader->SizeOfRawData; ! 2952: DWORD dwLastSectionSize = lastSectionHeader->SizeOfRawData; ! 2953: DWORD dwExtraLastSectionBytes = dwLastSectionSize % optionalHeader->SectionAlignment; ! 2954: if(dwExtraLastSectionBytes != 0) { ! 2955: DWORD dwRemain = optionalHeader->SectionAlignment - dwExtraLastSectionBytes; ! 2956: dwLastSectionSize += dwRemain; ! 2957: } ! 2958: DWORD dwVirtualAddress = lastSectionHeader->VirtualAddress + dwLastSectionSize; ! 2959: ! 2960: // store msdos.exe ! 2961: fseek(fp, 0, SEEK_SET); ! 2962: for(int i = 0; i < dwEndOfFile; i++) { ! 2963: if((data = fgetc(fp)) != EOF) { ! 2964: fputc(data, fo); ! 2965: } else { ! 2966: // we should not reach here :-( ! 2967: fputc(0, fo); ! 2968: } ! 2969: } ! 2970: ! 2971: // store options ! 2972: UINT8 flags = 0; ! 2973: if(stay_busy) { ! 2974: flags |= 0x01; ! 2975: } ! 2976: if(no_windows) { ! 2977: flags |= 0x02; ! 2978: } ! 2979: if(standard_env) { ! 2980: flags |= 0x04; ! 2981: } ! 2982: if(ignore_illegal_insn) { ! 2983: flags |= 0x08; ! 2984: } ! 2985: if(limit_max_memory) { ! 2986: flags |= 0x10; ! 2987: } ! 2988: if(sio_port_number[0] != 0 || sio_port_number[1] != 0 || sio_port_number[2] != 0 || sio_port_number[3] != 0) { ! 2989: flags |= 0x20; ! 2990: } ! 2991: if(support_ems) { ! 2992: flags |= 0x40; ! 2993: } ! 2994: #ifdef SUPPORT_XMS ! 2995: if(support_xms) { ! 2996: flags |= 0x80; ! 2997: } ! 2998: #endif ! 2999: ! 3000: fputc(flags, fo); ! 3001: fputc((buf_width >> 0) & 0xff, fo); ! 3002: fputc((buf_width >> 8) & 0xff, fo); ! 3003: fputc((buf_height >> 0) & 0xff, fo); ! 3004: fputc((buf_height >> 8) & 0xff, fo); ! 3005: fputc(dos_major_version, fo); ! 3006: fputc(dos_minor_version, fo); ! 3007: fputc(win_major_version, fo); ! 3008: fputc(win_minor_version, fo); ! 3009: fputc((code_page >> 0) & 0xff, fo); ! 3010: fputc((code_page >> 8) & 0xff, fo); ! 3011: ! 3012: // store command file info ! 3013: GetFullPathNameA(argv[arg_offset + 1], MAX_PATH, full, &name); ! 3014: int name_len = strlen(name); ! 3015: fseek(fs, 0, SEEK_END); ! 3016: long file_size = ftell(fs); ! 3017: ! 3018: fputc(name_len, fo); ! 3019: fputc((file_size >> 0) & 0xff, fo); ! 3020: fputc((file_size >> 8) & 0xff, fo); ! 3021: fputc((file_size >> 16) & 0xff, fo); ! 3022: fputc((file_size >> 24) & 0xff, fo); ! 3023: fwrite(name, name_len, 1, fo); ! 3024: ! 3025: // store command file ! 3026: fseek(fs, 0, SEEK_SET); ! 3027: for(int i = 0; i < file_size; i++) { ! 3028: if((data = fgetc(fs)) != EOF) { ! 3029: fputc(data, fo); ! 3030: } else { ! 3031: // we should not reach here :-( ! 3032: fputc(0, fo); ! 3033: } ! 3034: } ! 3035: ! 3036: // store padding data and update pe header ! 3037: _IMAGE_SECTION_HEADER *newSectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * coffHeader->NumberOfSections); ! 3038: coffHeader->NumberOfSections++; ! 3039: memset(newSectionHeader, 0, IMAGE_SIZEOF_SECTION_HEADER); ! 3040: memcpy(newSectionHeader->Name, ".msdos", 6); ! 3041: newSectionHeader->VirtualAddress = dwVirtualAddress; ! 3042: newSectionHeader->PointerToRawData = dwEndOfFile; ! 3043: newSectionHeader->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE; ! 3044: newSectionHeader->SizeOfRawData = 14 + name_len + file_size; ! 3045: DWORD dwExtraRawBytes = newSectionHeader->SizeOfRawData % optionalHeader->FileAlignment; ! 3046: if(dwExtraRawBytes != 0) { ! 3047: static const char padding[] = "PADDINGXXPADDING"; ! 3048: DWORD dwRemain = optionalHeader->FileAlignment - dwExtraRawBytes; ! 3049: for(int i = 0; i < dwRemain; i++) { ! 3050: if(i < 2) { ! 3051: fputc(padding[i & 15], fo); ! 3052: } else { ! 3053: fputc(padding[(i - 2) & 15], fo); ! 3054: } ! 3055: } ! 3056: newSectionHeader->SizeOfRawData += dwRemain; ! 3057: } ! 3058: newSectionHeader->Misc.VirtualSize = newSectionHeader->SizeOfRawData; ! 3059: ! 3060: DWORD dwNewSectionSize = newSectionHeader->SizeOfRawData; ! 3061: DWORD dwExtraNewSectionBytes = dwNewSectionSize % optionalHeader->SectionAlignment; ! 3062: if(dwExtraNewSectionBytes != 0) { ! 3063: DWORD dwRemain = optionalHeader->SectionAlignment - dwExtraNewSectionBytes; ! 3064: dwNewSectionSize += dwRemain; ! 3065: } ! 3066: optionalHeader->SizeOfImage += dwNewSectionSize; ! 3067: ! 3068: fseek(fo, 0, SEEK_SET); ! 3069: fwrite(header, sizeof(header), 1, fo); ! 3070: ! 3071: fprintf(stderr, "'%s' is successfully created\n", new_exec_file); ! 3072: retval = EXIT_SUCCESS; ! 3073: } ! 3074: } ! 3075: if(fp != NULL) { ! 3076: fclose(fp); ! 3077: } ! 3078: if(fs != NULL) { ! 3079: fclose(fs); ! 3080: } ! 3081: if(fo != NULL) { ! 3082: fclose(fo); ! 3083: } ! 3084: } ! 3085: #ifdef _DEBUG ! 3086: _CrtDumpMemoryLeaks(); ! 3087: #endif ! 3088: return(retval); ! 3089: } ! 3090: ! 3091: is_winxp_or_later = is_greater_windows_version(5, 1, 0, 0); ! 3092: is_xp_64_or_later = is_greater_windows_version(5, 2, 0, 0); ! 3093: is_vista_or_later = is_greater_windows_version(6, 0, 0, 0); ! 3094: ! 3095: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); ! 3096: CONSOLE_SCREEN_BUFFER_INFO csbi; ! 3097: CONSOLE_CURSOR_INFO ci; ! 3098: UINT input_cp = GetConsoleCP(); ! 3099: UINT output_cp = GetConsoleOutputCP(); ! 3100: int multibyte_cp = _getmbcp(); ! 3101: ! 3102: get_console_info_success = (GetConsoleScreenBufferInfo(hStdout, &csbi) != 0); ! 3103: GetConsoleCursorInfo(hStdout, &ci); ! 3104: ci_old = ci_new = ci; ! 3105: GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwConsoleMode); ! 3106: get_console_font_success = get_console_font_size(&font_width, &font_height); ! 3107: ! 3108: for(int y = 0; y < SCR_BUF_WIDTH; y++) { ! 3109: for(int x = 0; x < SCR_BUF_HEIGHT; x++) { ! 3110: SCR_BUF(y,x).Char.AsciiChar = ' '; ! 3111: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; ! 3112: } ! 3113: } ! 3114: if(get_console_info_success) { ! 3115: scr_width = csbi.dwSize.X; ! 3116: scr_height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; ! 3117: ! 3118: // v-text shadow buffer size must be lesser than 0x7fd0 ! 3119: if((scr_width > SCR_BUF_WIDTH) || (scr_height > SCR_BUF_HEIGHT) || (scr_width * scr_height * 2 > 0x7fd0) || ! 3120: (buf_width != 0 && buf_width != scr_width) || (buf_height != 0 && buf_height != scr_height)) { ! 3121: scr_width = min(buf_width != 0 ? buf_width : scr_width, SCR_BUF_WIDTH); ! 3122: scr_height = min(buf_height != 0 ? buf_height : scr_height, SCR_BUF_HEIGHT); ! 3123: if(scr_width * scr_height * 2 > 0x7fd0) { ! 3124: scr_width = 80; ! 3125: scr_height = 25; ! 3126: } ! 3127: screen_size_changed = true; ! 3128: } ! 3129: } else { ! 3130: // for a proof (not a console) ! 3131: scr_width = 80; ! 3132: scr_height = 25; ! 3133: } ! 3134: scr_buf_size.X = scr_width; ! 3135: scr_buf_size.Y = scr_height; ! 3136: scr_buf_pos.X = scr_buf_pos.Y = 0; ! 3137: scr_top = csbi.srWindow.Top; ! 3138: cursor_moved = false; ! 3139: cursor_moved_by_crtc = false; ! 3140: ! 3141: SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS); ! 3142: ! 3143: #ifdef USE_SERVICE_THREAD ! 3144: InitializeCriticalSection(&input_crit_sect); ! 3145: InitializeCriticalSection(&key_buf_crit_sect); ! 3146: InitializeCriticalSection(&putch_crit_sect); ! 3147: main_thread_id = GetCurrentThreadId(); ! 3148: #endif ! 3149: ! 3150: key_buf_char = new FIFO(256); ! 3151: key_buf_scan = new FIFO(256); ! 3152: key_buf_data = new FIFO(256); ! 3153: ! 3154: hardware_init(); ! 3155: ! 3156: #ifdef USE_DEBUGGER ! 3157: debugger_init(); ! 3158: #endif ! 3159: ! 3160: if(msdos_init(argc - (arg_offset + 1), argv + (arg_offset + 1), envp, standard_env)) { ! 3161: retval = EXIT_FAILURE; ! 3162: } else { ! 3163: #if defined(_MSC_VER) && (_MSC_VER >= 1400) ! 3164: _set_invalid_parameter_handler((_invalid_parameter_handler)ignore_invalid_parameters); ! 3165: #endif ! 3166: SetConsoleCtrlHandler(ctrl_handler, TRUE); ! 3167: ! 3168: if(screen_size_changed) { ! 3169: change_console_size(scr_width, scr_height); ! 3170: } ! 3171: TIMECAPS caps; ! 3172: timeGetDevCaps(&caps, sizeof(TIMECAPS)); ! 3173: timeBeginPeriod(caps.wPeriodMin); ! 3174: #ifdef USE_VRAM_THREAD ! 3175: InitializeCriticalSection(&vram_crit_sect); ! 3176: CloseHandle(CreateThread(NULL, 4096, vram_thread, NULL, 0, NULL)); ! 3177: #endif ! 3178: #ifdef USE_DEBUGGER ! 3179: CloseHandle(CreateThread(NULL, 0, debugger_thread, NULL, 0, NULL)); ! 3180: // wait until telnet client starts and connects to me ! 3181: if(_access(debugger_get_ttermpro_path(), 0) == 0 || ! 3182: _access(debugger_get_ttermpro_x86_path(), 0) == 0 || ! 3183: _access(debugger_get_putty_path(), 0) == 0 || ! 3184: _access(debugger_get_putty_x86_path(), 0) == 0 || ! 3185: _access(debugger_get_telnet_path(), 0) == 0) { ! 3186: for(int i = 0; i < 100 && cli_socket == 0; i++) { ! 3187: Sleep(100); ! 3188: } ! 3189: } ! 3190: #endif ! 3191: hardware_run(); ! 3192: #ifdef USE_VRAM_THREAD ! 3193: vram_flush(); ! 3194: DeleteCriticalSection(&vram_crit_sect); ! 3195: #endif ! 3196: timeEndPeriod(caps.wPeriodMin); ! 3197: ! 3198: // hStdin/hStdout (and all handles) will be closed in msdos_finish()... ! 3199: hStdout = GetStdHandle(STD_OUTPUT_HANDLE); ! 3200: ! 3201: // restore console settings ! 3202: _setmbcp(multibyte_cp); ! 3203: SetConsoleCP(input_cp); ! 3204: SetConsoleOutputCP(multibyte_cp); ! 3205: ! 3206: if(get_console_info_success) { ! 3207: if(restore_console_on_exit) { ! 3208: // window can't be bigger than buffer, ! 3209: // buffer can't be smaller than window, ! 3210: // so make a tiny window, ! 3211: // set the required buffer, ! 3212: // then set the required window ! 3213: CONSOLE_SCREEN_BUFFER_INFO cur_csbi; ! 3214: SMALL_RECT rect; ! 3215: GetConsoleScreenBufferInfo(hStdout, &cur_csbi); ! 3216: int min_width = min(cur_csbi.srWindow.Right - cur_csbi.srWindow.Left + 1, csbi.srWindow.Right - csbi.srWindow.Left + 1); ! 3217: int min_height = min(cur_csbi.srWindow.Bottom - cur_csbi.srWindow.Top + 1, csbi.srWindow.Bottom - csbi.srWindow.Top + 1); ! 3218: ! 3219: SET_RECT(rect, 0, cur_csbi.srWindow.Top, min_width - 1, cur_csbi.srWindow.Top + min_height - 1); ! 3220: SetConsoleWindowInfo(hStdout, TRUE, &rect); ! 3221: SetConsoleScreenBufferSize(hStdout, csbi.dwSize); ! 3222: SET_RECT(rect, 0, 0, csbi.srWindow.Right - csbi.srWindow.Left, csbi.srWindow.Bottom - csbi.srWindow.Top); ! 3223: if(!SetConsoleWindowInfo(hStdout, TRUE, &rect)) { ! 3224: SetWindowPos(get_console_window_handle(), NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER); ! 3225: SetConsoleWindowInfo(hStdout, TRUE, &rect); ! 3226: } ! 3227: } ! 3228: } ! 3229: if(get_console_font_success) { ! 3230: set_console_font_size(font_width, font_height); ! 3231: } ! 3232: if(get_console_info_success) { ! 3233: if(restore_console_on_exit) { ! 3234: SMALL_RECT rect; ! 3235: SetConsoleScreenBufferSize(hStdout, csbi.dwSize); ! 3236: SET_RECT(rect, 0, 0, csbi.srWindow.Right - csbi.srWindow.Left, csbi.srWindow.Bottom - csbi.srWindow.Top); ! 3237: if(!SetConsoleWindowInfo(hStdout, TRUE, &rect)) { ! 3238: SetWindowPos(get_console_window_handle(), NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER); ! 3239: SetConsoleWindowInfo(hStdout, TRUE, &rect); ! 3240: } ! 3241: } ! 3242: SetConsoleTextAttribute(hStdout, csbi.wAttributes); ! 3243: SetConsoleCursorInfo(hStdout, &ci); ! 3244: } ! 3245: if(dwConsoleMode & (ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE)) { ! 3246: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode | ENABLE_EXTENDED_FLAGS); ! 3247: } else { ! 3248: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode); ! 3249: } ! 3250: ! 3251: msdos_finish(); ! 3252: ! 3253: SetConsoleCtrlHandler(ctrl_handler, FALSE); ! 3254: } ! 3255: if(temp_file_created) { ! 3256: DeleteFileA(temp_file_path); ! 3257: temp_file_created = false; ! 3258: } ! 3259: hardware_finish(); ! 3260: ! 3261: if(key_buf_char != NULL) { ! 3262: key_buf_char->release(); ! 3263: delete key_buf_char; ! 3264: key_buf_char = NULL; ! 3265: } ! 3266: if(key_buf_scan != NULL) { ! 3267: key_buf_scan->release(); ! 3268: delete key_buf_scan; ! 3269: key_buf_scan = NULL; ! 3270: } ! 3271: if(key_buf_data != NULL) { ! 3272: key_buf_data->release(); ! 3273: delete key_buf_data; ! 3274: key_buf_data = NULL; ! 3275: } ! 3276: #ifdef USE_SERVICE_THREAD ! 3277: DeleteCriticalSection(&input_crit_sect); ! 3278: DeleteCriticalSection(&key_buf_crit_sect); ! 3279: DeleteCriticalSection(&putch_crit_sect); ! 3280: #endif ! 3281: #ifdef _DEBUG ! 3282: _CrtDumpMemoryLeaks(); ! 3283: #endif ! 3284: return(retval); ! 3285: } ! 3286: ! 3287: /* ---------------------------------------------------------------------------- ! 3288: console ! 3289: ---------------------------------------------------------------------------- */ ! 3290: ! 3291: void change_console_size(int width, int height) ! 3292: { ! 3293: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); ! 3294: CONSOLE_SCREEN_BUFFER_INFO csbi; ! 3295: SMALL_RECT rect; ! 3296: COORD co; ! 3297: ! 3298: GetConsoleScreenBufferInfo(hStdout, &csbi); ! 3299: if(csbi.srWindow.Top != 0 || csbi.dwCursorPosition.Y > height - 1) { ! 3300: if(csbi.srWindow.Right - csbi.srWindow.Left + 1 == width && csbi.srWindow.Bottom - csbi.srWindow.Top + 1 == height) { ! 3301: ReadConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &csbi.srWindow); ! 3302: SET_RECT(rect, 0, 0, width - 1, height - 1); ! 3303: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect); ! 3304: } else if(csbi.dwCursorPosition.Y > height - 1) { ! 3305: SET_RECT(rect, 0, csbi.dwCursorPosition.Y - (height - 1), width - 1, csbi.dwCursorPosition.Y); ! 3306: ReadConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect); ! 3307: SET_RECT(rect, 0, 0, width - 1, height - 1); ! 3308: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect); ! 3309: } ! 3310: } ! 3311: if(csbi.dwCursorPosition.Y > height - 1) { ! 3312: co.X = csbi.dwCursorPosition.X; ! 3313: co.Y = min(height - 1, csbi.dwCursorPosition.Y - csbi.srWindow.Top); ! 3314: SetConsoleCursorPosition(hStdout, co); ! 3315: cursor_moved = true; ! 3316: cursor_moved_by_crtc = false; ! 3317: } ! 3318: ! 3319: // window can't be bigger than buffer, ! 3320: // buffer can't be smaller than window, ! 3321: // so make a tiny window, ! 3322: // set the required buffer, ! 3323: // then set the required window ! 3324: int min_width = min(csbi.srWindow.Right - csbi.srWindow.Left + 1, width); ! 3325: int min_height = min(csbi.srWindow.Bottom - csbi.srWindow.Top + 1, height); ! 3326: ! 3327: SET_RECT(rect, 0, csbi.srWindow.Top, min_width - 1, csbi.srWindow.Top + min_height - 1); ! 3328: SetConsoleWindowInfo(hStdout, TRUE, &rect); ! 3329: co.X = width; ! 3330: co.Y = height; ! 3331: SetConsoleScreenBufferSize(hStdout, co); ! 3332: SET_RECT(rect, 0, 0, width - 1, height - 1); ! 3333: if(!SetConsoleWindowInfo(hStdout, TRUE, &rect)) { ! 3334: SetWindowPos(get_console_window_handle(), NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER); ! 3335: SetConsoleWindowInfo(hStdout, TRUE, &rect); ! 3336: } ! 3337: ! 3338: scr_width = scr_buf_size.X = width; ! 3339: scr_height = scr_buf_size.Y = height; ! 3340: scr_top = 0; ! 3341: ! 3342: clear_scr_buffer(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); ! 3343: ! 3344: int regen = min(scr_width * scr_height * 2, 0x8000); ! 3345: text_vram_end_address = text_vram_top_address + regen; ! 3346: shadow_buffer_end_address = shadow_buffer_top_address + regen; ! 3347: ! 3348: if(regen > 0x4000) { ! 3349: regen = 0x8000; ! 3350: vram_pages = 1; ! 3351: } else if(regen > 0x2000) { ! 3352: regen = 0x4000; ! 3353: vram_pages = 2; ! 3354: } else if(regen > 0x1000) { ! 3355: regen = 0x2000; ! 3356: vram_pages = 4; ! 3357: } else { ! 3358: regen = 0x1000; ! 3359: vram_pages = 8; ! 3360: } ! 3361: *(UINT16 *)(mem + 0x44a) = scr_width; ! 3362: *(UINT16 *)(mem + 0x44c) = regen; ! 3363: *(UINT8 *)(mem + 0x484) = scr_height - 1; ! 3364: ! 3365: mouse.min_position.x = 0; ! 3366: mouse.min_position.y = 0; ! 3367: mouse.max_position.x = 8 * (scr_width - 1); ! 3368: mouse.max_position.y = 8 * (scr_height - 1); ! 3369: ! 3370: restore_console_on_exit = true; ! 3371: } ! 3372: ! 3373: void clear_scr_buffer(WORD attr) ! 3374: { ! 3375: for(int y = 0; y < scr_height; y++) { ! 3376: for(int x = 0; x < scr_width; x++) { ! 3377: SCR_BUF(y,x).Char.AsciiChar = ' '; ! 3378: SCR_BUF(y,x).Attributes = attr; ! 3379: } ! 3380: } ! 3381: } ! 3382: ! 3383: bool update_console_input() ! 3384: { ! 3385: #ifdef USE_SERVICE_THREAD ! 3386: EnterCriticalSection(&input_crit_sect); ! 3387: #endif ! 3388: HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); ! 3389: DWORD dwNumberOfEvents = 0; ! 3390: DWORD dwRead; ! 3391: INPUT_RECORD ir[16]; ! 3392: CONSOLE_SCREEN_BUFFER_INFO csbi = {0}; ! 3393: bool result = false; ! 3394: ! 3395: if(GetNumberOfConsoleInputEvents(hStdin, &dwNumberOfEvents) && dwNumberOfEvents != 0) { ! 3396: if(ReadConsoleInputA(hStdin, ir, 16, &dwRead)) { ! 3397: for(int i = 0; i < dwRead; i++) { ! 3398: if(ir[i].EventType & MOUSE_EVENT) { ! 3399: if(ir[i].Event.MouseEvent.dwEventFlags & MOUSE_MOVED) { ! 3400: if(mouse.hidden == 0 || (mouse.call_addr_ps2.dw && mouse.enabled_ps2)) { ! 3401: // NOTE: if restore_console_on_exit, console is not scrolled ! 3402: if(!restore_console_on_exit && csbi.srWindow.Bottom == 0) { ! 3403: GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); ! 3404: } ! 3405: // FIXME: character size is always 8x8 ??? ! 3406: int x = 8 * (ir[i].Event.MouseEvent.dwMousePosition.X); ! 3407: int y = 8 * (ir[i].Event.MouseEvent.dwMousePosition.Y - csbi.srWindow.Top); ! 3408: ! 3409: if(mouse.position.x != x || mouse.position.y != y) { ! 3410: mouse.position.x = x; ! 3411: mouse.position.y = y; ! 3412: mouse.status |= 1; ! 3413: mouse.status_alt |= 1; ! 3414: } ! 3415: } ! 3416: } else if(ir[i].Event.MouseEvent.dwEventFlags == 0) { ! 3417: for(int j = 0; j < MAX_MOUSE_BUTTONS; j++) { ! 3418: static const DWORD bits[] = { ! 3419: FROM_LEFT_1ST_BUTTON_PRESSED, // left ! 3420: RIGHTMOST_BUTTON_PRESSED, // right ! 3421: FROM_LEFT_2ND_BUTTON_PRESSED, // middle ! 3422: }; ! 3423: bool prev_status = mouse.buttons[j].status; ! 3424: mouse.buttons[j].status = ((ir[i].Event.MouseEvent.dwButtonState & bits[j]) != 0); ! 3425: ! 3426: if(!prev_status && mouse.buttons[j].status) { ! 3427: mouse.buttons[j].pressed_times++; ! 3428: mouse.buttons[j].pressed_position.x = mouse.position.x; ! 3429: mouse.buttons[j].pressed_position.y = mouse.position.x; ! 3430: if(j < 2) { ! 3431: mouse.status_alt |= 2 << (j * 2); ! 3432: } ! 3433: mouse.status |= 2 << (j * 2); ! 3434: } else if(prev_status && !mouse.buttons[j].status) { ! 3435: mouse.buttons[j].released_times++; ! 3436: mouse.buttons[j].released_position.x = mouse.position.x; ! 3437: mouse.buttons[j].released_position.y = mouse.position.x; ! 3438: if(j < 2) { ! 3439: mouse.status_alt |= 4 << (j * 2); ! 3440: } ! 3441: mouse.status |= 4 << (j * 2); ! 3442: } ! 3443: } ! 3444: } ! 3445: } else if(ir[i].EventType & KEY_EVENT) { ! 3446: // update keyboard flags in bios data area ! 3447: if(ir[i].Event.KeyEvent.dwControlKeyState & CAPSLOCK_ON) { ! 3448: mem[0x417] |= 0x40; ! 3449: } else { ! 3450: mem[0x417] &= ~0x40; ! 3451: } ! 3452: if(ir[i].Event.KeyEvent.dwControlKeyState & NUMLOCK_ON) { ! 3453: mem[0x417] |= 0x20; ! 3454: } else { ! 3455: mem[0x417] &= ~0x20; ! 3456: } ! 3457: if(ir[i].Event.KeyEvent.dwControlKeyState & SCROLLLOCK_ON) { ! 3458: mem[0x417] |= 0x10; ! 3459: } else { ! 3460: mem[0x417] &= ~0x10; ! 3461: } ! 3462: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) { ! 3463: if(mouse.buttons[0].status || mouse.buttons[1].status) { ! 3464: mouse.status_alt |= 0x80; ! 3465: } ! 3466: mem[0x417] |= 0x08; ! 3467: } else { ! 3468: mem[0x417] &= ~0x08; ! 3469: } ! 3470: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) { ! 3471: if(mouse.buttons[0].status || mouse.buttons[1].status) { ! 3472: mouse.status_alt |= 0x40; ! 3473: } ! 3474: mem[0x417] |= 0x04; ! 3475: } else { ! 3476: mem[0x417] &= ~0x04; ! 3477: } ! 3478: if(ir[i].Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) { ! 3479: if(mouse.buttons[0].status || mouse.buttons[1].status) { ! 3480: mouse.status_alt |= 0x20; ! 3481: } ! 3482: if(!(mem[0x417] & 0x03)) { ! 3483: mem[0x417] |= 0x02; // left shift ! 3484: } ! 3485: } else { ! 3486: mem[0x417] &= ~0x03; ! 3487: } ! 3488: if(ir[i].Event.KeyEvent.dwControlKeyState & LEFT_ALT_PRESSED) { ! 3489: mem[0x418] |= 0x02; ! 3490: } else { ! 3491: mem[0x418] &= ~0x02; ! 3492: } ! 3493: if(ir[i].Event.KeyEvent.dwControlKeyState & LEFT_CTRL_PRESSED) { ! 3494: mem[0x418] |= 0x01; ! 3495: } else { ! 3496: mem[0x418] &= ~0x01; ! 3497: } ! 3498: ! 3499: // set scan code of last pressed/release key to kbd_data (in-port 60h) ! 3500: // kbd_data = ir[i].Event.KeyEvent.wVirtualScanCode; ! 3501: // kbd_status |= 1; ! 3502: UINT8 tmp_data = ir[i].Event.KeyEvent.wVirtualScanCode; ! 3503: ! 3504: // update dos key buffer ! 3505: UINT8 chr = ir[i].Event.KeyEvent.uChar.AsciiChar; ! 3506: UINT8 scn = ir[i].Event.KeyEvent.wVirtualScanCode & 0xff; ! 3507: UINT8 scn_old = scn; ! 3508: ! 3509: if(ir[i].Event.KeyEvent.bKeyDown) { ! 3510: // make ! 3511: tmp_data &= 0x7f; ! 3512: ! 3513: if(chr == 0x00) { ! 3514: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) { ! 3515: if(scn >= 0x3b && scn <= 0x44) { ! 3516: scn += 0x68 - 0x3b; // F1 to F10 ! 3517: } else if(scn == 0x57 || scn == 0x58) { ! 3518: scn += 0x8b - 0x57; // F11 & F12 ! 3519: } else if(scn >= 0x47 && scn <= 0x53) { ! 3520: scn += 0x97 - 0x47; // edit/arrow clusters ! 3521: } else if(scn == 0x35) { ! 3522: scn = 0xa4; // keypad / ! 3523: } ! 3524: } else if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) { ! 3525: if(scn == 0x07) { ! 3526: chr = 0x1e; // Ctrl+^ ! 3527: } else if(scn == 0x0c) { ! 3528: chr = 0x1f; // Ctrl+_ ! 3529: } else if(scn >= 0x35 && scn <= 0x58) { ! 3530: static const UINT8 ctrl_map[] = { ! 3531: 0x95, // keypad / ! 3532: 0, ! 3533: 0x96, // keypad * ! 3534: 0, 0, 0, ! 3535: 0x5e, // F1 ! 3536: 0x5f, // F2 ! 3537: 0x60, // F3 ! 3538: 0x61, // F4 ! 3539: 0x62, // F5 ! 3540: 0x63, // F6 ! 3541: 0x64, // F7 ! 3542: 0x65, // F8 ! 3543: 0x66, // F9 ! 3544: 0x67, // F10 ! 3545: 0, ! 3546: 0, ! 3547: 0x77, // Home ! 3548: 0x8d, // Up ! 3549: 0x84, // PgUp ! 3550: 0x8e, // keypad - ! 3551: 0x73, // Left ! 3552: 0x8f, // keypad center ! 3553: 0x74, // Right ! 3554: 0x90, // keyapd + ! 3555: 0x75, // End ! 3556: 0x91, // Down ! 3557: 0x76, // PgDn ! 3558: 0x92, // Insert ! 3559: 0x93, // Delete ! 3560: 0, 0, 0, ! 3561: 0x89, // F11 ! 3562: 0x8a, // F12 ! 3563: }; ! 3564: scn = ctrl_map[scn - 0x35]; ! 3565: } ! 3566: } else if(ir[i].Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) { ! 3567: if(scn >= 0x3b && scn <= 0x44) { ! 3568: scn += 0x54 - 0x3b; // F1 to F10 ! 3569: } else if(scn == 0x57 || scn == 0x58) { ! 3570: scn += 0x87 - 0x57; // F11 & F12 ! 3571: } ! 3572: } else if(scn == 0x57 || scn == 0x58) { ! 3573: scn += 0x85 - 0x57; ! 3574: } ! 3575: // ignore shift, ctrl, alt, win and menu keys ! 3576: if(scn != 0x1d && scn != 0x2a && scn != 0x36 && scn != 0x38 && !(scn >= 0x5b && scn <= 0x5d && scn == scn_old)) { ! 3577: if(key_buf_char != NULL && key_buf_scan != NULL) { ! 3578: #ifdef USE_SERVICE_THREAD ! 3579: EnterCriticalSection(&key_buf_crit_sect); ! 3580: #endif ! 3581: if(chr == 0) { ! 3582: pcbios_set_key_buffer(0x00, ir[i].Event.KeyEvent.dwControlKeyState & ENHANCED_KEY ? 0xe0 : 0x00); ! 3583: } ! 3584: pcbios_set_key_buffer(chr, scn); ! 3585: #ifdef USE_SERVICE_THREAD ! 3586: LeaveCriticalSection(&key_buf_crit_sect); ! 3587: #endif ! 3588: } ! 3589: } ! 3590: } else { ! 3591: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) { ! 3592: chr = 0; ! 3593: if(scn >= 0x02 && scn <= 0x0e) { ! 3594: scn += 0x78 - 0x02; // 1 to 0 - = ! 3595: } ! 3596: } ! 3597: if(key_buf_char != NULL && key_buf_scan != NULL) { ! 3598: #ifdef USE_SERVICE_THREAD ! 3599: EnterCriticalSection(&key_buf_crit_sect); ! 3600: #endif ! 3601: pcbios_set_key_buffer(chr, scn); ! 3602: #ifdef USE_SERVICE_THREAD ! 3603: LeaveCriticalSection(&key_buf_crit_sect); ! 3604: #endif ! 3605: } ! 3606: } ! 3607: } else { ! 3608: if(chr == 0x03 && (ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))) { ! 3609: // ctrl-break, ctrl-c ! 3610: if(scn == 0x46) { ! 3611: if(key_buf_char != NULL && key_buf_scan != NULL) { ! 3612: #ifdef USE_SERVICE_THREAD ! 3613: EnterCriticalSection(&key_buf_crit_sect); ! 3614: #endif ! 3615: pcbios_set_key_buffer(0x00, 0x00); ! 3616: #ifdef USE_SERVICE_THREAD ! 3617: LeaveCriticalSection(&key_buf_crit_sect); ! 3618: #endif ! 3619: } ! 3620: ctrl_break_pressed = true; ! 3621: mem[0x471] = 0x80; ! 3622: raise_int_1bh = true; ! 3623: } else { ! 3624: if(key_buf_char != NULL && key_buf_scan != NULL) { ! 3625: #ifdef USE_SERVICE_THREAD ! 3626: EnterCriticalSection(&key_buf_crit_sect); ! 3627: #endif ! 3628: pcbios_set_key_buffer(chr, scn); ! 3629: #ifdef USE_SERVICE_THREAD ! 3630: LeaveCriticalSection(&key_buf_crit_sect); ! 3631: #endif ! 3632: } ! 3633: ctrl_c_pressed = (scn == 0x2e); ! 3634: } ! 3635: } ! 3636: // break ! 3637: tmp_data |= 0x80; ! 3638: } ! 3639: if(!(kbd_status & 1)) { ! 3640: kbd_data = tmp_data; ! 3641: kbd_status |= 1; ! 3642: } else { ! 3643: if(key_buf_data != NULL) { ! 3644: #ifdef USE_SERVICE_THREAD ! 3645: EnterCriticalSection(&key_buf_crit_sect); ! 3646: #endif ! 3647: key_buf_data->write(tmp_data); ! 3648: #ifdef USE_SERVICE_THREAD ! 3649: LeaveCriticalSection(&key_buf_crit_sect); ! 3650: #endif ! 3651: } ! 3652: } ! 3653: result = key_changed = true; ! 3654: // IME may be on and it may causes screen scroll up and cursor position change ! 3655: cursor_moved = true; ! 3656: } ! 3657: } ! 3658: } ! 3659: } ! 3660: #ifdef USE_SERVICE_THREAD ! 3661: LeaveCriticalSection(&input_crit_sect); ! 3662: #endif ! 3663: return(result); ! 3664: } ! 3665: ! 3666: bool update_key_buffer() ! 3667: { ! 3668: if(update_console_input()) { ! 3669: return(true); ! 3670: } ! 3671: if(key_buf_char != NULL && key_buf_scan != NULL) { ! 3672: #ifdef USE_SERVICE_THREAD ! 3673: EnterCriticalSection(&key_buf_crit_sect); ! 3674: #endif ! 3675: bool empty = pcbios_is_key_buffer_empty(); ! 3676: #ifdef USE_SERVICE_THREAD ! 3677: LeaveCriticalSection(&key_buf_crit_sect); ! 3678: #endif ! 3679: if(!empty) return(true); ! 3680: } ! 3681: return(false); ! 3682: } ! 3683: ! 3684: /* ---------------------------------------------------------------------------- ! 3685: MS-DOS virtual machine ! 3686: ---------------------------------------------------------------------------- */ ! 3687: ! 3688: static const struct { ! 3689: char *name; ! 3690: DWORD lcid; ! 3691: char *std; ! 3692: char *dlt; ! 3693: } tz_table[] = { ! 3694: // https://science.ksc.nasa.gov/software/winvn/userguide/3_1_4.htm ! 3695: // 0 GMT Greenwich Mean Time GMT0 ! 3696: {"GMT Standard Time", 0x0809, "GMT", "BST"}, // (UTC+00:00) GB London (en-gb) ! 3697: {"GMT Standard Time", 0x1809, "GMT", "IST"}, // (UTC+00:00) IE Dublin (en-ie) ! 3698: {"GMT Standard Time", 0x0000, "WET", "WES"}, // (UTC+00:00) PT Lisbon ! 3699: {"Greenwich Standard Time", 0x0000, "GMT", "GST"}, // (UTC+00:00) IS Reykjavik ! 3700: // 2 FST FDT Fernando De Noronha Std FST2FDT ! 3701: {"Mid-Atlantic Standard Time", 0x0416, "FST", "FDT"}, // (UTC-02:00) BR Noronha (pt-br) ! 3702: {"UTC-02", 0x0416, "FST", "FDT"}, // (UTC-02:00) BR Noronha (pt-br) ! 3703: // 3 BST Brazil Standard Time BST3 ! 3704: {"Bahia Standard Time", 0x0000, "BST", "BDT"}, // (UTC-03:00) BR Bahia ! 3705: {"SA Eastern Standard Time", 0x0000, "BST", "BDT"}, // (UTC-03:00) BR Fortaleza ! 3706: {"Tocantins Standard Time", 0x0000, "BST", "BDT"}, // (UTC-03:00) BR Palmas ! 3707: // 3 EST EDT Eastern Standard (Brazil) EST3EDT ! 3708: {"E. South America Standard Time", 0x0000, "EST", "EDT"}, // (UTC-03:00) BR Sao Paulo ! 3709: // 3 GST Greenland Standard Time GST3 ! 3710: {"Greenland Standard Time", 0x0000, "GST", "GDT"}, // (UTC-03:00) GL Godthab ! 3711: // 3:30 NST NDT Newfoundland Standard Time NST3:30NDT ! 3712: {"Newfoundland Standard Time", 0x0000, "NST", "NDT"}, // (UTC-03:30) CA St.Johns ! 3713: // 4 AST ADT Atlantic Standard Time AST4ADT ! 3714: {"Atlantic Standard Time", 0x0000, "AST", "ADT"}, // (UTC-04:00) CA Halifax ! 3715: // 4 WST WDT Western Standard (Brazil) WST4WDT ! 3716: {"Central Brazilian Standard Time", 0x0000, "WST", "WDT"}, // (UTC-04:00) BR Cuiaba ! 3717: {"SA Western Standard Time", 0x0000, "WST", "WDT"}, // (UTC-04:00) BR Manaus ! 3718: // 5 EST EDT Eastern Standard Time EST5EDT ! 3719: {"Eastern Standard Time", 0x0000, "EST", "EDT"}, // (UTC-05:00) US New York ! 3720: {"Eastern Standard Time (Mexico)", 0x0000, "EST", "EDT"}, // (UTC-05:00) MX Cancun ! 3721: {"US Eastern Standard Time", 0x0000, "EST", "EDT"}, // (UTC-05:00) US Indianapolis ! 3722: // 5 CST CDT Chile Standard Time CST5CDT ! 3723: {"Pacific SA Standard Time", 0x0000, "CST", "CDT"}, // (UTC-04:00) CL Santiago ! 3724: // 5 AST ADT Acre Standard Time AST5ADT ! 3725: {"SA Pacific Standard Time", 0x0000, "AST", "ADT"}, // (UTC-05:00) BR Rio Branco ! 3726: // 5 CST CDT Cuba Standard Time CST5CDT ! 3727: {"Cuba Standard Time", 0x0000, "CST", "CDT"}, // (UTC-05:00) CU Havana ! 3728: // 6 CST CDT Central Standard Time CST6CDT ! 3729: {"Canada Central Standard Time", 0x0000, "CST", "CDT"}, // (UTC-06:00) CA Regina ! 3730: {"Central Standard Time", 0x0000, "CST", "CDT"}, // (UTC-06:00) US Chicago ! 3731: {"Central Standard Time (Mexico)", 0x0000, "CST", "CDT"}, // (UTC-06:00) MX Mexico City ! 3732: // 6 EST EDT Easter Island Standard EST6EDT ! 3733: {"Easter Island Standard Time", 0x0000, "EST", "EDT"}, // (UTC-06:00) CL Easter ! 3734: // 7 MST MDT Mountain Standard Time MST7MDT ! 3735: {"Mountain Standard Time", 0x0000, "MST", "MDT"}, // (UTC-07:00) US Denver ! 3736: {"Mountain Standard Time (Mexico)", 0x0000, "MST", "MDT"}, // (UTC-07:00) MX Chihuahua ! 3737: {"US Mountain Standard Time", 0x0000, "MST", "MDT"}, // (UTC-07:00) US Phoenix ! 3738: // 8 PST PDT Pacific Standard Time PST8PDT ! 3739: {"Pacific Standard Time", 0x0000, "PST", "PDT"}, // (UTC-08:00) US Los Angeles ! 3740: {"Pacific Standard Time (Mexico)", 0x0000, "PST", "PDT"}, // (UTC-08:00) MX Tijuana ! 3741: // 9 AKS AKD Alaska Standard Time AKS9AKD ! 3742: // 9 YST YDT Yukon Standard Time YST9YST ! 3743: {"Alaskan Standard Time", 0x0000, "AKS", "AKD"}, // (UTC-09:00) US Anchorage ! 3744: // 10 HST HDT Hawaii Standard Time HST10HDT ! 3745: {"Aleutian Standard Time", 0x0000, "HST", "HDT"}, // (UTC-10:00) US Aleutian ! 3746: {"Hawaiian Standard Time", 0x0000, "HST", "HDT"}, // (UTC-10:00) US Honolulu ! 3747: // 11 SST Samoa Standard Time SST11 ! 3748: {"Samoa Standard Time", 0x0000, "SST", "SDT"}, // (UTC-11:00) US Samoa ! 3749: // -12 NZS NZD New Zealand Standard Time NZS-12NZD ! 3750: {"New Zealand Standard Time", 0x0000, "NZS", "NZD"}, // (UTC+12:00) NZ Auckland ! 3751: // -10 GST Guam Standard Time GST-10 ! 3752: {"West Pacific Standard Time", 0x0000, "GST", "GDT"}, // (UTC+10:00) GU Guam ! 3753: // -10 EAS EAD Eastern Australian Standard EAS-10EAD ! 3754: {"AUS Eastern Standard Time", 0x0000, "EAS", "EAD"}, // (UTC+10:00) AU Sydney ! 3755: {"E. Australia Standard Time", 0x0000, "EAS", "EAD"}, // (UTC+10:00) AU Brisbane ! 3756: {"Tasmania Standard Time", 0x0000, "EAS", "EAD"}, // (UTC+10:00) AU Hobart ! 3757: // -9:30 CAS CAD Central Australian Standard CAS-9:30CAD ! 3758: {"AUS Central Standard Time", 0x0000, "CAS", "CAD"}, // (UTC+09:30) AU Darwin ! 3759: {"Cen. Australia Standard Time", 0x0000, "CAS", "CAD"}, // (UTC+09:30) AU Adelaide ! 3760: // -9 JST Japan Standard Time JST-9 ! 3761: {"Tokyo Standard Time", 0x0000, "JST", "JDT"}, // (UTC+09:00) JP Tokyo ! 3762: // -9 KST KDT Korean Standard Time KST-9KDT ! 3763: {"Korea Standard Time", 0x0000, "KST", "KDT"}, // (UTC+09:00) KR Seoul ! 3764: {"North Korea Standard Time", 0x0000, "KST", "KDT"}, // (UTC+08:30) KP Pyongyang ! 3765: // -8 HKT Hong Kong Time HKT-8 ! 3766: {"China Standard Time", 0x0C04, "HKT", "HKS"}, // (UTC+08:00) HK Hong Kong (zh-hk) ! 3767: // -8 CCT China Coast Time CCT-8 ! 3768: {"China Standard Time", 0x0000, "CCT", "CDT"}, // (UTC+08:00) CN Shanghai ! 3769: {"Taipei Standard Time", 0x0000, "CCT", "CDT"}, // (UTC+08:00) TW Taipei ! 3770: // -8 SST Singapore Standard Time SST-8 ! 3771: {"Singapore Standard Time", 0x0000, "SST", "SDT"}, // (UTC+08:00) SG Singapore ! 3772: // -8 WAS WAD Western Australian Standard WAS-8WAD ! 3773: {"Aus Central W. Standard Time", 0x0000, "WAS", "WAD"}, // (UTC+08:45) AU Eucla ! 3774: {"W. Australia Standard Time", 0x0000, "WAS", "WAD"}, // (UTC+08:00) AU Perth ! 3775: // -7:30 JT Java Standard Time JST-7:30 ! 3776: // -7 NST North Sumatra Time NST-7 ! 3777: {"SE Asia Standard Time", 0x0000, "NST", "NDT"}, // (UTC+07:00) ID Jakarta ! 3778: // -5:30 IST Indian Standard Time IST-5:30 ! 3779: {"India Standard Time", 0x0000, "IST", "IDT"}, // (UTC+05:30) IN Calcutta ! 3780: // -3:30 IST IDT Iran Standard Time IST-3:30IDT ! 3781: {"Iran Standard Time", 0x0000, "IST", "IDT"}, // (UTC+03:30) IR Tehran ! 3782: // -3 MSK MSD Moscow Winter Time MSK-3MSD ! 3783: {"Belarus Standard Time", 0x0000, "MSK", "MSD"}, // (UTC+03:00) BY Minsk ! 3784: {"Russian Standard Time", 0x0000, "MSK", "MSD"}, // (UTC+03:00) RU Moscow ! 3785: // -2 EET Eastern Europe Time EET-2 ! 3786: {"E. Europe Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) MD Chisinau ! 3787: {"FLE Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) UA Kiev ! 3788: {"GTB Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) RO Bucharest ! 3789: {"Kaliningrad Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) RU Kaliningrad ! 3790: // -2 IST IDT Israel Standard Time IST-2IDT ! 3791: {"Israel Standard Time", 0x0000, "IST", "IDT"}, // (UTC+02:00) IL Jerusalem ! 3792: // -1 MEZ MES Middle European Time MEZ-1MES ! 3793: // -1 SWT SST Swedish Winter Time SWT-1SST ! 3794: // -1 FWT FST French Winter Time FWT-1FST ! 3795: // -1 CET CES Central European Time CET-1CES ! 3796: {"Central Europe Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) HU Budapest ! 3797: {"Central European Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) PL Warsaw ! 3798: {"Romance Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) FR Paris ! 3799: {"W. Europe Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) DE Berlin ! 3800: // -1 WAT West African Time WAT-1 ! 3801: {"Namibia Standard Time", 0x0000, "WAT", "WAS"}, // (UTC+01:00) NA Windhoek ! 3802: {"W. Central Africa Standard Time", 0x0000, "WAT", "WAS"}, // (UTC+01:00) NG Lagos ! 3803: // 0 UTC Universal Coordinated Time UTC0 ! 3804: {"UTC", 0x0000, "UTC", "" }, // (UTC+00:00) GMT+0 ! 3805: {"UTC-02", 0x0000, "UTC", "" }, // (UTC-02:00) GMT+2 ! 3806: {"UTC-08", 0x0000, "UTC", "" }, // (UTC-08:00) GMT+8 ! 3807: {"UTC-09", 0x0000, "UTC", "" }, // (UTC-09:00) GMT+9 ! 3808: {"UTC-11", 0x0000, "UTC", "" }, // (UTC-11:00) GMT+11 ! 3809: {"UTC+12", 0x0000, "UTC", "" }, // (UTC+12:00) GMT-12 ! 3810: }; ! 3811: ! 3812: // FIXME: consider to build on non-Japanese environment :-( ! 3813: // message_japanese string must be in shift-jis ! 3814: ! 3815: static const struct { ! 3816: UINT16 code; ! 3817: char *message_english; ! 3818: char *message_japanese; ! 3819: } standard_error_table[] = { ! 3820: {0x01, "Invalid function", "�����ȃt�@���N�V�����ł�."}, ! 3821: {0x02, "File not found", "�t�@�C����������܂���."}, ! 3822: {0x03, "Path not found", "�p�X��������܂���."}, ! 3823: {0x04, "Too many open files", "�J����Ă���t�@�C�����������܂�."}, ! 3824: {0x05, "Access denied", "�A�N�Z�X�͋��ۂ���܂���."}, ! 3825: {0x06, "Invalid handle", "�����ȃn���h���ł�."}, ! 3826: {0x07, "Memory control blocks destroyed", "����������u���b�N���j������܂���."}, ! 3827: {0x08, "Insufficient memory", "������������܂���."}, ! 3828: {0x09, "Invalid memory block address", "�����ȃ������u���b�N�̃A�h���X�ł�."}, ! 3829: {0x0A, "Invalid Environment", "�����Ȋ��ł�."}, ! 3830: {0x0B, "Invalid format", "�����ȃt�H�[�}�b�g�ł�."}, ! 3831: {0x0C, "Invalid function parameter", "�����ȃt�@���N�V�����p�����[�^�ł�."}, ! 3832: {0x0D, "Invalid data", "�����ȃf�[�^�ł�."}, ! 3833: {0x0F, "Invalid drive specification", "�����ȃh���C�u�̎w��ł�."}, ! 3834: {0x10, "Attempt to remove current directory", "���݂̃f�B���N�g�����폜���悤�Ƃ��܂���."}, ! 3835: {0x11, "Not same device", "�����f�o�C�X�ł͂���܂���."}, ! 3836: {0x12, "No more files", "�t�@�C���͂���ȏ゠��܂���."}, ! 3837: {0x13, "Write protect error", "�������ݕی�G���[�ł�."}, ! 3838: {0x14, "Invalid unit", "�����ȃ��j�b�g�ł�."}, ! 3839: {0x15, "Not ready", "�������ł��Ă��܂���."}, ! 3840: {0x16, "Invalid device request", "�����ȃf�o�C�X�v���ł�."}, ! 3841: {0x17, "Data error", "�f�[�^�G���[�ł�."}, ! 3842: {0x18, "Invalid device request parameters", "�����ȃf�o�C�X�v���̃p�����[�^�ł�."}, ! 3843: {0x19, "Seek error", "�V�[�N�G���[�ł�."}, ! 3844: {0x1A, "Invalid media type", "�����ȃ��f�B�A�̎�ނł�."}, ! 3845: {0x1B, "Sector not found", "�Z�N�^��������܂���."}, ! 3846: {0x1C, "Printer out of paper error", "�v�����^�̗p��������܂���."}, ! 3847: {0x1D, "Write fault error", "�������݃G���[�ł�."}, ! 3848: {0x1E, "Read fault error", "�ǂݎ��G���[�ł�."}, ! 3849: {0x1F, "General failure", "�G���[�ł�."}, ! 3850: {0x20, "Sharing violation", "���L�ᔽ�ł�."}, ! 3851: {0x21, "Lock violation", "���b�N�ᔽ�ł�."}, ! 3852: {0x22, "Invalid disk change", "�����ȃf�B�X�N�̌����ł�."}, ! 3853: {0x23, "FCB unavailable", "FCB �͎g���܂���."}, ! 3854: {0x24, "System resource exhausted", "�V�X�e�����\�[�X�͂����g���܂���."}, ! 3855: {0x25, "Code page mismatch", "�R�[�h �y�[�W����v���܂���."}, ! 3856: {0x26, "Out of input", "���͂��I���܂���."}, ! 3857: {0x27, "Insufficient disk space", "�f�B�X�N�̋̈悪����܂���."}, ! 3858: /* ! 3859: {0x32, "Network request not supported", NULL}, ! 3860: {0x33, "Remote computer not listening", NULL}, ! 3861: {0x34, "Duplicate name on network", NULL}, ! 3862: {0x35, "Network name not found", NULL}, ! 3863: {0x36, "Network busy", NULL}, ! 3864: {0x37, "Network device no longer exists", NULL}, ! 3865: {0x38, "Network BIOS command limit exceeded", NULL}, ! 3866: {0x39, "Network adapter hardware error", NULL}, ! 3867: {0x3A, "Incorrect response from network", NULL}, ! 3868: {0x3B, "Unexpected network error", NULL}, ! 3869: {0x3C, "Incompatible remote adapter", NULL}, ! 3870: {0x3D, "Print queue full", NULL}, ! 3871: {0x3E, "Queue not full", NULL}, ! 3872: {0x3F, "Not enough space to print file", NULL}, ! 3873: {0x40, "Network name was deleted", NULL}, ! 3874: {0x41, "Network: Access denied", NULL}, ! 3875: {0x42, "Network device type incorrect", NULL}, ! 3876: {0x43, "Network name not found", NULL}, ! 3877: {0x44, "Network name limit exceeded", NULL}, ! 3878: {0x45, "Network BIOS session limit exceeded", NULL}, ! 3879: {0x46, "Temporarily paused", NULL}, ! 3880: {0x47, "Network request not accepted", NULL}, ! 3881: {0x48, "Network print/disk redirection paused", NULL}, ! 3882: {0x49, "Network software not installed", NULL}, ! 3883: {0x4A, "Unexpected adapter close", NULL}, ! 3884: */ ! 3885: {0x50, "File exists", "�t�@�C���͑��݂��܂�."}, ! 3886: {0x52, "Cannot make directory entry", "�f�B���N�g���G���g�����쐬�ł��܂���."}, ! 3887: {0x53, "Fail on INT 24", "INT 24 �Ŏ��s���܂���."}, ! 3888: {0x54, "Too many redirections", "���_�C���N�g���������܂�."}, ! 3889: {0x55, "Duplicate redirection", "���_�C���N�g���d�����Ă��܂�."}, ! 3890: {0x56, "Invalid password", "�p�X���[�h���Ⴂ�܂�."}, ! 3891: {0x57, "Invalid parameter", "�p�����[�^�̎w�肪�Ⴂ�܂�."}, ! 3892: {0x58, "Network data fault", "�l�b�g���[�N�f�[�^�̃G���[�ł�."}, ! 3893: {0x59, "Function not supported by network", "�t�@���N�V�����̓l�b�g���[�N�ŃT�|�[�g����Ă��܂���."}, ! 3894: {0x5A, "Required system component not installe", "�K�v�ȃV�X�e�� �R���|�[�l���g���g�ݍ��܂�Ă��܂���."}, ! 3895: #ifdef SUPPORT_MSCDEX ! 3896: {0x64, "Unknown error", "�s���ȃG���[�ł�."}, ! 3897: {0x65, "Not ready", "�������ł��Ă��܂���."}, ! 3898: {0x66, "EMS memory no longer valid", "EMS �������͂����L���ł͂���܂���."}, ! 3899: {0x67, "CDROM not High Sierra or ISO-9660 format", "CDROM �� High Sierra �܂��� ISO-9660 �t�H�[�}�b�g�ł͂���܂���."}, ! 3900: {0x68, "Door open", "���o�[���܂��Ă��܂���." ! 3901: #endif ! 3902: {0xB0, "Volume is not locked", "�{�����[�������b�N����Ă��܂���."}, ! 3903: {0xB1, "Volume is locked in drive", "�{�����[�������b�N����Ă��܂�."}, ! 3904: {0xB2, "Volume is not removable", "�{�����[���͎��O���ł��܂���."}, ! 3905: {0xB4, "Lock count has been exceeded", "�{�����[��������ȏネ�b�N�ł��܂���."}, ! 3906: {0xB5, "A valid eject request failed", "���o���Ɏ��s���܂���."}, ! 3907: {-1 , "Unknown error", "�s���ȃG���[�ł�."}, ! 3908: }; ! 3909: ! 3910: static const struct { ! 3911: UINT16 code; ! 3912: char *message_english; ! 3913: char *message_japanese; ! 3914: } param_error_table[] = { ! 3915: {0x01, "Too many parameters", "�p�����[�^���������܂�."}, ! 3916: {0x02, "Required parameter missing", "�p�����[�^������܂���."}, ! 3917: {0x03, "Invalid switch", "�����ȃX�C�b�`�ł�."}, ! 3918: {0x04, "Invalid keyword", "�����ȃL�[���[�h�ł�."}, ! 3919: {0x06, "Parameter value not in allowed range", "�p�����[�^�̒l���͈͂��Ă��܂�."}, ! 3920: {0x07, "Parameter value not allowed", "���̃p�����[�^�̒l�͎g���܂���."}, ! 3921: {0x08, "Parameter value not allowed", "���̃p�����[�^�̒l�͎g���܂���."}, ! 3922: {0x09, "Parameter format not correct", "�p�����[�^�̏������Ⴂ�܂�."}, ! 3923: {0x0A, "Invalid parameter", "�����ȃp�����[�^�ł�."}, ! 3924: {0x0B, "Invalid parameter combination", "�����ȃp�����[�^�̑g�ݍ��킹�ł�."}, ! 3925: {-1 , "Unknown error", "�s���ȃG���[�ł�."}, ! 3926: }; ! 3927: ! 3928: static const struct { ! 3929: UINT16 code; ! 3930: char *message_english; ! 3931: char *message_japanese; ! 3932: } critical_error_table[] = { ! 3933: {0x00, "Write protect error", "�������ݕی�G���[�ł�."}, ! 3934: {0x01, "Invalid unit", "�����ȃ��j�b�g�ł�."}, ! 3935: {0x02, "Not ready", "�������ł��Ă��܂���."}, ! 3936: {0x03, "Invalid device request", "�����ȃf�o�C�X�v���ł�."}, ! 3937: {0x04, "Data error", "�f�[�^�G���[�ł�."}, ! 3938: {0x05, "Invalid device request parameters", "�����ȃf�o�C�X�v���̃p�����[�^�ł�."}, ! 3939: {0x06, "Seek error", "�V�[�N�G���[�ł�."}, ! 3940: {0x07, "Invalid media type", "�����ȃ��f�B�A�̎�ނł�."}, ! 3941: {0x08, "Sector not found", "�Z�N�^��������܂���."}, ! 3942: {0x09, "Printer out of paper error", "�v�����^�̗p��������܂���."}, ! 3943: {0x0A, "Write fault error", "�������݃G���[�ł�."}, ! 3944: {0x0B, "Read fault error", "�ǂݎ��G���[�ł�."}, ! 3945: {0x0C, "General failure", "�G���[�ł�."}, ! 3946: {0x0D, "Sharing violation", "���L�ᔽ�ł�."}, ! 3947: {0x0E, "Lock violation", "���b�N�ᔽ�ł�."}, ! 3948: {0x0F, "Invalid disk change", "�����ȃf�B�X�N�̌����ł�."}, ! 3949: {0x10, "FCB unavailable", "FCB �͎g���܂���."}, ! 3950: {0x11, "System resource exhausted", "�V�X�e�����\�[�X�͂����g���܂���."}, ! 3951: {0x12, "Code page mismatch", "�R�[�h �y�[�W����v���܂���."}, ! 3952: {0x13, "Out of input", "���͂��I���܂���."}, ! 3953: {0x14, "Insufficient disk space", "�f�B�X�N�̋̈悪����܂���."}, ! 3954: {-1 , "Critical error", "�v���I�ȃG���[�ł�."}, ! 3955: }; ! 3956: ! 3957: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg); ! 3958: int msdos_psp_get_file_table(int fd, int psp_seg); ! 3959: void msdos_putch(UINT8 data); ! 3960: void msdos_putch_fast(UINT8 data); ! 3961: #ifdef USE_SERVICE_THREAD ! 3962: void msdos_putch_tmp(UINT8 data); ! 3963: #endif ! 3964: const char *msdos_short_path(const char *path); ! 3965: bool msdos_is_valid_drive(int drv); ! 3966: bool msdos_is_removable_drive(int drv); ! 3967: bool msdos_is_cdrom_drive(int drv); ! 3968: bool msdos_is_remote_drive(int drv); ! 3969: bool msdos_is_subst_drive(int drv); ! 3970: ! 3971: // process info ! 3972: ! 3973: process_t *msdos_process_info_create(UINT16 psp_seg) ! 3974: { ! 3975: for(int i = 0; i < MAX_PROCESS; i++) { ! 3976: if(process[i].psp == 0 || process[i].psp == psp_seg) { ! 3977: memset(&process[i], 0, sizeof(process_t)); ! 3978: process[i].psp = psp_seg; ! 3979: return(&process[i]); ! 3980: } ! 3981: } ! 3982: fatalerror("too many processes\n"); ! 3983: return(NULL); ! 3984: } ! 3985: ! 3986: process_t *msdos_process_info_get(UINT16 psp_seg, bool show_error = true) ! 3987: { ! 3988: for(int i = 0; i < MAX_PROCESS; i++) { ! 3989: if(process[i].psp == psp_seg) { ! 3990: return(&process[i]); ! 3991: } ! 3992: } ! 3993: if(show_error) { ! 3994: fatalerror("invalid psp address\n"); ! 3995: } ! 3996: return(NULL); ! 3997: } ! 3998: ! 3999: void msdos_sda_update(int psp_seg) ! 4000: { ! 4001: sda_t *sda = (sda_t *)(mem + SDA_TOP); ! 4002: ! 4003: for(int i = 0; i < MAX_PROCESS; i++) { ! 4004: if(process[i].psp == psp_seg) { ! 4005: sda->switchar = process[i].switchar; ! 4006: sda->current_dta.w.l = process[i].dta.w.l; ! 4007: sda->current_dta.w.h = process[i].dta.w.h; ! 4008: sda->current_psp = process[i].psp; ! 4009: break; ! 4010: } ! 4011: } ! 4012: sda->malloc_strategy = malloc_strategy; ! 4013: sda->return_code = retval; ! 4014: sda->current_drive = _getdrive(); ! 4015: } ! 4016: ! 4017: // dta info ! 4018: ! 4019: void msdos_dta_info_init() ! 4020: { ! 4021: for(int i = 0; i < MAX_DTAINFO; i++) { ! 4022: dtalist[i].find_handle = INVALID_HANDLE_VALUE; ! 4023: } ! 4024: } ! 4025: ! 4026: dtainfo_t *msdos_dta_info_get(UINT16 psp_seg, UINT32 dta_laddr) ! 4027: { ! 4028: dtainfo_t *free_dta = NULL; ! 4029: for(int i = 0; i < MAX_DTAINFO; i++) { ! 4030: if(dtalist[i].find_handle == INVALID_HANDLE_VALUE) { ! 4031: if(free_dta == NULL) { ! 4032: free_dta = &dtalist[i]; ! 4033: } ! 4034: } else if(dta_laddr < LFN_DTA_LADDR && dtalist[i].dta == dta_laddr) { ! 4035: return(&dtalist[i]); ! 4036: } ! 4037: } ! 4038: if(free_dta) { ! 4039: free_dta->psp = psp_seg; ! 4040: free_dta->dta = dta_laddr; ! 4041: return(free_dta); ! 4042: } ! 4043: fatalerror("too many dta\n"); ! 4044: return(NULL); ! 4045: } ! 4046: ! 4047: void msdos_dta_info_free(UINT16 psp_seg) ! 4048: { ! 4049: for(int i = 0; i < MAX_DTAINFO; i++) { ! 4050: if(dtalist[i].psp == psp_seg && dtalist[i].find_handle != INVALID_HANDLE_VALUE) { ! 4051: FindClose(dtalist[i].find_handle); ! 4052: dtalist[i].find_handle = INVALID_HANDLE_VALUE; ! 4053: } ! 4054: } ! 4055: } ! 4056: ! 4057: void msdos_cds_update(int drv) ! 4058: { ! 4059: cds_t *cds = (cds_t *)(mem + CDS_TOP + 88 * drv); ! 4060: ! 4061: memset(cds, 0, 88); ! 4062: ! 4063: if(msdos_is_valid_drive(drv)) { ! 4064: char path[MAX_PATH]; ! 4065: if(msdos_is_remote_drive(drv)) { ! 4066: cds->drive_attrib = 0xc000; // network drive ! 4067: } else if(msdos_is_subst_drive(drv)) { ! 4068: cds->drive_attrib = 0x5000; // subst drive ! 4069: } else { ! 4070: cds->drive_attrib = 0x4000; // physical drive ! 4071: } ! 4072: if(_getdcwd(drv + 1, path, MAX_PATH) != NULL) { ! 4073: strcpy_s(cds->path_name, sizeof(cds->path_name), msdos_short_path(path)); ! 4074: } ! 4075: } ! 4076: if(cds->path_name[0] == '\0') { ! 4077: sprintf(cds->path_name, "%c:\\", 'A' + drv); ! 4078: } ! 4079: cds->dpb_ptr.w.h = DPB_TOP >> 4; ! 4080: cds->dpb_ptr.w.l = sizeof(dpb_t) * drv; ! 4081: cds->word_1 = cds->word_2 = 0xffff; ! 4082: cds->word_3 = 0xffff; // stored user data from INT 21/AX=5F03h if this is network drive ! 4083: cds->bs_offset = 2; ! 4084: } ! 4085: ! 4086: void msdos_cds_update(int drv, const char *path) ! 4087: { ! 4088: cds_t *cds = (cds_t *)(mem + CDS_TOP + 88 * drv); ! 4089: ! 4090: strcpy_s(cds->path_name, sizeof(cds->path_name), msdos_short_path(path)); ! 4091: } ! 4092: ! 4093: // nls information tables ! 4094: ! 4095: // uppercase table (func 6502h) ! 4096: void msdos_upper_table_update() ! 4097: { ! 4098: *(UINT16 *)(mem + UPPERTABLE_TOP) = 0x80; ! 4099: for(unsigned i = 0; i < 0x80; ++i) { ! 4100: UINT8 c[4]; ! 4101: *(UINT32 *)c = 0; // reset internal conversion state ! 4102: CharUpperBuffA((LPSTR)c, 4); // (workaround for MBCS codepage) ! 4103: c[0] = 0x80 + i; ! 4104: DWORD rc = CharUpperBuffA((LPSTR)c, 1); ! 4105: mem[UPPERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i; ! 4106: } ! 4107: } ! 4108: ! 4109: // lowercase table (func 6503h) ! 4110: void msdos_lower_table_update() ! 4111: { ! 4112: *(UINT16 *)(mem + LOWERTABLE_TOP) = 0x80; ! 4113: for(unsigned i = 0; i < 0x80; ++i) { ! 4114: UINT8 c[4]; ! 4115: *(UINT32 *)c = 0; // reset internal conversion state ! 4116: CharLowerBuffA((LPSTR)c, 4); // (workaround for MBCS codepage) ! 4117: c[0] = 0x80 + i; ! 4118: DWORD rc = CharLowerBuffA((LPSTR)c, 1); ! 4119: mem[LOWERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i; ! 4120: } ! 4121: } ! 4122: ! 4123: // filename uppercase table (func 6504h) ! 4124: void msdos_filename_upper_table_init() ! 4125: { ! 4126: // depended on (file)system, not on active codepage ! 4127: // temporary solution: just filling data ! 4128: *(UINT16 *)(mem + FILENAME_UPPERTABLE_TOP) = 0x80; ! 4129: for(unsigned i = 0; i < 0x80; ++i) { ! 4130: mem[FILENAME_UPPERTABLE_TOP + 2 + i] = 0x80 + i; ! 4131: } ! 4132: } ! 4133: ! 4134: // filaname terminator table (func 6505h) ! 4135: void msdos_filename_terminator_table_init() ! 4136: { ! 4137: const char illegal_chars[] = ".\"/\\[]:|<>+=;,"; // for standard MS-DOS fs. ! 4138: UINT8 *data = mem + FILENAME_TERMINATOR_TOP; ! 4139: ! 4140: data[2] = 1; // marker? (permissible character value) ! 4141: data[3] = 0x00; // 00h...FFh ! 4142: data[4] = 0xff; ! 4143: data[5] = 0; // marker? (excluded character) ! 4144: data[6] = 0x00; // 00h...20h ! 4145: data[7] = 0x20; ! 4146: data[8] = 2; // marker? (illegal characters for filename) ! 4147: data[9] = (UINT8)strlen(illegal_chars); ! 4148: memcpy(data + 10, illegal_chars, data[9]); ! 4149: ! 4150: // total length ! 4151: *(UINT16 *)data = (10 - 2) + data[9]; ! 4152: } ! 4153: ! 4154: // collating table (func 6506h) ! 4155: void msdos_collating_table_update() ! 4156: { ! 4157: // temporary solution: just filling data ! 4158: *(UINT16 *)(mem + COLLATING_TABLE_TOP) = 0x100; ! 4159: for(unsigned i = 0; i < 256; ++i) { ! 4160: mem[COLLATING_TABLE_TOP + 2 + i] = i; ! 4161: } ! 4162: } ! 4163: ! 4164: // dbcs ! 4165: ! 4166: void msdos_dbcs_table_update() ! 4167: { ! 4168: UINT8 dbcs_data[DBCS_SIZE]; ! 4169: memset(dbcs_data, 0, sizeof(dbcs_data)); ! 4170: ! 4171: CPINFO info; ! 4172: GetCPInfo(active_code_page, &info); ! 4173: ! 4174: if(info.MaxCharSize != 1) { ! 4175: for(int i = 0;; i += 2) { ! 4176: UINT8 lo = info.LeadByte[i + 0]; ! 4177: UINT8 hi = info.LeadByte[i + 1]; ! 4178: dbcs_data[2 + i + 0] = lo; ! 4179: dbcs_data[2 + i + 1] = hi; ! 4180: if(lo == 0 && hi == 0) { ! 4181: dbcs_data[0] = i + 2; ! 4182: break; ! 4183: } ! 4184: } ! 4185: } else { ! 4186: dbcs_data[0] = 2; // ??? ! 4187: } ! 4188: memcpy(mem + DBCS_TOP, dbcs_data, sizeof(dbcs_data)); ! 4189: } ! 4190: ! 4191: void msdos_dbcs_table_finish() ! 4192: { ! 4193: if(system_code_page != _getmbcp()) { ! 4194: _setmbcp(system_code_page); ! 4195: } ! 4196: if(console_code_page != GetConsoleCP()) { ! 4197: SetConsoleCP(console_code_page); ! 4198: SetConsoleOutputCP(console_code_page); ! 4199: } ! 4200: } ! 4201: ! 4202: void msdos_nls_tables_init() ! 4203: { ! 4204: active_code_page = console_code_page = GetConsoleCP(); ! 4205: system_code_page = _getmbcp(); ! 4206: ! 4207: if(active_code_page != system_code_page) { ! 4208: if(_setmbcp(active_code_page) != 0) { ! 4209: active_code_page = system_code_page; ! 4210: } ! 4211: } ! 4212: ! 4213: msdos_upper_table_update(); ! 4214: msdos_lower_table_update(); ! 4215: msdos_filename_terminator_table_init(); ! 4216: msdos_filename_upper_table_init(); ! 4217: msdos_collating_table_update(); ! 4218: msdos_dbcs_table_update(); ! 4219: } ! 4220: ! 4221: void msdos_nls_tables_update() ! 4222: { ! 4223: msdos_dbcs_table_update(); ! 4224: msdos_upper_table_update(); ! 4225: msdos_lower_table_update(); ! 4226: // msdos_collating_table_update(); ! 4227: } ! 4228: ! 4229: int msdos_lead_byte_check(UINT8 code) ! 4230: { ! 4231: UINT8 *dbcs_table = mem + DBCS_TABLE; ! 4232: ! 4233: for(int i = 0;; i += 2) { ! 4234: UINT8 lo = dbcs_table[i + 0]; ! 4235: UINT8 hi = dbcs_table[i + 1]; ! 4236: if(lo == 0 && hi == 0) { ! 4237: break; ! 4238: } ! 4239: if(lo <= code && code <= hi) { ! 4240: return(1); ! 4241: } ! 4242: } ! 4243: return(0); ! 4244: } ! 4245: ! 4246: int msdos_ctrl_code_check(UINT8 code) ! 4247: { ! 4248: return (code >= 0x01 && code <= 0x1a && code != 0x07 && code != 0x08 && code != 0x09 && code != 0x0a && code != 0x0d); ! 4249: } ! 4250: ! 4251: int msdos_kanji_2nd_byte_check(UINT8 *buf, int n) ! 4252: { ! 4253: int is_kanji_1st = 0; ! 4254: int is_kanji_2nd = 0; ! 4255: ! 4256: for(int p = 0;; p++) { ! 4257: if(is_kanji_1st) { ! 4258: is_kanji_1st = 0; ! 4259: is_kanji_2nd = 1; ! 4260: } else if(msdos_lead_byte_check(buf[p])) { ! 4261: is_kanji_1st = 1; ! 4262: } ! 4263: if(p == n) { ! 4264: return(is_kanji_2nd); ! 4265: } ! 4266: is_kanji_2nd = 0; ! 4267: } ! 4268: } ! 4269: ! 4270: // file control ! 4271: ! 4272: const char *msdos_remove_double_quote(const char *path) ! 4273: { ! 4274: static char tmp[MAX_PATH]; ! 4275: ! 4276: if(strlen(path) >= 2 && path[0] == '"' && path[strlen(path) - 1] == '"') { ! 4277: memset(tmp, 0, sizeof(tmp)); ! 4278: memcpy(tmp, path + 1, strlen(path) - 2); ! 4279: } else { ! 4280: strcpy(tmp, path); ! 4281: } ! 4282: return(tmp); ! 4283: } ! 4284: ! 4285: const char *msdos_remove_end_separator(const char *path) ! 4286: { ! 4287: static char tmp[MAX_PATH]; ! 4288: ! 4289: strcpy(tmp, path); ! 4290: ! 4291: // for example "C:\" case, the end separator should not be removed ! 4292: if(strlen(tmp) > 3 && tmp[strlen(tmp) - 1] == '\\') { ! 4293: tmp[strlen(tmp) - 1] = '\0'; ! 4294: } ! 4295: return(tmp); ! 4296: } ! 4297: ! 4298: const char *msdos_combine_path(const char *dir, const char *file) ! 4299: { ! 4300: static char tmp[MAX_PATH]; ! 4301: const char *tmp_dir = msdos_remove_double_quote(dir); ! 4302: ! 4303: if(strlen(tmp_dir) == 0) { ! 4304: strcpy(tmp, file); ! 4305: } else if(tmp_dir[strlen(tmp_dir) - 1] == '\\') { ! 4306: sprintf(tmp, "%s%s", tmp_dir, file); ! 4307: } else { ! 4308: sprintf(tmp, "%s\\%s", tmp_dir, file); ! 4309: } ! 4310: return(tmp); ! 4311: } ! 4312: ! 4313: const char *msdos_trimmed_path(const char *path, int lfn) ! 4314: { ! 4315: static char tmp[MAX_PATH]; ! 4316: ! 4317: if(lfn) { ! 4318: strcpy(tmp, path); ! 4319: } else { ! 4320: // remove space in the path ! 4321: const char *src = path; ! 4322: char *dst = tmp; ! 4323: ! 4324: while(*src != '\0') { ! 4325: if(msdos_lead_byte_check(*src)) { ! 4326: *dst++ = *src++; ! 4327: *dst++ = *src++; ! 4328: } else if(*src != ' ') { ! 4329: *dst++ = *src++; ! 4330: } else { ! 4331: src++; // skip space ! 4332: } ! 4333: } ! 4334: *dst = '\0'; ! 4335: } ! 4336: if(_stricmp(tmp, "C:\\COMMAND.COM") == 0) { ! 4337: // redirect C:\COMMAND.COM to comspec_path ! 4338: strcpy(tmp, comspec_path); ! 4339: } else if(is_vista_or_later && _access(tmp, 0) != 0) { ! 4340: // redirect new files (without wildcards) in C:\ to %TEMP%, since C:\ is not usually writable ! 4341: static int root_drive_protected = -1; ! 4342: char temp[MAX_PATH], name[MAX_PATH], *name_temp = NULL; ! 4343: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP); ! 4344: ! 4345: if(GetFullPathNameA(tmp, MAX_PATH, temp, &name_temp) != 0 && ! 4346: name_temp != NULL && strstr(name_temp, "?") == NULL && strstr(name_temp, "*") == NULL) { ! 4347: strcpy(name, name_temp); ! 4348: name_temp[0] = '\0'; ! 4349: ! 4350: if((temp[0] == 'A' + dos_info->boot_drive - 1 || temp[0] == 'a' + dos_info->boot_drive - 1) && ! 4351: (temp[1] == ':') && (temp[2] == '\\' || temp[2] == '/') && (temp[3] == '\0')) { ! 4352: if(root_drive_protected == -1) { ! 4353: FILE *fp = NULL; ! 4354: ! 4355: sprintf(temp, "%c:\\MS-DOS_Player.$$$", 'A' + dos_info->boot_drive - 1); ! 4356: root_drive_protected = 1; ! 4357: try { ! 4358: if((fp = fopen(temp, "w")) != NULL) { ! 4359: if(fprintf(fp, "TEST") == 4) { ! 4360: root_drive_protected = 0; ! 4361: } ! 4362: } ! 4363: } catch(...) { ! 4364: } ! 4365: if(fp != NULL) { ! 4366: fclose(fp); ! 4367: } ! 4368: if(_access(temp, 0) == 0) { ! 4369: remove(temp); ! 4370: } ! 4371: } ! 4372: if(root_drive_protected == 1) { ! 4373: if(GetEnvironmentVariableA("TEMP", temp, MAX_PATH) != 0 || ! 4374: GetEnvironmentVariableA("TMP", temp, MAX_PATH) != 0) { ! 4375: strcpy(tmp, msdos_combine_path(temp, name)); ! 4376: } ! 4377: } ! 4378: } ! 4379: } ! 4380: } ! 4381: return(tmp); ! 4382: } ! 4383: ! 4384: const char *msdos_get_multiple_short_path(const char *src) ! 4385: { ! 4386: // "LONGPATH\";"LONGPATH\";"LONGPATH\" to SHORTPATH;SHORTPATH;SHORTPATH ! 4387: static char env_path[ENV_SIZE]; ! 4388: char tmp[ENV_SIZE], *token; ! 4389: ! 4390: memset(env_path, 0, sizeof(env_path)); ! 4391: strcpy(tmp, src); ! 4392: token = my_strtok(tmp, ";"); ! 4393: ! 4394: while(token != NULL) { ! 4395: if(token[0] != '\0') { ! 4396: const char *path = msdos_remove_double_quote(token); ! 4397: char short_path[MAX_PATH]; ! 4398: if(path != NULL && strlen(path) != 0) { ! 4399: if(env_path[0] != '\0') { ! 4400: strcat(env_path, ";"); ! 4401: } ! 4402: if(GetShortPathNameA(path, short_path, MAX_PATH) == 0) { ! 4403: strcat(env_path, msdos_remove_end_separator(path)); ! 4404: } else { ! 4405: my_strupr(short_path); ! 4406: strcat(env_path, msdos_remove_end_separator(short_path)); ! 4407: } ! 4408: } ! 4409: } ! 4410: token = my_strtok(NULL, ";"); ! 4411: } ! 4412: return(env_path); ! 4413: } ! 4414: ! 4415: bool match(const char *text, const char *pattern) ! 4416: { ! 4417: // http://www.prefield.com/algorithm/string/wildcard.html ! 4418: switch(*pattern) { ! 4419: case '\0': ! 4420: return !*text; ! 4421: case '*': ! 4422: return match(text, pattern + 1) || (*text && match(text + 1, pattern)); ! 4423: case '?': ! 4424: return *text && match(text + 1, pattern + 1); ! 4425: default: ! 4426: return (*text == *pattern) && match(text + 1, pattern + 1); ! 4427: } ! 4428: } ! 4429: ! 4430: bool msdos_match_volume_label(const char *path, const char *volume) ! 4431: { ! 4432: const char *p = NULL; ! 4433: ! 4434: if(!*volume) { ! 4435: return false; ! 4436: } else if((p = my_strchr(path, ':')) != NULL) { ! 4437: return msdos_match_volume_label(p + 1, volume); ! 4438: } else if((p = my_strchr(path, '\\')) != NULL) { ! 4439: return msdos_match_volume_label(p + 1, volume); ! 4440: } else if((p = my_strchr(path, '.')) != NULL) { ! 4441: char tmp[MAX_PATH]; ! 4442: sprintf(tmp, "%.*s%s", (int)(p - path), path, p + 1); ! 4443: return match(volume, tmp); ! 4444: } else { ! 4445: return match(volume, path); ! 4446: } ! 4447: } ! 4448: ! 4449: const char *msdos_fcb_path(fcb_t *fcb) ! 4450: { ! 4451: static char tmp[MAX_PATH]; ! 4452: char name[9], ext[4]; ! 4453: ! 4454: memset(name, 0, sizeof(name)); ! 4455: memcpy(name, fcb->file_name, 8); ! 4456: strcpy(name, msdos_trimmed_path(name, 0)); ! 4457: ! 4458: memset(ext, 0, sizeof(ext)); ! 4459: memcpy(ext, fcb->file_name + 8, 3); ! 4460: strcpy(ext, msdos_trimmed_path(ext, 0)); ! 4461: ! 4462: if(name[0] == '\0' || strcmp(name, "????????") == 0) { ! 4463: strcpy(name, "*"); ! 4464: } ! 4465: if(ext[0] == '\0') { ! 4466: strcpy(tmp, name); ! 4467: } else { ! 4468: if(strcmp(ext, "???") == 0) { ! 4469: strcpy(ext, "*"); ! 4470: } ! 4471: sprintf(tmp, "%s.%s", name, ext); ! 4472: } ! 4473: return(tmp); ! 4474: } ! 4475: ! 4476: void msdos_set_fcb_path(fcb_t *fcb, const char *path) ! 4477: { ! 4478: char tmp[MAX_PATH]; ! 4479: strcpy(tmp, path); ! 4480: char *ext = my_strchr(tmp, '.'); ! 4481: ! 4482: memset(fcb->file_name, 0x20, 8 + 3); ! 4483: if(ext != NULL && tmp[0] != '.') { ! 4484: *ext = '\0'; ! 4485: memcpy(fcb->file_name + 8, ext + 1, strlen(ext + 1)); ! 4486: } ! 4487: memcpy(fcb->file_name, tmp, strlen(tmp)); ! 4488: } ! 4489: ! 4490: const char *msdos_short_path(const char *path) ! 4491: { ! 4492: static char tmp[MAX_PATH]; ! 4493: ! 4494: if(GetShortPathNameA(path, tmp, MAX_PATH) == 0) { ! 4495: strcpy(tmp, path); ! 4496: } ! 4497: my_strupr(tmp); ! 4498: return(tmp); ! 4499: } ! 4500: ! 4501: const char *msdos_short_name(WIN32_FIND_DATAA *fd) ! 4502: { ! 4503: static char tmp[MAX_PATH]; ! 4504: ! 4505: if(fd->cAlternateFileName[0]) { ! 4506: strcpy(tmp, fd->cAlternateFileName); ! 4507: } else { ! 4508: strcpy(tmp, fd->cFileName); ! 4509: } ! 4510: my_strupr(tmp); ! 4511: return(tmp); ! 4512: } ! 4513: ! 4514: const char *msdos_short_full_path(const char *path) ! 4515: { ! 4516: static char tmp[MAX_PATH]; ! 4517: char full[MAX_PATH], *name; ! 4518: ! 4519: // Full works with non-existent files, but Short does not ! 4520: GetFullPathNameA(path, MAX_PATH, full, &name); ! 4521: *tmp = '\0'; ! 4522: if(GetShortPathNameA(full, tmp, MAX_PATH) == 0 && name > path) { ! 4523: name[-1] = '\0'; ! 4524: DWORD len = GetShortPathNameA(full, tmp, MAX_PATH); ! 4525: if(len == 0) { ! 4526: strcpy(tmp, full); ! 4527: } else { ! 4528: tmp[len++] = '\\'; ! 4529: strcpy(tmp + len, name); ! 4530: } ! 4531: } ! 4532: my_strupr(tmp); ! 4533: return(tmp); ! 4534: } ! 4535: ! 4536: const char *msdos_short_full_dir(const char *path) ! 4537: { ! 4538: static char tmp[MAX_PATH]; ! 4539: char full[MAX_PATH], *name; ! 4540: ! 4541: GetFullPathNameA(path, MAX_PATH, full, &name); ! 4542: name[-1] = '\0'; ! 4543: if(GetShortPathNameA(full, tmp, MAX_PATH) == 0) { ! 4544: strcpy(tmp, full); ! 4545: } ! 4546: my_strupr(tmp); ! 4547: return(tmp); ! 4548: } ! 4549: ! 4550: const char *msdos_local_file_path(const char *path, int lfn) ! 4551: { ! 4552: static char trimmed[MAX_PATH]; ! 4553: ! 4554: strcpy(trimmed, msdos_trimmed_path(path, lfn)); ! 4555: #if 0 ! 4556: // I have forgotten the reason of this routine... :-( ! 4557: if(_access(trimmed, 0) != 0) { ! 4558: process_t *process = msdos_process_info_get(current_psp); ! 4559: static char tmp[MAX_PATH]; ! 4560: ! 4561: sprintf(tmp, "%s\\%s", process->module_dir, trimmed); ! 4562: if(_access(tmp, 0) == 0) { ! 4563: return(tmp); ! 4564: } ! 4565: } ! 4566: #endif ! 4567: return(trimmed); ! 4568: } ! 4569: ! 4570: bool msdos_is_device_path(const char *path) ! 4571: { ! 4572: char full[MAX_PATH], *name; ! 4573: ! 4574: if(GetFullPathNameA(path, MAX_PATH, full, &name) != 0) { ! 4575: if(_stricmp(full, "\\\\.\\AUX" ) == 0 || ! 4576: _stricmp(full, "\\\\.\\CON" ) == 0 || ! 4577: _stricmp(full, "\\\\.\\NUL" ) == 0 || ! 4578: _stricmp(full, "\\\\.\\PRN" ) == 0 || ! 4579: _stricmp(full, "\\\\.\\COM1") == 0 || ! 4580: _stricmp(full, "\\\\.\\COM2") == 0 || ! 4581: _stricmp(full, "\\\\.\\COM3") == 0 || ! 4582: _stricmp(full, "\\\\.\\COM4") == 0 || ! 4583: _stricmp(full, "\\\\.\\COM5") == 0 || ! 4584: _stricmp(full, "\\\\.\\COM6") == 0 || ! 4585: _stricmp(full, "\\\\.\\COM7") == 0 || ! 4586: _stricmp(full, "\\\\.\\COM8") == 0 || ! 4587: _stricmp(full, "\\\\.\\COM9") == 0 || ! 4588: _stricmp(full, "\\\\.\\LPT1") == 0 || ! 4589: _stricmp(full, "\\\\.\\LPT2") == 0 || ! 4590: _stricmp(full, "\\\\.\\LPT3") == 0 || ! 4591: _stricmp(full, "\\\\.\\LPT4") == 0 || ! 4592: _stricmp(full, "\\\\.\\LPT5") == 0 || ! 4593: _stricmp(full, "\\\\.\\LPT6") == 0 || ! 4594: _stricmp(full, "\\\\.\\LPT7") == 0 || ! 4595: _stricmp(full, "\\\\.\\LPT8") == 0 || ! 4596: _stricmp(full, "\\\\.\\LPT9") == 0) { ! 4597: return(true); ! 4598: } else if(name != NULL) { ! 4599: if(_stricmp(name, "CLOCK$" ) == 0 || ! 4600: _stricmp(name, "CONFIG$" ) == 0 || ! 4601: _stricmp(name, "EMMXXXX0") == 0 || ! 4602: // _stricmp(name, "SCSIMGR$") == 0 || ! 4603: _stricmp(name, "$IBMAIAS") == 0) { ! 4604: return(true); ! 4605: } ! 4606: } ! 4607: } ! 4608: return(false); ! 4609: } ! 4610: ! 4611: bool msdos_is_con_path(const char *path) ! 4612: { ! 4613: char full[MAX_PATH], *name; ! 4614: ! 4615: if(GetFullPathNameA(path, MAX_PATH, full, &name) != 0) { ! 4616: return(_stricmp(full, "\\\\.\\CON") == 0); ! 4617: } ! 4618: return(false); ! 4619: } ! 4620: ! 4621: int msdos_is_comm_path(const char *path) ! 4622: { ! 4623: char full[MAX_PATH], *name; ! 4624: ! 4625: if(GetFullPathNameA(path, MAX_PATH, full, &name) != 0) { ! 4626: if(_stricmp(full, "\\\\.\\COM1") == 0) { ! 4627: return(1); ! 4628: } else if(_stricmp(full, "\\\\.\\COM2") == 0) { ! 4629: return(2); ! 4630: } else if(_stricmp(full, "\\\\.\\COM3") == 0) { ! 4631: return(3); ! 4632: } else if(_stricmp(full, "\\\\.\\COM4") == 0) { ! 4633: return(4); ! 4634: } ! 4635: } ! 4636: return(0); ! 4637: } ! 4638: ! 4639: void msdos_set_comm_params(int sio_port, const char *path) ! 4640: { ! 4641: // COM1:{110,150,300,600,1200,2400,4800,9600},{N,O,E,M,S},{8,7,6,5},{1,1.5,2} ! 4642: const char *p = NULL; ! 4643: ! 4644: if((p = strstr(path, ":")) != NULL) { ! 4645: UINT8 selector = sio_read(sio_port - 1, 3); ! 4646: ! 4647: // baud rate ! 4648: int baud = max(110, min(9600, atoi(p + 1))); ! 4649: UINT16 divisor = 115200 / baud; ! 4650: ! 4651: if((p = strstr(p + 1, ",")) != NULL) { ! 4652: // parity ! 4653: if(p[1] == 'N' || p[1] == 'n') { ! 4654: selector = (selector & ~0x38) | 0x00; ! 4655: } else if(p[1] == 'O' || p[1] == 'o') { ! 4656: selector = (selector & ~0x38) | 0x08; ! 4657: } else if(p[1] == 'E' || p[1] == 'e') { ! 4658: selector = (selector & ~0x38) | 0x18; ! 4659: } else if(p[1] == 'M' || p[1] == 'm') { ! 4660: selector = (selector & ~0x38) | 0x28; ! 4661: } else if(p[1] == 'S' || p[1] == 's') { ! 4662: selector = (selector & ~0x38) | 0x38; ! 4663: } ! 4664: if((p = strstr(p + 1, ",")) != NULL) { ! 4665: // word length ! 4666: if(p[1] == '8') { ! 4667: selector = (selector & ~0x03) | 0x03; ! 4668: } else if(p[1] == '7') { ! 4669: selector = (selector & ~0x03) | 0x02; ! 4670: } else if(p[1] == '6') { ! 4671: selector = (selector & ~0x03) | 0x01; ! 4672: } else if(p[1] == '5') { ! 4673: selector = (selector & ~0x03) | 0x00; ! 4674: } ! 4675: if((p = strstr(p + 1, ",")) != NULL) { ! 4676: // stop bits ! 4677: float bits = atof(p + 1); ! 4678: if(bits > 1.0F) { ! 4679: selector |= 0x04; ! 4680: } else { ! 4681: selector &= ~0x04; ! 4682: } ! 4683: } ! 4684: } ! 4685: } ! 4686: sio_write(sio_port - 1, 3, selector | 0x80); ! 4687: sio_write(sio_port - 1, 0, divisor & 0xff); ! 4688: sio_write(sio_port - 1, 1, divisor >> 8); ! 4689: sio_write(sio_port - 1, 3, selector); ! 4690: } ! 4691: } ! 4692: ! 4693: int msdos_is_prn_path(const char *path) ! 4694: { ! 4695: char full[MAX_PATH], *name; ! 4696: ! 4697: if(GetFullPathNameA(path, MAX_PATH, full, &name) != 0) { ! 4698: if(_stricmp(full, "\\\\.\\PRN") == 0) { ! 4699: return(1); ! 4700: } else if(_stricmp(full, "\\\\.\\LPT1") == 0) { ! 4701: return(1); ! 4702: } else if(_stricmp(full, "\\\\.\\LPT2") == 0) { ! 4703: return(2); ! 4704: } else if(_stricmp(full, "\\\\.\\LPT3") == 0) { ! 4705: return(3); ! 4706: } ! 4707: } ! 4708: return(0); ! 4709: } ! 4710: ! 4711: bool msdos_is_valid_drive(int drv) ! 4712: { ! 4713: return(drv >= 0 && drv < 26 && (GetLogicalDrives() & (1 << drv)) != 0); ! 4714: } ! 4715: ! 4716: bool msdos_is_removable_drive(int drv) ! 4717: { ! 4718: char volume[] = "A:\\"; ! 4719: ! 4720: volume[0] = 'A' + drv; ! 4721: ! 4722: return(GetDriveTypeA(volume) == DRIVE_REMOVABLE); ! 4723: } ! 4724: ! 4725: bool msdos_is_cdrom_drive(int drv) ! 4726: { ! 4727: char volume[] = "A:\\"; ! 4728: ! 4729: volume[0] = 'A' + drv; ! 4730: ! 4731: return(GetDriveTypeA(volume) == DRIVE_CDROM); ! 4732: } ! 4733: ! 4734: bool msdos_is_remote_drive(int drv) ! 4735: { ! 4736: char volume[] = "A:\\"; ! 4737: ! 4738: volume[0] = 'A' + drv; ! 4739: ! 4740: return(GetDriveTypeA(volume) == DRIVE_REMOTE); ! 4741: } ! 4742: ! 4743: bool msdos_is_subst_drive(int drv) ! 4744: { ! 4745: char device[] = "A:", path[MAX_PATH]; ! 4746: ! 4747: device[0] = 'A' + drv; ! 4748: ! 4749: if(QueryDosDeviceA(device, path, MAX_PATH)) { ! 4750: if(strncmp(path, "\\??\\", 4) == 0) { ! 4751: return(true); ! 4752: } ! 4753: } ! 4754: return(false); ! 4755: } ! 4756: ! 4757: bool msdos_is_existing_file(const char *path) ! 4758: { ! 4759: // http://d.hatena.ne.jp/yu-hr/20100317/1268826458 ! 4760: WIN32_FIND_DATAA fd; ! 4761: HANDLE hFind; ! 4762: ! 4763: if((hFind = FindFirstFileA(path, &fd)) != INVALID_HANDLE_VALUE) { ! 4764: FindClose(hFind); ! 4765: return((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0); ! 4766: } ! 4767: return(false); ! 4768: } ! 4769: ! 4770: bool msdos_is_existing_dir(const char *path) ! 4771: { ! 4772: // http://d.hatena.ne.jp/yu-hr/20100317/1268826458 ! 4773: WIN32_FIND_DATAA fd; ! 4774: HANDLE hFind; ! 4775: ! 4776: if((hFind = FindFirstFileA(path, &fd)) != INVALID_HANDLE_VALUE) { ! 4777: FindClose(hFind); ! 4778: return((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0); ! 4779: } ! 4780: return(false); ! 4781: } ! 4782: ! 4783: const char *msdos_search_command_com(const char *command_path, const char *env_path) ! 4784: { ! 4785: static char tmp[MAX_PATH]; ! 4786: char path[ENV_SIZE], *file_name; ! 4787: ! 4788: // check if COMMAND.COM is in the same directory as the target program file ! 4789: if(GetFullPathNameA(command_path, MAX_PATH, tmp, &file_name) != 0) { ! 4790: sprintf(file_name, "COMMAND.COM"); ! 4791: if(_access(tmp, 0) == 0) { ! 4792: return(tmp); ! 4793: } ! 4794: } ! 4795: ! 4796: // check if COMMAND.COM is in the same directory as the running msdos.exe ! 4797: if(GetModuleFileNameA(NULL, path, MAX_PATH) != 0 && GetFullPathNameA(path, MAX_PATH, tmp, &file_name) != 0) { ! 4798: sprintf(file_name, "COMMAND.COM"); ! 4799: if(_access(tmp, 0) == 0) { ! 4800: return(tmp); ! 4801: } ! 4802: } ! 4803: ! 4804: // check if COMMAND.COM is in the current directory ! 4805: if(GetFullPathNameA("COMMAND.COM", MAX_PATH, tmp, &file_name) != 0) { ! 4806: if(_access(tmp, 0) == 0) { ! 4807: return(tmp); ! 4808: } ! 4809: } ! 4810: ! 4811: // cehck if COMMAND.COM is in the directory that is in MSDOS_PATH and PATH environment variables ! 4812: strcpy(path, env_path); ! 4813: char *token = my_strtok(path, ";"); ! 4814: while(token != NULL) { ! 4815: if(strlen(token) != 0 && token[0] != '%') { ! 4816: strcpy(tmp, msdos_combine_path(token, "COMMAND.COM")); ! 4817: if(_access(tmp, 0) == 0) { ! 4818: return(tmp); ! 4819: } ! 4820: } ! 4821: token = my_strtok(NULL, ";"); ! 4822: } ! 4823: return(NULL); ! 4824: } ! 4825: ! 4826: int msdos_drive_number(const char *path) ! 4827: { ! 4828: char tmp[MAX_PATH], *name; ! 4829: ! 4830: if(GetFullPathNameA(path, MAX_PATH, tmp, &name) >= 2 && tmp[1] == ':') { ! 4831: if(tmp[0] >= 'a' && tmp[0] <= 'z') { ! 4832: return(tmp[0] - 'a'); ! 4833: } else if(tmp[0] >= 'A' && tmp[0] <= 'Z') { ! 4834: return(tmp[0] - 'A'); ! 4835: } ! 4836: } ! 4837: // return(msdos_drive_number(".")); ! 4838: return(_getdrive() - 1); ! 4839: } ! 4840: ! 4841: const char *msdos_volume_label(const char *path) ! 4842: { ! 4843: static char tmp[MAX_PATH]; ! 4844: char volume[] = "A:\\"; ! 4845: ! 4846: if(path[1] == ':') { ! 4847: volume[0] = path[0]; ! 4848: } else { ! 4849: volume[0] = 'A' + _getdrive() - 1; ! 4850: } ! 4851: if(!GetVolumeInformationA(volume, tmp, MAX_PATH, NULL, NULL, NULL, NULL, 0)) { ! 4852: memset(tmp, 0, sizeof(tmp)); ! 4853: } ! 4854: return(tmp); ! 4855: } ! 4856: ! 4857: const char *msdos_short_volume_label(const char *label) ! 4858: { ! 4859: static char tmp[(8 + 1 + 3) + 1]; ! 4860: const char *src = label; ! 4861: int remain = strlen(label); ! 4862: char *dst_n = tmp; ! 4863: char *dst_e = tmp + 9; ! 4864: ! 4865: strcpy(tmp, " . "); ! 4866: for(int i = 0; i < 8 && remain > 0; i++) { ! 4867: if(msdos_lead_byte_check(*src)) { ! 4868: if(++i == 8) { ! 4869: break; ! 4870: } ! 4871: *dst_n++ = *src++; ! 4872: remain--; ! 4873: } ! 4874: *dst_n++ = *src++; ! 4875: remain--; ! 4876: } ! 4877: if(remain > 0) { ! 4878: for(int i = 0; i < 3 && remain > 0; i++) { ! 4879: if(msdos_lead_byte_check(*src)) { ! 4880: if(++i == 3) { ! 4881: break; ! 4882: } ! 4883: *dst_e++ = *src++; ! 4884: remain--; ! 4885: } ! 4886: *dst_e++ = *src++; ! 4887: remain--; ! 4888: } ! 4889: *dst_e = '\0'; ! 4890: } else { ! 4891: *dst_n = '\0'; ! 4892: } ! 4893: my_strupr(tmp); ! 4894: return(tmp); ! 4895: } ! 4896: ! 4897: errno_t msdos_maperr(unsigned long oserrno) ! 4898: { ! 4899: _doserrno = oserrno; ! 4900: switch(oserrno) { ! 4901: case ERROR_FILE_NOT_FOUND: // 2 ! 4902: case ERROR_PATH_NOT_FOUND: // 3 ! 4903: case ERROR_INVALID_DRIVE: // 15 ! 4904: case ERROR_NO_MORE_FILES: // 18 ! 4905: case ERROR_BAD_NETPATH: // 53 ! 4906: case ERROR_BAD_NET_NAME: // 67 ! 4907: case ERROR_BAD_PATHNAME: // 161 ! 4908: case ERROR_FILENAME_EXCED_RANGE: // 206 ! 4909: return ENOENT; ! 4910: case ERROR_TOO_MANY_OPEN_FILES: // 4 ! 4911: return EMFILE; ! 4912: case ERROR_ACCESS_DENIED: // 5 ! 4913: case ERROR_CURRENT_DIRECTORY: // 16 ! 4914: case ERROR_NETWORK_ACCESS_DENIED: // 65 ! 4915: case ERROR_CANNOT_MAKE: // 82 ! 4916: case ERROR_FAIL_I24: // 83 ! 4917: case ERROR_DRIVE_LOCKED: // 108 ! 4918: case ERROR_SEEK_ON_DEVICE: // 132 ! 4919: case ERROR_NOT_LOCKED: // 158 ! 4920: case ERROR_LOCK_FAILED: // 167 ! 4921: return EACCES; ! 4922: case ERROR_INVALID_HANDLE: // 6 ! 4923: case ERROR_INVALID_TARGET_HANDLE: // 114 ! 4924: case ERROR_DIRECT_ACCESS_HANDLE: // 130 ! 4925: return EBADF; ! 4926: case ERROR_ARENA_TRASHED: // 7 ! 4927: case ERROR_NOT_ENOUGH_MEMORY: // 8 ! 4928: case ERROR_INVALID_BLOCK: // 9 ! 4929: case ERROR_NOT_ENOUGH_QUOTA: // 1816 ! 4930: return ENOMEM; ! 4931: case ERROR_BAD_ENVIRONMENT: // 10 ! 4932: return E2BIG; ! 4933: case ERROR_BAD_FORMAT: // 11 ! 4934: return ENOEXEC; ! 4935: case ERROR_NOT_SAME_DEVICE: // 17 ! 4936: return EXDEV; ! 4937: case ERROR_FILE_EXISTS: // 80 ! 4938: case ERROR_ALREADY_EXISTS: // 183 ! 4939: return EEXIST; ! 4940: case ERROR_NO_PROC_SLOTS: // 89 ! 4941: case ERROR_MAX_THRDS_REACHED: // 164 ! 4942: case ERROR_NESTING_NOT_ALLOWED: // 215 ! 4943: return EAGAIN; ! 4944: case ERROR_BROKEN_PIPE: // 109 ! 4945: return EPIPE; ! 4946: case ERROR_DISK_FULL: // 112 ! 4947: return ENOSPC; ! 4948: case ERROR_WAIT_NO_CHILDREN: // 128 ! 4949: case ERROR_CHILD_NOT_COMPLETE: // 129 ! 4950: return ECHILD; ! 4951: case ERROR_DIR_NOT_EMPTY: // 145 ! 4952: return ENOTEMPTY; ! 4953: } ! 4954: if(oserrno >= ERROR_WRITE_PROTECT /* 19 */ && ! 4955: oserrno <= ERROR_SHARING_BUFFER_EXCEEDED /* 36 */) { ! 4956: return EACCES; ! 4957: } ! 4958: if(oserrno >= ERROR_INVALID_STARTING_CODESEG /* 188 */ && ! 4959: oserrno <= ERROR_INFLOOP_IN_RELOC_CHAIN /* 202 */) { ! 4960: return ENOEXEC; ! 4961: } ! 4962: return EINVAL; ! 4963: } ! 4964: ! 4965: int msdos_open(const char *path, int oflag) ! 4966: { ! 4967: if((oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) != _O_RDONLY) { ! 4968: return(_open(path, oflag)); ! 4969: } ! 4970: ! 4971: SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, !(oflag & _O_NOINHERIT) }; ! 4972: DWORD disposition; ! 4973: switch(oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) { ! 4974: default: ! 4975: case _O_EXCL: ! 4976: disposition = OPEN_EXISTING; ! 4977: break; ! 4978: case _O_CREAT: ! 4979: disposition = OPEN_ALWAYS; ! 4980: break; ! 4981: case _O_CREAT | _O_EXCL: ! 4982: case _O_CREAT | _O_TRUNC | _O_EXCL: ! 4983: disposition = CREATE_NEW; ! 4984: break; ! 4985: case _O_TRUNC: ! 4986: case _O_TRUNC | _O_EXCL: ! 4987: disposition = TRUNCATE_EXISTING; ! 4988: break; ! 4989: case _O_CREAT | _O_TRUNC: ! 4990: disposition = CREATE_ALWAYS; ! 4991: break; ! 4992: } ! 4993: ! 4994: HANDLE h = CreateFileA(path, GENERIC_READ | FILE_WRITE_ATTRIBUTES, ! 4995: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition, ! 4996: FILE_ATTRIBUTE_NORMAL, NULL); ! 4997: if(h == INVALID_HANDLE_VALUE) { ! 4998: // FILE_WRITE_ATTRIBUTES may not be granted for standard users. ! 4999: // Retry without FILE_WRITE_ATTRIBUTES. ! 5000: h = CreateFileA(path, GENERIC_READ, ! 5001: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition, ! 5002: FILE_ATTRIBUTE_NORMAL, NULL); ! 5003: if(h == INVALID_HANDLE_VALUE) { ! 5004: errno = msdos_maperr(GetLastError()); ! 5005: return(-1); ! 5006: } ! 5007: } ! 5008: ! 5009: int fd = _open_osfhandle((intptr_t) h, oflag); ! 5010: if(fd == -1) { ! 5011: CloseHandle(h); ! 5012: } ! 5013: return(fd); ! 5014: } ! 5015: ! 5016: int msdos_open_device(const char *path, int oflag, int *sio_port, int *lpt_port) ! 5017: { ! 5018: int fd = -1; ! 5019: ! 5020: *sio_port = *lpt_port = 0; ! 5021: ! 5022: if(msdos_is_con_path(path)) { ! 5023: // MODE.COM opens CON device with read/write mode :-( ! 5024: if((oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) == _O_RDWR) { ! 5025: oflag &= ~(_O_RDONLY | _O_WRONLY | _O_RDWR); ! 5026: oflag |= _O_RDONLY; ! 5027: } ! 5028: if((fd = msdos_open("CON", oflag)) == -1) { ! 5029: // fd = msdos_open("NUL", oflag); ! 5030: } ! 5031: } else if((*sio_port = msdos_is_comm_path(path)) != 0) { ! 5032: fd = msdos_open("NUL", oflag); ! 5033: msdos_set_comm_params(*sio_port, path); ! 5034: } else if((*lpt_port = msdos_is_prn_path(path)) != 0) { ! 5035: fd = msdos_open("NUL", oflag); ! 5036: } else if(msdos_is_device_path(path)) { ! 5037: fd = msdos_open("NUL", oflag); ! 5038: // } else if(oflag & _O_CREAT) { ! 5039: // fd = _open(path, oflag, _S_IREAD | _S_IWRITE); ! 5040: // } else { ! 5041: // fd = _open(path, oflag); ! 5042: } ! 5043: return(fd); ! 5044: } ! 5045: ! 5046: UINT16 msdos_device_info(const char *path) ! 5047: { ! 5048: if(msdos_is_con_path(path)) { ! 5049: return(0x80d3); ! 5050: } else if(msdos_is_comm_path(path)) { ! 5051: return(0x80a0); ! 5052: } else if(msdos_is_prn_path(path)) { ! 5053: // return(0xa8c0); ! 5054: return(0x80a0); ! 5055: } else if(msdos_is_device_path(path)) { ! 5056: if(strstr(path, "EMMXXXX0") != NULL) { ! 5057: return(0xc0c0); ! 5058: } else if(strstr(path, "MSCD001") != NULL) { ! 5059: return(0xc880); ! 5060: } else { ! 5061: return(0x8084); ! 5062: } ! 5063: } else { ! 5064: return(msdos_drive_number(path)); ! 5065: } ! 5066: } ! 5067: ! 5068: void msdos_file_handler_open(int fd, const char *path, int atty, int mode, UINT16 info, UINT16 psp_seg, int sio_port = 0, int lpt_port = 0) ! 5069: { ! 5070: static int id = 0; ! 5071: char full[MAX_PATH], *name; ! 5072: ! 5073: if(GetFullPathNameA(path, MAX_PATH, full, &name) != 0) { ! 5074: strcpy(file_handler[fd].path, full); ! 5075: } else { ! 5076: strcpy(file_handler[fd].path, path); ! 5077: } ! 5078: // isatty makes no distinction between CON & NUL ! 5079: // GetFileSize fails on CON, succeeds on NUL ! 5080: if(atty && (info != 0x80d3 || GetFileSize((HANDLE)_get_osfhandle(fd), NULL) == 0)) { ! 5081: if(info == 0x80d3) { ! 5082: info = 0x8084; ! 5083: } ! 5084: atty = 0; ! 5085: } else if(!atty && info == 0x80d3) { ! 5086: // info = msdos_drive_number("."); ! 5087: info = msdos_drive_number(path); ! 5088: } ! 5089: file_handler[fd].valid = 1; ! 5090: file_handler[fd].id = id++; // dummy id for int 21h ax=71a6h ! 5091: file_handler[fd].atty = (sio_port == 0 && lpt_port == 0) ? atty : 0; ! 5092: file_handler[fd].mode = mode; ! 5093: file_handler[fd].info = info; ! 5094: file_handler[fd].psp = psp_seg; ! 5095: file_handler[fd].sio_port = sio_port; ! 5096: file_handler[fd].lpt_port = lpt_port; ! 5097: ! 5098: // init system file table ! 5099: if(fd < 20) { ! 5100: UINT8 *sft = mem + SFT_TOP + 6 + 0x3b * fd; ! 5101: ! 5102: memset(sft, 0, 0x3b); ! 5103: ! 5104: *(UINT16 *)(sft + 0x00) = 1; ! 5105: *(UINT16 *)(sft + 0x02) = file_handler[fd].mode; ! 5106: *(UINT8 *)(sft + 0x04) = GetFileAttributesA(file_handler[fd].path) & 0xff; ! 5107: *(UINT16 *)(sft + 0x05) = file_handler[fd].info & 0xff; ! 5108: ! 5109: if(!(file_handler[fd].info & 0x80)) { ! 5110: *(UINT16 *)(sft + 0x07) = sizeof(dpb_t) * (file_handler[fd].info & 0x1f); ! 5111: *(UINT16 *)(sft + 0x09) = DPB_TOP >> 4; ! 5112: ! 5113: FILETIME time, local; ! 5114: HANDLE hHandle; ! 5115: WORD dos_date = 0, dos_time = 0; ! 5116: DWORD file_size = 0; ! 5117: if((hHandle = (HANDLE)_get_osfhandle(fd)) != INVALID_HANDLE_VALUE) { ! 5118: if(GetFileTime(hHandle, NULL, NULL, &time)) { ! 5119: FileTimeToLocalFileTime(&time, &local); ! 5120: FileTimeToDosDateTime(&local, &dos_date, &dos_time); ! 5121: } ! 5122: file_size = GetFileSize(hHandle, NULL); ! 5123: } ! 5124: *(UINT16 *)(sft + 0x0d) = dos_time; ! 5125: *(UINT16 *)(sft + 0x0f) = dos_date; ! 5126: *(UINT32 *)(sft + 0x11) = file_size; ! 5127: } ! 5128: ! 5129: char fname[MAX_PATH] = {0}, ext[MAX_PATH] = {0}; ! 5130: _splitpath(file_handler[fd].path, NULL, NULL, fname, ext); ! 5131: my_strupr(fname); ! 5132: my_strupr(ext); ! 5133: memset(sft + 0x20, 0x20, 11); ! 5134: memcpy(sft + 0x20, fname, min(strlen(fname), 8)); ! 5135: memcpy(sft + 0x28, ext + 1, min(strlen(ext + 1), 3)); ! 5136: ! 5137: *(UINT16 *)(sft + 0x31) = psp_seg; ! 5138: } ! 5139: } ! 5140: ! 5141: void msdos_file_handler_dup(int dst, int src, UINT16 psp_seg) ! 5142: { ! 5143: strcpy(file_handler[dst].path, file_handler[src].path); ! 5144: file_handler[dst].valid = 1; ! 5145: file_handler[dst].id = file_handler[src].id; ! 5146: file_handler[dst].atty = file_handler[src].atty; ! 5147: file_handler[dst].mode = file_handler[src].mode; ! 5148: file_handler[dst].info = file_handler[src].info; ! 5149: file_handler[dst].psp = psp_seg; ! 5150: file_handler[dst].sio_port = file_handler[src].sio_port; ! 5151: file_handler[dst].lpt_port = file_handler[src].lpt_port; ! 5152: } ! 5153: ! 5154: void msdos_file_handler_close(int fd) ! 5155: { ! 5156: file_handler[fd].valid = 0; ! 5157: ! 5158: if(fd < 20) { ! 5159: memset(mem + SFT_TOP + 6 + 0x3b * fd, 0, 0x3b); ! 5160: } ! 5161: } ! 5162: ! 5163: inline int msdos_file_attribute_create(UINT16 new_attr) ! 5164: { ! 5165: return(new_attr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | ! 5166: FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE | ! 5167: FILE_ATTRIBUTE_DIRECTORY)); ! 5168: } ! 5169: ! 5170: // find file ! 5171: ! 5172: int msdos_find_file_check_attribute(int attribute, int allowed_mask, int required_mask) ! 5173: { ! 5174: if((allowed_mask & 0x08) && !(attribute & FILE_ATTRIBUTE_DIRECTORY)) { ! 5175: return(0); // search directory only !!! ! 5176: } else if(!(allowed_mask & 0x02) && (attribute & FILE_ATTRIBUTE_HIDDEN)) { ! 5177: return(0); ! 5178: } else if(!(allowed_mask & 0x04) && (attribute & FILE_ATTRIBUTE_SYSTEM)) { ! 5179: return(0); ! 5180: } else if(!(allowed_mask & 0x10) && (attribute & FILE_ATTRIBUTE_DIRECTORY)) { ! 5181: return(0); ! 5182: } else if((attribute & required_mask) != required_mask) { ! 5183: return(0); ! 5184: } else { ! 5185: return(1); ! 5186: } ! 5187: } ! 5188: ! 5189: int msdos_find_file_has_8dot3name(WIN32_FIND_DATAA *fd) ! 5190: { ! 5191: if(fd->cAlternateFileName[0]) { ! 5192: return(1); ! 5193: } ! 5194: size_t len = strlen(fd->cFileName); ! 5195: if(len > 12) { ! 5196: return(0); ! 5197: } ! 5198: const char *ext = strrchr(fd->cFileName, '.'); ! 5199: if((ext ? ext - fd->cFileName : len) > 8) { ! 5200: return(0); ! 5201: } ! 5202: return(1); ! 5203: } ! 5204: ! 5205: void msdos_find_file_conv_local_time(WIN32_FIND_DATAA *fd) ! 5206: { ! 5207: FILETIME local; ! 5208: ! 5209: FileTimeToLocalFileTime(&fd->ftCreationTime, &local); ! 5210: fd->ftCreationTime.dwLowDateTime = local.dwLowDateTime; ! 5211: fd->ftCreationTime.dwHighDateTime = local.dwHighDateTime; ! 5212: ! 5213: FileTimeToLocalFileTime(&fd->ftLastAccessTime, &local); ! 5214: fd->ftLastAccessTime.dwLowDateTime = local.dwLowDateTime; ! 5215: fd->ftLastAccessTime.dwHighDateTime = local.dwHighDateTime; ! 5216: ! 5217: FileTimeToLocalFileTime(&fd->ftLastWriteTime, &local); ! 5218: fd->ftLastWriteTime.dwLowDateTime = local.dwLowDateTime; ! 5219: fd->ftLastWriteTime.dwHighDateTime = local.dwHighDateTime; ! 5220: } ! 5221: ! 5222: // i/o ! 5223: ! 5224: void msdos_stdio_reopen() ! 5225: { ! 5226: if(!file_handler[0].valid) { ! 5227: _dup2(DUP_STDIN, 0); ! 5228: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0); ! 5229: } ! 5230: if(!file_handler[1].valid) { ! 5231: _dup2(DUP_STDOUT, 1); ! 5232: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0); ! 5233: } ! 5234: if(!file_handler[2].valid) { ! 5235: _dup2(DUP_STDERR, 2); ! 5236: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0); ! 5237: } ! 5238: if(!file_handler[3].valid) { ! 5239: _dup2(DUP_STDAUX, 3); ! 5240: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0); ! 5241: } ! 5242: if(!file_handler[4].valid) { ! 5243: _dup2(DUP_STDPRN, 4); ! 5244: // msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0, 0, 1); // LPT1 ! 5245: msdos_file_handler_open(4, "STDPRN", 0, 1, 0x80a0, 0, 0, 1); // LPT1 ! 5246: } ! 5247: for(int i = 0; i < 5; i++) { ! 5248: if(msdos_psp_get_file_table(i, current_psp) == 0xff) { ! 5249: msdos_psp_set_file_table(i, i, current_psp); ! 5250: } ! 5251: } ! 5252: } ! 5253: ! 5254: int msdos_read(int fd, void *buffer, unsigned int count) ! 5255: { ! 5256: if(fd < process->max_files && file_handler[fd].valid && file_handler[fd].sio_port >= 1 && file_handler[fd].sio_port <= 4) { ! 5257: // read from serial port ! 5258: int read = 0; ! 5259: if(sio_port_number[file_handler[fd].sio_port - 1] != 0) { ! 5260: UINT8 *buf = (UINT8 *)buffer; ! 5261: UINT8 selector = sio_read(file_handler[fd].sio_port - 1, 3); ! 5262: sio_write(file_handler[fd].sio_port - 1, 3, selector & ~0x80); ! 5263: DWORD timeout = timeGetTime() + 1000; ! 5264: while(read < count) { ! 5265: if(sio_read(file_handler[fd].sio_port - 1, 5) & 0x01) { ! 5266: buf[read++] = sio_read(file_handler[fd].sio_port - 1, 0); ! 5267: timeout = timeGetTime() + 1000; ! 5268: } else { ! 5269: if(timeGetTime() > timeout) { ! 5270: break; ! 5271: } ! 5272: Sleep(10); ! 5273: } ! 5274: } ! 5275: sio_write(file_handler[fd].sio_port - 1, 3, selector); ! 5276: } ! 5277: return(read); ! 5278: } ! 5279: return(_read(fd, buffer, count)); ! 5280: } ! 5281: ! 5282: int msdos_kbhit() ! 5283: { ! 5284: msdos_stdio_reopen(); ! 5285: ! 5286: process_t *process = msdos_process_info_get(current_psp); ! 5287: int fd = msdos_psp_get_file_table(0, current_psp); ! 5288: ! 5289: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) { ! 5290: // stdin is redirected to file ! 5291: return(eof(fd) == 0); ! 5292: } ! 5293: ! 5294: // check keyboard status ! 5295: if(key_recv != 0) { ! 5296: return(1); ! 5297: } ! 5298: if(key_buf_char != NULL && key_buf_scan != NULL) { ! 5299: #ifdef USE_SERVICE_THREAD ! 5300: EnterCriticalSection(&key_buf_crit_sect); ! 5301: #endif ! 5302: bool empty = pcbios_is_key_buffer_empty(); ! 5303: #ifdef USE_SERVICE_THREAD ! 5304: LeaveCriticalSection(&key_buf_crit_sect); ! 5305: #endif ! 5306: if(!empty) return(1); ! 5307: } ! 5308: return(_kbhit()); ! 5309: } ! 5310: ! 5311: int msdos_getch_ex(int echo) ! 5312: { ! 5313: static char prev = 0; ! 5314: ! 5315: msdos_stdio_reopen(); ! 5316: ! 5317: process_t *process = msdos_process_info_get(current_psp); ! 5318: int fd = msdos_psp_get_file_table(0, current_psp); ! 5319: ! 5320: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) { ! 5321: // stdin is redirected to file ! 5322: retry: ! 5323: char data; ! 5324: if(msdos_read(fd, &data, 1) == 1) { ! 5325: char tmp = data; ! 5326: if(data == 0x0a) { ! 5327: if(prev == 0x0d) { ! 5328: goto retry; // CRLF -> skip LF ! 5329: } else { ! 5330: data = 0x0d; // LF only -> CR ! 5331: } ! 5332: } ! 5333: prev = tmp; ! 5334: return(data); ! 5335: } ! 5336: return(EOF); ! 5337: } ! 5338: ! 5339: // input from console ! 5340: int key_char, key_scan; ! 5341: if(key_recv != 0) { ! 5342: key_char = (key_code >> 0) & 0xff; ! 5343: key_scan = (key_code >> 8) & 0xff; ! 5344: key_code >>= 16; ! 5345: key_recv >>= 16; ! 5346: } else { ! 5347: while(key_buf_char != NULL && key_buf_scan != NULL && !m_exit) { ! 5348: if(key_buf_char != NULL && key_buf_scan != NULL) { ! 5349: #ifdef USE_SERVICE_THREAD ! 5350: EnterCriticalSection(&key_buf_crit_sect); ! 5351: #endif ! 5352: bool empty = pcbios_is_key_buffer_empty(); ! 5353: #ifdef USE_SERVICE_THREAD ! 5354: LeaveCriticalSection(&key_buf_crit_sect); ! 5355: #endif ! 5356: if(!empty) break; ! 5357: } ! 5358: if(!(fd < process->max_files && file_handler[fd].valid && file_handler[fd].atty && file_mode[file_handler[fd].mode].in)) { ! 5359: // NOTE: stdin is redirected to stderr when we do "type (file) | more" on freedos's command.com ! 5360: if(_kbhit()) { ! 5361: if(key_buf_char != NULL && key_buf_scan != NULL) { ! 5362: #ifdef USE_SERVICE_THREAD ! 5363: EnterCriticalSection(&key_buf_crit_sect); ! 5364: #endif ! 5365: pcbios_set_key_buffer(_getch(), 0x00); ! 5366: #ifdef USE_SERVICE_THREAD ! 5367: LeaveCriticalSection(&key_buf_crit_sect); ! 5368: #endif ! 5369: } ! 5370: } else { ! 5371: Sleep(10); ! 5372: } ! 5373: } else { ! 5374: if(!update_key_buffer()) { ! 5375: Sleep(10); ! 5376: } ! 5377: } ! 5378: } ! 5379: if(m_exit) { ! 5380: // insert CR to terminate input loops ! 5381: key_char = 0x0d; ! 5382: key_scan = 0; ! 5383: } else if(key_buf_char != NULL && key_buf_scan != NULL) { ! 5384: #ifdef USE_SERVICE_THREAD ! 5385: EnterCriticalSection(&key_buf_crit_sect); ! 5386: #endif ! 5387: pcbios_get_key_buffer(&key_char, &key_scan); ! 5388: #ifdef USE_SERVICE_THREAD ! 5389: LeaveCriticalSection(&key_buf_crit_sect); ! 5390: #endif ! 5391: } ! 5392: } ! 5393: if(echo && key_char) { ! 5394: msdos_putch(key_char); ! 5395: } ! 5396: return key_char ? key_char : (key_scan != 0xe0) ? key_scan : 0; ! 5397: } ! 5398: ! 5399: inline int msdos_getch() ! 5400: { ! 5401: return(msdos_getch_ex(0)); ! 5402: } ! 5403: ! 5404: inline int msdos_getche() ! 5405: { ! 5406: return(msdos_getch_ex(1)); ! 5407: } ! 5408: ! 5409: int msdos_write(int fd, const void *buffer, unsigned int count) ! 5410: { ! 5411: if(fd < process->max_files && file_handler[fd].valid && file_handler[fd].sio_port >= 1 && file_handler[fd].sio_port <= 4) { ! 5412: // write to serial port ! 5413: int written = 0; ! 5414: if(sio_port_number[file_handler[fd].sio_port - 1] != 0) { ! 5415: UINT8 *buf = (UINT8 *)buffer; ! 5416: UINT8 selector = sio_read(file_handler[fd].sio_port - 1, 3); ! 5417: sio_write(file_handler[fd].sio_port - 1, 3, selector & ~0x80); ! 5418: DWORD timeout = timeGetTime() + 1000; ! 5419: while(written < count) { ! 5420: if(sio_read(file_handler[fd].sio_port - 1, 5) & 0x20) { ! 5421: sio_write(file_handler[fd].sio_port - 1, 0, buf[written++]); ! 5422: timeout = timeGetTime() + 1000; ! 5423: } else { ! 5424: if(timeGetTime() > timeout) { ! 5425: break; ! 5426: } ! 5427: Sleep(10); ! 5428: } ! 5429: } ! 5430: sio_write(file_handler[fd].sio_port - 1, 3, selector); ! 5431: } ! 5432: return(written); ! 5433: } else if(fd < process->max_files && file_handler[fd].valid && file_handler[fd].lpt_port >= 1 && file_handler[fd].lpt_port <= 3) { ! 5434: // write to printer port ! 5435: UINT8 *buf = (UINT8 *)buffer; ! 5436: for(unsigned int i = 0; i < count; i++) { ! 5437: // printer_out(file_handler[fd].lpt_port - 1, buf[i]); ! 5438: pcbios_printer_out(file_handler[fd].lpt_port - 1, buf[i]); ! 5439: } ! 5440: return(count); ! 5441: } else if(fd == 1 && file_handler[1].valid && !file_handler[1].atty) { ! 5442: // CR+LF -> LF ! 5443: static int is_cr = 0; ! 5444: UINT8 *buf = (UINT8 *)buffer; ! 5445: for(unsigned int i = 0; i < count; i++) { ! 5446: UINT8 data = buf[i]; ! 5447: if(is_cr) { ! 5448: if(data != 0x0a) { ! 5449: UINT8 tmp = 0x0d; ! 5450: _write(1, &tmp, 1); ! 5451: } ! 5452: _write(1, &data, 1); ! 5453: is_cr = 0; ! 5454: } else if(data == 0x0d) { ! 5455: is_cr = 1; ! 5456: } else { ! 5457: _write(1, &data, 1); ! 5458: } ! 5459: } ! 5460: return(count); ! 5461: } ! 5462: vram_flush(); ! 5463: return(_write(fd, buffer, count)); ! 5464: } ! 5465: ! 5466: void msdos_putch(UINT8 data) ! 5467: { ! 5468: msdos_stdio_reopen(); ! 5469: ! 5470: process_t *process = msdos_process_info_get(current_psp); ! 5471: int fd = msdos_psp_get_file_table(1, current_psp); ! 5472: ! 5473: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) { ! 5474: // stdout is redirected to file ! 5475: msdos_write(fd, &data, 1); ! 5476: return; ! 5477: } ! 5478: ! 5479: // call int 29h ? ! 5480: if(*(UINT16 *)(mem + 4 * 0x29 + 0) == (IRET_SIZE + 5 * 0x29) && ! 5481: *(UINT16 *)(mem + 4 * 0x29 + 2) == (IRET_TOP >> 4)) { ! 5482: // int 29h is not hooked, no need to call int 29h ! 5483: msdos_putch_fast(data); ! 5484: #ifdef USE_SERVICE_THREAD ! 5485: } else if(in_service && main_thread_id != GetCurrentThreadId()) { ! 5486: // XXX: in usually we should not reach here ! 5487: // this is called from service thread to echo the input ! 5488: // we can not call int 29h because it causes a critial issue to control cpu running in main thread :-( ! 5489: msdos_putch_fast(data); ! 5490: #endif ! 5491: } else if(in_service_29h) { ! 5492: // disallow reentering call int 29h routine to prevent an infinite loop :-( ! 5493: msdos_putch_fast(data); ! 5494: } else { ! 5495: // this is called from main thread, so we can call int 29h :-) ! 5496: in_service_29h = true; ! 5497: try { ! 5498: UINT32 tmp_pc = m_pc; ! 5499: UINT16 tmp_ax = REG16(AX); ! 5500: UINT32 tmp_bx = REG16(BX); // BX may be destroyed by some versions of DOS 3.3 ! 5501: ! 5502: // call int 29h routine is at fffc:0027 ! 5503: i386_call_far(DUMMY_TOP >> 4, 0x0027); ! 5504: REG8(AL) = data; ! 5505: ! 5506: // run cpu until call int 29h routine is done ! 5507: while(!m_exit && tmp_pc != m_pc) { ! 5508: try { ! 5509: hardware_run_cpu(); ! 5510: } catch(...) { ! 5511: } ! 5512: } ! 5513: REG16(AX) = tmp_ax; ! 5514: REG16(BX) = tmp_bx; ! 5515: } catch(...) { ! 5516: } ! 5517: in_service_29h = false; ! 5518: } ! 5519: } ! 5520: ! 5521: void msdos_putch_fast(UINT8 data) ! 5522: #ifdef USE_SERVICE_THREAD ! 5523: { ! 5524: EnterCriticalSection(&putch_crit_sect); ! 5525: msdos_putch_tmp(data); ! 5526: LeaveCriticalSection(&putch_crit_sect); ! 5527: } ! 5528: void msdos_putch_tmp(UINT8 data) ! 5529: #endif ! 5530: { ! 5531: CONSOLE_SCREEN_BUFFER_INFO csbi; ! 5532: SMALL_RECT rect; ! 5533: COORD co; ! 5534: static int p = 0; ! 5535: static int is_kanji = 0; ! 5536: static int is_esc = 0; ! 5537: static int stored_x; ! 5538: static int stored_y; ! 5539: static WORD stored_a; ! 5540: static char tmp[64], out[64]; ! 5541: ! 5542: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); ! 5543: ! 5544: // output to console ! 5545: tmp[p++] = data; ! 5546: ! 5547: vram_flush(); ! 5548: ! 5549: if(is_kanji) { ! 5550: // kanji character ! 5551: is_kanji = 0; ! 5552: } else if(is_esc) { ! 5553: // escape sequense ! 5554: if((tmp[1] == ')' || tmp[1] == '(') && p == 3) { ! 5555: p = is_esc = 0; ! 5556: } else if(tmp[1] == '=' && p == 4) { ! 5557: co.X = tmp[3] - 0x20; ! 5558: co.Y = tmp[2] - 0x20 + scr_top; ! 5559: SetConsoleCursorPosition(hStdout, co); ! 5560: mem[0x450 + mem[0x462] * 2] = co.X; ! 5561: mem[0x451 + mem[0x462] * 2] = co.Y - scr_top; ! 5562: cursor_moved = false; ! 5563: cursor_moved_by_crtc = false; ! 5564: p = is_esc = 0; ! 5565: } else if((data >= 'a' && data <= 'z') || (data >= 'A' && data <= 'Z') || data == '*') { ! 5566: if(cursor_moved_by_crtc) { ! 5567: if(!restore_console_on_exit) { ! 5568: GetConsoleScreenBufferInfo(hStdout, &csbi); ! 5569: scr_top = csbi.srWindow.Top; ! 5570: } ! 5571: co.X = mem[0x450 + REG8(BH) * 2]; ! 5572: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top; ! 5573: SetConsoleCursorPosition(hStdout, co); ! 5574: cursor_moved_by_crtc = false; ! 5575: } ! 5576: GetConsoleScreenBufferInfo(hStdout, &csbi); ! 5577: co.X = csbi.dwCursorPosition.X; ! 5578: co.Y = csbi.dwCursorPosition.Y; ! 5579: WORD wAttributes = csbi.wAttributes; ! 5580: ! 5581: if(tmp[1] == 'D') { ! 5582: co.Y++; ! 5583: } else if(tmp[1] == 'E') { ! 5584: co.X = 0; ! 5585: co.Y++; ! 5586: } else if(tmp[1] == 'M') { ! 5587: co.Y--; ! 5588: } else if(tmp[1] == '*') { ! 5589: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom); ! 5590: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect); ! 5591: co.X = 0; ! 5592: co.Y = csbi.srWindow.Top; ! 5593: } else if(tmp[1] == '[') { ! 5594: int param[256], params = 0; ! 5595: memset(param, 0, sizeof(param)); ! 5596: for(int i = 2; i < p; i++) { ! 5597: if(tmp[i] >= '0' && tmp[i] <= '9') { ! 5598: param[params] *= 10; ! 5599: param[params] += tmp[i] - '0'; ! 5600: } else { ! 5601: params++; ! 5602: } ! 5603: } ! 5604: if(data == 'A') { ! 5605: co.Y -= (params == 0) ? 1 : param[0]; ! 5606: } else if(data == 'B') { ! 5607: co.Y += (params == 0) ? 1 : param[0]; ! 5608: } else if(data == 'C') { ! 5609: co.X += (params == 0) ? 1 : param[0]; ! 5610: } else if(data == 'D') { ! 5611: co.X -= (params == 0) ? 1 : param[0]; ! 5612: } else if(data == 'H' || data == 'f') { ! 5613: co.X = (param[1] == 0 ? 1 : param[1]) - 1; ! 5614: co.Y = (param[0] == 0 ? 1 : param[0]) - 1 + csbi.srWindow.Top; ! 5615: } else if(data == 'J') { ! 5616: clear_scr_buffer(csbi.wAttributes); ! 5617: if(param[0] == 0) { ! 5618: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y); ! 5619: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect); ! 5620: if(co.Y < csbi.srWindow.Bottom) { ! 5621: SET_RECT(rect, 0, co.Y + 1, csbi.dwSize.X - 1, csbi.srWindow.Bottom); ! 5622: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect); ! 5623: } ! 5624: } else if(param[0] == 1) { ! 5625: if(co.Y > csbi.srWindow.Top) { ! 5626: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, co.Y - 1); ! 5627: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect); ! 5628: } ! 5629: SET_RECT(rect, 0, co.Y, co.X, co.Y); ! 5630: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect); ! 5631: } else if(param[0] == 2) { ! 5632: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom); ! 5633: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect); ! 5634: co.X = co.Y = 0; ! 5635: } ! 5636: } else if(data == 'K') { ! 5637: clear_scr_buffer(csbi.wAttributes); ! 5638: if(param[0] == 0) { ! 5639: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y); ! 5640: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect); ! 5641: } else if(param[0] == 1) { ! 5642: SET_RECT(rect, 0, co.Y, co.X, co.Y); ! 5643: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect); ! 5644: } else if(param[0] == 2) { ! 5645: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y); ! 5646: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect); ! 5647: } ! 5648: } else if(data == 'L') { ! 5649: if(params == 0) { ! 5650: param[0] = 1; ! 5651: } ! 5652: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom); ! 5653: ReadConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect); ! 5654: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom); ! 5655: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect); ! 5656: clear_scr_buffer(csbi.wAttributes); ! 5657: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y + param[0] - 1); ! 5658: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect); ! 5659: co.X = 0; ! 5660: } else if(data == 'M') { ! 5661: if(params == 0) { ! 5662: param[0] = 1; ! 5663: } ! 5664: if(co.Y + param[0] > csbi.srWindow.Bottom) { ! 5665: clear_scr_buffer(csbi.wAttributes); ! 5666: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom); ! 5667: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect); ! 5668: } else { ! 5669: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom); ! 5670: ReadConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect); ! 5671: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom); ! 5672: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect); ! 5673: clear_scr_buffer(csbi.wAttributes); ! 5674: } ! 5675: co.X = 0; ! 5676: } else if(data == 'h') { ! 5677: if(tmp[2] == '>' && tmp[3] == '5') { ! 5678: ci_new.bVisible = FALSE; ! 5679: } ! 5680: } else if(data == 'l') { ! 5681: if(tmp[2] == '>' && tmp[3] == '5') { ! 5682: ci_new.bVisible = TRUE; ! 5683: } ! 5684: } else if(data == 'm') { ! 5685: wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; ! 5686: int reverse = 0, hidden = 0; ! 5687: for(int i = 0; i < params; i++) { ! 5688: if(param[i] == 1) { ! 5689: wAttributes |= FOREGROUND_INTENSITY; ! 5690: } else if(param[i] == 4) { ! 5691: wAttributes |= COMMON_LVB_UNDERSCORE; ! 5692: } else if(param[i] == 7) { ! 5693: reverse = 1; ! 5694: } else if(param[i] == 8 || param[i] == 16) { ! 5695: hidden = 1; ! 5696: } else if((param[i] >= 17 && param[i] <= 23) || (param[i] >= 30 && param[i] <= 37)) { ! 5697: wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); ! 5698: if(param[i] >= 17 && param[i] <= 23) { ! 5699: param[i] -= 16; ! 5700: } else { ! 5701: param[i] -= 30; ! 5702: } ! 5703: if(param[i] & 1) { ! 5704: wAttributes |= FOREGROUND_RED; ! 5705: } ! 5706: if(param[i] & 2) { ! 5707: wAttributes |= FOREGROUND_GREEN; ! 5708: } ! 5709: if(param[i] & 4) { ! 5710: wAttributes |= FOREGROUND_BLUE; ! 5711: } ! 5712: } else if(param[i] >= 40 && param[i] <= 47) { ! 5713: wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); ! 5714: if((param[i] - 40) & 1) { ! 5715: wAttributes |= BACKGROUND_RED; ! 5716: } ! 5717: if((param[i] - 40) & 2) { ! 5718: wAttributes |= BACKGROUND_GREEN; ! 5719: } ! 5720: if((param[i] - 40) & 4) { ! 5721: wAttributes |= BACKGROUND_BLUE; ! 5722: } ! 5723: } ! 5724: } ! 5725: if(reverse) { ! 5726: wAttributes &= ~0xff; ! 5727: wAttributes |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; ! 5728: } ! 5729: if(hidden) { ! 5730: wAttributes &= ~0x0f; ! 5731: wAttributes |= (wAttributes >> 4) & 0x0f; ! 5732: } ! 5733: } else if(data == 'n') { ! 5734: if(param[0] == 6) { ! 5735: char tmp[16]; ! 5736: sprintf(tmp, "\x1b[%d;%dR", co.Y + 1, co.X + 1); ! 5737: int len = strlen(tmp); ! 5738: if(key_buf_char != NULL && key_buf_scan != NULL) { ! 5739: #ifdef USE_SERVICE_THREAD ! 5740: EnterCriticalSection(&key_buf_crit_sect); ! 5741: #endif ! 5742: for(int i = 0; i < len; i++) { ! 5743: pcbios_set_key_buffer(tmp[i], 0x00); ! 5744: } ! 5745: #ifdef USE_SERVICE_THREAD ! 5746: LeaveCriticalSection(&key_buf_crit_sect); ! 5747: #endif ! 5748: } ! 5749: } ! 5750: } else if(data == 's') { ! 5751: stored_x = co.X; ! 5752: stored_y = co.Y; ! 5753: stored_a = wAttributes; ! 5754: } else if(data == 'u') { ! 5755: co.X = stored_x; ! 5756: co.Y = stored_y; ! 5757: wAttributes = stored_a; ! 5758: } ! 5759: } ! 5760: if(co.X < 0) { ! 5761: co.X = 0; ! 5762: } else if(co.X >= csbi.dwSize.X) { ! 5763: co.X = csbi.dwSize.X - 1; ! 5764: } ! 5765: if(co.Y < csbi.srWindow.Top) { ! 5766: co.Y = csbi.srWindow.Top; ! 5767: } else if(co.Y > csbi.srWindow.Bottom) { ! 5768: co.Y = csbi.srWindow.Bottom; ! 5769: } ! 5770: if(co.X != csbi.dwCursorPosition.X || co.Y != csbi.dwCursorPosition.Y) { ! 5771: SetConsoleCursorPosition(hStdout, co); ! 5772: mem[0x450 + mem[0x462] * 2] = co.X; ! 5773: mem[0x451 + mem[0x462] * 2] = co.Y - csbi.srWindow.Top; ! 5774: cursor_moved = false; ! 5775: } ! 5776: if(wAttributes != csbi.wAttributes) { ! 5777: SetConsoleTextAttribute(hStdout, wAttributes); ! 5778: } ! 5779: p = is_esc = 0; ! 5780: } ! 5781: return; ! 5782: } else { ! 5783: if(msdos_lead_byte_check(data)) { ! 5784: is_kanji = 1; ! 5785: return; ! 5786: } else if(data == 0x1b) { ! 5787: is_esc = 1; ! 5788: return; ! 5789: } ! 5790: } ! 5791: ! 5792: DWORD q = 0, num; ! 5793: is_kanji = 0; ! 5794: for(int i = 0; i < p; i++) { ! 5795: UINT8 c = tmp[i]; ! 5796: if(is_kanji) { ! 5797: is_kanji = 0; ! 5798: } else if(msdos_lead_byte_check(data)) { ! 5799: is_kanji = 1; ! 5800: } else if(msdos_ctrl_code_check(data)) { ! 5801: out[q++] = '^'; ! 5802: c += 'A' - 1; ! 5803: } ! 5804: out[q++] = c; ! 5805: } ! 5806: if(cursor_moved_by_crtc) { ! 5807: if(!restore_console_on_exit) { ! 5808: GetConsoleScreenBufferInfo(hStdout, &csbi); ! 5809: scr_top = csbi.srWindow.Top; ! 5810: } ! 5811: co.X = mem[0x450 + REG8(BH) * 2]; ! 5812: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top; ! 5813: SetConsoleCursorPosition(hStdout, co); ! 5814: cursor_moved_by_crtc = false; ! 5815: } ! 5816: if(q == 1 && out[0] == 0x08) { ! 5817: // back space ! 5818: GetConsoleScreenBufferInfo(hStdout, &csbi); ! 5819: if(csbi.dwCursorPosition.X > 0) { ! 5820: co.X = csbi.dwCursorPosition.X - 1; ! 5821: co.Y = csbi.dwCursorPosition.Y; ! 5822: SetConsoleCursorPosition(hStdout, co); ! 5823: } else if(csbi.dwCursorPosition.Y > 0) { ! 5824: co.X = csbi.dwSize.X - 1; ! 5825: co.Y = csbi.dwCursorPosition.Y - 1; ! 5826: SetConsoleCursorPosition(hStdout, co); ! 5827: } else { ! 5828: WriteConsoleA(hStdout, out, q, &num, NULL); // to make sure ! 5829: } ! 5830: } else { ! 5831: WriteConsoleA(hStdout, out, q, &num, NULL); ! 5832: } ! 5833: p = 0; ! 5834: ! 5835: if(!restore_console_on_exit) { ! 5836: GetConsoleScreenBufferInfo(hStdout, &csbi); ! 5837: scr_top = csbi.srWindow.Top; ! 5838: } ! 5839: cursor_moved = true; ! 5840: } ! 5841: ! 5842: int msdos_aux_in() ! 5843: { ! 5844: msdos_stdio_reopen(); ! 5845: ! 5846: process_t *process = msdos_process_info_get(current_psp); ! 5847: int fd = msdos_psp_get_file_table(3, current_psp); ! 5848: ! 5849: if(fd < process->max_files && file_handler[fd].valid && !eof(fd)) { ! 5850: char data = 0; ! 5851: msdos_read(fd, &data, 1); ! 5852: return(data); ! 5853: } else { ! 5854: return(EOF); ! 5855: } ! 5856: } ! 5857: ! 5858: void msdos_aux_out(char data) ! 5859: { ! 5860: msdos_stdio_reopen(); ! 5861: ! 5862: process_t *process = msdos_process_info_get(current_psp); ! 5863: int fd = msdos_psp_get_file_table(3, current_psp); ! 5864: ! 5865: if(fd < process->max_files && file_handler[fd].valid) { ! 5866: msdos_write(fd, &data, 1); ! 5867: } ! 5868: } ! 5869: ! 5870: void msdos_prn_out(char data) ! 5871: { ! 5872: msdos_stdio_reopen(); ! 5873: ! 5874: process_t *process = msdos_process_info_get(current_psp); ! 5875: int fd = msdos_psp_get_file_table(4, current_psp); ! 5876: ! 5877: if(fd < process->max_files && file_handler[fd].valid) { ! 5878: msdos_write(fd, &data, 1); ! 5879: } ! 5880: } ! 5881: ! 5882: // memory control ! 5883: ! 5884: mcb_t *msdos_mcb_create(int mcb_seg, UINT8 mz, UINT16 psp, int paragraphs, const char *prog_name = NULL) ! 5885: { ! 5886: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4)); ! 5887: ! 5888: mcb->mz = mz; ! 5889: mcb->psp = psp; ! 5890: mcb->paragraphs = paragraphs; ! 5891: ! 5892: if(prog_name != NULL) { ! 5893: memset(mcb->prog_name, 0, 8); ! 5894: memcpy(mcb->prog_name, prog_name, min(8, strlen(prog_name))); ! 5895: } ! 5896: return(mcb); ! 5897: } ! 5898: ! 5899: void msdos_mcb_check(mcb_t *mcb) ! 5900: { ! 5901: if(!(mcb->mz == 'M' || mcb->mz == 'Z')) { ! 5902: #if 0 ! 5903: // shutdown now !!! ! 5904: fatalerror("broken memory control block\n"); ! 5905: #else ! 5906: // return error code and continue ! 5907: throw(0x07); // broken memory control block ! 5908: #endif ! 5909: } ! 5910: } ! 5911: ! 5912: void msdos_mem_split(int seg, int paragraphs) ! 5913: { ! 5914: int mcb_seg = seg - 1; ! 5915: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4)); ! 5916: msdos_mcb_check(mcb); ! 5917: ! 5918: if(mcb->paragraphs > paragraphs) { ! 5919: int new_seg = mcb_seg + 1 + paragraphs; ! 5920: int new_paragraphs = mcb->paragraphs - paragraphs - 1; ! 5921: ! 5922: msdos_mcb_create(new_seg, mcb->mz, 0, new_paragraphs); ! 5923: mcb->mz = 'M'; ! 5924: mcb->paragraphs = paragraphs; ! 5925: } ! 5926: } ! 5927: ! 5928: void msdos_mem_merge(int seg) ! 5929: { ! 5930: int mcb_seg = seg - 1; ! 5931: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4)); ! 5932: msdos_mcb_check(mcb); ! 5933: ! 5934: while(1) { ! 5935: if(mcb->mz == 'Z') { ! 5936: break; ! 5937: } ! 5938: int next_seg = mcb_seg + 1 + mcb->paragraphs; ! 5939: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4)); ! 5940: msdos_mcb_check(next_mcb); ! 5941: ! 5942: if(next_mcb->psp != 0) { ! 5943: break; ! 5944: } ! 5945: mcb->mz = next_mcb->mz; ! 5946: mcb->paragraphs = mcb->paragraphs + 1 + next_mcb->paragraphs; ! 5947: } ! 5948: } ! 5949: ! 5950: int msdos_mem_alloc(int mcb_seg, int paragraphs, int new_process) ! 5951: { ! 5952: while(1) { ! 5953: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4)); ! 5954: bool last_block; ! 5955: ! 5956: if(mcb->psp == 0) { ! 5957: msdos_mem_merge(mcb_seg + 1); ! 5958: } else { ! 5959: msdos_mcb_check(mcb); ! 5960: } ! 5961: if(!(last_block = (mcb->mz == 'Z'))) { ! 5962: // check if the next is dummy mcb to link to umb ! 5963: int next_seg = mcb_seg + 1 + mcb->paragraphs; ! 5964: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4)); ! 5965: last_block = (next_mcb->mz == 'Z' && next_mcb->paragraphs == 0); ! 5966: } ! 5967: if(!(new_process && !last_block)) { ! 5968: if(mcb->psp == 0 && mcb->paragraphs >= paragraphs) { ! 5969: msdos_mem_split(mcb_seg + 1, paragraphs); ! 5970: mcb->psp = current_psp; ! 5971: return(mcb_seg + 1); ! 5972: } ! 5973: } ! 5974: if(mcb->mz == 'Z') { ! 5975: break; ! 5976: } ! 5977: mcb_seg += 1 + mcb->paragraphs; ! 5978: } ! 5979: return(-1); ! 5980: } ! 5981: ! 5982: int msdos_mem_realloc(int seg, int paragraphs, int *max_paragraphs) ! 5983: { ! 5984: int mcb_seg = seg - 1; ! 5985: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4)); ! 5986: msdos_mcb_check(mcb); ! 5987: int current_paragraphs = mcb->paragraphs; ! 5988: ! 5989: msdos_mem_merge(seg); ! 5990: if(paragraphs > mcb->paragraphs) { ! 5991: if(max_paragraphs) { ! 5992: *max_paragraphs = mcb->paragraphs; ! 5993: } ! 5994: msdos_mem_split(seg, current_paragraphs); ! 5995: return(-1); ! 5996: } ! 5997: msdos_mem_split(seg, paragraphs); ! 5998: return(0); ! 5999: } ! 6000: ! 6001: void msdos_mem_free(int seg) ! 6002: { ! 6003: int mcb_seg = seg - 1; ! 6004: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4)); ! 6005: msdos_mcb_check(mcb); ! 6006: ! 6007: mcb->psp = 0; ! 6008: msdos_mem_merge(seg); ! 6009: } ! 6010: ! 6011: int msdos_mem_get_free(int mcb_seg, int new_process) ! 6012: { ! 6013: int max_paragraphs = 0; ! 6014: ! 6015: while(1) { ! 6016: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4)); ! 6017: bool last_block; ! 6018: ! 6019: msdos_mcb_check(mcb); ! 6020: ! 6021: if(!(last_block = (mcb->mz == 'Z'))) { ! 6022: // check if the next is dummy mcb to link to umb ! 6023: int next_seg = mcb_seg + 1 + mcb->paragraphs; ! 6024: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4)); ! 6025: last_block = (next_mcb->mz == 'Z' && next_mcb->paragraphs == 0); ! 6026: } ! 6027: if(!(new_process && !last_block)) { ! 6028: if(mcb->psp == 0 && mcb->paragraphs > max_paragraphs) { ! 6029: max_paragraphs = mcb->paragraphs; ! 6030: } ! 6031: } ! 6032: if(mcb->mz == 'Z') { ! 6033: break; ! 6034: } ! 6035: mcb_seg += 1 + mcb->paragraphs; ! 6036: } ! 6037: return(max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs); ! 6038: } ! 6039: ! 6040: int msdos_mem_get_last_mcb(int mcb_seg, UINT16 psp) ! 6041: { ! 6042: int last_seg = -1; ! 6043: ! 6044: while(1) { ! 6045: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4)); ! 6046: msdos_mcb_check(mcb); ! 6047: ! 6048: if(mcb->psp == psp) { ! 6049: last_seg = mcb_seg; ! 6050: } ! 6051: if(mcb->mz == 'Z') { ! 6052: break; ! 6053: } ! 6054: mcb_seg += 1 + mcb->paragraphs; ! 6055: } ! 6056: return(last_seg); ! 6057: } ! 6058: ! 6059: int msdos_mem_get_umb_linked() ! 6060: { ! 6061: mcb_t *mcb = (mcb_t *)(mem + MEMORY_END - 16); ! 6062: msdos_mcb_check(mcb); ! 6063: ! 6064: if(mcb->mz == 'M') { ! 6065: return(-1); ! 6066: } ! 6067: return(0); ! 6068: } ! 6069: ! 6070: void msdos_mem_link_umb() ! 6071: { ! 6072: mcb_t *mcb = (mcb_t *)(mem + MEMORY_END - 16); ! 6073: msdos_mcb_check(mcb); ! 6074: ! 6075: mcb->mz = 'M'; ! 6076: mcb->paragraphs = (UMB_TOP >> 4) - (MEMORY_END >> 4); ! 6077: ! 6078: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked |= 0x01; ! 6079: } ! 6080: ! 6081: void msdos_mem_unlink_umb() ! 6082: { ! 6083: mcb_t *mcb = (mcb_t *)(mem + MEMORY_END - 16); ! 6084: msdos_mcb_check(mcb); ! 6085: ! 6086: mcb->mz = 'Z'; ! 6087: mcb->paragraphs = 0; ! 6088: ! 6089: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked &= ~0x01; ! 6090: } ! 6091: ! 6092: #ifdef SUPPORT_HMA ! 6093: ! 6094: hma_mcb_t *msdos_hma_mcb_create(int offset, int owner, int size, int next) ! 6095: { ! 6096: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset); ! 6097: ! 6098: mcb->ms[0] = 'M'; ! 6099: mcb->ms[1] = 'S'; ! 6100: mcb->owner = owner; ! 6101: mcb->size = size; ! 6102: mcb->next = next; ! 6103: return(mcb); ! 6104: } ! 6105: ! 6106: bool msdos_is_hma_mcb_valid(hma_mcb_t *mcb) ! 6107: { ! 6108: return(mcb->ms[0] == 'M' && mcb->ms[1] == 'S'); ! 6109: } ! 6110: ! 6111: int msdos_hma_mem_split(int offset, int size) ! 6112: { ! 6113: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset); ! 6114: ! 6115: if(!msdos_is_hma_mcb_valid(mcb)) { ! 6116: return(-1); ! 6117: } ! 6118: if(mcb->size >= size + 0x10) { ! 6119: int new_offset = offset + 0x10 + size; ! 6120: int new_size = mcb->size - 0x10 - size; ! 6121: ! 6122: msdos_hma_mcb_create(new_offset, 0, new_size, mcb->next); ! 6123: mcb->size = size; ! 6124: mcb->next = new_offset; ! 6125: return(0); ! 6126: } ! 6127: return(-1); ! 6128: } ! 6129: ! 6130: void msdos_hma_mem_merge(int offset) ! 6131: { ! 6132: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset); ! 6133: ! 6134: if(!msdos_is_hma_mcb_valid(mcb)) { ! 6135: return; ! 6136: } ! 6137: while(1) { ! 6138: if(mcb->next == 0) { ! 6139: break; ! 6140: } ! 6141: hma_mcb_t *next_mcb = (hma_mcb_t *)(mem + 0xffff0 + mcb->next); ! 6142: ! 6143: if(!msdos_is_hma_mcb_valid(next_mcb)) { ! 6144: return; ! 6145: } ! 6146: if(next_mcb->owner != 0) { ! 6147: break; ! 6148: } ! 6149: mcb->size += 0x10 + next_mcb->size; ! 6150: mcb->next = next_mcb->next; ! 6151: } ! 6152: } ! 6153: ! 6154: int msdos_hma_mem_alloc(int size, UINT16 owner) ! 6155: { ! 6156: int offset = 0x10; // first mcb in HMA ! 6157: ! 6158: while(1) { ! 6159: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset); ! 6160: ! 6161: if(!msdos_is_hma_mcb_valid(mcb)) { ! 6162: return(-1); ! 6163: } ! 6164: if(mcb->owner == 0) { ! 6165: msdos_hma_mem_merge(offset); ! 6166: } ! 6167: if(mcb->owner == 0 && mcb->size >= size) { ! 6168: msdos_hma_mem_split(offset, size); ! 6169: mcb->owner = owner; ! 6170: return(offset); ! 6171: } ! 6172: if(mcb->next == 0) { ! 6173: break; ! 6174: } ! 6175: offset = mcb->next; ! 6176: } ! 6177: return(-1); ! 6178: } ! 6179: ! 6180: int msdos_hma_mem_realloc(int offset, int size) ! 6181: { ! 6182: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset); ! 6183: ! 6184: if(!msdos_is_hma_mcb_valid(mcb)) { ! 6185: return(-1); ! 6186: } ! 6187: if(mcb->size < size) { ! 6188: return(-1); ! 6189: } ! 6190: msdos_hma_mem_split(offset, size); ! 6191: return(0); ! 6192: } ! 6193: ! 6194: void msdos_hma_mem_free(int offset) ! 6195: { ! 6196: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset); ! 6197: ! 6198: if(!msdos_is_hma_mcb_valid(mcb)) { ! 6199: return; ! 6200: } ! 6201: mcb->owner = 0; ! 6202: msdos_hma_mem_merge(offset); ! 6203: } ! 6204: ! 6205: int msdos_hma_mem_get_free(int *available_offset) ! 6206: { ! 6207: int offset = 0x10; // first mcb in HMA ! 6208: int size = 0; ! 6209: ! 6210: while(1) { ! 6211: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset); ! 6212: ! 6213: if(!msdos_is_hma_mcb_valid(mcb)) { ! 6214: return(0); ! 6215: } ! 6216: if(mcb->owner == 0 && size < mcb->size) { ! 6217: if(available_offset != NULL) { ! 6218: *available_offset = offset; ! 6219: } ! 6220: size = mcb->size; ! 6221: } ! 6222: if(mcb->next == 0) { ! 6223: break; ! 6224: } ! 6225: offset = mcb->next; ! 6226: } ! 6227: return(size); ! 6228: } ! 6229: ! 6230: #endif ! 6231: ! 6232: // environment ! 6233: ! 6234: void msdos_env_set_argv(int env_seg, const char *argv) ! 6235: { ! 6236: char *dst = (char *)(mem + (env_seg << 4)); ! 6237: ! 6238: while(1) { ! 6239: if(dst[0] == 0) { ! 6240: break; ! 6241: } ! 6242: dst += strlen(dst) + 1; ! 6243: } ! 6244: *dst++ = 0; // end of environment ! 6245: *dst++ = 1; // top of argv[0] ! 6246: *dst++ = 0; ! 6247: memcpy(dst, argv, strlen(argv)); ! 6248: dst += strlen(argv); ! 6249: *dst++ = 0; ! 6250: *dst++ = 0; ! 6251: } ! 6252: ! 6253: const char *msdos_env_get_argv(int env_seg) ! 6254: { ! 6255: static char env[ENV_SIZE]; ! 6256: char *src = env; ! 6257: ! 6258: memcpy(src, mem + (env_seg << 4), ENV_SIZE); ! 6259: while(1) { ! 6260: if(src[0] == 0) { ! 6261: if(src[1] == 1) { ! 6262: return(src + 3); ! 6263: } ! 6264: break; ! 6265: } ! 6266: src += strlen(src) + 1; ! 6267: } ! 6268: return(NULL); ! 6269: } ! 6270: ! 6271: const char *msdos_env_get(int env_seg, const char *name) ! 6272: { ! 6273: static char env[ENV_SIZE]; ! 6274: char *src = env; ! 6275: ! 6276: memcpy(src, mem + (env_seg << 4), ENV_SIZE); ! 6277: while(1) { ! 6278: if(src[0] == 0) { ! 6279: break; ! 6280: } ! 6281: int len = strlen(src); ! 6282: char *n = my_strtok(src, "="); ! 6283: char *v = src + strlen(n) + 1; ! 6284: ! 6285: if(_stricmp(name, n) == 0) { ! 6286: return(v); ! 6287: } ! 6288: src += len + 1; ! 6289: } ! 6290: return(NULL); ! 6291: } ! 6292: ! 6293: void msdos_env_set(int env_seg, const char *name, const char *value) ! 6294: { ! 6295: char env[ENV_SIZE]; ! 6296: char *src = env; ! 6297: char *dst = (char *)(mem + (env_seg << 4)); ! 6298: const char *argv = msdos_env_get_argv(env_seg); ! 6299: int done = 0; ! 6300: ! 6301: memcpy(src, dst, ENV_SIZE); ! 6302: memset(dst, 0, ENV_SIZE); ! 6303: while(1) { ! 6304: if(src[0] == 0) { ! 6305: break; ! 6306: } ! 6307: int len = strlen(src); ! 6308: char *n = my_strtok(src, "="); ! 6309: char *v = src + strlen(n) + 1; ! 6310: char tmp[1024]; ! 6311: ! 6312: if(_stricmp(name, n) == 0) { ! 6313: sprintf(tmp, "%s=%s", n, value); ! 6314: done = 1; ! 6315: } else { ! 6316: sprintf(tmp, "%s=%s", n, v); ! 6317: } ! 6318: memcpy(dst, tmp, strlen(tmp)); ! 6319: dst += strlen(tmp) + 1; ! 6320: src += len + 1; ! 6321: } ! 6322: if(!done) { ! 6323: char tmp[1024]; ! 6324: ! 6325: sprintf(tmp, "%s=%s", name, value); ! 6326: memcpy(dst, tmp, strlen(tmp)); ! 6327: dst += strlen(tmp) + 1; ! 6328: } ! 6329: if(argv) { ! 6330: *dst++ = 0; // end of environment ! 6331: *dst++ = 1; // top of argv[0] ! 6332: *dst++ = 0; ! 6333: memcpy(dst, argv, strlen(argv)); ! 6334: dst += strlen(argv); ! 6335: *dst++ = 0; ! 6336: *dst++ = 0; ! 6337: } ! 6338: } ! 6339: ! 6340: // process ! 6341: ! 6342: psp_t *msdos_psp_create(int psp_seg, UINT16 mcb_seg, UINT16 parent_psp, UINT16 env_seg) ! 6343: { ! 6344: psp_t *psp = (psp_t *)(mem + (psp_seg << 4)); ! 6345: ! 6346: memset(psp, 0, PSP_SIZE); ! 6347: psp->exit[0] = 0xcd; ! 6348: psp->exit[1] = 0x20; ! 6349: psp->first_mcb = mcb_seg; ! 6350: #if 1 ! 6351: psp->call5[0] = 0xcd; // int 30h ! 6352: psp->call5[1] = 0x30; ! 6353: psp->call5[2] = 0xc3; // ret ! 6354: #else ! 6355: psp->call5[0] = 0x8a; // mov ah, cl ! 6356: psp->call5[1] = 0xe1; ! 6357: psp->call5[2] = 0xcd; // int 21h ! 6358: psp->call5[3] = 0x21; ! 6359: psp->call5[4] = 0xc3; // ret ! 6360: #endif ! 6361: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22); ! 6362: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23); ! 6363: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24); ! 6364: psp->parent_psp = parent_psp; ! 6365: if(parent_psp == (UINT16)-1) { ! 6366: for(int i = 0; i < 20; i++) { ! 6367: if(file_handler[i].valid) { ! 6368: psp->file_table[i] = i; ! 6369: } else { ! 6370: psp->file_table[i] = 0xff; ! 6371: } ! 6372: } ! 6373: } else { ! 6374: memcpy(psp->file_table, ((psp_t *)(mem + (parent_psp << 4)))->file_table, 20); ! 6375: } ! 6376: psp->env_seg = env_seg; ! 6377: psp->stack.w.l = REG16(SP); ! 6378: psp->stack.w.h = SREG(SS); ! 6379: psp->file_table_size = 20; ! 6380: psp->file_table_ptr.w.l = 0x18; ! 6381: psp->file_table_ptr.w.h = psp_seg; ! 6382: psp->service[0] = 0xcd; ! 6383: psp->service[1] = 0x21; ! 6384: psp->service[2] = 0xcb; ! 6385: return(psp); ! 6386: } ! 6387: ! 6388: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg) ! 6389: { ! 6390: if(psp_seg && fd < 20) { ! 6391: psp_t *psp = (psp_t *)(mem + (psp_seg << 4)); ! 6392: psp->file_table[fd] = value; ! 6393: } ! 6394: } ! 6395: ! 6396: int msdos_psp_get_file_table(int fd, int psp_seg) ! 6397: { ! 6398: if(psp_seg && fd < 20) { ! 6399: psp_t *psp = (psp_t *)(mem + (psp_seg << 4)); ! 6400: fd = psp->file_table[fd]; ! 6401: } ! 6402: return fd; ! 6403: } ! 6404: ! 6405: int msdos_process_exec(const char *cmd, param_block_t *param, UINT8 al, bool first_process = false) ! 6406: { ! 6407: // load command file ! 6408: int fd = -1; ! 6409: int sio_port = 0; ! 6410: int lpt_port = 0; ! 6411: int dos_command = 0; ! 6412: char command[MAX_PATH], path[MAX_PATH], opt[MAX_PATH], *name = NULL, name_tmp[MAX_PATH]; ! 6413: char pipe_stdin_path[MAX_PATH] = {0}; ! 6414: char pipe_stdout_path[MAX_PATH] = {0}; ! 6415: char pipe_stderr_path[MAX_PATH] = {0}; ! 6416: ! 6417: int opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l; ! 6418: int opt_len = mem[opt_ofs]; ! 6419: memset(opt, 0, sizeof(opt)); ! 6420: memcpy(opt, mem + opt_ofs + 1, opt_len); ! 6421: ! 6422: if(strlen(cmd) >= 5 && _stricmp(&cmd[strlen(cmd) - 4], ".BAT") == 0) { ! 6423: // this is a batch file, run command.com ! 6424: char tmp[MAX_PATH]; ! 6425: if(opt_len != 0) { ! 6426: sprintf(tmp, "/C %s %s", cmd, opt); ! 6427: } else { ! 6428: sprintf(tmp, "/C %s", cmd); ! 6429: } ! 6430: strcpy(opt, tmp); ! 6431: opt_len = strlen(opt); ! 6432: mem[opt_ofs] = opt_len; ! 6433: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt); ! 6434: strcpy(command, comspec_path); ! 6435: strcpy(name_tmp, "COMMAND.COM"); ! 6436: } else { ! 6437: if(_stricmp(cmd, "C:\\COMMAND.COM") == 0) { ! 6438: // redirect C:\COMMAND.COM to comspec_path ! 6439: strcpy(command, comspec_path); ! 6440: } else { ! 6441: strcpy(command, cmd); ! 6442: } ! 6443: if(GetFullPathNameA(command, MAX_PATH, path, &name) == 0) { ! 6444: return(-1); ! 6445: } ! 6446: memset(name_tmp, 0, sizeof(name_tmp)); ! 6447: strcpy(name_tmp, name); ! 6448: ! 6449: // check command.com ! 6450: if((_stricmp(name, "COMMAND.COM") == 0 || _stricmp(name, "COMMAND") == 0) && _access(comspec_path, 0) != 0) { ! 6451: // we can not load command.com, so run program directly if "command /c (program)" is specified ! 6452: if(opt_len == 0) { ! 6453: // process_t *current_process = msdos_process_info_get(current_psp); ! 6454: process_t *current_process = NULL; ! 6455: for(int i = 0; i < MAX_PROCESS; i++) { ! 6456: if(process[i].psp == current_psp) { ! 6457: current_process = &process[i]; ! 6458: break; ! 6459: } ! 6460: } ! 6461: if(current_process != NULL) { ! 6462: param->cmd_line.dw = current_process->dta.dw; ! 6463: opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l; ! 6464: opt_len = mem[opt_ofs]; ! 6465: memset(opt, 0, sizeof(opt)); ! 6466: memcpy(opt, mem + opt_ofs + 1, opt_len); ! 6467: } ! 6468: } ! 6469: for(int i = 0; i < opt_len; i++) { ! 6470: if(opt[i] == ' ') { ! 6471: continue; ! 6472: } ! 6473: if(opt[i] == '/' && (opt[i + 1] == 'c' || opt[i + 1] == 'C') && opt[i + 2] == ' ') { ! 6474: for(int j = i + 3; j < opt_len; j++) { ! 6475: if(opt[j] == ' ') { ! 6476: continue; ! 6477: } ! 6478: char *token = my_strtok(opt + j, " "); ! 6479: ! 6480: strcpy(command, token); ! 6481: char tmp[MAX_PATH]; ! 6482: strcpy(tmp, token + strlen(token) + 1); ! 6483: strcpy(opt, ""); ! 6484: for(int i = 0; i < strlen(tmp); i++) { ! 6485: if(tmp[i] != ' ') { ! 6486: strcpy(opt, tmp + i); ! 6487: break; ! 6488: } ! 6489: } ! 6490: strcpy(tmp, opt); ! 6491: ! 6492: if(al == 0x00) { ! 6493: #define GET_FILE_PATH() { \ ! 6494: if(token[0] != '>' && token[0] != '<') { \ ! 6495: token++; \ ! 6496: } \ ! 6497: token++; \ ! 6498: while(*token == ' ') { \ ! 6499: token++; \ ! 6500: } \ ! 6501: char *ptr = token; \ ! 6502: while(*ptr != ' ' && *ptr != '\r' && *ptr != '\0') { \ ! 6503: ptr++; \ ! 6504: } \ ! 6505: *ptr = '\0'; \ ! 6506: } ! 6507: if((token = strstr(opt, "0<")) != NULL || (token = strstr(opt, "<")) != NULL) { ! 6508: GET_FILE_PATH(); ! 6509: strcpy(pipe_stdin_path, token); ! 6510: strcpy(opt, tmp); ! 6511: } ! 6512: if((token = strstr(opt, "1>")) != NULL || (token = strstr(opt, ">")) != NULL) { ! 6513: GET_FILE_PATH(); ! 6514: strcpy(pipe_stdout_path, token); ! 6515: strcpy(opt, tmp); ! 6516: } ! 6517: if((token = strstr(opt, "2>")) != NULL) { ! 6518: GET_FILE_PATH(); ! 6519: strcpy(pipe_stderr_path, token); ! 6520: strcpy(opt, tmp); ! 6521: } ! 6522: #undef GET_FILE_PATH ! 6523: ! 6524: if((token = strstr(opt, "0<")) != NULL) { ! 6525: *token = '\0'; ! 6526: } ! 6527: if((token = strstr(opt, "1>")) != NULL) { ! 6528: *token = '\0'; ! 6529: } ! 6530: if((token = strstr(opt, "2>")) != NULL) { ! 6531: *token = '\0'; ! 6532: } ! 6533: if((token = strstr(opt, "<")) != NULL) { ! 6534: *token = '\0'; ! 6535: } ! 6536: if((token = strstr(opt, ">")) != NULL) { ! 6537: *token = '\0'; ! 6538: } ! 6539: } ! 6540: for(int i = strlen(opt) - 1; i >= 0 && opt[i] == ' '; i--) { ! 6541: opt[i] = '\0'; ! 6542: } ! 6543: opt_len = strlen(opt); ! 6544: mem[opt_ofs] = opt_len; ! 6545: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt); ! 6546: dos_command = 1; ! 6547: break; ! 6548: } ! 6549: } ! 6550: break; ! 6551: } ! 6552: } ! 6553: } ! 6554: ! 6555: // load command file ! 6556: strcpy(path, command); ! 6557: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) { ! 6558: sprintf(path, "%s.COM", command); ! 6559: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) { ! 6560: sprintf(path, "%s.EXE", command); ! 6561: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) { ! 6562: sprintf(path, "%s.BAT", command); ! 6563: if(_access(path, 0) == 0) { ! 6564: // this is a batch file, run command.com ! 6565: char tmp[MAX_PATH]; ! 6566: if(opt_len != 0) { ! 6567: sprintf(tmp, "/C %s %s", path, opt); ! 6568: } else { ! 6569: sprintf(tmp, "/C %s", path); ! 6570: } ! 6571: strcpy(opt, tmp); ! 6572: opt_len = strlen(opt); ! 6573: mem[opt_ofs] = opt_len; ! 6574: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt); ! 6575: strcpy(path, comspec_path); ! 6576: strcpy(name_tmp, "COMMAND.COM"); ! 6577: fd = _open(path, _O_RDONLY | _O_BINARY); ! 6578: } else { ! 6579: // search path in parent environments ! 6580: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4)); ! 6581: const char *env = msdos_env_get(parent_psp->env_seg, "PATH"); ! 6582: if(env != NULL) { ! 6583: char env_path[4096]; ! 6584: strcpy(env_path, env); ! 6585: char *token = my_strtok(env_path, ";"); ! 6586: ! 6587: while(token != NULL) { ! 6588: if(strlen(token) != 0) { ! 6589: sprintf(path, "%s", msdos_combine_path(token, command)); ! 6590: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) { ! 6591: break; ! 6592: } ! 6593: sprintf(path, "%s.COM", msdos_combine_path(token, command)); ! 6594: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) { ! 6595: break; ! 6596: } ! 6597: sprintf(path, "%s.EXE", msdos_combine_path(token, command)); ! 6598: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) { ! 6599: break; ! 6600: } ! 6601: sprintf(path, "%s.BAT", msdos_combine_path(token, command)); ! 6602: if(_access(path, 0) == 0) { ! 6603: // this is a batch file, run command.com ! 6604: char tmp[MAX_PATH]; ! 6605: if(opt_len != 0) { ! 6606: sprintf(tmp, "/C %s %s", path, opt); ! 6607: } else { ! 6608: sprintf(tmp, "/C %s", path); ! 6609: } ! 6610: strcpy(opt, tmp); ! 6611: opt_len = strlen(opt); ! 6612: mem[opt_ofs] = opt_len; ! 6613: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt); ! 6614: strcpy(path, comspec_path); ! 6615: strcpy(name_tmp, "COMMAND.COM"); ! 6616: fd = _open(path, _O_RDONLY | _O_BINARY); ! 6617: break; ! 6618: } ! 6619: } ! 6620: token = my_strtok(NULL, ";"); ! 6621: } ! 6622: } ! 6623: } ! 6624: } ! 6625: } ! 6626: } ! 6627: if(fd == -1) { ! 6628: // we can not find command.com in the path, so open comspec_path ! 6629: if(_stricmp(command, "COMMAND.COM") == 0 || _stricmp(command, "COMMAND") == 0) { ! 6630: strcpy(command, comspec_path); ! 6631: strcpy(path, command); ! 6632: fd = _open(path, _O_RDONLY | _O_BINARY); ! 6633: } ! 6634: } ! 6635: if(fd == -1) { ! 6636: if(!first_process && al == 0 && dos_command) { ! 6637: // may be dos command ! 6638: char tmp[MAX_PATH]; ! 6639: if(opt_len != 0) { ! 6640: sprintf(tmp, "%s %s", command, opt); ! 6641: } else { ! 6642: sprintf(tmp, "%s", command); ! 6643: } ! 6644: retval = system(tmp); ! 6645: return(0); ! 6646: } else { ! 6647: return(-1); ! 6648: } ! 6649: } ! 6650: memset(file_buffer, 0, sizeof(file_buffer)); ! 6651: _read(fd, file_buffer, sizeof(file_buffer)); ! 6652: _close(fd); ! 6653: ! 6654: // check if this is win32 program ! 6655: if(!first_process && al == 0) { ! 6656: UINT16 sign_dos = *(UINT16 *)(file_buffer + 0x00); ! 6657: UINT32 e_lfanew = *(UINT32 *)(file_buffer + 0x3c); ! 6658: if(sign_dos == IMAGE_DOS_SIGNATURE && e_lfanew >= 0x40 && e_lfanew < 0x400) { ! 6659: UINT32 sign_nt = *(UINT32 *)(file_buffer + e_lfanew + 0x00); ! 6660: UINT16 machine = *(UINT16 *)(file_buffer + e_lfanew + 0x04); ! 6661: if(sign_nt == IMAGE_NT_SIGNATURE && (machine == IMAGE_FILE_MACHINE_I386 || machine == IMAGE_FILE_MACHINE_AMD64)) { ! 6662: char tmp[MAX_PATH]; ! 6663: if(opt_len != 0) { ! 6664: sprintf(tmp, "\"%s\" %s", path, opt); ! 6665: } else { ! 6666: sprintf(tmp, "\"%s\"", path); ! 6667: } ! 6668: retval = system(tmp); ! 6669: return(0); ! 6670: } ! 6671: } ! 6672: } ! 6673: ! 6674: // copy environment ! 6675: int umb_linked, env_seg, psp_seg; ! 6676: ! 6677: if((umb_linked = msdos_mem_get_umb_linked()) != 0) { ! 6678: msdos_mem_unlink_umb(); ! 6679: } ! 6680: if((env_seg = msdos_mem_alloc(first_mcb, ENV_SIZE >> 4, 1)) == -1) { ! 6681: if((env_seg = msdos_mem_alloc(UMB_TOP >> 4, ENV_SIZE >> 4, 1)) == -1) { ! 6682: if(umb_linked != 0) { ! 6683: msdos_mem_link_umb(); ! 6684: } ! 6685: return(-1); ! 6686: } ! 6687: } ! 6688: if(param->env_seg == 0) { ! 6689: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4)); ! 6690: memcpy(mem + (env_seg << 4), mem + (parent_psp->env_seg << 4), ENV_SIZE); ! 6691: } else { ! 6692: memcpy(mem + (env_seg << 4), mem + (param->env_seg << 4), ENV_SIZE); ! 6693: } ! 6694: msdos_env_set_argv(env_seg, msdos_short_full_path(path)); ! 6695: ! 6696: // check exe header ! 6697: exe_header_t *header = (exe_header_t *)file_buffer; ! 6698: int paragraphs, free_paragraphs = msdos_mem_get_free(first_mcb, 1); ! 6699: UINT16 cs, ss, ip, sp; ! 6700: ! 6701: if(header->mz == 0x4d5a || header->mz == 0x5a4d) { ! 6702: // memory allocation ! 6703: int header_size = header->header_size * 16; ! 6704: int load_size = header->pages * 512 - header_size; ! 6705: if(header_size + load_size < 512) { ! 6706: load_size = 512 - header_size; ! 6707: } ! 6708: paragraphs = (PSP_SIZE + load_size) >> 4; ! 6709: if(paragraphs + header->min_alloc > free_paragraphs) { ! 6710: msdos_mem_free(env_seg); ! 6711: return(-1); ! 6712: } ! 6713: paragraphs += header->max_alloc ? header->max_alloc : header->min_alloc; ! 6714: if(paragraphs > free_paragraphs) { ! 6715: paragraphs = free_paragraphs; ! 6716: } ! 6717: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) { ! 6718: if((psp_seg = msdos_mem_alloc(UMB_TOP >> 4, paragraphs, 1)) == -1) { ! 6719: if(umb_linked != 0) { ! 6720: msdos_mem_link_umb(); ! 6721: } ! 6722: msdos_mem_free(env_seg); ! 6723: return(-1); ! 6724: } ! 6725: } ! 6726: // relocation ! 6727: int start_seg = psp_seg + (PSP_SIZE >> 4); ! 6728: for(int i = 0; i < header->relocations; i++) { ! 6729: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0); ! 6730: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2); ! 6731: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg; ! 6732: } ! 6733: memcpy(mem + (start_seg << 4), file_buffer + header_size, load_size); ! 6734: // segments ! 6735: cs = header->init_cs + start_seg; ! 6736: ss = header->init_ss + start_seg; ! 6737: ip = header->init_ip; ! 6738: sp = header->init_sp - 2; // for symdeb ! 6739: } else { ! 6740: // memory allocation ! 6741: paragraphs = free_paragraphs; ! 6742: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) { ! 6743: if((psp_seg = msdos_mem_alloc(UMB_TOP >> 4, paragraphs, 1)) == -1) { ! 6744: if(umb_linked != 0) { ! 6745: msdos_mem_link_umb(); ! 6746: } ! 6747: msdos_mem_free(env_seg); ! 6748: return(-1); ! 6749: } ! 6750: } ! 6751: int start_seg = psp_seg + (PSP_SIZE >> 4); ! 6752: memcpy(mem + (start_seg << 4), file_buffer, 0x10000 - PSP_SIZE); ! 6753: // segments ! 6754: cs = ss = psp_seg; ! 6755: ip = 0x100; ! 6756: sp = 0xfffe; ! 6757: } ! 6758: if(umb_linked != 0) { ! 6759: msdos_mem_link_umb(); ! 6760: } ! 6761: ! 6762: // create psp ! 6763: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_eip; ! 6764: *(UINT16 *)(mem + 4 * 0x22 + 2) = SREG(CS); ! 6765: psp_t *psp = msdos_psp_create(psp_seg, psp_seg + paragraphs, current_psp, env_seg); ! 6766: memcpy(psp->fcb1, mem + (param->fcb1.w.h << 4) + param->fcb1.w.l, sizeof(psp->fcb1)); ! 6767: memcpy(psp->fcb2, mem + (param->fcb2.w.h << 4) + param->fcb2.w.l, sizeof(psp->fcb2)); ! 6768: memcpy(psp->buffer, mem + (param->cmd_line.w.h << 4) + param->cmd_line.w.l, sizeof(psp->buffer)); ! 6769: ! 6770: mcb_t *mcb_env = (mcb_t *)(mem + ((env_seg - 1) << 4)); ! 6771: mcb_t *mcb_psp = (mcb_t *)(mem + ((psp_seg - 1) << 4)); ! 6772: mcb_psp->psp = mcb_env->psp = psp_seg; ! 6773: ! 6774: for(int i = 0; i < 8; i++) { ! 6775: if(name_tmp[i] == '.') { ! 6776: mcb_psp->prog_name[i] = '\0'; ! 6777: break; ! 6778: } else if(i < 7 && msdos_lead_byte_check(name_tmp[i])) { ! 6779: mcb_psp->prog_name[i] = name_tmp[i]; ! 6780: i++; ! 6781: mcb_psp->prog_name[i] = name_tmp[i]; ! 6782: } else if(name_tmp[i] >= 'a' && name_tmp[i] <= 'z') { ! 6783: mcb_psp->prog_name[i] = name_tmp[i] - 'a' + 'A'; ! 6784: } else { ! 6785: mcb_psp->prog_name[i] = name_tmp[i]; ! 6786: } ! 6787: } ! 6788: ! 6789: // process info ! 6790: process_t *process = msdos_process_info_create(psp_seg); ! 6791: strcpy(process->module_dir, msdos_short_full_dir(path)); ! 6792: #ifdef USE_DEBUGGER ! 6793: strcpy(process->module_path, path); ! 6794: #endif ! 6795: process->dta.w.l = 0x80; ! 6796: process->dta.w.h = psp_seg; ! 6797: process->switchar = '/'; ! 6798: process->max_files = 20; ! 6799: process->parent_int_10h_feh_called = int_10h_feh_called; ! 6800: process->parent_int_10h_ffh_called = int_10h_ffh_called; ! 6801: process->parent_ds = SREG(DS); ! 6802: process->parent_es = SREG(ES); ! 6803: ! 6804: current_psp = psp_seg; ! 6805: msdos_sda_update(current_psp); ! 6806: ! 6807: if(al == 0x00) { ! 6808: int_10h_feh_called = int_10h_ffh_called = false; ! 6809: ! 6810: // pipe ! 6811: if(pipe_stdin_path[0] != '\0') { ! 6812: // if((fd = _open(pipe_stdin_path, _O_RDONLY | _O_BINARY)) != -1) { ! 6813: if(msdos_is_device_path(pipe_stdin_path)) { ! 6814: fd = msdos_open_device(pipe_stdin_path, _O_RDONLY | _O_BINARY, &sio_port, &lpt_port); ! 6815: } else { ! 6816: fd = _open(pipe_stdin_path, _O_RDONLY | _O_BINARY); ! 6817: } ! 6818: if(fd != -1) { ! 6819: msdos_file_handler_open(fd, pipe_stdin_path, _isatty(fd), 0, msdos_device_info(pipe_stdin_path), current_psp, sio_port, lpt_port); ! 6820: psp->file_table[0] = fd; ! 6821: msdos_psp_set_file_table(fd, fd, current_psp); ! 6822: } ! 6823: } ! 6824: if(pipe_stdout_path[0] != '\0') { ! 6825: if(_access(pipe_stdout_path, 0) == 0) { ! 6826: SetFileAttributesA(pipe_stdout_path, FILE_ATTRIBUTE_NORMAL); ! 6827: DeleteFileA(pipe_stdout_path); ! 6828: } ! 6829: // if((fd = _open(pipe_stdout_path, _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE)) != -1) { ! 6830: if(msdos_is_device_path(pipe_stdout_path)) { ! 6831: fd = msdos_open_device(pipe_stdout_path, _O_WRONLY | _O_BINARY, &sio_port, &lpt_port); ! 6832: } else { ! 6833: fd = _open(pipe_stdout_path, _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE); ! 6834: } ! 6835: if(fd != -1) { ! 6836: msdos_file_handler_open(fd, pipe_stdout_path, _isatty(fd), 1, msdos_device_info(pipe_stdout_path), current_psp, sio_port, lpt_port); ! 6837: psp->file_table[1] = fd; ! 6838: msdos_psp_set_file_table(fd, fd, current_psp); ! 6839: } ! 6840: } ! 6841: if(pipe_stderr_path[0] != '\0') { ! 6842: if(_access(pipe_stderr_path, 0) == 0) { ! 6843: SetFileAttributesA(pipe_stderr_path, FILE_ATTRIBUTE_NORMAL); ! 6844: DeleteFileA(pipe_stderr_path); ! 6845: } ! 6846: // if((fd = _open(pipe_stderr_path, _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE)) != -1) { ! 6847: if(msdos_is_device_path(pipe_stderr_path)) { ! 6848: fd = msdos_open_device(pipe_stderr_path, _O_WRONLY | _O_BINARY, &sio_port, &lpt_port); ! 6849: } else { ! 6850: fd = _open(pipe_stdout_path, _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE); ! 6851: } ! 6852: if(fd != -1) { ! 6853: msdos_file_handler_open(fd, pipe_stderr_path, _isatty(fd), 1, msdos_device_info(pipe_stderr_path), current_psp, sio_port, lpt_port); ! 6854: psp->file_table[2] = fd; ! 6855: msdos_psp_set_file_table(fd, fd, current_psp); ! 6856: } ! 6857: } ! 6858: ! 6859: // registers and segments ! 6860: REG16(AX) = REG16(BX) = 0x00; ! 6861: REG16(CX) = 0xff; ! 6862: REG16(DX) = psp_seg; ! 6863: REG16(SI) = ip; ! 6864: REG16(DI) = sp; ! 6865: REG16(SP) = sp; ! 6866: SREG(DS) = SREG(ES) = psp_seg; ! 6867: SREG(SS) = ss; ! 6868: i386_load_segment_descriptor(DS); ! 6869: i386_load_segment_descriptor(ES); ! 6870: i386_load_segment_descriptor(SS); ! 6871: ! 6872: *(UINT16 *)(mem + (ss << 4) + sp) = 0; ! 6873: i386_jmp_far(cs, ip); ! 6874: } else if(al == 0x01) { ! 6875: // copy ss:sp and cs:ip to param block ! 6876: param->sp = sp; ! 6877: param->ss = ss; ! 6878: param->ip = ip; ! 6879: param->cs = cs; ! 6880: ! 6881: // the AX value to be passed to the child program is put on top of the child's stack ! 6882: *(UINT16 *)(mem + (ss << 4) + sp) = REG16(AX); ! 6883: } ! 6884: return(0); ! 6885: } ! 6886: ! 6887: void msdos_process_terminate(int psp_seg, int ret, int mem_free) ! 6888: { ! 6889: psp_t *psp = (psp_t *)(mem + (psp_seg << 4)); ! 6890: ! 6891: *(UINT32 *)(mem + 4 * 0x22) = psp->int_22h.dw; ! 6892: *(UINT32 *)(mem + 4 * 0x23) = psp->int_23h.dw; ! 6893: *(UINT32 *)(mem + 4 * 0x24) = psp->int_24h.dw; ! 6894: ! 6895: SREG(SS) = psp->stack.w.h; ! 6896: i386_load_segment_descriptor(SS); ! 6897: REG16(SP) = psp->stack.w.l; ! 6898: i386_jmp_far(psp->int_22h.w.h, psp->int_22h.w.l); ! 6899: ! 6900: // process_t *current_process = msdos_process_info_get(psp_seg); ! 6901: process_t *current_process = NULL; ! 6902: for(int i = 0; i < MAX_PROCESS; i++) { ! 6903: if(process[i].psp == psp_seg) { ! 6904: current_process = &process[i]; ! 6905: break; ! 6906: } ! 6907: } ! 6908: if(current_process == NULL) { ! 6909: throw(0x1f); // general failure ! 6910: } ! 6911: int_10h_feh_called = current_process->parent_int_10h_feh_called; ! 6912: int_10h_ffh_called = current_process->parent_int_10h_ffh_called; ! 6913: if(current_process->called_by_int2eh) { ! 6914: REG16(AX) = ret; ! 6915: } ! 6916: SREG(DS) = current_process->parent_ds; ! 6917: SREG(ES) = current_process->parent_es; ! 6918: i386_load_segment_descriptor(DS); ! 6919: i386_load_segment_descriptor(ES); ! 6920: ! 6921: if(mem_free) { ! 6922: int mcb_seg; ! 6923: while((mcb_seg = msdos_mem_get_last_mcb(first_mcb, psp_seg)) != -1) { ! 6924: msdos_mem_free(mcb_seg + 1); ! 6925: } ! 6926: while((mcb_seg = msdos_mem_get_last_mcb(UMB_TOP >> 4, psp_seg)) != -1) { ! 6927: msdos_mem_free(mcb_seg + 1); ! 6928: } ! 6929: ! 6930: for(int i = 0; i < MAX_FILES; i++) { ! 6931: if(file_handler[i].valid && file_handler[i].psp == psp_seg) { ! 6932: _close(i); ! 6933: msdos_file_handler_close(i); ! 6934: msdos_psp_set_file_table(i, 0x0ff, psp_seg); // FIXME: consider duplicated file handles ! 6935: } ! 6936: } ! 6937: msdos_dta_info_free(psp_seg); ! 6938: } ! 6939: msdos_stdio_reopen(); ! 6940: ! 6941: memset(current_process, 0, sizeof(process_t)); ! 6942: ! 6943: current_psp = psp->parent_psp; ! 6944: retval = ret; ! 6945: msdos_sda_update(current_psp); ! 6946: } ! 6947: ! 6948: // drive ! 6949: ! 6950: int pcbios_update_drive_param(int drive_num, int force_update); ! 6951: ! 6952: int msdos_drive_param_block_update(int drive_num, UINT16 *seg, UINT16 *ofs, int force_update) ! 6953: { ! 6954: if(!(drive_num >= 0 && drive_num < 26)) { ! 6955: return(0); ! 6956: } ! 6957: pcbios_update_drive_param(drive_num, force_update); ! 6958: ! 6959: drive_param_t *drive_param = &drive_params[drive_num]; ! 6960: *seg = DPB_TOP >> 4; ! 6961: *ofs = sizeof(dpb_t) * drive_num; ! 6962: dpb_t *dpb = (dpb_t *)(mem + (*seg << 4) + *ofs); ! 6963: ! 6964: memset(dpb, 0, sizeof(dpb_t)); ! 6965: ! 6966: dpb->drive_num = drive_num; ! 6967: dpb->unit_num = drive_num; ! 6968: ! 6969: if(drive_param->valid) { ! 6970: DISK_GEOMETRY *geo = &drive_param->geometry; ! 6971: ! 6972: dpb->bytes_per_sector = (UINT16)geo->BytesPerSector; ! 6973: dpb->highest_sector_num = (UINT8)(geo->SectorsPerTrack - 1); ! 6974: dpb->highest_cluster_num = (UINT16)(geo->TracksPerCylinder * geo->Cylinders.QuadPart + 1); ! 6975: dpb->maximum_cluster_num = (UINT32)(geo->TracksPerCylinder * geo->Cylinders.QuadPart + 1); ! 6976: switch(geo->MediaType) { ! 6977: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K) ! 6978: dpb->media_type = 0xff; ! 6979: break; ! 6980: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K) ! 6981: dpb->media_type = 0xfe; ! 6982: break; ! 6983: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K) ! 6984: dpb->media_type = 0xfd; ! 6985: break; ! 6986: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K) ! 6987: dpb->media_type = 0xfc; ! 6988: break; ! 6989: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M) ! 6990: case F3_1Pt2_512: ! 6991: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5") ! 6992: case F5_720_512: ! 6993: dpb->media_type = 0xf9; ! 6994: break; ! 6995: case FixedMedia: // hard disk ! 6996: case RemovableMedia: ! 6997: case Unknown: ! 6998: dpb->media_type = 0xf8; ! 6999: break; ! 7000: default: ! 7001: dpb->media_type = 0xf0; ! 7002: break; ! 7003: } ! 7004: } ! 7005: dpb->next_dpb_ofs = (drive_num == 25) ? 0xffff : *ofs + sizeof(dpb_t); ! 7006: dpb->next_dpb_seg = (drive_num == 25) ? 0xffff : *seg; ! 7007: dpb->info_sector = 0xffff; ! 7008: dpb->backup_boot_sector = 0xffff; ! 7009: dpb->free_clusters = 0xffff; ! 7010: dpb->free_search_cluster = 0xffffffff; ! 7011: ! 7012: return(drive_param->valid); ! 7013: } ! 7014: ! 7015: // pc bios ! 7016: ! 7017: #ifdef USE_SERVICE_THREAD ! 7018: void start_service_loop(LPTHREAD_START_ROUTINE lpStartAddress) ! 7019: { ! 7020: #if defined(HAS_I386) ! 7021: if(m_SF != 0) { ! 7022: m_SF = 0; ! 7023: mem[DUMMY_TOP + 0x15] = 0x79; // jns -4 ! 7024: } else { ! 7025: m_SF = 1; ! 7026: mem[DUMMY_TOP + 0x15] = 0x78; // js -4 ! 7027: } ! 7028: #else ! 7029: if(m_SignVal < 0) { ! 7030: m_SignVal = 0; ! 7031: mem[DUMMY_TOP + 0x15] = 0x79; // jns -4 ! 7032: } else { ! 7033: m_SignVal = -1; ! 7034: mem[DUMMY_TOP + 0x15] = 0x78; // js -4 ! 7035: } ! 7036: #endif ! 7037: // dummy loop to wait BIOS/DOS service is done is at fffc:0013 ! 7038: i386_call_far(DUMMY_TOP >> 4, 0x0013); ! 7039: in_service = true; ! 7040: service_exit = false; ! 7041: CloseHandle(CreateThread(NULL, 0, lpStartAddress, NULL, 0, NULL)); ! 7042: } ! 7043: ! 7044: void finish_service_loop() ! 7045: { ! 7046: if(in_service && service_exit) { ! 7047: #if defined(HAS_I386) ! 7048: if(m_SF != 0) { ! 7049: m_SF = 0; ! 7050: } else { ! 7051: m_SF = 1; ! 7052: } ! 7053: #else ! 7054: if(m_SignVal < 0) { ! 7055: m_SignVal = 0; ! 7056: } else { ! 7057: m_SignVal = -1; ! 7058: } ! 7059: #endif ! 7060: in_service = false; ! 7061: } ! 7062: } ! 7063: #endif ! 7064: ! 7065: UINT32 get_ticks_since_midnight(UINT32 cur_msec) ! 7066: { ! 7067: static unsigned __int64 start_msec_since_midnight = 0; ! 7068: static unsigned __int64 start_msec_since_hostboot = 0; ! 7069: ! 7070: if(start_msec_since_midnight == 0) { ! 7071: SYSTEMTIME time; ! 7072: GetLocalTime(&time); ! 7073: start_msec_since_midnight = ((time.wHour * 60 + time.wMinute) * 60 + time.wSecond) * 1000 + time.wMilliseconds; ! 7074: start_msec_since_hostboot = cur_msec; ! 7075: } ! 7076: unsigned __int64 msec = (start_msec_since_midnight + cur_msec - start_msec_since_hostboot) % (24 * 60 * 60 * 1000); ! 7077: unsigned __int64 tick = msec * 0x1800b0 / (24 * 60 * 60 * 1000); ! 7078: return (UINT32)tick; ! 7079: } ! 7080: ! 7081: void pcbios_update_daily_timer_counter(UINT32 cur_msec) ! 7082: { ! 7083: UINT32 prev_tick = *(UINT32 *)(mem + 0x46c); ! 7084: UINT32 next_tick = get_ticks_since_midnight(cur_msec); ! 7085: ! 7086: if(prev_tick > next_tick) { ! 7087: mem[0x470] = 1; ! 7088: } ! 7089: *(UINT32 *)(mem + 0x46c) = next_tick; ! 7090: } ! 7091: ! 7092: inline void pcbios_irq0() ! 7093: { ! 7094: //++*(UINT32 *)(mem + 0x46c); ! 7095: pcbios_update_daily_timer_counter(timeGetTime()); ! 7096: } ! 7097: ! 7098: int pcbios_get_text_vram_address(int page) ! 7099: { ! 7100: if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) { ! 7101: return TEXT_VRAM_TOP; ! 7102: } else { ! 7103: return TEXT_VRAM_TOP + VIDEO_REGEN * (page % vram_pages); ! 7104: } ! 7105: } ! 7106: ! 7107: int pcbios_get_shadow_buffer_address(int page) ! 7108: { ! 7109: if(!int_10h_feh_called) { ! 7110: return pcbios_get_text_vram_address(page); ! 7111: } else if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) { ! 7112: return SHADOW_BUF_TOP; ! 7113: } else { ! 7114: return SHADOW_BUF_TOP + VIDEO_REGEN * (page % vram_pages); ! 7115: } ! 7116: } ! 7117: ! 7118: int pcbios_get_shadow_buffer_address(int page, int x, int y) ! 7119: { ! 7120: return pcbios_get_shadow_buffer_address(page) + (x + y * scr_width) * 2; ! 7121: } ! 7122: ! 7123: bool pcbios_set_font_size(int width, int height) ! 7124: { ! 7125: if(set_console_font_size(width, height)) { ! 7126: *(UINT16 *)(mem + 0x485) = height; ! 7127: return(true); ! 7128: } ! 7129: return(false); ! 7130: } ! 7131: ! 7132: void pcbios_set_console_size(int width, int height, bool clr_screen) ! 7133: { ! 7134: // clear the existing screen, not just the new one ! 7135: int clr_height = max(height, scr_height); ! 7136: ! 7137: if(scr_width != width || scr_height != height) { ! 7138: change_console_size(width, height); ! 7139: } ! 7140: mem[0x462] = 0; ! 7141: *(UINT16 *)(mem + 0x44e) = 0; ! 7142: ! 7143: text_vram_top_address = pcbios_get_text_vram_address(0); ! 7144: text_vram_end_address = text_vram_top_address + width * height * 2; ! 7145: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(0); ! 7146: shadow_buffer_end_address = shadow_buffer_top_address + width * height * 2; ! 7147: cursor_position_address = 0x450 + mem[0x462] * 2; ! 7148: ! 7149: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); ! 7150: if(clr_screen) { ! 7151: for(int ofs = shadow_buffer_top_address; ofs < shadow_buffer_end_address;) { ! 7152: mem[ofs++] = 0x20; ! 7153: mem[ofs++] = 0x07; ! 7154: } ! 7155: ! 7156: #ifdef USE_VRAM_THREAD ! 7157: EnterCriticalSection(&vram_crit_sect); ! 7158: #endif ! 7159: for(int y = 0; y < clr_height; y++) { ! 7160: for(int x = 0; x < scr_width; x++) { ! 7161: SCR_BUF(y,x).Char.AsciiChar = ' '; ! 7162: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; ! 7163: } ! 7164: } ! 7165: SMALL_RECT rect; ! 7166: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + clr_height - 1); ! 7167: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect); ! 7168: vram_length_char = vram_last_length_char = 0; ! 7169: vram_length_attr = vram_last_length_attr = 0; ! 7170: #ifdef USE_VRAM_THREAD ! 7171: LeaveCriticalSection(&vram_crit_sect); ! 7172: #endif ! 7173: } ! 7174: COORD co; ! 7175: co.X = 0; ! 7176: co.Y = scr_top; ! 7177: SetConsoleCursorPosition(hStdout, co); ! 7178: cursor_moved = true; ! 7179: cursor_moved_by_crtc = false; ! 7180: SetConsoleTextAttribute(hStdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); ! 7181: } ! 7182: ! 7183: void pcbios_update_cursor_position() ! 7184: { ! 7185: CONSOLE_SCREEN_BUFFER_INFO csbi; ! 7186: GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); ! 7187: if(!restore_console_on_exit) { ! 7188: scr_top = csbi.srWindow.Top; ! 7189: } ! 7190: mem[0x450 + mem[0x462] * 2] = csbi.dwCursorPosition.X; ! 7191: mem[0x451 + mem[0x462] * 2] = csbi.dwCursorPosition.Y - scr_top; ! 7192: } ! 7193: ! 7194: inline void pcbios_int_10h_00h() ! 7195: { ! 7196: switch(REG8(AL) & 0x7f) { ! 7197: case 0x70: // v-text mode ! 7198: case 0x71: // extended cga v-text mode ! 7199: pcbios_set_console_size(scr_width, scr_height, !(REG8(AL) & 0x80)); ! 7200: break; ! 7201: case 0x73: ! 7202: case 0x03: ! 7203: change_console_size(80, 25); // for Windows10 ! 7204: pcbios_set_font_size(font_width, font_height); ! 7205: pcbios_set_console_size(80, 25, !(REG8(AL) & 0x80)); ! 7206: break; ! 7207: } ! 7208: if(REG8(AL) & 0x80) { ! 7209: mem[0x487] |= 0x80; ! 7210: } else { ! 7211: mem[0x487] &= ~0x80; ! 7212: } ! 7213: mem[0x449] = REG8(AL) & 0x7f; ! 7214: } ! 7215: ! 7216: inline void pcbios_int_10h_01h() ! 7217: { ! 7218: mem[0x460] = REG8(CL); ! 7219: mem[0x461] = REG8(CH); ! 7220: ! 7221: int size = (int)(REG8(CL) & 7) - (int)(REG8(CH) & 7) + 1; ! 7222: ! 7223: if(!((REG8(CH) & 0x20) != 0 || size < 0)) { ! 7224: ci_new.bVisible = TRUE; ! 7225: ci_new.dwSize = (size + 2) * 100 / (8 + 2); ! 7226: } else { ! 7227: ci_new.bVisible = FALSE; ! 7228: } ! 7229: } ! 7230: ! 7231: inline void pcbios_int_10h_02h() ! 7232: { ! 7233: // continuously setting the cursor effectively stops it blinking ! 7234: if(mem[0x462] == REG8(BH) && (REG8(DL) != mem[0x450 + REG8(BH) * 2] || REG8(DH) != mem[0x451 + REG8(BH) * 2] || cursor_moved_by_crtc)) { ! 7235: COORD co; ! 7236: co.X = REG8(DL); ! 7237: co.Y = REG8(DH) + scr_top; ! 7238: ! 7239: // some programs hide the cursor by moving it off screen ! 7240: static bool hidden = false; ! 7241: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); ! 7242: ! 7243: if(REG8(DH) >= scr_height || !SetConsoleCursorPosition(hStdout, co)) { ! 7244: if(ci_new.bVisible) { ! 7245: ci_new.bVisible = FALSE; ! 7246: hidden = true; ! 7247: } ! 7248: } else if(hidden) { ! 7249: if(!ci_new.bVisible) { ! 7250: ci_new.bVisible = TRUE; ! 7251: } ! 7252: hidden = false; ! 7253: } ! 7254: cursor_moved_by_crtc = false; ! 7255: } ! 7256: mem[0x450 + (REG8(BH) % vram_pages) * 2] = REG8(DL); ! 7257: mem[0x451 + (REG8(BH) % vram_pages) * 2] = REG8(DH); ! 7258: } ! 7259: ! 7260: inline void pcbios_int_10h_03h() ! 7261: { ! 7262: REG8(DL) = mem[0x450 + (REG8(BH) % vram_pages) * 2]; ! 7263: REG8(DH) = mem[0x451 + (REG8(BH) % vram_pages) * 2]; ! 7264: REG8(CL) = mem[0x460]; ! 7265: REG8(CH) = mem[0x461]; ! 7266: } ! 7267: ! 7268: inline void pcbios_int_10h_05h() ! 7269: { ! 7270: if(REG8(AL) >= vram_pages) { ! 7271: return; ! 7272: } ! 7273: if(mem[0x462] != REG8(AL)) { ! 7274: vram_flush(); ! 7275: ! 7276: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); ! 7277: SMALL_RECT rect; ! 7278: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1); ! 7279: ReadConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect); ! 7280: ! 7281: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(mem[0x462]); y < scr_height; y++) { ! 7282: for(int x = 0; x < scr_width; x++) { ! 7283: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar; ! 7284: mem[ofs++] = SCR_BUF(y,x).Attributes; ! 7285: } ! 7286: } ! 7287: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(REG8(AL)); y < scr_height; y++) { ! 7288: for(int x = 0; x < scr_width; x++) { ! 7289: SCR_BUF(y,x).Char.AsciiChar = mem[ofs++]; ! 7290: SCR_BUF(y,x).Attributes = mem[ofs++]; ! 7291: } ! 7292: } ! 7293: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect); ! 7294: ! 7295: COORD co; ! 7296: co.X = mem[0x450 + REG8(AL) * 2]; ! 7297: co.Y = mem[0x451 + REG8(AL) * 2] + scr_top; ! 7298: if(co.Y < scr_top + scr_height) { ! 7299: SetConsoleCursorPosition(hStdout, co); ! 7300: } ! 7301: cursor_moved_by_crtc = false; ! 7302: } ! 7303: mem[0x462] = REG8(AL); ! 7304: *(UINT16 *)(mem + 0x44e) = REG8(AL) * VIDEO_REGEN; ! 7305: int regen = min(scr_width * scr_height * 2, 0x8000); ! 7306: text_vram_top_address = pcbios_get_text_vram_address(mem[0x462]); ! 7307: text_vram_end_address = text_vram_top_address + regen; ! 7308: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(mem[0x462]); ! 7309: shadow_buffer_end_address = shadow_buffer_top_address + regen; ! 7310: cursor_position_address = 0x450 + mem[0x462] * 2; ! 7311: } ! 7312: ! 7313: inline void pcbios_int_10h_06h() ! 7314: { ! 7315: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) || ! 7316: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) { ! 7317: return; ! 7318: } ! 7319: vram_flush(); ! 7320: ! 7321: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); ! 7322: SMALL_RECT rect; ! 7323: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1); ! 7324: ReadConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect); ! 7325: ! 7326: int right = min(REG8(DL), scr_width - 1); ! 7327: int bottom = min(REG8(DH), scr_height - 1); ! 7328: ! 7329: if(REG8(AL) == 0) { ! 7330: for(int y = REG8(CH); y <= bottom; y++) { ! 7331: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) { ! 7332: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' '; ! 7333: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH); ! 7334: } ! 7335: } ! 7336: } else { ! 7337: for(int y = REG8(CH), y2 = min(REG8(CH) + REG8(AL), bottom + 1); y <= bottom; y++, y2++) { ! 7338: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) { ! 7339: if(y2 <= bottom) { ! 7340: SCR_BUF(y,x) = SCR_BUF(y2,x); ! 7341: } else { ! 7342: SCR_BUF(y,x).Char.AsciiChar = ' '; ! 7343: SCR_BUF(y,x).Attributes = REG8(BH); ! 7344: } ! 7345: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar; ! 7346: mem[ofs++] = SCR_BUF(y,x).Attributes; ! 7347: } ! 7348: } ! 7349: } ! 7350: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect); ! 7351: } ! 7352: ! 7353: inline void pcbios_int_10h_07h() ! 7354: { ! 7355: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) || ! 7356: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) { ! 7357: return; ! 7358: } ! 7359: vram_flush(); ! 7360: ! 7361: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); ! 7362: SMALL_RECT rect; ! 7363: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1); ! 7364: ReadConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect); ! 7365: ! 7366: int right = min(REG8(DL), scr_width - 1); ! 7367: int bottom = min(REG8(DH), scr_height - 1); ! 7368: ! 7369: if(REG8(AL) == 0) { ! 7370: for(int y = REG8(CH); y <= bottom; y++) { ! 7371: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) { ! 7372: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' '; ! 7373: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH); ! 7374: } ! 7375: } ! 7376: } else { ! 7377: for(int y = bottom, y2 = max(REG8(CH) - 1, bottom - REG8(AL)); y >= REG8(CH); y--, y2--) { ! 7378: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) { ! 7379: if(y2 >= REG8(CH)) { ! 7380: SCR_BUF(y,x) = SCR_BUF(y2,x); ! 7381: } else { ! 7382: SCR_BUF(y,x).Char.AsciiChar = ' '; ! 7383: SCR_BUF(y,x).Attributes = REG8(BH); ! 7384: } ! 7385: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar; ! 7386: mem[ofs++] = SCR_BUF(y,x).Attributes; ! 7387: } ! 7388: } ! 7389: } ! 7390: WriteConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect); ! 7391: } ! 7392: ! 7393: inline void pcbios_int_10h_08h() ! 7394: { ! 7395: COORD co; ! 7396: DWORD num; ! 7397: ! 7398: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2]; ! 7399: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2]; ! 7400: ! 7401: if(mem[0x462] == REG8(BH)) { ! 7402: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); ! 7403: co.Y += scr_top; ! 7404: vram_flush(); ! 7405: ReadConsoleOutputCharacterA(hStdout, scr_char, 1, co, &num); ! 7406: ReadConsoleOutputAttribute(hStdout, scr_attr, 1, co, &num); ! 7407: REG8(AL) = scr_char[0]; ! 7408: REG8(AH) = scr_attr[0]; ! 7409: } else { ! 7410: REG16(AX) = *(UINT16 *)(mem + pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y)); ! 7411: } ! 7412: } ! 7413: ! 7414: inline void pcbios_int_10h_09h() ! 7415: { ! 7416: COORD co; ! 7417: ! 7418: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2]; ! 7419: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2]; ! 7420: ! 7421: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y); ! 7422: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height)); ! 7423: ! 7424: if(mem[0x462] == REG8(BH)) { ! 7425: #ifdef USE_VRAM_THREAD ! 7426: EnterCriticalSection(&vram_crit_sect); ! 7427: #endif ! 7428: int vram = pcbios_get_shadow_buffer_address(REG8(BH)); ! 7429: while(dest < end) { ! 7430: write_text_vram_char(dest - vram, REG8(AL)); ! 7431: mem[dest++] = REG8(AL); ! 7432: write_text_vram_attr(dest - vram, REG8(BL)); ! 7433: mem[dest++] = REG8(BL); ! 7434: } ! 7435: #ifdef USE_VRAM_THREAD ! 7436: LeaveCriticalSection(&vram_crit_sect); ! 7437: #endif ! 7438: } else { ! 7439: while(dest < end) { ! 7440: mem[dest++] = REG8(AL); ! 7441: mem[dest++] = REG8(BL); ! 7442: } ! 7443: } ! 7444: } ! 7445: ! 7446: inline void pcbios_int_10h_0ah() ! 7447: { ! 7448: COORD co; ! 7449: ! 7450: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2]; ! 7451: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2]; ! 7452: ! 7453: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y); ! 7454: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height)); ! 7455: ! 7456: if(mem[0x462] == REG8(BH)) { ! 7457: #ifdef USE_VRAM_THREAD ! 7458: EnterCriticalSection(&vram_crit_sect); ! 7459: #endif ! 7460: int vram = pcbios_get_shadow_buffer_address(REG8(BH)); ! 7461: while(dest < end) { ! 7462: write_text_vram_char(dest - vram, REG8(AL)); ! 7463: mem[dest++] = REG8(AL); ! 7464: dest++; ! 7465: } ! 7466: #ifdef USE_VRAM_THREAD ! 7467: LeaveCriticalSection(&vram_crit_sect); ! 7468: #endif ! 7469: } else { ! 7470: while(dest < end) { ! 7471: mem[dest++] = REG8(AL); ! 7472: dest++; ! 7473: } ! 7474: } ! 7475: } ! 7476: ! 7477: inline void pcbios_int_10h_0ch() ! 7478: { ! 7479: HDC hdc = get_console_window_device_context(); ! 7480: ! 7481: if(hdc != NULL) { ! 7482: BYTE r = (REG8(AL) & 2) ? 255 : 0; ! 7483: BYTE g = (REG8(AL) & 4) ? 255 : 0; ! 7484: BYTE b = (REG8(AL) & 1) ? 255 : 0; ! 7485: ! 7486: if(REG8(AL) & 0x80) { ! 7487: COLORREF color = GetPixel(hdc, REG16(CX), REG16(DX)); ! 7488: if(color != CLR_INVALID) { ! 7489: r ^= ((DWORD)color & 0x0000ff) ? 255 : 0; ! 7490: g ^= ((DWORD)color & 0x00ff00) ? 255 : 0; ! 7491: b ^= ((DWORD)color & 0xff0000) ? 255 : 0; ! 7492: } ! 7493: } ! 7494: SetPixel(hdc, REG16(CX), REG16(DX), RGB(r, g, b)); ! 7495: } ! 7496: } ! 7497: ! 7498: inline void pcbios_int_10h_0dh() ! 7499: { ! 7500: HDC hdc = get_console_window_device_context(); ! 7501: BYTE r = 0; ! 7502: BYTE g = 0; ! 7503: BYTE b = 0; ! 7504: ! 7505: if(hdc != NULL) { ! 7506: COLORREF color = GetPixel(hdc, REG16(CX), REG16(DX)); ! 7507: if(color != CLR_INVALID) { ! 7508: r = ((DWORD)color & 0x0000ff) ? 255 : 0; ! 7509: g = ((DWORD)color & 0x00ff00) ? 255 : 0; ! 7510: b = ((DWORD)color & 0xff0000) ? 255 : 0; ! 7511: } ! 7512: } ! 7513: REG8(AL) = ((b != 0) ? 1 : 0) | ((r != 0) ? 2 : 0) | ((g != 0) ? 4 : 0); ! 7514: } ! 7515: ! 7516: inline void pcbios_int_10h_0eh() ! 7517: { ! 7518: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); ! 7519: CONSOLE_SCREEN_BUFFER_INFO csbi; ! 7520: DWORD num; ! 7521: COORD co; ! 7522: ! 7523: if(cursor_moved_by_crtc) { ! 7524: if(!restore_console_on_exit) { ! 7525: GetConsoleScreenBufferInfo(hStdout, &csbi); ! 7526: scr_top = csbi.srWindow.Top; ! 7527: } ! 7528: co.X = mem[0x450 + REG8(BH) * 2]; ! 7529: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top; ! 7530: SetConsoleCursorPosition(hStdout, co); ! 7531: cursor_moved_by_crtc = false; ! 7532: } ! 7533: co.X = mem[0x450 + mem[0x462] * 2]; ! 7534: co.Y = mem[0x451 + mem[0x462] * 2]; ! 7535: ! 7536: if(REG8(AL) == 7) { ! 7537: //MessageBeep(-1); ! 7538: } else if(REG8(AL) == 8 || REG8(AL) == 10 || REG8(AL) == 13) { ! 7539: if(REG8(AL) == 10) { ! 7540: vram_flush(); ! 7541: } ! 7542: WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), ®8(AL), 1, &num, NULL); ! 7543: cursor_moved = true; ! 7544: } else { ! 7545: int dest = pcbios_get_shadow_buffer_address(mem[0x462], co.X, co.Y); ! 7546: #ifdef USE_VRAM_THREAD ! 7547: EnterCriticalSection(&vram_crit_sect); ! 7548: #endif ! 7549: int vram = pcbios_get_shadow_buffer_address(mem[0x462]); ! 7550: write_text_vram_char(dest - vram, REG8(AL)); ! 7551: #ifdef USE_VRAM_THREAD ! 7552: LeaveCriticalSection(&vram_crit_sect); ! 7553: #endif ! 7554: ! 7555: if(++co.X == scr_width) { ! 7556: co.X = 0; ! 7557: if(++co.Y == scr_height) { ! 7558: vram_flush(); ! 7559: WriteConsoleA(hStdout, "\n", 1, &num, NULL); ! 7560: cursor_moved = true; ! 7561: } ! 7562: } ! 7563: if(!cursor_moved) { ! 7564: co.Y += scr_top; ! 7565: SetConsoleCursorPosition(hStdout, co); ! 7566: cursor_moved = true; ! 7567: } ! 7568: mem[dest] = REG8(AL); ! 7569: } ! 7570: } ! 7571: ! 7572: inline void pcbios_int_10h_0fh() ! 7573: { ! 7574: REG8(AL) = mem[0x449]; ! 7575: REG8(AH) = mem[0x44a]; ! 7576: REG8(BH) = mem[0x462]; ! 7577: } ! 7578: ! 7579: inline void pcbios_int_10h_11h() ! 7580: { ! 7581: switch(REG8(AL)) { ! 7582: case 0x00: ! 7583: case 0x10: ! 7584: if(REG8(BH)) { ! 7585: change_console_size(80, 25); // for Windows10 ! 7586: if(!pcbios_set_font_size(font_width, (int)REG8(BH))) { ! 7587: for(int h = min(font_height, (int)REG8(BH)); h <= max(font_height, (int)REG8(BH)); h++) { ! 7588: if(h != (int)REG8(BH)) { ! 7589: if(pcbios_set_font_size(font_width, h)) { ! 7590: break; ! 7591: } ! 7592: } ! 7593: } ! 7594: } ! 7595: pcbios_set_console_size(80, (25 * 16) / REG8(BH), true); ! 7596: } ! 7597: break; ! 7598: case 0x01: ! 7599: case 0x11: ! 7600: change_console_size(80, 28); // for Windows10 ! 7601: if(!pcbios_set_font_size(font_width, 14)) { ! 7602: for(int h = min(font_height, 14); h <= max(font_height, 14); h++) { ! 7603: if(h != 14) { ! 7604: if(pcbios_set_font_size(font_width, h)) { ! 7605: break; ! 7606: } ! 7607: } ! 7608: } ! 7609: } ! 7610: pcbios_set_console_size(80, 28, true); // 28 = 25 * 16 / 14 ! 7611: break; ! 7612: case 0x02: ! 7613: case 0x12: ! 7614: change_console_size(80, 25); // for Windows10 ! 7615: if(!pcbios_set_font_size(8, 8)) { ! 7616: bool success = false; ! 7617: for(int y = 8; y <= 14; y++) { ! 7618: for(int x = min(font_width, 6); x <= max(font_width, 8); x++) { ! 7619: if(pcbios_set_font_size(x, y)) { ! 7620: success = true; ! 7621: break; ! 7622: } ! 7623: } ! 7624: } ! 7625: if(!success) { ! 7626: pcbios_set_font_size(font_width, font_height); ! 7627: } ! 7628: } ! 7629: pcbios_set_console_size(80, 50, true); // 50 = 25 * 16 / 8 ! 7630: break; ! 7631: case 0x04: ! 7632: case 0x14: ! 7633: change_console_size(80, 25); // for Windows10 ! 7634: pcbios_set_font_size(font_width, font_height); ! 7635: pcbios_set_console_size(80, 25, true); ! 7636: break; ! 7637: case 0x18: ! 7638: change_console_size(80, 25); // for Windows10 ! 7639: pcbios_set_font_size(font_width, font_height); ! 7640: pcbios_set_console_size(80, 25, true); ! 7641: break; ! 7642: case 0x30: ! 7643: SREG(ES) = 0; ! 7644: i386_load_segment_descriptor(ES); ! 7645: REG16(BP) = 0; ! 7646: REG16(CX) = mem[0x485]; ! 7647: REG8(DL) = mem[0x484]; ! 7648: break; ! 7649: default: ! 7650: unimplemented_10h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x10, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 7651: m_CF = 1; ! 7652: break; ! 7653: } ! 7654: } ! 7655: ! 7656: inline void pcbios_int_10h_12h() ! 7657: { ! 7658: switch(REG8(BL)) { ! 7659: case 0x10: ! 7660: REG16(BX) = 0x0003; ! 7661: REG16(CX) = 0x0009; ! 7662: break; ! 7663: } ! 7664: } ! 7665: ! 7666: inline void pcbios_int_10h_13h() ! 7667: { ! 7668: int ofs = SREG_BASE(ES) + REG16(BP); ! 7669: COORD co; ! 7670: DWORD num; ! 7671: ! 7672: co.X = REG8(DL); ! 7673: co.Y = REG8(DH) + scr_top; ! 7674: ! 7675: vram_flush(); ! 7676: ! 7677: switch(REG8(AL)) { ! 7678: case 0x00: ! 7679: case 0x01: ! 7680: if(mem[0x462] == REG8(BH)) { ! 7681: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); ! 7682: CONSOLE_SCREEN_BUFFER_INFO csbi; ! 7683: GetConsoleScreenBufferInfo(hStdout, &csbi); ! 7684: SetConsoleCursorPosition(hStdout, co); ! 7685: ! 7686: if(csbi.wAttributes != REG8(BL)) { ! 7687: SetConsoleTextAttribute(hStdout, REG8(BL)); ! 7688: } ! 7689: WriteConsoleA(hStdout, &mem[ofs], REG16(CX), &num, NULL); ! 7690: ! 7691: if(csbi.wAttributes != REG8(BL)) { ! 7692: SetConsoleTextAttribute(hStdout, csbi.wAttributes); ! 7693: } ! 7694: if(REG8(AL) == 0x00) { ! 7695: if(!restore_console_on_exit) { ! 7696: GetConsoleScreenBufferInfo(hStdout, &csbi); ! 7697: scr_top = csbi.srWindow.Top; ! 7698: } ! 7699: co.X = mem[0x450 + REG8(BH) * 2]; ! 7700: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top; ! 7701: SetConsoleCursorPosition(hStdout, co); ! 7702: } else { ! 7703: cursor_moved = true; ! 7704: } ! 7705: cursor_moved_by_crtc = false; ! 7706: } else { ! 7707: m_CF = 1; ! 7708: } ! 7709: break; ! 7710: case 0x02: ! 7711: case 0x03: ! 7712: if(mem[0x462] == REG8(BH)) { ! 7713: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); ! 7714: CONSOLE_SCREEN_BUFFER_INFO csbi; ! 7715: GetConsoleScreenBufferInfo(hStdout, &csbi); ! 7716: SetConsoleCursorPosition(hStdout, co); ! 7717: ! 7718: WORD wAttributes = csbi.wAttributes; ! 7719: for(int i = 0; i < REG16(CX); i++, ofs += 2) { ! 7720: if(wAttributes != mem[ofs + 1]) { ! 7721: SetConsoleTextAttribute(hStdout, mem[ofs + 1]); ! 7722: wAttributes = mem[ofs + 1]; ! 7723: } ! 7724: WriteConsoleA(hStdout, &mem[ofs], 1, &num, NULL); ! 7725: } ! 7726: if(csbi.wAttributes != wAttributes) { ! 7727: SetConsoleTextAttribute(hStdout, csbi.wAttributes); ! 7728: } ! 7729: if(REG8(AL) == 0x02) { ! 7730: co.X = mem[0x450 + REG8(BH) * 2]; ! 7731: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top; ! 7732: SetConsoleCursorPosition(hStdout, co); ! 7733: } else { ! 7734: cursor_moved = true; ! 7735: } ! 7736: cursor_moved_by_crtc = false; ! 7737: } else { ! 7738: m_CF = 1; ! 7739: } ! 7740: break; ! 7741: case 0x10: ! 7742: case 0x11: ! 7743: if(mem[0x462] == REG8(BH)) { ! 7744: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); ! 7745: ReadConsoleOutputCharacterA(hStdout, scr_char, REG16(CX), co, &num); ! 7746: ReadConsoleOutputAttribute(hStdout, scr_attr, REG16(CX), co, &num); ! 7747: for(int i = 0; i < num; i++) { ! 7748: mem[ofs++] = scr_char[i]; ! 7749: mem[ofs++] = scr_attr[i]; ! 7750: if(REG8(AL) & 0x01) { ! 7751: mem[ofs++] = 0; ! 7752: mem[ofs++] = 0; ! 7753: } ! 7754: } ! 7755: } else { ! 7756: for(int i = 0, src = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y - scr_top); i < REG16(CX); i++) { ! 7757: mem[ofs++] = mem[src++]; ! 7758: mem[ofs++] = mem[src++]; ! 7759: if(REG8(AL) & 0x01) { ! 7760: mem[ofs++] = 0; ! 7761: mem[ofs++] = 0; ! 7762: } ! 7763: if(++co.X == scr_width) { ! 7764: if(++co.Y == scr_height) { ! 7765: break; ! 7766: } ! 7767: co.X = 0; ! 7768: } ! 7769: } ! 7770: } ! 7771: break; ! 7772: case 0x12: // ??? ! 7773: case 0x13: // ??? ! 7774: case 0x20: ! 7775: case 0x21: ! 7776: if(mem[0x462] == REG8(BH)) { ! 7777: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); ! 7778: int len = min(REG16(CX), scr_width * scr_height); ! 7779: for(int i = 0; i < len; i++) { ! 7780: scr_char[i] = mem[ofs++]; ! 7781: scr_attr[i] = mem[ofs++]; ! 7782: if(REG8(AL) & 0x01) { ! 7783: ofs += 2; ! 7784: } ! 7785: } ! 7786: WriteConsoleOutputCharacterA(hStdout, scr_char, len, co, &num); ! 7787: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num); ! 7788: } else { ! 7789: for(int i = 0, dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y - scr_top); i < REG16(CX); i++) { ! 7790: mem[dest++] = mem[ofs++]; ! 7791: mem[dest++] = mem[ofs++]; ! 7792: if(REG8(AL) & 0x01) { ! 7793: ofs += 2; ! 7794: } ! 7795: if(++co.X == scr_width) { ! 7796: if(++co.Y == scr_height) { ! 7797: break; ! 7798: } ! 7799: co.X = 0; ! 7800: } ! 7801: } ! 7802: } ! 7803: break; ! 7804: default: ! 7805: unimplemented_10h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x10, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 7806: m_CF = 1; ! 7807: break; ! 7808: } ! 7809: } ! 7810: ! 7811: inline void pcbios_int_10h_18h() ! 7812: { ! 7813: switch(REG8(AL)) { ! 7814: case 0x00: ! 7815: case 0x01: ! 7816: // REG8(AL) = 0x86; ! 7817: REG8(AL) = 0x00; ! 7818: break; ! 7819: default: ! 7820: unimplemented_10h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x10, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 7821: m_CF = 1; ! 7822: break; ! 7823: } ! 7824: } ! 7825: ! 7826: inline void pcbios_int_10h_1ah() ! 7827: { ! 7828: switch(REG8(AL)) { ! 7829: case 0x00: ! 7830: REG8(AL) = 0x1a; ! 7831: REG8(BL) = 0x08; ! 7832: REG8(BH) = 0x00; ! 7833: break; ! 7834: default: ! 7835: unimplemented_10h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x10, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 7836: m_CF = 1; ! 7837: break; ! 7838: } ! 7839: } ! 7840: ! 7841: inline void pcbios_int_10h_1dh() ! 7842: { ! 7843: switch(REG8(AL)) { ! 7844: case 0x00: ! 7845: // DOS/V Shift Status Line Control is not supported ! 7846: m_CF = 1; ! 7847: break; ! 7848: case 0x01: ! 7849: break; ! 7850: case 0x02: ! 7851: REG16(BX) = 0; ! 7852: break; ! 7853: default: ! 7854: unimplemented_10h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x10, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 7855: m_CF = 1; ! 7856: break; ! 7857: } ! 7858: } ! 7859: ! 7860: inline void pcbios_int_10h_4fh() ! 7861: { ! 7862: switch(REG8(AL)) { ! 7863: case 0x00: ! 7864: REG8(AH) = 0x02; // not supported ! 7865: break; ! 7866: case 0x01: ! 7867: case 0x02: ! 7868: case 0x03: ! 7869: case 0x04: ! 7870: case 0x05: ! 7871: case 0x06: ! 7872: case 0x07: ! 7873: case 0x08: ! 7874: case 0x09: ! 7875: case 0x0a: ! 7876: case 0x0b: ! 7877: case 0x0c: ! 7878: REG8(AH) = 0x01; // failed ! 7879: break; ! 7880: default: ! 7881: unimplemented_10h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x10, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 7882: m_CF = 1; ! 7883: break; ! 7884: } ! 7885: } ! 7886: ! 7887: inline void pcbios_int_10h_82h() ! 7888: { ! 7889: static UINT8 mode = 0; ! 7890: ! 7891: switch(REG8(AL)) { ! 7892: case 0x00: ! 7893: if(REG8(BL) != 0xff) { ! 7894: mode = REG8(BL); ! 7895: } ! 7896: REG8(AL) = mode; ! 7897: break; ! 7898: default: ! 7899: unimplemented_10h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x10, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 7900: m_CF = 1; ! 7901: break; ! 7902: } ! 7903: } ! 7904: ! 7905: inline void pcbios_int_10h_83h() ! 7906: { ! 7907: static UINT8 mode = 0; ! 7908: ! 7909: switch(REG8(AL)) { ! 7910: case 0x00: ! 7911: REG16(AX) = 0; // offset??? ! 7912: SREG(ES) = (SHADOW_BUF_TOP >> 4); ! 7913: i386_load_segment_descriptor(ES); ! 7914: REG16(BX) = (SHADOW_BUF_TOP & 0x0f); ! 7915: break; ! 7916: default: ! 7917: unimplemented_10h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x10, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 7918: m_CF = 1; ! 7919: break; ! 7920: } ! 7921: } ! 7922: ! 7923: inline void pcbios_int_10h_90h() ! 7924: { ! 7925: REG8(AL) = mem[0x449]; ! 7926: } ! 7927: ! 7928: inline void pcbios_int_10h_91h() ! 7929: { ! 7930: REG8(AL) = 0x04; // VGA ! 7931: } ! 7932: ! 7933: inline void pcbios_int_10h_efh() ! 7934: { ! 7935: REG16(DX) = 0xffff; ! 7936: } ! 7937: ! 7938: inline void pcbios_int_10h_feh() ! 7939: { ! 7940: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) { ! 7941: SREG(ES) = (SHADOW_BUF_TOP >> 4); ! 7942: i386_load_segment_descriptor(ES); ! 7943: REG16(DI) = (SHADOW_BUF_TOP & 0x0f); ! 7944: } ! 7945: int_10h_feh_called = true; ! 7946: } ! 7947: ! 7948: inline void pcbios_int_10h_ffh() ! 7949: { ! 7950: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) { ! 7951: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); ! 7952: COORD co; ! 7953: DWORD num; ! 7954: ! 7955: vram_flush(); ! 7956: ! 7957: co.X = (REG16(DI) >> 1) % scr_width; ! 7958: co.Y = (REG16(DI) >> 1) / scr_width; ! 7959: int ofs = pcbios_get_shadow_buffer_address(0, co.X, co.Y); ! 7960: int end = min(ofs + REG16(CX) * 2, pcbios_get_shadow_buffer_address(0, 0, scr_height)); ! 7961: int len; ! 7962: for(len = 0; ofs < end; len++) { ! 7963: scr_char[len] = mem[ofs++]; ! 7964: scr_attr[len] = mem[ofs++]; ! 7965: } ! 7966: co.Y += scr_top; ! 7967: WriteConsoleOutputCharacterA(hStdout, scr_char, len, co, &num); ! 7968: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num); ! 7969: } ! 7970: int_10h_ffh_called = true; ! 7971: } ! 7972: ! 7973: int pcbios_update_drive_param(int drive_num, int force_update) ! 7974: { ! 7975: if(drive_num >= 0 && drive_num < 26) { ! 7976: drive_param_t *drive_param = &drive_params[drive_num]; ! 7977: ! 7978: if(force_update || !drive_param->initialized) { ! 7979: drive_param->valid = 0; ! 7980: char dev[64]; ! 7981: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num); ! 7982: ! 7983: HANDLE hFile = CreateFileA(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); ! 7984: if(hFile != INVALID_HANDLE_VALUE) { ! 7985: DWORD dwSize; ! 7986: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &drive_param->geometry, sizeof(DISK_GEOMETRY), &dwSize, NULL)) { ! 7987: drive_param->valid = 1; ! 7988: } ! 7989: CloseHandle(hFile); ! 7990: } ! 7991: drive_param->initialized = 1; ! 7992: } ! 7993: return(drive_param->valid); ! 7994: } ! 7995: return(0); ! 7996: } ! 7997: ! 7998: inline void pcbios_int_13h_00h() ! 7999: { ! 8000: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1; ! 8001: ! 8002: if(pcbios_update_drive_param(drive_num, 1)) { ! 8003: REG8(AH) = 0x00; // successful completion ! 8004: } else { ! 8005: if(REG8(DL) & 0x80) { ! 8006: REG8(AH) = 0x05; // reset failed (hard disk) ! 8007: } else { ! 8008: REG8(AH) = 0x80; // timeout (not ready) ! 8009: } ! 8010: m_CF = 1; ! 8011: } ! 8012: } ! 8013: ! 8014: inline void pcbios_int_13h_02h() ! 8015: { ! 8016: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1; ! 8017: ! 8018: if(REG8(AL) == 0) { ! 8019: REG8(AH) = 0x01; // invalid function in AH or invalid parameter ! 8020: m_CF = 1; ! 8021: } else if(!pcbios_update_drive_param(drive_num, 0)) { ! 8022: REG8(AH) = 0xff; // sense operation failed (hard disk) ! 8023: m_CF = 1; ! 8024: } else { ! 8025: drive_param_t *drive_param = &drive_params[drive_num]; ! 8026: DISK_GEOMETRY *geo = &drive_param->geometry; ! 8027: char dev[64]; ! 8028: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num); ! 8029: ! 8030: HANDLE hFile = CreateFileA(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL); ! 8031: if(hFile == INVALID_HANDLE_VALUE) { ! 8032: REG8(AH) = 0xff; // sense operation failed (hard disk) ! 8033: m_CF = 1; ! 8034: } else { ! 8035: UINT32 sector_num = REG8(AL); ! 8036: UINT32 cylinder = REG8(CH) | ((REG8(CL) & 0xc0) << 2); ! 8037: UINT32 head = REG8(DH); ! 8038: UINT32 sector = REG8(CL) & 0x3f; ! 8039: UINT32 top_sector = ((cylinder * drive_param->head_num() + head) * geo->SectorsPerTrack) + sector - 1; ! 8040: UINT32 buffer_addr = SREG_BASE(ES) + REG16(BX); ! 8041: DWORD dwSize; ! 8042: ! 8043: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) { ! 8044: // REG8(AH) = 0xff; // sense operation failed (hard disk) ! 8045: // m_CF = 1; ! 8046: // } else ! 8047: if(SetFilePointer(hFile, top_sector * geo->BytesPerSector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { ! 8048: REG8(AH) = 0x04; // sector not found/read error ! 8049: m_CF = 1; ! 8050: } else if(ReadFile(hFile, mem + buffer_addr, sector_num * geo->BytesPerSector, &dwSize, NULL) == 0) { ! 8051: REG8(AH) = 0x04; // sector not found/read error ! 8052: m_CF = 1; ! 8053: } else { ! 8054: REG8(AH) = 0x00; // successful completion ! 8055: } ! 8056: CloseHandle(hFile); ! 8057: } ! 8058: } ! 8059: } ! 8060: ! 8061: inline void pcbios_int_13h_03h() ! 8062: { ! 8063: // this operation may cause serious damage for drives, so support only floppy disk... ! 8064: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1; ! 8065: ! 8066: if(REG8(AL) == 0) { ! 8067: REG8(AH) = 0x01; // invalid function in AH or invalid parameter ! 8068: m_CF = 1; ! 8069: } else if(!pcbios_update_drive_param(drive_num, 0)) { ! 8070: REG8(AH) = 0xff; // sense operation failed (hard disk) ! 8071: m_CF = 1; ! 8072: } else if(!drive_params[drive_num].is_fdd()) { ! 8073: REG8(AH) = 0xff; // sense operation failed (hard disk) ! 8074: m_CF = 1; ! 8075: } else { ! 8076: drive_param_t *drive_param = &drive_params[drive_num]; ! 8077: DISK_GEOMETRY *geo = &drive_param->geometry; ! 8078: char dev[64]; ! 8079: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num); ! 8080: ! 8081: HANDLE hFile = CreateFileA(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL); ! 8082: if(hFile == INVALID_HANDLE_VALUE) { ! 8083: REG8(AH) = 0xff; // sense operation failed (hard disk) ! 8084: m_CF = 1; ! 8085: } else { ! 8086: UINT32 sector_num = REG8(AL); ! 8087: UINT32 cylinder = REG8(CH) | ((REG8(CL) & 0xc0) << 2); ! 8088: UINT32 head = REG8(DH); ! 8089: UINT32 sector = REG8(CL) & 0x3f; ! 8090: UINT32 top_sector = ((cylinder * drive_param->head_num() + head) * geo->SectorsPerTrack) + sector - 1; ! 8091: UINT32 buffer_addr = SREG_BASE(ES) + REG16(BX); ! 8092: DWORD dwSize; ! 8093: ! 8094: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) { ! 8095: // REG8(AH) = 0xff; // sense operation failed (hard disk) ! 8096: // m_CF = 1; ! 8097: // } else ! 8098: if(SetFilePointer(hFile, top_sector * geo->BytesPerSector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { ! 8099: REG8(AH) = 0x04; // sector not found/read error ! 8100: m_CF = 1; ! 8101: } else if(WriteFile(hFile, mem + buffer_addr, sector_num * geo->BytesPerSector, &dwSize, NULL) == 0) { ! 8102: REG8(AH) = 0x04; // sector not found/read error ! 8103: m_CF = 1; ! 8104: } else { ! 8105: REG8(AH) = 0x00; // successful completion ! 8106: } ! 8107: CloseHandle(hFile); ! 8108: } ! 8109: } ! 8110: } ! 8111: ! 8112: inline void pcbios_int_13h_04h() ! 8113: { ! 8114: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1; ! 8115: ! 8116: if(REG8(AL) == 0) { ! 8117: REG8(AH) = 0x01; // invalid function in AH or invalid parameter ! 8118: m_CF = 1; ! 8119: } else if(!pcbios_update_drive_param(drive_num, 0)) { ! 8120: REG8(AH) = 0xff; // sense operation failed (hard disk) ! 8121: m_CF = 1; ! 8122: } else { ! 8123: drive_param_t *drive_param = &drive_params[drive_num]; ! 8124: DISK_GEOMETRY *geo = &drive_param->geometry; ! 8125: char dev[64]; ! 8126: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num); ! 8127: ! 8128: HANDLE hFile = CreateFileA(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL); ! 8129: if(hFile == INVALID_HANDLE_VALUE) { ! 8130: REG8(AH) = 0xff; // sense operation failed (hard disk) ! 8131: m_CF = 1; ! 8132: } else { ! 8133: UINT32 sector_num = REG8(AL); ! 8134: UINT32 cylinder = REG8(CH) | ((REG8(CL) & 0xc0) << 2); ! 8135: UINT32 head = REG8(DH); ! 8136: UINT32 sector = REG8(CL) & 0x3f; ! 8137: UINT32 top_sector = ((cylinder * drive_param->head_num() + head) * geo->SectorsPerTrack) + sector - 1; ! 8138: UINT32 buffer_addr = SREG_BASE(ES) + REG16(BX); ! 8139: DWORD dwSize; ! 8140: UINT8 *tmp_buffer = (UINT8 *)malloc(sector_num * geo->BytesPerSector); ! 8141: ! 8142: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) { ! 8143: // REG8(AH) = 0xff; // sense operation failed (hard disk) ! 8144: // m_CF = 1; ! 8145: // } else ! 8146: if(SetFilePointer(hFile, top_sector * geo->BytesPerSector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { ! 8147: REG8(AH) = 0x04; // sector not found/read error ! 8148: m_CF = 1; ! 8149: } else if(ReadFile(hFile, tmp_buffer, sector_num * geo->BytesPerSector, &dwSize, NULL) == 0) { ! 8150: REG8(AH) = 0x04; // sector not found/read error ! 8151: m_CF = 1; ! 8152: } else if(memcmp(mem + buffer_addr, tmp_buffer, sector_num * geo->BytesPerSector) != 0) { ! 8153: REG8(AH) = 0x05; // data did not verify correctly (TI Professional PC) ! 8154: m_CF = 1; ! 8155: } else { ! 8156: REG8(AH) = 0x00; // successful completion ! 8157: } ! 8158: free(tmp_buffer); ! 8159: CloseHandle(hFile); ! 8160: } ! 8161: } ! 8162: } ! 8163: ! 8164: inline void pcbios_int_13h_08h() ! 8165: { ! 8166: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1; ! 8167: ! 8168: if(pcbios_update_drive_param(drive_num, 1)) { ! 8169: drive_param_t *drive_param = &drive_params[drive_num]; ! 8170: DISK_GEOMETRY *geo = &drive_param->geometry; ! 8171: ! 8172: REG16(AX) = 0x0000; ! 8173: switch(geo->MediaType) { ! 8174: case F5_360_512: ! 8175: case F5_320_512: ! 8176: case F5_320_1024: ! 8177: case F5_180_512: ! 8178: case F5_160_512: ! 8179: REG8(BL) = 0x01; // 320K/360K disk ! 8180: break; ! 8181: case F5_1Pt2_512: ! 8182: case F3_1Pt2_512: ! 8183: case F3_1Pt23_1024: ! 8184: case F5_1Pt23_1024: ! 8185: REG8(BL) = 0x02; // 1.2M disk ! 8186: break; ! 8187: case F3_720_512: ! 8188: case F3_640_512: ! 8189: case F5_640_512: ! 8190: case F5_720_512: ! 8191: REG8(BL) = 0x03; // 720K disk ! 8192: break; ! 8193: case F3_1Pt44_512: ! 8194: REG8(BL) = 0x04; // 1.44M disk ! 8195: break; ! 8196: case F3_2Pt88_512: ! 8197: REG8(BL) = 0x06; // 2.88M disk ! 8198: break; ! 8199: case RemovableMedia: ! 8200: REG8(BL) = 0x10; // ATAPI Removable Media Device ! 8201: break; ! 8202: default: ! 8203: REG8(BL) = 0x00; // unknown ! 8204: break; ! 8205: } ! 8206: if(REG8(DL) & 0x80) { ! 8207: switch(GetLogicalDrives() & 0x0c) { ! 8208: case 0x00: REG8(DL) = 0x00; break; ! 8209: case 0x04: ! 8210: case 0x08: REG8(DL) = 0x01; break; ! 8211: case 0x0c: REG8(DL) = 0x02; break; ! 8212: } ! 8213: } else { ! 8214: switch(GetLogicalDrives() & 0x03) { ! 8215: case 0x00: REG8(DL) = 0x00; break; ! 8216: case 0x01: ! 8217: case 0x02: REG8(DL) = 0x01; break; ! 8218: case 0x03: REG8(DL) = 0x02; break; ! 8219: } ! 8220: } ! 8221: REG8(DH) = drive_param->head_num(); ! 8222: int cyl = (geo->Cylinders.QuadPart > 0x3ff) ? 0x3ff : geo->Cylinders.QuadPart; ! 8223: int sec = (geo->SectorsPerTrack > 0x3f) ? 0x3f : geo->SectorsPerTrack; ! 8224: REG8(CH) = cyl & 0xff; ! 8225: REG8(CL) = (sec & 0x3f) | ((cyl & 0x300) >> 2); ! 8226: } else { ! 8227: REG8(AH) = 0x07; ! 8228: m_CF = 1; ! 8229: } ! 8230: } ! 8231: ! 8232: inline void pcbios_int_13h_10h() ! 8233: { ! 8234: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1; ! 8235: ! 8236: if(pcbios_update_drive_param(drive_num, 1)) { ! 8237: REG8(AH) = 0x00; // successful completion ! 8238: } else { ! 8239: if(REG8(DL) & 0x80) { ! 8240: REG8(AH) = 0xaa; // drive not ready (hard disk) ! 8241: } else { ! 8242: REG8(AH) = 0x80; // timeout (not ready) ! 8243: } ! 8244: m_CF = 1; ! 8245: } ! 8246: } ! 8247: ! 8248: inline void pcbios_int_13h_15h() ! 8249: { ! 8250: int drive_num = (REG8(DL) & 0x80) ? ((REG8(DL) & 0x7f) + 2) : (REG8(DL) < 2) ? REG8(DL) : -1; ! 8251: ! 8252: if(pcbios_update_drive_param(drive_num, 1)) { ! 8253: if(REG8(DL) & 0x80) { ! 8254: REG8(AH) = 0x02; // floppy (or other removable drive) with change-line support ! 8255: } else { ! 8256: REG8(AH) = 0x03; // hard disk ! 8257: } ! 8258: } else { ! 8259: REG8(AH) = 0x00; // no such drive ! 8260: } ! 8261: } ! 8262: ! 8263: inline void pcbios_int_13h_41h() ! 8264: { ! 8265: if(REG16(BX) == 0x55aa) { ! 8266: // IBM/MS INT 13 Extensions is not installed ! 8267: REG8(AH) = 0x01; ! 8268: m_CF = 1; ! 8269: } else { ! 8270: unimplemented_13h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x13, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 8271: REG8(AH) = 0x01; ! 8272: m_CF = 1; ! 8273: } ! 8274: } ! 8275: ! 8276: inline void pcbios_int_14h_00h() ! 8277: { ! 8278: if(REG16(DX) < 4) { ! 8279: static const unsigned int rate[] = {110, 150, 300, 600, 1200, 2400, 4800, 9600}; ! 8280: UINT8 selector = sio_read(REG16(DX), 3); ! 8281: selector &= ~0x3f; ! 8282: selector |= REG8(AL) & 0x1f; ! 8283: UINT16 divisor = 115200 / rate[REG8(AL) >> 5]; ! 8284: sio_write(REG16(DX), 3, selector | 0x80); ! 8285: sio_write(REG16(DX), 0, divisor & 0xff); ! 8286: sio_write(REG16(DX), 1, divisor >> 8); ! 8287: sio_write(REG16(DX), 3, selector); ! 8288: REG8(AH) = sio_read(REG16(DX), 5); ! 8289: REG8(AL) = sio_read(REG16(DX), 6); ! 8290: } else { ! 8291: REG8(AH) = 0x80; ! 8292: } ! 8293: } ! 8294: ! 8295: inline void pcbios_int_14h_01h() ! 8296: { ! 8297: if(REG16(DX) < 4) { ! 8298: UINT8 selector = sio_read(REG16(DX), 3); ! 8299: sio_write(REG16(DX), 3, selector & ~0x80); ! 8300: sio_write(REG16(DX), 0, REG8(AL)); ! 8301: sio_write(REG16(DX), 3, selector); ! 8302: REG8(AH) = sio_read(REG16(DX), 5); ! 8303: } else { ! 8304: REG8(AH) = 0x80; ! 8305: } ! 8306: } ! 8307: ! 8308: inline void pcbios_int_14h_02h() ! 8309: { ! 8310: if(REG16(DX) < 4) { ! 8311: UINT8 selector = sio_read(REG16(DX), 3); ! 8312: sio_write(REG16(DX), 3, selector & ~0x80); ! 8313: REG8(AL) = sio_read(REG16(DX), 0); ! 8314: sio_write(REG16(DX), 3, selector); ! 8315: REG8(AH) = sio_read(REG16(DX), 5); ! 8316: } else { ! 8317: REG8(AH) = 0x80; ! 8318: } ! 8319: } ! 8320: ! 8321: inline void pcbios_int_14h_03h() ! 8322: { ! 8323: if(REG16(DX) < 4) { ! 8324: REG8(AH) = sio_read(REG16(DX), 5); ! 8325: REG8(AL) = sio_read(REG16(DX), 6); ! 8326: } else { ! 8327: REG8(AH) = 0x80; ! 8328: } ! 8329: } ! 8330: ! 8331: inline void pcbios_int_14h_04h() ! 8332: { ! 8333: if(REG16(DX) < 4) { ! 8334: UINT8 selector = sio_read(REG16(DX), 3); ! 8335: if(REG8(CH) <= 0x03) { ! 8336: selector = (selector & ~0x03) | REG8(CH); ! 8337: } ! 8338: if(REG8(BL) == 0x00) { ! 8339: selector &= ~0x04; ! 8340: } else if(REG8(BL) == 0x01) { ! 8341: selector |= 0x04; ! 8342: } ! 8343: if(REG8(BH) == 0x00) { ! 8344: selector = (selector & ~0x38) | 0x00; ! 8345: } else if(REG8(BH) == 0x01) { ! 8346: selector = (selector & ~0x38) | 0x08; ! 8347: } else if(REG8(BH) == 0x02) { ! 8348: selector = (selector & ~0x38) | 0x18; ! 8349: } else if(REG8(BH) == 0x03) { ! 8350: selector = (selector & ~0x38) | 0x28; ! 8351: } else if(REG8(BH) == 0x04) { ! 8352: selector = (selector & ~0x38) | 0x38; ! 8353: } ! 8354: if(REG8(AL) == 0x00) { ! 8355: selector |= 0x40; ! 8356: } else if(REG8(AL) == 0x01) { ! 8357: selector &= ~0x40; ! 8358: } ! 8359: if(REG8(CL) <= 0x0b) { ! 8360: static const unsigned int rate[] = {110, 150, 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200}; ! 8361: UINT16 divisor = 115200 / rate[REG8(CL)]; ! 8362: sio_write(REG16(DX), 3, selector | 0x80); ! 8363: sio_write(REG16(DX), 0, divisor & 0xff); ! 8364: sio_write(REG16(DX), 1, divisor >> 8); ! 8365: } ! 8366: sio_write(REG16(DX), 3, selector); ! 8367: REG8(AH) = sio_read(REG16(DX), 5); ! 8368: REG8(AL) = sio_read(REG16(DX), 6); ! 8369: } else { ! 8370: REG8(AH) = 0x80; ! 8371: } ! 8372: } ! 8373: ! 8374: inline void pcbios_int_14h_05h() ! 8375: { ! 8376: if(REG16(DX) < 4) { ! 8377: if(REG8(AL) == 0x00) { ! 8378: REG8(BL) = sio_read(REG16(DX), 4); ! 8379: REG8(AH) = sio_read(REG16(DX), 5); ! 8380: REG8(AL) = sio_read(REG16(DX), 6); ! 8381: } else if(REG8(AL) == 0x01) { ! 8382: sio_write(REG16(DX), 4, REG8(BL)); ! 8383: REG8(AH) = sio_read(REG16(DX), 5); ! 8384: REG8(AL) = sio_read(REG16(DX), 6); ! 8385: } else { ! 8386: unimplemented_14h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x14, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 8387: } ! 8388: } else { ! 8389: REG8(AH) = 0x80; ! 8390: } ! 8391: } ! 8392: ! 8393: inline void pcbios_int_15h_23h() ! 8394: { ! 8395: switch(REG8(AL)) { ! 8396: case 0x00: ! 8397: REG8(CL) = cmos_read(0x2d); ! 8398: REG8(CH) = cmos_read(0x2e); ! 8399: break; ! 8400: case 0x01: ! 8401: cmos_write(0x2d, REG8(CL)); ! 8402: cmos_write(0x2e, REG8(CH)); ! 8403: break; ! 8404: default: ! 8405: unimplemented_15h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x15, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 8406: REG8(AH) = 0x86; ! 8407: m_CF = 1; ! 8408: break; ! 8409: } ! 8410: } ! 8411: ! 8412: inline void pcbios_int_15h_24h() ! 8413: { ! 8414: switch(REG8(AL)) { ! 8415: case 0x00: ! 8416: i386_set_a20_line(0); ! 8417: REG8(AH) = 0; ! 8418: break; ! 8419: case 0x01: ! 8420: i386_set_a20_line(1); ! 8421: REG8(AH) = 0; ! 8422: break; ! 8423: case 0x02: ! 8424: REG8(AH) = 0; ! 8425: REG8(AL) = (m_a20_mask >> 20) & 1; ! 8426: REG16(CX) = 0; ! 8427: break; ! 8428: case 0x03: ! 8429: REG16(AX) = 0; ! 8430: REG16(BX) = 0; ! 8431: break; ! 8432: default: ! 8433: unimplemented_15h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x15, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 8434: REG8(AH) = 0x86; ! 8435: m_CF = 1; ! 8436: break; ! 8437: } ! 8438: } ! 8439: ! 8440: inline void pcbios_int_15h_49h() ! 8441: { ! 8442: REG8(AH) = 0x00; ! 8443: REG8(BL) = 0x00; // DOS/V ! 8444: // REG8(BL) = 0x01; // standard DBCS DOS (hardware DBCS support) ! 8445: } ! 8446: ! 8447: inline void pcbios_int_15h_50h() ! 8448: { ! 8449: switch(REG8(AL)) { ! 8450: case 0x00: ! 8451: case 0x01: ! 8452: if(REG8(BH) != 0x00 && REG8(BH) != 0x01) { ! 8453: REG8(AH) = 0x01; // invalid font type in bh ! 8454: m_CF = 1; ! 8455: } else if(REG8(BL) != 0x00) { ! 8456: REG8(AH) = 0x02; // bl not zero ! 8457: m_CF = 1; ! 8458: } else if(REG16(BP) != 0 && REG16(BP) != 437 && REG16(BP) != 932 && REG16(BP) != 934 && REG16(BP) != 936 && REG16(BP) != 938) { ! 8459: REG8(AH) = 0x04; // invalid code page ! 8460: m_CF = 1; ! 8461: } else if(REG8(AL) == 0x01) { ! 8462: REG8(AH) = 0x06; // font is read only ! 8463: m_CF = 1; ! 8464: } else { ! 8465: // dummy font read routine is at fffc:000d ! 8466: SREG(ES) = DUMMY_TOP >> 4; ! 8467: i386_load_segment_descriptor(ES); ! 8468: REG16(BX) = 0x000d; ! 8469: REG8(AH) = 0x00; // success ! 8470: } ! 8471: break; ! 8472: default: ! 8473: unimplemented_15h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x15, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 8474: REG8(AH) = 0x86; ! 8475: m_CF = 1; ! 8476: break; ! 8477: } ! 8478: } ! 8479: ! 8480: inline void pcbios_int_15h_53h() ! 8481: { ! 8482: switch(REG8(AL)) { ! 8483: case 0x00: ! 8484: // APM is not installed ! 8485: REG8(AH) = 0x86; ! 8486: m_CF = 1; ! 8487: break; ! 8488: default: ! 8489: unimplemented_15h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x15, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 8490: REG8(AH) = 0x86; ! 8491: m_CF = 1; ! 8492: break; ! 8493: } ! 8494: } ! 8495: ! 8496: inline void pcbios_int_15h_84h() ! 8497: { ! 8498: // joystick support (from DOSBox) ! 8499: switch(REG16(DX)) { ! 8500: case 0x00: ! 8501: REG16(AX) = 0x00f0; ! 8502: REG16(DX) = 0x0201; ! 8503: m_CF = 1; ! 8504: break; ! 8505: case 0x01: ! 8506: REG16(AX) = REG16(BX) = REG16(CX) = REG16(DX) = 0x0000; ! 8507: m_CF = 1; ! 8508: break; ! 8509: default: ! 8510: unimplemented_15h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x15, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 8511: REG8(AH) = 0x86; ! 8512: m_CF = 1; ! 8513: break; ! 8514: } ! 8515: } ! 8516: ! 8517: DWORD WINAPI pcbios_int_15h_86h_thread(LPVOID) ! 8518: { ! 8519: UINT32 usec = (REG16(CX) << 16) | REG16(DX); ! 8520: UINT32 msec = usec / 1000; ! 8521: ! 8522: while(msec && !m_exit) { ! 8523: UINT32 tmp = min(msec, 100); ! 8524: if(msec - tmp < 10) { ! 8525: tmp = msec; ! 8526: } ! 8527: Sleep(tmp); ! 8528: msec -= tmp; ! 8529: } ! 8530: ! 8531: #ifdef USE_SERVICE_THREAD ! 8532: service_exit = true; ! 8533: #endif ! 8534: return(0); ! 8535: } ! 8536: ! 8537: inline void pcbios_int_15h_86h() ! 8538: { ! 8539: if(!(REG16(CX) == 0 && REG16(DX) == 0)) { ! 8540: #ifdef USE_SERVICE_THREAD ! 8541: if(!in_service && !in_service_29h) { ! 8542: start_service_loop(pcbios_int_15h_86h_thread); ! 8543: } else { ! 8544: #endif ! 8545: pcbios_int_15h_86h_thread(NULL); ! 8546: REQUEST_HARDWRE_UPDATE(); ! 8547: #ifdef USE_SERVICE_THREAD ! 8548: } ! 8549: #endif ! 8550: } ! 8551: } ! 8552: ! 8553: inline void pcbios_int_15h_87h() ! 8554: { ! 8555: // copy extended memory (from DOSBox) ! 8556: int len = REG16(CX) * 2; ! 8557: int ofs = SREG_BASE(ES) + REG16(SI); ! 8558: int src = (*(UINT32 *)(mem + ofs + 0x12) & 0xffffff); // + (mem[ofs + 0x16] << 24); ! 8559: int dst = (*(UINT32 *)(mem + ofs + 0x1a) & 0xffffff); // + (mem[ofs + 0x1e] << 24); ! 8560: memcpy(mem + dst, mem + src, len); ! 8561: REG16(AX) = 0x00; ! 8562: } ! 8563: ! 8564: inline void pcbios_int_15h_88h() ! 8565: { ! 8566: REG16(AX) = ((min(MAX_MEM, 0x4000000) - 0x100000) >> 10); ! 8567: } ! 8568: ! 8569: inline void pcbios_int_15h_89h() ! 8570: { ! 8571: #if defined(HAS_I286) || defined(HAS_I386) ! 8572: // switch to protected mode (from DOSBox) ! 8573: write_io_byte(0x20, 0x10); ! 8574: write_io_byte(0x21, REG8(BH)); ! 8575: write_io_byte(0x21, 0x00); ! 8576: write_io_byte(0x21, 0xff); ! 8577: write_io_byte(0xa0, 0x10); ! 8578: write_io_byte(0xa1, REG8(BL)); ! 8579: write_io_byte(0xa1, 0x00); ! 8580: write_io_byte(0xa1, 0xff); ! 8581: i386_set_a20_line(1); ! 8582: m_gdtr.limit = *(UINT16 *)(mem + SREG_BASE(ES) + REG16(SI) + 0x08); ! 8583: m_gdtr.base = *(UINT32 *)(mem + SREG_BASE(ES) + REG16(SI) + 0x08 + 0x02) & 0xffffff; ! 8584: m_idtr.limit = *(UINT16 *)(mem + SREG_BASE(ES) + REG16(SI) + 0x10); ! 8585: m_idtr.base = *(UINT32 *)(mem + SREG_BASE(ES) + REG16(SI) + 0x10 + 0x02) & 0xffffff; ! 8586: #if defined(HAS_I386) ! 8587: m_cr[0] |= 1; ! 8588: #else ! 8589: m_msw |= 1; ! 8590: #endif ! 8591: i386_sreg_load(0x18, DS, NULL); ! 8592: i386_sreg_load(0x20, ES, NULL); ! 8593: i386_sreg_load(0x28, SS, NULL); ! 8594: UINT16 offset = *(UINT16 *)(mem + SREG_BASE(SS) + REG16(SP)); ! 8595: REG16(SP) += 6; // clear stack of interrupt frame ! 8596: UINT32 flags = i386_get_flags(); ! 8597: flags &= ~0x247fd5; // clear CF,PF,AF,ZF,SF,TF,IF,DF,OF,IOPL,NT,AC,ID ! 8598: i386_set_flags(flags); ! 8599: REG16(AX) = 0x00; ! 8600: i386_jmp_far(0x30, /*REG16(CX)*/offset); ! 8601: #else ! 8602: // i86/i186/v30: protected mode is not supported ! 8603: REG8(AH) = 0x86; ! 8604: m_CF = 1; ! 8605: #endif ! 8606: } ! 8607: ! 8608: inline void pcbios_int_15h_8ah() ! 8609: { ! 8610: UINT32 size = MAX_MEM - 0x100000; ! 8611: REG16(AX) = size & 0xffff; ! 8612: REG16(DX) = size >> 16; ! 8613: } ! 8614: ! 8615: #ifdef EXT_BIOS_TOP ! 8616: inline void pcbios_int_15h_c1h() ! 8617: { ! 8618: SREG(ES) = EXT_BIOS_TOP >> 4; ! 8619: i386_load_segment_descriptor(ES); ! 8620: } ! 8621: #endif ! 8622: ! 8623: void pcbios_read_from_ps2_mouse(UINT16 *data_1st, UINT16 *data_2nd, UINT16 *data_3rd) ! 8624: { ! 8625: // from DOSBox DoPS2Callback() ! 8626: UINT16 mdat = 0x08; ! 8627: INT16 xdiff = mouse.position.x - mouse.prev_position.x; ! 8628: INT16 ydiff = mouse.prev_position.y - mouse.position.y; ! 8629: ! 8630: #if 1 ! 8631: if(xdiff > +16) xdiff = +16; ! 8632: if(xdiff < -16) xdiff = -16; ! 8633: if(ydiff > +16) ydiff = +16; ! 8634: if(ydiff < -16) ydiff = -16; ! 8635: #endif ! 8636: ! 8637: if(mouse.buttons[0].status) { ! 8638: mdat |= 0x01; ! 8639: } ! 8640: if(mouse.buttons[1].status) { ! 8641: mdat |= 0x02; ! 8642: } ! 8643: mouse.prev_position.x = mouse.position.x; ! 8644: mouse.prev_position.y = mouse.position.y; ! 8645: ! 8646: if((xdiff > 0xff) || (xdiff < -0xff)) { ! 8647: mdat |= 0x40; // x overflow ! 8648: } ! 8649: if((ydiff > 0xff) || (ydiff < -0xff)) { ! 8650: mdat |= 0x80; // y overflow ! 8651: } ! 8652: xdiff %= 256; ! 8653: ydiff %= 256; ! 8654: if(xdiff < 0) { ! 8655: xdiff = (0x100 + xdiff); ! 8656: mdat |= 0x10; ! 8657: } ! 8658: if(ydiff < 0) { ! 8659: ydiff = (0x100 + ydiff); ! 8660: mdat |= 0x20; ! 8661: } ! 8662: *data_1st = (UINT16)mdat; ! 8663: *data_2nd = (UINT16)(xdiff % 256); ! 8664: *data_3rd = (UINT16)(ydiff % 256); ! 8665: } ! 8666: ! 8667: inline void pcbios_int_15h_c2h() ! 8668: { ! 8669: static UINT8 sampling_rate = 5; ! 8670: static UINT8 resolution = 2; ! 8671: static UINT8 scaling = 1; ! 8672: ! 8673: switch(REG8(AL)) { ! 8674: case 0x00: ! 8675: if(REG8(BH) == 0x00) { ! 8676: if(dwConsoleMode & (ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE)) { ! 8677: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode | ENABLE_EXTENDED_FLAGS); ! 8678: } else { ! 8679: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode); ! 8680: } ! 8681: pic[1].imr |= 0x10; // disable irq12 ! 8682: mouse.enabled_ps2 = false; ! 8683: REG8(AH) = 0x00; // successful ! 8684: } else if(REG8(BH) == 0x01) { ! 8685: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), (dwConsoleMode | ENABLE_MOUSE_INPUT | ENABLE_EXTENDED_FLAGS) & ~ENABLE_QUICK_EDIT_MODE); ! 8686: pic[1].imr &= ~0x10; // enable irq12 ! 8687: mouse.enabled_ps2 = true; ! 8688: REG8(AH) = 0x00; // successful ! 8689: } else { ! 8690: REG8(AH) = 0x01; // invalid function ! 8691: m_CF = 1; ! 8692: } ! 8693: break; ! 8694: case 0x01: ! 8695: REG8(BH) = 0x00; // device id ! 8696: REG8(BL) = 0xaa; // mouse ! 8697: case 0x05: ! 8698: if(dwConsoleMode & (ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE)) { ! 8699: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode | ENABLE_EXTENDED_FLAGS); ! 8700: } else { ! 8701: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode); ! 8702: } ! 8703: pic[1].imr |= 0x10; // disable irq12 ! 8704: mouse.enabled_ps2 = false; ! 8705: sampling_rate = 5; ! 8706: resolution = 2; ! 8707: scaling = 1; ! 8708: REG8(AH) = 0x00; // successful ! 8709: break; ! 8710: case 0x02: ! 8711: sampling_rate = REG8(BH); ! 8712: REG8(AH) = 0x00; // successful ! 8713: break; ! 8714: case 0x03: ! 8715: resolution = REG8(BH); ! 8716: REG8(AH) = 0x00; // successful ! 8717: break; ! 8718: case 0x04: ! 8719: REG8(BH) = 0x00; // device id ! 8720: REG8(AH) = 0x00; // successful ! 8721: break; ! 8722: case 0x06: ! 8723: switch(REG8(BH)) { ! 8724: case 0x00: ! 8725: REG8(BL) = 0x00; ! 8726: if(mouse.buttons[1].status) { ! 8727: REG8(BL) |= 0x01; ! 8728: } ! 8729: if(mouse.buttons[0].status) { ! 8730: REG8(BL) |= 0x04; ! 8731: } ! 8732: if(scaling == 2) { ! 8733: REG8(BL) |= 0x10; ! 8734: } ! 8735: REG8(CL) = resolution; ! 8736: switch(sampling_rate) { ! 8737: case 0: REG8(DL) = 10; break; ! 8738: case 1: REG8(DL) = 20; break; ! 8739: case 2: REG8(DL) = 40; break; ! 8740: case 3: REG8(DL) = 60; break; ! 8741: case 4: REG8(DL) = 80; break; ! 8742: // case 5: REG8(DL) = 100; break; ! 8743: case 6: REG8(DL) = 200; break; ! 8744: default: REG8(DL) = 100; break; ! 8745: } ! 8746: REG8(AH) = 0x00; // successful ! 8747: break; ! 8748: case 0x01: ! 8749: case 0x02: ! 8750: scaling = REG8(BH); ! 8751: REG8(AH) = 0x00; // successful ! 8752: break; ! 8753: default: ! 8754: unimplemented_15h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x15, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 8755: REG8(AH) = 0x01; // invalid function ! 8756: m_CF = 1; ! 8757: break; ! 8758: } ! 8759: break; ! 8760: case 0x07: // set device handler addr ! 8761: mouse.call_addr_ps2.w.l = REG16(BX); ! 8762: mouse.call_addr_ps2.w.h = SREG(ES); ! 8763: REG8(AH) = 0x00; // successful ! 8764: break; ! 8765: case 0x08: ! 8766: REG8(AH) = 0x00; // successful ! 8767: break; ! 8768: case 0x09: ! 8769: { ! 8770: UINT16 data_1st, data_2nd, data_3rd; ! 8771: pcbios_read_from_ps2_mouse(&data_1st, &data_2nd, &data_3rd); ! 8772: REG8(BL) = (UINT8)(data_1st & 0xff); ! 8773: REG8(CL) = (UINT8)(data_2nd & 0xff); ! 8774: REG8(DL) = (UINT8)(data_3rd & 0xff); ! 8775: } ! 8776: REG8(AH) = 0x00; // successful ! 8777: break; ! 8778: default: ! 8779: unimplemented_15h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x15, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 8780: // REG8(AH) = 0x86; ! 8781: REG8(AH) = 0x01; // invalid function ! 8782: m_CF = 1; ! 8783: break; ! 8784: } ! 8785: } ! 8786: ! 8787: #if defined(HAS_I386) ! 8788: inline void pcbios_int_15h_c9h() ! 8789: { ! 8790: REG8(AH) = 0x00; ! 8791: REG8(CH) = cpu_type; ! 8792: REG8(CL) = cpu_step; ! 8793: } ! 8794: #endif ! 8795: ! 8796: inline void pcbios_int_15h_cah() ! 8797: { ! 8798: switch(REG8(AL)) { ! 8799: case 0x00: ! 8800: if(REG8(BL) > 0x3f) { ! 8801: REG8(AH) = 0x03; ! 8802: m_CF = 1; ! 8803: } else if(REG8(BL) < 0x0e) { ! 8804: REG8(AH) = 0x04; ! 8805: m_CF = 1; ! 8806: } else { ! 8807: REG8(CL) = cmos_read(REG8(BL)); ! 8808: } ! 8809: break; ! 8810: case 0x01: ! 8811: if(REG8(BL) > 0x3f) { ! 8812: REG8(AH) = 0x03; ! 8813: m_CF = 1; ! 8814: } else if(REG8(BL) < 0x0e) { ! 8815: REG8(AH) = 0x04; ! 8816: m_CF = 1; ! 8817: } else { ! 8818: cmos_write(REG8(BL), REG8(CL)); ! 8819: } ! 8820: break; ! 8821: default: ! 8822: unimplemented_15h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x15, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 8823: REG8(AH) = 0x86; ! 8824: m_CF = 1; ! 8825: break; ! 8826: } ! 8827: } ! 8828: ! 8829: inline void pcbios_int_15h_e8h() ! 8830: { ! 8831: switch(REG8(AL)) { ! 8832: case 0x01: ! 8833: REG16(AX) = REG16(CX) = ((min(MAX_MEM, 0x1000000) - 0x0100000) >> 10); ! 8834: REG16(BX) = REG16(DX) = ((max(MAX_MEM, 0x1000000) - 0x1000000) >> 16); ! 8835: break; ! 8836: #if defined(HAS_I386) ! 8837: case 0x20: ! 8838: if(REG32(EDX) == 0x534d4150 && REG32(ECX) >= 20) { ! 8839: if(REG32(EBX) < 3) { ! 8840: UINT32 base = 0, len = 0, type = 0; ! 8841: switch(REG32(EBX)) { ! 8842: case 0: ! 8843: base = 0x000000; ! 8844: len = MEMORY_END; ! 8845: type = 1; ! 8846: break; ! 8847: case 1: ! 8848: base = DUMMY_TOP; ! 8849: len = 0x100000 - DUMMY_TOP; ! 8850: type = 2; ! 8851: break; ! 8852: case 2: ! 8853: base = 0x100000; ! 8854: len = MAX_MEM - 0x100000; ! 8855: type = 1; ! 8856: break; ! 8857: } ! 8858: *(UINT32 *)(mem + SREG_BASE(ES) + REG16(DI) + 0x00) = base; ! 8859: *(UINT32 *)(mem + SREG_BASE(ES) + REG16(DI) + 0x04) = 0; ! 8860: *(UINT32 *)(mem + SREG_BASE(ES) + REG16(DI) + 0x08) = len; ! 8861: *(UINT32 *)(mem + SREG_BASE(ES) + REG16(DI) + 0x0c) = 0; ! 8862: *(UINT32 *)(mem + SREG_BASE(ES) + REG16(DI) + 0x10) = type; ! 8863: ! 8864: if(++REG32(EBX) >= 3) { ! 8865: REG32(EBX) = 0; ! 8866: } ! 8867: REG32(ECX) = 20; ! 8868: } else { ! 8869: m_CF = 1; ! 8870: } ! 8871: REG32(EAX) = 0x534d4150; ! 8872: break; ! 8873: } ! 8874: case 0x81: ! 8875: REG32(EAX) = REG32(ECX) = ((min(MAX_MEM, 0x1000000) - 0x0100000) >> 10); ! 8876: REG32(EBX) = REG32(EDX) = ((max(MAX_MEM, 0x1000000) - 0x1000000) >> 16); ! 8877: break; ! 8878: #endif ! 8879: default: ! 8880: unimplemented_15h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x15, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 8881: REG8(AH) = 0x86; ! 8882: m_CF = 1; ! 8883: break; ! 8884: } ! 8885: } ! 8886: ! 8887: bool pcbios_is_key_buffer_empty() ! 8888: { ! 8889: return(*(UINT16 *)(mem + 0x41a) == *(UINT16 *)(mem + 0x41c)); ! 8890: } ! 8891: ! 8892: void pcbios_clear_key_buffer() ! 8893: { ! 8894: key_buf_char->clear(); ! 8895: key_buf_scan->clear(); ! 8896: ! 8897: // update key buffer ! 8898: *(UINT16 *)(mem + 0x41a) = *(UINT16 *)(mem + 0x41c); // head = tail ! 8899: } ! 8900: ! 8901: void pcbios_set_key_buffer(int key_char, int key_scan) ! 8902: { ! 8903: // update key buffer ! 8904: UINT16 head = *(UINT16 *)(mem + 0x41a); ! 8905: UINT16 tail = *(UINT16 *)(mem + 0x41c); ! 8906: UINT16 next = tail + 2; ! 8907: if(next >= *(UINT16 *)(mem + 0x482)) { ! 8908: next = *(UINT16 *)(mem + 0x480); ! 8909: } ! 8910: if(next != head) { ! 8911: *(UINT16 *)(mem + 0x41c) = next; ! 8912: mem[0x400 + (tail++)] = key_char; ! 8913: mem[0x400 + (tail++)] = key_scan; ! 8914: } else { ! 8915: // store to extra key buffer ! 8916: if(key_buf_char != NULL && key_buf_scan != NULL) { ! 8917: key_buf_char->write(key_char); ! 8918: key_buf_scan->write(key_scan); ! 8919: } ! 8920: } ! 8921: } ! 8922: ! 8923: bool pcbios_get_key_buffer(int *key_char, int *key_scan) ! 8924: { ! 8925: // update key buffer ! 8926: UINT16 head = *(UINT16 *)(mem + 0x41a); ! 8927: UINT16 tail = *(UINT16 *)(mem + 0x41c); ! 8928: UINT16 next = head + 2; ! 8929: if(next >= *(UINT16 *)(mem + 0x482)) { ! 8930: next = *(UINT16 *)(mem + 0x480); ! 8931: } ! 8932: if(head != tail) { ! 8933: *(UINT16 *)(mem + 0x41a) = next; ! 8934: *key_char = mem[0x400 + (head++)]; ! 8935: *key_scan = mem[0x400 + (head++)]; ! 8936: ! 8937: // restore from extra key buffer ! 8938: if(key_buf_char != NULL && key_buf_scan != NULL) { ! 8939: if(!key_buf_char->empty()) { ! 8940: pcbios_set_key_buffer(key_buf_char->read(), key_buf_scan->read()); ! 8941: } ! 8942: } ! 8943: return(true); ! 8944: } else { ! 8945: *key_char = 0x00; ! 8946: *key_scan = 0x00; ! 8947: return(false); ! 8948: } ! 8949: } ! 8950: ! 8951: bool pcbios_check_key_buffer(int *key_char, int *key_scan) ! 8952: { ! 8953: // do not remove from key buffer ! 8954: UINT16 head = *(UINT16 *)(mem + 0x41a); ! 8955: UINT16 tail = *(UINT16 *)(mem + 0x41c); ! 8956: if(head != tail) { ! 8957: *key_char = mem[0x400 + (head++)]; ! 8958: *key_scan = mem[0x400 + (head++)]; ! 8959: return(true); ! 8960: } else { ! 8961: *key_char = 0x00; ! 8962: *key_scan = 0x00; ! 8963: return(false); ! 8964: } ! 8965: } ! 8966: ! 8967: void pcbios_update_key_code(bool wait) ! 8968: { ! 8969: if(key_buf_char != NULL && key_buf_scan != NULL) { ! 8970: #ifdef USE_SERVICE_THREAD ! 8971: EnterCriticalSection(&key_buf_crit_sect); ! 8972: #endif ! 8973: bool empty = pcbios_is_key_buffer_empty(); ! 8974: #ifdef USE_SERVICE_THREAD ! 8975: LeaveCriticalSection(&key_buf_crit_sect); ! 8976: #endif ! 8977: if(empty) { ! 8978: if(!update_key_buffer()) { ! 8979: if(wait) { ! 8980: Sleep(10); ! 8981: } else { ! 8982: maybe_idle(); ! 8983: } ! 8984: } ! 8985: } ! 8986: } ! 8987: if(key_buf_char != NULL && key_buf_scan != NULL) { ! 8988: #ifdef USE_SERVICE_THREAD ! 8989: EnterCriticalSection(&key_buf_crit_sect); ! 8990: #endif ! 8991: int key_char, key_scan; ! 8992: if(pcbios_get_key_buffer(&key_char, &key_scan)) { ! 8993: key_code = key_char << 0; ! 8994: key_code |= key_scan << 8; ! 8995: key_recv = 0x0000ffff; ! 8996: } ! 8997: if(pcbios_get_key_buffer(&key_char, &key_scan)) { ! 8998: key_code |= key_char << 16; ! 8999: key_code |= key_scan << 24; ! 9000: key_recv |= 0xffff0000; ! 9001: } ! 9002: #ifdef USE_SERVICE_THREAD ! 9003: LeaveCriticalSection(&key_buf_crit_sect); ! 9004: #endif ! 9005: } ! 9006: } ! 9007: ! 9008: DWORD WINAPI pcbios_int_16h_00h_thread(LPVOID) ! 9009: { ! 9010: while(key_recv == 0 && !m_exit) { ! 9011: pcbios_update_key_code(true); ! 9012: } ! 9013: if((key_recv & 0x0000ffff) && (key_recv & 0xffff0000)) { ! 9014: if((key_code & 0xffff) == 0x0000 || (key_code & 0xffff) == 0xe000) { ! 9015: if(REG8(AH) == 0x10) { ! 9016: key_code = ((key_code >> 8) & 0xff) | ((key_code >> 16) & 0xff00); ! 9017: } else { ! 9018: key_code = ((key_code >> 16) & 0xff00); ! 9019: } ! 9020: key_recv >>= 16; ! 9021: } ! 9022: } ! 9023: REG16(AX) = key_code & 0xffff; ! 9024: key_code >>= 16; ! 9025: key_recv >>= 16; ! 9026: ! 9027: #ifdef USE_SERVICE_THREAD ! 9028: service_exit = true; ! 9029: #endif ! 9030: return(0); ! 9031: } ! 9032: ! 9033: inline void pcbios_int_16h_00h() ! 9034: { ! 9035: #ifdef USE_SERVICE_THREAD ! 9036: if(!in_service && !in_service_29h) { ! 9037: start_service_loop(pcbios_int_16h_00h_thread); ! 9038: } else { ! 9039: #endif ! 9040: pcbios_int_16h_00h_thread(NULL); ! 9041: REQUEST_HARDWRE_UPDATE(); ! 9042: #ifdef USE_SERVICE_THREAD ! 9043: } ! 9044: #endif ! 9045: } ! 9046: ! 9047: inline void pcbios_int_16h_01h() ! 9048: { ! 9049: if(key_recv == 0) { ! 9050: pcbios_update_key_code(false); ! 9051: } ! 9052: if(key_recv != 0) { ! 9053: UINT32 key_code_tmp = key_code; ! 9054: if((key_recv & 0x0000ffff) && (key_recv & 0xffff0000)) { ! 9055: if((key_code_tmp & 0xffff) == 0x0000 || (key_code_tmp & 0xffff) == 0xe000) { ! 9056: if(REG8(AH) == 0x11) { ! 9057: key_code_tmp = ((key_code_tmp >> 8) & 0xff) | ((key_code_tmp >> 16) & 0xff00); ! 9058: } else { ! 9059: key_code_tmp = ((key_code_tmp >> 16) & 0xff00); ! 9060: } ! 9061: } ! 9062: } ! 9063: REG16(AX) = key_code_tmp & 0xffff; ! 9064: #if defined(HAS_I386) ! 9065: m_ZF = 0; ! 9066: #else ! 9067: m_ZeroVal = 1; ! 9068: #endif ! 9069: } else { ! 9070: #if defined(HAS_I386) ! 9071: m_ZF = 1; ! 9072: #else ! 9073: m_ZeroVal = 0; ! 9074: #endif ! 9075: } ! 9076: } ! 9077: ! 9078: inline void pcbios_int_16h_02h() ! 9079: { ! 9080: REG8(AL) = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0; ! 9081: REG8(AL) |= (GetAsyncKeyState(VK_CAPITAL) & 0x0001) ? 0x40 : 0; ! 9082: REG8(AL) |= (GetAsyncKeyState(VK_NUMLOCK) & 0x0001) ? 0x20 : 0; ! 9083: REG8(AL) |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0; ! 9084: REG8(AL) |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0; ! 9085: REG8(AL) |= (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? 0x04 : 0; ! 9086: REG8(AL) |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0; ! 9087: REG8(AL) |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0; ! 9088: } ! 9089: ! 9090: inline void pcbios_int_16h_03h() ! 9091: { ! 9092: static UINT16 status = 0; ! 9093: ! 9094: switch(REG8(AL)) { ! 9095: case 0x05: ! 9096: status = REG16(BX); ! 9097: break; ! 9098: case 0x06: ! 9099: REG16(BX) = status; ! 9100: break; ! 9101: default: ! 9102: m_CF = 1; ! 9103: break; ! 9104: } ! 9105: } ! 9106: ! 9107: inline void pcbios_int_16h_05h() ! 9108: { ! 9109: if(key_buf_char != NULL && key_buf_scan != NULL) { ! 9110: #ifdef USE_SERVICE_THREAD ! 9111: EnterCriticalSection(&key_buf_crit_sect); ! 9112: #endif ! 9113: pcbios_set_key_buffer(REG8(CL), REG8(CH)); ! 9114: #ifdef USE_SERVICE_THREAD ! 9115: LeaveCriticalSection(&key_buf_crit_sect); ! 9116: #endif ! 9117: } ! 9118: REG8(AL) = 0x00; ! 9119: } ! 9120: ! 9121: inline void pcbios_int_16h_09h() ! 9122: { ! 9123: REG8(AL) = 0x00; ! 9124: // REG8(AL) |= 0x01; // INT 16/AX=0300h supported (set default delay and rate (PCjr and some PS/2)) ! 9125: // REG8(AL) |= 0x02; // INT 16/AX=0304h supported (turn off typematic repeat (PCjr and some PS/2)) ! 9126: REG8(AL) |= 0x04; // INT 16/AX=0305h supported (set repeat rate and delay (AT,PS)) ! 9127: REG8(AL) |= 0x08; // INT 16/AX=0306h supported (get current typematic rate and delay (newer PS/2s)) ! 9128: REG8(AL) |= 0x10; // INT 16/AH=0Ah supported (get keyboard id) ! 9129: REG8(AL) |= 0x20; // INT 16/AH=10h-12h supported (enhanced keyboard support) ! 9130: // REG8(AL) |= 0x40; // INT 16/AH=20h-22h supported (122-key keyboard support) ! 9131: // REG8(AL) |= 0x80; // reserved ! 9132: } ! 9133: ! 9134: inline void pcbios_int_16h_0ah() ! 9135: { ! 9136: // REG16(BX) = 0x41ab; // MF2 Keyboard (usually in translate mode) ! 9137: REG16(BX) = 0x83ab; // MF2 Keyboard (pass-through mode) ! 9138: } ! 9139: ! 9140: inline void pcbios_int_16h_11h() ! 9141: { ! 9142: int key_char, key_scan; ! 9143: ! 9144: #ifdef USE_SERVICE_THREAD ! 9145: EnterCriticalSection(&key_buf_crit_sect); ! 9146: #endif ! 9147: if(pcbios_check_key_buffer(&key_char, &key_scan)) { ! 9148: REG8(AL) = key_char; ! 9149: REG8(AH) = key_scan; ! 9150: #if defined(HAS_I386) ! 9151: m_ZF = 0; ! 9152: #else ! 9153: m_ZeroVal = 1; ! 9154: #endif ! 9155: } else { ! 9156: #if defined(HAS_I386) ! 9157: m_ZF = 1; ! 9158: #else ! 9159: m_ZeroVal = 0; ! 9160: #endif ! 9161: } ! 9162: #ifdef USE_SERVICE_THREAD ! 9163: LeaveCriticalSection(&key_buf_crit_sect); ! 9164: #endif ! 9165: } ! 9166: ! 9167: inline void pcbios_int_16h_12h() ! 9168: { ! 9169: pcbios_int_16h_02h(); ! 9170: ! 9171: REG8(AH) = 0;//(GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x80 : 0; ! 9172: REG8(AH) |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0; ! 9173: REG8(AH) |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0; ! 9174: REG8(AH) |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0; ! 9175: REG8(AH) |= (GetAsyncKeyState(VK_RMENU ) & 0x8000) ? 0x08 : 0; ! 9176: REG8(AH) |= (GetAsyncKeyState(VK_RCONTROL) & 0x8000) ? 0x04 : 0; ! 9177: REG8(AH) |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0; ! 9178: REG8(AH) |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0; ! 9179: } ! 9180: ! 9181: inline void pcbios_int_16h_13h() ! 9182: { ! 9183: static UINT16 status = 0; ! 9184: ! 9185: switch(REG8(AL)) { ! 9186: case 0x00: ! 9187: status = REG16(DX); ! 9188: break; ! 9189: case 0x01: ! 9190: REG16(DX) = status; ! 9191: break; ! 9192: default: ! 9193: unimplemented_16h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x16, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 9194: m_CF = 1; ! 9195: break; ! 9196: } ! 9197: } ! 9198: ! 9199: inline void pcbios_int_16h_14h() ! 9200: { ! 9201: static UINT8 status = 0; ! 9202: ! 9203: switch(REG8(AL)) { ! 9204: case 0x00: ! 9205: case 0x01: ! 9206: status = REG8(AL); ! 9207: break; ! 9208: case 0x02: ! 9209: REG8(AL) = status; ! 9210: break; ! 9211: default: ! 9212: unimplemented_16h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x16, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 9213: m_CF = 1; ! 9214: break; ! 9215: } ! 9216: } ! 9217: ! 9218: inline void pcbios_int_16h_55h() ! 9219: { ! 9220: switch(REG8(AL)) { ! 9221: case 0x00: ! 9222: // keyboard tsr is not present ! 9223: break; ! 9224: case 0xfe: ! 9225: // handlers for INT 08, INT 09, INT 16, INT 1B, and INT 1C are installed ! 9226: break; ! 9227: case 0xff: ! 9228: break; ! 9229: default: ! 9230: unimplemented_16h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x16, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 9231: m_CF = 1; ! 9232: break; ! 9233: } ! 9234: } ! 9235: ! 9236: inline void pcbios_int_16h_6fh() ! 9237: { ! 9238: switch(REG8(AL)) { ! 9239: case 0x00: ! 9240: // HP Vectra EX-BIOS - "F16_INQUIRE" - Extended BIOS is not installed ! 9241: break; ! 9242: default: ! 9243: unimplemented_16h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x16, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 9244: m_CF = 1; ! 9245: break; ! 9246: } ! 9247: } ! 9248: ! 9249: UINT16 pcbios_printer_jis2sjis(UINT16 jis) ! 9250: { ! 9251: UINT8 hi = jis >> 8; ! 9252: UINT8 lo = jis & 0xff; ! 9253: ! 9254: lo = (hi & 0x01) ? lo - 0x1f : lo + 0x7d; ! 9255: hi = (hi - 0x21) / 2 + 0x81; ! 9256: hi = (hi >= 0xa0) ? hi + 0x40 : hi; ! 9257: lo = (lo >= 0x7f) ? lo + 0x01 : lo; ! 9258: ! 9259: return((hi << 8) + lo); ! 9260: } ! 9261: ! 9262: UINT16 pcbios_printer_sjis2jis(UINT16 sjis) ! 9263: { ! 9264: UINT8 hi = sjis >> 8; ! 9265: UINT8 lo = sjis & 0xff; ! 9266: ! 9267: if(hi == 0x80 || (hi >= 0xeb && hi <= 0xef) || (hi >= 0xf4 && hi <= 0xff)) { ! 9268: return(0x2121); ! 9269: } ! 9270: if((lo >= 0x00 && lo <= 0x3f) || lo == 0x7f || (lo >= 0xfd && lo <= 0xff)) { ! 9271: return(0x2121); ! 9272: } ! 9273: if(hi >= 0xf0 && hi <= 0xf3) { ! 9274: // gaiji ! 9275: if(lo >= 0x40 && lo <= 0x7e) { ! 9276: return(0x7721 + lo - 0x40 + (hi - 0xf0) * 0x200); ! 9277: } ! 9278: if(lo >= 0x80 && lo <= 0x9e) { ! 9279: return(0x7760 + lo - 0x80 + (hi - 0xf0) * 0x200); ! 9280: } ! 9281: if(lo >= 0x9f && lo <= 0xfc) { ! 9282: return(0x7821 + lo - 0x9f + (hi - 0xf0) * 0x200); ! 9283: } ! 9284: } ! 9285: hi = (hi >= 0xe0) ? hi - 0x40 : hi; ! 9286: lo = (lo >= 0x80) ? lo - 0x01 : lo; ! 9287: hi = ((lo >= 0x9e) ? 1 : 0) + (hi - 0x81) * 2 + 0x21; ! 9288: lo = ((lo >= 0x9e) ? lo - 0x9e : lo - 0x40) + 0x21; ! 9289: ! 9290: return((hi << 8) + lo); ! 9291: } ! 9292: ! 9293: // AX�e�N�j�J�����t�@�����X�K�C�h 1989 ! 9294: // �t�^10 ���{��g��PRINTER DRIVER NIOS�T�d�l ! 9295: // 6. �R���g���[���R�[�h�̉�� ! 9296: ! 9297: void pcbios_printer_out(int c, UINT8 data) ! 9298: { ! 9299: if(pio[c].conv_mode) { ! 9300: if(pio[c].sjis_hi != 0) { ! 9301: if(!pio[c].jis_mode) { ! 9302: printer_out(c, 0x1c); ! 9303: printer_out(c, 0x26); ! 9304: pio[c].jis_mode = true; ! 9305: } ! 9306: UINT16 jis = pcbios_printer_sjis2jis((pio[c].sjis_hi << 8) | data); ! 9307: printer_out(c, jis >> 8); ! 9308: printer_out(c, jis & 0xff); ! 9309: pio[c].sjis_hi = 0; ! 9310: } else if(pio[c].esc_buf[0] == 0x1b) { ! 9311: printer_out(c, data); ! 9312: if(pio[c].esc_len < sizeof(pio[c].esc_buf)) { ! 9313: pio[c].esc_buf[pio[c].esc_len] = data; ! 9314: } ! 9315: pio[c].esc_len++; ! 9316: ! 9317: switch(pio[c].esc_buf[1]) { ! 9318: case 0x33: // 1Bh 33h XX ! 9319: case 0x4a: // 1Bh 4Ah XX ! 9320: case 0x4e: // 1Bh 4Eh XX ! 9321: case 0x51: // 1Bh 51h XX ! 9322: case 0x55: // 1Bh 55h XX ! 9323: case 0x6c: // 1Bh 6Ch XX ! 9324: case 0x71: // 1Bh 71h XX ! 9325: case 0x72: // 1Bh 72h XX ! 9326: if(pio[c].esc_len == 3) { ! 9327: pio[c].esc_buf[0] = 0x00; ! 9328: } ! 9329: break; ! 9330: case 0x24: // 1Bh 24h XX XX ! 9331: case 0x5c: // 1Bh 5Ch XX XX ! 9332: if(pio[c].esc_len == 4) { ! 9333: pio[c].esc_buf[0] = 0x00; ! 9334: } ! 9335: break; ! 9336: case 0x2a: // 1Bh 2Ah XX XX XX data ! 9337: if(pio[c].esc_len >= 3) { ! 9338: switch(pio[c].esc_buf[2]) { ! 9339: case 0: case 1: case 2: case 3: case 4: case 6: ! 9340: if(pio[c].esc_len >= 5 && pio[c].esc_len == 5 + (pio[c].esc_buf[3] + pio[c].esc_buf[4] * 256) * 1) { ! 9341: pio[c].esc_buf[0] = 0x00; ! 9342: } ! 9343: break; ! 9344: case 32: case 33: case 38: case 39: case 40: ! 9345: if(pio[c].esc_len >= 5 && pio[c].esc_len == 5 + (pio[c].esc_buf[3] + pio[c].esc_buf[4] * 256) * 3) { ! 9346: pio[c].esc_buf[0] = 0x00; ! 9347: } ! 9348: break; ! 9349: case 71: case 72: case 73: ! 9350: if(pio[c].esc_len >= 5 && pio[c].esc_len == 5 + (pio[c].esc_buf[3] + pio[c].esc_buf[4] * 256) * 6) { ! 9351: pio[c].esc_buf[0] = 0x00; ! 9352: } ! 9353: break; ! 9354: default: ! 9355: pio[c].esc_buf[0] = 0x00; ! 9356: break; ! 9357: } ! 9358: } ! 9359: break; ! 9360: case 0x40: // 1Bh 40h ! 9361: if(pio[c].jis_mode) { ! 9362: printer_out(c, 0x1c); ! 9363: printer_out(c, 0x2e); ! 9364: pio[c].jis_mode = false; ! 9365: } ! 9366: pio[c].esc_buf[0] = 0x00; ! 9367: break; ! 9368: case 0x42: // 1Bh 42h data 00h ! 9369: case 0x44: // 1Bh 44h data 00h ! 9370: if(pio[c].esc_len >= 3 && data == 0) { ! 9371: pio[c].esc_buf[0] = 0x00; ! 9372: } ! 9373: break; ! 9374: case 0x43: // 1Bh 43h (00h) XX ! 9375: if(pio[c].esc_len >= 3 && data != 0) { ! 9376: pio[c].esc_buf[0] = 0x00; ! 9377: } ! 9378: break; ! 9379: default: // 1Bh XX ! 9380: pio[c].esc_buf[0] = 0x00; ! 9381: break; ! 9382: } ! 9383: } else if(pio[c].esc_buf[0] == 0x1c) { ! 9384: printer_out(c, data); ! 9385: if(pio[c].esc_len < sizeof(pio[c].esc_buf)) { ! 9386: pio[c].esc_buf[pio[c].esc_len] = data; ! 9387: } ! 9388: pio[c].esc_len++; ! 9389: ! 9390: switch(pio[c].esc_buf[1]) { ! 9391: case 0x21: // 1Ch 21h XX ! 9392: case 0x2d: // 1Ch 2Dh XX ! 9393: case 0x57: // 1Ch 57h XX ! 9394: case 0x6b: // 1Ch 6Bh XX ! 9395: case 0x72: // 1Ch 72h XX ! 9396: case 0x78: // 1Ch 78h XX ! 9397: if(pio[c].esc_len == 3) { ! 9398: pio[c].esc_buf[0] = 0x00; ! 9399: } ! 9400: break; ! 9401: case 0x26: // 1Ch 26h ! 9402: pio[c].jis_mode = true; ! 9403: pio[c].esc_buf[0] = 0x00; ! 9404: break; ! 9405: case 0x2e: // 1Ch 2Eh ! 9406: pio[c].jis_mode = false; ! 9407: pio[c].esc_buf[0] = 0x00; ! 9408: break; ! 9409: case 0x32: // 1Ch 32h XX XX data ! 9410: if(pio[c].esc_len == 76) { ! 9411: pio[c].esc_buf[0] = 0x00; ! 9412: } ! 9413: break; ! 9414: case 0x44: // 1Bh 44h data 00h ! 9415: if(pio[c].esc_len == 6) { ! 9416: pio[c].esc_buf[0] = 0x00; ! 9417: } ! 9418: break; ! 9419: case 0x53: // 1Ch 53h XX XX ! 9420: case 0x54: // 1Ch 54h XX XX ! 9421: if(pio[c].esc_len == 4) { ! 9422: pio[c].esc_buf[0] = 0x00; ! 9423: } ! 9424: break; ! 9425: default: // 1Ch XX ! 9426: pio[c].esc_buf[0] = 0x00; ! 9427: break; ! 9428: } ! 9429: } else if(data == 0x1b || data == 0x1c) { ! 9430: printer_out(c, data); ! 9431: pio[c].esc_buf[0] = data; ! 9432: pio[c].esc_len = 1; ! 9433: } else if((data >= 0x80 && data <= 0x9f) || (data >= 0xe0 && data <= 0xff)) { ! 9434: pio[c].sjis_hi = data; ! 9435: } else { ! 9436: if(pio[c].jis_mode) { ! 9437: printer_out(c, 0x1c); ! 9438: printer_out(c, 0x2e); ! 9439: pio[c].jis_mode = false; ! 9440: } ! 9441: printer_out(c, data); ! 9442: } ! 9443: } else { ! 9444: if(pio[c].jis_mode) { ! 9445: printer_out(c, 0x1c); ! 9446: printer_out(c, 0x2e); ! 9447: pio[c].jis_mode = false; ! 9448: } ! 9449: printer_out(c, data); ! 9450: } ! 9451: } ! 9452: ! 9453: inline void pcbios_int_17h_00h() ! 9454: { ! 9455: if(REG16(DX) < 3) { ! 9456: pcbios_printer_out(REG16(DX), REG8(AL)); ! 9457: REG8(AH) = 0xd0; ! 9458: } ! 9459: } ! 9460: ! 9461: inline void pcbios_int_17h_01h() ! 9462: { ! 9463: if(REG16(DX) < 3) { ! 9464: REG8(AH) = 0xd0; ! 9465: } ! 9466: } ! 9467: ! 9468: inline void pcbios_int_17h_02h() ! 9469: { ! 9470: if(REG16(DX) < 3) { ! 9471: REG8(AH) = 0xd0; ! 9472: } ! 9473: } ! 9474: ! 9475: inline void pcbios_int_17h_03h() ! 9476: { ! 9477: switch(REG8(AL)) { ! 9478: case 0x00: ! 9479: if(REG16(DX) < 3) { ! 9480: if(pio[REG16(DX)].jis_mode) { ! 9481: printer_out(REG16(DX), 0x1c); ! 9482: printer_out(REG16(DX), 0x2e); ! 9483: pio[REG16(DX)].jis_mode = false; ! 9484: } ! 9485: for(UINT16 i = 0; i < REG16(CX); i++) { ! 9486: printer_out(REG16(DX), mem[SREG_BASE(ES) + REG16(BX) + i]); ! 9487: } ! 9488: REG16(CX) = 0x0000; ! 9489: REG8(AH) = 0xd0; ! 9490: } ! 9491: break; ! 9492: default: ! 9493: unimplemented_17h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x17, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 9494: break; ! 9495: } ! 9496: } ! 9497: ! 9498: inline void pcbios_int_17h_50h() ! 9499: { ! 9500: switch(REG8(AL)) { ! 9501: case 0x00: ! 9502: if(REG16(DX) < 3) { ! 9503: if(REG16(BX) = 0x0001) { ! 9504: pio[REG16(DX)].conv_mode = false; ! 9505: REG8(AL) = 0x00; ! 9506: } else if(REG16(BX) = 0x0051) { ! 9507: pio[REG16(DX)].conv_mode = true; ! 9508: REG8(AL) = 0x00; ! 9509: } else { ! 9510: REG8(AL) = 0x01; ! 9511: } ! 9512: } else { ! 9513: REG8(AL) = 0x02; ! 9514: } ! 9515: break; ! 9516: case 0x01: ! 9517: if(REG16(DX) < 3) { ! 9518: if(pio[REG16(DX)].conv_mode) { ! 9519: REG16(BX) = 0x0051; ! 9520: } else { ! 9521: REG16(BX) = 0x0001; ! 9522: } ! 9523: REG8(AL) = 0x00; ! 9524: } else { ! 9525: REG8(AL) = 0x02; ! 9526: } ! 9527: break; ! 9528: default: ! 9529: unimplemented_17h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x17, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 9530: break; ! 9531: } ! 9532: } ! 9533: ! 9534: inline void pcbios_int_17h_51h() ! 9535: { ! 9536: if(REG8(DH) >= 0x21 && REG8(DH) <= 0x7e && REG8(DL) >= 0x21 && REG8(DL) <= 0x7e) { ! 9537: REG16(DX) = pcbios_printer_jis2sjis(REG16(DX)); ! 9538: } else { ! 9539: REG16(DX) = 0x0000; ! 9540: } ! 9541: } ! 9542: ! 9543: inline void pcbios_int_17h_52h() ! 9544: { ! 9545: if(((REG8(DH) >= 0x81 && REG8(DH) <= 0x9f) || (REG8(DH) >= 0xe0 && REG8(DH) <= 0xfc)) && (REG8(DL) >= 0x40 && REG8(DL) <= 0xfc && REG8(DL) != 0x7f)) { ! 9546: REG16(DX) = pcbios_printer_sjis2jis(REG16(DX)); ! 9547: } else { ! 9548: REG16(DX) = 0x0000; ! 9549: } ! 9550: } ! 9551: ! 9552: inline void pcbios_int_17h_84h() ! 9553: { ! 9554: if(REG16(DX) < 3) { ! 9555: if(pio[REG16(DX)].jis_mode) { ! 9556: printer_out(REG16(DX), 0x1c); ! 9557: printer_out(REG16(DX), 0x2e); ! 9558: pio[REG16(DX)].jis_mode = false; ! 9559: } ! 9560: printer_out(REG16(DX), REG8(AL)); ! 9561: REG8(AH) = 0xd0; ! 9562: } ! 9563: } ! 9564: ! 9565: inline void pcbios_int_17h_85h() ! 9566: { ! 9567: pio[0].conv_mode = (REG8(AL) == 0x00); ! 9568: } ! 9569: ! 9570: inline void pcbios_int_1ah_00h() ! 9571: { ! 9572: pcbios_update_daily_timer_counter(timeGetTime()); ! 9573: REG16(CX) = *(UINT16 *)(mem + 0x46e); ! 9574: REG16(DX) = *(UINT16 *)(mem + 0x46c); ! 9575: REG8(AL) = mem[0x470]; ! 9576: mem[0x470] = 0; ! 9577: } ! 9578: ! 9579: inline int to_bcd(int t) ! 9580: { ! 9581: int u = (t % 100) / 10; ! 9582: return (u << 4) | (t % 10); ! 9583: } ! 9584: ! 9585: inline void pcbios_int_1ah_02h() ! 9586: { ! 9587: SYSTEMTIME time; ! 9588: ! 9589: GetLocalTime(&time); ! 9590: REG8(CH) = to_bcd(time.wHour); ! 9591: REG8(CL) = to_bcd(time.wMinute); ! 9592: REG8(DH) = to_bcd(time.wSecond); ! 9593: REG8(DL) = 0x00; ! 9594: } ! 9595: ! 9596: inline void pcbios_int_1ah_04h() ! 9597: { ! 9598: SYSTEMTIME time; ! 9599: ! 9600: GetLocalTime(&time); ! 9601: REG8(CH) = to_bcd(time.wYear / 100); ! 9602: REG8(CL) = to_bcd(time.wYear); ! 9603: REG8(DH) = to_bcd(time.wMonth); ! 9604: REG8(DL) = to_bcd(time.wDay); ! 9605: } ! 9606: ! 9607: inline void pcbios_int_1ah_0ah() ! 9608: { ! 9609: SYSTEMTIME time; ! 9610: FILETIME file_time; ! 9611: WORD dos_date, dos_time; ! 9612: ! 9613: GetLocalTime(&time); ! 9614: SystemTimeToFileTime(&time, &file_time); ! 9615: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time); ! 9616: REG16(CX) = dos_date; ! 9617: } ! 9618: ! 9619: // msdos system call ! 9620: ! 9621: inline void msdos_int_21h_56h(int lfn); ! 9622: ! 9623: inline void msdos_int_21h_00h() ! 9624: { ! 9625: msdos_process_terminate(SREG(CS), retval, 1); ! 9626: } ! 9627: ! 9628: DWORD WINAPI msdos_int_21h_01h_thread(LPVOID) ! 9629: { ! 9630: REG8(AL) = msdos_getche(); ! 9631: ctrl_break_detected = ctrl_break_pressed; ! 9632: ! 9633: #ifdef USE_SERVICE_THREAD ! 9634: service_exit = true; ! 9635: #endif ! 9636: return(0); ! 9637: } ! 9638: ! 9639: inline void msdos_int_21h_01h() ! 9640: { ! 9641: #ifdef USE_SERVICE_THREAD ! 9642: if(!in_service && !in_service_29h && ! 9643: *(UINT16 *)(mem + 4 * 0x29 + 0) == (IRET_SIZE + 5 * 0x29) && ! 9644: *(UINT16 *)(mem + 4 * 0x29 + 2) == (IRET_TOP >> 4)) { ! 9645: // msdos_putch() will be used in this service ! 9646: // if int 29h is hooked, run this service in main thread to call int 29h ! 9647: start_service_loop(msdos_int_21h_01h_thread); ! 9648: } else { ! 9649: #endif ! 9650: msdos_int_21h_01h_thread(NULL); ! 9651: REQUEST_HARDWRE_UPDATE(); ! 9652: #ifdef USE_SERVICE_THREAD ! 9653: } ! 9654: #endif ! 9655: } ! 9656: ! 9657: inline void msdos_int_21h_02h() ! 9658: { ! 9659: UINT8 data = REG8(DL); ! 9660: msdos_putch(data); ! 9661: REG8(AL) = data; ! 9662: ctrl_break_detected = ctrl_break_pressed; ! 9663: } ! 9664: ! 9665: inline void msdos_int_21h_03h() ! 9666: { ! 9667: REG8(AL) = msdos_aux_in(); ! 9668: } ! 9669: ! 9670: inline void msdos_int_21h_04h() ! 9671: { ! 9672: msdos_aux_out(REG8(DL)); ! 9673: } ! 9674: ! 9675: inline void msdos_int_21h_05h() ! 9676: { ! 9677: msdos_prn_out(REG8(DL)); ! 9678: } ! 9679: ! 9680: inline void msdos_int_21h_06h() ! 9681: { ! 9682: if(REG8(DL) == 0xff) { ! 9683: if(msdos_kbhit()) { ! 9684: REG8(AL) = msdos_getch(); ! 9685: #if defined(HAS_I386) ! 9686: m_ZF = 0; ! 9687: #else ! 9688: m_ZeroVal = 1; ! 9689: #endif ! 9690: } else { ! 9691: REG8(AL) = 0; ! 9692: #if defined(HAS_I386) ! 9693: m_ZF = 1; ! 9694: #else ! 9695: m_ZeroVal = 0; ! 9696: #endif ! 9697: maybe_idle(); ! 9698: } ! 9699: } else { ! 9700: UINT8 data = REG8(DL); ! 9701: msdos_putch(data); ! 9702: REG8(AL) = data; ! 9703: } ! 9704: } ! 9705: ! 9706: DWORD WINAPI msdos_int_21h_07h_thread(LPVOID) ! 9707: { ! 9708: REG8(AL) = msdos_getch(); ! 9709: ! 9710: #ifdef USE_SERVICE_THREAD ! 9711: service_exit = true; ! 9712: #endif ! 9713: return(0); ! 9714: } ! 9715: ! 9716: inline void msdos_int_21h_07h() ! 9717: { ! 9718: #ifdef USE_SERVICE_THREAD ! 9719: if(!in_service && !in_service_29h) { ! 9720: start_service_loop(msdos_int_21h_07h_thread); ! 9721: } else { ! 9722: #endif ! 9723: msdos_int_21h_07h_thread(NULL); ! 9724: REQUEST_HARDWRE_UPDATE(); ! 9725: #ifdef USE_SERVICE_THREAD ! 9726: } ! 9727: #endif ! 9728: } ! 9729: ! 9730: DWORD WINAPI msdos_int_21h_08h_thread(LPVOID) ! 9731: { ! 9732: REG8(AL) = msdos_getch(); ! 9733: ctrl_break_detected = ctrl_break_pressed; ! 9734: ! 9735: #ifdef USE_SERVICE_THREAD ! 9736: service_exit = true; ! 9737: #endif ! 9738: return(0); ! 9739: } ! 9740: ! 9741: inline void msdos_int_21h_08h() ! 9742: { ! 9743: #ifdef USE_SERVICE_THREAD ! 9744: if(!in_service && !in_service_29h) { ! 9745: start_service_loop(msdos_int_21h_08h_thread); ! 9746: } else { ! 9747: #endif ! 9748: msdos_int_21h_08h_thread(NULL); ! 9749: REQUEST_HARDWRE_UPDATE(); ! 9750: #ifdef USE_SERVICE_THREAD ! 9751: } ! 9752: #endif ! 9753: } ! 9754: ! 9755: inline void msdos_int_21h_09h() ! 9756: { ! 9757: msdos_stdio_reopen(); ! 9758: ! 9759: process_t *process = msdos_process_info_get(current_psp); ! 9760: int fd = msdos_psp_get_file_table(1, current_psp); ! 9761: ! 9762: char *str = (char *)(mem + SREG_BASE(DS) + REG16(DX)); ! 9763: int len = 0; ! 9764: ! 9765: while(str[len] != '$' && len < 0x10000) { ! 9766: len++; ! 9767: } ! 9768: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) { ! 9769: // stdout is redirected to file ! 9770: msdos_write(fd, str, len); ! 9771: } else { ! 9772: for(int i = 0; i < len; i++) { ! 9773: msdos_putch(str[i]); ! 9774: } ! 9775: } ! 9776: REG8(AL) = '$'; ! 9777: ctrl_break_detected = ctrl_break_pressed; ! 9778: } ! 9779: ! 9780: DWORD WINAPI msdos_int_21h_0ah_thread(LPVOID) ! 9781: { ! 9782: int ofs = SREG_BASE(DS) + REG16(DX); ! 9783: int max = mem[ofs] - 1; ! 9784: UINT8 *buf = mem + ofs + 2; ! 9785: int chr, p = 0; ! 9786: ! 9787: while((chr = msdos_getch()) != 0x0d) { ! 9788: if((ctrl_break_checking && ctrl_break_pressed) || ctrl_c_pressed) { ! 9789: p = 0; ! 9790: msdos_putch(0x03); ! 9791: msdos_putch(0x0d); ! 9792: msdos_putch(0x0a); ! 9793: break; ! 9794: } else if(ctrl_break_pressed) { ! 9795: // skip this byte ! 9796: } else if(chr == 0x00) { ! 9797: // skip 2nd byte ! 9798: msdos_getch(); ! 9799: } else if(chr == 0x08) { ! 9800: // back space ! 9801: if(p > 0) { ! 9802: p--; ! 9803: if(msdos_ctrl_code_check(buf[p])) { ! 9804: msdos_putch(0x08); ! 9805: msdos_putch(0x08); ! 9806: msdos_putch(0x20); ! 9807: msdos_putch(0x20); ! 9808: msdos_putch(0x08); ! 9809: msdos_putch(0x08); ! 9810: } else if(p > 0 && msdos_kanji_2nd_byte_check(buf, p)) { ! 9811: p--; ! 9812: msdos_putch(0x08); ! 9813: msdos_putch(0x08); ! 9814: msdos_putch(0x20); ! 9815: msdos_putch(0x20); ! 9816: msdos_putch(0x08); ! 9817: msdos_putch(0x08); ! 9818: } else { ! 9819: msdos_putch(0x08); ! 9820: msdos_putch(0x20); ! 9821: msdos_putch(0x08); ! 9822: } ! 9823: } ! 9824: } else if(chr == 0x1b) { ! 9825: // escape ! 9826: while(p > 0) { ! 9827: p--; ! 9828: if(msdos_ctrl_code_check(buf[p])) { ! 9829: msdos_putch(0x08); ! 9830: msdos_putch(0x08); ! 9831: msdos_putch(0x20); ! 9832: msdos_putch(0x20); ! 9833: msdos_putch(0x08); ! 9834: msdos_putch(0x08); ! 9835: } else { ! 9836: msdos_putch(0x08); ! 9837: msdos_putch(0x20); ! 9838: msdos_putch(0x08); ! 9839: } ! 9840: } ! 9841: } else if(p < max) { ! 9842: buf[p++] = chr; ! 9843: msdos_putch(chr); ! 9844: } ! 9845: } ! 9846: buf[p] = 0x0d; ! 9847: msdos_putch(0x0d); ! 9848: mem[ofs + 1] = p; ! 9849: ctrl_break_detected = ctrl_break_pressed; ! 9850: ! 9851: #ifdef USE_SERVICE_THREAD ! 9852: service_exit = true; ! 9853: #endif ! 9854: return(0); ! 9855: } ! 9856: ! 9857: inline void msdos_int_21h_0ah() ! 9858: { ! 9859: if(mem[SREG_BASE(DS) + REG16(DX)] != 0x00) { ! 9860: #ifdef USE_SERVICE_THREAD ! 9861: if(!in_service && !in_service_29h && ! 9862: *(UINT16 *)(mem + 4 * 0x29 + 0) == (IRET_SIZE + 5 * 0x29) && ! 9863: *(UINT16 *)(mem + 4 * 0x29 + 2) == (IRET_TOP >> 4)) { ! 9864: // msdos_putch() will be used in this service ! 9865: // if int 29h is hooked, run this service in main thread to call int 29h ! 9866: start_service_loop(msdos_int_21h_0ah_thread); ! 9867: } else { ! 9868: #endif ! 9869: msdos_int_21h_0ah_thread(NULL); ! 9870: REQUEST_HARDWRE_UPDATE(); ! 9871: #ifdef USE_SERVICE_THREAD ! 9872: } ! 9873: #endif ! 9874: } ! 9875: } ! 9876: ! 9877: inline void msdos_int_21h_0bh() ! 9878: { ! 9879: if(msdos_kbhit()) { ! 9880: REG8(AL) = 0xff; ! 9881: } else { ! 9882: REG8(AL) = 0x00; ! 9883: maybe_idle(); ! 9884: } ! 9885: ctrl_break_detected = ctrl_break_pressed; ! 9886: } ! 9887: ! 9888: inline void msdos_int_21h_0ch() ! 9889: { ! 9890: // clear key buffer ! 9891: msdos_stdio_reopen(); ! 9892: ! 9893: process_t *process = msdos_process_info_get(current_psp); ! 9894: int fd = msdos_psp_get_file_table(0, current_psp); ! 9895: ! 9896: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) { ! 9897: // stdin is redirected to file ! 9898: } else { ! 9899: while(msdos_kbhit()) { ! 9900: msdos_getch(); ! 9901: } ! 9902: } ! 9903: ! 9904: switch(REG8(AL)) { ! 9905: case 0x01: ! 9906: msdos_int_21h_01h(); ! 9907: break; ! 9908: case 0x06: ! 9909: msdos_int_21h_06h(); ! 9910: break; ! 9911: case 0x07: ! 9912: msdos_int_21h_07h(); ! 9913: break; ! 9914: case 0x08: ! 9915: msdos_int_21h_08h(); ! 9916: break; ! 9917: case 0x0a: ! 9918: msdos_int_21h_0ah(); ! 9919: break; ! 9920: default: ! 9921: // the buffer is flushed but no input is attempted ! 9922: break; ! 9923: } ! 9924: } ! 9925: ! 9926: inline void msdos_int_21h_0dh() ! 9927: { ! 9928: } ! 9929: ! 9930: inline void msdos_int_21h_0eh() ! 9931: { ! 9932: if(REG8(DL) < 26) { ! 9933: _chdrive(REG8(DL) + 1); ! 9934: msdos_cds_update(REG8(DL)); ! 9935: msdos_sda_update(current_psp); ! 9936: } ! 9937: REG8(AL) = 26; // zdrive ! 9938: } ! 9939: ! 9940: inline void msdos_int_21h_0fh() ! 9941: { ! 9942: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX)); ! 9943: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0)); ! 9944: const char *path = msdos_fcb_path(fcb); ! 9945: HANDLE hFile = CreateFileA(path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); ! 9946: ! 9947: if(hFile == INVALID_HANDLE_VALUE) { ! 9948: REG8(AL) = 0xff; ! 9949: } else { ! 9950: REG8(AL) = 0; ! 9951: fcb->current_block = 0; ! 9952: fcb->record_size = 128; ! 9953: fcb->file_size = GetFileSize(hFile, NULL); ! 9954: fcb->handle = hFile; ! 9955: } ! 9956: } ! 9957: ! 9958: inline void msdos_int_21h_10h() ! 9959: { ! 9960: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX)); ! 9961: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0)); ! 9962: ! 9963: REG8(AL) = CloseHandle(fcb->handle) ? 0 : 0xff; ! 9964: } ! 9965: ! 9966: inline void msdos_int_21h_11h() ! 9967: { ! 9968: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX)); ! 9969: fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0)); ! 9970: ! 9971: process_t *process = msdos_process_info_get(current_psp); ! 9972: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l; ! 9973: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr); ! 9974: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0)); ! 9975: const char *path = msdos_fcb_path(fcb); ! 9976: WIN32_FIND_DATAA fd; ! 9977: ! 9978: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr); ! 9979: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) { ! 9980: FindClose(dtainfo->find_handle); ! 9981: dtainfo->find_handle = INVALID_HANDLE_VALUE; ! 9982: } ! 9983: strcpy(process->volume_label, msdos_volume_label(path)); ! 9984: dtainfo->allowable_mask = (ext_fcb->flag == 0xff) ? ext_fcb->attribute : 0x20; ! 9985: bool label_only = (dtainfo->allowable_mask == 8); ! 9986: ! 9987: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) { ! 9988: dtainfo->allowable_mask &= ~8; ! 9989: } ! 9990: if(!label_only && (dtainfo->find_handle = FindFirstFileA(path, &fd)) != INVALID_HANDLE_VALUE) { ! 9991: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) || ! 9992: !msdos_find_file_has_8dot3name(&fd)) { ! 9993: if(!FindNextFileA(dtainfo->find_handle, &fd)) { ! 9994: FindClose(dtainfo->find_handle); ! 9995: dtainfo->find_handle = INVALID_HANDLE_VALUE; ! 9996: break; ! 9997: } ! 9998: } ! 9999: } ! 10000: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) { ! 10001: if(ext_fcb->flag == 0xff) { ! 10002: ext_find->flag = 0xff; ! 10003: memset(ext_find->reserved, 0, 5); ! 10004: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f); ! 10005: } ! 10006: find->drive = _getdrive(); ! 10007: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd)); ! 10008: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f); ! 10009: find->nt_res = 0; ! 10010: msdos_find_file_conv_local_time(&fd); ! 10011: find->create_time_ms = 0; ! 10012: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time); ! 10013: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time); ! 10014: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time); ! 10015: find->cluster_hi = find->cluster_lo = 0; ! 10016: find->file_size = fd.nFileSizeLow; ! 10017: REG8(AL) = 0x00; ! 10018: } else if(dtainfo->allowable_mask & 8) { ! 10019: if(ext_fcb->flag == 0xff) { ! 10020: ext_find->flag = 0xff; ! 10021: memset(ext_find->reserved, 0, 5); ! 10022: ext_find->attribute = 8; ! 10023: } ! 10024: find->drive = _getdrive(); ! 10025: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label)); ! 10026: find->attribute = 8; ! 10027: find->nt_res = 0; ! 10028: msdos_find_file_conv_local_time(&fd); ! 10029: find->create_time_ms = 0; ! 10030: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time); ! 10031: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time); ! 10032: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time); ! 10033: find->cluster_hi = find->cluster_lo = 0; ! 10034: find->file_size = 0; ! 10035: dtainfo->allowable_mask &= ~8; ! 10036: REG8(AL) = 0x00; ! 10037: } else { ! 10038: REG8(AL) = 0xff; ! 10039: } ! 10040: } ! 10041: ! 10042: inline void msdos_int_21h_12h() ! 10043: { ! 10044: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX)); ! 10045: // fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0)); ! 10046: ! 10047: process_t *process = msdos_process_info_get(current_psp); ! 10048: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l; ! 10049: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr); ! 10050: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0)); ! 10051: WIN32_FIND_DATAA fd; ! 10052: ! 10053: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr); ! 10054: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) { ! 10055: if(FindNextFileA(dtainfo->find_handle, &fd)) { ! 10056: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) || ! 10057: !msdos_find_file_has_8dot3name(&fd)) { ! 10058: if(!FindNextFileA(dtainfo->find_handle, &fd)) { ! 10059: FindClose(dtainfo->find_handle); ! 10060: dtainfo->find_handle = INVALID_HANDLE_VALUE; ! 10061: break; ! 10062: } ! 10063: } ! 10064: } else { ! 10065: FindClose(dtainfo->find_handle); ! 10066: dtainfo->find_handle = INVALID_HANDLE_VALUE; ! 10067: } ! 10068: } ! 10069: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) { ! 10070: if(ext_fcb->flag == 0xff) { ! 10071: ext_find->flag = 0xff; ! 10072: memset(ext_find->reserved, 0, 5); ! 10073: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f); ! 10074: } ! 10075: find->drive = _getdrive(); ! 10076: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd)); ! 10077: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f); ! 10078: find->nt_res = 0; ! 10079: msdos_find_file_conv_local_time(&fd); ! 10080: find->create_time_ms = 0; ! 10081: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time); ! 10082: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time); ! 10083: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time); ! 10084: find->cluster_hi = find->cluster_lo = 0; ! 10085: find->file_size = fd.nFileSizeLow; ! 10086: REG8(AL) = 0x00; ! 10087: } else if(dtainfo->allowable_mask & 8) { ! 10088: if(ext_fcb->flag == 0xff) { ! 10089: ext_find->flag = 0xff; ! 10090: memset(ext_find->reserved, 0, 5); ! 10091: ext_find->attribute = 8; ! 10092: } ! 10093: find->drive = _getdrive(); ! 10094: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label)); ! 10095: find->attribute = 8; ! 10096: find->nt_res = 0; ! 10097: msdos_find_file_conv_local_time(&fd); ! 10098: find->create_time_ms = 0; ! 10099: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time); ! 10100: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time); ! 10101: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time); ! 10102: find->cluster_hi = find->cluster_lo = 0; ! 10103: find->file_size = 0; ! 10104: dtainfo->allowable_mask &= ~8; ! 10105: REG8(AL) = 0x00; ! 10106: } else { ! 10107: REG8(AL) = 0xff; ! 10108: } ! 10109: } ! 10110: ! 10111: inline void msdos_int_21h_13h() ! 10112: { ! 10113: if(remove(msdos_fcb_path((fcb_t *)(mem + SREG_BASE(DS) + REG16(DX))))) { ! 10114: REG8(AL) = 0xff; ! 10115: } else { ! 10116: REG8(AL) = 0x00; ! 10117: } ! 10118: } ! 10119: ! 10120: inline void msdos_int_21h_14h() ! 10121: { ! 10122: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX)); ! 10123: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0)); ! 10124: process_t *process = msdos_process_info_get(current_psp); ! 10125: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l; ! 10126: DWORD num = 0; ! 10127: ! 10128: memset(mem + dta_laddr, 0, fcb->record_size); ! 10129: SetFilePointer(fcb->handle, fcb->record_size * (fcb->current_block * 128 + fcb->cur_record), NULL, FILE_BEGIN); ! 10130: ! 10131: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) { ! 10132: REG8(AL) = 1; ! 10133: } else { ! 10134: if(++fcb->cur_record >= 128) { ! 10135: fcb->current_block += fcb->cur_record / 128; ! 10136: fcb->cur_record %= 128; ! 10137: } ! 10138: REG8(AL) = (num == fcb->record_size) ? 0 : 3; ! 10139: } ! 10140: } ! 10141: ! 10142: inline void msdos_int_21h_15h() ! 10143: { ! 10144: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX)); ! 10145: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0)); ! 10146: process_t *process = msdos_process_info_get(current_psp); ! 10147: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l; ! 10148: DWORD num = 0; ! 10149: ! 10150: SetFilePointer(fcb->handle, fcb->record_size * (fcb->current_block * 128 + fcb->cur_record), NULL, FILE_BEGIN); ! 10151: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL); ! 10152: fcb->file_size = GetFileSize(fcb->handle, NULL); ! 10153: ! 10154: if(num != fcb->record_size) { ! 10155: REG8(AL) = 1; ! 10156: } else { ! 10157: if(++fcb->cur_record >= 128) { ! 10158: fcb->current_block += fcb->cur_record / 128; ! 10159: fcb->cur_record %= 128; ! 10160: } ! 10161: REG8(AL) = 0; ! 10162: } ! 10163: } ! 10164: ! 10165: inline void msdos_int_21h_16h() ! 10166: { ! 10167: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX)); ! 10168: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0)); ! 10169: const char *path = msdos_fcb_path(fcb); ! 10170: HANDLE hFile = CreateFileA(path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, ext_fcb->flag == 0xff ? ext_fcb->attribute : FILE_ATTRIBUTE_NORMAL, NULL); ! 10171: ! 10172: if(hFile == INVALID_HANDLE_VALUE) { ! 10173: REG8(AL) = 0xff; ! 10174: } else { ! 10175: REG8(AL) = 0; ! 10176: fcb->current_block = 0; ! 10177: fcb->record_size = 128; ! 10178: fcb->file_size = 0; ! 10179: fcb->handle = hFile; ! 10180: } ! 10181: } ! 10182: ! 10183: inline void msdos_int_21h_17h() ! 10184: { ! 10185: ext_fcb_t *ext_fcb_src = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX)); ! 10186: fcb_t *fcb_src = (fcb_t *)(ext_fcb_src + (ext_fcb_src->flag == 0xff ? 1 : 0)); ! 10187: // const char *path_src = msdos_fcb_path(fcb_src); ! 10188: char path_src[MAX_PATH]; ! 10189: strcpy(path_src, msdos_fcb_path(fcb_src)); ! 10190: ! 10191: fcb_t *fcb_dst = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + 16 + (ext_fcb_src->flag == 0xff ? 7 : 0)); ! 10192: // const char *path_dst = msdos_fcb_path(fcb_dst); ! 10193: char path_dst[MAX_PATH]; ! 10194: strcpy(path_dst, msdos_fcb_path(fcb_dst)); ! 10195: ! 10196: if(rename(path_src, path_dst)) { ! 10197: REG8(AL) = 0xff; ! 10198: } else { ! 10199: REG8(AL) = 0; ! 10200: } ! 10201: } ! 10202: ! 10203: inline void msdos_int_21h_18h() ! 10204: { ! 10205: REG8(AL) = 0x00; ! 10206: } ! 10207: ! 10208: inline void msdos_int_21h_19h() ! 10209: { ! 10210: REG8(AL) = _getdrive() - 1; ! 10211: } ! 10212: ! 10213: inline void msdos_int_21h_1ah() ! 10214: { ! 10215: process_t *process = msdos_process_info_get(current_psp); ! 10216: ! 10217: process->dta.w.l = REG16(DX); ! 10218: process->dta.w.h = SREG(DS); ! 10219: msdos_sda_update(current_psp); ! 10220: } ! 10221: ! 10222: inline void msdos_int_21h_1bh() ! 10223: { ! 10224: int drive_num = _getdrive() - 1; ! 10225: UINT16 seg, ofs; ! 10226: ! 10227: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) { ! 10228: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs); ! 10229: REG8(AL) = dpb->highest_sector_num + 1; ! 10230: REG16(CX) = dpb->bytes_per_sector; ! 10231: REG16(DX) = dpb->highest_cluster_num - 1; ! 10232: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type; ! 10233: } else { ! 10234: REG8(AL) = 0xff; ! 10235: m_CF = 1; ! 10236: } ! 10237: ! 10238: } ! 10239: ! 10240: inline void msdos_int_21h_1ch() ! 10241: { ! 10242: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1); ! 10243: UINT16 seg, ofs; ! 10244: ! 10245: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) { ! 10246: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs); ! 10247: REG8(AL) = dpb->highest_sector_num + 1; ! 10248: REG16(CX) = dpb->bytes_per_sector; ! 10249: REG16(DX) = dpb->highest_cluster_num - 1; ! 10250: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type; ! 10251: } else { ! 10252: REG8(AL) = 0xff; ! 10253: m_CF = 1; ! 10254: } ! 10255: ! 10256: } ! 10257: ! 10258: inline void msdos_int_21h_1dh() ! 10259: { ! 10260: REG8(AL) = 0; ! 10261: } ! 10262: ! 10263: inline void msdos_int_21h_1eh() ! 10264: { ! 10265: REG8(AL) = 0; ! 10266: } ! 10267: ! 10268: inline void msdos_int_21h_1fh() ! 10269: { ! 10270: int drive_num = _getdrive() - 1; ! 10271: UINT16 seg, ofs; ! 10272: ! 10273: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) { ! 10274: REG8(AL) = 0; ! 10275: SREG(DS) = seg; ! 10276: i386_load_segment_descriptor(DS); ! 10277: REG16(BX) = ofs; ! 10278: } else { ! 10279: REG8(AL) = 0xff; ! 10280: m_CF = 1; ! 10281: } ! 10282: } ! 10283: ! 10284: inline void msdos_int_21h_20h() ! 10285: { ! 10286: REG8(AL) = 0; ! 10287: } ! 10288: ! 10289: inline void msdos_int_21h_21h() ! 10290: { ! 10291: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX)); ! 10292: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0)); ! 10293: UINT32 rec = (fcb->record_size >= 64) ? fcb->rand_record & 0xffffff : fcb->rand_record; ! 10294: ! 10295: fcb->current_block = rec / 128; ! 10296: fcb->cur_record = rec % 128; ! 10297: ! 10298: if(SetFilePointer(fcb->handle, fcb->record_size * rec, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { ! 10299: REG8(AL) = 1; ! 10300: } else { ! 10301: process_t *process = msdos_process_info_get(current_psp); ! 10302: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l; ! 10303: memset(mem + dta_laddr, 0, fcb->record_size); ! 10304: DWORD num = 0; ! 10305: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) { ! 10306: REG8(AL) = 1; ! 10307: } else { ! 10308: REG8(AL) = (num == fcb->record_size) ? 0 : 3; ! 10309: } ! 10310: } ! 10311: } ! 10312: ! 10313: inline void msdos_int_21h_22h() ! 10314: { ! 10315: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX)); ! 10316: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0)); ! 10317: UINT32 rec = (fcb->record_size >= 64) ? fcb->rand_record & 0xffffff : fcb->rand_record; ! 10318: ! 10319: fcb->current_block = rec / 128; ! 10320: fcb->cur_record = rec % 128; ! 10321: ! 10322: if(SetFilePointer(fcb->handle, fcb->record_size * rec, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { ! 10323: REG8(AL) = 1; ! 10324: } else { ! 10325: process_t *process = msdos_process_info_get(current_psp); ! 10326: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l; ! 10327: DWORD num = 0; ! 10328: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL); ! 10329: fcb->file_size = GetFileSize(fcb->handle, NULL); ! 10330: REG8(AL) = (num == fcb->record_size) ? 0 : 1; ! 10331: } ! 10332: } ! 10333: ! 10334: inline void msdos_int_21h_23h() ! 10335: { ! 10336: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX)); ! 10337: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0)); ! 10338: const char *path = msdos_fcb_path(fcb); ! 10339: HANDLE hFile = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); ! 10340: ! 10341: if(hFile == INVALID_HANDLE_VALUE) { ! 10342: REG8(AL) = 0xff; ! 10343: } else { ! 10344: UINT32 size = GetFileSize(hFile, NULL); ! 10345: UINT32 rec = size / fcb->record_size + ((size % fcb->record_size) != 0); ! 10346: fcb->rand_record = (fcb->record_size >= 64) ? (fcb->rand_record & 0xff000000) | (rec & 0xffffff) : rec; ! 10347: CloseHandle(hFile); ! 10348: REG8(AL) = 0; ! 10349: } ! 10350: } ! 10351: ! 10352: inline void msdos_int_21h_24h() ! 10353: { ! 10354: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX)); ! 10355: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0)); ! 10356: UINT32 rec = fcb->current_block * 128 + fcb->cur_record; ! 10357: ! 10358: fcb->rand_record = (fcb->record_size >= 64) ? (fcb->rand_record & 0xff000000) | (rec & 0xffffff) : rec; ! 10359: } ! 10360: ! 10361: inline void msdos_int_21h_25h() ! 10362: { ! 10363: *(UINT16 *)(mem + 4 * REG8(AL) + 0) = REG16(DX); ! 10364: *(UINT16 *)(mem + 4 * REG8(AL) + 2) = SREG(DS); ! 10365: } ! 10366: ! 10367: inline void msdos_int_21h_26h() ! 10368: { ! 10369: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4)); ! 10370: ! 10371: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t)); ! 10372: psp->first_mcb = REG16(DX) + (PSP_SIZE >> 4); ! 10373: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22); ! 10374: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23); ! 10375: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24); ! 10376: psp->parent_psp = 0; ! 10377: } ! 10378: ! 10379: inline void msdos_int_21h_27h() ! 10380: { ! 10381: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX)); ! 10382: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0)); ! 10383: UINT32 rec = (fcb->record_size >= 64) ? fcb->rand_record & 0xffffff : fcb->rand_record; ! 10384: ! 10385: if(SetFilePointer(fcb->handle, fcb->record_size * rec, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { ! 10386: REG8(AL) = 1; ! 10387: } else if(REG16(CX) == 0) { ! 10388: REG8(AL) = 0; ! 10389: } else { ! 10390: process_t *process = msdos_process_info_get(current_psp); ! 10391: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l; ! 10392: UINT32 len = fcb->record_size * REG16(CX); ! 10393: memset(mem + dta_laddr, 0, len); ! 10394: DWORD num = 0; ! 10395: if(!ReadFile(fcb->handle, mem + dta_laddr, len, &num, NULL) || num == 0) { ! 10396: REG8(AL) = 1; ! 10397: } else { ! 10398: UINT16 nrec = num / fcb->record_size + ((num % fcb->record_size) != 0); ! 10399: rec += nrec; ! 10400: fcb->rand_record = (fcb->record_size >= 64) ? (fcb->rand_record & 0xff000000) | (rec & 0xffffff) : rec; ! 10401: REG8(AL) = (num == len) ? 0 : 3; ! 10402: REG16(CX) = nrec; ! 10403: } ! 10404: } ! 10405: fcb->current_block = rec / 128; ! 10406: fcb->cur_record = rec % 128; ! 10407: } ! 10408: ! 10409: inline void msdos_int_21h_28h() ! 10410: { ! 10411: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX)); ! 10412: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0)); ! 10413: UINT32 rec = (fcb->record_size >= 64) ? fcb->rand_record & 0xffffff : fcb->rand_record; ! 10414: ! 10415: if(SetFilePointer(fcb->handle, fcb->record_size * rec, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { ! 10416: REG8(AL) = 1; ! 10417: } else if(REG16(CX) == 0) { ! 10418: if(!SetEndOfFile(fcb->handle)) { ! 10419: REG8(AL) = 1; ! 10420: } else { ! 10421: fcb->file_size = GetFileSize(fcb->handle, NULL); ! 10422: REG8(AL) = 0; ! 10423: } ! 10424: } else { ! 10425: process_t *process = msdos_process_info_get(current_psp); ! 10426: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l; ! 10427: UINT32 len = fcb->record_size * REG16(CX); ! 10428: DWORD num = 0; ! 10429: WriteFile(fcb->handle, mem + dta_laddr, len, &num, NULL); ! 10430: fcb->file_size = GetFileSize(fcb->handle, NULL); ! 10431: UINT16 nrec = num / fcb->record_size + ((num % fcb->record_size) != 0); ! 10432: rec += nrec; ! 10433: fcb->rand_record = (fcb->record_size >= 64) ? (fcb->rand_record & 0xff000000) | (rec & 0xffffff) : rec; ! 10434: REG8(AL) = (num == len) ? 0 : 1; ! 10435: REG16(CX) = nrec; ! 10436: } ! 10437: fcb->current_block = rec / 128; ! 10438: fcb->cur_record = rec % 128; ! 10439: } ! 10440: ! 10441: inline void msdos_int_21h_29h() ! 10442: { ! 10443: int ofs = 0;//SREG_BASE(DS) + REG16(SI); ! 10444: char buffer[1024], name[MAX_PATH], ext[MAX_PATH]; ! 10445: UINT8 drv = 0; ! 10446: char sep_chars[] = ":.;,=+"; ! 10447: char end_chars[] = "\\<>|/\"[]"; ! 10448: char spc_chars[] = " \t"; ! 10449: ! 10450: memcpy(buffer, mem + SREG_BASE(DS) + REG16(SI), 1023); ! 10451: buffer[1023] = 0; ! 10452: memset(name, 0x20, sizeof(name)); ! 10453: memset(ext, 0x20, sizeof(ext)); ! 10454: ! 10455: if(REG8(AL) & 1) { ! 10456: ofs += strspn((char *)(buffer + ofs), spc_chars); ! 10457: if(my_strchr(sep_chars, buffer[ofs]) && buffer[ofs] != '\0') { ! 10458: ofs++; ! 10459: } ! 10460: } ! 10461: ofs += strspn((char *)(buffer + ofs), spc_chars); ! 10462: ! 10463: if(buffer[ofs + 1] == ':') { ! 10464: if(buffer[ofs] >= 'a' && buffer[ofs] <= 'z') { ! 10465: drv = buffer[ofs] - 'a' + 1; ! 10466: ofs += 2; ! 10467: if(buffer[ofs] == '\\' || buffer[ofs] == '/') { ! 10468: ofs++; ! 10469: } ! 10470: } else if(buffer[ofs] >= 'A' && buffer[ofs] <= 'Z') { ! 10471: drv = buffer[ofs] - 'A' + 1; ! 10472: ofs += 2; ! 10473: if(buffer[ofs] == '\\' || buffer[ofs] == '/') { ! 10474: ofs++; ! 10475: } ! 10476: } ! 10477: } ! 10478: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) { ! 10479: UINT8 c = buffer[ofs]; ! 10480: if(is_kanji) { ! 10481: is_kanji = 0; ! 10482: } else if(msdos_lead_byte_check(c)) { ! 10483: is_kanji = 1; ! 10484: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) { ! 10485: break; ! 10486: } else if(c >= 'a' && c <= 'z') { ! 10487: c -= 0x20; ! 10488: } ! 10489: ofs++; ! 10490: name[i] = c; ! 10491: } ! 10492: if(buffer[ofs] == '.') { ! 10493: ofs++; ! 10494: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) { ! 10495: UINT8 c = buffer[ofs]; ! 10496: if(is_kanji) { ! 10497: is_kanji = 0; ! 10498: } else if(msdos_lead_byte_check(c)) { ! 10499: is_kanji = 1; ! 10500: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) { ! 10501: break; ! 10502: } else if(c >= 'a' && c <= 'z') { ! 10503: c -= 0x20; ! 10504: } ! 10505: ofs++; ! 10506: ext[i] = c; ! 10507: } ! 10508: } ! 10509: int si = REG16(SI) + ofs; ! 10510: int ds = SREG(DS); ! 10511: while(si > 0xffff) { ! 10512: si -= 0x10; ! 10513: ds++; ! 10514: } ! 10515: REG16(SI) = si; ! 10516: SREG(DS) = ds; ! 10517: i386_load_segment_descriptor(DS); ! 10518: ! 10519: UINT8 *fcb = mem + SREG_BASE(ES) + REG16(DI); ! 10520: if(!(REG8(AL) & 2) || drv != 0) { ! 10521: fcb[0] = drv; ! 10522: } ! 10523: if(!(REG8(AL) & 4) || name[0] != 0x20) { ! 10524: memcpy(fcb + 1, name, 8); ! 10525: } ! 10526: if(!(REG8(AL) & 8) || ext[0] != 0x20) { ! 10527: memcpy(fcb + 9, ext, 3); ! 10528: } ! 10529: for(int i = 1, found_star = 0; i < 1 + 8; i++) { ! 10530: if(fcb[i] == '*') { ! 10531: found_star = 1; ! 10532: } ! 10533: if(found_star) { ! 10534: fcb[i] = '?'; ! 10535: } ! 10536: } ! 10537: for(int i = 9, found_star = 0; i < 9 + 3; i++) { ! 10538: if(fcb[i] == '*') { ! 10539: found_star = 1; ! 10540: } ! 10541: if(found_star) { ! 10542: fcb[i] = '?'; ! 10543: } ! 10544: } ! 10545: ! 10546: if(drv == 0 || msdos_is_valid_drive(drv - 1)) { ! 10547: if(memchr(fcb + 1, '?', 8 + 3)) { ! 10548: REG8(AL) = 0x01; ! 10549: } else { ! 10550: REG8(AL) = 0x00; ! 10551: } ! 10552: } else { ! 10553: REG8(AL) = 0xff; ! 10554: } ! 10555: } ! 10556: ! 10557: inline void msdos_int_21h_2ah() ! 10558: { ! 10559: SYSTEMTIME sTime; ! 10560: ! 10561: GetLocalTime(&sTime); ! 10562: REG16(CX) = sTime.wYear; ! 10563: REG8(DH) = (UINT8)sTime.wMonth; ! 10564: REG8(DL) = (UINT8)sTime.wDay; ! 10565: REG8(AL) = (UINT8)sTime.wDayOfWeek; ! 10566: } ! 10567: ! 10568: inline void msdos_int_21h_2bh() ! 10569: { ! 10570: REG8(AL) = 0xff; ! 10571: } ! 10572: ! 10573: inline void msdos_int_21h_2ch() ! 10574: { ! 10575: SYSTEMTIME sTime; ! 10576: ! 10577: GetLocalTime(&sTime); ! 10578: REG8(CH) = (UINT8)sTime.wHour; ! 10579: REG8(CL) = (UINT8)sTime.wMinute; ! 10580: REG8(DH) = (UINT8)sTime.wSecond; ! 10581: REG8(DL) = (UINT8)sTime.wMilliseconds / 10; ! 10582: } ! 10583: ! 10584: inline void msdos_int_21h_2dh() ! 10585: { ! 10586: REG8(AL) = 0x00; ! 10587: } ! 10588: ! 10589: inline void msdos_int_21h_2eh() ! 10590: { ! 10591: process_t *process = msdos_process_info_get(current_psp); ! 10592: ! 10593: process->verify = REG8(AL); ! 10594: } ! 10595: ! 10596: inline void msdos_int_21h_2fh() ! 10597: { ! 10598: process_t *process = msdos_process_info_get(current_psp); ! 10599: ! 10600: REG16(BX) = process->dta.w.l; ! 10601: SREG(ES) = process->dta.w.h; ! 10602: i386_load_segment_descriptor(ES); ! 10603: } ! 10604: ! 10605: inline void msdos_int_21h_30h() ! 10606: { ! 10607: // Version Flag / OEM ! 10608: if(REG8(AL) == 0x01) { ! 10609: #ifdef SUPPORT_HMA ! 10610: REG16(BX) = 0x0000; ! 10611: #else ! 10612: REG16(BX) = 0x1000; // DOS is in HMA ! 10613: #endif ! 10614: } else { ! 10615: // NOTE: EXDEB invites BL shows the machine type (0=PC-98, 1=PC/AT, 2=FMR), ! 10616: // but this is not correct on Windows 98 SE ! 10617: // REG16(BX) = 0xff01; // OEM = Microsoft, PC/AT ! 10618: REG16(BX) = 0xff00; // OEM = Microsoft ! 10619: } ! 10620: REG16(CX) = 0x0000; ! 10621: REG8(AL) = dos_major_version; // 7 ! 10622: REG8(AH) = dos_minor_version; // 10 ! 10623: } ! 10624: ! 10625: inline void msdos_int_21h_31h() ! 10626: { ! 10627: try { ! 10628: msdos_mem_realloc(current_psp, REG16(DX), NULL); ! 10629: } catch(...) { ! 10630: // recover the broken mcb ! 10631: int mcb_seg = current_psp - 1; ! 10632: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4)); ! 10633: ! 10634: if(mcb_seg < (MEMORY_END >> 4)) { ! 10635: mcb->mz = 'M'; ! 10636: mcb->paragraphs = (MEMORY_END >> 4) - mcb_seg - 2; ! 10637: ! 10638: if(((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked & 0x01) { ! 10639: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', PSP_SYSTEM, (UMB_TOP >> 4) - (MEMORY_END >> 4), "SC"); ! 10640: } else { ! 10641: msdos_mcb_create((MEMORY_END >> 4) - 1, 'Z', PSP_SYSTEM, 0, "SC"); ! 10642: } ! 10643: } else { ! 10644: mcb->mz = 'Z'; ! 10645: mcb->paragraphs = (UMB_END >> 4) - mcb_seg - 1; ! 10646: } ! 10647: msdos_mem_realloc(current_psp, REG16(DX), NULL); ! 10648: } ! 10649: msdos_process_terminate(current_psp, REG8(AL) | 0x300, 0); ! 10650: } ! 10651: ! 10652: inline void msdos_int_21h_32h() ! 10653: { ! 10654: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1); ! 10655: UINT16 seg, ofs; ! 10656: ! 10657: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) { ! 10658: REG8(AL) = 0; ! 10659: SREG(DS) = seg; ! 10660: i386_load_segment_descriptor(DS); ! 10661: REG16(BX) = ofs; ! 10662: } else { ! 10663: REG8(AL) = 0xff; ! 10664: m_CF = 1; ! 10665: } ! 10666: } ! 10667: ! 10668: inline void msdos_int_21h_33h() ! 10669: { ! 10670: char path[MAX_PATH]; ! 10671: char drive = 3; // C: ! 10672: ! 10673: switch(REG8(AL)) { ! 10674: case 0x00: ! 10675: REG8(DL) = ctrl_break_checking; ! 10676: break; ! 10677: case 0x01: ! 10678: ctrl_break_checking = REG8(DL); ! 10679: break; ! 10680: case 0x02: ! 10681: { ! 10682: UINT8 old = ctrl_break_checking; ! 10683: ctrl_break_checking = REG8(DL); ! 10684: REG8(DL) = old; ! 10685: } ! 10686: break; ! 10687: case 0x03: ! 10688: case 0x04: ! 10689: // DOS 4.0+ - Unused ! 10690: break; ! 10691: case 0x05: ! 10692: if(GetSystemDirectoryA(path, MAX_PATH) != 0) { ! 10693: if(path[0] >= 'a' && path[0] <= 'z') { ! 10694: drive = path[0] - 'a' + 1; ! 10695: } else if(path[0] >= 'A' && path[0] <= 'Z') { ! 10696: drive = path[0] - 'A' + 1; ! 10697: } ! 10698: } ! 10699: REG8(DL) = (UINT8)drive; ! 10700: break; ! 10701: case 0x06: ! 10702: // MS-DOS version (7.10) ! 10703: REG8(BL) = 7; ! 10704: REG8(BH) = 10; ! 10705: REG8(DL) = 0; ! 10706: #ifdef SUPPORT_HMA ! 10707: REG8(DH) = 0x00; ! 10708: #else ! 10709: REG8(DH) = 0x10; // DOS is in HMA ! 10710: #endif ! 10711: break; ! 10712: case 0x07: ! 10713: if(REG8(DL) == 0) { ! 10714: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag &= ~0x20; ! 10715: } else if(REG8(DL) == 1) { ! 10716: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag |= 0x20; ! 10717: } ! 10718: break; ! 10719: default: ! 10720: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 10721: // REG16(AX) = 0x01; ! 10722: // m_CF = 1; ! 10723: REG8(AL) = 0xff; ! 10724: break; ! 10725: } ! 10726: } ! 10727: ! 10728: inline void msdos_int_21h_34h() ! 10729: { ! 10730: SREG(ES) = SDA_TOP >> 4; ! 10731: i386_load_segment_descriptor(ES); ! 10732: REG16(BX) = offsetof(sda_t, indos_flag); ! 10733: } ! 10734: ! 10735: inline void msdos_int_21h_35h() ! 10736: { ! 10737: REG16(BX) = *(UINT16 *)(mem + 4 * REG8(AL) + 0); ! 10738: SREG(ES) = *(UINT16 *)(mem + 4 * REG8(AL) + 2); ! 10739: i386_load_segment_descriptor(ES); ! 10740: } ! 10741: ! 10742: inline void msdos_int_21h_36h() ! 10743: { ! 10744: struct _diskfree_t df = {0}; ! 10745: ! 10746: if(_getdiskfree(REG8(DL), &df) == 0) { ! 10747: REG16(AX) = (UINT16)df.sectors_per_cluster; ! 10748: REG16(CX) = (UINT16)df.bytes_per_sector; ! 10749: REG16(BX) = df.avail_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.avail_clusters; ! 10750: REG16(DX) = df.total_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.total_clusters; ! 10751: } else { ! 10752: REG16(AX) = 0xffff; ! 10753: } ! 10754: } ! 10755: ! 10756: inline void msdos_int_21h_37h() ! 10757: { ! 10758: static UINT8 dev_flag = 0xff; ! 10759: ! 10760: switch(REG8(AL)) { ! 10761: case 0x00: ! 10762: { ! 10763: process_t *process = msdos_process_info_get(current_psp); ! 10764: REG8(AL) = 0x00; ! 10765: REG8(DL) = process->switchar; ! 10766: } ! 10767: break; ! 10768: case 0x01: ! 10769: { ! 10770: process_t *process = msdos_process_info_get(current_psp); ! 10771: REG8(AL) = 0x00; ! 10772: process->switchar = REG8(DL); ! 10773: msdos_sda_update(current_psp); ! 10774: } ! 10775: break; ! 10776: case 0x02: ! 10777: REG8(DL) = dev_flag; ! 10778: break; ! 10779: case 0x03: ! 10780: dev_flag = REG8(DL); ! 10781: break; ! 10782: case 0xd0: ! 10783: case 0xd1: ! 10784: case 0xd2: ! 10785: case 0xd3: ! 10786: case 0xd4: ! 10787: case 0xd5: ! 10788: case 0xd6: ! 10789: case 0xd7: ! 10790: case 0xdc: ! 10791: case 0xdd: ! 10792: case 0xde: ! 10793: case 0xdf: ! 10794: // DIET v1.43e ! 10795: // REG16(AX) = 1; ! 10796: REG8(AL) = 0xff; ! 10797: break; ! 10798: default: ! 10799: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 10800: // REG16(AX) = 1; ! 10801: REG8(AL) = 0xff; ! 10802: break; ! 10803: } ! 10804: } ! 10805: ! 10806: int get_country_info(country_info_t *ci, LCID locale = LOCALE_USER_DEFAULT) ! 10807: { ! 10808: char LCdata[80]; ! 10809: ! 10810: ZeroMemory(ci, offsetof(country_info_t, reserved)); ! 10811: GetLocaleInfoA(locale, LOCALE_ICURRDIGITS, LCdata, sizeof(LCdata)); ! 10812: ci->currency_dec_digits = atoi(LCdata); ! 10813: GetLocaleInfoA(locale, LOCALE_ICURRENCY, LCdata, sizeof(LCdata)); ! 10814: ci->currency_format = *LCdata - '0'; ! 10815: GetLocaleInfoA(locale, LOCALE_IDATE, LCdata, sizeof(LCdata)); ! 10816: ci->date_format = *LCdata - '0'; ! 10817: GetLocaleInfoA(locale, LOCALE_SCURRENCY, LCdata, sizeof(LCdata)); ! 10818: memcpy(&ci->currency_symbol, LCdata, 4); ! 10819: GetLocaleInfoA(locale, LOCALE_SDATE, LCdata, sizeof(LCdata)); ! 10820: *ci->date_sep = *LCdata; ! 10821: GetLocaleInfoA(locale, LOCALE_SDECIMAL, LCdata, sizeof(LCdata)); ! 10822: *ci->dec_sep = *LCdata; ! 10823: GetLocaleInfoA(locale, LOCALE_SLIST, LCdata, sizeof(LCdata)); ! 10824: *ci->list_sep = *LCdata; ! 10825: GetLocaleInfoA(locale, LOCALE_STHOUSAND, LCdata, sizeof(LCdata)); ! 10826: *ci->thou_sep = *LCdata; ! 10827: GetLocaleInfoA(locale, LOCALE_STIME, LCdata, sizeof(LCdata)); ! 10828: *ci->time_sep = *LCdata; ! 10829: GetLocaleInfoA(locale, LOCALE_STIMEFORMAT, LCdata, sizeof(LCdata)); ! 10830: if(strchr(LCdata, 'H') != NULL) { ! 10831: ci->time_format = 1; ! 10832: } ! 10833: ci->case_map.w.l = 0x000a; // dummy case map routine is at fffc:000a ! 10834: ci->case_map.w.h = DUMMY_TOP >> 4; ! 10835: GetLocaleInfoA(locale, LOCALE_ICOUNTRY, LCdata, sizeof(LCdata)); ! 10836: return atoi(LCdata); ! 10837: } ! 10838: ! 10839: int get_country_info(country_info_t *ci, USHORT usPrimaryLanguage, USHORT usSubLanguage) ! 10840: { ! 10841: return get_country_info(ci, MAKELCID(MAKELANGID(usPrimaryLanguage, usSubLanguage), SORT_DEFAULT)); ! 10842: } ! 10843: ! 10844: void set_country_info(country_info_t *ci, int size) ! 10845: { ! 10846: char LCdata[80]; ! 10847: ! 10848: if(size >= 0x00 + 2) { ! 10849: memset(LCdata, 0, sizeof(LCdata)); ! 10850: *LCdata = '0' + ci->date_format; ! 10851: SetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_IDATE, LCdata); ! 10852: } ! 10853: if(size >= 0x02 + 5) { ! 10854: memset(LCdata, 0, sizeof(LCdata)); ! 10855: memcpy(LCdata, &ci->currency_symbol, 4); ! 10856: SetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SCURRENCY, LCdata); ! 10857: } ! 10858: if(size >= 0x07 + 2) { ! 10859: memset(LCdata, 0, sizeof(LCdata)); ! 10860: *LCdata = *ci->thou_sep; ! 10861: SetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, LCdata); ! 10862: } ! 10863: if(size >= 0x09 + 2) { ! 10864: memset(LCdata, 0, sizeof(LCdata)); ! 10865: *LCdata = *ci->dec_sep; ! 10866: SetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, LCdata); ! 10867: } ! 10868: if(size >= 0x0b + 2) { ! 10869: memset(LCdata, 0, sizeof(LCdata)); ! 10870: *LCdata = *ci->date_sep; ! 10871: SetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SDATE, LCdata); ! 10872: } ! 10873: if(size >= 0x0d + 2) { ! 10874: memset(LCdata, 0, sizeof(LCdata)); ! 10875: *LCdata = *ci->time_sep; ! 10876: SetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_STIME, LCdata); ! 10877: } ! 10878: if(size >= 0x0f + 1) { ! 10879: memset(LCdata, 0, sizeof(LCdata)); ! 10880: *LCdata = '0' + ci->currency_format; ! 10881: SetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ICURRENCY, LCdata); ! 10882: } ! 10883: if(size >= 0x10 + 1) { ! 10884: sprintf(LCdata, "%d", ci->currency_dec_digits); ! 10885: SetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ICURRDIGITS, LCdata); ! 10886: } ! 10887: if(size >= 0x11 + 1) { ! 10888: // FIXME: is time format always H/h:mm:ss ??? ! 10889: if(ci->time_format & 1) { ! 10890: sprintf(LCdata, "H%cmm%css", *ci->time_sep, *ci->time_sep); ! 10891: } else { ! 10892: sprintf(LCdata, "h%cmm%css", *ci->time_sep, *ci->time_sep); ! 10893: } ! 10894: SetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, LCdata); ! 10895: } ! 10896: if(size >= 0x12 + 4) { ! 10897: // 12h DWORD address of case map routine ! 10898: // (FAR CALL, AL = character to map to upper case [>= 80h]) ! 10899: } ! 10900: if(size >= 0x16 + 2) { ! 10901: memset(LCdata, 0, sizeof(LCdata)); ! 10902: *LCdata = *ci->list_sep; ! 10903: SetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SLIST, LCdata); ! 10904: } ! 10905: } ! 10906: ! 10907: #ifndef SUBLANG_SWAHILI ! 10908: #define SUBLANG_SWAHILI 0x01 ! 10909: #endif ! 10910: #ifndef SUBLANG_TSWANA_BOTSWANA ! 10911: #define SUBLANG_TSWANA_BOTSWANA 0x02 ! 10912: #endif ! 10913: #ifndef SUBLANG_LITHUANIAN_LITHUANIA ! 10914: #define SUBLANG_LITHUANIAN_LITHUANIA 0x01 ! 10915: #endif ! 10916: #ifndef LANG_BANGLA ! 10917: #define LANG_BANGLA 0x45 ! 10918: #endif ! 10919: #ifndef SUBLANG_BANGLA_BANGLADESH ! 10920: #define SUBLANG_BANGLA_BANGLADESH 0x02 ! 10921: #endif ! 10922: ! 10923: static const struct { ! 10924: int code; ! 10925: USHORT usPrimaryLanguage; ! 10926: USHORT usSubLanguage; ! 10927: } country_table[] = { ! 10928: {0x001, LANG_ENGLISH, SUBLANG_ENGLISH_US}, // United States ! 10929: {0x002, LANG_FRENCH, SUBLANG_FRENCH_CANADIAN}, // Canadian-French ! 10930: {0x004, LANG_ENGLISH, SUBLANG_ENGLISH_CAN}, // Canada (English) ! 10931: {0x007, LANG_RUSSIAN, SUBLANG_RUSSIAN_RUSSIA}, // Russia ! 10932: {0x014, LANG_ARABIC, SUBLANG_ARABIC_EGYPT}, // Egypt ! 10933: {0x01B, LANG_ZULU, SUBLANG_ZULU_SOUTH_AFRICA}, // South Africa ! 10934: // {0x01B, LANG_XHOSA, SUBLANG_XHOSA_SOUTH_AFRICA}, // South Africa ! 10935: // {0x01B, LANG_AFRIKAANS, SUBLANG_AFRIKAANS_SOUTH_AFRICA}, // South Africa ! 10936: // {0x01B, LANG_ENGLISH, SUBLANG_ENGLISH_SOUTH_AFRICA}, // South Africa ! 10937: // {0x01B, LANG_SOTHO, SUBLANG_SOTHO_NORTHERN_SOUTH_AFRICA}, // South Africa ! 10938: // {0x01B, LANG_TSWANA, SUBLANG_TSWANA_SOUTH_AFRICA}, // South Africa ! 10939: {0x01E, LANG_GREEK, SUBLANG_GREEK_GREECE}, // Greece ! 10940: {0x01F, LANG_DUTCH, SUBLANG_DUTCH}, // Netherlands ! 10941: // {0x01F, LANG_FRISIAN, SUBLANG_FRISIAN_NETHERLANDS}, // Netherlands ! 10942: {0x020, LANG_DUTCH, SUBLANG_DUTCH_BELGIAN}, // Belgium ! 10943: // {0x020, LANG_FRENCH, SUBLANG_FRENCH_BELGIAN}, // Belgium ! 10944: {0x021, LANG_FRENCH, SUBLANG_FRENCH}, // France ! 10945: {0x022, LANG_SPANISH, SUBLANG_SPANISH}, // Spain ! 10946: {0x023, LANG_BULGARIAN, SUBLANG_BULGARIAN_BULGARIA}, // Bulgaria??? ! 10947: {0x024, LANG_HUNGARIAN, SUBLANG_HUNGARIAN_HUNGARY}, // Hungary (not supported by DR DOS 5.0) ! 10948: {0x027, LANG_ITALIAN, SUBLANG_ITALIAN}, // Italy / San Marino / Vatican City ! 10949: {0x028, LANG_ROMANIAN, SUBLANG_ROMANIAN_ROMANIA}, // Romania ! 10950: {0x029, LANG_GERMAN, SUBLANG_GERMAN_SWISS}, // Switzerland / Liechtenstein ! 10951: // {0x029, LANG_FRENCH, SUBLANG_FRENCH_SWISS}, // Switzerland / Liechtenstein ! 10952: // {0x029, LANG_ITALIAN, SUBLANG_ITALIAN_SWISS}, // Switzerland / Liechtenstein ! 10953: {0x02A, LANG_SLOVAK, SUBLANG_SLOVAK_SLOVAKIA}, // Czechoslovakia / Tjekia / Slovakia (not supported by DR DOS 5.0) ! 10954: {0x02B, LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN}, // Austria (DR DOS 5.0) ! 10955: {0x02C, LANG_ENGLISH, SUBLANG_ENGLISH_UK}, // United Kingdom ! 10956: {0x02D, LANG_DANISH, SUBLANG_DANISH_DENMARK}, // Denmark ! 10957: {0x02E, LANG_SWEDISH, SUBLANG_SWEDISH}, // Sweden ! 10958: // {0x02E, LANG_SAMI, SUBLANG_SAMI_NORTHERN_SWEDEN}, // Sweden ! 10959: // {0x02E, LANG_SAMI, SUBLANG_SAMI_LULE_SWEDEN}, // Sweden ! 10960: // {0x02E, LANG_SAMI, SUBLANG_SAMI_SOUTHERN_SWEDEN}, // Sweden ! 10961: {0x02F, LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL}, // Norway ! 10962: // {0x02F, LANG_NORWEGIAN, SUBLANG_NORWEGIAN_NYNORSK}, // Norway ! 10963: // {0x02F, LANG_SAMI, SUBLANG_SAMI_NORTHERN_NORWAY}, // Norway ! 10964: // {0x02F, LANG_SAMI, SUBLANG_SAMI_LULE_NORWAY}, // Norway ! 10965: // {0x02F, LANG_SAMI, SUBLANG_SAMI_SOUTHERN_NORWAY}, // Norway ! 10966: {0x030, LANG_POLISH, SUBLANG_POLISH_POLAND}, // Poland (not supported by DR DOS 5.0) ! 10967: {0x031, LANG_GERMAN, SUBLANG_GERMAN}, // Germany ! 10968: {0x033, LANG_SPANISH, SUBLANG_SPANISH_PERU}, // Peru ! 10969: // {0x033, LANG_QUECHUA, SUBLANG_QUECHUA_PERU}, // Peru ! 10970: {0x034, LANG_SPANISH, SUBLANG_SPANISH_MEXICAN}, // Mexico ! 10971: {0x035, LANG_SPANISH, SUBLANG_NEUTRAL}, // Cuba ! 10972: {0x036, LANG_SPANISH, SUBLANG_SPANISH_ARGENTINA}, // Argentina ! 10973: {0x037, LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN}, // Brazil (not supported by DR DOS 5.0) ! 10974: {0x038, LANG_SPANISH, SUBLANG_SPANISH_CHILE}, // Chile ! 10975: {0x039, LANG_SPANISH, SUBLANG_SPANISH_COLOMBIA}, // Columbia ! 10976: {0x03A, LANG_SPANISH, SUBLANG_SPANISH_VENEZUELA}, // Venezuela ! 10977: {0x03C, LANG_MALAY, SUBLANG_MALAY_MALAYSIA}, // Malaysia ! 10978: {0x03D, LANG_ENGLISH, SUBLANG_ENGLISH_AUS}, // International English / Australia ! 10979: {0x03E, LANG_INDONESIAN, SUBLANG_INDONESIAN_INDONESIA}, // Indonesia / East Timor ! 10980: {0x03F, LANG_ENGLISH, SUBLANG_ENGLISH_PHILIPPINES}, // Philippines ! 10981: {0x040, LANG_ENGLISH, SUBLANG_ENGLISH_NZ}, // New Zealand ! 10982: {0x041, LANG_CHINESE, SUBLANG_CHINESE_SINGAPORE}, // Singapore ! 10983: // {0x041, LANG_ENGLISH, SUBLANG_ENGLISH_SINGAPORE}, // Singapore ! 10984: {0x042, LANG_CHINESE_TRADITIONAL, SUBLANG_CHINESE_TRADITIONAL}, // Taiwan??? ! 10985: {0x051, LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN}, // Japan (DR DOS 5.0, MS-DOS 5.0+) ! 10986: {0x052, LANG_KOREAN, SUBLANG_KOREAN}, // South Korea (DR DOS 5.0) ! 10987: {0x054, LANG_VIETNAMESE, SUBLANG_VIETNAMESE_VIETNAM}, // Vietnam ! 10988: {0x056, LANG_CHINESE_SIMPLIFIED, SUBLANG_CHINESE_SIMPLIFIED}, // China (MS-DOS 5.0+) ! 10989: {0x058, LANG_CHINESE_TRADITIONAL, SUBLANG_CHINESE_TRADITIONAL}, // Taiwan (MS-DOS 5.0+) ! 10990: {0x05A, LANG_TURKISH, SUBLANG_TURKISH_TURKEY}, // Turkey (MS-DOS 5.0+) ! 10991: {0x05B, LANG_HINDI, SUBLANG_HINDI_INDIA}, // India ! 10992: {0x05C, LANG_URDU, SUBLANG_URDU_PAKISTAN}, // Pakistan ! 10993: {0x05D, LANG_PASHTO, SUBLANG_PASHTO_AFGHANISTAN}, // Afghanistan ! 10994: // {0x05D, LANG_DARI, SUBLANG_DARI_AFGHANISTAN}, // Afghanistan ! 10995: {0x05E, LANG_SINHALESE, SUBLANG_SINHALESE_SRI_LANKA}, // Sri Lanka ! 10996: // {0x05E, LANG_TAMIL, SUBLANG_TAMIL_SRI_LANKA}, // Sri Lanka ! 10997: {0x062, LANG_PERSIAN, SUBLANG_PERSIAN_IRAN}, // Iran ! 10998: {0x070, LANG_BELARUSIAN, SUBLANG_BELARUSIAN_BELARUS}, // Belarus ! 10999: {0x0C8, LANG_THAI, SUBLANG_THAI_THAILAND}, // Thailand ! 11000: {0x0D4, LANG_ARABIC, SUBLANG_ARABIC_MOROCCO}, // Morocco ! 11001: {0x0D5, LANG_ARABIC, SUBLANG_ARABIC_ALGERIA}, // Algeria ! 11002: {0x0D8, LANG_ARABIC, SUBLANG_ARABIC_TUNISIA}, // Tunisia ! 11003: {0x0DA, LANG_ARABIC, SUBLANG_ARABIC_LIBYA}, // Libya ! 11004: {0x0DD, LANG_WOLOF, SUBLANG_WOLOF_SENEGAL}, // Senegal ! 11005: // {0x0DD, LANG_PULAR, SUBLANG_PULAR_SENEGAL}, // Senegal ! 11006: {0x0EA, LANG_HAUSA, SUBLANG_HAUSA_NIGERIA_LATIN}, // Nigeria ! 11007: // {0x0EA, LANG_YORUBA, SUBLANG_YORUBA_NIGERIA}, // Nigeria ! 11008: // {0x0EA, LANG_IGBO, SUBLANG_IGBO_NIGERIA}, // Nigeria ! 11009: {0x0FB, LANG_AMHARIC, SUBLANG_AMHARIC_ETHIOPIA}, // Ethiopia ! 11010: // {0x0FB, LANG_TIGRINYA, SUBLANG_TIGRINYA_ETHIOPIA}, // Ethiopia ! 11011: {0x0FE, LANG_SWAHILI, SUBLANG_SWAHILI}, // Kenya ! 11012: {0x107, LANG_ENGLISH, SUBLANG_ENGLISH_ZIMBABWE}, // Zimbabwe ! 11013: {0x10B, LANG_TSWANA, SUBLANG_TSWANA_BOTSWANA}, // Botswana ! 11014: {0x12A, LANG_FAEROESE, SUBLANG_FAEROESE_FAROE_ISLANDS}, // Faroe Islands ! 11015: {0x12B, LANG_GREENLANDIC, SUBLANG_GREENLANDIC_GREENLAND}, // Greenland ! 11016: {0x15F, LANG_PORTUGUESE, SUBLANG_PORTUGUESE}, // Portugal ! 11017: {0x160, LANG_LUXEMBOURGISH, SUBLANG_LUXEMBOURGISH_LUXEMBOURG}, // Luxembourg ! 11018: // {0x160, LANG_GERMAN, SUBLANG_GERMAN_LUXEMBOURG}, // Luxembourg ! 11019: // {0x160, LANG_FRENCH, SUBLANG_FRENCH_LUXEMBOURG}, // Luxembourg ! 11020: {0x161, LANG_IRISH, SUBLANG_IRISH_IRELAND}, // Ireland ! 11021: // {0x161, LANG_ENGLISH, SUBLANG_ENGLISH_IRELAND}, // Ireland ! 11022: {0x162, LANG_ICELANDIC, SUBLANG_ICELANDIC_ICELAND}, // Iceland ! 11023: {0x163, LANG_ALBANIAN, SUBLANG_ALBANIAN_ALBANIA}, // Albania ! 11024: {0x164, LANG_MALTESE, SUBLANG_MALTESE_MALTA}, // Malta ! 11025: {0x166, LANG_FINNISH, SUBLANG_FINNISH_FINLAND}, // Finland ! 11026: // {0x166, LANG_SAMI, SUBLANG_SAMI_NORTHERN_FINLAND}, // Finland ! 11027: // {0x166, LANG_SAMI, SUBLANG_SAMI_SKOLT_FINLAND}, // Finland ! 11028: // {0x166, LANG_SAMI, SUBLANG_SAMI_INARI_FINLAND}, // Finland ! 11029: {0x167, LANG_BULGARIAN, SUBLANG_BULGARIAN_BULGARIA}, // Bulgaria ! 11030: {0x172, LANG_LITHUANIAN, SUBLANG_LITHUANIAN_LITHUANIA}, // Lithuania ! 11031: {0x173, LANG_LATVIAN, SUBLANG_LATVIAN_LATVIA}, // Latvia ! 11032: {0x174, LANG_ESTONIAN, SUBLANG_ESTONIAN_ESTONIA}, // Estonia ! 11033: {0x17D, LANG_SERBIAN, SUBLANG_SERBIAN_LATIN}, // Serbia / Montenegro ! 11034: {0x180, LANG_SERBIAN, SUBLANG_SERBIAN_CROATIA}, // Croatia??? ! 11035: {0x181, LANG_SERBIAN, SUBLANG_SERBIAN_CROATIA}, // Croatia ! 11036: {0x182, LANG_SLOVENIAN, SUBLANG_SLOVENIAN_SLOVENIA}, // Slovenia ! 11037: {0x183, LANG_BOSNIAN, SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_LATIN}, // Bosnia-Herzegovina (Latin) ! 11038: {0x184, LANG_BOSNIAN, SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_CYRILLIC}, // Bosnia-Herzegovina (Cyrillic) ! 11039: {0x185, LANG_MACEDONIAN, SUBLANG_MACEDONIAN_MACEDONIA}, // FYR Macedonia ! 11040: {0x1A5, LANG_CZECH, SUBLANG_CZECH_CZECH_REPUBLIC}, // Czech Republic ! 11041: {0x1A6, LANG_SLOVAK, SUBLANG_SLOVAK_SLOVAKIA}, // Slovakia ! 11042: {0x1F5, LANG_ENGLISH, SUBLANG_ENGLISH_BELIZE}, // Belize ! 11043: {0x1F6, LANG_SPANISH, SUBLANG_SPANISH_GUATEMALA}, // Guatemala ! 11044: {0x1F7, LANG_SPANISH, SUBLANG_SPANISH_EL_SALVADOR}, // El Salvador ! 11045: {0x1F8, LANG_SPANISH, SUBLANG_SPANISH_HONDURAS}, // Honduras ! 11046: {0x1F9, LANG_SPANISH, SUBLANG_SPANISH_NICARAGUA}, // Nicraragua ! 11047: {0x1FA, LANG_SPANISH, SUBLANG_SPANISH_COSTA_RICA}, // Costa Rica ! 11048: {0x1FB, LANG_SPANISH, SUBLANG_SPANISH_PANAMA}, // Panama ! 11049: {0x24F, LANG_SPANISH, SUBLANG_SPANISH_BOLIVIA}, // Bolivia ! 11050: // {0x24F, LANG_QUECHUA, SUBLANG_QUECHUA_BOLIVIA}, // Bolivia ! 11051: {0x251, LANG_SPANISH, SUBLANG_SPANISH_ECUADOR}, // Ecuador ! 11052: // {0x251, LANG_QUECHUA, SUBLANG_QUECHUA_ECUADOR}, // Ecuador ! 11053: {0x253, LANG_SPANISH, SUBLANG_SPANISH_PARAGUAY}, // Paraguay ! 11054: {0x256, LANG_SPANISH, SUBLANG_SPANISH_URUGUAY}, // Uruguay ! 11055: {0x2A1, LANG_MALAY, SUBLANG_MALAY_BRUNEI_DARUSSALAM}, // Brunei Darussalam ! 11056: {0x311, LANG_ARABIC, SUBLANG_NEUTRAL}, // Arabic (Middle East/Saudi Arabia/etc.) ! 11057: {0x324, LANG_UKRAINIAN, SUBLANG_UKRAINIAN_UKRAINE}, // Ukraine ! 11058: {0x352, LANG_KOREAN, SUBLANG_KOREAN}, // North Korea ! 11059: {0x354, LANG_CHINESE, SUBLANG_CHINESE_HONGKONG}, // Hong Kong ! 11060: {0x355, LANG_CHINESE, SUBLANG_CHINESE_MACAU}, // Macao ! 11061: {0x357, LANG_KHMER, SUBLANG_KHMER_CAMBODIA}, // Cambodia ! 11062: {0x370, LANG_BANGLA, SUBLANG_BANGLA_BANGLADESH}, // Bangladesh ! 11063: {0x376, LANG_CHINESE_TRADITIONAL, SUBLANG_CHINESE_TRADITIONAL}, // Taiwan (DOS 6.22+) ! 11064: {0x3C0, LANG_DIVEHI, SUBLANG_DIVEHI_MALDIVES}, // Maldives ! 11065: {0x3C1, LANG_ARABIC, SUBLANG_ARABIC_LEBANON}, // Lebanon ! 11066: {0x3C2, LANG_ARABIC, SUBLANG_ARABIC_JORDAN}, // Jordan ! 11067: {0x3C3, LANG_ARABIC, SUBLANG_ARABIC_SYRIA}, // Syrian Arab Republic ! 11068: {0x3C4, LANG_ARABIC, SUBLANG_ARABIC_IRAQ}, // Ireq ! 11069: {0x3C5, LANG_ARABIC, SUBLANG_ARABIC_KUWAIT}, // Kuwait ! 11070: {0x3C6, LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA}, // Saudi Arabia ! 11071: {0x3C7, LANG_ARABIC, SUBLANG_ARABIC_YEMEN}, // Yemen ! 11072: {0x3C8, LANG_ARABIC, SUBLANG_ARABIC_OMAN}, // Oman ! 11073: {0x3CB, LANG_ARABIC, SUBLANG_ARABIC_UAE}, // United Arab Emirates ! 11074: {0x3CC, LANG_HEBREW, SUBLANG_HEBREW_ISRAEL}, // Israel (Hebrew) (DR DOS 5.0,MS-DOS 5.0+) ! 11075: {0x3CD, LANG_ARABIC, SUBLANG_ARABIC_BAHRAIN}, // Bahrain ! 11076: {0x3CE, LANG_ARABIC, SUBLANG_ARABIC_QATAR}, // Qatar ! 11077: {0x3D0, LANG_MONGOLIAN, SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA}, // Mongolia ! 11078: // {0x3D0, LANG_MONGOLIAN, SUBLANG_MONGOLIAN_PRC}, // Mongolia ! 11079: {0x3D1, LANG_NEPALI, SUBLANG_NEPALI_NEPAL}, // Nepal ! 11080: {-1, 0, 0}, ! 11081: }; ! 11082: ! 11083: inline void msdos_int_21h_38h() ! 11084: { ! 11085: switch(REG8(AL)) { ! 11086: case 0x00: ! 11087: REG16(BX) = get_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(DX))); ! 11088: break; ! 11089: default: ! 11090: for(int i = 0;; i++) { ! 11091: if(country_table[i].code == (REG8(AL) != 0xff ? REG8(AL) : REG16(BX))) { ! 11092: REG16(BX) = get_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(DX)), country_table[i].usPrimaryLanguage, country_table[i].usSubLanguage); ! 11093: break; ! 11094: } else if(country_table[i].code == -1) { ! 11095: // unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 11096: // REG16(AX) = 2; ! 11097: // m_CF = 1; ! 11098: // get current coutry info ! 11099: REG16(BX) = get_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(DX))); ! 11100: break; ! 11101: } ! 11102: } ! 11103: break; ! 11104: } ! 11105: } ! 11106: ! 11107: inline void msdos_int_21h_39h(int lfn) ! 11108: { ! 11109: if(_mkdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) { ! 11110: REG16(AX) = errno; ! 11111: m_CF = 1; ! 11112: } ! 11113: } ! 11114: ! 11115: inline void msdos_int_21h_3ah(int lfn) ! 11116: { ! 11117: if(_rmdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) { ! 11118: REG16(AX) = errno; ! 11119: m_CF = 1; ! 11120: } ! 11121: } ! 11122: ! 11123: inline void msdos_int_21h_3bh(int lfn) ! 11124: { ! 11125: const char *path = msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn); ! 11126: ! 11127: if(_chdir(path)) { ! 11128: REG16(AX) = 3; // must be 3 (path not found) ! 11129: m_CF = 1; ! 11130: } else { ! 11131: int drv = _getdrive() - 1; ! 11132: if(path[1] == ':') { ! 11133: if(path[0] >= 'A' && path[0] <= 'Z') { ! 11134: drv = path[0] - 'A'; ! 11135: } else if(path[0] >= 'a' && path[0] <= 'z') { ! 11136: drv = path[0] - 'a'; ! 11137: } ! 11138: } ! 11139: msdos_cds_update(drv, path); ! 11140: } ! 11141: } ! 11142: ! 11143: inline void msdos_int_21h_3ch() ! 11144: { ! 11145: const char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0); ! 11146: int attr = GetFileAttributesA(path); ! 11147: int fd = -1; ! 11148: int sio_port = 0; ! 11149: int lpt_port = 0; ! 11150: ! 11151: if(msdos_is_device_path(path)) { ! 11152: fd = msdos_open_device(path, _O_WRONLY | _O_BINARY, &sio_port, &lpt_port); ! 11153: } else { ! 11154: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE); ! 11155: } ! 11156: if(fd != -1) { ! 11157: if(attr == -1) { ! 11158: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY; ! 11159: } ! 11160: SetFileAttributesA(path, attr); ! 11161: REG16(AX) = fd; ! 11162: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_device_info(path), current_psp, sio_port, lpt_port); ! 11163: msdos_psp_set_file_table(fd, fd, current_psp); ! 11164: } else { ! 11165: REG16(AX) = errno; ! 11166: m_CF = 1; ! 11167: } ! 11168: } ! 11169: ! 11170: inline void msdos_int_21h_3dh() ! 11171: { ! 11172: const char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0); ! 11173: int mode = REG8(AL) & 0x03; ! 11174: int fd = -1; ! 11175: int sio_port = 0; ! 11176: int lpt_port = 0; ! 11177: ! 11178: if(mode < 0x03) { ! 11179: if(msdos_is_device_path(path)) { ! 11180: fd = msdos_open_device(path, file_mode[mode].mode, &sio_port, &lpt_port); ! 11181: } else { ! 11182: fd = msdos_open(path, file_mode[mode].mode); ! 11183: } ! 11184: if(fd != -1) { ! 11185: REG16(AX) = fd; ! 11186: msdos_file_handler_open(fd, path, _isatty(fd), mode, msdos_device_info(path), current_psp, sio_port, lpt_port); ! 11187: msdos_psp_set_file_table(fd, fd, current_psp); ! 11188: } else { ! 11189: REG16(AX) = errno; ! 11190: m_CF = 1; ! 11191: } ! 11192: } else { ! 11193: REG16(AX) = 0x0c; ! 11194: m_CF = 1; ! 11195: } ! 11196: } ! 11197: ! 11198: inline void msdos_int_21h_3eh() ! 11199: { ! 11200: process_t *process = msdos_process_info_get(current_psp); ! 11201: int fd = msdos_psp_get_file_table(REG16(BX), current_psp); ! 11202: ! 11203: if(fd < process->max_files && file_handler[fd].valid) { ! 11204: _close(fd); ! 11205: msdos_file_handler_close(fd); ! 11206: msdos_psp_set_file_table(REG16(BX), 0x0ff, current_psp); ! 11207: } else { ! 11208: REG16(AX) = 0x06; ! 11209: m_CF = 1; ! 11210: } ! 11211: } ! 11212: ! 11213: DWORD WINAPI msdos_int_21h_3fh_thread(LPVOID) ! 11214: { ! 11215: UINT8 *buf = mem + SREG_BASE(DS) + REG16(DX); ! 11216: int max = REG16(CX); ! 11217: int p = 0; ! 11218: ! 11219: while(max > p) { ! 11220: int chr = msdos_getch(); ! 11221: ! 11222: if((ctrl_break_checking && ctrl_break_pressed) || ctrl_c_pressed) { ! 11223: p = 0; ! 11224: buf[p++] = 0x0d; ! 11225: if(max > p) { ! 11226: buf[p++] = 0x0a; ! 11227: } ! 11228: msdos_putch(0x03); ! 11229: msdos_putch(0x0d); ! 11230: msdos_putch(0x0a); ! 11231: break; ! 11232: } else if(ctrl_break_pressed) { ! 11233: // skip this byte ! 11234: } else if(chr == 0x00) { ! 11235: // skip 2nd byte ! 11236: msdos_getch(); ! 11237: } else if(chr == 0x0d) { ! 11238: // carriage return ! 11239: buf[p++] = 0x0d; ! 11240: if(max > p) { ! 11241: buf[p++] = 0x0a; ! 11242: } ! 11243: msdos_putch('\n'); ! 11244: break; ! 11245: } else if(chr == 0x08) { ! 11246: // back space ! 11247: if(p > 0) { ! 11248: p--; ! 11249: if(msdos_ctrl_code_check(buf[p])) { ! 11250: msdos_putch(0x08); ! 11251: msdos_putch(0x08); ! 11252: msdos_putch(0x20); ! 11253: msdos_putch(0x20); ! 11254: msdos_putch(0x08); ! 11255: msdos_putch(0x08); ! 11256: } else if(p > 0 && msdos_kanji_2nd_byte_check(buf, p)) { ! 11257: p--; ! 11258: msdos_putch(0x08); ! 11259: msdos_putch(0x08); ! 11260: msdos_putch(0x20); ! 11261: msdos_putch(0x20); ! 11262: msdos_putch(0x08); ! 11263: msdos_putch(0x08); ! 11264: } else { ! 11265: msdos_putch(0x08); ! 11266: msdos_putch(0x20); ! 11267: msdos_putch(0x08); ! 11268: } ! 11269: } ! 11270: } else if(chr == 0x1b) { ! 11271: // escape ! 11272: while(p > 0) { ! 11273: p--; ! 11274: if(msdos_ctrl_code_check(buf[p])) { ! 11275: msdos_putch(0x08); ! 11276: msdos_putch(0x08); ! 11277: msdos_putch(0x20); ! 11278: msdos_putch(0x20); ! 11279: msdos_putch(0x08); ! 11280: msdos_putch(0x08); ! 11281: } else { ! 11282: msdos_putch(0x08); ! 11283: msdos_putch(0x20); ! 11284: msdos_putch(0x08); ! 11285: } ! 11286: } ! 11287: } else { ! 11288: buf[p++] = chr; ! 11289: msdos_putch(chr); ! 11290: } ! 11291: } ! 11292: REG16(AX) = p; ! 11293: ! 11294: #ifdef USE_SERVICE_THREAD ! 11295: service_exit = true; ! 11296: #endif ! 11297: return(0); ! 11298: } ! 11299: ! 11300: inline void msdos_int_21h_3fh() ! 11301: { ! 11302: process_t *process = msdos_process_info_get(current_psp); ! 11303: int fd = msdos_psp_get_file_table(REG16(BX), current_psp); ! 11304: ! 11305: if(fd < process->max_files && file_handler[fd].valid) { ! 11306: if(file_mode[file_handler[fd].mode].in) { ! 11307: if(file_handler[fd].atty) { ! 11308: // BX is stdin or is redirected to stdin ! 11309: if(REG16(CX) != 0) { ! 11310: #ifdef USE_SERVICE_THREAD ! 11311: if(!in_service && !in_service_29h && ! 11312: *(UINT16 *)(mem + 4 * 0x29 + 0) == (IRET_SIZE + 5 * 0x29) && ! 11313: *(UINT16 *)(mem + 4 * 0x29 + 2) == (IRET_TOP >> 4)) { ! 11314: // msdos_putch() will be used in this service ! 11315: // if int 29h is hooked, run this service in main thread to call int 29h ! 11316: start_service_loop(msdos_int_21h_3fh_thread); ! 11317: } else { ! 11318: #endif ! 11319: msdos_int_21h_3fh_thread(NULL); ! 11320: REQUEST_HARDWRE_UPDATE(); ! 11321: #ifdef USE_SERVICE_THREAD ! 11322: } ! 11323: #endif ! 11324: } else { ! 11325: REG16(AX) = 0; ! 11326: } ! 11327: } else { ! 11328: REG16(AX) = msdos_read(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX)); ! 11329: } ! 11330: } else { ! 11331: REG16(AX) = 0x05; ! 11332: m_CF = 1; ! 11333: } ! 11334: } else { ! 11335: REG16(AX) = 0x06; ! 11336: m_CF = 1; ! 11337: } ! 11338: } ! 11339: ! 11340: inline void msdos_int_21h_40h() ! 11341: { ! 11342: process_t *process = msdos_process_info_get(current_psp); ! 11343: int fd = msdos_psp_get_file_table(REG16(BX), current_psp); ! 11344: ! 11345: if(fd < process->max_files && file_handler[fd].valid) { ! 11346: if(file_mode[file_handler[fd].mode].out) { ! 11347: if(REG16(CX)) { ! 11348: if(file_handler[fd].atty) { ! 11349: // BX is stdout/stderr or is redirected to stdout ! 11350: for(int i = 0; i < REG16(CX); i++) { ! 11351: msdos_putch(mem[SREG_BASE(DS) + REG16(DX) + i]); ! 11352: } ! 11353: REG16(AX) = REG16(CX); ! 11354: } else { ! 11355: REG16(AX) = msdos_write(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX)); ! 11356: } ! 11357: } else { ! 11358: UINT32 pos = _tell(fd); ! 11359: _lseek(fd, 0, SEEK_END); ! 11360: UINT32 size = _tell(fd); ! 11361: if(pos < size) { ! 11362: _lseek(fd, pos, SEEK_SET); ! 11363: SetEndOfFile((HANDLE)_get_osfhandle(fd)); ! 11364: } else { ! 11365: for(UINT32 i = size; i < pos; i++) { ! 11366: UINT8 tmp = 0; ! 11367: msdos_write(fd, &tmp, 1); ! 11368: } ! 11369: _lseek(fd, pos, SEEK_SET); ! 11370: } ! 11371: REG16(AX) = 0; ! 11372: } ! 11373: } else { ! 11374: REG16(AX) = 0x05; ! 11375: m_CF = 1; ! 11376: } ! 11377: } else { ! 11378: REG16(AX) = 0x06; ! 11379: m_CF = 1; ! 11380: } ! 11381: } ! 11382: ! 11383: inline void msdos_int_21h_41h(int lfn) ! 11384: { ! 11385: if(remove(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) { ! 11386: REG16(AX) = errno; ! 11387: m_CF = 1; ! 11388: } ! 11389: } ! 11390: ! 11391: inline void msdos_int_21h_42h() ! 11392: { ! 11393: process_t *process = msdos_process_info_get(current_psp); ! 11394: int fd = msdos_psp_get_file_table(REG16(BX), current_psp); ! 11395: ! 11396: if(fd < process->max_files && file_handler[fd].valid) { ! 11397: if(REG8(AL) < 0x03) { ! 11398: static const int ptrname[] = { SEEK_SET, SEEK_CUR, SEEK_END }; ! 11399: _lseek(fd, (REG16(CX) << 16) | REG16(DX), ptrname[REG8(AL)]); ! 11400: UINT32 pos = _tell(fd); ! 11401: REG16(AX) = pos & 0xffff; ! 11402: REG16(DX) = (pos >> 16); ! 11403: } else { ! 11404: REG16(AX) = 0x01; ! 11405: m_CF = 1; ! 11406: } ! 11407: } else { ! 11408: REG16(AX) = 0x06; ! 11409: m_CF = 1; ! 11410: } ! 11411: } ! 11412: ! 11413: inline void msdos_int_21h_43h(int lfn) ! 11414: { ! 11415: const char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn); ! 11416: int attr; ! 11417: ! 11418: if(!lfn && REG8(AL) > 2) { ! 11419: REG16(AX) = 0x01; ! 11420: m_CF = 1; ! 11421: return; ! 11422: } ! 11423: switch(REG8(lfn ? BL : AL)) { ! 11424: case 0x00: ! 11425: if((attr = GetFileAttributesA(path)) != -1) { ! 11426: REG16(CX) = (UINT16)msdos_file_attribute_create((UINT16)attr); ! 11427: } else { ! 11428: REG16(AX) = (UINT16)GetLastError(); ! 11429: m_CF = 1; ! 11430: } ! 11431: break; ! 11432: case 0x01: ! 11433: if(!SetFileAttributesA(path, msdos_file_attribute_create(REG16(CX)))) { ! 11434: REG16(AX) = (UINT16)GetLastError(); ! 11435: m_CF = 1; ! 11436: } ! 11437: break; ! 11438: case 0x02: ! 11439: { ! 11440: DWORD compressed_size = GetCompressedFileSizeA(path, NULL), file_size = 0; ! 11441: if(compressed_size != INVALID_FILE_SIZE) { ! 11442: if(compressed_size != 0) { ! 11443: HANDLE hFile = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); ! 11444: if(hFile != INVALID_HANDLE_VALUE) { ! 11445: file_size = GetFileSize(hFile, NULL); ! 11446: CloseHandle(hFile); ! 11447: } ! 11448: if(compressed_size == file_size) { ! 11449: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters; ! 11450: // this isn't correct if the file is in the NTFS MFT ! 11451: if(GetDiskFreeSpaceA(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) { ! 11452: compressed_size = ((compressed_size - 1) | (sectors_per_cluster * bytes_per_sector - 1)) + 1; ! 11453: } ! 11454: } ! 11455: } ! 11456: REG16(AX) = LOWORD(compressed_size); ! 11457: REG16(DX) = HIWORD(compressed_size); ! 11458: } else { ! 11459: REG16(AX) = (UINT16)GetLastError(); ! 11460: m_CF = 1; ! 11461: } ! 11462: } ! 11463: break; ! 11464: case 0x03: ! 11465: case 0x05: ! 11466: case 0x07: ! 11467: if(lfn) { ! 11468: HANDLE hFile = CreateFileA(path, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); ! 11469: if(hFile != INVALID_HANDLE_VALUE) { ! 11470: FILETIME local, time; ! 11471: DosDateTimeToFileTime(REG16(DI), /*REG8(BL) == 5 ? 0 : */REG16(CX), &local); ! 11472: if(REG8(BL) == 7) { ! 11473: ULARGE_INTEGER hund; ! 11474: hund.LowPart = local.dwLowDateTime; ! 11475: hund.HighPart = local.dwHighDateTime; ! 11476: hund.QuadPart += REG16(SI) * 100000; ! 11477: local.dwLowDateTime = hund.LowPart; ! 11478: local.dwHighDateTime = hund.HighPart; ! 11479: } ! 11480: LocalFileTimeToFileTime(&local, &time); ! 11481: if(!SetFileTime(hFile, REG8(BL) == 0x07 ? &time : NULL, ! 11482: REG8(BL) == 0x05 ? &time : NULL, ! 11483: REG8(BL) == 0x03 ? &time : NULL)) { ! 11484: REG16(AX) = (UINT16)GetLastError(); ! 11485: m_CF = 1; ! 11486: } ! 11487: CloseHandle(hFile); ! 11488: } else { ! 11489: REG16(AX) = (UINT16)GetLastError(); ! 11490: m_CF = 1; ! 11491: } ! 11492: } else { ! 11493: // 214303 DR DOS 3.41+ internal - Set Access Rights And Password ! 11494: // 214305 DR DOS 5.0-6.0 internal - Set Extended File Attributes ! 11495: // 214307 DR DOS 6.0 - Set File Owner ! 11496: // unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 11497: REG16(AX) = 0x01; ! 11498: m_CF = 1; ! 11499: } ! 11500: break; ! 11501: case 0x04: ! 11502: case 0x06: ! 11503: case 0x08: ! 11504: if(lfn) { ! 11505: WIN32_FILE_ATTRIBUTE_DATA fad; ! 11506: if(GetFileAttributesExA(path, GetFileExInfoStandard, (LPVOID)&fad)) { ! 11507: FILETIME *time, local; ! 11508: time = REG8(BL) == 0x04 ? &fad.ftLastWriteTime : ! 11509: 0x06 ? &fad.ftLastAccessTime : ! 11510: &fad.ftCreationTime; ! 11511: FileTimeToLocalFileTime(time, &local); ! 11512: FileTimeToDosDateTime(&local, ®16(DI), ®16(CX)); ! 11513: if(REG8(BL) == 0x08) { ! 11514: ULARGE_INTEGER hund; ! 11515: hund.LowPart = local.dwLowDateTime; ! 11516: hund.HighPart = local.dwHighDateTime; ! 11517: hund.QuadPart /= 100000; ! 11518: REG16(SI) = (UINT16)(hund.QuadPart % 200); ! 11519: } ! 11520: } else { ! 11521: REG16(AX) = (UINT16)GetLastError(); ! 11522: m_CF = 1; ! 11523: } ! 11524: } else { ! 11525: // 214304 DR DOS 5.0-6.0 internal - Get Encrypted Password ! 11526: // 214306 DR DOS 6.0 - Get File Owner ! 11527: // unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 11528: REG16(AX) = 0x01; ! 11529: m_CF = 1; ! 11530: } ! 11531: break; ! 11532: case 0xff: ! 11533: if(!lfn && REG16(BP) == 0x5053) { ! 11534: if(REG8(CL) == 0x39) { ! 11535: msdos_int_21h_39h(1); ! 11536: break; ! 11537: } else if(REG8(CL) == 0x56) { ! 11538: msdos_int_21h_56h(1); ! 11539: break; ! 11540: } ! 11541: } ! 11542: default: ! 11543: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 11544: REG16(AX) = lfn ? 0x7100 : 0x01; ! 11545: m_CF = 1; ! 11546: break; ! 11547: } ! 11548: } ! 11549: ! 11550: inline void msdos_int_21h_44h() ! 11551: { ! 11552: static UINT16 iteration_count = 0; ! 11553: ! 11554: process_t *process; ! 11555: int fd, drv; ! 11556: ! 11557: switch(REG8(AL)) { ! 11558: case 0x00: ! 11559: case 0x01: ! 11560: case 0x02: ! 11561: case 0x03: ! 11562: case 0x04: ! 11563: case 0x05: ! 11564: case 0x06: ! 11565: case 0x07: ! 11566: process = msdos_process_info_get(current_psp); ! 11567: fd = msdos_psp_get_file_table(REG16(BX), current_psp); ! 11568: if(fd >= process->max_files || !file_handler[fd].valid) { ! 11569: REG16(AX) = 0x06; ! 11570: m_CF = 1; ! 11571: return; ! 11572: } ! 11573: break; ! 11574: case 0x08: ! 11575: case 0x09: ! 11576: drv = (REG8(BL) ? REG8(BL) : _getdrive()) - 1; ! 11577: if(!msdos_is_valid_drive(drv)) { ! 11578: // invalid drive ! 11579: REG16(AX) = 0x0f; ! 11580: m_CF = 1; ! 11581: return; ! 11582: } ! 11583: break; ! 11584: } ! 11585: switch(REG8(AL)) { ! 11586: case 0x00: // Get Device Information ! 11587: REG16(DX) = file_handler[fd].info; ! 11588: break; ! 11589: case 0x01: // Set Device Information ! 11590: if(REG8(DH) != 0) { ! 11591: // REG16(AX) = 0x0d; // data invalid ! 11592: // m_CF = 1; ! 11593: file_handler[fd].info = REG16(DX); ! 11594: } else { ! 11595: file_handler[fd].info &= 0xff00; ! 11596: file_handler[fd].info |= REG8(DL); ! 11597: } ! 11598: break; ! 11599: case 0x02: // Read From Character Device Control Channel ! 11600: if(strstr(file_handler[fd].path, "EMMXXXX0") != NULL && support_ems) { ! 11601: // from DOSBox ! 11602: switch(*(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX))) { ! 11603: case 0x00: ! 11604: if(REG16(CX) >= 6) { ! 11605: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 0x0023; ! 11606: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = 0x0000; ! 11607: REG16(AX) = 6; // number of bytes actually read ! 11608: } else { ! 11609: REG16(AX) = 0x0d; // data invalid ! 11610: m_CF = 1; ! 11611: } ! 11612: break; ! 11613: case 0x01: ! 11614: if(REG16(CX) >= 6) { ! 11615: *(UINT16 *)(mem + XMS_TOP + 0x18 + 0x000) = 0x0004; // flags ! 11616: *(UINT16 *)(mem + XMS_TOP + 0x18 + 0x002) = 0x019d; // size of this structure ! 11617: *(UINT16 *)(mem + XMS_TOP + 0x18 + 0x004) = 0x0001; // version 1.0 ! 11618: *(UINT32 *)(mem + XMS_TOP + 0x18 + 0x006) = 0x00000000; // reserved ! 11619: for(int addr = 0, ofs = 0x00a; addr < 0x100000; addr += 0x4000, ofs += 6) { ! 11620: if(addr >= EMS_TOP && addr < EMS_TOP + EMS_SIZE) { ! 11621: int page = (addr - EMS_TOP) / 0x4000; ! 11622: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 0) = 0x03; // frame type: EMS frame in 64k page ! 11623: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 1) = 0xff; // owner: NONE ! 11624: *(UINT16 *)(mem + XMS_TOP + 0x18 + ofs + 2) = 0x7fff; // no logical page number ! 11625: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 4) = page; // physical EMS page number ! 11626: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 5) = 0x00; // flags: EMS frame ! 11627: } else { ! 11628: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 0) = 0x00; // frame type: NONE ! 11629: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 1) = 0xff; // owner: NONE ! 11630: *(UINT16 *)(mem + XMS_TOP + 0x18 + ofs + 2) = 0xffff; // non-EMS frame ! 11631: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 4) = 0xff; // EMS page number (NONE) ! 11632: *(UINT8 *)(mem + XMS_TOP + 0x18 + ofs + 5) = 0xaa; // flags: direct mapping ! 11633: } ! 11634: } ! 11635: *(UINT8 *)(mem + XMS_TOP + 0x18 + 0x18a) = 0x74; // ?? ! 11636: *(UINT8 *)(mem + XMS_TOP + 0x18 + 0x18b) = 0x00; // no UMB descriptors following ! 11637: *(UINT8 *)(mem + XMS_TOP + 0x18 + 0x18c) = 0x01; // 1 EMS handle info record ! 11638: *(UINT16 *)(mem + XMS_TOP + 0x18 + 0x17d) = 0x0000; // system handle ! 11639: *(UINT32 *)(mem + XMS_TOP + 0x18 + 0x18f) = 0x00000000; // handle name ! 11640: *(UINT32 *)(mem + XMS_TOP + 0x18 + 0x193) = 0x00000000; // handle name ! 11641: *(UINT16 *)(mem + XMS_TOP + 0x18 + 0x197) = 0x0001; // system handle ! 11642: *(UINT32 *)(mem + XMS_TOP + 0x18 + 0x199) = 0x00110000; // physical address ! 11643: ! 11644: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 0x0018; ! 11645: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = XMS_TOP >> 4; ! 11646: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4) = 0x0001; // version 1.0 ! 11647: REG16(AX) = 6; // number of bytes actually read ! 11648: } else { ! 11649: REG16(AX) = 0x0d; // data invalid ! 11650: m_CF = 1; ! 11651: } ! 11652: break; ! 11653: case 0x02: ! 11654: if(REG16(CX) >= 2) { ! 11655: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 0x40; // EMS 4.0 ! 11656: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 1) = 0x00; ! 11657: REG16(AX) = 2; // number of bytes actually read ! 11658: } else { ! 11659: REG16(AX) = 0x0d; // data invalid ! 11660: m_CF = 1; ! 11661: } ! 11662: break; ! 11663: case 0x03: ! 11664: if(REG16(CX) >= 4) { ! 11665: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = MAX_EMS_PAGES * 16; // max size (kb) ! 11666: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = 0x0080; // min size (kb) ! 11667: REG16(AX) = 4; // number of bytes actually read ! 11668: } else { ! 11669: REG16(AX) = 0x0d; // data invalid ! 11670: m_CF = 1; ! 11671: } ! 11672: break; ! 11673: default: ! 11674: REG16(AX) = 0x01; // function number invalid ! 11675: m_CF = 1; ! 11676: } ! 11677: } else if(strstr(file_handler[fd].path, "CONFIG$") != NULL) { ! 11678: if(REG16(CX) >= 5) { ! 11679: memset(mem + SREG_BASE(DS) + REG16(DX), 0, 5); ! 11680: REG16(AX) = 5; // number of bytes actually read ! 11681: } else { ! 11682: REG16(AX) = 0x0d; // data invalid ! 11683: m_CF = 1; ! 11684: } ! 11685: } else { ! 11686: // memset(mem + SREG_BASE(DS) + REG16(DX), 0, REG16(CX)); ! 11687: // REG16(AX) = REG16(CX); ! 11688: REG16(AX) = 0x05; // access denied ! 11689: m_CF = 1; ! 11690: } ! 11691: break; ! 11692: case 0x03: // Write To Character Device Control Channel ! 11693: // REG16(AX) = 0x05; ! 11694: // m_CF = 1; ! 11695: REG16(AX) = 0x00; // success ! 11696: break; ! 11697: case 0x04: // Read From Block Device Control Channel ! 11698: case 0x05: // Write To Block Device Control Channel ! 11699: REG16(AX) = 0x05; ! 11700: m_CF = 1; ! 11701: break; ! 11702: case 0x06: // Get Input Status ! 11703: if(file_mode[file_handler[fd].mode].in) { ! 11704: if(file_handler[fd].atty) { ! 11705: REG8(AL) = msdos_kbhit() ? 0xff : 0x00; ! 11706: } else { ! 11707: REG8(AL) = eof(fd) ? 0x00 : 0xff; ! 11708: } ! 11709: } else { ! 11710: REG8(AL) = 0x00; ! 11711: } ! 11712: break; ! 11713: case 0x07: // Get Output Status ! 11714: if(file_mode[file_handler[fd].mode].out) { ! 11715: REG8(AL) = 0xff; ! 11716: } else { ! 11717: REG8(AL) = 0x00; ! 11718: } ! 11719: break; ! 11720: case 0x08: // Check If Block Device Removable ! 11721: if(msdos_is_removable_drive(drv) || msdos_is_cdrom_drive(drv)) { ! 11722: // removable drive ! 11723: REG16(AX) = 0x00; ! 11724: } else { ! 11725: // fixed drive ! 11726: REG16(AX) = 0x01; ! 11727: } ! 11728: break; ! 11729: case 0x09: // Check If Block Device Remote ! 11730: if(msdos_is_remote_drive(drv)) { ! 11731: // remote drive ! 11732: REG16(DX) = 0x1000; ! 11733: } else if(msdos_is_subst_drive(drv)) { ! 11734: // subst drive ! 11735: REG16(DX) = 0x8000; ! 11736: } else { ! 11737: // local drive ! 11738: REG16(DX) = 0x0000; ! 11739: } ! 11740: break; ! 11741: case 0x0a: // Check If Handle Is Remote ! 11742: if(!(file_handler[fd].info & 0x8000) && msdos_is_remote_drive(msdos_drive_number(file_handler[fd].path))) { ! 11743: REG16(DX) = 0x8000; ! 11744: } else { ! 11745: REG16(DX) = 0x0000; ! 11746: } ! 11747: break; ! 11748: case 0x0b: // Set Sharing Retry Count ! 11749: break; ! 11750: case 0x0c: // Generic Character Device Request ! 11751: if(REG8(CL) == 0x45) { ! 11752: // set iteration (retry) count ! 11753: iteration_count = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX)); ! 11754: } else if(REG8(CL) == 0x4a) { ! 11755: // select code page ! 11756: active_code_page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2); ! 11757: msdos_nls_tables_update(); ! 11758: } else if(REG8(CL) == 0x4c) { ! 11759: // start code-page preparation ! 11760: int ids[3] = {437, 0, 0}; // 437: US English ! 11761: int count = 1, offset = 0; ! 11762: if(active_code_page != 437) { ! 11763: ids[count++] = active_code_page; ! 11764: } ! 11765: if(system_code_page != 437 && system_code_page != active_code_page) { ! 11766: ids[count++] = system_code_page; ! 11767: } ! 11768: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = 0; ! 11769: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = 2 + 2 * count; ! 11770: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = count; ! 11771: for(int i = 0; i < count; i++) { ! 11772: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = ids[i]; ! 11773: } ! 11774: } else if(REG8(CL) == 0x4d) { ! 11775: // end code-page preparation ! 11776: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 2; ! 11777: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = active_code_page; ! 11778: } else if(REG8(CL) == 0x5f) { ! 11779: // set display information ! 11780: if(*(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02) >= 14) { ! 11781: int cur_width = *(UINT16 *)(mem + 0x44a) + 0; ! 11782: int cur_height = *(UINT8 *)(mem + 0x484) + 1; ! 11783: int new_width = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e); // character columns ! 11784: int new_height = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x10); // character rows ! 11785: ! 11786: if(cur_width != new_width || cur_height != new_height) { ! 11787: pcbios_set_console_size(new_width, new_height, true); ! 11788: } ! 11789: } ! 11790: } else if(REG8(CL) == 0x65) { ! 11791: // get iteration (retry) count ! 11792: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX)) = iteration_count; ! 11793: } else if(REG8(CL) == 0x6a) { ! 11794: // query selected code page ! 11795: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 2; // FIXME ! 11796: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = active_code_page; ! 11797: ! 11798: CPINFO info; ! 11799: GetCPInfo(active_code_page, &info); ! 11800: ! 11801: if(info.MaxCharSize != 1) { ! 11802: for(int i = 0;; i++) { ! 11803: UINT8 lo = info.LeadByte[2 * i + 0]; ! 11804: UINT8 hi = info.LeadByte[2 * i + 1]; ! 11805: ! 11806: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 0) = lo; ! 11807: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 2) = hi; ! 11808: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) + 4; ! 11809: ! 11810: if(lo == 0 && hi == 0) { ! 11811: break; ! 11812: } ! 11813: } ! 11814: } ! 11815: } else if(REG8(CL) == 0x6b) { ! 11816: // query prepare list ! 11817: int ids[3] = {437, 0, 0}; // 437: US English ! 11818: int count = 1, offset = 0; ! 11819: if(active_code_page != 437) { ! 11820: ids[count++] = active_code_page; ! 11821: } ! 11822: if(system_code_page != 437 && system_code_page != active_code_page) { ! 11823: ids[count++] = system_code_page; ! 11824: } ! 11825: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = 2 * (2 + 2 * count); ! 11826: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = count; ! 11827: for(int i = 0; i < count; i++) { ! 11828: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = ids[i]; ! 11829: } ! 11830: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = count; ! 11831: for(int i = 0; i < count; i++) { ! 11832: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2 * (offset++)) = ids[i]; ! 11833: } ! 11834: } else if(REG8(CL) == 0x7f) { ! 11835: // get display information ! 11836: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x00) = 0; // level (0 for DOS 4.x-6.0) ! 11837: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x01) = 0; // reserved (0) ! 11838: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02) = 14; // length of following data (14) ! 11839: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x04) = 1; // bit 0 set for blink, clear for intensity ! 11840: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x06) = 1; // mode type (1=text, 2=graphics) ! 11841: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x07) = 0; // reserved (0) ! 11842: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x08) = 4; // 4 bits per pixel ! 11843: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0a) = 8 * (*(UINT16 *)(mem + 0x44a) + 0); // pixel columns ! 11844: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0c) = 16 * (*(UINT8 *)(mem + 0x484) + 1); // pixel rows ! 11845: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e) = *(UINT16 *)(mem + 0x44a) + 0; // character columns ! 11846: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x10) = *(UINT8 *)(mem + 0x484) + 1; // character rows ! 11847: } else { ! 11848: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 11849: REG16(AX) = 0x01; // invalid function ! 11850: m_CF = 1; ! 11851: } ! 11852: break; ! 11853: case 0x0d: // Generic Block Device Request ! 11854: if(REG8(CL) == 0x40) { ! 11855: // set device parameters ! 11856: // } else if(REG8(CL) == 0x41) { ! 11857: // // write logical device track ! 11858: // } else if(REG8(CL) == 0x42) { ! 11859: // // format and verify logical device track ! 11860: } else if(REG8(CL) == 0x46) { ! 11861: // set volume serial number ! 11862: } else if(REG8(CL) == 0x47) { ! 11863: // set access flag ! 11864: // } else if(REG8(CL) == 0x48) { ! 11865: // // set media lock state ! 11866: // } else if(REG8(CL) == 0x49) { ! 11867: // // eject media in drive ! 11868: } else if(REG8(CL) == 0x4a) { ! 11869: // lock logical volume ! 11870: } else if(REG8(CL) == 0x4b) { ! 11871: // lock physical volume ! 11872: } else if(REG8(CL) == 0x60) { ! 11873: // get device parameters ! 11874: int drive_num = (REG8(BL) ? REG8(BL) : _getdrive()) - 1; ! 11875: ! 11876: if(pcbios_update_drive_param(drive_num, 1)) { ! 11877: drive_param_t *drive_param = &drive_params[drive_num]; ! 11878: DISK_GEOMETRY *geo = &drive_param->geometry; ! 11879: ! 11880: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x07; // ??? ! 11881: switch(geo->MediaType) { ! 11882: case F5_360_512: ! 11883: case F5_320_512: ! 11884: case F5_320_1024: ! 11885: case F5_180_512: ! 11886: case F5_160_512: ! 11887: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // 320K/360K disk ! 11888: break; ! 11889: case F5_1Pt2_512: ! 11890: case F3_1Pt2_512: ! 11891: case F3_1Pt23_1024: ! 11892: case F5_1Pt23_1024: ! 11893: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x01; // 1.2M disk ! 11894: break; ! 11895: case F3_720_512: ! 11896: case F3_640_512: ! 11897: case F5_640_512: ! 11898: case F5_720_512: ! 11899: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02; // 720K disk ! 11900: break; ! 11901: case F8_256_128: ! 11902: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x03; // single-density 8-inch disk ! 11903: break; ! 11904: case FixedMedia: ! 11905: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk ! 11906: break; ! 11907: case F3_1Pt44_512: ! 11908: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07; // (DOS 3.3+) other type of block device, normally 1.44M floppy ! 11909: break; ! 11910: case F3_2Pt88_512: ! 11911: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09; // (DOS 5+) 2.88M floppy ! 11912: break; ! 11913: default: ! 11914: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk ! 11915: // *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // (DOS 3.3+) other type of block device, normally 1.44M floppy ! 11916: break; ! 11917: } ! 11918: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = (geo->MediaType == FixedMedia) ? 0x01 : 0x00; ! 11919: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04) = (geo->Cylinders.QuadPart > 0xffff) ? 0xffff : geo->Cylinders.QuadPart; ! 11920: switch(geo->MediaType) { ! 11921: case F5_360_512: ! 11922: case F5_320_512: ! 11923: case F5_320_1024: ! 11924: case F5_180_512: ! 11925: case F5_160_512: ! 11926: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x01; // 320K/360K disk ! 11927: break; ! 11928: default: ! 11929: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x00; // other drive types ! 11930: break; ! 11931: } ! 11932: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x00) = geo->BytesPerSector; ! 11933: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x02) = geo->SectorsPerTrack * geo->TracksPerCylinder; ! 11934: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x03) = 0; ! 11935: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x05) = 0; ! 11936: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x06) = 0; ! 11937: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x08) = 0; ! 11938: switch(geo->MediaType) { ! 11939: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K) ! 11940: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xff; ! 11941: break; ! 11942: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K) ! 11943: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfe; ! 11944: break; ! 11945: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K) ! 11946: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfd; ! 11947: break; ! 11948: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K) ! 11949: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfc; ! 11950: break; ! 11951: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M) ! 11952: case F3_1Pt2_512: ! 11953: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5") ! 11954: case F5_720_512: ! 11955: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf9; ! 11956: break; ! 11957: case FixedMedia: // hard disk ! 11958: case RemovableMedia: ! 11959: case Unknown: ! 11960: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf8; ! 11961: break; ! 11962: default: ! 11963: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf0; ! 11964: break; ! 11965: } ! 11966: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0d) = geo->SectorsPerTrack; ! 11967: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0f) = 1; ! 11968: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x11) = 0; ! 11969: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x15) = geo->TracksPerCylinder * geo->Cylinders.QuadPart; ! 11970: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x1f) = geo->Cylinders.QuadPart; ! 11971: // 21h BYTE device type ! 11972: // 22h WORD device attributes (removable or not, etc) ! 11973: } else { ! 11974: REG16(AX) = 0x0f; // invalid drive ! 11975: m_CF = 1; ! 11976: } ! 11977: // } else if(REG8(CL) == 0x61) { ! 11978: // // read logical device track ! 11979: // } else if(REG8(CL) == 0x62) { ! 11980: // // verify logical device track ! 11981: } else if(REG8(CL) == 0x66) { ! 11982: // get volume serial number ! 11983: char path[] = "A:\\"; ! 11984: char volume_label[MAX_PATH]; ! 11985: DWORD serial_number = 0; ! 11986: char file_system[MAX_PATH]; ! 11987: ! 11988: path[0] = 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1; ! 11989: ! 11990: if(GetVolumeInformationA(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) { ! 11991: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0; ! 11992: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = serial_number; ! 11993: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x06, 0x20, 11); ! 11994: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x06, volume_label, min(strlen(volume_label), 11)); ! 11995: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x11, 0x20, 8); ! 11996: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x11, file_system, min(strlen(file_system), 8)); ! 11997: } else { ! 11998: REG16(AX) = 0x0f; // invalid drive ! 11999: m_CF = 1; ! 12000: } ! 12001: } else if(REG8(CL) == 0x67) { ! 12002: // get access flag ! 12003: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0; ! 12004: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 1; ! 12005: } else if(REG8(CL) == 0x68) { ! 12006: // sense media type ! 12007: int drive_num = (REG8(BL) ? REG8(BL) : _getdrive()) - 1; ! 12008: ! 12009: if(pcbios_update_drive_param(drive_num, 1)) { ! 12010: drive_param_t *drive_param = &drive_params[drive_num]; ! 12011: DISK_GEOMETRY *geo = &drive_param->geometry; ! 12012: ! 12013: switch(geo->MediaType) { ! 12014: case F3_720_512: ! 12015: case F5_720_512: ! 12016: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01; ! 12017: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02; ! 12018: break; ! 12019: case F3_1Pt44_512: ! 12020: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01; ! 12021: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07; ! 12022: break; ! 12023: case F3_2Pt88_512: ! 12024: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01; ! 12025: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09; ! 12026: break; ! 12027: default: ! 12028: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x00; ! 12029: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // ??? ! 12030: break; ! 12031: } ! 12032: } else { ! 12033: REG16(AX) = 0x0f; // invalid drive ! 12034: m_CF = 1; ! 12035: } ! 12036: } else if(REG8(CL) == 0x6a) { ! 12037: // unlock logical volume ! 12038: } else if(REG8(CL) == 0x6b) { ! 12039: // unlock physical volume ! 12040: // } else if(REG8(CL) == 0x6c) { ! 12041: // // get lock flag ! 12042: // } else if(REG8(CL) == 0x6d) { ! 12043: // // enumerate open files ! 12044: // } else if(REG8(CL) == 0x6e) { ! 12045: // // find swap file ! 12046: // } else if(REG8(CL) == 0x6f) { ! 12047: // // get drive map information ! 12048: // } else if(REG8(CL) == 0x70) { ! 12049: // // get current lock state ! 12050: // } else if(REG8(CL) == 0x71) { ! 12051: // // get first cluster ! 12052: } else { ! 12053: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 12054: REG16(AX) = 0x01; // invalid function ! 12055: m_CF = 1; ! 12056: } ! 12057: break; ! 12058: case 0x0e: // Get Lgical Drive Map ! 12059: if(!msdos_is_valid_drive((REG8(BL) ? REG8(BL) : _getdrive()) - 1)) { ! 12060: REG16(AX) = 0x0f; // invalid drive ! 12061: m_CF = 1; ! 12062: } else { ! 12063: REG8(AL) = 0; ! 12064: } ! 12065: break; ! 12066: case 0x0f: // Set Logical Drive Map ! 12067: if(!msdos_is_valid_drive((REG8(BL) ? REG8(BL) : _getdrive()) - 1)) { ! 12068: REG16(AX) = 0x0f; // invalid drive ! 12069: m_CF = 1; ! 12070: } ! 12071: break; ! 12072: case 0x10: // Query Generic IOCTRL Capability (Handle) ! 12073: switch(REG8(CL)) { ! 12074: case 0x45: ! 12075: case 0x4a: ! 12076: case 0x4c: ! 12077: case 0x4d: ! 12078: case 0x65: ! 12079: case 0x6a: ! 12080: case 0x6b: ! 12081: case 0x7f: ! 12082: REG16(AX) = 0x0000; // supported ! 12083: break; ! 12084: default: ! 12085: REG8(AL) = 0x01; // ioctl capability not available ! 12086: m_CF = 1; ! 12087: break; ! 12088: } ! 12089: break; ! 12090: case 0x11: // Query Generic IOCTRL Capability (Drive) ! 12091: switch(REG8(CL)) { ! 12092: case 0x40: ! 12093: case 0x46: ! 12094: case 0x4a: ! 12095: case 0x4b: ! 12096: case 0x60: ! 12097: case 0x66: ! 12098: case 0x67: ! 12099: case 0x68: ! 12100: case 0x6a: ! 12101: case 0x6b: ! 12102: if(REG8(CH) == 0x00 || REG8(CH) == 0x01 || REG8(CH) == 0x03 || REG8(CH) == 0x05) { ! 12103: // CH = 00h Unknown ! 12104: // CH = 01h COMn: ! 12105: // CH = 03h CON ! 12106: // CH = 05h LPTn: ! 12107: REG16(AX) = 0x0000; // supported ! 12108: break; ! 12109: } ! 12110: default: ! 12111: REG8(AL) = 0x01; // ioctl capability not available ! 12112: m_CF = 1; ! 12113: break; ! 12114: } ! 12115: break; ! 12116: case 0x12: // DR DOS 5.0-6.0 - Determine DOS Type ! 12117: case 0x14: // DR DOS 5.0-6.0 - Set Global Password ! 12118: case 0x16: // DR DOS 5.0-6.0 - History Buffer, Share, And Hiload Control ! 12119: case 0x51: // Concurrent DOS v3.2+ - Installation Check ! 12120: case 0x52: // DR DOS 3.41+ - Determine DOS tTpe/Get DR DOS Version ! 12121: case 0x54: // DR DOS 3.41+ - Set Global Password ! 12122: case 0x56: // DR DOS 5.0+ - History Buffer Control ! 12123: case 0x57: // DR DOS 5.0-6.0 - Share/Hiload Control ! 12124: case 0x58: // DR DOS 5.0+ internal - Get Pointer To Internal Variable Table ! 12125: case 0x59: // DR Multiuser DOS 5.0 - API ! 12126: REG16(AX) = 0x01; // this is not DR-DOS ! 12127: m_CF = 1; ! 12128: break; ! 12129: default: ! 12130: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 12131: REG16(AX) = 0x01; ! 12132: m_CF = 1; ! 12133: break; ! 12134: } ! 12135: } ! 12136: ! 12137: inline void msdos_int_21h_45h() ! 12138: { ! 12139: process_t *process = msdos_process_info_get(current_psp); ! 12140: int fd = msdos_psp_get_file_table(REG16(BX), current_psp); ! 12141: ! 12142: if(fd < process->max_files && file_handler[fd].valid) { ! 12143: int dup_fd = _dup(fd); ! 12144: if(dup_fd != -1) { ! 12145: REG16(AX) = dup_fd; ! 12146: msdos_file_handler_dup(dup_fd, fd, current_psp); ! 12147: // msdos_psp_set_file_table(dup_fd, fd, current_psp); ! 12148: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp); ! 12149: } else { ! 12150: REG16(AX) = errno; ! 12151: m_CF = 1; ! 12152: } ! 12153: } else { ! 12154: REG16(AX) = 0x06; ! 12155: m_CF = 1; ! 12156: } ! 12157: } ! 12158: ! 12159: inline void msdos_int_21h_46h() ! 12160: { ! 12161: process_t *process = msdos_process_info_get(current_psp); ! 12162: int fd = msdos_psp_get_file_table(REG16(BX), current_psp); ! 12163: int dup_fd = REG16(CX); ! 12164: int tmp_fd = msdos_psp_get_file_table(REG16(CX), current_psp); ! 12165: ! 12166: if(REG16(BX) == REG16(CX)) { ! 12167: REG16(AX) = 0x06; ! 12168: m_CF = 1; ! 12169: } else if(fd < process->max_files && file_handler[fd].valid && dup_fd < process->max_files) { ! 12170: if(tmp_fd < process->max_files && file_handler[tmp_fd].valid) { ! 12171: _close(tmp_fd); ! 12172: msdos_file_handler_close(tmp_fd); ! 12173: msdos_psp_set_file_table(dup_fd, 0x0ff, current_psp); ! 12174: } ! 12175: if(_dup2(fd, dup_fd) != -1) { ! 12176: msdos_file_handler_dup(dup_fd, fd, current_psp); ! 12177: // msdos_psp_set_file_table(dup_fd, fd, current_psp); ! 12178: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp); ! 12179: } else { ! 12180: REG16(AX) = errno; ! 12181: m_CF = 1; ! 12182: } ! 12183: } else { ! 12184: REG16(AX) = 0x06; ! 12185: m_CF = 1; ! 12186: } ! 12187: } ! 12188: ! 12189: inline void msdos_int_21h_47h(int lfn) ! 12190: { ! 12191: char path[MAX_PATH]; ! 12192: ! 12193: if(_getdcwd(REG8(DL), path, MAX_PATH) != NULL) { ! 12194: if(!lfn) { ! 12195: strcpy(path, msdos_short_path(path)); ! 12196: } ! 12197: if(path[1] == ':') { ! 12198: // the returned path does not include a drive or the initial backslash ! 12199: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), path + 3); ! 12200: } else { ! 12201: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), path); ! 12202: } ! 12203: } else { ! 12204: REG16(AX) = errno; ! 12205: m_CF = 1; ! 12206: } ! 12207: } ! 12208: ! 12209: inline void msdos_int_21h_48h() ! 12210: { ! 12211: int seg, umb_linked; ! 12212: ! 12213: if((malloc_strategy & 0xf0) == 0x00) { ! 12214: // unlink umb not to allocate memory in umb ! 12215: if((umb_linked = msdos_mem_get_umb_linked()) != 0) { ! 12216: msdos_mem_unlink_umb(); ! 12217: } ! 12218: if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) { ! 12219: REG16(AX) = seg; ! 12220: } else { ! 12221: REG16(AX) = 0x08; ! 12222: REG16(BX) = msdos_mem_get_free(first_mcb, 0); ! 12223: m_CF = 1; ! 12224: } ! 12225: if(umb_linked != 0) { ! 12226: msdos_mem_link_umb(); ! 12227: } ! 12228: } else if((malloc_strategy & 0xf0) == 0x40) { ! 12229: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) { ! 12230: REG16(AX) = seg; ! 12231: } else { ! 12232: REG16(AX) = 0x08; ! 12233: REG16(BX) = msdos_mem_get_free(UMB_TOP >> 4, 0); ! 12234: m_CF = 1; ! 12235: } ! 12236: } else if((malloc_strategy & 0xf0) == 0x80) { ! 12237: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) { ! 12238: REG16(AX) = seg; ! 12239: } else if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) { ! 12240: REG16(AX) = seg; ! 12241: } else { ! 12242: REG16(AX) = 0x08; ! 12243: REG16(BX) = max(msdos_mem_get_free(UMB_TOP >> 4, 0), msdos_mem_get_free(first_mcb, 0)); ! 12244: m_CF = 1; ! 12245: } ! 12246: } ! 12247: } ! 12248: ! 12249: inline void msdos_int_21h_49h() ! 12250: { ! 12251: int mcb_seg = SREG(ES) - 1; ! 12252: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4)); ! 12253: ! 12254: if(mcb->mz == 'M' || mcb->mz == 'Z') { ! 12255: msdos_mem_free(SREG(ES)); ! 12256: } else { ! 12257: REG16(AX) = 0x09; // illegal memory block address ! 12258: m_CF = 1; ! 12259: } ! 12260: } ! 12261: ! 12262: inline void msdos_int_21h_4ah() ! 12263: { ! 12264: int mcb_seg = SREG(ES) - 1; ! 12265: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4)); ! 12266: int max_paragraphs; ! 12267: ! 12268: if(mcb->mz == 'M' || mcb->mz == 'Z') { ! 12269: if(msdos_mem_realloc(SREG(ES), REG16(BX), &max_paragraphs)) { ! 12270: REG16(AX) = 0x08; ! 12271: REG16(BX) = max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs; ! 12272: m_CF = 1; ! 12273: } ! 12274: } else { ! 12275: REG16(AX) = 0x09; // illegal memory block address ! 12276: m_CF = 1; ! 12277: } ! 12278: } ! 12279: ! 12280: inline void msdos_int_21h_4bh() ! 12281: { ! 12282: char *command = (char *)(mem + SREG_BASE(DS) + REG16(DX)); ! 12283: param_block_t *param = (param_block_t *)(mem + SREG_BASE(ES) + REG16(BX)); ! 12284: ! 12285: switch(REG8(AL)) { ! 12286: case 0x00: ! 12287: case 0x01: ! 12288: if(msdos_process_exec(command, param, REG8(AL))) { ! 12289: REG16(AX) = 0x02; ! 12290: m_CF = 1; ! 12291: } ! 12292: break; ! 12293: case 0x03: ! 12294: { ! 12295: int fd; ! 12296: if((fd = _open(command, _O_RDONLY | _O_BINARY)) == -1) { ! 12297: REG16(AX) = 0x02; ! 12298: m_CF = 1; ! 12299: break; ! 12300: } ! 12301: int size = _read(fd, file_buffer, sizeof(file_buffer)); ! 12302: _close(fd); ! 12303: ! 12304: UINT16 *overlay = (UINT16 *)param; ! 12305: ! 12306: // check exe header ! 12307: exe_header_t *header = (exe_header_t *)file_buffer; ! 12308: int header_size = 0; ! 12309: if(header->mz == 0x4d5a || header->mz == 0x5a4d) { ! 12310: header_size = header->header_size * 16; ! 12311: // relocation ! 12312: int start_seg = overlay[1]; ! 12313: for(int i = 0; i < header->relocations; i++) { ! 12314: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0); ! 12315: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2); ! 12316: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg; ! 12317: } ! 12318: } ! 12319: memcpy(mem + (overlay[0] << 4), file_buffer + header_size, size - header_size); ! 12320: } ! 12321: break; ! 12322: case 0x04: ! 12323: // Load And Execute In Background (European MS-DOS 4.0 only) ! 12324: // case 0x05: ! 12325: // // DOS 5+ - Set Execution State ! 12326: case 0x80: ! 12327: // DR DOS v3.41 - Run Already-Loaded Kernel File ! 12328: case 0xf0: ! 12329: case 0xf1: ! 12330: // DIET v1.10+ ! 12331: case 0xfd: ! 12332: case 0xfe: ! 12333: // unknown function called in FreeCOM ! 12334: REG16(AX) = 0x01; ! 12335: m_CF = 1; ! 12336: break; ! 12337: default: ! 12338: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 12339: REG16(AX) = 0x01; ! 12340: m_CF = 1; ! 12341: break; ! 12342: } ! 12343: } ! 12344: ! 12345: inline void msdos_int_21h_4ch() ! 12346: { ! 12347: msdos_process_terminate(current_psp, REG8(AL), 1); ! 12348: } ! 12349: ! 12350: inline void msdos_int_21h_4dh() ! 12351: { ! 12352: REG16(AX) = retval; ! 12353: } ! 12354: ! 12355: inline void msdos_int_21h_4eh() ! 12356: { ! 12357: process_t *process = msdos_process_info_get(current_psp); ! 12358: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l; ! 12359: find_t *find = (find_t *)(mem + dta_laddr); ! 12360: const char *path = msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0); ! 12361: WIN32_FIND_DATAA fd; ! 12362: ! 12363: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR); ! 12364: find->find_magic = FIND_MAGIC; ! 12365: find->dta_index = dtainfo - dtalist; ! 12366: strcpy(process->volume_label, msdos_volume_label(path)); ! 12367: dtainfo->allowable_mask = REG8(CL); ! 12368: // note: SO1 dir command sets 0x3f, but only directories and volue label are found if bit3 is set :-( ! 12369: if((dtainfo->allowable_mask & 0x3f) == 0x3f) { ! 12370: dtainfo->allowable_mask &= ~0x08; ! 12371: } ! 12372: bool label_only = (dtainfo->allowable_mask == 8); ! 12373: ! 12374: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) { ! 12375: dtainfo->allowable_mask &= ~8; ! 12376: } ! 12377: if(!label_only && (dtainfo->find_handle = FindFirstFileA(path, &fd)) != INVALID_HANDLE_VALUE) { ! 12378: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) || ! 12379: !msdos_find_file_has_8dot3name(&fd)) { ! 12380: if(!FindNextFileA(dtainfo->find_handle, &fd)) { ! 12381: FindClose(dtainfo->find_handle); ! 12382: dtainfo->find_handle = INVALID_HANDLE_VALUE; ! 12383: break; ! 12384: } ! 12385: } ! 12386: } ! 12387: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) { ! 12388: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f); ! 12389: msdos_find_file_conv_local_time(&fd); ! 12390: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time); ! 12391: find->size = fd.nFileSizeLow; ! 12392: strcpy(find->name, msdos_short_name(&fd)); ! 12393: REG16(AX) = 0; ! 12394: } else if(dtainfo->allowable_mask & 8) { ! 12395: find->attrib = 8; ! 12396: find->size = 0; ! 12397: strcpy(find->name, msdos_short_volume_label(process->volume_label)); ! 12398: dtainfo->allowable_mask &= ~8; ! 12399: REG16(AX) = 0; ! 12400: } else { ! 12401: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid ! 12402: m_CF = 1; ! 12403: } ! 12404: } ! 12405: ! 12406: inline void msdos_int_21h_4fh() ! 12407: { ! 12408: process_t *process = msdos_process_info_get(current_psp); ! 12409: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l; ! 12410: find_t *find = (find_t *)(mem + dta_laddr); ! 12411: WIN32_FIND_DATAA fd; ! 12412: ! 12413: if(find->find_magic != FIND_MAGIC || find->dta_index >= MAX_DTAINFO) { ! 12414: REG16(AX) = 0x12; ! 12415: m_CF = 1; ! 12416: return; ! 12417: } ! 12418: dtainfo_t *dtainfo = &dtalist[find->dta_index]; ! 12419: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) { ! 12420: if(FindNextFileA(dtainfo->find_handle, &fd)) { ! 12421: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) || ! 12422: !msdos_find_file_has_8dot3name(&fd)) { ! 12423: if(!FindNextFileA(dtainfo->find_handle, &fd)) { ! 12424: FindClose(dtainfo->find_handle); ! 12425: dtainfo->find_handle = INVALID_HANDLE_VALUE; ! 12426: break; ! 12427: } ! 12428: } ! 12429: } else { ! 12430: FindClose(dtainfo->find_handle); ! 12431: dtainfo->find_handle = INVALID_HANDLE_VALUE; ! 12432: } ! 12433: } ! 12434: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) { ! 12435: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f); ! 12436: msdos_find_file_conv_local_time(&fd); ! 12437: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time); ! 12438: find->size = fd.nFileSizeLow; ! 12439: strcpy(find->name, msdos_short_name(&fd)); ! 12440: REG16(AX) = 0; ! 12441: } else if(dtainfo->allowable_mask & 8) { ! 12442: find->attrib = 8; ! 12443: find->size = 0; ! 12444: strcpy(find->name, msdos_short_volume_label(process->volume_label)); ! 12445: dtainfo->allowable_mask &= ~8; ! 12446: REG16(AX) = 0; ! 12447: } else { ! 12448: REG16(AX) = 0x12; ! 12449: m_CF = 1; ! 12450: } ! 12451: } ! 12452: ! 12453: inline void msdos_int_21h_50h() ! 12454: { ! 12455: if(current_psp != REG16(BX)) { ! 12456: process_t *process = msdos_process_info_get(current_psp); ! 12457: if(process != NULL) { ! 12458: process->psp = REG16(BX); ! 12459: } ! 12460: current_psp = REG16(BX); ! 12461: msdos_sda_update(current_psp); ! 12462: } ! 12463: } ! 12464: ! 12465: inline void msdos_int_21h_51h() ! 12466: { ! 12467: REG16(BX) = current_psp; ! 12468: } ! 12469: ! 12470: inline void msdos_int_21h_52h() ! 12471: { ! 12472: SREG(ES) = DOS_INFO_TOP >> 4; ! 12473: i386_load_segment_descriptor(ES); ! 12474: REG16(BX) = offsetof(dos_info_t, first_dpb); ! 12475: } ! 12476: ! 12477: inline void msdos_int_21h_53h() ! 12478: { ! 12479: dpb_t *dpb = (dpb_t *)(mem + SREG_BASE(ES) + REG16(BP)); ! 12480: bpb_t *bpb = (bpb_t *)(mem + SREG_BASE(DS) + REG16(SI)); ! 12481: ! 12482: dpb->bytes_per_sector = bpb->bytes_per_sector; ! 12483: dpb->highest_sector_num = bpb->sectors_per_track - 1; ! 12484: dpb->shift_count = 0; ! 12485: dpb->reserved_sectors = 0; ! 12486: dpb->fat_num = bpb->fat_num; ! 12487: dpb->root_entries = bpb->root_entries; ! 12488: dpb->first_data_sector = 0; ! 12489: if(bpb->sectors_per_cluster != 0) { ! 12490: dpb->highest_cluster_num = (UINT16)(((REG16(CX) == 0x4558 && bpb->total_sectors == 0) ? bpb->ext_total_sectors : bpb->total_sectors) / bpb->sectors_per_cluster + 1); ! 12491: } else { ! 12492: dpb->highest_cluster_num = 0; ! 12493: } ! 12494: dpb->sectors_per_fat = (REG16(CX) == 0x4558 && bpb->sectors_per_fat == 0) ? bpb->ext_sectors_per_fat : bpb->sectors_per_fat; ! 12495: dpb->first_dir_sector = 0; ! 12496: dpb->device_driver_header = 0; ! 12497: dpb->media_type = bpb->media_type; ! 12498: dpb->drive_accessed = 0; ! 12499: dpb->next_dpb_ofs = 0xffff; ! 12500: dpb->next_dpb_seg = 0xffff; ! 12501: dpb->first_free_cluster = 0; ! 12502: dpb->free_clusters = 0xffff; ! 12503: } ! 12504: ! 12505: inline void msdos_int_21h_54h() ! 12506: { ! 12507: process_t *process = msdos_process_info_get(current_psp); ! 12508: ! 12509: REG8(AL) = process->verify; ! 12510: } ! 12511: ! 12512: inline void msdos_int_21h_55h() ! 12513: { ! 12514: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4)); ! 12515: ! 12516: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t)); ! 12517: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22); ! 12518: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23); ! 12519: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24); ! 12520: psp->parent_psp = current_psp; ! 12521: } ! 12522: ! 12523: inline void msdos_int_21h_56h(int lfn) ! 12524: { ! 12525: char src[MAX_PATH], dst[MAX_PATH]; ! 12526: strcpy(src, msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn)); ! 12527: strcpy(dst, msdos_trimmed_path((char *)(mem + SREG_BASE(ES) + REG16(DI)), lfn)); ! 12528: ! 12529: if(msdos_is_existing_file(dst) || msdos_is_existing_dir(dst)) { ! 12530: REG16(AX) = 0x05; // access denied ! 12531: m_CF = 1; ! 12532: } else if(rename(src, dst)) { ! 12533: REG16(AX) = errno; ! 12534: m_CF = 1; ! 12535: } ! 12536: } ! 12537: ! 12538: inline void msdos_int_21h_57h() ! 12539: { ! 12540: FILETIME time, local; ! 12541: FILETIME *ctime, *atime, *mtime; ! 12542: HANDLE hHandle; ! 12543: ! 12544: if((hHandle = (HANDLE)_get_osfhandle(REG16(BX))) == INVALID_HANDLE_VALUE) { ! 12545: REG16(AX) = (UINT16)GetLastError(); ! 12546: m_CF = 1; ! 12547: return; ! 12548: } ! 12549: ctime = atime = mtime = NULL; ! 12550: ! 12551: switch(REG8(AL)) { ! 12552: case 0x00: ! 12553: case 0x01: ! 12554: mtime = &time; ! 12555: break; ! 12556: // case 0x02: // DOS 4.x only - Get Extended Attributes For File ! 12557: // case 0x03: // DOS 4.x only - Get Extended Attribute Properties ! 12558: // break; ! 12559: case 0x04: ! 12560: case 0x05: ! 12561: atime = &time; ! 12562: break; ! 12563: case 0x06: ! 12564: case 0x07: ! 12565: ctime = &time; ! 12566: break; ! 12567: default: ! 12568: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 12569: REG16(AX) = 0x01; ! 12570: m_CF = 1; ! 12571: return; ! 12572: } ! 12573: if(REG8(AL) & 1) { ! 12574: DosDateTimeToFileTime(REG16(DX), REG16(CX), &local); ! 12575: LocalFileTimeToFileTime(&local, &time); ! 12576: if(!SetFileTime(hHandle, ctime, atime, mtime)) { ! 12577: REG16(AX) = (UINT16)GetLastError(); ! 12578: m_CF = 1; ! 12579: } ! 12580: } else { ! 12581: if(!GetFileTime(hHandle, ctime, atime, mtime)) { ! 12582: // assume a device and use the current time ! 12583: GetSystemTimeAsFileTime(&time); ! 12584: } ! 12585: FileTimeToLocalFileTime(&time, &local); ! 12586: FileTimeToDosDateTime(&local, ®16(DX), ®16(CX)); ! 12587: } ! 12588: } ! 12589: ! 12590: inline void msdos_int_21h_58h() ! 12591: { ! 12592: switch(REG8(AL)) { ! 12593: case 0x00: ! 12594: REG16(AX) = malloc_strategy; ! 12595: break; ! 12596: case 0x01: ! 12597: // switch(REG16(BX)) { ! 12598: switch(REG8(BL)) { ! 12599: case 0x0000: ! 12600: case 0x0001: ! 12601: case 0x0002: ! 12602: case 0x0040: ! 12603: case 0x0041: ! 12604: case 0x0042: ! 12605: case 0x0080: ! 12606: case 0x0081: ! 12607: case 0x0082: ! 12608: malloc_strategy = REG16(BX); ! 12609: msdos_sda_update(current_psp); ! 12610: break; ! 12611: default: ! 12612: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 12613: REG16(AX) = 0x01; ! 12614: m_CF = 1; ! 12615: break; ! 12616: } ! 12617: break; ! 12618: case 0x02: ! 12619: REG8(AL) = msdos_mem_get_umb_linked() ? 1 : 0; ! 12620: break; ! 12621: case 0x03: ! 12622: // switch(REG16(BX)) { ! 12623: switch(REG8(BL)) { ! 12624: case 0x0000: ! 12625: msdos_mem_unlink_umb(); ! 12626: break; ! 12627: case 0x0001: ! 12628: msdos_mem_link_umb(); ! 12629: break; ! 12630: default: ! 12631: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 12632: REG16(AX) = 0x01; ! 12633: m_CF = 1; ! 12634: break; ! 12635: } ! 12636: break; ! 12637: default: ! 12638: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 12639: REG16(AX) = 0x01; ! 12640: m_CF = 1; ! 12641: break; ! 12642: } ! 12643: } ! 12644: ! 12645: inline void msdos_int_21h_59h() ! 12646: { ! 12647: if(REG16(BX) == 0x0000) { ! 12648: sda_t *sda = (sda_t *)(mem + SDA_TOP); ! 12649: ! 12650: REG16(AX) = sda->extended_error_code; ! 12651: REG8(BH) = sda->error_class; ! 12652: REG8(BL) = sda->suggested_action; ! 12653: REG8(CH) = sda->locus_of_last_error; ! 12654: // XXX: GW-BASIC 3.23 invites the registers contents of CL, DX, SI, DI, DS, and ES are not destroyed ! 12655: if(sda->int21h_5d0ah_called != 0) { ! 12656: REG8(CL) = sda->int21h_5d0ah_cl; ! 12657: REG16(DX) = sda->int21h_5d0ah_dx; ! 12658: // REG16(SI) = sda->int21h_5d0ah_si; ! 12659: REG16(DI) = sda->last_error_pointer.w.l; ! 12660: // SREG(DS) = sda->int21h_5d0ah_ds; ! 12661: // i386_load_segment_descriptor(DS); ! 12662: SREG(ES) = sda->last_error_pointer.w.h; ! 12663: i386_load_segment_descriptor(ES); ! 12664: } ! 12665: sda->int21h_5d0ah_called = 0; ! 12666: // } else if(REG16(BX) == 0x0001) { ! 12667: // // European MS-DOS 4.0 - Get Hard Error Information ! 12668: } else { ! 12669: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 12670: REG16(AX) = 0x01; ! 12671: m_CF = 1; ! 12672: } ! 12673: } ! 12674: ! 12675: inline void msdos_int_21h_5ah() ! 12676: { ! 12677: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX)); ! 12678: int len = strlen(path); ! 12679: char tmp[MAX_PATH]; ! 12680: ! 12681: if(GetTempFileNameA(path, "TMP", 0, tmp)) { ! 12682: int fd = _open(tmp, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE); ! 12683: ! 12684: SetFileAttributesA(tmp, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY); ! 12685: REG16(AX) = fd; ! 12686: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp); ! 12687: msdos_psp_set_file_table(fd, fd, current_psp); ! 12688: ! 12689: strcpy(path, tmp); ! 12690: int dx = REG16(DX) + len; ! 12691: int ds = SREG(DS); ! 12692: while(dx > 0xffff) { ! 12693: dx -= 0x10; ! 12694: ds++; ! 12695: } ! 12696: REG16(DX) = dx; ! 12697: SREG(DS) = ds; ! 12698: i386_load_segment_descriptor(DS); ! 12699: } else { ! 12700: REG16(AX) = (UINT16)GetLastError(); ! 12701: m_CF = 1; ! 12702: } ! 12703: } ! 12704: ! 12705: inline void msdos_int_21h_5bh() ! 12706: { ! 12707: const char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0); ! 12708: ! 12709: if(msdos_is_device_path(path) || msdos_is_existing_file(path)) { ! 12710: // already exists ! 12711: REG16(AX) = 0x50; ! 12712: m_CF = 1; ! 12713: } else { ! 12714: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE); ! 12715: ! 12716: if(fd != -1) { ! 12717: SetFileAttributesA(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY); ! 12718: REG16(AX) = fd; ! 12719: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp); ! 12720: msdos_psp_set_file_table(fd, fd, current_psp); ! 12721: } else { ! 12722: REG16(AX) = errno; ! 12723: m_CF = 1; ! 12724: } ! 12725: } ! 12726: } ! 12727: ! 12728: inline void msdos_int_21h_5ch() ! 12729: { ! 12730: process_t *process = msdos_process_info_get(current_psp); ! 12731: int fd = msdos_psp_get_file_table(REG16(BX), current_psp); ! 12732: ! 12733: if(fd < process->max_files && file_handler[fd].valid) { ! 12734: if(REG8(AL) == 0 || REG8(AL) == 1) { ! 12735: static const int modes[2] = {_LK_LOCK, _LK_UNLCK}; ! 12736: UINT32 pos = _tell(fd); ! 12737: _lseek(fd, (REG16(CX) << 16) | REG16(DX), SEEK_SET); ! 12738: if(_locking(fd, modes[REG8(AL)], (REG16(SI) << 16) | REG16(DI))) { ! 12739: REG16(AX) = errno; ! 12740: m_CF = 1; ! 12741: } ! 12742: _lseek(fd, pos, SEEK_SET); ! 12743: ! 12744: // some seconds may be passed in _locking() ! 12745: REQUEST_HARDWRE_UPDATE(); ! 12746: } else { ! 12747: REG16(AX) = 0x01; ! 12748: m_CF = 1; ! 12749: } ! 12750: } else { ! 12751: REG16(AX) = 0x06; ! 12752: m_CF = 1; ! 12753: } ! 12754: } ! 12755: ! 12756: inline void msdos_int_21h_5dh() ! 12757: { ! 12758: switch(REG8(AL)) { ! 12759: case 0x00: // DOS 3.1+ internal - Server Function Call ! 12760: if(*(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x12) == 0x0000) { ! 12761: // current system ! 12762: static bool reenter = false; ! 12763: if(!reenter) { ! 12764: UINT32 offset = SREG_BASE(DS) + REG16(DX); ! 12765: REG16(AX) = *(UINT16 *)(mem + offset + 0x00); ! 12766: REG16(BX) = *(UINT16 *)(mem + offset + 0x02); ! 12767: REG16(CX) = *(UINT16 *)(mem + offset + 0x04); ! 12768: REG16(DX) = *(UINT16 *)(mem + offset + 0x06); ! 12769: REG16(SI) = *(UINT16 *)(mem + offset + 0x08); ! 12770: REG16(DI) = *(UINT16 *)(mem + offset + 0x0a); ! 12771: SREG(DS) = *(UINT16 *)(mem + offset + 0x0c); ! 12772: SREG(ES) = *(UINT16 *)(mem + offset + 0x0e); ! 12773: i386_load_segment_descriptor(DS); ! 12774: i386_load_segment_descriptor(ES); ! 12775: reenter = true; ! 12776: try { ! 12777: msdos_syscall(0x21); ! 12778: } catch(...) { ! 12779: } ! 12780: reenter = false; ! 12781: } ! 12782: } else { ! 12783: REG16(AX) = 0x49; // network software not installed ! 12784: m_CF = 1; ! 12785: } ! 12786: break; ! 12787: // case 0x01: // DOS 3.1+ internal - Commit All Files For Specified Computer/Process ! 12788: // case 0x02: // DOS 3.1+ internal - SHARE.EXE - Close File By Name ! 12789: // case 0x03: // DOS 3.1+ internal - SHARE.EXE - Close ALL Files For Given Computer ! 12790: // case 0x04: // DOS 3.1+ internal - SHARE.EXE - Close ALL Files For Given Process ! 12791: // case 0x05: // DOS 3.1+ internal - SHARE.EXE - Get Open File List Entry ! 12792: case 0x06: // DOS 3.0+ internal - Get Address Of DOS Swappable Data Area ! 12793: SREG(DS) = (SDA_TOP >> 4); ! 12794: i386_load_segment_descriptor(DS); ! 12795: REG16(SI) = offsetof(sda_t, crit_error_flag); ! 12796: REG16(CX) = 0x80; ! 12797: REG16(DX) = 0x1a; ! 12798: break; ! 12799: case 0x07: // DOS 3.1+ network - Get Redirected Printer Mode ! 12800: case 0x08: // DOS 3.1+ network - Set Redirected Printer Mode ! 12801: case 0x09: // DOS 3.1+ network - Flush Redirected Printer Output ! 12802: REG16(AX) = 0x49; // network software not installed ! 12803: m_CF = 1; ! 12804: break; ! 12805: case 0x0a: // DOS 3.1+ - Set Extended Error Information ! 12806: { ! 12807: sda_t *sda = (sda_t *)(mem + SDA_TOP); ! 12808: sda->int21h_5d0ah_called = 1; ! 12809: sda->extended_error_code = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x00); // AX ! 12810: // XXX: which one is correct ??? ! 12811: #if 1 ! 12812: // Ralf Brown's Interrupt List and DR-DOS System and Programmer's Guide ! 12813: sda->suggested_action = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02); // BL ! 12814: sda->error_class = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x03); // BH ! 12815: sda->int21h_5d0ah_cl = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x04); // CL ! 12816: sda->locus_of_last_error = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x05); // CH ! 12817: #else ! 12818: // PC DOS 7 Technical Update ! 12819: sda->error_class = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02); // BH ! 12820: sda->suggested_action = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x03); // BL ! 12821: sda->locus_of_last_error = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x04); // CH ! 12822: sda->int21h_5d0ah_cl = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x05); // CL ! 12823: #endif ! 12824: sda->int21h_5d0ah_dx = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x06); // DX ! 12825: // sda->int21h_5d0ah_si = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x08); // SI ! 12826: sda->last_error_pointer.w.l = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0a); // DI ! 12827: // sda->int21h_5d0ah_ds = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0c); // DS ! 12828: sda->last_error_pointer.w.h = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e); // ES ! 12829: } ! 12830: break; ! 12831: case 0x0b: // DOS 4.x only - internal - Get DOS Swappable Data Areas ! 12832: REG16(AX) = 0x01; ! 12833: m_CF = 1; ! 12834: break; ! 12835: default: ! 12836: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 12837: REG16(AX) = 0x01; ! 12838: m_CF = 1; ! 12839: break; ! 12840: } ! 12841: } ! 12842: ! 12843: inline void msdos_int_21h_5eh() ! 12844: { ! 12845: switch(REG8(AL)) { ! 12846: case 0x00: // DOS 3.1+ network - Get Machine Name ! 12847: { ! 12848: char name[256] = {0}; ! 12849: DWORD dwSize = 256; ! 12850: ! 12851: if(GetComputerNameA(name, &dwSize)) { ! 12852: char *dest = (char *)(mem + SREG_BASE(DS) + REG16(DX)); ! 12853: for(int i = 0; i < 15; i++) { ! 12854: dest[i] = (i < strlen(name)) ? name[i] : ' '; ! 12855: } ! 12856: dest[15] = '\0'; ! 12857: REG8(CH) = 0x01; // nonzero valid ! 12858: REG8(CL) = 0x01; // NetBIOS number for machine name ??? ! 12859: } else { ! 12860: REG16(AX) = 0x01; ! 12861: m_CF = 1; ! 12862: } ! 12863: } ! 12864: break; ! 12865: // case 0x01: // DOS 3.1+ network - Set Machine Name ! 12866: // case 0x02: // DOS 3.1+ network - Set Network Printer Setup String ! 12867: // case 0x03: // DOS 3.1+ network - Get Network Printer Setup String ! 12868: // case 0x04: // DOS 3.1+ network - Set Printer Mode ! 12869: // case 0x05: // DOS 3.1+ network - Get Printer Mode ! 12870: default: ! 12871: // unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 12872: // REG16(AX) = 0x01; ! 12873: REG16(AX) = 0x49; // network software not installed ! 12874: m_CF = 1; ! 12875: break; ! 12876: } ! 12877: } ! 12878: ! 12879: inline void msdos_int_21h_5fh() ! 12880: { ! 12881: switch(REG8(AL)) { ! 12882: // case 0x00: // DOS 3.1+ network - Get Redirection Mode ! 12883: // case 0x01: // DOS 3.1+ network - Set Redirection Mode ! 12884: case 0x05: // DOS 4.0+ network - Get Extended Redirection List Entry ! 12885: REG16(BP) = 0; ! 12886: for(int i = 0; i < 26; i++) { ! 12887: if(msdos_is_remote_drive(i)) { ! 12888: REG16(BP)++; ! 12889: } ! 12890: } ! 12891: case 0x02: // DOS 3.1+ network - Get Redirection List Entry ! 12892: for(int i = 0, index = 0; i < 26; i++) { ! 12893: if(msdos_is_remote_drive(i)) { ! 12894: if(index == REG16(BX)) { ! 12895: char volume[] = "A:"; ! 12896: volume[0] = 'A' + i; ! 12897: DWORD dwSize = 128; ! 12898: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), volume); ! 12899: WNetGetConnectionA(volume, (char *)(mem + SREG_BASE(ES) + REG16(DI)), &dwSize); ! 12900: REG8(BH) = 0x00; // valid ! 12901: REG8(BL) = 0x04; // disk drive ! 12902: REG16(CX) = 0x00; // LANtastic ! 12903: return; ! 12904: } ! 12905: index++; ! 12906: } ! 12907: } ! 12908: REG16(AX) = 0x12; // no more files ! 12909: m_CF = 1; ! 12910: break; ! 12911: // case 0x03: // DOS 3.1+ network - Redirect Device ! 12912: // case 0x04: // DOS 3.1+ network - Cancel Redirection ! 12913: // case 0x06: // Network - Get Full Redirection List ! 12914: case 0x07: // DOS 5+ - Enable Drive ! 12915: if(msdos_is_valid_drive(REG8(DL))) { ! 12916: msdos_cds_update(REG8(DL)); ! 12917: } else { ! 12918: REG16(AX) = 0x0f; // invalid drive ! 12919: m_CF = 1; ! 12920: } ! 12921: break; ! 12922: case 0x08: // DOS 5+ - Disable Drive ! 12923: if(msdos_is_valid_drive(REG8(DL))) { ! 12924: cds_t *cds = (cds_t *)(mem + CDS_TOP + 88 * REG8(DL)); ! 12925: cds->drive_attrib = 0x0000; ! 12926: } else { ! 12927: REG16(AX) = 0x0f; // invalid drive ! 12928: m_CF = 1; ! 12929: } ! 12930: break; ! 12931: default: ! 12932: // unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 12933: // REG16(AX) = 0x01; ! 12934: REG16(AX) = 0x49; // network software not installed ! 12935: m_CF = 1; ! 12936: break; ! 12937: } ! 12938: } ! 12939: ! 12940: inline void msdos_int_21h_60h(int lfn) ! 12941: { ! 12942: char full[MAX_PATH]; ! 12943: const char *path = NULL; ! 12944: ! 12945: if(lfn) { ! 12946: char *name; ! 12947: *full = '\0'; ! 12948: GetFullPathNameA((char *)(mem + SREG_BASE(DS) + REG16(SI)), MAX_PATH, full, &name); ! 12949: switch(REG8(CL)) { ! 12950: case 1: ! 12951: GetShortPathNameA(full, full, MAX_PATH); ! 12952: my_strupr(full); ! 12953: break; ! 12954: case 2: ! 12955: GetLongPathNameA(full, full, MAX_PATH); ! 12956: break; ! 12957: } ! 12958: path = full; ! 12959: } else { ! 12960: path = msdos_short_full_path((char *)(mem + SREG_BASE(DS) + REG16(SI))); ! 12961: } ! 12962: if(*path != '\0') { ! 12963: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path); ! 12964: } else { ! 12965: REG16(AX) = (UINT16)GetLastError(); ! 12966: m_CF = 1; ! 12967: } ! 12968: } ! 12969: ! 12970: inline void msdos_int_21h_61h() ! 12971: { ! 12972: REG8(AL) = 0; ! 12973: } ! 12974: ! 12975: inline void msdos_int_21h_62h() ! 12976: { ! 12977: REG16(BX) = current_psp; ! 12978: } ! 12979: ! 12980: inline void msdos_int_21h_63h() ! 12981: { ! 12982: switch(REG8(AL)) { ! 12983: case 0x00: ! 12984: SREG(DS) = (DBCS_TABLE >> 4); ! 12985: i386_load_segment_descriptor(DS); ! 12986: REG16(SI) = (DBCS_TABLE & 0x0f); ! 12987: REG8(AL) = 0x00; ! 12988: break; ! 12989: case 0x01: // set korean input mode ! 12990: case 0x02: // get korean input mode ! 12991: REG8(AL) = 0xff; // not supported ! 12992: break; ! 12993: default: ! 12994: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 12995: REG16(AX) = 0x01; ! 12996: m_CF = 1; ! 12997: break; ! 12998: } ! 12999: } ! 13000: ! 13001: UINT16 get_extended_country_info(UINT8 func) ! 13002: { ! 13003: switch(func) { ! 13004: case 0x01: ! 13005: if(REG16(CX) >= 5) { ! 13006: UINT8 data[1 + 2 + 2 + 2 + sizeof(country_info_t)]; ! 13007: if(REG16(CX) > sizeof(data)) // cx = actual transfer size ! 13008: REG16(CX) = sizeof(data); ! 13009: ZeroMemory(data, sizeof(data)); ! 13010: data[0] = 0x01; ! 13011: *(UINT16 *)(data + 1) = REG16(CX) - 3; ! 13012: *(UINT16 *)(data + 3) = get_country_info((country_info_t*)(data + 7)); ! 13013: *(UINT16 *)(data + 5) = active_code_page; ! 13014: memcpy(mem + SREG_BASE(ES) + REG16(DI), data, REG16(CX)); ! 13015: // REG16(AX) = active_code_page; ! 13016: } else { ! 13017: return(0x08); // insufficient memory ! 13018: } ! 13019: break; ! 13020: case 0x02: ! 13021: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02; ! 13022: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (UPPERTABLE_TOP & 0x0f); ! 13023: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (UPPERTABLE_TOP >> 4); ! 13024: // REG16(AX) = active_code_page; ! 13025: REG16(CX) = 0x05; ! 13026: break; ! 13027: case 0x03: ! 13028: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02; ! 13029: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (LOWERTABLE_TOP & 0x0f); ! 13030: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (LOWERTABLE_TOP >> 4); ! 13031: // REG16(AX) = active_code_page; ! 13032: REG16(CX) = 0x05; ! 13033: break; ! 13034: case 0x04: ! 13035: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x04; ! 13036: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_UPPERTABLE_TOP & 0x0f); ! 13037: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_UPPERTABLE_TOP >> 4); ! 13038: // REG16(AX) = active_code_page; ! 13039: REG16(CX) = 0x05; ! 13040: break; ! 13041: case 0x05: ! 13042: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x05; ! 13043: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_TERMINATOR_TOP & 0x0f); ! 13044: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_TERMINATOR_TOP >> 4); ! 13045: // REG16(AX) = active_code_page; ! 13046: REG16(CX) = 0x05; ! 13047: break; ! 13048: case 0x06: ! 13049: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x06; ! 13050: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (COLLATING_TABLE_TOP & 0x0f); ! 13051: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (COLLATING_TABLE_TOP >> 4); ! 13052: // REG16(AX) = active_code_page; ! 13053: REG16(CX) = 0x05; ! 13054: break; ! 13055: case 0x07: ! 13056: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x07; ! 13057: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (DBCS_TOP & 0x0f); ! 13058: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (DBCS_TOP >> 4); ! 13059: // REG16(AX) = active_code_page; ! 13060: REG16(CX) = 0x05; ! 13061: break; ! 13062: default: ! 13063: return(0x01); // function number invalid ! 13064: } ! 13065: return(0x00); ! 13066: } ! 13067: ! 13068: inline void msdos_int_21h_65h() ! 13069: { ! 13070: char tmp[0x10000]; ! 13071: ! 13072: switch(REG8(AL)) { ! 13073: case 0x00: ! 13074: if(REG16(CX) >= 7) { ! 13075: set_country_info((country_info_t *)(mem + SREG_BASE(ES) + REG16(DI)), REG16(CX) - 7); ! 13076: REG16(AX) = system_code_page; ! 13077: } else { ! 13078: REG16(AX) = 0x0c; ! 13079: m_CF = 1; ! 13080: } ! 13081: break; ! 13082: case 0x01: ! 13083: case 0x02: ! 13084: case 0x03: ! 13085: case 0x04: ! 13086: case 0x05: ! 13087: case 0x06: ! 13088: case 0x07: ! 13089: { ! 13090: UINT16 result = get_extended_country_info(REG8(AL)); ! 13091: if(result) { ! 13092: REG16(AX) = result; ! 13093: m_CF = 1; ! 13094: } else { ! 13095: REG16(AX) = active_code_page; // FIXME: is this correct??? ! 13096: } ! 13097: } ! 13098: break; ! 13099: case 0x20: ! 13100: case 0xa0: ! 13101: memset(tmp, 0, sizeof(tmp)); ! 13102: tmp[0] = REG8(DL); ! 13103: my_strupr(tmp); ! 13104: REG8(DL) = tmp[0]; ! 13105: break; ! 13106: case 0x21: ! 13107: case 0xa1: ! 13108: memset(tmp, 0, sizeof(tmp)); ! 13109: memcpy(tmp, mem + SREG_BASE(DS) + REG16(DX), REG16(CX)); ! 13110: my_strupr(tmp); ! 13111: memcpy(mem + SREG_BASE(DS) + REG16(DX), tmp, REG16(CX)); ! 13112: break; ! 13113: case 0x22: ! 13114: case 0xa2: ! 13115: my_strupr((char *)(mem + SREG_BASE(DS) + REG16(DX))); ! 13116: break; ! 13117: case 0x23: ! 13118: // FIXME: need to check multi-byte (kanji) charactre? ! 13119: if(REG8(DL) == 'N' || REG8(DL) == 'n' || (REG8(DL) == 0x82 && REG8(DH) == 0x6d) || (REG8(DL) == 0x82 && REG8(DH) == 0x8e)) { ! 13120: // 826dh/828eh: multi-byte (kanji) N and n ! 13121: REG16(AX) = 0x00; ! 13122: } else if(REG8(DL) == 'Y' || REG8(DL) == 'y' || (REG8(DL) == 0x82 && REG8(DH) == 0x78) || (REG8(DL) == 0x82 && REG8(DH) == 0x99)) { ! 13123: // 8278h/8299h: multi-byte (kanji) Y and y ! 13124: REG16(AX) = 0x01; ! 13125: } else { ! 13126: REG16(AX) = 0x02; ! 13127: } ! 13128: break; ! 13129: default: ! 13130: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 13131: REG16(AX) = 0x01; ! 13132: m_CF = 1; ! 13133: break; ! 13134: } ! 13135: } ! 13136: ! 13137: inline void msdos_int_21h_66h() ! 13138: { ! 13139: switch(REG8(AL)) { ! 13140: case 0x01: ! 13141: REG16(BX) = active_code_page; ! 13142: REG16(DX) = system_code_page; ! 13143: break; ! 13144: case 0x02: ! 13145: if(active_code_page == REG16(BX)) { ! 13146: REG16(AX) = 0xeb41; ! 13147: } else if(_setmbcp(REG16(BX)) == 0) { ! 13148: active_code_page = REG16(BX); ! 13149: msdos_nls_tables_update(); ! 13150: REG16(AX) = 0xeb41; ! 13151: SetConsoleCP(active_code_page); ! 13152: SetConsoleOutputCP(active_code_page); ! 13153: } else { ! 13154: REG16(AX) = 0x25; ! 13155: m_CF = 1; ! 13156: } ! 13157: break; ! 13158: default: ! 13159: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 13160: REG16(AX) = 0x01; ! 13161: m_CF = 1; ! 13162: break; ! 13163: } ! 13164: } ! 13165: ! 13166: inline void msdos_int_21h_67h() ! 13167: { ! 13168: process_t *process = msdos_process_info_get(current_psp); ! 13169: ! 13170: if(REG16(BX) <= MAX_FILES) { ! 13171: process->max_files = max(REG16(BX), 20); ! 13172: } else { ! 13173: REG16(AX) = 0x08; ! 13174: m_CF = 1; ! 13175: } ! 13176: } ! 13177: ! 13178: inline void msdos_int_21h_68h() ! 13179: { ! 13180: process_t *process = msdos_process_info_get(current_psp); ! 13181: int fd = msdos_psp_get_file_table(REG16(BX), current_psp); ! 13182: ! 13183: if(fd < process->max_files && file_handler[fd].valid) { ! 13184: // fflush(_fdopen(fd, "")); ! 13185: } else { ! 13186: REG16(AX) = 0x06; ! 13187: m_CF = 1; ! 13188: } ! 13189: } ! 13190: ! 13191: inline void msdos_int_21h_69h() ! 13192: { ! 13193: drive_info_t *info = (drive_info_t *)(mem + SREG_BASE(DS) + REG16(DX)); ! 13194: char path[] = "A:\\"; ! 13195: char volume_label[MAX_PATH]; ! 13196: DWORD serial_number = 0; ! 13197: char file_system[MAX_PATH]; ! 13198: ! 13199: if(REG8(BL) == 0) { ! 13200: path[0] = 'A' + _getdrive() - 1; ! 13201: } else { ! 13202: path[0] = 'A' + REG8(BL) - 1; ! 13203: } ! 13204: ! 13205: switch(REG8(AL)) { ! 13206: case 0x00: ! 13207: if(GetVolumeInformationA(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) { ! 13208: info->info_level = 0; ! 13209: info->serial_number = serial_number; ! 13210: memset(info->volume_label, 0x20, 11); ! 13211: memcpy(info->volume_label, volume_label, min(strlen(volume_label), 11)); ! 13212: memset(info->file_system, 0x20, 8); ! 13213: memcpy(info->file_system, file_system, min(strlen(file_system), 8)); ! 13214: } else { ! 13215: REG16(AX) = errno; ! 13216: m_CF = 1; ! 13217: } ! 13218: break; ! 13219: case 0x01: ! 13220: REG16(AX) = 0x03; ! 13221: m_CF = 1; ! 13222: break; ! 13223: default: ! 13224: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 13225: REG16(AX) = 0x01; ! 13226: m_CF = 1; ! 13227: break; ! 13228: } ! 13229: } ! 13230: ! 13231: inline void msdos_int_21h_6ah() ! 13232: { ! 13233: REG8(AH) = 0x68; ! 13234: msdos_int_21h_68h(); ! 13235: } ! 13236: ! 13237: inline void msdos_int_21h_6bh() ! 13238: { ! 13239: REG8(AL) = 0x00; ! 13240: } ! 13241: ! 13242: inline void msdos_int_21h_6ch(int lfn) ! 13243: { ! 13244: const char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn); ! 13245: int mode = REG8(BL) & 0x03; ! 13246: ! 13247: if(mode < 0x03) { ! 13248: if(msdos_is_device_path(path) || msdos_is_existing_file(path)) { ! 13249: // file exists ! 13250: if(REG8(DL) & 1) { ! 13251: int fd = -1; ! 13252: int sio_port = 0; ! 13253: int lpt_port = 0; ! 13254: ! 13255: if(msdos_is_device_path(path)) { ! 13256: fd = msdos_open_device(path, file_mode[mode].mode, &sio_port, &lpt_port); ! 13257: } else { ! 13258: fd = msdos_open(path, file_mode[mode].mode); ! 13259: } ! 13260: if(fd != -1) { ! 13261: REG16(AX) = fd; ! 13262: REG16(CX) = 1; ! 13263: msdos_file_handler_open(fd, path, _isatty(fd), mode, msdos_device_info(path), current_psp, sio_port, lpt_port); ! 13264: msdos_psp_set_file_table(fd, fd, current_psp); ! 13265: } else { ! 13266: REG16(AX) = errno; ! 13267: m_CF = 1; ! 13268: } ! 13269: } else if(REG8(DL) & 2) { ! 13270: int attr = GetFileAttributesA(path); ! 13271: int fd = -1; ! 13272: int sio_port = 0; ! 13273: int lpt_port = 0; ! 13274: ! 13275: if(msdos_is_device_path(path)) { ! 13276: fd = msdos_open_device(path, file_mode[mode].mode, &sio_port, &lpt_port); ! 13277: } else { ! 13278: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE); ! 13279: } ! 13280: if(fd != -1) { ! 13281: if(attr == -1) { ! 13282: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY; ! 13283: } ! 13284: SetFileAttributesA(path, attr); ! 13285: REG16(AX) = fd; ! 13286: REG16(CX) = 3; ! 13287: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_device_info(path), current_psp, sio_port, lpt_port); ! 13288: msdos_psp_set_file_table(fd, fd, current_psp); ! 13289: } else { ! 13290: REG16(AX) = errno; ! 13291: m_CF = 1; ! 13292: } ! 13293: } else { ! 13294: REG16(AX) = 0x50; ! 13295: m_CF = 1; ! 13296: } ! 13297: } else { ! 13298: // file not exists ! 13299: if(REG8(DL) & 0x10) { ! 13300: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE); ! 13301: ! 13302: if(fd != -1) { ! 13303: SetFileAttributesA(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY); ! 13304: REG16(AX) = fd; ! 13305: REG16(CX) = 2; ! 13306: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp); ! 13307: msdos_psp_set_file_table(fd, fd, current_psp); ! 13308: } else { ! 13309: REG16(AX) = errno; ! 13310: m_CF = 1; ! 13311: } ! 13312: } else { ! 13313: REG16(AX) = 0x02; ! 13314: m_CF = 1; ! 13315: } ! 13316: } ! 13317: } else { ! 13318: REG16(AX) = 0x0c; ! 13319: m_CF = 1; ! 13320: } ! 13321: } ! 13322: ! 13323: inline void msdos_int_21h_70h() ! 13324: { ! 13325: switch(REG8(AL)) { ! 13326: case 0x00: // get ??? info ! 13327: case 0x01: // set above info ! 13328: // unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 13329: REG16(AX) = 0x7000; ! 13330: m_CF = 1; ! 13331: break; ! 13332: case 0x02: // set general internationalization info ! 13333: if(REG16(CX) >= 7) { ! 13334: active_code_page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 5); ! 13335: msdos_nls_tables_update(); ! 13336: set_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(SI) + 7), REG16(CX) - 7); ! 13337: REG16(AX) = system_code_page; ! 13338: } else { ! 13339: REG16(AX) = 0x0c; ! 13340: m_CF = 1; ! 13341: } ! 13342: break; ! 13343: default: ! 13344: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 13345: REG16(AX) = 0x7000; ! 13346: m_CF = 1; ! 13347: break; ! 13348: } ! 13349: } ! 13350: ! 13351: inline void msdos_int_21h_710dh() ! 13352: { ! 13353: // reset drive ! 13354: } ! 13355: ! 13356: inline void msdos_int_21h_7141h() ! 13357: { ! 13358: if(REG16(SI) == 0) { ! 13359: msdos_int_21h_41h(1); ! 13360: return; ! 13361: } ! 13362: if(REG16(SI) != 1) { ! 13363: REG16(AX) = 5; ! 13364: m_CF = 1; ! 13365: } ! 13366: /* wild card and matching attributes... */ ! 13367: char tmp[MAX_PATH * 2]; ! 13368: // copy search pathname (and quick check overrun) ! 13369: ZeroMemory(tmp, sizeof(tmp)); ! 13370: tmp[MAX_PATH - 1] = '\0'; ! 13371: tmp[MAX_PATH] = 1; ! 13372: strncpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(DX)), MAX_PATH); ! 13373: ! 13374: if(tmp[MAX_PATH - 1] != '\0' || tmp[MAX_PATH] != 1) { ! 13375: REG16(AX) = 1; ! 13376: m_CF = 1; ! 13377: return; ! 13378: } ! 13379: for(char *s = tmp; *s; ++s) { ! 13380: if(*s == '/') { ! 13381: *s = '\\'; ! 13382: } ! 13383: } ! 13384: char *tmp_name = my_strrchr(tmp, '\\'); ! 13385: if(tmp_name) { ! 13386: ++tmp_name; ! 13387: } else { ! 13388: tmp_name = strchr(tmp, ':'); ! 13389: tmp_name = tmp_name ? tmp_name + 1 : tmp; ! 13390: } ! 13391: ! 13392: WIN32_FIND_DATAA fd; ! 13393: HANDLE fh = FindFirstFileA(tmp, &fd); ! 13394: if(fh == INVALID_HANDLE_VALUE) { ! 13395: REG16(AX) = 2; ! 13396: m_CF = 1; ! 13397: return; ! 13398: } ! 13399: do { ! 13400: if(msdos_find_file_check_attribute(fd.dwFileAttributes, REG8(CL), REG8(CH)) && msdos_find_file_has_8dot3name(&fd)) { ! 13401: strcpy(tmp_name, fd.cFileName); ! 13402: if(remove(msdos_trimmed_path(tmp, 1))) { ! 13403: REG16(AX) = 5; ! 13404: m_CF = 1; ! 13405: break; ! 13406: } ! 13407: } ! 13408: } while(FindNextFileA(fh, &fd)); ! 13409: if(!m_CF) { ! 13410: if(GetLastError() != ERROR_NO_MORE_FILES) { ! 13411: m_CF = 1; ! 13412: REG16(AX) = 2; ! 13413: } ! 13414: } ! 13415: FindClose(fh); ! 13416: } ! 13417: ! 13418: inline void msdos_int_21h_714eh() ! 13419: { ! 13420: process_t *process = msdos_process_info_get(current_psp); ! 13421: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI)); ! 13422: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX)); ! 13423: WIN32_FIND_DATAA fd; ! 13424: ! 13425: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR); ! 13426: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) { ! 13427: FindClose(dtainfo->find_handle); ! 13428: dtainfo->find_handle = INVALID_HANDLE_VALUE; ! 13429: } ! 13430: strcpy(process->volume_label, msdos_volume_label(path)); ! 13431: dtainfo->allowable_mask = REG8(CL); ! 13432: dtainfo->required_mask = REG8(CH); ! 13433: bool label_only = (dtainfo->allowable_mask == 8); ! 13434: ! 13435: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) { ! 13436: dtainfo->allowable_mask &= ~8; ! 13437: } ! 13438: if(!label_only && (dtainfo->find_handle = FindFirstFileA(path, &fd)) != INVALID_HANDLE_VALUE) { ! 13439: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) { ! 13440: if(!FindNextFileA(dtainfo->find_handle, &fd)) { ! 13441: FindClose(dtainfo->find_handle); ! 13442: dtainfo->find_handle = INVALID_HANDLE_VALUE; ! 13443: break; ! 13444: } ! 13445: } ! 13446: } ! 13447: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) { ! 13448: find->attrib = fd.dwFileAttributes; ! 13449: msdos_find_file_conv_local_time(&fd); ! 13450: if(REG16(SI) == 0) { ! 13451: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime; ! 13452: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime; ! 13453: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime; ! 13454: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime; ! 13455: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime; ! 13456: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime; ! 13457: } else { ! 13458: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l); ! 13459: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l); ! 13460: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l); ! 13461: } ! 13462: find->size_hi = fd.nFileSizeHigh; ! 13463: find->size_lo = fd.nFileSizeLow; ! 13464: strcpy(find->full_name, fd.cFileName); ! 13465: strcpy(find->short_name, fd.cAlternateFileName); ! 13466: REG16(AX) = dtainfo - dtalist + 1; ! 13467: } else if(dtainfo->allowable_mask & 8) { ! 13468: // volume label ! 13469: find->attrib = 8; ! 13470: find->size_hi = find->size_lo = 0; ! 13471: strcpy(find->full_name, process->volume_label); ! 13472: strcpy(find->short_name, msdos_short_volume_label(process->volume_label)); ! 13473: dtainfo->allowable_mask &= ~8; ! 13474: REG16(AX) = dtainfo - dtalist + 1; ! 13475: } else { ! 13476: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid ! 13477: m_CF = 1; ! 13478: } ! 13479: } ! 13480: ! 13481: inline void msdos_int_21h_714fh() ! 13482: { ! 13483: process_t *process = msdos_process_info_get(current_psp); ! 13484: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI)); ! 13485: WIN32_FIND_DATAA fd; ! 13486: ! 13487: if(REG16(BX) - 1u >= MAX_DTAINFO) { ! 13488: REG16(AX) = 6; ! 13489: m_CF = 1; ! 13490: return; ! 13491: } ! 13492: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1]; ! 13493: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) { ! 13494: if(FindNextFileA(dtainfo->find_handle, &fd)) { ! 13495: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) { ! 13496: if(!FindNextFileA(dtainfo->find_handle, &fd)) { ! 13497: FindClose(dtainfo->find_handle); ! 13498: dtainfo->find_handle = INVALID_HANDLE_VALUE; ! 13499: break; ! 13500: } ! 13501: } ! 13502: } else { ! 13503: FindClose(dtainfo->find_handle); ! 13504: dtainfo->find_handle = INVALID_HANDLE_VALUE; ! 13505: } ! 13506: } ! 13507: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) { ! 13508: find->attrib = fd.dwFileAttributes; ! 13509: msdos_find_file_conv_local_time(&fd); ! 13510: if(REG16(SI) == 0) { ! 13511: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime; ! 13512: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime; ! 13513: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime; ! 13514: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime; ! 13515: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime; ! 13516: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime; ! 13517: } else { ! 13518: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l); ! 13519: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l); ! 13520: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l); ! 13521: } ! 13522: find->size_hi = fd.nFileSizeHigh; ! 13523: find->size_lo = fd.nFileSizeLow; ! 13524: strcpy(find->full_name, fd.cFileName); ! 13525: strcpy(find->short_name, fd.cAlternateFileName); ! 13526: } else if(dtainfo->allowable_mask & 8) { ! 13527: // volume label ! 13528: find->attrib = 8; ! 13529: find->size_hi = find->size_lo = 0; ! 13530: strcpy(find->full_name, process->volume_label); ! 13531: strcpy(find->short_name, msdos_short_volume_label(process->volume_label)); ! 13532: dtainfo->allowable_mask &= ~8; ! 13533: } else { ! 13534: REG16(AX) = 0x12; ! 13535: m_CF = 1; ! 13536: } ! 13537: } ! 13538: ! 13539: inline void msdos_int_21h_71a0h() ! 13540: { ! 13541: DWORD max_component_len, file_sys_flag; ! 13542: ! 13543: if(GetVolumeInformationA((char *)(mem + SREG_BASE(DS) + REG16(DX)), NULL, 0, NULL, &max_component_len, &file_sys_flag, REG16(CX) == 0 ? NULL : (char *)(mem + SREG_BASE(ES) + REG16(DI)), REG16(CX))) { ! 13544: REG16(BX) = (UINT16)file_sys_flag & (FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_VOLUME_IS_COMPRESSED); ! 13545: REG16(BX) |= 0x4000; // supports LFN functions ! 13546: REG16(CX) = (UINT16)max_component_len; // 255 ! 13547: REG16(DX) = (UINT16)max_component_len + 5; // 260 ! 13548: } else { ! 13549: REG16(AX) = (UINT16)GetLastError(); ! 13550: m_CF = 1; ! 13551: } ! 13552: } ! 13553: ! 13554: inline void msdos_int_21h_71a1h() ! 13555: { ! 13556: if(REG16(BX) - 1u >= MAX_DTAINFO) { ! 13557: REG16(AX) = 6; ! 13558: m_CF = 1; ! 13559: return; ! 13560: } ! 13561: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1]; ! 13562: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) { ! 13563: FindClose(dtainfo->find_handle); ! 13564: dtainfo->find_handle = INVALID_HANDLE_VALUE; ! 13565: } ! 13566: } ! 13567: ! 13568: inline void msdos_int_21h_71a6h() ! 13569: { ! 13570: process_t *process = msdos_process_info_get(current_psp); ! 13571: int fd = msdos_psp_get_file_table(REG16(BX), current_psp); ! 13572: ! 13573: UINT8 *buffer = (UINT8 *)(mem + SREG_BASE(DS) + REG16(DX)); ! 13574: struct _stat64 status; ! 13575: DWORD serial_number = 0; ! 13576: ! 13577: if(fd < process->max_files && file_handler[fd].valid) { ! 13578: if(_fstat64(fd, &status) == 0) { ! 13579: if(file_handler[fd].path[1] == ':') { ! 13580: // NOTE: we need to consider the network file path "\\host\share\" ! 13581: char volume[] = "A:\\"; ! 13582: volume[0] = file_handler[fd].path[1]; ! 13583: GetVolumeInformationA(volume, NULL, 0, &serial_number, NULL, NULL, NULL, 0); ! 13584: } ! 13585: *(UINT32 *)(buffer + 0x00) = GetFileAttributesA(file_handler[fd].path); ! 13586: *(UINT32 *)(buffer + 0x04) = (UINT32)(status.st_ctime & 0xffffffff); ! 13587: *(UINT32 *)(buffer + 0x08) = (UINT32)((status.st_ctime >> 32) & 0xffffffff); ! 13588: *(UINT32 *)(buffer + 0x0c) = (UINT32)(status.st_atime & 0xffffffff); ! 13589: *(UINT32 *)(buffer + 0x10) = (UINT32)((status.st_atime >> 32) & 0xffffffff); ! 13590: *(UINT32 *)(buffer + 0x14) = (UINT32)(status.st_mtime & 0xffffffff); ! 13591: *(UINT32 *)(buffer + 0x18) = (UINT32)((status.st_mtime >> 32) & 0xffffffff); ! 13592: *(UINT32 *)(buffer + 0x1c) = serial_number; ! 13593: *(UINT32 *)(buffer + 0x20) = (UINT32)((status.st_size >> 32) & 0xffffffff); ! 13594: *(UINT32 *)(buffer + 0x24) = (UINT32)(status.st_size & 0xffffffff); ! 13595: *(UINT32 *)(buffer + 0x28) = status.st_nlink; ! 13596: // this is dummy id and it will be changed when it is reopened... ! 13597: *(UINT32 *)(buffer + 0x2c) = 0; ! 13598: *(UINT32 *)(buffer + 0x30) = file_handler[fd].id; ! 13599: } else { ! 13600: REG16(AX) = errno; ! 13601: m_CF = 1; ! 13602: } ! 13603: } else { ! 13604: REG16(AX) = 0x06; ! 13605: m_CF = 1; ! 13606: } ! 13607: } ! 13608: ! 13609: inline void msdos_int_21h_71a7h() ! 13610: { ! 13611: switch(REG8(BL)) { ! 13612: case 0x00: ! 13613: if(!FileTimeToDosDateTime((FILETIME *)(mem + SREG_BASE(DS) + REG16(SI)), ®16(DX), ®16(CX))) { ! 13614: REG16(AX) = (UINT16)GetLastError(); ! 13615: m_CF = 1; ! 13616: } ! 13617: break; ! 13618: case 0x01: ! 13619: // NOTE: we need to check BH that shows 10-millisecond untils past time in CX ! 13620: if(!DosDateTimeToFileTime(REG16(DX), REG16(CX), (FILETIME *)(mem + SREG_BASE(ES) + REG16(DI)))) { ! 13621: REG16(AX) = (UINT16)GetLastError(); ! 13622: m_CF = 1; ! 13623: } ! 13624: break; ! 13625: default: ! 13626: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 13627: REG16(AX) = 0x7100; ! 13628: m_CF = 1; ! 13629: break; ! 13630: } ! 13631: } ! 13632: ! 13633: inline void msdos_int_21h_71a8h() ! 13634: { ! 13635: if(REG8(DH) == 0) { ! 13636: char tmp[MAX_PATH], fcb[MAX_PATH]; ! 13637: strcpy(tmp, msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI)))); ! 13638: memset(fcb, 0x20, sizeof(fcb)); ! 13639: int len = strlen(tmp); ! 13640: for(int i = 0, pos = 0; i < len; i++) { ! 13641: if(tmp[i] == '.') { ! 13642: pos = 8; ! 13643: } else { ! 13644: if(msdos_lead_byte_check(tmp[i])) { ! 13645: fcb[pos++] = tmp[i++]; ! 13646: } ! 13647: fcb[pos++] = tmp[i]; ! 13648: } ! 13649: } ! 13650: memcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), fcb, 11); ! 13651: } else { ! 13652: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI)))); ! 13653: } ! 13654: } ! 13655: ! 13656: inline void msdos_int_21h_71aah() ! 13657: { ! 13658: char drv[] = "A:", path[MAX_PATH]; ! 13659: char *hoge=(char *)(mem + SREG_BASE(DS) + REG16(DX)); ! 13660: ! 13661: if(REG8(BL) == 0) { ! 13662: drv[0] = 'A' + _getdrive() - 1; ! 13663: } else { ! 13664: drv[0] = 'A' + REG8(BL) - 1; ! 13665: } ! 13666: switch(REG8(BH)) { ! 13667: case 0x00: ! 13668: if(msdos_is_valid_drive((REG8(BL) ? REG8(BL) : _getdrive()) - 1)) { ! 13669: REG16(AX) = 0x0f; // invalid drive ! 13670: m_CF = 1; ! 13671: } else if(DefineDosDeviceA(0, drv, (char *)(mem + SREG_BASE(DS) + REG16(DX))) == 0) { ! 13672: REG16(AX) = 0x03; // path not found ! 13673: m_CF = 1; ! 13674: } ! 13675: break; ! 13676: case 0x01: ! 13677: if(!msdos_is_valid_drive((REG8(BL) ? REG8(BL) : _getdrive()) - 1)) { ! 13678: REG16(AX) = 0x0f; // invalid drive ! 13679: m_CF = 1; ! 13680: } else if(DefineDosDeviceA(DDD_REMOVE_DEFINITION, drv, NULL) == 0) { ! 13681: REG16(AX) = 0x0f; // invalid drive ! 13682: m_CF = 1; ! 13683: } ! 13684: break; ! 13685: case 0x02: ! 13686: if(!msdos_is_valid_drive((REG8(BL) ? REG8(BL) : _getdrive()) - 1)) { ! 13687: REG16(AX) = 0x0f; // invalid drive ! 13688: m_CF = 1; ! 13689: } else if(QueryDosDeviceA(drv, path, MAX_PATH) == 0) { ! 13690: REG16(AX) = 0x0f; // invalid drive ! 13691: m_CF = 1; ! 13692: } else if(strncmp(path, "\\??\\", 4) != 0) { ! 13693: REG16(AX) = 0x0f; // invalid drive ! 13694: m_CF = 1; ! 13695: } else { ! 13696: strcpy((char *)(mem + SREG_BASE(DS) + REG16(DX)), path + 4); ! 13697: } ! 13698: break; ! 13699: default: ! 13700: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 13701: REG16(AX) = 0x7100; ! 13702: m_CF = 1; ! 13703: break; ! 13704: } ! 13705: } ! 13706: ! 13707: inline void msdos_int_21h_7300h() ! 13708: { ! 13709: REG8(AL) = REG8(CL); ! 13710: REG8(AH) = 0; ! 13711: } ! 13712: ! 13713: inline void msdos_int_21h_7302h() ! 13714: { ! 13715: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1); ! 13716: UINT16 seg, ofs; ! 13717: ! 13718: if(REG16(CX) < 0x3f) { ! 13719: REG8(AL) = 0x18; ! 13720: m_CF = 1; ! 13721: } else if(!msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) { ! 13722: REG8(AL) = 0xff; ! 13723: m_CF = 1; ! 13724: } else { ! 13725: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 2, mem + (seg << 4) + ofs, sizeof(dpb_t)); ! 13726: } ! 13727: } ! 13728: ! 13729: inline void msdos_int_21h_7303h() ! 13730: { ! 13731: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX)); ! 13732: ext_space_info_t *info = (ext_space_info_t *)(mem + SREG_BASE(ES) + REG16(DI)); ! 13733: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters; ! 13734: ! 13735: if(GetDiskFreeSpaceA(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) { ! 13736: info->size_of_structure = sizeof(ext_space_info_t); ! 13737: info->structure_version = 0; ! 13738: info->sectors_per_cluster = sectors_per_cluster; ! 13739: info->bytes_per_sector = bytes_per_sector; ! 13740: info->available_clusters_on_drive = free_clusters; ! 13741: info->total_clusters_on_drive = total_clusters; ! 13742: info->available_sectors_on_drive = sectors_per_cluster * free_clusters; ! 13743: info->total_sectors_on_drive = sectors_per_cluster * total_clusters; ! 13744: info->available_allocation_units = free_clusters; // ??? ! 13745: info->total_allocation_units = total_clusters; // ??? ! 13746: } else { ! 13747: REG16(AX) = errno; ! 13748: m_CF = 1; ! 13749: } ! 13750: } ! 13751: ! 13752: inline void msdos_int_21h_dbh() ! 13753: { ! 13754: // Novell NetWare - Workstation - Get Number of Local Drives ! 13755: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP); ! 13756: REG8(AL) = dos_info->last_drive; ! 13757: } ! 13758: ! 13759: inline void msdos_int_21h_dch() ! 13760: { ! 13761: // Novell NetWare - Connection Services - Get Connection Number ! 13762: REG8(AL) = 0x00; ! 13763: } ! 13764: ! 13765: inline void msdos_int_24h() ! 13766: { ! 13767: const char *message = NULL; ! 13768: int key = 0; ! 13769: ! 13770: for(int i = 0; i < array_length(critical_error_table); i++) { ! 13771: if(critical_error_table[i].code == (REG16(DI) & 0xff) || critical_error_table[i].code == (UINT16)-1) { ! 13772: if(active_code_page == 932) { ! 13773: message = critical_error_table[i].message_japanese; ! 13774: } ! 13775: if(message == NULL) { ! 13776: message = critical_error_table[i].message_english; ! 13777: } ! 13778: *(UINT8 *)(mem + WORK_TOP) = strlen(message); ! 13779: strcpy((char *)(mem + WORK_TOP + 1), message); ! 13780: ! 13781: SREG(ES) = WORK_TOP >> 4; ! 13782: i386_load_segment_descriptor(ES); ! 13783: REG16(DI) = 0x0000; ! 13784: break; ! 13785: } ! 13786: } ! 13787: fprintf(stderr, "\n%s", message); ! 13788: if(!(REG8(AH) & 0x80)) { ! 13789: if(REG8(AH) & 0x01) { ! 13790: fprintf(stderr, " %s %c", (active_code_page == 932) ? "�������ݒ� �h���C�u" : "writing drive", 'A' + REG8(AL)); ! 13791: } else { ! 13792: fprintf(stderr, " %s %c", (active_code_page == 932) ? "�ǂݎ�蒆 �h���C�u" : "reading drive", 'A' + REG8(AL)); ! 13793: } ! 13794: } ! 13795: fprintf(stderr, "\n"); ! 13796: ! 13797: { ! 13798: fprintf(stderr, "%s", (active_code_page == 932) ? "���~ (A)" : "Abort"); ! 13799: } ! 13800: if(REG8(AH) & 0x10) { ! 13801: fprintf(stderr, ", %s", (active_code_page == 932) ? "�Ď��s (R)" : "Retry"); ! 13802: } ! 13803: if(REG8(AH) & 0x20) { ! 13804: fprintf(stderr, ", %s", (active_code_page == 932) ? "���� (I)" : "Ignore"); ! 13805: } ! 13806: if(REG8(AH) & 0x08) { ! 13807: fprintf(stderr, ", %s", (active_code_page == 932) ? "���s (F)" : "Fail"); ! 13808: } ! 13809: fprintf(stderr, "? "); ! 13810: ! 13811: while(1) { ! 13812: while(!_kbhit()) { ! 13813: Sleep(10); ! 13814: } ! 13815: key = _getch(); ! 13816: ! 13817: if(key == 'I' || key == 'i') { ! 13818: if(REG8(AH) & 0x20) { ! 13819: REG8(AL) = 0; ! 13820: break; ! 13821: } ! 13822: } else if(key == 'R' || key == 'r') { ! 13823: if(REG8(AH) & 0x10) { ! 13824: REG8(AL) = 1; ! 13825: break; ! 13826: } ! 13827: } else if(key == 'A' || key == 'a') { ! 13828: REG8(AL) = 2; ! 13829: break; ! 13830: } else if(key == 'F' || key == 'f') { ! 13831: if(REG8(AH) & 0x08) { ! 13832: REG8(AL) = 3; ! 13833: break; ! 13834: } ! 13835: } ! 13836: } ! 13837: fprintf(stderr, "%c\n", key); ! 13838: } ! 13839: ! 13840: inline void msdos_int_25h() ! 13841: { ! 13842: UINT16 seg, ofs; ! 13843: DWORD dwSize; ! 13844: ! 13845: #if defined(HAS_I386) ! 13846: I386OP(pushf)(); ! 13847: #else ! 13848: PREFIX86(_pushf()); ! 13849: #endif ! 13850: ! 13851: if(!(REG8(AL) < 26)) { ! 13852: REG8(AL) = 0x01; // unit unknown ! 13853: m_CF = 1; ! 13854: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) { ! 13855: REG8(AL) = 0x02; // drive not ready ! 13856: m_CF = 1; ! 13857: } else { ! 13858: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs); ! 13859: char dev[64]; ! 13860: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL)); ! 13861: ! 13862: HANDLE hFile = CreateFileA(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL); ! 13863: if(hFile == INVALID_HANDLE_VALUE) { ! 13864: REG8(AL) = 0x02; // drive not ready ! 13865: m_CF = 1; ! 13866: } else { ! 13867: UINT32 top_sector = REG16(DX); ! 13868: UINT16 sector_num = REG16(CX); ! 13869: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX); ! 13870: ! 13871: if(sector_num == 0xffff) { ! 13872: top_sector = *(UINT32 *)(mem + buffer_addr + 0); ! 13873: sector_num = *(UINT16 *)(mem + buffer_addr + 4); ! 13874: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6); ! 13875: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8); ! 13876: buffer_addr = (seg << 4) + ofs; ! 13877: } ! 13878: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) { ! 13879: // REG8(AL) = 0x02; // drive not ready ! 13880: // m_CF = 1; ! 13881: // } else ! 13882: if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { ! 13883: REG8(AL) = 0x08; // sector not found ! 13884: m_CF = 1; ! 13885: } else if(ReadFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) { ! 13886: REG8(AL) = 0x0b; // read error ! 13887: m_CF = 1; ! 13888: } ! 13889: CloseHandle(hFile); ! 13890: } ! 13891: } ! 13892: } ! 13893: ! 13894: inline void msdos_int_26h() ! 13895: { ! 13896: // this operation may cause serious damage for drives, so support only floppy disk... ! 13897: UINT16 seg, ofs; ! 13898: DWORD dwSize; ! 13899: ! 13900: #if defined(HAS_I386) ! 13901: I386OP(pushf)(); ! 13902: #else ! 13903: PREFIX86(_pushf()); ! 13904: #endif ! 13905: ! 13906: if(!(REG8(AL) < 26)) { ! 13907: REG8(AL) = 0x01; // unit unknown ! 13908: m_CF = 1; ! 13909: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) { ! 13910: REG8(AL) = 0x02; // drive not ready ! 13911: m_CF = 1; ! 13912: } else { ! 13913: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs); ! 13914: char dev[64]; ! 13915: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL)); ! 13916: ! 13917: if(dpb->media_type == 0xf8) { ! 13918: // this drive is not a floppy ! 13919: // if(!(((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag & 0x40)) { ! 13920: // fatalerror("This application tried the absolute disk write to drive %c:\n", 'A' + REG8(AL)); ! 13921: // } ! 13922: REG8(AL) = 0x02; // drive not ready ! 13923: m_CF = 1; ! 13924: } else { ! 13925: HANDLE hFile = CreateFileA(dev, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL); ! 13926: if(hFile == INVALID_HANDLE_VALUE) { ! 13927: REG8(AL) = 0x02; // drive not ready ! 13928: m_CF = 1; ! 13929: } else { ! 13930: UINT32 top_sector = REG16(DX); ! 13931: UINT16 sector_num = REG16(CX); ! 13932: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX); ! 13933: ! 13934: if(sector_num == 0xffff) { ! 13935: top_sector = *(UINT32 *)(mem + buffer_addr + 0); ! 13936: sector_num = *(UINT16 *)(mem + buffer_addr + 4); ! 13937: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6); ! 13938: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8); ! 13939: buffer_addr = (seg << 4) + ofs; ! 13940: } ! 13941: if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) { ! 13942: REG8(AL) = 0x02; // drive not ready ! 13943: m_CF = 1; ! 13944: } else if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { ! 13945: REG8(AL) = 0x08; // sector not found ! 13946: m_CF = 1; ! 13947: } else if(WriteFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) { ! 13948: REG8(AL) = 0x0a; // write error ! 13949: m_CF = 1; ! 13950: } ! 13951: CloseHandle(hFile); ! 13952: } ! 13953: } ! 13954: } ! 13955: } ! 13956: ! 13957: inline void msdos_int_27h() ! 13958: { ! 13959: int paragraphs = (min(REG16(DX), 0xfff0) + 15) >> 4; ! 13960: try { ! 13961: msdos_mem_realloc(SREG(CS), paragraphs, NULL); ! 13962: } catch(...) { ! 13963: // recover the broken mcb ! 13964: int mcb_seg = SREG(CS) - 1; ! 13965: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4)); ! 13966: ! 13967: if(mcb_seg < (MEMORY_END >> 4)) { ! 13968: mcb->mz = 'M'; ! 13969: mcb->paragraphs = (MEMORY_END >> 4) - mcb_seg - 2; ! 13970: ! 13971: if(((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked & 0x01) { ! 13972: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', PSP_SYSTEM, (UMB_TOP >> 4) - (MEMORY_END >> 4), "SC"); ! 13973: } else { ! 13974: msdos_mcb_create((MEMORY_END >> 4) - 1, 'Z', PSP_SYSTEM, 0, "SC"); ! 13975: } ! 13976: } else { ! 13977: mcb->mz = 'Z'; ! 13978: mcb->paragraphs = (UMB_END >> 4) - mcb_seg - 1; ! 13979: } ! 13980: msdos_mem_realloc(SREG(CS), paragraphs, NULL); ! 13981: } ! 13982: msdos_process_terminate(SREG(CS), retval | 0x300, 0); ! 13983: } ! 13984: ! 13985: inline void msdos_int_29h() ! 13986: { ! 13987: msdos_putch_fast(REG8(AL)); ! 13988: } ! 13989: ! 13990: inline void msdos_int_2eh() ! 13991: { ! 13992: char tmp[MAX_PATH], command[MAX_PATH], opt[MAX_PATH]; ! 13993: memset(tmp, 0, sizeof(tmp)); ! 13994: strcpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(SI))); ! 13995: char *token = my_strtok(tmp, " "); ! 13996: strcpy(command, token); ! 13997: strcpy(opt, token + strlen(token) + 1); ! 13998: ! 13999: param_block_t *param = (param_block_t *)(mem + WORK_TOP); ! 14000: param->env_seg = 0; ! 14001: param->cmd_line.w.l = 44; ! 14002: param->cmd_line.w.h = (WORK_TOP >> 4); ! 14003: param->fcb1.w.l = 24; ! 14004: param->fcb1.w.h = (WORK_TOP >> 4); ! 14005: param->fcb2.w.l = 24; ! 14006: param->fcb2.w.h = (WORK_TOP >> 4); ! 14007: ! 14008: memset(mem + WORK_TOP + 24, 0x20, 20); ! 14009: ! 14010: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44); ! 14011: cmd_line->len = strlen(opt); ! 14012: strcpy(cmd_line->cmd, opt); ! 14013: cmd_line->cmd[cmd_line->len] = 0x0d; ! 14014: ! 14015: try { ! 14016: if(msdos_process_exec(command, param, 0)) { ! 14017: REG16(AX) = 0xffff; // error before processing command ! 14018: } else { ! 14019: // set flag to set retval to ax when the started process is terminated ! 14020: process_t *process = msdos_process_info_get(current_psp); ! 14021: process->called_by_int2eh = true; ! 14022: } ! 14023: } catch(...) { ! 14024: REG16(AX) = 0xffff; // error before processing command ! 14025: } ! 14026: } ! 14027: ! 14028: inline void msdos_int_2fh_05h() ! 14029: { ! 14030: switch(REG8(AL)) { ! 14031: case 0x00: ! 14032: // critical error handler is installed ! 14033: REG8(AL) = 0xff; ! 14034: break; ! 14035: case 0x01: ! 14036: case 0x02: ! 14037: for(int i = 0; i < array_length(standard_error_table); i++) { ! 14038: if(standard_error_table[i].code == REG16(BX) || standard_error_table[i].code == (UINT16)-1) { ! 14039: const char *message = NULL; ! 14040: if(active_code_page == 932) { ! 14041: message = standard_error_table[i].message_japanese; ! 14042: } ! 14043: if(message == NULL) { ! 14044: message = standard_error_table[i].message_english; ! 14045: } ! 14046: strcpy((char *)(mem + WORK_TOP), message); ! 14047: ! 14048: SREG(ES) = WORK_TOP >> 4; ! 14049: i386_load_segment_descriptor(ES); ! 14050: REG16(DI) = 0x0000; ! 14051: REG8(AL) = 0x01; ! 14052: break; ! 14053: } ! 14054: } ! 14055: break; ! 14056: default: ! 14057: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 14058: REG16(AX) = 0x01; ! 14059: m_CF = 1; ! 14060: } ! 14061: } ! 14062: ! 14063: inline void msdos_int_2fh_06h() ! 14064: { ! 14065: switch(REG8(AL)) { ! 14066: case 0x00: ! 14067: // ASSIGN is not installed ! 14068: // REG8(AL) = 0x00; ! 14069: break; ! 14070: case 0x01: ! 14071: // this call is available from within MIRROR.COM even if ASSIGN is not installed ! 14072: REG16(AX) = 0x01; ! 14073: m_CF = 1; ! 14074: break; ! 14075: default: ! 14076: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 14077: REG16(AX) = 0x01; ! 14078: m_CF = 1; ! 14079: break; ! 14080: } ! 14081: } ! 14082: ! 14083: inline void msdos_int_2fh_11h() ! 14084: { ! 14085: switch(REG8(AL)) { ! 14086: case 0x00: ! 14087: if(i386_read_stack() == 0xdada) { ! 14088: #ifdef SUPPORT_MSCDEX ! 14089: // MSCDEX is installed ! 14090: REG8(AL) = 0xff; ! 14091: i386_write_stack(0xadad); ! 14092: #else ! 14093: // MSCDEX is not installed ! 14094: // REG8(AL) = 0x00; ! 14095: #endif ! 14096: } else { ! 14097: // Network Redirector is not installed ! 14098: // REG8(AL) = 0x00; ! 14099: } ! 14100: break; ! 14101: default: ! 14102: // unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 14103: REG16(AX) = 0x49; // network software not installed ! 14104: m_CF = 1; ! 14105: break; ! 14106: } ! 14107: } ! 14108: ! 14109: inline void msdos_int_2fh_12h() ! 14110: { ! 14111: switch(REG8(AL)) { ! 14112: case 0x00: ! 14113: // DOS 3.0+ internal functions are installed ! 14114: REG8(AL) = 0xff; ! 14115: break; ! 14116: // case 0x01: // DOS 3.0+ internal - Close Current File ! 14117: case 0x02: ! 14118: { ! 14119: UINT16 stack = i386_read_stack(); ! 14120: REG16(BX) = *(UINT16 *)(mem + 4 * stack + 0); ! 14121: SREG(ES) = *(UINT16 *)(mem + 4 * stack + 2); ! 14122: i386_load_segment_descriptor(ES); ! 14123: } ! 14124: break; ! 14125: case 0x03: ! 14126: SREG(DS) = (DEVICE_TOP >> 4); ! 14127: i386_load_segment_descriptor(DS); ! 14128: break; ! 14129: case 0x04: ! 14130: { ! 14131: UINT16 stack = i386_read_stack(); ! 14132: REG8(AL) = (stack == '/') ? '\\' : stack; ! 14133: #if defined(HAS_I386) ! 14134: m_ZF = (REG8(AL) == '\\'); ! 14135: #else ! 14136: m_ZeroVal = (REG8(AL) != '\\'); ! 14137: #endif ! 14138: } ! 14139: break; ! 14140: case 0x05: ! 14141: { ! 14142: UINT16 c = i386_read_stack(); ! 14143: if((c >> 0) & 0xff) { ! 14144: msdos_putch((c >> 0) & 0xff); ! 14145: } ! 14146: if((c >> 8) & 0xff) { ! 14147: msdos_putch((c >> 8) & 0xff); ! 14148: } ! 14149: } ! 14150: break; ! 14151: // case 0x06: // DOS 3.0+ internal - Invoke Critical Error ! 14152: // case 0x07: // DOS 3.0+ internal - Make Disk Buffer Most Recentry Used ! 14153: // case 0x08: // DOS 3.0+ internal - Decrement SFT Reference Count ! 14154: // case 0x09: // DOS 3.0+ internal - Flush and Free Disk Buffer ! 14155: // case 0x0a: // DOS 3.0+ internal - Perform Critical Error Interrupt ! 14156: // case 0x0b: // DOS 3.0+ internal - Signal Sharing Violation to User ! 14157: // case 0x0c: // DOS 3.0+ internal - Open Device and Set SFT Owner/Mode ! 14158: case 0x0d: ! 14159: { ! 14160: SYSTEMTIME time; ! 14161: FILETIME file_time; ! 14162: WORD dos_date, dos_time; ! 14163: GetLocalTime(&time); ! 14164: SystemTimeToFileTime(&time, &file_time); ! 14165: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time); ! 14166: REG16(AX) = dos_date; ! 14167: REG16(DX) = dos_time; ! 14168: } ! 14169: break; ! 14170: // case 0x0e: // DOS 3.0+ internal - Mark All Disk Buffers Unreferenced ! 14171: // case 0x0f: // DOS 3.0+ internal - Make Buffer Most Recentry Used ! 14172: // case 0x10: // DOS 3.0+ internal - Find Unreferenced Disk Buffer ! 14173: case 0x11: ! 14174: { ! 14175: char path[MAX_PATH], *p; ! 14176: strcpy(path, (char *)(mem + SREG_BASE(DS) + REG16(SI))); ! 14177: my_strupr(path); ! 14178: while((p = my_strchr(path, '/')) != NULL) { ! 14179: *p = '\\'; ! 14180: } ! 14181: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path); ! 14182: } ! 14183: break; ! 14184: case 0x12: ! 14185: REG16(CX) = strlen((char *)(mem + SREG_BASE(ES) + REG16(DI))); ! 14186: break; ! 14187: case 0x13: ! 14188: { ! 14189: char tmp[2] = {0}; ! 14190: tmp[0] = i386_read_stack(); ! 14191: my_strupr(tmp); ! 14192: REG8(AL) = tmp[0]; ! 14193: } ! 14194: break; ! 14195: case 0x14: ! 14196: #if defined(HAS_I386) ! 14197: m_ZF = (SREG_BASE(DS) + REG16(SI) == SREG_BASE(ES) + REG16(DI)); ! 14198: #else ! 14199: m_ZeroVal = (SREG_BASE(DS) + REG16(SI) != SREG_BASE(ES) + REG16(DI)); ! 14200: #endif ! 14201: m_CF = (SREG_BASE(DS) + REG16(SI) != SREG_BASE(ES) + REG16(DI)); ! 14202: break; ! 14203: // case 0x15: // DOS 3.0+ internal - Flush Buffer ! 14204: case 0x16: ! 14205: if(REG16(BX) < 20) { ! 14206: SREG(ES) = SFT_TOP >> 4; ! 14207: i386_load_segment_descriptor(ES); ! 14208: REG16(DI) = 6 + 0x3b * REG16(BX); ! 14209: ! 14210: // update system file table ! 14211: UINT8* sft = mem + SFT_TOP + 6 + 0x3b * REG16(BX); ! 14212: if(file_handler[REG16(BX)].valid) { ! 14213: int count = 0; ! 14214: for(int i = 0; i < 20; i++) { ! 14215: if(msdos_psp_get_file_table(i, current_psp) == REG16(BX)) { ! 14216: count++; ! 14217: } ! 14218: } ! 14219: *(UINT16 *)(sft + 0x00) = count ? count : 0xffff; ! 14220: *(UINT32 *)(sft + 0x15) = _tell(REG16(BX)); ! 14221: _lseek(REG16(BX), 0, SEEK_END); ! 14222: *(UINT32 *)(sft + 0x11) = _tell(REG16(BX)); ! 14223: _lseek(REG16(BX), *(UINT32 *)(sft + 0x15), SEEK_SET); ! 14224: } else { ! 14225: memset(sft, 0, 0x3b); ! 14226: } ! 14227: } else { ! 14228: REG16(AX) = 0x06; ! 14229: m_CF = 1; ! 14230: } ! 14231: break; ! 14232: case 0x17: ! 14233: { ! 14234: UINT16 drive = i386_read_stack(); ! 14235: if(msdos_is_valid_drive(drive)) { ! 14236: msdos_cds_update(drive); ! 14237: } ! 14238: REG16(SI) = 88 * drive; ! 14239: SREG(DS) = (CDS_TOP >> 4); ! 14240: i386_load_segment_descriptor(DS); ! 14241: } ! 14242: break; ! 14243: // case 0x18: // DOS 3.0+ internal - Get Caller's Registers ! 14244: // case 0x19: // DOS 3.0+ internal - Set Drive??? ! 14245: case 0x1a: ! 14246: { ! 14247: char *path = (char *)(mem + SREG_BASE(DS) + REG16(SI)), full[MAX_PATH]; ! 14248: if(path[1] == ':') { ! 14249: if(path[0] >= 'a' && path[0] <= 'z') { ! 14250: REG8(AL) = path[0] - 'a' + 1; ! 14251: } else if(path[0] >= 'A' && path[0] <= 'Z') { ! 14252: REG8(AL) = path[0] - 'A' + 1; ! 14253: } else { ! 14254: REG8(AL) = 0xff; // invalid ! 14255: } ! 14256: strcpy(full, path); ! 14257: strcpy(path, full + 2); ! 14258: } else if(GetFullPathNameA(path, MAX_PATH, full, NULL) != 0 && full[1] == ':') { ! 14259: if(full[0] >= 'a' && full[0] <= 'z') { ! 14260: REG8(AL) = full[0] - 'a' + 1; ! 14261: } else if(full[0] >= 'A' && full[0] <= 'Z') { ! 14262: REG8(AL) = full[0] - 'A' + 1; ! 14263: } else { ! 14264: REG8(AL) = 0xff; // invalid ! 14265: } ! 14266: } else { ! 14267: REG8(AL) = 0x00; // default ! 14268: } ! 14269: } ! 14270: break; ! 14271: case 0x1b: ! 14272: { ! 14273: int year = REG16(CX) + 1980; ! 14274: REG8(AL) = ((year % 4) == 0 && (year % 100) != 0 && (year % 400) == 0) ? 29 : 28; ! 14275: } ! 14276: break; ! 14277: // case 0x1c: // DOS 3.0+ internal - Check Sum Memory ! 14278: // case 0x1d: // DOS 3.0+ internal - Sum Memory ! 14279: case 0x1e: ! 14280: { ! 14281: char *path_1st = (char *)(mem + SREG_BASE(DS) + REG16(SI)), full_1st[MAX_PATH]; ! 14282: char *path_2nd = (char *)(mem + SREG_BASE(ES) + REG16(DI)), full_2nd[MAX_PATH]; ! 14283: if(GetFullPathNameA(path_1st, MAX_PATH, full_1st, NULL) != 0 && GetFullPathNameA(path_2nd, MAX_PATH, full_2nd, NULL) != 0) { ! 14284: #if defined(HAS_I386) ! 14285: m_ZF = (strcmp(full_1st, full_2nd) == 0); ! 14286: #else ! 14287: m_ZeroVal = (strcmp(full_1st, full_2nd) != 0); ! 14288: #endif ! 14289: } else { ! 14290: #if defined(HAS_I386) ! 14291: m_ZF = (strcmp(path_1st, path_2nd) == 0); ! 14292: #else ! 14293: m_ZeroVal = (strcmp(path_1st, path_2nd) != 0); ! 14294: #endif ! 14295: } ! 14296: } ! 14297: break; ! 14298: case 0x1f: ! 14299: { ! 14300: UINT16 drive = i386_read_stack(); ! 14301: if(msdos_is_valid_drive(drive)) { ! 14302: msdos_cds_update(drive); ! 14303: } ! 14304: REG16(SI) = 88 * drive; ! 14305: SREG(ES) = (CDS_TOP >> 4); ! 14306: i386_load_segment_descriptor(ES); ! 14307: } ! 14308: break; ! 14309: case 0x20: ! 14310: { ! 14311: int fd = msdos_psp_get_file_table(REG16(BX), current_psp); ! 14312: ! 14313: if(fd < 20) { ! 14314: SREG(ES) = current_psp; ! 14315: i386_load_segment_descriptor(ES); ! 14316: REG16(DI) = offsetof(psp_t, file_table) + fd; ! 14317: } else { ! 14318: REG16(AX) = 0x06; ! 14319: m_CF = 1; ! 14320: } ! 14321: } ! 14322: break; ! 14323: case 0x21: ! 14324: msdos_int_21h_60h(0); ! 14325: break; ! 14326: case 0x22: ! 14327: { ! 14328: sda_t *sda = (sda_t *)(mem + SDA_TOP); ! 14329: if(*(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x00) != 0xff) { ! 14330: sda->extended_error_code = *(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x00); ! 14331: } ! 14332: if(*(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x01) != 0xff) { ! 14333: sda->error_class = *(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x01); ! 14334: } ! 14335: if(*(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x02) != 0xff) { ! 14336: sda->suggested_action = *(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x02); ! 14337: } ! 14338: if(*(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x03) != 0xff) { ! 14339: sda->locus_of_last_error = *(UINT8 *)(mem + SREG_BASE(SS) + REG16(SI) + 0x03); ! 14340: } ! 14341: } ! 14342: break; ! 14343: // case 0x23: // DOS 3.0+ internal - Check If Character Device ! 14344: // case 0x24: // DOS 3.0+ internal - Sharing Retry Delay ! 14345: case 0x25: ! 14346: REG16(CX) = strlen((char *)(mem + SREG_BASE(DS) + REG16(SI))); ! 14347: break; ! 14348: case 0x26: ! 14349: REG8(AL) = REG8(CL); ! 14350: msdos_int_21h_3dh(); ! 14351: break; ! 14352: case 0x27: ! 14353: msdos_int_21h_3eh(); ! 14354: break; ! 14355: case 0x28: ! 14356: REG16(AX) = REG16(BP); ! 14357: msdos_int_21h_42h(); ! 14358: break; ! 14359: case 0x29: ! 14360: msdos_int_21h_3fh(); ! 14361: break; ! 14362: // case 0x2a: // DOS 3.0+ internal - Set Fast Open Entry Point ! 14363: case 0x2b: ! 14364: REG16(AX) = REG16(BP); ! 14365: msdos_int_21h_44h(); ! 14366: break; ! 14367: case 0x2c: ! 14368: REG16(BX) = DEVICE_TOP >> 4; ! 14369: REG16(AX) = 22; ! 14370: break; ! 14371: case 0x2d: ! 14372: { ! 14373: sda_t *sda = (sda_t *)(mem + SDA_TOP); ! 14374: REG16(AX) = sda->extended_error_code; ! 14375: } ! 14376: break; ! 14377: case 0x2e: ! 14378: if(REG8(DL) == 0x00 || REG8(DL) == 0x02 || REG8(DL) == 0x04 || REG8(DL) == 0x06) { ! 14379: SREG(ES) = 0x0001; ! 14380: i386_load_segment_descriptor(ES); ! 14381: REG16(DI) = 0x00; ! 14382: } else if(REG8(DL) == 0x08) { ! 14383: // dummy parameter error message read routine is at fffc:0010 ! 14384: SREG(ES) = DUMMY_TOP >> 4; ! 14385: i386_load_segment_descriptor(ES); ! 14386: REG16(DI) = 0x0010; ! 14387: } ! 14388: break; ! 14389: case 0x2f: ! 14390: if(REG16(DX) != 0) { ! 14391: dos_major_version = REG8(DL); ! 14392: dos_minor_version = REG8(DH); ! 14393: } else { ! 14394: REG8(DL) = 7; ! 14395: REG8(DH) = 10; ! 14396: } ! 14397: break; ! 14398: // case 0x30: // Windows95 - Find SFT Entry in Internal File Tables ! 14399: // case 0x31: // Windows95 - Set/Clear "Report Windows to DOS Programs" Flag ! 14400: default: ! 14401: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 14402: REG16(AX) = 0x01; ! 14403: m_CF = 1; ! 14404: break; ! 14405: } ! 14406: } ! 14407: ! 14408: inline void msdos_int_2fh_13h() ! 14409: { ! 14410: static UINT16 prevDS = 0, prevDX = 0; ! 14411: static UINT16 prevES = 0, prevBX = 0; ! 14412: UINT16 tmp; ! 14413: ! 14414: tmp = SREG(DS); SREG(DS) = prevDS; prevDS = tmp; ! 14415: i386_load_segment_descriptor(DS); ! 14416: tmp = REG16(DX); REG16(DX) = prevDX; prevDX = tmp; ! 14417: ! 14418: tmp = SREG(ES); SREG(ES) = prevES; prevES = tmp; ! 14419: i386_load_segment_descriptor(ES); ! 14420: tmp = REG16(BX); REG16(BX) = prevBX; prevBX = tmp; ! 14421: } ! 14422: ! 14423: inline void msdos_int_2fh_14h() ! 14424: { ! 14425: switch(REG8(AL)) { ! 14426: case 0x00: ! 14427: // NLSFUNC.COM is installed ! 14428: REG8(AL) = 0xff; ! 14429: break; ! 14430: case 0x01: ! 14431: case 0x03: ! 14432: REG8(AL) = 0x00; ! 14433: active_code_page = REG16(BX); ! 14434: msdos_nls_tables_update(); ! 14435: break; ! 14436: case 0x02: ! 14437: REG8(AL) = get_extended_country_info(REG16(BP)); ! 14438: break; ! 14439: case 0x04: ! 14440: for(int i = 0;; i++) { ! 14441: if(country_table[i].code == REG16(DX)) { ! 14442: get_country_info((country_info_t *)(mem + SREG_BASE(ES) + REG16(DI)), country_table[i].usPrimaryLanguage, country_table[i].usSubLanguage); ! 14443: break; ! 14444: } else if(country_table[i].code == -1) { ! 14445: get_country_info((country_info_t *)(mem + SREG_BASE(ES) + REG16(DI))); ! 14446: break; ! 14447: } ! 14448: } ! 14449: REG8(AL) = 0x00; ! 14450: break; ! 14451: default: ! 14452: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 14453: REG16(AX) = 0x01; ! 14454: m_CF = 1; ! 14455: break; ! 14456: } ! 14457: } ! 14458: ! 14459: inline void msdos_int_2fh_15h() ! 14460: { ! 14461: switch(REG8(AL)) { ! 14462: case 0x00: // CD-ROM - Installation Check ! 14463: if(REG16(BX) == 0x0000) { ! 14464: #ifdef SUPPORT_MSCDEX ! 14465: // MSCDEX is installed ! 14466: REG16(BX) = 0; ! 14467: for(int i = 0, n = 0; i < 26; i++) { ! 14468: if(msdos_is_cdrom_drive(i)) { ! 14469: if(REG16(BX) == 0) { ! 14470: REG16(CX) = i; ! 14471: } ! 14472: REG16(BX)++; ! 14473: } ! 14474: } ! 14475: #else ! 14476: // MSCDEX is not installed ! 14477: // REG8(AL) = 0x00; ! 14478: #endif ! 14479: } else { ! 14480: // GRAPHICS.COM is not installed ! 14481: // REG8(AL) = 0x00; ! 14482: } ! 14483: break; ! 14484: case 0x0b: ! 14485: // this call is available from within DOSSHELL even if MSCDEX is not installed ! 14486: REG16(AX) = msdos_is_cdrom_drive(REG8(CL)) ? 0x5ad8 : 0x0000; ! 14487: REG16(BX) = 0xadad; ! 14488: break; ! 14489: case 0x0d: ! 14490: for(int i = 0, n = 0; i < 26; i++) { ! 14491: if(msdos_is_cdrom_drive(i)) { ! 14492: mem[SREG_BASE(ES) + REG16(BX) + (n++)] = i; ! 14493: } ! 14494: } ! 14495: break; ! 14496: case 0xff: ! 14497: if(REG16(BX) == 0x0000) { ! 14498: // CORELCDX is not installed ! 14499: } else { ! 14500: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 14501: REG16(AX) = 0x01; ! 14502: m_CF = 1; ! 14503: } ! 14504: break; ! 14505: default: ! 14506: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 14507: REG16(AX) = 0x01; ! 14508: m_CF = 1; ! 14509: break; ! 14510: } ! 14511: } ! 14512: ! 14513: inline void msdos_int_2fh_16h() ! 14514: { ! 14515: switch(REG8(AL)) { ! 14516: case 0x00: ! 14517: if(no_windows) { ! 14518: // neither Windows 3.x enhanced mode nor Windows/386 2.x running ! 14519: // REG8(AL) = 0x00; ! 14520: } else { ! 14521: REG8(AL) = win_major_version; ! 14522: REG8(AH) = win_minor_version; ! 14523: } ! 14524: break; ! 14525: case 0x05: // Windows Enhanced Mode & 286 DOSX Init Broadcast ! 14526: // from DOSBox ! 14527: i386_set_a20_line(1); ! 14528: break; ! 14529: case 0x06: // Windows Enhanced Mode & 286 DOSX Exit Broadcast ! 14530: case 0x08: // Windows Enhanced Mode Init Complete Broadcast ! 14531: case 0x09: // Windows Enhanced Mode Begin Exit Broadcast ! 14532: break; ! 14533: case 0x07: ! 14534: // Virtual Device Call API ! 14535: break; ! 14536: case 0x0a: ! 14537: if(!no_windows) { ! 14538: REG16(AX) = 0x0000; ! 14539: REG8(BH) = win_major_version; ! 14540: REG8(BL) = win_minor_version; ! 14541: // REG16(CX) = 0x0002; // standard ! 14542: REG16(CX) = 0x0003; // enhanced ! 14543: } ! 14544: break; ! 14545: case 0x0b: ! 14546: // no TRS, keep ES:DI = 0000h:0000h ! 14547: case 0x0e: ! 14548: case 0x0f: ! 14549: case 0x10: ! 14550: case 0x11: ! 14551: case 0x12: ! 14552: case 0x13: ! 14553: case 0x14: ! 14554: case 0x15: ! 14555: case 0x81: ! 14556: case 0x82: ! 14557: case 0x84: ! 14558: case 0x85: ! 14559: case 0x86: ! 14560: case 0x87: ! 14561: case 0x89: ! 14562: case 0x8a: ! 14563: // function not supported, do not clear AX ! 14564: break; ! 14565: case 0x80: ! 14566: Sleep(10); ! 14567: REQUEST_HARDWRE_UPDATE(); ! 14568: REG8(AL) = 0x00; ! 14569: break; ! 14570: case 0x83: ! 14571: REG16(BX) = 0x01; // system vm id ! 14572: break; ! 14573: case 0x8e: ! 14574: REG16(AX) = 0x00; // failed ! 14575: break; ! 14576: case 0x8f: ! 14577: switch(REG8(DH)) { ! 14578: case 0x01: ! 14579: // REG16(AX) = 0x0000; // close command selected but not yet acknowledged ! 14580: // REG16(AX) = 0x0001; // close command issued and acknowledged ! 14581: REG16(AX) = 0x168f; // close command not selected -- application should continue ! 14582: break; ! 14583: default: ! 14584: REG16(AX) = 0x0000; // successful ! 14585: break; ! 14586: } ! 14587: break; ! 14588: default: ! 14589: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 14590: REG16(AX) = 0x01; ! 14591: m_CF = 1; ! 14592: break; ! 14593: } ! 14594: } ! 14595: ! 14596: inline void msdos_int_2fh_19h() ! 14597: { ! 14598: switch(REG8(AL)) { ! 14599: case 0x00: ! 14600: // SHELLB.COM is not installed ! 14601: // REG8(AL) = 0x00; ! 14602: break; ! 14603: case 0x01: ! 14604: case 0x02: ! 14605: case 0x03: ! 14606: case 0x04: ! 14607: REG16(AX) = 0x01; ! 14608: m_CF = 1; ! 14609: break; ! 14610: case 0x80: ! 14611: // IBM ROM-DOS v4.0 is not installed ! 14612: // REG8(AL) = 0x00; ! 14613: break; ! 14614: default: ! 14615: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 14616: REG16(AX) = 0x01; ! 14617: m_CF = 1; ! 14618: break; ! 14619: } ! 14620: } ! 14621: ! 14622: inline void msdos_int_2fh_1ah() ! 14623: { ! 14624: switch(REG8(AL)) { ! 14625: case 0x00: ! 14626: // ANSI.SYS is installed ! 14627: REG8(AL) = 0xff; ! 14628: break; ! 14629: case 0x01: ! 14630: if(REG8(CL) == 0x5f) { ! 14631: // set display information ! 14632: if(*(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02) >= 14) { ! 14633: int cur_width = *(UINT16 *)(mem + 0x44a) + 0; ! 14634: int cur_height = *(UINT8 *)(mem + 0x484) + 1; ! 14635: int new_width = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e); // character columns ! 14636: int new_height = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x10); // character rows ! 14637: ! 14638: if(cur_width != new_width || cur_height != new_height) { ! 14639: pcbios_set_console_size(new_width, new_height, true); ! 14640: } ! 14641: } ! 14642: } else if(REG8(CL) == 0x7f) { ! 14643: // get display information ! 14644: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x00) = 0; // level (0 for DOS 4.x-6.0) ! 14645: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x01) = 0; // reserved (0) ! 14646: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02) = 14; // length of following data (14) ! 14647: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x04) = 1; // bit 0 set for blink, clear for intensity ! 14648: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x06) = 1; // mode type (1=text, 2=graphics) ! 14649: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x07) = 0; // reserved (0) ! 14650: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x08) = 4; // 4 bits per pixel ! 14651: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0a) = 8 * (*(UINT16 *)(mem + 0x44a) + 0); // pixel columns ! 14652: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0c) = 16 * (*(UINT8 *)(mem + 0x484) + 1); // pixel rows ! 14653: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e) = *(UINT16 *)(mem + 0x44a) + 0; // character columns ! 14654: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x10) = *(UINT8 *)(mem + 0x484) + 1; // character rows ! 14655: } else { ! 14656: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 14657: REG16(AX) = 0x01; ! 14658: m_CF = 1; ! 14659: } ! 14660: break; ! 14661: default: ! 14662: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 14663: REG16(AX) = 0x01; ! 14664: m_CF = 1; ! 14665: break; ! 14666: } ! 14667: } ! 14668: ! 14669: inline void msdos_int_2fh_40h() ! 14670: { ! 14671: switch(REG8(AL)) { ! 14672: case 0x00: ! 14673: // Windows 3+ - Get Virtual Device Driver (VDD) Capabilities ! 14674: REG8(AL) = 0x01; // does not virtualize video access ! 14675: break; ! 14676: case 0x10: ! 14677: // OS/2 v2.0+ - Installation Check ! 14678: REG16(AX) = 0x01; ! 14679: m_CF = 1; ! 14680: break; ! 14681: default: ! 14682: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 14683: REG16(AX) = 0x01; ! 14684: m_CF = 1; ! 14685: break; ! 14686: } ! 14687: } ! 14688: ! 14689: inline void msdos_int_2fh_43h() ! 14690: { ! 14691: switch(REG8(AL)) { ! 14692: case 0x00: ! 14693: // XMS is installed ? ! 14694: #ifdef SUPPORT_XMS ! 14695: if(support_xms) { ! 14696: REG8(AL) = 0x80; ! 14697: } ! 14698: #endif ! 14699: break; ! 14700: case 0x08: ! 14701: #ifdef SUPPORT_XMS ! 14702: if(support_xms) { ! 14703: REG8(AL) = 0x43; ! 14704: REG8(BL) = 0x01; // IBM PC/AT ! 14705: REG8(BH) = 0x01; // Fast AT A20 switch time ! 14706: } ! 14707: #endif ! 14708: break; ! 14709: case 0x10: ! 14710: SREG(ES) = XMS_TOP >> 4; ! 14711: i386_load_segment_descriptor(ES); ! 14712: REG16(BX) = 0x15; ! 14713: break; ! 14714: case 0xe0: ! 14715: // DOS Protected Mode Services (DPMS) v1.0 is not installed ! 14716: if(REG16(BX) == 0x0000 && REG16(CX) == 0x4450 && REG16(DX) == 0x4d53) { ! 14717: break; ! 14718: } ! 14719: default: ! 14720: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 14721: REG16(AX) = 0x01; ! 14722: m_CF = 1; ! 14723: break; ! 14724: } ! 14725: } ! 14726: ! 14727: inline void msdos_int_2fh_46h() ! 14728: { ! 14729: switch(REG8(AL)) { ! 14730: case 0x80: ! 14731: // Windows v3.0 is not installed ! 14732: // REG8(AL) = 0x00; ! 14733: break; ! 14734: default: ! 14735: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 14736: REG16(AX) = 0x01; ! 14737: m_CF = 1; ! 14738: break; ! 14739: } ! 14740: } ! 14741: ! 14742: inline void msdos_int_2fh_48h() ! 14743: { ! 14744: switch(REG8(AL)) { ! 14745: case 0x00: ! 14746: // DOSKEY is not installed ! 14747: // REG8(AL) = 0x00; ! 14748: break; ! 14749: case 0x10: ! 14750: msdos_int_21h_0ah(); ! 14751: REG16(AX) = 0x00; ! 14752: break; ! 14753: default: ! 14754: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 14755: REG16(AX) = 0x01; ! 14756: m_CF = 1; ! 14757: break; ! 14758: } ! 14759: } ! 14760: ! 14761: inline void msdos_int_2fh_4ah() ! 14762: { ! 14763: switch(REG8(AL)) { ! 14764: #ifdef SUPPORT_HMA ! 14765: case 0x01: // DOS 5.0+ - Query Free HMA Space ! 14766: if(!is_hma_used_by_xms && !is_hma_used_by_int_2fh) { ! 14767: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) { ! 14768: // restore first free mcb in high memory area ! 14769: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0); ! 14770: } ! 14771: int offset = 0xffff; ! 14772: if((REG16(BX) = msdos_hma_mem_get_free(&offset)) != 0) { ! 14773: REG16(DI) = offset + 0x10; ! 14774: } else { ! 14775: REG16(DI) = 0xffff; ! 14776: } ! 14777: } else { ! 14778: // HMA is already used ! 14779: REG16(BX) = 0; ! 14780: REG16(DI) = 0xffff; ! 14781: } ! 14782: SREG(ES) = 0xffff; ! 14783: i386_load_segment_descriptor(ES); ! 14784: break; ! 14785: case 0x02: // DOS 5.0+ - Allocate HMA Space ! 14786: if(!is_hma_used_by_xms && !is_hma_used_by_int_2fh) { ! 14787: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) { ! 14788: // restore first free mcb in high memory area ! 14789: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0); ! 14790: } ! 14791: int size = REG16(BX), offset; ! 14792: if((size % 16) != 0) { ! 14793: size &= ~15; ! 14794: size += 16; ! 14795: } ! 14796: if((offset = msdos_hma_mem_alloc(size, current_psp)) != -1) { ! 14797: REG16(BX) = size; ! 14798: REG16(DI) = offset + 0x10; ! 14799: is_hma_used_by_int_2fh = true; ! 14800: } else { ! 14801: REG16(BX) = 0; ! 14802: REG16(DI) = 0xffff; ! 14803: } ! 14804: } else { ! 14805: // HMA is already used ! 14806: REG16(BX) = 0; ! 14807: REG16(DI) = 0xffff; ! 14808: } ! 14809: SREG(ES) = 0xffff; ! 14810: i386_load_segment_descriptor(ES); ! 14811: break; ! 14812: case 0x03: // Windows95 - (De)Allocate HMA Memory Block ! 14813: if(REG8(DL) == 0x00) { ! 14814: if(!is_hma_used_by_xms) { ! 14815: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) { ! 14816: // restore first free mcb in high memory area ! 14817: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0); ! 14818: is_hma_used_by_int_2fh = false; ! 14819: } ! 14820: int size = REG16(BX), offset; ! 14821: if((size % 16) != 0) { ! 14822: size &= ~15; ! 14823: size += 16; ! 14824: } ! 14825: if((offset = msdos_hma_mem_alloc(size, REG16(CX))) != -1) { ! 14826: // REG16(BX) = size; ! 14827: SREG(ES) = 0xffff; ! 14828: i386_load_segment_descriptor(ES); ! 14829: REG16(DI) = offset + 0x10; ! 14830: is_hma_used_by_int_2fh = true; ! 14831: } else { ! 14832: REG16(DI) = 0xffff; ! 14833: } ! 14834: } else { ! 14835: REG16(DI) = 0xffff; ! 14836: } ! 14837: } else if(REG8(DL) == 0x01) { ! 14838: if(!is_hma_used_by_xms) { ! 14839: int size = REG16(BX); ! 14840: if((size % 16) != 0) { ! 14841: size &= ~15; ! 14842: size += 16; ! 14843: } ! 14844: if(msdos_hma_mem_realloc(SREG_BASE(ES) + REG16(DI) - 0xffff0 - 0x10, size) != -1) { ! 14845: // memory block address is not changed ! 14846: } else { ! 14847: REG16(DI) = 0xffff; ! 14848: } ! 14849: } else { ! 14850: REG16(DI) = 0xffff; ! 14851: } ! 14852: } else if(REG8(DL) == 0x02) { ! 14853: if(!is_hma_used_by_xms) { ! 14854: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) { ! 14855: // restore first free mcb in high memory area ! 14856: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0); ! 14857: is_hma_used_by_int_2fh = false; ! 14858: } else { ! 14859: msdos_hma_mem_free(SREG_BASE(ES) + REG16(DI) - 0xffff0 - 0x10); ! 14860: if(msdos_hma_mem_get_free(NULL) == 0xffe0) { ! 14861: is_hma_used_by_int_2fh = false; ! 14862: } ! 14863: } ! 14864: } ! 14865: } else { ! 14866: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 14867: REG16(AX) = 0x01; ! 14868: m_CF = 1; ! 14869: } ! 14870: break; ! 14871: case 0x04: // Windows95 - Get Start of HMA Memory Chain ! 14872: if(!is_hma_used_by_xms) { ! 14873: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) { ! 14874: // restore first free mcb in high memory area ! 14875: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0); ! 14876: is_hma_used_by_int_2fh = false; ! 14877: } ! 14878: REG16(AX) = 0x0000; ! 14879: SREG(ES) = 0xffff; ! 14880: i386_load_segment_descriptor(ES); ! 14881: REG16(DI) = 0x10; ! 14882: } ! 14883: break; ! 14884: #else ! 14885: case 0x01: ! 14886: case 0x02: ! 14887: // HMA is already used ! 14888: REG16(BX) = 0x0000; ! 14889: SREG(ES) = 0xffff; ! 14890: i386_load_segment_descriptor(ES); ! 14891: REG16(DI) = 0xffff; ! 14892: break; ! 14893: case 0x03: ! 14894: // unable to allocate ! 14895: REG16(DI) = 0xffff; ! 14896: break; ! 14897: case 0x04: ! 14898: // function not supported, do not clear AX ! 14899: break; ! 14900: #endif ! 14901: case 0x10: ! 14902: switch(REG16(BX)) { ! 14903: case 0x0000: ! 14904: case 0x0001: ! 14905: case 0x0002: ! 14906: case 0x0003: ! 14907: case 0x0004: ! 14908: case 0x0005: ! 14909: case 0x0006: ! 14910: case 0x0007: ! 14911: case 0x0008: ! 14912: case 0x000a: ! 14913: case 0x1234: ! 14914: // SMARTDRV v4.00+ is not installed ! 14915: break; ! 14916: default: ! 14917: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 14918: REG16(AX) = 0x01; ! 14919: m_CF = 1; ! 14920: break; ! 14921: } ! 14922: break; ! 14923: case 0x11: ! 14924: switch(REG16(BX)) { ! 14925: case 0x0000: ! 14926: case 0x0001: ! 14927: case 0x0002: ! 14928: case 0x0003: ! 14929: case 0x0004: ! 14930: case 0x0005: ! 14931: case 0x0006: ! 14932: case 0x0007: ! 14933: case 0x0008: ! 14934: case 0x0009: ! 14935: case 0x000a: ! 14936: case 0x000b: ! 14937: case 0xfffe: ! 14938: case 0xffff: ! 14939: // DBLSPACE.BIN is not installed ! 14940: break; ! 14941: default: ! 14942: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 14943: REG16(AX) = 0x01; ! 14944: m_CF = 1; ! 14945: break; ! 14946: } ! 14947: break; ! 14948: case 0x12: ! 14949: if(REG16(CX) == 0x4d52 && REG16(DX) == 0x4349) { ! 14950: // Microsoft Realtime Compression Interface (MRCI) is not installed ! 14951: } else if(REG16(CX) == 0x5354 && REG16(DX) == 0x4143) { ! 14952: // Stacker 4 LZS Compression Interface (LZSAPI) is not installed ! 14953: } else { ! 14954: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 14955: REG16(AX) = 0x01; ! 14956: m_CF = 1; ! 14957: } ! 14958: break; ! 14959: case 0x13: ! 14960: // DBLSPACE.BIN is not installed ! 14961: break; ! 14962: default: ! 14963: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 14964: REG16(AX) = 0x01; ! 14965: m_CF = 1; ! 14966: break; ! 14967: } ! 14968: } ! 14969: ! 14970: inline void msdos_int_2fh_4bh() ! 14971: { ! 14972: switch(REG8(AL)) { ! 14973: case 0x01: ! 14974: case 0x02: ! 14975: // Task Switcher is not installed ! 14976: break; ! 14977: case 0x03: ! 14978: // this call is available from within DOSSHELL even if the task switcher is not installed ! 14979: REG16(AX) = REG16(BX) = 0x0000; // no more avaiable switcher id ! 14980: break; ! 14981: case 0x04: ! 14982: REG16(BX) = 0x0000; // free switcher id successfully ! 14983: break; ! 14984: case 0x05: ! 14985: REG16(BX) = 0x0000; // no instance data chain ! 14986: SREG(ES) = 0x0000; ! 14987: i386_load_segment_descriptor(ES); ! 14988: break; ! 14989: default: ! 14990: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 14991: REG16(AX) = 0x01; ! 14992: m_CF = 1; ! 14993: break; ! 14994: } ! 14995: } ! 14996: ! 14997: inline void msdos_int_2fh_4dh() ! 14998: { ! 14999: switch(REG8(AL)) { ! 15000: case 0x00: ! 15001: // KKCFUNC is not installed ??? ! 15002: break; ! 15003: default: ! 15004: // unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 15005: REG16(AX) = 0x01; // invalid function ! 15006: m_CF = 1; ! 15007: break; ! 15008: } ! 15009: } ! 15010: ! 15011: inline void msdos_int_2fh_4fh() ! 15012: { ! 15013: switch(REG8(AL)) { ! 15014: case 0x00: ! 15015: // BILING is installed ! 15016: REG16(AX) = 0x0000; ! 15017: REG8(DL) = 0x01; // major version ! 15018: REG8(DH) = 0x00; // minor version ! 15019: break; ! 15020: case 0x01: ! 15021: REG16(AX) = 0x0000; ! 15022: REG16(BX) = active_code_page; ! 15023: break; ! 15024: default: ! 15025: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 15026: REG16(AX) = 0x01; ! 15027: m_CF = 1; ! 15028: break; ! 15029: } ! 15030: } ! 15031: ! 15032: inline void msdos_int_2fh_55h() ! 15033: { ! 15034: switch(REG8(AL)) { ! 15035: case 0x00: ! 15036: case 0x01: ! 15037: // unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 15038: break; ! 15039: default: ! 15040: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 15041: REG16(AX) = 0x01; ! 15042: m_CF = 1; ! 15043: break; ! 15044: } ! 15045: } ! 15046: ! 15047: inline void msdos_int_2fh_56h() ! 15048: { ! 15049: switch(REG8(AL)) { ! 15050: case 0x00: ! 15051: // INTERLNK is not installed ! 15052: break; ! 15053: case 0x01: ! 15054: // this call is available from within SCANDISK even if INTERLNK is not installed ! 15055: // if(msdos_is_remote_drive(REG8(BH))) { ! 15056: // REG8(AL) = 0x00; ! 15057: // } ! 15058: break; ! 15059: default: ! 15060: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 15061: REG16(AX) = 0x01; ! 15062: m_CF = 1; ! 15063: break; ! 15064: } ! 15065: } ! 15066: ! 15067: inline void msdos_int_2fh_adh() ! 15068: { ! 15069: switch(REG8(AL)) { ! 15070: case 0x00: ! 15071: // DISPLAY.SYS is installed ! 15072: REG8(AL) = 0xff; ! 15073: REG16(BX) = 0x100; // ??? ! 15074: break; ! 15075: case 0x01: ! 15076: active_code_page = REG16(BX); ! 15077: msdos_nls_tables_update(); ! 15078: REG16(AX) = 0x01; ! 15079: break; ! 15080: case 0x02: ! 15081: REG16(BX) = active_code_page; ! 15082: break; ! 15083: case 0x03: ! 15084: // FIXME ! 15085: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 1; ! 15086: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2) = 3; ! 15087: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4) = 1; ! 15088: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 6) = active_code_page; ! 15089: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 8) = active_code_page; ! 15090: break; ! 15091: case 0x80: ! 15092: // KEYB.COM is not installed ! 15093: break; ! 15094: default: ! 15095: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 15096: REG16(AX) = 0x01; ! 15097: m_CF = 1; ! 15098: break; ! 15099: } ! 15100: } ! 15101: ! 15102: inline void msdos_int_2fh_aeh() ! 15103: { ! 15104: switch(REG8(AL)) { ! 15105: case 0x00: ! 15106: // FIXME: we need to check the given command line ! 15107: REG8(AL) = 0x00; // the command should be executed as usual ! 15108: // REG8(AL) = 0xff; // this command is a TSR extension to COMMAND.COM ! 15109: break; ! 15110: case 0x01: ! 15111: { ! 15112: char command[MAX_PATH]; ! 15113: memset(command, 0, sizeof(command)); ! 15114: memcpy(command, mem + SREG_BASE(DS) + REG16(SI) + 1, mem[SREG_BASE(DS) + REG16(SI)]); ! 15115: ! 15116: param_block_t *param = (param_block_t *)(mem + WORK_TOP); ! 15117: param->env_seg = 0; ! 15118: param->cmd_line.w.l = 44; ! 15119: param->cmd_line.w.h = (WORK_TOP >> 4); ! 15120: param->fcb1.w.l = 24; ! 15121: param->fcb1.w.h = (WORK_TOP >> 4); ! 15122: param->fcb2.w.l = 24; ! 15123: param->fcb2.w.h = (WORK_TOP >> 4); ! 15124: ! 15125: memset(mem + WORK_TOP + 24, 0x20, 20); ! 15126: ! 15127: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44); ! 15128: cmd_line->len = mem[SREG_BASE(DS) + REG16(BX) + 1]; ! 15129: memcpy(cmd_line->cmd, mem + SREG_BASE(DS) + REG16(BX) + 2, cmd_line->len); ! 15130: cmd_line->cmd[cmd_line->len] = 0x0d; ! 15131: ! 15132: try { ! 15133: msdos_process_exec(command, param, 0); ! 15134: } catch(...) { ! 15135: fatalerror("failed to start '%s' by int 2Fh, AX=AE01h\n", command); ! 15136: } ! 15137: } ! 15138: break; ! 15139: default: ! 15140: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 15141: REG16(AX) = 0x01; ! 15142: m_CF = 1; ! 15143: break; ! 15144: } ! 15145: } ! 15146: ! 15147: inline void msdos_int_2fh_b7h() ! 15148: { ! 15149: switch(REG8(AL)) { ! 15150: case 0x00: ! 15151: // APPEND is not installed ! 15152: // REG8(AL) = 0x00; ! 15153: break; ! 15154: case 0x06: ! 15155: REG16(BX) = 0x0000; ! 15156: break; ! 15157: case 0x07: ! 15158: case 0x11: ! 15159: // COMMAND.COM calls this service without checking APPEND is installed ! 15160: break; ! 15161: default: ! 15162: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 15163: REG16(AX) = 0x01; ! 15164: m_CF = 1; ! 15165: break; ! 15166: } ! 15167: } ! 15168: ! 15169: inline void msdos_int_33h_0000h() ! 15170: { ! 15171: REG16(AX) = 0xffff; // hardware/driver installed ! 15172: REG16(BX) = MAX_MOUSE_BUTTONS; ! 15173: } ! 15174: ! 15175: inline void msdos_int_33h_0001h() ! 15176: { ! 15177: if(mouse.hidden > 0) { ! 15178: mouse.hidden--; ! 15179: } ! 15180: if(mouse.hidden == 0) { ! 15181: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), (dwConsoleMode | ENABLE_MOUSE_INPUT | ENABLE_EXTENDED_FLAGS) & ~ENABLE_QUICK_EDIT_MODE); ! 15182: pic[1].imr &= ~0x10; // enable irq12 ! 15183: } ! 15184: } ! 15185: ! 15186: inline void msdos_int_33h_0002h() ! 15187: { ! 15188: mouse.hidden++; ! 15189: if(dwConsoleMode & (ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE)) { ! 15190: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode | ENABLE_EXTENDED_FLAGS); ! 15191: } else { ! 15192: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode); ! 15193: } ! 15194: pic[1].imr |= 0x10; // disable irq12 ! 15195: } ! 15196: ! 15197: inline void msdos_int_33h_0003h() ! 15198: { ! 15199: // if(mouse.hidden > 0) { ! 15200: update_console_input(); ! 15201: // } ! 15202: REG16(BX) = mouse.get_buttons(); ! 15203: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.position.x)); ! 15204: REG16(DX) = max(mouse.min_position.y & ~7, min(mouse.max_position.y & ~7, mouse.position.y)); ! 15205: } ! 15206: ! 15207: inline void msdos_int_33h_0004h() ! 15208: { ! 15209: mouse.position.x = REG16(CX); ! 15210: mouse.position.x = REG16(DX); ! 15211: } ! 15212: ! 15213: inline void msdos_int_33h_0005h() ! 15214: { ! 15215: // if(mouse.hidden > 0) { ! 15216: update_console_input(); ! 15217: // } ! 15218: if(REG16(BX) < MAX_MOUSE_BUTTONS) { ! 15219: int idx = REG16(BX); ! 15220: REG16(BX) = min(mouse.buttons[idx].pressed_times, 0x7fff); ! 15221: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.buttons[idx].pressed_position.x)); ! 15222: REG16(DX) = max(mouse.min_position.y & ~7, min(mouse.max_position.y & ~7, mouse.buttons[idx].pressed_position.y)); ! 15223: mouse.buttons[idx].pressed_times = 0; ! 15224: } else { ! 15225: REG16(BX) = REG16(CX) = REG16(DX) = 0x0000; ! 15226: } ! 15227: REG16(AX) = mouse.get_buttons(); ! 15228: } ! 15229: ! 15230: inline void msdos_int_33h_0006h() ! 15231: { ! 15232: // if(mouse.hidden > 0) { ! 15233: update_console_input(); ! 15234: // } ! 15235: if(REG16(BX) < MAX_MOUSE_BUTTONS) { ! 15236: int idx = REG16(BX); ! 15237: REG16(BX) = min(mouse.buttons[idx].released_times, 0x7fff); ! 15238: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.buttons[idx].released_position.x)); ! 15239: REG16(DX) = max(mouse.min_position.y & ~7, min(mouse.max_position.y & ~7, mouse.buttons[idx].released_position.y)); ! 15240: mouse.buttons[idx].released_times = 0; ! 15241: } else { ! 15242: REG16(BX) = REG16(CX) = REG16(DX) = 0x0000; ! 15243: } ! 15244: REG16(AX) = mouse.get_buttons(); ! 15245: } ! 15246: ! 15247: inline void msdos_int_33h_0007h() ! 15248: { ! 15249: mouse.min_position.x = min(REG16(CX), REG16(DX)); ! 15250: mouse.max_position.x = max(REG16(CX), REG16(DX)); ! 15251: } ! 15252: ! 15253: inline void msdos_int_33h_0008h() ! 15254: { ! 15255: mouse.min_position.y = min(REG16(CX), REG16(DX)); ! 15256: mouse.max_position.y = max(REG16(CX), REG16(DX)); ! 15257: } ! 15258: ! 15259: inline void msdos_int_33h_0009h() ! 15260: { ! 15261: mouse.hot_spot[0] = REG16(BX); ! 15262: mouse.hot_spot[1] = REG16(CX); ! 15263: } ! 15264: ! 15265: inline void msdos_int_33h_000ah() ! 15266: { ! 15267: mouse.screen_mask = REG16(CX); ! 15268: mouse.cursor_mask = REG16(DX); ! 15269: } ! 15270: ! 15271: inline void msdos_int_33h_000bh() ! 15272: { ! 15273: // if(mouse.hidden > 0) { ! 15274: update_console_input(); ! 15275: // } ! 15276: int dx = (mouse.position.x - mouse.prev_position.x) * mouse.mickey.x / 8; ! 15277: int dy = (mouse.position.y - mouse.prev_position.y) * mouse.mickey.y / 8; ! 15278: mouse.prev_position.x = mouse.position.x; ! 15279: mouse.prev_position.y = mouse.position.y; ! 15280: REG16(CX) = dx; ! 15281: REG16(DX) = dy; ! 15282: } ! 15283: ! 15284: inline void msdos_int_33h_000ch() ! 15285: { ! 15286: mouse.call_mask = REG16(CX); ! 15287: mouse.call_addr.w.l = REG16(DX); ! 15288: mouse.call_addr.w.h = SREG(ES); ! 15289: } ! 15290: ! 15291: inline void msdos_int_33h_000fh() ! 15292: { ! 15293: mouse.mickey.x = REG16(CX); ! 15294: mouse.mickey.y = REG16(DX); ! 15295: } ! 15296: ! 15297: inline void msdos_int_33h_0011h() ! 15298: { ! 15299: REG16(AX) = 0xffff; ! 15300: REG16(BX) = MAX_MOUSE_BUTTONS; ! 15301: } ! 15302: ! 15303: inline void msdos_int_33h_0014h() ! 15304: { ! 15305: UINT16 old_mask = mouse.call_mask; ! 15306: UINT16 old_ofs = mouse.call_addr.w.l; ! 15307: UINT16 old_seg = mouse.call_addr.w.h; ! 15308: ! 15309: mouse.call_mask = REG16(CX); ! 15310: mouse.call_addr.w.l = REG16(DX); ! 15311: mouse.call_addr.w.h = SREG(ES); ! 15312: ! 15313: REG16(CX) = old_mask; ! 15314: REG16(DX) = old_ofs; ! 15315: SREG(ES) = old_seg; ! 15316: i386_load_segment_descriptor(ES); ! 15317: } ! 15318: ! 15319: inline void msdos_int_33h_0015h() ! 15320: { ! 15321: REG16(BX) = sizeof(mouse); ! 15322: } ! 15323: ! 15324: inline void msdos_int_33h_0016h() ! 15325: { ! 15326: memcpy(mem + SREG_BASE(ES) + REG16(DX), &mouse, sizeof(mouse)); ! 15327: } ! 15328: ! 15329: inline void msdos_int_33h_0017h() ! 15330: { ! 15331: memcpy(&mouse, mem + SREG_BASE(ES) + REG16(DX), sizeof(mouse)); ! 15332: } ! 15333: ! 15334: inline void msdos_int_33h_0018h() ! 15335: { ! 15336: for(int i = 0; i < 8; i++) { ! 15337: if(REG16(CX) & (1 << i)) { ! 15338: if(mouse.call_addr_alt[i].dw && !(REG16(DX) == 0 && SREG(ES) == 0)) { ! 15339: // event handler already exists ! 15340: REG16(AX) = 0xffff; ! 15341: break; ! 15342: } ! 15343: mouse.call_addr_alt[i].w.l = REG16(DX); ! 15344: mouse.call_addr_alt[i].w.h = SREG(ES); ! 15345: } ! 15346: } ! 15347: } ! 15348: ! 15349: inline void msdos_int_33h_0019h() ! 15350: { ! 15351: UINT16 call_mask = REG16(CX); ! 15352: ! 15353: REG16(CX) = 0; ! 15354: ! 15355: for(int i = 0; i < 8; i++) { ! 15356: if((call_mask & (1 << i)) && mouse.call_addr_alt[i].dw) { ! 15357: for(int j = 0; j < 8; j++) { ! 15358: if((call_mask & (1 << j)) && mouse.call_addr_alt[i].dw == mouse.call_addr_alt[j].dw) { ! 15359: REG16(CX) |= (1 << j); ! 15360: } ! 15361: } ! 15362: REG16(DX) = mouse.call_addr_alt[i].w.l; ! 15363: REG16(BX) = mouse.call_addr_alt[i].w.h; ! 15364: break; ! 15365: } ! 15366: } ! 15367: } ! 15368: ! 15369: inline void msdos_int_33h_001ah() ! 15370: { ! 15371: mouse.sensitivity[0] = REG16(BX); ! 15372: mouse.sensitivity[1] = REG16(CX); ! 15373: mouse.sensitivity[2] = REG16(DX); ! 15374: } ! 15375: ! 15376: inline void msdos_int_33h_001bh() ! 15377: { ! 15378: REG16(BX) = mouse.sensitivity[0]; ! 15379: REG16(CX) = mouse.sensitivity[1]; ! 15380: REG16(DX) = mouse.sensitivity[2]; ! 15381: } ! 15382: ! 15383: inline void msdos_int_33h_001dh() ! 15384: { ! 15385: mouse.display_page = REG16(BX); ! 15386: } ! 15387: ! 15388: inline void msdos_int_33h_001eh() ! 15389: { ! 15390: REG16(BX) = mouse.display_page; ! 15391: } ! 15392: ! 15393: inline void msdos_int_33h_001fh() ! 15394: { ! 15395: // from DOSBox ! 15396: REG16(BX) = 0x0000; ! 15397: SREG(ES) = 0x0000; ! 15398: i386_load_segment_descriptor(ES); ! 15399: mouse.enabled = false; ! 15400: mouse.old_hidden = mouse.hidden; ! 15401: mouse.hidden = 1; ! 15402: } ! 15403: ! 15404: inline void msdos_int_33h_0020h() ! 15405: { ! 15406: // from DOSBox ! 15407: mouse.enabled = true; ! 15408: mouse.hidden = mouse.old_hidden; ! 15409: } ! 15410: ! 15411: inline void msdos_int_33h_0021h() ! 15412: { ! 15413: REG16(AX) = 0xffff; ! 15414: REG16(BX) = MAX_MOUSE_BUTTONS; ! 15415: } ! 15416: ! 15417: inline void msdos_int_33h_0022h() ! 15418: { ! 15419: mouse.language = REG16(BX); ! 15420: } ! 15421: ! 15422: inline void msdos_int_33h_0023h() ! 15423: { ! 15424: REG16(BX) = mouse.language; ! 15425: } ! 15426: ! 15427: inline void msdos_int_33h_0024h() ! 15428: { ! 15429: REG16(BX) = 0x0805; // V8.05 ! 15430: REG16(CX) = 0x0400; // PS/2 ! 15431: } ! 15432: ! 15433: inline void msdos_int_33h_0025h() ! 15434: { ! 15435: REG16(AX) = 0x8000; // driver (not TSR), software text cursor ! 15436: } ! 15437: ! 15438: inline void msdos_int_33h_0026h() ! 15439: { ! 15440: REG16(BX) = 0x0000; ! 15441: REG16(CX) = mouse.max_position.x; ! 15442: REG16(DX) = mouse.max_position.y; ! 15443: } ! 15444: ! 15445: inline void msdos_int_33h_0027h() ! 15446: { ! 15447: // if(mouse.hidden > 0) { ! 15448: update_console_input(); ! 15449: // } ! 15450: int dx = (mouse.position.x - mouse.prev_position.x) * mouse.mickey.x / 8; ! 15451: int dy = (mouse.position.y - mouse.prev_position.y) * mouse.mickey.y / 8; ! 15452: mouse.prev_position.x = mouse.position.x; ! 15453: mouse.prev_position.y = mouse.position.y; ! 15454: REG16(AX) = mouse.screen_mask; ! 15455: REG16(BX) = mouse.cursor_mask; ! 15456: REG16(CX) = dx; ! 15457: REG16(DX) = dy; ! 15458: } ! 15459: ! 15460: inline void msdos_int_33h_0028h() ! 15461: { ! 15462: if(REG16(CX) != 0) { ! 15463: UINT8 tmp = REG8(AL); ! 15464: REG8(AL) = REG8(CL); ! 15465: pcbios_int_10h_00h(); ! 15466: REG8(AL) = tmp; ! 15467: } ! 15468: REG8(CL) = 0x00; // successful ! 15469: } ! 15470: ! 15471: inline void msdos_int_33h_0029h() ! 15472: { ! 15473: switch(REG16(CX)) { ! 15474: case 0x0000: ! 15475: REG16(CX) = 0x0003; ! 15476: sprintf((char *)(mem + WORK_TOP), "TEXT Mode (80x25)$"); ! 15477: break; ! 15478: case 0x0003: ! 15479: REG16(CX) = 0x0070; ! 15480: sprintf((char *)(mem + WORK_TOP), "V-TEXT Mode (%dx%d)$", scr_width, scr_height); ! 15481: break; ! 15482: case 0x0070: ! 15483: REG16(CX) = 0x0071; ! 15484: sprintf((char *)(mem + WORK_TOP), "Extended CGA V-TEXT Mode (%dx%d)$", scr_width, scr_height); ! 15485: break; ! 15486: case 0x0071: ! 15487: REG16(CX) = 0x0073; ! 15488: sprintf((char *)(mem + WORK_TOP), "Extended CGA TEXT Mode (80x25)$"); ! 15489: break; ! 15490: default: ! 15491: REG16(CX) = 0x0000; ! 15492: break; ! 15493: } ! 15494: if(REG16(CX) != 0) { ! 15495: SREG(DS) = (WORK_TOP >> 4); ! 15496: } else { ! 15497: SREG(DS) = 0x0000; ! 15498: } ! 15499: i386_load_segment_descriptor(DS); ! 15500: REG16(DX) = 0x0000; ! 15501: } ! 15502: ! 15503: inline void msdos_int_33h_002ah() ! 15504: { ! 15505: REG16(AX) = -mouse.hidden; ! 15506: REG16(BX) = mouse.hot_spot[0]; ! 15507: REG16(CX) = mouse.hot_spot[1]; ! 15508: REG16(DX) = 4; // PS/2 ! 15509: } ! 15510: ! 15511: inline void msdos_int_33h_0031h() ! 15512: { ! 15513: REG16(AX) = mouse.min_position.x; ! 15514: REG16(BX) = mouse.min_position.y; ! 15515: REG16(CX) = mouse.max_position.x; ! 15516: REG16(DX) = mouse.max_position.y; ! 15517: } ! 15518: ! 15519: inline void msdos_int_33h_0032h() ! 15520: { ! 15521: REG16(AX) = 0; ! 15522: REG16(AX) |= 0x8000; // 0025h ! 15523: REG16(AX) |= 0x4000; // 0026h ! 15524: REG16(AX) |= 0x2000; // 0027h ! 15525: // REG16(AX) |= 0x1000; // 0028h ! 15526: // REG16(AX) |= 0x0800; // 0029h ! 15527: REG16(AX) |= 0x0400; // 002ah ! 15528: // REG16(AX) |= 0x0200; // 002bh ! 15529: // REG16(AX) |= 0x0100; // 002ch ! 15530: // REG16(AX) |= 0x0080; // 002dh ! 15531: // REG16(AX) |= 0x0040; // 002eh ! 15532: REG16(AX) |= 0x0020; // 002fh ! 15533: // REG16(AX) |= 0x0010; // 0030h ! 15534: REG16(AX) |= 0x0008; // 0031h ! 15535: REG16(AX) |= 0x0004; // 0032h ! 15536: // REG16(AX) |= 0x0002; // 0033h ! 15537: // REG16(AX) |= 0x0001; // 0034h ! 15538: } ! 15539: ! 15540: inline void msdos_int_33h_004dh() ! 15541: { ! 15542: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), "Copyright 2017 MS-DOS Player"); ! 15543: } ! 15544: ! 15545: inline void msdos_int_33h_006dh() ! 15546: { ! 15547: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x08; // V8.05 ! 15548: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = 0x05; ! 15549: } ! 15550: ! 15551: inline void msdos_int_67h_40h() ! 15552: { ! 15553: if(!support_ems) { ! 15554: REG8(AH) = 0x84; ! 15555: } else { ! 15556: REG8(AH) = 0x00; ! 15557: } ! 15558: } ! 15559: ! 15560: inline void msdos_int_67h_41h() ! 15561: { ! 15562: if(!support_ems) { ! 15563: REG8(AH) = 0x84; ! 15564: } else { ! 15565: REG8(AH) = 0x00; ! 15566: REG16(BX) = EMS_TOP >> 4; ! 15567: } ! 15568: } ! 15569: ! 15570: inline void msdos_int_67h_42h() ! 15571: { ! 15572: if(!support_ems) { ! 15573: REG8(AH) = 0x84; ! 15574: } else { ! 15575: REG8(AH) = 0x00; ! 15576: REG16(BX) = free_ems_pages; ! 15577: REG16(DX) = MAX_EMS_PAGES; ! 15578: } ! 15579: } ! 15580: ! 15581: inline void msdos_int_67h_43h() ! 15582: { ! 15583: if(!support_ems) { ! 15584: REG8(AH) = 0x84; ! 15585: } else if(REG16(BX) > MAX_EMS_PAGES) { ! 15586: REG8(AH) = 0x87; ! 15587: } else if(REG16(BX) > free_ems_pages) { ! 15588: REG8(AH) = 0x88; ! 15589: } else if(REG16(BX) == 0) { ! 15590: REG8(AH) = 0x89; ! 15591: } else { ! 15592: for(int i = 1; i <= MAX_EMS_HANDLES; i++) { ! 15593: if(!ems_handles[i].allocated) { ! 15594: ems_allocate_pages(i, REG16(BX)); ! 15595: REG8(AH) = 0x00; ! 15596: REG16(DX) = i; ! 15597: return; ! 15598: } ! 15599: } ! 15600: REG8(AH) = 0x85; ! 15601: } ! 15602: } ! 15603: ! 15604: inline void msdos_int_67h_44h() ! 15605: { ! 15606: if(!support_ems) { ! 15607: REG8(AH) = 0x84; ! 15608: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) { ! 15609: REG8(AH) = 0x83; ! 15610: } else if(!(REG16(BX) == 0xffff || REG16(BX) < ems_handles[REG16(DX)].pages)) { ! 15611: REG8(AH) = 0x8a; ! 15612: // } else if(!(REG8(AL) < 4)) { ! 15613: // REG8(AH) = 0x8b; ! 15614: } else if(REG16(BX) == 0xffff) { ! 15615: ems_unmap_page(REG8(AL) & 3); ! 15616: REG8(AH) = 0x00; ! 15617: } else { ! 15618: ems_map_page(REG8(AL) & 3, REG16(DX), REG16(BX)); ! 15619: REG8(AH) = 0x00; ! 15620: } ! 15621: } ! 15622: ! 15623: inline void msdos_int_67h_45h() ! 15624: { ! 15625: if(!support_ems) { ! 15626: REG8(AH) = 0x84; ! 15627: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) { ! 15628: REG8(AH) = 0x83; ! 15629: } else { ! 15630: ems_release_pages(REG16(DX)); ! 15631: REG8(AH) = 0x00; ! 15632: } ! 15633: } ! 15634: ! 15635: inline void msdos_int_67h_46h() ! 15636: { ! 15637: if(!support_ems) { ! 15638: REG8(AH) = 0x84; ! 15639: } else { ! 15640: // REG16(AX) = 0x0032; // EMS 3.2 ! 15641: REG16(AX) = 0x0040; // EMS 4.0 ! 15642: } ! 15643: } ! 15644: ! 15645: inline void msdos_int_67h_47h() ! 15646: { ! 15647: // NOTE: the map data should be stored in the specified ems page, not process data ! 15648: process_t *process = msdos_process_info_get(current_psp); ! 15649: ! 15650: if(!support_ems) { ! 15651: REG8(AH) = 0x84; ! 15652: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) { ! 15653: // REG8(AH) = 0x83; ! 15654: } else if(process->ems_pages_stored) { ! 15655: REG8(AH) = 0x8d; ! 15656: } else { ! 15657: for(int i = 0; i < 4; i++) { ! 15658: process->ems_pages[i].handle = ems_pages[i].handle; ! 15659: process->ems_pages[i].page = ems_pages[i].page; ! 15660: process->ems_pages[i].mapped = ems_pages[i].mapped; ! 15661: } ! 15662: process->ems_pages_stored = true; ! 15663: REG8(AH) = 0x00; ! 15664: } ! 15665: } ! 15666: ! 15667: inline void msdos_int_67h_48h() ! 15668: { ! 15669: // NOTE: the map data should be restored from the specified ems page, not process data ! 15670: process_t *process = msdos_process_info_get(current_psp); ! 15671: ! 15672: if(!support_ems) { ! 15673: REG8(AH) = 0x84; ! 15674: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) { ! 15675: // REG8(AH) = 0x83; ! 15676: } else if(!process->ems_pages_stored) { ! 15677: REG8(AH) = 0x8e; ! 15678: } else { ! 15679: for(int i = 0; i < 4; i++) { ! 15680: if(process->ems_pages[i].mapped) { ! 15681: ems_map_page(i, process->ems_pages[i].handle, process->ems_pages[i].page); ! 15682: } else { ! 15683: ems_unmap_page(i); ! 15684: } ! 15685: } ! 15686: process->ems_pages_stored = false; ! 15687: REG8(AH) = 0x00; ! 15688: } ! 15689: } ! 15690: ! 15691: inline void msdos_int_67h_4bh() ! 15692: { ! 15693: if(!support_ems) { ! 15694: REG8(AH) = 0x84; ! 15695: } else { ! 15696: REG8(AH) = 0x00; ! 15697: REG16(BX) = 0; ! 15698: for(int i = 1; i <= MAX_EMS_HANDLES; i++) { ! 15699: if(ems_handles[i].allocated) { ! 15700: REG16(BX)++; ! 15701: } ! 15702: } ! 15703: } ! 15704: } ! 15705: ! 15706: inline void msdos_int_67h_4ch() ! 15707: { ! 15708: if(!support_ems) { ! 15709: REG8(AH) = 0x84; ! 15710: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) { ! 15711: REG8(AH) = 0x83; ! 15712: } else { ! 15713: REG8(AH) = 0x00; ! 15714: REG16(BX) = ems_handles[REG16(DX)].pages; ! 15715: } ! 15716: } ! 15717: ! 15718: inline void msdos_int_67h_4dh() ! 15719: { ! 15720: if(!support_ems) { ! 15721: REG8(AH) = 0x84; ! 15722: } else { ! 15723: REG8(AH) = 0x00; ! 15724: REG16(BX) = 0; ! 15725: for(int i = 1; i <= MAX_EMS_HANDLES; i++) { ! 15726: if(ems_handles[i].allocated) { ! 15727: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 0) = i; ! 15728: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 2) = ems_handles[i].pages; ! 15729: REG16(BX)++; ! 15730: } ! 15731: } ! 15732: } ! 15733: } ! 15734: ! 15735: inline void msdos_int_67h_4eh() ! 15736: { ! 15737: if(!support_ems) { ! 15738: REG8(AH) = 0x84; ! 15739: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01 || REG8(AL) == 0x02) { ! 15740: if(REG8(AL) == 0x00 || REG8(AL) == 0x02) { ! 15741: // save page map ! 15742: for(int i = 0; i < 4; i++) { ! 15743: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = ems_pages[i].mapped ? ems_pages[i].handle : 0xffff; ! 15744: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = ems_pages[i].mapped ? ems_pages[i].page : 0xffff; ! 15745: } ! 15746: } ! 15747: if(REG8(AL) == 0x01 || REG8(AL) == 0x02) { ! 15748: // restore page map ! 15749: for(int i = 0; i < 4; i++) { ! 15750: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0); ! 15751: UINT16 page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2); ! 15752: ! 15753: if(handle >= 1 && handle <= MAX_EMS_HANDLES && ems_handles[handle].allocated && page < ems_handles[handle].pages) { ! 15754: ems_map_page(i, handle, page); ! 15755: } else { ! 15756: ems_unmap_page(i); ! 15757: } ! 15758: } ! 15759: } ! 15760: REG8(AH) = 0x00; ! 15761: } else if(REG8(AL) == 0x03) { ! 15762: REG8(AH) = 0x00; ! 15763: REG8(AL) = 4 * 4; ! 15764: } else { ! 15765: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 15766: REG8(AH) = 0x8f; ! 15767: } ! 15768: } ! 15769: ! 15770: inline void msdos_int_67h_4fh() ! 15771: { ! 15772: if(!support_ems) { ! 15773: REG8(AH) = 0x84; ! 15774: } else if(REG8(AL) == 0x00) { ! 15775: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI)); ! 15776: ! 15777: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI)) = count; ! 15778: for(int i = 0; i < count; i++) { ! 15779: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 2 * i); ! 15780: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000; ! 15781: ! 15782: // if(!(physical < 4)) { ! 15783: // REG8(AH) = 0x8b; ! 15784: // return; ! 15785: // } ! 15786: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 0) = segment; ! 15787: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 2) = ems_pages[physical & 3].mapped ? ems_pages[physical & 3].handle : 0xffff; ! 15788: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 4) = ems_pages[physical & 3].mapped ? ems_pages[physical & 3].page : 0xffff; ! 15789: } ! 15790: REG8(AH) = 0x00; ! 15791: } else if(REG8(AL) == 0x01) { ! 15792: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI)); ! 15793: ! 15794: for(int i = 0; i < count; i++) { ! 15795: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 0); ! 15796: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000; ! 15797: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 2); ! 15798: UINT16 logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 4); ! 15799: ! 15800: // if(!(physical < 4)) { ! 15801: // REG8(AH) = 0x8b; ! 15802: // return; ! 15803: // } else ! 15804: if(handle >= 1 && handle <= MAX_EMS_HANDLES && ems_handles[handle].allocated && logical < ems_handles[handle].pages) { ! 15805: ems_map_page(physical & 3, handle, logical); ! 15806: } else { ! 15807: ems_unmap_page(physical & 3); ! 15808: } ! 15809: } ! 15810: REG8(AH) = 0x00; ! 15811: } else if(REG8(AL) == 0x02) { ! 15812: REG8(AH) = 0x00; ! 15813: REG8(AL) = 2 + REG16(BX) * 6; ! 15814: } else { ! 15815: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 15816: REG8(AH) = 0x8f; ! 15817: } ! 15818: } ! 15819: ! 15820: inline void msdos_int_67h_50h() ! 15821: { ! 15822: if(!support_ems) { ! 15823: REG8(AH) = 0x84; ! 15824: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) { ! 15825: REG8(AH) = 0x83; ! 15826: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) { ! 15827: for(int i = 0; i < REG16(CX); i++) { ! 15828: int logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0); ! 15829: int physical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2); ! 15830: ! 15831: if(REG8(AL) == 0x01) { ! 15832: physical = ((physical << 4) - EMS_TOP) / 0x4000; ! 15833: } ! 15834: // if(!(physical < 4)) { ! 15835: // REG8(AH) = 0x8b; ! 15836: // return; ! 15837: // } else ! 15838: if(logical == 0xffff) { ! 15839: ems_unmap_page(physical & 3); ! 15840: } else if(logical < ems_handles[REG16(DX)].pages) { ! 15841: ems_map_page(physical & 3, REG16(DX), logical); ! 15842: } else { ! 15843: REG8(AH) = 0x8a; ! 15844: return; ! 15845: } ! 15846: } ! 15847: REG8(AH) = 0x00; ! 15848: } else { ! 15849: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 15850: REG8(AH) = 0x8f; ! 15851: } ! 15852: } ! 15853: ! 15854: inline void msdos_int_67h_51h() ! 15855: { ! 15856: if(!support_ems) { ! 15857: REG8(AH) = 0x84; ! 15858: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) { ! 15859: REG8(AH) = 0x83; ! 15860: } else if(REG16(BX) > MAX_EMS_PAGES) { ! 15861: REG8(AH) = 0x87; ! 15862: } else if(REG16(BX) > free_ems_pages + ems_handles[REG16(DX)].pages) { ! 15863: REG8(AH) = 0x88; ! 15864: } else { ! 15865: ems_reallocate_pages(REG16(DX), REG16(BX)); ! 15866: REG8(AH) = 0x00; ! 15867: } ! 15868: } ! 15869: ! 15870: inline void msdos_int_67h_52h() ! 15871: { ! 15872: if(!support_ems) { ! 15873: REG8(AH) = 0x84; ! 15874: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) { ! 15875: // REG8(AH) = 0x83; ! 15876: } else if(REG8(AL) == 0x00) { ! 15877: REG8(AL) = 0x00; // handle is volatile ! 15878: REG8(AH) = 0x00; ! 15879: } else if(REG8(AL) == 0x01) { ! 15880: if(REG8(BL) == 0x00) { ! 15881: REG8(AH) = 0x00; ! 15882: } else { ! 15883: REG8(AH) = 0x90; // undefined attribute type ! 15884: } ! 15885: } else if(REG8(AL) == 0x02) { ! 15886: REG8(AL) = 0x00; // only volatile handles supported ! 15887: REG8(AH) = 0x00; ! 15888: } else { ! 15889: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 15890: REG8(AH) = 0x8f; ! 15891: } ! 15892: } ! 15893: ! 15894: inline void msdos_int_67h_53h() ! 15895: { ! 15896: if(!support_ems) { ! 15897: REG8(AH) = 0x84; ! 15898: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) { ! 15899: REG8(AH) = 0x83; ! 15900: } else if(REG8(AL) == 0x00) { ! 15901: memcpy(mem + SREG_BASE(ES) + REG16(DI), ems_handles[REG16(DX)].name, 8); ! 15902: REG8(AH) = 0x00; ! 15903: } else if(REG8(AL) == 0x01) { ! 15904: for(int i = 1; i <= MAX_EMS_HANDLES; i++) { ! 15905: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) { ! 15906: REG8(AH) = 0xa1; ! 15907: return; ! 15908: } ! 15909: } ! 15910: REG8(AH) = 0x00; ! 15911: memcpy(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8); ! 15912: } else { ! 15913: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 15914: REG8(AH) = 0x8f; ! 15915: } ! 15916: } ! 15917: ! 15918: inline void msdos_int_67h_54h() ! 15919: { ! 15920: if(!support_ems) { ! 15921: REG8(AH) = 0x84; ! 15922: } else if(REG8(AL) == 0x00) { ! 15923: for(int i = 1; i <= MAX_EMS_HANDLES; i++) { ! 15924: if(ems_handles[i].allocated) { ! 15925: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, ems_handles[i].name, 10); ! 15926: } else { ! 15927: memset(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, 0, 10); ! 15928: } ! 15929: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 0) = i; ! 15930: } ! 15931: REG8(AH) = 0x00; ! 15932: REG8(AL) = MAX_EMS_HANDLES; ! 15933: } else if(REG8(AL) == 0x01) { ! 15934: REG8(AH) = 0xa0; // not found ! 15935: for(int i = 1; i <= MAX_EMS_HANDLES; i++) { ! 15936: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) { ! 15937: REG8(AH) = 0x00; ! 15938: REG16(DX) = i; ! 15939: break; ! 15940: } ! 15941: } ! 15942: } else if(REG8(AL) == 0x02) { ! 15943: REG8(AH) = 0x00; ! 15944: REG16(BX) = MAX_EMS_HANDLES; ! 15945: } else { ! 15946: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 15947: REG8(AH) = 0x8f; ! 15948: } ! 15949: } ! 15950: ! 15951: inline void msdos_int_67h_55h() ! 15952: { ! 15953: if(!support_ems) { ! 15954: REG8(AH) = 0x84; ! 15955: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) { ! 15956: REG8(AH) = 0x83; ! 15957: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) { ! 15958: UINT16 jump_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0); ! 15959: UINT16 jump_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2); ! 15960: UINT8 entries = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 4); ! 15961: UINT16 map_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 5); ! 15962: UINT16 map_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 7); ! 15963: ! 15964: for(int i = 0; i < (int)entries; i++) { ! 15965: int logical = *(UINT16 *)(mem + (map_seg << 4) + map_ofs + 4 * i + 0); ! 15966: int physical = *(UINT16 *)(mem + (map_seg << 4) + map_ofs + 4 * i + 2); ! 15967: ! 15968: if(REG8(AL) == 0x01) { ! 15969: physical = ((physical << 4) - EMS_TOP) / 0x4000; ! 15970: } ! 15971: // if(!(physical < 4)) { ! 15972: // REG8(AH) = 0x8b; ! 15973: // return; ! 15974: // } else ! 15975: if(logical == 0xffff) { ! 15976: ems_unmap_page(physical & 3); ! 15977: } else if(logical < ems_handles[REG16(DX)].pages) { ! 15978: ems_map_page(physical & 3, REG16(DX), logical); ! 15979: } else { ! 15980: REG8(AH) = 0x8a; ! 15981: return; ! 15982: } ! 15983: } ! 15984: i386_jmp_far(jump_seg, jump_ofs); ! 15985: REG8(AH) = 0x00; ! 15986: } else { ! 15987: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 15988: REG8(AH) = 0x8f; ! 15989: } ! 15990: } ! 15991: ! 15992: inline void msdos_int_67h_56h() ! 15993: { ! 15994: if(!support_ems) { ! 15995: REG8(AH) = 0x84; ! 15996: } else if(REG8(AL) == 0x02) { ! 15997: REG16(BX) = (2 + 2) * 4; ! 15998: REG8(AH) = 0x00; ! 15999: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) { ! 16000: REG8(AH) = 0x83; ! 16001: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) { ! 16002: UINT16 call_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0); ! 16003: UINT16 call_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2); ! 16004: UINT8 new_entries = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 4); ! 16005: UINT16 new_map_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 5); ! 16006: UINT16 new_map_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 7); ! 16007: #if 0 ! 16008: UINT8 old_entries = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 9); ! 16009: UINT16 old_map_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 10); ! 16010: UINT16 old_map_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 12); ! 16011: #endif ! 16012: UINT16 handles[4], pages[4]; ! 16013: ! 16014: // alter page map and call routine is at fffc:001f ! 16015: if(!(call_seg == 0 && call_ofs == 0)) { ! 16016: mem[DUMMY_TOP + 0x1f] = 0x9a; // call far ! 16017: mem[DUMMY_TOP + 0x20] = (call_ofs >> 0) & 0xff; ! 16018: mem[DUMMY_TOP + 0x21] = (call_ofs >> 8) & 0xff; ! 16019: mem[DUMMY_TOP + 0x22] = (call_seg >> 0) & 0xff; ! 16020: mem[DUMMY_TOP + 0x23] = (call_seg >> 8) & 0xff; ! 16021: } else { ! 16022: // invalid call addr :-( ! 16023: mem[DUMMY_TOP + 0x1f] = 0x90; // nop ! 16024: mem[DUMMY_TOP + 0x20] = 0x90; // nop ! 16025: mem[DUMMY_TOP + 0x21] = 0x90; // nop ! 16026: mem[DUMMY_TOP + 0x22] = 0x90; // nop ! 16027: mem[DUMMY_TOP + 0x23] = 0x90; // nop ! 16028: } ! 16029: // do call far (push cs/ip) in old mapping ! 16030: i386_call_far(DUMMY_TOP >> 4, 0x001f); ! 16031: ! 16032: // get old mapping data ! 16033: #if 0 ! 16034: for(int i = 0; i < (int)old_entries; i++) { ! 16035: int logical = *(UINT16 *)(mem + (old_map_seg << 4) + old_map_ofs + 4 * i + 0); ! 16036: int physical = *(UINT16 *)(mem + (old_map_seg << 4) + old_map_ofs + 4 * i + 2); ! 16037: ! 16038: if(REG8(AL) == 0x01) { ! 16039: physical = ((physical << 4) - EMS_TOP) / 0x4000; ! 16040: } ! 16041: // if(!(physical < 4)) { ! 16042: // REG8(AH) = 0x8b; ! 16043: // return; ! 16044: // } else ! 16045: if(logical == 0xffff) { ! 16046: ems_unmap_page(physical & 3); ! 16047: } else if(logical < ems_handles[REG16(DX)].pages) { ! 16048: ems_map_page(physical & 3, REG16(DX), logical); ! 16049: } else { ! 16050: REG8(AH) = 0x8a; ! 16051: return; ! 16052: } ! 16053: } ! 16054: #endif ! 16055: for(int i = 0; i < 4; i++) { ! 16056: handles[i] = ems_pages[i].mapped ? ems_pages[i].handle : 0xffff; ! 16057: pages [i] = ems_pages[i].mapped ? ems_pages[i].page : 0xffff; ! 16058: } ! 16059: ! 16060: // set new mapping ! 16061: for(int i = 0; i < (int)new_entries; i++) { ! 16062: int logical = *(UINT16 *)(mem + (new_map_seg << 4) + new_map_ofs + 4 * i + 0); ! 16063: int physical = *(UINT16 *)(mem + (new_map_seg << 4) + new_map_ofs + 4 * i + 2); ! 16064: ! 16065: if(REG8(AL) == 0x01) { ! 16066: physical = ((physical << 4) - EMS_TOP) / 0x4000; ! 16067: } ! 16068: // if(!(physical < 4)) { ! 16069: // REG8(AH) = 0x8b; ! 16070: // return; ! 16071: // } else ! 16072: if(logical == 0xffff) { ! 16073: ems_unmap_page(physical & 3); ! 16074: } else if(logical < ems_handles[REG16(DX)].pages) { ! 16075: ems_map_page(physical & 3, REG16(DX), logical); ! 16076: } else { ! 16077: REG8(AH) = 0x8a; ! 16078: return; ! 16079: } ! 16080: } ! 16081: ! 16082: // push old mapping data in new mapping ! 16083: for(int i = 0; i < 4; i++) { ! 16084: i386_push16(handles[i]); ! 16085: i386_push16(pages [i]); ! 16086: } ! 16087: REG8(AH) = 0x00; ! 16088: } else { ! 16089: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 16090: REG8(AH) = 0x8f; ! 16091: } ! 16092: } ! 16093: ! 16094: inline void msdos_int_67h_57h_tmp() ! 16095: { ! 16096: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00); ! 16097: UINT8 src_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04); ! 16098: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x05); ! 16099: UINT16 src_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07); ! 16100: UINT16 src_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x09); ! 16101: UINT8 dest_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0b); ! 16102: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c); ! 16103: UINT16 dest_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0e); ! 16104: UINT16 dest_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x10); ! 16105: ! 16106: UINT8 *src_buffer = NULL, *dest_buffer = NULL; ! 16107: UINT32 src_addr, dest_addr; ! 16108: UINT32 src_addr_max, dest_addr_max; ! 16109: ! 16110: if(src_type == 0) { ! 16111: src_buffer = mem; ! 16112: src_addr = (src_seg << 4) + src_ofs; ! 16113: src_addr_max = MAX_MEM; ! 16114: } else { ! 16115: if(!(src_handle >= 1 && src_handle <= MAX_EMS_HANDLES && ems_handles[src_handle].allocated)) { ! 16116: REG8(AH) = 0x83; ! 16117: return; ! 16118: } else if(!(src_seg < ems_handles[src_handle].pages)) { ! 16119: REG8(AH) = 0x8a; ! 16120: return; ! 16121: } ! 16122: if(ems_handles[src_handle].buffer != NULL) { ! 16123: src_buffer = ems_handles[src_handle].buffer + 0x4000 * src_seg; ! 16124: } ! 16125: src_addr = src_ofs; ! 16126: src_addr_max = 0x4000 * (ems_handles[src_handle].pages - src_seg); ! 16127: } ! 16128: if(dest_type == 0) { ! 16129: dest_buffer = mem; ! 16130: dest_addr = (dest_seg << 4) + dest_ofs; ! 16131: dest_addr_max = MAX_MEM; ! 16132: } else { ! 16133: if(!(dest_handle >= 1 && dest_handle <= MAX_EMS_HANDLES && ems_handles[dest_handle].allocated)) { ! 16134: REG8(AH) = 0x83; ! 16135: return; ! 16136: } else if(!(dest_seg < ems_handles[dest_handle].pages)) { ! 16137: REG8(AH) = 0x8a; ! 16138: return; ! 16139: } ! 16140: if(ems_handles[dest_handle].buffer != NULL) { ! 16141: dest_buffer = ems_handles[dest_handle].buffer + 0x4000 * dest_seg; ! 16142: } ! 16143: dest_addr = dest_ofs; ! 16144: dest_addr_max = 0x4000 * (ems_handles[dest_handle].pages - dest_seg); ! 16145: } ! 16146: if(src_buffer != NULL && dest_buffer != NULL) { ! 16147: for(int i = 0; i < copy_length; i++) { ! 16148: if(src_addr < src_addr_max && dest_addr < dest_addr_max) { ! 16149: if(REG8(AL) == 0x00) { ! 16150: dest_buffer[dest_addr++] = src_buffer[src_addr++]; ! 16151: } else if(REG8(AL) == 0x01) { ! 16152: UINT8 tmp = dest_buffer[dest_addr]; ! 16153: dest_buffer[dest_addr++] = src_buffer[src_addr]; ! 16154: src_buffer[src_addr++] = tmp; ! 16155: } ! 16156: } else { ! 16157: REG8(AH) = 0x93; ! 16158: return; ! 16159: } ! 16160: } ! 16161: REG8(AH) = 0x00; ! 16162: } else { ! 16163: REG8(AH) = 0x80; ! 16164: } ! 16165: } ! 16166: ! 16167: inline void msdos_int_67h_57h() ! 16168: { ! 16169: if(!support_ems) { ! 16170: REG8(AH) = 0x84; ! 16171: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) { ! 16172: struct { ! 16173: UINT16 handle; ! 16174: UINT16 page; ! 16175: bool mapped; ! 16176: } tmp_pages[4]; ! 16177: ! 16178: // unmap pages to copy memory data to ems buffer ! 16179: for(int i = 0; i < 4; i++) { ! 16180: tmp_pages[i].handle = ems_pages[i].handle; ! 16181: tmp_pages[i].page = ems_pages[i].page; ! 16182: tmp_pages[i].mapped = ems_pages[i].mapped; ! 16183: ems_unmap_page(i); ! 16184: } ! 16185: ! 16186: // run move/exchange operation ! 16187: msdos_int_67h_57h_tmp(); ! 16188: ! 16189: // restore unmapped pages ! 16190: for(int i = 0; i < 4; i++) { ! 16191: if(tmp_pages[i].mapped) { ! 16192: ems_map_page(i, tmp_pages[i].handle, tmp_pages[i].page); ! 16193: } ! 16194: } ! 16195: } else { ! 16196: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 16197: REG8(AH) = 0x8f; ! 16198: } ! 16199: } ! 16200: ! 16201: inline void msdos_int_67h_58h() ! 16202: { ! 16203: if(!support_ems) { ! 16204: REG8(AH) = 0x84; ! 16205: } else if(REG8(AL) == 0x00) { ! 16206: for(int i = 0; i < 4; i++) { ! 16207: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = (EMS_TOP + 0x4000 * i) >> 4; ! 16208: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = i; ! 16209: } ! 16210: REG8(AH) = 0x00; ! 16211: REG16(CX) = 4; ! 16212: } else if(REG8(AL) == 0x01) { ! 16213: REG8(AH) = 0x00; ! 16214: REG16(CX) = 4; ! 16215: } else { ! 16216: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 16217: REG8(AH) = 0x8f; ! 16218: } ! 16219: } ! 16220: ! 16221: inline void msdos_int_67h_59h() ! 16222: { ! 16223: if(!support_ems) { ! 16224: REG8(AH) = 0x84; ! 16225: } else if(REG8(AL) == 0x00) { ! 16226: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 1024; ! 16227: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2) = 0; ! 16228: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4) = 4 * 4; ! 16229: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 6) = 0; ! 16230: REG8(AH) = 0x00; ! 16231: // REG8(AH) = 0xa4; // access denied by operating system ! 16232: } else if(REG8(AL) == 0x01) { ! 16233: REG8(AH) = 0x00; ! 16234: REG16(BX) = free_ems_pages; ! 16235: REG16(DX) = MAX_EMS_PAGES; ! 16236: } else { ! 16237: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 16238: REG8(AH) = 0x8f; ! 16239: } ! 16240: } ! 16241: ! 16242: inline void msdos_int_67h_5ah() ! 16243: { ! 16244: if(!support_ems) { ! 16245: REG8(AH) = 0x84; ! 16246: } else if(REG16(BX) > MAX_EMS_PAGES) { ! 16247: REG8(AH) = 0x87; ! 16248: } else if(REG16(BX) > free_ems_pages) { ! 16249: REG8(AH) = 0x88; ! 16250: // } else if(REG16(BX) == 0) { ! 16251: // REG8(AH) = 0x89; ! 16252: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) { ! 16253: for(int i = 1; i <= MAX_EMS_HANDLES; i++) { ! 16254: if(!ems_handles[i].allocated) { ! 16255: ems_allocate_pages(i, REG16(BX)); ! 16256: REG8(AH) = 0x00; ! 16257: REG16(DX) = i; ! 16258: return; ! 16259: } ! 16260: } ! 16261: REG8(AH) = 0x85; ! 16262: } else { ! 16263: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 16264: REG8(AH) = 0x8f; ! 16265: } ! 16266: } ! 16267: ! 16268: inline void msdos_int_67h_5bh() ! 16269: { ! 16270: static UINT8 stored_bl = 0x00; ! 16271: static UINT16 stored_es = 0x0000; ! 16272: static UINT16 stored_di = 0x0000; ! 16273: ! 16274: if(!support_ems) { ! 16275: REG8(AH) = 0x84; ! 16276: } else if(REG8(AL) == 0x00) { ! 16277: if(stored_bl == 0x00) { ! 16278: if(!(stored_es == 0 && stored_di == 0)) { ! 16279: for(int i = 0; i < 4; i++) { ! 16280: *(UINT16 *)(mem + (stored_es << 4) + stored_di + 4 * i + 0) = ems_pages[i].mapped ? ems_pages[i].handle : 0xffff; ! 16281: *(UINT16 *)(mem + (stored_es << 4) + stored_di + 4 * i + 2) = ems_pages[i].mapped ? ems_pages[i].page : 0xffff; ! 16282: } ! 16283: } ! 16284: SREG(ES) = stored_es; ! 16285: i386_load_segment_descriptor(ES); ! 16286: REG16(DI) = stored_di; ! 16287: } else { ! 16288: REG8(BL) = stored_bl; ! 16289: } ! 16290: REG8(AH) = 0x00; ! 16291: } else if(REG8(AL) == 0x01) { ! 16292: if(REG8(BL) == 0x00) { ! 16293: if(!(SREG(ES) == 0 && REG16(DI) == 0)) { ! 16294: for(int i = 0; i < 4; i++) { ! 16295: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0); ! 16296: UINT16 page = *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2); ! 16297: ! 16298: if(handle >= 1 && handle <= MAX_EMS_HANDLES && ems_handles[handle].allocated && page < ems_handles[handle].pages) { ! 16299: ems_map_page(i, handle, page); ! 16300: } else { ! 16301: ems_unmap_page(i); ! 16302: } ! 16303: } ! 16304: } ! 16305: } ! 16306: stored_bl = REG8(BL); ! 16307: stored_es = SREG(ES); ! 16308: stored_di = REG16(DI); ! 16309: REG8(AH) = 0x00; ! 16310: } else if(REG8(AL) == 0x02) { ! 16311: REG16(DX) = 4 * 4; ! 16312: REG8(AH) = 0x00; ! 16313: } else if(REG8(AL) == 0x03) { ! 16314: REG8(BL) = 0x00; // not supported ! 16315: REG8(AH) = 0x00; ! 16316: } else if(REG8(AL) == 0x04) { ! 16317: REG8(AH) = 0x00; ! 16318: } else if(REG8(AL) == 0x05) { ! 16319: REG8(BL) = 0x00; // not supported ! 16320: REG8(AH) = 0x00; ! 16321: } else { ! 16322: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 16323: REG8(AH) = 0x8f; ! 16324: } ! 16325: } ! 16326: ! 16327: inline void msdos_int_67h_5dh() ! 16328: { ! 16329: if(!support_ems) { ! 16330: REG8(AH) = 0x84; ! 16331: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01 || REG8(AL) == 0x02) { ! 16332: REG8(AH) = 0xa4; // operating system denied access ! 16333: } else { ! 16334: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 16335: REG8(AH) = 0x8f; ! 16336: } ! 16337: } ! 16338: ! 16339: inline void msdos_int_67h_70h() ! 16340: { ! 16341: if(!support_ems) { ! 16342: REG8(AH) = 0x84; ! 16343: } else if(REG8(AL) == 0x00) { ! 16344: REG8(AL) = 0x00; ! 16345: REG8(AH) = 0x00; ! 16346: } else if(REG8(AL) == 0x01) { ! 16347: REG8(AL) = 0x00; ! 16348: // REG8(AH) = (REG8(BL) == 0x00) ? 0x00 : 0x80; ! 16349: REG8(AH) = 0x00; ! 16350: } else { ! 16351: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 16352: REG8(AH) = 0x8f; ! 16353: } ! 16354: } ! 16355: ! 16356: inline void msdos_int_67h_deh() ! 16357: { ! 16358: #if defined(SUPPORT_VCPI) ! 16359: if(!support_ems) { ! 16360: REG8(AH) = 0x84; ! 16361: } else if(REG8(AL) == 0x00) { ! 16362: REG8(AH) = 0x00; ! 16363: REG16(BX) = 0x0100; ! 16364: } else if(REG8(AL) == 0x01) { ! 16365: REG8(AH) = 0x00; ! 16366: // from DOSBox ! 16367: for(int ct = 0; ct < 0xff; ct++) { ! 16368: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + ct * 4 + 0x00) = 0x67; // access bits ! 16369: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + ct * 4 + 0x01) = ct * 0x10; // mapping ! 16370: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + ct * 4 + 0x03) = 0x00; ! 16371: } ! 16372: for(int ct = 0xff; ct < 0x100; ct++) { ! 16373: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + ct * 4 + 0x00) = 0x67; // access bits ! 16374: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + ct * 4 + 0x01) = (ct - 0xff) * 0x10 + 0x1100; // mapping ! 16375: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + ct * 4 + 0x03) = 0x00; ! 16376: } ! 16377: REG16(DI) += 0x400; // advance pointer by 0x100*4 ! 16378: ! 16379: // Set up three descriptor table entries ! 16380: UINT32 cbseg_low = (DUMMY_TOP & 0x00ffff) << 16; ! 16381: UINT32 cbseg_high = (DUMMY_TOP & 0x1f0000) >> 16; ! 16382: // Descriptor 1 (code segment, callback segment) ! 16383: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x0000ffff | cbseg_low ; ! 16384: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04) = 0x00009a00 | cbseg_high; ! 16385: // Descriptor 2 (data segment, full access) ! 16386: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x08) = 0x0000ffff; ! 16387: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c) = 0x00009200; ! 16388: // Descriptor 3 (full access) ! 16389: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x10) = 0x0000ffff; ! 16390: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x14) = 0x00009200; ! 16391: // Offset in code segment of protected mode entry point ! 16392: REG32(EBX) = 0x2a; // fffc:002a ! 16393: } else if(REG8(AL) == 0x02) { ! 16394: REG8(AH) = 0x00; ! 16395: REG32(EDX) = (MAX_MEM - 1) & 0xfffff000; ! 16396: } else if(REG8(AL) == 0x03) { ! 16397: REG8(AH) = 0x00; ! 16398: REG32(EDX) = 0; ! 16399: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) { ! 16400: if(emb_handle->handle == 0) { ! 16401: REG32(EDX) += emb_handle->size_kb; ! 16402: } ! 16403: } ! 16404: REG32(EDX) /= 4; ! 16405: } else if(REG8(AL) == 0x04) { ! 16406: emb_handle_t *emb_handle = msdos_xms_alloc_emb_handle(4); ! 16407: if(emb_handle != NULL) { ! 16408: REG8(AH) = 0x00; ! 16409: REG32(EDX) = emb_handle->address; ! 16410: } ! 16411: } else if(REG8(AL) == 0x05) { ! 16412: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) { ! 16413: if(emb_handle->handle != 0 && emb_handle->address == REG32(EDX)) { ! 16414: REG8(AH) = 0x00; ! 16415: msdos_xms_free_emb_handle(emb_handle); ! 16416: break; ! 16417: } ! 16418: } ! 16419: } else if(REG8(AL) == 0x06) { ! 16420: REG8(AH) = 0x00; ! 16421: REG32(EDX) = REG16(CX) << 12; ! 16422: } else if(REG8(AL) == 0x07) { ! 16423: REG8(AH) = 0x00; ! 16424: REG32(EBX) = m_cr[0]; ! 16425: } else if(REG8(AL) == 0x08) { ! 16426: REG8(AH) = 0x00; ! 16427: for(int i = 0; i < 8; i++) { ! 16428: *(UINT32 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i) = m_dr[i]; ! 16429: } ! 16430: } else if(REG8(AL) == 0x09) { ! 16431: REG8(AH) = 0x00; ! 16432: for(int i = 0; i < 8; i++) { ! 16433: m_dr[i] = *(UINT32 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i); ! 16434: } ! 16435: } else if(REG8(AL) == 0x0a) { ! 16436: REG8(AH) = 0x00; ! 16437: REG16(BX) = pic[0].icw2; ! 16438: REG16(CX) = pic[1].icw2; ! 16439: } else if(REG8(AL) == 0x0b) { ! 16440: REG8(AH) = 0x00; ! 16441: pic[0].icw2 = REG8(BL); ! 16442: pic[1].icw2 = REG8(CL); ! 16443: } else if(REG8(AL) == 0x0c) { ! 16444: // from DOSBox ! 16445: m_IF = 0; ! 16446: m_CPL = 0; ! 16447: ! 16448: // Read data from ESI (linear address) ! 16449: UINT32 new_cr3 = *(UINT32 *)(mem + REG32(ESI) + 0x00); ! 16450: UINT32 new_gdt_addr = *(UINT32 *)(mem + REG32(ESI) + 0x04); ! 16451: UINT32 new_idt_addr = *(UINT32 *)(mem + REG32(ESI) + 0x08); ! 16452: UINT16 new_ldt = *(UINT16 *)(mem + REG32(ESI) + 0x0c); ! 16453: UINT16 new_tr = *(UINT16 *)(mem + REG32(ESI) + 0x0e); ! 16454: UINT32 new_eip = *(UINT32 *)(mem + REG32(ESI) + 0x10); ! 16455: UINT16 new_cs = *(UINT16 *)(mem + REG32(ESI) + 0x14); ! 16456: ! 16457: // Get GDT and IDT entries ! 16458: UINT16 new_gdt_limit = *(UINT16 *)(mem + new_gdt_addr + 0); ! 16459: UINT32 new_gdt_base = *(UINT32 *)(mem + new_gdt_addr + 2); ! 16460: UINT16 new_idt_limit = *(UINT16 *)(mem + new_idt_addr + 0); ! 16461: UINT32 new_idt_base = *(UINT32 *)(mem + new_idt_addr + 2); ! 16462: ! 16463: // Switch to protected mode, paging enabled if necessary ! 16464: if(new_cr3 != 0) { ! 16465: m_cr[0] |= 0x80000000; ! 16466: } ! 16467: m_cr[3] = new_cr3; ! 16468: ! 16469: *(UINT8 *)(mem + new_gdt_base + (new_tr & 0xfff8) + 5) &= 0xfd; ! 16470: ! 16471: // Load tables and initialize segment registers ! 16472: m_gdtr.limit = new_gdt_limit; ! 16473: m_gdtr.base = new_gdt_base; ! 16474: m_idtr.limit = new_idt_limit; ! 16475: m_idtr.base = new_idt_base; ! 16476: ! 16477: i386_sreg_load(0x00, DS, NULL); ! 16478: i386_sreg_load(0x00, ES, NULL); ! 16479: i386_sreg_load(0x00, FS, NULL); ! 16480: i386_sreg_load(0x00, GS, NULL); ! 16481: ! 16482: // i386_set_a20_line(1); ! 16483: ! 16484: /* Switch to protected mode */ ! 16485: m_VM = m_NT = 0; ! 16486: m_IOP1 = m_IOP2 = 1; ! 16487: ! 16488: i386_jmp_far(new_cs, new_eip); ! 16489: } else { ! 16490: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 16491: REG8(AH) = 0x8f; ! 16492: } ! 16493: #else ! 16494: REG8(AH) = 0x84; ! 16495: #endif ! 16496: } ! 16497: ! 16498: #ifdef SUPPORT_XMS ! 16499: ! 16500: void msdos_xms_init() ! 16501: { ! 16502: emb_handle_top = (emb_handle_t *)calloc(1, sizeof(emb_handle_t)); ! 16503: emb_handle_top->address = EMB_TOP; ! 16504: emb_handle_top->size_kb = (EMB_END - EMB_TOP) >> 10; ! 16505: xms_a20_local_enb_count = 0; ! 16506: } ! 16507: ! 16508: void msdos_xms_finish() ! 16509: { ! 16510: msdos_xms_release(); ! 16511: } ! 16512: ! 16513: void msdos_xms_release() ! 16514: { ! 16515: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL;) { ! 16516: emb_handle_t *next_handle = emb_handle->next; ! 16517: free(emb_handle); ! 16518: emb_handle = next_handle; ! 16519: } ! 16520: } ! 16521: ! 16522: emb_handle_t *msdos_xms_get_emb_handle(int handle) ! 16523: { ! 16524: if(handle != 0) { ! 16525: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) { ! 16526: if(emb_handle->handle == handle) { ! 16527: return(emb_handle); ! 16528: } ! 16529: } ! 16530: } ! 16531: return(NULL); ! 16532: } ! 16533: ! 16534: int msdos_xms_get_unused_emb_handle_id() ! 16535: { ! 16536: for(int handle = 1;; handle++) { ! 16537: if(msdos_xms_get_emb_handle(handle) == NULL) { ! 16538: return(handle); ! 16539: } ! 16540: } ! 16541: return(0); ! 16542: } ! 16543: ! 16544: int msdos_xms_get_unused_emb_handle_count() ! 16545: { ! 16546: int count = 64; //255; ! 16547: ! 16548: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) { ! 16549: if(emb_handle->handle != 0) { ! 16550: if(--count == 1) { ! 16551: break; ! 16552: } ! 16553: } ! 16554: } ! 16555: return(count); ! 16556: } ! 16557: ! 16558: void msdos_xms_split_emb_handle(emb_handle_t *emb_handle, int size_kb) ! 16559: { ! 16560: if(emb_handle->size_kb > size_kb) { ! 16561: emb_handle_t *new_handle = (emb_handle_t *)calloc(1, sizeof(emb_handle_t)); ! 16562: ! 16563: new_handle->address = emb_handle->address + size_kb * 1024; ! 16564: new_handle->size_kb = emb_handle->size_kb - size_kb; ! 16565: emb_handle->size_kb = size_kb; ! 16566: ! 16567: new_handle->prev = emb_handle; ! 16568: new_handle->next = emb_handle->next; ! 16569: if(emb_handle->next != NULL) { ! 16570: emb_handle->next->prev = new_handle; ! 16571: } ! 16572: emb_handle->next = new_handle; ! 16573: } ! 16574: } ! 16575: ! 16576: void msdos_xms_combine_emb_handles(emb_handle_t *emb_handle) ! 16577: { ! 16578: emb_handle_t *next_handle = emb_handle->next; ! 16579: ! 16580: if(next_handle != NULL) { ! 16581: emb_handle->size_kb += next_handle->size_kb; ! 16582: ! 16583: if(next_handle->next != NULL) { ! 16584: next_handle->next->prev = emb_handle; ! 16585: } ! 16586: emb_handle->next = next_handle->next; ! 16587: free(next_handle); ! 16588: } ! 16589: } ! 16590: ! 16591: emb_handle_t *msdos_xms_alloc_emb_handle(int size_kb) ! 16592: { ! 16593: emb_handle_t *target_handle = NULL; ! 16594: ! 16595: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) { ! 16596: if(emb_handle->handle == 0 && emb_handle->size_kb >= size_kb) { ! 16597: if(target_handle == NULL || target_handle->size_kb > emb_handle->size_kb) { ! 16598: target_handle = emb_handle; ! 16599: } ! 16600: } ! 16601: } ! 16602: if(target_handle != NULL) { ! 16603: if(target_handle->size_kb > size_kb) { ! 16604: msdos_xms_split_emb_handle(target_handle, size_kb); ! 16605: } ! 16606: // target_handle->handle = msdos_xms_get_unused_emb_handle_id(); ! 16607: return(target_handle); ! 16608: } ! 16609: return(NULL); ! 16610: } ! 16611: ! 16612: void msdos_xms_free_emb_handle(emb_handle_t *emb_handle) ! 16613: { ! 16614: emb_handle_t *prev_handle = emb_handle->prev; ! 16615: emb_handle_t *next_handle = emb_handle->next; ! 16616: ! 16617: if(prev_handle != NULL && prev_handle->handle == 0) { ! 16618: msdos_xms_combine_emb_handles(prev_handle); ! 16619: emb_handle = prev_handle; ! 16620: } ! 16621: if(next_handle != NULL && next_handle->handle == 0) { ! 16622: msdos_xms_combine_emb_handles(emb_handle); ! 16623: } ! 16624: emb_handle->handle = 0; ! 16625: } ! 16626: ! 16627: inline void msdos_call_xms_00h() ! 16628: { ! 16629: #if defined(HAS_I386) ! 16630: REG16(AX) = 0x0300; // V3.00 (XMS Version) ! 16631: REG16(BX) = 0x0395; // V3.95 (Driver Revision in BCD) ! 16632: // REG16(BX) = 0x035f; // V3.95 (Driver Revision) ! 16633: #else ! 16634: REG16(AX) = 0x0200; // V2.00 (XMS Version) ! 16635: REG16(BX) = 0x0270; // V2.70 (Driver Revision) ! 16636: #endif ! 16637: // REG16(DX) = 0x0000; // HMA does not exist ! 16638: REG16(DX) = 0x0001; // HMA does exist ! 16639: } ! 16640: ! 16641: inline void msdos_call_xms_01h() ! 16642: { ! 16643: if(REG8(AL) == 0x40) { ! 16644: // HIMEM.SYS will fail function 01h with error code 91h if AL=40h and ! 16645: // DX=KB free extended memory returned by last call of function 08h ! 16646: REG16(AX) = 0x0000; ! 16647: REG8(BL) = 0x91; ! 16648: REG16(DX) = xms_dx_after_call_08h; ! 16649: } else if(memcmp(mem + 0x100003, "VDISK", 5) == 0) { ! 16650: REG16(AX) = 0x0000; ! 16651: REG8(BL) = 0x81; // Vdisk was detected ! 16652: #ifdef SUPPORT_HMA ! 16653: } else if(is_hma_used_by_int_2fh) { ! 16654: REG16(AX) = 0x0000; ! 16655: REG8(BL) = 0x90; // HMA does not exist or is not managed by XMS provider ! 16656: } else if(is_hma_used_by_xms) { ! 16657: REG16(AX) = 0x0000; ! 16658: REG8(BL) = 0x91; // HMA is already in use ! 16659: } else { ! 16660: REG16(AX) = 0x0001; ! 16661: is_hma_used_by_xms = true; ! 16662: #else ! 16663: } else { ! 16664: REG16(AX) = 0x0000; ! 16665: REG8(BL) = 0x91; // HMA is already in use ! 16666: #endif ! 16667: } ! 16668: } ! 16669: ! 16670: inline void msdos_call_xms_02h() ! 16671: { ! 16672: if(memcmp(mem + 0x100003, "VDISK", 5) == 0) { ! 16673: REG16(AX) = 0x0000; ! 16674: REG8(BL) = 0x81; // Vdisk was detected ! 16675: #ifdef SUPPORT_HMA ! 16676: } else if(is_hma_used_by_int_2fh) { ! 16677: REG16(AX) = 0x0000; ! 16678: REG8(BL) = 0x90; // HMA does not exist or is not managed by XMS provider ! 16679: } else if(!is_hma_used_by_xms) { ! 16680: REG16(AX) = 0x0000; ! 16681: REG8(BL) = 0x93; // HMA is not allocated ! 16682: } else { ! 16683: REG16(AX) = 0x0001; ! 16684: is_hma_used_by_xms = false; ! 16685: // restore first free mcb in high memory area ! 16686: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0); ! 16687: #else ! 16688: } else { ! 16689: REG16(AX) = 0x0000; ! 16690: REG8(BL) = 0x91; // HMA is already in use ! 16691: #endif ! 16692: } ! 16693: } ! 16694: ! 16695: inline void msdos_call_xms_03h() ! 16696: { ! 16697: i386_set_a20_line(1); ! 16698: REG16(AX) = 0x0001; ! 16699: REG8(BL) = 0x00; ! 16700: } ! 16701: ! 16702: inline void msdos_call_xms_04h() ! 16703: { ! 16704: i386_set_a20_line(0); ! 16705: REG16(AX) = 0x0001; ! 16706: REG8(BL) = 0x00; ! 16707: } ! 16708: ! 16709: inline void msdos_call_xms_05h() ! 16710: { ! 16711: i386_set_a20_line(1); ! 16712: REG16(AX) = 0x0001; ! 16713: REG8(BL) = 0x00; ! 16714: xms_a20_local_enb_count++; ! 16715: } ! 16716: ! 16717: void msdos_call_xms_06h() ! 16718: { ! 16719: if(xms_a20_local_enb_count > 0) { ! 16720: if(--xms_a20_local_enb_count == 0) { ! 16721: i386_set_a20_line(0); ! 16722: REG16(AX) = 0x0001; ! 16723: REG8(BL) = 0x00; ! 16724: } else { ! 16725: REG16(AX) = 0x0000; ! 16726: REG8(BL) = 0x94; ! 16727: } ! 16728: } else { ! 16729: i386_set_a20_line(0); ! 16730: REG16(AX) = 0x0001; ! 16731: REG8(BL) = 0x00; ! 16732: } ! 16733: } ! 16734: ! 16735: inline void msdos_call_xms_07h() ! 16736: { ! 16737: REG16(AX) = (m_a20_mask >> 20) & 1; ! 16738: REG8(BL) = 0x00; ! 16739: } ! 16740: ! 16741: inline void msdos_call_xms_08h() ! 16742: { ! 16743: UINT32 eax = 0, edx = 0; ! 16744: ! 16745: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) { ! 16746: if(emb_handle->handle == 0) { ! 16747: if(eax < emb_handle->size_kb) { ! 16748: eax = emb_handle->size_kb; ! 16749: } ! 16750: edx += emb_handle->size_kb; ! 16751: } ! 16752: } ! 16753: if(eax > 65535) { ! 16754: eax = 65535; ! 16755: } ! 16756: if(edx > 65535) { ! 16757: edx = 65535; ! 16758: } ! 16759: if(eax == 0 && edx == 0) { ! 16760: REG8(BL) = 0xa0; ! 16761: } else { ! 16762: REG8(BL) = 0x00; ! 16763: } ! 16764: #if defined(HAS_I386) ! 16765: REG32(EAX) = eax; ! 16766: REG32(EDX) = edx; ! 16767: #else ! 16768: REG16(AX) = (UINT16)eax; ! 16769: REG16(DX) = (UINT16)edx; ! 16770: #endif ! 16771: xms_dx_after_call_08h = REG16(DX); ! 16772: } ! 16773: ! 16774: void msdos_call_xms_09h(int size_kb) ! 16775: { ! 16776: emb_handle_t *emb_handle = msdos_xms_alloc_emb_handle(size_kb); ! 16777: ! 16778: if(emb_handle != NULL) { ! 16779: emb_handle->handle = msdos_xms_get_unused_emb_handle_id(); ! 16780: ! 16781: REG16(AX) = 0x0001; ! 16782: REG16(DX) = emb_handle->handle; ! 16783: REG8(BL) = 0x00; ! 16784: } else { ! 16785: REG16(AX) = REG16(DX) = 0x0000; ! 16786: REG8(BL) = 0xa0; ! 16787: } ! 16788: } ! 16789: ! 16790: inline void msdos_call_xms_09h() ! 16791: { ! 16792: msdos_call_xms_09h(REG16(DX)); ! 16793: } ! 16794: ! 16795: inline void msdos_call_xms_0ah() ! 16796: { ! 16797: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX)); ! 16798: ! 16799: if(emb_handle == NULL) { ! 16800: REG16(AX) = 0x0000; ! 16801: REG8(BL) = 0xa2; ! 16802: // } else if(emb_handle->lock > 0) { ! 16803: // REG16(AX) = 0x0000; ! 16804: // REG8(BL) = 0xab; ! 16805: } else { ! 16806: msdos_xms_free_emb_handle(emb_handle); ! 16807: ! 16808: REG16(AX) = 0x0001; ! 16809: REG8(BL) = 0x00; ! 16810: } ! 16811: } ! 16812: ! 16813: inline void msdos_call_xms_0bh() ! 16814: { ! 16815: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00); ! 16816: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04); ! 16817: UINT32 src_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06); ! 16818: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0a); ! 16819: UINT32 dest_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c); ! 16820: ! 16821: UINT8 *src_buffer, *dest_buffer; ! 16822: UINT32 src_addr_max, dest_addr_max; ! 16823: emb_handle_t *emb_handle; ! 16824: ! 16825: if(src_handle == 0) { ! 16826: src_buffer = mem; ! 16827: src_addr = (((src_addr >> 16) & 0xffff) << 4) + (src_addr & 0xffff); ! 16828: src_addr_max = MAX_MEM; ! 16829: } else { ! 16830: if((emb_handle = msdos_xms_get_emb_handle(src_handle)) == NULL) { ! 16831: REG16(AX) = 0x0000; ! 16832: REG8(BL) = 0xa3; ! 16833: return; ! 16834: } ! 16835: src_buffer = mem + emb_handle->address; ! 16836: src_addr_max = emb_handle->size_kb * 1024; ! 16837: } ! 16838: if(dest_handle == 0) { ! 16839: dest_buffer = mem; ! 16840: dest_addr = (((dest_addr >> 16) & 0xffff) << 4) + (dest_addr & 0xffff); ! 16841: dest_addr_max = MAX_MEM; ! 16842: } else { ! 16843: if((emb_handle = msdos_xms_get_emb_handle(dest_handle)) == NULL) { ! 16844: REG16(AX) = 0x0000; ! 16845: REG8(BL) = 0xa5; ! 16846: return; ! 16847: } ! 16848: dest_buffer = mem + emb_handle->address; ! 16849: dest_addr_max = emb_handle->size_kb * 1024; ! 16850: } ! 16851: for(int i = 0; i < copy_length; i++) { ! 16852: if(src_addr < src_addr_max && dest_addr < dest_addr_max) { ! 16853: dest_buffer[dest_addr++] = src_buffer[src_addr++]; ! 16854: } else { ! 16855: break; ! 16856: } ! 16857: } ! 16858: REG16(AX) = 0x0001; ! 16859: REG8(BL) = 0x00; ! 16860: } ! 16861: ! 16862: inline void msdos_call_xms_0ch() ! 16863: { ! 16864: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX)); ! 16865: ! 16866: if(emb_handle == NULL) { ! 16867: REG16(AX) = 0x0000; ! 16868: REG8(BL) = 0xa2; ! 16869: } else { ! 16870: if(emb_handle->lock < 255) { ! 16871: emb_handle->lock++; ! 16872: } ! 16873: REG16(AX) = 0x0001; ! 16874: REG16(DX) = (emb_handle->address >> 16) & 0xffff; ! 16875: REG16(BX) = (emb_handle->address ) & 0xffff; ! 16876: } ! 16877: } ! 16878: ! 16879: inline void msdos_call_xms_0dh() ! 16880: { ! 16881: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX)); ! 16882: ! 16883: if(emb_handle == NULL) { ! 16884: REG16(AX) = 0x0000; ! 16885: REG8(BL) = 0xa2; ! 16886: } else if(!(emb_handle->lock > 0)) { ! 16887: REG16(AX) = 0x0000; ! 16888: REG8(BL) = 0xaa; ! 16889: } else { ! 16890: emb_handle->lock--; ! 16891: REG16(AX) = 0x0001; ! 16892: REG8(BL) = 0x00; ! 16893: } ! 16894: } ! 16895: ! 16896: inline void msdos_call_xms_0eh() ! 16897: { ! 16898: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX)); ! 16899: ! 16900: if(emb_handle == NULL) { ! 16901: REG16(AX) = 0x0000; ! 16902: REG8(BL) = 0xa2; ! 16903: } else { ! 16904: REG16(AX) = 0x0001; ! 16905: REG8(BH) = emb_handle->lock; ! 16906: REG8(BL) = msdos_xms_get_unused_emb_handle_count(); ! 16907: REG16(DX) = emb_handle->size_kb; ! 16908: } ! 16909: } ! 16910: ! 16911: void msdos_call_xms_0fh(int size_kb) ! 16912: { ! 16913: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX)); ! 16914: ! 16915: if(emb_handle == NULL) { ! 16916: REG16(AX) = 0x0000; ! 16917: REG8(BL) = 0xa2; ! 16918: } else if(emb_handle->lock > 0) { ! 16919: REG16(AX) = 0x0000; ! 16920: REG8(BL) = 0xab; ! 16921: } else { ! 16922: if(emb_handle->size_kb < size_kb) { ! 16923: if(emb_handle->next != NULL && emb_handle->next->handle == 0 && (emb_handle->size_kb + emb_handle->next->size_kb) >= size_kb) { ! 16924: msdos_xms_combine_emb_handles(emb_handle); ! 16925: if(emb_handle->size_kb > size_kb) { ! 16926: msdos_xms_split_emb_handle(emb_handle, size_kb); ! 16927: } ! 16928: } else { ! 16929: int old_handle = emb_handle->handle; ! 16930: int old_size_kb = emb_handle->size_kb; ! 16931: UINT8 *buffer = (UINT8 *)malloc(old_size_kb * 1024); ! 16932: ! 16933: memcpy(buffer, mem + emb_handle->address, old_size_kb * 1024); ! 16934: msdos_xms_free_emb_handle(emb_handle); ! 16935: ! 16936: if((emb_handle = msdos_xms_alloc_emb_handle(size_kb)) == NULL) { ! 16937: emb_handle = msdos_xms_alloc_emb_handle(old_size_kb); // should be always successed ! 16938: } ! 16939: emb_handle->handle = old_handle; ! 16940: memcpy(mem + emb_handle->address, buffer, old_size_kb * 1024); ! 16941: free(buffer); ! 16942: } ! 16943: } else if(emb_handle->size_kb > size_kb) { ! 16944: msdos_xms_split_emb_handle(emb_handle, size_kb); ! 16945: } ! 16946: if(emb_handle->size_kb != size_kb) { ! 16947: REG16(AX) = 0x0000; ! 16948: REG8(BL) = 0xa0; ! 16949: } else { ! 16950: REG16(AX) = 0x0001; ! 16951: REG8(BL) = 0x00; ! 16952: } ! 16953: } ! 16954: } ! 16955: ! 16956: inline void msdos_call_xms_0fh() ! 16957: { ! 16958: msdos_call_xms_0fh(REG16(BX)); ! 16959: } ! 16960: ! 16961: inline void msdos_call_xms_10h() ! 16962: { ! 16963: int seg; ! 16964: ! 16965: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(DX), 0)) != -1) { ! 16966: REG16(AX) = 0x0001; ! 16967: REG16(BX) = seg; ! 16968: } else { ! 16969: REG16(AX) = 0x0000; ! 16970: REG8(BL) = 0xb0; ! 16971: REG16(DX) = msdos_mem_get_free(UMB_TOP >> 4, 0); ! 16972: } ! 16973: } ! 16974: ! 16975: inline void msdos_call_xms_11h() ! 16976: { ! 16977: int mcb_seg = REG16(DX) - 1; ! 16978: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4)); ! 16979: ! 16980: if(mcb->mz == 'M' || mcb->mz == 'Z') { ! 16981: msdos_mem_free(REG16(DX)); ! 16982: REG16(AX) = 0x0001; ! 16983: REG8(BL) = 0x00; ! 16984: } else { ! 16985: REG16(AX) = 0x0000; ! 16986: REG8(BL) = 0xb2; ! 16987: } ! 16988: } ! 16989: ! 16990: inline void msdos_call_xms_12h() ! 16991: { ! 16992: int mcb_seg = REG16(DX) - 1; ! 16993: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4)); ! 16994: int max_paragraphs; ! 16995: ! 16996: if(mcb->mz == 'M' || mcb->mz == 'Z') { ! 16997: if(!msdos_mem_realloc(REG16(DX), REG16(BX), &max_paragraphs)) { ! 16998: REG16(AX) = 0x0001; ! 16999: REG8(BL) = 0x00; ! 17000: } else { ! 17001: REG16(AX) = 0x0000; ! 17002: REG8(BL) = 0xb0; ! 17003: REG16(DX) = max_paragraphs; ! 17004: } ! 17005: } else { ! 17006: REG16(AX) = 0x0000; ! 17007: REG8(BL) = 0xb2; ! 17008: } ! 17009: } ! 17010: ! 17011: #if defined(HAS_I386) ! 17012: ! 17013: inline void msdos_call_xms_88h() ! 17014: { ! 17015: REG32(EAX) = REG32(EDX) = 0x0000; ! 17016: ! 17017: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) { ! 17018: if(emb_handle->handle == 0) { ! 17019: if(REG32(EAX) < emb_handle->size_kb) { ! 17020: REG32(EAX) = emb_handle->size_kb; ! 17021: } ! 17022: REG32(EDX) += emb_handle->size_kb; ! 17023: } ! 17024: } ! 17025: if(REG32(EAX) == 0 && REG32(EDX) == 0) { ! 17026: REG8(BL) = 0xa0; ! 17027: } else { ! 17028: REG8(BL) = 0x00; ! 17029: } ! 17030: REG32(ECX) = EMB_END - 1; ! 17031: } ! 17032: ! 17033: inline void msdos_call_xms_89h() ! 17034: { ! 17035: msdos_call_xms_09h(REG32(EDX)); ! 17036: } ! 17037: ! 17038: inline void msdos_call_xms_8eh() ! 17039: { ! 17040: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX)); ! 17041: ! 17042: if(emb_handle == NULL) { ! 17043: REG16(AX) = 0x0000; ! 17044: REG8(BL) = 0xa2; ! 17045: } else { ! 17046: REG16(AX) = 0x0001; ! 17047: REG8(BH) = emb_handle->lock; ! 17048: REG16(CX) = msdos_xms_get_unused_emb_handle_count(); ! 17049: REG32(EDX) = emb_handle->size_kb; ! 17050: } ! 17051: } ! 17052: ! 17053: inline void msdos_call_xms_8fh() ! 17054: { ! 17055: msdos_call_xms_0fh(REG32(EBX)); ! 17056: } ! 17057: ! 17058: #endif ! 17059: #endif ! 17060: ! 17061: UINT16 msdos_get_equipment() ! 17062: { ! 17063: static UINT16 equip = 0; ! 17064: ! 17065: if(equip == 0) { ! 17066: #ifdef SUPPORT_FPU ! 17067: equip |= (1 << 1); // 80x87 coprocessor installed ! 17068: #endif ! 17069: equip |= (1 << 2); // pointing device installed (PS/2) ! 17070: equip |= (2 << 4); // initial video mode (80x25 color) ! 17071: // equip |= (1 << 8); // 0 if DMA installed ! 17072: equip |= (2 << 9); // number of serial ports ! 17073: equip |= (3 << 14); // number of printer ports (NOTE: this number is 3 on Windows 98 SE though only LPT1 exists) ! 17074: ! 17075: // check only A: and B: if it is floppy drive ! 17076: int n = 0; ! 17077: for(int i = 0; i < 2; i++) { ! 17078: if(msdos_is_valid_drive(i) && msdos_is_removable_drive(i)) { ! 17079: n++; ! 17080: } ! 17081: } ! 17082: if(n != 0) { ! 17083: equip |= (1 << 0); // floppy disk(s) installed ! 17084: n--; ! 17085: equip |= (n << 6); // number of floppies installed less 1 ! 17086: } ! 17087: // if(joyGetNumDevs() != 0) { ! 17088: // equip |= (1 << 12); // game port installed ! 17089: // } ! 17090: } ! 17091: return(equip); ! 17092: } ! 17093: ! 17094: void msdos_syscall(unsigned num) ! 17095: { ! 17096: #ifdef ENABLE_DEBUG_SYSCALL ! 17097: if(num == 0x08 || num == 0x1c) { ! 17098: // don't log the timer interrupts ! 17099: // fprintf(fp_debug_log, "int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 17100: } else if(num == 0x30) { ! 17101: // dummy interrupt for call 0005h (call near) ! 17102: fprintf(fp_debug_log, "call 0005h (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 17103: } else if(num == 0x65) { ! 17104: // dummy interrupt for EMS (int 67h) ! 17105: fprintf(fp_debug_log, "int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 17106: } else if(num == 0x66) { ! 17107: // dummy interrupt for XMS (call far) ! 17108: fprintf(fp_debug_log, "call XMS (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 17109: } else if(num >= 0x68 && num <= 0x6f) { ! 17110: // dummy interrupt ! 17111: } else { ! 17112: fprintf(fp_debug_log, "int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 17113: } ! 17114: #endif ! 17115: // update cursor position ! 17116: if(cursor_moved) { ! 17117: pcbios_update_cursor_position(); ! 17118: cursor_moved = false; ! 17119: } ! 17120: #ifdef USE_SERVICE_THREAD ! 17121: // this is called from dummy loop to wait until a serive that waits input is done ! 17122: if(!in_service) ! 17123: #endif ! 17124: ctrl_break_detected = ctrl_break_pressed = ctrl_c_pressed = false; ! 17125: ! 17126: switch(num) { ! 17127: case 0x00: ! 17128: try { ! 17129: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1); ! 17130: error("division by zero\n"); ! 17131: } catch(...) { ! 17132: fatalerror("division by zero detected, and failed to terminate current process\n"); ! 17133: } ! 17134: break; ! 17135: case 0x04: ! 17136: try { ! 17137: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1); ! 17138: error("overflow\n"); ! 17139: } catch(...) { ! 17140: fatalerror("overflow detected, and failed to terminate current process\n"); ! 17141: } ! 17142: break; ! 17143: case 0x06: ! 17144: // NOTE: ish.com has illegal instruction... ! 17145: if(!ignore_illegal_insn) { ! 17146: try { ! 17147: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1); ! 17148: error("illegal instruction\n"); ! 17149: } catch(...) { ! 17150: fatalerror("illegal instruction detected, and failed to terminate current process\n"); ! 17151: } ! 17152: } else { ! 17153: #if defined(HAS_I386) ! 17154: m_eip = m_int6h_skip_eip; ! 17155: #elif defined(HAS_I286) ! 17156: m_pc = m_int6h_skip_pc; ! 17157: #else ! 17158: // 8086/80186 ignore an invalid opcode ! 17159: #endif ! 17160: } ! 17161: break; ! 17162: case 0x09: ! 17163: // ctrl-break is pressed ! 17164: if(raise_int_1bh) { ! 17165: #if defined(HAS_I386) ! 17166: m_ext = 0; // not an external interrupt ! 17167: i386_trap(0x1b, 1, 0); ! 17168: m_ext = 1; ! 17169: #else ! 17170: PREFIX86(_interrupt)(0x1b); ! 17171: #endif ! 17172: raise_int_1bh = false; ! 17173: } ! 17174: case 0x08: ! 17175: // pcbios_irq0(); // this causes too slow emulation... ! 17176: case 0x0b: ! 17177: case 0x0c: ! 17178: case 0x0d: ! 17179: case 0x0e: ! 17180: case 0x0f: ! 17181: // EOI ! 17182: pic[0].isr &= ~(1 << (num - 0x08)); ! 17183: pic_update(); ! 17184: break; ! 17185: case 0x10: ! 17186: // PC BIOS - Video ! 17187: if(!restore_console_on_exit) { ! 17188: change_console_size(scr_width, scr_height); ! 17189: } ! 17190: m_CF = 0; ! 17191: switch(REG8(AH)) { ! 17192: case 0x00: pcbios_int_10h_00h(); break; ! 17193: case 0x01: pcbios_int_10h_01h(); break; ! 17194: case 0x02: pcbios_int_10h_02h(); break; ! 17195: case 0x03: pcbios_int_10h_03h(); break; ! 17196: case 0x05: pcbios_int_10h_05h(); break; ! 17197: case 0x06: pcbios_int_10h_06h(); break; ! 17198: case 0x07: pcbios_int_10h_07h(); break; ! 17199: case 0x08: pcbios_int_10h_08h(); break; ! 17200: case 0x09: pcbios_int_10h_09h(); break; ! 17201: case 0x0a: pcbios_int_10h_0ah(); break; ! 17202: case 0x0b: break; ! 17203: case 0x0c: pcbios_int_10h_0ch(); break; ! 17204: case 0x0d: pcbios_int_10h_0dh(); break; ! 17205: case 0x0e: pcbios_int_10h_0eh(); break; ! 17206: case 0x0f: pcbios_int_10h_0fh(); break; ! 17207: case 0x10: break; ! 17208: case 0x11: pcbios_int_10h_11h(); break; ! 17209: case 0x12: pcbios_int_10h_12h(); break; ! 17210: case 0x13: pcbios_int_10h_13h(); break; ! 17211: case 0x18: pcbios_int_10h_18h(); break; ! 17212: case 0x1a: pcbios_int_10h_1ah(); break; ! 17213: case 0x1b: REG8(AL) = 0x00; break; // functionality/state information is not supported ! 17214: case 0x1c: REG8(AL) = 0x00; break; // save/restore video state is not supported ! 17215: case 0x1d: pcbios_int_10h_1dh(); break; ! 17216: case 0x1e: REG8(AL) = 0x00; break; // flat-panel functions are not supported ! 17217: case 0x1f: REG8(AL) = 0x00; break; // xga functions are not supported ! 17218: case 0x4f: pcbios_int_10h_4fh(); break; ! 17219: case 0x6f: break; ! 17220: case 0x80: m_CF = 1; break; // unknown ! 17221: case 0x81: m_CF = 1; break; // unknown ! 17222: case 0x82: pcbios_int_10h_82h(); break; ! 17223: case 0x83: pcbios_int_10h_83h(); break; ! 17224: case 0x8b: break; ! 17225: case 0x8c: m_CF = 1; break; // unknown ! 17226: case 0x8d: m_CF = 1; break; // unknown ! 17227: case 0x8e: m_CF = 1; break; // unknown ! 17228: case 0x90: pcbios_int_10h_90h(); break; ! 17229: case 0x91: pcbios_int_10h_91h(); break; ! 17230: case 0x92: break; ! 17231: case 0x93: break; ! 17232: case 0xef: pcbios_int_10h_efh(); break; ! 17233: case 0xfa: break; // ega register interface library is not installed ! 17234: case 0xfe: pcbios_int_10h_feh(); break; ! 17235: case 0xff: pcbios_int_10h_ffh(); break; ! 17236: default: ! 17237: unimplemented_10h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 17238: m_CF = 1; ! 17239: break; ! 17240: } ! 17241: break; ! 17242: case 0x11: ! 17243: // PC BIOS - Get Equipment List ! 17244: REG16(AX) = msdos_get_equipment(); ! 17245: break; ! 17246: case 0x12: ! 17247: // PC BIOS - Get Memory Size ! 17248: REG16(AX) = *(UINT16 *)(mem + 0x413); ! 17249: break; ! 17250: case 0x13: ! 17251: // PC BIOS - Disk I/O ! 17252: { ! 17253: static UINT8 last = 0x00; ! 17254: switch(REG8(AH)) { ! 17255: case 0x00: pcbios_int_13h_00h(); break; ! 17256: case 0x01: // get last status ! 17257: REG8(AH) = last; ! 17258: break; ! 17259: case 0x02: pcbios_int_13h_02h(); break; ! 17260: case 0x03: pcbios_int_13h_03h(); break; ! 17261: case 0x04: pcbios_int_13h_04h(); break; ! 17262: case 0x08: pcbios_int_13h_08h(); break; ! 17263: case 0x0a: pcbios_int_13h_02h(); break; ! 17264: case 0x0b: pcbios_int_13h_03h(); break; ! 17265: case 0x0d: pcbios_int_13h_00h(); break; ! 17266: case 0x10: pcbios_int_13h_10h(); break; ! 17267: case 0x15: pcbios_int_13h_15h(); break; ! 17268: case 0x41: pcbios_int_13h_41h(); break; ! 17269: case 0x05: // format ! 17270: case 0x06: ! 17271: case 0x07: ! 17272: REG8(AH) = 0x0c; // unsupported track or invalid media ! 17273: m_CF = 1; ! 17274: break; ! 17275: case 0x09: ! 17276: case 0x0c: // seek ! 17277: case 0x11: // recalib ! 17278: case 0x14: ! 17279: case 0x17: ! 17280: REG8(AH) = 0x00; // successful completion ! 17281: break; ! 17282: case 0x21: // QUICKCACHE II v4.20 - Flush Cache ! 17283: case 0xa1: // Super PC-Kwik v3.20+ - Flush Cache ! 17284: REG8(AH) = 0x01; // invalid function ! 17285: m_CF = 1; ! 17286: break; ! 17287: default: ! 17288: unimplemented_13h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 17289: REG8(AH) = 0x01; // invalid function ! 17290: m_CF = 1; ! 17291: break; ! 17292: } ! 17293: last = REG8(AH); ! 17294: } ! 17295: break; ! 17296: case 0x14: ! 17297: // PC BIOS - Serial I/O ! 17298: switch(REG8(AH)) { ! 17299: case 0x00: pcbios_int_14h_00h(); break; ! 17300: case 0x01: pcbios_int_14h_01h(); break; ! 17301: case 0x02: pcbios_int_14h_02h(); break; ! 17302: case 0x03: pcbios_int_14h_03h(); break; ! 17303: case 0x04: pcbios_int_14h_04h(); break; ! 17304: case 0x05: pcbios_int_14h_05h(); break; ! 17305: default: ! 17306: unimplemented_14h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 17307: break; ! 17308: } ! 17309: break; ! 17310: case 0x15: ! 17311: // PC BIOS ! 17312: m_CF = 0; ! 17313: switch(REG8(AH)) { ! 17314: case 0x23: pcbios_int_15h_23h(); break; ! 17315: case 0x24: pcbios_int_15h_24h(); break; ! 17316: case 0x41: break; ! 17317: case 0x49: pcbios_int_15h_49h(); break; ! 17318: case 0x4f: m_CF = 1; break; // from DOSBox ! 17319: case 0x50: pcbios_int_15h_50h(); break; ! 17320: case 0x53: pcbios_int_15h_53h(); break; ! 17321: case 0x84: pcbios_int_15h_84h(); break; ! 17322: case 0x86: pcbios_int_15h_86h(); break; ! 17323: case 0x87: pcbios_int_15h_87h(); break; ! 17324: case 0x88: pcbios_int_15h_88h(); break; ! 17325: case 0x89: pcbios_int_15h_89h(); break; ! 17326: case 0x8a: pcbios_int_15h_8ah(); break; ! 17327: case 0x90: REG8(AH) = 0x00; break; // from DOSBox ! 17328: case 0x91: REG8(AH) = 0x00; break; // from DOSBox ! 17329: case 0xc0: // PS/2 ??? ! 17330: #ifndef EXT_BIOS_TOP ! 17331: case 0xc1: ! 17332: #endif ! 17333: case 0xc3: // PS50+ ??? ! 17334: case 0xc4: ! 17335: REG8(AH) = 0x86; ! 17336: m_CF = 1; ! 17337: break; ! 17338: #ifdef EXT_BIOS_TOP ! 17339: case 0xc1: pcbios_int_15h_c1h(); break; ! 17340: #endif ! 17341: case 0xc2: pcbios_int_15h_c2h(); break; ! 17342: #if defined(HAS_I386) ! 17343: case 0xc9: pcbios_int_15h_c9h(); break; ! 17344: #endif ! 17345: case 0xca: pcbios_int_15h_cah(); break; ! 17346: case 0xe8: pcbios_int_15h_e8h(); break; ! 17347: default: ! 17348: unimplemented_15h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 17349: REG8(AH) = 0x86; ! 17350: m_CF = 1; ! 17351: break; ! 17352: } ! 17353: break; ! 17354: case 0x16: ! 17355: // PC BIOS - Keyboard ! 17356: m_CF = 0; ! 17357: switch(REG8(AH)) { ! 17358: case 0x00: pcbios_int_16h_00h(); break; ! 17359: case 0x01: pcbios_int_16h_01h(); break; ! 17360: case 0x02: pcbios_int_16h_02h(); break; ! 17361: case 0x03: pcbios_int_16h_03h(); break; ! 17362: case 0x05: pcbios_int_16h_05h(); break; ! 17363: case 0x09: pcbios_int_16h_09h(); break; ! 17364: case 0x0a: pcbios_int_16h_0ah(); break; ! 17365: case 0x10: pcbios_int_16h_00h(); break; ! 17366: case 0x11: pcbios_int_16h_11h(); break; ! 17367: case 0x12: pcbios_int_16h_12h(); break; ! 17368: case 0x13: pcbios_int_16h_13h(); break; ! 17369: case 0x14: pcbios_int_16h_14h(); break; ! 17370: case 0x55: pcbios_int_16h_55h(); break; ! 17371: case 0x6f: pcbios_int_16h_6fh(); break; ! 17372: case 0xda: break; // unknown ! 17373: case 0xdb: break; // unknown ! 17374: case 0xff: break; // unknown ! 17375: default: ! 17376: unimplemented_16h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 17377: break; ! 17378: } ! 17379: break; ! 17380: case 0x17: ! 17381: // PC BIOS - Printer ! 17382: m_CF = 0; ! 17383: switch(REG8(AH)) { ! 17384: case 0x00: pcbios_int_17h_00h(); break; ! 17385: case 0x01: pcbios_int_17h_01h(); break; ! 17386: case 0x02: pcbios_int_17h_02h(); break; ! 17387: case 0x03: pcbios_int_17h_03h(); break; ! 17388: case 0x50: pcbios_int_17h_50h(); break; ! 17389: case 0x51: pcbios_int_17h_51h(); break; ! 17390: case 0x52: pcbios_int_17h_52h(); break; ! 17391: case 0x84: pcbios_int_17h_84h(); break; ! 17392: case 0x85: pcbios_int_17h_85h(); break; ! 17393: default: ! 17394: unimplemented_17h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 17395: break; ! 17396: } ! 17397: break; ! 17398: case 0x1a: ! 17399: // PC BIOS - Timer ! 17400: m_CF = 0; ! 17401: switch(REG8(AH)) { ! 17402: case 0x00: pcbios_int_1ah_00h(); break; ! 17403: case 0x01: break; ! 17404: case 0x02: pcbios_int_1ah_02h(); break; ! 17405: case 0x03: break; ! 17406: case 0x04: pcbios_int_1ah_04h(); break; ! 17407: case 0x05: break; ! 17408: case 0x0a: pcbios_int_1ah_0ah(); break; ! 17409: case 0x0b: break; ! 17410: case 0x35: break; // Word Perfect Third Party Interface? ! 17411: case 0x36: break; // Word Perfect Third Party Interface ! 17412: case 0x70: break; // SNAP? (Simple Network Application Protocol) ! 17413: case 0xb0: break; // Microsoft Real-Time Compression Interface (MRCI) ! 17414: case 0xb1: break; // PCI BIOS v2.0c+ ! 17415: case 0xb4: break; // Intel Plug-and-Play Auto-Configuration ! 17416: default: ! 17417: unimplemented_1ah("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 17418: break; ! 17419: } ! 17420: break; ! 17421: case 0x1b: ! 17422: mem[0x471] = 0x00; ! 17423: break; ! 17424: case 0x20: ! 17425: try { ! 17426: msdos_process_terminate(SREG(CS), retval, 1); ! 17427: } catch(...) { ! 17428: fatalerror("failed to terminate the process (PSP=%04X) by int 20h\n", SREG(CS)); ! 17429: } ! 17430: break; ! 17431: case 0x30: ! 17432: // dummy interrupt for case map routine pointed in the country info ! 17433: // if(!(REG8(CL) >= 0x00 && REG8(CL) <= 0x24)) { ! 17434: // REG8(AL) = 0x00; ! 17435: // break; ! 17436: // } ! 17437: case 0x21: ! 17438: // MS-DOS System Call ! 17439: m_CF = 0; ! 17440: try { ! 17441: switch(num == 0x21 ? REG8(AH) : REG8(CL)) { ! 17442: case 0x00: msdos_int_21h_00h(); break; ! 17443: case 0x01: msdos_int_21h_01h(); break; ! 17444: case 0x02: msdos_int_21h_02h(); break; ! 17445: case 0x03: msdos_int_21h_03h(); break; ! 17446: case 0x04: msdos_int_21h_04h(); break; ! 17447: case 0x05: msdos_int_21h_05h(); break; ! 17448: case 0x06: msdos_int_21h_06h(); break; ! 17449: case 0x07: msdos_int_21h_07h(); break; ! 17450: case 0x08: msdos_int_21h_08h(); break; ! 17451: case 0x09: msdos_int_21h_09h(); break; ! 17452: case 0x0a: msdos_int_21h_0ah(); break; ! 17453: case 0x0b: msdos_int_21h_0bh(); break; ! 17454: case 0x0c: msdos_int_21h_0ch(); break; ! 17455: case 0x0d: msdos_int_21h_0dh(); break; ! 17456: case 0x0e: msdos_int_21h_0eh(); break; ! 17457: case 0x0f: msdos_int_21h_0fh(); break; ! 17458: case 0x10: msdos_int_21h_10h(); break; ! 17459: case 0x11: msdos_int_21h_11h(); break; ! 17460: case 0x12: msdos_int_21h_12h(); break; ! 17461: case 0x13: msdos_int_21h_13h(); break; ! 17462: case 0x14: msdos_int_21h_14h(); break; ! 17463: case 0x15: msdos_int_21h_15h(); break; ! 17464: case 0x16: msdos_int_21h_16h(); break; ! 17465: case 0x17: msdos_int_21h_17h(); break; ! 17466: case 0x18: msdos_int_21h_18h(); break; ! 17467: case 0x19: msdos_int_21h_19h(); break; ! 17468: case 0x1a: msdos_int_21h_1ah(); break; ! 17469: case 0x1b: msdos_int_21h_1bh(); break; ! 17470: case 0x1c: msdos_int_21h_1ch(); break; ! 17471: case 0x1d: msdos_int_21h_1dh(); break; ! 17472: case 0x1e: msdos_int_21h_1eh(); break; ! 17473: case 0x1f: msdos_int_21h_1fh(); break; ! 17474: case 0x20: msdos_int_21h_20h(); break; ! 17475: case 0x21: msdos_int_21h_21h(); break; ! 17476: case 0x22: msdos_int_21h_22h(); break; ! 17477: case 0x23: msdos_int_21h_23h(); break; ! 17478: case 0x24: msdos_int_21h_24h(); break; ! 17479: case 0x25: msdos_int_21h_25h(); break; ! 17480: case 0x26: msdos_int_21h_26h(); break; ! 17481: case 0x27: msdos_int_21h_27h(); break; ! 17482: case 0x28: msdos_int_21h_28h(); break; ! 17483: case 0x29: msdos_int_21h_29h(); break; ! 17484: case 0x2a: msdos_int_21h_2ah(); break; ! 17485: case 0x2b: msdos_int_21h_2bh(); break; ! 17486: case 0x2c: msdos_int_21h_2ch(); break; ! 17487: case 0x2d: msdos_int_21h_2dh(); break; ! 17488: case 0x2e: msdos_int_21h_2eh(); break; ! 17489: case 0x2f: msdos_int_21h_2fh(); break; ! 17490: case 0x30: msdos_int_21h_30h(); break; ! 17491: case 0x31: msdos_int_21h_31h(); break; ! 17492: case 0x32: msdos_int_21h_32h(); break; ! 17493: case 0x33: msdos_int_21h_33h(); break; ! 17494: case 0x34: msdos_int_21h_34h(); break; ! 17495: case 0x35: msdos_int_21h_35h(); break; ! 17496: case 0x36: msdos_int_21h_36h(); break; ! 17497: case 0x37: msdos_int_21h_37h(); break; ! 17498: case 0x38: msdos_int_21h_38h(); break; ! 17499: case 0x39: msdos_int_21h_39h(0); break; ! 17500: case 0x3a: msdos_int_21h_3ah(0); break; ! 17501: case 0x3b: msdos_int_21h_3bh(0); break; ! 17502: case 0x3c: msdos_int_21h_3ch(); break; ! 17503: case 0x3d: msdos_int_21h_3dh(); break; ! 17504: case 0x3e: msdos_int_21h_3eh(); break; ! 17505: case 0x3f: msdos_int_21h_3fh(); break; ! 17506: case 0x40: msdos_int_21h_40h(); break; ! 17507: case 0x41: msdos_int_21h_41h(0); break; ! 17508: case 0x42: msdos_int_21h_42h(); break; ! 17509: case 0x43: msdos_int_21h_43h(0); break; ! 17510: case 0x44: msdos_int_21h_44h(); break; ! 17511: case 0x45: msdos_int_21h_45h(); break; ! 17512: case 0x46: msdos_int_21h_46h(); break; ! 17513: case 0x47: msdos_int_21h_47h(0); break; ! 17514: case 0x48: msdos_int_21h_48h(); break; ! 17515: case 0x49: msdos_int_21h_49h(); break; ! 17516: case 0x4a: msdos_int_21h_4ah(); break; ! 17517: case 0x4b: msdos_int_21h_4bh(); break; ! 17518: case 0x4c: msdos_int_21h_4ch(); break; ! 17519: case 0x4d: msdos_int_21h_4dh(); break; ! 17520: case 0x4e: msdos_int_21h_4eh(); break; ! 17521: case 0x4f: msdos_int_21h_4fh(); break; ! 17522: case 0x50: msdos_int_21h_50h(); break; ! 17523: case 0x51: msdos_int_21h_51h(); break; ! 17524: case 0x52: msdos_int_21h_52h(); break; ! 17525: case 0x53: msdos_int_21h_53h(); break; ! 17526: case 0x54: msdos_int_21h_54h(); break; ! 17527: case 0x55: msdos_int_21h_55h(); break; ! 17528: case 0x56: msdos_int_21h_56h(0); break; ! 17529: case 0x57: msdos_int_21h_57h(); break; ! 17530: case 0x58: msdos_int_21h_58h(); break; ! 17531: case 0x59: msdos_int_21h_59h(); break; ! 17532: case 0x5a: msdos_int_21h_5ah(); break; ! 17533: case 0x5b: msdos_int_21h_5bh(); break; ! 17534: case 0x5c: msdos_int_21h_5ch(); break; ! 17535: case 0x5d: msdos_int_21h_5dh(); break; ! 17536: case 0x5e: msdos_int_21h_5eh(); break; ! 17537: case 0x5f: msdos_int_21h_5fh(); break; ! 17538: case 0x60: msdos_int_21h_60h(0); break; ! 17539: case 0x61: msdos_int_21h_61h(); break; ! 17540: case 0x62: msdos_int_21h_62h(); break; ! 17541: case 0x63: msdos_int_21h_63h(); break; ! 17542: // 0x64: Set Device Driver Lockahead Flag ! 17543: case 0x65: msdos_int_21h_65h(); break; ! 17544: case 0x66: msdos_int_21h_66h(); break; ! 17545: case 0x67: msdos_int_21h_67h(); break; ! 17546: case 0x68: msdos_int_21h_68h(); break; ! 17547: case 0x69: msdos_int_21h_69h(); break; ! 17548: case 0x6a: msdos_int_21h_6ah(); break; ! 17549: case 0x6b: msdos_int_21h_6bh(); break; ! 17550: case 0x6c: msdos_int_21h_6ch(0); break; ! 17551: case 0x6d: // Find First ROM Program ! 17552: case 0x6e: // Find Next ROM Program ! 17553: case 0x6f: // Get/Set ROM Scan Start Address ! 17554: REG8(AL) = 0x00; // if not supported (DOS <5, MS-DOS 5+ non-ROM versions) ! 17555: break; ! 17556: case 0x70: msdos_int_21h_70h(); break; ! 17557: case 0x71: // Windows95 - Long Filename Functions ! 17558: switch(REG8(AL)) { ! 17559: case 0x0d: msdos_int_21h_710dh(); break; ! 17560: case 0x39: msdos_int_21h_39h(1); break; ! 17561: case 0x3a: msdos_int_21h_3ah(1); break; ! 17562: case 0x3b: msdos_int_21h_3bh(1); break; ! 17563: case 0x41: msdos_int_21h_7141h(); break; ! 17564: case 0x43: msdos_int_21h_43h(1); break; ! 17565: case 0x47: msdos_int_21h_47h(1); break; ! 17566: case 0x4e: msdos_int_21h_714eh(); break; ! 17567: case 0x4f: msdos_int_21h_714fh(); break; ! 17568: case 0x56: msdos_int_21h_56h(1); break; ! 17569: case 0x60: msdos_int_21h_60h(1); break; ! 17570: case 0x6c: msdos_int_21h_6ch(1); break; ! 17571: case 0xa0: msdos_int_21h_71a0h(); break; ! 17572: case 0xa1: msdos_int_21h_71a1h(); break; ! 17573: case 0xa6: msdos_int_21h_71a6h(); break; ! 17574: case 0xa7: msdos_int_21h_71a7h(); break; ! 17575: case 0xa8: msdos_int_21h_71a8h(); break; ! 17576: case 0xa9: msdos_int_21h_6ch(1); break; ! 17577: case 0xaa: msdos_int_21h_71aah(); break; ! 17578: default: ! 17579: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 17580: REG16(AX) = 0x7100; ! 17581: m_CF = 1; ! 17582: break; ! 17583: } ! 17584: break; ! 17585: case 0x72: // Windows95 beta - LFN FindClose ! 17586: // unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 17587: REG16(AX) = 0x7200; ! 17588: m_CF = 1; ! 17589: break; ! 17590: case 0x73: // Windows95 - FAT32 Functions ! 17591: switch(REG8(AL)) { ! 17592: case 0x00: msdos_int_21h_7300h(); break; ! 17593: // 0x01: Set Drive Locking ??? ! 17594: case 0x02: msdos_int_21h_7302h(); break; ! 17595: case 0x03: msdos_int_21h_7303h(); break; ! 17596: // 0x04: Set DPB to Use for Formatting ! 17597: // 0x05: Extended Absolute Disk Read/Write ! 17598: default: ! 17599: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 17600: REG16(AX) = 0x7300; ! 17601: m_CF = 1; ! 17602: break; ! 17603: } ! 17604: break; ! 17605: case 0xdb: msdos_int_21h_dbh(); break; ! 17606: case 0xdc: msdos_int_21h_dch(); break; ! 17607: default: ! 17608: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 17609: REG16(AX) = 0x01; ! 17610: m_CF = 1; ! 17611: break; ! 17612: } ! 17613: } catch(int error) { ! 17614: REG16(AX) = error; ! 17615: m_CF = 1; ! 17616: } catch(...) { ! 17617: REG16(AX) = 0x1f; // general failure ! 17618: m_CF = 1; ! 17619: } ! 17620: if(m_CF) { ! 17621: sda_t *sda = (sda_t *)(mem + SDA_TOP); ! 17622: sda->int21h_5d0ah_called = 0; ! 17623: sda->extended_error_code = REG16(AX); ! 17624: switch(sda->extended_error_code) { ! 17625: case 4: // Too many open files ! 17626: case 8: // Insufficient memory ! 17627: sda->error_class = 1; // Out of resource ! 17628: break; ! 17629: case 5: // Access denied ! 17630: sda->error_class = 3; // Authorization ! 17631: break; ! 17632: case 7: // Memory control block destroyed ! 17633: sda->error_class = 4; // Internal ! 17634: break; ! 17635: case 2: // File not found ! 17636: case 3: // Path not found ! 17637: case 15: // Invaid drive specified ! 17638: case 18: // No more files ! 17639: sda->error_class = 8; // Not found ! 17640: break; ! 17641: case 32: // Sharing violation ! 17642: case 33: // Lock violation ! 17643: sda->error_class = 10; // Locked ! 17644: break; ! 17645: // case 16: // Removal of current directory attempted ! 17646: case 19: // Attempted write on protected disk ! 17647: case 21: // Drive not ready ! 17648: // case 29: // Write failure ! 17649: // case 30: // Read failure ! 17650: // case 82: // Cannot create subdirectory ! 17651: sda->error_class = 11; // Media ! 17652: break; ! 17653: case 80: // File already exists ! 17654: sda->error_class = 12; // Already exist ! 17655: break; ! 17656: default: ! 17657: sda->error_class = 13; // Unknown ! 17658: break; ! 17659: } ! 17660: sda->suggested_action = 1; // Retry ! 17661: sda->locus_of_last_error = 1; // Unknown ! 17662: } ! 17663: if(ctrl_break_checking && ctrl_break_detected) { ! 17664: // raise int 23h ! 17665: #if defined(HAS_I386) ! 17666: m_ext = 0; // not an external interrupt ! 17667: i386_trap(0x23, 1, 0); ! 17668: m_ext = 1; ! 17669: #else ! 17670: PREFIX86(_interrupt)(0x23); ! 17671: #endif ! 17672: } ! 17673: break; ! 17674: case 0x22: ! 17675: fatalerror("int 22h (terminate address)\n"); ! 17676: case 0x23: ! 17677: try { ! 17678: msdos_process_terminate(current_psp, (retval & 0xff) | 0x100, 1); ! 17679: } catch(...) { ! 17680: fatalerror("failed to terminate the current process by int 23h\n"); ! 17681: } ! 17682: break; ! 17683: case 0x24: ! 17684: /* ! 17685: try { ! 17686: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1); ! 17687: } catch(...) { ! 17688: fatalerror("failed to terminate the current process by int 24h\n"); ! 17689: } ! 17690: */ ! 17691: msdos_int_24h(); ! 17692: break; ! 17693: case 0x25: ! 17694: msdos_int_25h(); ! 17695: break; ! 17696: case 0x26: ! 17697: msdos_int_26h(); ! 17698: break; ! 17699: case 0x27: ! 17700: try { ! 17701: msdos_int_27h(); ! 17702: } catch(...) { ! 17703: fatalerror("failed to terminate the process (PSP=%04X) by int 27h\n", SREG(CS)); ! 17704: } ! 17705: break; ! 17706: case 0x28: ! 17707: Sleep(10); ! 17708: REQUEST_HARDWRE_UPDATE(); ! 17709: break; ! 17710: case 0x29: ! 17711: msdos_int_29h(); ! 17712: break; ! 17713: case 0x2e: ! 17714: msdos_int_2eh(); ! 17715: break; ! 17716: case 0x2f: ! 17717: // multiplex interrupt ! 17718: switch(REG8(AH)) { ! 17719: case 0x05: msdos_int_2fh_05h(); break; ! 17720: case 0x06: msdos_int_2fh_06h(); break; ! 17721: case 0x11: msdos_int_2fh_11h(); break; ! 17722: case 0x12: msdos_int_2fh_12h(); break; ! 17723: case 0x13: msdos_int_2fh_13h(); break; ! 17724: case 0x14: msdos_int_2fh_14h(); break; ! 17725: case 0x15: msdos_int_2fh_15h(); break; ! 17726: case 0x16: msdos_int_2fh_16h(); break; ! 17727: case 0x19: msdos_int_2fh_19h(); break; ! 17728: case 0x1a: msdos_int_2fh_1ah(); break; ! 17729: case 0x40: msdos_int_2fh_40h(); break; ! 17730: case 0x43: msdos_int_2fh_43h(); break; ! 17731: case 0x46: msdos_int_2fh_46h(); break; ! 17732: case 0x48: msdos_int_2fh_48h(); break; ! 17733: case 0x4a: msdos_int_2fh_4ah(); break; ! 17734: case 0x4b: msdos_int_2fh_4bh(); break; ! 17735: case 0x4d: msdos_int_2fh_4dh(); break; ! 17736: case 0x4f: msdos_int_2fh_4fh(); break; ! 17737: case 0x55: msdos_int_2fh_55h(); break; ! 17738: case 0x56: msdos_int_2fh_56h(); break; ! 17739: case 0xad: msdos_int_2fh_adh(); break; ! 17740: case 0xae: msdos_int_2fh_aeh(); break; ! 17741: case 0xb7: msdos_int_2fh_b7h(); break; ! 17742: default: ! 17743: switch(REG8(AL)) { ! 17744: case 0x00: ! 17745: // This is not installed ! 17746: // REG8(AL) = 0x00; ! 17747: break; ! 17748: case 0x01: ! 17749: // Quarterdeck RPCI - QEMM/QRAM - PCL-838.EXE is not installed ! 17750: if(REG8(AH) == 0xd2 && REG16(BX) == 0x5145 && REG16(CX) == 0x4d4d && REG16(DX) == 0x3432) { ! 17751: break; ! 17752: } ! 17753: // Banyan VINES v4+ is not installed ! 17754: if(REG8(AH) == 0xd7 && REG16(BX) == 0x0000) { ! 17755: break; ! 17756: } ! 17757: // Quarterdeck QDPMI.SYS v1.0 is not installed ! 17758: if(REG8(AH) == 0xde && REG16(BX) == 0x4450 && REG16(CX) == 0x4d49 && REG16(DX) == 0x8f4f) { ! 17759: break; ! 17760: } ! 17761: default: ! 17762: // NORTON UTILITIES 5.0+ ! 17763: if(REG8(AH) == 0xfe && REG16(DI) == 0x4e55) { ! 17764: break; ! 17765: } ! 17766: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 17767: REG16(AX) = 0x01; // invalid function ! 17768: m_CF = 1; ! 17769: break; ! 17770: } ! 17771: break; ! 17772: } ! 17773: break; ! 17774: case 0x33: ! 17775: switch(REG8(AH)) { ! 17776: case 0x00: ! 17777: // Mouse ! 17778: switch(REG16(AX)) { ! 17779: case 0x0000: msdos_int_33h_0000h(); break; ! 17780: case 0x0001: msdos_int_33h_0001h(); break; ! 17781: case 0x0002: msdos_int_33h_0002h(); break; ! 17782: case 0x0003: msdos_int_33h_0003h(); break; ! 17783: case 0x0004: msdos_int_33h_0004h(); break; ! 17784: case 0x0005: msdos_int_33h_0005h(); break; ! 17785: case 0x0006: msdos_int_33h_0006h(); break; ! 17786: case 0x0007: msdos_int_33h_0007h(); break; ! 17787: case 0x0008: msdos_int_33h_0008h(); break; ! 17788: case 0x0009: msdos_int_33h_0009h(); break; ! 17789: case 0x000a: msdos_int_33h_000ah(); break; ! 17790: case 0x000b: msdos_int_33h_000bh(); break; ! 17791: case 0x000c: msdos_int_33h_000ch(); break; ! 17792: case 0x000d: break; // MS MOUSE v1.0+ - Light Pen Emulation On ! 17793: case 0x000e: break; // MS MOUSE v1.0+ - Light Pen Emulation Off ! 17794: case 0x000f: msdos_int_33h_000fh(); break; ! 17795: case 0x0010: break; // MS MOUSE v1.0+ - Define Screen Region for Updating ! 17796: case 0x0011: msdos_int_33h_0011h(); break; ! 17797: case 0x0012: REG16(AX) = 0xffff; break; // MS MOUSE - Set Large Graphics Cursor Block ! 17798: case 0x0013: break; // MS MOUSE v5.0+ - Define Double-Speed Threshold ! 17799: case 0x0014: msdos_int_33h_0014h(); break; ! 17800: case 0x0015: msdos_int_33h_0015h(); break; ! 17801: case 0x0016: msdos_int_33h_0016h(); break; ! 17802: case 0x0017: msdos_int_33h_0017h(); break; ! 17803: case 0x0018: msdos_int_33h_0018h(); break; ! 17804: case 0x0019: msdos_int_33h_0019h(); break; ! 17805: case 0x001a: msdos_int_33h_001ah(); break; ! 17806: case 0x001b: msdos_int_33h_001bh(); break; ! 17807: case 0x001c: break; // MS MOUSE v6.0+ - Set Interrupt Rate ! 17808: case 0x001d: msdos_int_33h_001dh(); break; ! 17809: case 0x001e: msdos_int_33h_001eh(); break; ! 17810: case 0x001f: msdos_int_33h_001fh(); break; ! 17811: case 0x0020: msdos_int_33h_0020h(); break; ! 17812: case 0x0021: msdos_int_33h_0021h(); break; ! 17813: case 0x0022: msdos_int_33h_0022h(); break; ! 17814: case 0x0023: msdos_int_33h_0023h(); break; ! 17815: case 0x0024: msdos_int_33h_0024h(); break; ! 17816: case 0x0025: msdos_int_33h_0025h(); break; ! 17817: case 0x0026: msdos_int_33h_0026h(); break; ! 17818: case 0x0027: msdos_int_33h_0027h(); break; ! 17819: case 0x0028: msdos_int_33h_0028h(); break; ! 17820: case 0x0029: msdos_int_33h_0029h(); break; ! 17821: case 0x002a: msdos_int_33h_002ah(); break; ! 17822: // 0x002b: MS MOUSE v7.0+ - Load Acceleration Profiles ! 17823: // 0x002c: MS MOUSE v7.0+ - Get Acceleration Profiles ! 17824: // 0x002d: MS MOUSE v7.0+ - Select Acceleration Profile ! 17825: // 0x002e: MS MOUSE v8.10+ - Set Acceleration Profile Names ! 17826: case 0x002f: break; // Mouse Hardware Reset ! 17827: // 0x0030: MS MOUSE v7.04+ - Get/Set BallPoint Information ! 17828: case 0x0031: msdos_int_33h_0031h(); break; ! 17829: case 0x0032: msdos_int_33h_0032h(); break; ! 17830: // 0x0033: MS MOUSE v7.05+ - Get Switch Settings And Acceleration Profile Data ! 17831: // 0x0034: MS MOUSE v8.0+ - Get Initialization File ! 17832: // 0x0035: MS MOUSE v8.10+ - LCD Screen Large Pointer Support ! 17833: case 0x004d: msdos_int_33h_004dh(); break; ! 17834: case 0x006d: msdos_int_33h_006dh(); break; ! 17835: default: ! 17836: unimplemented_33h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 17837: break; ! 17838: } ! 17839: break; ! 17840: default: ! 17841: unimplemented_33h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 17842: break; ! 17843: } ! 17844: break; ! 17845: case 0x65: ! 17846: // dummy interrupt for EMS (int 67h) ! 17847: switch(REG8(AH)) { ! 17848: case 0x40: msdos_int_67h_40h(); break; ! 17849: case 0x41: msdos_int_67h_41h(); break; ! 17850: case 0x42: msdos_int_67h_42h(); break; ! 17851: case 0x43: msdos_int_67h_43h(); break; ! 17852: case 0x44: msdos_int_67h_44h(); break; ! 17853: case 0x45: msdos_int_67h_45h(); break; ! 17854: case 0x46: msdos_int_67h_46h(); break; ! 17855: case 0x47: msdos_int_67h_47h(); break; ! 17856: case 0x48: msdos_int_67h_48h(); break; ! 17857: // 0x49: LIM EMS - Reserved - Get I/O Port Address (Undocumented in EMS 3.2) ! 17858: // 0x4a: LIM EMS - Reserved - Get Translation Array (Undocumented in EMS 3.2) ! 17859: case 0x4b: msdos_int_67h_4bh(); break; ! 17860: case 0x4c: msdos_int_67h_4ch(); break; ! 17861: case 0x4d: msdos_int_67h_4dh(); break; ! 17862: case 0x4e: msdos_int_67h_4eh(); break; ! 17863: case 0x4f: msdos_int_67h_4fh(); break; ! 17864: case 0x50: msdos_int_67h_50h(); break; ! 17865: case 0x51: msdos_int_67h_51h(); break; ! 17866: case 0x52: msdos_int_67h_52h(); break; ! 17867: case 0x53: msdos_int_67h_53h(); break; ! 17868: case 0x54: msdos_int_67h_54h(); break; ! 17869: case 0x55: msdos_int_67h_55h(); break; ! 17870: case 0x56: msdos_int_67h_56h(); break; ! 17871: case 0x57: msdos_int_67h_57h(); break; ! 17872: case 0x58: msdos_int_67h_58h(); break; ! 17873: case 0x59: msdos_int_67h_59h(); break; ! 17874: case 0x5a: msdos_int_67h_5ah(); break; ! 17875: case 0x5b: msdos_int_67h_5bh(); break; ! 17876: // 0x5c: LIM EMS 4.0 - Prepare Expanded Memory Hardware For Warm Boot ! 17877: case 0x5d: msdos_int_67h_5dh(); break; ! 17878: case 0x70: msdos_int_67h_70h(); break; ! 17879: // 0xde: VCPI ! 17880: case 0xde: msdos_int_67h_deh(); break; ! 17881: default: ! 17882: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 17883: REG8(AH) = 0x84; ! 17884: break; ! 17885: } ! 17886: break; ! 17887: #ifdef SUPPORT_XMS ! 17888: case 0x66: ! 17889: // dummy interrupt for XMS (call far) ! 17890: try { ! 17891: switch(REG8(AH)) { ! 17892: case 0x00: msdos_call_xms_00h(); break; ! 17893: case 0x01: msdos_call_xms_01h(); break; ! 17894: case 0x02: msdos_call_xms_02h(); break; ! 17895: case 0x03: msdos_call_xms_03h(); break; ! 17896: case 0x04: msdos_call_xms_04h(); break; ! 17897: case 0x05: msdos_call_xms_05h(); break; ! 17898: case 0x06: msdos_call_xms_06h(); break; ! 17899: case 0x07: msdos_call_xms_07h(); break; ! 17900: case 0x08: msdos_call_xms_08h(); break; ! 17901: case 0x09: msdos_call_xms_09h(); break; ! 17902: case 0x0a: msdos_call_xms_0ah(); break; ! 17903: case 0x0b: msdos_call_xms_0bh(); break; ! 17904: case 0x0c: msdos_call_xms_0ch(); break; ! 17905: case 0x0d: msdos_call_xms_0dh(); break; ! 17906: case 0x0e: msdos_call_xms_0eh(); break; ! 17907: case 0x0f: msdos_call_xms_0fh(); break; ! 17908: case 0x10: msdos_call_xms_10h(); break; ! 17909: case 0x11: msdos_call_xms_11h(); break; ! 17910: case 0x12: msdos_call_xms_12h(); break; ! 17911: #if defined(HAS_I386) ! 17912: case 0x88: msdos_call_xms_88h(); break; ! 17913: case 0x89: msdos_call_xms_89h(); break; ! 17914: case 0x8e: msdos_call_xms_8eh(); break; ! 17915: case 0x8f: msdos_call_xms_8fh(); break; ! 17916: #endif ! 17917: default: ! 17918: unimplemented_xms("call XMS (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 17919: REG16(AX) = 0x0000; ! 17920: REG8(BL) = 0x80; // function not implemented ! 17921: break; ! 17922: } ! 17923: } catch(...) { ! 17924: REG16(AX) = 0x0000; ! 17925: REG8(BL) = 0x8f; // unrecoverable driver error ! 17926: } ! 17927: break; ! 17928: #endif ! 17929: /* ! 17930: case 0x67: ! 17931: // int 67h handler is in EMS device driver (EMMXXXX0) and it calls int 65h ! 17932: // NOTE: some softwares get address of int 67h handler and recognize the address is in EMS device driver ! 17933: break; ! 17934: */ ! 17935: case 0x69: ! 17936: // irq12 (mouse) ! 17937: mouse_push_ax = REG16(AX); ! 17938: mouse_push_bx = REG16(BX); ! 17939: mouse_push_cx = REG16(CX); ! 17940: mouse_push_dx = REG16(DX); ! 17941: mouse_push_si = REG16(SI); ! 17942: mouse_push_di = REG16(DI); ! 17943: ! 17944: if(mouse.status_irq && mouse.call_addr.dw) { ! 17945: REG16(AX) = mouse.status_irq; ! 17946: REG16(BX) = mouse.get_buttons(); ! 17947: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.position.x)); ! 17948: REG16(DX) = max(mouse.min_position.y & ~7, min(mouse.max_position.y & ~7, mouse.position.y)); ! 17949: REG16(SI) = REG16(CX) * mouse.mickey.x / 8; ! 17950: REG16(DI) = REG16(DX) * mouse.mickey.y / 8; ! 17951: ! 17952: mem[DUMMY_TOP + 0x02] = 0x9a; // call far ! 17953: mem[DUMMY_TOP + 0x03] = mouse.call_addr.w.l & 0xff; ! 17954: mem[DUMMY_TOP + 0x04] = mouse.call_addr.w.l >> 8; ! 17955: mem[DUMMY_TOP + 0x05] = mouse.call_addr.w.h & 0xff; ! 17956: mem[DUMMY_TOP + 0x06] = mouse.call_addr.w.h >> 8; ! 17957: mem[DUMMY_TOP + 0x07] = 0xcd; // int 6bh (dummy) ! 17958: mem[DUMMY_TOP + 0x08] = 0x6b; ! 17959: break; ! 17960: } ! 17961: for(int i = 0; i < 8; i++) { ! 17962: if((mouse.status_irq_alt & (1 << i)) && mouse.call_addr_alt[i].dw) { ! 17963: REG16(AX) = mouse.status_irq_alt; ! 17964: REG16(BX) = mouse.get_buttons(); ! 17965: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.position.x)); ! 17966: REG16(DX) = max(mouse.min_position.y & ~7, min(mouse.max_position.y & ~7, mouse.position.y)); ! 17967: REG16(SI) = REG16(CX) * mouse.mickey.x / 8; ! 17968: REG16(DI) = REG16(DX) * mouse.mickey.y / 8; ! 17969: ! 17970: mem[DUMMY_TOP + 0x02] = 0x9a; // call far ! 17971: mem[DUMMY_TOP + 0x03] = mouse.call_addr_alt[i].w.l & 0xff; ! 17972: mem[DUMMY_TOP + 0x04] = mouse.call_addr_alt[i].w.l >> 8; ! 17973: mem[DUMMY_TOP + 0x05] = mouse.call_addr_alt[i].w.h & 0xff; ! 17974: mem[DUMMY_TOP + 0x06] = mouse.call_addr_alt[i].w.h >> 8; ! 17975: mem[DUMMY_TOP + 0x07] = 0xcd; // int 6bh (dummy) ! 17976: mem[DUMMY_TOP + 0x08] = 0x6b; ! 17977: break; ! 17978: } ! 17979: } ! 17980: if(mouse.status_irq_ps2 && mouse.call_addr_ps2.dw && mouse.enabled_ps2) { ! 17981: UINT16 data_1st, data_2nd, data_3rd; ! 17982: pcbios_read_from_ps2_mouse(&data_1st, &data_2nd, &data_3rd); ! 17983: i386_push16(data_1st); ! 17984: i386_push16(data_2nd); ! 17985: i386_push16(data_3rd); ! 17986: i386_push16(0x0000); ! 17987: ! 17988: mem[DUMMY_TOP + 0x02] = 0x9a; // call far ! 17989: mem[DUMMY_TOP + 0x03] = mouse.call_addr_ps2.w.l & 0xff; ! 17990: mem[DUMMY_TOP + 0x04] = mouse.call_addr_ps2.w.l >> 8; ! 17991: mem[DUMMY_TOP + 0x05] = mouse.call_addr_ps2.w.h & 0xff; ! 17992: mem[DUMMY_TOP + 0x06] = mouse.call_addr_ps2.w.h >> 8; ! 17993: mem[DUMMY_TOP + 0x07] = 0xcd; // int 6ah (dummy) ! 17994: mem[DUMMY_TOP + 0x08] = 0x6a; ! 17995: break; ! 17996: } ! 17997: // invalid call addr :-( ! 17998: mem[DUMMY_TOP + 0x02] = 0x90; // nop ! 17999: mem[DUMMY_TOP + 0x03] = 0x90; // nop ! 18000: mem[DUMMY_TOP + 0x04] = 0x90; // nop ! 18001: mem[DUMMY_TOP + 0x05] = 0x90; // nop ! 18002: mem[DUMMY_TOP + 0x06] = 0x90; // nop ! 18003: mem[DUMMY_TOP + 0x07] = 0xcd; // int 6bh (dummy) ! 18004: mem[DUMMY_TOP + 0x08] = 0x6b; ! 18005: break; ! 18006: case 0x6a: ! 18007: // end of ps/2 mouse bios ! 18008: i386_pop16(); ! 18009: i386_pop16(); ! 18010: i386_pop16(); ! 18011: i386_pop16(); ! 18012: case 0x6b: ! 18013: // end of irq12 (mouse) ! 18014: REG16(AX) = mouse_push_ax; ! 18015: REG16(BX) = mouse_push_bx; ! 18016: REG16(CX) = mouse_push_cx; ! 18017: REG16(DX) = mouse_push_dx; ! 18018: REG16(SI) = mouse_push_si; ! 18019: REG16(DI) = mouse_push_di; ! 18020: ! 18021: // EOI ! 18022: if((pic[1].isr &= ~(1 << 4)) == 0) { ! 18023: pic[0].isr &= ~(1 << 2); // master ! 18024: } ! 18025: pic_update(); ! 18026: break; ! 18027: case 0x6c: ! 18028: // dummy interrupt for case map routine pointed in the country info ! 18029: if(REG8(AL) >= 0x80) { ! 18030: char tmp[2] = {0}; ! 18031: tmp[0] = REG8(AL); ! 18032: my_strupr(tmp); ! 18033: REG8(AL) = tmp[0]; ! 18034: } ! 18035: break; ! 18036: case 0x6d: ! 18037: // dummy interrupt for font read routine pointed by int 15h, ax=5000h ! 18038: REG8(AL) = 0x86; // not supported ! 18039: m_CF = 1; ! 18040: break; ! 18041: case 0x6e: ! 18042: // dummy interrupt for parameter error message read routine pointed by int 2fh, ax=122eh, dl=08h ! 18043: { ! 18044: UINT16 code = REG16(AX); ! 18045: if(code & 0xf0) { ! 18046: code = (code & 7) | ((code & 0x10) >> 1); ! 18047: } ! 18048: for(int i = 0; i < array_length(param_error_table); i++) { ! 18049: if(param_error_table[i].code == code || param_error_table[i].code == (UINT16)-1) { ! 18050: const char *message = NULL; ! 18051: if(active_code_page == 932) { ! 18052: message = param_error_table[i].message_japanese; ! 18053: } ! 18054: if(message == NULL) { ! 18055: message = param_error_table[i].message_english; ! 18056: } ! 18057: *(UINT8 *)(mem + WORK_TOP) = strlen(message); ! 18058: strcpy((char *)(mem + WORK_TOP + 1), message); ! 18059: ! 18060: SREG(ES) = WORK_TOP >> 4; ! 18061: i386_load_segment_descriptor(ES); ! 18062: REG16(DI) = 0x0000; ! 18063: break; ! 18064: } ! 18065: } ! 18066: } ! 18067: break; ! 18068: case 0x6f: ! 18069: // dummy interrupt for end of alter page map and call ! 18070: { ! 18071: UINT16 handles[4], pages[4]; ! 18072: ! 18073: // pop old mapping data in new mapping ! 18074: for(int i = 0; i < 4; i++) { ! 18075: pages [3 - i] = i386_pop16(); ! 18076: handles[3 - i] = i386_pop16(); ! 18077: } ! 18078: ! 18079: // restore old mapping ! 18080: for(int i = 0; i < 4; i++) { ! 18081: UINT16 handle = handles[i]; ! 18082: UINT16 page = pages [i]; ! 18083: ! 18084: if(handle >= 1 && handle <= MAX_EMS_HANDLES && ems_handles[handle].allocated && page < ems_handles[handle].pages) { ! 18085: ems_map_page(i, handle, page); ! 18086: } else { ! 18087: ems_unmap_page(i); ! 18088: } ! 18089: } ! 18090: // do ret_far (pop cs/ip) in old mapping ! 18091: } ! 18092: break; ! 18093: case 0x70: ! 18094: case 0x71: ! 18095: case 0x72: ! 18096: case 0x73: ! 18097: case 0x74: ! 18098: case 0x75: ! 18099: case 0x76: ! 18100: case 0x77: ! 18101: // EOI ! 18102: if((pic[1].isr &= ~(1 << (num - 0x70))) == 0) { ! 18103: pic[0].isr &= ~(1 << 2); // master ! 18104: } ! 18105: pic_update(); ! 18106: break; ! 18107: default: ! 18108: // fatalerror("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES)); ! 18109: break; ! 18110: } ! 18111: ! 18112: // update cursor position ! 18113: if(cursor_moved) { ! 18114: pcbios_update_cursor_position(); ! 18115: cursor_moved = false; ! 18116: } ! 18117: } ! 18118: ! 18119: // init ! 18120: ! 18121: int msdos_init(int argc, char *argv[], char *envp[], int standard_env) ! 18122: { ! 18123: // init file handler ! 18124: memset(file_handler, 0, sizeof(file_handler)); ! 18125: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0); ! 18126: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0); ! 18127: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0); ! 18128: #ifdef MAP_AUX_DEVICE_TO_FILE ! 18129: if(_open("stdaux.txt", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) { ! 18130: #else ! 18131: if(_open("NUL", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) { ! 18132: #endif ! 18133: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0); ! 18134: } ! 18135: if(_open("NUL", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) { ! 18136: // msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0, 0, 1); // LPT1 ! 18137: msdos_file_handler_open(4, "STDPRN", 0, 1, 0x80a0, 0, 0, 1); // LPT1 ! 18138: } ! 18139: _dup2(0, DUP_STDIN); ! 18140: _dup2(1, DUP_STDOUT); ! 18141: _dup2(2, DUP_STDERR); ! 18142: _dup2(3, DUP_STDAUX); ! 18143: _dup2(4, DUP_STDPRN); ! 18144: ! 18145: // init mouse ! 18146: memset(&mouse, 0, sizeof(mouse)); ! 18147: mouse.enabled = true; // from DOSBox ! 18148: mouse.hidden = 1; // hidden in default ??? ! 18149: mouse.old_hidden = 1; // from DOSBox ! 18150: mouse.max_position.x = 8 * (scr_width - 1); ! 18151: mouse.max_position.y = 8 * (scr_height - 1); ! 18152: mouse.mickey.x = 8; ! 18153: mouse.mickey.y = 16; ! 18154: ! 18155: #ifdef SUPPORT_XMS ! 18156: // init xms ! 18157: msdos_xms_init(); ! 18158: #endif ! 18159: ! 18160: // init process ! 18161: memset(process, 0, sizeof(process)); ! 18162: ! 18163: // init dtainfo ! 18164: msdos_dta_info_init(); ! 18165: ! 18166: // init memory ! 18167: memset(mem, 0, sizeof(mem)); ! 18168: ! 18169: // bios data area ! 18170: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); ! 18171: CONSOLE_SCREEN_BUFFER_INFO csbi; ! 18172: GetConsoleScreenBufferInfo(hStdout, &csbi); ! 18173: // CONSOLE_FONT_INFO cfi; ! 18174: // GetCurrentConsoleFont(hStdout, FALSE, &cfi); ! 18175: ! 18176: int regen = min(scr_width * scr_height * 2, 0x8000); ! 18177: text_vram_top_address = TEXT_VRAM_TOP; ! 18178: text_vram_end_address = text_vram_top_address + regen; ! 18179: shadow_buffer_top_address = SHADOW_BUF_TOP; ! 18180: shadow_buffer_end_address = shadow_buffer_top_address + regen; ! 18181: cursor_position_address = 0x450 + mem[0x462] * 2; ! 18182: ! 18183: if(regen > 0x4000) { ! 18184: regen = 0x8000; ! 18185: vram_pages = 1; ! 18186: } else if(regen > 0x2000) { ! 18187: regen = 0x4000; ! 18188: vram_pages = 2; ! 18189: } else if(regen > 0x1000) { ! 18190: regen = 0x2000; ! 18191: vram_pages = 4; ! 18192: } else { ! 18193: regen = 0x1000; ! 18194: vram_pages = 8; ! 18195: } ! 18196: ! 18197: *(UINT16 *)(mem + 0x400) = 0x3f8; // com1 port address ! 18198: *(UINT16 *)(mem + 0x402) = 0x2f8; // com2 port address ! 18199: *(UINT16 *)(mem + 0x404) = 0x3e8; // com3 port address ! 18200: *(UINT16 *)(mem + 0x406) = 0x2e8; // com4 port address ! 18201: *(UINT16 *)(mem + 0x408) = 0x378; // lpt1 port address ! 18202: *(UINT16 *)(mem + 0x40a) = 0x278; // lpt2 port address ! 18203: *(UINT16 *)(mem + 0x40c) = 0x3bc; // lpt3 port address ! 18204: #ifdef EXT_BIOS_TOP ! 18205: *(UINT16 *)(mem + 0x40e) = EXT_BIOS_TOP >> 4; ! 18206: #endif ! 18207: *(UINT16 *)(mem + 0x410) = msdos_get_equipment(); ! 18208: *(UINT16 *)(mem + 0x413) = MEMORY_END >> 10; ! 18209: *(UINT16 *)(mem + 0x41a) = 0x1e; ! 18210: *(UINT16 *)(mem + 0x41c) = 0x1e; ! 18211: *(UINT8 *)(mem + 0x449) = 0x03;//0x73; ! 18212: *(UINT16 *)(mem + 0x44a) = csbi.dwSize.X; ! 18213: *(UINT16 *)(mem + 0x44c) = regen; ! 18214: *(UINT16 *)(mem + 0x44e) = 0; ! 18215: *(UINT8 *)(mem + 0x450) = csbi.dwCursorPosition.X; ! 18216: *(UINT8 *)(mem + 0x451) = csbi.dwCursorPosition.Y - scr_top; ! 18217: *(UINT8 *)(mem + 0x460) = 7; ! 18218: *(UINT8 *)(mem + 0x461) = 7; ! 18219: *(UINT8 *)(mem + 0x462) = 0; ! 18220: *(UINT16 *)(mem + 0x463) = 0x3d4; ! 18221: *(UINT8 *)(mem + 0x465) = 0x09; ! 18222: *(UINT32 *)(mem + 0x46c) = get_ticks_since_midnight(timeGetTime()); ! 18223: *(UINT16 *)(mem + 0x472) = 0x4321; // preserve memory in cpu reset ! 18224: *(UINT16 *)(mem + 0x480) = 0x1e; ! 18225: *(UINT16 *)(mem + 0x482) = 0x3e; ! 18226: *(UINT8 *)(mem + 0x484) = csbi.srWindow.Bottom - csbi.srWindow.Top; ! 18227: *(UINT16 *)(mem + 0x485) = font_height; ! 18228: *(UINT8 *)(mem + 0x487) = 0x60; ! 18229: *(UINT8 *)(mem + 0x496) = 0x10; // enhanced keyboard installed ! 18230: #ifdef EXT_BIOS_TOP ! 18231: *(UINT16 *)(mem + EXT_BIOS_TOP) = 1; ! 18232: #endif ! 18233: ! 18234: // initial screen ! 18235: SMALL_RECT rect; ! 18236: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom); ! 18237: ReadConsoleOutputA(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect); ! 18238: for(int y = 0, ofs1 = TEXT_VRAM_TOP, ofs2 = SHADOW_BUF_TOP; y < scr_height; y++) { ! 18239: for(int x = 0; x < scr_width; x++) { ! 18240: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Char.AsciiChar; ! 18241: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Attributes; ! 18242: } ! 18243: } ! 18244: ! 18245: // init mcb ! 18246: int seg = MEMORY_TOP >> 4; ! 18247: ! 18248: // iret table ! 18249: // note: int 2eh vector should address the routine in command.com, ! 18250: // and some softwares invite (int 2eh vector segment) - 1 must address the mcb of command.com. ! 18251: // so move iret table into allocated memory block ! 18252: // http://www5c.biglobe.ne.jp/~ecb/assembler2/2_6.html ! 18253: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, (IRET_SIZE + 5 * 128) >> 4); ! 18254: IRET_TOP = seg << 4; ! 18255: seg += (IRET_SIZE + 5 * 128) >> 4; ! 18256: memset(mem + IRET_TOP, 0xcf, IRET_SIZE); // iret ! 18257: ! 18258: // note: SO1 checks int 21h vector and if it aims iret (cfh) ! 18259: // it is recognized SO1 is not running on MS-DOS environment ! 18260: for(int i = 0; i < 128; i++) { ! 18261: // jmp far (IRET_TOP >> 4):(interrupt number) ! 18262: *(UINT8 *)(mem + IRET_TOP + IRET_SIZE + 5 * i + 0) = 0xea; ! 18263: *(UINT16 *)(mem + IRET_TOP + IRET_SIZE + 5 * i + 1) = i; ! 18264: *(UINT16 *)(mem + IRET_TOP + IRET_SIZE + 5 * i + 3) = IRET_TOP >> 4; ! 18265: } ! 18266: ! 18267: // dummy xms/ems device ! 18268: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, XMS_SIZE >> 4); ! 18269: XMS_TOP = seg << 4; ! 18270: seg += XMS_SIZE >> 4; ! 18271: ! 18272: // environment ! 18273: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, ENV_SIZE >> 4); ! 18274: int env_seg = seg; ! 18275: int ofs = 0; ! 18276: char env_append[ENV_SIZE] = {0}, append_added = 0; ! 18277: char comspec_added = 0; ! 18278: char lastdrive_added = 0; ! 18279: char env_msdos_path[ENV_SIZE] = {0}; ! 18280: char env_path[ENV_SIZE] = {0}, path_added = 0; ! 18281: char prompt_added = 0; ! 18282: char env_temp[ENV_SIZE] = {0}, temp_added = 0, tmp_added = 0; ! 18283: char tz_added = 0; ! 18284: const char *path, *short_path; ! 18285: ! 18286: if((path = getenv("MSDOS_APPEND")) != NULL) { ! 18287: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') { ! 18288: strcpy(env_append, short_path); ! 18289: } ! 18290: } ! 18291: if((path = getenv("APPEND")) != NULL) { ! 18292: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') { ! 18293: if(env_append[0] != '\0') { ! 18294: strcat(env_append, ";"); ! 18295: } ! 18296: strcat(env_append, short_path); ! 18297: } ! 18298: } ! 18299: ! 18300: if((path = msdos_search_command_com(argv[0], env_path)) != NULL) { ! 18301: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') { ! 18302: strcpy(comspec_path, short_path); ! 18303: } ! 18304: } ! 18305: if((path = getenv("MSDOS_COMSPEC")) != NULL && _access(path, 0) == 0) { ! 18306: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') { ! 18307: strcpy(comspec_path, short_path); ! 18308: } ! 18309: } ! 18310: ! 18311: if((path = getenv("MSDOS_PATH")) != NULL) { ! 18312: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') { ! 18313: strcpy(env_msdos_path, short_path); ! 18314: strcpy(env_path, short_path); ! 18315: } ! 18316: } ! 18317: if((path = getenv("PATH")) != NULL) { ! 18318: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') { ! 18319: if(env_path[0] != '\0') { ! 18320: strcat(env_path, ";"); ! 18321: } ! 18322: strcat(env_path, short_path); ! 18323: } ! 18324: } ! 18325: ! 18326: if(GetTempPathA(ENV_SIZE, env_temp) != 0) { ! 18327: strcpy(env_temp, msdos_get_multiple_short_path(env_temp)); ! 18328: } ! 18329: for(int i = 0; i < 4; i++) { ! 18330: static const char *name[4] = {"MSDOS_TEMP", "MSDOS_TMP", "TEMP", "TMP"}; ! 18331: if((path = getenv(name[i])) != NULL && _access(path, 0) == 0) { ! 18332: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') { ! 18333: strcpy(env_temp, short_path); ! 18334: break; ! 18335: } ! 18336: } ! 18337: } ! 18338: ! 18339: for(char **p = envp; p != NULL && *p != NULL; p++) { ! 18340: // lower to upper ! 18341: char tmp[ENV_SIZE], name[ENV_SIZE]; ! 18342: strcpy(tmp, *p); ! 18343: for(int i = 0;; i++) { ! 18344: if(tmp[i] == '=') { ! 18345: tmp[i] = '\0'; ! 18346: sprintf(name, ";%s;", tmp); ! 18347: my_strupr(name); ! 18348: tmp[i] = '='; ! 18349: break; ! 18350: } else if(tmp[i] >= 'a' && tmp[i] <= 'z') { ! 18351: tmp[i] = (tmp[i] - 'a') + 'A'; ! 18352: } ! 18353: } ! 18354: if(strstr(";MSDOS_APPEND;MSDOS_COMSPEC;MSDOS_LASTDRIVE;MSDOS_TEMP;MSDOS_TMP;MSDOS_TZ;", name) != NULL) { ! 18355: // ignore MSDOS_(APPEND/COMSPEC/LASTDRIVE/TEMP/TMP/TZ) ! 18356: } else if(standard_env && strstr(";APPEND;COMSPEC;LASTDRIVE;MSDOS_PATH;PATH;PROMPT;TEMP;TMP;TZ;", name) == NULL) { ! 18357: // ignore non standard environments ! 18358: } else { ! 18359: if(strncmp(tmp, "APPEND=", 7) == 0) { ! 18360: if(env_append[0] != '\0') { ! 18361: sprintf(tmp, "APPEND=%s", env_append); ! 18362: } else { ! 18363: sprintf(tmp, "APPEND=%s", msdos_get_multiple_short_path(tmp + 7)); ! 18364: } ! 18365: append_added = 1; ! 18366: } else if(strncmp(tmp, "COMSPEC=", 8) == 0) { ! 18367: strcpy(tmp, "COMSPEC=C:\\COMMAND.COM"); ! 18368: comspec_added = 1; ! 18369: } else if(strncmp(tmp, "LASTDRIVE=", 10) == 0) { ! 18370: char *env = getenv("MSDOS_LASTDRIVE"); ! 18371: if(env != NULL) { ! 18372: sprintf(tmp, "LASTDRIVE=%s", env); ! 18373: } ! 18374: lastdrive_added = 1; ! 18375: } else if(strncmp(tmp, "MSDOS_PATH=", 11) == 0) { ! 18376: if(env_msdos_path[0] != '\0') { ! 18377: sprintf(tmp, "MSDOS_PATH=%s", env_msdos_path); ! 18378: } else { ! 18379: sprintf(tmp, "MSDOS_PATH=%s", msdos_get_multiple_short_path(tmp + 11)); ! 18380: } ! 18381: } else if(strncmp(tmp, "PATH=", 5) == 0) { ! 18382: if(env_path[0] != '\0') { ! 18383: sprintf(tmp, "PATH=%s", env_path); ! 18384: } else { ! 18385: sprintf(tmp, "PATH=%s", msdos_get_multiple_short_path(tmp + 5)); ! 18386: } ! 18387: path_added = 1; ! 18388: } else if(strncmp(tmp, "PROMPT=", 7) == 0) { ! 18389: prompt_added = 1; ! 18390: } else if(strncmp(tmp, "TEMP=", 5) == 0) { ! 18391: if(env_temp[0] != '\0') { ! 18392: sprintf(tmp, "TEMP=%s", env_temp); ! 18393: } else { ! 18394: sprintf(tmp, "TEMP=%s", msdos_get_multiple_short_path(tmp + 5)); ! 18395: } ! 18396: temp_added = 1; ! 18397: } else if(strncmp(tmp, "TMP=", 4) == 0) { ! 18398: if(env_temp[0] != '\0') { ! 18399: sprintf(tmp, "TMP=%s", env_temp); ! 18400: } else { ! 18401: sprintf(tmp, "TMP=%s", msdos_get_multiple_short_path(tmp + 4)); ! 18402: } ! 18403: tmp_added = 1; ! 18404: } else if(strncmp(tmp, "TZ=", 3) == 0) { ! 18405: char *env = getenv("MSDOS_TZ"); ! 18406: if(env != NULL) { ! 18407: sprintf(tmp, "TZ=%s", env); ! 18408: } ! 18409: tz_added = 1; ! 18410: } ! 18411: int len = strlen(tmp); ! 18412: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) { ! 18413: fatalerror("too many environments\n"); ! 18414: } ! 18415: memcpy(mem + (seg << 4) + ofs, tmp, len); ! 18416: ofs += len + 1; ! 18417: } ! 18418: } ! 18419: if(!append_added && env_append[0] != '\0') { ! 18420: #define SET_ENV(name, value) { \ ! 18421: char tmp[ENV_SIZE]; \ ! 18422: sprintf(tmp, "%s=%s", name, value); \ ! 18423: int len = strlen(tmp); \ ! 18424: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) { \ ! 18425: fatalerror("too many environments\n"); \ ! 18426: } \ ! 18427: memcpy(mem + (seg << 4) + ofs, tmp, len); \ ! 18428: ofs += len + 1; \ ! 18429: } ! 18430: SET_ENV("APPEND", env_append); ! 18431: } ! 18432: if(!comspec_added) { ! 18433: SET_ENV("COMSPEC", "C:\\COMMAND.COM"); ! 18434: } ! 18435: if(!lastdrive_added) { ! 18436: SET_ENV("LASTDRIVE", "Z"); ! 18437: } ! 18438: if(!path_added) { ! 18439: SET_ENV("PATH", env_path); ! 18440: } ! 18441: if(!prompt_added) { ! 18442: SET_ENV("PROMPT", "$P$G"); ! 18443: } ! 18444: if(!temp_added) { ! 18445: SET_ENV("TEMP", env_temp); ! 18446: } ! 18447: if(!tmp_added) { ! 18448: SET_ENV("TMP", env_temp); ! 18449: } ! 18450: if(!tz_added) { ! 18451: TIME_ZONE_INFORMATION tzi; ! 18452: HKEY hKey, hSubKey; ! 18453: char tzi_std_name[64]; ! 18454: char tz_std[8] = "GMT"; ! 18455: char tz_dlt[8] = "GST"; ! 18456: char tz_value[32]; ! 18457: ! 18458: // timezone name from GetTimeZoneInformation may not be english ! 18459: bool daylight = (GetTimeZoneInformation(&tzi) != TIME_ZONE_ID_UNKNOWN); ! 18460: setlocale(LC_CTYPE, ""); ! 18461: wcstombs(tzi_std_name, tzi.StandardName, sizeof(tzi_std_name)); ! 18462: ! 18463: // get english timezone name from registry ! 18464: if(RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones", 0, KEY_READ, &hKey) == ERROR_SUCCESS) { ! 18465: for(DWORD i = 0; !tz_added; i++) { ! 18466: char reg_name[256], sub_key[1024], std_name[256]; ! 18467: DWORD size; ! 18468: FILETIME ftTime; ! 18469: LONG result = RegEnumKeyExA(hKey, i, reg_name, &(size = array_length(reg_name)), NULL, NULL, NULL, &ftTime); ! 18470: ! 18471: if(result == ERROR_SUCCESS) { ! 18472: sprintf(sub_key, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\%s", reg_name); ! 18473: if(RegOpenKeyExA(HKEY_LOCAL_MACHINE, sub_key, 0, KEY_QUERY_VALUE, &hSubKey) == ERROR_SUCCESS) { ! 18474: if(RegQueryValueExA(hSubKey, "Std", NULL, NULL, (LPBYTE)std_name, &(size = array_length(std_name))) == ERROR_SUCCESS) { ! 18475: // search english timezone name from table ! 18476: if(strcmp(std_name, tzi_std_name) == 0) { ! 18477: for(int j = 0; j < array_length(tz_table); j++) { ! 18478: if(strcmp(reg_name, tz_table[j].name) == 0 && (tz_table[j].lcid == 0 || tz_table[j].lcid == GetUserDefaultLCID())) { ! 18479: if(tz_table[j].std != NULL) { ! 18480: strcpy(tz_std, tz_table[j].std); ! 18481: } ! 18482: if(tz_table[j].dlt != NULL) { ! 18483: strcpy(tz_dlt, tz_table[j].dlt); ! 18484: } ! 18485: tz_added = 1; ! 18486: break; ! 18487: } ! 18488: } ! 18489: } ! 18490: } ! 18491: RegCloseKey(hSubKey); ! 18492: } ! 18493: } else if(result == ERROR_NO_MORE_ITEMS) { ! 18494: break; ! 18495: } ! 18496: } ! 18497: RegCloseKey(hKey); ! 18498: } ! 18499: if((tzi.Bias % 60) != 0) { ! 18500: sprintf(tz_value, "%s%d:%2d", tz_std, tzi.Bias / 60, abs(tzi.Bias % 60)); ! 18501: } else { ! 18502: sprintf(tz_value, "%s%d", tz_std, tzi.Bias / 60); ! 18503: } ! 18504: if(daylight) { ! 18505: strcat(tz_value, tz_dlt); ! 18506: } ! 18507: SET_ENV("TZ", tz_value); ! 18508: } ! 18509: seg += (ENV_SIZE >> 4); ! 18510: ! 18511: // psp ! 18512: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, PSP_SIZE >> 4); ! 18513: current_psp = seg; ! 18514: psp_t *psp = msdos_psp_create(seg, seg + (PSP_SIZE >> 4), -1, env_seg); ! 18515: psp->parent_psp = current_psp; ! 18516: seg += (PSP_SIZE >> 4); ! 18517: ! 18518: // first free mcb in conventional memory ! 18519: msdos_mcb_create(seg, 'M', 0, (MEMORY_END >> 4) - seg - 2); ! 18520: first_mcb = seg; ! 18521: ! 18522: // dummy mcb to link to umb ! 18523: #if 0 ! 18524: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', PSP_SYSTEM, (UMB_TOP >> 4) - (MEMORY_END >> 4), "SC"); // link umb ! 18525: #else ! 18526: msdos_mcb_create((MEMORY_END >> 4) - 1, 'Z', PSP_SYSTEM, 0, "SC"); // unlink umb ! 18527: #endif ! 18528: ! 18529: // first free mcb in upper memory block ! 18530: msdos_mcb_create(UMB_TOP >> 4, 'Z', 0, (UMB_END >> 4) - (UMB_TOP >> 4) - 1); ! 18531: ! 18532: #ifdef SUPPORT_HMA ! 18533: // first free mcb in high memory area ! 18534: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0); ! 18535: #endif ! 18536: ! 18537: // interrupt vector ! 18538: for(int i = 0; i < 256; i++) { ! 18539: // 00-07: CPU exception handler ! 18540: // 08-0F: IRQ 0-7 ! 18541: // 10-1F: PC BIOS ! 18542: // 20-3F: MS-DOS system call ! 18543: // 70-77: IRQ 8-15 ! 18544: *(UINT16 *)(mem + 4 * i + 0) = (i <= 0x3f || (i >= 0x70 && i <= 0x77)) ? (IRET_SIZE + 5 * i) : i; ! 18545: *(UINT16 *)(mem + 4 * i + 2) = (IRET_TOP >> 4); ! 18546: } ! 18547: *(UINT16 *)(mem + 4 * 0x08 + 0) = 0x0018; // fffc:0018 irq0 (system timer) ! 18548: *(UINT16 *)(mem + 4 * 0x08 + 2) = DUMMY_TOP >> 4; ! 18549: *(UINT16 *)(mem + 4 * 0x22 + 0) = 0x0000; // ffff:0000 boot ! 18550: *(UINT16 *)(mem + 4 * 0x22 + 2) = 0xffff; ! 18551: *(UINT16 *)(mem + 4 * 0x67 + 0) = 0x0012; // xxxx:0012 ems ! 18552: *(UINT16 *)(mem + 4 * 0x67 + 2) = XMS_TOP >> 4; ! 18553: *(UINT16 *)(mem + 4 * 0x74 + 0) = 0x0000; // fffc:0000 irq12 (mouse) ! 18554: *(UINT16 *)(mem + 4 * 0x74 + 2) = DUMMY_TOP >> 4; ! 18555: ! 18556: // dummy devices (NUL -> CON -> ... -> CONFIG$ -> EMMXXXX0) ! 18557: static const struct { ! 18558: UINT16 attributes; ! 18559: char *dev_name; ! 18560: } dummy_devices[] = { ! 18561: {0x8013, "CON "}, ! 18562: {0x8000, "AUX "}, ! 18563: {0xa0c0, "PRN "}, ! 18564: {0x8008, "CLOCK$ "}, ! 18565: {0x8000, "COM1 "}, ! 18566: {0xa0c0, "LPT1 "}, ! 18567: {0xa0c0, "LPT2 "}, ! 18568: {0xa0c0, "LPT3 "}, ! 18569: {0x8000, "COM2 "}, ! 18570: {0x8000, "COM3 "}, ! 18571: {0x8000, "COM4 "}, ! 18572: // {0xc000, "CONFIG$ "}, ! 18573: {0xc000, "$IBMADSP"}, // for windows3.1 setup.exe ! 18574: }; ! 18575: static const UINT8 dummy_device_routine[] = { ! 18576: // from NUL device of Windows 98 SE ! 18577: // or word ptr ES:[BX+03],0100 ! 18578: 0x26, 0x81, 0x4f, 0x03, 0x00, 0x01, ! 18579: // retf ! 18580: 0xcb, ! 18581: }; ! 18582: device_t *last = NULL; ! 18583: for(int i = 0; i < array_length(dummy_devices); i++) { ! 18584: device_t *device = (device_t *)(mem + DEVICE_TOP + 22 + 18 * i); ! 18585: device->next_driver.w.l = 22 + 18 * (i + 1); ! 18586: device->next_driver.w.h = DEVICE_TOP >> 4; ! 18587: device->attributes = dummy_devices[i].attributes; ! 18588: device->strategy = DEVICE_SIZE - sizeof(dummy_device_routine); ! 18589: device->interrupt = DEVICE_SIZE - sizeof(dummy_device_routine) + 6; ! 18590: memcpy(device->dev_name, dummy_devices[i].dev_name, 8); ! 18591: last = device; ! 18592: } ! 18593: if(last != NULL) { ! 18594: last->next_driver.w.l = 0; ! 18595: last->next_driver.w.h = XMS_TOP >> 4; ! 18596: } ! 18597: memcpy(mem + DEVICE_TOP + DEVICE_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine)); ! 18598: ! 18599: // dos info ! 18600: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP); ! 18601: dos_info->magic_word = 1; ! 18602: dos_info->first_mcb = MEMORY_TOP >> 4; ! 18603: dos_info->first_dpb.w.l = 0; ! 18604: dos_info->first_dpb.w.h = DPB_TOP >> 4; ! 18605: dos_info->first_sft.w.l = 0; ! 18606: dos_info->first_sft.w.h = SFT_TOP >> 4; ! 18607: dos_info->clock_device.w.l = 22 + 18 * 3; // CLOCK$ is the 4th device in IO.SYS ! 18608: dos_info->clock_device.w.h = DEVICE_TOP >> 4; ! 18609: dos_info->con_device.w.l = 22 + 18 * 0; // CON is the 1st device in IO.SYS ! 18610: dos_info->con_device.w.h = DEVICE_TOP >> 4; ! 18611: dos_info->max_sector_len = 512; ! 18612: dos_info->disk_buf_info.w.l = offsetof(dos_info_t, disk_buf_heads); ! 18613: dos_info->disk_buf_info.w.h = DOS_INFO_TOP >> 4; ! 18614: dos_info->cds.w.l = 0; ! 18615: dos_info->cds.w.h = CDS_TOP >> 4; ! 18616: dos_info->fcb_table.w.l = 0; ! 18617: dos_info->fcb_table.w.h = FCB_TABLE_TOP >> 4; ! 18618: dos_info->last_drive = 'Z' - 'A' + 1; ! 18619: dos_info->buffers_x = 20; ! 18620: dos_info->buffers_y = 0; ! 18621: dos_info->boot_drive = 'C' - 'A' + 1; ! 18622: dos_info->nul_device.next_driver.w.l = 22; ! 18623: dos_info->nul_device.next_driver.w.h = DEVICE_TOP >> 4; ! 18624: dos_info->nul_device.attributes = 0x8004; ! 18625: dos_info->nul_device.strategy = DOS_INFO_SIZE - sizeof(dummy_device_routine); ! 18626: dos_info->nul_device.interrupt = DOS_INFO_SIZE - sizeof(dummy_device_routine) + 6; ! 18627: memcpy(dos_info->nul_device.dev_name, "NUL ", 8); ! 18628: dos_info->disk_buf_heads.w.l = 0; ! 18629: dos_info->disk_buf_heads.w.h = DISK_BUF_TOP >> 4; ! 18630: dos_info->umb_linked = (((mcb_t *)(mem + MEMORY_END - 16))->mz == 'M' ? 0x01 : 0x00); ! 18631: dos_info->first_umb_fcb = UMB_TOP >> 4; ! 18632: dos_info->first_mcb_2 = MEMORY_TOP >> 4; ! 18633: memcpy(mem + DOS_INFO_TOP + DOS_INFO_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine)); ! 18634: ! 18635: char *env; ! 18636: if((env = getenv("LASTDRIVE")) != NULL) { ! 18637: if(env[0] >= 'A' && env[0] <= 'Z') { ! 18638: dos_info->last_drive = env[0] - 'A' + 1; ! 18639: } else if(env[0] >= 'a' && env[0] <= 'z') { ! 18640: dos_info->last_drive = env[0] - 'a' + 1; ! 18641: } ! 18642: } ! 18643: if((env = getenv("windir")) != NULL) { ! 18644: if(env[0] >= 'A' && env[0] <= 'Z') { ! 18645: dos_info->boot_drive = env[0] - 'A' + 1; ! 18646: } else if(env[0] >= 'a' && env[0] <= 'z') { ! 18647: dos_info->boot_drive = env[0] - 'a' + 1; ! 18648: } ! 18649: } ! 18650: #if defined(HAS_I386) ! 18651: dos_info->i386_or_later = 1; ! 18652: #else ! 18653: dos_info->i386_or_later = 0; ! 18654: #endif ! 18655: dos_info->ext_mem_size = (min(MAX_MEM, 0x4000000) - 0x100000) >> 10; ! 18656: ! 18657: // ems (int 67h) and xms ! 18658: device_t *xms_device = (device_t *)(mem + XMS_TOP); ! 18659: xms_device->next_driver.w.l = 0xffff; ! 18660: xms_device->next_driver.w.h = 0xffff; ! 18661: xms_device->attributes = 0xc000; ! 18662: xms_device->strategy = XMS_SIZE - sizeof(dummy_device_routine); ! 18663: xms_device->interrupt = XMS_SIZE - sizeof(dummy_device_routine) + 6; ! 18664: memcpy(xms_device->dev_name, "EMMXXXX0", 8); ! 18665: ! 18666: mem[XMS_TOP + 0x12] = 0xcd; // int 65h (dummy) ! 18667: mem[XMS_TOP + 0x13] = 0x65; ! 18668: mem[XMS_TOP + 0x14] = 0xcf; // iret ! 18669: #ifdef SUPPORT_XMS ! 18670: if(support_xms) { ! 18671: mem[XMS_TOP + 0x15] = 0xcd; // int 66h (dummy) ! 18672: mem[XMS_TOP + 0x16] = 0x66; ! 18673: mem[XMS_TOP + 0x17] = 0xcb; // retf ! 18674: } else ! 18675: #endif ! 18676: mem[XMS_TOP + 0x15] = 0xcb; // retf ! 18677: memcpy(mem + XMS_TOP + XMS_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine)); ! 18678: ! 18679: // irq12 routine (mouse) ! 18680: mem[DUMMY_TOP + 0x00] = 0xcd; // int 69h (dummy) ! 18681: mem[DUMMY_TOP + 0x01] = 0x69; ! 18682: mem[DUMMY_TOP + 0x02] = 0x9a; // call far mouse ! 18683: mem[DUMMY_TOP + 0x03] = 0xff; ! 18684: mem[DUMMY_TOP + 0x04] = 0xff; ! 18685: mem[DUMMY_TOP + 0x05] = 0xff; ! 18686: mem[DUMMY_TOP + 0x06] = 0xff; ! 18687: // mem[DUMMY_TOP + 0x07] = 0xcd; // int 6ah (dummy) ! 18688: // mem[DUMMY_TOP + 0x08] = 0x6a; ! 18689: mem[DUMMY_TOP + 0x07] = 0xcd; // int 6bh (dummy) ! 18690: mem[DUMMY_TOP + 0x08] = 0x6b; ! 18691: mem[DUMMY_TOP + 0x09] = 0xcf; // iret ! 18692: ! 18693: // case map routine ! 18694: mem[DUMMY_TOP + 0x0a] = 0xcd; // int 6ch (dummy) ! 18695: mem[DUMMY_TOP + 0x0b] = 0x6c; ! 18696: mem[DUMMY_TOP + 0x0c] = 0xcb; // retf ! 18697: ! 18698: // font read routine ! 18699: mem[DUMMY_TOP + 0x0d] = 0xcd; // int 6dh (dummy) ! 18700: mem[DUMMY_TOP + 0x0e] = 0x6d; ! 18701: mem[DUMMY_TOP + 0x0f] = 0xcb; // retf ! 18702: ! 18703: // error message read routine ! 18704: mem[DUMMY_TOP + 0x10] = 0xcd; // int 6eh (dummy) ! 18705: mem[DUMMY_TOP + 0x11] = 0x6e; ! 18706: mem[DUMMY_TOP + 0x12] = 0xcb; // retf ! 18707: ! 18708: // dummy loop to wait BIOS/DOS service is done ! 18709: mem[DUMMY_TOP + 0x13] = 0xe6; // out f7h, al ! 18710: mem[DUMMY_TOP + 0x14] = 0xf7; ! 18711: mem[DUMMY_TOP + 0x15] = 0x78; // js/jns -4 ! 18712: mem[DUMMY_TOP + 0x16] = 0xfc; ! 18713: mem[DUMMY_TOP + 0x17] = 0xcb; // retf ! 18714: ! 18715: // irq0 routine (system timer) ! 18716: mem[DUMMY_TOP + 0x18] = 0xcd; // int 1ch ! 18717: mem[DUMMY_TOP + 0x19] = 0x1c; ! 18718: mem[DUMMY_TOP + 0x1a] = 0xea; // jmp far (IRET_TOP >> 4):0008 ! 18719: mem[DUMMY_TOP + 0x1b] = 0x08; ! 18720: mem[DUMMY_TOP + 0x1c] = 0x00; ! 18721: mem[DUMMY_TOP + 0x1d] = ((IRET_TOP >> 4) ) & 0xff; ! 18722: mem[DUMMY_TOP + 0x1e] = ((IRET_TOP >> 4) >> 8) & 0xff; ! 18723: ! 18724: // alter page map and call routine ! 18725: mem[DUMMY_TOP + 0x1f] = 0x9a; // call far ! 18726: mem[DUMMY_TOP + 0x20] = 0xff; ! 18727: mem[DUMMY_TOP + 0x21] = 0xff; ! 18728: mem[DUMMY_TOP + 0x22] = 0xff; ! 18729: mem[DUMMY_TOP + 0x23] = 0xff; ! 18730: mem[DUMMY_TOP + 0x24] = 0xcd; // int 6fh (dummy) ! 18731: mem[DUMMY_TOP + 0x25] = 0x6f; ! 18732: mem[DUMMY_TOP + 0x26] = 0xcb; // retf ! 18733: ! 18734: // call int 29h routine ! 18735: mem[DUMMY_TOP + 0x27] = 0xcd; // int 29h ! 18736: mem[DUMMY_TOP + 0x28] = 0x29; ! 18737: mem[DUMMY_TOP + 0x29] = 0xcb; // retf ! 18738: ! 18739: // VCPI entry point ! 18740: mem[DUMMY_TOP + 0x2a] = 0xcd; // int 65h ! 18741: mem[DUMMY_TOP + 0x2b] = 0x65; ! 18742: mem[DUMMY_TOP + 0x2c] = 0xcb; // retf ! 18743: ! 18744: // boot routine ! 18745: mem[0xffff0 + 0x00] = 0xf4; // halt to exit MS-DOS Player ! 18746: #if 1 ! 18747: mem[0xffff0 + 0x05] = '0'; // rom date (same as DOSBox) ! 18748: mem[0xffff0 + 0x06] = '1'; ! 18749: mem[0xffff0 + 0x07] = '/'; ! 18750: mem[0xffff0 + 0x08] = '0'; ! 18751: mem[0xffff0 + 0x09] = '1'; ! 18752: mem[0xffff0 + 0x0a] = '/'; ! 18753: mem[0xffff0 + 0x0b] = '9'; ! 18754: mem[0xffff0 + 0x0c] = '2'; ! 18755: mem[0xffff0 + 0x0e] = 0xfc; // machine id (pc/at) ! 18756: mem[0xffff0 + 0x0f] = 0x55; // signature ! 18757: #else ! 18758: mem[0xffff0 + 0x05] = '0'; // rom date (same as Windows 98 SE) ! 18759: mem[0xffff0 + 0x06] = '2'; ! 18760: mem[0xffff0 + 0x07] = '/'; ! 18761: mem[0xffff0 + 0x08] = '2'; ! 18762: mem[0xffff0 + 0x09] = '2'; ! 18763: mem[0xffff0 + 0x0a] = '/'; ! 18764: mem[0xffff0 + 0x0b] = '0'; ! 18765: mem[0xffff0 + 0x0c] = '6'; ! 18766: mem[0xffff0 + 0x0e] = 0xfc; // machine id (pc/at) ! 18767: mem[0xffff0 + 0x0f] = 0x00; ! 18768: #endif ! 18769: ! 18770: // param block ! 18771: // + 0: param block (22bytes) ! 18772: // +24: fcb1/2 (20bytes) ! 18773: // +44: command tail (128bytes) ! 18774: param_block_t *param = (param_block_t *)(mem + WORK_TOP); ! 18775: param->env_seg = 0; ! 18776: param->cmd_line.w.l = 44; ! 18777: param->cmd_line.w.h = (WORK_TOP >> 4); ! 18778: param->fcb1.w.l = 24; ! 18779: param->fcb1.w.h = (WORK_TOP >> 4); ! 18780: param->fcb2.w.l = 24; ! 18781: param->fcb2.w.h = (WORK_TOP >> 4); ! 18782: ! 18783: memset(mem + WORK_TOP + 24, 0x20, 20); ! 18784: ! 18785: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44); ! 18786: if(argc > 1) { ! 18787: sprintf(cmd_line->cmd, " %s", argv[1]); ! 18788: for(int i = 2; i < argc; i++) { ! 18789: char tmp[128]; ! 18790: sprintf(tmp, "%s %s", cmd_line->cmd, argv[i]); ! 18791: strcpy(cmd_line->cmd, tmp); ! 18792: } ! 18793: cmd_line->len = (UINT8)strlen(cmd_line->cmd); ! 18794: } else { ! 18795: cmd_line->len = 0; ! 18796: } ! 18797: cmd_line->cmd[cmd_line->len] = 0x0d; ! 18798: ! 18799: // system file table ! 18800: *(UINT32 *)(mem + SFT_TOP + 0) = 0xffffffff; ! 18801: *(UINT16 *)(mem + SFT_TOP + 4) = 20; ! 18802: ! 18803: // disk buffer header (from DOSBox) ! 18804: *(UINT16 *)(mem + DISK_BUF_TOP + 0) = 0xffff; // forward ptr ! 18805: *(UINT16 *)(mem + DISK_BUF_TOP + 2) = 0xffff; // backward ptr ! 18806: *(UINT8 *)(mem + DISK_BUF_TOP + 4) = 0xff; // not in use ! 18807: *(UINT8 *)(mem + DISK_BUF_TOP + 10) = 0x01; // number of FATs ! 18808: *(UINT32 *)(mem + DISK_BUF_TOP + 13) = 0xffffffff; // pointer to DPB ! 18809: ! 18810: // fcb table ! 18811: *(UINT32 *)(mem + FCB_TABLE_TOP + 0) = 0xffffffff; ! 18812: *(UINT16 *)(mem + FCB_TABLE_TOP + 4) = 0; ! 18813: ! 18814: // drive parameter block ! 18815: for(int i = 0; i < 2; i++) { ! 18816: // may be a floppy drive ! 18817: cds_t *cds = (cds_t *)(mem + CDS_TOP + 88 * i); ! 18818: sprintf(cds->path_name, "%c:\\", 'A' + i); ! 18819: cds->drive_attrib = 0x4000; // physical drive ! 18820: cds->dpb_ptr.w.l = sizeof(dpb_t) * i; ! 18821: cds->dpb_ptr.w.h = DPB_TOP >> 4; ! 18822: cds->word_1 = cds->word_2 = cds->word_3 = 0xffff; ! 18823: cds->bs_offset = 2; ! 18824: ! 18825: dpb_t *dpb = (dpb_t *)(mem + DPB_TOP + sizeof(dpb_t) * i); ! 18826: dpb->drive_num = i; ! 18827: dpb->unit_num = i; ! 18828: dpb->next_dpb_ofs = /*(i == 25) ? 0xffff : */sizeof(dpb_t) * (i + 1); ! 18829: dpb->next_dpb_seg = /*(i == 25) ? 0xffff : */DPB_TOP >> 4; ! 18830: } ! 18831: for(int i = 2; i < 26; i++) { ! 18832: msdos_cds_update(i); ! 18833: UINT16 seg, ofs; ! 18834: msdos_drive_param_block_update(i, &seg, &ofs, 1); ! 18835: } ! 18836: ! 18837: // nls stuff ! 18838: msdos_nls_tables_init(); ! 18839: ! 18840: // execute command ! 18841: try { ! 18842: if(msdos_process_exec(argv[0], param, 0, true)) { ! 18843: fatalerror("'%s' not found\n", argv[0]); ! 18844: } ! 18845: } catch(...) { ! 18846: // we should not reach here :-( ! 18847: fatalerror("failed to start '%s' because of unexpected exeption\n", argv[0]); ! 18848: } ! 18849: retval = 0; ! 18850: return(0); ! 18851: } ! 18852: ! 18853: #define remove_std_file(path) { \ ! 18854: int fd = _open(path, _O_RDONLY | _O_BINARY); \ ! 18855: if(fd != -1) { \ ! 18856: _lseek(fd, 0, SEEK_END); \ ! 18857: int size = _tell(fd); \ ! 18858: _close(fd); \ ! 18859: if(size == 0) { \ ! 18860: remove(path); \ ! 18861: } \ ! 18862: } \ ! 18863: } ! 18864: ! 18865: void msdos_finish() ! 18866: { ! 18867: for(int i = 0; i < MAX_FILES; i++) { ! 18868: if(file_handler[i].valid) { ! 18869: _close(i); ! 18870: } ! 18871: } ! 18872: #ifdef MAP_AUX_DEVICE_TO_FILE ! 18873: remove_std_file("stdaux.txt"); ! 18874: #endif ! 18875: #ifdef SUPPORT_XMS ! 18876: msdos_xms_finish(); ! 18877: #endif ! 18878: msdos_dbcs_table_finish(); ! 18879: } ! 18880: ! 18881: /* ---------------------------------------------------------------------------- ! 18882: PC/AT hardware emulation ! 18883: ---------------------------------------------------------------------------- */ ! 18884: ! 18885: void hardware_init() ! 18886: { ! 18887: CPU_INIT_CALL(CPU_MODEL); ! 18888: CPU_RESET_CALL(CPU_MODEL); ! 18889: m_IF = 1; ! 18890: #if defined(HAS_I386) ! 18891: cpu_type = (REG32(EDX) >> 8) & 0x0f; ! 18892: cpu_step = (REG32(EDX) >> 0) & 0x0f; ! 18893: #endif ! 18894: i386_set_a20_line(0); ! 18895: ! 18896: ems_init(); ! 18897: dma_init(); ! 18898: pic_init(); ! 18899: pio_init(); ! 18900: #ifdef PIT_ALWAYS_RUNNING ! 18901: pit_init(); ! 18902: #else ! 18903: pit_active = 0; ! 18904: #endif ! 18905: sio_init(); ! 18906: cmos_init(); ! 18907: kbd_init(); ! 18908: } ! 18909: ! 18910: void hardware_finish() ! 18911: { ! 18912: #if defined(HAS_I386) ! 18913: vtlb_free(m_vtlb); ! 18914: #endif ! 18915: ems_finish(); ! 18916: pio_finish(); ! 18917: sio_finish(); ! 18918: } ! 18919: ! 18920: void hardware_release() ! 18921: { ! 18922: // release hardware resources when this program will be terminated abnormally ! 18923: #ifdef EXPORT_DEBUG_TO_FILE ! 18924: if(fp_debug_log != NULL) { ! 18925: fclose(fp_debug_log); ! 18926: fp_debug_log = NULL; ! 18927: } ! 18928: #endif ! 18929: #if defined(HAS_I386) ! 18930: vtlb_free(m_vtlb); ! 18931: #endif ! 18932: ems_release(); ! 18933: pio_release(); ! 18934: sio_release(); ! 18935: } ! 18936: ! 18937: void hardware_run() ! 18938: { ! 18939: #ifdef EXPORT_DEBUG_TO_FILE ! 18940: // open debug log file after msdos_init() is done not to use the standard file handlers ! 18941: fp_debug_log = fopen("debug.log", "w"); ! 18942: #endif ! 18943: #ifdef USE_DEBUGGER ! 18944: m_int_num = -1; ! 18945: #endif ! 18946: while(!m_exit) { ! 18947: hardware_run_cpu(); ! 18948: } ! 18949: #ifdef EXPORT_DEBUG_TO_FILE ! 18950: if(fp_debug_log != NULL) { ! 18951: fclose(fp_debug_log); ! 18952: fp_debug_log = NULL; ! 18953: } ! 18954: #endif ! 18955: } ! 18956: ! 18957: inline void hardware_run_cpu() ! 18958: { ! 18959: #if defined(HAS_I386) ! 18960: CPU_EXECUTE_CALL(i386); ! 18961: if(m_eip != m_prev_eip) { ! 18962: idle_ops++; ! 18963: } ! 18964: #else ! 18965: CPU_EXECUTE_CALL(CPU_MODEL); ! 18966: if(m_pc != m_prevpc) { ! 18967: idle_ops++; ! 18968: } ! 18969: #endif ! 18970: #ifdef USE_DEBUGGER ! 18971: // Disallow reentering CPU_EXECUTE() in msdos_syscall() ! 18972: if(m_int_num >= 0) { ! 18973: unsigned num = (unsigned)m_int_num; ! 18974: m_int_num = -1; ! 18975: msdos_syscall(num); ! 18976: } ! 18977: #endif ! 18978: if(++update_ops == UPDATE_OPS) { ! 18979: update_ops = 0; ! 18980: hardware_update(); ! 18981: } ! 18982: } ! 18983: ! 18984: void hardware_update() ! 18985: { ! 18986: static UINT32 prev_time = 0; ! 18987: UINT32 cur_time = timeGetTime(); ! 18988: ! 18989: if(prev_time != cur_time) { ! 18990: // update pit and raise irq0 ! 18991: #ifndef PIT_ALWAYS_RUNNING ! 18992: if(pit_active) ! 18993: #endif ! 18994: { ! 18995: if(pit_run(0, cur_time)) { ! 18996: pic_req(0, 0, 1); ! 18997: } ! 18998: pit_run(1, cur_time); ! 18999: pit_run(2, cur_time); ! 19000: } ! 19001: ! 19002: // update sio and raise irq4/3 ! 19003: for(int c = 0; c < 4; c++) { ! 19004: sio_update(c); ! 19005: } ! 19006: ! 19007: // update keyboard and mouse ! 19008: static UINT32 prev_tick = 0; ! 19009: UINT32 cur_tick = cur_time / 32; ! 19010: ! 19011: if(prev_tick != cur_tick) { ! 19012: // update keyboard flags ! 19013: UINT8 state; ! 19014: state = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0; ! 19015: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x0001) ? 0x40 : 0; ! 19016: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x0001) ? 0x20 : 0; ! 19017: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0; ! 19018: state |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0; ! 19019: state |= (GetAsyncKeyState(VK_CONTROL ) & 0x8000) ? 0x04 : 0; ! 19020: state |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0; ! 19021: state |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0; ! 19022: mem[0x417] = state; ! 19023: state = (GetAsyncKeyState(VK_INSERT ) & 0x8000) ? 0x80 : 0; ! 19024: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0; ! 19025: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0; ! 19026: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0; ! 19027: // state |= (GetAsyncKeyState(VK_PAUSE ) & 0x0001) ? 0x08 : 0; ! 19028: // state |= (GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x04 : 0; ! 19029: state |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0; ! 19030: state |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0; ! 19031: mem[0x418] = state; ! 19032: ! 19033: // update console input if needed ! 19034: if(!key_changed || mouse.hidden == 0) { ! 19035: update_console_input(); ! 19036: } ! 19037: if(!(kbd_status & 1)) { ! 19038: if(key_buf_data != NULL) { ! 19039: #ifdef USE_SERVICE_THREAD ! 19040: EnterCriticalSection(&key_buf_crit_sect); ! 19041: #endif ! 19042: if(!key_buf_data->empty()) { ! 19043: kbd_data = key_buf_data->read(); ! 19044: kbd_status |= 1; ! 19045: key_changed = true; ! 19046: } ! 19047: #ifdef USE_SERVICE_THREAD ! 19048: LeaveCriticalSection(&key_buf_crit_sect); ! 19049: #endif ! 19050: } ! 19051: } ! 19052: ! 19053: // raise irq1 if key is pressed/released or key buffer is not empty ! 19054: if(!key_changed) { ! 19055: #ifdef USE_SERVICE_THREAD ! 19056: EnterCriticalSection(&key_buf_crit_sect); ! 19057: #endif ! 19058: if(!pcbios_is_key_buffer_empty()) { ! 19059: /* ! 19060: if(!(kbd_status & 1)) { ! 19061: UINT16 head = *(UINT16 *)(mem + 0x41a); ! 19062: UINT16 tail = *(UINT16 *)(mem + 0x41c); ! 19063: if(head != tail) { ! 19064: int key_char = mem[0x400 + (head++)]; ! 19065: int key_scan = mem[0x400 + (head++)]; ! 19066: kbd_data = key_char ? key_char : key_scan; ! 19067: kbd_status |= 1; ! 19068: } ! 19069: } ! 19070: */ ! 19071: key_changed = true; ! 19072: } ! 19073: #ifdef USE_SERVICE_THREAD ! 19074: LeaveCriticalSection(&key_buf_crit_sect); ! 19075: #endif ! 19076: } ! 19077: if(key_changed) { ! 19078: pic_req(0, 1, 1); ! 19079: key_changed = false; ! 19080: } ! 19081: ! 19082: // raise irq12 if mouse status is changed ! 19083: if((mouse.status & 0x1f) && mouse.call_addr_ps2.dw && mouse.enabled_ps2) { ! 19084: mouse.status_irq = 0; // ??? ! 19085: mouse.status_irq_alt = 0; // ??? ! 19086: mouse.status_irq_ps2 = mouse.status & 0x1f; ! 19087: mouse.status = 0; ! 19088: pic_req(1, 4, 1); ! 19089: } else if((mouse.status & mouse.call_mask) && mouse.call_addr.dw) { ! 19090: mouse.status_irq = mouse.status & mouse.call_mask; ! 19091: mouse.status_irq_alt = 0; // ??? ! 19092: mouse.status_irq_ps2 = 0; // ??? ! 19093: mouse.status &= ~mouse.call_mask; ! 19094: pic_req(1, 4, 1); ! 19095: } else { ! 19096: for(int i = 0; i < 8; i++) { ! 19097: if((mouse.status_alt & (1 << i)) && mouse.call_addr_alt[i].dw) { ! 19098: mouse.status_irq = 0; // ??? ! 19099: mouse.status_irq_alt = 0; ! 19100: mouse.status_irq_ps2 = 0; // ??? ! 19101: for(int j = 0; j < 8; j++) { ! 19102: if((mouse.status_alt & (1 << j)) && mouse.call_addr_alt[i].dw == mouse.call_addr_alt[j].dw) { ! 19103: mouse.status_irq_alt |= (1 << j); ! 19104: mouse.status_alt &= ~(1 << j); ! 19105: } ! 19106: } ! 19107: pic_req(1, 4, 1); ! 19108: break; ! 19109: } ! 19110: } ! 19111: } ! 19112: ! 19113: prev_tick = cur_tick; ! 19114: } ! 19115: ! 19116: // update cursor size/position by crtc ! 19117: if(crtc_changed[10] != 0 || crtc_changed[11] != 0) { ! 19118: int size = (int)(crtc_regs[11] & 7) - (int)(crtc_regs[10] & 7) + 1; ! 19119: if(!((crtc_regs[10] & 0x20) != 0 || size < 0)) { ! 19120: ci_new.bVisible = TRUE; ! 19121: ci_new.dwSize = (size + 2) * 100 / (8 + 2); ! 19122: } else { ! 19123: ci_new.bVisible = FALSE; ! 19124: } ! 19125: crtc_changed[10] = crtc_changed[11] = 0; ! 19126: } ! 19127: if(crtc_changed[14] != 0 || crtc_changed[15] != 0) { ! 19128: if(cursor_moved) { ! 19129: pcbios_update_cursor_position(); ! 19130: cursor_moved = false; ! 19131: } ! 19132: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); ! 19133: int position = crtc_regs[14] * 256 + crtc_regs[15]; ! 19134: int width = *(UINT16 *)(mem + 0x44a); ! 19135: COORD co; ! 19136: co.X = position % width; ! 19137: co.Y = position / width + scr_top; ! 19138: SetConsoleCursorPosition(hStdout, co); ! 19139: ! 19140: crtc_changed[14] = crtc_changed[15] = 0; ! 19141: cursor_moved_by_crtc = true; ! 19142: } ! 19143: ! 19144: // update cursor info ! 19145: if(!is_cursor_blink_off()) { ! 19146: ci_new.bVisible = TRUE; ! 19147: } ! 19148: if(!(ci_old.dwSize == ci_new.dwSize && ci_old.bVisible == ci_new.bVisible)) { ! 19149: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); ! 19150: SetConsoleCursorInfo(hStdout, &ci_new); ! 19151: } ! 19152: ci_old = ci_new; ! 19153: ! 19154: // update daily timer counter ! 19155: pcbios_update_daily_timer_counter(cur_time); ! 19156: ! 19157: prev_time = cur_time; ! 19158: } ! 19159: } ! 19160: ! 19161: // ems ! 19162: ! 19163: void ems_init() ! 19164: { ! 19165: memset(ems_handles, 0, sizeof(ems_handles)); ! 19166: memset(ems_pages, 0, sizeof(ems_pages)); ! 19167: free_ems_pages = MAX_EMS_PAGES; ! 19168: } ! 19169: ! 19170: void ems_finish() ! 19171: { ! 19172: ems_release(); ! 19173: } ! 19174: ! 19175: void ems_release() ! 19176: { ! 19177: for(int i = 1; i <= MAX_EMS_HANDLES; i++) { ! 19178: if(ems_handles[i].buffer != NULL) { ! 19179: free(ems_handles[i].buffer); ! 19180: ems_handles[i].buffer = NULL; ! 19181: } ! 19182: } ! 19183: } ! 19184: ! 19185: void ems_allocate_pages(int handle, int pages) ! 19186: { ! 19187: if(pages > 0) { ! 19188: ems_handles[handle].buffer = (UINT8 *)calloc(1, 0x4000 * pages); ! 19189: } else { ! 19190: ems_handles[handle].buffer = NULL; ! 19191: } ! 19192: ems_handles[handle].pages = pages; ! 19193: ems_handles[handle].allocated = true; ! 19194: free_ems_pages -= pages; ! 19195: } ! 19196: ! 19197: void ems_reallocate_pages(int handle, int pages) ! 19198: { ! 19199: if(ems_handles[handle].allocated) { ! 19200: if(ems_handles[handle].pages != pages) { ! 19201: UINT8 *new_buffer = NULL; ! 19202: ! 19203: if(pages > 0) { ! 19204: new_buffer = (UINT8 *)calloc(1, 0x4000 * pages); ! 19205: } ! 19206: if(ems_handles[handle].buffer != NULL) { ! 19207: if(new_buffer != NULL) { ! 19208: if(pages > ems_handles[handle].pages) { ! 19209: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * ems_handles[handle].pages); ! 19210: } else { ! 19211: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * pages); ! 19212: } ! 19213: } ! 19214: free(ems_handles[handle].buffer); ! 19215: ems_handles[handle].buffer = NULL; ! 19216: } ! 19217: free_ems_pages += ems_handles[handle].pages; ! 19218: ! 19219: ems_handles[handle].buffer = new_buffer; ! 19220: ems_handles[handle].pages = pages; ! 19221: free_ems_pages -= pages; ! 19222: } ! 19223: } else { ! 19224: ems_allocate_pages(handle, pages); ! 19225: } ! 19226: } ! 19227: ! 19228: void ems_release_pages(int handle) ! 19229: { ! 19230: if(ems_handles[handle].allocated) { ! 19231: if(ems_handles[handle].buffer != NULL) { ! 19232: free(ems_handles[handle].buffer); ! 19233: ems_handles[handle].buffer = NULL; ! 19234: } ! 19235: free_ems_pages += ems_handles[handle].pages; ! 19236: ems_handles[handle].allocated = false; ! 19237: } ! 19238: } ! 19239: ! 19240: void ems_map_page(int physical, int handle, int logical) ! 19241: { ! 19242: if(ems_pages[physical].mapped) { ! 19243: if(ems_pages[physical].handle == handle && ems_pages[physical].page == logical) { ! 19244: return; ! 19245: } ! 19246: ems_unmap_page(physical); ! 19247: } ! 19248: if(ems_handles[handle].allocated && ems_handles[handle].buffer != NULL && logical < ems_handles[handle].pages) { ! 19249: memcpy(mem + EMS_TOP + 0x4000 * physical, ems_handles[handle].buffer + 0x4000 * logical, 0x4000); ! 19250: } ! 19251: ems_pages[physical].handle = handle; ! 19252: ems_pages[physical].page = logical; ! 19253: ems_pages[physical].mapped = true; ! 19254: } ! 19255: ! 19256: void ems_unmap_page(int physical) ! 19257: { ! 19258: if(ems_pages[physical].mapped) { ! 19259: int handle = ems_pages[physical].handle; ! 19260: int logical = ems_pages[physical].page; ! 19261: ! 19262: if(ems_handles[handle].allocated && ems_handles[handle].buffer != NULL && logical < ems_handles[handle].pages) { ! 19263: memcpy(ems_handles[handle].buffer + 0x4000 * logical, mem + EMS_TOP + 0x4000 * physical, 0x4000); ! 19264: } ! 19265: ems_pages[physical].mapped = false; ! 19266: } ! 19267: } ! 19268: ! 19269: // dma ! 19270: ! 19271: void dma_init() ! 19272: { ! 19273: memset(dma, 0, sizeof(dma)); ! 19274: for(int c = 0; c < 2; c++) { ! 19275: // for(int ch = 0; ch < 4; ch++) { ! 19276: // dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w = 0xffff; ! 19277: // } ! 19278: dma_reset(c); ! 19279: } ! 19280: } ! 19281: ! 19282: void dma_reset(int c) ! 19283: { ! 19284: dma[c].low_high = false; ! 19285: dma[c].cmd = dma[c].req = dma[c].tc = 0; ! 19286: dma[c].mask = 0xff; ! 19287: } ! 19288: ! 19289: void dma_write(int c, UINT32 addr, UINT8 data) ! 19290: { ! 19291: int ch = (addr >> 1) & 3; ! 19292: UINT8 bit = 1 << (data & 3); ! 19293: ! 19294: switch(addr & 0x0f) { ! 19295: case 0x00: case 0x02: case 0x04: case 0x06: ! 19296: if(dma[c].low_high) { ! 19297: dma[c].ch[ch].bareg.b.h = data; ! 19298: } else { ! 19299: dma[c].ch[ch].bareg.b.l = data; ! 19300: } ! 19301: dma[c].ch[ch].areg.w = dma[c].ch[ch].bareg.w; ! 19302: dma[c].low_high = !dma[c].low_high; ! 19303: break; ! 19304: case 0x01: case 0x03: case 0x05: case 0x07: ! 19305: if(dma[c].low_high) { ! 19306: dma[c].ch[ch].bcreg.b.h = data; ! 19307: } else { ! 19308: dma[c].ch[ch].bcreg.b.l = data; ! 19309: } ! 19310: dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w; ! 19311: dma[c].low_high = !dma[c].low_high; ! 19312: break; ! 19313: case 0x08: ! 19314: // command register ! 19315: dma[c].cmd = data; ! 19316: break; ! 19317: case 0x09: ! 19318: // dma[c].request register ! 19319: if(data & 4) { ! 19320: if(!(dma[c].req & bit)) { ! 19321: dma[c].req |= bit; ! 19322: // dma_run(c, ch); ! 19323: } ! 19324: } else { ! 19325: dma[c].req &= ~bit; ! 19326: } ! 19327: break; ! 19328: case 0x0a: ! 19329: // single mask register ! 19330: if(data & 4) { ! 19331: dma[c].mask |= bit; ! 19332: } else { ! 19333: dma[c].mask &= ~bit; ! 19334: } ! 19335: break; ! 19336: case 0x0b: ! 19337: // mode register ! 19338: dma[c].ch[data & 3].mode = data; ! 19339: break; ! 19340: case 0x0c: ! 19341: dma[c].low_high = false; ! 19342: break; ! 19343: case 0x0d: ! 19344: // clear master ! 19345: dma_reset(c); ! 19346: break; ! 19347: case 0x0e: ! 19348: // clear mask register ! 19349: dma[c].mask = 0; ! 19350: break; ! 19351: case 0x0f: ! 19352: // all mask register ! 19353: dma[c].mask = data & 0x0f; ! 19354: break; ! 19355: } ! 19356: } ! 19357: ! 19358: UINT8 dma_read(int c, UINT32 addr) ! 19359: { ! 19360: int ch = (addr >> 1) & 3; ! 19361: UINT8 val = 0xff; ! 19362: ! 19363: switch(addr & 0x0f) { ! 19364: case 0x00: case 0x02: case 0x04: case 0x06: ! 19365: if(dma[c].low_high) { ! 19366: val = dma[c].ch[ch].areg.b.h; ! 19367: } else { ! 19368: val = dma[c].ch[ch].areg.b.l; ! 19369: } ! 19370: dma[c].low_high = !dma[c].low_high; ! 19371: return(val); ! 19372: case 0x01: case 0x03: case 0x05: case 0x07: ! 19373: if(dma[c].low_high) { ! 19374: val = dma[c].ch[ch].creg.b.h; ! 19375: } else { ! 19376: val = dma[c].ch[ch].creg.b.l; ! 19377: } ! 19378: dma[c].low_high = !dma[c].low_high; ! 19379: return(val); ! 19380: case 0x08: ! 19381: // status register ! 19382: val = (dma[c].req << 4) | dma[c].tc; ! 19383: dma[c].tc = 0; ! 19384: return(val); ! 19385: case 0x0d: ! 19386: // temporary register (intel 82374 does not support) ! 19387: return(dma[c].tmp & 0xff); ! 19388: case 0x0f: ! 19389: // mask register (intel 82374 does support) ! 19390: return(dma[c].mask); ! 19391: } ! 19392: return(0xff); ! 19393: } ! 19394: ! 19395: void dma_page_write(int c, int ch, UINT8 data) ! 19396: { ! 19397: dma[c].ch[ch].pagereg = data; ! 19398: } ! 19399: ! 19400: UINT8 dma_page_read(int c, int ch) ! 19401: { ! 19402: return(dma[c].ch[ch].pagereg); ! 19403: } ! 19404: ! 19405: void dma_run(int c, int ch) ! 19406: { ! 19407: UINT8 bit = 1 << ch; ! 19408: ! 19409: if((dma[c].req & bit) && !(dma[c].mask & bit)) { ! 19410: // execute dma ! 19411: while(dma[c].req & bit) { ! 19412: if(ch == 0 && (dma[c].cmd & 0x01)) { ! 19413: // memory -> memory ! 19414: UINT32 saddr = dma[c].ch[0].areg.w | (dma[c].ch[0].pagereg << 16); ! 19415: UINT32 daddr = dma[c].ch[1].areg.w | (dma[c].ch[1].pagereg << 16); ! 19416: ! 19417: if(c == 0) { ! 19418: dma[c].tmp = read_byte(saddr); ! 19419: write_byte(daddr, dma[c].tmp); ! 19420: } else { ! 19421: dma[c].tmp = read_word(saddr << 1); ! 19422: write_word(daddr << 1, dma[c].tmp); ! 19423: } ! 19424: if(!(dma[c].cmd & 0x02)) { ! 19425: if(dma[c].ch[0].mode & 0x20) { ! 19426: dma[c].ch[0].areg.w--; ! 19427: if(dma[c].ch[0].areg.w == 0xffff) { ! 19428: dma[c].ch[0].pagereg--; ! 19429: } ! 19430: } else { ! 19431: dma[c].ch[0].areg.w++; ! 19432: if(dma[c].ch[0].areg.w == 0) { ! 19433: dma[c].ch[0].pagereg++; ! 19434: } ! 19435: } ! 19436: } ! 19437: if(dma[c].ch[1].mode & 0x20) { ! 19438: dma[c].ch[1].areg.w--; ! 19439: if(dma[c].ch[1].areg.w == 0xffff) { ! 19440: dma[c].ch[1].pagereg--; ! 19441: } ! 19442: } else { ! 19443: dma[c].ch[1].areg.w++; ! 19444: if(dma[c].ch[1].areg.w == 0) { ! 19445: dma[c].ch[1].pagereg++; ! 19446: } ! 19447: } ! 19448: ! 19449: // check dma condition ! 19450: if(dma[c].ch[0].creg.w-- == 0) { ! 19451: if(dma[c].ch[0].mode & 0x10) { ! 19452: // self initialize ! 19453: dma[c].ch[0].areg.w = dma[c].ch[0].bareg.w; ! 19454: dma[c].ch[0].creg.w = dma[c].ch[0].bcreg.w; ! 19455: } else { ! 19456: // dma[c].mask |= bit; ! 19457: } ! 19458: } ! 19459: if(dma[c].ch[1].creg.w-- == 0) { ! 19460: // terminal count ! 19461: if(dma[c].ch[1].mode & 0x10) { ! 19462: // self initialize ! 19463: dma[c].ch[1].areg.w = dma[c].ch[1].bareg.w; ! 19464: dma[c].ch[1].creg.w = dma[c].ch[1].bcreg.w; ! 19465: } else { ! 19466: dma[c].mask |= bit; ! 19467: } ! 19468: dma[c].req &= ~bit; ! 19469: dma[c].tc |= bit; ! 19470: } ! 19471: } else { ! 19472: UINT32 addr = dma[c].ch[ch].areg.w | (dma[c].ch[ch].pagereg << 16); ! 19473: ! 19474: if((dma[c].ch[ch].mode & 0x0c) == 0x00) { ! 19475: // verify ! 19476: } else if((dma[c].ch[ch].mode & 0x0c) == 0x04) { ! 19477: // io -> memory ! 19478: if(c == 0) { ! 19479: dma[c].tmp = read_io_byte(dma[c].ch[ch].port); ! 19480: write_byte(addr, dma[c].tmp); ! 19481: } else { ! 19482: dma[c].tmp = read_io_word(dma[c].ch[ch].port); ! 19483: write_word(addr << 1, dma[c].tmp); ! 19484: } ! 19485: } else if((dma[c].ch[ch].mode & 0x0c) == 0x08) { ! 19486: // memory -> io ! 19487: if(c == 0) { ! 19488: dma[c].tmp = read_byte(addr); ! 19489: write_io_byte(dma[c].ch[ch].port, dma[c].tmp); ! 19490: } else { ! 19491: dma[c].tmp = read_word(addr << 1); ! 19492: write_io_word(dma[c].ch[ch].port, dma[c].tmp); ! 19493: } ! 19494: } ! 19495: if(dma[c].ch[ch].mode & 0x20) { ! 19496: dma[c].ch[ch].areg.w--; ! 19497: if(dma[c].ch[ch].areg.w == 0xffff) { ! 19498: dma[c].ch[ch].pagereg--; ! 19499: } ! 19500: } else { ! 19501: dma[c].ch[ch].areg.w++; ! 19502: if(dma[c].ch[ch].areg.w == 0) { ! 19503: dma[c].ch[ch].pagereg++; ! 19504: } ! 19505: } ! 19506: ! 19507: // check dma condition ! 19508: if(dma[c].ch[ch].creg.w-- == 0) { ! 19509: // terminal count ! 19510: if(dma[c].ch[ch].mode & 0x10) { ! 19511: // self initialize ! 19512: dma[c].ch[ch].areg.w = dma[c].ch[ch].bareg.w; ! 19513: dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w; ! 19514: } else { ! 19515: dma[c].mask |= bit; ! 19516: } ! 19517: dma[c].req &= ~bit; ! 19518: dma[c].tc |= bit; ! 19519: } else if((dma[c].ch[ch].mode & 0xc0) == 0x40) { ! 19520: // single mode ! 19521: break; ! 19522: } ! 19523: } ! 19524: } ! 19525: } ! 19526: } ! 19527: ! 19528: // pic ! 19529: ! 19530: void pic_init() ! 19531: { ! 19532: memset(pic, 0, sizeof(pic)); ! 19533: pic[0].imr = pic[1].imr = 0xff; ! 19534: ! 19535: // from bochs bios ! 19536: pic_write(0, 0, 0x11); // icw1 = 11h ! 19537: pic_write(0, 1, 0x08); // icw2 = 08h ! 19538: pic_write(0, 1, 0x04); // icw3 = 04h ! 19539: pic_write(0, 1, 0x01); // icw4 = 01h ! 19540: pic_write(0, 1, 0xb8); // ocw1 = b8h ! 19541: pic_write(1, 0, 0x11); // icw1 = 11h ! 19542: pic_write(1, 1, 0x70); // icw2 = 70h ! 19543: pic_write(1, 1, 0x02); // icw3 = 02h ! 19544: pic_write(1, 1, 0x01); // icw4 = 01h ! 19545: } ! 19546: ! 19547: void pic_write(int c, UINT32 addr, UINT8 data) ! 19548: { ! 19549: if(addr & 1) { ! 19550: if(pic[c].icw2_r) { ! 19551: // icw2 ! 19552: pic[c].icw2 = data; ! 19553: pic[c].icw2_r = 0; ! 19554: } else if(pic[c].icw3_r) { ! 19555: // icw3 ! 19556: pic[c].icw3 = data; ! 19557: pic[c].icw3_r = 0; ! 19558: } else if(pic[c].icw4_r) { ! 19559: // icw4 ! 19560: pic[c].icw4 = data; ! 19561: pic[c].icw4_r = 0; ! 19562: } else { ! 19563: // ocw1 ! 19564: pic[c].imr = data; ! 19565: } ! 19566: } else { ! 19567: if(data & 0x10) { ! 19568: // icw1 ! 19569: pic[c].icw1 = data; ! 19570: pic[c].icw2_r = 1; ! 19571: pic[c].icw3_r = (data & 2) ? 0 : 1; ! 19572: pic[c].icw4_r = data & 1; ! 19573: pic[c].irr = 0; ! 19574: pic[c].isr = 0; ! 19575: pic[c].imr = 0; ! 19576: pic[c].prio = 0; ! 19577: if(!(pic[c].icw1 & 1)) { ! 19578: pic[c].icw4 = 0; ! 19579: } ! 19580: pic[c].ocw3 = 0; ! 19581: } else if(data & 8) { ! 19582: // ocw3 ! 19583: if(!(data & 2)) { ! 19584: data = (data & ~1) | (pic[c].ocw3 & 1); ! 19585: } ! 19586: if(!(data & 0x40)) { ! 19587: data = (data & ~0x20) | (pic[c].ocw3 & 0x20); ! 19588: } ! 19589: pic[c].ocw3 = data; ! 19590: } else { ! 19591: // ocw2 ! 19592: int level = 0; ! 19593: if(data & 0x40) { ! 19594: level = data & 7; ! 19595: } else { ! 19596: if(!pic[c].isr) { ! 19597: return; ! 19598: } ! 19599: level = pic[c].prio; ! 19600: while(!(pic[c].isr & (1 << level))) { ! 19601: level = (level + 1) & 7; ! 19602: } ! 19603: } ! 19604: if(data & 0x80) { ! 19605: pic[c].prio = (level + 1) & 7; ! 19606: } ! 19607: if(data & 0x20) { ! 19608: pic[c].isr &= ~(1 << level); ! 19609: } ! 19610: } ! 19611: } ! 19612: pic_update(); ! 19613: } ! 19614: ! 19615: UINT8 pic_read(int c, UINT32 addr) ! 19616: { ! 19617: if(addr & 1) { ! 19618: return(pic[c].imr); ! 19619: } else { ! 19620: // polling mode is not supported... ! 19621: //if(pic[c].ocw3 & 4) { ! 19622: // return ???; ! 19623: //} ! 19624: if(pic[c].ocw3 & 1) { ! 19625: return(pic[c].isr); ! 19626: } else { ! 19627: return(pic[c].irr); ! 19628: } ! 19629: } ! 19630: } ! 19631: ! 19632: void pic_req(int c, int level, int signal) ! 19633: { ! 19634: if(signal) { ! 19635: pic[c].irr |= (1 << level); ! 19636: } else { ! 19637: pic[c].irr &= ~(1 << level); ! 19638: } ! 19639: pic_update(); ! 19640: } ! 19641: ! 19642: int pic_ack() ! 19643: { ! 19644: // ack (INTA=L) ! 19645: pic[pic_req_chip].isr |= pic_req_bit; ! 19646: pic[pic_req_chip].irr &= ~pic_req_bit; ! 19647: if(pic_req_chip > 0) { ! 19648: // update isr and irr of master ! 19649: UINT8 slave = 1 << (pic[pic_req_chip].icw3 & 7); ! 19650: pic[pic_req_chip - 1].isr |= slave; ! 19651: pic[pic_req_chip - 1].irr &= ~slave; ! 19652: } ! 19653: //if(pic[pic_req_chip].icw4 & 1) { ! 19654: // 8086 mode ! 19655: int vector = (pic[pic_req_chip].icw2 & 0xf8) | pic_req_level; ! 19656: //} else { ! 19657: // // 8080 mode ! 19658: // UINT16 addr = (UINT16)pic[pic_req_chip].icw2 << 8; ! 19659: // if(pic[pic_req_chip].icw1 & 4) { ! 19660: // addr |= (pic[pic_req_chip].icw1 & 0xe0) | (pic_req_level << 2); ! 19661: // } else { ! 19662: // addr |= (pic[pic_req_chip].icw1 & 0xc0) | (pic_req_level << 3); ! 19663: // } ! 19664: // vector = 0xcd | (addr << 8); ! 19665: //} ! 19666: if(pic[pic_req_chip].icw4 & 2) { ! 19667: // auto eoi ! 19668: pic[pic_req_chip].isr &= ~pic_req_bit; ! 19669: } ! 19670: return(vector); ! 19671: } ! 19672: ! 19673: void pic_update() ! 19674: { ! 19675: for(int c = 0; c < 2; c++) { ! 19676: UINT8 irr = pic[c].irr; ! 19677: if(c + 1 < 2) { ! 19678: // this is master ! 19679: if(pic[c + 1].irr & (~pic[c + 1].imr)) { ! 19680: // request from slave ! 19681: irr |= 1 << (pic[c + 1].icw3 & 7); ! 19682: } ! 19683: } ! 19684: irr &= (~pic[c].imr); ! 19685: if(!irr) { ! 19686: break; ! 19687: } ! 19688: if(!(pic[c].ocw3 & 0x20)) { ! 19689: irr |= pic[c].isr; ! 19690: } ! 19691: int level = pic[c].prio; ! 19692: UINT8 bit = 1 << level; ! 19693: while(!(irr & bit)) { ! 19694: level = (level + 1) & 7; ! 19695: bit = 1 << level; ! 19696: } ! 19697: if((c + 1 < 2) && (pic[c].icw3 & bit)) { ! 19698: // check slave ! 19699: continue; ! 19700: } ! 19701: if(pic[c].isr & bit) { ! 19702: break; ! 19703: } ! 19704: // interrupt request ! 19705: pic_req_chip = c; ! 19706: pic_req_level = level; ! 19707: pic_req_bit = bit; ! 19708: i386_set_irq_line(INPUT_LINE_IRQ, HOLD_LINE); ! 19709: return; ! 19710: } ! 19711: i386_set_irq_line(INPUT_LINE_IRQ, CLEAR_LINE); ! 19712: } ! 19713: ! 19714: // pio ! 19715: ! 19716: void pio_init() ! 19717: { ! 19718: // bool conv_mode = (GetConsoleCP() == 932); ! 19719: ! 19720: memset(pio, 0, sizeof(pio)); ! 19721: ! 19722: for(int c = 0; c < 2; c++) { ! 19723: pio[c].stat = 0xdf; ! 19724: pio[c].ctrl = 0x0c; ! 19725: // pio[c].conv_mode = conv_mode; ! 19726: } ! 19727: } ! 19728: ! 19729: void pio_finish() ! 19730: { ! 19731: pio_release(); ! 19732: } ! 19733: ! 19734: void pio_release() ! 19735: { ! 19736: for(int c = 0; c < 2; c++) { ! 19737: if(pio[c].fp != NULL) { ! 19738: if(pio[c].jis_mode) { ! 19739: fputc(0x1c, pio[c].fp); ! 19740: fputc(0x2e, pio[c].fp); ! 19741: } ! 19742: fclose(pio[c].fp); ! 19743: pio[c].fp = NULL; ! 19744: } ! 19745: } ! 19746: } ! 19747: ! 19748: void pio_write(int c, UINT32 addr, UINT8 data) ! 19749: { ! 19750: switch(addr & 3) { ! 19751: case 0: ! 19752: pio[c].data = data; ! 19753: break; ! 19754: case 2: ! 19755: if((pio[c].ctrl & 0x01) && !(data & 0x01)) { ! 19756: // strobe H -> L ! 19757: if(pio[c].data == 0x0d && (data & 0x02)) { ! 19758: // auto feed ! 19759: printer_out(c, 0x0d); ! 19760: printer_out(c, 0x0a); ! 19761: } else { ! 19762: printer_out(c, pio[c].data); ! 19763: } ! 19764: pio[c].stat &= ~0x40; // set ack ! 19765: } ! 19766: pio[c].ctrl = data; ! 19767: break; ! 19768: } ! 19769: } ! 19770: ! 19771: UINT8 pio_read(int c, UINT32 addr) ! 19772: { ! 19773: switch(addr & 3) { ! 19774: case 0: ! 19775: if(pio[c].ctrl & 0x20) { ! 19776: // input mode ! 19777: return(0xff); ! 19778: } ! 19779: return(pio[c].data); ! 19780: case 1: ! 19781: { ! 19782: UINT8 stat = pio[c].stat; ! 19783: pio[c].stat |= 0x40; // clear ack ! 19784: return(stat); ! 19785: } ! 19786: case 2: ! 19787: return(pio[c].ctrl); ! 19788: } ! 19789: return(0xff); ! 19790: } ! 19791: ! 19792: void printer_out(int c, UINT8 data) ! 19793: { ! 19794: SYSTEMTIME time; ! 19795: bool jis_mode = false; ! 19796: ! 19797: GetLocalTime(&time); ! 19798: ! 19799: if(pio[c].fp != NULL) { ! 19800: // if at least 1000ms passed from last written, close the current file ! 19801: FILETIME ftime1; ! 19802: FILETIME ftime2; ! 19803: SystemTimeToFileTime(&pio[c].time, &ftime1); ! 19804: SystemTimeToFileTime(&time, &ftime2); ! 19805: INT64 *time1 = (INT64 *)&ftime1; ! 19806: INT64 *time2 = (INT64 *)&ftime2; ! 19807: INT64 msec = (*time2 - *time1) / 10000; ! 19808: ! 19809: if(msec >= 1000) { ! 19810: if(pio[c].jis_mode) { ! 19811: fputc(0x1c, pio[c].fp); ! 19812: fputc(0x2e, pio[c].fp); ! 19813: jis_mode = true; ! 19814: } ! 19815: fclose(pio[c].fp); ! 19816: pio[c].fp = NULL; ! 19817: } ! 19818: } ! 19819: if(pio[c].fp == NULL) { ! 19820: // create a new file in the temp folder ! 19821: char file_name[MAX_PATH]; ! 19822: ! 19823: sprintf(file_name, "%d-%0.2d-%0.2d_%0.2d-%0.2d-%0.2d.PRN", time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond); ! 19824: if(GetTempPathA(MAX_PATH, pio[c].path)) { ! 19825: strcat(pio[c].path, file_name); ! 19826: } else { ! 19827: strcpy(pio[c].path, file_name); ! 19828: } ! 19829: pio[c].fp = fopen(pio[c].path, "w+b"); ! 19830: } ! 19831: if(pio[c].fp != NULL) { ! 19832: if(jis_mode) { ! 19833: fputc(0x1c, pio[c].fp); ! 19834: fputc(0x26, pio[c].fp); ! 19835: } ! 19836: fputc(data, pio[c].fp); ! 19837: ! 19838: // reopen file if 1ch 26h 1ch 2eh (kanji-on kanji-off) are written at the top ! 19839: if(data == 0x2e && ftell(pio[c].fp) == 4) { ! 19840: UINT8 buffer[4]; ! 19841: fseek(pio[c].fp, 0, SEEK_SET); ! 19842: fread(buffer, 4, 1, pio[c].fp); ! 19843: if(buffer[0] == 0x1c && buffer[1] == 0x26 && buffer[2] == 0x1c/* && buffer[3] == 0x2e*/) { ! 19844: fclose(pio[c].fp); ! 19845: pio[c].fp = fopen(pio[c].path, "w+b"); ! 19846: } ! 19847: } ! 19848: pio[c].time = time; ! 19849: } ! 19850: } ! 19851: ! 19852: // pit ! 19853: ! 19854: #define PIT_FREQ 1193182ULL ! 19855: #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) ! 19856: ! 19857: void pit_init() ! 19858: { ! 19859: memset(pit, 0, sizeof(pit)); ! 19860: for(int ch = 0; ch < 3; ch++) { ! 19861: pit[ch].count = 0x10000; ! 19862: pit[ch].ctrl_reg = 0x34; ! 19863: pit[ch].mode = 3; ! 19864: } ! 19865: ! 19866: // from bochs bios ! 19867: pit_write(3, 0x34); ! 19868: pit_write(0, 0x00); ! 19869: pit_write(0, 0x00); ! 19870: } ! 19871: ! 19872: void pit_write(int ch, UINT8 val) ! 19873: { ! 19874: #ifndef PIT_ALWAYS_RUNNING ! 19875: if(!pit_active) { ! 19876: pit_active = 1; ! 19877: pit_init(); ! 19878: } ! 19879: #endif ! 19880: switch(ch) { ! 19881: case 0: ! 19882: case 1: ! 19883: case 2: ! 19884: // write count register ! 19885: if(!pit[ch].low_write && !pit[ch].high_write) { ! 19886: if(pit[ch].ctrl_reg & 0x10) { ! 19887: pit[ch].low_write = 1; ! 19888: } ! 19889: if(pit[ch].ctrl_reg & 0x20) { ! 19890: pit[ch].high_write = 1; ! 19891: } ! 19892: } ! 19893: if(pit[ch].low_write) { ! 19894: pit[ch].count_reg = val; ! 19895: pit[ch].low_write = 0; ! 19896: } else if(pit[ch].high_write) { ! 19897: if((pit[ch].ctrl_reg & 0x30) == 0x20) { ! 19898: pit[ch].count_reg = val << 8; ! 19899: } else { ! 19900: pit[ch].count_reg |= val << 8; ! 19901: } ! 19902: pit[ch].high_write = 0; ! 19903: } ! 19904: // start count ! 19905: if(!pit[ch].low_write && !pit[ch].high_write) { ! 19906: if(pit[ch].mode == 0 || pit[ch].mode == 4 || pit[ch].prev_time == 0) { ! 19907: pit[ch].count = PIT_COUNT_VALUE(ch); ! 19908: pit[ch].prev_time = timeGetTime(); ! 19909: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch); ! 19910: } ! 19911: } ! 19912: break; ! 19913: case 3: // ctrl reg ! 19914: if((val & 0xc0) == 0xc0) { ! 19915: // i8254 read-back command ! 19916: for(ch = 0; ch < 3; ch++) { ! 19917: if(!(val & 0x10) && !pit[ch].status_latched) { ! 19918: pit[ch].status = pit[ch].ctrl_reg & 0x3f; ! 19919: pit[ch].status_latched = 1; ! 19920: } ! 19921: if(!(val & 0x20) && !pit[ch].count_latched) { ! 19922: pit_latch_count(ch); ! 19923: } ! 19924: } ! 19925: break; ! 19926: } ! 19927: ch = (val >> 6) & 3; ! 19928: if(val & 0x30) { ! 19929: static const int modes[8] = {0, 1, 2, 3, 4, 5, 2, 3}; ! 19930: pit[ch].mode = modes[(val >> 1) & 7]; ! 19931: pit[ch].count_latched = 0; ! 19932: pit[ch].low_read = pit[ch].high_read = 0; ! 19933: pit[ch].low_write = pit[ch].high_write = 0; ! 19934: pit[ch].ctrl_reg = val; ! 19935: // stop count ! 19936: pit[ch].prev_time = pit[ch].expired_time = 0; ! 19937: pit[ch].count_reg = 0; ! 19938: } else if(!pit[ch].count_latched) { ! 19939: pit_latch_count(ch); ! 19940: } ! 19941: break; ! 19942: } ! 19943: } ! 19944: ! 19945: UINT8 pit_read(int ch) ! 19946: { ! 19947: #ifndef PIT_ALWAYS_RUNNING ! 19948: if(!pit_active) { ! 19949: pit_active = 1; ! 19950: pit_init(); ! 19951: } ! 19952: #endif ! 19953: switch(ch) { ! 19954: case 0: ! 19955: case 1: ! 19956: case 2: ! 19957: if(pit[ch].status_latched) { ! 19958: pit[ch].status_latched = 0; ! 19959: return(pit[ch].status); ! 19960: } ! 19961: // if not latched, through current count ! 19962: if(!pit[ch].count_latched) { ! 19963: if(!pit[ch].low_read && !pit[ch].high_read) { ! 19964: pit_latch_count(ch); ! 19965: } ! 19966: } ! 19967: // return latched count ! 19968: if(pit[ch].low_read) { ! 19969: pit[ch].low_read = 0; ! 19970: if(!pit[ch].high_read) { ! 19971: pit[ch].count_latched = 0; ! 19972: } ! 19973: return(pit[ch].latch & 0xff); ! 19974: } else if(pit[ch].high_read) { ! 19975: pit[ch].high_read = 0; ! 19976: pit[ch].count_latched = 0; ! 19977: return((pit[ch].latch >> 8) & 0xff); ! 19978: } ! 19979: } ! 19980: return(0xff); ! 19981: } ! 19982: ! 19983: int pit_run(int ch, UINT32 cur_time) ! 19984: { ! 19985: if(pit[ch].expired_time != 0 && cur_time >= pit[ch].expired_time) { ! 19986: pit[ch].count = PIT_COUNT_VALUE(ch); ! 19987: pit[ch].prev_time = pit[ch].expired_time; ! 19988: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch); ! 19989: if(cur_time >= pit[ch].expired_time) { ! 19990: pit[ch].prev_time = cur_time; ! 19991: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch); ! 19992: } ! 19993: return(1); ! 19994: } ! 19995: return(0); ! 19996: } ! 19997: ! 19998: void pit_latch_count(int ch) ! 19999: { ! 20000: if(pit[ch].expired_time != 0) { ! 20001: UINT32 cur_time = timeGetTime(); ! 20002: pit_run(ch, cur_time); ! 20003: UINT32 tmp = (pit[ch].count * (pit[ch].expired_time - cur_time)) / (pit[ch].expired_time - pit[ch].prev_time); ! 20004: UINT16 latch = (tmp != 0) ? (UINT16)tmp : 1; ! 20005: ! 20006: if(pit[ch].prev_latch == latch && pit[ch].expired_time > cur_time) { ! 20007: // decrement counter in 1msec period ! 20008: if(pit[ch].next_latch == 0) { ! 20009: tmp = (pit[ch].count * (pit[ch].expired_time - cur_time - 1)) / (pit[ch].expired_time - pit[ch].prev_time); ! 20010: pit[ch].next_latch = (tmp != 0) ? (UINT16)tmp : 1; ! 20011: } ! 20012: if(pit[ch].latch > pit[ch].next_latch) { ! 20013: pit[ch].latch--; ! 20014: } ! 20015: } else { ! 20016: pit[ch].prev_latch = pit[ch].latch = latch; ! 20017: pit[ch].next_latch = 0; ! 20018: } ! 20019: } else { ! 20020: pit[ch].latch = (UINT16)pit[ch].count; ! 20021: pit[ch].prev_latch = pit[ch].next_latch = 0; ! 20022: } ! 20023: pit[ch].count_latched = 1; ! 20024: if((pit[ch].ctrl_reg & 0x30) == 0x10) { ! 20025: // lower byte ! 20026: pit[ch].low_read = 1; ! 20027: pit[ch].high_read = 0; ! 20028: } else if((pit[ch].ctrl_reg & 0x30) == 0x20) { ! 20029: // upper byte ! 20030: pit[ch].low_read = 0; ! 20031: pit[ch].high_read = 1; ! 20032: } else { ! 20033: // lower -> upper ! 20034: pit[ch].low_read = pit[ch].high_read = 1; ! 20035: } ! 20036: } ! 20037: ! 20038: int pit_get_expired_time(int ch) ! 20039: { ! 20040: pit[ch].accum += 1024ULL * 1000ULL * (UINT64)pit[ch].count / PIT_FREQ; ! 20041: UINT64 val = pit[ch].accum >> 10; ! 20042: pit[ch].accum -= val << 10; ! 20043: return((val != 0) ? val : 1); ! 20044: } ! 20045: ! 20046: // sio ! 20047: ! 20048: void sio_init() ! 20049: { ! 20050: memset(sio, 0, sizeof(sio)); ! 20051: memset(sio_mt, 0, sizeof(sio_mt)); ! 20052: ! 20053: for(int c = 0; c < 4; c++) { ! 20054: sio[c].send_buffer = new FIFO(SIO_BUFFER_SIZE); ! 20055: sio[c].recv_buffer = new FIFO(SIO_BUFFER_SIZE); ! 20056: ! 20057: sio[c].divisor.w = 12; // 115200Hz / 9600Baud ! 20058: sio[c].line_ctrl = 0x03; // 8bit, stop 1bit, non parity ! 20059: sio[c].modem_ctrl = 0x03; // rts=on, dtr=on ! 20060: sio[c].set_rts = sio[c].set_dtr = true; ! 20061: sio[c].line_stat_buf = 0x60; // send/recv buffers are empty ! 20062: sio[c].irq_identify = 0x01; // no pending irq ! 20063: ! 20064: InitializeCriticalSection(&sio_mt[c].csSendData); ! 20065: InitializeCriticalSection(&sio_mt[c].csRecvData); ! 20066: InitializeCriticalSection(&sio_mt[c].csLineCtrl); ! 20067: InitializeCriticalSection(&sio_mt[c].csLineStat); ! 20068: InitializeCriticalSection(&sio_mt[c].csModemCtrl); ! 20069: InitializeCriticalSection(&sio_mt[c].csModemStat); ! 20070: ! 20071: if(sio_port_number[c] != 0) { ! 20072: sio[c].channel = c; ! 20073: sio_mt[c].hThread = CreateThread(NULL, 0, sio_thread, &sio[c], 0, NULL); ! 20074: } ! 20075: } ! 20076: } ! 20077: ! 20078: void sio_finish() ! 20079: { ! 20080: for(int c = 0; c < 4; c++) { ! 20081: if(sio_mt[c].hThread != NULL) { ! 20082: WaitForSingleObject(sio_mt[c].hThread, INFINITE); ! 20083: CloseHandle(sio_mt[c].hThread); ! 20084: sio_mt[c].hThread = NULL; ! 20085: } ! 20086: DeleteCriticalSection(&sio_mt[c].csSendData); ! 20087: DeleteCriticalSection(&sio_mt[c].csRecvData); ! 20088: DeleteCriticalSection(&sio_mt[c].csLineCtrl); ! 20089: DeleteCriticalSection(&sio_mt[c].csLineStat); ! 20090: DeleteCriticalSection(&sio_mt[c].csModemCtrl); ! 20091: DeleteCriticalSection(&sio_mt[c].csModemStat); ! 20092: } ! 20093: sio_release(); ! 20094: } ! 20095: ! 20096: void sio_release() ! 20097: { ! 20098: for(int c = 0; c < 4; c++) { ! 20099: // sio_thread() may access the resources :-( ! 20100: bool running = (sio_mt[c].hThread != NULL); ! 20101: ! 20102: if(running) { ! 20103: EnterCriticalSection(&sio_mt[c].csSendData); ! 20104: } ! 20105: if(sio[c].send_buffer != NULL) { ! 20106: sio[c].send_buffer->release(); ! 20107: delete sio[c].send_buffer; ! 20108: sio[c].send_buffer = NULL; ! 20109: } ! 20110: if(running) { ! 20111: LeaveCriticalSection(&sio_mt[c].csSendData); ! 20112: EnterCriticalSection(&sio_mt[c].csRecvData); ! 20113: } ! 20114: if(sio[c].recv_buffer != NULL) { ! 20115: sio[c].recv_buffer->release(); ! 20116: delete sio[c].recv_buffer; ! 20117: sio[c].recv_buffer = NULL; ! 20118: } ! 20119: if(running) { ! 20120: LeaveCriticalSection(&sio_mt[c].csRecvData); ! 20121: } ! 20122: } ! 20123: } ! 20124: ! 20125: void sio_write(int c, UINT32 addr, UINT8 data) ! 20126: { ! 20127: switch(addr & 7) { ! 20128: case 0: ! 20129: if(sio[c].selector & 0x80) { ! 20130: if(sio[c].divisor.b.l != data) { ! 20131: EnterCriticalSection(&sio_mt[c].csLineCtrl); ! 20132: sio[c].divisor.b.l = data; ! 20133: LeaveCriticalSection(&sio_mt[c].csLineCtrl); ! 20134: } ! 20135: } else { ! 20136: EnterCriticalSection(&sio_mt[c].csSendData); ! 20137: if(sio[c].send_buffer != NULL) { ! 20138: sio[c].send_buffer->write(data); ! 20139: } ! 20140: // transmitter holding/shift registers are not empty ! 20141: sio[c].line_stat_buf &= ~0x60; ! 20142: LeaveCriticalSection(&sio_mt[c].csSendData); ! 20143: ! 20144: if(sio[c].irq_enable & 0x02) { ! 20145: sio_update_irq(c); ! 20146: } ! 20147: } ! 20148: break; ! 20149: case 1: ! 20150: if(sio[c].selector & 0x80) { ! 20151: if(sio[c].divisor.b.h != data) { ! 20152: EnterCriticalSection(&sio_mt[c].csLineCtrl); ! 20153: sio[c].divisor.b.h = data; ! 20154: LeaveCriticalSection(&sio_mt[c].csLineCtrl); ! 20155: } ! 20156: } else { ! 20157: if(sio[c].irq_enable != data) { ! 20158: sio[c].irq_enable = data; ! 20159: sio_update_irq(c); ! 20160: } ! 20161: } ! 20162: break; ! 20163: case 3: ! 20164: { ! 20165: UINT8 line_ctrl = data & 0x3f; ! 20166: bool set_brk = ((data & 0x40) != 0); ! 20167: ! 20168: if(sio[c].line_ctrl != line_ctrl) { ! 20169: EnterCriticalSection(&sio_mt[c].csLineCtrl); ! 20170: sio[c].line_ctrl = line_ctrl; ! 20171: LeaveCriticalSection(&sio_mt[c].csLineCtrl); ! 20172: } ! 20173: if(sio[c].set_brk != set_brk) { ! 20174: EnterCriticalSection(&sio_mt[c].csModemCtrl); ! 20175: sio[c].set_brk = set_brk; ! 20176: LeaveCriticalSection(&sio_mt[c].csModemCtrl); ! 20177: } ! 20178: } ! 20179: sio[c].selector = data; ! 20180: break; ! 20181: case 4: ! 20182: { ! 20183: bool set_dtr = ((data & 0x01) != 0); ! 20184: bool set_rts = ((data & 0x02) != 0); ! 20185: ! 20186: if(sio[c].set_dtr != set_dtr || sio[c].set_rts != set_rts) { ! 20187: // EnterCriticalSection(&sio_mt[c].csModemCtrl); ! 20188: sio[c].set_dtr = set_dtr; ! 20189: sio[c].set_rts = set_rts; ! 20190: // LeaveCriticalSection(&sio_mt[c].csModemCtrl); ! 20191: ! 20192: bool state_changed = false; ! 20193: ! 20194: EnterCriticalSection(&sio_mt[c].csModemStat); ! 20195: if(set_dtr) { ! 20196: sio[c].modem_stat |= 0x20; // dsr on ! 20197: } else { ! 20198: sio[c].modem_stat &= ~0x20; // dsr off ! 20199: } ! 20200: if(set_rts) { ! 20201: sio[c].modem_stat |= 0x10; // cts on ! 20202: } else { ! 20203: sio[c].modem_stat &= ~0x10; // cts off ! 20204: } ! 20205: if((sio[c].prev_modem_stat & 0x20) != (sio[c].modem_stat & 0x20)) { ! 20206: if(!(sio[c].modem_stat & 0x02)) { ! 20207: if(sio[c].irq_enable & 0x08) { ! 20208: state_changed = true; ! 20209: } ! 20210: sio[c].modem_stat |= 0x02; ! 20211: } ! 20212: } ! 20213: if((sio[c].prev_modem_stat & 0x10) != (sio[c].modem_stat & 0x10)) { ! 20214: if(!(sio[c].modem_stat & 0x01)) { ! 20215: if(sio[c].irq_enable & 0x08) { ! 20216: state_changed = true; ! 20217: } ! 20218: sio[c].modem_stat |= 0x01; ! 20219: } ! 20220: } ! 20221: LeaveCriticalSection(&sio_mt[c].csModemStat); ! 20222: ! 20223: if(state_changed) { ! 20224: sio_update_irq(c); ! 20225: } ! 20226: } ! 20227: } ! 20228: sio[c].modem_ctrl = data; ! 20229: break; ! 20230: case 7: ! 20231: sio[c].scratch = data; ! 20232: break; ! 20233: } ! 20234: } ! 20235: ! 20236: UINT8 sio_read(int c, UINT32 addr) ! 20237: { ! 20238: switch(addr & 7) { ! 20239: case 0: ! 20240: if(sio[c].selector & 0x80) { ! 20241: return(sio[c].divisor.b.l); ! 20242: } else { ! 20243: EnterCriticalSection(&sio_mt[c].csRecvData); ! 20244: UINT8 data = 0; ! 20245: if(sio[c].recv_buffer != NULL) { ! 20246: data = sio[c].recv_buffer->read(); ! 20247: } ! 20248: // data is not ready ! 20249: sio[c].line_stat_buf &= ~0x01; ! 20250: LeaveCriticalSection(&sio_mt[c].csRecvData); ! 20251: ! 20252: if(sio[c].irq_enable & 0x01) { ! 20253: sio_update_irq(c); ! 20254: } ! 20255: return(data); ! 20256: } ! 20257: case 1: ! 20258: if(sio[c].selector & 0x80) { ! 20259: return(sio[c].divisor.b.h); ! 20260: } else { ! 20261: return(sio[c].irq_enable); ! 20262: } ! 20263: case 2: ! 20264: return(sio[c].irq_identify); ! 20265: case 3: ! 20266: return(sio[c].selector); ! 20267: case 4: ! 20268: return(sio[c].modem_ctrl); ! 20269: case 5: ! 20270: { ! 20271: EnterCriticalSection(&sio_mt[c].csLineStat); ! 20272: UINT8 val = sio[c].line_stat_err | sio[c].line_stat_buf; ! 20273: sio[c].line_stat_err = 0x00; ! 20274: LeaveCriticalSection(&sio_mt[c].csLineStat); ! 20275: ! 20276: bool state_changed = false; ! 20277: ! 20278: if((sio[c].line_stat_buf & 0x60) == 0x00) { ! 20279: EnterCriticalSection(&sio_mt[c].csSendData); ! 20280: if(sio[c].send_buffer != NULL && !sio[c].send_buffer->full()) { ! 20281: // transmitter holding register will be empty first ! 20282: if(sio[c].irq_enable & 0x02) { ! 20283: state_changed = true; ! 20284: } ! 20285: sio[c].line_stat_buf |= 0x20; ! 20286: } ! 20287: LeaveCriticalSection(&sio_mt[c].csSendData); ! 20288: } else if((sio[c].line_stat_buf & 0x60) == 0x20) { ! 20289: // transmitter shift register will be empty later ! 20290: sio[c].line_stat_buf |= 0x40; ! 20291: } ! 20292: if(!(sio[c].line_stat_buf & 0x01)) { ! 20293: EnterCriticalSection(&sio_mt[c].csRecvData); ! 20294: if(sio[c].recv_buffer != NULL && !sio[c].recv_buffer->empty()) { ! 20295: // data is ready ! 20296: if(sio[c].irq_enable & 0x01) { ! 20297: state_changed = true; ! 20298: } ! 20299: sio[c].line_stat_buf |= 0x01; ! 20300: } ! 20301: LeaveCriticalSection(&sio_mt[c].csRecvData); ! 20302: } ! 20303: if(state_changed) { ! 20304: sio_update_irq(c); ! 20305: } ! 20306: return(val); ! 20307: } ! 20308: case 6: ! 20309: { ! 20310: EnterCriticalSection(&sio_mt[c].csModemStat); ! 20311: UINT8 val = sio[c].modem_stat; ! 20312: sio[c].modem_stat &= 0xf0; ! 20313: sio[c].prev_modem_stat = sio[c].modem_stat; ! 20314: LeaveCriticalSection(&sio_mt[c].csModemStat); ! 20315: ! 20316: if(sio[c].modem_ctrl & 0x10) { ! 20317: // loop-back ! 20318: val &= 0x0f; ! 20319: val |= (sio[c].modem_ctrl & 0x0c) << 4; ! 20320: val |= (sio[c].modem_ctrl & 0x01) << 5; ! 20321: val |= (sio[c].modem_ctrl & 0x02) << 3; ! 20322: } ! 20323: return(val); ! 20324: } ! 20325: case 7: ! 20326: return(sio[c].scratch); ! 20327: } ! 20328: return(0xff); ! 20329: } ! 20330: ! 20331: void sio_update(int c) ! 20332: { ! 20333: if((sio[c].line_stat_buf & 0x60) == 0x00) { ! 20334: EnterCriticalSection(&sio_mt[c].csSendData); ! 20335: if(sio[c].send_buffer != NULL && !sio[c].send_buffer->full()) { ! 20336: // transmitter holding/shift registers will be empty ! 20337: sio[c].line_stat_buf |= 0x60; ! 20338: } ! 20339: LeaveCriticalSection(&sio_mt[c].csSendData); ! 20340: } else if((sio[c].line_stat_buf & 0x60) == 0x20) { ! 20341: // transmitter shift register will be empty ! 20342: sio[c].line_stat_buf |= 0x40; ! 20343: } ! 20344: if(!(sio[c].line_stat_buf & 0x01)) { ! 20345: EnterCriticalSection(&sio_mt[c].csRecvData); ! 20346: if(sio[c].recv_buffer != NULL && !sio[c].recv_buffer->empty()) { ! 20347: // data is ready ! 20348: sio[c].line_stat_buf |= 0x01; ! 20349: } ! 20350: LeaveCriticalSection(&sio_mt[c].csRecvData); ! 20351: } ! 20352: sio_update_irq(c); ! 20353: } ! 20354: ! 20355: void sio_update_irq(int c) ! 20356: { ! 20357: int level = -1; ! 20358: ! 20359: if(sio[c].irq_enable & 0x08) { ! 20360: EnterCriticalSection(&sio_mt[c].csModemStat); ! 20361: if((sio[c].modem_stat & 0x0f) != 0) { ! 20362: level = 0; ! 20363: } ! 20364: EnterCriticalSection(&sio_mt[c].csModemStat); ! 20365: } ! 20366: if(sio[c].irq_enable & 0x02) { ! 20367: if(sio[c].line_stat_buf & 0x20) { ! 20368: level = 1; ! 20369: } ! 20370: } ! 20371: if(sio[c].irq_enable & 0x01) { ! 20372: if(sio[c].line_stat_buf & 0x01) { ! 20373: level = 2; ! 20374: } ! 20375: } ! 20376: if(sio[c].irq_enable & 0x04) { ! 20377: EnterCriticalSection(&sio_mt[c].csLineStat); ! 20378: if(sio[c].line_stat_err != 0) { ! 20379: level = 3; ! 20380: } ! 20381: LeaveCriticalSection(&sio_mt[c].csLineStat); ! 20382: } ! 20383: ! 20384: // COM1 and COM3 shares IRQ4, COM2 and COM4 shares IRQ3 ! 20385: if(level != -1) { ! 20386: sio[c].irq_identify = level << 1; ! 20387: pic_req(0, (c == 0 || c == 2) ? 4 : 3, 1); ! 20388: } else { ! 20389: sio[c].irq_identify = 1; ! 20390: pic_req(0, (c == 0 || c == 2) ? 4 : 3, 0); ! 20391: } ! 20392: } ! 20393: ! 20394: DWORD WINAPI sio_thread(void *lpx) ! 20395: { ! 20396: volatile sio_t *p = (sio_t *)lpx; ! 20397: sio_mt_t *q = &sio_mt[p->channel]; ! 20398: ! 20399: char name[] = "COM1"; ! 20400: name[3] = '0' + sio_port_number[p->channel]; ! 20401: HANDLE hComm = NULL; ! 20402: COMMPROP commProp; ! 20403: DCB dcb; ! 20404: DWORD dwSettableBaud = 0xffb; // 75, 110, 150, 300, 600, 1200, 1800, 2400, 4800, 7200, and 9600bps ! 20405: BYTE bytBuffer[SIO_BUFFER_SIZE]; ! 20406: ! 20407: if((hComm = CreateFileA(name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE) { ! 20408: if(GetCommProperties(hComm, &commProp)) { ! 20409: dwSettableBaud = commProp.dwSettableBaud; ! 20410: } ! 20411: EscapeCommFunction(hComm, CLRBREAK); ! 20412: // EscapeCommFunction(hComm, SETRTS); ! 20413: // EscapeCommFunction(hComm, SETDTR); ! 20414: ! 20415: while(!m_exit) { ! 20416: // setup comm port ! 20417: bool comm_state_changed = false; ! 20418: ! 20419: EnterCriticalSection(&q->csLineCtrl); ! 20420: if((p->prev_divisor != p->divisor.w || p->prev_line_ctrl != p->line_ctrl) && p->divisor.w != 0) { ! 20421: p->prev_divisor = p->divisor.w; ! 20422: p->prev_line_ctrl = p->line_ctrl; ! 20423: comm_state_changed = true; ! 20424: } ! 20425: LeaveCriticalSection(&q->csLineCtrl); ! 20426: ! 20427: if(comm_state_changed) { ! 20428: if(GetCommState(hComm, &dcb)) { ! 20429: // dcb.BaudRate = min(9600, 115200 / p->prev_divisor); ! 20430: DWORD baud = 115200 / p->prev_divisor; ! 20431: dcb.BaudRate = 9600; // default ! 20432: ! 20433: if((dwSettableBaud & BAUD_075 ) && baud >= 75 ) dcb.BaudRate = 75; ! 20434: if((dwSettableBaud & BAUD_110 ) && baud >= 110 ) dcb.BaudRate = 110; ! 20435: // 134.5bps is not supported ??? ! 20436: // if((dwSettableBaud & BAUD_134_5) && baud >= 134.5) dcb.BaudRate = 134.5; ! 20437: if((dwSettableBaud & BAUD_150 ) && baud >= 150 ) dcb.BaudRate = 150; ! 20438: if((dwSettableBaud & BAUD_300 ) && baud >= 300 ) dcb.BaudRate = 300; ! 20439: if((dwSettableBaud & BAUD_600 ) && baud >= 600 ) dcb.BaudRate = 600; ! 20440: if((dwSettableBaud & BAUD_1200 ) && baud >= 1200 ) dcb.BaudRate = 1200; ! 20441: if((dwSettableBaud & BAUD_1800 ) && baud >= 1800 ) dcb.BaudRate = 1800; ! 20442: if((dwSettableBaud & BAUD_2400 ) && baud >= 2400 ) dcb.BaudRate = 2400; ! 20443: if((dwSettableBaud & BAUD_4800 ) && baud >= 4800 ) dcb.BaudRate = 4800; ! 20444: if((dwSettableBaud & BAUD_7200 ) && baud >= 7200 ) dcb.BaudRate = 7200; ! 20445: if((dwSettableBaud & BAUD_9600 ) && baud >= 9600 ) dcb.BaudRate = 9600; ! 20446: // if((dwSettableBaud & BAUD_14400) && baud >= 14400) dcb.BaudRate = 14400; ! 20447: // if((dwSettableBaud & BAUD_19200) && baud >= 19200) dcb.BaudRate = 19200; ! 20448: // if((dwSettableBaud & BAUD_38400) && baud >= 38400) dcb.BaudRate = 38400; ! 20449: ! 20450: switch(p->prev_line_ctrl & 0x03) { ! 20451: case 0x00: dcb.ByteSize = 5; break; ! 20452: case 0x01: dcb.ByteSize = 6; break; ! 20453: case 0x02: dcb.ByteSize = 7; break; ! 20454: case 0x03: dcb.ByteSize = 8; break; ! 20455: } ! 20456: switch(p->prev_line_ctrl & 0x04) { ! 20457: case 0x00: dcb.StopBits = ONESTOPBIT; break; ! 20458: case 0x04: dcb.StopBits = (dcb.ByteSize == 5) ? ONE5STOPBITS : TWOSTOPBITS; break; ! 20459: } ! 20460: switch(p->prev_line_ctrl & 0x38) { ! 20461: case 0x08: dcb.Parity = ODDPARITY; break; ! 20462: case 0x18: dcb.Parity = EVENPARITY; break; ! 20463: case 0x28: dcb.Parity = MARKPARITY; break; ! 20464: case 0x38: dcb.Parity = SPACEPARITY; break; ! 20465: default: dcb.Parity = NOPARITY; break; ! 20466: } ! 20467: dcb.fBinary = TRUE; ! 20468: dcb.fParity = (dcb.Parity != NOPARITY); ! 20469: dcb.fOutxCtsFlow = dcb.fOutxDsrFlow = TRUE; ! 20470: dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; ! 20471: dcb.fDsrSensitivity = FALSE;//TRUE; ! 20472: dcb.fTXContinueOnXoff = TRUE; ! 20473: dcb.fOutX = dcb.fInX = FALSE; ! 20474: dcb.fErrorChar = FALSE; ! 20475: dcb.fNull = FALSE; ! 20476: dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; ! 20477: dcb.fAbortOnError = FALSE; ! 20478: ! 20479: SetCommState(hComm, &dcb); ! 20480: } ! 20481: ! 20482: // check again to apply all comm state changes ! 20483: Sleep(10); ! 20484: continue; ! 20485: } ! 20486: ! 20487: // set comm pins ! 20488: bool change_brk = false; ! 20489: // bool change_rts = false; ! 20490: // bool change_dtr = false; ! 20491: ! 20492: EnterCriticalSection(&q->csModemCtrl); ! 20493: if(p->prev_set_brk != p->set_brk) { ! 20494: p->prev_set_brk = p->set_brk; ! 20495: change_brk = true; ! 20496: } ! 20497: // if(p->prev_set_rts != p->set_rts) { ! 20498: // p->prev_set_rts = p->set_rts; ! 20499: // change_rts = true; ! 20500: // } ! 20501: // if(p->prev_set_dtr != p->set_dtr) { ! 20502: // p->prev_set_dtr = p->set_dtr; ! 20503: // change_dtr = true; ! 20504: // } ! 20505: LeaveCriticalSection(&q->csModemCtrl); ! 20506: ! 20507: if(change_brk) { ! 20508: static UINT32 clear_time = 0; ! 20509: if(p->prev_set_brk) { ! 20510: EscapeCommFunction(hComm, SETBREAK); ! 20511: clear_time = timeGetTime() + 200; ! 20512: } else { ! 20513: // keep break for at least 200msec ! 20514: UINT32 cur_time = timeGetTime(); ! 20515: if(clear_time > cur_time) { ! 20516: Sleep(clear_time - cur_time); ! 20517: } ! 20518: EscapeCommFunction(hComm, CLRBREAK); ! 20519: } ! 20520: } ! 20521: // if(change_rts) { ! 20522: // if(p->prev_set_rts) { ! 20523: // EscapeCommFunction(hComm, SETRTS); ! 20524: // } else { ! 20525: // EscapeCommFunction(hComm, CLRRTS); ! 20526: // } ! 20527: // } ! 20528: // if(change_dtr) { ! 20529: // if(p->prev_set_dtr) { ! 20530: // EscapeCommFunction(hComm, SETDTR); ! 20531: // } else { ! 20532: // EscapeCommFunction(hComm, CLRDTR); ! 20533: // } ! 20534: // } ! 20535: ! 20536: // get comm pins ! 20537: DWORD dwModemStat = 0; ! 20538: ! 20539: if(GetCommModemStatus(hComm, &dwModemStat)) { ! 20540: EnterCriticalSection(&q->csModemStat); ! 20541: if(dwModemStat & MS_RLSD_ON) { ! 20542: p->modem_stat |= 0x80; ! 20543: } else { ! 20544: p->modem_stat &= ~0x80; ! 20545: } ! 20546: if(dwModemStat & MS_RING_ON) { ! 20547: p->modem_stat |= 0x40; ! 20548: } else { ! 20549: p->modem_stat &= ~0x40; ! 20550: } ! 20551: // if(dwModemStat & MS_DSR_ON) { ! 20552: // p->modem_stat |= 0x20; ! 20553: // } else { ! 20554: // p->modem_stat &= ~0x20; ! 20555: // } ! 20556: // if(dwModemStat & MS_CTS_ON) { ! 20557: // p->modem_stat |= 0x10; ! 20558: // } else { ! 20559: // p->modem_stat &= ~0x10; ! 20560: // } ! 20561: if((p->prev_modem_stat & 0x80) != (p->modem_stat & 0x80)) { ! 20562: p->modem_stat |= 0x08; ! 20563: } ! 20564: if((p->prev_modem_stat & 0x40) && !(p->modem_stat & 0x40)) { ! 20565: p->modem_stat |= 0x04; ! 20566: } ! 20567: // if((p->prev_modem_stat & 0x20) != (p->modem_stat & 0x20)) { ! 20568: // p->modem_stat |= 0x02; ! 20569: // } ! 20570: // if((p->prev_modem_stat & 0x10) != (p->modem_stat & 0x10)) { ! 20571: // p->modem_stat |= 0x01; ! 20572: // } ! 20573: LeaveCriticalSection(&q->csModemStat); ! 20574: } ! 20575: ! 20576: // send data ! 20577: DWORD dwSend = 0; ! 20578: ! 20579: EnterCriticalSection(&q->csSendData); ! 20580: while(p->send_buffer != NULL && !p->send_buffer->empty()) { ! 20581: bytBuffer[dwSend++] = p->send_buffer->read(); ! 20582: } ! 20583: LeaveCriticalSection(&q->csSendData); ! 20584: ! 20585: if(dwSend != 0) { ! 20586: DWORD dwWritten = 0; ! 20587: WriteFile(hComm, bytBuffer, dwSend, &dwWritten, NULL); ! 20588: } ! 20589: ! 20590: // get line status and recv data ! 20591: DWORD dwLineStat = 0; ! 20592: COMSTAT comStat; ! 20593: ! 20594: if(ClearCommError(hComm, &dwLineStat, &comStat)) { ! 20595: EnterCriticalSection(&q->csLineStat); ! 20596: if(dwLineStat & CE_BREAK) { ! 20597: p->line_stat_err |= 0x10; ! 20598: } ! 20599: if(dwLineStat & CE_FRAME) { ! 20600: p->line_stat_err |= 0x08; ! 20601: } ! 20602: if(dwLineStat & CE_RXPARITY) { ! 20603: p->line_stat_err |= 0x04; ! 20604: } ! 20605: if(dwLineStat & CE_OVERRUN) { ! 20606: p->line_stat_err |= 0x02; ! 20607: } ! 20608: LeaveCriticalSection(&q->csLineStat); ! 20609: ! 20610: if(comStat.cbInQue != 0) { ! 20611: EnterCriticalSection(&q->csRecvData); ! 20612: DWORD dwRecv = 0; ! 20613: if(p->recv_buffer != NULL) { ! 20614: dwRecv = min(comStat.cbInQue, p->recv_buffer->remain()); ! 20615: } ! 20616: LeaveCriticalSection(&q->csRecvData); ! 20617: ! 20618: if(dwRecv != 0) { ! 20619: DWORD dwRead = 0; ! 20620: if(ReadFile(hComm, bytBuffer, dwRecv, &dwRead, NULL) && dwRead != 0) { ! 20621: EnterCriticalSection(&q->csRecvData); ! 20622: if(p->recv_buffer != NULL) { ! 20623: for(int i = 0; i < dwRead; i++) { ! 20624: p->recv_buffer->write(bytBuffer[i]); ! 20625: } ! 20626: } ! 20627: LeaveCriticalSection(&q->csRecvData); ! 20628: } ! 20629: } ! 20630: } ! 20631: } ! 20632: Sleep(10); ! 20633: } ! 20634: CloseHandle(hComm); ! 20635: } ! 20636: return 0; ! 20637: } ! 20638: ! 20639: // cmos ! 20640: ! 20641: void cmos_init() ! 20642: { ! 20643: memset(cmos, 0, sizeof(cmos)); ! 20644: cmos_addr = 0; ! 20645: ! 20646: // from DOSBox ! 20647: cmos_write(0x0a, 0x26); ! 20648: cmos_write(0x0b, 0x02); ! 20649: cmos_write(0x0d, 0x80); ! 20650: } ! 20651: ! 20652: void cmos_write(int addr, UINT8 val) ! 20653: { ! 20654: cmos[addr & 0x7f] = val; ! 20655: } ! 20656: ! 20657: #define CMOS_GET_TIME() { \ ! 20658: UINT32 cur_sec = timeGetTime() / 1000 ; \ ! 20659: if(prev_sec != cur_sec) { \ ! 20660: GetLocalTime(&time); \ ! 20661: prev_sec = cur_sec; \ ! 20662: } \ ! 20663: } ! 20664: #define CMOS_BCD(v) ((cmos[0x0b] & 4) ? (v) : to_bcd(v)) ! 20665: ! 20666: UINT8 cmos_read(int addr) ! 20667: { ! 20668: static SYSTEMTIME time; ! 20669: static UINT32 prev_sec = 0; ! 20670: ! 20671: switch(addr & 0x7f) { ! 20672: case 0x00: CMOS_GET_TIME(); return(CMOS_BCD(time.wSecond)); ! 20673: case 0x02: CMOS_GET_TIME(); return(CMOS_BCD(time.wMinute)); ! 20674: case 0x04: CMOS_GET_TIME(); return(CMOS_BCD(time.wHour)); ! 20675: case 0x06: CMOS_GET_TIME(); return(time.wDayOfWeek + 1); ! 20676: case 0x07: CMOS_GET_TIME(); return(CMOS_BCD(time.wDay)); ! 20677: case 0x08: CMOS_GET_TIME(); return(CMOS_BCD(time.wMonth)); ! 20678: case 0x09: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear)); ! 20679: // case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 2 ? 0x80 : 0)); // 2msec ! 20680: case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 20 ? 0x80 : 0)); // precision of timeGetTime() may not be 1msec ! 20681: case 0x15: return((MEMORY_END >> 10) & 0xff); ! 20682: case 0x16: return((MEMORY_END >> 18) & 0xff); ! 20683: case 0x17: return(((MAX_MEM - 0x100000) >> 10) & 0xff); ! 20684: case 0x18: return(((MAX_MEM - 0x100000) >> 18) & 0xff); ! 20685: case 0x30: return(((MAX_MEM - 0x100000) >> 10) & 0xff); ! 20686: case 0x31: return(((MAX_MEM - 0x100000) >> 18) & 0xff); ! 20687: case 0x32: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear / 100)); ! 20688: } ! 20689: return(cmos[addr & 0x7f]); ! 20690: } ! 20691: ! 20692: // kbd (a20) ! 20693: ! 20694: void kbd_init() ! 20695: { ! 20696: kbd_data = kbd_command = 0; ! 20697: kbd_status = 0x18; ! 20698: } ! 20699: ! 20700: UINT8 kbd_read_data() ! 20701: { ! 20702: UINT8 data = kbd_data; ! 20703: kbd_data = 0; ! 20704: kbd_status &= ~1; ! 20705: return(data); ! 20706: } ! 20707: ! 20708: void kbd_write_data(UINT8 val) ! 20709: { ! 20710: switch(kbd_command) { ! 20711: case 0xd1: ! 20712: i386_set_a20_line((val >> 1) & 1); ! 20713: break; ! 20714: } ! 20715: kbd_command = 0; ! 20716: kbd_status &= ~8; ! 20717: } ! 20718: ! 20719: UINT8 kbd_read_status() ! 20720: { ! 20721: return(kbd_status); ! 20722: } ! 20723: ! 20724: void kbd_write_command(UINT8 val) ! 20725: { ! 20726: switch(val) { ! 20727: case 0xd0: ! 20728: kbd_data = ((m_a20_mask >> 19) & 2) | 1; ! 20729: kbd_status |= 1; ! 20730: break; ! 20731: case 0xdd: ! 20732: i386_set_a20_line(0); ! 20733: break; ! 20734: case 0xdf: ! 20735: i386_set_a20_line(1); ! 20736: break; ! 20737: case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: ! 20738: case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: ! 20739: if(!(val & 1)) { ! 20740: if((cmos[0x0f] & 0x7f) == 5) { ! 20741: // reset pic ! 20742: pic_init(); ! 20743: pic[0].irr = pic[1].irr = 0x00; ! 20744: pic[0].imr = pic[1].imr = 0xff; ! 20745: } ! 20746: CPU_RESET_CALL(CPU_MODEL); ! 20747: UINT16 address = *(UINT16 *)(mem + 0x467); ! 20748: UINT16 selector = *(UINT16 *)(mem + 0x469); ! 20749: i386_jmp_far(selector, address); ! 20750: } ! 20751: i386_set_a20_line((val >> 1) & 1); ! 20752: break; ! 20753: } ! 20754: kbd_command = val; ! 20755: kbd_status |= 8; ! 20756: } ! 20757: ! 20758: // vga ! 20759: ! 20760: UINT8 vga_read_status() ! 20761: { ! 20762: // 60hz ! 20763: static const int period[3] = {16, 17, 17}; ! 20764: static int index = 0; ! 20765: UINT32 time = timeGetTime() % period[index]; ! 20766: ! 20767: index = (index + 1) % 3; ! 20768: return((time < 4 ? 0x08 : 0) | (time == 0 ? 0 : 0x01)); ! 20769: } ! 20770: ! 20771: // i/o bus ! 20772: ! 20773: // this is ugly patch for SW1US.EXE, it sometimes mistakely read/write 01h-10h for serial I/O ! 20774: //#define SW1US_PATCH ! 20775: ! 20776: UINT8 read_io_byte(offs_t addr) ! 20777: #ifdef USE_DEBUGGER ! 20778: { ! 20779: if(now_debugging) { ! 20780: for(int i = 0; i < MAX_BREAK_POINTS; i++) { ! 20781: if(in_break_point.table[i].status == 1) { ! 20782: if(addr == in_break_point.table[i].addr) { ! 20783: in_break_point.hit = i + 1; ! 20784: now_suspended = true; ! 20785: break; ! 20786: } ! 20787: } ! 20788: } ! 20789: } ! 20790: return(debugger_read_io_byte(addr)); ! 20791: } ! 20792: UINT8 debugger_read_io_byte(offs_t addr) ! 20793: #endif ! 20794: { ! 20795: UINT8 val = 0xff; ! 20796: ! 20797: switch(addr) { ! 20798: #ifdef SW1US_PATCH ! 20799: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08: ! 20800: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: case 0x10: ! 20801: val = sio_read(0, addr - 1); ! 20802: break; ! 20803: #else ! 20804: case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: ! 20805: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: ! 20806: val = dma_read(0, addr); ! 20807: break; ! 20808: #endif ! 20809: case 0x20: case 0x21: ! 20810: val = pic_read(0, addr); ! 20811: break; ! 20812: case 0x40: case 0x41: case 0x42: case 0x43: ! 20813: val = pit_read(addr & 0x03); ! 20814: break; ! 20815: case 0x60: ! 20816: val = kbd_read_data(); ! 20817: break; ! 20818: case 0x61: ! 20819: val = system_port; ! 20820: break; ! 20821: case 0x64: ! 20822: val = kbd_read_status(); ! 20823: break; ! 20824: case 0x71: ! 20825: val = cmos_read(cmos_addr); ! 20826: break; ! 20827: case 0x81: ! 20828: val = dma_page_read(0, 2); ! 20829: break; ! 20830: case 0x82: ! 20831: val = dma_page_read(0, 3); ! 20832: break; ! 20833: case 0x83: ! 20834: val = dma_page_read(0, 1); ! 20835: break; ! 20836: case 0x87: ! 20837: val = dma_page_read(0, 0); ! 20838: break; ! 20839: case 0x89: ! 20840: val = dma_page_read(1, 2); ! 20841: break; ! 20842: case 0x8a: ! 20843: val = dma_page_read(1, 3); ! 20844: break; ! 20845: case 0x8b: ! 20846: val = dma_page_read(1, 1); ! 20847: break; ! 20848: case 0x8f: ! 20849: val = dma_page_read(1, 0); ! 20850: break; ! 20851: case 0x92: ! 20852: val = (m_a20_mask >> 19) & 2; ! 20853: break; ! 20854: case 0xa0: case 0xa1: ! 20855: val = pic_read(1, addr); ! 20856: break; ! 20857: case 0xc0: case 0xc2: case 0xc4: case 0xc6: case 0xc8: case 0xca: case 0xcc: case 0xce: ! 20858: case 0xd0: case 0xd2: case 0xd4: case 0xd6: case 0xd8: case 0xda: case 0xdc: case 0xde: ! 20859: val = dma_read(1, (addr - 0xc0) >> 1); ! 20860: break; ! 20861: case 0x278: case 0x279: case 0x27a: ! 20862: val = pio_read(1, addr); ! 20863: break; ! 20864: case 0x2e8: case 0x2e9: case 0x2ea: case 0x2eb: case 0x2ec: case 0x2ed: case 0x2ee: case 0x2ef: ! 20865: val = sio_read(3, addr); ! 20866: break; ! 20867: case 0x2f8: case 0x2f9: case 0x2fa: case 0x2fb: case 0x2fc: case 0x2fd: case 0x2fe: case 0x2ff: ! 20868: val = sio_read(1, addr); ! 20869: break; ! 20870: case 0x378: case 0x379: case 0x37a: ! 20871: val = pio_read(0, addr); ! 20872: break; ! 20873: case 0x3ba: case 0x3da: ! 20874: val = vga_read_status(); ! 20875: break; ! 20876: case 0x3bc: case 0x3bd: case 0x3be: ! 20877: val = pio_read(2, addr); ! 20878: break; ! 20879: case 0x3d5: ! 20880: if(crtc_addr < 16) { ! 20881: val = crtc_regs[crtc_addr]; ! 20882: } ! 20883: break; ! 20884: case 0x3e8: case 0x3e9: case 0x3ea: case 0x3eb: case 0x3ec: case 0x3ed: case 0x3ee: case 0x3ef: ! 20885: val = sio_read(2, addr); ! 20886: break; ! 20887: case 0x3f8: case 0x3f9: case 0x3fa: case 0x3fb: case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff: ! 20888: val = sio_read(0, addr); ! 20889: break; ! 20890: default: ! 20891: // fatalerror("unknown inb %4x\n", addr); ! 20892: break; ! 20893: } ! 20894: #ifdef ENABLE_DEBUG_IOPORT ! 20895: if(fp_debug_log != NULL) { ! 20896: fprintf(fp_debug_log, "inb %04X, %02X\n", addr, val); ! 20897: } ! 20898: #endif ! 20899: return(val); ! 20900: } ! 20901: ! 20902: UINT16 read_io_word(offs_t addr) ! 20903: { ! 20904: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8)); ! 20905: } ! 20906: ! 20907: #ifdef USE_DEBUGGER ! 20908: UINT16 debugger_read_io_word(offs_t addr) ! 20909: { ! 20910: return(debugger_read_io_byte(addr) | (debugger_read_io_byte(addr + 1) << 8)); ! 20911: } ! 20912: #endif ! 20913: ! 20914: UINT32 read_io_dword(offs_t addr) ! 20915: { ! 20916: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8) | (read_io_byte(addr + 2) << 16) | (read_io_byte(addr + 3) << 24)); ! 20917: } ! 20918: ! 20919: #ifdef USE_DEBUGGER ! 20920: UINT32 debugger_read_io_dword(offs_t addr) ! 20921: { ! 20922: return(debugger_read_io_byte(addr) | (debugger_read_io_byte(addr + 1) << 8) | (debugger_read_io_byte(addr + 2) << 16) | (debugger_read_io_byte(addr + 3) << 24)); ! 20923: } ! 20924: #endif ! 20925: ! 20926: void write_io_byte(offs_t addr, UINT8 val) ! 20927: #ifdef USE_DEBUGGER ! 20928: { ! 20929: if(now_debugging) { ! 20930: for(int i = 0; i < MAX_BREAK_POINTS; i++) { ! 20931: if(out_break_point.table[i].status == 1) { ! 20932: if(addr == out_break_point.table[i].addr) { ! 20933: out_break_point.hit = i + 1; ! 20934: now_suspended = true; ! 20935: break; ! 20936: } ! 20937: } ! 20938: } ! 20939: } ! 20940: debugger_write_io_byte(addr, val); ! 20941: } ! 20942: void debugger_write_io_byte(offs_t addr, UINT8 val) ! 20943: #endif ! 20944: { ! 20945: #ifdef ENABLE_DEBUG_IOPORT ! 20946: if(fp_debug_log != NULL) { ! 20947: #ifdef USE_SERVICE_THREAD ! 20948: if(addr != 0xf7) ! 20949: #endif ! 20950: fprintf(fp_debug_log, "outb %04X, %02X\n", addr, val); ! 20951: } ! 20952: #endif ! 20953: switch(addr) { ! 20954: #ifdef SW1US_PATCH ! 20955: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08: ! 20956: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: case 0x10: ! 20957: sio_write(0, addr - 1, val); ! 20958: break; ! 20959: #else ! 20960: case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: ! 20961: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: ! 20962: dma_write(0, addr, val); ! 20963: break; ! 20964: #endif ! 20965: case 0x20: case 0x21: ! 20966: pic_write(0, addr, val); ! 20967: break; ! 20968: case 0x40: case 0x41: case 0x42: case 0x43: ! 20969: pit_write(addr & 0x03, val); ! 20970: break; ! 20971: case 0x60: ! 20972: kbd_write_data(val); ! 20973: break; ! 20974: case 0x61: ! 20975: if((system_port & 3) != 3 && (val & 3) == 3) { ! 20976: // beep on ! 20977: // MessageBeep(-1); ! 20978: } else if((system_port & 3) == 3 && (val & 3) != 3) { ! 20979: // beep off ! 20980: } ! 20981: system_port = val; ! 20982: break; ! 20983: case 0x64: ! 20984: kbd_write_command(val); ! 20985: break; ! 20986: case 0x70: ! 20987: cmos_addr = val; ! 20988: break; ! 20989: case 0x71: ! 20990: cmos_write(cmos_addr, val); ! 20991: break; ! 20992: case 0x81: ! 20993: dma_page_write(0, 2, val); ! 20994: case 0x82: ! 20995: dma_page_write(0, 3, val); ! 20996: case 0x83: ! 20997: dma_page_write(0, 1, val); ! 20998: case 0x87: ! 20999: dma_page_write(0, 0, val); ! 21000: case 0x89: ! 21001: dma_page_write(1, 2, val); ! 21002: case 0x8a: ! 21003: dma_page_write(1, 3, val); ! 21004: case 0x8b: ! 21005: dma_page_write(1, 1, val); ! 21006: case 0x8f: ! 21007: dma_page_write(1, 0, val); ! 21008: case 0x92: ! 21009: i386_set_a20_line((val >> 1) & 1); ! 21010: break; ! 21011: case 0xa0: case 0xa1: ! 21012: pic_write(1, addr, val); ! 21013: break; ! 21014: case 0xc0: case 0xc2: case 0xc4: case 0xc6: case 0xc8: case 0xca: case 0xcc: case 0xce: ! 21015: case 0xd0: case 0xd2: case 0xd4: case 0xd6: case 0xd8: case 0xda: case 0xdc: case 0xde: ! 21016: dma_write(1, (addr - 0xc0) >> 1, val); ! 21017: break; ! 21018: #ifdef USE_SERVICE_THREAD ! 21019: case 0xf7: ! 21020: // dummy i/o for BIOS/DOS service ! 21021: if(in_service && cursor_moved) { ! 21022: // update cursor position before service is done ! 21023: pcbios_update_cursor_position(); ! 21024: cursor_moved = false; ! 21025: } ! 21026: finish_service_loop(); ! 21027: break; ! 21028: #endif ! 21029: case 0x278: case 0x279: case 0x27a: ! 21030: pio_write(1, addr, val); ! 21031: break; ! 21032: case 0x2e8: case 0x2e9: case 0x2ea: case 0x2eb: case 0x2ec: case 0x2ed: case 0x2ee: case 0x2ef: ! 21033: sio_write(3, addr, val); ! 21034: break; ! 21035: case 0x2f8: case 0x2f9: case 0x2fa: case 0x2fb: case 0x2fc: case 0x2fd: case 0x2fe: case 0x2ff: ! 21036: sio_write(1, addr, val); ! 21037: break; ! 21038: case 0x378: case 0x379: case 0x37a: ! 21039: pio_write(0, addr, val); ! 21040: break; ! 21041: case 0x3bc: case 0x3bd: case 0x3be: ! 21042: pio_write(2, addr, val); ! 21043: break; ! 21044: case 0x3d4: ! 21045: crtc_addr = val; ! 21046: break; ! 21047: case 0x3d5: ! 21048: if(crtc_addr < 16) { ! 21049: if(crtc_regs[crtc_addr] != val) { ! 21050: crtc_regs[crtc_addr] = val; ! 21051: crtc_changed[crtc_addr] = 1; ! 21052: } ! 21053: } ! 21054: break; ! 21055: case 0x3e8: case 0x3e9: case 0x3ea: case 0x3eb: case 0x3ec: case 0x3ed: case 0x3ee: case 0x3ef: ! 21056: sio_write(2, addr, val); ! 21057: break; ! 21058: case 0x3f8: case 0x3f9: case 0x3fa: case 0x3fb: case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff: ! 21059: sio_write(0, addr, val); ! 21060: break; ! 21061: default: ! 21062: // fatalerror("unknown outb %4x,%2x\n", addr, val); ! 21063: break; ! 21064: } ! 21065: } ! 21066: ! 21067: void write_io_word(offs_t addr, UINT16 val) ! 21068: { ! 21069: write_io_byte(addr + 0, (val >> 0) & 0xff); ! 21070: write_io_byte(addr + 1, (val >> 8) & 0xff); ! 21071: } ! 21072: ! 21073: #ifdef USE_DEBUGGER ! 21074: void debugger_write_io_word(offs_t addr, UINT16 val) ! 21075: { ! 21076: debugger_write_io_byte(addr + 0, (val >> 0) & 0xff); ! 21077: debugger_write_io_byte(addr + 1, (val >> 8) & 0xff); ! 21078: } ! 21079: #endif ! 21080: ! 21081: void write_io_dword(offs_t addr, UINT32 val) ! 21082: { ! 21083: write_io_byte(addr + 0, (val >> 0) & 0xff); ! 21084: write_io_byte(addr + 1, (val >> 8) & 0xff); ! 21085: write_io_byte(addr + 2, (val >> 16) & 0xff); ! 21086: write_io_byte(addr + 3, (val >> 24) & 0xff); ! 21087: } ! 21088: ! 21089: #ifdef USE_DEBUGGER ! 21090: void debugger_write_io_dword(offs_t addr, UINT32 val) ! 21091: { ! 21092: debugger_write_io_byte(addr + 0, (val >> 0) & 0xff); ! 21093: debugger_write_io_byte(addr + 1, (val >> 8) & 0xff); ! 21094: debugger_write_io_byte(addr + 2, (val >> 16) & 0xff); ! 21095: debugger_write_io_byte(addr + 3, (val >> 24) & 0xff); ! 21096: } ! 21097: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.