|
|
1.1 root 1: /*
2: MS-DOS Player for Win32 console
3:
4: Author : Takeda.Toshiya
5: Date : 2009.11.09-
6: */
7:
8: #include "msdos.h"
9:
10: #define my_strchr(str, chr) (char *)_mbschr((unsigned char *)(str), (unsigned int)(chr))
11: #define my_strtok(tok, del) (char *)_mbstok((unsigned char *)(tok), (const unsigned char *)(del))
12: #define my_strupr(str) (char *)_mbsupr((unsigned char *)(str))
13:
14: #define fatalerror(...) { \
15: fprintf(stderr, __VA_ARGS__); \
16: exit(1); \
17: }
18: #define error(...) fprintf(stderr, "error: " __VA_ARGS__)
19:
1.1.1.12 root 20: #if defined(__MINGW32__)
21: extern "C" int _CRT_glob = 0;
22: #endif
23:
24: /*
25: kludge for "more-standardized" C++
26: */
27: #if !defined(_MSC_VER)
28: inline int kludge_min(int a, int b) { return (a<b ? a:b); }
29: inline int kludge_max(int a, int b) { return (a>b ? a:b); }
30: #define min(a,b) kludge_min(a,b)
31: #define max(a,b) kludge_max(a,b)
1.1.1.14! root 32: #elif _MSC_VER >= 1400
! 33: void ignore_invalid_parameters(const wchar_t *, const wchar_t *, const wchar_t *, unsigned int, uintptr_t)
! 34: {
! 35: }
! 36: #endif
! 37:
! 38: #define USE_THREAD
! 39:
! 40: #ifdef USE_THREAD
! 41: static CRITICAL_SECTION vram_crit_sect;
! 42: #else
! 43: #define EnterCriticalSection(x)
! 44: #define LeaveCriticalSection(x)
! 45: #define vram_flush()
1.1.1.12 root 46: #endif
47:
1.1.1.14! root 48: #define VIDEO_REGEN *(UINT16 *)(mem + 0x44c)
! 49: #define SCR_BUF(y,x) scr_buf[(y) * scr_buf_size.X + (x)]
! 50:
! 51: void change_console_size(int width, int height);
! 52: void clear_scr_buffer(WORD attr);
! 53:
! 54: static UINT32 vram_length_char = 0, vram_length_attr = 0;
! 55: static UINT32 vram_last_length_char = 0, vram_last_length_attr = 0;
! 56: static COORD vram_coord_char, vram_coord_attr;
! 57:
! 58: bool ignore_illegal_insn = false;
! 59: bool limit_max_memory = false;
! 60: bool no_windows = false;
! 61: //bool ctrl_break = false;
! 62: bool stay_busy = false;
! 63: UINT32 iops = 0;
! 64:
! 65: BOOL is_vista_or_later;
! 66:
! 67: inline UINT32 get_ticks_since_midnight()
! 68: {
! 69: SYSTEMTIME time;
! 70:
! 71: GetLocalTime(&time);
! 72: unsigned __int64 msec = ((time.wHour * 60 + time.wMinute) * 60 + time.wSecond) * 1000 + time.wMilliseconds;
! 73: unsigned __int64 tick = msec * 0x1800b0 / 24 / 60 / 60 / 1000;
! 74: return (UINT32)tick;
! 75: }
! 76:
! 77: inline void maybe_idle()
! 78: {
! 79: // if it appears to be in a tight loop, assume waiting for input
! 80: // allow for one updated video character, for a spinning cursor
! 81: if(!stay_busy && iops < 1000 && vram_length_char <= 1 && vram_length_attr <= 1) {
! 82: Sleep(10);
! 83: }
! 84: iops = 0;
! 85: }
1.1.1.12 root 86:
1.1 root 87: /* ----------------------------------------------------------------------------
1.1.1.3 root 88: MAME i86/i386
1.1 root 89: ---------------------------------------------------------------------------- */
90:
91: //#define SUPPORT_DISASSEMBLER
92:
1.1.1.7 root 93: #if defined(HAS_I86)
94: #define CPU_MODEL i8086
1.1.1.9 root 95: #elif defined(HAS_I186)
96: #define CPU_MODEL i80186
1.1.1.7 root 97: #elif defined(HAS_I286)
98: #define CPU_MODEL i80286
99: #elif defined(HAS_I386)
1.1.1.3 root 100: #define CPU_MODEL i386
1.1.1.9 root 101: #else
102: #if defined(HAS_I386SX)
103: #define CPU_MODEL i386SX
104: #else
1.1.1.11 root 105: #if defined(HAS_I486)
106: #define CPU_MODEL i486
107: #else
108: #if defined(HAS_PENTIUM)
109: #define CPU_MODEL pentium
110: #elif defined(HAS_MEDIAGX)
111: #define CPU_MODEL mediagx
112: #elif defined(HAS_PENTIUM_PRO)
113: #define CPU_MODEL pentium_pro
114: #elif defined(HAS_PENTIUM_MMX)
115: #define CPU_MODEL pentium_mmx
116: #elif defined(HAS_PENTIUM2)
117: #define CPU_MODEL pentium2
118: #elif defined(HAS_PENTIUM3)
119: #define CPU_MODEL pentium3
120: #elif defined(HAS_PENTIUM4)
121: #define CPU_MODEL pentium4
122: #endif
123: #define SUPPORT_RDTSC
1.1.1.9 root 124: #endif
1.1.1.11 root 125: #define SUPPORT_FPU
1.1.1.9 root 126: #endif
1.1.1.7 root 127: #define HAS_I386
1.1.1.3 root 128: #endif
1.1 root 129:
1.1.1.10 root 130: #ifndef __BIG_ENDIAN__
1.1 root 131: #define LSB_FIRST
1.1.1.10 root 132: #endif
1.1 root 133:
134: #ifndef INLINE
135: #define INLINE inline
136: #endif
137: #define U64(v) UINT64(v)
138:
139: //#define logerror(...) fprintf(stderr, __VA_ARGS__)
140: #define logerror(...)
141: //#define popmessage(...) fprintf(stderr, __VA_ARGS__)
142: #define popmessage(...)
143:
144: /*****************************************************************************/
1.1.1.10 root 145: /* src/emu/devcpu.h */
146:
147: // CPU interface functions
148: #define CPU_INIT_NAME(name) cpu_init_##name
149: #define CPU_INIT(name) void CPU_INIT_NAME(name)()
150: #define CPU_INIT_CALL(name) CPU_INIT_NAME(name)()
151:
152: #define CPU_RESET_NAME(name) cpu_reset_##name
153: #define CPU_RESET(name) void CPU_RESET_NAME(name)()
154: #define CPU_RESET_CALL(name) CPU_RESET_NAME(name)()
155:
156: #define CPU_EXECUTE_NAME(name) cpu_execute_##name
157: #define CPU_EXECUTE(name) void CPU_EXECUTE_NAME(name)()
158: #define CPU_EXECUTE_CALL(name) CPU_EXECUTE_NAME(name)()
159:
160: #define CPU_TRANSLATE_NAME(name) cpu_translate_##name
161: #define CPU_TRANSLATE(name) int CPU_TRANSLATE_NAME(name)(address_spacenum space, int intention, offs_t *address)
162: #define CPU_TRANSLATE_CALL(name) CPU_TRANSLATE_NAME(name)(space, intention, address)
163:
164: #define CPU_DISASSEMBLE_NAME(name) cpu_disassemble_##name
165: #define CPU_DISASSEMBLE(name) int CPU_DISASSEMBLE_NAME(name)(char *buffer, offs_t eip, const UINT8 *oprom)
166: #define CPU_DISASSEMBLE_CALL(name) CPU_DISASSEMBLE_NAME(name)(buffer, eip, oprom)
167:
1.1.1.14! root 168: #define CPU_MODEL_STR(name) #name
! 169: #define CPU_MODEL_NAME(name) CPU_MODEL_STR(name)
! 170:
1.1.1.10 root 171: /*****************************************************************************/
172: /* src/emu/didisasm.h */
173:
174: // Disassembler constants
175: const UINT32 DASMFLAG_SUPPORTED = 0x80000000; // are disassembly flags supported?
176: const UINT32 DASMFLAG_STEP_OUT = 0x40000000; // this instruction should be the end of a step out sequence
177: const UINT32 DASMFLAG_STEP_OVER = 0x20000000; // this instruction should be stepped over by setting a breakpoint afterwards
178: const UINT32 DASMFLAG_OVERINSTMASK = 0x18000000; // number of extra instructions to skip when stepping over
179: const UINT32 DASMFLAG_OVERINSTSHIFT = 27; // bits to shift after masking to get the value
180: const UINT32 DASMFLAG_LENGTHMASK = 0x0000ffff; // the low 16-bits contain the actual length
181:
182: /*****************************************************************************/
1.1 root 183: /* src/emu/diexec.h */
184:
185: // I/O line states
186: enum line_state
187: {
188: CLEAR_LINE = 0, // clear (a fired or held) line
189: ASSERT_LINE, // assert an interrupt immediately
190: HOLD_LINE, // hold interrupt line until acknowledged
191: PULSE_LINE // pulse interrupt line instantaneously (only for NMI, RESET)
192: };
193:
194: // I/O line definitions
195: enum
196: {
197: INPUT_LINE_IRQ = 0,
198: INPUT_LINE_NMI
199: };
200:
201: /*****************************************************************************/
1.1.1.10 root 202: /* src/emu/dimemory.h */
1.1 root 203:
1.1.1.10 root 204: // Translation intentions
205: const int TRANSLATE_TYPE_MASK = 0x03; // read write or fetch
206: const int TRANSLATE_USER_MASK = 0x04; // user mode or fully privileged
207: const int TRANSLATE_DEBUG_MASK = 0x08; // debug mode (no side effects)
208:
209: const int TRANSLATE_READ = 0; // translate for read
210: const int TRANSLATE_WRITE = 1; // translate for write
211: const int TRANSLATE_FETCH = 2; // translate for instruction fetch
212: const int TRANSLATE_READ_USER = (TRANSLATE_READ | TRANSLATE_USER_MASK);
213: const int TRANSLATE_WRITE_USER = (TRANSLATE_WRITE | TRANSLATE_USER_MASK);
214: const int TRANSLATE_FETCH_USER = (TRANSLATE_FETCH | TRANSLATE_USER_MASK);
215: const int TRANSLATE_READ_DEBUG = (TRANSLATE_READ | TRANSLATE_DEBUG_MASK);
216: const int TRANSLATE_WRITE_DEBUG = (TRANSLATE_WRITE | TRANSLATE_DEBUG_MASK);
217: const int TRANSLATE_FETCH_DEBUG = (TRANSLATE_FETCH | TRANSLATE_DEBUG_MASK);
1.1 root 218:
1.1.1.10 root 219: /*****************************************************************************/
220: /* src/emu/emucore.h */
1.1 root 221:
1.1.1.10 root 222: // constants for expression endianness
223: enum endianness_t
224: {
225: ENDIANNESS_LITTLE,
226: ENDIANNESS_BIG
227: };
1.1 root 228:
1.1.1.10 root 229: // declare native endianness to be one or the other
230: #ifdef LSB_FIRST
231: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_LITTLE;
232: #else
233: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_BIG;
234: #endif
235:
236: // endian-based value: first value is if 'endian' is little-endian, second is if 'endian' is big-endian
237: #define ENDIAN_VALUE_LE_BE(endian,leval,beval) (((endian) == ENDIANNESS_LITTLE) ? (leval) : (beval))
238:
239: // endian-based value: first value is if native endianness is little-endian, second is if native is big-endian
240: #define NATIVE_ENDIAN_VALUE_LE_BE(leval,beval) ENDIAN_VALUE_LE_BE(ENDIANNESS_NATIVE, leval, beval)
241:
242: // endian-based value: first value is if 'endian' matches native, second is if 'endian' doesn't match native
243: #define ENDIAN_VALUE_NE_NNE(endian,leval,beval) (((endian) == ENDIANNESS_NATIVE) ? (neval) : (nneval))
1.1 root 244:
245: /*****************************************************************************/
246: /* src/emu/memory.h */
247:
1.1.1.10 root 248: // address spaces
249: enum address_spacenum
250: {
251: AS_0, // first address space
252: AS_1, // second address space
253: AS_2, // third address space
254: AS_3, // fourth address space
255: ADDRESS_SPACES, // maximum number of address spaces
256:
257: // alternate address space names for common use
258: AS_PROGRAM = AS_0, // program address space
259: AS_DATA = AS_1, // data address space
260: AS_IO = AS_2 // I/O address space
261: };
262:
1.1 root 263: // offsets and addresses are 32-bit (for now...)
264: typedef UINT32 offs_t;
265:
266: // read accessors
267: UINT8 read_byte(offs_t byteaddress)
268: {
1.1.1.4 root 269: #if defined(HAS_I386)
1.1 root 270: if(byteaddress < MAX_MEM) {
271: return mem[byteaddress];
1.1.1.3 root 272: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
273: // return read_byte(byteaddress & 0xfffff);
1.1 root 274: }
275: return 0;
1.1.1.4 root 276: #else
277: return mem[byteaddress];
278: #endif
1.1 root 279: }
280:
281: UINT16 read_word(offs_t byteaddress)
282: {
1.1.1.14! root 283: if(byteaddress == 0x41c) {
! 284: // pointer to first free slot in keyboard buffer
! 285: // XXX: the buffer itself doesn't actually exist in DOS memory
! 286: if(key_buf_char->count() == 0) {
! 287: maybe_idle();
! 288: }
! 289: return (UINT16)key_buf_char->count();
! 290: }
1.1.1.4 root 291: #if defined(HAS_I386)
1.1 root 292: if(byteaddress < MAX_MEM - 1) {
293: return *(UINT16 *)(mem + byteaddress);
1.1.1.3 root 294: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
295: // return read_word(byteaddress & 0xfffff);
1.1 root 296: }
297: return 0;
1.1.1.4 root 298: #else
299: return *(UINT16 *)(mem + byteaddress);
300: #endif
1.1 root 301: }
302:
303: UINT32 read_dword(offs_t byteaddress)
304: {
1.1.1.14! root 305: if(byteaddress == 0x46c) {
! 306: return get_ticks_since_midnight();
! 307: }
1.1.1.4 root 308: #if defined(HAS_I386)
1.1 root 309: if(byteaddress < MAX_MEM - 3) {
310: return *(UINT32 *)(mem + byteaddress);
1.1.1.3 root 311: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
312: // return read_dword(byteaddress & 0xfffff);
1.1 root 313: }
314: return 0;
1.1.1.4 root 315: #else
316: return *(UINT32 *)(mem + byteaddress);
317: #endif
1.1 root 318: }
319:
320: // write accessors
1.1.1.14! root 321: #ifdef USE_THREAD
! 322: void vram_flush_char()
! 323: {
! 324: if(vram_length_char != 0) {
! 325: DWORD num;
! 326: WriteConsoleOutputCharacter(hStdout, scr_char, vram_length_char, vram_coord_char, &num);
! 327: vram_length_char = vram_last_length_char = 0;
! 328: }
! 329: }
! 330:
! 331: void vram_flush_attr()
! 332: {
! 333: if(vram_length_attr != 0) {
! 334: DWORD num;
! 335: WriteConsoleOutputAttribute(hStdout, scr_attr, vram_length_attr, vram_coord_attr, &num);
! 336: vram_length_attr = vram_last_length_attr = 0;
! 337: }
! 338: }
! 339:
! 340: void vram_flush()
! 341: {
! 342: if(vram_length_char != 0 || vram_length_attr != 0) {
! 343: EnterCriticalSection(&vram_crit_sect);
! 344: vram_flush_char();
! 345: vram_flush_attr();
! 346: LeaveCriticalSection(&vram_crit_sect);
! 347: }
! 348: }
! 349: #endif
! 350:
! 351: void write_text_vram_char(offs_t offset, UINT8 data)
1.1.1.8 root 352: {
1.1.1.14! root 353: #ifdef USE_THREAD
! 354: static offs_t first_offset_char, last_offset_char;
! 355:
! 356: if(vram_length_char != 0) {
! 357: if(offset <= last_offset_char && offset >= first_offset_char) {
! 358: scr_char[(offset - first_offset_char) >> 1] = data;
! 359: return;
! 360: }
! 361: if(offset != last_offset_char + 2) {
! 362: vram_flush_char();
! 363: }
! 364: }
! 365: if(vram_length_char == 0) {
! 366: first_offset_char = offset;
! 367: vram_coord_char.X = (offset >> 1) % scr_width;
! 368: vram_coord_char.Y = (offset >> 1) / scr_width + scr_top;
! 369: }
! 370: scr_char[vram_length_char++] = data;
! 371: last_offset_char = offset;
! 372: #else
1.1.1.8 root 373: COORD co;
374: DWORD num;
375:
1.1.1.14! root 376: co.X = (offset >> 1) % scr_width;
! 377: co.Y = (offset >> 1) / scr_width;
! 378: scr_char[0] = data;
! 379: WriteConsoleOutputCharacter(hStdout, scr_char, 1, co, &num);
! 380: #endif
! 381: }
! 382:
! 383: void write_text_vram_attr(offs_t offset, UINT8 data)
! 384: {
! 385: #ifdef USE_THREAD
! 386: static offs_t first_offset_attr, last_offset_attr;
! 387:
! 388: if(vram_length_attr != 0) {
! 389: if(offset <= last_offset_attr && offset >= first_offset_attr) {
! 390: scr_attr[(offset - first_offset_attr) >> 1] = data;
! 391: return;
! 392: }
! 393: if(offset != last_offset_attr + 2) {
! 394: vram_flush_attr();
! 395: }
! 396: }
! 397: if(vram_length_attr == 0) {
! 398: first_offset_attr = offset;
! 399: vram_coord_attr.X = (offset >> 1) % scr_width;
! 400: vram_coord_attr.Y = (offset >> 1) / scr_width + scr_top;
! 401: }
! 402: scr_attr[vram_length_attr++] = data;
! 403: last_offset_attr = offset;
! 404: #else
! 405: COORD co;
! 406: DWORD num;
1.1.1.8 root 407:
1.1.1.14! root 408: co.X = (offset >> 1) % scr_width;
! 409: co.Y = (offset >> 1) / scr_width;
! 410: scr_attr[0] = data;
! 411: WriteConsoleOutputAttribute(hStdout, scr_attr, 1, co, &num);
! 412: #endif
! 413: }
! 414:
! 415: void write_text_vram_byte(offs_t offset, UINT8 data)
! 416: {
! 417: EnterCriticalSection(&vram_crit_sect);
1.1.1.8 root 418: if(offset & 1) {
1.1.1.14! root 419: write_text_vram_attr(offset, data);
1.1.1.8 root 420: } else {
1.1.1.14! root 421: write_text_vram_char(offset, data);
1.1.1.8 root 422: }
1.1.1.14! root 423: LeaveCriticalSection(&vram_crit_sect);
1.1.1.8 root 424: }
425:
426: void write_text_vram_word(offs_t offset, UINT16 data)
427: {
1.1.1.14! root 428: EnterCriticalSection(&vram_crit_sect);
1.1.1.8 root 429: if(offset & 1) {
1.1.1.14! root 430: write_text_vram_attr(offset , (data ) & 0xff);
! 431: write_text_vram_char(offset + 1, (data >> 8) & 0xff);
1.1.1.8 root 432: } else {
1.1.1.14! root 433: write_text_vram_char(offset , (data ) & 0xff);
! 434: write_text_vram_attr(offset + 1, (data >> 8) & 0xff);
1.1.1.8 root 435: }
1.1.1.14! root 436: LeaveCriticalSection(&vram_crit_sect);
1.1.1.8 root 437: }
438:
439: void write_text_vram_dword(offs_t offset, UINT32 data)
440: {
1.1.1.14! root 441: EnterCriticalSection(&vram_crit_sect);
1.1.1.8 root 442: if(offset & 1) {
1.1.1.14! root 443: write_text_vram_attr(offset , (data ) & 0xff);
! 444: write_text_vram_char(offset + 1, (data >> 8) & 0xff);
! 445: write_text_vram_attr(offset + 2, (data >> 16) & 0xff);
! 446: write_text_vram_char(offset + 3, (data >> 24) & 0xff);
! 447: } else {
! 448: write_text_vram_char(offset , (data ) & 0xff);
! 449: write_text_vram_attr(offset + 1, (data >> 8) & 0xff);
! 450: write_text_vram_char(offset + 2, (data >> 16) & 0xff);
! 451: write_text_vram_attr(offset + 3, (data >> 24) & 0xff);
1.1.1.8 root 452: }
1.1.1.14! root 453: LeaveCriticalSection(&vram_crit_sect);
1.1.1.8 root 454: }
455:
1.1 root 456: void write_byte(offs_t byteaddress, UINT8 data)
457: {
1.1.1.8 root 458: if(byteaddress < MEMORY_END) {
1.1.1.3 root 459: mem[byteaddress] = data;
1.1.1.8 root 460: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14! root 461: if(!restore_console_on_exit) {
! 462: change_console_size(scr_width, scr_height);
1.1.1.12 root 463: restore_console_on_exit = true;
464: }
1.1.1.8 root 465: write_text_vram_byte(byteaddress - text_vram_top_address, data);
466: mem[byteaddress] = data;
467: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
468: if(int_10h_feh_called && !int_10h_ffh_called) {
469: write_text_vram_byte(byteaddress - shadow_buffer_top_address, data);
1.1 root 470: }
471: mem[byteaddress] = data;
1.1.1.4 root 472: #if defined(HAS_I386)
1.1.1.3 root 473: } else if(byteaddress < MAX_MEM) {
1.1.1.4 root 474: #else
475: } else {
476: #endif
1.1.1.3 root 477: mem[byteaddress] = data;
1.1 root 478: }
479: }
480:
481: void write_word(offs_t byteaddress, UINT16 data)
482: {
1.1.1.8 root 483: if(byteaddress < MEMORY_END) {
1.1.1.14! root 484: if(byteaddress == 0x450 + mem[0x462] * 2) {
! 485: COORD co;
! 486: co.X = data & 0xff;
! 487: co.Y = (data >> 8) + scr_top;
! 488: SetConsoleCursorPosition(hStdout, co);
! 489: }
1.1.1.3 root 490: *(UINT16 *)(mem + byteaddress) = data;
1.1.1.8 root 491: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14! root 492: if(!restore_console_on_exit) {
! 493: change_console_size(scr_width, scr_height);
1.1.1.12 root 494: restore_console_on_exit = true;
495: }
1.1.1.8 root 496: write_text_vram_word(byteaddress - text_vram_top_address, data);
497: *(UINT16 *)(mem + byteaddress) = data;
498: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
499: if(int_10h_feh_called && !int_10h_ffh_called) {
500: write_text_vram_word(byteaddress - shadow_buffer_top_address, data);
1.1 root 501: }
502: *(UINT16 *)(mem + byteaddress) = data;
1.1.1.4 root 503: #if defined(HAS_I386)
1.1.1.3 root 504: } else if(byteaddress < MAX_MEM - 1) {
1.1.1.4 root 505: #else
506: } else {
507: #endif
1.1.1.3 root 508: *(UINT16 *)(mem + byteaddress) = data;
1.1 root 509: }
510: }
511:
512: void write_dword(offs_t byteaddress, UINT32 data)
513: {
1.1.1.8 root 514: if(byteaddress < MEMORY_END) {
1.1.1.3 root 515: *(UINT32 *)(mem + byteaddress) = data;
1.1.1.8 root 516: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14! root 517: if(!restore_console_on_exit) {
! 518: change_console_size(scr_width, scr_height);
1.1.1.12 root 519: restore_console_on_exit = true;
520: }
1.1.1.8 root 521: write_text_vram_dword(byteaddress - text_vram_top_address, data);
522: *(UINT32 *)(mem + byteaddress) = data;
523: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
524: if(int_10h_feh_called && !int_10h_ffh_called) {
525: write_text_vram_dword(byteaddress - shadow_buffer_top_address, data);
1.1 root 526: }
527: *(UINT32 *)(mem + byteaddress) = data;
1.1.1.4 root 528: #if defined(HAS_I386)
1.1.1.3 root 529: } else if(byteaddress < MAX_MEM - 3) {
1.1.1.4 root 530: #else
531: } else {
532: #endif
1.1.1.3 root 533: *(UINT32 *)(mem + byteaddress) = data;
1.1 root 534: }
535: }
536:
537: #define read_decrypted_byte read_byte
538: #define read_decrypted_word read_word
539: #define read_decrypted_dword read_dword
540:
1.1.1.3 root 541: #define read_raw_byte read_byte
542: #define write_raw_byte write_byte
543:
544: #define read_word_unaligned read_word
545: #define write_word_unaligned write_word
546:
547: #define read_io_word_unaligned read_io_word
548: #define write_io_word_unaligned write_io_word
549:
1.1 root 550: UINT8 read_io_byte(offs_t byteaddress);
551: UINT16 read_io_word(offs_t byteaddress);
552: UINT32 read_io_dword(offs_t byteaddress);
553:
554: void write_io_byte(offs_t byteaddress, UINT8 data);
555: void write_io_word(offs_t byteaddress, UINT16 data);
556: void write_io_dword(offs_t byteaddress, UINT32 data);
557:
558: /*****************************************************************************/
559: /* src/osd/osdcomm.h */
560:
561: /* Highly useful macro for compile-time knowledge of an array size */
562: #define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0]))
563:
1.1.1.3 root 564: #if defined(HAS_I386)
1.1.1.10 root 565: static CPU_TRANSLATE(i386);
566: #include "mame/lib/softfloat/softfloat.c"
567: #include "mame/emu/cpu/i386/i386.c"
1.1.1.12 root 568: #include "mame/emu/cpu/vtlb.c"
1.1.1.3 root 569: #elif defined(HAS_I286)
1.1.1.10 root 570: #include "mame/emu/cpu/i86/i286.c"
1.1.1.3 root 571: #else
1.1.1.10 root 572: #include "mame/emu/cpu/i86/i86.c"
1.1.1.3 root 573: #endif
1.1 root 574: #ifdef SUPPORT_DISASSEMBLER
1.1.1.10 root 575: #include "mame/emu/cpu/i386/i386dasm.c"
1.1.1.3 root 576: bool dasm = false;
1.1 root 577: #endif
578:
1.1.1.3 root 579: #if defined(HAS_I386)
580: #define SREG(x) m_sreg[x].selector
581: #define SREG_BASE(x) m_sreg[x].base
582:
583: int cpu_type, cpu_step;
584: #else
585: #define REG8(x) m_regs.b[x]
586: #define REG16(x) m_regs.w[x]
587: #define SREG(x) m_sregs[x]
588: #define SREG_BASE(x) m_base[x]
589: #define m_CF m_CarryVal
590: #define m_a20_mask AMASK
591: #define i386_load_segment_descriptor(x) m_base[x] = SegBase(x)
592: #if defined(HAS_I286)
593: #define i386_set_a20_line(x) i80286_set_a20_line(x)
594: #else
595: #define i386_set_a20_line(x)
596: #endif
597: #define i386_set_irq_line(x, y) set_irq_line(x, y)
598: #endif
1.1 root 599:
600: void i386_jmp_far(UINT16 selector, UINT32 address)
601: {
1.1.1.3 root 602: #if defined(HAS_I386)
1.1 root 603: if(PROTECTED_MODE && !V8086_MODE) {
1.1.1.3 root 604: i386_protected_mode_jump(selector, address, 1, m_operand_size);
1.1 root 605: } else {
1.1.1.3 root 606: SREG(CS) = selector;
607: m_performed_intersegment_jump = 1;
608: i386_load_segment_descriptor(CS);
609: m_eip = address;
610: CHANGE_PC(m_eip);
1.1 root 611: }
1.1.1.3 root 612: #elif defined(HAS_I286)
613: i80286_code_descriptor(selector, address, 1);
614: #else
615: SREG(CS) = selector;
616: i386_load_segment_descriptor(CS);
617: m_pc = (SREG_BASE(CS) + address) & m_a20_mask;
618: #endif
1.1 root 619: }
620:
621: /* ----------------------------------------------------------------------------
622: main
623: ---------------------------------------------------------------------------- */
624:
1.1.1.10 root 625: bool is_started_from_command_prompt()
626: {
1.1.1.14! root 627: DWORD pl;
! 628: return(GetConsoleProcessList(&pl, 1) > 1);
! 629: }
! 630:
! 631: BOOL is_greater_windows_version(DWORD dwMajorVersion, DWORD dwMinorVersion, WORD wServicePackMajor, WORD wServicePackMinor)
! 632: {
! 633: //https://msdn.microsoft.com/en-us/library/windows/desktop/ms725491(v=vs.85).aspx
! 634: OSVERSIONINFOEX osvi;
! 635: DWORDLONG dwlConditionMask = 0;
! 636: int op = VER_GREATER_EQUAL;
! 637:
! 638: // Initialize the OSVERSIONINFOEX structure.
! 639: ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
! 640: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
! 641: osvi.dwMajorVersion = dwMajorVersion;
! 642: osvi.dwMinorVersion = dwMinorVersion;
! 643: osvi.wServicePackMajor = wServicePackMajor;
! 644: osvi.wServicePackMinor = wServicePackMinor;
! 645:
! 646: // Initialize the condition mask.
! 647: VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, op );
! 648: VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, op );
! 649: VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, op );
! 650: VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMINOR, op );
! 651:
! 652: // Perform the test.
! 653: return VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, dwlConditionMask);
! 654: }
! 655:
! 656: BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
! 657: {
! 658: if(dwCtrlType == CTRL_BREAK_EVENT || dwCtrlType == CTRL_C_EVENT) {
! 659: m_halted = 1;
! 660: return TRUE;
! 661: }
! 662: return FALSE;
! 663: }
! 664:
! 665: #ifdef USE_THREAD
! 666: DWORD WINAPI vram_thread(LPVOID)
! 667: {
! 668: while(!m_halted) {
! 669: EnterCriticalSection(&vram_crit_sect);
! 670: if(vram_length_char != 0 && vram_length_char == vram_last_length_char) {
! 671: vram_flush_char();
! 672: }
! 673: if(vram_length_attr != 0 && vram_length_attr == vram_last_length_attr) {
! 674: vram_flush_attr();
! 675: }
! 676: vram_last_length_char = vram_length_char;
! 677: vram_last_length_attr = vram_length_attr;
! 678: LeaveCriticalSection(&vram_crit_sect);
! 679: // this is about half the maximum keyboard repeat rate - any
! 680: // lower tends to be jerky, any higher misses updates
! 681: Sleep(15);
1.1.1.10 root 682: }
1.1.1.14! root 683: return 0;
1.1.1.10 root 684: }
1.1.1.14! root 685: #endif
1.1.1.10 root 686:
1.1.1.9 root 687: #define IS_NUMERIC(c) ((c) >= '0' && (c) <= '9')
688:
1.1 root 689: int main(int argc, char *argv[], char *envp[])
690: {
1.1.1.9 root 691: int arg_offset = 0;
692: int standard_env = 0;
1.1.1.14! root 693: int buf_width = 0, buf_height = 0;
1.1.1.12 root 694: BOOL bSuccess;
1.1 root 695:
1.1.1.9 root 696: for(int i = 1; i < argc; i++) {
697: if(_strnicmp(argv[i], "-e", 2) == 0) {
698: standard_env = 1;
699: arg_offset++;
1.1.1.14! root 700: } else if(_strnicmp(argv[i], "-i", 2) == 0) {
! 701: ignore_illegal_insn = true;
! 702: arg_offset++;
! 703: } else if(_strnicmp(argv[i], "-m", 2) == 0) {
! 704: limit_max_memory = true;
! 705: arg_offset++;
! 706: } else if(_strnicmp(argv[i], "-d", 2) == 0) {
! 707: no_windows = true;
! 708: arg_offset++;
! 709: } else if(_strnicmp(argv[i], "-b", 2) == 0) {
! 710: stay_busy = true;
! 711: arg_offset++;
! 712: } else if(_strnicmp(argv[i], "-n", 2) == 0) {
! 713: buf_width = 80;
! 714: buf_height = 25;
! 715: sscanf(argv[1] + 2, "%hd,%hd", &buf_height, &buf_width);
! 716: arg_offset++;
1.1.1.9 root 717: } else if(_strnicmp(argv[i], "-v", 2) == 0) {
718: if(strlen(argv[i]) >= 6 && IS_NUMERIC(argv[i][2]) && argv[i][3] == '.' && IS_NUMERIC(argv[i][4]) && IS_NUMERIC(argv[i][5])) {
719: major_version = argv[i][2] - '0';
720: minor_version = (argv[i][4] - '0') * 10 + (argv[i][5] - '0');
721: }
722: arg_offset++;
723: } else {
724: break;
725: }
726: }
727:
728: if(argc < 2 + arg_offset) {
1.1 root 729: #ifdef _WIN64
1.1.1.14! root 730: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32-x64 console\n\n");
1.1 root 731: #else
1.1.1.14! root 732: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32 console\n\n");
1.1 root 733: #endif
1.1.1.14! root 734: fprintf(stderr, "Usage: MSDOS [-b] [-d] [-e] [-i] [-m] [-n[L[,C]]] [-vX.XX] (command file) [options]\n"
! 735: "\n"
! 736: "\t-b\tstay busy during keyboard polling\n"
! 737: "\t-d\tpretend running under straight DOS, not Windows\n"
! 738: "\t-e\tuse a reduced environment block\n"
! 739: "\t-i\tignore invalid instructions\n"
! 740: "\t-m\trestrict free memory to 0x7FFF paragraphs\n"
! 741: "\t-n\tcreate a new buffer (25 lines, 80 columns by default)\n"
! 742: "\t-v\tset the DOS version\n");
1.1.1.10 root 743:
744: if(!is_started_from_command_prompt()) {
745: fprintf(stderr, "\nStart this program from a command prompt!\n\nHit any key to quit...");
746: while(!_kbhit()) {
747: Sleep(10);
748: }
749: }
1.1 root 750: return(EXIT_FAILURE);
751: }
752:
1.1.1.14! root 753: is_vista_or_later = is_greater_windows_version(6, 0, 0, 0);
! 754:
1.1 root 755: CONSOLE_SCREEN_BUFFER_INFO csbi;
1.1.1.14! root 756: CONSOLE_CURSOR_INFO ci;
1.1 root 757: hStdin = GetStdHandle(STD_INPUT_HANDLE);
758: hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.12 root 759: bSuccess = GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14! root 760: GetConsoleCursorInfo(hStdout, &ci);
1.1 root 761:
1.1.1.14! root 762: for(int y = 0; y < SCR_BUF_WIDTH; y++) {
! 763: for(int x = 0; x < SCR_BUF_HEIGHT; x++) {
! 764: SCR_BUF(y,x).Char.AsciiChar = ' ';
! 765: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 766: }
767: }
1.1.1.12 root 768: if(bSuccess) {
769: scr_width = csbi.dwSize.X;
1.1.1.14! root 770: scr_height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
! 771:
! 772: // v-text shadow buffer size is 0x7ff0
! 773: if((scr_width > SCR_BUF_WIDTH) || (scr_height > SCR_BUF_HEIGHT) || (scr_width * scr_height * 2 > 0x7ff0) ||
! 774: (buf_width != 0 && buf_width != scr_width) || (buf_height != 0 && buf_height != scr_height)) {
! 775: scr_width = min(buf_width != 0 ? buf_width : scr_width, SCR_BUF_WIDTH);
! 776: scr_height = min(buf_height != 0 ? buf_height : scr_height, SCR_BUF_HEIGHT);
! 777: if(scr_width * scr_height * 2 > 0x7ff0) {
! 778: scr_width = 80;
! 779: scr_height = 25;
! 780: }
! 781: change_console_size(scr_width, scr_height);
! 782: restore_console_on_exit = true;
! 783: }
1.1.1.12 root 784: } else {
785: // for a proof (not a console)
786: scr_width = 80;
787: scr_height = 25;
788: }
1.1.1.14! root 789: scr_buf_size.X = scr_width;
! 790: scr_buf_size.Y = scr_height;
! 791: scr_buf_pos.X = scr_buf_pos.Y = 0;
! 792: scr_top = csbi.srWindow.Top;
1.1 root 793: cursor_moved = false;
794:
795: key_buf_char = new FIFO();
796: key_buf_scan = new FIFO();
797:
798: hardware_init();
799:
1.1.1.9 root 800: if(msdos_init(argc - (arg_offset + 1), argv + (arg_offset + 1), envp, standard_env)) {
1.1 root 801: retval = EXIT_FAILURE;
802: } else {
1.1.1.14! root 803: #if defined(_MSC_VER) && _MSC_VER >= 1400
! 804: _set_invalid_parameter_handler((_invalid_parameter_handler)ignore_invalid_parameters);
! 805: #endif
! 806: SetConsoleCtrlHandler(ctrl_handler, TRUE);
! 807:
1.1.1.8 root 808: TIMECAPS caps;
809: timeGetDevCaps(&caps, sizeof(TIMECAPS));
810: timeBeginPeriod(caps.wPeriodMin);
1.1.1.14! root 811:
! 812: #ifdef USE_THREAD
! 813: InitializeCriticalSection(&vram_crit_sect);
! 814: CloseHandle(CreateThread(NULL, 4096, vram_thread, NULL, 0, NULL));
! 815: #endif
1.1 root 816: hardware_run();
1.1.1.14! root 817: #ifdef USE_THREAD
! 818: vram_flush();
! 819: DeleteCriticalSection(&vram_crit_sect);
! 820: #endif
! 821:
1.1.1.12 root 822: if(bSuccess) {
823: if(restore_console_on_exit) {
1.1.1.14! root 824: // window can't be bigger than buffer,
! 825: // buffer can't be smaller than window,
! 826: // so make a tiny window,
! 827: // set the required buffer,
! 828: // then set the required window
! 829: SMALL_RECT rect;
! 830: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
! 831: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.12 root 832: SetConsoleScreenBufferSize(hStdout, csbi.dwSize);
1.1.1.14! root 833: SET_RECT(rect, 0, 0, csbi.srWindow.Right - csbi.srWindow.Left, csbi.srWindow.Bottom - csbi.srWindow.Top);
1.1.1.12 root 834: SetConsoleWindowInfo(hStdout, TRUE, &rect);
835: }
1.1.1.14! root 836: // hStdout (and all handles) will close in msdos_finish()...
! 837: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
! 838: SetConsoleCursorInfo(hStdout, &ci);
1.1.1.12 root 839: }
1.1 root 840: msdos_finish();
1.1.1.14! root 841:
1.1.1.8 root 842: timeEndPeriod(caps.wPeriodMin);
1.1.1.14! root 843: SetConsoleCtrlHandler(ctrl_handler, FALSE);
1.1 root 844: }
845:
1.1.1.10 root 846: hardware_finish();
847:
1.1 root 848: delete key_buf_char;
849: delete key_buf_scan;
850:
1.1.1.12 root 851: // SetConsoleTextAttribute(hStdout, csbi.wAttributes);
1.1 root 852:
853: return(retval);
854: }
855:
1.1.1.14! root 856: void change_console_size(int width, int height)
1.1.1.12 root 857: {
858: CONSOLE_SCREEN_BUFFER_INFO csbi;
859: SMALL_RECT rect;
860: COORD co;
861:
862: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14! root 863: if(csbi.srWindow.Top != 0 || csbi.dwCursorPosition.Y > height - 1) {
! 864: if(csbi.srWindow.Right - csbi.srWindow.Left + 1 == width && csbi.srWindow.Bottom - csbi.srWindow.Top + 1 == height) {
! 865: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &csbi.srWindow);
! 866: SET_RECT(rect, 0, 0, width - 1, height - 1);
! 867: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
! 868: } else if(csbi.dwCursorPosition.Y > height - 1) {
! 869: SET_RECT(rect, 0, csbi.dwCursorPosition.Y - (height - 1), width - 1, csbi.dwCursorPosition.Y);
! 870: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
! 871: SET_RECT(rect, 0, 0, width - 1, height - 1);
! 872: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1.1.12 root 873: }
874: }
1.1.1.14! root 875: if(csbi.dwCursorPosition.Y > height - 1) {
1.1.1.12 root 876: co.X = csbi.dwCursorPosition.X;
1.1.1.14! root 877: co.Y = min(height - 1, csbi.dwCursorPosition.Y - csbi.srWindow.Top);
1.1.1.12 root 878: SetConsoleCursorPosition(hStdout, co);
879: cursor_moved = true;
880: }
1.1.1.14! root 881:
! 882: // window can't be bigger than buffer,
! 883: // buffer can't be smaller than window,
! 884: // so make a tiny window,
! 885: // set the required buffer,
! 886: // then set the required window
! 887: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
1.1.1.12 root 888: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.14! root 889: co.X = width;
! 890: co.Y = height;
1.1.1.12 root 891: SetConsoleScreenBufferSize(hStdout, co);
1.1.1.14! root 892: SET_RECT(rect, 0, 0, width - 1, height - 1);
! 893: SetConsoleWindowInfo(hStdout, TRUE, &rect);
! 894:
! 895: scr_width = scr_buf_size.X = width;
! 896: scr_height = scr_buf_size.Y = height;
! 897: scr_top = 0;
! 898:
! 899: clear_scr_buffer(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
! 900:
! 901: int regen = min(scr_width * scr_height * 2, 0x8000);
! 902: if(regen > 0x4000) {
! 903: regen = 0x8000;
! 904: vram_pages = 1;
! 905: } else if(regen > 0x2000) {
! 906: regen = 0x4000;
! 907: vram_pages = 2;
! 908: } else if(regen > 0x1000) {
! 909: regen = 0x2000;
! 910: vram_pages = 4;
! 911: } else {
! 912: regen = 0x1000;
! 913: vram_pages = 8;
! 914: }
! 915: VIDEO_REGEN = regen;
! 916: }
! 917:
! 918: void clear_scr_buffer(WORD attr)
! 919: {
! 920: for(int y = 0; y < scr_height; y++) {
! 921: for(int x = 0; x < scr_width; x++) {
! 922: SCR_BUF(y,x).Char.AsciiChar = ' ';
! 923: SCR_BUF(y,x).Attributes = attr;
! 924: }
! 925: }
1.1.1.12 root 926: }
927:
1.1 root 928: /* ----------------------------------------------------------------------------
929: MS-DOS virtual machine
930: ---------------------------------------------------------------------------- */
931:
1.1.1.14! root 932: bool update_key_buffer_tmp()
1.1 root 933: {
1.1.1.8 root 934: DWORD dwNumberOfEvents = 0;
1.1 root 935: DWORD dwRead;
936: INPUT_RECORD ir[16];
937:
1.1.1.8 root 938: if(GetNumberOfConsoleInputEvents(hStdin, &dwNumberOfEvents) && dwNumberOfEvents != 0) {
939: if(ReadConsoleInputA(hStdin, ir, 16, &dwRead)) {
940: for(int i = 0; i < dwRead; i++) {
941: if((ir[i].EventType & KEY_EVENT) && ir[i].Event.KeyEvent.bKeyDown) {
1.1.1.14! root 942: UINT8 chr = ir[i].Event.KeyEvent.uChar.AsciiChar;
! 943: UINT8 scn = ir[i].Event.KeyEvent.wVirtualScanCode & 0xff;
! 944: if(chr == 0) {
! 945: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
! 946: if(scn >= 0x3b && scn <= 0x44) {
! 947: scn += 0x68 - 0x3b; // F1 to F10
! 948: } else if(scn == 0x57 || scn == 0x58) {
! 949: scn += 0x8b - 0x57; // F11 & F12
! 950: } else if(scn >= 0x47 && scn <= 0x53) {
! 951: scn += 0x97 - 0x47; // edit/arrow clusters
! 952: } else if(scn == 0x35) {
! 953: scn = 0xa4; // keypad /
! 954: }
! 955: } else if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
! 956: if(scn == 0x07) {
! 957: chr = 0x1e; // Ctrl+^
! 958: } else if(scn == 0x0c) {
! 959: chr = 0x1f; // Ctrl+_
! 960: } else if(scn >= 0x35 && scn <= 0x58) {
! 961: static const UINT8 ctrl_map[] = {
! 962: 0x95, // keypad /
! 963: 0,
! 964: 0x96, // keypad *
! 965: 0, 0, 0,
! 966: 0x5e, // F1
! 967: 0x5f, // F2
! 968: 0x60, // F3
! 969: 0x61, // F4
! 970: 0x62, // F5
! 971: 0x63, // F6
! 972: 0x64, // F7
! 973: 0x65, // F8
! 974: 0x66, // F9
! 975: 0x67, // F10
! 976: 0,
! 977: 0,
! 978: 0x77, // Home
! 979: 0x8d, // Up
! 980: 0x84, // PgUp
! 981: 0x8e, // keypad -
! 982: 0x73, // Left
! 983: 0x8f, // keypad center
! 984: 0x74, // Right
! 985: 0x90, // keyapd +
! 986: 0x75, // End
! 987: 0x91, // Down
! 988: 0x76, // PgDn
! 989: 0x92, // Insert
! 990: 0x93, // Delete
! 991: 0, 0, 0,
! 992: 0x89, // F11
! 993: 0x8a, // F12
! 994: };
! 995: scn = ctrl_map[scn - 0x35];
! 996: }
! 997: } else if(ir[i].Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
! 998: if(scn >= 0x3b && scn <= 0x44) {
! 999: scn += 0x54 - 0x3b; // F1 to F10
! 1000: } else if(scn == 0x57 || scn == 0x58) {
! 1001: scn += 0x87 - 0x57; // F11 & F12
! 1002: }
! 1003: } else if(scn == 0x57 || scn == 0x58) {
! 1004: scn += 0x85 - 0x57;
! 1005: }
! 1006: // ignore shift, ctrl, alt, win and menu keys
! 1007: if(scn != 0x1d && scn != 0x2a && scn != 0x36 && scn != 0x38 && (scn < 0x5b || scn > 0x5e)) {
! 1008: if(chr == 0) {
! 1009: key_buf_char->write(0x00);
! 1010: key_buf_scan->write(ir[i].Event.KeyEvent.dwControlKeyState & ENHANCED_KEY ? 0xe0 : 0x00);
! 1011: }
! 1012: key_buf_char->write(chr);
! 1013: key_buf_scan->write(scn);
1.1.1.8 root 1014: }
1015: } else {
1.1.1.14! root 1016: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
! 1017: chr = 0;
! 1018: if(scn >= 0x02 && scn <= 0x0e) {
! 1019: scn += 0x78 - 0x02; // 1 to 0 - =
! 1020: }
! 1021: }
! 1022: key_buf_char->write(chr);
! 1023: key_buf_scan->write(scn);
! 1024: }
! 1025: }
! 1026: }
! 1027: for(int i = dwRead; --i >= 0;) {
! 1028: if((ir[i].EventType & KEY_EVENT)) {
! 1029: kbd_data = ir[i].Event.KeyEvent.wVirtualScanCode & 0x7f;
! 1030: if(!ir[i].Event.KeyEvent.bKeyDown) {
! 1031: kbd_data |= 0x80;
1.1 root 1032: }
1.1.1.14! root 1033: return true;
1.1 root 1034: }
1035: }
1036: }
1037: }
1.1.1.14! root 1038: return false;
1.1.1.8 root 1039: }
1040:
1.1.1.14! root 1041: bool update_key_buffer()
1.1.1.8 root 1042: {
1043: int prev_count = key_buf_char->count();
1.1.1.14! root 1044: bool input = update_key_buffer_tmp();
1.1.1.8 root 1045: key_input += key_buf_char->count() - prev_count;
1.1.1.14! root 1046: return(input || key_buf_char->count() != 0);
1.1 root 1047: }
1048:
1.1.1.8 root 1049: int check_key_input()
1050: {
1051: if(key_input == 0) {
1052: int prev_count = key_buf_char->count();
1.1.1.14! root 1053: bool input = update_key_buffer_tmp();
1.1.1.8 root 1054: key_input = key_buf_char->count() - prev_count;
1.1.1.14! root 1055: if(key_input == 0 && input) {
! 1056: key_input = 1;
! 1057: }
1.1.1.8 root 1058: }
1059: int val = key_input;
1060: key_input = 0;
1061: return(val);
1062: }
1063:
1.1 root 1064: // process info
1065:
1066: process_t *msdos_process_info_create(UINT16 psp_seg)
1067: {
1068: for(int i = 0; i < MAX_PROCESS; i++) {
1069: if(process[i].psp == 0 || process[i].psp == psp_seg) {
1070: memset(&process[i], 0, sizeof(process_t));
1071: process[i].psp = psp_seg;
1072: return(&process[i]);
1073: }
1074: }
1075: fatalerror("too many processes\n");
1076: return(NULL);
1077: }
1078:
1079: process_t *msdos_process_info_get(UINT16 psp_seg)
1080: {
1081: for(int i = 0; i < MAX_PROCESS; i++) {
1082: if(process[i].psp == psp_seg) {
1083: return(&process[i]);
1084: }
1085: }
1086: fatalerror("invalid psp address\n");
1087: return(NULL);
1088: }
1089:
1.1.1.13 root 1090: // dta info
1091:
1092: void msdos_dta_info_init()
1093: {
1.1.1.14! root 1094: for(int i = 0; i < MAX_DTAINFO; i++) {
1.1.1.13 root 1095: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
1096: }
1097: }
1098:
1099: dtainfo_t *msdos_dta_info_get(UINT16 psp_seg, UINT32 dta_laddr)
1100: {
1101: dtainfo_t *free_dta = NULL;
1.1.1.14! root 1102: for(int i = 0; i < MAX_DTAINFO; i++) {
! 1103: if(dtalist[i].find_handle == INVALID_HANDLE_VALUE) {
! 1104: if(free_dta == NULL) {
1.1.1.13 root 1105: free_dta = &dtalist[i];
1106: }
1.1.1.14! root 1107: } else if(dta_laddr < LFN_DTA_LADDR && dtalist[i].dta == dta_laddr) {
1.1.1.13 root 1108: return(&dtalist[i]);
1109: }
1110: }
1.1.1.14! root 1111: if(free_dta) {
1.1.1.13 root 1112: free_dta->psp = psp_seg;
1113: free_dta->dta = dta_laddr;
1114: return(free_dta);
1115: }
1116: fatalerror("too many dta\n");
1117: return(NULL);
1118: }
1119:
1120: void msdos_dta_info_free(UINT16 psp_seg)
1121: {
1.1.1.14! root 1122: for(int i = 0; i < MAX_DTAINFO; i++) {
! 1123: if(dtalist[i].psp == psp_seg && dtalist[i].find_handle != INVALID_HANDLE_VALUE) {
1.1.1.13 root 1124: FindClose(dtalist[i].find_handle);
1125: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
1126: }
1127: }
1128: }
1129:
1.1 root 1130: void msdos_cds_update(int drv)
1131: {
1132: cds_t *cds = (cds_t *)(mem + CDS_TOP);
1133:
1134: memset(mem + CDS_TOP, 0, CDS_SIZE);
1135: sprintf(cds->path_name, "%c:\\", 'A' + drv);
1136: cds->drive_attrib = 0x4000; // physical drive
1137: cds->physical_drive_number = drv;
1138: }
1139:
1140: // dbcs
1141:
1142: void msdos_dbcs_table_update()
1143: {
1144: UINT8 dbcs_data[DBCS_SIZE];
1145: memset(dbcs_data, 0, sizeof(dbcs_data));
1146:
1147: CPINFO info;
1148: GetCPInfo(active_code_page, &info);
1149:
1150: if(info.MaxCharSize != 1) {
1151: for(int i = 0;; i += 2) {
1152: UINT8 lo = info.LeadByte[i + 0];
1153: UINT8 hi = info.LeadByte[i + 1];
1154: dbcs_data[2 + i + 0] = lo;
1155: dbcs_data[2 + i + 1] = hi;
1156: if(lo == 0 && hi == 0) {
1157: dbcs_data[0] = i + 2;
1158: break;
1159: }
1160: }
1161: } else {
1162: dbcs_data[0] = 2; // ???
1163: }
1164: memcpy(mem + DBCS_TOP, dbcs_data, sizeof(dbcs_data));
1165: }
1166:
1167: void msdos_dbcs_table_init()
1168: {
1169: system_code_page = active_code_page = _getmbcp();
1170: msdos_dbcs_table_update();
1171: }
1172:
1173: void msdos_dbcs_table_finish()
1174: {
1175: if(active_code_page != system_code_page) {
1176: _setmbcp(system_code_page);
1177: }
1178: }
1179:
1180: int msdos_lead_byte_check(UINT8 code)
1181: {
1182: UINT8 *dbcs_table = mem + DBCS_TABLE;
1183:
1184: for(int i = 0;; i += 2) {
1185: UINT8 lo = dbcs_table[i + 0];
1186: UINT8 hi = dbcs_table[i + 1];
1187: if(lo == 0 && hi == 0) {
1188: break;
1189: }
1190: if(lo <= code && code <= hi) {
1191: return(1);
1192: }
1193: }
1194: return(0);
1195: }
1196:
1197: // file control
1198:
1.1.1.14! root 1199: char *msdos_remove_double_quote(char *path)
! 1200: {
! 1201: static char tmp[MAX_PATH];
! 1202:
! 1203: memset(tmp, 0, sizeof(tmp));
! 1204: if(strlen(path) >= 2 && path[0] == '"' && path[strlen(path) - 1] == '"') {
! 1205: memcpy(tmp, path + 1, strlen(path) - 2);
! 1206: } else {
! 1207: strcpy(tmp, path);
! 1208: }
! 1209: return(tmp);
! 1210: }
! 1211:
! 1212: char *msdos_combine_path(char *dir, const char *file)
! 1213: {
! 1214: static char tmp[MAX_PATH];
! 1215: char *tmp_dir = msdos_remove_double_quote(dir);
! 1216:
! 1217: if(strlen(tmp_dir) == 0) {
! 1218: strcpy(tmp, file);
! 1219: } else if(tmp_dir[strlen(tmp_dir) - 1] == '\\') {
! 1220: sprintf(tmp, "%s%s", tmp_dir, file);
! 1221: } else {
! 1222: sprintf(tmp, "%s\\%s", tmp_dir, file);
! 1223: }
! 1224: return(tmp);
! 1225: }
! 1226:
1.1 root 1227: char *msdos_trimmed_path(char *path, int lfn)
1228: {
1229: static char tmp[MAX_PATH];
1230:
1231: if(lfn) {
1232: strcpy(tmp, path);
1233: } else {
1234: // remove space in the path
1235: char *src = path, *dst = tmp;
1236:
1237: while(*src != '\0') {
1238: if(msdos_lead_byte_check(*src)) {
1239: *dst++ = *src++;
1240: *dst++ = *src++;
1241: } else if(*src != ' ') {
1242: *dst++ = *src++;
1243: } else {
1244: src++; // skip space
1245: }
1246: }
1247: *dst = '\0';
1248: }
1.1.1.14! root 1249: if(_stricmp(tmp, "C:\\COMMAND.COM") == 0) {
! 1250: // redirect C:\COMMAND.COM to comspec_path
! 1251: strcpy(tmp, comspec_path);
! 1252: } else if(is_vista_or_later && _access(tmp, 0) != 0) {
! 1253: // redirect new files (without wildcards) in C:\ to %TEMP%, since C:\ is not usually writable
! 1254: static int root_drive_protected = -1;
! 1255: char temp[MAX_PATH], name[MAX_PATH], *name_temp = NULL;
! 1256: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
! 1257:
! 1258: if(GetFullPathName(tmp, MAX_PATH, temp, &name_temp) != 0 &&
! 1259: name_temp != NULL && strstr(name_temp, "?") == NULL && strstr(name_temp, "*") == NULL) {
! 1260: strcpy(name, name_temp);
! 1261: name_temp[0] = '\0';
! 1262:
! 1263: if((temp[0] == 'A' + dos_info->boot_drive - 1 || temp[0] == 'a' + dos_info->boot_drive - 1) &&
! 1264: (temp[1] == ':') && (temp[2] == '\\' || temp[2] == '/') && (temp[3] == '\0')) {
! 1265: if(root_drive_protected == -1) {
! 1266: FILE *fp = NULL;
! 1267:
! 1268: sprintf(temp, "%c:\\MS-DOS_Player.$$$", 'A' + dos_info->boot_drive - 1);
! 1269: root_drive_protected = 1;
! 1270: try {
! 1271: if((fp = fopen(temp, "w")) != NULL) {
! 1272: if(fprintf(fp, "TEST") == 4) {
! 1273: root_drive_protected = 0;
! 1274: }
! 1275: }
! 1276: } catch(...) {
! 1277: }
! 1278: if(fp != NULL) {
! 1279: fclose(fp);
! 1280: }
! 1281: if(_access(temp, 0) == 0) {
! 1282: remove(temp);
! 1283: }
! 1284: }
! 1285: if(root_drive_protected == 1) {
! 1286: if(GetEnvironmentVariable("TEMP", temp, MAX_PATH) != 0 ||
! 1287: GetEnvironmentVariable("TMP", temp, MAX_PATH) != 0) {
! 1288: strcpy(tmp, msdos_combine_path(temp, name));
! 1289: }
! 1290: }
! 1291: }
! 1292: }
! 1293: }
1.1 root 1294: return(tmp);
1295: }
1296:
1297: bool match(char *text, char *pattern)
1298: {
1299: //http://www.prefield.com/algorithm/string/wildcard.html
1.1.1.14! root 1300: switch(*pattern) {
1.1 root 1301: case '\0':
1302: return !*text;
1303: case '*':
1.1.1.14! root 1304: return match(text, pattern + 1) || (*text && match(text + 1, pattern));
1.1 root 1305: case '?':
1306: return *text && match(text + 1, pattern + 1);
1307: default:
1308: return (*text == *pattern) && match(text + 1, pattern + 1);
1309: }
1310: }
1311:
1312: bool msdos_match_volume_label(char *path, char *volume)
1313: {
1314: char *p;
1315:
1.1.1.14! root 1316: if(!*volume) {
! 1317: return false;
! 1318: } else if((p = my_strchr(path, ':')) != NULL) {
1.1 root 1319: return msdos_match_volume_label(p + 1, volume);
1320: } else if((p = my_strchr(path, '\\')) != NULL) {
1321: return msdos_match_volume_label(p + 1, volume);
1322: } else if((p = my_strchr(path, '.')) != NULL) {
1.1.1.14! root 1323: char tmp[MAX_PATH];
! 1324: sprintf(tmp, "%.*s%s", (int)(p - path), path, p + 1);
! 1325: return match(volume, tmp);
1.1 root 1326: } else {
1327: return match(volume, path);
1328: }
1329: }
1330:
1331: char *msdos_fcb_path(fcb_t *fcb)
1332: {
1333: static char tmp[MAX_PATH];
1334: char name[9], ext[4];
1335:
1336: memset(name, 0, sizeof(name));
1337: memcpy(name, fcb->file_name, 8);
1338: strcpy(name, msdos_trimmed_path(name, 0));
1339:
1340: memset(ext, 0, sizeof(ext));
1341: memcpy(ext, fcb->file_name + 8, 3);
1342: strcpy(ext, msdos_trimmed_path(ext, 0));
1343:
1344: if(name[0] == '\0' || strcmp(name, "????????") == 0) {
1345: strcpy(name, "*");
1346: }
1347: if(ext[0] == '\0') {
1348: strcpy(tmp, name);
1349: } else {
1350: if(strcmp(ext, "???") == 0) {
1351: strcpy(ext, "*");
1352: }
1353: sprintf(tmp, "%s.%s", name, ext);
1354: }
1355: return(tmp);
1356: }
1357:
1358: void msdos_set_fcb_path(fcb_t *fcb, char *path)
1359: {
1360: char *ext = my_strchr(path, '.');
1361:
1362: memset(fcb->file_name, 0x20, 8 + 3);
1363: if(ext != NULL && path[0] != '.') {
1364: *ext = '\0';
1365: memcpy(fcb->file_name + 8, ext + 1, strlen(ext + 1));
1366: }
1367: memcpy(fcb->file_name, path, strlen(path));
1368: }
1369:
1370: char *msdos_short_path(char *path)
1371: {
1372: static char tmp[MAX_PATH];
1373:
1374: GetShortPathName(path, tmp, MAX_PATH);
1375: my_strupr(tmp);
1376: return(tmp);
1377: }
1378:
1.1.1.13 root 1379: char *msdos_short_name(WIN32_FIND_DATA *fd)
1380: {
1381: static char tmp[MAX_PATH];
1382:
1.1.1.14! root 1383: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 1384: strcpy(tmp, fd->cAlternateFileName);
1385: } else {
1386: strcpy(tmp, fd->cFileName);
1387: }
1388: my_strupr(tmp);
1389: return(tmp);
1390: }
1391:
1.1 root 1392: char *msdos_short_full_path(char *path)
1393: {
1394: static char tmp[MAX_PATH];
1395: char full[MAX_PATH], *name;
1396:
1.1.1.14! root 1397: // Full works with non-existent files, but Short does not
1.1 root 1398: GetFullPathName(path, MAX_PATH, full, &name);
1.1.1.14! root 1399: *tmp = '\0';
! 1400: if(GetShortPathName(full, tmp, MAX_PATH) == 0 && name > path) {
! 1401: name[-1] = '\0';
! 1402: DWORD len = GetShortPathName(full, tmp, MAX_PATH);
! 1403: if(len == 0) {
! 1404: strcpy(tmp, full);
! 1405: } else {
! 1406: tmp[len++] = '\\';
! 1407: strcpy(tmp + len, name);
! 1408: }
! 1409: }
1.1 root 1410: my_strupr(tmp);
1411: return(tmp);
1412: }
1413:
1414: char *msdos_short_full_dir(char *path)
1415: {
1416: static char tmp[MAX_PATH];
1417: char full[MAX_PATH], *name;
1418:
1419: GetFullPathName(path, MAX_PATH, full, &name);
1420: name[-1] = '\0';
1421: GetShortPathName(full, tmp, MAX_PATH);
1422: my_strupr(tmp);
1423: return(tmp);
1424: }
1425:
1426: char *msdos_local_file_path(char *path, int lfn)
1427: {
1428: char *trimmed = msdos_trimmed_path(path, lfn);
1.1.1.14! root 1429: #if 0
! 1430: // I have forgotten the reason of this routine... :-(
1.1 root 1431: if(_access(trimmed, 0) != 0) {
1432: process_t *process = msdos_process_info_get(current_psp);
1433: static char tmp[MAX_PATH];
1434:
1435: sprintf(tmp, "%s\\%s", process->module_dir, trimmed);
1436: if(_access(tmp, 0) == 0) {
1437: return(tmp);
1438: }
1439: }
1.1.1.14! root 1440: #endif
1.1 root 1441: return(trimmed);
1442: }
1443:
1.1.1.11 root 1444: bool msdos_is_con_path(char *path)
1445: {
1446: char full[MAX_PATH], *name;
1447:
1448: GetFullPathName(path, MAX_PATH, full, &name);
1449: return(_stricmp(full, "\\\\.\\CON") == 0);
1450: }
1451:
1.1.1.14! root 1452: bool msdos_is_nul_path(char *path)
1.1.1.8 root 1453: {
1.1.1.14! root 1454: char full[MAX_PATH], *name;
1.1.1.8 root 1455:
1.1.1.14! root 1456: GetFullPathName(path, MAX_PATH, full, &name);
! 1457: return(_stricmp(full, "\\\\.\\NUL") == 0);
1.1.1.8 root 1458: }
1459:
1.1.1.9 root 1460: char *msdos_search_command_com(char *command_path, char *env_path)
1461: {
1462: static char tmp[MAX_PATH];
1463: char path[MAX_PATH], *file_name;
1464:
1465: if(GetFullPathName(command_path, MAX_PATH, tmp, &file_name) != 0) {
1466: sprintf(file_name, "COMMAND.COM");
1467: if(_access(tmp, 0) == 0) {
1468: return(tmp);
1469: }
1470: }
1471: if(GetModuleFileName(NULL, path, MAX_PATH) != 0 && GetFullPathName(path, MAX_PATH, tmp, &file_name) != 0) {
1472: sprintf(file_name, "COMMAND.COM");
1473: if(_access(tmp, 0) == 0) {
1474: return(tmp);
1475: }
1476: }
1477: if(GetFullPathName("COMMAND.COM", MAX_PATH, tmp, &file_name) != 0) {
1478: if(_access(tmp, 0) == 0) {
1479: return(tmp);
1480: }
1481: }
1482: char *token = my_strtok(env_path, ";");
1483: while(token != NULL) {
1.1.1.14! root 1484: if(strlen(token) != 0 && token[0] != '%') {
1.1.1.9 root 1485: strcpy(tmp, msdos_combine_path(token, "COMMAND.COM"));
1486: if(_access(tmp, 0) == 0) {
1487: return(tmp);
1488: }
1489: }
1490: token = my_strtok(NULL, ";");
1491: }
1492: return(NULL);
1493: }
1494:
1.1.1.14! root 1495: int msdos_drive_number(const char *path)
1.1 root 1496: {
1497: char tmp[MAX_PATH], *name;
1498:
1499: GetFullPathName(path, MAX_PATH, tmp, &name);
1500: if(tmp[0] >= 'a' && tmp[0] <= 'z') {
1501: return(tmp[0] - 'a');
1502: } else {
1503: return(tmp[0] - 'A');
1504: }
1505: }
1506:
1507: char *msdos_volume_label(char *path)
1508: {
1509: static char tmp[MAX_PATH];
1510: char volume[] = "A:\\";
1511:
1512: if(path[1] == ':') {
1513: volume[0] = path[0];
1514: } else {
1515: volume[0] = 'A' + _getdrive() - 1;
1516: }
1517: if(!GetVolumeInformation(volume, tmp, MAX_PATH, NULL, NULL, NULL, NULL, 0)) {
1518: memset(tmp, 0, sizeof(tmp));
1519: }
1520: return(tmp);
1521: }
1522:
1523: char *msdos_short_volume_label(char *label)
1524: {
1525: static char tmp[(8 + 1 + 3) + 1];
1526: char *src = label;
1527: int remain = strlen(label);
1528: char *dst_n = tmp;
1529: char *dst_e = tmp + 9;
1530:
1531: strcpy(tmp, " . ");
1532: for(int i = 0; i < 8 && remain > 0; i++) {
1533: if(msdos_lead_byte_check(*src)) {
1534: if(++i == 8) {
1535: break;
1536: }
1537: *dst_n++ = *src++;
1538: remain--;
1539: }
1540: *dst_n++ = *src++;
1541: remain--;
1542: }
1543: if(remain > 0) {
1544: for(int i = 0; i < 3 && remain > 0; i++) {
1545: if(msdos_lead_byte_check(*src)) {
1546: if(++i == 3) {
1547: break;
1548: }
1549: *dst_e++ = *src++;
1550: remain--;
1551: }
1552: *dst_e++ = *src++;
1553: remain--;
1554: }
1555: *dst_e = '\0';
1556: } else {
1557: *dst_n = '\0';
1558: }
1559: my_strupr(tmp);
1560: return(tmp);
1561: }
1562:
1.1.1.13 root 1563: errno_t msdos_maperr(unsigned long oserrno)
1564: {
1565: _doserrno = oserrno;
1.1.1.14! root 1566: switch(oserrno) {
1.1.1.13 root 1567: case ERROR_FILE_NOT_FOUND: // 2
1568: case ERROR_PATH_NOT_FOUND: // 3
1569: case ERROR_INVALID_DRIVE: // 15
1570: case ERROR_NO_MORE_FILES: // 18
1571: case ERROR_BAD_NETPATH: // 53
1572: case ERROR_BAD_NET_NAME: // 67
1573: case ERROR_BAD_PATHNAME: // 161
1574: case ERROR_FILENAME_EXCED_RANGE: // 206
1575: return ENOENT;
1576: case ERROR_TOO_MANY_OPEN_FILES: // 4
1577: return EMFILE;
1578: case ERROR_ACCESS_DENIED: // 5
1579: case ERROR_CURRENT_DIRECTORY: // 16
1580: case ERROR_NETWORK_ACCESS_DENIED: // 65
1581: case ERROR_CANNOT_MAKE: // 82
1582: case ERROR_FAIL_I24: // 83
1583: case ERROR_DRIVE_LOCKED: // 108
1584: case ERROR_SEEK_ON_DEVICE: // 132
1585: case ERROR_NOT_LOCKED: // 158
1586: case ERROR_LOCK_FAILED: // 167
1587: return EACCES;
1588: case ERROR_INVALID_HANDLE: // 6
1589: case ERROR_INVALID_TARGET_HANDLE: // 114
1590: case ERROR_DIRECT_ACCESS_HANDLE: // 130
1591: return EBADF;
1592: case ERROR_ARENA_TRASHED: // 7
1593: case ERROR_NOT_ENOUGH_MEMORY: // 8
1594: case ERROR_INVALID_BLOCK: // 9
1595: case ERROR_NOT_ENOUGH_QUOTA: // 1816
1596: return ENOMEM;
1597: case ERROR_BAD_ENVIRONMENT: // 10
1598: return E2BIG;
1599: case ERROR_BAD_FORMAT: // 11
1600: return ENOEXEC;
1601: case ERROR_NOT_SAME_DEVICE: // 17
1602: return EXDEV;
1603: case ERROR_FILE_EXISTS: // 80
1604: case ERROR_ALREADY_EXISTS: // 183
1605: return EEXIST;
1606: case ERROR_NO_PROC_SLOTS: // 89
1607: case ERROR_MAX_THRDS_REACHED: // 164
1608: case ERROR_NESTING_NOT_ALLOWED: // 215
1609: return EAGAIN;
1610: case ERROR_BROKEN_PIPE: // 109
1611: return EPIPE;
1612: case ERROR_DISK_FULL: // 112
1613: return ENOSPC;
1614: case ERROR_WAIT_NO_CHILDREN: // 128
1615: case ERROR_CHILD_NOT_COMPLETE: // 129
1616: return ECHILD;
1617: case ERROR_DIR_NOT_EMPTY: // 145
1618: return ENOTEMPTY;
1619: }
1.1.1.14! root 1620: if(oserrno >= ERROR_WRITE_PROTECT /* 19 */ &&
1.1.1.13 root 1621: oserrno <= ERROR_SHARING_BUFFER_EXCEEDED /* 36 */) {
1622: return EACCES;
1623: }
1.1.1.14! root 1624: if(oserrno >= ERROR_INVALID_STARTING_CODESEG /* 188 */ &&
1.1.1.13 root 1625: oserrno <= ERROR_INFLOOP_IN_RELOC_CHAIN /* 202 */) {
1626: return ENOEXEC;
1627: }
1628: return EINVAL;
1629: }
1630:
1631: int msdos_open(const char *filename, int oflag)
1632: {
1.1.1.14! root 1633: if((oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) != _O_RDONLY) {
1.1.1.13 root 1634: return _open(filename, oflag);
1635: }
1.1.1.14! root 1636:
! 1637: SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, !(oflag & _O_NOINHERIT) };
1.1.1.13 root 1638: DWORD disposition;
1.1.1.14! root 1639: switch(oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
! 1640: default:
1.1.1.13 root 1641: case _O_EXCL:
1642: disposition = OPEN_EXISTING;
1643: break;
1644: case _O_CREAT:
1645: disposition = OPEN_ALWAYS;
1646: break;
1647: case _O_CREAT | _O_EXCL:
1648: case _O_CREAT | _O_TRUNC | _O_EXCL:
1649: disposition = CREATE_NEW;
1650: break;
1651: case _O_TRUNC:
1652: case _O_TRUNC | _O_EXCL:
1653: disposition = TRUNCATE_EXISTING;
1654: break;
1655: case _O_CREAT | _O_TRUNC:
1656: disposition = CREATE_ALWAYS;
1657: break;
1658: }
1.1.1.14! root 1659:
1.1.1.13 root 1660: HANDLE h = CreateFile(filename, GENERIC_READ | FILE_WRITE_ATTRIBUTES,
1661: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
1662: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14! root 1663: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 1664: // FILE_WRITE_ATTRIBUTES may not be granted for standard users.
1665: // Retry without FILE_WRITE_ATTRIBUTES.
1666: h = CreateFile(filename, GENERIC_READ,
1667: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
1668: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14! root 1669: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 1670: errno = msdos_maperr(GetLastError());
1671: return -1;
1672: }
1673: }
1.1.1.14! root 1674:
1.1.1.13 root 1675: int fd = _open_osfhandle((intptr_t) h, oflag);
1.1.1.14! root 1676: if(fd == -1) {
1.1.1.13 root 1677: CloseHandle(h);
1678: }
1679: return fd;
1680: }
1681:
1.1.1.14! root 1682: void msdos_file_handler_open(int fd, const char *path, int atty, int mode, UINT16 info, UINT16 psp_seg)
1.1 root 1683: {
1684: static int id = 0;
1685: char full[MAX_PATH], *name;
1686:
1687: if(psp_seg && fd < 20) {
1688: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
1689: psp->file_table[fd] = fd;
1690: }
1691: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1692: strcpy(file_handler[fd].path, full);
1693: } else {
1694: strcpy(file_handler[fd].path, path);
1695: }
1.1.1.14! root 1696: // isatty makes no distinction between CON & NUL
! 1697: // GetFileSize fails on CON, succeeds on NUL
! 1698: if(atty && (info != 0x80d3 || GetFileSize((HANDLE)_get_osfhandle(fd), NULL) == 0)) {
! 1699: info = 0x8084;
! 1700: atty = 0;
! 1701: } else if(!atty && info == 0x80d3) {
! 1702: info = msdos_drive_number(".");
! 1703: }
1.1 root 1704: file_handler[fd].valid = 1;
1705: file_handler[fd].id = id++; // dummy id for int 21h ax=71a6h
1706: file_handler[fd].atty = atty;
1707: file_handler[fd].mode = mode;
1708: file_handler[fd].info = info;
1709: file_handler[fd].psp = psp_seg;
1710: }
1711:
1712: void msdos_file_handler_dup(int dst, int src, UINT16 psp_seg)
1713: {
1714: if(psp_seg && dst < 20) {
1715: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
1716: psp->file_table[dst] = dst;
1717: }
1718: strcpy(file_handler[dst].path, file_handler[src].path);
1719: file_handler[dst].valid = 1;
1720: file_handler[dst].id = file_handler[src].id;
1721: file_handler[dst].atty = file_handler[src].atty;
1722: file_handler[dst].mode = file_handler[src].mode;
1723: file_handler[dst].info = file_handler[src].info;
1724: file_handler[dst].psp = psp_seg;
1725: }
1726:
1727: void msdos_file_handler_close(int fd, UINT16 psp_seg)
1728: {
1729: if(psp_seg && fd < 20) {
1730: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
1731: psp->file_table[fd] = 0xff;
1732: }
1733: file_handler[fd].valid = 0;
1734: }
1735:
1.1.1.14! root 1736: inline int msdos_file_attribute_create(UINT16 new_attr)
1.1 root 1737: {
1.1.1.14! root 1738: return(new_attr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
! 1739: FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE |
! 1740: FILE_ATTRIBUTE_DIRECTORY));
1.1 root 1741: }
1742:
1743: // find file
1744:
1745: int msdos_find_file_check_attribute(int attribute, int allowed_mask, int required_mask)
1746: {
1747: if((allowed_mask & 0x08) && !(attribute & FILE_ATTRIBUTE_DIRECTORY)) {
1748: return(0); // search directory only !!!
1749: } else if(!(allowed_mask & 0x02) && (attribute & FILE_ATTRIBUTE_HIDDEN)) {
1750: return(0);
1751: } else if(!(allowed_mask & 0x04) && (attribute & FILE_ATTRIBUTE_SYSTEM)) {
1752: return(0);
1753: } else if(!(allowed_mask & 0x10) && (attribute & FILE_ATTRIBUTE_DIRECTORY)) {
1754: return(0);
1755: } else if((attribute & required_mask) != required_mask) {
1756: return(0);
1757: } else {
1758: return(1);
1759: }
1760: }
1761:
1.1.1.13 root 1762: int msdos_find_file_has_8dot3name(WIN32_FIND_DATA *fd)
1763: {
1.1.1.14! root 1764: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 1765: return 1;
1766: }
1767: size_t len = strlen(fd->cFileName);
1.1.1.14! root 1768: if(len > 12) {
1.1.1.13 root 1769: return 0;
1770: }
1771: const char *ext = strrchr(fd->cFileName, '.');
1.1.1.14! root 1772: if((ext ? ext - fd->cFileName : len) > 8) {
1.1.1.13 root 1773: return 0;
1774: }
1775: return 1;
1776: }
1777:
1.1 root 1778: void msdos_find_file_conv_local_time(WIN32_FIND_DATA *fd)
1779: {
1780: FILETIME local;
1781:
1782: FileTimeToLocalFileTime(&fd->ftCreationTime, &local);
1783: fd->ftCreationTime.dwLowDateTime = local.dwLowDateTime;
1784: fd->ftCreationTime.dwHighDateTime = local.dwHighDateTime;
1785:
1786: FileTimeToLocalFileTime(&fd->ftLastAccessTime, &local);
1787: fd->ftLastAccessTime.dwLowDateTime = local.dwLowDateTime;
1788: fd->ftLastAccessTime.dwHighDateTime = local.dwHighDateTime;
1789:
1790: FileTimeToLocalFileTime(&fd->ftLastWriteTime, &local);
1791: fd->ftLastWriteTime.dwLowDateTime = local.dwLowDateTime;
1792: fd->ftLastWriteTime.dwHighDateTime = local.dwHighDateTime;
1793: }
1794:
1795: // i/o
1796:
1797: void msdos_putch(UINT8 data);
1798:
1799: void msdos_stdio_reopen()
1800: {
1801: if(!file_handler[0].valid) {
1802: _dup2(DUP_STDIN, 0);
1803: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
1804: }
1805: if(!file_handler[1].valid) {
1806: _dup2(DUP_STDOUT, 1);
1807: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
1808: }
1809: if(!file_handler[2].valid) {
1810: _dup2(DUP_STDERR, 2);
1811: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
1812: }
1813: }
1814:
1815: int msdos_kbhit()
1816: {
1817: msdos_stdio_reopen();
1818:
1819: if(!file_handler[0].atty) {
1820: // stdin is redirected to file
1821: return(eof(0) == 0);
1822: }
1823:
1824: // check keyboard status
1.1.1.5 root 1825: if(key_buf_char->count() != 0 || key_code != 0) {
1.1 root 1826: return(1);
1827: } else {
1828: return(_kbhit());
1829: }
1830: }
1831:
1832: int msdos_getch_ex(int echo)
1833: {
1834: static char prev = 0;
1835:
1836: msdos_stdio_reopen();
1837:
1838: if(!file_handler[0].atty) {
1839: // stdin is redirected to file
1840: retry:
1841: char data;
1842: if(_read(0, &data, 1) == 1) {
1843: char tmp = data;
1844: if(data == 0x0a) {
1845: if(prev == 0x0d) {
1846: goto retry; // CRLF -> skip LF
1847: } else {
1848: data = 0x0d; // LF only -> CR
1849: }
1850: }
1851: prev = tmp;
1852: return(data);
1853: }
1854: return(EOF);
1855: }
1856:
1857: // input from console
1.1.1.5 root 1858: int key_char, key_scan;
1859: if(key_code != 0) {
1860: key_char = (key_code >> 0) & 0xff;
1861: key_scan = (key_code >> 8) & 0xff;
1862: key_code >>= 16;
1863: } else {
1.1.1.14! root 1864: while(key_buf_char->count() == 0 && !m_halted) {
! 1865: if(!update_key_buffer()) {
! 1866: Sleep(10);
! 1867: }
! 1868: }
! 1869: if(m_halted) {
! 1870: // ctrl-c pressed - insert CR to terminate input loops
! 1871: key_char = 0x0d;
! 1872: key_scan = 0;
! 1873: } else {
! 1874: key_char = key_buf_char->read();
! 1875: key_scan = key_buf_scan->read();
1.1.1.5 root 1876: }
1.1 root 1877: }
1878: if(echo && key_char) {
1879: msdos_putch(key_char);
1880: }
1881: return key_char ? key_char : (key_scan != 0xe0) ? key_scan : 0;
1882: }
1883:
1884: inline int msdos_getch()
1885: {
1886: return(msdos_getch_ex(0));
1887: }
1888:
1889: inline int msdos_getche()
1890: {
1891: return(msdos_getch_ex(1));
1892: }
1893:
1894: int msdos_write(int fd, const void *buffer, unsigned int count)
1895: {
1896: static int is_cr = 0;
1897:
1898: if(fd == 1 && !file_handler[1].atty) {
1899: // CR+LF -> LF
1900: UINT8 *buf = (UINT8 *)buffer;
1901: for(unsigned int i = 0; i < count; i++) {
1902: UINT8 data = buf[i];
1903: if(is_cr) {
1904: if(data != 0x0a) {
1905: UINT8 tmp = 0x0d;
1906: _write(1, &tmp, 1);
1907: }
1908: _write(1, &data, 1);
1909: is_cr = 0;
1910: } else if(data == 0x0d) {
1911: is_cr = 1;
1912: } else {
1913: _write(1, &data, 1);
1914: }
1915: }
1916: return(count);
1917: }
1.1.1.14! root 1918: vram_flush();
1.1 root 1919: return(_write(fd, buffer, count));
1920: }
1921:
1922: void msdos_putch(UINT8 data)
1923: {
1924: static int p = 0;
1925: static int is_kanji = 0;
1926: static int is_esc = 0;
1927: static int stored_x;
1928: static int stored_y;
1929: static WORD stored_a;
1930: static char tmp[64];
1931:
1932: msdos_stdio_reopen();
1933:
1934: if(!file_handler[1].atty) {
1935: // stdout is redirected to file
1936: msdos_write(1, &data, 1);
1937: return;
1938: }
1939:
1940: // output to console
1941: tmp[p++] = data;
1942:
1.1.1.14! root 1943: vram_flush();
! 1944:
1.1 root 1945: if(is_kanji) {
1946: // kanji character
1947: is_kanji = 0;
1948: } else if(is_esc) {
1949: // escape sequense
1950: if((tmp[1] == ')' || tmp[1] == '(') && p == 3) {
1951: p = is_esc = 0;
1952: } else if(tmp[1] == '=' && p == 4) {
1953: COORD co;
1954: co.X = tmp[3] - 0x20;
1.1.1.14! root 1955: co.Y = tmp[2] - 0x20 + scr_top;
1.1 root 1956: SetConsoleCursorPosition(hStdout, co);
1957: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14! root 1958: mem[0x451 + mem[0x462] * 2] = co.Y - scr_top;
1.1 root 1959: cursor_moved = false;
1960: p = is_esc = 0;
1961: } else if((data >= 'a' && data <= 'z') || (data >= 'A' && data <= 'Z') || data == '*') {
1962: CONSOLE_SCREEN_BUFFER_INFO csbi;
1963: COORD co;
1964: GetConsoleScreenBufferInfo(hStdout, &csbi);
1965: co.X = csbi.dwCursorPosition.X;
1966: co.Y = csbi.dwCursorPosition.Y;
1967: WORD wAttributes = csbi.wAttributes;
1968:
1969: if(tmp[1] == 'D') {
1970: co.Y++;
1971: } else if(tmp[1] == 'E') {
1972: co.X = 0;
1973: co.Y++;
1974: } else if(tmp[1] == 'M') {
1975: co.Y--;
1976: } else if(tmp[1] == '*') {
1977: SMALL_RECT rect;
1.1.1.14! root 1978: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
! 1979: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
! 1980: co.X = 0;
! 1981: co.Y = csbi.srWindow.Top;
1.1 root 1982: } else if(tmp[1] == '[') {
1983: int param[256], params = 0;
1984: memset(param, 0, sizeof(param));
1985: for(int i = 2; i < p; i++) {
1986: if(tmp[i] >= '0' && tmp[i] <= '9') {
1987: param[params] *= 10;
1988: param[params] += tmp[i] - '0';
1989: } else {
1990: params++;
1991: }
1992: }
1993: if(data == 'A') {
1.1.1.14! root 1994: co.Y -= (params == 0) ? 1 : param[0];
1.1 root 1995: } else if(data == 'B') {
1.1.1.14! root 1996: co.Y += (params == 0) ? 1 : param[0];
1.1 root 1997: } else if(data == 'C') {
1.1.1.14! root 1998: co.X += (params == 0) ? 1 : param[0];
1.1 root 1999: } else if(data == 'D') {
1.1.1.14! root 2000: co.X -= (params == 0) ? 1 : param[0];
1.1 root 2001: } else if(data == 'H' || data == 'f') {
1.1.1.14! root 2002: co.X = (param[1] == 0 ? 1 : param[1]) - 1;
! 2003: co.Y = (param[0] == 0 ? 1 : param[0]) - 1 + csbi.srWindow.Top;
1.1 root 2004: } else if(data == 'J') {
2005: SMALL_RECT rect;
1.1.1.14! root 2006: clear_scr_buffer(csbi.wAttributes);
1.1 root 2007: if(param[0] == 0) {
2008: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14! root 2009: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
! 2010: if(co.Y < csbi.srWindow.Bottom) {
! 2011: SET_RECT(rect, 0, co.Y + 1, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
! 2012: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2013: }
2014: } else if(param[0] == 1) {
1.1.1.14! root 2015: if(co.Y > csbi.srWindow.Top) {
! 2016: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, co.Y - 1);
! 2017: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2018: }
2019: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14! root 2020: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2021: } else if(param[0] == 2) {
1.1.1.14! root 2022: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
! 2023: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2024: co.X = co.Y = 0;
2025: }
2026: } else if(data == 'K') {
2027: SMALL_RECT rect;
1.1.1.14! root 2028: clear_scr_buffer(csbi.wAttributes);
1.1 root 2029: if(param[0] == 0) {
2030: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14! root 2031: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2032: } else if(param[0] == 1) {
2033: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14! root 2034: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2035: } else if(param[0] == 2) {
2036: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14! root 2037: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2038: }
2039: } else if(data == 'L') {
2040: SMALL_RECT rect;
1.1.1.14! root 2041: if(params == 0) {
! 2042: param[0] = 1;
1.1 root 2043: }
1.1.1.14! root 2044: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
! 2045: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
! 2046: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
! 2047: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
! 2048: clear_scr_buffer(csbi.wAttributes);
1.1 root 2049: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y + param[0] - 1);
1.1.1.14! root 2050: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2051: co.X = 0;
2052: } else if(data == 'M') {
2053: SMALL_RECT rect;
1.1.1.14! root 2054: if(params == 0) {
! 2055: param[0] = 1;
! 2056: }
! 2057: if(co.Y + param[0] > csbi.srWindow.Bottom) {
! 2058: clear_scr_buffer(csbi.wAttributes);
! 2059: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
! 2060: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2061: } else {
1.1.1.14! root 2062: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
! 2063: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
! 2064: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
! 2065: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
! 2066: clear_scr_buffer(csbi.wAttributes);
1.1 root 2067: }
2068: co.X = 0;
2069: } else if(data == 'h') {
2070: if(tmp[2] == '>' && tmp[3] == '5') {
2071: CONSOLE_CURSOR_INFO cur;
2072: GetConsoleCursorInfo(hStdout, &cur);
2073: if(cur.bVisible) {
2074: cur.bVisible = FALSE;
1.1.1.14! root 2075: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 2076: }
2077: }
2078: } else if(data == 'l') {
2079: if(tmp[2] == '>' && tmp[3] == '5') {
2080: CONSOLE_CURSOR_INFO cur;
2081: GetConsoleCursorInfo(hStdout, &cur);
2082: if(!cur.bVisible) {
2083: cur.bVisible = TRUE;
1.1.1.14! root 2084: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 2085: }
2086: }
2087: } else if(data == 'm') {
2088: wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
2089: int reverse = 0, hidden = 0;
2090: for(int i = 0; i < params; i++) {
2091: if(param[i] == 1) {
2092: wAttributes |= FOREGROUND_INTENSITY;
2093: } else if(param[i] == 4) {
2094: wAttributes |= COMMON_LVB_UNDERSCORE;
2095: } else if(param[i] == 7) {
2096: reverse = 1;
2097: } else if(param[i] == 8 || param[i] == 16) {
2098: hidden = 1;
2099: } else if((param[i] >= 17 && param[i] <= 23) || (param[i] >= 30 && param[i] <= 37)) {
2100: wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
2101: if(param[i] >= 17 && param[i] <= 23) {
2102: param[i] -= 16;
2103: } else {
2104: param[i] -= 30;
2105: }
2106: if(param[i] & 1) {
2107: wAttributes |= FOREGROUND_RED;
2108: }
2109: if(param[i] & 2) {
2110: wAttributes |= FOREGROUND_GREEN;
2111: }
2112: if(param[i] & 4) {
2113: wAttributes |= FOREGROUND_BLUE;
2114: }
2115: } else if(param[i] >= 40 && param[i] <= 47) {
2116: wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
2117: if((param[i] - 40) & 1) {
2118: wAttributes |= BACKGROUND_RED;
2119: }
2120: if((param[i] - 40) & 2) {
2121: wAttributes |= BACKGROUND_GREEN;
2122: }
2123: if((param[i] - 40) & 4) {
2124: wAttributes |= BACKGROUND_BLUE;
2125: }
2126: }
2127: }
2128: if(reverse) {
2129: wAttributes &= ~0xff;
2130: wAttributes |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
2131: }
2132: if(hidden) {
2133: wAttributes &= ~0x0f;
2134: wAttributes |= (wAttributes >> 4) & 0x0f;
2135: }
2136: } else if(data == 'n') {
2137: if(param[0] == 6) {
2138: char tmp[16];
2139: sprintf(tmp, "\x1b[%d;%dR", co.Y + 1, co.X + 1);
2140: int len = strlen(tmp);
2141: for(int i = 0; i < len; i++) {
2142: key_buf_char->write(tmp[i]);
2143: key_buf_scan->write(0x00);
2144: }
2145: }
2146: } else if(data == 's') {
2147: stored_x = co.X;
2148: stored_y = co.Y;
2149: stored_a = wAttributes;
2150: } else if(data == 'u') {
2151: co.X = stored_x;
2152: co.Y = stored_y;
2153: wAttributes = stored_a;
2154: }
2155: }
2156: if(co.X < 0) {
2157: co.X = 0;
2158: } else if(co.X >= csbi.dwSize.X) {
2159: co.X = csbi.dwSize.X - 1;
2160: }
1.1.1.14! root 2161: if(co.Y < csbi.srWindow.Top) {
! 2162: co.Y = csbi.srWindow.Top;
! 2163: } else if(co.Y > csbi.srWindow.Bottom) {
! 2164: co.Y = csbi.srWindow.Bottom;
1.1 root 2165: }
2166: if(co.X != csbi.dwCursorPosition.X || co.Y != csbi.dwCursorPosition.Y) {
2167: SetConsoleCursorPosition(hStdout, co);
2168: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14! root 2169: mem[0x451 + mem[0x462] * 2] = co.Y - csbi.srWindow.Top;
1.1 root 2170: cursor_moved = false;
2171: }
2172: if(wAttributes != csbi.wAttributes) {
2173: SetConsoleTextAttribute(hStdout, wAttributes);
2174: }
2175: p = is_esc = 0;
2176: }
2177: return;
2178: } else {
2179: if(msdos_lead_byte_check(data)) {
2180: is_kanji = 1;
2181: return;
2182: } else if(data == 0x1b) {
2183: is_esc = 1;
2184: return;
2185: }
2186: }
1.1.1.14! root 2187: // tmp[p++] = '\0';
! 2188: // printf("%s", tmp);
! 2189: DWORD num;
! 2190: WriteConsole(hStdout, tmp, p, &num, NULL);
1.1 root 2191: p = 0;
1.1.1.14! root 2192:
! 2193: CONSOLE_SCREEN_BUFFER_INFO csbi;
! 2194: GetConsoleScreenBufferInfo(hStdout, &csbi);
! 2195: scr_top = csbi.srWindow.Top;
1.1 root 2196: cursor_moved = true;
2197: }
2198:
2199: int msdos_aux_in()
2200: {
2201: #ifdef SUPPORT_AUX_PRN
2202: if(file_handler[3].valid && !eof(3)) {
2203: char data = 0;
2204: _read(3, &data, 1);
2205: return(data);
2206: } else {
2207: return(EOF);
2208: }
2209: #else
2210: return(0);
2211: #endif
2212: }
2213:
2214: void msdos_aux_out(char data)
2215: {
2216: #ifdef SUPPORT_AUX_PRN
2217: if(file_handler[3].valid) {
2218: msdos_write(3, &data, 1);
2219: }
2220: #endif
2221: }
2222:
2223: void msdos_prn_out(char data)
2224: {
2225: #ifdef SUPPORT_AUX_PRN
2226: if(file_handler[4].valid) {
2227: msdos_write(4, &data, 1);
2228: }
2229: #endif
2230: }
2231:
2232: // memory control
2233:
2234: mcb_t *msdos_mcb_create(int mcb_seg, UINT8 mz, UINT16 psp, UINT16 paragraphs)
2235: {
2236: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2237:
2238: mcb->mz = mz;
2239: mcb->psp = psp;
2240: mcb->paragraphs = paragraphs;
2241: return(mcb);
2242: }
2243:
2244: void msdos_mcb_check(mcb_t *mcb)
2245: {
2246: if(!(mcb->mz == 'M' || mcb->mz == 'Z')) {
2247: fatalerror("broken mcb\n");
2248: }
2249: }
2250:
2251: int msdos_mem_split(int seg, int paragraphs)
2252: {
2253: int mcb_seg = seg - 1;
2254: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2255: msdos_mcb_check(mcb);
2256:
2257: if(mcb->paragraphs > paragraphs) {
2258: int new_seg = mcb_seg + 1 + paragraphs;
2259: int new_paragraphs = mcb->paragraphs - paragraphs - 1;
2260:
2261: msdos_mcb_create(new_seg, mcb->mz, 0, new_paragraphs);
2262: mcb->mz = 'M';
2263: mcb->paragraphs = paragraphs;
2264: return(0);
2265: }
2266: return(-1);
2267: }
2268:
2269: void msdos_mem_merge(int seg)
2270: {
2271: int mcb_seg = seg - 1;
2272: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2273: msdos_mcb_check(mcb);
2274:
2275: while(1) {
2276: if(mcb->mz == 'Z') {
2277: break;
2278: }
2279: int next_seg = mcb_seg + 1 + mcb->paragraphs;
2280: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
2281: msdos_mcb_check(next_mcb);
2282:
2283: if(next_mcb->psp != 0) {
2284: break;
2285: }
2286: mcb->mz = next_mcb->mz;
2287: mcb->paragraphs += 1 + next_mcb->paragraphs;
2288: }
2289: }
2290:
1.1.1.8 root 2291: int msdos_mem_alloc(int mcb_seg, int paragraphs, int new_process)
1.1 root 2292: {
2293: while(1) {
2294: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2295:
1.1.1.14! root 2296: if(mcb->psp == 0) {
! 2297: msdos_mem_merge(mcb_seg + 1);
! 2298: } else {
! 2299: msdos_mcb_check(mcb);
! 2300: }
1.1.1.8 root 2301: if(!(new_process && mcb->mz != 'Z')) {
1.1 root 2302: if(mcb->psp == 0 && mcb->paragraphs >= paragraphs) {
2303: msdos_mem_split(mcb_seg + 1, paragraphs);
2304: mcb->psp = current_psp;
2305: return(mcb_seg + 1);
2306: }
2307: }
2308: if(mcb->mz == 'Z') {
2309: break;
2310: }
2311: mcb_seg += 1 + mcb->paragraphs;
2312: }
2313: return(-1);
2314: }
2315:
2316: int msdos_mem_realloc(int seg, int paragraphs, int *max_paragraphs)
2317: {
2318: int mcb_seg = seg - 1;
2319: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2320: msdos_mcb_check(mcb);
2321: int current_paragraphs = mcb->paragraphs;
2322:
2323: msdos_mem_merge(seg);
2324: if(paragraphs > mcb->paragraphs) {
1.1.1.14! root 2325: if(max_paragraphs) {
! 2326: *max_paragraphs = mcb->paragraphs;
! 2327: }
1.1 root 2328: msdos_mem_split(seg, current_paragraphs);
2329: return(-1);
2330: }
2331: msdos_mem_split(seg, paragraphs);
2332: return(0);
2333: }
2334:
2335: void msdos_mem_free(int seg)
2336: {
2337: int mcb_seg = seg - 1;
2338: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2339: msdos_mcb_check(mcb);
2340:
2341: mcb->psp = 0;
2342: msdos_mem_merge(seg);
2343: }
2344:
1.1.1.8 root 2345: int msdos_mem_get_free(int mcb_seg, int new_process)
1.1 root 2346: {
2347: int max_paragraphs = 0;
2348:
2349: while(1) {
2350: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2351: msdos_mcb_check(mcb);
2352:
1.1.1.8 root 2353: if(!(new_process && mcb->mz != 'Z')) {
1.1 root 2354: if(mcb->psp == 0 && mcb->paragraphs > max_paragraphs) {
2355: max_paragraphs = mcb->paragraphs;
2356: }
2357: }
2358: if(mcb->mz == 'Z') {
2359: break;
2360: }
2361: mcb_seg += 1 + mcb->paragraphs;
2362: }
1.1.1.14! root 2363: return(max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs);
1.1 root 2364: }
2365:
1.1.1.8 root 2366: int msdos_mem_get_last_mcb(int mcb_seg, UINT16 psp)
2367: {
2368: int last_seg = -1;
2369:
2370: while(1) {
2371: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2372: msdos_mcb_check(mcb);
2373:
1.1.1.14! root 2374: if(mcb->psp == psp) {
1.1.1.8 root 2375: last_seg = mcb_seg;
2376: }
1.1.1.14! root 2377: if(mcb->mz == 'Z') {
! 2378: break;
! 2379: }
1.1.1.8 root 2380: mcb_seg += 1 + mcb->paragraphs;
2381: }
2382: return(last_seg);
2383: }
2384:
1.1 root 2385: // environment
2386:
2387: void msdos_env_set_argv(int env_seg, char *argv)
2388: {
2389: char *dst = (char *)(mem + (env_seg << 4));
2390:
2391: while(1) {
2392: if(dst[0] == 0) {
2393: break;
2394: }
2395: dst += strlen(dst) + 1;
2396: }
2397: *dst++ = 0; // end of environment
2398: *dst++ = 1; // top of argv[0]
2399: *dst++ = 0;
2400: memcpy(dst, argv, strlen(argv));
2401: dst += strlen(argv);
2402: *dst++ = 0;
2403: *dst++ = 0;
2404: }
2405:
2406: char *msdos_env_get_argv(int env_seg)
2407: {
2408: static char env[ENV_SIZE];
2409: char *src = env;
2410:
2411: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
2412: while(1) {
2413: if(src[0] == 0) {
2414: if(src[1] == 1) {
2415: return(src + 3);
2416: }
2417: break;
2418: }
2419: src += strlen(src) + 1;
2420: }
2421: return(NULL);
2422: }
2423:
2424: char *msdos_env_get(int env_seg, const char *name)
2425: {
2426: static char env[ENV_SIZE];
2427: char *src = env;
2428:
2429: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
2430: while(1) {
2431: if(src[0] == 0) {
2432: break;
2433: }
2434: int len = strlen(src);
2435: char *n = my_strtok(src, "=");
2436: char *v = src + strlen(n) + 1;
2437:
2438: if(_stricmp(name, n) == 0) {
2439: return(v);
2440: }
2441: src += len + 1;
2442: }
2443: return(NULL);
2444: }
2445:
2446: void msdos_env_set(int env_seg, char *name, char *value)
2447: {
2448: char env[ENV_SIZE];
2449: char *src = env;
2450: char *dst = (char *)(mem + (env_seg << 4));
2451: char *argv = msdos_env_get_argv(env_seg);
2452: int done = 0;
2453:
2454: memcpy(src, dst, ENV_SIZE);
2455: memset(dst, 0, ENV_SIZE);
2456: while(1) {
2457: if(src[0] == 0) {
2458: break;
2459: }
2460: int len = strlen(src);
2461: char *n = my_strtok(src, "=");
2462: char *v = src + strlen(n) + 1;
2463: char tmp[1024];
2464:
2465: if(_stricmp(name, n) == 0) {
2466: sprintf(tmp, "%s=%s", n, value);
2467: done = 1;
2468: } else {
2469: sprintf(tmp, "%s=%s", n, v);
2470: }
2471: memcpy(dst, tmp, strlen(tmp));
2472: dst += strlen(tmp) + 1;
2473: src += len + 1;
2474: }
2475: if(!done) {
2476: char tmp[1024];
2477:
2478: sprintf(tmp, "%s=%s", name, value);
2479: memcpy(dst, tmp, strlen(tmp));
2480: dst += strlen(tmp) + 1;
2481: }
2482: if(argv) {
2483: *dst++ = 0; // end of environment
2484: *dst++ = 1; // top of argv[0]
2485: *dst++ = 0;
2486: memcpy(dst, argv, strlen(argv));
2487: dst += strlen(argv);
2488: *dst++ = 0;
2489: *dst++ = 0;
2490: }
2491: }
2492:
2493: // process
2494:
1.1.1.8 root 2495: psp_t *msdos_psp_create(int psp_seg, UINT16 mcb_seg, UINT16 parent_psp, UINT16 env_seg)
1.1 root 2496: {
2497: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
2498:
2499: memset(psp, 0, PSP_SIZE);
2500: psp->exit[0] = 0xcd;
2501: psp->exit[1] = 0x20;
1.1.1.8 root 2502: psp->first_mcb = mcb_seg;
1.1 root 2503: psp->far_call = 0xea;
2504: psp->cpm_entry.w.l = 0xfff1; // int 21h, retf
2505: psp->cpm_entry.w.h = 0xf000;
2506: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
2507: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
2508: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
2509: psp->parent_psp = parent_psp;
2510: for(int i = 0; i < 20; i++) {
2511: if(file_handler[i].valid) {
2512: psp->file_table[i] = i;
2513: } else {
2514: psp->file_table[i] = 0xff;
2515: }
2516: }
2517: psp->env_seg = env_seg;
2518: psp->stack.w.l = REG16(SP);
1.1.1.3 root 2519: psp->stack.w.h = SREG(SS);
1.1.1.14! root 2520: psp->file_table_size = 20;
! 2521: psp->file_table_ptr.w.l = 0x18;
! 2522: psp->file_table_ptr.w.h = psp_seg;
1.1 root 2523: psp->service[0] = 0xcd;
2524: psp->service[1] = 0x21;
2525: psp->service[2] = 0xcb;
2526: return(psp);
2527: }
2528:
2529: int msdos_process_exec(char *cmd, param_block_t *param, UINT8 al)
2530: {
2531: // load command file
2532: int fd = -1;
2533: int dos_command = 0;
1.1.1.4 root 2534: char command[MAX_PATH], path[MAX_PATH], opt[MAX_PATH], *name, name_tmp[MAX_PATH];
1.1 root 2535:
2536: int opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
2537: int opt_len = mem[opt_ofs];
2538: memset(opt, 0, sizeof(opt));
2539: memcpy(opt, mem + opt_ofs + 1, opt_len);
2540:
1.1.1.14! root 2541: if(strlen(cmd) >= 5 && _stricmp(&cmd[strlen(cmd) - 4], ".BAT") == 0) {
! 2542: // this is a batch file, run command.com
! 2543: char tmp[MAX_PATH];
! 2544: if(opt_len != 0) {
! 2545: sprintf(tmp, "/C %s %s", cmd, opt);
! 2546: } else {
! 2547: sprintf(tmp, "/C %s", cmd);
! 2548: }
! 2549: strcpy(opt, tmp);
! 2550: opt_len = strlen(opt);
! 2551: mem[opt_ofs] = opt_len;
! 2552: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
! 2553: strcpy(command, comspec_path);
! 2554: strcpy(name_tmp, "COMMAND.COM");
! 2555: } else {
! 2556: if(_stricmp(cmd, "C:\\COMMAND.COM") == 0) {
! 2557: // redirect C:\COMMAND.COM to comspec_path
! 2558: strcpy(command, comspec_path);
! 2559: } else {
! 2560: strcpy(command, cmd);
! 2561: }
! 2562: GetFullPathName(command, MAX_PATH, path, &name);
! 2563: memset(name_tmp, 0, sizeof(name_tmp));
! 2564: strcpy(name_tmp, name);
! 2565:
! 2566: // check command.com
! 2567: if(_stricmp(name, "COMMAND.COM") == 0 || _stricmp(name, "COMMAND") == 0) {
! 2568: if(opt_len == 0) {
! 2569: // process_t *current_process = msdos_process_info_get(current_psp);
! 2570: process_t *current_process = NULL;
! 2571: for(int i = 0; i < MAX_PROCESS; i++) {
! 2572: if(process[i].psp == current_psp) {
! 2573: current_process = &process[i];
! 2574: break;
! 2575: }
! 2576: }
! 2577: if(current_process != NULL) {
! 2578: param->cmd_line.dw = current_process->dta.dw;
! 2579: opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
! 2580: opt_len = mem[opt_ofs];
! 2581: memset(opt, 0, sizeof(opt));
! 2582: memcpy(opt, mem + opt_ofs + 1, opt_len);
! 2583: }
! 2584: }
! 2585: for(int i = 0; i < opt_len; i++) {
! 2586: if(opt[i] == ' ') {
! 2587: continue;
! 2588: }
! 2589: if(opt[i] == '/' && (opt[i + 1] == 'c' || opt[i + 1] == 'C') && opt[i + 2] == ' ') {
! 2590: for(int j = i + 3; j < opt_len; j++) {
! 2591: if(opt[j] == ' ') {
! 2592: continue;
! 2593: }
! 2594: char *token = my_strtok(opt + j, " ");
! 2595:
! 2596: if(strlen(token) >= 5 && _stricmp(&token[strlen(token) - 4], ".BAT") == 0) {
! 2597: // this is a batch file, okay to run command.com
! 2598: } else {
! 2599: // run program directly without command.com
! 2600: strcpy(command, token);
! 2601: char tmp[MAX_PATH];
! 2602: strcpy(tmp, token + strlen(token) + 1);
! 2603: strcpy(opt, tmp);
! 2604: opt_len = strlen(opt);
! 2605: mem[opt_ofs] = opt_len;
! 2606: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
! 2607: dos_command = 1;
! 2608: }
! 2609: break;
1.1 root 2610: }
2611: }
1.1.1.14! root 2612: break;
1.1 root 2613: }
2614: }
2615: }
2616:
2617: // load command file
2618: strcpy(path, command);
2619: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
2620: sprintf(path, "%s.COM", command);
2621: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
2622: sprintf(path, "%s.EXE", command);
2623: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
1.1.1.14! root 2624: sprintf(path, "%s.BAT", command);
! 2625: if(_access(path, 0) == 0) {
! 2626: // this is a batch file, run command.com
! 2627: char tmp[MAX_PATH];
! 2628: if(opt_len != 0) {
! 2629: sprintf(tmp, "/C %s %s", path, opt);
! 2630: } else {
! 2631: sprintf(tmp, "/C %s", path);
! 2632: }
! 2633: strcpy(opt, tmp);
! 2634: opt_len = strlen(opt);
! 2635: mem[opt_ofs] = opt_len;
! 2636: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
! 2637: strcpy(path, comspec_path);
! 2638: strcpy(name_tmp, "COMMAND.COM");
! 2639: fd = _open(path, _O_RDONLY | _O_BINARY);
! 2640: } else {
! 2641: // search path in parent environments
! 2642: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
! 2643: char *env = msdos_env_get(parent_psp->env_seg, "PATH");
! 2644: if(env != NULL) {
! 2645: char env_path[4096];
! 2646: strcpy(env_path, env);
! 2647: char *token = my_strtok(env_path, ";");
! 2648:
! 2649: while(token != NULL) {
! 2650: if(strlen(token) != 0) {
! 2651: sprintf(path, "%s", msdos_combine_path(token, command));
! 2652: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
! 2653: break;
! 2654: }
! 2655: sprintf(path, "%s.COM", msdos_combine_path(token, command));
! 2656: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
! 2657: break;
! 2658: }
! 2659: sprintf(path, "%s.EXE", msdos_combine_path(token, command));
! 2660: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
! 2661: break;
! 2662: }
! 2663: sprintf(path, "%s.BAT", msdos_combine_path(token, command));
! 2664: if(_access(path, 0) == 0) {
! 2665: // this is a batch file, run command.com
! 2666: char tmp[MAX_PATH];
! 2667: if(opt_len != 0) {
! 2668: sprintf(tmp, "/C %s %s", path, opt);
! 2669: } else {
! 2670: sprintf(tmp, "/C %s", path);
! 2671: }
! 2672: strcpy(opt, tmp);
! 2673: opt_len = strlen(opt);
! 2674: mem[opt_ofs] = opt_len;
! 2675: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
! 2676: strcpy(path, comspec_path);
! 2677: strcpy(name_tmp, "COMMAND.COM");
! 2678: fd = _open(path, _O_RDONLY | _O_BINARY);
! 2679: break;
! 2680: }
1.1.1.8 root 2681: }
1.1.1.14! root 2682: token = my_strtok(NULL, ";");
1.1 root 2683: }
2684: }
2685: }
2686: }
2687: }
2688: }
2689: if(fd == -1) {
2690: if(dos_command) {
2691: // may be dos command
2692: char tmp[MAX_PATH];
2693: sprintf(tmp, "%s %s", command, opt);
2694: system(tmp);
2695: return(0);
2696: } else {
2697: return(-1);
2698: }
2699: }
2700: _read(fd, file_buffer, sizeof(file_buffer));
2701: _close(fd);
2702:
2703: // copy environment
2704: int env_seg, psp_seg;
2705:
1.1.1.8 root 2706: if((env_seg = msdos_mem_alloc(first_mcb, ENV_SIZE >> 4, 1)) == -1) {
1.1 root 2707: return(-1);
2708: }
2709: if(param->env_seg == 0) {
2710: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
2711: memcpy(mem + (env_seg << 4), mem + (parent_psp->env_seg << 4), ENV_SIZE);
2712: } else {
2713: memcpy(mem + (env_seg << 4), mem + (param->env_seg << 4), ENV_SIZE);
2714: }
2715: msdos_env_set_argv(env_seg, msdos_short_full_path(path));
2716:
2717: // check exe header
2718: exe_header_t *header = (exe_header_t *)file_buffer;
1.1.1.8 root 2719: int paragraphs, free_paragraphs = msdos_mem_get_free(first_mcb, 1);
1.1 root 2720: UINT16 cs, ss, ip, sp;
2721:
2722: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
2723: // memory allocation
2724: int header_size = header->header_size * 16;
2725: int load_size = header->pages * 512 - header_size;
2726: if(header_size + load_size < 512) {
2727: load_size = 512 - header_size;
2728: }
2729: paragraphs = (PSP_SIZE + load_size) >> 4;
2730: if(paragraphs + header->min_alloc > free_paragraphs) {
2731: msdos_mem_free(env_seg);
2732: return(-1);
2733: }
2734: paragraphs += header->max_alloc ? header->max_alloc : header->min_alloc;
2735: if(paragraphs > free_paragraphs) {
2736: paragraphs = free_paragraphs;
2737: }
1.1.1.8 root 2738: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1 root 2739: msdos_mem_free(env_seg);
2740: return(-1);
2741: }
2742: // relocation
2743: int start_seg = psp_seg + (PSP_SIZE >> 4);
2744: for(int i = 0; i < header->relocations; i++) {
2745: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
2746: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
2747: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
2748: }
2749: memcpy(mem + (start_seg << 4), file_buffer + header_size, load_size);
2750: // segments
2751: cs = header->init_cs + start_seg;
2752: ss = header->init_ss + start_seg;
2753: ip = header->init_ip;
2754: sp = header->init_sp - 2; // for symdeb
2755: } else {
2756: // memory allocation
2757: paragraphs = free_paragraphs;
1.1.1.8 root 2758: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1 root 2759: msdos_mem_free(env_seg);
2760: return(-1);
2761: }
2762: int start_seg = psp_seg + (PSP_SIZE >> 4);
2763: memcpy(mem + (start_seg << 4), file_buffer, 0x10000 - PSP_SIZE);
2764: // segments
2765: cs = ss = psp_seg;
2766: ip = 0x100;
2767: sp = 0xfffe;
2768: }
2769:
2770: // create psp
1.1.1.3 root 2771: #if defined(HAS_I386)
2772: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_eip;
2773: #else
2774: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_pc - SREG_BASE(CS);
2775: #endif
2776: *(UINT16 *)(mem + 4 * 0x22 + 2) = SREG(CS);
1.1 root 2777: psp_t *psp = msdos_psp_create(psp_seg, psp_seg + paragraphs, current_psp, env_seg);
2778: memcpy(psp->fcb1, mem + (param->fcb1.w.h << 4) + param->fcb1.w.l, sizeof(psp->fcb1));
2779: memcpy(psp->fcb2, mem + (param->fcb2.w.h << 4) + param->fcb2.w.l, sizeof(psp->fcb2));
2780: memcpy(psp->buffer, mem + (param->cmd_line.w.h << 4) + param->cmd_line.w.l, sizeof(psp->buffer));
2781:
2782: mcb_t *mcb_env = (mcb_t *)(mem + ((env_seg - 1) << 4));
2783: mcb_t *mcb_psp = (mcb_t *)(mem + ((psp_seg - 1) << 4));
2784: mcb_psp->psp = mcb_env->psp = psp_seg;
2785:
1.1.1.4 root 2786: for(int i = 0; i < 8; i++) {
2787: if(name_tmp[i] == '.') {
2788: mcb_psp->prog_name[i] = '\0';
2789: break;
2790: } else if(i < 7 && msdos_lead_byte_check(name_tmp[i])) {
2791: mcb_psp->prog_name[i] = name_tmp[i];
2792: i++;
2793: mcb_psp->prog_name[i] = name_tmp[i];
2794: } else if(name_tmp[i] >= 'a' && name_tmp[i] <= 'z') {
2795: mcb_psp->prog_name[i] = name_tmp[i] - 'a' + 'A';
2796: } else {
2797: mcb_psp->prog_name[i] = name_tmp[i];
2798: }
2799: }
2800:
1.1 root 2801: // process info
2802: process_t *process = msdos_process_info_create(psp_seg);
2803: strcpy(process->module_dir, msdos_short_full_dir(path));
2804: process->dta.w.l = 0x80;
2805: process->dta.w.h = psp_seg;
2806: process->switchar = '/';
2807: process->max_files = 20;
2808: process->parent_int_10h_feh_called = int_10h_feh_called;
2809: process->parent_int_10h_ffh_called = int_10h_ffh_called;
1.1.1.14! root 2810: process->parent_ds = SREG(DS);
1.1 root 2811:
2812: current_psp = psp_seg;
2813:
2814: if(al == 0x00) {
2815: int_10h_feh_called = int_10h_ffh_called = false;
2816:
2817: // registers and segments
2818: REG16(AX) = REG16(BX) = 0x00;
2819: REG16(CX) = 0xff;
2820: REG16(DX) = psp_seg;
2821: REG16(SI) = ip;
2822: REG16(DI) = sp;
2823: REG16(SP) = sp;
1.1.1.3 root 2824: SREG(DS) = SREG(ES) = psp_seg;
2825: SREG(SS) = ss;
2826: i386_load_segment_descriptor(DS);
2827: i386_load_segment_descriptor(ES);
2828: i386_load_segment_descriptor(SS);
1.1 root 2829:
2830: *(UINT16 *)(mem + (ss << 4) + sp) = 0;
2831: i386_jmp_far(cs, ip);
2832: } else if(al == 0x01) {
2833: // copy ss:sp and cs:ip to param block
2834: param->sp = sp;
2835: param->ss = ss;
2836: param->ip = ip;
2837: param->cs = cs;
2838: }
2839: return(0);
2840: }
2841:
2842: void msdos_process_terminate(int psp_seg, int ret, int mem_free)
2843: {
2844: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
2845:
2846: *(UINT32 *)(mem + 4 * 0x22) = psp->int_22h.dw;
2847: *(UINT32 *)(mem + 4 * 0x23) = psp->int_23h.dw;
2848: *(UINT32 *)(mem + 4 * 0x24) = psp->int_24h.dw;
2849:
1.1.1.3 root 2850: SREG(SS) = psp->stack.w.h;
2851: i386_load_segment_descriptor(SS);
1.1 root 2852: REG16(SP) = psp->stack.w.l;
2853: i386_jmp_far(psp->int_22h.w.h, psp->int_22h.w.l);
2854:
2855: process_t *process = msdos_process_info_get(psp_seg);
2856: int_10h_feh_called = process->parent_int_10h_feh_called;
2857: int_10h_ffh_called = process->parent_int_10h_ffh_called;
1.1.1.14! root 2858: SREG(DS) = process->parent_ds;
! 2859: i386_load_segment_descriptor(DS);
1.1 root 2860:
2861: if(mem_free) {
1.1.1.8 root 2862: int mcb_seg;
2863: while((mcb_seg = msdos_mem_get_last_mcb(first_mcb, psp_seg)) != -1) {
2864: msdos_mem_free(mcb_seg + 1);
2865: }
2866: while((mcb_seg = msdos_mem_get_last_mcb(UMB_TOP >> 4, psp_seg)) != -1) {
2867: msdos_mem_free(mcb_seg + 1);
2868: }
1.1 root 2869:
2870: for(int i = 0; i < MAX_FILES; i++) {
2871: if(file_handler[i].valid && file_handler[i].psp == psp_seg) {
2872: _close(i);
2873: msdos_file_handler_close(i, psp_seg);
2874: }
2875: }
1.1.1.13 root 2876: msdos_dta_info_free(psp_seg);
1.1 root 2877: }
1.1.1.14! root 2878: msdos_stdio_reopen();
1.1 root 2879:
2880: memset(process, 0, sizeof(process_t));
2881:
2882: current_psp = psp->parent_psp;
2883: retval = ret;
2884: }
2885:
2886: // drive
2887:
2888: int msdos_drive_param_block_update(int drive_num, UINT16 *seg, UINT16 *ofs, int force_update)
2889: {
2890: *seg = DPB_TOP >> 4;
2891: *ofs = sizeof(dpb_t) * drive_num;
2892: dpb_t *dpb = (dpb_t *)(mem + (*seg << 4) + *ofs);
2893:
2894: if(!force_update && dpb->free_clusters != 0) {
2895: return(dpb->bytes_per_sector ? 1 : 0);
2896: }
2897: memset(dpb, 0, sizeof(dpb_t));
2898:
2899: int res = 0;
2900: char dev[64];
2901: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
2902:
2903: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
2904: if(hFile != INVALID_HANDLE_VALUE) {
2905: DISK_GEOMETRY geo;
2906: DWORD dwSize;
2907: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
2908: dpb->bytes_per_sector = (UINT16)geo.BytesPerSector;
2909: dpb->highest_sector_num = (UINT8)(geo.SectorsPerTrack - 1);
2910: dpb->highest_cluster_num = (UINT16)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1.1.14! root 2911: dpb->maximum_cluster_num = (UINT32)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1 root 2912: switch(geo.MediaType) {
2913: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
2914: dpb->media_type = 0xff;
2915: break;
2916: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
2917: dpb->media_type = 0xfe;
2918: break;
2919: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
2920: dpb->media_type = 0xfd;
2921: break;
2922: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
2923: dpb->media_type = 0xfc;
2924: break;
2925: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
2926: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
2927: dpb->media_type = 0xf9;
2928: break;
2929: case FixedMedia: // hard disk
2930: case RemovableMedia:
2931: dpb->media_type = 0xf8;
2932: break;
2933: default:
2934: dpb->media_type = 0xf0;
2935: break;
2936: }
2937: res = 1;
2938: }
2939: dpb->drive_num = drive_num;
2940: dpb->unit_num = drive_num;
2941: dpb->next_dpb_ofs = *ofs + sizeof(dpb_t);
2942: dpb->next_dpb_seg = *seg;
1.1.1.14! root 2943: dpb->info_sector = 0xffff;
! 2944: dpb->backup_boot_sector = 0xffff;
1.1 root 2945: dpb->free_clusters = 0xffff;
1.1.1.14! root 2946: dpb->free_search_cluster = 0xffffffff;
1.1 root 2947: CloseHandle(hFile);
2948: }
2949: return(res);
2950: }
2951:
2952: // pc bios
2953:
1.1.1.14! root 2954: inline void pcbios_irq0()
! 2955: {
! 2956: //++*(UINT32 *)(mem + 0x46c);
! 2957: *(UINT32 *)(mem + 0x46c) = get_ticks_since_midnight();
! 2958: }
! 2959:
1.1.1.8 root 2960: int get_text_vram_address(int page)
1.1 root 2961: {
2962: if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 2963: return TEXT_VRAM_TOP;
1.1 root 2964: } else {
1.1.1.14! root 2965: return TEXT_VRAM_TOP + VIDEO_REGEN * (page % vram_pages);
1.1 root 2966: }
2967: }
2968:
1.1.1.8 root 2969: int get_shadow_buffer_address(int page)
1.1 root 2970: {
1.1.1.14! root 2971: if(!int_10h_feh_called) {
! 2972: return get_text_vram_address(page);
! 2973: } else if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 2974: return SHADOW_BUF_TOP;
2975: } else {
1.1.1.14! root 2976: return SHADOW_BUF_TOP + VIDEO_REGEN * (page % vram_pages);
1.1.1.8 root 2977: }
2978: }
2979:
2980: inline int get_shadow_buffer_address(int page, int x, int y)
2981: {
1.1.1.14! root 2982: return get_shadow_buffer_address(page) + (x + y * scr_width) * 2;
1.1 root 2983: }
2984:
1.1.1.14! root 2985: inline void pcbios_int_10h_00h(int height)
1.1 root 2986: {
1.1.1.14! root 2987: // clear the existing screen, not just the new one
! 2988: int clr_height = max(height, scr_height);
! 2989:
! 2990: if(scr_width != 80 || scr_height != height) {
! 2991: change_console_size(80, height);
! 2992: restore_console_on_exit = true;
! 2993: mem[0x44a] = 80;
! 2994: mem[0x484] = height - 1;
! 2995: }
1.1 root 2996: mem[0x449] = REG8(AL) & 0x7f;
1.1.1.14! root 2997: mem[0x462] = 0;
! 2998: *(UINT16 *)(mem + 0x44e) = 0;
! 2999:
! 3000: text_vram_top_address = get_text_vram_address(0);
! 3001: text_vram_end_address = text_vram_top_address + scr_width * height * 2;
! 3002: shadow_buffer_top_address = get_shadow_buffer_address(0);
! 3003: shadow_buffer_end_address = shadow_buffer_top_address + scr_width * height * 2;
1.1 root 3004:
3005: if(REG8(AL) & 0x80) {
3006: mem[0x487] |= 0x80;
3007: } else {
1.1.1.14! root 3008: mem[0x487] &= ~0x80;
! 3009: for(int ofs = shadow_buffer_top_address; ofs < shadow_buffer_end_address;) {
! 3010: mem[ofs++] = 0x20;
! 3011: mem[ofs++] = 0x07;
! 3012: }
! 3013:
! 3014: EnterCriticalSection(&vram_crit_sect);
! 3015: for(int y = 0; y < clr_height; y++) {
! 3016: for(int x = 0; x < scr_width; x++) {
! 3017: SCR_BUF(y,x).Char.AsciiChar = ' ';
! 3018: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 3019: }
3020: }
3021: SMALL_RECT rect;
1.1.1.14! root 3022: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + clr_height - 1);
! 3023: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
! 3024: vram_length_char = vram_last_length_char = 0;
! 3025: vram_length_attr = vram_last_length_attr = 0;
! 3026: LeaveCriticalSection(&vram_crit_sect);
1.1 root 3027: }
1.1.1.14! root 3028: COORD co;
! 3029: co.X = 0;
! 3030: co.Y = scr_top;
! 3031: SetConsoleCursorPosition(hStdout, co);
! 3032: cursor_moved = true;
! 3033: SetConsoleTextAttribute(hStdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
1.1 root 3034: }
3035:
3036: inline void pcbios_int_10h_01h()
3037: {
1.1.1.13 root 3038: mem[0x460] = REG8(CL);
3039: mem[0x461] = REG8(CH);
1.1.1.14! root 3040:
! 3041: CONSOLE_CURSOR_INFO ci;
! 3042: GetConsoleCursorInfo(hStdout, &ci);
! 3043: // ci.bVisible = !(REG8(CH) & 0x60) && REG8(CH) <= REG8(CL);
! 3044: // if(ci.bVisible) {
! 3045: int lines = max(8, REG8(CL) + 1);
! 3046: ci.dwSize = (REG8(CL) - REG8(CH) + 1) * 100 / lines;
! 3047: // }
! 3048: SetConsoleCursorInfo(hStdout, &ci);
1.1 root 3049: }
3050:
3051: inline void pcbios_int_10h_02h()
3052: {
1.1.1.14! root 3053: // continuously setting the cursor effectively stops it blinking
! 3054: if(mem[0x462] == REG8(BH) && (REG8(DL) != mem[0x450 + REG8(BH) * 2] || REG8(DH) != mem[0x451 + REG8(BH) * 2])) {
1.1 root 3055: COORD co;
3056: co.X = REG8(DL);
1.1.1.14! root 3057: co.Y = REG8(DH) + scr_top;
! 3058:
! 3059: // some programs hide the cursor by moving it off screen
! 3060: static bool hidden = false;
! 3061: CONSOLE_CURSOR_INFO ci;
! 3062: GetConsoleCursorInfo(hStdout, &ci);
! 3063:
! 3064: if(REG8(DH) >= scr_height || !SetConsoleCursorPosition(hStdout, co)) {
! 3065: if(ci.bVisible) {
! 3066: ci.bVisible = FALSE;
! 3067: // SetConsoleCursorInfo(hStdout, &ci);
! 3068: hidden = true;
! 3069: }
! 3070: } else if(hidden) {
! 3071: if(!ci.bVisible) {
! 3072: ci.bVisible = TRUE;
! 3073: // SetConsoleCursorInfo(hStdout, &ci);
! 3074: }
! 3075: hidden = false;
! 3076: }
1.1 root 3077: }
1.1.1.14! root 3078: mem[0x450 + (REG8(BH) % vram_pages) * 2] = REG8(DL);
! 3079: mem[0x451 + (REG8(BH) % vram_pages) * 2] = REG8(DH);
1.1 root 3080: }
3081:
3082: inline void pcbios_int_10h_03h()
3083: {
1.1.1.14! root 3084: REG8(DL) = mem[0x450 + (REG8(BH) % vram_pages) * 2];
! 3085: REG8(DH) = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 3086: REG8(CL) = mem[0x460];
3087: REG8(CH) = mem[0x461];
3088: }
3089:
3090: inline void pcbios_int_10h_05h()
3091: {
1.1.1.14! root 3092: if(REG8(AL) >= vram_pages) {
! 3093: return;
! 3094: }
! 3095: if(mem[0x462] != REG8(AL)) {
! 3096: vram_flush();
! 3097:
1.1 root 3098: SMALL_RECT rect;
1.1.1.14! root 3099: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
! 3100: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3101:
1.1.1.14! root 3102: for(int y = 0, ofs = get_shadow_buffer_address(mem[0x462]); y < scr_height; y++) {
! 3103: for(int x = 0; x < scr_width; x++) {
! 3104: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
! 3105: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 3106: }
3107: }
1.1.1.14! root 3108: for(int y = 0, ofs = get_shadow_buffer_address(REG8(AL)); y < scr_height; y++) {
! 3109: for(int x = 0; x < scr_width; x++) {
! 3110: SCR_BUF(y,x).Char.AsciiChar = mem[ofs++];
! 3111: SCR_BUF(y,x).Attributes = mem[ofs++];
1.1 root 3112: }
3113: }
1.1.1.14! root 3114: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3115:
3116: COORD co;
1.1.1.14! root 3117: co.X = mem[0x450 + REG8(AL) * 2];
! 3118: co.Y = mem[0x451 + REG8(AL) * 2] + scr_top;
! 3119: if(co.Y < scr_top + scr_height) {
! 3120: SetConsoleCursorPosition(hStdout, co);
! 3121: }
1.1 root 3122: }
1.1.1.14! root 3123: mem[0x462] = REG8(AL);
! 3124: *(UINT16 *)(mem + 0x44e) = REG8(AL) * VIDEO_REGEN;
! 3125: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.8 root 3126: text_vram_top_address = get_text_vram_address(mem[0x462]);
1.1.1.14! root 3127: text_vram_end_address = text_vram_top_address + regen;
1.1.1.8 root 3128: shadow_buffer_top_address = get_shadow_buffer_address(mem[0x462]);
1.1.1.14! root 3129: shadow_buffer_end_address = shadow_buffer_top_address + regen;
1.1 root 3130: }
3131:
3132: inline void pcbios_int_10h_06h()
3133: {
1.1.1.14! root 3134: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
! 3135: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
! 3136: return;
! 3137: }
! 3138: vram_flush();
! 3139:
1.1 root 3140: SMALL_RECT rect;
1.1.1.14! root 3141: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
! 3142: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
! 3143:
! 3144: int right = min(REG8(DL), scr_width - 1);
! 3145: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 3146:
3147: if(REG8(AL) == 0) {
1.1.1.14! root 3148: for(int y = REG8(CH); y <= bottom; y++) {
! 3149: for(int x = REG8(CL), ofs = get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
! 3150: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
! 3151: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3152: }
3153: }
3154: } else {
1.1.1.14! root 3155: for(int y = REG8(CH), y2 = min(REG8(CH) + REG8(AL), bottom + 1); y <= bottom; y++, y2++) {
! 3156: for(int x = REG8(CL), ofs = get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
! 3157: if(y2 <= bottom) {
! 3158: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 3159: } else {
1.1.1.14! root 3160: SCR_BUF(y,x).Char.AsciiChar = ' ';
! 3161: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3162: }
1.1.1.14! root 3163: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
! 3164: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 3165: }
3166: }
3167: }
1.1.1.14! root 3168: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3169: }
3170:
3171: inline void pcbios_int_10h_07h()
3172: {
1.1.1.14! root 3173: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
! 3174: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
! 3175: return;
! 3176: }
! 3177: vram_flush();
! 3178:
1.1 root 3179: SMALL_RECT rect;
1.1.1.14! root 3180: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
! 3181: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
! 3182:
! 3183: int right = min(REG8(DL), scr_width - 1);
! 3184: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 3185:
3186: if(REG8(AL) == 0) {
1.1.1.14! root 3187: for(int y = REG8(CH); y <= bottom; y++) {
! 3188: for(int x = REG8(CL), ofs = get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
! 3189: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
! 3190: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3191: }
3192: }
3193: } else {
1.1.1.14! root 3194: for(int y = bottom, y2 = max(REG8(CH) - 1, bottom - REG8(AL)); y >= REG8(CH); y--, y2--) {
! 3195: for(int x = REG8(CL), ofs = get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
! 3196: if(y2 >= REG8(CH)) {
! 3197: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 3198: } else {
1.1.1.14! root 3199: SCR_BUF(y,x).Char.AsciiChar = ' ';
! 3200: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3201: }
1.1.1.14! root 3202: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
! 3203: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 3204: }
3205: }
3206: }
1.1.1.14! root 3207: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3208: }
3209:
3210: inline void pcbios_int_10h_08h()
3211: {
3212: COORD co;
3213: DWORD num;
3214:
1.1.1.14! root 3215: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
! 3216: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 3217:
3218: if(mem[0x462] == REG8(BH)) {
1.1.1.14! root 3219: co.Y += scr_top;
! 3220: vram_flush();
1.1 root 3221: ReadConsoleOutputCharacter(hStdout, scr_char, 1, co, &num);
3222: ReadConsoleOutputAttribute(hStdout, scr_attr, 1, co, &num);
3223: REG8(AL) = scr_char[0];
3224: REG8(AH) = scr_attr[0];
3225: } else {
1.1.1.8 root 3226: REG16(AX) = *(UINT16 *)(mem + get_shadow_buffer_address(REG8(BH), co.X, co.Y));
1.1 root 3227: }
3228: }
3229:
3230: inline void pcbios_int_10h_09h()
3231: {
3232: COORD co;
3233:
1.1.1.14! root 3234: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
! 3235: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
! 3236:
! 3237: int dest = get_shadow_buffer_address(REG8(BH), co.X, co.Y);
! 3238: int end = min(dest + REG16(CX) * 2, get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 3239:
3240: if(mem[0x462] == REG8(BH)) {
1.1.1.14! root 3241: EnterCriticalSection(&vram_crit_sect);
! 3242: int vram = get_shadow_buffer_address(REG8(BH));
! 3243: while(dest < end) {
! 3244: write_text_vram_char(dest - vram, REG8(AL));
! 3245: mem[dest++] = REG8(AL);
! 3246: write_text_vram_attr(dest - vram, REG8(BL));
! 3247: mem[dest++] = REG8(BL);
1.1 root 3248: }
1.1.1.14! root 3249: LeaveCriticalSection(&vram_crit_sect);
1.1 root 3250: } else {
1.1.1.14! root 3251: while(dest < end) {
1.1 root 3252: mem[dest++] = REG8(AL);
3253: mem[dest++] = REG8(BL);
3254: }
3255: }
3256: }
3257:
3258: inline void pcbios_int_10h_0ah()
3259: {
3260: COORD co;
3261:
1.1.1.14! root 3262: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
! 3263: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
! 3264:
! 3265: int dest = get_shadow_buffer_address(REG8(BH), co.X, co.Y);
! 3266: int end = min(dest + REG16(CX) * 2, get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 3267:
3268: if(mem[0x462] == REG8(BH)) {
1.1.1.14! root 3269: EnterCriticalSection(&vram_crit_sect);
! 3270: int vram = get_shadow_buffer_address(REG8(BH));
! 3271: while(dest < end) {
! 3272: write_text_vram_char(dest - vram, REG8(AL));
! 3273: mem[dest++] = REG8(AL);
! 3274: dest++;
1.1 root 3275: }
1.1.1.14! root 3276: LeaveCriticalSection(&vram_crit_sect);
1.1 root 3277: } else {
1.1.1.14! root 3278: while(dest < end) {
1.1 root 3279: mem[dest++] = REG8(AL);
3280: dest++;
3281: }
3282: }
3283: }
3284:
3285: inline void pcbios_int_10h_0eh()
3286: {
1.1.1.14! root 3287: DWORD num;
! 3288: COORD co;
! 3289:
! 3290: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
! 3291: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
! 3292:
! 3293: if(REG8(AL) == 7) {
! 3294: //MessageBeep(-1);
! 3295: } else if(REG8(AL) == 8 || REG8(AL) == 10 || REG8(AL) == 13) {
! 3296: if(REG8(AL) == 10) {
! 3297: vram_flush();
! 3298: }
! 3299: WriteConsole(hStdout, ®8(AL), 1, &num, NULL);
! 3300: cursor_moved = true;
! 3301: } else {
! 3302: int dest = get_shadow_buffer_address(REG8(BH), co.X, co.Y);
! 3303: if(mem[0x462] == REG8(BH)) {
! 3304: EnterCriticalSection(&vram_crit_sect);
! 3305: int vram = get_shadow_buffer_address(REG8(BH));
! 3306: write_text_vram_char(dest - vram, REG8(AL));
! 3307: LeaveCriticalSection(&vram_crit_sect);
! 3308:
! 3309: if(++co.X == scr_width) {
! 3310: co.X = 0;
! 3311: if(++co.Y == scr_height) {
! 3312: vram_flush();
! 3313: WriteConsole(hStdout, "\n", 1, &num, NULL);
! 3314: cursor_moved = true;
! 3315: }
! 3316: }
! 3317: if(!cursor_moved) {
! 3318: co.Y += scr_top;
! 3319: SetConsoleCursorPosition(hStdout, co);
! 3320: cursor_moved = true;
! 3321: }
! 3322: }
! 3323: mem[dest] = REG8(AL);
! 3324: }
1.1 root 3325: }
3326:
3327: inline void pcbios_int_10h_0fh()
3328: {
3329: REG8(AL) = mem[0x449];
3330: REG8(AH) = mem[0x44a];
3331: REG8(BH) = mem[0x462];
3332: }
3333:
1.1.1.14! root 3334: inline void pcbios_int_10h_11h()
! 3335: {
! 3336: switch(REG8(AL)) {
! 3337: case 0x11:
! 3338: pcbios_int_10h_00h(28);
! 3339: break;
! 3340: case 0x12:
! 3341: pcbios_int_10h_00h(50);
! 3342: break;
! 3343: case 0x14:
! 3344: pcbios_int_10h_00h(25);
! 3345: break;
! 3346: case 0x30:
! 3347: SREG(ES) = 0;
! 3348: i386_load_segment_descriptor(ES);
! 3349: REG16(BP) = 0;
! 3350: REG16(CX) = mem[0x485];
! 3351: REG8(DL) = mem[0x484];
! 3352: break;
! 3353: }
! 3354: }
! 3355:
! 3356: inline void pcbios_int_10h_12h()
! 3357: {
! 3358: if(REG8(BL) == 0x10) {
! 3359: REG16(BX) = 0x0003;
! 3360: REG16(CX) = 0x0009;
! 3361: }
! 3362: }
! 3363:
1.1 root 3364: inline void pcbios_int_10h_13h()
3365: {
1.1.1.3 root 3366: int ofs = SREG_BASE(ES) + REG16(BP);
1.1 root 3367: COORD co;
3368: DWORD num;
3369:
3370: co.X = REG8(DL);
1.1.1.14! root 3371: co.Y = REG8(DH) + scr_top;
! 3372:
! 3373: vram_flush();
1.1 root 3374:
3375: switch(REG8(AL)) {
3376: case 0x00:
3377: case 0x01:
3378: if(mem[0x462] == REG8(BH)) {
3379: CONSOLE_SCREEN_BUFFER_INFO csbi;
3380: GetConsoleScreenBufferInfo(hStdout, &csbi);
3381: SetConsoleCursorPosition(hStdout, co);
3382:
3383: if(csbi.wAttributes != REG8(BL)) {
3384: SetConsoleTextAttribute(hStdout, REG8(BL));
3385: }
1.1.1.14! root 3386: WriteConsole(hStdout, &mem[ofs], REG16(CX), &num, NULL);
! 3387:
1.1 root 3388: if(csbi.wAttributes != REG8(BL)) {
3389: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
3390: }
3391: if(REG8(AL) == 0x00) {
1.1.1.14! root 3392: GetConsoleScreenBufferInfo(hStdout, &csbi);
! 3393: scr_top = csbi.srWindow.Top;
! 3394: co.X = mem[0x450 + REG8(BH) * 2];
! 3395: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 3396: SetConsoleCursorPosition(hStdout, co);
3397: } else {
3398: cursor_moved = true;
3399: }
3400: } else {
1.1.1.3 root 3401: m_CF = 1;
1.1 root 3402: }
3403: break;
3404: case 0x02:
3405: case 0x03:
3406: if(mem[0x462] == REG8(BH)) {
3407: CONSOLE_SCREEN_BUFFER_INFO csbi;
3408: GetConsoleScreenBufferInfo(hStdout, &csbi);
3409: SetConsoleCursorPosition(hStdout, co);
3410:
3411: WORD wAttributes = csbi.wAttributes;
3412: for(int i = 0; i < REG16(CX); i++, ofs += 2) {
3413: if(wAttributes != mem[ofs + 1]) {
3414: SetConsoleTextAttribute(hStdout, mem[ofs + 1]);
3415: wAttributes = mem[ofs + 1];
3416: }
1.1.1.14! root 3417: WriteConsole(hStdout, &mem[ofs], 1, &num, NULL);
1.1 root 3418: }
3419: if(csbi.wAttributes != wAttributes) {
3420: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
3421: }
3422: if(REG8(AL) == 0x02) {
1.1.1.14! root 3423: co.X = mem[0x450 + REG8(BH) * 2];
! 3424: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 3425: SetConsoleCursorPosition(hStdout, co);
3426: } else {
3427: cursor_moved = true;
3428: }
3429: } else {
1.1.1.3 root 3430: m_CF = 1;
1.1 root 3431: }
3432: break;
3433: case 0x10:
3434: case 0x11:
3435: if(mem[0x462] == REG8(BH)) {
3436: ReadConsoleOutputCharacter(hStdout, scr_char, REG16(CX), co, &num);
3437: ReadConsoleOutputAttribute(hStdout, scr_attr, REG16(CX), co, &num);
3438: for(int i = 0; i < num; i++) {
3439: mem[ofs++] = scr_char[i];
3440: mem[ofs++] = scr_attr[i];
3441: if(REG8(AL) == 0x11) {
3442: mem[ofs++] = 0;
3443: mem[ofs++] = 0;
3444: }
3445: }
3446: } else {
1.1.1.14! root 3447: for(int i = 0, src = get_shadow_buffer_address(REG8(BH), co.X, co.Y - scr_top); i < REG16(CX); i++) {
1.1 root 3448: mem[ofs++] = mem[src++];
3449: mem[ofs++] = mem[src++];
3450: if(REG8(AL) == 0x11) {
3451: mem[ofs++] = 0;
3452: mem[ofs++] = 0;
3453: }
1.1.1.14! root 3454: if(++co.X == scr_width) {
! 3455: if(++co.Y == scr_height) {
1.1 root 3456: break;
3457: }
3458: co.X = 0;
3459: }
3460: }
3461: }
3462: break;
3463: case 0x20:
3464: case 0x21:
3465: if(mem[0x462] == REG8(BH)) {
1.1.1.14! root 3466: int len = min(REG16(CX), scr_width * scr_height);
! 3467: for(int i = 0; i < len; i++) {
1.1 root 3468: scr_char[i] = mem[ofs++];
3469: scr_attr[i] = mem[ofs++];
3470: if(REG8(AL) == 0x21) {
3471: ofs += 2;
3472: }
3473: }
1.1.1.14! root 3474: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
! 3475: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 3476: } else {
1.1.1.14! root 3477: for(int i = 0, dest = get_shadow_buffer_address(REG8(BH), co.X, co.Y - scr_top); i < REG16(CX); i++) {
1.1 root 3478: mem[dest++] = mem[ofs++];
3479: mem[dest++] = mem[ofs++];
3480: if(REG8(AL) == 0x21) {
3481: ofs += 2;
3482: }
1.1.1.14! root 3483: if(++co.X == scr_width) {
! 3484: if(++co.Y == scr_height) {
1.1 root 3485: break;
3486: }
3487: co.X = 0;
3488: }
3489: }
3490: }
3491: break;
3492: default:
1.1.1.3 root 3493: m_CF = 1;
1.1 root 3494: break;
3495: }
3496: }
3497:
1.1.1.14! root 3498: inline void pcbios_int_10h_1ah()
! 3499: {
! 3500: switch(REG8(AL)) {
! 3501: case 0x00:
! 3502: REG8(AL) = 0x1a;
! 3503: REG8(BL) = 0x08;
! 3504: REG8(BH) = 0x00;
! 3505: break;
! 3506: default:
! 3507: m_CF = 1;
! 3508: break;
! 3509: }
! 3510: }
! 3511:
1.1 root 3512: inline void pcbios_int_10h_1dh()
3513: {
3514: switch(REG8(AL)) {
3515: case 0x01:
3516: break;
3517: case 0x02:
3518: REG16(BX) = 0;
3519: break;
3520: default:
1.1.1.3 root 3521: m_CF = 1;
1.1 root 3522: break;
3523: }
3524: }
3525:
3526: inline void pcbios_int_10h_82h()
3527: {
3528: static UINT8 mode = 0;
3529:
3530: switch(REG8(AL)) {
3531: case 0:
3532: if(REG8(BL) != 0xff) {
3533: mode = REG8(BL);
3534: }
3535: REG8(AL) = mode;
3536: break;
3537: default:
1.1.1.3 root 3538: m_CF = 1;
1.1 root 3539: break;
3540: }
3541: }
3542:
3543: inline void pcbios_int_10h_feh()
3544: {
3545: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 3546: SREG(ES) = (SHADOW_BUF_TOP >> 4);
1.1.1.3 root 3547: i386_load_segment_descriptor(ES);
1.1.1.8 root 3548: REG16(DI) = (SHADOW_BUF_TOP & 0x0f);
1.1 root 3549: }
3550: int_10h_feh_called = true;
3551: }
3552:
3553: inline void pcbios_int_10h_ffh()
3554: {
3555: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
3556: COORD co;
3557: DWORD num;
3558:
1.1.1.14! root 3559: vram_flush();
! 3560:
! 3561: co.X = (REG16(DI) >> 1) % scr_width;
! 3562: co.Y = (REG16(DI) >> 1) / scr_width;
! 3563: int ofs = get_shadow_buffer_address(0, co.X, co.Y);
! 3564: int end = min(ofs + REG16(CX) * 2, get_shadow_buffer_address(0, 0, scr_height));
! 3565: int len;
! 3566: for(len = 0; ofs < end; len++) {
! 3567: scr_char[len] = mem[ofs++];
! 3568: scr_attr[len] = mem[ofs++];
! 3569: }
! 3570: co.Y += scr_top;
! 3571: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
! 3572: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 3573: }
3574: int_10h_ffh_called = true;
3575: }
3576:
1.1.1.14! root 3577: inline void pcbios_int_15h_10h()
! 3578: {
! 3579: if(REG8(AL) == 0) {
! 3580: Sleep(10);
! 3581: hardware_update();
! 3582: } else {
! 3583: REG8(AH) = 0x86;
! 3584: m_CF = 1;
! 3585: }
! 3586: }
! 3587:
1.1 root 3588: inline void pcbios_int_15h_23h()
3589: {
3590: switch(REG8(AL)) {
3591: case 0:
1.1.1.8 root 3592: REG8(CL) = cmos_read(0x2d);
3593: REG8(CH) = cmos_read(0x2e);
1.1 root 3594: break;
3595: case 1:
1.1.1.8 root 3596: cmos_write(0x2d, REG8(CL));
3597: cmos_write(0x2e, REG8(CH));
1.1 root 3598: break;
3599: default:
3600: REG8(AH) = 0x86;
1.1.1.3 root 3601: m_CF = 1;
1.1 root 3602: break;
3603: }
3604: }
3605:
3606: inline void pcbios_int_15h_24h()
3607: {
3608: switch(REG8(AL)) {
3609: case 0:
1.1.1.3 root 3610: i386_set_a20_line(0);
1.1 root 3611: REG8(AH) = 0;
3612: break;
3613: case 1:
1.1.1.3 root 3614: i386_set_a20_line(1);
1.1 root 3615: REG8(AH) = 0;
3616: break;
3617: case 2:
3618: REG8(AH) = 0;
1.1.1.3 root 3619: REG8(AL) = (m_a20_mask >> 20) & 1;
1.1 root 3620: REG16(CX) = 0;
3621: break;
3622: case 3:
3623: REG16(AX) = 0;
3624: REG16(BX) = 0;
3625: break;
3626: }
3627: }
3628:
3629: inline void pcbios_int_15h_49h()
3630: {
1.1.1.14! root 3631: REG8(AH) = 0;
! 3632: REG8(BL) = 0; // DOS/V
1.1 root 3633: }
3634:
3635: inline void pcbios_int_15h_86h()
3636: {
3637: UINT32 usec = (REG16(CX) << 16) | REG16(DX);
1.1.1.14! root 3638: UINT32 msec = usec / 1000;
! 3639:
! 3640: while(msec) {
! 3641: UINT32 tmp = min(msec, 100);
! 3642: if(msec - tmp < 10) {
! 3643: tmp = msec;
! 3644: }
! 3645: Sleep(tmp);
! 3646:
! 3647: if(m_halted) {
! 3648: return;
! 3649: }
! 3650: msec -= tmp;
! 3651: }
1.1 root 3652: }
3653:
3654: inline void pcbios_int_15h_87h()
3655: {
3656: // copy extended memory (from DOSBox)
3657: int len = REG16(CX) * 2;
1.1.1.3 root 3658: int ofs = SREG_BASE(ES) + REG16(SI);
1.1 root 3659: int src = (*(UINT32 *)(mem + ofs + 0x12) & 0xffffff); // + (mem[ofs + 0x16] << 24);
3660: int dst = (*(UINT32 *)(mem + ofs + 0x1a) & 0xffffff); // + (mem[ofs + 0x1e] << 24);
3661: memcpy(mem + dst, mem + src, len);
3662: REG16(AX) = 0x00;
3663: }
3664:
3665: inline void pcbios_int_15h_88h()
3666: {
3667: REG16(AX) = ((min(MAX_MEM, 0x1000000) - 0x100000) >> 10);
3668: }
3669:
3670: inline void pcbios_int_15h_89h()
3671: {
1.1.1.3 root 3672: #if defined(HAS_I386) || defined(HAS_I286)
1.1 root 3673: // switch to protected mode (from DOSBox)
3674: write_io_byte(0x20, 0x10);
3675: write_io_byte(0x21, REG8(BH));
3676: write_io_byte(0x21, 0x00);
3677: write_io_byte(0xa0, 0x10);
3678: write_io_byte(0xa1, REG8(BL));
3679: write_io_byte(0xa1, 0x00);
1.1.1.3 root 3680: i386_set_a20_line(1);
3681: int ofs = SREG_BASE(ES) + REG16(SI);
3682: m_gdtr.limit = *(UINT16 *)(mem + ofs + 0x08);
3683: m_gdtr.base = *(UINT32 *)(mem + ofs + 0x08 + 0x02) & 0xffffff;
3684: m_idtr.limit = *(UINT16 *)(mem + ofs + 0x10);
3685: m_idtr.base = *(UINT32 *)(mem + ofs + 0x10 + 0x02) & 0xffffff;
3686: #if defined(HAS_I386)
3687: m_cr[0] |= 1;
3688: #else
3689: m_msw |= 1;
3690: #endif
3691: SREG(DS) = 0x18;
3692: SREG(ES) = 0x20;
3693: SREG(SS) = 0x28;
3694: i386_load_segment_descriptor(DS);
3695: i386_load_segment_descriptor(ES);
3696: i386_load_segment_descriptor(SS);
1.1 root 3697: REG16(SP) += 6;
1.1.1.3 root 3698: #if defined(HAS_I386)
3699: set_flags(0); // ???
3700: #else
3701: m_flags = 2;
3702: ExpandFlags(m_flags);
3703: #endif
1.1 root 3704: REG16(AX) = 0x00;
3705: i386_jmp_far(0x30, REG16(CX));
3706: #else
3707: REG8(AH) = 0x86;
1.1.1.3 root 3708: m_CF = 1;
1.1 root 3709: #endif
3710: }
3711:
1.1.1.3 root 3712: #if defined(HAS_I386)
1.1 root 3713: inline void pcbios_int_15h_c9h()
3714: {
3715: REG8(AH) = 0x00;
3716: REG8(CH) = cpu_type;
3717: REG8(CL) = cpu_step;
3718: }
1.1.1.3 root 3719: #endif
1.1 root 3720:
3721: inline void pcbios_int_15h_cah()
3722: {
3723: switch(REG8(AL)) {
3724: case 0:
3725: if(REG8(BL) > 0x3f) {
3726: REG8(AH) = 0x03;
1.1.1.3 root 3727: m_CF = 1;
1.1 root 3728: } else if(REG8(BL) < 0x0e) {
3729: REG8(AH) = 0x04;
1.1.1.3 root 3730: m_CF = 1;
1.1 root 3731: } else {
1.1.1.8 root 3732: REG8(CL) = cmos_read(REG8(BL));
1.1 root 3733: }
3734: break;
3735: case 1:
3736: if(REG8(BL) > 0x3f) {
3737: REG8(AH) = 0x03;
1.1.1.3 root 3738: m_CF = 1;
1.1 root 3739: } else if(REG8(BL) < 0x0e) {
3740: REG8(AH) = 0x04;
1.1.1.3 root 3741: m_CF = 1;
1.1 root 3742: } else {
1.1.1.8 root 3743: cmos_write(REG8(BL), REG8(CL));
1.1 root 3744: }
3745: break;
3746: default:
3747: REG8(AH) = 0x86;
1.1.1.3 root 3748: m_CF = 1;
1.1 root 3749: break;
3750: }
3751: }
3752:
3753: UINT32 get_key_code(bool clear_buffer)
3754: {
3755: UINT32 code = 0;
3756:
3757: if(key_buf_char->count() == 0) {
1.1.1.14! root 3758: if(!update_key_buffer()) {
! 3759: if(clear_buffer) {
! 3760: Sleep(10);
! 3761: } else {
! 3762: maybe_idle();
! 3763: }
! 3764: }
1.1 root 3765: }
3766: if(!clear_buffer) {
3767: key_buf_char->store_buffer();
3768: key_buf_scan->store_buffer();
3769: }
3770: if(key_buf_char->count() != 0) {
3771: code = key_buf_char->read() | (key_buf_scan->read() << 8);
3772: }
3773: if(key_buf_char->count() != 0) {
3774: code |= (key_buf_char->read() << 16) | (key_buf_scan->read() << 24);
3775: }
3776: if(!clear_buffer) {
3777: key_buf_char->restore_buffer();
3778: key_buf_scan->restore_buffer();
3779: }
3780: return code;
3781: }
3782:
3783: inline void pcbios_int_16h_00h()
3784: {
1.1.1.14! root 3785: while(key_code == 0 && !m_halted) {
1.1 root 3786: key_code = get_key_code(true);
3787: }
3788: if((key_code & 0xffff) == 0x0000 || (key_code & 0xffff) == 0xe000) {
3789: if(REG8(AH) == 0x10) {
3790: key_code = ((key_code >> 8) & 0xff) | ((key_code >> 16) & 0xff00);
3791: } else {
3792: key_code = ((key_code >> 16) & 0xff00);
3793: }
3794: }
3795: REG16(AX) = key_code & 0xffff;
3796: key_code >>= 16;
3797: }
3798:
3799: inline void pcbios_int_16h_01h()
3800: {
1.1.1.5 root 3801: UINT32 key_code_tmp = key_code;
1.1 root 3802:
1.1.1.5 root 3803: if(key_code_tmp == 0) {
3804: key_code_tmp = get_key_code(false);
3805: }
1.1.1.14! root 3806: if((key_code_tmp & 0xffff) == 0x0000 || (key_code_tmp & 0xffff) == 0xe000) {
! 3807: if(REG8(AH) == 0x11) {
! 3808: key_code_tmp = ((key_code_tmp >> 8) & 0xff) | ((key_code_tmp >> 16) & 0xff00);
! 3809: } else {
! 3810: key_code_tmp = ((key_code_tmp >> 16) & 0xff00);
1.1 root 3811: }
3812: }
1.1.1.5 root 3813: if(key_code_tmp != 0) {
3814: REG16(AX) = key_code_tmp & 0xffff;
1.1 root 3815: }
1.1.1.3 root 3816: #if defined(HAS_I386)
1.1.1.5 root 3817: m_ZF = (key_code_tmp == 0);
1.1.1.3 root 3818: #else
1.1.1.5 root 3819: m_ZeroVal = (key_code_tmp != 0);
1.1.1.3 root 3820: #endif
1.1 root 3821: }
3822:
3823: inline void pcbios_int_16h_02h()
3824: {
3825: REG8(AL) = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
3826: REG8(AL) |= (GetAsyncKeyState(VK_CAPITAL) & 0x0001) ? 0x40 : 0;
3827: REG8(AL) |= (GetAsyncKeyState(VK_NUMLOCK) & 0x0001) ? 0x20 : 0;
3828: REG8(AL) |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
3829: REG8(AL) |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
3830: REG8(AL) |= (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? 0x04 : 0;
3831: REG8(AL) |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
3832: REG8(AL) |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
3833: }
3834:
3835: inline void pcbios_int_16h_03h()
3836: {
3837: static UINT16 status = 0;
3838:
3839: switch(REG8(AL)) {
3840: case 0x05:
3841: status = REG16(BX);
3842: break;
3843: case 0x06:
3844: REG16(BX) = status;
3845: break;
3846: default:
1.1.1.3 root 3847: m_CF = 1;
1.1 root 3848: break;
3849: }
3850: }
3851:
3852: inline void pcbios_int_16h_05h()
3853: {
1.1.1.14! root 3854: key_buf_char->write(REG8(CL));
! 3855: key_buf_scan->write(REG8(CH));
1.1 root 3856: REG8(AL) = 0x00;
3857: }
3858:
3859: inline void pcbios_int_16h_12h()
3860: {
3861: pcbios_int_16h_02h();
3862:
3863: REG8(AH) = 0;//(GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x80 : 0;
3864: REG8(AH) |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
3865: REG8(AH) |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
3866: REG8(AH) |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
3867: REG8(AH) |= (GetAsyncKeyState(VK_RMENU ) & 0x8000) ? 0x08 : 0;
3868: REG8(AH) |= (GetAsyncKeyState(VK_RCONTROL) & 0x8000) ? 0x04 : 0;
3869: REG8(AH) |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
3870: REG8(AH) |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
3871: }
3872:
3873: inline void pcbios_int_16h_13h()
3874: {
3875: static UINT16 status = 0;
3876:
3877: switch(REG8(AL)) {
3878: case 0x00:
3879: status = REG16(DX);
3880: break;
3881: case 0x01:
3882: REG16(DX) = status;
3883: break;
3884: default:
1.1.1.3 root 3885: m_CF = 1;
1.1 root 3886: break;
3887: }
3888: }
3889:
3890: inline void pcbios_int_16h_14h()
3891: {
3892: static UINT8 status = 0;
3893:
3894: switch(REG8(AL)) {
3895: case 0x00:
3896: case 0x01:
3897: status = REG8(AL);
3898: break;
3899: case 0x02:
3900: REG8(AL) = status;
3901: break;
3902: default:
1.1.1.3 root 3903: m_CF = 1;
1.1 root 3904: break;
3905: }
3906: }
3907:
3908: inline void pcbios_int_1ah_00h()
3909: {
3910: static WORD prev_day = 0;
3911: SYSTEMTIME time;
3912:
3913: GetLocalTime(&time);
1.1.1.14! root 3914: UINT32 tick = get_ticks_since_midnight();
1.1 root 3915: REG16(CX) = (tick >> 16) & 0xffff;
3916: REG16(DX) = (tick ) & 0xffff;
3917: REG8(AL) = (prev_day != 0 && prev_day != time.wDay) ? 1 : 0;
3918: prev_day = time.wDay;
3919: }
3920:
3921: inline int to_bcd(int t)
3922: {
3923: int u = (t % 100) / 10;
3924: return (u << 4) | (t % 10);
3925: }
3926:
3927: inline void pcbios_int_1ah_02h()
3928: {
3929: SYSTEMTIME time;
3930:
3931: GetLocalTime(&time);
3932: REG8(CH) = to_bcd(time.wHour);
3933: REG8(CL) = to_bcd(time.wMinute);
3934: REG8(DH) = to_bcd(time.wSecond);
3935: REG8(DL) = 0x00;
3936: }
3937:
3938: inline void pcbios_int_1ah_04h()
3939: {
3940: SYSTEMTIME time;
3941:
3942: GetLocalTime(&time);
3943: REG8(CH) = to_bcd(time.wYear / 100);
3944: REG8(CL) = to_bcd(time.wYear);
3945: REG8(DH) = to_bcd(time.wMonth);
3946: REG8(DL) = to_bcd(time.wDay);
3947: }
3948:
3949: inline void pcbios_int_1ah_0ah()
3950: {
3951: SYSTEMTIME time;
3952: FILETIME file_time;
3953: WORD dos_date, dos_time;
3954:
3955: GetLocalTime(&time);
3956: SystemTimeToFileTime(&time, &file_time);
3957: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time);
3958: REG16(CX) = dos_date;
3959: }
3960:
3961: // msdos system call
3962:
3963: inline void msdos_int_21h_00h()
3964: {
1.1.1.3 root 3965: msdos_process_terminate(SREG(CS), retval, 1);
1.1 root 3966: }
3967:
3968: inline void msdos_int_21h_01h()
3969: {
3970: REG8(AL) = msdos_getche();
1.1.1.8 root 3971: // some seconds may be passed in console
1.1 root 3972: hardware_update();
3973: }
3974:
3975: inline void msdos_int_21h_02h()
3976: {
3977: msdos_putch(REG8(DL));
3978: }
3979:
3980: inline void msdos_int_21h_03h()
3981: {
3982: REG8(AL) = msdos_aux_in();
3983: }
3984:
3985: inline void msdos_int_21h_04h()
3986: {
3987: msdos_aux_out(REG8(DL));
3988: }
3989:
3990: inline void msdos_int_21h_05h()
3991: {
3992: msdos_prn_out(REG8(DL));
3993: }
3994:
3995: inline void msdos_int_21h_06h()
3996: {
3997: if(REG8(DL) == 0xff) {
3998: if(msdos_kbhit()) {
3999: REG8(AL) = msdos_getch();
1.1.1.3 root 4000: #if defined(HAS_I386)
4001: m_ZF = 0;
4002: #else
4003: m_ZeroVal = 1;
4004: #endif
1.1 root 4005: } else {
4006: REG8(AL) = 0;
1.1.1.3 root 4007: #if defined(HAS_I386)
4008: m_ZF = 1;
4009: #else
4010: m_ZeroVal = 0;
4011: #endif
1.1.1.14! root 4012: maybe_idle();
1.1 root 4013: }
4014: } else {
4015: msdos_putch(REG8(DL));
4016: }
4017: }
4018:
4019: inline void msdos_int_21h_07h()
4020: {
4021: REG8(AL) = msdos_getch();
1.1.1.8 root 4022: // some seconds may be passed in console
1.1 root 4023: hardware_update();
4024: }
4025:
4026: inline void msdos_int_21h_08h()
4027: {
4028: REG8(AL) = msdos_getch();
1.1.1.8 root 4029: // some seconds may be passed in console
1.1 root 4030: hardware_update();
4031: }
4032:
4033: inline void msdos_int_21h_09h()
4034: {
1.1.1.14! root 4035: char *str = (char *)(mem + SREG_BASE(DS) + REG16(DX));
! 4036: int len = 0;
1.1 root 4037:
1.1.1.14! root 4038: while(str[len] != '$' && len < 0x10000) {
! 4039: len++;
! 4040: }
1.1 root 4041: if(file_handler[1].valid && !file_handler[1].atty) {
4042: // stdout is redirected to file
1.1.1.14! root 4043: msdos_write(1, str, len);
1.1 root 4044: } else {
4045: for(int i = 0; i < len; i++) {
1.1.1.14! root 4046: msdos_putch(str[i]);
1.1 root 4047: }
4048: }
4049: }
4050:
4051: inline void msdos_int_21h_0ah()
4052: {
1.1.1.3 root 4053: int ofs = SREG_BASE(DS) + REG16(DX);
1.1 root 4054: int max = mem[ofs] - 1;
4055: UINT8 *buf = mem + ofs + 2;
4056: int chr, p = 0;
4057:
4058: while((chr = msdos_getch()) != 0x0d) {
4059: if(chr == 0x00) {
4060: // skip 2nd byte
4061: msdos_getch();
4062: } else if(chr == 0x08) {
4063: // back space
4064: if(p > 0) {
4065: p--;
4066: msdos_putch(chr);
4067: msdos_putch(' ');
4068: msdos_putch(chr);
4069: }
4070: } else if(p < max) {
4071: buf[p++] = chr;
4072: msdos_putch(chr);
4073: }
4074: }
4075: buf[p] = 0x0d;
4076: mem[ofs + 1] = p;
1.1.1.8 root 4077: // some seconds may be passed in console
1.1 root 4078: hardware_update();
4079: }
4080:
4081: inline void msdos_int_21h_0bh()
4082: {
4083: if(msdos_kbhit()) {
4084: REG8(AL) = 0xff;
4085: } else {
4086: REG8(AL) = 0x00;
1.1.1.14! root 4087: maybe_idle();
1.1 root 4088: }
4089: }
4090:
4091: inline void msdos_int_21h_0ch()
4092: {
4093: // clear key buffer
4094: if(file_handler[0].valid && !file_handler[0].atty) {
4095: // stdin is redirected to file
4096: } else {
4097: while(msdos_kbhit()) {
4098: msdos_getch();
4099: }
4100: }
4101:
4102: switch(REG8(AL)) {
4103: case 0x01:
4104: msdos_int_21h_01h();
4105: break;
4106: case 0x06:
4107: msdos_int_21h_06h();
4108: break;
4109: case 0x07:
4110: msdos_int_21h_07h();
4111: break;
4112: case 0x08:
4113: msdos_int_21h_08h();
4114: break;
4115: case 0x0a:
4116: msdos_int_21h_0ah();
4117: break;
4118: default:
4119: REG16(AX) = 0x01;
1.1.1.3 root 4120: m_CF = 1;
1.1 root 4121: break;
4122: }
4123: }
4124:
4125: inline void msdos_int_21h_0dh()
4126: {
4127: }
4128:
4129: inline void msdos_int_21h_0eh()
4130: {
4131: if(REG8(DL) < 26) {
4132: _chdrive(REG8(DL) + 1);
4133: msdos_cds_update(REG8(DL));
4134: }
4135: REG8(AL) = 26; // zdrive
4136: }
4137:
1.1.1.14! root 4138: inline void msdos_int_21h_0fh()
! 4139: {
! 4140: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
! 4141: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
! 4142:
! 4143: char *path = msdos_fcb_path(fcb);
! 4144: HANDLE hFile = CreateFile(path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
! 4145: if(hFile == INVALID_HANDLE_VALUE) {
! 4146: REG8(AL) = 0xff;
! 4147: } else {
! 4148: REG8(AL) = 0;
! 4149: fcb->current_block = 0;
! 4150: fcb->record_size = 128;
! 4151: fcb->file_size = GetFileSize(hFile, NULL);
! 4152: fcb->handle = hFile;
! 4153: fcb->cur_record = 0;
! 4154: }
! 4155: }
! 4156:
! 4157: inline void msdos_int_21h_10h()
! 4158: {
! 4159: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
! 4160: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
! 4161:
! 4162: REG8(AL) = CloseHandle(fcb->handle) ? 0 : 0xff;
! 4163: }
! 4164:
1.1 root 4165: inline void msdos_int_21h_11h()
4166: {
1.1.1.3 root 4167: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4168: fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 4169:
4170: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 4171: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4172: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
4173: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 4174: char *path = msdos_fcb_path(fcb);
4175: WIN32_FIND_DATA fd;
4176:
1.1.1.13 root 4177: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
4178: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
4179: FindClose(dtainfo->find_handle);
4180: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 4181: }
4182: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14! root 4183: dtainfo->allowable_mask = (ext_fcb->flag == 0xff) ? ext_fcb->attribute : 0x20;
! 4184: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 4185:
1.1.1.14! root 4186: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
! 4187: dtainfo->allowable_mask &= ~8;
1.1 root 4188: }
1.1.1.14! root 4189: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
! 4190: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 4191: !msdos_find_file_has_8dot3name(&fd)) {
4192: if(!FindNextFile(dtainfo->find_handle, &fd)) {
4193: FindClose(dtainfo->find_handle);
4194: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 4195: break;
4196: }
4197: }
4198: }
1.1.1.13 root 4199: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 4200: if(ext_fcb->flag == 0xff) {
4201: ext_find->flag = 0xff;
4202: memset(ext_find->reserved, 0, 5);
4203: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
4204: }
4205: find->drive = _getdrive();
1.1.1.13 root 4206: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 4207: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
4208: find->nt_res = 0;
4209: msdos_find_file_conv_local_time(&fd);
4210: find->create_time_ms = 0;
4211: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
4212: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
4213: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
4214: find->cluster_hi = find->cluster_lo = 0;
4215: find->file_size = fd.nFileSizeLow;
4216: REG8(AL) = 0x00;
1.1.1.14! root 4217: } else if(dtainfo->allowable_mask & 8) {
1.1 root 4218: if(ext_fcb->flag == 0xff) {
4219: ext_find->flag = 0xff;
4220: memset(ext_find->reserved, 0, 5);
4221: ext_find->attribute = 8;
4222: }
4223: find->drive = _getdrive();
4224: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
4225: find->attribute = 8;
4226: find->nt_res = 0;
4227: msdos_find_file_conv_local_time(&fd);
4228: find->create_time_ms = 0;
4229: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
4230: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
4231: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
4232: find->cluster_hi = find->cluster_lo = 0;
4233: find->file_size = 0;
1.1.1.14! root 4234: dtainfo->allowable_mask &= ~8;
1.1 root 4235: REG8(AL) = 0x00;
4236: } else {
4237: REG8(AL) = 0xff;
4238: }
4239: }
4240:
4241: inline void msdos_int_21h_12h()
4242: {
1.1.1.3 root 4243: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1.1.14! root 4244: // fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 4245:
4246: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 4247: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4248: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
4249: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 4250: WIN32_FIND_DATA fd;
4251:
1.1.1.13 root 4252: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
4253: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
4254: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14! root 4255: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 4256: !msdos_find_file_has_8dot3name(&fd)) {
4257: if(!FindNextFile(dtainfo->find_handle, &fd)) {
4258: FindClose(dtainfo->find_handle);
4259: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 4260: break;
4261: }
4262: }
4263: } else {
1.1.1.13 root 4264: FindClose(dtainfo->find_handle);
4265: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 4266: }
4267: }
1.1.1.13 root 4268: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 4269: if(ext_fcb->flag == 0xff) {
4270: ext_find->flag = 0xff;
4271: memset(ext_find->reserved, 0, 5);
4272: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
4273: }
4274: find->drive = _getdrive();
1.1.1.13 root 4275: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 4276: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
4277: find->nt_res = 0;
4278: msdos_find_file_conv_local_time(&fd);
4279: find->create_time_ms = 0;
4280: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
4281: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
4282: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
4283: find->cluster_hi = find->cluster_lo = 0;
4284: find->file_size = fd.nFileSizeLow;
4285: REG8(AL) = 0x00;
1.1.1.14! root 4286: } else if(dtainfo->allowable_mask & 8) {
1.1 root 4287: if(ext_fcb->flag == 0xff) {
4288: ext_find->flag = 0xff;
4289: memset(ext_find->reserved, 0, 5);
4290: ext_find->attribute = 8;
4291: }
4292: find->drive = _getdrive();
4293: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
4294: find->attribute = 8;
4295: find->nt_res = 0;
4296: msdos_find_file_conv_local_time(&fd);
4297: find->create_time_ms = 0;
4298: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
4299: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
4300: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
4301: find->cluster_hi = find->cluster_lo = 0;
4302: find->file_size = 0;
1.1.1.14! root 4303: dtainfo->allowable_mask &= ~8;
1.1 root 4304: REG8(AL) = 0x00;
4305: } else {
4306: REG8(AL) = 0xff;
4307: }
4308: }
4309:
4310: inline void msdos_int_21h_13h()
4311: {
1.1.1.3 root 4312: if(remove(msdos_fcb_path((fcb_t *)(mem + SREG_BASE(DS) + REG16(DX))))) {
1.1 root 4313: REG8(AL) = 0xff;
4314: } else {
4315: REG8(AL) = 0x00;
4316: }
4317: }
4318:
1.1.1.14! root 4319: inline void msdos_int_21h_16h()
! 4320: {
! 4321: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
! 4322: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
! 4323:
! 4324: char *path = msdos_fcb_path(fcb);
! 4325: HANDLE hFile = CreateFile(path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, ext_fcb->flag == 0xff ? ext_fcb->attribute : FILE_ATTRIBUTE_NORMAL, NULL);
! 4326: if(hFile == INVALID_HANDLE_VALUE) {
! 4327: REG8(AL) = 0xff;
! 4328: } else {
! 4329: REG8(AL) = 0;
! 4330: fcb->current_block = 0;
! 4331: fcb->record_size = 128;
! 4332: fcb->file_size = 0;
! 4333: fcb->handle = hFile;
! 4334: fcb->cur_record = 0;
! 4335: }
! 4336: }
! 4337:
1.1 root 4338: inline void msdos_int_21h_18h()
4339: {
4340: REG8(AL) = 0x00;
4341: }
4342:
4343: inline void msdos_int_21h_19h()
4344: {
4345: REG8(AL) = _getdrive() - 1;
4346: }
4347:
4348: inline void msdos_int_21h_1ah()
4349: {
4350: process_t *process = msdos_process_info_get(current_psp);
4351:
4352: process->dta.w.l = REG16(DX);
1.1.1.3 root 4353: process->dta.w.h = SREG(DS);
1.1 root 4354: }
4355:
4356: inline void msdos_int_21h_1bh()
4357: {
4358: int drive_num = _getdrive() - 1;
4359: UINT16 seg, ofs;
4360:
4361: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
4362: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
4363: REG8(AL) = dpb->highest_sector_num + 1;
4364: REG16(CX) = dpb->bytes_per_sector;
4365: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 4366: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 4367: } else {
4368: REG8(AL) = 0xff;
1.1.1.3 root 4369: m_CF = 1;
1.1 root 4370: }
4371:
4372: }
4373:
4374: inline void msdos_int_21h_1ch()
4375: {
4376: int drive_num = REG8(DL) ? (REG8(DL) - 1) : (_getdrive() - 1);
4377: UINT16 seg, ofs;
4378:
4379: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
4380: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
4381: REG8(AL) = dpb->highest_sector_num + 1;
4382: REG16(CX) = dpb->bytes_per_sector;
4383: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 4384: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 4385: } else {
4386: REG8(AL) = 0xff;
1.1.1.3 root 4387: m_CF = 1;
1.1 root 4388: }
4389:
4390: }
4391:
4392: inline void msdos_int_21h_1dh()
4393: {
4394: REG8(AL) = 0;
4395: }
4396:
4397: inline void msdos_int_21h_1eh()
4398: {
4399: REG8(AL) = 0;
4400: }
4401:
4402: inline void msdos_int_21h_1fh()
4403: {
4404: int drive_num = _getdrive() - 1;
4405: UINT16 seg, ofs;
4406:
4407: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
4408: REG8(AL) = 0;
1.1.1.3 root 4409: SREG(DS) = seg;
4410: i386_load_segment_descriptor(DS);
1.1 root 4411: REG16(BX) = ofs;
4412: } else {
4413: REG8(AL) = 0xff;
1.1.1.3 root 4414: m_CF = 1;
1.1 root 4415: }
4416: }
4417:
4418: inline void msdos_int_21h_20h()
4419: {
4420: REG8(AL) = 0;
4421: }
4422:
1.1.1.14! root 4423: inline void msdos_int_21h_21h()
! 4424: {
! 4425: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
! 4426: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
! 4427:
! 4428: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
! 4429: REG8(AL) = 1;
! 4430: } else {
! 4431: process_t *process = msdos_process_info_get(current_psp);
! 4432: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
! 4433: memset(mem + dta_laddr, 0, fcb->record_size);
! 4434: DWORD num;
! 4435: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
! 4436: REG8(AL) = 1;
! 4437: } else {
! 4438: REG8(AL) = num == fcb->record_size ? 0 : 3;
! 4439: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
! 4440: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
! 4441: }
! 4442: }
! 4443: }
! 4444:
! 4445: inline void msdos_int_21h_22h()
! 4446: {
! 4447: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
! 4448: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
! 4449:
! 4450: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
! 4451: REG8(AL) = 0xff;
! 4452: } else {
! 4453: process_t *process = msdos_process_info_get(current_psp);
! 4454: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
! 4455: DWORD num;
! 4456: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL);
! 4457: fcb->file_size = GetFileSize(fcb->handle, NULL);
! 4458: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
! 4459: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
! 4460: REG8(AL) = num == fcb->record_size ? 0 : 1;
! 4461: }
! 4462: }
! 4463:
1.1 root 4464: inline void msdos_int_21h_25h()
4465: {
4466: *(UINT16 *)(mem + 4 * REG8(AL) + 0) = REG16(DX);
1.1.1.3 root 4467: *(UINT16 *)(mem + 4 * REG8(AL) + 2) = SREG(DS);
1.1 root 4468: }
4469:
4470: inline void msdos_int_21h_26h()
4471: {
4472: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
4473:
4474: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
4475: psp->first_mcb = REG16(DX) + 16;
4476: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
4477: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
4478: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
4479: psp->parent_psp = 0;
4480: }
4481:
4482: inline void msdos_int_21h_29h()
4483: {
1.1.1.3 root 4484: int ofs = SREG_BASE(DS) + REG16(SI);
1.1 root 4485: char name[MAX_PATH], ext[MAX_PATH];
4486: UINT8 drv = 0;
4487: char sep_chars[] = ":.;,=+";
4488: char end_chars[] = "\\<>|/\"[]";
4489: char spc_chars[] = " \t";
4490:
4491: if(REG8(AL) & 1) {
4492: ofs += strspn((char *)&mem[ofs], spc_chars);
4493: if(my_strchr(sep_chars, mem[ofs]) && mem[ofs] != '\0') {
4494: ofs++;
4495: }
4496: }
4497: ofs += strspn((char *)&mem[ofs], spc_chars);
4498:
4499: if(mem[ofs + 1] == ':') {
4500: UINT8 c = mem[ofs];
4501: if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
4502: ; // invalid drive letter
4503: } else {
4504: if(c >= 'a' && c <= 'z') {
4505: drv = c - 'a' + 1;
4506: } else {
4507: drv = c - 'A' + 1;
4508: }
4509: ofs += 2;
4510: }
4511: }
4512: memset(name, 0x20, sizeof(name));
4513: memset(ext, 0x20, sizeof(ext));
4514: for(int i = 0; i < MAX_PATH; i++) {
4515: UINT8 c = mem[ofs];
4516: if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
4517: break;
4518: } else if(c >= 'a' && c <= 'z') {
4519: c -= 0x20;
4520: }
4521: ofs++;
4522: name[i] = c;
4523: }
4524: if(mem[ofs] == '.') {
4525: ofs++;
4526: for(int i = 0; i < MAX_PATH; i++) {
4527: UINT8 c = mem[ofs];
4528: if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
4529: break;
4530: } else if(c >= 'a' && c <= 'z') {
4531: c -= 0x20;
4532: }
4533: ofs++;
4534: ext[i] = c;
4535: }
4536: }
1.1.1.3 root 4537: int si = ofs - SREG_BASE(DS);
4538: int ds = SREG(DS);
1.1 root 4539: while(si > 0xffff) {
4540: si -= 0x10;
4541: ds++;
4542: }
4543: REG16(SI) = si;
1.1.1.3 root 4544: SREG(DS) = ds;
4545: i386_load_segment_descriptor(DS);
1.1 root 4546:
1.1.1.3 root 4547: UINT8 *fcb = mem + SREG_BASE(ES) + REG16(DI);
1.1 root 4548: fcb[0] = drv;
4549: memcpy(fcb + 1, name, 8);
4550: int found_star = 0;
4551: for(int i = 1; i < 1 + 8; i++) {
4552: if(fcb[i] == '*') {
4553: found_star = 1;
4554: }
4555: if(found_star) {
4556: fcb[i] = '?';
4557: }
4558: }
4559: memcpy(fcb + 9, ext, 3);
4560: found_star = 0;
4561: for(int i = 9; i < 9 + 3; i++) {
4562: if(fcb[i] == '*') {
4563: found_star = 1;
4564: }
4565: if(found_star) {
4566: fcb[i] = '?';
4567: }
4568: }
4569:
4570: REG8(AL) = 0x00;
4571: if(drv == 0 || (drv > 0 && drv <= 26 && (GetLogicalDrives() & ( 1 << (drv - 1) )))) {
4572: if(memchr(fcb + 1, '?', 8 + 3)) {
4573: REG8(AL) = 0x01;
4574: }
4575: } else {
4576: REG8(AL) = 0xff;
4577: }
4578: }
4579:
4580: inline void msdos_int_21h_2ah()
4581: {
4582: SYSTEMTIME sTime;
4583:
4584: GetLocalTime(&sTime);
4585: REG16(CX) = sTime.wYear;
4586: REG8(DH) = (UINT8)sTime.wMonth;
4587: REG8(DL) = (UINT8)sTime.wDay;
4588: REG8(AL) = (UINT8)sTime.wDayOfWeek;
4589: }
4590:
4591: inline void msdos_int_21h_2bh()
4592: {
1.1.1.14! root 4593: REG8(AL) = 0xff;
1.1 root 4594: }
4595:
4596: inline void msdos_int_21h_2ch()
4597: {
4598: SYSTEMTIME sTime;
4599:
4600: GetLocalTime(&sTime);
4601: REG8(CH) = (UINT8)sTime.wHour;
4602: REG8(CL) = (UINT8)sTime.wMinute;
4603: REG8(DH) = (UINT8)sTime.wSecond;
1.1.1.14! root 4604: REG8(DL) = (UINT8)sTime.wMilliseconds / 10;
1.1 root 4605: }
4606:
4607: inline void msdos_int_21h_2dh()
4608: {
4609: REG8(AL) = 0x00;
4610: }
4611:
4612: inline void msdos_int_21h_2eh()
4613: {
4614: process_t *process = msdos_process_info_get(current_psp);
4615:
4616: process->verify = REG8(AL);
4617: }
4618:
4619: inline void msdos_int_21h_2fh()
4620: {
4621: process_t *process = msdos_process_info_get(current_psp);
4622:
4623: REG16(BX) = process->dta.w.l;
1.1.1.3 root 4624: SREG(ES) = process->dta.w.h;
4625: i386_load_segment_descriptor(ES);
1.1 root 4626: }
4627:
4628: inline void msdos_int_21h_30h()
4629: {
4630: // Version Flag / OEM
4631: if(REG8(AL) == 1) {
4632: REG8(BH) = 0x00; // not in ROM
4633: } else {
4634: REG8(BH) = 0xff; // OEM = Microsoft
4635: }
1.1.1.9 root 4636: REG8(AL) = major_version; // 7
4637: REG8(AH) = minor_version; // 10
1.1 root 4638: }
4639:
4640: inline void msdos_int_21h_31h()
4641: {
1.1.1.14! root 4642: msdos_mem_realloc(current_psp, REG16(DX), NULL);
1.1 root 4643: msdos_process_terminate(current_psp, REG8(AL) | 0x300, 0);
4644: }
4645:
4646: inline void msdos_int_21h_32h()
4647: {
4648: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
4649: UINT16 seg, ofs;
4650:
4651: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
4652: REG8(AL) = 0;
1.1.1.3 root 4653: SREG(DS) = seg;
4654: i386_load_segment_descriptor(DS);
1.1 root 4655: REG16(BX) = ofs;
4656: } else {
4657: REG8(AL) = 0xff;
1.1.1.3 root 4658: m_CF = 1;
1.1 root 4659: }
4660: }
4661:
4662: inline void msdos_int_21h_33h()
4663: {
4664: static UINT8 state = 0x00;
4665: char path[MAX_PATH];
4666:
4667: switch(REG8(AL)) {
4668: case 0x00:
4669: REG8(DL) = state;
4670: break;
4671: case 0x01:
4672: state = REG8(DL);
4673: break;
4674: case 0x05:
4675: GetSystemDirectory(path, MAX_PATH);
4676: if(path[0] >= 'a' && path[0] <= 'z') {
4677: REG8(DL) = path[0] - 'a' + 1;
4678: } else {
4679: REG8(DL) = path[0] - 'A' + 1;
4680: }
4681: break;
4682: case 0x06:
1.1.1.2 root 4683: // MS-DOS version (7.10)
1.1 root 4684: REG8(BL) = 7;
1.1.1.2 root 4685: REG8(BH) = 10;
1.1 root 4686: REG8(DL) = 0;
4687: REG8(DH) = 0x10; // in HMA
4688: break;
1.1.1.6 root 4689: case 0x07:
4690: if(REG8(DL) == 0) {
4691: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag &= ~0x20;
4692: } else if(REG8(DL) == 1) {
4693: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag |= 0x20;
4694: }
4695: break;
1.1 root 4696: default:
4697: REG16(AX) = 0x01;
1.1.1.3 root 4698: m_CF = 1;
1.1 root 4699: break;
4700: }
4701: }
4702:
4703: inline void msdos_int_21h_35h()
4704: {
4705: REG16(BX) = *(UINT16 *)(mem + 4 * REG8(AL) + 0);
1.1.1.3 root 4706: SREG(ES) = *(UINT16 *)(mem + 4 * REG8(AL) + 2);
4707: i386_load_segment_descriptor(ES);
1.1 root 4708: }
4709:
4710: inline void msdos_int_21h_36h()
4711: {
4712: struct _diskfree_t df = {0};
4713:
4714: if(_getdiskfree(REG8(DL), &df) == 0) {
4715: REG16(AX) = (UINT16)df.sectors_per_cluster;
4716: REG16(CX) = (UINT16)df.bytes_per_sector;
1.1.1.13 root 4717: REG16(BX) = df.avail_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.avail_clusters;
4718: REG16(DX) = df.total_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.total_clusters;
1.1 root 4719: } else {
4720: REG16(AX) = 0xffff;
4721: }
4722: }
4723:
4724: inline void msdos_int_21h_37h()
4725: {
4726: process_t *process = msdos_process_info_get(current_psp);
4727:
4728: switch(REG8(AL)) {
4729: case 0x00:
4730: REG8(AL) = 0x00;
4731: REG8(DL) = process->switchar;
4732: break;
4733: case 0x01:
4734: REG8(AL) = 0x00;
4735: process->switchar = REG8(DL);
4736: break;
4737: default:
4738: REG16(AX) = 1;
4739: break;
4740: }
4741: }
4742:
1.1.1.14! root 4743: inline void msdos_int_21h_38h()
! 4744: {
! 4745: switch(REG8(AL)) {
! 4746: case 0x00:
! 4747: {
! 4748: char LCdata[80];
! 4749: struct CI {
! 4750: UINT16 date_format;
! 4751: char currency_symbol[5];
! 4752: char thou_sep[2];
! 4753: char dec_sep[2];
! 4754: char date_sep[2];
! 4755: char time_sep[2];
! 4756: char currency_format;
! 4757: char currency_dec_digits;
! 4758: char time_format;
! 4759: UINT32 case_map;
! 4760: char list_sep[2];
! 4761: // char reserved[10];
! 4762: } *ci = (CI *)(mem + SREG_BASE(DS) + REG16(DX));
! 4763: memset(ci, 0, sizeof(*ci));
! 4764: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRDIGITS, LCdata, sizeof(LCdata));
! 4765: ci->currency_dec_digits = atoi(LCdata);
! 4766: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRENCY, LCdata, sizeof(LCdata));
! 4767: ci->currency_format = *LCdata - '0';
! 4768: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDATE, LCdata, sizeof(LCdata));
! 4769: ci->date_format = *LCdata - '0';
! 4770: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SCURRENCY, LCdata, sizeof(LCdata));
! 4771: memcpy(&ci->currency_symbol, LCdata, 4);
! 4772: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDATE, LCdata, sizeof(LCdata));
! 4773: *ci->date_sep = *LCdata;
! 4774: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, LCdata, sizeof(LCdata));
! 4775: *ci->dec_sep = *LCdata;
! 4776: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLIST, LCdata, sizeof(LCdata));
! 4777: *ci->list_sep = *LCdata;
! 4778: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, LCdata, sizeof(LCdata));
! 4779: *ci->thou_sep = *LCdata;
! 4780: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIME, LCdata, sizeof(LCdata));
! 4781: *ci->time_sep = *LCdata;
! 4782: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, LCdata, sizeof(LCdata));
! 4783: if(strchr(LCdata, 'H') != NULL) {
! 4784: ci->time_format = 1;
! 4785: }
! 4786: }
! 4787: break;
! 4788: default:
! 4789: REG16(AX) = 2;
! 4790: m_CF = 1;
! 4791: break;
! 4792: }
! 4793: }
! 4794:
1.1 root 4795: inline void msdos_int_21h_39h(int lfn)
4796: {
1.1.1.3 root 4797: if(_mkdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 4798: REG16(AX) = errno;
1.1.1.3 root 4799: m_CF = 1;
1.1 root 4800: }
4801: }
4802:
4803: inline void msdos_int_21h_3ah(int lfn)
4804: {
1.1.1.3 root 4805: if(_rmdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 4806: REG16(AX) = errno;
1.1.1.3 root 4807: m_CF = 1;
1.1 root 4808: }
4809: }
4810:
4811: inline void msdos_int_21h_3bh(int lfn)
4812: {
1.1.1.3 root 4813: if(_chdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 4814: REG16(AX) = errno;
1.1.1.3 root 4815: m_CF = 1;
1.1 root 4816: }
4817: }
4818:
4819: inline void msdos_int_21h_3ch()
4820: {
1.1.1.3 root 4821: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 4822: int attr = GetFileAttributes(path);
4823: int fd = -1;
1.1.1.11 root 4824: UINT16 info;
1.1 root 4825:
1.1.1.11 root 4826: if(msdos_is_con_path(path)) {
4827: fd = _open("CON", _O_WRONLY | _O_BINARY);
4828: info = 0x80d3;
1.1.1.14! root 4829: } else if(msdos_is_nul_path(path)) {
! 4830: fd = _open("NUL", _O_WRONLY | _O_BINARY);
! 4831: info = 0x80d3;
1.1 root 4832: } else {
4833: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 4834: info = msdos_drive_number(path);
1.1 root 4835: }
4836: if(fd != -1) {
4837: if(attr == -1) {
4838: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
4839: }
4840: SetFileAttributes(path, attr);
4841: REG16(AX) = fd;
1.1.1.11 root 4842: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp);
1.1 root 4843: } else {
4844: REG16(AX) = errno;
1.1.1.3 root 4845: m_CF = 1;
1.1 root 4846: }
4847: }
4848:
4849: inline void msdos_int_21h_3dh()
4850: {
1.1.1.3 root 4851: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 4852: int mode = REG8(AL) & 0x03;
1.1.1.11 root 4853: int fd = -1;
4854: UINT16 info;
1.1 root 4855:
4856: if(mode < 0x03) {
1.1.1.11 root 4857: if(msdos_is_con_path(path)) {
1.1.1.13 root 4858: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 4859: info = 0x80d3;
1.1.1.14! root 4860: } else if(msdos_is_nul_path(path)) {
! 4861: fd = msdos_open("NUL", file_mode[mode].mode);
! 4862: info = 0x80d3;
1.1.1.11 root 4863: } else {
1.1.1.13 root 4864: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 4865: info = msdos_drive_number(path);
4866: }
1.1 root 4867: if(fd != -1) {
4868: REG16(AX) = fd;
1.1.1.11 root 4869: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp);
1.1 root 4870: } else {
4871: REG16(AX) = errno;
1.1.1.3 root 4872: m_CF = 1;
1.1 root 4873: }
4874: } else {
4875: REG16(AX) = 0x0c;
1.1.1.3 root 4876: m_CF = 1;
1.1 root 4877: }
4878: }
4879:
4880: inline void msdos_int_21h_3eh()
4881: {
4882: process_t *process = msdos_process_info_get(current_psp);
4883:
4884: if(REG16(BX) < process->max_files && file_handler[REG16(BX)].valid) {
4885: _close(REG16(BX));
4886: msdos_file_handler_close(REG16(BX), current_psp);
4887: } else {
4888: REG16(AX) = 0x06;
1.1.1.3 root 4889: m_CF = 1;
1.1 root 4890: }
4891: }
4892:
4893: inline void msdos_int_21h_3fh()
4894: {
4895: process_t *process = msdos_process_info_get(current_psp);
4896:
4897: if(REG16(BX) < process->max_files && file_handler[REG16(BX)].valid) {
4898: if(file_mode[file_handler[REG16(BX)].mode].in) {
4899: if(file_handler[REG16(BX)].atty) {
4900: // BX is stdin or is redirected to stdin
1.1.1.3 root 4901: UINT8 *buf = mem + SREG_BASE(DS) + REG16(DX);
1.1 root 4902: int max = REG16(CX);
4903: int p = 0;
4904:
4905: while(max > p) {
4906: int chr = msdos_getch();
4907:
4908: if(chr == 0x00) {
4909: // skip 2nd byte
4910: msdos_getch();
4911: } else if(chr == 0x0d) {
4912: // carriage return
4913: buf[p++] = 0x0d;
4914: if(max > p) {
4915: buf[p++] = 0x0a;
4916: }
1.1.1.14! root 4917: msdos_putch('\n');
1.1 root 4918: break;
4919: } else if(chr == 0x08) {
4920: // back space
4921: if(p > 0) {
4922: p--;
4923: msdos_putch(chr);
4924: msdos_putch(' ');
4925: msdos_putch(chr);
4926: }
4927: } else {
4928: buf[p++] = chr;
4929: msdos_putch(chr);
4930: }
4931: }
4932: REG16(AX) = p;
1.1.1.8 root 4933: // some seconds may be passed in console
1.1 root 4934: hardware_update();
4935: } else {
1.1.1.3 root 4936: REG16(AX) = _read(REG16(BX), mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 4937: }
4938: } else {
4939: REG16(AX) = 0x05;
1.1.1.3 root 4940: m_CF = 1;
1.1 root 4941: }
4942: } else {
4943: REG16(AX) = 0x06;
1.1.1.3 root 4944: m_CF = 1;
1.1 root 4945: }
4946: }
4947:
4948: inline void msdos_int_21h_40h()
4949: {
4950: process_t *process = msdos_process_info_get(current_psp);
4951:
4952: if(REG16(BX) < process->max_files && file_handler[REG16(BX)].valid) {
4953: if(file_mode[file_handler[REG16(BX)].mode].out) {
4954: if(REG16(CX)) {
4955: if(file_handler[REG16(BX)].atty) {
4956: // BX is stdout/stderr or is redirected to stdout
4957: for(int i = 0; i < REG16(CX); i++) {
1.1.1.3 root 4958: msdos_putch(mem[SREG_BASE(DS) + REG16(DX) + i]);
1.1 root 4959: }
4960: REG16(AX) = REG16(CX);
4961: } else {
1.1.1.3 root 4962: REG16(AX) = msdos_write(REG16(BX), mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 4963: }
4964: } else {
4965: UINT32 pos = _tell(REG16(BX));
4966: _lseek(REG16(BX), 0, SEEK_END);
4967: UINT32 size = _tell(REG16(BX));
4968: REG16(AX) = 0;
1.1.1.12 root 4969: if(pos < size) {
4970: _lseek(REG16(BX), pos, SEEK_SET);
4971: SetEndOfFile((HANDLE)_get_osfhandle(REG16(BX)));
4972: } else {
4973: for(UINT32 i = size; i < pos; i++) {
4974: UINT8 tmp = 0;
4975: REG16(AX) += msdos_write(REG16(BX), &tmp, 1);
4976: }
4977: _lseek(REG16(BX), pos, SEEK_SET);
1.1 root 4978: }
4979: }
4980: } else {
4981: REG16(AX) = 0x05;
1.1.1.3 root 4982: m_CF = 1;
1.1 root 4983: }
4984: } else {
4985: REG16(AX) = 0x06;
1.1.1.3 root 4986: m_CF = 1;
1.1 root 4987: }
4988: }
4989:
4990: inline void msdos_int_21h_41h(int lfn)
4991: {
1.1.1.3 root 4992: if(remove(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 4993: REG16(AX) = errno;
1.1.1.3 root 4994: m_CF = 1;
1.1 root 4995: }
4996: }
4997:
4998: inline void msdos_int_21h_42h()
4999: {
5000: process_t *process = msdos_process_info_get(current_psp);
5001:
5002: if(REG16(BX) < process->max_files && file_handler[REG16(BX)].valid) {
5003: if(REG8(AL) < 0x03) {
5004: static int ptrname[] = { SEEK_SET, SEEK_CUR, SEEK_END };
5005: _lseek(REG16(BX), (REG16(CX) << 16) | REG16(DX), ptrname[REG8(AL)]);
5006: UINT32 pos = _tell(REG16(BX));
5007: REG16(AX) = pos & 0xffff;
5008: REG16(DX) = (pos >> 16);
5009: } else {
5010: REG16(AX) = 0x01;
1.1.1.3 root 5011: m_CF = 1;
1.1 root 5012: }
5013: } else {
5014: REG16(AX) = 0x06;
1.1.1.3 root 5015: m_CF = 1;
1.1 root 5016: }
5017: }
5018:
5019: inline void msdos_int_21h_43h(int lfn)
5020: {
1.1.1.3 root 5021: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn);
1.1 root 5022: int attr;
5023:
1.1.1.14! root 5024: if(!lfn && REG8(AL) > 2) {
! 5025: REG16(AX) = 0x01;
! 5026: m_CF = 1;
! 5027: return;
! 5028: }
! 5029: switch(REG8(lfn ? BL : AL)) {
1.1 root 5030: case 0x00:
5031: if((attr = GetFileAttributes(path)) != -1) {
1.1.1.14! root 5032: REG16(CX) = (UINT16)msdos_file_attribute_create((UINT16)attr);
! 5033: } else {
! 5034: REG16(AX) = (UINT16)GetLastError();
! 5035: m_CF = 1;
! 5036: }
! 5037: break;
! 5038: case 0x01:
! 5039: if(!SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)))) {
! 5040: REG16(AX) = (UINT16)GetLastError();
! 5041: m_CF = 1;
! 5042: }
! 5043: break;
! 5044: case 0x02:
! 5045: {
! 5046: DWORD size = GetCompressedFileSize(path, NULL);
! 5047: if(size != INVALID_FILE_SIZE) {
! 5048: if(size != 0 && size == GetFileSize(path, NULL)) {
! 5049: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
! 5050: // this isn't correct if the file is in the NTFS MFT
! 5051: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
! 5052: size = ((size - 1) | (sectors_per_cluster * bytes_per_sector - 1)) + 1;
! 5053: }
! 5054: }
! 5055: REG16(AX) = LOWORD(size);
! 5056: REG16(DX) = HIWORD(size);
! 5057: } else {
! 5058: REG16(AX) = (UINT16)GetLastError();
! 5059: m_CF = 1;
1.1 root 5060: }
1.1.1.14! root 5061: }
! 5062: break;
! 5063: case 0x03:
! 5064: case 0x05:
! 5065: case 0x07:
! 5066: {
! 5067: HANDLE hFile = CreateFile(path, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
! 5068: if(hFile != INVALID_HANDLE_VALUE) {
! 5069: FILETIME local, time;
! 5070: DosDateTimeToFileTime(REG16(DI), /*REG8(BL) == 5 ? 0 : */REG16(CX), &local);
! 5071: if(REG8(BL) == 7) {
! 5072: ULARGE_INTEGER hund;
! 5073: hund.LowPart = local.dwLowDateTime;
! 5074: hund.HighPart = local.dwHighDateTime;
! 5075: hund.QuadPart += REG16(SI) * 100000;
! 5076: local.dwLowDateTime = hund.LowPart;
! 5077: local.dwHighDateTime = hund.HighPart;
! 5078: }
! 5079: LocalFileTimeToFileTime(&local, &time);
! 5080: if(!SetFileTime(hFile, REG8(BL) == 0x07 ? &time : NULL,
! 5081: REG8(BL) == 0x05 ? &time : NULL,
! 5082: REG8(BL) == 0x03 ? &time : NULL)) {
! 5083: REG16(AX) = (UINT16)GetLastError();
! 5084: m_CF = 1;
! 5085: }
! 5086: CloseHandle(hFile);
! 5087: } else {
! 5088: REG16(AX) = (UINT16)GetLastError();
! 5089: m_CF = 1;
1.1 root 5090: }
1.1.1.14! root 5091: }
! 5092: break;
! 5093: case 0x04:
! 5094: case 0x06:
! 5095: case 0x08:
! 5096: {
! 5097: WIN32_FILE_ATTRIBUTE_DATA fad;
! 5098: if(GetFileAttributesEx(path, GetFileExInfoStandard, (LPVOID)&fad)) {
! 5099: FILETIME *time, local;
! 5100: time = REG8(BL) == 0x04 ? &fad.ftLastWriteTime :
! 5101: 0x06 ? &fad.ftLastAccessTime :
! 5102: &fad.ftCreationTime;
! 5103: FileTimeToLocalFileTime(time, &local);
! 5104: FileTimeToDosDateTime(&local, ®16(DI), ®16(CX));
! 5105: if(REG8(BL) == 0x08) {
! 5106: ULARGE_INTEGER hund;
! 5107: hund.LowPart = local.dwLowDateTime;
! 5108: hund.HighPart = local.dwHighDateTime;
! 5109: hund.QuadPart /= 100000;
! 5110: REG16(SI) = (UINT16)(hund.QuadPart % 200);
! 5111: }
! 5112: } else {
! 5113: REG16(AX) = (UINT16)GetLastError();
! 5114: m_CF = 1;
1.1 root 5115: }
1.1.1.14! root 5116: }
! 5117: break;
! 5118: default:
! 5119: REG16(AX) = 0x01;
! 5120: m_CF = 1;
! 5121: break;
! 5122: }
! 5123: }
! 5124:
! 5125: inline void msdos_int_21h_44h()
! 5126: {
! 5127: UINT32 val = DRIVE_NO_ROOT_DIR;
! 5128:
! 5129: switch(REG8(AL)) {
! 5130: case 0x00:
! 5131: case 0x01:
! 5132: case 0x02:
! 5133: case 0x03:
! 5134: case 0x04:
! 5135: case 0x05:
! 5136: case 0x06:
! 5137: case 0x07:
! 5138: {
! 5139: process_t *process = msdos_process_info_get(current_psp);
! 5140:
! 5141: if(REG16(BX) >= process->max_files || !file_handler[REG16(BX)].valid) {
! 5142: REG16(AX) = 0x06;
! 5143: m_CF = 1;
! 5144: return;
! 5145: }
! 5146: }
! 5147: break;
! 5148: case 0x08:
! 5149: case 0x09:
! 5150: if(REG8(BL) >= ('Z' - 'A' + 1)) {
! 5151: // invalid drive number
! 5152: REG16(AX) = 0x0f;
! 5153: m_CF = 1;
! 5154: return;
! 5155: } else {
! 5156: if(REG8(BL) == 0) {
! 5157: val = GetDriveType(NULL);
! 5158: } else {
! 5159: char tmp[8];
! 5160: sprintf(tmp, "%c:\\", 'A' + REG8(BL) - 1);
! 5161: val = GetDriveType(tmp);
! 5162: }
! 5163: if(val == DRIVE_NO_ROOT_DIR) {
! 5164: // no drive
! 5165: REG16(AX) = 0x0f;
! 5166: m_CF = 1;
! 5167: return;
1.1 root 5168: }
5169: }
5170: break;
5171: }
5172: switch(REG8(AL)) {
5173: case 0x00: // get ioctrl data
5174: REG16(DX) = file_handler[REG16(BX)].info;
5175: break;
5176: case 0x01: // set ioctrl data
5177: file_handler[REG16(BX)].info |= REG8(DL);
5178: break;
5179: case 0x02: // recv from character device
5180: case 0x03: // send to character device
5181: case 0x04: // recv from block device
5182: case 0x05: // send to block device
5183: REG16(AX) = 0x05;
1.1.1.3 root 5184: m_CF = 1;
1.1 root 5185: break;
5186: case 0x06: // get read status
1.1.1.14! root 5187: if(file_mode[file_handler[REG16(BX)].mode].in) {
! 5188: if(file_handler[REG16(BX)].atty) {
! 5189: REG8(AL) = msdos_kbhit() ? 0xff : 0x00;
1.1 root 5190: } else {
1.1.1.14! root 5191: REG8(AL) = eof(REG16(BX)) ? 0x00 : 0xff;
1.1 root 5192: }
1.1.1.14! root 5193: } else {
! 5194: REG8(AL) = 0x00;
1.1 root 5195: }
5196: break;
5197: case 0x07: // get write status
1.1.1.14! root 5198: if(file_mode[file_handler[REG16(BX)].mode].out) {
! 5199: REG8(AL) = 0xff;
! 5200: } else {
! 5201: REG8(AL) = 0x00;
1.1 root 5202: }
5203: break;
5204: case 0x08: // check removable drive
1.1.1.14! root 5205: if(val == DRIVE_REMOVABLE || val == DRIVE_CDROM) {
! 5206: // removable drive
! 5207: REG16(AX) = 0x00;
1.1 root 5208: } else {
1.1.1.14! root 5209: // fixed drive
! 5210: REG16(AX) = 0x01;
1.1 root 5211: }
5212: break;
5213: case 0x09: // check remote drive
1.1.1.14! root 5214: if(val == DRIVE_REMOTE) {
! 5215: // remote drive
! 5216: REG16(DX) = 0x1000;
1.1 root 5217: } else {
1.1.1.14! root 5218: // local drive
! 5219: REG16(DX) = 0x00;
1.1 root 5220: }
5221: break;
5222: case 0x0b: // set retry count
5223: break;
5224: default:
5225: REG16(AX) = 0x01;
1.1.1.3 root 5226: m_CF = 1;
1.1 root 5227: break;
5228: }
5229: }
5230:
5231: inline void msdos_int_21h_45h()
5232: {
5233: process_t *process = msdos_process_info_get(current_psp);
5234:
5235: if(REG16(BX) < process->max_files && file_handler[REG16(BX)].valid) {
5236: int fd = _dup(REG16(BX));
5237: if(fd != -1) {
5238: REG16(AX) = fd;
5239: msdos_file_handler_dup(REG16(AX), REG16(BX), current_psp);
5240: } else {
5241: REG16(AX) = errno;
1.1.1.3 root 5242: m_CF = 1;
1.1 root 5243: }
5244: } else {
5245: REG16(AX) = 0x06;
1.1.1.3 root 5246: m_CF = 1;
1.1 root 5247: }
5248: }
5249:
5250: inline void msdos_int_21h_46h()
5251: {
5252: process_t *process = msdos_process_info_get(current_psp);
5253:
5254: if(REG16(BX) < process->max_files && REG16(CX) < process->max_files && file_handler[REG16(BX)].valid) {
5255: if(_dup2(REG16(BX), REG16(CX)) != -1) {
5256: msdos_file_handler_dup(REG16(CX), REG16(BX), current_psp);
5257: } else {
5258: REG16(AX) = errno;
1.1.1.3 root 5259: m_CF = 1;
1.1 root 5260: }
5261: } else {
5262: REG16(AX) = 0x06;
1.1.1.3 root 5263: m_CF = 1;
1.1 root 5264: }
5265: }
5266:
5267: inline void msdos_int_21h_47h(int lfn)
5268: {
5269: char path[MAX_PATH];
5270:
5271: if(_getdcwd(REG8(DL), path, MAX_PATH) != NULL) {
5272: if(path[1] == ':') {
5273: // the returned path does not include a drive or the initial backslash
1.1.1.3 root 5274: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), (lfn ? path : msdos_short_path(path)) + 3);
1.1 root 5275: } else {
1.1.1.3 root 5276: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn ? path : msdos_short_path(path));
1.1 root 5277: }
5278: } else {
5279: REG16(AX) = errno;
1.1.1.3 root 5280: m_CF = 1;
1.1 root 5281: }
5282: }
5283:
5284: inline void msdos_int_21h_48h()
5285: {
5286: int seg;
5287:
1.1.1.8 root 5288: if((malloc_strategy & 0xf0) == 0x00) {
5289: if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
5290: REG16(AX) = seg;
5291: } else {
5292: REG16(AX) = 0x08;
5293: REG16(BX) = msdos_mem_get_free(first_mcb, 0);
5294: m_CF = 1;
5295: }
5296: } else if((malloc_strategy & 0xf0) == 0x40) {
5297: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
5298: REG16(AX) = seg;
5299: } else {
5300: REG16(AX) = 0x08;
5301: REG16(BX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
5302: m_CF = 1;
5303: }
5304: } else if((malloc_strategy & 0xf0) == 0x80) {
5305: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
5306: REG16(AX) = seg;
5307: } else if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
5308: REG16(AX) = seg;
5309: } else {
5310: REG16(AX) = 0x08;
5311: REG16(BX) = max(msdos_mem_get_free(UMB_TOP >> 4, 0), msdos_mem_get_free(first_mcb, 0));
5312: m_CF = 1;
5313: }
1.1 root 5314: }
5315: }
5316:
5317: inline void msdos_int_21h_49h()
5318: {
1.1.1.14! root 5319: int mcb_seg = SREG(ES) - 1;
! 5320: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
! 5321:
! 5322: if(mcb->mz == 'M' || mcb->mz == 'Z') {
! 5323: msdos_mem_free(SREG(ES));
! 5324: } else {
! 5325: REG16(AX) = 9;
! 5326: m_CF = 1;
! 5327: }
1.1 root 5328: }
5329:
5330: inline void msdos_int_21h_4ah()
5331: {
1.1.1.14! root 5332: int mcb_seg = SREG(ES) - 1;
! 5333: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1 root 5334: int max_paragraphs;
5335:
1.1.1.14! root 5336: if(mcb->mz == 'M' || mcb->mz == 'Z') {
! 5337: if(msdos_mem_realloc(SREG(ES), REG16(BX), &max_paragraphs)) {
! 5338: REG16(AX) = 0x08;
! 5339: REG16(BX) = max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs;
! 5340: m_CF = 1;
! 5341: }
! 5342: } else {
! 5343: REG16(AX) = 7;
1.1.1.3 root 5344: m_CF = 1;
1.1 root 5345: }
5346: }
5347:
5348: inline void msdos_int_21h_4bh()
5349: {
1.1.1.3 root 5350: char *command = (char *)(mem + SREG_BASE(DS) + REG16(DX));
5351: param_block_t *param = (param_block_t *)(mem + SREG_BASE(ES) + REG16(BX));
1.1 root 5352:
5353: switch(REG8(AL)) {
5354: case 0x00:
5355: case 0x01:
5356: if(msdos_process_exec(command, param, REG8(AL))) {
5357: REG16(AX) = 0x02;
1.1.1.3 root 5358: m_CF = 1;
1.1 root 5359: }
5360: break;
1.1.1.14! root 5361: case 0x03:
! 5362: {
! 5363: int fd;
! 5364: if((fd = _open(command, _O_RDONLY | _O_BINARY)) == -1) {
! 5365: REG16(AX) = 0x02;
! 5366: m_CF = 1;
! 5367: break;
! 5368: }
! 5369: int size = _read(fd, file_buffer, sizeof(file_buffer));
! 5370: _close(fd);
! 5371:
! 5372: UINT16 *overlay = (UINT16 *)param;
! 5373:
! 5374: // check exe header
! 5375: exe_header_t *header = (exe_header_t *)file_buffer;
! 5376: int header_size = 0;
! 5377: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
! 5378: header_size = header->header_size * 16;
! 5379: // relocation
! 5380: int start_seg = overlay[1];
! 5381: for(int i = 0; i < header->relocations; i++) {
! 5382: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
! 5383: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
! 5384: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
! 5385: }
! 5386: }
! 5387: memcpy(mem + (overlay[0] << 4), file_buffer + header_size, size - header_size);
! 5388: }
! 5389: break;
1.1 root 5390: default:
5391: REG16(AX) = 0x01;
1.1.1.3 root 5392: m_CF = 1;
1.1 root 5393: break;
5394: }
5395: }
5396:
5397: inline void msdos_int_21h_4ch()
5398: {
5399: msdos_process_terminate(current_psp, REG8(AL), 1);
5400: }
5401:
5402: inline void msdos_int_21h_4dh()
5403: {
5404: REG16(AX) = retval;
5405: }
5406:
5407: inline void msdos_int_21h_4eh()
5408: {
5409: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 5410: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5411: find_t *find = (find_t *)(mem + dta_laddr);
1.1.1.3 root 5412: char *path = msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 5413: WIN32_FIND_DATA fd;
5414:
1.1.1.14! root 5415: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
! 5416: find->find_magic = FIND_MAGIC;
! 5417: find->dta_index = dtainfo - dtalist;
1.1 root 5418: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14! root 5419: dtainfo->allowable_mask = REG8(CL);
! 5420: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 5421:
1.1.1.14! root 5422: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
! 5423: dtainfo->allowable_mask &= ~8;
1.1 root 5424: }
1.1.1.14! root 5425: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
! 5426: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 5427: !msdos_find_file_has_8dot3name(&fd)) {
5428: if(!FindNextFile(dtainfo->find_handle, &fd)) {
5429: FindClose(dtainfo->find_handle);
5430: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 5431: break;
5432: }
5433: }
5434: }
1.1.1.13 root 5435: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 5436: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
5437: msdos_find_file_conv_local_time(&fd);
5438: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
5439: find->size = fd.nFileSizeLow;
1.1.1.13 root 5440: strcpy(find->name, msdos_short_name(&fd));
1.1 root 5441: REG16(AX) = 0;
1.1.1.14! root 5442: } else if(dtainfo->allowable_mask & 8) {
1.1 root 5443: find->attrib = 8;
5444: find->size = 0;
5445: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14! root 5446: dtainfo->allowable_mask &= ~8;
1.1 root 5447: REG16(AX) = 0;
5448: } else {
5449: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 5450: m_CF = 1;
1.1 root 5451: }
5452: }
5453:
5454: inline void msdos_int_21h_4fh()
5455: {
5456: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 5457: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5458: find_t *find = (find_t *)(mem + dta_laddr);
1.1 root 5459: WIN32_FIND_DATA fd;
5460:
1.1.1.14! root 5461: if(find->find_magic != FIND_MAGIC || find->dta_index >= MAX_DTAINFO) {
! 5462: REG16(AX) = 0x12;
! 5463: m_CF = 1;
! 5464: return;
! 5465: }
! 5466: dtainfo_t *dtainfo = &dtalist[find->dta_index];
1.1.1.13 root 5467: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
5468: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14! root 5469: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 5470: !msdos_find_file_has_8dot3name(&fd)) {
5471: if(!FindNextFile(dtainfo->find_handle, &fd)) {
5472: FindClose(dtainfo->find_handle);
5473: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 5474: break;
5475: }
5476: }
5477: } else {
1.1.1.13 root 5478: FindClose(dtainfo->find_handle);
5479: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 5480: }
5481: }
1.1.1.13 root 5482: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 5483: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
5484: msdos_find_file_conv_local_time(&fd);
5485: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
5486: find->size = fd.nFileSizeLow;
1.1.1.13 root 5487: strcpy(find->name, msdos_short_name(&fd));
1.1 root 5488: REG16(AX) = 0;
1.1.1.14! root 5489: } else if(dtainfo->allowable_mask & 8) {
1.1 root 5490: find->attrib = 8;
5491: find->size = 0;
5492: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14! root 5493: dtainfo->allowable_mask &= ~8;
1.1 root 5494: REG16(AX) = 0;
5495: } else {
5496: REG16(AX) = 0x12;
1.1.1.3 root 5497: m_CF = 1;
1.1 root 5498: }
5499: }
5500:
5501: inline void msdos_int_21h_50h()
5502: {
1.1.1.8 root 5503: if(current_psp != REG16(BX)) {
5504: process_t *process = msdos_process_info_get(current_psp);
5505: if(process != NULL) {
5506: process->psp = REG16(BX);
5507: }
5508: current_psp = REG16(BX);
5509: }
1.1 root 5510: }
5511:
5512: inline void msdos_int_21h_51h()
5513: {
5514: REG16(BX) = current_psp;
5515: }
5516:
5517: inline void msdos_int_21h_52h()
5518: {
1.1.1.3 root 5519: SREG(ES) = (DOS_INFO_BASE >> 4);
5520: i386_load_segment_descriptor(ES);
1.1 root 5521: REG16(BX) = (DOS_INFO_BASE & 0x0f);
5522: }
5523:
5524: inline void msdos_int_21h_54h()
5525: {
5526: process_t *process = msdos_process_info_get(current_psp);
5527:
5528: REG8(AL) = process->verify;
5529: }
5530:
5531: inline void msdos_int_21h_55h()
5532: {
5533: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
5534:
5535: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
5536: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
5537: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
5538: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
5539: psp->parent_psp = current_psp;
5540: }
5541:
5542: inline void msdos_int_21h_56h(int lfn)
5543: {
5544: char src[MAX_PATH], dst[MAX_PATH];
1.1.1.3 root 5545: strcpy(src, msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn));
5546: strcpy(dst, msdos_trimmed_path((char *)(mem + SREG_BASE(ES) + REG16(DI)), lfn));
1.1 root 5547:
5548: if(rename(src, dst)) {
5549: REG16(AX) = errno;
1.1.1.3 root 5550: m_CF = 1;
1.1 root 5551: }
5552: }
5553:
5554: inline void msdos_int_21h_57h()
5555: {
5556: FILETIME time, local;
1.1.1.14! root 5557: FILETIME *ctime, *atime, *mtime;
1.1.1.6 root 5558: HANDLE handle;
1.1 root 5559:
1.1.1.14! root 5560: if((handle = (HANDLE)_get_osfhandle(REG16(BX))) == INVALID_HANDLE_VALUE) {
! 5561: REG16(AX) = (UINT16)GetLastError();
! 5562: m_CF = 1;
! 5563: return;
! 5564: }
! 5565: ctime = atime = mtime = NULL;
! 5566:
1.1 root 5567: switch(REG8(AL)) {
5568: case 0x00:
1.1.1.6 root 5569: case 0x01:
1.1.1.14! root 5570: mtime = &time;
1.1.1.6 root 5571: break;
5572: case 0x04:
5573: case 0x05:
1.1.1.14! root 5574: atime = &time;
1.1 root 5575: break;
1.1.1.6 root 5576: case 0x06:
5577: case 0x07:
1.1.1.14! root 5578: ctime = &time;
! 5579: break;
! 5580: default:
! 5581: REG16(AX) = 0x01;
! 5582: m_CF = 1;
! 5583: return;
! 5584: }
! 5585: if(REG8(AL) & 1) {
1.1 root 5586: DosDateTimeToFileTime(REG16(DX), REG16(CX), &local);
5587: LocalFileTimeToFileTime(&local, &time);
1.1.1.14! root 5588: if(!SetFileTime(handle, ctime, atime, mtime)) {
1.1 root 5589: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 5590: m_CF = 1;
1.1 root 5591: }
1.1.1.14! root 5592: } else {
! 5593: if(!GetFileTime(handle, ctime, atime, mtime)) {
! 5594: // assume a device and use the current time
! 5595: GetSystemTimeAsFileTime(&time);
! 5596: }
! 5597: FileTimeToLocalFileTime(&time, &local);
! 5598: FileTimeToDosDateTime(&local, ®16(DX), ®16(CX));
1.1 root 5599: }
5600: }
5601:
5602: inline void msdos_int_21h_58h()
5603: {
5604: switch(REG8(AL)) {
5605: case 0x00:
1.1.1.7 root 5606: REG16(AX) = malloc_strategy;
5607: break;
5608: case 0x01:
5609: switch(REG16(BX)) {
5610: case 0x0000:
5611: case 0x0001:
5612: case 0x0002:
5613: case 0x0040:
5614: case 0x0041:
5615: case 0x0042:
5616: case 0x0080:
5617: case 0x0081:
5618: case 0x0082:
5619: malloc_strategy = REG16(BX);
5620: break;
5621: default:
5622: REG16(AX) = 0x01;
5623: m_CF = 1;
5624: break;
5625: }
5626: break;
5627: case 0x02:
5628: REG8(AL) = umb_linked;
5629: break;
5630: case 0x03:
5631: switch(REG16(BX)) {
5632: case 0x0000:
5633: case 0x0001:
5634: umb_linked = REG8(BL);
5635: break;
5636: default:
5637: REG16(AX) = 0x01;
5638: m_CF = 1;
5639: break;
5640: }
1.1 root 5641: break;
5642: default:
5643: REG16(AX) = 0x01;
1.1.1.3 root 5644: m_CF = 1;
1.1 root 5645: break;
5646: }
5647: }
5648:
5649: inline void msdos_int_21h_59h()
5650: {
5651: REG16(AX) = error_code;
5652: switch(error_code) {
5653: case 4: // Too many open files
5654: case 8: // Insufficient memory
5655: REG8(BH) = 1; // Out of resource
5656: break;
5657: case 5: // Access denied
5658: REG8(BH) = 3; // Authorization
5659: break;
5660: case 7: // Memory control block destroyed
5661: REG8(BH) = 4; // Internal
5662: break;
5663: case 2: // File not found
5664: case 3: // Path not found
5665: case 15: // Invaid drive specified
5666: case 18: // No more files
5667: REG8(BH) = 8; // Not found
5668: break;
5669: case 32: // Sharing violation
5670: case 33: // Lock violation
5671: REG8(BH) = 10; // Locked
5672: break;
5673: // case 16: // Removal of current directory attempted
5674: case 19: // Attempted write on protected disk
5675: case 21: // Drive not ready
5676: // case 29: // Write failure
5677: // case 30: // Read failure
5678: // case 82: // Cannot create subdirectory
5679: REG8(BH) = 11; // Media
5680: break;
5681: case 80: // File already exists
5682: REG8(BH) = 12; // Already exist
5683: break;
5684: default:
5685: REG8(BH) = 13; // Unknown
5686: break;
5687: }
5688: REG8(BL) = 1; // Retry
5689: REG8(CH) = 1; // Unknown
5690: }
5691:
5692: inline void msdos_int_21h_5ah()
5693: {
1.1.1.3 root 5694: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 5695: int len = strlen(path);
5696: char tmp[MAX_PATH];
5697:
5698: if(GetTempFileName(path, "TMP", 0, tmp)) {
5699: int fd = _open(tmp, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
5700:
5701: SetFileAttributes(tmp, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
5702: REG16(AX) = fd;
5703: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
5704:
5705: strcpy(path, tmp);
5706: int dx = REG16(DX) + len;
1.1.1.3 root 5707: int ds = SREG(DS);
1.1 root 5708: while(dx > 0xffff) {
5709: dx -= 0x10;
5710: ds++;
5711: }
5712: REG16(DX) = dx;
1.1.1.3 root 5713: SREG(DS) = ds;
5714: i386_load_segment_descriptor(DS);
1.1 root 5715: } else {
5716: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 5717: m_CF = 1;
1.1 root 5718: }
5719: }
5720:
5721: inline void msdos_int_21h_5bh()
5722: {
1.1.1.3 root 5723: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 5724:
5725: if(_access(path, 0) == 0) {
5726: // already exists
5727: REG16(AX) = 0x50;
1.1.1.3 root 5728: m_CF = 1;
1.1 root 5729: } else {
5730: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
5731:
5732: if(fd != -1) {
5733: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
5734: REG16(AX) = fd;
5735: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
5736: } else {
5737: REG16(AX) = errno;
1.1.1.3 root 5738: m_CF = 1;
1.1 root 5739: }
5740: }
5741: }
5742:
5743: inline void msdos_int_21h_5ch()
5744: {
5745: process_t *process = msdos_process_info_get(current_psp);
5746:
5747: if(REG16(BX) < process->max_files && file_handler[REG16(BX)].valid) {
5748: if(REG8(AL) == 0 || REG8(AL) == 1) {
5749: static int modes[2] = {_LK_LOCK, _LK_UNLCK};
5750: UINT32 pos = _tell(REG16(BX));
5751: _lseek(REG16(BX), (REG16(CX) << 16) | REG16(DX), SEEK_SET);
5752: if(_locking(REG16(BX), modes[REG8(AL)], (REG16(SI) << 16) | REG16(DI))) {
5753: REG16(AX) = errno;
1.1.1.3 root 5754: m_CF = 1;
1.1 root 5755: }
5756: _lseek(REG16(BX), pos, SEEK_SET);
5757: // some seconds may be passed in _locking()
5758: hardware_update();
5759: } else {
5760: REG16(AX) = 0x01;
1.1.1.3 root 5761: m_CF = 1;
1.1 root 5762: }
5763: } else {
5764: REG16(AX) = 0x06;
1.1.1.3 root 5765: m_CF = 1;
1.1 root 5766: }
5767: }
5768:
5769: inline void msdos_int_21h_60h(int lfn)
5770: {
1.1.1.14! root 5771: char full[MAX_PATH], *path;
! 5772:
1.1 root 5773: if(lfn) {
1.1.1.14! root 5774: char *name;
! 5775: *full = '\0';
1.1.1.3 root 5776: GetFullPathName((char *)(mem + SREG_BASE(DS) + REG16(SI)), MAX_PATH, full, &name);
1.1.1.14! root 5777: switch(REG8(CL)) {
! 5778: case 1:
! 5779: GetShortPathName(full, full, MAX_PATH);
! 5780: my_strupr(full);
! 5781: break;
! 5782: case 2:
! 5783: GetLongPathName(full, full, MAX_PATH);
! 5784: break;
! 5785: }
! 5786: path = full;
! 5787: } else {
! 5788: path = msdos_short_full_path((char *)(mem + SREG_BASE(DS) + REG16(SI)));
! 5789: }
! 5790: if(*path != '\0') {
! 5791: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path);
1.1 root 5792: } else {
1.1.1.14! root 5793: REG16(AX) = (UINT16)GetLastError();
! 5794: m_CF = 1;
1.1 root 5795: }
5796: }
5797:
5798: inline void msdos_int_21h_61h()
5799: {
5800: REG8(AL) = 0;
5801: }
5802:
5803: inline void msdos_int_21h_62h()
5804: {
5805: REG16(BX) = current_psp;
5806: }
5807:
5808: inline void msdos_int_21h_63h()
5809: {
5810: switch(REG8(AL)) {
5811: case 0x00:
1.1.1.3 root 5812: SREG(DS) = (DBCS_TABLE >> 4);
5813: i386_load_segment_descriptor(DS);
1.1 root 5814: REG16(SI) = (DBCS_TABLE & 0x0f);
5815: REG8(AL) = 0x00;
5816: break;
5817: default:
5818: REG16(AX) = 0x01;
1.1.1.3 root 5819: m_CF = 1;
1.1 root 5820: break;
5821: }
5822: }
5823:
5824: inline void msdos_int_21h_65h()
5825: {
5826: char tmp[0x10000];
5827:
5828: switch(REG8(AL)) {
5829: case 0x07:
1.1.1.3 root 5830: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x07;
5831: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (DBCS_TOP & 0x0f);
5832: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (DBCS_TOP >> 4);
1.1 root 5833: REG16(CX) = 0x05;
5834: break;
5835: case 0x20:
5836: sprintf(tmp, "%c", REG8(DL));
5837: my_strupr(tmp);
5838: REG8(DL) = tmp[0];
5839: break;
5840: case 0x21:
5841: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 5842: memcpy(tmp, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 5843: my_strupr(tmp);
1.1.1.3 root 5844: memcpy(mem + SREG_BASE(DS) + REG16(DX), tmp, REG16(CX));
1.1 root 5845: break;
5846: case 0x22:
1.1.1.3 root 5847: my_strupr((char *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1 root 5848: break;
5849: default:
5850: REG16(AX) = 0x01;
1.1.1.3 root 5851: m_CF = 1;
1.1 root 5852: break;
5853: }
5854: }
5855:
5856: inline void msdos_int_21h_66h()
5857: {
5858: switch(REG8(AL)) {
5859: case 0x01:
5860: REG16(BX) = active_code_page;
5861: REG16(DX) = system_code_page;
5862: break;
5863: case 0x02:
5864: if(active_code_page == REG16(BX)) {
5865: REG16(AX) = 0xeb41;
5866: } else if(_setmbcp(REG16(BX)) == 0) {
5867: active_code_page = REG16(BX);
5868: msdos_dbcs_table_update();
5869: REG16(AX) = 0xeb41;
5870: } else {
5871: REG16(AX) = 0x25;
1.1.1.3 root 5872: m_CF = 1;
1.1 root 5873: }
5874: break;
5875: default:
5876: REG16(AX) = 0x01;
1.1.1.3 root 5877: m_CF = 1;
1.1 root 5878: break;
5879: }
5880: }
5881:
5882: inline void msdos_int_21h_67h()
5883: {
5884: process_t *process = msdos_process_info_get(current_psp);
5885:
5886: if(REG16(BX) <= MAX_FILES) {
5887: process->max_files = max(REG16(BX), 20);
5888: } else {
5889: REG16(AX) = 0x08;
1.1.1.3 root 5890: m_CF = 1;
1.1 root 5891: }
5892: }
5893:
5894: inline void msdos_int_21h_68h()
5895: {
5896: process_t *process = msdos_process_info_get(current_psp);
5897:
5898: if(REG16(BX) < process->max_files && file_handler[REG16(BX)].valid) {
5899: // fflush(_fdopen(REG16(BX), ""));
5900: } else {
5901: REG16(AX) = 0x06;
1.1.1.3 root 5902: m_CF = 1;
1.1 root 5903: }
5904: }
5905:
5906: inline void msdos_int_21h_69h()
5907: {
1.1.1.3 root 5908: drive_info_t *info = (drive_info_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 5909: char path[] = "A:\\";
5910: char volume_label[MAX_PATH];
5911: DWORD serial_number = 0;
5912: char file_system[MAX_PATH];
5913:
5914: if(REG8(BL) == 0) {
5915: path[0] = 'A' + _getdrive() - 1;
5916: } else {
5917: path[0] = 'A' + REG8(BL) - 1;
5918: }
5919:
5920: switch(REG8(AL)) {
5921: case 0x00:
5922: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
5923: info->info_level = 0;
5924: info->serial_number = serial_number;
5925: memset(info->volume_label, 0x20, 11);
5926: memcpy(info->volume_label, volume_label, min(strlen(volume_label), 11));
5927: memset(info->file_system, 0x20, 8);
5928: memcpy(info->file_system, file_system, min(strlen(file_system), 8));
5929: } else {
5930: REG16(AX) = errno;
1.1.1.3 root 5931: m_CF = 1;
1.1 root 5932: }
5933: break;
5934: case 0x01:
5935: REG16(AX) = 0x03;
1.1.1.3 root 5936: m_CF = 1;
1.1 root 5937: }
5938: }
5939:
5940: inline void msdos_int_21h_6ah()
5941: {
5942: REG8(AH) = 0x68;
5943: msdos_int_21h_68h();
5944: }
5945:
5946: inline void msdos_int_21h_6bh()
5947: {
5948: REG8(AL) = 0;
5949: }
5950:
5951: inline void msdos_int_21h_6ch(int lfn)
5952: {
1.1.1.3 root 5953: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn);
1.1 root 5954: int mode = REG8(BL) & 0x03;
5955:
5956: if(mode < 0x03) {
5957: if(_access(path, 0) == 0) {
5958: // file exists
5959: if(REG8(DL) & 1) {
1.1.1.11 root 5960: int fd = -1;
5961: UINT16 info;
1.1 root 5962:
1.1.1.11 root 5963: if(msdos_is_con_path(path)) {
1.1.1.13 root 5964: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 5965: info = 0x80d3;
1.1.1.14! root 5966: } else if(msdos_is_nul_path(path)) {
! 5967: fd = msdos_open("NUL", file_mode[mode].mode);
! 5968: info = 0x80d3;
1.1.1.11 root 5969: } else {
1.1.1.13 root 5970: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 5971: info = msdos_drive_number(path);
5972: }
1.1 root 5973: if(fd != -1) {
5974: REG16(AX) = fd;
5975: REG16(CX) = 1;
1.1.1.11 root 5976: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp);
1.1 root 5977: } else {
5978: REG16(AX) = errno;
1.1.1.3 root 5979: m_CF = 1;
1.1 root 5980: }
5981: } else if(REG8(DL) & 2) {
5982: int attr = GetFileAttributes(path);
5983: int fd = -1;
1.1.1.11 root 5984: UINT16 info;
1.1 root 5985:
1.1.1.11 root 5986: if(msdos_is_con_path(path)) {
1.1.1.13 root 5987: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 5988: info = 0x80d3;
1.1.1.14! root 5989: } else if(msdos_is_nul_path(path)) {
! 5990: fd = msdos_open("NUL", file_mode[mode].mode);
! 5991: info = 0x80d3;
1.1 root 5992: } else {
5993: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 5994: info = msdos_drive_number(path);
1.1 root 5995: }
5996: if(fd != -1) {
5997: if(attr == -1) {
5998: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
5999: }
6000: SetFileAttributes(path, attr);
6001: REG16(AX) = fd;
6002: REG16(CX) = 3;
1.1.1.11 root 6003: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp);
1.1 root 6004: } else {
6005: REG16(AX) = errno;
1.1.1.3 root 6006: m_CF = 1;
1.1 root 6007: }
6008: } else {
6009: REG16(AX) = 0x50;
1.1.1.3 root 6010: m_CF = 1;
1.1 root 6011: }
6012: } else {
6013: // file not exists
6014: if(REG8(DL) & 0x10) {
6015: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
6016:
6017: if(fd != -1) {
6018: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
6019: REG16(AX) = fd;
6020: REG16(CX) = 2;
6021: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
6022: } else {
6023: REG16(AX) = errno;
1.1.1.3 root 6024: m_CF = 1;
1.1 root 6025: }
6026: } else {
6027: REG16(AX) = 0x02;
1.1.1.3 root 6028: m_CF = 1;
1.1 root 6029: }
6030: }
6031: } else {
6032: REG16(AX) = 0x0c;
1.1.1.3 root 6033: m_CF = 1;
1.1 root 6034: }
6035: }
6036:
6037: inline void msdos_int_21h_710dh()
6038: {
6039: // reset drive
6040: }
6041:
6042: inline void msdos_int_21h_714eh()
6043: {
6044: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 6045: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
6046: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 6047: WIN32_FIND_DATA fd;
6048:
1.1.1.13 root 6049: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
6050: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
6051: FindClose(dtainfo->find_handle);
6052: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6053: }
6054: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14! root 6055: dtainfo->allowable_mask = REG8(CL);
! 6056: dtainfo->required_mask = REG8(CH);
! 6057: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 6058:
1.1.1.14! root 6059: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
! 6060: dtainfo->allowable_mask &= ~8;
1.1 root 6061: }
1.1.1.14! root 6062: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
! 6063: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 6064: if(!FindNextFile(dtainfo->find_handle, &fd)) {
6065: FindClose(dtainfo->find_handle);
6066: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6067: break;
6068: }
6069: }
6070: }
1.1.1.13 root 6071: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 6072: find->attrib = fd.dwFileAttributes;
6073: msdos_find_file_conv_local_time(&fd);
6074: if(REG16(SI) == 0) {
6075: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
6076: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
6077: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
6078: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
6079: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
6080: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
6081: } else {
6082: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
6083: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
6084: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
6085: }
6086: find->size_hi = fd.nFileSizeHigh;
6087: find->size_lo = fd.nFileSizeLow;
6088: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 6089: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14! root 6090: REG16(AX) = dtainfo - dtalist + 1;
! 6091: } else if(dtainfo->allowable_mask & 8) {
1.1 root 6092: // volume label
6093: find->attrib = 8;
6094: find->size_hi = find->size_lo = 0;
6095: strcpy(find->full_name, process->volume_label);
6096: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14! root 6097: dtainfo->allowable_mask &= ~8;
! 6098: REG16(AX) = dtainfo - dtalist + 1;
1.1 root 6099: } else {
6100: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 6101: m_CF = 1;
1.1 root 6102: }
6103: }
6104:
6105: inline void msdos_int_21h_714fh()
6106: {
6107: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 6108: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 6109: WIN32_FIND_DATA fd;
6110:
1.1.1.14! root 6111: if(REG16(BX) - 1u >= MAX_DTAINFO) {
! 6112: REG16(AX) = 6;
1.1.1.13 root 6113: m_CF = 1;
6114: return;
6115: }
1.1.1.14! root 6116: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 6117: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
6118: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14! root 6119: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 6120: if(!FindNextFile(dtainfo->find_handle, &fd)) {
6121: FindClose(dtainfo->find_handle);
6122: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6123: break;
6124: }
6125: }
6126: } else {
1.1.1.13 root 6127: FindClose(dtainfo->find_handle);
6128: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6129: }
6130: }
1.1.1.13 root 6131: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 6132: find->attrib = fd.dwFileAttributes;
6133: msdos_find_file_conv_local_time(&fd);
6134: if(REG16(SI) == 0) {
6135: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
6136: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
6137: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
6138: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
6139: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
6140: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
6141: } else {
6142: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
6143: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
6144: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
6145: }
6146: find->size_hi = fd.nFileSizeHigh;
6147: find->size_lo = fd.nFileSizeLow;
6148: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 6149: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14! root 6150: } else if(dtainfo->allowable_mask & 8) {
1.1 root 6151: // volume label
6152: find->attrib = 8;
6153: find->size_hi = find->size_lo = 0;
6154: strcpy(find->full_name, process->volume_label);
6155: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14! root 6156: dtainfo->allowable_mask &= ~8;
1.1 root 6157: } else {
6158: REG16(AX) = 0x12;
1.1.1.3 root 6159: m_CF = 1;
1.1 root 6160: }
6161: }
6162:
6163: inline void msdos_int_21h_71a0h()
6164: {
6165: DWORD max_component_len, file_sys_flag;
6166:
1.1.1.14! root 6167: if(GetVolumeInformation((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))) {
! 6168: REG16(BX) = (UINT16)file_sys_flag & (FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_VOLUME_IS_COMPRESSED);
! 6169: REG16(BX) |= 0x4000; // supports LFN functions
1.1 root 6170: REG16(CX) = (UINT16)max_component_len; // 255
6171: REG16(DX) = (UINT16)max_component_len + 5; // 260
6172: } else {
6173: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 6174: m_CF = 1;
1.1 root 6175: }
6176: }
6177:
6178: inline void msdos_int_21h_71a1h()
6179: {
1.1.1.14! root 6180: if(REG16(BX) - 1u >= MAX_DTAINFO) {
! 6181: REG16(AX) = 6;
1.1.1.13 root 6182: m_CF = 1;
6183: return;
6184: }
1.1.1.14! root 6185: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 6186: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
6187: FindClose(dtainfo->find_handle);
6188: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6189: }
6190: }
6191:
6192: inline void msdos_int_21h_71a6h()
6193: {
6194: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 6195: UINT8 *buffer = (UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 6196: struct _stat64 status;
6197: DWORD serial_number = 0;
6198:
6199: if(REG16(BX) < process->max_files && file_handler[REG16(BX)].valid) {
6200: if(_fstat64(REG16(BX), &status) == 0) {
6201: if(file_handler[REG16(BX)].path[1] == ':') {
6202: // NOTE: we need to consider the network file path "\\host\share\"
6203: char volume[] = "A:\\";
6204: volume[0] = file_handler[REG16(BX)].path[1];
6205: GetVolumeInformation(volume, NULL, 0, &serial_number, NULL, NULL, NULL, 0);
6206: }
6207: *(UINT32 *)(buffer + 0x00) = GetFileAttributes(file_handler[REG16(BX)].path);
6208: *(UINT32 *)(buffer + 0x04) = (UINT32)(status.st_ctime & 0xffffffff);
6209: *(UINT32 *)(buffer + 0x08) = (UINT32)((status.st_ctime >> 32) & 0xffffffff);
6210: *(UINT32 *)(buffer + 0x0c) = (UINT32)(status.st_atime & 0xffffffff);
6211: *(UINT32 *)(buffer + 0x10) = (UINT32)((status.st_atime >> 32) & 0xffffffff);
6212: *(UINT32 *)(buffer + 0x14) = (UINT32)(status.st_mtime & 0xffffffff);
6213: *(UINT32 *)(buffer + 0x18) = (UINT32)((status.st_mtime >> 32) & 0xffffffff);
6214: *(UINT32 *)(buffer + 0x1c) = serial_number;
6215: *(UINT32 *)(buffer + 0x20) = (UINT32)((status.st_size >> 32) & 0xffffffff);
6216: *(UINT32 *)(buffer + 0x24) = (UINT32)(status.st_size & 0xffffffff);
6217: *(UINT32 *)(buffer + 0x28) = status.st_nlink;
1.1.1.14! root 6218: // this is dummy id and it will be changed when it is reopened...
1.1 root 6219: *(UINT32 *)(buffer + 0x2c) = 0;
6220: *(UINT32 *)(buffer + 0x30) = file_handler[REG16(BX)].id;
6221: } else {
6222: REG16(AX) = errno;
1.1.1.3 root 6223: m_CF = 1;
1.1 root 6224: }
6225: } else {
6226: REG16(AX) = 0x06;
1.1.1.3 root 6227: m_CF = 1;
1.1 root 6228: }
6229: }
6230:
6231: inline void msdos_int_21h_71a7h()
6232: {
6233: switch(REG8(BL)) {
6234: case 0x00:
1.1.1.3 root 6235: if(!FileTimeToDosDateTime((FILETIME *)(mem + SREG_BASE(DS) + REG16(SI)), ®16(DX), ®16(CX))) {
1.1 root 6236: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 6237: m_CF = 1;
1.1 root 6238: }
6239: break;
6240: case 0x01:
6241: // NOTE: we need to check BH that shows 10-millisecond untils past time in CX
1.1.1.3 root 6242: if(!DosDateTimeToFileTime(REG16(DX), REG16(CX), (FILETIME *)(mem + SREG_BASE(ES) + REG16(DI)))) {
1.1 root 6243: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 6244: m_CF = 1;
1.1 root 6245: }
6246: break;
6247: default:
6248: REG16(AX) = 0x01;
1.1.1.3 root 6249: m_CF = 1;
1.1 root 6250: break;
6251: }
6252: }
6253:
6254: inline void msdos_int_21h_71a8h()
6255: {
6256: if(REG8(DH) == 0) {
6257: char tmp[MAX_PATH], fcb[MAX_PATH];
1.1.1.3 root 6258: strcpy(tmp, msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 6259: memset(fcb, 0x20, sizeof(fcb));
6260: int len = strlen(tmp);
6261: int pos = 0;
6262: for(int i = 0; i < len; i++) {
6263: if(tmp[i] == '.') {
6264: pos = 8;
6265: } else {
6266: if(msdos_lead_byte_check(tmp[i])) {
6267: fcb[pos++] = tmp[i++];
6268: }
6269: fcb[pos++] = tmp[i];
6270: }
6271: }
1.1.1.3 root 6272: memcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), fcb, 11);
1.1 root 6273: } else {
1.1.1.3 root 6274: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 6275: }
6276: }
6277:
1.1.1.14! root 6278: inline void msdos_int_21h_7300h()
! 6279: {
! 6280: if(REG8(AL) == 0) {
! 6281: REG8(AL) = REG8(CL);
! 6282: REG8(AH) = 0;
! 6283: } else {
! 6284: REG16(AX) = 0x01;
! 6285: m_CF = 1;
! 6286: }
! 6287: }
! 6288:
! 6289: inline void msdos_int_21h_7302h()
! 6290: {
! 6291: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
! 6292: UINT16 seg, ofs;
! 6293:
! 6294: if(REG16(CX) < 0x3f) {
! 6295: REG8(AL) = 0x18;
! 6296: m_CF = 1;
! 6297: } else if(!msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
! 6298: REG8(AL) = 0xff;
! 6299: m_CF = 1;
! 6300: } else {
! 6301: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 2, mem + (seg << 4) + ofs, sizeof(dpb_t));
! 6302: }
! 6303: }
! 6304:
1.1 root 6305: inline void msdos_int_21h_7303h()
6306: {
1.1.1.3 root 6307: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
6308: ext_space_info_t *info = (ext_space_info_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 6309: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
6310:
6311: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
6312: info->size_of_structure = sizeof(ext_space_info_t);
6313: info->structure_version = 0;
6314: info->sectors_per_cluster = sectors_per_cluster;
6315: info->bytes_per_sector = bytes_per_sector;
6316: info->available_clusters_on_drive = free_clusters;
6317: info->total_clusters_on_drive = total_clusters;
6318: info->available_sectors_on_drive = sectors_per_cluster * free_clusters;
6319: info->total_sectors_on_drive = sectors_per_cluster * total_clusters;
6320: info->available_allocation_units = free_clusters; // ???
6321: info->total_allocation_units = total_clusters; // ???
6322: } else {
6323: REG16(AX) = errno;
1.1.1.3 root 6324: m_CF = 1;
1.1 root 6325: }
6326: }
6327:
6328: inline void msdos_int_25h()
6329: {
6330: UINT16 seg, ofs;
6331: DWORD dwSize;
6332:
1.1.1.3 root 6333: #if defined(HAS_I386)
6334: I386OP(pushf)();
6335: #else
6336: PREFIX86(_pushf());
6337: #endif
1.1 root 6338:
6339: if(!(REG8(AL) < 26)) {
6340: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 6341: m_CF = 1;
1.1 root 6342: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
6343: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 6344: m_CF = 1;
1.1 root 6345: } else {
6346: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
6347: char dev[64];
6348: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
6349:
6350: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
6351: if(hFile == INVALID_HANDLE_VALUE) {
6352: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 6353: m_CF = 1;
1.1 root 6354: } else {
6355: if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
6356: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 6357: m_CF = 1;
1.1 root 6358: } else if(SetFilePointer(hFile, REG16(DX) * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
6359: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 6360: m_CF = 1;
6361: } else if(ReadFile(hFile, mem + SREG_BASE(DS) + REG16(BX), REG16(CX) * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 6362: REG8(AL) = 0x0b; // read error
1.1.1.3 root 6363: m_CF = 1;
1.1 root 6364: }
6365: CloseHandle(hFile);
6366: }
6367: }
6368: }
6369:
6370: inline void msdos_int_26h()
6371: {
6372: // this operation may cause serious damage for drives, so always returns error...
6373: UINT16 seg, ofs;
6374: DWORD dwSize;
6375:
1.1.1.3 root 6376: #if defined(HAS_I386)
6377: I386OP(pushf)();
6378: #else
6379: PREFIX86(_pushf());
6380: #endif
1.1 root 6381:
6382: if(!(REG8(AL) < 26)) {
6383: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 6384: m_CF = 1;
1.1 root 6385: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
6386: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 6387: m_CF = 1;
1.1 root 6388: } else {
6389: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
6390: char dev[64];
6391: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
6392:
6393: if(dpb->media_type == 0xf8) {
6394: // this drive is not a floppy
1.1.1.6 root 6395: // if(!(((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag & 0x40)) {
6396: // fatalerror("This application tried the absolute disk write to drive %c:\n", 'A' + REG8(AL));
6397: // }
1.1 root 6398: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 6399: m_CF = 1;
1.1 root 6400: } else {
6401: HANDLE hFile = CreateFile(dev, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
6402: if(hFile == INVALID_HANDLE_VALUE) {
6403: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 6404: m_CF = 1;
1.1 root 6405: } else {
6406: if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
6407: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 6408: m_CF = 1;
1.1 root 6409: } else if(SetFilePointer(hFile, REG16(DX) * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
6410: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 6411: m_CF = 1;
6412: } else if(WriteFile(hFile, mem + SREG_BASE(DS) + REG16(BX), REG16(CX) * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 6413: REG8(AL) = 0x0a; // write error
1.1.1.3 root 6414: m_CF = 1;
1.1 root 6415: }
6416: CloseHandle(hFile);
6417: }
6418: }
6419: }
6420: }
6421:
6422: inline void msdos_int_27h()
6423: {
1.1.1.14! root 6424: msdos_mem_realloc(SREG(CS), (REG16(DX) + 15) >> 4, NULL);
1.1.1.3 root 6425: msdos_process_terminate(SREG(CS), retval | 0x300, 0);
1.1.1.14! root 6426:
! 6427: // int_21h_4bh succeeded
! 6428: m_CF = 0;
1.1 root 6429: }
6430:
6431: inline void msdos_int_29h()
6432: {
1.1.1.14! root 6433: #if 1
! 6434: // need to check escape sequences
1.1 root 6435: msdos_putch(REG8(AL));
1.1.1.14! root 6436: #else
! 6437: DWORD num;
! 6438:
! 6439: vram_flush();
! 6440: WriteConsole(hStdout, ®8(AL), 1, &num, NULL);
! 6441: cursor_moved = true;
! 6442: #endif
1.1 root 6443: }
6444:
6445: inline void msdos_int_2eh()
6446: {
6447: char tmp[MAX_PATH], command[MAX_PATH], opt[MAX_PATH];
6448: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 6449: strcpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(SI)));
1.1 root 6450: char *token = my_strtok(tmp, " ");
6451: strcpy(command, token);
6452: strcpy(opt, token + strlen(token) + 1);
6453:
6454: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
6455: param->env_seg = 0;
6456: param->cmd_line.w.l = 44;
6457: param->cmd_line.w.h = (WORK_TOP >> 4);
6458: param->fcb1.w.l = 24;
6459: param->fcb1.w.h = (WORK_TOP >> 4);
6460: param->fcb2.w.l = 24;
6461: param->fcb2.w.h = (WORK_TOP >> 4);
6462:
6463: memset(mem + WORK_TOP + 24, 0x20, 20);
6464:
6465: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
6466: cmd_line->len = strlen(opt);
6467: strcpy(cmd_line->cmd, opt);
6468: cmd_line->cmd[cmd_line->len] = 0x0d;
6469:
6470: msdos_process_exec(command, param, 0);
6471: REG8(AL) = 0;
6472: }
6473:
6474: inline void msdos_int_2fh_16h()
6475: {
6476: switch(REG8(AL)) {
6477: case 0x00:
1.1.1.14! root 6478: if(no_windows) {
! 6479: REG8(AL) = 0;
! 6480: } else {
1.1 root 6481: OSVERSIONINFO osvi;
6482: ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
6483: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
6484: GetVersionEx(&osvi);
6485: REG8(AL) = osvi.dwMajorVersion;
6486: REG8(AH) = osvi.dwMinorVersion;
6487: }
6488: break;
1.1.1.14! root 6489: case 0x80:
! 6490: Sleep(10);
! 6491: hardware_update();
! 6492: REG8(AL) = 0;
! 6493: break;
1.1 root 6494: default:
6495: REG16(AX) = 0x01;
1.1.1.3 root 6496: m_CF = 1;
1.1 root 6497: break;
6498: }
6499: }
6500:
6501: inline void msdos_int_2fh_1ah()
6502: {
6503: switch(REG8(AL)) {
6504: case 0x00:
6505: // ansi.sys is installed
6506: REG8(AL) = 0xff;
6507: break;
6508: default:
6509: REG16(AX) = 0x01;
1.1.1.3 root 6510: m_CF = 1;
1.1 root 6511: break;
6512: }
6513: }
6514:
6515: inline void msdos_int_2fh_43h()
6516: {
6517: switch(REG8(AL)) {
6518: case 0x00:
6519: // xms is not installed
6520: REG8(AL) = 0;
6521: break;
6522: default:
6523: REG16(AX) = 0x01;
1.1.1.3 root 6524: m_CF = 1;
1.1 root 6525: break;
6526: }
6527: }
6528:
6529: inline void msdos_int_2fh_4ah()
6530: {
6531: switch(REG8(AL)) {
6532: case 0x01:
6533: case 0x02:
6534: // hma is not installed
6535: REG16(BX) = 0;
1.1.1.3 root 6536: SREG(ES) = 0xffff;
6537: i386_load_segment_descriptor(ES);
1.1 root 6538: REG16(DI) = 0xffff;
6539: break;
6540: default:
6541: REG16(AX) = 0x01;
1.1.1.3 root 6542: m_CF = 1;
1.1 root 6543: break;
6544: }
6545: }
6546:
6547: inline void msdos_int_2fh_4fh()
6548: {
6549: switch(REG8(AL)) {
6550: case 0x00:
6551: REG16(AX) = 0;
6552: REG8(DL) = 1; // major version
6553: REG8(DH) = 0; // minor version
6554: break;
6555: case 0x01:
6556: REG16(AX) = 0;
6557: REG16(BX) = active_code_page;
6558: break;
6559: default:
6560: REG16(AX) = 0x01;
1.1.1.3 root 6561: m_CF = 1;
1.1 root 6562: break;
6563: }
6564: }
6565:
6566: inline void msdos_int_2fh_aeh()
6567: {
6568: switch(REG8(AL)) {
6569: case 0x00:
6570: REG8(AL) = 0;
6571: break;
6572: case 0x01:
6573: {
6574: char command[MAX_PATH];
6575: memset(command, 0, sizeof(command));
1.1.1.3 root 6576: memcpy(command, mem + SREG_BASE(DS) + REG16(SI) + 1, mem[SREG_BASE(DS) + REG16(SI)]);
1.1 root 6577:
6578: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
6579: param->env_seg = 0;
6580: param->cmd_line.w.l = 44;
6581: param->cmd_line.w.h = (WORK_TOP >> 4);
6582: param->fcb1.w.l = 24;
6583: param->fcb1.w.h = (WORK_TOP >> 4);
6584: param->fcb2.w.l = 24;
6585: param->fcb2.w.h = (WORK_TOP >> 4);
6586:
6587: memset(mem + WORK_TOP + 24, 0x20, 20);
6588:
6589: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
1.1.1.3 root 6590: cmd_line->len = mem[SREG_BASE(DS) + REG16(BX) + 1];
6591: memcpy(cmd_line->cmd, mem + SREG_BASE(DS) + REG16(BX) + 2, cmd_line->len);
1.1 root 6592: cmd_line->cmd[cmd_line->len] = 0x0d;
6593:
6594: if(msdos_process_exec(command, param, 0)) {
6595: REG16(AX) = 0x02;
1.1.1.3 root 6596: m_CF = 1;
1.1 root 6597: }
6598: }
6599: break;
6600: default:
6601: REG16(AX) = 0x01;
1.1.1.3 root 6602: m_CF = 1;
1.1 root 6603: break;
6604: }
6605: }
6606:
6607: inline void msdos_int_2fh_b7h()
6608: {
6609: switch(REG8(AL)) {
6610: case 0x00:
6611: // append is not installed
6612: REG8(AL) = 0;
6613: break;
6614: default:
6615: REG16(AX) = 0x01;
1.1.1.3 root 6616: m_CF = 1;
1.1 root 6617: break;
6618: }
6619: }
6620:
6621: void msdos_syscall(unsigned num)
6622: {
6623: switch(num) {
6624: case 0x00:
6625: error("division by zero\n");
6626: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
6627: break;
6628: case 0x04:
6629: error("overflow\n");
6630: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
6631: break;
6632: case 0x06:
6633: // NOTE: ish.com has illegal instruction...
1.1.1.14! root 6634: if(!ignore_illegal_insn) {
! 6635: error("illegal instruction\n");
! 6636: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
! 6637: } else {
! 6638: #if defined(HAS_I386)
! 6639: m_eip++;
! 6640: #else
! 6641: m_pc++;
! 6642: #endif
! 6643: }
1.1 root 6644: break;
1.1.1.8 root 6645: case 0x08:
1.1.1.14! root 6646: // pcbios_irq0(); // this causes too slow emulation...
1.1.1.8 root 6647: case 0x09:
6648: case 0x0a:
6649: case 0x0b:
6650: case 0x0c:
6651: case 0x0d:
6652: case 0x0e:
6653: case 0x0f:
6654: // EOI
6655: pic[0].isr &= ~(1 << (num - 0x08));
6656: pic_update();
6657: break;
1.1 root 6658: case 0x10:
6659: // PC BIOS - Video
1.1.1.14! root 6660: if(!restore_console_on_exit) {
! 6661: change_console_size(80, scr_height);
1.1.1.12 root 6662: restore_console_on_exit = true;
1.1 root 6663: }
1.1.1.3 root 6664: m_CF = 0;
1.1 root 6665: switch(REG8(AH)) {
1.1.1.14! root 6666: case 0x00: pcbios_int_10h_00h(25); break;
1.1 root 6667: case 0x01: pcbios_int_10h_01h(); break;
6668: case 0x02: pcbios_int_10h_02h(); break;
6669: case 0x03: pcbios_int_10h_03h(); break;
6670: case 0x05: pcbios_int_10h_05h(); break;
6671: case 0x06: pcbios_int_10h_06h(); break;
6672: case 0x07: pcbios_int_10h_07h(); break;
6673: case 0x08: pcbios_int_10h_08h(); break;
6674: case 0x09: pcbios_int_10h_09h(); break;
6675: case 0x0a: pcbios_int_10h_0ah(); break;
6676: case 0x0b: break;
6677: case 0x0c: break;
6678: case 0x0d: break;
6679: case 0x0e: pcbios_int_10h_0eh(); break;
6680: case 0x0f: pcbios_int_10h_0fh(); break;
6681: case 0x10: break;
1.1.1.14! root 6682: case 0x11: pcbios_int_10h_11h(); break;
! 6683: case 0x12: pcbios_int_10h_12h(); break;
1.1 root 6684: case 0x13: pcbios_int_10h_13h(); break;
6685: case 0x18: REG8(AL) = 0x86; break;
1.1.1.14! root 6686: case 0x1a: pcbios_int_10h_1ah(); break;
1.1.1.11 root 6687: case 0x1b: break;
1.1 root 6688: case 0x1c: REG8(AL) = 0x00; break;
6689: case 0x1d: pcbios_int_10h_1dh(); break;
6690: case 0x82: pcbios_int_10h_82h(); break;
1.1.1.11 root 6691: case 0xef: REG16(DX) = 0xffff; break;
1.1 root 6692: case 0xfe: pcbios_int_10h_feh(); break;
6693: case 0xff: pcbios_int_10h_ffh(); break;
6694: default:
1.1.1.14! root 6695: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
1.1 root 6696: break;
6697: }
6698: break;
6699: case 0x11:
6700: // PC BIOS - Get Equipment List
1.1.1.11 root 6701: #ifdef SUPPORT_FPU
6702: REG16(AX) = 0x22;
6703: #else
1.1 root 6704: REG16(AX) = 0x20;
1.1.1.11 root 6705: #endif
1.1 root 6706: break;
6707: case 0x12:
6708: // PC BIOS - Get Memory Size
6709: REG16(AX) = MEMORY_END / 1024;
6710: break;
6711: case 0x13:
6712: // PC BIOS - Disk
6713: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
6714: REG8(AH) = 0xff;
1.1.1.3 root 6715: m_CF = 1;
1.1 root 6716: break;
6717: case 0x14:
6718: // PC BIOS - Serial I/O
6719: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
6720: REG8(AH) = 0xff;
1.1.1.3 root 6721: m_CF = 1;
1.1 root 6722: break;
6723: case 0x15:
6724: // PC BIOS
1.1.1.3 root 6725: m_CF = 0;
1.1 root 6726: switch(REG8(AH)) {
1.1.1.14! root 6727: case 0x10: pcbios_int_15h_10h(); break;
1.1 root 6728: case 0x23: pcbios_int_15h_23h(); break;
6729: case 0x24: pcbios_int_15h_24h(); break;
6730: case 0x49: pcbios_int_15h_49h(); break;
6731: case 0x86: pcbios_int_15h_86h(); break;
6732: case 0x87: pcbios_int_15h_87h(); break;
6733: case 0x88: pcbios_int_15h_88h(); break;
6734: case 0x89: pcbios_int_15h_89h(); break;
1.1.1.3 root 6735: #if defined(HAS_I386)
1.1 root 6736: case 0xc9: pcbios_int_15h_c9h(); break;
1.1.1.3 root 6737: #endif
1.1 root 6738: case 0xca: pcbios_int_15h_cah(); break;
6739: default:
6740: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
6741: REG8(AH)=0x86;
1.1.1.3 root 6742: m_CF = 1;
1.1 root 6743: break;
6744: }
6745: break;
6746: case 0x16:
6747: // PC BIOS - Keyboard
1.1.1.3 root 6748: m_CF = 0;
1.1 root 6749: switch(REG8(AH)) {
6750: case 0x00: pcbios_int_16h_00h(); break;
6751: case 0x01: pcbios_int_16h_01h(); break;
6752: case 0x02: pcbios_int_16h_02h(); break;
6753: case 0x03: pcbios_int_16h_03h(); break;
6754: case 0x05: pcbios_int_16h_05h(); break;
6755: case 0x10: pcbios_int_16h_00h(); break;
6756: case 0x11: pcbios_int_16h_01h(); break;
6757: case 0x12: pcbios_int_16h_12h(); break;
6758: case 0x13: pcbios_int_16h_13h(); break;
6759: case 0x14: pcbios_int_16h_14h(); break;
6760: default:
1.1.1.14! root 6761: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
1.1 root 6762: break;
6763: }
6764: break;
6765: case 0x17:
6766: // PC BIOS - Printer
6767: fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
6768: break;
6769: case 0x1a:
6770: // PC BIOS - Timer
1.1.1.3 root 6771: m_CF = 0;
1.1 root 6772: switch(REG8(AH)) {
6773: case 0x00: pcbios_int_1ah_00h(); break;
6774: case 0x01: break;
6775: case 0x02: pcbios_int_1ah_02h(); break;
6776: case 0x03: break;
6777: case 0x04: pcbios_int_1ah_04h(); break;
6778: case 0x05: break;
6779: case 0x0a: pcbios_int_1ah_0ah(); break;
6780: case 0x0b: break;
1.1.1.14! root 6781: case 0x35: break; // Word Perfect Third Party Interface?
! 6782: case 0x36: break; // Word Perfect Third Party Interface
! 6783: case 0x70: break; // SNAP? (Simple Network Application Protocol)
1.1 root 6784: default:
6785: fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
6786: break;
6787: }
6788: break;
6789: case 0x20:
1.1.1.3 root 6790: msdos_process_terminate(SREG(CS), retval, 1);
1.1 root 6791: break;
6792: case 0x21:
6793: // MS-DOS System Call
1.1.1.3 root 6794: m_CF = 0;
1.1 root 6795: switch(REG8(AH)) {
6796: case 0x00: msdos_int_21h_00h(); break;
6797: case 0x01: msdos_int_21h_01h(); break;
6798: case 0x02: msdos_int_21h_02h(); break;
6799: case 0x03: msdos_int_21h_03h(); break;
6800: case 0x04: msdos_int_21h_04h(); break;
6801: case 0x05: msdos_int_21h_05h(); break;
6802: case 0x06: msdos_int_21h_06h(); break;
6803: case 0x07: msdos_int_21h_07h(); break;
6804: case 0x08: msdos_int_21h_08h(); break;
6805: case 0x09: msdos_int_21h_09h(); break;
6806: case 0x0a: msdos_int_21h_0ah(); break;
6807: case 0x0b: msdos_int_21h_0bh(); break;
6808: case 0x0c: msdos_int_21h_0ch(); break;
6809: case 0x0d: msdos_int_21h_0dh(); break;
6810: case 0x0e: msdos_int_21h_0eh(); break;
1.1.1.14! root 6811: case 0x0f: msdos_int_21h_0fh(); break;
! 6812: case 0x10: msdos_int_21h_10h(); break;
1.1 root 6813: case 0x11: msdos_int_21h_11h(); break;
6814: case 0x12: msdos_int_21h_12h(); break;
6815: case 0x13: msdos_int_21h_13h(); break;
6816: // 0x14: sequential read with fcb
6817: // 0x15: sequential write with fcb
1.1.1.14! root 6818: case 0x16: msdos_int_21h_16h(); break;
1.1 root 6819: // 0x17: rename file with fcb
6820: case 0x18: msdos_int_21h_18h(); break;
6821: case 0x19: msdos_int_21h_19h(); break;
6822: case 0x1a: msdos_int_21h_1ah(); break;
6823: case 0x1b: msdos_int_21h_1bh(); break;
6824: case 0x1c: msdos_int_21h_1ch(); break;
6825: case 0x1d: msdos_int_21h_1dh(); break;
6826: case 0x1e: msdos_int_21h_1eh(); break;
6827: case 0x1f: msdos_int_21h_1fh(); break;
6828: case 0x20: msdos_int_21h_20h(); break;
1.1.1.14! root 6829: case 0x21: msdos_int_21h_21h(); break;
! 6830: case 0x22: msdos_int_21h_22h(); break;
1.1 root 6831: // 0x23: get file size with fcb
6832: // 0x24: set relative record field with fcb
6833: case 0x25: msdos_int_21h_25h(); break;
6834: case 0x26: msdos_int_21h_26h(); break;
6835: // 0x27: random block read with fcb
6836: // 0x28: random block write with fcb
6837: case 0x29: msdos_int_21h_29h(); break;
6838: case 0x2a: msdos_int_21h_2ah(); break;
6839: case 0x2b: msdos_int_21h_2bh(); break;
6840: case 0x2c: msdos_int_21h_2ch(); break;
6841: case 0x2d: msdos_int_21h_2dh(); break;
6842: case 0x2e: msdos_int_21h_2eh(); break;
6843: case 0x2f: msdos_int_21h_2fh(); break;
6844: case 0x30: msdos_int_21h_30h(); break;
6845: case 0x31: msdos_int_21h_31h(); break;
6846: case 0x32: msdos_int_21h_32h(); break;
6847: case 0x33: msdos_int_21h_33h(); break;
6848: // 0x34: get address of indos flag
6849: case 0x35: msdos_int_21h_35h(); break;
6850: case 0x36: msdos_int_21h_36h(); break;
6851: case 0x37: msdos_int_21h_37h(); break;
1.1.1.14! root 6852: case 0x38: msdos_int_21h_38h(); break;
1.1 root 6853: case 0x39: msdos_int_21h_39h(0); break;
6854: case 0x3a: msdos_int_21h_3ah(0); break;
6855: case 0x3b: msdos_int_21h_3bh(0); break;
6856: case 0x3c: msdos_int_21h_3ch(); break;
6857: case 0x3d: msdos_int_21h_3dh(); break;
6858: case 0x3e: msdos_int_21h_3eh(); break;
6859: case 0x3f: msdos_int_21h_3fh(); break;
6860: case 0x40: msdos_int_21h_40h(); break;
6861: case 0x41: msdos_int_21h_41h(0); break;
6862: case 0x42: msdos_int_21h_42h(); break;
6863: case 0x43: msdos_int_21h_43h(0); break;
6864: case 0x44: msdos_int_21h_44h(); break;
6865: case 0x45: msdos_int_21h_45h(); break;
6866: case 0x46: msdos_int_21h_46h(); break;
6867: case 0x47: msdos_int_21h_47h(0); break;
6868: case 0x48: msdos_int_21h_48h(); break;
6869: case 0x49: msdos_int_21h_49h(); break;
6870: case 0x4a: msdos_int_21h_4ah(); break;
6871: case 0x4b: msdos_int_21h_4bh(); break;
6872: case 0x4c: msdos_int_21h_4ch(); break;
6873: case 0x4d: msdos_int_21h_4dh(); break;
6874: case 0x4e: msdos_int_21h_4eh(); break;
6875: case 0x4f: msdos_int_21h_4fh(); break;
6876: case 0x50: msdos_int_21h_50h(); break;
6877: case 0x51: msdos_int_21h_51h(); break;
6878: case 0x52: msdos_int_21h_52h(); break;
6879: // 0x53: translate bios parameter block to drive param bock
6880: case 0x54: msdos_int_21h_54h(); break;
6881: case 0x55: msdos_int_21h_55h(); break;
6882: case 0x56: msdos_int_21h_56h(0); break;
6883: case 0x57: msdos_int_21h_57h(); break;
6884: case 0x58: msdos_int_21h_58h(); break;
6885: case 0x59: msdos_int_21h_59h(); break;
6886: case 0x5a: msdos_int_21h_5ah(); break;
6887: case 0x5b: msdos_int_21h_5bh(); break;
6888: case 0x5c: msdos_int_21h_5ch(); break;
6889: // 0x5e: ms-network
6890: // 0x5f: ms-network
6891: case 0x60: msdos_int_21h_60h(0); break;
6892: case 0x61: msdos_int_21h_61h(); break;
6893: case 0x62: msdos_int_21h_62h(); break;
6894: case 0x63: msdos_int_21h_63h(); break;
6895: // 0x64: set device driver lockahead flag
6896: case 0x65: msdos_int_21h_65h(); break;
6897: case 0x66: msdos_int_21h_66h(); break;
6898: case 0x67: msdos_int_21h_67h(); break;
6899: case 0x68: msdos_int_21h_68h(); break;
6900: case 0x69: msdos_int_21h_69h(); break;
6901: case 0x6a: msdos_int_21h_6ah(); break;
6902: case 0x6b: msdos_int_21h_6bh(); break;
6903: case 0x6c: msdos_int_21h_6ch(0); break;
6904: // 0x6d: find first rom program
6905: // 0x6e: find next rom program
6906: // 0x6f: get/set rom scan start address
6907: // 0x70: windows95 get/set internationalization information
6908: case 0x71:
6909: // windows95 long filename functions
6910: switch(REG8(AL)) {
6911: case 0x0d: msdos_int_21h_710dh(); break;
6912: case 0x39: msdos_int_21h_39h(1); break;
6913: case 0x3a: msdos_int_21h_3ah(1); break;
6914: case 0x3b: msdos_int_21h_3bh(1); break;
6915: case 0x41: msdos_int_21h_41h(1); break;
6916: case 0x43: msdos_int_21h_43h(1); break;
6917: case 0x47: msdos_int_21h_47h(1); break;
6918: case 0x4e: msdos_int_21h_714eh(); break;
6919: case 0x4f: msdos_int_21h_714fh(); break;
6920: case 0x56: msdos_int_21h_56h(1); break;
6921: case 0x60: msdos_int_21h_60h(1); break;
6922: case 0x6c: msdos_int_21h_6ch(1); break;
6923: case 0xa0: msdos_int_21h_71a0h(); break;
6924: case 0xa1: msdos_int_21h_71a1h(); break;
6925: case 0xa6: msdos_int_21h_71a6h(); break;
6926: case 0xa7: msdos_int_21h_71a7h(); break;
6927: case 0xa8: msdos_int_21h_71a8h(); break;
6928: // 0xa9: server create/open file
6929: // 0xaa: create/terminate SUBST
6930: default:
6931: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
6932: REG16(AX) = 0x7100;
1.1.1.3 root 6933: m_CF = 1;
1.1 root 6934: break;
6935: }
6936: break;
6937: // 0x72: Windows95 beta - LFN FindClose
6938: case 0x73:
6939: // windows95 fat32 functions
6940: switch(REG8(AL)) {
1.1.1.14! root 6941: case 0x00: msdos_int_21h_7300h(); break;
! 6942: // 0x01: set drive locking ???
! 6943: case 0x02: msdos_int_21h_7302h(); break;
1.1 root 6944: case 0x03: msdos_int_21h_7303h(); break;
6945: // 0x04: set dpb to use for formatting
6946: default:
6947: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
6948: REG16(AX) = 0x7300;
1.1.1.3 root 6949: m_CF = 1;
1.1 root 6950: break;
6951: }
6952: break;
6953: default:
6954: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
6955: REG16(AX) = 0x01;
1.1.1.3 root 6956: m_CF = 1;
1.1 root 6957: break;
6958: }
1.1.1.3 root 6959: if(m_CF) {
1.1 root 6960: error_code = REG16(AX);
6961: }
6962: break;
6963: case 0x22:
6964: fatalerror("int 22h (terminate address)\n");
6965: case 0x23:
6966: msdos_process_terminate(current_psp, (retval & 0xff) | 0x100, 1);
6967: break;
6968: case 0x24:
6969: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
6970: break;
6971: case 0x25:
6972: msdos_int_25h();
6973: break;
6974: case 0x26:
6975: msdos_int_26h();
6976: break;
6977: case 0x27:
6978: msdos_int_27h();
6979: break;
6980: case 0x28:
6981: Sleep(10);
6982: break;
6983: case 0x29:
6984: msdos_int_29h();
6985: break;
6986: case 0x2e:
6987: msdos_int_2eh();
6988: break;
6989: case 0x2f:
6990: // multiplex interrupt
6991: switch(REG8(AH)) {
6992: case 0x16: msdos_int_2fh_16h(); break;
6993: case 0x1a: msdos_int_2fh_1ah(); break;
6994: case 0x43: msdos_int_2fh_43h(); break;
6995: case 0x4a: msdos_int_2fh_4ah(); break;
6996: case 0x4f: msdos_int_2fh_4fh(); break;
6997: case 0xae: msdos_int_2fh_aeh(); break;
6998: case 0xb7: msdos_int_2fh_b7h(); break;
6999: }
7000: break;
1.1.1.8 root 7001: case 0x70:
7002: case 0x71:
7003: case 0x72:
7004: case 0x73:
7005: case 0x74:
7006: case 0x75:
7007: case 0x76:
7008: case 0x77:
7009: // EOI
7010: if((pic[1].isr &= ~(1 << (num - 0x70))) == 0) {
7011: pic[0].isr &= ~(1 << 2); // master
7012: }
7013: pic_update();
7014: break;
1.1 root 7015: default:
7016: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
7017: break;
7018: }
7019:
7020: // update cursor position
7021: if(cursor_moved) {
7022: CONSOLE_SCREEN_BUFFER_INFO csbi;
7023: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14! root 7024: scr_top = csbi.srWindow.Top;
1.1 root 7025: mem[0x450 + mem[0x462] * 2] = csbi.dwCursorPosition.X;
1.1.1.14! root 7026: mem[0x451 + mem[0x462] * 2] = csbi.dwCursorPosition.Y - scr_top;
1.1 root 7027: cursor_moved = false;
7028: }
7029: }
7030:
7031: // init
7032:
7033: int msdos_init(int argc, char *argv[], char *envp[], int standard_env)
7034: {
7035: // init file handler
7036: memset(file_handler, 0, sizeof(file_handler));
7037: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
7038: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
7039: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
7040: #ifdef SUPPORT_AUX_PRN
7041: if(_open("stdaux.txt", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
7042: msdos_file_handler_open(3, 0, 2, 0x80c0, 0);
7043: }
7044: if(_open("stdprn.txt", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
7045: msdos_file_handler_open(4, 0, 1, 0xa8c0, 0);
7046: }
7047: #endif
7048: _dup2(0, DUP_STDIN);
7049: _dup2(1, DUP_STDOUT);
7050: _dup2(2, DUP_STDERR);
7051:
7052: // init process
7053: memset(process, 0, sizeof(process));
7054:
1.1.1.13 root 7055: // init dtainfo
7056: msdos_dta_info_init();
7057:
1.1 root 7058: // init memory
7059: memset(mem, 0, sizeof(mem));
1.1.1.14! root 7060: for(int i = 0; i < 0x80; i++) {
1.1 root 7061: *(UINT16 *)(mem + 4 * i + 0) = i;
7062: *(UINT16 *)(mem + 4 * i + 2) = (IRET_TOP >> 4);
7063: }
1.1.1.14! root 7064: *(UINT16 *)(mem + 4 * 0x08 + 0) = 0xfea5;
! 7065: *(UINT16 *)(mem + 4 * 0x08 + 2) = 0xf000;
1.1 root 7066: *(UINT16 *)(mem + 4 * 0x22 + 0) = 0xfff0;
7067: *(UINT16 *)(mem + 4 * 0x22 + 2) = 0xf000;
7068: memset(mem + IRET_TOP, 0xcf, IRET_SIZE);
7069:
7070: // bios data area
7071: CONSOLE_SCREEN_BUFFER_INFO csbi;
7072: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14! root 7073: CONSOLE_FONT_INFO cfi;
! 7074: GetCurrentConsoleFont(hStdout, FALSE, &cfi);
! 7075:
! 7076: int regen = min(scr_width * scr_height * 2, 0x8000);
! 7077: text_vram_top_address = TEXT_VRAM_TOP;
! 7078: text_vram_end_address = text_vram_top_address + regen;
! 7079: shadow_buffer_top_address = SHADOW_BUF_TOP;
! 7080: shadow_buffer_end_address = shadow_buffer_top_address + regen;
! 7081:
! 7082: if(regen > 0x4000) {
! 7083: regen = 0x8000;
! 7084: vram_pages = 1;
! 7085: } else if(regen > 0x2000) {
! 7086: regen = 0x4000;
! 7087: vram_pages = 2;
! 7088: } else if(regen > 0x1000) {
! 7089: regen = 0x2000;
! 7090: vram_pages = 4;
! 7091: } else {
! 7092: regen = 0x1000;
! 7093: vram_pages = 8;
! 7094: }
1.1 root 7095:
1.1.1.14! root 7096: #ifdef SUPPORT_FPU
! 7097: *(UINT16 *)(mem + 0x410) = 0x22;
! 7098: #else
1.1 root 7099: *(UINT16 *)(mem + 0x410) = 0x20;
1.1.1.14! root 7100: #endif
1.1 root 7101: *(UINT16 *)(mem + 0x413) = MEMORY_END / 1024;
7102: *(UINT8 *)(mem + 0x449) = 0x03;//0x73;
1.1.1.14! root 7103: *(UINT16 *)(mem + 0x44a) = csbi.dwSize.X;
! 7104: *(UINT16 *)(mem + 0x44c) = regen;
1.1 root 7105: *(UINT16 *)(mem + 0x44e) = 0;
7106: *(UINT8 *)(mem + 0x450) = csbi.dwCursorPosition.X;
1.1.1.14! root 7107: *(UINT8 *)(mem + 0x451) = csbi.dwCursorPosition.Y - scr_top;
1.1 root 7108: *(UINT8 *)(mem + 0x460) = 7;
7109: *(UINT8 *)(mem + 0x461) = 7;
7110: *(UINT8 *)(mem + 0x462) = 0;
7111: *(UINT16 *)(mem + 0x463) = 0x3d4;
1.1.1.14! root 7112: *(UINT8 *)(mem + 0x465) = 0x9;
! 7113: *(UINT32 *)(mem + 0x46c) = get_ticks_since_midnight();
! 7114: *(UINT8 *)(mem + 0x484) = csbi.srWindow.Bottom - csbi.srWindow.Top;
! 7115: *(UINT8 *)(mem + 0x485) = cfi.dwFontSize.Y;
! 7116: *(UINT8 *)(mem + 0x487) = 0x60;
! 7117: *(UINT8 *)(mem + 0x496) = 0x10; // enhanced keyboard installed
! 7118:
! 7119: // initial screen
! 7120: SMALL_RECT rect;
! 7121: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
! 7122: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
! 7123: for(int y = 0, ofs1 = TEXT_VRAM_TOP, ofs2 = SHADOW_BUF_TOP; y < scr_height; y++) {
! 7124: for(int x = 0; x < scr_width; x++) {
! 7125: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Char.AsciiChar;
! 7126: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Attributes;
! 7127: }
! 7128: }
1.1 root 7129:
7130: // dos info
7131: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
7132: dos_info->first_mcb = MEMORY_TOP >> 4;
7133: dos_info->first_dpb.w.l = 0;
7134: dos_info->first_dpb.w.h = DPB_TOP >> 4;
7135: dos_info->first_sft.w.l = 0;
7136: dos_info->first_sft.w.h = FILE_TABLE_TOP >> 4;
7137: dos_info->cds.w.l = 0;
7138: dos_info->cds.w.h = CDS_TOP >> 4;
7139: dos_info->fcb_table.w.l = 0;
7140: dos_info->fcb_table.w.h = FCB_TABLE_TOP >> 4;
7141: dos_info->last_drive = 'Z' - 'A' + 1;
7142: dos_info->buffers_x = 20;
7143: dos_info->buffers_y = 0;
1.1.1.14! root 7144: dos_info->boot_drive = 'C' - 'A' + 1;
1.1 root 7145: char *env;
7146: if((env = getenv("LASTDRIVE")) != NULL) {
7147: if(env[0] >= 'A' && env[0] <= 'Z') {
7148: dos_info->last_drive = env[0] - 'A' + 1;
7149: } else if(env[0] >= 'a' && env[0] <= 'z') {
7150: dos_info->last_drive = env[0] - 'a' + 1;
7151: }
7152: }
7153: if((env = getenv("windir")) != NULL) {
7154: if(env[0] >= 'A' && env[0] <= 'Z') {
7155: dos_info->boot_drive = env[0] - 'A' + 1;
7156: } else if(env[0] >= 'a' && env[0] <= 'z') {
7157: dos_info->boot_drive = env[0] - 'a' + 1;
7158: }
7159: }
1.1.1.3 root 7160: #if defined(HAS_I386)
1.1 root 7161: dos_info->i386_or_later = 1;
1.1.1.3 root 7162: #else
7163: dos_info->i386_or_later = 0;
7164: #endif
1.1 root 7165: dos_info->ext_mem_size = (MAX_MEM - 0x100000) >> 10;
7166:
7167: // environment
7168: int seg = MEMORY_TOP >> 4;
7169: msdos_mcb_create(seg++, 'M', -1, ENV_SIZE >> 4);
7170: int env_seg = seg;
7171: int ofs = 0;
1.1.1.14! root 7172: char env_path[8192] = "";
1.1 root 7173:
7174: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1.1.14! root 7175: if(_strnicmp(*p, "MSDOS_PATH=", 11) == 0) {
! 7176: sprintf(env_path, "%s;", *p + 11);
! 7177: break;
! 7178: }
! 7179: }
! 7180: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1.1.9 root 7181: if(_strnicmp(*p, "PATH=", 5) == 0) {
1.1.1.14! root 7182: strcat(env_path, *p + 5);
1.1.1.9 root 7183: break;
7184: }
7185: }
7186: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1 root 7187: // lower to upper
7188: char tmp[ENV_SIZE], name[ENV_SIZE], value[ENV_SIZE];
7189: int value_pos = 0;
7190: strcpy(tmp, *p);
7191: for(int i = 0;; i++) {
7192: if(tmp[i] == '=') {
7193: tmp[i] = '\0';
7194: sprintf(name, ";%s;", tmp);
7195: strcpy(value, tmp + (value_pos = i + 1));
7196: tmp[i] = '=';
7197: break;
7198: } else if(tmp[i] >= 'a' && tmp[i] <= 'z') {
7199: tmp[i] = tmp[i] - 'a' + 'A';
7200: }
7201: }
7202: if(!(standard_env && strstr(";COMSPEC;INCLUDE;LIB;PATH;PROMPT;TEMP;TMP;TZ;", name) == NULL)) {
7203: if(strncmp(tmp, "COMSPEC=", 8) == 0) {
1.1.1.14! root 7204: char *path = msdos_search_command_com(argv[0], env_path);
! 7205: if(path != NULL) {
! 7206: strcpy(comspec_path, path);
! 7207: }
! 7208: strcpy(tmp, "COMSPEC=C:\\COMMAND.COM");
1.1 root 7209: } else if(strncmp(tmp, "PATH=", 5) == 0 || strncmp(tmp, "TEMP=", 5) == 0 || strncmp(tmp, "TMP=", 4) == 0) {
7210: tmp[value_pos] = '\0';
7211: char *token = my_strtok(value, ";");
7212: while(token != NULL) {
7213: if(strlen(token) != 0) {
1.1.1.8 root 7214: char *path = msdos_remove_double_quote(token), tmp_path[MAX_PATH];
7215: if(strlen(path) != 0) {
7216: GetShortPathName(path, tmp_path, MAX_PATH);
7217: strcat(tmp, tmp_path);
7218: strcat(tmp, ";");
1.1 root 7219: }
7220: }
7221: token = my_strtok(NULL, ";");
7222: }
7223: tmp[strlen(tmp) - 1] = '\0';
7224: my_strupr(tmp);
7225: }
7226: int len = strlen(tmp);
1.1.1.14! root 7227: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) {
1.1 root 7228: fatalerror("too many environments\n");
7229: }
7230: memcpy(mem + (seg << 4) + ofs, tmp, len);
7231: ofs += len + 1;
7232: }
7233: }
7234: seg += (ENV_SIZE >> 4);
7235:
7236: // psp
7237: msdos_mcb_create(seg++, 'M', -1, PSP_SIZE >> 4);
7238: current_psp = seg;
1.1.1.14! root 7239: msdos_psp_create(seg, seg + (PSP_SIZE >> 4), -1, env_seg);
1.1 root 7240: seg += (PSP_SIZE >> 4);
7241:
1.1.1.8 root 7242: // first mcb in conventional memory
1.1 root 7243: msdos_mcb_create(seg, 'Z', 0, (MEMORY_END >> 4) - seg - 1);
1.1.1.8 root 7244: first_mcb = seg;
7245:
7246: // first mcb in upper memory block
7247: msdos_mcb_create(UMB_TOP >> 4, 'Z', 0, (UMB_END >> 4) - (UMB_TOP >> 4) - 1);
1.1 root 7248:
1.1.1.14! root 7249: // have irq0 call system timer tick
! 7250: mem[0xffea5] = 0xcd; // int 1ch
! 7251: mem[0xffea6] = 0x1c;
! 7252: mem[0xffea7] = 0xea; // jmp 80:08
! 7253: mem[0xffea8] = 0x08;
! 7254: mem[0xffea9] = 0x00;
! 7255: mem[0xffeaa] = ((IRET_TOP >> 4) ) & 0xff;
! 7256: mem[0xffeab] = ((IRET_TOP >> 4) >> 8) & 0xff;
! 7257:
1.1 root 7258: // boot
7259: mem[0xffff0] = 0xf4; // halt
7260: mem[0xffff1] = 0xcd; // int 21h
7261: mem[0xffff2] = 0x21;
7262: mem[0xffff3] = 0xcb; // retf
7263:
7264: // param block
7265: // + 0: param block (22bytes)
7266: // +24: fcb1/2 (20bytes)
7267: // +44: command tail (128bytes)
7268: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
7269: param->env_seg = 0;
7270: param->cmd_line.w.l = 44;
7271: param->cmd_line.w.h = (WORK_TOP >> 4);
7272: param->fcb1.w.l = 24;
7273: param->fcb1.w.h = (WORK_TOP >> 4);
7274: param->fcb2.w.l = 24;
7275: param->fcb2.w.h = (WORK_TOP >> 4);
7276:
7277: memset(mem + WORK_TOP + 24, 0x20, 20);
7278:
7279: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
7280: if(argc > 1) {
7281: sprintf(cmd_line->cmd, " %s", argv[1]);
7282: for(int i = 2; i < argc; i++) {
7283: char tmp[128];
7284: sprintf(tmp, "%s %s", cmd_line->cmd, argv[i]);
7285: strcpy(cmd_line->cmd, tmp);
7286: }
7287: cmd_line->len = (UINT8)strlen(cmd_line->cmd);
7288: } else {
7289: cmd_line->len = 0;
7290: }
7291: cmd_line->cmd[cmd_line->len] = 0x0d;
7292:
7293: // system file table
1.1.1.14! root 7294: *(UINT32 *)(mem + FILE_TABLE_TOP + 0) = 0xffffffff;
! 7295: *(UINT16 *)(mem + FILE_TABLE_TOP + 4) = 0;
1.1 root 7296:
7297: // current directory structure
7298: msdos_cds_update(_getdrive() - 1);
7299:
7300: // fcb table
7301: *(UINT32 *)(mem + FCB_TABLE_TOP + 0) = 0xffffffff;
1.1.1.14! root 7302: *(UINT16 *)(mem + FCB_TABLE_TOP + 4) = 0;
1.1 root 7303:
7304: // dbcs table
7305: msdos_dbcs_table_init();
7306:
7307: // execute command
7308: if(msdos_process_exec(argv[0], param, 0)) {
7309: fatalerror("'%s' not found\n", argv[0]);
7310: }
7311: retval = 0;
7312: return(0);
7313: }
7314:
7315: #define remove_std_file(path) { \
7316: int fd = _open(path, _O_RDONLY | _O_BINARY); \
7317: if(fd != -1) { \
7318: _lseek(fd, 0, SEEK_END); \
7319: int size = _tell(fd); \
7320: _close(fd); \
7321: if(size == 0) { \
7322: remove(path); \
7323: } \
7324: } \
7325: }
7326:
7327: void msdos_finish()
7328: {
7329: for(int i = 0; i < MAX_FILES; i++) {
7330: if(file_handler[i].valid) {
7331: _close(i);
7332: }
7333: }
7334: #ifdef SUPPORT_AUX_PRN
7335: remove_std_file("stdaux.txt");
7336: remove_std_file("stdprn.txt");
7337: #endif
7338: msdos_dbcs_table_finish();
7339: }
7340:
7341: /* ----------------------------------------------------------------------------
7342: PC/AT hardware emulation
7343: ---------------------------------------------------------------------------- */
7344:
7345: void hardware_init()
7346: {
1.1.1.3 root 7347: CPU_INIT_CALL(CPU_MODEL);
1.1 root 7348: CPU_RESET_CALL(CPU_MODEL);
1.1.1.14! root 7349: m_IF = 1;
1.1.1.3 root 7350: #if defined(HAS_I386)
1.1 root 7351: cpu_type = (REG32(EDX) >> 8) & 0x0f;
7352: cpu_step = (REG32(EDX) >> 0) & 0x0f;
1.1.1.3 root 7353: #endif
7354: i386_set_a20_line(0);
1.1.1.14! root 7355:
1.1 root 7356: pic_init();
1.1.1.8 root 7357: #ifdef PIT_ALWAYS_RUNNING
7358: pit_init();
7359: #else
1.1 root 7360: pit_active = 0;
7361: #endif
1.1.1.8 root 7362: cmos_init();
7363: kbd_init();
1.1 root 7364: }
7365:
1.1.1.10 root 7366: void hardware_finish()
7367: {
7368: #if defined(HAS_I386)
7369: vtlb_free(m_vtlb);
7370: #endif
7371: }
7372:
1.1 root 7373: void hardware_run()
7374: {
7375: int ops = 0;
7376:
1.1.1.3 root 7377: while(!m_halted) {
1.1 root 7378: #ifdef SUPPORT_DISASSEMBLER
7379: if(dasm) {
7380: char buffer[256];
1.1.1.3 root 7381: #if defined(HAS_I386)
7382: UINT64 eip = m_eip;
7383: #else
7384: UINT64 eip = m_pc - SREG_BASE(CS);
7385: #endif
7386: UINT8 *oprom = mem + SREG_BASE(CS) + eip;
1.1 root 7387:
1.1.1.3 root 7388: #if defined(HAS_I386)
7389: if(m_operand_size) {
1.1 root 7390: CPU_DISASSEMBLE_CALL(x86_32);
1.1.1.3 root 7391: } else
7392: #endif
7393: CPU_DISASSEMBLE_CALL(x86_16);
1.1.1.12 root 7394: fprintf(stderr, "%04x:%04x\t%s\n", SREG(CS), (unsigned)eip, buffer);
1.1 root 7395: }
7396: #endif
1.1.1.3 root 7397: #if defined(HAS_I386)
7398: m_cycles = 1;
1.1 root 7399: CPU_EXECUTE_CALL(i386);
1.1.1.3 root 7400: #else
7401: CPU_EXECUTE_CALL(CPU_MODEL);
7402: #endif
1.1.1.14! root 7403: #if defined(HAS_I386)
! 7404: if(m_eip != m_prev_eip) {
! 7405: #else
! 7406: if(m_pc != m_prevpc) {
! 7407: #endif
! 7408: iops++;
! 7409: }
1.1.1.8 root 7410: if(++ops == 16384) {
1.1 root 7411: hardware_update();
7412: ops = 0;
7413: }
7414: }
7415: }
7416:
7417: void hardware_update()
7418: {
1.1.1.8 root 7419: static UINT32 prev_time = 0;
7420: UINT32 cur_time = timeGetTime();
7421:
7422: if(prev_time != cur_time) {
7423: // update pit and raise irq0
7424: #ifndef PIT_ALWAYS_RUNNING
7425: if(pit_active)
7426: #endif
7427: {
7428: if(pit_run(0, cur_time)) {
7429: pic_req(0, 0, 1);
7430: }
7431: pit_run(1, cur_time);
7432: pit_run(2, cur_time);
7433: }
7434: // check key input and raise irq1
1.1.1.14! root 7435: static UINT32 prev_tick = 0;
! 7436: UINT32 cur_tick = cur_time / 32;
! 7437: if(prev_tick != cur_tick) {
! 7438: // update keyboard flags
! 7439: UINT8 state;
! 7440: state = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
! 7441: state |= (GetAsyncKeyState(VK_CAPITAL) & 0x0001) ? 0x40 : 0;
! 7442: state |= (GetAsyncKeyState(VK_NUMLOCK) & 0x0001) ? 0x20 : 0;
! 7443: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
! 7444: state |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
! 7445: state |= (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? 0x04 : 0;
! 7446: state |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
! 7447: state |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
! 7448: mem[0x417] = state;
! 7449: state = (GetAsyncKeyState(VK_INSERT ) & 0x8000) ? 0x80 : 0;
! 7450: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
! 7451: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
! 7452: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
! 7453: // state |= (GetAsyncKeyState(VK_PAUSE ) & 0x0001) ? 0x08 : 0;
! 7454: // state |= (GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x04 : 0;
! 7455: state |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
! 7456: state |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
! 7457: mem[0x418] = state;
! 7458:
! 7459: // update keyboard input
1.1.1.8 root 7460: if(check_key_input()) {
7461: pic_req(0, 1, 1);
7462: }
1.1.1.14! root 7463: prev_tick = cur_tick;
1.1.1.8 root 7464: }
7465: prev_time = cur_time;
1.1 root 7466: }
7467: }
7468:
7469: // pic
7470:
7471: void pic_init()
7472: {
1.1.1.8 root 7473: memset(pic, 0, sizeof(pic));
7474: pic[0].imr = pic[1].imr = 0xff;
1.1 root 7475:
7476: // from bochs bios
7477: pic_write(0, 0, 0x11); // icw1 = 11h
7478: pic_write(0, 1, 0x08); // icw2 = 08h
7479: pic_write(0, 1, 0x04); // icw3 = 04h
7480: pic_write(0, 1, 0x01); // icw4 = 01h
7481: pic_write(0, 1, 0xb8); // ocw1 = b8h
7482: pic_write(1, 0, 0x11); // icw1 = 11h
7483: pic_write(1, 1, 0x70); // icw2 = 70h
7484: pic_write(1, 1, 0x02); // icw3 = 02h
7485: pic_write(1, 1, 0x01); // icw4 = 01h
7486: }
7487:
7488: void pic_write(int c, UINT32 addr, UINT8 data)
7489: {
7490: if(addr & 1) {
7491: if(pic[c].icw2_r) {
7492: // icw2
7493: pic[c].icw2 = data;
7494: pic[c].icw2_r = 0;
7495: } else if(pic[c].icw3_r) {
7496: // icw3
7497: pic[c].icw3 = data;
7498: pic[c].icw3_r = 0;
7499: } else if(pic[c].icw4_r) {
7500: // icw4
7501: pic[c].icw4 = data;
7502: pic[c].icw4_r = 0;
7503: } else {
7504: // ocw1
7505: pic[c].imr = data;
7506: }
7507: } else {
7508: if(data & 0x10) {
7509: // icw1
7510: pic[c].icw1 = data;
7511: pic[c].icw2_r = 1;
7512: pic[c].icw3_r = (data & 2) ? 0 : 1;
7513: pic[c].icw4_r = data & 1;
7514: pic[c].irr = 0;
7515: pic[c].isr = 0;
7516: pic[c].imr = 0;
7517: pic[c].prio = 0;
7518: if(!(pic[c].icw1 & 1)) {
7519: pic[c].icw4 = 0;
7520: }
7521: pic[c].ocw3 = 0;
7522: } else if(data & 8) {
7523: // ocw3
7524: if(!(data & 2)) {
7525: data = (data & ~1) | (pic[c].ocw3 & 1);
7526: }
7527: if(!(data & 0x40)) {
7528: data = (data & ~0x20) | (pic[c].ocw3 & 0x20);
7529: }
7530: pic[c].ocw3 = data;
7531: } else {
7532: // ocw2
7533: int level = 0;
7534: if(data & 0x40) {
7535: level = data & 7;
7536: } else {
7537: if(!pic[c].isr) {
7538: return;
7539: }
7540: level = pic[c].prio;
7541: while(!(pic[c].isr & (1 << level))) {
7542: level = (level + 1) & 7;
7543: }
7544: }
7545: if(data & 0x80) {
7546: pic[c].prio = (level + 1) & 7;
7547: }
7548: if(data & 0x20) {
7549: pic[c].isr &= ~(1 << level);
7550: }
7551: }
7552: }
7553: pic_update();
7554: }
7555:
7556: UINT8 pic_read(int c, UINT32 addr)
7557: {
7558: if(addr & 1) {
7559: return(pic[c].imr);
7560: } else {
7561: // polling mode is not supported...
7562: //if(pic[c].ocw3 & 4) {
7563: // return ???;
7564: //}
7565: if(pic[c].ocw3 & 1) {
7566: return(pic[c].isr);
7567: } else {
7568: return(pic[c].irr);
7569: }
7570: }
7571: }
7572:
7573: void pic_req(int c, int level, int signal)
7574: {
7575: if(signal) {
7576: pic[c].irr |= (1 << level);
7577: } else {
7578: pic[c].irr &= ~(1 << level);
7579: }
7580: pic_update();
7581: }
7582:
7583: int pic_ack()
7584: {
7585: // ack (INTA=L)
7586: pic[pic_req_chip].isr |= pic_req_bit;
7587: pic[pic_req_chip].irr &= ~pic_req_bit;
7588: if(pic_req_chip > 0) {
7589: // update isr and irr of master
7590: UINT8 slave = 1 << (pic[pic_req_chip].icw3 & 7);
7591: pic[pic_req_chip - 1].isr |= slave;
7592: pic[pic_req_chip - 1].irr &= ~slave;
7593: }
7594: //if(pic[pic_req_chip].icw4 & 1) {
7595: // 8086 mode
7596: int vector = (pic[pic_req_chip].icw2 & 0xf8) | pic_req_level;
7597: //} else {
7598: // // 8080 mode
7599: // UINT16 addr = (UINT16)pic[pic_req_chip].icw2 << 8;
7600: // if(pic[pic_req_chip].icw1 & 4) {
7601: // addr |= (pic[pic_req_chip].icw1 & 0xe0) | (pic_req_level << 2);
7602: // } else {
7603: // addr |= (pic[pic_req_chip].icw1 & 0xc0) | (pic_req_level << 3);
7604: // }
7605: // vector = 0xcd | (addr << 8);
7606: //}
7607: if(pic[pic_req_chip].icw4 & 2) {
7608: // auto eoi
7609: pic[pic_req_chip].isr &= ~pic_req_bit;
7610: }
7611: return(vector);
7612: }
7613:
7614: void pic_update()
7615: {
7616: for(int c = 0; c < 2; c++) {
7617: UINT8 irr = pic[c].irr;
7618: if(c + 1 < 2) {
7619: // this is master
7620: if(pic[c + 1].irr & (~pic[c + 1].imr)) {
7621: // request from slave
7622: irr |= 1 << (pic[c + 1].icw3 & 7);
7623: }
7624: }
7625: irr &= (~pic[c].imr);
7626: if(!irr) {
7627: break;
7628: }
7629: if(!(pic[c].ocw3 & 0x20)) {
7630: irr |= pic[c].isr;
7631: }
7632: int level = pic[c].prio;
7633: UINT8 bit = 1 << level;
7634: while(!(irr & bit)) {
7635: level = (level + 1) & 7;
7636: bit = 1 << level;
7637: }
7638: if((c + 1 < 2) && (pic[c].icw3 & bit)) {
7639: // check slave
7640: continue;
7641: }
7642: if(pic[c].isr & bit) {
7643: break;
7644: }
7645: // interrupt request
7646: pic_req_chip = c;
7647: pic_req_level = level;
7648: pic_req_bit = bit;
1.1.1.3 root 7649: i386_set_irq_line(INPUT_LINE_IRQ, HOLD_LINE);
1.1 root 7650: return;
7651: }
1.1.1.3 root 7652: i386_set_irq_line(INPUT_LINE_IRQ, CLEAR_LINE);
1.1.1.2 root 7653: }
1.1 root 7654:
7655: // pit
7656:
7657: #define PIT_FREQ 1193182
7658: #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)
7659:
7660: void pit_init()
7661: {
1.1.1.8 root 7662: memset(pit, 0, sizeof(pit));
1.1 root 7663: for(int ch = 0; ch < 3; ch++) {
7664: pit[ch].count = 0x10000;
7665: pit[ch].ctrl_reg = 0x34;
7666: pit[ch].mode = 3;
7667: }
7668:
7669: // from bochs bios
7670: pit_write(3, 0x34);
7671: pit_write(0, 0x00);
7672: pit_write(0, 0x00);
7673: }
7674:
7675: void pit_write(int ch, UINT8 val)
7676: {
1.1.1.8 root 7677: #ifndef PIT_ALWAYS_RUNNING
1.1 root 7678: if(!pit_active) {
7679: pit_active = 1;
7680: pit_init();
7681: }
1.1.1.8 root 7682: #endif
1.1 root 7683: switch(ch) {
7684: case 0:
7685: case 1:
7686: case 2:
7687: // write count register
7688: if(!pit[ch].low_write && !pit[ch].high_write) {
7689: if(pit[ch].ctrl_reg & 0x10) {
7690: pit[ch].low_write = 1;
7691: }
7692: if(pit[ch].ctrl_reg & 0x20) {
7693: pit[ch].high_write = 1;
7694: }
7695: }
7696: if(pit[ch].low_write) {
7697: pit[ch].count_reg = val;
7698: pit[ch].low_write = 0;
7699: } else if(pit[ch].high_write) {
7700: if((pit[ch].ctrl_reg & 0x30) == 0x20) {
7701: pit[ch].count_reg = val << 8;
7702: } else {
7703: pit[ch].count_reg |= val << 8;
7704: }
7705: pit[ch].high_write = 0;
7706: }
7707: // start count
1.1.1.8 root 7708: if(!pit[ch].low_write && !pit[ch].high_write) {
7709: if(pit[ch].mode == 0 || pit[ch].mode == 4 || pit[ch].prev_time == 0) {
7710: pit[ch].count = PIT_COUNT_VALUE(ch);
7711: pit[ch].prev_time = timeGetTime();
7712: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 7713: }
7714: }
7715: break;
7716: case 3: // ctrl reg
7717: if((val & 0xc0) == 0xc0) {
7718: // i8254 read-back command
7719: for(ch = 0; ch < 3; ch++) {
7720: if(!(val & 0x10) && !pit[ch].status_latched) {
7721: pit[ch].status = pit[ch].ctrl_reg & 0x3f;
7722: pit[ch].status_latched = 1;
7723: }
7724: if(!(val & 0x20) && !pit[ch].count_latched) {
7725: pit_latch_count(ch);
7726: }
7727: }
7728: break;
7729: }
7730: ch = (val >> 6) & 3;
7731: if(val & 0x30) {
7732: static int modes[8] = {0, 1, 2, 3, 4, 5, 2, 3};
7733: pit[ch].mode = modes[(val >> 1) & 7];
7734: pit[ch].count_latched = 0;
7735: pit[ch].low_read = pit[ch].high_read = 0;
7736: pit[ch].low_write = pit[ch].high_write = 0;
7737: pit[ch].ctrl_reg = val;
7738: // stop count
1.1.1.8 root 7739: pit[ch].prev_time = pit[ch].expired_time = 0;
1.1 root 7740: pit[ch].count_reg = 0;
7741: } else if(!pit[ch].count_latched) {
7742: pit_latch_count(ch);
7743: }
7744: break;
7745: }
7746: }
7747:
7748: UINT8 pit_read(int ch)
7749: {
1.1.1.8 root 7750: #ifndef PIT_ALWAYS_RUNNING
1.1 root 7751: if(!pit_active) {
7752: pit_active = 1;
7753: pit_init();
7754: }
1.1.1.8 root 7755: #endif
1.1 root 7756: switch(ch) {
7757: case 0:
7758: case 1:
7759: case 2:
7760: if(pit[ch].status_latched) {
7761: pit[ch].status_latched = 0;
7762: return(pit[ch].status);
7763: }
7764: // if not latched, through current count
7765: if(!pit[ch].count_latched) {
7766: if(!pit[ch].low_read && !pit[ch].high_read) {
7767: pit_latch_count(ch);
7768: }
7769: }
7770: // return latched count
7771: if(pit[ch].low_read) {
7772: pit[ch].low_read = 0;
7773: if(!pit[ch].high_read) {
7774: pit[ch].count_latched = 0;
7775: }
7776: return(pit[ch].latch & 0xff);
7777: } else if(pit[ch].high_read) {
7778: pit[ch].high_read = 0;
7779: pit[ch].count_latched = 0;
7780: return((pit[ch].latch >> 8) & 0xff);
7781: }
7782: }
7783: return(0xff);
7784: }
7785:
1.1.1.8 root 7786: int pit_run(int ch, UINT32 cur_time)
1.1 root 7787: {
1.1.1.8 root 7788: if(pit[ch].expired_time != 0 && cur_time >= pit[ch].expired_time) {
1.1 root 7789: pit[ch].count = PIT_COUNT_VALUE(ch);
1.1.1.8 root 7790: pit[ch].prev_time = pit[ch].expired_time;
7791: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
7792: if(cur_time >= pit[ch].expired_time) {
7793: pit[ch].prev_time = cur_time;
7794: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 7795: }
1.1.1.8 root 7796: return(1);
1.1 root 7797: }
1.1.1.8 root 7798: return(0);
1.1 root 7799: }
7800:
7801: void pit_latch_count(int ch)
7802: {
1.1.1.8 root 7803: UINT32 cur_time = timeGetTime();
7804:
7805: if(pit[ch].expired_time != 0) {
7806: pit_run(ch, cur_time);
7807: UINT32 tmp = (pit[ch].count * (pit[ch].expired_time - cur_time)) / (pit[ch].expired_time - pit[ch].prev_time);
7808: pit[ch].latch = (tmp != 0) ? (UINT16)tmp : 1;
7809: } else {
7810: pit[ch].latch = (UINT16)pit[ch].count;
1.1 root 7811: }
7812: pit[ch].count_latched = 1;
7813: if((pit[ch].ctrl_reg & 0x30) == 0x10) {
7814: // lower byte
7815: pit[ch].low_read = 1;
7816: pit[ch].high_read = 0;
7817: } else if((pit[ch].ctrl_reg & 0x30) == 0x20) {
7818: // upper byte
7819: pit[ch].low_read = 0;
7820: pit[ch].high_read = 1;
7821: } else {
7822: // lower -> upper
1.1.1.14! root 7823: pit[ch].low_read = pit[ch].high_read = 1;
1.1 root 7824: }
7825: }
7826:
1.1.1.8 root 7827: int pit_get_expired_time(int ch)
1.1 root 7828: {
1.1.1.8 root 7829: UINT32 val = (1000 * pit[ch].count) / PIT_FREQ;
7830: return((val > 0) ? val : 1);
7831: }
7832:
7833: // cmos
7834:
7835: void cmos_init()
7836: {
7837: memset(cmos, 0, sizeof(cmos));
7838: cmos_addr = 0;
1.1 root 7839:
1.1.1.8 root 7840: // from DOSBox
7841: cmos_write(0x0a, 0x26);
7842: cmos_write(0x0b, 0x02);
7843: cmos_write(0x0d, 0x80);
1.1 root 7844: }
7845:
1.1.1.8 root 7846: void cmos_write(int addr, UINT8 val)
1.1 root 7847: {
1.1.1.8 root 7848: cmos[addr & 0x7f] = val;
7849: }
7850:
7851: #define CMOS_GET_TIME() { \
7852: UINT32 cur_sec = timeGetTime() / 1000 ; \
7853: if(prev_sec != cur_sec) { \
7854: GetLocalTime(&time); \
7855: prev_sec = cur_sec; \
7856: } \
1.1 root 7857: }
1.1.1.8 root 7858: #define CMOS_BCD(v) ((cmos[0x0b] & 4) ? (v) : to_bcd(v))
1.1 root 7859:
1.1.1.8 root 7860: UINT8 cmos_read(int addr)
1.1 root 7861: {
1.1.1.8 root 7862: static SYSTEMTIME time;
7863: static UINT32 prev_sec = 0;
1.1 root 7864:
1.1.1.8 root 7865: switch(addr & 0x7f) {
7866: case 0x00: CMOS_GET_TIME(); return(CMOS_BCD(time.wSecond));
7867: case 0x02: CMOS_GET_TIME(); return(CMOS_BCD(time.wMinute));
7868: case 0x04: CMOS_GET_TIME(); return(CMOS_BCD(time.wHour));
7869: case 0x06: CMOS_GET_TIME(); return(time.wDayOfWeek + 1);
7870: case 0x07: CMOS_GET_TIME(); return(CMOS_BCD(time.wDay));
7871: case 0x08: CMOS_GET_TIME(); return(CMOS_BCD(time.wMonth));
7872: case 0x09: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear));
7873: // case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 2 ? 0x80 : 0)); // 2msec
7874: case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 20 ? 0x80 : 0)); // precision of timeGetTime() may not be 1msec
7875: case 0x15: return((MEMORY_END >> 10) & 0xff);
7876: case 0x16: return((MEMORY_END >> 18) & 0xff);
7877: case 0x17: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
7878: case 0x18: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
7879: case 0x30: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
7880: case 0x31: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
7881: case 0x32: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear / 100));
1.1 root 7882: }
1.1.1.8 root 7883: return(cmos[addr & 0x7f]);
1.1 root 7884: }
7885:
1.1.1.7 root 7886: // kbd (a20)
7887:
7888: void kbd_init()
7889: {
1.1.1.8 root 7890: kbd_data = kbd_command = 0;
1.1.1.7 root 7891: kbd_status = 0x18;
7892: }
7893:
7894: UINT8 kbd_read_data()
7895: {
1.1.1.8 root 7896: kbd_status &= ~1;
1.1.1.7 root 7897: return(kbd_data);
7898: }
7899:
7900: void kbd_write_data(UINT8 val)
7901: {
7902: switch(kbd_command) {
7903: case 0xd1:
7904: i386_set_a20_line((val >> 1) & 1);
7905: break;
7906: }
7907: kbd_command = 0;
1.1.1.8 root 7908: kbd_status &= ~8;
1.1.1.7 root 7909: }
7910:
7911: UINT8 kbd_read_status()
7912: {
7913: return(kbd_status);
7914: }
7915:
7916: void kbd_write_command(UINT8 val)
7917: {
7918: switch(val) {
7919: case 0xd0:
7920: kbd_data = ((m_a20_mask >> 19) & 2) | 1;
1.1.1.8 root 7921: kbd_status |= 1;
1.1.1.7 root 7922: break;
7923: case 0xdd:
7924: i386_set_a20_line(0);
7925: break;
7926: case 0xdf:
7927: i386_set_a20_line(1);
7928: break;
7929: case 0xf0:
7930: case 0xf1:
7931: case 0xf2:
7932: case 0xf3:
7933: case 0xf4:
7934: case 0xf5:
7935: case 0xf6:
7936: case 0xf7:
7937: case 0xf8:
7938: case 0xf9:
7939: case 0xfa:
7940: case 0xfb:
7941: case 0xfc:
7942: case 0xfd:
7943: case 0xfe:
7944: case 0xff:
7945: if(!(val & 1)) {
1.1.1.8 root 7946: if((cmos[0x0f] & 0x7f) == 5) {
1.1.1.7 root 7947: // reset pic
7948: pic_init();
7949: pic[0].irr = pic[1].irr = 0x00;
7950: pic[0].imr = pic[1].imr = 0xff;
7951: }
7952: CPU_RESET_CALL(CPU_MODEL);
7953: i386_jmp_far(0x40, 0x67);
7954: }
7955: i386_set_a20_line((val >> 1) & 1);
7956: break;
7957: }
7958: kbd_command = val;
1.1.1.8 root 7959: kbd_status |= 8;
1.1.1.7 root 7960: }
7961:
1.1.1.9 root 7962: // vga
7963:
7964: UINT8 vga_read_status()
7965: {
7966: // 60hz
7967: static const int period[3] = {16, 17, 17};
7968: static int index = 0;
7969: UINT32 time = timeGetTime() % period[index];
7970:
7971: index = (index + 1) % 3;
1.1.1.14! root 7972: return((time < 4 ? 0x08 : 0) | (time == 0 ? 0 : 0x01));
1.1.1.9 root 7973: }
7974:
1.1 root 7975: // i/o bus
7976:
7977: UINT8 read_io_byte(offs_t addr)
7978: {
7979: switch(addr) {
7980: case 0x20:
7981: case 0x21:
7982: return(pic_read(0, addr));
7983: case 0x40:
7984: case 0x41:
7985: case 0x42:
7986: case 0x43:
7987: return(pit_read(addr & 0x03));
1.1.1.7 root 7988: case 0x60:
7989: return(kbd_read_data());
1.1.1.9 root 7990: case 0x61:
7991: return(system_port);
1.1.1.7 root 7992: case 0x64:
7993: return(kbd_read_status());
1.1 root 7994: case 0x71:
1.1.1.8 root 7995: return(cmos_read(cmos_addr));
1.1 root 7996: case 0x92:
1.1.1.3 root 7997: return((m_a20_mask >> 19) & 2);
1.1 root 7998: case 0xa0:
7999: case 0xa1:
8000: return(pic_read(1, addr));
1.1.1.9 root 8001: case 0x3ba:
8002: case 0x3da:
8003: return(vga_read_status());
1.1 root 8004: default:
8005: // error("inb %4x\n", addr);
8006: break;
8007: }
8008: return(0xff);
8009: }
8010:
8011: UINT16 read_io_word(offs_t addr)
8012: {
8013: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8));
8014: }
8015:
8016: UINT32 read_io_dword(offs_t addr)
8017: {
8018: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8) | (read_io_byte(addr + 2) << 16) | (read_io_byte(addr + 3) << 24));
8019: }
8020:
8021: void write_io_byte(offs_t addr, UINT8 val)
8022: {
8023: switch(addr) {
8024: case 0x20:
8025: case 0x21:
8026: pic_write(0, addr, val);
8027: break;
8028: case 0x40:
8029: case 0x41:
8030: case 0x42:
8031: case 0x43:
8032: pit_write(addr & 0x03, val);
8033: break;
1.1.1.7 root 8034: case 0x60:
8035: kbd_write_data(val);
8036: break;
1.1.1.9 root 8037: case 0x61:
8038: if((system_port & 3) != 3 && (val & 3) == 3) {
8039: // beep on
8040: // MessageBeep(-1);
8041: } else if((system_port & 3) == 3 && (val & 3) != 3) {
8042: // beep off
8043: }
8044: system_port = val;
8045: break;
1.1 root 8046: case 0x64:
1.1.1.7 root 8047: kbd_write_command(val);
1.1 root 8048: break;
8049: case 0x70:
8050: cmos_addr = val;
8051: break;
8052: case 0x71:
1.1.1.8 root 8053: cmos_write(cmos_addr, val);
1.1 root 8054: break;
8055: case 0x92:
1.1.1.7 root 8056: i386_set_a20_line((val >> 1) & 1);
1.1 root 8057: break;
8058: case 0xa0:
8059: case 0xa1:
8060: pic_write(1, addr, val);
8061: break;
8062: default:
8063: // error("outb %4x,%2x\n", addr, val);
8064: break;
8065: }
8066: }
8067:
8068: void write_io_word(offs_t addr, UINT16 val)
8069: {
8070: write_io_byte(addr + 0, (val >> 0) & 0xff);
8071: write_io_byte(addr + 1, (val >> 8) & 0xff);
8072: }
8073:
8074: void write_io_dword(offs_t addr, UINT32 val)
8075: {
8076: write_io_byte(addr + 0, (val >> 0) & 0xff);
8077: write_io_byte(addr + 1, (val >> 8) & 0xff);
8078: write_io_byte(addr + 2, (val >> 16) & 0xff);
8079: write_io_byte(addr + 3, (val >> 24) & 0xff);
8080: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.