|
|
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:
1.1.1.28 root 10: void exit_handler();
11:
1.1 root 12: #define fatalerror(...) { \
13: fprintf(stderr, __VA_ARGS__); \
1.1.1.28 root 14: exit_handler(); \
1.1 root 15: exit(1); \
16: }
17: #define error(...) fprintf(stderr, "error: " __VA_ARGS__)
1.1.1.22 root 18: #define nolog(...)
19:
1.1.1.33! root 20: //#define ENABLE_DEBUG_LOG
! 21: #ifdef ENABLE_DEBUG_LOG
1.1.1.22 root 22: #define EXPORT_DEBUG_TO_FILE
23: #define ENABLE_DEBUG_SYSCALL
24: #define ENABLE_DEBUG_UNIMPLEMENTED
1.1.1.25 root 25: #define ENABLE_DEBUG_IOPORT
1.1.1.22 root 26:
27: #ifdef EXPORT_DEBUG_TO_FILE
1.1.1.33! root 28: FILE* fp_debug_log = NULL;
1.1.1.22 root 29: #else
1.1.1.33! root 30: #define fp_debug_log stderr
1.1.1.22 root 31: #endif
32: #ifdef ENABLE_DEBUG_UNIMPLEMENTED
33: #define unimplemented_10h fatalerror
1.1.1.25 root 34: #define unimplemented_14h fatalerror
1.1.1.22 root 35: #define unimplemented_15h fatalerror
36: #define unimplemented_16h fatalerror
37: #define unimplemented_1ah fatalerror
38: #define unimplemented_21h fatalerror
39: #define unimplemented_2fh fatalerror
1.1.1.24 root 40: #define unimplemented_33h fatalerror
1.1.1.22 root 41: #define unimplemented_67h fatalerror
42: #define unimplemented_xms fatalerror
43: #endif
44: #endif
45: #ifndef unimplemented_10h
46: #define unimplemented_10h nolog
47: #endif
1.1.1.25 root 48: #ifndef unimplemented_14h
49: #define unimplemented_14h nolog
50: #endif
1.1.1.22 root 51: #ifndef unimplemented_15h
52: #define unimplemented_15h nolog
53: #endif
54: #ifndef unimplemented_16h
55: #define unimplemented_16h nolog
56: #endif
57: #ifndef unimplemented_1ah
58: #define unimplemented_1ah nolog
59: #endif
60: #ifndef unimplemented_21h
61: #define unimplemented_21h nolog
62: #endif
63: #ifndef unimplemented_2fh
64: #define unimplemented_2fh nolog
65: #endif
1.1.1.24 root 66: #ifndef unimplemented_33h
67: #define unimplemented_33h nolog
68: #endif
1.1.1.22 root 69: #ifndef unimplemented_67h
70: #define unimplemented_67h nolog
71: #endif
72: #ifndef unimplemented_xms
73: #define unimplemented_xms nolog
74: #endif
75:
1.1.1.32 root 76: #define array_length(array) (sizeof(array) / sizeof(array[0]))
1.1.1.22 root 77: #define my_strchr(str, chr) (char *)_mbschr((unsigned char *)(str), (unsigned int)(chr))
78: #define my_strtok(tok, del) (char *)_mbstok((unsigned char *)(tok), (const unsigned char *)(del))
79: #define my_strupr(str) (char *)_mbsupr((unsigned char *)(str))
1.1 root 80:
1.1.1.12 root 81: #if defined(__MINGW32__)
82: extern "C" int _CRT_glob = 0;
83: #endif
84:
85: /*
86: kludge for "more-standardized" C++
87: */
88: #if !defined(_MSC_VER)
89: inline int kludge_min(int a, int b) { return (a<b ? a:b); }
90: inline int kludge_max(int a, int b) { return (a>b ? a:b); }
91: #define min(a,b) kludge_min(a,b)
92: #define max(a,b) kludge_max(a,b)
1.1.1.14 root 93: #elif _MSC_VER >= 1400
94: void ignore_invalid_parameters(const wchar_t *, const wchar_t *, const wchar_t *, unsigned int, uintptr_t)
95: {
96: }
97: #endif
98:
99: #define USE_THREAD
100:
101: #ifdef USE_THREAD
102: static CRITICAL_SECTION vram_crit_sect;
103: #else
104: #define EnterCriticalSection(x)
105: #define LeaveCriticalSection(x)
106: #define vram_flush()
1.1.1.12 root 107: #endif
108:
1.1.1.14 root 109: #define VIDEO_REGEN *(UINT16 *)(mem + 0x44c)
110: #define SCR_BUF(y,x) scr_buf[(y) * scr_buf_size.X + (x)]
111:
112: void change_console_size(int width, int height);
113: void clear_scr_buffer(WORD attr);
114:
115: static UINT32 vram_length_char = 0, vram_length_attr = 0;
116: static UINT32 vram_last_length_char = 0, vram_last_length_attr = 0;
117: static COORD vram_coord_char, vram_coord_attr;
118:
1.1.1.28 root 119: char temp_file_path[MAX_PATH];
120: bool temp_file_created = false;
121:
1.1.1.14 root 122: bool ignore_illegal_insn = false;
123: bool limit_max_memory = false;
124: bool no_windows = false;
125: bool stay_busy = false;
126: UINT32 iops = 0;
1.1.1.19 root 127: bool support_ems = false;
128: #ifdef SUPPORT_XMS
129: bool support_xms = false;
130: #endif
1.1.1.29 root 131: int sio_port_number[4] = {0, 0, 0, 0};
1.1.1.14 root 132:
133: BOOL is_vista_or_later;
134:
135: inline void maybe_idle()
136: {
137: // if it appears to be in a tight loop, assume waiting for input
138: // allow for one updated video character, for a spinning cursor
139: if(!stay_busy && iops < 1000 && vram_length_char <= 1 && vram_length_attr <= 1) {
140: Sleep(10);
141: }
142: iops = 0;
143: }
1.1.1.12 root 144:
1.1 root 145: /* ----------------------------------------------------------------------------
1.1.1.3 root 146: MAME i86/i386
1.1 root 147: ---------------------------------------------------------------------------- */
148:
1.1.1.10 root 149: #ifndef __BIG_ENDIAN__
1.1 root 150: #define LSB_FIRST
1.1.1.10 root 151: #endif
1.1 root 152:
153: #ifndef INLINE
154: #define INLINE inline
155: #endif
156: #define U64(v) UINT64(v)
157:
158: //#define logerror(...) fprintf(stderr, __VA_ARGS__)
159: #define logerror(...)
160: //#define popmessage(...) fprintf(stderr, __VA_ARGS__)
161: #define popmessage(...)
162:
163: /*****************************************************************************/
1.1.1.10 root 164: /* src/emu/devcpu.h */
165:
166: // CPU interface functions
167: #define CPU_INIT_NAME(name) cpu_init_##name
168: #define CPU_INIT(name) void CPU_INIT_NAME(name)()
169: #define CPU_INIT_CALL(name) CPU_INIT_NAME(name)()
170:
171: #define CPU_RESET_NAME(name) cpu_reset_##name
172: #define CPU_RESET(name) void CPU_RESET_NAME(name)()
173: #define CPU_RESET_CALL(name) CPU_RESET_NAME(name)()
174:
175: #define CPU_EXECUTE_NAME(name) cpu_execute_##name
176: #define CPU_EXECUTE(name) void CPU_EXECUTE_NAME(name)()
177: #define CPU_EXECUTE_CALL(name) CPU_EXECUTE_NAME(name)()
178:
179: #define CPU_TRANSLATE_NAME(name) cpu_translate_##name
180: #define CPU_TRANSLATE(name) int CPU_TRANSLATE_NAME(name)(address_spacenum space, int intention, offs_t *address)
181: #define CPU_TRANSLATE_CALL(name) CPU_TRANSLATE_NAME(name)(space, intention, address)
182:
183: #define CPU_DISASSEMBLE_NAME(name) cpu_disassemble_##name
184: #define CPU_DISASSEMBLE(name) int CPU_DISASSEMBLE_NAME(name)(char *buffer, offs_t eip, const UINT8 *oprom)
185: #define CPU_DISASSEMBLE_CALL(name) CPU_DISASSEMBLE_NAME(name)(buffer, eip, oprom)
186:
1.1.1.14 root 187: #define CPU_MODEL_STR(name) #name
188: #define CPU_MODEL_NAME(name) CPU_MODEL_STR(name)
189:
1.1.1.10 root 190: /*****************************************************************************/
191: /* src/emu/didisasm.h */
192:
193: // Disassembler constants
194: const UINT32 DASMFLAG_SUPPORTED = 0x80000000; // are disassembly flags supported?
195: const UINT32 DASMFLAG_STEP_OUT = 0x40000000; // this instruction should be the end of a step out sequence
196: const UINT32 DASMFLAG_STEP_OVER = 0x20000000; // this instruction should be stepped over by setting a breakpoint afterwards
197: const UINT32 DASMFLAG_OVERINSTMASK = 0x18000000; // number of extra instructions to skip when stepping over
198: const UINT32 DASMFLAG_OVERINSTSHIFT = 27; // bits to shift after masking to get the value
199: const UINT32 DASMFLAG_LENGTHMASK = 0x0000ffff; // the low 16-bits contain the actual length
200:
201: /*****************************************************************************/
1.1 root 202: /* src/emu/diexec.h */
203:
204: // I/O line states
205: enum line_state
206: {
207: CLEAR_LINE = 0, // clear (a fired or held) line
208: ASSERT_LINE, // assert an interrupt immediately
209: HOLD_LINE, // hold interrupt line until acknowledged
210: PULSE_LINE // pulse interrupt line instantaneously (only for NMI, RESET)
211: };
212:
213: // I/O line definitions
214: enum
215: {
216: INPUT_LINE_IRQ = 0,
217: INPUT_LINE_NMI
218: };
219:
220: /*****************************************************************************/
1.1.1.10 root 221: /* src/emu/dimemory.h */
1.1 root 222:
1.1.1.10 root 223: // Translation intentions
224: const int TRANSLATE_TYPE_MASK = 0x03; // read write or fetch
225: const int TRANSLATE_USER_MASK = 0x04; // user mode or fully privileged
226: const int TRANSLATE_DEBUG_MASK = 0x08; // debug mode (no side effects)
227:
228: const int TRANSLATE_READ = 0; // translate for read
229: const int TRANSLATE_WRITE = 1; // translate for write
230: const int TRANSLATE_FETCH = 2; // translate for instruction fetch
231: const int TRANSLATE_READ_USER = (TRANSLATE_READ | TRANSLATE_USER_MASK);
232: const int TRANSLATE_WRITE_USER = (TRANSLATE_WRITE | TRANSLATE_USER_MASK);
233: const int TRANSLATE_FETCH_USER = (TRANSLATE_FETCH | TRANSLATE_USER_MASK);
234: const int TRANSLATE_READ_DEBUG = (TRANSLATE_READ | TRANSLATE_DEBUG_MASK);
235: const int TRANSLATE_WRITE_DEBUG = (TRANSLATE_WRITE | TRANSLATE_DEBUG_MASK);
236: const int TRANSLATE_FETCH_DEBUG = (TRANSLATE_FETCH | TRANSLATE_DEBUG_MASK);
1.1 root 237:
1.1.1.10 root 238: /*****************************************************************************/
239: /* src/emu/emucore.h */
1.1 root 240:
1.1.1.10 root 241: // constants for expression endianness
242: enum endianness_t
243: {
244: ENDIANNESS_LITTLE,
245: ENDIANNESS_BIG
246: };
1.1 root 247:
1.1.1.10 root 248: // declare native endianness to be one or the other
249: #ifdef LSB_FIRST
250: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_LITTLE;
251: #else
252: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_BIG;
253: #endif
254:
255: // endian-based value: first value is if 'endian' is little-endian, second is if 'endian' is big-endian
256: #define ENDIAN_VALUE_LE_BE(endian,leval,beval) (((endian) == ENDIANNESS_LITTLE) ? (leval) : (beval))
257:
258: // endian-based value: first value is if native endianness is little-endian, second is if native is big-endian
259: #define NATIVE_ENDIAN_VALUE_LE_BE(leval,beval) ENDIAN_VALUE_LE_BE(ENDIANNESS_NATIVE, leval, beval)
260:
261: // endian-based value: first value is if 'endian' matches native, second is if 'endian' doesn't match native
262: #define ENDIAN_VALUE_NE_NNE(endian,leval,beval) (((endian) == ENDIANNESS_NATIVE) ? (neval) : (nneval))
1.1 root 263:
264: /*****************************************************************************/
265: /* src/emu/memory.h */
266:
1.1.1.10 root 267: // address spaces
268: enum address_spacenum
269: {
270: AS_0, // first address space
271: AS_1, // second address space
272: AS_2, // third address space
273: AS_3, // fourth address space
274: ADDRESS_SPACES, // maximum number of address spaces
275:
276: // alternate address space names for common use
277: AS_PROGRAM = AS_0, // program address space
278: AS_DATA = AS_1, // data address space
279: AS_IO = AS_2 // I/O address space
280: };
281:
1.1 root 282: // offsets and addresses are 32-bit (for now...)
1.1.1.30 root 283: //typedef UINT32 offs_t;
1.1 root 284:
285: // read accessors
286: UINT8 read_byte(offs_t byteaddress)
1.1.1.33! root 287: #ifdef USE_DEBUGGER
! 288: {
! 289: if(now_debugging) {
! 290: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
! 291: if(rd_break_point.table[i].status == 1) {
! 292: if(byteaddress == rd_break_point.table[i].addr) {
! 293: rd_break_point.hit = i + 1;
! 294: now_suspended = true;
! 295: break;
! 296: }
! 297: }
! 298: }
! 299: }
! 300: return(debugger_read_byte(byteaddress));
! 301: }
! 302: UINT8 debugger_read_byte(offs_t byteaddress)
! 303: #endif
1.1 root 304: {
1.1.1.4 root 305: #if defined(HAS_I386)
1.1 root 306: if(byteaddress < MAX_MEM) {
307: return mem[byteaddress];
1.1.1.3 root 308: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
309: // return read_byte(byteaddress & 0xfffff);
1.1 root 310: }
311: return 0;
1.1.1.4 root 312: #else
313: return mem[byteaddress];
314: #endif
1.1 root 315: }
316:
317: UINT16 read_word(offs_t byteaddress)
1.1.1.33! root 318: #ifdef USE_DEBUGGER
! 319: {
! 320: if(now_debugging) {
! 321: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
! 322: if(rd_break_point.table[i].status == 1) {
! 323: if(byteaddress >= rd_break_point.table[i].addr && byteaddress < rd_break_point.table[i].addr + 2) {
! 324: rd_break_point.hit = i + 1;
! 325: now_suspended = true;
! 326: break;
! 327: }
! 328: }
! 329: }
! 330: }
! 331: return(debugger_read_word(byteaddress));
! 332: }
! 333: UINT16 debugger_read_word(offs_t byteaddress)
! 334: #endif
1.1 root 335: {
1.1.1.14 root 336: if(byteaddress == 0x41c) {
337: // pointer to first free slot in keyboard buffer
338: // XXX: the buffer itself doesn't actually exist in DOS memory
1.1.1.32 root 339: if(key_buf_char != NULL) {
340: if(key_buf_char->count() == 0) {
341: maybe_idle();
342: }
343: return (UINT16)key_buf_char->count();
1.1.1.14 root 344: }
1.1.1.32 root 345: return 0;
1.1.1.14 root 346: }
1.1.1.4 root 347: #if defined(HAS_I386)
1.1 root 348: if(byteaddress < MAX_MEM - 1) {
349: return *(UINT16 *)(mem + byteaddress);
1.1.1.3 root 350: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
351: // return read_word(byteaddress & 0xfffff);
1.1 root 352: }
353: return 0;
1.1.1.4 root 354: #else
355: return *(UINT16 *)(mem + byteaddress);
356: #endif
1.1 root 357: }
358:
359: UINT32 read_dword(offs_t byteaddress)
1.1.1.33! root 360: #ifdef USE_DEBUGGER
! 361: {
! 362: if(now_debugging) {
! 363: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
! 364: if(rd_break_point.table[i].status == 1) {
! 365: if(byteaddress >= rd_break_point.table[i].addr && byteaddress < rd_break_point.table[i].addr + 4) {
! 366: rd_break_point.hit = i + 1;
! 367: now_suspended = true;
! 368: break;
! 369: }
! 370: }
! 371: }
! 372: }
! 373: return(debugger_read_dword(byteaddress));
! 374: }
! 375: UINT32 debugger_read_dword(offs_t byteaddress)
! 376: #endif
1.1 root 377: {
1.1.1.4 root 378: #if defined(HAS_I386)
1.1 root 379: if(byteaddress < MAX_MEM - 3) {
380: return *(UINT32 *)(mem + byteaddress);
1.1.1.3 root 381: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
382: // return read_dword(byteaddress & 0xfffff);
1.1 root 383: }
384: return 0;
1.1.1.4 root 385: #else
386: return *(UINT32 *)(mem + byteaddress);
387: #endif
1.1 root 388: }
389:
390: // write accessors
1.1.1.14 root 391: #ifdef USE_THREAD
392: void vram_flush_char()
393: {
394: if(vram_length_char != 0) {
395: DWORD num;
1.1.1.23 root 396: WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), scr_char, vram_length_char, vram_coord_char, &num);
1.1.1.14 root 397: vram_length_char = vram_last_length_char = 0;
398: }
399: }
400:
401: void vram_flush_attr()
402: {
403: if(vram_length_attr != 0) {
404: DWORD num;
1.1.1.23 root 405: WriteConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), scr_attr, vram_length_attr, vram_coord_attr, &num);
1.1.1.14 root 406: vram_length_attr = vram_last_length_attr = 0;
407: }
408: }
409:
410: void vram_flush()
411: {
412: if(vram_length_char != 0 || vram_length_attr != 0) {
413: EnterCriticalSection(&vram_crit_sect);
414: vram_flush_char();
415: vram_flush_attr();
416: LeaveCriticalSection(&vram_crit_sect);
417: }
418: }
419: #endif
420:
421: void write_text_vram_char(offs_t offset, UINT8 data)
1.1.1.8 root 422: {
1.1.1.14 root 423: #ifdef USE_THREAD
424: static offs_t first_offset_char, last_offset_char;
425:
426: if(vram_length_char != 0) {
427: if(offset <= last_offset_char && offset >= first_offset_char) {
428: scr_char[(offset - first_offset_char) >> 1] = data;
429: return;
430: }
431: if(offset != last_offset_char + 2) {
432: vram_flush_char();
433: }
434: }
435: if(vram_length_char == 0) {
436: first_offset_char = offset;
437: vram_coord_char.X = (offset >> 1) % scr_width;
438: vram_coord_char.Y = (offset >> 1) / scr_width + scr_top;
439: }
440: scr_char[vram_length_char++] = data;
441: last_offset_char = offset;
442: #else
1.1.1.8 root 443: COORD co;
444: DWORD num;
445:
1.1.1.14 root 446: co.X = (offset >> 1) % scr_width;
447: co.Y = (offset >> 1) / scr_width;
448: scr_char[0] = data;
1.1.1.23 root 449: WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), scr_char, 1, co, &num);
1.1.1.14 root 450: #endif
451: }
452:
453: void write_text_vram_attr(offs_t offset, UINT8 data)
454: {
455: #ifdef USE_THREAD
456: static offs_t first_offset_attr, last_offset_attr;
457:
458: if(vram_length_attr != 0) {
459: if(offset <= last_offset_attr && offset >= first_offset_attr) {
460: scr_attr[(offset - first_offset_attr) >> 1] = data;
461: return;
462: }
463: if(offset != last_offset_attr + 2) {
464: vram_flush_attr();
465: }
466: }
467: if(vram_length_attr == 0) {
468: first_offset_attr = offset;
469: vram_coord_attr.X = (offset >> 1) % scr_width;
470: vram_coord_attr.Y = (offset >> 1) / scr_width + scr_top;
471: }
472: scr_attr[vram_length_attr++] = data;
473: last_offset_attr = offset;
474: #else
475: COORD co;
476: DWORD num;
1.1.1.8 root 477:
1.1.1.14 root 478: co.X = (offset >> 1) % scr_width;
479: co.Y = (offset >> 1) / scr_width;
480: scr_attr[0] = data;
1.1.1.23 root 481: WriteConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), scr_attr, 1, co, &num);
1.1.1.14 root 482: #endif
483: }
484:
485: void write_text_vram_byte(offs_t offset, UINT8 data)
486: {
487: EnterCriticalSection(&vram_crit_sect);
1.1.1.8 root 488: if(offset & 1) {
1.1.1.14 root 489: write_text_vram_attr(offset, data);
1.1.1.8 root 490: } else {
1.1.1.14 root 491: write_text_vram_char(offset, data);
1.1.1.8 root 492: }
1.1.1.14 root 493: LeaveCriticalSection(&vram_crit_sect);
1.1.1.8 root 494: }
495:
496: void write_text_vram_word(offs_t offset, UINT16 data)
497: {
1.1.1.14 root 498: EnterCriticalSection(&vram_crit_sect);
1.1.1.8 root 499: if(offset & 1) {
1.1.1.14 root 500: write_text_vram_attr(offset , (data ) & 0xff);
501: write_text_vram_char(offset + 1, (data >> 8) & 0xff);
1.1.1.8 root 502: } else {
1.1.1.14 root 503: write_text_vram_char(offset , (data ) & 0xff);
504: write_text_vram_attr(offset + 1, (data >> 8) & 0xff);
1.1.1.8 root 505: }
1.1.1.14 root 506: LeaveCriticalSection(&vram_crit_sect);
1.1.1.8 root 507: }
508:
509: void write_text_vram_dword(offs_t offset, UINT32 data)
510: {
1.1.1.14 root 511: EnterCriticalSection(&vram_crit_sect);
1.1.1.8 root 512: if(offset & 1) {
1.1.1.14 root 513: write_text_vram_attr(offset , (data ) & 0xff);
514: write_text_vram_char(offset + 1, (data >> 8) & 0xff);
515: write_text_vram_attr(offset + 2, (data >> 16) & 0xff);
516: write_text_vram_char(offset + 3, (data >> 24) & 0xff);
517: } else {
518: write_text_vram_char(offset , (data ) & 0xff);
519: write_text_vram_attr(offset + 1, (data >> 8) & 0xff);
520: write_text_vram_char(offset + 2, (data >> 16) & 0xff);
521: write_text_vram_attr(offset + 3, (data >> 24) & 0xff);
1.1.1.8 root 522: }
1.1.1.14 root 523: LeaveCriticalSection(&vram_crit_sect);
1.1.1.8 root 524: }
525:
1.1 root 526: void write_byte(offs_t byteaddress, UINT8 data)
1.1.1.33! root 527: #ifdef USE_DEBUGGER
! 528: {
! 529: if(now_debugging) {
! 530: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
! 531: if(wr_break_point.table[i].status == 1) {
! 532: if(byteaddress == wr_break_point.table[i].addr) {
! 533: wr_break_point.hit = i + 1;
! 534: now_suspended = true;
! 535: break;
! 536: }
! 537: }
! 538: }
! 539: }
! 540: debugger_write_byte(byteaddress, data);
! 541: }
! 542: void debugger_write_byte(offs_t byteaddress, UINT8 data)
! 543: #endif
1.1 root 544: {
1.1.1.8 root 545: if(byteaddress < MEMORY_END) {
1.1.1.3 root 546: mem[byteaddress] = data;
1.1.1.8 root 547: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 548: if(!restore_console_on_exit) {
549: change_console_size(scr_width, scr_height);
1.1.1.12 root 550: }
1.1.1.8 root 551: write_text_vram_byte(byteaddress - text_vram_top_address, data);
552: mem[byteaddress] = data;
553: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
554: if(int_10h_feh_called && !int_10h_ffh_called) {
555: write_text_vram_byte(byteaddress - shadow_buffer_top_address, data);
1.1 root 556: }
557: mem[byteaddress] = data;
1.1.1.4 root 558: #if defined(HAS_I386)
1.1.1.3 root 559: } else if(byteaddress < MAX_MEM) {
1.1.1.4 root 560: #else
561: } else {
562: #endif
1.1.1.3 root 563: mem[byteaddress] = data;
1.1 root 564: }
565: }
566:
567: void write_word(offs_t byteaddress, UINT16 data)
1.1.1.33! root 568: #ifdef USE_DEBUGGER
! 569: {
! 570: if(now_debugging) {
! 571: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
! 572: if(wr_break_point.table[i].status == 1) {
! 573: if(byteaddress >= wr_break_point.table[i].addr && byteaddress < wr_break_point.table[i].addr + 2) {
! 574: wr_break_point.hit = i + 1;
! 575: now_suspended = true;
! 576: break;
! 577: }
! 578: }
! 579: }
! 580: }
! 581: debugger_write_word(byteaddress, data);
! 582: }
! 583: void debugger_write_word(offs_t byteaddress, UINT16 data)
! 584: #endif
1.1 root 585: {
1.1.1.8 root 586: if(byteaddress < MEMORY_END) {
1.1.1.14 root 587: if(byteaddress == 0x450 + mem[0x462] * 2) {
588: COORD co;
589: co.X = data & 0xff;
590: co.Y = (data >> 8) + scr_top;
1.1.1.23 root 591: SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), co);
1.1.1.14 root 592: }
1.1.1.3 root 593: *(UINT16 *)(mem + byteaddress) = data;
1.1.1.8 root 594: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 595: if(!restore_console_on_exit) {
596: change_console_size(scr_width, scr_height);
1.1.1.12 root 597: }
1.1.1.8 root 598: write_text_vram_word(byteaddress - text_vram_top_address, data);
599: *(UINT16 *)(mem + byteaddress) = data;
600: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
601: if(int_10h_feh_called && !int_10h_ffh_called) {
602: write_text_vram_word(byteaddress - shadow_buffer_top_address, data);
1.1 root 603: }
604: *(UINT16 *)(mem + byteaddress) = data;
1.1.1.4 root 605: #if defined(HAS_I386)
1.1.1.3 root 606: } else if(byteaddress < MAX_MEM - 1) {
1.1.1.4 root 607: #else
608: } else {
609: #endif
1.1.1.3 root 610: *(UINT16 *)(mem + byteaddress) = data;
1.1 root 611: }
612: }
613:
614: void write_dword(offs_t byteaddress, UINT32 data)
1.1.1.33! root 615: #ifdef USE_DEBUGGER
! 616: {
! 617: if(now_debugging) {
! 618: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
! 619: if(wr_break_point.table[i].status == 1) {
! 620: if(byteaddress >= wr_break_point.table[i].addr && byteaddress < wr_break_point.table[i].addr + 4) {
! 621: wr_break_point.hit = i + 1;
! 622: now_suspended = true;
! 623: break;
! 624: }
! 625: }
! 626: }
! 627: }
! 628: debugger_write_dword(byteaddress, data);
! 629: }
! 630: void debugger_write_dword(offs_t byteaddress, UINT32 data)
! 631: #endif
1.1 root 632: {
1.1.1.8 root 633: if(byteaddress < MEMORY_END) {
1.1.1.3 root 634: *(UINT32 *)(mem + byteaddress) = data;
1.1.1.8 root 635: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 636: if(!restore_console_on_exit) {
637: change_console_size(scr_width, scr_height);
1.1.1.12 root 638: }
1.1.1.8 root 639: write_text_vram_dword(byteaddress - text_vram_top_address, data);
640: *(UINT32 *)(mem + byteaddress) = data;
641: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
642: if(int_10h_feh_called && !int_10h_ffh_called) {
643: write_text_vram_dword(byteaddress - shadow_buffer_top_address, data);
1.1 root 644: }
645: *(UINT32 *)(mem + byteaddress) = data;
1.1.1.4 root 646: #if defined(HAS_I386)
1.1.1.3 root 647: } else if(byteaddress < MAX_MEM - 3) {
1.1.1.4 root 648: #else
649: } else {
650: #endif
1.1.1.3 root 651: *(UINT32 *)(mem + byteaddress) = data;
1.1 root 652: }
653: }
654:
655: #define read_decrypted_byte read_byte
656: #define read_decrypted_word read_word
657: #define read_decrypted_dword read_dword
658:
1.1.1.3 root 659: #define read_raw_byte read_byte
660: #define write_raw_byte write_byte
661:
662: #define read_word_unaligned read_word
663: #define write_word_unaligned write_word
664:
665: #define read_io_word_unaligned read_io_word
666: #define write_io_word_unaligned write_io_word
667:
1.1 root 668: UINT8 read_io_byte(offs_t byteaddress);
669: UINT16 read_io_word(offs_t byteaddress);
670: UINT32 read_io_dword(offs_t byteaddress);
671:
672: void write_io_byte(offs_t byteaddress, UINT8 data);
673: void write_io_word(offs_t byteaddress, UINT16 data);
674: void write_io_dword(offs_t byteaddress, UINT32 data);
675:
676: /*****************************************************************************/
677: /* src/osd/osdcomm.h */
678:
679: /* Highly useful macro for compile-time knowledge of an array size */
680: #define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0]))
681:
1.1.1.3 root 682: #if defined(HAS_I386)
1.1.1.10 root 683: static CPU_TRANSLATE(i386);
684: #include "mame/lib/softfloat/softfloat.c"
685: #include "mame/emu/cpu/i386/i386.c"
1.1.1.12 root 686: #include "mame/emu/cpu/vtlb.c"
1.1.1.3 root 687: #elif defined(HAS_I286)
1.1.1.10 root 688: #include "mame/emu/cpu/i86/i286.c"
1.1.1.3 root 689: #else
1.1.1.10 root 690: #include "mame/emu/cpu/i86/i86.c"
1.1.1.3 root 691: #endif
1.1.1.33! root 692: #ifdef USE_DEBUGGER
1.1.1.10 root 693: #include "mame/emu/cpu/i386/i386dasm.c"
1.1 root 694: #endif
695:
1.1.1.3 root 696: #if defined(HAS_I386)
697: #define SREG(x) m_sreg[x].selector
698: #define SREG_BASE(x) m_sreg[x].base
699: int cpu_type, cpu_step;
700: #else
701: #define REG8(x) m_regs.b[x]
702: #define REG16(x) m_regs.w[x]
703: #define SREG(x) m_sregs[x]
704: #define SREG_BASE(x) m_base[x]
1.1.1.33! root 705: #define m_eip (m_pc - m_base[CS])
1.1.1.3 root 706: #define m_CF m_CarryVal
707: #define m_a20_mask AMASK
708: #define i386_load_segment_descriptor(x) m_base[x] = SegBase(x)
709: #if defined(HAS_I286)
710: #define i386_set_a20_line(x) i80286_set_a20_line(x)
711: #else
712: #define i386_set_a20_line(x)
713: #endif
714: #define i386_set_irq_line(x, y) set_irq_line(x, y)
715: #endif
1.1 root 716:
717: void i386_jmp_far(UINT16 selector, UINT32 address)
718: {
1.1.1.3 root 719: #if defined(HAS_I386)
1.1 root 720: if(PROTECTED_MODE && !V8086_MODE) {
1.1.1.3 root 721: i386_protected_mode_jump(selector, address, 1, m_operand_size);
1.1 root 722: } else {
1.1.1.3 root 723: SREG(CS) = selector;
724: m_performed_intersegment_jump = 1;
725: i386_load_segment_descriptor(CS);
726: m_eip = address;
727: CHANGE_PC(m_eip);
1.1 root 728: }
1.1.1.3 root 729: #elif defined(HAS_I286)
730: i80286_code_descriptor(selector, address, 1);
731: #else
732: SREG(CS) = selector;
733: i386_load_segment_descriptor(CS);
734: m_pc = (SREG_BASE(CS) + address) & m_a20_mask;
735: #endif
1.1 root 736: }
737:
1.1.1.24 root 738: /*
739: void i386_call_far(UINT16 selector, UINT32 address)
740: {
741: #if defined(HAS_I386)
742: if(PROTECTED_MODE && !V8086_MODE) {
743: i386_protected_mode_call(selector, address, 1, m_operand_size);
744: } else {
745: PUSH16(SREG(CS));
746: PUSH16(m_eip);
747: SREG(CS) = selector;
748: m_performed_intersegment_jump = 1;
749: i386_load_segment_descriptor(CS);
750: m_eip = address;
751: CHANGE_PC(m_eip);
752: }
753: #else
754: UINT16 ip = m_pc - SREG_BASE(CS);
755: UINT16 cs = SREG(CS);
756: #if defined(HAS_I286)
757: i80286_code_descriptor(selector, address, 2);
758: #else
759: SREG(CS) = selector;
760: i386_load_segment_descriptor(CS);
761: m_pc = (SREG_BASE(CS) + address) & m_a20_mask;
762: #endif
763: PUSH(cs);
764: PUSH(ip);
765: CHANGE_PC(m_pc);
766: #endif
767: }
768: */
769:
1.1.1.29 root 770: UINT16 i386_read_stack()
771: {
772: #if defined(HAS_I386)
773: UINT32 ea, new_esp;
774: if( STACK_32BIT ) {
775: new_esp = REG32(ESP) + 2;
776: ea = i386_translate(SS, new_esp - 2, 0);
777: } else {
778: new_esp = REG16(SP) + 2;
779: ea = i386_translate(SS, (new_esp - 2) & 0xffff, 0);
780: }
781: return READ16(ea);
782: #else
783: UINT16 sp = m_regs.w[SP] + 2;
784: return ReadWord(((m_base[SS] + ((sp - 2) & 0xffff)) & AMASK));
785: #endif
786: }
787:
1.1 root 788: /* ----------------------------------------------------------------------------
1.1.1.33! root 789: debugger
! 790: ---------------------------------------------------------------------------- */
! 791:
! 792: #ifdef USE_DEBUGGER
! 793: #define TELNET_BLUE 0x0004 // text color contains blue.
! 794: #define TELNET_GREEN 0x0002 // text color contains green.
! 795: #define TELNET_RED 0x0001 // text color contains red.
! 796: #define TELNET_INTENSITY 0x0008 // text color is intensified.
! 797:
! 798: int svr_socket = 0;
! 799: int cli_socket = 0;
! 800:
! 801: process_t *msdos_process_info_get(UINT16 psp_seg, bool show_error);
! 802:
! 803: void debugger_init()
! 804: {
! 805: now_debugging = false;
! 806: now_going = false;
! 807: now_suspended = false;
! 808: force_suspend = false;
! 809:
! 810: memset(&break_point, 0, sizeof(break_point_t));
! 811: memset(&rd_break_point, 0, sizeof(break_point_t));
! 812: memset(&wr_break_point, 0, sizeof(break_point_t));
! 813: memset(&in_break_point, 0, sizeof(break_point_t));
! 814: memset(&out_break_point, 0, sizeof(break_point_t));
! 815: memset(&int_break_point, 0, sizeof(int_break_point_t));
! 816: }
! 817:
! 818: void telnet_send(char *string)
! 819: {
! 820: char buffer[8192], *ptr;
! 821: strcpy(buffer, string);
! 822: while((ptr = strstr(buffer, "\n")) != NULL) {
! 823: char tmp[8192];
! 824: *ptr = '\0';
! 825: sprintf(tmp, "%s\033E%s", buffer, ptr + 1);
! 826: strcpy(buffer, tmp);
! 827: }
! 828:
! 829: int len = strlen(buffer), res;
! 830: ptr = buffer;
! 831: while(len > 0) {
! 832: if((res = send(cli_socket, ptr, len, 0)) > 0) {
! 833: len -= res;
! 834: ptr += res;
! 835: }
! 836: }
! 837: }
! 838:
! 839: void telnet_command(const char *format, ...)
! 840: {
! 841: char buffer[1024];
! 842: va_list ap;
! 843: va_start(ap, format);
! 844: vsprintf(buffer, format, ap);
! 845: va_end(ap);
! 846:
! 847: telnet_send(buffer);
! 848: }
! 849:
! 850: void telnet_printf(const char *format, ...)
! 851: {
! 852: char buffer[1024];
! 853: va_list ap;
! 854: va_start(ap, format);
! 855: vsprintf(buffer, format, ap);
! 856: va_end(ap);
! 857:
! 858: if(fp_debugger != NULL) {
! 859: fprintf(fp_debugger, "%s", buffer);
! 860: }
! 861: telnet_send(buffer);
! 862: }
! 863:
! 864: bool telnet_gets(char *str, int n)
! 865: {
! 866: char buffer[1024];
! 867: int ptr = 0;
! 868:
! 869: telnet_command("\033[12l"); // local echo on
! 870: telnet_command("\033[2l"); // key unlock
! 871:
! 872: while(!m_halted) {
! 873: int len = recv(cli_socket, buffer, sizeof(buffer), 0);
! 874:
! 875: if(len > 0 && buffer[0] != 0xff) {
! 876: for(int i = 0; i < len; i++) {
! 877: if(buffer[i] == 0x0d || buffer[i] == 0x0a) {
! 878: str[ptr] = 0;
! 879: telnet_command("\033[2h"); // key lock
! 880: telnet_command("\033[12h"); // local echo off
! 881: return(!m_halted);
! 882: } else if(buffer[i] == 0x08) {
! 883: if(ptr > 0) {
! 884: telnet_command("\033[0K"); // erase from cursor position
! 885: ptr--;
! 886: } else {
! 887: telnet_command("\033[1C"); // move cursor forward
! 888: }
! 889: } else if(ptr < n - 1) {
! 890: if (buffer[i] >= 0x20 && buffer[i] <= 0x7e) {
! 891: str[ptr++] = buffer[i];
! 892: }
! 893: } else {
! 894: telnet_command("\033[1D\033[0K"); // move cursor backward and erase from cursor position
! 895: }
! 896: }
! 897: } else if(len == -1) {
! 898: if(WSAGetLastError() != WSAEWOULDBLOCK) {
! 899: return(false);
! 900: }
! 901: } else if(len == 0) {
! 902: return(false);
! 903: }
! 904: Sleep(10);
! 905: }
! 906: return(!m_halted);
! 907: }
! 908:
! 909: bool telnet_kbhit()
! 910: {
! 911: char buffer[1024];
! 912:
! 913: if(!m_halted) {
! 914: int len = recv(cli_socket, buffer, sizeof(buffer), 0);
! 915:
! 916: if(len > 0) {
! 917: for(int i = 0; i < len; i++) {
! 918: if(buffer[i] == 0x0d || buffer[i] == 0x0a) {
! 919: return(true);
! 920: }
! 921: }
! 922: } else if(len == 0) {
! 923: return(true); // disconnected
! 924: }
! 925: }
! 926: return(false);
! 927: }
! 928:
! 929: bool telnet_disconnected()
! 930: {
! 931: char buffer[1024];
! 932: int len = recv(cli_socket, buffer, sizeof(buffer), 0);
! 933:
! 934: if(len == 0) {
! 935: return(true);
! 936: } else if(len == -1) {
! 937: if(WSAGetLastError() != WSAEWOULDBLOCK) {
! 938: return(true);
! 939: }
! 940: }
! 941: return(false);
! 942: }
! 943:
! 944: void telnet_set_color(int color)
! 945: {
! 946: telnet_command("\033[%dm\033[3%dm", (color >> 3) & 1, (color & 7));
! 947: }
! 948:
! 949: int debugger_dasm(char *buffer, UINT32 cs, UINT32 eip)
! 950: {
! 951: // UINT8 *oprom = mem + (((cs << 4) + eip) & (MAX_MEM - 1));
! 952: UINT8 ops[16];
! 953: for(int i = 0; i < 16; i++) {
! 954: ops[i] = debugger_read_byte(((cs << 4) + (eip + i)) & ADDR_MASK);
! 955: }
! 956: UINT8 *oprom = ops;
! 957:
! 958: #if defined(HAS_I386)
! 959: if(m_operand_size) {
! 960: return(CPU_DISASSEMBLE_CALL(x86_32) & DASMFLAG_LENGTHMASK);
! 961: } else
! 962: #endif
! 963: return(CPU_DISASSEMBLE_CALL(x86_16) & DASMFLAG_LENGTHMASK);
! 964: }
! 965:
! 966: void debugger_regs_info(char *buffer)
! 967: {
! 968: #if defined(HAS_I386)
! 969: UINT32 flags = get_flags();
! 970: #else
! 971: UINT32 flags = CompressFlags();
! 972: #endif
! 973:
! 974: #if defined(HAS_I386)
! 975: if(m_operand_size) {
! 976: sprintf(buffer, "EAX=%08X EBX=%08X ECX=%08X EDX=%08X\nESP=%08X EBP=%08X ESI=%08X EDI=%08X\nEIP=%08X DS=%04X ES=%04X SS=%04X CS=%04X FLAG=[%c %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c]\n",
! 977: REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SP), REG16(BP), REG16(SI), REG16(DI), m_eip, SREG(DS), SREG(ES), SREG(SS), SREG(CS),
! 978: PROTECTED_MODE ? "PE" : "--",
! 979: (flags & 0x40000) ? 'A' : '-',
! 980: (flags & 0x20000) ? 'V' : '-',
! 981: (flags & 0x10000) ? 'R' : '-',
! 982: (flags & 0x04000) ? 'N' : '-',
! 983: (flags & 0x02000) ? '1' : '0',
! 984: (flags & 0x01000) ? '1' : '0',
! 985: (flags & 0x00800) ? 'O' : '-',
! 986: (flags & 0x00400) ? 'D' : '-',
! 987: (flags & 0x00200) ? 'I' : '-',
! 988: (flags & 0x00100) ? 'T' : '-',
! 989: (flags & 0x00080) ? 'S' : '-',
! 990: (flags & 0x00040) ? 'Z' : '-',
! 991: (flags & 0x00010) ? 'A' : '-',
! 992: (flags & 0x00004) ? 'P' : '-',
! 993: (flags & 0x00001) ? 'C' : '-');
! 994: } else {
! 995: #endif
! 996: sprintf(buffer, "AX=%04X BX=%04X CX=%04X DX=%04X SP=%04X BP=%04X SI=%04X DI=%04X\nIP=%04X DS=%04X ES=%04X SS=%04X CS=%04X FLAG=[%c %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c]\n",
! 997: REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SP), REG16(BP), REG16(SI), REG16(DI), m_eip, SREG(DS), SREG(ES), SREG(SS), SREG(CS),
! 998: #if defined(HAS_I386)
! 999: PROTECTED_MODE ? "PE" : "--",
! 1000: #else
! 1001: "--",
! 1002: #endif
! 1003: (flags & 0x40000) ? 'A' : '-',
! 1004: (flags & 0x20000) ? 'V' : '-',
! 1005: (flags & 0x10000) ? 'R' : '-',
! 1006: (flags & 0x04000) ? 'N' : '-',
! 1007: (flags & 0x02000) ? '1' : '0',
! 1008: (flags & 0x01000) ? '1' : '0',
! 1009: (flags & 0x00800) ? 'O' : '-',
! 1010: (flags & 0x00400) ? 'D' : '-',
! 1011: (flags & 0x00200) ? 'I' : '-',
! 1012: (flags & 0x00100) ? 'T' : '-',
! 1013: (flags & 0x00080) ? 'S' : '-',
! 1014: (flags & 0x00040) ? 'Z' : '-',
! 1015: (flags & 0x00010) ? 'A' : '-',
! 1016: (flags & 0x00004) ? 'P' : '-',
! 1017: (flags & 0x00001) ? 'C' : '-');
! 1018: #if defined(HAS_I386)
! 1019: }
! 1020: #endif
! 1021: }
! 1022:
! 1023: void debugger_process_info(char *buffer)
! 1024: {
! 1025: UINT16 psp_seg = current_psp;
! 1026: process_t *process;
! 1027: bool check[0x10000] = {0};
! 1028:
! 1029: buffer[0] = '\0';
! 1030:
! 1031: while(!check[psp_seg] && (process = msdos_process_info_get(psp_seg, false)) != NULL) {
! 1032: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
! 1033: char *file = process->module_path, *s;
! 1034: char tmp[8192];
! 1035:
! 1036: while((s = strstr(file, "\\")) != NULL) {
! 1037: file = s + 1;
! 1038: }
! 1039: sprintf(tmp, "PSP=%04X ENV=%04X RETURN=%04X:%04X PROGRAM=%s\n", psp_seg, psp->env_seg, psp->int_22h.w.h, psp->int_22h.w.l, my_strupr(file));
! 1040: strcat(tmp, buffer);
! 1041: strcpy(buffer, tmp);
! 1042:
! 1043: check[psp_seg] = true;
! 1044: psp_seg = psp->parent_psp;
! 1045: }
! 1046: }
! 1047:
! 1048: UINT32 debugger_get_val(const char *str)
! 1049: {
! 1050: char tmp[1024];
! 1051:
! 1052: if(str == NULL || strlen(str) == 0) {
! 1053: return(0);
! 1054: }
! 1055: strcpy(tmp, str);
! 1056:
! 1057: if(strlen(tmp) == 3 && tmp[0] == '\'' && tmp[2] == '\'') {
! 1058: // ank
! 1059: return(tmp[1] & 0xff);
! 1060: } else if(tmp[0] == '%') {
! 1061: // decimal
! 1062: return(strtoul(tmp + 1, NULL, 10));
! 1063: }
! 1064: return(strtoul(tmp, NULL, 16));
! 1065: }
! 1066:
! 1067: UINT32 debugger_get_seg(const char *str, UINT32 val)
! 1068: {
! 1069: char tmp[1024], *s;
! 1070:
! 1071: if(str == NULL || strlen(str) == 0) {
! 1072: return(val);
! 1073: }
! 1074: strcpy(tmp, str);
! 1075:
! 1076: if((s = strstr(tmp, ":")) != NULL) {
! 1077: // 0000:0000
! 1078: *s = '\0';
! 1079: return(debugger_get_val(tmp));
! 1080: }
! 1081: return(val);
! 1082: }
! 1083:
! 1084: UINT32 debugger_get_ofs(const char *str)
! 1085: {
! 1086: char tmp[1024], *s;
! 1087:
! 1088: if(str == NULL || strlen(str) == 0) {
! 1089: return(0);
! 1090: }
! 1091: strcpy(tmp, str);
! 1092:
! 1093: if((s = strstr(tmp, ":")) != NULL) {
! 1094: // 0000:0000
! 1095: return(debugger_get_val(s + 1));
! 1096: }
! 1097: return(debugger_get_val(tmp));
! 1098: }
! 1099:
! 1100: void debugger_main()
! 1101: {
! 1102: telnet_command("\033[20h"); // cr-lf
! 1103:
! 1104: force_suspend = true;
! 1105: now_going = false;
! 1106: now_debugging = true;
! 1107: Sleep(100);
! 1108:
! 1109: if(!m_halted && !now_suspended) {
! 1110: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
! 1111: telnet_printf("waiting until cpu is suspended...\n");
! 1112: }
! 1113: while(!m_halted && !now_suspended) {
! 1114: if(telnet_disconnected()) {
! 1115: break;
! 1116: }
! 1117: Sleep(10);
! 1118: }
! 1119:
! 1120: char buffer[8192];
! 1121:
! 1122: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
! 1123: debugger_process_info(buffer);
! 1124: telnet_printf("%s", buffer);
! 1125: debugger_regs_info(buffer);
! 1126: telnet_printf("%s", buffer);
! 1127: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
! 1128: telnet_printf("breaked at %04X:%04X\n", SREG(CS), m_eip);
! 1129: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
! 1130: debugger_dasm(buffer, SREG(CS), m_eip);
! 1131: telnet_printf("next\t%04X:%04X %s\n", SREG(CS), m_eip, buffer);
! 1132: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
! 1133:
! 1134: #define MAX_COMMAND_LEN 64
! 1135:
! 1136: char command[MAX_COMMAND_LEN + 1];
! 1137: char prev_command[MAX_COMMAND_LEN + 1] = {0};
! 1138:
! 1139: UINT32 data_seg = SREG(DS);
! 1140: UINT32 data_ofs = 0;
! 1141: UINT32 dasm_seg = SREG(CS);
! 1142: UINT32 dasm_ofs = m_eip;
! 1143:
! 1144: while(!m_halted) {
! 1145: telnet_printf("- ");
! 1146: command[0] = '\0';
! 1147:
! 1148: if(fi_debugger != NULL) {
! 1149: while(command[0] == '\0') {
! 1150: if(fgets(command, sizeof(command), fi_debugger) == NULL) {
! 1151: break;
! 1152: }
! 1153: while(strlen(command) > 0 && (command[strlen(command) - 1] == 0x0d || command[strlen(command) - 1] == 0x0a)) {
! 1154: command[strlen(command) - 1] = '\0';
! 1155: }
! 1156: }
! 1157: if(command[0] != '\0') {
! 1158: telnet_command("%s\n", command);
! 1159: }
! 1160: }
! 1161: if(command[0] == '\0') {
! 1162: if(!telnet_gets(command, sizeof(command))) {
! 1163: break;
! 1164: }
! 1165: }
! 1166: if(command[0] == '\0') {
! 1167: strcpy(command, prev_command);
! 1168: } else {
! 1169: strcpy(prev_command, command);
! 1170: }
! 1171: if(fp_debugger != NULL) {
! 1172: fprintf(fp_debugger, "%s\n", command);
! 1173: }
! 1174:
! 1175: if(!m_halted && command[0] != 0) {
! 1176: char *params[32], *token = NULL;
! 1177: int num = 0;
! 1178:
! 1179: if((token = strtok(command, " ")) != NULL) {
! 1180: params[num++] = token;
! 1181: while(num < 32 && (token = strtok(NULL, " ")) != NULL) {
! 1182: params[num++] = token;
! 1183: }
! 1184: }
! 1185: if(stricmp(params[0], "D") == 0) {
! 1186: if(num <= 3) {
! 1187: if(num >= 2) {
! 1188: data_seg = debugger_get_seg(params[1], data_seg);
! 1189: data_ofs = debugger_get_ofs(params[1]);
! 1190: }
! 1191: UINT32 end_seg = data_seg;
! 1192: UINT32 end_ofs = data_ofs + 8 * 16 - 1;
! 1193: if(num == 3) {
! 1194: end_seg = debugger_get_seg(params[2], data_seg);
! 1195: end_ofs = debugger_get_ofs(params[2]);
! 1196: }
! 1197: UINT64 start_addr = (data_seg << 4) + data_ofs;
! 1198: UINT64 end_addr = (end_seg << 4) + end_ofs;
! 1199: // bool sjis = false;
! 1200:
! 1201: for(UINT64 addr = (start_addr & ~0x0f); addr <= (end_addr | 0x0f); addr++) {
! 1202: if((addr & 0x0f) == 0) {
! 1203: if((data_ofs = addr - (data_seg << 4)) > 0xffff) {
! 1204: data_seg += 0x1000;
! 1205: data_ofs -= 0x10000;
! 1206: }
! 1207: telnet_printf("%06X:%04X ", data_seg, data_ofs);
! 1208: memset(buffer, 0, sizeof(buffer));
! 1209: }
! 1210: if(addr < start_addr || addr > end_addr) {
! 1211: telnet_printf(" ");
! 1212: buffer[addr & 0x0f] = ' ';
! 1213: } else {
! 1214: UINT8 data = debugger_read_byte(addr & ADDR_MASK);
! 1215: telnet_printf(" %02X", data);
! 1216: // if(sjis) {
! 1217: // buffer[addr & 0x0f] = data;
! 1218: // sjis = false;
! 1219: // } else if(((data >= 0x81 && data <= 0x9f) || (data >= 0xe0 && data <= 0xef)) && (addr & 0x0f) < 0x0f) {
! 1220: // buffer[addr & 0x0f] = data;
! 1221: // sjis = true;
! 1222: // } else
! 1223: if((data >= 0x20 && data <= 0x7e)/* || (data >= 0xa1 && data <= 0xdf)*/) {
! 1224: buffer[addr & 0x0f] = data;
! 1225: } else {
! 1226: buffer[addr & 0x0f] = '.';
! 1227: }
! 1228: }
! 1229: if((addr & 0x0f) == 0x0f) {
! 1230: telnet_printf(" %s\n", buffer);
! 1231: }
! 1232: }
! 1233: if((data_ofs = (end_addr + 1) - (data_seg << 4)) > 0xffff) {
! 1234: data_seg += 0x1000;
! 1235: data_ofs -= 0x10000;
! 1236: }
! 1237: prev_command[1] = '\0'; // remove parameters to dump continuously
! 1238: } else {
! 1239: telnet_printf("invalid parameter number\n");
! 1240: }
! 1241: } else if(stricmp(params[0], "E") == 0 || stricmp(params[0], "EB") == 0) {
! 1242: if(num >= 3) {
! 1243: UINT32 seg = debugger_get_seg(params[1], data_seg);
! 1244: UINT32 ofs = debugger_get_ofs(params[1]);
! 1245: for(int i = 2, j = 0; i < num; i++, j++) {
! 1246: debugger_write_byte(((seg << 4) + (ofs + j)) & ADDR_MASK, debugger_get_val(params[i]) & 0xff);
! 1247: }
! 1248: } else {
! 1249: telnet_printf("invalid parameter number\n");
! 1250: }
! 1251: } else if(stricmp(params[0], "EW") == 0) {
! 1252: if(num >= 3) {
! 1253: UINT32 seg = debugger_get_seg(params[1], data_seg);
! 1254: UINT32 ofs = debugger_get_ofs(params[1]);
! 1255: for(int i = 2, j = 0; i < num; i++, j += 2) {
! 1256: debugger_write_word(((seg << 4) + (ofs + j)) & ADDR_MASK, debugger_get_val(params[i]) & 0xffff);
! 1257: }
! 1258: } else {
! 1259: telnet_printf("invalid parameter number\n");
! 1260: }
! 1261: } else if(stricmp(params[0], "ED") == 0) {
! 1262: if(num >= 3) {
! 1263: UINT32 seg = debugger_get_seg(params[1], data_seg);
! 1264: UINT32 ofs = debugger_get_ofs(params[1]);
! 1265: for(int i = 2, j = 0; i < num; i++, j += 4) {
! 1266: debugger_write_dword(((seg << 4) + (ofs + j)) & ADDR_MASK, debugger_get_val(params[i]));
! 1267: }
! 1268: } else {
! 1269: telnet_printf("invalid parameter number\n");
! 1270: }
! 1271: } else if(stricmp(params[0], "EA") == 0) {
! 1272: if(num >= 3) {
! 1273: UINT32 seg = debugger_get_seg(params[1], data_seg);
! 1274: UINT32 ofs = debugger_get_ofs(params[1]);
! 1275: strcpy(buffer, prev_command);
! 1276: if((token = strtok(buffer, "\"")) != NULL && (token = strtok(NULL, "\"")) != NULL) {
! 1277: int len = strlen(token);
! 1278: for(int i = 0; i < len; i++) {
! 1279: debugger_write_byte(((seg << 4) + (ofs + i)) & ADDR_MASK, token[i] & 0xff);
! 1280: }
! 1281: } else {
! 1282: telnet_printf("invalid parameter\n");
! 1283: }
! 1284: } else {
! 1285: telnet_printf("invalid parameter number\n");
! 1286: }
! 1287: } else if(stricmp(params[0], "I") == 0 || stricmp(params[0], "IB") == 0) {
! 1288: if(num == 2) {
! 1289: telnet_printf("%02X\n", debugger_read_io_byte(debugger_get_val(params[1])) & 0xff);
! 1290: } else {
! 1291: telnet_printf("invalid parameter number\n");
! 1292: }
! 1293: } else if(stricmp(params[0], "IW") == 0) {
! 1294: if(num == 2) {
! 1295: telnet_printf("%04X\n", debugger_read_io_word(debugger_get_val(params[1])) & 0xffff);
! 1296: } else {
! 1297: telnet_printf("invalid parameter number\n");
! 1298: }
! 1299: } else if(stricmp(params[0], "ID") == 0) {
! 1300: if(num == 2) {
! 1301: telnet_printf("%08X\n", debugger_read_io_dword(debugger_get_val(params[1])));
! 1302: } else {
! 1303: telnet_printf("invalid parameter number\n");
! 1304: }
! 1305: } else if(stricmp(params[0], "O") == 0 || stricmp(params[0], "OB") == 0) {
! 1306: if(num == 3) {
! 1307: debugger_write_io_byte(debugger_get_val(params[1]), debugger_get_val(params[2]) & 0xff);
! 1308: } else {
! 1309: telnet_printf("invalid parameter number\n");
! 1310: }
! 1311: } else if(stricmp(params[0], "OW") == 0) {
! 1312: if(num == 3) {
! 1313: debugger_write_io_word(debugger_get_val(params[1]), debugger_get_val(params[2]) & 0xffff);
! 1314: } else {
! 1315: telnet_printf("invalid parameter number\n");
! 1316: }
! 1317: } else if(stricmp(params[0], "OD") == 0) {
! 1318: if(num == 3) {
! 1319: debugger_write_io_dword(debugger_get_val(params[1]), debugger_get_val(params[2]));
! 1320: } else {
! 1321: telnet_printf("invalid parameter number\n");
! 1322: }
! 1323: } else if(stricmp(params[0], "R") == 0) {
! 1324: if(num == 1) {
! 1325: debugger_regs_info(buffer);
! 1326: telnet_printf("%s", buffer);
! 1327: } else if(num == 3) {
! 1328: #if defined(HAS_I386)
! 1329: if(stricmp(params[1], "EAX") == 0) {
! 1330: REG32(EAX) = debugger_get_val(params[2]);
! 1331: } else if(stricmp(params[1], "EBX") == 0) {
! 1332: REG32(EBX) = debugger_get_val(params[2]);
! 1333: } else if(stricmp(params[1], "ECX") == 0) {
! 1334: REG32(ECX) = debugger_get_val(params[2]);
! 1335: } else if(stricmp(params[1], "EDX") == 0) {
! 1336: REG32(EDX) = debugger_get_val(params[2]);
! 1337: } else if(stricmp(params[1], "ESP") == 0) {
! 1338: REG32(ESP) = debugger_get_val(params[2]);
! 1339: } else if(stricmp(params[1], "EBP") == 0) {
! 1340: REG32(EBP) = debugger_get_val(params[2]);
! 1341: } else if(stricmp(params[1], "ESI") == 0) {
! 1342: REG32(ESI) = debugger_get_val(params[2]);
! 1343: } else if(stricmp(params[1], "EDI") == 0) {
! 1344: REG32(EDI) = debugger_get_val(params[2]);
! 1345: } else
! 1346: #endif
! 1347: if(stricmp(params[1], "AX") == 0) {
! 1348: REG16(AX) = debugger_get_val(params[2]);
! 1349: } else if(stricmp(params[1], "BX") == 0) {
! 1350: REG16(BX) = debugger_get_val(params[2]);
! 1351: } else if(stricmp(params[1], "CX") == 0) {
! 1352: REG16(CX) = debugger_get_val(params[2]);
! 1353: } else if(stricmp(params[1], "DX") == 0) {
! 1354: REG16(DX) = debugger_get_val(params[2]);
! 1355: } else if(stricmp(params[1], "SP") == 0) {
! 1356: REG16(SP) = debugger_get_val(params[2]);
! 1357: } else if(stricmp(params[1], "BP") == 0) {
! 1358: REG16(BP) = debugger_get_val(params[2]);
! 1359: } else if(stricmp(params[1], "SI") == 0) {
! 1360: REG16(SI) = debugger_get_val(params[2]);
! 1361: } else if(stricmp(params[1], "DI") == 0) {
! 1362: REG16(DI) = debugger_get_val(params[2]);
! 1363: } else if(stricmp(params[1], "IP") == 0 || stricmp(params[1], "EIP") == 0) {
! 1364: #if defined(HAS_I386)
! 1365: if(m_operand_size) {
! 1366: m_eip = debugger_get_val(params[2]);
! 1367: } else {
! 1368: m_eip = debugger_get_val(params[2]) & 0xffff;
! 1369: }
! 1370: CHANGE_PC(m_eip);
! 1371: #else
! 1372: m_pc = (SREG_BASE(CS) + (debugger_get_val(params[2]) & 0xffff)) & ADDR_MASK;
! 1373: CHANGE_PC(m_pc);
! 1374: #endif
! 1375: } else if(stricmp(params[1], "AL") == 0) {
! 1376: REG8(AL) = debugger_get_val(params[2]);
! 1377: } else if(stricmp(params[1], "AH") == 0) {
! 1378: REG8(AH) = debugger_get_val(params[2]);
! 1379: } else if(stricmp(params[1], "BL") == 0) {
! 1380: REG8(BL) = debugger_get_val(params[2]);
! 1381: } else if(stricmp(params[1], "BH") == 0) {
! 1382: REG8(BH) = debugger_get_val(params[2]);
! 1383: } else if(stricmp(params[1], "CL") == 0) {
! 1384: REG8(CL) = debugger_get_val(params[2]);
! 1385: } else if(stricmp(params[1], "CH") == 0) {
! 1386: REG8(CH) = debugger_get_val(params[2]);
! 1387: } else if(stricmp(params[1], "DL") == 0) {
! 1388: REG8(DL) = debugger_get_val(params[2]);
! 1389: } else if(stricmp(params[1], "DH") == 0) {
! 1390: REG8(DH) = debugger_get_val(params[2]);
! 1391: } else {
! 1392: telnet_printf("unknown register %s\n", params[1]);
! 1393: }
! 1394: } else {
! 1395: telnet_printf("invalid parameter number\n");
! 1396: }
! 1397: } else if(_tcsicmp(params[0], "S") == 0) {
! 1398: if(num >= 4) {
! 1399: UINT32 cur_seg = debugger_get_seg(params[1], data_seg);
! 1400: UINT32 cur_ofs = debugger_get_ofs(params[1]);
! 1401: UINT32 end_seg = debugger_get_seg(params[2], cur_seg);
! 1402: UINT32 end_ofs = debugger_get_ofs(params[2]);
! 1403: UINT8 list[32];
! 1404:
! 1405: for(int i = 3, j = 0; i < num && j < 32; i++, j++) {
! 1406: list[j] = debugger_get_val(params[i]);
! 1407: }
! 1408: while((cur_seg << 4) + cur_ofs <= (end_seg << 4) + end_ofs) {
! 1409: bool found = true;
! 1410: for(int i = 3, j = 0; i < num && j < 32; i++, j++) {
! 1411: if(debugger_read_byte(((cur_seg << 4) + (cur_ofs + j)) & ADDR_MASK) != list[j]) {
! 1412: found = false;
! 1413: break;
! 1414: }
! 1415: }
! 1416: if(found) {
! 1417: telnet_printf("%04X:%04X\n", cur_seg, cur_ofs);
! 1418: }
! 1419: if((cur_ofs += 1) > 0xffff) {
! 1420: cur_seg += 0x1000;
! 1421: cur_ofs -= 0x10000;
! 1422: }
! 1423: }
! 1424: } else {
! 1425: telnet_printf("invalid parameter number\n");
! 1426: }
! 1427: } else if(stricmp(params[0], "U") == 0) {
! 1428: if(num <= 3) {
! 1429: if(num >= 2) {
! 1430: dasm_seg = debugger_get_seg(params[1], dasm_seg);
! 1431: dasm_ofs = debugger_get_ofs(params[1]);
! 1432: }
! 1433: if(num == 3) {
! 1434: UINT32 end_seg = debugger_get_seg(params[2], dasm_seg);
! 1435: UINT32 end_ofs = debugger_get_ofs(params[2]);
! 1436:
! 1437: while((dasm_seg << 4) + dasm_ofs <= (end_seg << 4) + end_ofs) {
! 1438: int len = debugger_dasm(buffer, dasm_seg, dasm_ofs);
! 1439: telnet_printf("%04X:%04X ", dasm_seg, dasm_ofs);
! 1440: for(int i = 0; i < len; i++) {
! 1441: telnet_printf("%02X", debugger_read_byte(((dasm_seg << 4) + (dasm_ofs + i)) & ADDR_MASK));
! 1442: }
! 1443: for(int i = len; i < 8; i++) {
! 1444: telnet_printf(" ");
! 1445: }
! 1446: telnet_printf(" %s\n", buffer);
! 1447: if((dasm_ofs += len) > 0xffff) {
! 1448: dasm_seg += 0x1000;
! 1449: dasm_ofs -= 0x10000;
! 1450: }
! 1451: }
! 1452: } else {
! 1453: for(int i = 0; i < 16; i++) {
! 1454: int len = debugger_dasm(buffer, dasm_seg, dasm_ofs);
! 1455: telnet_printf("%04X:%04X ", dasm_seg, dasm_ofs);
! 1456: for(int i = 0; i < len; i++) {
! 1457: telnet_printf("%02X", debugger_read_byte(((dasm_seg << 4) + (dasm_ofs + i)) & ADDR_MASK));
! 1458: }
! 1459: for(int i = len; i < 8; i++) {
! 1460: telnet_printf(" ");
! 1461: }
! 1462: telnet_printf(" %s\n", buffer);
! 1463: if((dasm_ofs += len) > 0xffff) {
! 1464: dasm_seg += 0x1000;
! 1465: dasm_ofs -= 0x10000;
! 1466: }
! 1467: }
! 1468: }
! 1469: prev_command[1] = '\0'; // remove parameters to disassemble continuously
! 1470: } else {
! 1471: telnet_printf("invalid parameter number\n");
! 1472: }
! 1473: } else if(stricmp(params[0], "H") == 0) {
! 1474: if(num == 3) {
! 1475: UINT32 l = debugger_get_val(params[1]);
! 1476: UINT32 r = debugger_get_val(params[2]);
! 1477: telnet_printf("%08X %08X\n", l + r, l - r);
! 1478: } else {
! 1479: telnet_printf("invalid parameter number\n");
! 1480: }
! 1481: } else if(stricmp(params[0], "BP") == 0 || stricmp(params[0], "RBP") == 0 || stricmp(params[0], "WBP") == 0) {
! 1482: break_point_t *break_point_ptr;
! 1483: #define GET_BREAK_POINT_PTR() { \
! 1484: if(params[0][0] == 'R') { \
! 1485: break_point_ptr = &rd_break_point; \
! 1486: } else if(params[0][0] == 'W') { \
! 1487: break_point_ptr = &wr_break_point; \
! 1488: } else if(params[0][0] == 'I') { \
! 1489: break_point_ptr = &in_break_point; \
! 1490: } else if(params[0][0] == 'O') { \
! 1491: break_point_ptr = &out_break_point; \
! 1492: } else { \
! 1493: break_point_ptr = &break_point; \
! 1494: } \
! 1495: }
! 1496: GET_BREAK_POINT_PTR();
! 1497: if(num == 2) {
! 1498: UINT32 seg = debugger_get_seg(params[1], SREG(CS));
! 1499: UINT32 ofs = debugger_get_ofs(params[1]);
! 1500: bool found = false;
! 1501: for(int i = 0; i < MAX_BREAK_POINTS && !found; i++) {
! 1502: if(break_point_ptr->table[i].status == 0 || break_point_ptr->table[i].addr == ((seg << 4) + ofs)) {
! 1503: break_point_ptr->table[i].addr = (seg << 4) + ofs;
! 1504: break_point_ptr->table[i].seg = seg;
! 1505: break_point_ptr->table[i].ofs = ofs;
! 1506: break_point_ptr->table[i].status = 1;
! 1507: found = true;
! 1508: }
! 1509: }
! 1510: if(!found) {
! 1511: telnet_printf("too many break points\n");
! 1512: }
! 1513: } else {
! 1514: telnet_printf("invalid parameter number\n");
! 1515: }
! 1516: } else if(stricmp(params[0], "IBP") == 0 || stricmp(params[0], "OBP") == 0) {
! 1517: break_point_t *break_point_ptr;
! 1518: GET_BREAK_POINT_PTR();
! 1519: if(num == 2) {
! 1520: UINT32 addr = debugger_get_val(params[1]);
! 1521: bool found = false;
! 1522: for(int i = 0; i < MAX_BREAK_POINTS && !found; i++) {
! 1523: if(break_point_ptr->table[i].status == 0 || break_point_ptr->table[i].addr == addr) {
! 1524: break_point_ptr->table[i].addr = addr;
! 1525: break_point_ptr->table[i].status = 1;
! 1526: found = true;
! 1527: }
! 1528: }
! 1529: if(!found) {
! 1530: telnet_printf("too many break points\n");
! 1531: }
! 1532: } else {
! 1533: telnet_printf("invalid parameter number\n");
! 1534: }
! 1535: } else if(stricmp(params[0], "BC") == 0 || stricmp(params[0], "RBC") == 0 || stricmp(params[0], "WBC") == 0 || stricmp(params[0], "IBC") == 0 || stricmp(params[0], "OBC") == 0) {
! 1536: break_point_t *break_point_ptr;
! 1537: GET_BREAK_POINT_PTR();
! 1538: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) {
! 1539: memset(break_point_ptr, 0, sizeof(break_point_t));
! 1540: } else if(num >= 2) {
! 1541: for(int i = 1; i < num; i++) {
! 1542: int index = debugger_get_val(params[i]);
! 1543: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
! 1544: telnet_printf("invalid index %x\n", index);
! 1545: } else {
! 1546: break_point_ptr->table[index - 1].addr = 0;
! 1547: break_point_ptr->table[index - 1].seg = 0;
! 1548: break_point_ptr->table[index - 1].ofs = 0;
! 1549: break_point_ptr->table[index - 1].status = 0;
! 1550: }
! 1551: }
! 1552: } else {
! 1553: telnet_printf("invalid parameter number\n");
! 1554: }
! 1555: } else if(stricmp(params[0], "BD") == 0 || stricmp(params[0], "RBD") == 0 || stricmp(params[0], "WBD") == 0 || stricmp(params[0], "IBD") == 0 || stricmp(params[0], "OBD") == 0 ||
! 1556: stricmp(params[0], "BE") == 0 || stricmp(params[0], "RBE") == 0 || stricmp(params[0], "WBE") == 0 || stricmp(params[0], "IBE") == 0 || stricmp(params[0], "OBE") == 0) {
! 1557: break_point_t *break_point_ptr;
! 1558: GET_BREAK_POINT_PTR();
! 1559: bool enabled = (params[0][strlen(params[0]) - 1] == 'E' || params[0][strlen(params[0]) - 1] == 'e');
! 1560: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) {
! 1561: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
! 1562: if(break_point_ptr->table[i].status != 0) {
! 1563: break_point_ptr->table[i].status = enabled ? 1 : -1;
! 1564: }
! 1565: }
! 1566: } else if(num >= 2) {
! 1567: for(int i = 1; i < num; i++) {
! 1568: int index = debugger_get_val(params[i]);
! 1569: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
! 1570: telnet_printf("invalid index %x\n", index);
! 1571: } else if(break_point_ptr->table[index - 1].status == 0) {
! 1572: telnet_printf("break point %x is null\n", index);
! 1573: } else {
! 1574: break_point_ptr->table[index - 1].status = enabled ? 1 : -1;
! 1575: }
! 1576: }
! 1577: } else {
! 1578: telnet_printf("invalid parameter number\n");
! 1579: }
! 1580: } else if(stricmp(params[0], "BL") == 0 || stricmp(params[0], "RBL") == 0 || stricmp(params[0], "WBL") == 0) {
! 1581: break_point_t *break_point_ptr;
! 1582: GET_BREAK_POINT_PTR();
! 1583: if(num == 1) {
! 1584: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
! 1585: if(break_point_ptr->table[i].status) {
! 1586: telnet_printf("%d %c %04X:%04X\n", i + 1, break_point_ptr->table[i].status == 1 ? 'e' : 'd', break_point_ptr->table[i].seg, break_point_ptr->table[i].ofs);
! 1587: }
! 1588: }
! 1589: } else {
! 1590: telnet_printf("invalid parameter number\n");
! 1591: }
! 1592: } else if(stricmp(params[0], "IBL") == 0 || stricmp(params[0], "OBL") == 0) {
! 1593: break_point_t *break_point_ptr;
! 1594: GET_BREAK_POINT_PTR();
! 1595: if(num == 1) {
! 1596: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
! 1597: if(break_point_ptr->table[i].status) {
! 1598: telnet_printf("%d %c %04X\n", i + 1, break_point_ptr->table[i].status == 1 ? 'e' : 'd', break_point_ptr->table[i].addr);
! 1599: }
! 1600: }
! 1601: } else {
! 1602: telnet_printf("invalid parameter number\n");
! 1603: }
! 1604: } else if(stricmp(params[0], "INTBP") == 0) {
! 1605: if(num >= 2 && num <= 4) {
! 1606: int int_num = debugger_get_val(params[1]);
! 1607: UINT8 ah = 0, ah_registered = 0;
! 1608: UINT8 al = 0, al_registered = 0;
! 1609: if(num >= 3) {
! 1610: ah = debugger_get_val(params[2]);
! 1611: ah_registered = 1;
! 1612: }
! 1613: if(num == 4) {
! 1614: al = debugger_get_val(params[3]);
! 1615: al_registered = 1;
! 1616: }
! 1617: bool found = false;
! 1618: for(int i = 0; i < MAX_BREAK_POINTS && !found; i++) {
! 1619: if(int_break_point.table[i].status == 0 || (
! 1620: int_break_point.table[i].int_num == int_num &&
! 1621: int_break_point.table[i].ah == ah && int_break_point.table[i].ah_registered == ah_registered &&
! 1622: int_break_point.table[i].al == al && int_break_point.table[i].al_registered == al_registered)) {
! 1623: int_break_point.table[i].int_num = int_num;
! 1624: int_break_point.table[i].ah = ah;
! 1625: int_break_point.table[i].ah_registered = ah_registered;
! 1626: int_break_point.table[i].al = al;
! 1627: int_break_point.table[i].al_registered = al_registered;
! 1628: int_break_point.table[i].status = 1;
! 1629: found = true;
! 1630: }
! 1631: }
! 1632: if(!found) {
! 1633: telnet_printf("too many break points\n");
! 1634: }
! 1635: } else {
! 1636: telnet_printf("invalid parameter number\n");
! 1637: }
! 1638: } else if(stricmp(params[0], "INTBC") == 0) {
! 1639: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) {
! 1640: memset(&int_break_point, 0, sizeof(int_break_point_t));
! 1641: } else if(num >= 2) {
! 1642: for(int i = 1; i < num; i++) {
! 1643: int index = debugger_get_val(params[i]);
! 1644: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
! 1645: telnet_printf("invalid index %x\n", index);
! 1646: } else {
! 1647: int_break_point.table[index - 1].int_num = 0;
! 1648: int_break_point.table[index - 1].ah = 0;
! 1649: int_break_point.table[index - 1].ah_registered = 0;
! 1650: int_break_point.table[index - 1].al = 0;
! 1651: int_break_point.table[index - 1].al_registered = 0;
! 1652: int_break_point.table[index - 1].status = 0;
! 1653: }
! 1654: }
! 1655: } else {
! 1656: telnet_printf("invalid parameter number\n");
! 1657: }
! 1658: } else if(stricmp(params[0], "INTBD") == 0 || stricmp(params[0], "INTBE") == 0) {
! 1659: bool enabled = (params[0][strlen(params[0]) - 1] == 'E' || params[0][strlen(params[0]) - 1] == 'e');
! 1660: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) {
! 1661: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
! 1662: if(int_break_point.table[i].status != 0) {
! 1663: int_break_point.table[i].status = enabled ? 1 : -1;
! 1664: }
! 1665: }
! 1666: } else if(num >= 2) {
! 1667: for(int i = 1; i < num; i++) {
! 1668: int index = debugger_get_val(params[i]);
! 1669: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
! 1670: telnet_printf("invalid index %x\n", index);
! 1671: } else if(int_break_point.table[index - 1].status == 0) {
! 1672: telnet_printf("break point %x is null\n", index);
! 1673: } else {
! 1674: int_break_point.table[index - 1].status = enabled ? 1 : -1;
! 1675: }
! 1676: }
! 1677: } else {
! 1678: telnet_printf("invalid parameter number\n");
! 1679: }
! 1680: } else if(stricmp(params[0], "INTBL") == 0) {
! 1681: if(num == 1) {
! 1682: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
! 1683: if(int_break_point.table[i].status) {
! 1684: telnet_printf("%d %c %02X", i + 1, int_break_point.table[i].status == 1 ? 'e' : 'd', int_break_point.table[i].int_num);
! 1685: if(int_break_point.table[i].ah_registered) {
! 1686: telnet_printf(" %02X", int_break_point.table[i].ah);
! 1687: }
! 1688: if(int_break_point.table[i].al_registered) {
! 1689: telnet_printf(" %02X", int_break_point.table[i].al);
! 1690: }
! 1691: telnet_printf("\n");
! 1692: }
! 1693: }
! 1694: } else {
! 1695: telnet_printf("invalid parameter number\n");
! 1696: }
! 1697: } else if(stricmp(params[0], "G") == 0 || stricmp(params[0], "P") == 0) {
! 1698: if(num == 1 || num == 2) {
! 1699: break_point_t break_point_stored;
! 1700: bool break_points_stored = false;
! 1701:
! 1702: if(stricmp(params[0], "P") == 0) {
! 1703: memcpy(&break_point_stored, &break_point, sizeof(break_point_t));
! 1704: memset(&break_point, 0, sizeof(break_point_t));
! 1705: break_points_stored = true;
! 1706:
! 1707: break_point.table[0].addr = (SREG(CS) << 4) + m_eip + debugger_dasm(buffer, SREG(CS), m_eip);
! 1708: break_point.table[0].status = 1;
! 1709: } else if(num >= 2) {
! 1710: memcpy(&break_point_stored, &break_point, sizeof(break_point_t));
! 1711: memset(&break_point, 0, sizeof(break_point_t));
! 1712: break_points_stored = true;
! 1713:
! 1714: UINT32 seg = debugger_get_seg(params[1], SREG(CS));
! 1715: UINT32 ofs = debugger_get_ofs(params[1]);
! 1716: break_point.table[0].addr = (seg << 4) + ofs;
! 1717: break_point.table[0].seg = seg;
! 1718: break_point.table[0].ofs = ofs;
! 1719: break_point.table[0].status = 1;
! 1720: }
! 1721: break_point.hit = rd_break_point.hit = wr_break_point.hit = in_break_point.hit = out_break_point.hit = int_break_point.hit = 0;
! 1722: now_going = true;
! 1723: now_suspended = false;
! 1724:
! 1725: telnet_command("\033[2l"); // key unlock
! 1726: while(!m_halted && !now_suspended) {
! 1727: if(telnet_kbhit()) {
! 1728: break;
! 1729: }
! 1730: Sleep(10);
! 1731: }
! 1732: now_going = false;
! 1733: telnet_command("\033[2h"); // key lock
! 1734:
! 1735: if(!(break_point.hit || rd_break_point.hit || wr_break_point.hit || in_break_point.hit || out_break_point.hit || int_break_point.hit)) {
! 1736: Sleep(100);
! 1737: if(!m_halted && !now_suspended) {
! 1738: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
! 1739: telnet_printf("waiting until cpu is suspended...\n");
! 1740: }
! 1741: }
! 1742: while(!m_halted && !now_suspended) {
! 1743: if(telnet_disconnected()) {
! 1744: break;
! 1745: }
! 1746: Sleep(10);
! 1747: }
! 1748: dasm_seg = SREG(CS);
! 1749: dasm_ofs = m_eip;
! 1750:
! 1751: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
! 1752: debugger_dasm(buffer, m_prev_cs, m_prev_eip);
! 1753: telnet_printf("done\t%04X:%04X %s\n", m_prev_cs, m_prev_eip, buffer);
! 1754:
! 1755: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
! 1756: debugger_regs_info(buffer);
! 1757: telnet_printf("%s", buffer);
! 1758:
! 1759: if(break_point.hit) {
! 1760: if(stricmp(params[0], "G") == 0 && num == 1) {
! 1761: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
! 1762: telnet_printf("breaked at %04X:%04X: break point is hit\n", SREG(CS), m_eip);
! 1763: }
! 1764: } else if(rd_break_point.hit) {
! 1765: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
! 1766: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was read at %04X:%04X\n", SREG(CS), m_eip,
! 1767: rd_break_point.table[rd_break_point.hit - 1].seg, rd_break_point.table[rd_break_point.hit - 1].ofs,
! 1768: m_prev_cs, m_prev_eip);
! 1769: } else if(wr_break_point.hit) {
! 1770: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
! 1771: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was written at %04X:%04X\n", SREG(CS), m_eip,
! 1772: wr_break_point.table[wr_break_point.hit - 1].seg, wr_break_point.table[wr_break_point.hit - 1].ofs,
! 1773: m_prev_cs, m_prev_eip);
! 1774: } else if(in_break_point.hit) {
! 1775: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
! 1776: telnet_printf("breaked at %04X:%04X: port %04X was read at %04X:%04X\n", SREG(CS), m_eip,
! 1777: in_break_point.table[in_break_point.hit - 1].addr,
! 1778: m_prev_cs, m_prev_eip);
! 1779: } else if(out_break_point.hit) {
! 1780: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
! 1781: telnet_printf("breaked at %04X:%04X: port %04X was written at %04X:%04X\n", SREG(CS), m_eip,
! 1782: out_break_point.table[out_break_point.hit - 1].addr,
! 1783: m_prev_cs, m_prev_eip);
! 1784: } else if(int_break_point.hit) {
! 1785: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
! 1786: telnet_printf("breaked at %04X:%04X: INT %02x", SREG(CS), m_eip, int_break_point.table[int_break_point.hit - 1].int_num);
! 1787: if(int_break_point.table[int_break_point.hit - 1].ah_registered) {
! 1788: telnet_printf(" AH=%02x", int_break_point.table[int_break_point.hit - 1].ah);
! 1789: }
! 1790: if(int_break_point.table[int_break_point.hit - 1].al_registered) {
! 1791: telnet_printf(" AL=%02x", int_break_point.table[int_break_point.hit - 1].al);
! 1792: }
! 1793: telnet_printf(" is raised at %04X:%04X\n", m_prev_cs, m_prev_eip);
! 1794: } else {
! 1795: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
! 1796: telnet_printf("breaked at %04X:%04X: enter key was pressed\n", SREG(CS), m_eip);
! 1797: }
! 1798: if(break_points_stored) {
! 1799: memcpy(&break_point, &break_point_stored, sizeof(break_point_t));
! 1800: }
! 1801: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
! 1802: debugger_dasm(buffer, SREG(CS), m_eip);
! 1803: telnet_printf("next\t%04X:%04X %s\n", SREG(CS), m_eip, buffer);
! 1804: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
! 1805: } else {
! 1806: telnet_printf("invalid parameter number\n");
! 1807: }
! 1808: } else if(stricmp(params[0], "T") == 0) {
! 1809: if(num == 1 || num == 2) {
! 1810: int steps = 1;
! 1811: if(num >= 2) {
! 1812: steps = debugger_get_val(params[1]);
! 1813: }
! 1814:
! 1815: telnet_command("\033[2l"); // key unlock
! 1816: while(steps-- > 0) {
! 1817: break_point.hit = rd_break_point.hit = wr_break_point.hit = in_break_point.hit = out_break_point.hit = int_break_point.hit = 0;
! 1818: now_going = false;
! 1819: now_suspended = false;
! 1820:
! 1821: while(!m_halted && !now_suspended) {
! 1822: if(telnet_disconnected()) {
! 1823: break;
! 1824: }
! 1825: Sleep(10);
! 1826: }
! 1827: dasm_seg = SREG(CS);
! 1828: dasm_ofs = m_eip;
! 1829:
! 1830: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
! 1831: debugger_dasm(buffer, m_prev_cs, m_prev_eip);
! 1832: telnet_printf("done\t%04X:%04X %s\n", m_prev_cs, m_prev_eip, buffer);
! 1833:
! 1834: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
! 1835: debugger_regs_info(buffer);
! 1836: telnet_printf("%s", buffer);
! 1837:
! 1838: if(break_point.hit || rd_break_point.hit || wr_break_point.hit || in_break_point.hit || out_break_point.hit || int_break_point.hit || telnet_kbhit()) {
! 1839: break;
! 1840: }
! 1841: }
! 1842: telnet_command("\033[2h"); // key lock
! 1843:
! 1844: if(!(break_point.hit || rd_break_point.hit || wr_break_point.hit || in_break_point.hit || out_break_point.hit || int_break_point.hit)) {
! 1845: Sleep(100);
! 1846: if(!m_halted && !now_suspended) {
! 1847: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
! 1848: telnet_printf("waiting until cpu is suspended...\n");
! 1849: }
! 1850: }
! 1851: while(!m_halted && !now_suspended) {
! 1852: if(telnet_disconnected()) {
! 1853: break;
! 1854: }
! 1855: Sleep(10);
! 1856: }
! 1857: if(break_point.hit) {
! 1858: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
! 1859: telnet_printf("breaked at %04X:%04X: break point is hit\n", SREG(CS), m_eip);
! 1860: } else if(rd_break_point.hit) {
! 1861: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
! 1862: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was read at %04X:%04X\n", SREG(CS), m_eip,
! 1863: rd_break_point.table[rd_break_point.hit - 1].seg, rd_break_point.table[rd_break_point.hit - 1].ofs,
! 1864: m_prev_cs, m_prev_eip);
! 1865: } else if(wr_break_point.hit) {
! 1866: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
! 1867: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was written at %04X:%04X\n", SREG(CS), m_eip,
! 1868: wr_break_point.table[wr_break_point.hit - 1].seg, wr_break_point.table[wr_break_point.hit - 1].ofs,
! 1869: m_prev_cs, m_prev_eip);
! 1870: } else if(in_break_point.hit) {
! 1871: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
! 1872: telnet_printf("breaked at %04X:%04X: port %04X was read at %04X:%04X\n", SREG(CS), m_eip,
! 1873: in_break_point.table[in_break_point.hit - 1].addr,
! 1874: m_prev_cs, m_prev_eip);
! 1875: } else if(out_break_point.hit) {
! 1876: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
! 1877: telnet_printf("breaked at %04X:%04X: port %04X was written at %04X:%04X\n", SREG(CS), m_eip,
! 1878: out_break_point.table[out_break_point.hit - 1].addr,
! 1879: m_prev_cs, m_prev_eip);
! 1880: } else if(int_break_point.hit) {
! 1881: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
! 1882: telnet_printf("breaked at %04X:%04X: INT %02x", SREG(CS), m_eip, int_break_point.table[int_break_point.hit - 1].int_num);
! 1883: if(int_break_point.table[int_break_point.hit - 1].ah_registered) {
! 1884: telnet_printf(" AH=%02x", int_break_point.table[int_break_point.hit - 1].ah);
! 1885: }
! 1886: if(int_break_point.table[int_break_point.hit - 1].al_registered) {
! 1887: telnet_printf(" AL=%02x", int_break_point.table[int_break_point.hit - 1].al);
! 1888: }
! 1889: telnet_printf(" is raised at %04X:%04X\n", m_prev_cs, m_prev_eip);
! 1890: } else if(steps > 0) {
! 1891: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
! 1892: telnet_printf("breaked at %04X:%04X: enter key was pressed\n", SREG(CS), m_eip);
! 1893: }
! 1894: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
! 1895: debugger_dasm(buffer, SREG(CS), m_eip);
! 1896: telnet_printf("next\t%04X:%04X %s\n", SREG(CS), m_eip, buffer);
! 1897: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
! 1898: } else {
! 1899: telnet_printf("invalid parameter number\n");
! 1900: }
! 1901: } else if(stricmp(params[0], "Q") == 0) {
! 1902: break;
! 1903: } else if(stricmp(params[0], "X") == 0) {
! 1904: debugger_process_info(buffer);
! 1905: telnet_printf("%s", buffer);
! 1906: } else if(stricmp(params[0], ">") == 0) {
! 1907: if(num == 2) {
! 1908: if(fp_debugger != NULL) {
! 1909: fclose(fp_debugger);
! 1910: fp_debugger = NULL;
! 1911: }
! 1912: fp_debugger = fopen(params[1], "w");
! 1913: } else {
! 1914: telnet_printf("invalid parameter number\n");
! 1915: }
! 1916: } else if(stricmp(params[0], "<") == 0) {
! 1917: if(num == 2) {
! 1918: if(fi_debugger != NULL) {
! 1919: fclose(fi_debugger);
! 1920: fi_debugger = NULL;
! 1921: }
! 1922: fi_debugger = fopen(params[1], "r");
! 1923: } else {
! 1924: telnet_printf("invalid parameter number\n");
! 1925: }
! 1926: } else if(stricmp(params[0], "?") == 0) {
! 1927: telnet_printf("D [<start> [<end>]] - dump memory\n");
! 1928: telnet_printf("E[{B,W,D}] <address> <list> - edit memory (byte,word,dword)\n");
! 1929: telnet_printf("EA <address> \"<value>\" - edit memory (ascii)\n");
! 1930: telnet_printf("I[{B,W,D}] <port> - input port (byte,word,dword)\n");
! 1931: telnet_printf("O[{B,W,D}] <port> <value> - output port (byte,word,dword)\n");
! 1932:
! 1933: telnet_printf("R - show registers\n");
! 1934: telnet_printf("R <reg> <value> - edit register\n");
! 1935: telnet_printf("S <start> <end> <list> - search\n");
! 1936: telnet_printf("U [<start> [<end>]] - unassemble\n");
! 1937:
! 1938: telnet_printf("H <value> <value> - hexadd\n");
! 1939:
! 1940: telnet_printf("BP <address> - set breakpoint\n");
! 1941: telnet_printf("{R,W}BP <address> - set breakpoint (break at memory access)\n");
! 1942: telnet_printf("{I,O}BP <port> - set breakpoint (break at i/o access)\n");
! 1943: telnet_printf("INTBP <num> [<ah> [<al>]]- set breakpoint (break at interrupt)\n");
! 1944: telnet_printf("[{R,W,I,O,INT}]B{C,D,E} {*,<list>} - clear/disable/enable breakpoint(s)\n");
! 1945: telnet_printf("[{R,W,I,O,INT}]BL - list breakpoint(s)\n");
! 1946:
! 1947: telnet_printf("G - go (press enter key to break)\n");
! 1948: telnet_printf("G <address> - go and break at address\n");
! 1949: telnet_printf("P - trace one opcode (step over)\n");
! 1950: telnet_printf("T [<count>] - trace (step in)\n");
! 1951: telnet_printf("Q - quit\n");
! 1952: telnet_printf("X - show dos process info\n");
! 1953:
! 1954: telnet_printf("> <filename> - output logfile\n");
! 1955: telnet_printf("< <filename> - input commands from file\n");
! 1956:
! 1957: telnet_printf("<value> - hexa, decimal(%%d), ascii('a')\n");
! 1958: telnet_printf("<list> - <value> [<value> [<value> [...]]]\n");
! 1959: } else {
! 1960: telnet_printf("unknown command %s\n", params[0]);
! 1961: }
! 1962: }
! 1963: }
! 1964: if(fp_debugger != NULL) {
! 1965: fclose(fp_debugger);
! 1966: fp_debugger = NULL;
! 1967: }
! 1968: if(fi_debugger != NULL) {
! 1969: fclose(fi_debugger);
! 1970: fi_debugger = NULL;
! 1971: }
! 1972: now_debugging = now_going = now_suspended = force_suspend = false;
! 1973: closesocket(cli_socket);
! 1974: }
! 1975:
! 1976: const char *debugger_get_ttermpro_path()
! 1977: {
! 1978: static char path[MAX_PATH] = {0};
! 1979:
! 1980: if(getenv("ProgramFiles")) {
! 1981: sprintf(path, "%s\\teraterm\\ttermpro.exe", getenv("ProgramFiles"));
! 1982: }
! 1983: return(path);
! 1984: }
! 1985:
! 1986: const char *debugger_get_ttermpro_x86_path()
! 1987: {
! 1988: static char path[MAX_PATH] = {0};
! 1989:
! 1990: if(getenv("ProgramFiles(x86)")) {
! 1991: sprintf(path, "%s\\teraterm\\ttermpro.exe", getenv("ProgramFiles(x86)"));
! 1992: }
! 1993: return(path);
! 1994: }
! 1995:
! 1996: const char *debugger_get_putty_path()
! 1997: {
! 1998: static char path[MAX_PATH] = {0};
! 1999:
! 2000: if(getenv("ProgramFiles")) {
! 2001: sprintf(path, "%s\\PuTTY\\putty.exe", getenv("ProgramFiles"));
! 2002: }
! 2003: return(path);
! 2004: }
! 2005:
! 2006: const char *debugger_get_putty_x86_path()
! 2007: {
! 2008: static char path[MAX_PATH] = {0};
! 2009:
! 2010: if(getenv("ProgramFiles(x86)")) {
! 2011: sprintf(path, "%s\\PuTTY\\putty.exe", getenv("ProgramFiles(x86)"));
! 2012: }
! 2013: return(path);
! 2014: }
! 2015:
! 2016: const char *debugger_get_telnet_path()
! 2017: {
! 2018: // NOTE: When you run 32bit version of msdos.exe on Windows x64,
! 2019: // C:\Windows\System32\telnet.exe is redirected to telnet.exe in SysWOW64.
! 2020: // But 32bit version of telnet.exe will not be installed in SysWOW64
! 2021: // and 64bit version of telnet.exe will be installed in System32.
! 2022: static char path[MAX_PATH] = {0};
! 2023:
! 2024: if(getenv("windir") != NULL) {
! 2025: sprintf(path, "%s\\System32\\telnet.exe", getenv("windir"));
! 2026: }
! 2027: return(path);
! 2028: }
! 2029:
! 2030: DWORD WINAPI debugger_thread(LPVOID)
! 2031: {
! 2032: WSADATA was_data;
! 2033: struct sockaddr_in svr_addr;
! 2034: struct sockaddr_in cli_addr;
! 2035: int cli_addr_len = sizeof(cli_addr);
! 2036: int port = 23;
! 2037: int bind_stat = SOCKET_ERROR;
! 2038: struct timeval timeout;
! 2039:
! 2040: WSAStartup(MAKEWORD(2,0), &was_data);
! 2041:
! 2042: if((svr_socket = socket(AF_INET, SOCK_STREAM, 0)) != INVALID_SOCKET) {
! 2043: memset(&svr_addr, 0, sizeof(svr_addr));
! 2044: svr_addr.sin_family = AF_INET;
! 2045: svr_addr.sin_addr.s_addr = htonl(INADDR_ANY);
! 2046:
! 2047: while(!m_halted && port < 10000) {
! 2048: svr_addr.sin_port = htons(port);
! 2049: if((bind_stat = bind(svr_socket, (struct sockaddr *)&svr_addr, sizeof(svr_addr))) == 0) {
! 2050: break;
! 2051: } else {
! 2052: port = (port == 23) ? 9000 : (port + 1);
! 2053: }
! 2054: }
! 2055: if(bind_stat == 0) {
! 2056: timeout.tv_sec = 1;
! 2057: timeout.tv_usec = 0;
! 2058: setsockopt(svr_socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
! 2059:
! 2060: listen(svr_socket, 1);
! 2061:
! 2062: char command[MAX_PATH] = {0};
! 2063: STARTUPINFO si;
! 2064: PROCESS_INFORMATION pi;
! 2065:
! 2066: if(_access(debugger_get_ttermpro_path(), 0) == 0) {
! 2067: sprintf(command, "%s localhost:%d /T=1", debugger_get_ttermpro_path(), port);
! 2068: } else if(_access(debugger_get_ttermpro_x86_path(), 0) == 0) {
! 2069: sprintf(command, "%s localhost:%d /T=1", debugger_get_ttermpro_x86_path(), port);
! 2070: } else if(_access(debugger_get_putty_path(), 0) == 0) {
! 2071: sprintf(command, "%s -telnet localhost %d", debugger_get_putty_path(), port);
! 2072: } else if(_access(debugger_get_putty_x86_path(), 0) == 0) {
! 2073: sprintf(command, "%s -telnet localhost %d", debugger_get_putty_x86_path(), port);
! 2074: } else if(_access(debugger_get_telnet_path(), 0) == 0) {
! 2075: sprintf(command, "%s -t vt100 localhost %d", debugger_get_telnet_path(), port);
! 2076: }
! 2077: if(command[0] != '\0') {
! 2078: memset(&si, 0, sizeof(STARTUPINFO));
! 2079: memset(&pi, 0, sizeof(PROCESS_INFORMATION));
! 2080: CreateProcess(NULL, command, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
! 2081: }
! 2082:
! 2083: while(!m_halted) {
! 2084: if((cli_socket = accept(svr_socket, (struct sockaddr *) &cli_addr, &cli_addr_len)) != INVALID_SOCKET) {
! 2085: u_long val = 1;
! 2086: ioctlsocket(cli_socket, FIONBIO, &val);
! 2087: debugger_main();
! 2088: }
! 2089: }
! 2090: }
! 2091: }
! 2092: WSACleanup();
! 2093: return(0);
! 2094: }
! 2095: #endif
! 2096:
! 2097: /* ----------------------------------------------------------------------------
1.1 root 2098: main
2099: ---------------------------------------------------------------------------- */
2100:
1.1.1.28 root 2101: BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
2102: {
2103: if(dwCtrlType == CTRL_BREAK_EVENT) {
1.1.1.33! root 2104: if(key_buf_char != NULL && key_buf_scan != NULL) {
! 2105: key_buf_char->clear();
! 2106: key_buf_scan->clear();
! 2107: }
! 2108: // key_code = key_recv = 0;
1.1.1.28 root 2109: return TRUE;
2110: } else if(dwCtrlType == CTRL_C_EVENT) {
2111: return TRUE;
2112: } else if(dwCtrlType == CTRL_CLOSE_EVENT) {
2113: // this program will be terminated abnormally, do minimum end process
2114: exit_handler();
2115: exit(1);
2116: }
2117: return FALSE;
2118: }
2119:
2120: void exit_handler()
2121: {
2122: if(temp_file_created) {
2123: DeleteFile(temp_file_path);
2124: temp_file_created = false;
2125: }
2126: if(key_buf_char != NULL) {
2127: key_buf_char->release();
2128: delete key_buf_char;
2129: key_buf_char = NULL;
2130: }
2131: if(key_buf_scan != NULL) {
2132: key_buf_scan->release();
2133: delete key_buf_scan;
2134: key_buf_scan = NULL;
2135: }
1.1.1.32 root 2136: #ifdef SUPPORT_XMS
2137: msdos_xms_release();
2138: #endif
1.1.1.28 root 2139: hardware_release();
2140: }
2141:
2142: #ifdef USE_THREAD
2143: DWORD WINAPI vram_thread(LPVOID)
2144: {
2145: while(!m_halted) {
2146: EnterCriticalSection(&vram_crit_sect);
2147: if(vram_length_char != 0 && vram_length_char == vram_last_length_char) {
2148: vram_flush_char();
2149: }
2150: if(vram_length_attr != 0 && vram_length_attr == vram_last_length_attr) {
2151: vram_flush_attr();
2152: }
2153: vram_last_length_char = vram_length_char;
2154: vram_last_length_attr = vram_length_attr;
2155: LeaveCriticalSection(&vram_crit_sect);
2156: // this is about half the maximum keyboard repeat rate - any
2157: // lower tends to be jerky, any higher misses updates
2158: Sleep(15);
2159: }
2160: return 0;
2161: }
2162: #endif
2163:
2164: long get_section_in_exec_file(FILE *fp, char *name)
2165: {
2166: UINT8 header[0x400];
2167:
2168: long position = ftell(fp);
2169: fseek(fp, 0, SEEK_SET);
2170: fread(header, sizeof(header), 1, fp);
2171: fseek(fp, position, SEEK_SET);
2172:
2173: try {
2174: _IMAGE_DOS_HEADER *dosHeader = (_IMAGE_DOS_HEADER *)(header + 0);
2175: DWORD dwTopOfSignature = dosHeader->e_lfanew;
2176: DWORD dwTopOfCoffHeader = dwTopOfSignature + 4;
2177: _IMAGE_FILE_HEADER *coffHeader = (_IMAGE_FILE_HEADER *)(header + dwTopOfCoffHeader);
2178: DWORD dwTopOfOptionalHeader = dwTopOfCoffHeader + sizeof(_IMAGE_FILE_HEADER);
2179: DWORD dwTopOfFirstSectionHeader = dwTopOfOptionalHeader + coffHeader->SizeOfOptionalHeader;
2180:
2181: for(int i = 0; i < coffHeader->NumberOfSections; i++) {
2182: _IMAGE_SECTION_HEADER *sectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * i);
2183: if(memcmp(sectionHeader->Name, name, strlen(name)) == 0) {
2184: return(sectionHeader->PointerToRawData);
2185: }
2186: }
2187: } catch(...) {
2188: }
2189: return(0);
2190: }
2191:
1.1.1.10 root 2192: bool is_started_from_command_prompt()
2193: {
1.1.1.18 root 2194: bool ret = false;
2195:
2196: HMODULE hLibrary = LoadLibrary(_T("Kernel32.dll"));
2197: if(hLibrary) {
2198: typedef DWORD (WINAPI *GetConsoleProcessListFunction)(__out LPDWORD lpdwProcessList, __in DWORD dwProcessCount);
2199: GetConsoleProcessListFunction lpfnGetConsoleProcessList;
2200: lpfnGetConsoleProcessList = reinterpret_cast<GetConsoleProcessListFunction>(::GetProcAddress(hLibrary, "GetConsoleProcessList"));
2201: if(lpfnGetConsoleProcessList) {
2202: DWORD pl;
2203: ret = (lpfnGetConsoleProcessList(&pl, 1) > 1);
2204: FreeLibrary(hLibrary);
2205: return(ret);
2206: }
2207: FreeLibrary(hLibrary);
2208: }
2209:
2210: HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
2211: if(hSnapshot != INVALID_HANDLE_VALUE) {
2212: DWORD dwParentProcessID = 0;
2213: PROCESSENTRY32 pe32;
2214: pe32.dwSize = sizeof(PROCESSENTRY32);
2215: if(Process32First(hSnapshot, &pe32)) {
2216: do {
2217: if(pe32.th32ProcessID == GetCurrentProcessId()) {
2218: dwParentProcessID = pe32.th32ParentProcessID;
2219: break;
2220: }
2221: } while(Process32Next(hSnapshot, &pe32));
2222: }
2223: CloseHandle(hSnapshot);
2224: if(dwParentProcessID != 0) {
2225: HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwParentProcessID);
2226: if(hProcess != NULL) {
2227: HMODULE hMod;
2228: DWORD cbNeeded;
2229: if(EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {
2230: char module_name[MAX_PATH];
2231: if(GetModuleBaseName(hProcess, hMod, module_name, sizeof(module_name))) {
2232: ret = (_strnicmp(module_name, "cmd.exe", 7) == 0);
2233: }
2234: }
2235: CloseHandle(hProcess);
2236: }
2237: }
2238: }
2239: return(ret);
1.1.1.14 root 2240: }
2241:
2242: BOOL is_greater_windows_version(DWORD dwMajorVersion, DWORD dwMinorVersion, WORD wServicePackMajor, WORD wServicePackMinor)
2243: {
1.1.1.24 root 2244: // https://msdn.microsoft.com/en-us/library/windows/desktop/ms725491(v=vs.85).aspx
1.1.1.14 root 2245: OSVERSIONINFOEX osvi;
2246: DWORDLONG dwlConditionMask = 0;
2247: int op = VER_GREATER_EQUAL;
2248:
2249: // Initialize the OSVERSIONINFOEX structure.
2250: ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
2251: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
2252: osvi.dwMajorVersion = dwMajorVersion;
2253: osvi.dwMinorVersion = dwMinorVersion;
2254: osvi.wServicePackMajor = wServicePackMajor;
2255: osvi.wServicePackMinor = wServicePackMinor;
2256:
2257: // Initialize the condition mask.
2258: VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, op );
2259: VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, op );
2260: VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, op );
2261: VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMINOR, op );
2262:
2263: // Perform the test.
2264: return VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, dwlConditionMask);
2265: }
2266:
1.1.1.27 root 2267: void get_sio_port_numbers()
2268: {
2269: SP_DEVINFO_DATA DeviceInfoData = {sizeof(SP_DEVINFO_DATA)};
2270: HDEVINFO hDevInfo = 0;
2271: HKEY hKey = 0;
2272: if((hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_COMPORT, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE))) != 0) {
2273: for(int i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData); i++) {
2274: if((hKey = SetupDiOpenDevRegKey(hDevInfo, &DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE)) != INVALID_HANDLE_VALUE) {
2275: char chData[256];
2276: DWORD dwType = 0;
2277: DWORD dwSize = sizeof(chData);
2278: int port_number = 0;
2279:
2280: if(RegQueryValueEx(hKey, _T("PortName"), NULL, &dwType, (BYTE *)chData, &dwSize) == ERROR_SUCCESS) {
2281: if(_strnicmp(chData, "COM", 3) == 0) {
2282: port_number = atoi(chData + 3);
2283: }
2284: }
2285: RegCloseKey(hKey);
2286:
1.1.1.29 root 2287: if(sio_port_number[0] == port_number || sio_port_number[1] == port_number || sio_port_number[2] == port_number || sio_port_number[3] == port_number) {
1.1.1.27 root 2288: continue;
2289: }
2290: if(sio_port_number[0] == 0) {
2291: sio_port_number[0] = port_number;
2292: } else if(sio_port_number[1] == 0) {
2293: sio_port_number[1] = port_number;
1.1.1.29 root 2294: } else if(sio_port_number[2] == 0) {
2295: sio_port_number[2] = port_number;
2296: } else if(sio_port_number[3] == 0) {
2297: sio_port_number[3] = port_number;
1.1.1.27 root 2298: }
1.1.1.29 root 2299: if(sio_port_number[0] != 0 && sio_port_number[1] != 0 && sio_port_number[2] != 0 && sio_port_number[3] != 0) {
1.1.1.27 root 2300: break;
2301: }
2302: }
2303: }
2304: }
2305: }
2306:
1.1.1.28 root 2307: #define IS_NUMERIC(c) ((c) >= '0' && (c) <= '9')
2308:
1.1 root 2309: int main(int argc, char *argv[], char *envp[])
2310: {
1.1.1.9 root 2311: int arg_offset = 0;
2312: int standard_env = 0;
1.1.1.14 root 2313: int buf_width = 0, buf_height = 0;
1.1.1.28 root 2314: bool get_console_info_success = false;
2315: bool screen_size_changed = false;
2316:
2317: _TCHAR path[MAX_PATH], full[MAX_PATH], *name = NULL;
2318: GetModuleFileName(NULL, path, MAX_PATH);
2319: GetFullPathName(path, MAX_PATH, full, &name);
1.1 root 2320:
1.1.1.27 root 2321: char dummy_argv_0[] = "msdos.exe";
2322: char dummy_argv_1[MAX_PATH];
2323: char *dummy_argv[256] = {dummy_argv_0, dummy_argv_1, 0};
2324: char new_exec_file[MAX_PATH];
2325: bool convert_cmd_file = false;
1.1.1.28 root 2326: unsigned int code_page = 0;
1.1.1.27 root 2327:
2328: if(name != NULL && stricmp(name, "msdos.exe") != 0) {
1.1.1.28 root 2329: // check if command file is embedded to this execution file
2330: // if this execution file name is msdos.exe, don't check
1.1.1.27 root 2331: FILE* fp = fopen(full, "rb");
1.1.1.28 root 2332: long offset = get_section_in_exec_file(fp, ".msdos");
2333: if(offset != 0) {
1.1.1.30 root 2334: UINT8 buffer[16];
1.1.1.28 root 2335: fseek(fp, offset, SEEK_SET);
2336: fread(buffer, sizeof(buffer), 1, fp);
2337:
2338: // restore flags
2339: stay_busy = ((buffer[0] & 0x01) != 0);
2340: no_windows = ((buffer[0] & 0x02) != 0);
2341: standard_env = ((buffer[0] & 0x04) != 0);
2342: ignore_illegal_insn = ((buffer[0] & 0x08) != 0);
2343: limit_max_memory = ((buffer[0] & 0x10) != 0);
2344: if((buffer[0] & 0x20) != 0) {
2345: get_sio_port_numbers();
2346: }
2347: if((buffer[0] & 0x40) != 0) {
2348: UMB_TOP = EMS_TOP + EMS_SIZE;
2349: support_ems = true;
1.1.1.30 root 2350: }
1.1.1.27 root 2351: #ifdef SUPPORT_XMS
1.1.1.30 root 2352: if((buffer[0] & 0x80) != 0) {
1.1.1.28 root 2353: support_xms = true;
2354: }
1.1.1.30 root 2355: #endif
1.1.1.28 root 2356: if((buffer[1] != 0 || buffer[2] != 0) && (buffer[3] != 0 || buffer[4] != 0)) {
2357: buf_width = buffer[1] | (buffer[2] << 8);
2358: buf_height = buffer[3] | (buffer[4] << 8);
2359: }
2360: if(buffer[5] != 0) {
1.1.1.30 root 2361: dos_major_version = buffer[5];
2362: dos_minor_version = buffer[6];
2363: }
2364: if(buffer[7] != 0) {
2365: win_major_version = buffer[7];
2366: win_minor_version = buffer[8];
1.1.1.28 root 2367: }
1.1.1.30 root 2368: if((code_page = buffer[9] | (buffer[10] << 8)) != 0) {
1.1.1.28 root 2369: SetConsoleCP(code_page);
2370: SetConsoleOutputCP(code_page);
2371: }
1.1.1.30 root 2372: int name_len = buffer[11];
2373: int file_len = buffer[12] | (buffer[13] << 8) | (buffer[14] << 16) | (buffer[15] << 24);
1.1.1.28 root 2374:
2375: // restore command file name
2376: memset(dummy_argv_1, 0, sizeof(dummy_argv_1));
2377: fread(dummy_argv_1, name_len, 1, fp);
2378:
2379: if(name_len != 0 && _access(dummy_argv_1, 0) == 0) {
2380: // if original command file exists, create a temporary file name
2381: if(GetTempFileName(_T("."), _T("DOS"), 0, dummy_argv_1) != 0) {
2382: // create a temporary command file in the current director
2383: DeleteFile(dummy_argv_1);
1.1.1.27 root 2384: } else {
1.1.1.28 root 2385: // create a temporary command file in the temporary folder
2386: GetTempPath(MAX_PATH, path);
2387: if(GetTempFileName(path, _T("DOS"), 0, dummy_argv_1) != 0) {
2388: DeleteFile(dummy_argv_1);
2389: } else {
2390: sprintf(dummy_argv_1, "%s$DOSPRG$.TMP", path);
2391: }
1.1.1.27 root 2392: }
1.1.1.28 root 2393: // check the command file type
2394: fread(buffer, 2, 1, fp);
2395: fseek(fp, -2, SEEK_CUR);
2396: if(memcmp(buffer, "MZ", 2) != 0) {
2397: memcpy(dummy_argv_1 + strlen(dummy_argv_1) - 4, ".COM", 4);
2398: } else {
2399: memcpy(dummy_argv_1 + strlen(dummy_argv_1) - 4, ".EXE", 4);
1.1.1.27 root 2400: }
2401: }
1.1.1.28 root 2402:
2403: // restore command file
2404: FILE* fo = fopen(dummy_argv_1, "wb");
2405: for(int i = 0; i < file_len; i++) {
2406: fputc(fgetc(fp), fo);
2407: }
2408: fclose(fo);
2409:
2410: GetFullPathName(dummy_argv_1, MAX_PATH, temp_file_path, NULL);
2411: temp_file_created = true;
2412: SetFileAttributes(temp_file_path, FILE_ATTRIBUTE_HIDDEN);
2413:
2414: // adjust argc/argv
2415: for(int i = 1; i < argc && (i + 1) < 256; i++) {
2416: dummy_argv[i + 1] = argv[i];
2417: }
2418: argc++;
2419: argv = dummy_argv;
1.1.1.27 root 2420: }
2421: fclose(fp);
2422: }
1.1.1.9 root 2423: for(int i = 1; i < argc; i++) {
1.1.1.25 root 2424: if(_strnicmp(argv[i], "-b", 2) == 0) {
2425: stay_busy = true;
2426: arg_offset++;
1.1.1.27 root 2427: } else if(_strnicmp(argv[i], "-c", 2) == 0) {
2428: if(argv[i][2] != '\0') {
2429: strcpy(new_exec_file, &argv[i][2]);
2430: } else {
2431: strcpy(new_exec_file, "new_exec_file.exe");
2432: }
2433: convert_cmd_file = true;
2434: arg_offset++;
1.1.1.28 root 2435: } else if(_strnicmp(argv[i], "-p", 2) == 0) {
2436: if(IS_NUMERIC(argv[i][2])) {
2437: code_page = atoi(&argv[i][2]);
2438: } else {
2439: code_page = GetConsoleCP();
2440: }
2441: arg_offset++;
1.1.1.25 root 2442: } else if(_strnicmp(argv[i], "-d", 2) == 0) {
2443: no_windows = true;
2444: arg_offset++;
2445: } else if(_strnicmp(argv[i], "-e", 2) == 0) {
1.1.1.9 root 2446: standard_env = 1;
2447: arg_offset++;
1.1.1.14 root 2448: } else if(_strnicmp(argv[i], "-i", 2) == 0) {
2449: ignore_illegal_insn = true;
2450: arg_offset++;
2451: } else if(_strnicmp(argv[i], "-m", 2) == 0) {
2452: limit_max_memory = true;
2453: arg_offset++;
2454: } else if(_strnicmp(argv[i], "-n", 2) == 0) {
1.1.1.17 root 2455: if(sscanf(argv[1] + 2, "%d,%d", &buf_height, &buf_width) != 2) {
2456: buf_width = buf_height = 0;
2457: }
2458: if(buf_width <= 0 || buf_width > 0x7fff) {
2459: buf_width = 80;
2460: }
2461: if(buf_height <= 0 || buf_height > 0x7fff) {
2462: buf_height = 25;
2463: }
1.1.1.14 root 2464: arg_offset++;
1.1.1.25 root 2465: } else if(_strnicmp(argv[i], "-s", 2) == 0) {
1.1.1.28 root 2466: if(IS_NUMERIC(argv[i][2])) {
1.1.1.29 root 2467: char *p0 = &argv[i][2], *p1, *p2, *p3;
2468: if((p1 = strchr(p0, ',')) != NULL && IS_NUMERIC(p1[1])) {
2469: sio_port_number[1] = atoi(p1 + 1);
2470: if((p2 = strchr(p1, ',')) != NULL && IS_NUMERIC(p2[1])) {
2471: sio_port_number[2] = atoi(p2 + 1);
2472: if((p3 = strchr(p2, ',')) != NULL && IS_NUMERIC(p3[1])) {
2473: sio_port_number[3] = atoi(p3 + 1);
2474: }
2475: }
1.1.1.25 root 2476: }
1.1.1.29 root 2477: sio_port_number[0] = atoi(p0);
1.1.1.25 root 2478: }
1.1.1.29 root 2479: if(sio_port_number[0] == 0 || sio_port_number[1] == 0 || sio_port_number[2] == 0 || sio_port_number[3] == 0) {
1.1.1.27 root 2480: get_sio_port_numbers();
1.1.1.25 root 2481: }
2482: arg_offset++;
1.1.1.9 root 2483: } else if(_strnicmp(argv[i], "-v", 2) == 0) {
1.1.1.17 root 2484: if(strlen(argv[i]) >= 5 && IS_NUMERIC(argv[i][2]) && argv[i][3] == '.' && IS_NUMERIC(argv[i][4]) && (argv[i][5] == '\0' || IS_NUMERIC(argv[i][5]))) {
1.1.1.30 root 2485: dos_major_version = argv[i][2] - '0';
2486: dos_minor_version = (argv[i][4] - '0') * 10 + (argv[i][5] ? (argv[i][5] - '0') : 0);
2487: }
2488: arg_offset++;
2489: } else if(_strnicmp(argv[i], "-w", 2) == 0) {
2490: if(strlen(argv[i]) >= 5 && IS_NUMERIC(argv[i][2]) && argv[i][3] == '.' && IS_NUMERIC(argv[i][4]) && (argv[i][5] == '\0' || IS_NUMERIC(argv[i][5]))) {
2491: win_major_version = argv[i][2] - '0';
2492: win_minor_version = (argv[i][4] - '0') * 10 + (argv[i][5] ? (argv[i][5] - '0') : 0);
1.1.1.9 root 2493: }
2494: arg_offset++;
1.1.1.25 root 2495: } else if(_strnicmp(argv[i], "-x", 2) == 0) {
2496: UMB_TOP = EMS_TOP + EMS_SIZE;
2497: support_ems = true;
2498: #ifdef SUPPORT_XMS
2499: support_xms = true;
2500: #endif
2501: arg_offset++;
1.1.1.9 root 2502: } else {
2503: break;
2504: }
2505: }
2506: if(argc < 2 + arg_offset) {
1.1 root 2507: #ifdef _WIN64
1.1.1.14 root 2508: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32-x64 console\n\n");
1.1 root 2509: #else
1.1.1.14 root 2510: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32 console\n\n");
1.1 root 2511: #endif
1.1.1.25 root 2512: fprintf(stderr,
1.1.1.28 root 2513: "Usage: MSDOS [-b] [-c[(new exec file)] [-p[P]]] [-d] [-e] [-i] [-m] [-n[L[,C]]]\n"
1.1.1.30 root 2514: " [-s[P1[,P2[,P3[,P4]]]]] [-vX.XX] [-wX.XX] [-x] (command) [options]\n"
1.1.1.25 root 2515: "\n"
2516: "\t-b\tstay busy during keyboard polling\n"
1.1.1.28 root 2517: #ifdef _WIN64
1.1.1.27 root 2518: "\t-c\tconvert command file to 64bit execution file\n"
1.1.1.28 root 2519: #else
1.1.1.27 root 2520: "\t-c\tconvert command file to 32bit execution file\n"
2521: #endif
1.1.1.28 root 2522: "\t-p\trecord current code page when convert command file\n"
1.1.1.25 root 2523: "\t-d\tpretend running under straight DOS, not Windows\n"
2524: "\t-e\tuse a reduced environment block\n"
2525: "\t-i\tignore invalid instructions\n"
2526: "\t-m\trestrict free memory to 0x7FFF paragraphs\n"
2527: "\t-n\tcreate a new buffer (25 lines, 80 columns by default)\n"
2528: "\t-s\tenable serial I/O and set host's COM port numbers\n"
2529: "\t-v\tset the DOS version\n"
1.1.1.30 root 2530: "\t-w\tset the Windows version\n"
1.1.1.19 root 2531: #ifdef SUPPORT_XMS
1.1.1.28 root 2532: "\t-x\tenable XMS and LIM EMS\n"
1.1.1.19 root 2533: #else
1.1.1.28 root 2534: "\t-x\tenable LIM EMS\n"
1.1.1.19 root 2535: #endif
2536: );
1.1.1.10 root 2537:
2538: if(!is_started_from_command_prompt()) {
2539: fprintf(stderr, "\nStart this program from a command prompt!\n\nHit any key to quit...");
2540: while(!_kbhit()) {
2541: Sleep(10);
2542: }
2543: }
1.1.1.20 root 2544: #ifdef _DEBUG
2545: _CrtDumpMemoryLeaks();
2546: #endif
1.1 root 2547: return(EXIT_FAILURE);
2548: }
1.1.1.27 root 2549: if(convert_cmd_file) {
2550: retval = EXIT_FAILURE;
1.1.1.28 root 2551: if(name != NULL/* && stricmp(name, "msdos.exe") == 0*/) {
1.1.1.27 root 2552: FILE *fp = NULL, *fs = NULL, *fo = NULL;
1.1.1.28 root 2553: int len = strlen(argv[arg_offset + 1]), data;
1.1.1.27 root 2554:
1.1.1.28 root 2555: if(!(len > 4 && (stricmp(argv[arg_offset + 1] + len - 4, ".COM") == 0 || stricmp(argv[arg_offset + 1] + len - 4, ".EXE") == 0))) {
2556: fprintf(stderr, "Specify command file with extenstion (.COM or .EXE)\n");
2557: } else if((fp = fopen(full, "rb")) == NULL) {
2558: fprintf(stderr, "Can't open '%s'\n", name);
1.1.1.27 root 2559: } else {
1.1.1.28 root 2560: long offset = get_section_in_exec_file(fp, ".msdos");
2561: if(offset != 0) {
2562: UINT8 buffer[14];
2563: fseek(fp, offset, SEEK_SET);
2564: fread(buffer, sizeof(buffer), 1, fp);
2565: memset(path, 0, sizeof(path));
2566: fread(path, buffer[9], 1, fp);
2567: fprintf(stderr, "Command file '%s' was already embedded to '%s'\n", path, name);
2568: } else if((fs = fopen(argv[arg_offset + 1], "rb")) == NULL) {
2569: fprintf(stderr, "Can't open '%s'\n", argv[arg_offset + 1]);
2570: } else if((fo = fopen(new_exec_file, "wb")) == NULL) {
2571: fprintf(stderr, "Can't open '%s'\n", new_exec_file);
2572: } else {
2573: // read pe header of msdos.exe
2574: UINT8 header[0x400];
2575: fseek(fp, 0, SEEK_SET);
2576: fread(header, sizeof(header), 1, fp);
2577:
2578: _IMAGE_DOS_HEADER *dosHeader = (_IMAGE_DOS_HEADER *)(header + 0);
2579: DWORD dwTopOfSignature = dosHeader->e_lfanew;
2580: DWORD dwTopOfCoffHeader = dwTopOfSignature + 4;
2581: _IMAGE_FILE_HEADER *coffHeader = (_IMAGE_FILE_HEADER *)(header + dwTopOfCoffHeader);
2582: DWORD dwTopOfOptionalHeader = dwTopOfCoffHeader + sizeof(_IMAGE_FILE_HEADER);
2583: _IMAGE_OPTIONAL_HEADER *optionalHeader = (_IMAGE_OPTIONAL_HEADER *)(header + dwTopOfOptionalHeader);
2584: DWORD dwTopOfFirstSectionHeader = dwTopOfOptionalHeader + coffHeader->SizeOfOptionalHeader;
2585:
2586: _IMAGE_SECTION_HEADER *lastSectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * (coffHeader->NumberOfSections - 1));
2587: DWORD dwEndOfFile = lastSectionHeader->PointerToRawData + lastSectionHeader->SizeOfRawData;
2588: DWORD dwLastSectionSize = lastSectionHeader->SizeOfRawData;
2589: DWORD dwExtraLastSectionBytes = dwLastSectionSize % optionalHeader->SectionAlignment;
2590: if(dwExtraLastSectionBytes != 0) {
2591: DWORD dwRemain = optionalHeader->SectionAlignment - dwExtraLastSectionBytes;
2592: dwLastSectionSize += dwRemain;
2593: }
2594: DWORD dwVirtualAddress = lastSectionHeader->VirtualAddress + dwLastSectionSize;
2595:
2596: // store msdos.exe
2597: fseek(fp, 0, SEEK_SET);
2598: for(int i = 0; i < dwEndOfFile; i++) {
2599: if((data = fgetc(fp)) != EOF) {
2600: fputc(data, fo);
2601: } else {
2602: // we should not reach here :-(
2603: fputc(0, fo);
2604: }
2605: }
2606:
2607: // store options
2608: UINT8 flags = 0;
2609: if(stay_busy) {
2610: flags |= 0x01;
2611: }
2612: if(no_windows) {
2613: flags |= 0x02;
2614: }
2615: if(standard_env) {
2616: flags |= 0x04;
2617: }
2618: if(ignore_illegal_insn) {
2619: flags |= 0x08;
2620: }
2621: if(limit_max_memory) {
2622: flags |= 0x10;
2623: }
1.1.1.29 root 2624: if(sio_port_number[0] != 0 || sio_port_number[1] != 0 || sio_port_number[2] != 0 || sio_port_number[3] != 0) {
1.1.1.28 root 2625: flags |= 0x20;
2626: }
2627: if(support_ems) {
2628: flags |= 0x40;
2629: }
1.1.1.30 root 2630: #ifdef SUPPORT_XMS
2631: if(support_xms) {
2632: flags |= 0x80;
2633: }
2634: #endif
1.1.1.28 root 2635:
2636: fputc(flags, fo);
2637: fputc((buf_width >> 0) & 0xff, fo);
2638: fputc((buf_width >> 8) & 0xff, fo);
2639: fputc((buf_height >> 0) & 0xff, fo);
2640: fputc((buf_height >> 8) & 0xff, fo);
1.1.1.30 root 2641: fputc(dos_major_version, fo);
2642: fputc(dos_minor_version, fo);
2643: fputc(win_major_version, fo);
2644: fputc(win_minor_version, fo);
1.1.1.28 root 2645: fputc((code_page >> 0) & 0xff, fo);
2646: fputc((code_page >> 8) & 0xff, fo);
2647:
2648: // store command file info
2649: GetFullPathName(argv[arg_offset + 1], MAX_PATH, full, &name);
2650: int name_len = strlen(name);
2651: fseek(fs, 0, SEEK_END);
2652: long file_size = ftell(fs);
2653:
2654: fputc(name_len, fo);
2655: fputc((file_size >> 0) & 0xff, fo);
2656: fputc((file_size >> 8) & 0xff, fo);
2657: fputc((file_size >> 16) & 0xff, fo);
2658: fputc((file_size >> 24) & 0xff, fo);
2659: fwrite(name, name_len, 1, fo);
2660:
2661: // store command file
2662: fseek(fs, 0, SEEK_SET);
2663: for(int i = 0; i < file_size; i++) {
2664: if((data = fgetc(fs)) != EOF) {
2665: fputc(data, fo);
2666: } else {
2667: // we should not reach here :-(
2668: fputc(0, fo);
2669: }
2670: }
2671:
2672: // store padding data and update pe header
1.1.1.29 root 2673: _IMAGE_SECTION_HEADER *newSectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * coffHeader->NumberOfSections);
2674: coffHeader->NumberOfSections++;
2675: memset(newSectionHeader, 0, IMAGE_SIZEOF_SECTION_HEADER);
2676: memcpy(newSectionHeader->Name, ".msdos", 6);
2677: newSectionHeader->VirtualAddress = dwVirtualAddress;
2678: newSectionHeader->PointerToRawData = dwEndOfFile;
2679: newSectionHeader->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE;
1.1.1.28 root 2680: newSectionHeader->SizeOfRawData = 14 + name_len + file_size;
2681: DWORD dwExtraRawBytes = newSectionHeader->SizeOfRawData % optionalHeader->FileAlignment;
2682: if(dwExtraRawBytes != 0) {
1.1.1.29 root 2683: static const char padding[] = "PADDINGXXPADDING";
1.1.1.28 root 2684: DWORD dwRemain = optionalHeader->FileAlignment - dwExtraRawBytes;
2685: for(int i = 0; i < dwRemain; i++) {
1.1.1.29 root 2686: if(i < 2) {
2687: fputc(padding[i & 15], fo);
2688: } else {
2689: fputc(padding[(i - 2) & 15], fo);
2690: }
1.1.1.28 root 2691: }
2692: newSectionHeader->SizeOfRawData += dwRemain;
2693: }
2694: newSectionHeader->Misc.VirtualSize = newSectionHeader->SizeOfRawData;
2695:
2696: DWORD dwNewSectionSize = newSectionHeader->SizeOfRawData;
2697: DWORD dwExtraNewSectionBytes = dwNewSectionSize % optionalHeader->SectionAlignment;
2698: if(dwExtraNewSectionBytes != 0) {
2699: DWORD dwRemain = optionalHeader->SectionAlignment - dwExtraNewSectionBytes;
2700: dwNewSectionSize += dwRemain;
2701: }
2702: optionalHeader->SizeOfImage += dwNewSectionSize;
2703:
2704: fseek(fo, 0, SEEK_SET);
2705: fwrite(header, sizeof(header), 1, fo);
2706:
2707: fprintf(stderr, "'%s' is successfully created\n", new_exec_file);
2708: retval = EXIT_SUCCESS;
1.1.1.27 root 2709: }
2710: }
2711: if(fp != NULL) {
2712: fclose(fp);
2713: }
2714: if(fs != NULL) {
2715: fclose(fs);
2716: }
2717: if(fo != NULL) {
2718: fclose(fo);
2719: }
2720: }
2721: #ifdef _DEBUG
2722: _CrtDumpMemoryLeaks();
2723: #endif
2724: return(retval);
2725: }
1.1 root 2726:
1.1.1.14 root 2727: is_vista_or_later = is_greater_windows_version(6, 0, 0, 0);
2728:
1.1.1.23 root 2729: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 2730: CONSOLE_SCREEN_BUFFER_INFO csbi;
1.1.1.14 root 2731: CONSOLE_CURSOR_INFO ci;
1.1.1.23 root 2732:
1.1.1.28 root 2733: get_console_info_success = (GetConsoleScreenBufferInfo(hStdout, &csbi) != 0);
1.1.1.14 root 2734: GetConsoleCursorInfo(hStdout, &ci);
1.1.1.24 root 2735: GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwConsoleMode);
1.1 root 2736:
1.1.1.14 root 2737: for(int y = 0; y < SCR_BUF_WIDTH; y++) {
2738: for(int x = 0; x < SCR_BUF_HEIGHT; x++) {
2739: SCR_BUF(y,x).Char.AsciiChar = ' ';
2740: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 2741: }
2742: }
1.1.1.28 root 2743: if(get_console_info_success) {
1.1.1.12 root 2744: scr_width = csbi.dwSize.X;
1.1.1.14 root 2745: scr_height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
2746:
1.1.1.28 root 2747: // v-text shadow buffer size must be lesser than 0x7fd0
2748: if((scr_width > SCR_BUF_WIDTH) || (scr_height > SCR_BUF_HEIGHT) || (scr_width * scr_height * 2 > 0x7fd0) ||
1.1.1.14 root 2749: (buf_width != 0 && buf_width != scr_width) || (buf_height != 0 && buf_height != scr_height)) {
2750: scr_width = min(buf_width != 0 ? buf_width : scr_width, SCR_BUF_WIDTH);
2751: scr_height = min(buf_height != 0 ? buf_height : scr_height, SCR_BUF_HEIGHT);
1.1.1.28 root 2752: if(scr_width * scr_height * 2 > 0x7fd0) {
1.1.1.14 root 2753: scr_width = 80;
2754: scr_height = 25;
2755: }
1.1.1.28 root 2756: screen_size_changed = true;
1.1.1.14 root 2757: }
1.1.1.12 root 2758: } else {
2759: // for a proof (not a console)
2760: scr_width = 80;
2761: scr_height = 25;
2762: }
1.1.1.14 root 2763: scr_buf_size.X = scr_width;
2764: scr_buf_size.Y = scr_height;
2765: scr_buf_pos.X = scr_buf_pos.Y = 0;
2766: scr_top = csbi.srWindow.Top;
1.1 root 2767: cursor_moved = false;
2768:
1.1.1.25 root 2769: key_buf_char = new FIFO(256);
2770: key_buf_scan = new FIFO(256);
1.1 root 2771:
2772: hardware_init();
2773:
1.1.1.33! root 2774: #ifdef USE_DEBUGGER
! 2775: debugger_init();
! 2776: #endif
! 2777:
1.1.1.9 root 2778: if(msdos_init(argc - (arg_offset + 1), argv + (arg_offset + 1), envp, standard_env)) {
1.1 root 2779: retval = EXIT_FAILURE;
2780: } else {
1.1.1.27 root 2781: #if defined(_MSC_VER) && (_MSC_VER >= 1400)
1.1.1.14 root 2782: _set_invalid_parameter_handler((_invalid_parameter_handler)ignore_invalid_parameters);
2783: #endif
2784: SetConsoleCtrlHandler(ctrl_handler, TRUE);
2785:
1.1.1.28 root 2786: if(screen_size_changed) {
1.1.1.24 root 2787: change_console_size(scr_width, scr_height);
2788: }
1.1.1.8 root 2789: TIMECAPS caps;
2790: timeGetDevCaps(&caps, sizeof(TIMECAPS));
2791: timeBeginPeriod(caps.wPeriodMin);
1.1.1.14 root 2792: #ifdef USE_THREAD
2793: InitializeCriticalSection(&vram_crit_sect);
2794: CloseHandle(CreateThread(NULL, 4096, vram_thread, NULL, 0, NULL));
2795: #endif
1.1.1.33! root 2796: #ifdef USE_DEBUGGER
! 2797: CloseHandle(CreateThread(NULL, 0, debugger_thread, NULL, 0, NULL));
! 2798: // wait until telnet client starts and connects to me
! 2799: if(_access(debugger_get_ttermpro_path(), 0) == 0 ||
! 2800: _access(debugger_get_ttermpro_x86_path(), 0) == 0 ||
! 2801: _access(debugger_get_putty_path(), 0) == 0 ||
! 2802: _access(debugger_get_putty_x86_path(), 0) == 0 ||
! 2803: _access(debugger_get_telnet_path(), 0) == 0) {
! 2804: for(int i = 0; i < 100 && cli_socket == 0; i++) {
! 2805: Sleep(100);
! 2806: }
! 2807: }
! 2808: #endif
1.1 root 2809: hardware_run();
1.1.1.14 root 2810: #ifdef USE_THREAD
2811: vram_flush();
2812: DeleteCriticalSection(&vram_crit_sect);
2813: #endif
1.1.1.24 root 2814: timeEndPeriod(caps.wPeriodMin);
1.1.1.14 root 2815:
1.1.1.24 root 2816: // hStdin/hStdout (and all handles) will be closed in msdos_finish()...
1.1.1.28 root 2817: if(get_console_info_success) {
1.1.1.23 root 2818: hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.12 root 2819: if(restore_console_on_exit) {
1.1.1.14 root 2820: // window can't be bigger than buffer,
2821: // buffer can't be smaller than window,
2822: // so make a tiny window,
2823: // set the required buffer,
2824: // then set the required window
2825: SMALL_RECT rect;
2826: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
2827: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.12 root 2828: SetConsoleScreenBufferSize(hStdout, csbi.dwSize);
1.1.1.14 root 2829: SET_RECT(rect, 0, 0, csbi.srWindow.Right - csbi.srWindow.Left, csbi.srWindow.Bottom - csbi.srWindow.Top);
1.1.1.12 root 2830: SetConsoleWindowInfo(hStdout, TRUE, &rect);
2831: }
1.1.1.14 root 2832: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
2833: SetConsoleCursorInfo(hStdout, &ci);
1.1.1.12 root 2834: }
1.1.1.24 root 2835: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode);
2836:
1.1 root 2837: msdos_finish();
1.1.1.14 root 2838:
2839: SetConsoleCtrlHandler(ctrl_handler, FALSE);
1.1 root 2840: }
2841:
1.1.1.10 root 2842: hardware_finish();
2843:
1.1.1.28 root 2844: if(key_buf_char != NULL) {
2845: key_buf_char->release();
2846: delete key_buf_char;
2847: key_buf_char = NULL;
2848: }
2849: if(key_buf_scan != NULL) {
2850: key_buf_scan->release();
2851: delete key_buf_scan;
2852: key_buf_scan = NULL;
2853: }
2854: if(temp_file_created) {
2855: DeleteFile(temp_file_path);
2856: temp_file_created = false;
2857: }
2858: // if(argv == dummy_argv) {
2859: // if(!is_started_from_command_prompt()) {
2860: // fprintf(stderr, "\nHit any key to quit...");
2861: // while(!_kbhit()) {
2862: // Sleep(10);
2863: // }
2864: // }
2865: // }
1.1.1.20 root 2866: #ifdef _DEBUG
2867: _CrtDumpMemoryLeaks();
2868: #endif
1.1 root 2869: return(retval);
2870: }
2871:
1.1.1.20 root 2872: /* ----------------------------------------------------------------------------
2873: console
2874: ---------------------------------------------------------------------------- */
2875:
1.1.1.14 root 2876: void change_console_size(int width, int height)
1.1.1.12 root 2877: {
1.1.1.23 root 2878: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.12 root 2879: CONSOLE_SCREEN_BUFFER_INFO csbi;
2880: SMALL_RECT rect;
2881: COORD co;
2882:
2883: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 2884: if(csbi.srWindow.Top != 0 || csbi.dwCursorPosition.Y > height - 1) {
2885: if(csbi.srWindow.Right - csbi.srWindow.Left + 1 == width && csbi.srWindow.Bottom - csbi.srWindow.Top + 1 == height) {
2886: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &csbi.srWindow);
2887: SET_RECT(rect, 0, 0, width - 1, height - 1);
2888: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2889: } else if(csbi.dwCursorPosition.Y > height - 1) {
2890: SET_RECT(rect, 0, csbi.dwCursorPosition.Y - (height - 1), width - 1, csbi.dwCursorPosition.Y);
2891: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2892: SET_RECT(rect, 0, 0, width - 1, height - 1);
2893: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1.1.12 root 2894: }
2895: }
1.1.1.14 root 2896: if(csbi.dwCursorPosition.Y > height - 1) {
1.1.1.12 root 2897: co.X = csbi.dwCursorPosition.X;
1.1.1.14 root 2898: co.Y = min(height - 1, csbi.dwCursorPosition.Y - csbi.srWindow.Top);
1.1.1.12 root 2899: SetConsoleCursorPosition(hStdout, co);
2900: cursor_moved = true;
2901: }
1.1.1.14 root 2902:
2903: // window can't be bigger than buffer,
2904: // buffer can't be smaller than window,
2905: // so make a tiny window,
2906: // set the required buffer,
2907: // then set the required window
2908: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
1.1.1.12 root 2909: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.14 root 2910: co.X = width;
2911: co.Y = height;
1.1.1.12 root 2912: SetConsoleScreenBufferSize(hStdout, co);
1.1.1.14 root 2913: SET_RECT(rect, 0, 0, width - 1, height - 1);
2914: SetConsoleWindowInfo(hStdout, TRUE, &rect);
2915:
2916: scr_width = scr_buf_size.X = width;
2917: scr_height = scr_buf_size.Y = height;
2918: scr_top = 0;
2919:
2920: clear_scr_buffer(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
2921:
2922: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.15 root 2923: text_vram_end_address = text_vram_top_address + regen;
2924: shadow_buffer_end_address = shadow_buffer_top_address + regen;
2925:
1.1.1.14 root 2926: if(regen > 0x4000) {
2927: regen = 0x8000;
2928: vram_pages = 1;
2929: } else if(regen > 0x2000) {
2930: regen = 0x4000;
2931: vram_pages = 2;
2932: } else if(regen > 0x1000) {
2933: regen = 0x2000;
2934: vram_pages = 4;
2935: } else {
2936: regen = 0x1000;
2937: vram_pages = 8;
2938: }
1.1.1.15 root 2939: *(UINT16 *)(mem + 0x44a) = scr_width;
2940: *(UINT16 *)(mem + 0x44c) = regen;
2941: *(UINT8 *)(mem + 0x484) = scr_height - 1;
2942:
1.1.1.24 root 2943: mouse.min_position.x = 0;
2944: mouse.min_position.y = 0;
2945: mouse.max_position.x = 8 * scr_width - 1;
2946: mouse.max_position.y = 8 * scr_height - 1;
2947:
1.1.1.15 root 2948: restore_console_on_exit = true;
1.1.1.14 root 2949: }
2950:
2951: void clear_scr_buffer(WORD attr)
2952: {
2953: for(int y = 0; y < scr_height; y++) {
2954: for(int x = 0; x < scr_width; x++) {
2955: SCR_BUF(y,x).Char.AsciiChar = ' ';
2956: SCR_BUF(y,x).Attributes = attr;
2957: }
2958: }
1.1.1.12 root 2959: }
2960:
1.1.1.24 root 2961: bool update_console_input()
1.1 root 2962: {
1.1.1.23 root 2963: HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
1.1.1.8 root 2964: DWORD dwNumberOfEvents = 0;
1.1 root 2965: DWORD dwRead;
2966: INPUT_RECORD ir[16];
1.1.1.24 root 2967: CONSOLE_SCREEN_BUFFER_INFO csbi = {0};
2968: bool result = false;
1.1 root 2969:
1.1.1.8 root 2970: if(GetNumberOfConsoleInputEvents(hStdin, &dwNumberOfEvents) && dwNumberOfEvents != 0) {
2971: if(ReadConsoleInputA(hStdin, ir, 16, &dwRead)) {
2972: for(int i = 0; i < dwRead; i++) {
1.1.1.24 root 2973: if(ir[i].EventType & MOUSE_EVENT) {
2974: if(mouse.active) {
2975: if(ir[i].Event.MouseEvent.dwEventFlags == 0) {
2976: for(int i = 0; i < MAX_MOUSE_BUTTONS; i++) {
2977: static const DWORD bits[] = {
2978: FROM_LEFT_1ST_BUTTON_PRESSED, // left
2979: RIGHTMOST_BUTTON_PRESSED, // right
2980: FROM_LEFT_2ND_BUTTON_PRESSED, // middle
1.1.1.14 root 2981: };
1.1.1.24 root 2982: bool prev_status = mouse.buttons[i].status;
2983: mouse.buttons[i].status = ((ir[i].Event.MouseEvent.dwButtonState & bits[i]) != 0);
2984:
2985: if(!prev_status && mouse.buttons[i].status) {
2986: mouse.buttons[i].pressed_times++;
2987: mouse.buttons[i].pressed_position.x = mouse.position.x;
2988: mouse.buttons[i].pressed_position.y = mouse.position.y;
2989: mouse.status |= 2 << (i * 2);
2990: } else if(prev_status && !mouse.buttons[i].status) {
2991: mouse.buttons[i].released_times++;
2992: mouse.buttons[i].released_position.x = mouse.position.x;
2993: mouse.buttons[i].released_position.y = mouse.position.y;
2994: mouse.status |= 4 << (i * 2);
2995: }
1.1.1.14 root 2996: }
1.1.1.24 root 2997: } else if(ir[i].Event.MouseEvent.dwEventFlags & MOUSE_MOVED) {
2998: // NOTE: if restore_console_on_exit, console is not scrolled
2999: if(!restore_console_on_exit && csbi.srWindow.Bottom == 0) {
3000: GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
1.1.1.14 root 3001: }
1.1.1.28 root 3002: // FIXME: character size is always 8x8 ???
3003: int x = 3 + 8 * (ir[i].Event.MouseEvent.dwMousePosition.X);
3004: int y = 4 + 8 * (ir[i].Event.MouseEvent.dwMousePosition.Y - csbi.srWindow.Top);
1.1.1.24 root 3005: if(mouse.position.x != x || mouse.position.y != y) {
3006: mouse.position.x = x;
3007: mouse.position.y = y;
3008: mouse.status |= 1;
1.1.1.14 root 3009: }
3010: }
3011: }
1.1.1.24 root 3012: } else if(ir[i].EventType & KEY_EVENT) {
1.1.1.33! root 3013: // update keyboard flags in bios data area
! 3014: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
! 3015: mem[0x417] |= 0x04;
! 3016: } else {
! 3017: mem[0x417] &= ~0x04;
! 3018: }
! 3019: if(ir[i].Event.KeyEvent.dwControlKeyState & LEFT_CTRL_PRESSED) {
! 3020: mem[0x418] |= 0x01;
! 3021: } else {
! 3022: mem[0x418] &= ~0x01;
! 3023: }
! 3024: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
! 3025: mem[0x417] |= 0x08;
! 3026: } else {
! 3027: mem[0x417] &= ~0x08;
! 3028: }
! 3029: if(ir[i].Event.KeyEvent.dwControlKeyState & LEFT_ALT_PRESSED) {
! 3030: mem[0x418] |= 0x02;
! 3031: } else {
! 3032: mem[0x418] &= ~0x02;
! 3033: }
! 3034: if(ir[i].Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
! 3035: if(!(mem[0x417] & 0x03)) {
! 3036: mem[0x417] |= 0x02; // left shift
! 3037: }
! 3038: } else {
! 3039: mem[0x417] &= ~0x03;
! 3040: }
! 3041:
1.1.1.28 root 3042: // set scan code of last pressed/release key to kbd_data (in-port 60h)
1.1.1.24 root 3043: kbd_data = ir[i].Event.KeyEvent.wVirtualScanCode;
1.1.1.33! root 3044: kbd_status |= 1;
! 3045:
! 3046: // update dos key buffer
! 3047: UINT8 chr = ir[i].Event.KeyEvent.uChar.AsciiChar;
! 3048: UINT8 scn = ir[i].Event.KeyEvent.wVirtualScanCode & 0xff;
! 3049:
! 3050: if(ir[i].Event.KeyEvent.bKeyDown) {
1.1.1.28 root 3051: // make
1.1.1.24 root 3052: kbd_data &= 0x7f;
3053:
1.1.1.33! root 3054: if(chr == 0x00) {
1.1.1.24 root 3055: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
3056: if(scn >= 0x3b && scn <= 0x44) {
3057: scn += 0x68 - 0x3b; // F1 to F10
3058: } else if(scn == 0x57 || scn == 0x58) {
3059: scn += 0x8b - 0x57; // F11 & F12
3060: } else if(scn >= 0x47 && scn <= 0x53) {
3061: scn += 0x97 - 0x47; // edit/arrow clusters
3062: } else if(scn == 0x35) {
3063: scn = 0xa4; // keypad /
3064: }
3065: } else if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
3066: if(scn == 0x07) {
3067: chr = 0x1e; // Ctrl+^
3068: } else if(scn == 0x0c) {
3069: chr = 0x1f; // Ctrl+_
3070: } else if(scn >= 0x35 && scn <= 0x58) {
3071: static const UINT8 ctrl_map[] = {
3072: 0x95, // keypad /
3073: 0,
3074: 0x96, // keypad *
3075: 0, 0, 0,
3076: 0x5e, // F1
3077: 0x5f, // F2
3078: 0x60, // F3
3079: 0x61, // F4
3080: 0x62, // F5
3081: 0x63, // F6
3082: 0x64, // F7
3083: 0x65, // F8
3084: 0x66, // F9
3085: 0x67, // F10
3086: 0,
3087: 0,
3088: 0x77, // Home
3089: 0x8d, // Up
3090: 0x84, // PgUp
3091: 0x8e, // keypad -
3092: 0x73, // Left
3093: 0x8f, // keypad center
3094: 0x74, // Right
3095: 0x90, // keyapd +
3096: 0x75, // End
3097: 0x91, // Down
3098: 0x76, // PgDn
3099: 0x92, // Insert
3100: 0x93, // Delete
3101: 0, 0, 0,
3102: 0x89, // F11
3103: 0x8a, // F12
3104: };
3105: scn = ctrl_map[scn - 0x35];
3106: }
3107: } else if(ir[i].Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
3108: if(scn >= 0x3b && scn <= 0x44) {
3109: scn += 0x54 - 0x3b; // F1 to F10
3110: } else if(scn == 0x57 || scn == 0x58) {
3111: scn += 0x87 - 0x57; // F11 & F12
3112: }
3113: } else if(scn == 0x57 || scn == 0x58) {
3114: scn += 0x85 - 0x57;
3115: }
3116: // ignore shift, ctrl, alt, win and menu keys
3117: if(scn != 0x1d && scn != 0x2a && scn != 0x36 && scn != 0x38 && (scn < 0x5b || scn > 0x5e)) {
1.1.1.32 root 3118: if(key_buf_char != NULL && key_buf_scan != NULL) {
3119: if(chr == 0) {
3120: key_buf_char->write(0x00);
3121: key_buf_scan->write(ir[i].Event.KeyEvent.dwControlKeyState & ENHANCED_KEY ? 0xe0 : 0x00);
3122: }
3123: key_buf_char->write(chr);
3124: key_buf_scan->write(scn);
1.1.1.24 root 3125: }
3126: }
3127: } else {
3128: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
3129: chr = 0;
3130: if(scn >= 0x02 && scn <= 0x0e) {
3131: scn += 0x78 - 0x02; // 1 to 0 - =
3132: }
3133: }
1.1.1.32 root 3134: if(key_buf_char != NULL && key_buf_scan != NULL) {
3135: key_buf_char->write(chr);
3136: key_buf_scan->write(scn);
3137: }
1.1.1.24 root 3138: }
1.1.1.33! root 3139: } else if(chr == 0x03 && (ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))) {
! 3140: // ctrl-break, ctrl-c
! 3141: if(scn == 0x46) {
! 3142: if(key_buf_char != NULL && key_buf_scan != NULL) {
! 3143: key_buf_char->write(0x00);
! 3144: key_buf_scan->write(0x00);
! 3145: }
! 3146: ctrl_break_pressed = true;
! 3147: mem[0x471] = 0x80;
! 3148: raise_int_1bh = true;
! 3149: } else {
! 3150: if(key_buf_char != NULL && key_buf_scan != NULL) {
! 3151: key_buf_char->write(chr);
! 3152: key_buf_scan->write(scn);
! 3153: }
! 3154: ctrl_c_pressed = (scn == 0x2e);
! 3155: }
! 3156: } else {
! 3157: // break
! 3158: kbd_data |= 0x80;
1.1 root 3159: }
1.1.1.24 root 3160: result = key_changed = true;
1.1 root 3161: }
3162: }
3163: }
3164: }
1.1.1.24 root 3165: return(result);
1.1.1.8 root 3166: }
3167:
1.1.1.14 root 3168: bool update_key_buffer()
1.1.1.8 root 3169: {
1.1.1.32 root 3170: return(update_console_input() || (key_buf_char != NULL && key_buf_char->count() != 0));
1.1.1.8 root 3171: }
3172:
1.1.1.20 root 3173: /* ----------------------------------------------------------------------------
3174: MS-DOS virtual machine
3175: ---------------------------------------------------------------------------- */
3176:
1.1.1.32 root 3177: static const struct {
1.1.1.33! root 3178: char *name;
! 3179: DWORD lcid;
! 3180: char *std;
! 3181: char *dlt;
! 3182: } tz_table[] = {
! 3183: // https://science.ksc.nasa.gov/software/winvn/userguide/3_1_4.htm
! 3184: // 0 GMT Greenwich Mean Time GMT0
! 3185: {"GMT Standard Time", 0x0809, "GMT", "BST"}, // (UTC+00:00) GB London (en-gb)
! 3186: {"GMT Standard Time", 0x1809, "GMT", "IST"}, // (UTC+00:00) IE Dublin (en-ie)
! 3187: {"GMT Standard Time", 0x0000, "WET", "WES"}, // (UTC+00:00) PT Lisbon
! 3188: {"Greenwich Standard Time", 0x0000, "GMT", "GST"}, // (UTC+00:00) IS Reykjavik
! 3189: // 2 FST FDT Fernando De Noronha Std FST2FDT
! 3190: {"Mid-Atlantic Standard Time", 0x0416, "FST", "FDT"}, // (UTC-02:00) BR Noronha (pt-br)
! 3191: {"UTC-02", 0x0416, "FST", "FDT"}, // (UTC-02:00) BR Noronha (pt-br)
! 3192: // 3 BST Brazil Standard Time BST3
! 3193: {"Bahia Standard Time", 0x0000, "BST", "BDT"}, // (UTC-03:00) BR Bahia
! 3194: {"SA Eastern Standard Time", 0x0000, "BST", "BDT"}, // (UTC-03:00) BR Fortaleza
! 3195: {"Tocantins Standard Time", 0x0000, "BST", "BDT"}, // (UTC-03:00) BR Palmas
! 3196: // 3 EST EDT Eastern Standard (Brazil) EST3EDT
! 3197: {"E. South America Standard Time", 0x0000, "EST", "EDT"}, // (UTC-03:00) BR Sao Paulo
! 3198: // 3 GST Greenland Standard Time GST3
! 3199: {"Greenland Standard Time", 0x0000, "GST", "GDT"}, // (UTC-03:00) GL Godthab
! 3200: // 3:30 NST NDT Newfoundland Standard Time NST3:30NDT
! 3201: {"Newfoundland Standard Time", 0x0000, "NST", "NDT"}, // (UTC-03:30) CA St.Johns
! 3202: // 4 AST ADT Atlantic Standard Time AST4ADT
! 3203: {"Atlantic Standard Time", 0x0000, "AST", "ADT"}, // (UTC-04:00) CA Halifax
! 3204: // 4 WST WDT Western Standard (Brazil) WST4WDT
! 3205: {"Central Brazilian Standard Time", 0x0000, "WST", "WDT"}, // (UTC-04:00) BR Cuiaba
! 3206: {"SA Western Standard Time", 0x0000, "WST", "WDT"}, // (UTC-04:00) BR Manaus
! 3207: // 5 EST EDT Eastern Standard Time EST5EDT
! 3208: {"Eastern Standard Time", 0x0000, "EST", "EDT"}, // (UTC-05:00) US New York
! 3209: {"Eastern Standard Time (Mexico)", 0x0000, "EST", "EDT"}, // (UTC-05:00) MX Cancun
! 3210: {"US Eastern Standard Time", 0x0000, "EST", "EDT"}, // (UTC-05:00) US Indianapolis
! 3211: // 5 CST CDT Chile Standard Time CST5CDT
! 3212: {"Pacific SA Standard Time", 0x0000, "CST", "CDT"}, // (UTC-04:00) CL Santiago
! 3213: // 5 AST ADT Acre Standard Time AST5ADT
! 3214: {"SA Pacific Standard Time", 0x0000, "AST", "ADT"}, // (UTC-05:00) BR Rio Branco
! 3215: // 5 CST CDT Cuba Standard Time CST5CDT
! 3216: {"Cuba Standard Time", 0x0000, "CST", "CDT"}, // (UTC-05:00) CU Havana
! 3217: // 6 CST CDT Central Standard Time CST6CDT
! 3218: {"Canada Central Standard Time", 0x0000, "CST", "CDT"}, // (UTC-06:00) CA Regina
! 3219: {"Central Standard Time", 0x0000, "CST", "CDT"}, // (UTC-06:00) US Chicago
! 3220: {"Central Standard Time (Mexico)", 0x0000, "CST", "CDT"}, // (UTC-06:00) MX Mexico City
! 3221: // 6 EST EDT Easter Island Standard EST6EDT
! 3222: {"Easter Island Standard Time", 0x0000, "EST", "EDT"}, // (UTC-06:00) CL Easter
! 3223: // 7 MST MDT Mountain Standard Time MST7MDT
! 3224: {"Mountain Standard Time", 0x0000, "MST", "MDT"}, // (UTC-07:00) US Denver
! 3225: {"Mountain Standard Time (Mexico)", 0x0000, "MST", "MDT"}, // (UTC-07:00) MX Chihuahua
! 3226: {"US Mountain Standard Time", 0x0000, "MST", "MDT"}, // (UTC-07:00) US Phoenix
! 3227: // 8 PST PDT Pacific Standard Time PST8PDT
! 3228: {"Pacific Standard Time", 0x0000, "PST", "PDT"}, // (UTC-08:00) US Los Angeles
! 3229: {"Pacific Standard Time (Mexico)", 0x0000, "PST", "PDT"}, // (UTC-08:00) MX Tijuana
! 3230: // 9 AKS AKD Alaska Standard Time AKS9AKD
! 3231: // 9 YST YDT Yukon Standard Time YST9YST
! 3232: {"Alaskan Standard Time", 0x0000, "AKS", "AKD"}, // (UTC-09:00) US Anchorage
! 3233: // 10 HST HDT Hawaii Standard Time HST10HDT
! 3234: {"Aleutian Standard Time", 0x0000, "HST", "HDT"}, // (UTC-10:00) US Aleutian
! 3235: {"Hawaiian Standard Time", 0x0000, "HST", "HDT"}, // (UTC-10:00) US Honolulu
! 3236: // 11 SST Samoa Standard Time SST11
! 3237: {"Samoa Standard Time", 0x0000, "SST", "SDT"}, // (UTC-11:00) US Samoa
! 3238: // -12 NZS NZD New Zealand Standard Time NZS-12NZD
! 3239: {"New Zealand Standard Time", 0x0000, "NZS", "NZD"}, // (UTC+12:00) NZ Auckland
! 3240: // -10 GST Guam Standard Time GST-10
! 3241: {"West Pacific Standard Time", 0x0000, "GST", "GDT"}, // (UTC+10:00) GU Guam
! 3242: // -10 EAS EAD Eastern Australian Standard EAS-10EAD
! 3243: {"AUS Eastern Standard Time", 0x0000, "EAS", "EAD"}, // (UTC+10:00) AU Sydney
! 3244: {"E. Australia Standard Time", 0x0000, "EAS", "EAD"}, // (UTC+10:00) AU Brisbane
! 3245: {"Tasmania Standard Time", 0x0000, "EAS", "EAD"}, // (UTC+10:00) AU Hobart
! 3246: // -9:30 CAS CAD Central Australian Standard CAS-9:30CAD
! 3247: {"AUS Central Standard Time", 0x0000, "CAS", "CAD"}, // (UTC+09:30) AU Darwin
! 3248: {"Cen. Australia Standard Time", 0x0000, "CAS", "CAD"}, // (UTC+09:30) AU Adelaide
! 3249: // -9 JST Japan Standard Time JST-9
! 3250: {"Tokyo Standard Time", 0x0000, "JST", "JDT"}, // (UTC+09:00) JP Tokyo
! 3251: // -9 KST KDT Korean Standard Time KST-9KDT
! 3252: {"Korea Standard Time", 0x0000, "KST", "KDT"}, // (UTC+09:00) KR Seoul
! 3253: {"North Korea Standard Time", 0x0000, "KST", "KDT"}, // (UTC+08:30) KP Pyongyang
! 3254: // -8 HKT Hong Kong Time HKT-8
! 3255: {"China Standard Time", 0x0C04, "HKT", "HKS"}, // (UTC+08:00) HK Hong Kong (zh-hk)
! 3256: // -8 CCT China Coast Time CCT-8
! 3257: {"China Standard Time", 0x0000, "CCT", "CDT"}, // (UTC+08:00) CN Shanghai
! 3258: {"Taipei Standard Time", 0x0000, "CCT", "CDT"}, // (UTC+08:00) TW Taipei
! 3259: // -8 SST Singapore Standard Time SST-8
! 3260: {"Singapore Standard Time", 0x0000, "SST", "SDT"}, // (UTC+08:00) SG Singapore
! 3261: // -8 WAS WAD Western Australian Standard WAS-8WAD
! 3262: {"Aus Central W. Standard Time", 0x0000, "WAS", "WAD"}, // (UTC+08:45) AU Eucla
! 3263: {"W. Australia Standard Time", 0x0000, "WAS", "WAD"}, // (UTC+08:00) AU Perth
! 3264: // -7:30 JT Java Standard Time JST-7:30
! 3265: // -7 NST North Sumatra Time NST-7
! 3266: {"SE Asia Standard Time", 0x0000, "NST", "NDT"}, // (UTC+07:00) ID Jakarta
! 3267: // -5:30 IST Indian Standard Time IST-5:30
! 3268: {"India Standard Time", 0x0000, "IST", "IDT"}, // (UTC+05:30) IN Calcutta
! 3269: // -3:30 IST IDT Iran Standard Time IST-3:30IDT
! 3270: {"Iran Standard Time", 0x0000, "IST", "IDT"}, // (UTC+03:30) IR Tehran
! 3271: // -3 MSK MSD Moscow Winter Time MSK-3MSD
! 3272: {"Belarus Standard Time", 0x0000, "MSK", "MSD"}, // (UTC+03:00) BY Minsk
! 3273: {"Russian Standard Time", 0x0000, "MSK", "MSD"}, // (UTC+03:00) RU Moscow
! 3274: // -2 EET Eastern Europe Time EET-2
! 3275: {"E. Europe Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) MD Chisinau
! 3276: {"FLE Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) UA Kiev
! 3277: {"GTB Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) RO Bucharest
! 3278: {"Kaliningrad Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) RU Kaliningrad
! 3279: // -2 IST IDT Israel Standard Time IST-2IDT
! 3280: {"Israel Standard Time", 0x0000, "IST", "IDT"}, // (UTC+02:00) IL Jerusalem
! 3281: // -1 MEZ MES Middle European Time MEZ-1MES
! 3282: // -1 SWT SST Swedish Winter Time SWT-1SST
! 3283: // -1 FWT FST French Winter Time FWT-1FST
! 3284: // -1 CET CES Central European Time CET-1CES
! 3285: {"Central Europe Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) HU Budapest
! 3286: {"Central European Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) PL Warsaw
! 3287: {"Romance Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) FR Paris
! 3288: {"W. Europe Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) DE Berlin
! 3289: // -1 WAT West African Time WAT-1
! 3290: {"Namibia Standard Time", 0x0000, "WAT", "WAS"}, // (UTC+01:00) NA Windhoek
! 3291: {"W. Central Africa Standard Time", 0x0000, "WAT", "WAS"}, // (UTC+01:00) NG Lagos
! 3292: // 0 UTC Universal Coordinated Time UTC0
! 3293: {"UTC", 0x0000, "UTC", "" }, // (UTC+00:00) GMT+0
! 3294: {"UTC-02", 0x0000, "UTC", "" }, // (UTC-02:00) GMT+2
! 3295: {"UTC-08", 0x0000, "UTC", "" }, // (UTC-08:00) GMT+8
! 3296: {"UTC-09", 0x0000, "UTC", "" }, // (UTC-09:00) GMT+9
! 3297: {"UTC-11", 0x0000, "UTC", "" }, // (UTC-11:00) GMT+11
! 3298: {"UTC+12", 0x0000, "UTC", "" }, // (UTC+12:00) GMT-12
! 3299: };
! 3300:
! 3301: static const struct {
1.1.1.32 root 3302: UINT16 code;
3303: char *message_english;
3304: char *message_japanese;
3305: } standard_error_table[] = {
3306: {0x01, "Invalid function", "�����ȃt�@���N�V�����ł�."},
3307: {0x02, "File not found", "�t�@�C����������܂���."},
3308: {0x03, "Path not found", "�p�X��������܂���."},
3309: {0x04, "Too many open files", "�J����Ă���t�@�C�����������܂�."},
3310: {0x05, "Access denied", "�A�N�Z�X�͋��ۂ���܂���."},
3311: {0x06, "Invalid handle", "�����ȃn���h���ł�."},
3312: {0x07, "Memory control blocks destroyed", "����������u���b�N���j������܂���."},
3313: {0x08, "Insufficient memory", "������������܂���."},
3314: {0x09, "Invalid memory block address", "�����ȃ������u���b�N�̃A�h���X�ł�."},
3315: {0x0A, "Invalid Environment", "�����Ȋ��ł�."},
3316: {0x0B, "Invalid format", "�����ȃt�H�[�}�b�g�ł�."},
3317: {0x0C, "Invalid function parameter", "�����ȃt�@���N�V�����p�����[�^�ł�."},
3318: {0x0D, "Invalid data", "�����ȃf�[�^�ł�."},
3319: {0x0F, "Invalid drive specification", "�����ȃh���C�u�̎w��ł�."},
3320: {0x10, "Attempt to remove current directory", "���݂̃f�B���N�g�����폜���悤�Ƃ��܂���."},
3321: {0x11, "Not same device", "�����f�o�C�X�ł͂���܂���."},
3322: {0x12, "No more files", "�t�@�C���͂���ȏ゠��܂���."},
3323: {0x13, "Write protect error", "�������ݕی�G���[�ł�."},
3324: {0x14, "Invalid unit", "�����ȃ��j�b�g�ł�."},
3325: {0x15, "Not ready", "�������ł��Ă��܂���."},
3326: {0x16, "Invalid device request", "�����ȃf�o�C�X�v���ł�."},
3327: {0x17, "Data error", "�f�[�^�G���[�ł�."},
3328: {0x18, "Invalid device request parameters", "�����ȃf�o�C�X�v���̃p�����[�^�ł�."},
3329: {0x19, "Seek error", "�V�[�N�G���[�ł�."},
3330: {0x1A, "Invalid media type", "�����ȃ��f�B�A�̎�ނł�."},
3331: {0x1B, "Sector not found", "�Z�N�^��������܂���."},
3332: {0x1C, "Printer out of paper error", "�v�����^�̗p��������܂���."},
3333: {0x1D, "Write fault error", "�������݃G���[�ł�."},
3334: {0x1E, "Read fault error", "�ǂݎ��G���[�ł�."},
3335: {0x1F, "General failure", "�G���[�ł�."},
3336: {0x20, "Sharing violation", "���L�ᔽ�ł�."},
3337: {0x21, "Lock violation", "���b�N�ᔽ�ł�."},
3338: {0x22, "Invalid disk change", "�����ȃf�B�X�N�̌����ł�."},
3339: {0x23, "FCB unavailable", "FCB �͎g���܂���."},
3340: {0x24, "System resource exhausted", "�V�X�e�����\�[�X�͂����g���܂���."},
3341: {0x25, "Code page mismatch", "�R�[�h �y�[�W����v���܂���."},
3342: {0x26, "Out of input", "���͂��I���܂���."},
3343: {0x27, "Insufficient disk space", "�f�B�X�N�̋̈悪����܂���."},
3344: /*
3345: {0x32, "Network request not supported", NULL},
3346: {0x33, "Remote computer not listening", NULL},
3347: {0x34, "Duplicate name on network", NULL},
3348: {0x35, "Network name not found", NULL},
3349: {0x36, "Network busy", NULL},
3350: {0x37, "Network device no longer exists", NULL},
3351: {0x38, "Network BIOS command limit exceeded", NULL},
3352: {0x39, "Network adapter hardware error", NULL},
3353: {0x3A, "Incorrect response from network", NULL},
3354: {0x3B, "Unexpected network error", NULL},
3355: {0x3C, "Incompatible remote adapter", NULL},
3356: {0x3D, "Print queue full", NULL},
3357: {0x3E, "Queue not full", NULL},
3358: {0x3F, "Not enough space to print file", NULL},
3359: {0x40, "Network name was deleted", NULL},
3360: {0x41, "Network: Access denied", NULL},
3361: {0x42, "Network device type incorrect", NULL},
3362: {0x43, "Network name not found", NULL},
3363: {0x44, "Network name limit exceeded", NULL},
3364: {0x45, "Network BIOS session limit exceeded", NULL},
3365: {0x46, "Temporarily paused", NULL},
3366: {0x47, "Network request not accepted", NULL},
3367: {0x48, "Network print/disk redirection paused", NULL},
3368: {0x49, "Network software not installed", NULL},
3369: {0x4A, "Unexpected adapter close", NULL},
3370: */
3371: {0x50, "File exists", "�t�@�C���͑��݂��܂�."},
1.1.1.33! root 3372: {0x52, "Cannot make directory entry", "�f�B���N�g���G���g�����쐬�ł��܂���."},
1.1.1.32 root 3373: {0x53, "Fail on INT 24", "INT 24 �Ŏ��s���܂���."},
3374: {0x54, "Too many redirections", "���_�C���N�g���������܂�."},
3375: {0x55, "Duplicate redirection", "���_�C���N�g���d�����Ă��܂�."},
3376: {0x56, "Invalid password", "�p�X���[�h���Ⴂ�܂�."},
3377: {0x57, "Invalid parameter", "�p�����[�^�̎w�肪�Ⴂ�܂�."},
3378: {0x58, "Network data fault", "�l�b�g���[�N�f�[�^�̃G���[�ł�."},
3379: {0x59, "Function not supported by network", "�t�@���N�V�����̓l�b�g���[�N�ŃT�|�[�g����Ă��܂���."},
3380: {0x5A, "Required system component not installe", "�K�v�ȃV�X�e�� �R���|�[�l���g���g�ݍ��܂�Ă��܂���."},
3381: /*
3382: {0x64, "Unknown error", "�s���ȃG���[�ł�."},
3383: {0x65, "Not ready", "�������ł��Ă��܂���."},
3384: {0x66, "EMS memory no longer valid", "EMS �������͂����L���ł͂���܂���."},
3385: {0x67, "CDROM not High Sierra or ISO-9660 format", "CDROM �� High Sierra �܂��� ISO-9660 �t�H�[�}�b�g�ł͂���܂���."},
3386: {0x68, "Door open", "���o�[���܂��Ă��܂���."
3387: */
3388: {0xB0, "Volume is not locked", "�{�����[�������b�N����Ă��܂���."},
3389: {0xB1, "Volume is locked in drive", "�{�����[�������b�N����Ă��܂�."},
3390: {0xB2, "Volume is not removable", "�{�����[���͎��O���ł��܂���."},
3391: {0xB4, "Lock count has been exceeded", "�{�����[��������ȏネ�b�N�ł��܂���."},
3392: {0xB5, "A valid eject request failed", "���o���Ɏ��s���܂���."},
3393: {-1 , "Unknown error", "�s���ȃG���[�ł�."},
3394: };
3395:
3396: static const struct {
3397: UINT16 code;
3398: char *message_english;
3399: char *message_japanese;
3400: } param_error_table[] = {
3401: {0x01, "Too many parameters", "�p�����[�^���������܂�."},
3402: {0x02, "Required parameter missing", "�p�����[�^������܂���."},
3403: {0x03, "Invalid switch", "�����ȃX�C�b�`�ł�."},
3404: {0x04, "Invalid keyword", "�����ȃL�[���[�h�ł�."},
3405: {0x06, "Parameter value not in allowed range", "�p�����[�^�̒l���͈͂��Ă��܂�."},
3406: {0x07, "Parameter value not allowed", "���̃p�����[�^�̒l�͎g���܂���."},
3407: {0x08, "Parameter value not allowed", "���̃p�����[�^�̒l�͎g���܂���."},
3408: {0x09, "Parameter format not correct", "�p�����[�^�̏������Ⴂ�܂�."},
3409: {0x0A, "Invalid parameter", "�����ȃp�����[�^�ł�."},
3410: {0x0B, "Invalid parameter combination", "�����ȃp�����[�^�̑g�ݍ��킹�ł�."},
3411: {-1 , "Unknown error", "�s���ȃG���[�ł�."},
3412: };
3413:
3414: static const struct {
3415: UINT16 code;
3416: char *message_english;
3417: char *message_japanese;
3418: } critical_error_table[] = {
3419: {0x00, "Write protect error", "�������ݕی�G���[�ł�."},
3420: {0x01, "Invalid unit", "�����ȃ��j�b�g�ł�."},
3421: {0x02, "Not ready", "�������ł��Ă��܂���."},
3422: {0x03, "Invalid device request", "�����ȃf�o�C�X�v���ł�."},
3423: {0x04, "Data error", "�f�[�^�G���[�ł�."},
3424: {0x05, "Invalid device request parameters", "�����ȃf�o�C�X�v���̃p�����[�^�ł�."},
3425: {0x06, "Seek error", "�V�[�N�G���[�ł�."},
3426: {0x07, "Invalid media type", "�����ȃ��f�B�A�̎�ނł�."},
3427: {0x08, "Sector not found", "�Z�N�^��������܂���."},
3428: {0x09, "Printer out of paper error", "�v�����^�̗p��������܂���."},
3429: {0x0A, "Write fault error", "�������݃G���[�ł�."},
3430: {0x0B, "Read fault error", "�ǂݎ��G���[�ł�."},
3431: {0x0C, "General failure", "�G���[�ł�."},
3432: {0x0D, "Sharing violation", "���L�ᔽ�ł�."},
3433: {0x0E, "Lock violation", "���b�N�ᔽ�ł�."},
3434: {0x0F, "Invalid disk change", "�����ȃf�B�X�N�̌����ł�."},
3435: {0x10, "FCB unavailable", "FCB �͎g���܂���."},
3436: {0x11, "System resource exhausted", "�V�X�e�����\�[�X�͂����g���܂���."},
3437: {0x12, "Code page mismatch", "�R�[�h �y�[�W����v���܂���."},
3438: {0x13, "Out of input", "���͂��I���܂���."},
3439: {0x14, "Insufficient disk space", "�f�B�X�N�̋̈悪����܂���."},
3440: {-1 , "Critical error", "�v���I�ȃG���[�ł�."},
3441: };
3442:
1.1.1.20 root 3443: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg);
3444: int msdos_psp_get_file_table(int fd, int psp_seg);
3445: void msdos_putch(UINT8 data);
3446:
1.1 root 3447: // process info
3448:
3449: process_t *msdos_process_info_create(UINT16 psp_seg)
3450: {
3451: for(int i = 0; i < MAX_PROCESS; i++) {
3452: if(process[i].psp == 0 || process[i].psp == psp_seg) {
3453: memset(&process[i], 0, sizeof(process_t));
3454: process[i].psp = psp_seg;
3455: return(&process[i]);
3456: }
3457: }
3458: fatalerror("too many processes\n");
3459: return(NULL);
3460: }
3461:
1.1.1.33! root 3462: process_t *msdos_process_info_get(UINT16 psp_seg, bool show_error)
1.1 root 3463: {
3464: for(int i = 0; i < MAX_PROCESS; i++) {
3465: if(process[i].psp == psp_seg) {
3466: return(&process[i]);
3467: }
3468: }
1.1.1.33! root 3469: if(show_error) {
! 3470: fatalerror("invalid psp address\n");
! 3471: }
1.1 root 3472: return(NULL);
3473: }
3474:
1.1.1.33! root 3475: process_t *msdos_process_info_get(UINT16 psp_seg)
! 3476: {
! 3477: return(msdos_process_info_get(psp_seg, true));
! 3478: }
! 3479:
1.1.1.23 root 3480: void msdos_sda_update(int psp_seg)
3481: {
3482: sda_t *sda = (sda_t *)(mem + SDA_TOP);
3483:
3484: for(int i = 0; i < MAX_PROCESS; i++) {
3485: if(process[i].psp == psp_seg) {
3486: sda->switchar = process[i].switchar;
3487: sda->current_dta.w.l = process[i].dta.w.l;
3488: sda->current_dta.w.h = process[i].dta.w.h;
3489: sda->current_psp = process[i].psp;
3490: break;
3491: }
3492: }
3493: sda->malloc_strategy = malloc_strategy;
3494: sda->return_code = retval;
3495: sda->current_drive = _getdrive();
3496: }
3497:
1.1.1.13 root 3498: // dta info
3499:
3500: void msdos_dta_info_init()
3501: {
1.1.1.14 root 3502: for(int i = 0; i < MAX_DTAINFO; i++) {
1.1.1.13 root 3503: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
3504: }
3505: }
3506:
3507: dtainfo_t *msdos_dta_info_get(UINT16 psp_seg, UINT32 dta_laddr)
3508: {
3509: dtainfo_t *free_dta = NULL;
1.1.1.14 root 3510: for(int i = 0; i < MAX_DTAINFO; i++) {
3511: if(dtalist[i].find_handle == INVALID_HANDLE_VALUE) {
3512: if(free_dta == NULL) {
1.1.1.13 root 3513: free_dta = &dtalist[i];
3514: }
1.1.1.14 root 3515: } else if(dta_laddr < LFN_DTA_LADDR && dtalist[i].dta == dta_laddr) {
1.1.1.13 root 3516: return(&dtalist[i]);
3517: }
3518: }
1.1.1.14 root 3519: if(free_dta) {
1.1.1.13 root 3520: free_dta->psp = psp_seg;
3521: free_dta->dta = dta_laddr;
3522: return(free_dta);
3523: }
3524: fatalerror("too many dta\n");
3525: return(NULL);
3526: }
3527:
3528: void msdos_dta_info_free(UINT16 psp_seg)
3529: {
1.1.1.14 root 3530: for(int i = 0; i < MAX_DTAINFO; i++) {
3531: if(dtalist[i].psp == psp_seg && dtalist[i].find_handle != INVALID_HANDLE_VALUE) {
1.1.1.13 root 3532: FindClose(dtalist[i].find_handle);
3533: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
3534: }
3535: }
3536: }
3537:
1.1 root 3538: void msdos_cds_update(int drv)
3539: {
3540: cds_t *cds = (cds_t *)(mem + CDS_TOP);
3541:
3542: memset(mem + CDS_TOP, 0, CDS_SIZE);
3543: sprintf(cds->path_name, "%c:\\", 'A' + drv);
3544: cds->drive_attrib = 0x4000; // physical drive
3545: cds->physical_drive_number = drv;
3546: }
3547:
1.1.1.17 root 3548: // nls information tables
3549:
3550: // uppercase table (func 6502h)
3551: void msdos_upper_table_update()
3552: {
3553: *(UINT16 *)(mem + UPPERTABLE_TOP) = 0x80;
1.1.1.22 root 3554: for(unsigned i = 0; i < 0x80; ++i) {
1.1.1.17 root 3555: UINT8 c[4];
1.1.1.33! root 3556: *(UINT32 *)c = 0; // reset internal conversion state
! 3557: CharUpperBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
1.1.1.17 root 3558: c[0] = 0x80 + i;
3559: DWORD rc = CharUpperBuffA((LPSTR)c, 1);
3560: mem[UPPERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
3561: }
3562: }
3563:
1.1.1.23 root 3564: // lowercase table (func 6503h)
3565: void msdos_lower_table_update()
3566: {
3567: *(UINT16 *)(mem + LOWERTABLE_TOP) = 0x80;
3568: for(unsigned i = 0; i < 0x80; ++i) {
3569: UINT8 c[4];
1.1.1.33! root 3570: *(UINT32 *)c = 0; // reset internal conversion state
! 3571: CharLowerBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
1.1.1.23 root 3572: c[0] = 0x80 + i;
3573: DWORD rc = CharLowerBuffA((LPSTR)c, 1);
3574: mem[LOWERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
3575: }
3576: }
3577:
1.1.1.17 root 3578: // filename uppercase table (func 6504h)
3579: void msdos_filename_upper_table_init()
3580: {
3581: // depended on (file)system, not on active codepage
3582: // temporary solution: just filling data
3583: *(UINT16 *)(mem + FILENAME_UPPERTABLE_TOP) = 0x80;
1.1.1.22 root 3584: for(unsigned i = 0; i < 0x80; ++i) {
1.1.1.17 root 3585: mem[FILENAME_UPPERTABLE_TOP + 2 + i] = 0x80 + i;
3586: }
3587: }
3588:
3589: // filaname terminator table (func 6505h)
3590: void msdos_filename_terminator_table_init()
3591: {
3592: const char illegal_chars[] = ".\"/\\[]:|<>+=;,"; // for standard MS-DOS fs.
3593: UINT8 *data = mem + FILENAME_TERMINATOR_TOP;
3594:
3595: data[2] = 1; // marker? (permissible character value)
3596: data[3] = 0x00; // 00h...FFh
3597: data[4] = 0xff;
3598: data[5] = 0; // marker? (excluded character)
3599: data[6] = 0x00; // 00h...20h
3600: data[7] = 0x20;
3601: data[8] = 2; // marker? (illegal characters for filename)
3602: data[9] = (UINT8)strlen(illegal_chars);
3603: memcpy(data + 10, illegal_chars, data[9]);
3604:
3605: // total length
3606: *(UINT16 *)data = (10 - 2) + data[9];
3607: }
3608:
3609: // collating table (func 6506h)
3610: void msdos_collating_table_update()
3611: {
3612: // temporary solution: just filling data
3613: *(UINT16 *)(mem + COLLATING_TABLE_TOP) = 0x100;
1.1.1.22 root 3614: for(unsigned i = 0; i < 256; ++i) {
1.1.1.17 root 3615: mem[COLLATING_TABLE_TOP + 2 + i] = i;
3616: }
3617: }
3618:
1.1 root 3619: // dbcs
3620:
3621: void msdos_dbcs_table_update()
3622: {
3623: UINT8 dbcs_data[DBCS_SIZE];
3624: memset(dbcs_data, 0, sizeof(dbcs_data));
3625:
3626: CPINFO info;
3627: GetCPInfo(active_code_page, &info);
3628:
3629: if(info.MaxCharSize != 1) {
3630: for(int i = 0;; i += 2) {
3631: UINT8 lo = info.LeadByte[i + 0];
3632: UINT8 hi = info.LeadByte[i + 1];
3633: dbcs_data[2 + i + 0] = lo;
3634: dbcs_data[2 + i + 1] = hi;
3635: if(lo == 0 && hi == 0) {
3636: dbcs_data[0] = i + 2;
3637: break;
3638: }
3639: }
3640: } else {
3641: dbcs_data[0] = 2; // ???
3642: }
3643: memcpy(mem + DBCS_TOP, dbcs_data, sizeof(dbcs_data));
3644: }
3645:
1.1.1.17 root 3646: void msdos_dbcs_table_finish()
3647: {
1.1.1.32 root 3648: if(system_code_page != _getmbcp()) {
1.1.1.17 root 3649: _setmbcp(system_code_page);
3650: }
1.1.1.32 root 3651: if(console_code_page != GetConsoleCP()) {
3652: SetConsoleCP(console_code_page);
3653: SetConsoleOutputCP(console_code_page);
3654: }
1.1.1.17 root 3655: }
3656:
3657: void msdos_nls_tables_init()
1.1 root 3658: {
1.1.1.32 root 3659: active_code_page = console_code_page = GetConsoleCP();
3660: system_code_page = _getmbcp();
3661:
3662: if(active_code_page != system_code_page) {
3663: if(_setmbcp(active_code_page) != 0) {
3664: active_code_page = system_code_page;
3665: }
3666: }
3667:
1.1.1.17 root 3668: msdos_upper_table_update();
1.1.1.23 root 3669: msdos_lower_table_update();
1.1.1.17 root 3670: msdos_filename_terminator_table_init();
3671: msdos_filename_upper_table_init();
3672: msdos_collating_table_update();
1.1 root 3673: msdos_dbcs_table_update();
3674: }
3675:
1.1.1.17 root 3676: void msdos_nls_tables_update()
1.1 root 3677: {
1.1.1.17 root 3678: msdos_dbcs_table_update();
3679: msdos_upper_table_update();
1.1.1.23 root 3680: msdos_lower_table_update();
3681: // msdos_collating_table_update();
1.1 root 3682: }
3683:
3684: int msdos_lead_byte_check(UINT8 code)
3685: {
3686: UINT8 *dbcs_table = mem + DBCS_TABLE;
3687:
3688: for(int i = 0;; i += 2) {
3689: UINT8 lo = dbcs_table[i + 0];
3690: UINT8 hi = dbcs_table[i + 1];
3691: if(lo == 0 && hi == 0) {
3692: break;
3693: }
3694: if(lo <= code && code <= hi) {
3695: return(1);
3696: }
3697: }
3698: return(0);
3699: }
3700:
1.1.1.20 root 3701: int msdos_ctrl_code_check(UINT8 code)
3702: {
1.1.1.22 root 3703: return (code >= 0x01 && code <= 0x1a && code != 0x07 && code != 0x08 && code != 0x09 && code != 0x0a && code != 0x0d);
1.1.1.20 root 3704: }
3705:
1.1 root 3706: // file control
3707:
1.1.1.14 root 3708: char *msdos_remove_double_quote(char *path)
3709: {
3710: static char tmp[MAX_PATH];
3711:
3712: memset(tmp, 0, sizeof(tmp));
3713: if(strlen(path) >= 2 && path[0] == '"' && path[strlen(path) - 1] == '"') {
3714: memcpy(tmp, path + 1, strlen(path) - 2);
3715: } else {
3716: strcpy(tmp, path);
3717: }
3718: return(tmp);
3719: }
3720:
1.1.1.32 root 3721: char *msdos_remove_end_separator(char *path)
3722: {
3723: static char tmp[MAX_PATH];
3724:
3725: strcpy(tmp, path);
3726: int len = strlen(tmp);
3727: if(len > 3 && tmp[len - 1] == '\\') {
3728: tmp[len - 1] = '\0';
3729: }
3730: return(tmp);
3731: }
3732:
1.1.1.14 root 3733: char *msdos_combine_path(char *dir, const char *file)
3734: {
3735: static char tmp[MAX_PATH];
3736: char *tmp_dir = msdos_remove_double_quote(dir);
3737:
3738: if(strlen(tmp_dir) == 0) {
3739: strcpy(tmp, file);
3740: } else if(tmp_dir[strlen(tmp_dir) - 1] == '\\') {
3741: sprintf(tmp, "%s%s", tmp_dir, file);
3742: } else {
3743: sprintf(tmp, "%s\\%s", tmp_dir, file);
3744: }
3745: return(tmp);
3746: }
3747:
1.1 root 3748: char *msdos_trimmed_path(char *path, int lfn)
3749: {
3750: static char tmp[MAX_PATH];
3751:
3752: if(lfn) {
3753: strcpy(tmp, path);
3754: } else {
3755: // remove space in the path
3756: char *src = path, *dst = tmp;
3757:
3758: while(*src != '\0') {
3759: if(msdos_lead_byte_check(*src)) {
3760: *dst++ = *src++;
3761: *dst++ = *src++;
3762: } else if(*src != ' ') {
3763: *dst++ = *src++;
3764: } else {
3765: src++; // skip space
3766: }
3767: }
3768: *dst = '\0';
3769: }
1.1.1.14 root 3770: if(_stricmp(tmp, "C:\\COMMAND.COM") == 0) {
3771: // redirect C:\COMMAND.COM to comspec_path
3772: strcpy(tmp, comspec_path);
3773: } else if(is_vista_or_later && _access(tmp, 0) != 0) {
3774: // redirect new files (without wildcards) in C:\ to %TEMP%, since C:\ is not usually writable
3775: static int root_drive_protected = -1;
3776: char temp[MAX_PATH], name[MAX_PATH], *name_temp = NULL;
3777: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
3778:
3779: if(GetFullPathName(tmp, MAX_PATH, temp, &name_temp) != 0 &&
3780: name_temp != NULL && strstr(name_temp, "?") == NULL && strstr(name_temp, "*") == NULL) {
3781: strcpy(name, name_temp);
3782: name_temp[0] = '\0';
3783:
3784: if((temp[0] == 'A' + dos_info->boot_drive - 1 || temp[0] == 'a' + dos_info->boot_drive - 1) &&
3785: (temp[1] == ':') && (temp[2] == '\\' || temp[2] == '/') && (temp[3] == '\0')) {
3786: if(root_drive_protected == -1) {
3787: FILE *fp = NULL;
3788:
3789: sprintf(temp, "%c:\\MS-DOS_Player.$$$", 'A' + dos_info->boot_drive - 1);
3790: root_drive_protected = 1;
3791: try {
3792: if((fp = fopen(temp, "w")) != NULL) {
3793: if(fprintf(fp, "TEST") == 4) {
3794: root_drive_protected = 0;
3795: }
3796: }
3797: } catch(...) {
3798: }
3799: if(fp != NULL) {
3800: fclose(fp);
3801: }
3802: if(_access(temp, 0) == 0) {
3803: remove(temp);
3804: }
3805: }
3806: if(root_drive_protected == 1) {
3807: if(GetEnvironmentVariable("TEMP", temp, MAX_PATH) != 0 ||
3808: GetEnvironmentVariable("TMP", temp, MAX_PATH) != 0) {
3809: strcpy(tmp, msdos_combine_path(temp, name));
3810: }
3811: }
3812: }
3813: }
3814: }
1.1 root 3815: return(tmp);
3816: }
3817:
1.1.1.28 root 3818: char *msdos_get_multiple_short_path(char *src)
3819: {
1.1.1.32 root 3820: // "LONGPATH\";"LONGPATH\";"LONGPATH\" to SHORTPATH;SHORTPATH;SHORTPATH
1.1.1.28 root 3821: static char env_path[ENV_SIZE];
3822: char tmp[ENV_SIZE], *token;
3823:
3824: memset(env_path, 0, sizeof(env_path));
3825: strcpy(tmp, src);
3826: token = my_strtok(tmp, ";");
3827:
3828: while(token != NULL) {
3829: if(token[0] != '\0') {
3830: char *path = msdos_remove_double_quote(token), short_path[MAX_PATH];
1.1.1.32 root 3831: if(path != NULL && strlen(path) != 0) {
3832: if(env_path[0] != '\0') {
3833: strcat(env_path, ";");
3834: }
1.1.1.28 root 3835: if(GetShortPathName(path, short_path, MAX_PATH) == 0) {
1.1.1.32 root 3836: strcat(env_path, msdos_remove_end_separator(path));
1.1.1.28 root 3837: } else {
3838: my_strupr(short_path);
1.1.1.32 root 3839: strcat(env_path, msdos_remove_end_separator(short_path));
1.1.1.28 root 3840: }
3841: }
3842: }
3843: token = my_strtok(NULL, ";");
3844: }
3845: return(env_path);
3846: }
3847:
1.1 root 3848: bool match(char *text, char *pattern)
3849: {
1.1.1.24 root 3850: // http://www.prefield.com/algorithm/string/wildcard.html
1.1.1.14 root 3851: switch(*pattern) {
1.1 root 3852: case '\0':
3853: return !*text;
3854: case '*':
1.1.1.14 root 3855: return match(text, pattern + 1) || (*text && match(text + 1, pattern));
1.1 root 3856: case '?':
3857: return *text && match(text + 1, pattern + 1);
3858: default:
3859: return (*text == *pattern) && match(text + 1, pattern + 1);
3860: }
3861: }
3862:
3863: bool msdos_match_volume_label(char *path, char *volume)
3864: {
3865: char *p;
3866:
1.1.1.14 root 3867: if(!*volume) {
3868: return false;
3869: } else if((p = my_strchr(path, ':')) != NULL) {
1.1 root 3870: return msdos_match_volume_label(p + 1, volume);
3871: } else if((p = my_strchr(path, '\\')) != NULL) {
3872: return msdos_match_volume_label(p + 1, volume);
3873: } else if((p = my_strchr(path, '.')) != NULL) {
1.1.1.14 root 3874: char tmp[MAX_PATH];
3875: sprintf(tmp, "%.*s%s", (int)(p - path), path, p + 1);
3876: return match(volume, tmp);
1.1 root 3877: } else {
3878: return match(volume, path);
3879: }
3880: }
3881:
3882: char *msdos_fcb_path(fcb_t *fcb)
3883: {
3884: static char tmp[MAX_PATH];
3885: char name[9], ext[4];
3886:
3887: memset(name, 0, sizeof(name));
3888: memcpy(name, fcb->file_name, 8);
3889: strcpy(name, msdos_trimmed_path(name, 0));
3890:
3891: memset(ext, 0, sizeof(ext));
3892: memcpy(ext, fcb->file_name + 8, 3);
3893: strcpy(ext, msdos_trimmed_path(ext, 0));
3894:
3895: if(name[0] == '\0' || strcmp(name, "????????") == 0) {
3896: strcpy(name, "*");
3897: }
3898: if(ext[0] == '\0') {
3899: strcpy(tmp, name);
3900: } else {
3901: if(strcmp(ext, "???") == 0) {
3902: strcpy(ext, "*");
3903: }
3904: sprintf(tmp, "%s.%s", name, ext);
3905: }
3906: return(tmp);
3907: }
3908:
3909: void msdos_set_fcb_path(fcb_t *fcb, char *path)
3910: {
3911: char *ext = my_strchr(path, '.');
3912:
3913: memset(fcb->file_name, 0x20, 8 + 3);
3914: if(ext != NULL && path[0] != '.') {
3915: *ext = '\0';
3916: memcpy(fcb->file_name + 8, ext + 1, strlen(ext + 1));
3917: }
3918: memcpy(fcb->file_name, path, strlen(path));
3919: }
3920:
3921: char *msdos_short_path(char *path)
3922: {
3923: static char tmp[MAX_PATH];
3924:
1.1.1.24 root 3925: if(GetShortPathName(path, tmp, MAX_PATH) == 0) {
3926: strcpy(tmp, path);
3927: }
1.1 root 3928: my_strupr(tmp);
3929: return(tmp);
3930: }
3931:
1.1.1.13 root 3932: char *msdos_short_name(WIN32_FIND_DATA *fd)
3933: {
3934: static char tmp[MAX_PATH];
3935:
1.1.1.14 root 3936: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 3937: strcpy(tmp, fd->cAlternateFileName);
3938: } else {
3939: strcpy(tmp, fd->cFileName);
3940: }
3941: my_strupr(tmp);
3942: return(tmp);
3943: }
3944:
1.1 root 3945: char *msdos_short_full_path(char *path)
3946: {
3947: static char tmp[MAX_PATH];
3948: char full[MAX_PATH], *name;
3949:
1.1.1.14 root 3950: // Full works with non-existent files, but Short does not
1.1 root 3951: GetFullPathName(path, MAX_PATH, full, &name);
1.1.1.14 root 3952: *tmp = '\0';
3953: if(GetShortPathName(full, tmp, MAX_PATH) == 0 && name > path) {
3954: name[-1] = '\0';
3955: DWORD len = GetShortPathName(full, tmp, MAX_PATH);
3956: if(len == 0) {
3957: strcpy(tmp, full);
3958: } else {
3959: tmp[len++] = '\\';
3960: strcpy(tmp + len, name);
3961: }
3962: }
1.1 root 3963: my_strupr(tmp);
3964: return(tmp);
3965: }
3966:
3967: char *msdos_short_full_dir(char *path)
3968: {
3969: static char tmp[MAX_PATH];
3970: char full[MAX_PATH], *name;
3971:
3972: GetFullPathName(path, MAX_PATH, full, &name);
3973: name[-1] = '\0';
1.1.1.24 root 3974: if(GetShortPathName(full, tmp, MAX_PATH) == 0) {
3975: strcpy(tmp, full);
3976: }
1.1 root 3977: my_strupr(tmp);
3978: return(tmp);
3979: }
3980:
3981: char *msdos_local_file_path(char *path, int lfn)
3982: {
3983: char *trimmed = msdos_trimmed_path(path, lfn);
1.1.1.14 root 3984: #if 0
3985: // I have forgotten the reason of this routine... :-(
1.1 root 3986: if(_access(trimmed, 0) != 0) {
3987: process_t *process = msdos_process_info_get(current_psp);
3988: static char tmp[MAX_PATH];
3989:
3990: sprintf(tmp, "%s\\%s", process->module_dir, trimmed);
3991: if(_access(tmp, 0) == 0) {
3992: return(tmp);
3993: }
3994: }
1.1.1.14 root 3995: #endif
1.1 root 3996: return(trimmed);
3997: }
3998:
1.1.1.29 root 3999: bool msdos_is_device_path(char *path)
1.1.1.11 root 4000: {
4001: char full[MAX_PATH], *name;
4002:
1.1.1.24 root 4003: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1.1.1.29 root 4004: if(_stricmp(full, "\\\\.\\AUX" ) == 0 ||
4005: _stricmp(full, "\\\\.\\CON" ) == 0 ||
4006: _stricmp(full, "\\\\.\\NUL" ) == 0 ||
4007: _stricmp(full, "\\\\.\\PRN" ) == 0 ||
4008: _stricmp(full, "\\\\.\\COM1") == 0 ||
4009: _stricmp(full, "\\\\.\\COM2") == 0 ||
4010: _stricmp(full, "\\\\.\\COM3") == 0 ||
4011: _stricmp(full, "\\\\.\\COM4") == 0 ||
4012: _stricmp(full, "\\\\.\\COM5") == 0 ||
4013: _stricmp(full, "\\\\.\\COM6") == 0 ||
4014: _stricmp(full, "\\\\.\\COM7") == 0 ||
4015: _stricmp(full, "\\\\.\\COM8") == 0 ||
4016: _stricmp(full, "\\\\.\\COM9") == 0 ||
4017: _stricmp(full, "\\\\.\\LPT1") == 0 ||
4018: _stricmp(full, "\\\\.\\LPT2") == 0 ||
4019: _stricmp(full, "\\\\.\\LPT3") == 0 ||
4020: _stricmp(full, "\\\\.\\LPT4") == 0 ||
4021: _stricmp(full, "\\\\.\\LPT5") == 0 ||
4022: _stricmp(full, "\\\\.\\LPT6") == 0 ||
4023: _stricmp(full, "\\\\.\\LPT7") == 0 ||
4024: _stricmp(full, "\\\\.\\LPT8") == 0 ||
4025: _stricmp(full, "\\\\.\\LPT9") == 0) {
4026: return(true);
4027: } else if(name != NULL) {
4028: if(_stricmp(name, "CLOCK$" ) == 0 ||
4029: _stricmp(name, "CONFIG$" ) == 0 ||
1.1.1.30 root 4030: _stricmp(name, "EMMXXXX0") == 0 ||
4031: _stricmp(name, "$IBMAIAS") == 0) {
1.1.1.29 root 4032: return(true);
4033: }
4034: }
1.1.1.24 root 4035: }
4036: return(false);
1.1.1.11 root 4037: }
4038:
1.1.1.29 root 4039: bool msdos_is_con_path(char *path)
1.1.1.8 root 4040: {
1.1.1.14 root 4041: char full[MAX_PATH], *name;
1.1.1.8 root 4042:
1.1.1.24 root 4043: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1.1.1.29 root 4044: return(_stricmp(full, "\\\\.\\CON") == 0);
1.1.1.24 root 4045: }
4046: return(false);
4047: }
4048:
1.1.1.29 root 4049: int msdos_is_comm_path(char *path)
1.1.1.24 root 4050: {
4051: char full[MAX_PATH], *name;
4052:
4053: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1.1.1.29 root 4054: if(_stricmp(full, "\\\\.\\COM1") == 0) {
4055: return(1);
4056: } else if(_stricmp(full, "\\\\.\\COM2") == 0) {
4057: return(2);
4058: } else if(_stricmp(full, "\\\\.\\COM3") == 0) {
4059: return(3);
4060: } else if(_stricmp(full, "\\\\.\\COM4") == 0) {
4061: return(4);
1.1.1.24 root 4062: }
4063: }
1.1.1.29 root 4064: return(0);
4065: }
4066:
1.1.1.30 root 4067: int msdos_is_prn_path(char *path)
4068: {
4069: char full[MAX_PATH], *name;
4070:
4071: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
4072: if(_stricmp(full, "\\\\.\\PRN") == 0) {
4073: return(1);
4074: } else if(_stricmp(full, "\\\\.\\LPT1") == 0) {
4075: return(1);
4076: } else if(_stricmp(full, "\\\\.\\LPT2") == 0) {
4077: return(2);
4078: } else if(_stricmp(full, "\\\\.\\LPT3") == 0) {
4079: return(3);
4080: }
4081: }
4082: return(0);
4083: }
4084:
1.1.1.29 root 4085: char *msdos_create_comm_path(char *path, int port)
4086: {
4087: static char tmp[MAX_PATH];
4088: char *p = NULL;
4089:
4090: sprintf(tmp, "COM%d", port);
4091: if((p = strchr(path, ':')) != NULL) {
4092: strcat(tmp, p);
4093: }
4094: return(tmp);
1.1.1.24 root 4095: }
4096:
4097: bool msdos_is_existing_file(char *path)
4098: {
4099: // http://d.hatena.ne.jp/yu-hr/20100317/1268826458
4100: WIN32_FIND_DATA FindData;
4101: HANDLE hFind;
4102:
4103: if((hFind = FindFirstFile(path, &FindData)) != INVALID_HANDLE_VALUE) {
4104: FindClose(hFind);
4105: return(!(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
4106: }
4107: return(false);
1.1.1.8 root 4108: }
4109:
1.1.1.9 root 4110: char *msdos_search_command_com(char *command_path, char *env_path)
4111: {
4112: static char tmp[MAX_PATH];
1.1.1.28 root 4113: char path[ENV_SIZE], *file_name;
1.1.1.9 root 4114:
1.1.1.28 root 4115: // check if COMMAND.COM is in the same directory as the target program file
1.1.1.9 root 4116: if(GetFullPathName(command_path, MAX_PATH, tmp, &file_name) != 0) {
4117: sprintf(file_name, "COMMAND.COM");
4118: if(_access(tmp, 0) == 0) {
4119: return(tmp);
4120: }
4121: }
1.1.1.28 root 4122:
4123: // check if COMMAND.COM is in the same directory as the running msdos.exe
1.1.1.9 root 4124: if(GetModuleFileName(NULL, path, MAX_PATH) != 0 && GetFullPathName(path, MAX_PATH, tmp, &file_name) != 0) {
4125: sprintf(file_name, "COMMAND.COM");
4126: if(_access(tmp, 0) == 0) {
4127: return(tmp);
4128: }
4129: }
1.1.1.28 root 4130:
4131: // check if COMMAND.COM is in the current directory
1.1.1.9 root 4132: if(GetFullPathName("COMMAND.COM", MAX_PATH, tmp, &file_name) != 0) {
4133: if(_access(tmp, 0) == 0) {
4134: return(tmp);
4135: }
4136: }
1.1.1.28 root 4137:
4138: // cehck if COMMAND.COM is in the directory that is in MSDOS_PATH and PATH environment variables
4139: strcpy(path, env_path);
4140: char *token = my_strtok(path, ";");
1.1.1.9 root 4141: while(token != NULL) {
1.1.1.14 root 4142: if(strlen(token) != 0 && token[0] != '%') {
1.1.1.9 root 4143: strcpy(tmp, msdos_combine_path(token, "COMMAND.COM"));
4144: if(_access(tmp, 0) == 0) {
4145: return(tmp);
4146: }
4147: }
4148: token = my_strtok(NULL, ";");
4149: }
4150: return(NULL);
4151: }
4152:
1.1.1.14 root 4153: int msdos_drive_number(const char *path)
1.1 root 4154: {
4155: char tmp[MAX_PATH], *name;
4156:
4157: GetFullPathName(path, MAX_PATH, tmp, &name);
4158: if(tmp[0] >= 'a' && tmp[0] <= 'z') {
4159: return(tmp[0] - 'a');
4160: } else {
4161: return(tmp[0] - 'A');
4162: }
4163: }
4164:
4165: char *msdos_volume_label(char *path)
4166: {
4167: static char tmp[MAX_PATH];
4168: char volume[] = "A:\\";
4169:
4170: if(path[1] == ':') {
4171: volume[0] = path[0];
4172: } else {
4173: volume[0] = 'A' + _getdrive() - 1;
4174: }
4175: if(!GetVolumeInformation(volume, tmp, MAX_PATH, NULL, NULL, NULL, NULL, 0)) {
4176: memset(tmp, 0, sizeof(tmp));
4177: }
4178: return(tmp);
4179: }
4180:
4181: char *msdos_short_volume_label(char *label)
4182: {
4183: static char tmp[(8 + 1 + 3) + 1];
4184: char *src = label;
4185: int remain = strlen(label);
4186: char *dst_n = tmp;
4187: char *dst_e = tmp + 9;
4188:
4189: strcpy(tmp, " . ");
4190: for(int i = 0; i < 8 && remain > 0; i++) {
4191: if(msdos_lead_byte_check(*src)) {
4192: if(++i == 8) {
4193: break;
4194: }
4195: *dst_n++ = *src++;
4196: remain--;
4197: }
4198: *dst_n++ = *src++;
4199: remain--;
4200: }
4201: if(remain > 0) {
4202: for(int i = 0; i < 3 && remain > 0; i++) {
4203: if(msdos_lead_byte_check(*src)) {
4204: if(++i == 3) {
4205: break;
4206: }
4207: *dst_e++ = *src++;
4208: remain--;
4209: }
4210: *dst_e++ = *src++;
4211: remain--;
4212: }
4213: *dst_e = '\0';
4214: } else {
4215: *dst_n = '\0';
4216: }
4217: my_strupr(tmp);
4218: return(tmp);
4219: }
4220:
1.1.1.13 root 4221: errno_t msdos_maperr(unsigned long oserrno)
4222: {
4223: _doserrno = oserrno;
1.1.1.14 root 4224: switch(oserrno) {
1.1.1.13 root 4225: case ERROR_FILE_NOT_FOUND: // 2
4226: case ERROR_PATH_NOT_FOUND: // 3
4227: case ERROR_INVALID_DRIVE: // 15
4228: case ERROR_NO_MORE_FILES: // 18
4229: case ERROR_BAD_NETPATH: // 53
4230: case ERROR_BAD_NET_NAME: // 67
4231: case ERROR_BAD_PATHNAME: // 161
4232: case ERROR_FILENAME_EXCED_RANGE: // 206
4233: return ENOENT;
4234: case ERROR_TOO_MANY_OPEN_FILES: // 4
4235: return EMFILE;
4236: case ERROR_ACCESS_DENIED: // 5
4237: case ERROR_CURRENT_DIRECTORY: // 16
4238: case ERROR_NETWORK_ACCESS_DENIED: // 65
4239: case ERROR_CANNOT_MAKE: // 82
4240: case ERROR_FAIL_I24: // 83
4241: case ERROR_DRIVE_LOCKED: // 108
4242: case ERROR_SEEK_ON_DEVICE: // 132
4243: case ERROR_NOT_LOCKED: // 158
4244: case ERROR_LOCK_FAILED: // 167
4245: return EACCES;
4246: case ERROR_INVALID_HANDLE: // 6
4247: case ERROR_INVALID_TARGET_HANDLE: // 114
4248: case ERROR_DIRECT_ACCESS_HANDLE: // 130
4249: return EBADF;
4250: case ERROR_ARENA_TRASHED: // 7
4251: case ERROR_NOT_ENOUGH_MEMORY: // 8
4252: case ERROR_INVALID_BLOCK: // 9
4253: case ERROR_NOT_ENOUGH_QUOTA: // 1816
4254: return ENOMEM;
4255: case ERROR_BAD_ENVIRONMENT: // 10
4256: return E2BIG;
4257: case ERROR_BAD_FORMAT: // 11
4258: return ENOEXEC;
4259: case ERROR_NOT_SAME_DEVICE: // 17
4260: return EXDEV;
4261: case ERROR_FILE_EXISTS: // 80
4262: case ERROR_ALREADY_EXISTS: // 183
4263: return EEXIST;
4264: case ERROR_NO_PROC_SLOTS: // 89
4265: case ERROR_MAX_THRDS_REACHED: // 164
4266: case ERROR_NESTING_NOT_ALLOWED: // 215
4267: return EAGAIN;
4268: case ERROR_BROKEN_PIPE: // 109
4269: return EPIPE;
4270: case ERROR_DISK_FULL: // 112
4271: return ENOSPC;
4272: case ERROR_WAIT_NO_CHILDREN: // 128
4273: case ERROR_CHILD_NOT_COMPLETE: // 129
4274: return ECHILD;
4275: case ERROR_DIR_NOT_EMPTY: // 145
4276: return ENOTEMPTY;
4277: }
1.1.1.14 root 4278: if(oserrno >= ERROR_WRITE_PROTECT /* 19 */ &&
1.1.1.13 root 4279: oserrno <= ERROR_SHARING_BUFFER_EXCEEDED /* 36 */) {
4280: return EACCES;
4281: }
1.1.1.14 root 4282: if(oserrno >= ERROR_INVALID_STARTING_CODESEG /* 188 */ &&
1.1.1.13 root 4283: oserrno <= ERROR_INFLOOP_IN_RELOC_CHAIN /* 202 */) {
4284: return ENOEXEC;
4285: }
4286: return EINVAL;
4287: }
4288:
4289: int msdos_open(const char *filename, int oflag)
4290: {
1.1.1.14 root 4291: if((oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) != _O_RDONLY) {
1.1.1.13 root 4292: return _open(filename, oflag);
4293: }
1.1.1.14 root 4294:
4295: SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, !(oflag & _O_NOINHERIT) };
1.1.1.13 root 4296: DWORD disposition;
1.1.1.14 root 4297: switch(oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
4298: default:
1.1.1.13 root 4299: case _O_EXCL:
4300: disposition = OPEN_EXISTING;
4301: break;
4302: case _O_CREAT:
4303: disposition = OPEN_ALWAYS;
4304: break;
4305: case _O_CREAT | _O_EXCL:
4306: case _O_CREAT | _O_TRUNC | _O_EXCL:
4307: disposition = CREATE_NEW;
4308: break;
4309: case _O_TRUNC:
4310: case _O_TRUNC | _O_EXCL:
4311: disposition = TRUNCATE_EXISTING;
4312: break;
4313: case _O_CREAT | _O_TRUNC:
4314: disposition = CREATE_ALWAYS;
4315: break;
4316: }
1.1.1.14 root 4317:
1.1.1.13 root 4318: HANDLE h = CreateFile(filename, GENERIC_READ | FILE_WRITE_ATTRIBUTES,
4319: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
4320: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 4321: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 4322: // FILE_WRITE_ATTRIBUTES may not be granted for standard users.
4323: // Retry without FILE_WRITE_ATTRIBUTES.
4324: h = CreateFile(filename, GENERIC_READ,
4325: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
4326: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 4327: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 4328: errno = msdos_maperr(GetLastError());
4329: return -1;
4330: }
4331: }
1.1.1.14 root 4332:
1.1.1.13 root 4333: int fd = _open_osfhandle((intptr_t) h, oflag);
1.1.1.14 root 4334: if(fd == -1) {
1.1.1.13 root 4335: CloseHandle(h);
4336: }
4337: return fd;
4338: }
4339:
1.1.1.14 root 4340: void msdos_file_handler_open(int fd, const char *path, int atty, int mode, UINT16 info, UINT16 psp_seg)
1.1 root 4341: {
4342: static int id = 0;
4343: char full[MAX_PATH], *name;
4344:
4345: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
4346: strcpy(file_handler[fd].path, full);
4347: } else {
4348: strcpy(file_handler[fd].path, path);
4349: }
1.1.1.14 root 4350: // isatty makes no distinction between CON & NUL
4351: // GetFileSize fails on CON, succeeds on NUL
4352: if(atty && (info != 0x80d3 || GetFileSize((HANDLE)_get_osfhandle(fd), NULL) == 0)) {
4353: info = 0x8084;
4354: atty = 0;
4355: } else if(!atty && info == 0x80d3) {
4356: info = msdos_drive_number(".");
4357: }
1.1 root 4358: file_handler[fd].valid = 1;
4359: file_handler[fd].id = id++; // dummy id for int 21h ax=71a6h
4360: file_handler[fd].atty = atty;
4361: file_handler[fd].mode = mode;
4362: file_handler[fd].info = info;
4363: file_handler[fd].psp = psp_seg;
1.1.1.21 root 4364:
4365: // init system file table
4366: if(fd < 20) {
4367: UINT8 *sft = mem + SFT_TOP + 6 + 0x3b * fd;
4368:
4369: memset(sft, 0, 0x3b);
4370:
4371: *(UINT16 *)(sft + 0x00) = 1;
4372: *(UINT16 *)(sft + 0x02) = file_handler[fd].mode;
4373: *(UINT8 *)(sft + 0x04) = GetFileAttributes(file_handler[fd].path) & 0xff;
4374: *(UINT16 *)(sft + 0x05) = file_handler[fd].info & 0xff;
4375:
4376: if(!(file_handler[fd].info & 0x80)) {
4377: *(UINT16 *)(sft + 0x07) = sizeof(dpb_t) * (file_handler[fd].info & 0x1f);
4378: *(UINT16 *)(sft + 0x09) = DPB_TOP >> 4;
4379:
4380: FILETIME time, local;
4381: HANDLE hHandle;
4382: WORD dos_date = 0, dos_time = 0;
4383: DWORD file_size = 0;
4384: if((hHandle = (HANDLE)_get_osfhandle(fd)) != INVALID_HANDLE_VALUE) {
4385: if(GetFileTime(hHandle, NULL, NULL, &time)) {
4386: FileTimeToLocalFileTime(&time, &local);
4387: FileTimeToDosDateTime(&local, &dos_date, &dos_time);
4388: }
4389: file_size = GetFileSize(hHandle, NULL);
4390: }
4391: *(UINT16 *)(sft + 0x0d) = dos_time;
4392: *(UINT16 *)(sft + 0x0f) = dos_date;
4393: *(UINT32 *)(sft + 0x11) = file_size;
4394: }
4395:
4396: char fname[MAX_PATH] = {0}, ext[MAX_PATH] = {0};
4397: _splitpath(file_handler[fd].path, NULL, NULL, fname, ext);
4398: my_strupr(fname);
4399: my_strupr(ext);
4400: memset(sft + 0x20, 0x20, 11);
4401: memcpy(sft + 0x20, fname, min(strlen(fname), 8));
4402: memcpy(sft + 0x28, ext + 1, min(strlen(ext + 1), 3));
4403:
4404: *(UINT16 *)(sft + 0x31) = psp_seg;
4405: }
1.1 root 4406: }
4407:
4408: void msdos_file_handler_dup(int dst, int src, UINT16 psp_seg)
4409: {
4410: strcpy(file_handler[dst].path, file_handler[src].path);
4411: file_handler[dst].valid = 1;
4412: file_handler[dst].id = file_handler[src].id;
4413: file_handler[dst].atty = file_handler[src].atty;
4414: file_handler[dst].mode = file_handler[src].mode;
4415: file_handler[dst].info = file_handler[src].info;
4416: file_handler[dst].psp = psp_seg;
4417: }
4418:
1.1.1.20 root 4419: void msdos_file_handler_close(int fd)
1.1 root 4420: {
4421: file_handler[fd].valid = 0;
1.1.1.21 root 4422:
4423: if(fd < 20) {
4424: memset(mem + SFT_TOP + 6 + 0x3b * fd, 0, 0x3b);
4425: }
1.1 root 4426: }
4427:
1.1.1.14 root 4428: inline int msdos_file_attribute_create(UINT16 new_attr)
1.1 root 4429: {
1.1.1.14 root 4430: return(new_attr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
4431: FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE |
4432: FILE_ATTRIBUTE_DIRECTORY));
1.1 root 4433: }
4434:
4435: // find file
4436:
4437: int msdos_find_file_check_attribute(int attribute, int allowed_mask, int required_mask)
4438: {
4439: if((allowed_mask & 0x08) && !(attribute & FILE_ATTRIBUTE_DIRECTORY)) {
4440: return(0); // search directory only !!!
4441: } else if(!(allowed_mask & 0x02) && (attribute & FILE_ATTRIBUTE_HIDDEN)) {
4442: return(0);
4443: } else if(!(allowed_mask & 0x04) && (attribute & FILE_ATTRIBUTE_SYSTEM)) {
4444: return(0);
4445: } else if(!(allowed_mask & 0x10) && (attribute & FILE_ATTRIBUTE_DIRECTORY)) {
4446: return(0);
4447: } else if((attribute & required_mask) != required_mask) {
4448: return(0);
4449: } else {
4450: return(1);
4451: }
4452: }
4453:
1.1.1.13 root 4454: int msdos_find_file_has_8dot3name(WIN32_FIND_DATA *fd)
4455: {
1.1.1.14 root 4456: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 4457: return 1;
4458: }
4459: size_t len = strlen(fd->cFileName);
1.1.1.14 root 4460: if(len > 12) {
1.1.1.13 root 4461: return 0;
4462: }
4463: const char *ext = strrchr(fd->cFileName, '.');
1.1.1.14 root 4464: if((ext ? ext - fd->cFileName : len) > 8) {
1.1.1.13 root 4465: return 0;
4466: }
4467: return 1;
4468: }
4469:
1.1 root 4470: void msdos_find_file_conv_local_time(WIN32_FIND_DATA *fd)
4471: {
4472: FILETIME local;
4473:
4474: FileTimeToLocalFileTime(&fd->ftCreationTime, &local);
4475: fd->ftCreationTime.dwLowDateTime = local.dwLowDateTime;
4476: fd->ftCreationTime.dwHighDateTime = local.dwHighDateTime;
4477:
4478: FileTimeToLocalFileTime(&fd->ftLastAccessTime, &local);
4479: fd->ftLastAccessTime.dwLowDateTime = local.dwLowDateTime;
4480: fd->ftLastAccessTime.dwHighDateTime = local.dwHighDateTime;
4481:
4482: FileTimeToLocalFileTime(&fd->ftLastWriteTime, &local);
4483: fd->ftLastWriteTime.dwLowDateTime = local.dwLowDateTime;
4484: fd->ftLastWriteTime.dwHighDateTime = local.dwHighDateTime;
4485: }
4486:
4487: // i/o
4488:
4489: void msdos_stdio_reopen()
4490: {
4491: if(!file_handler[0].valid) {
4492: _dup2(DUP_STDIN, 0);
4493: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
4494: }
4495: if(!file_handler[1].valid) {
4496: _dup2(DUP_STDOUT, 1);
4497: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
4498: }
4499: if(!file_handler[2].valid) {
4500: _dup2(DUP_STDERR, 2);
4501: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
4502: }
1.1.1.21 root 4503: if(!file_handler[3].valid) {
4504: _dup2(DUP_STDAUX, 3);
4505: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
4506: }
4507: if(!file_handler[4].valid) {
4508: _dup2(DUP_STDPRN, 4);
4509: msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0);
4510: }
4511: for(int i = 0; i < 5; i++) {
4512: if(msdos_psp_get_file_table(i, current_psp) == 0xff) {
4513: msdos_psp_set_file_table(i, i, current_psp);
4514: }
4515: }
1.1 root 4516: }
4517:
4518: int msdos_kbhit()
4519: {
4520: msdos_stdio_reopen();
4521:
1.1.1.20 root 4522: process_t *process = msdos_process_info_get(current_psp);
4523: int fd = msdos_psp_get_file_table(0, current_psp);
4524:
4525: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4526: // stdin is redirected to file
1.1.1.20 root 4527: return(eof(fd) == 0);
1.1 root 4528: }
4529:
4530: // check keyboard status
1.1.1.33! root 4531: if((key_buf_char != NULL && key_buf_char->count() != 0) || key_recv != 0) {
1.1 root 4532: return(1);
4533: } else {
4534: return(_kbhit());
4535: }
4536: }
4537:
4538: int msdos_getch_ex(int echo)
4539: {
4540: static char prev = 0;
4541:
4542: msdos_stdio_reopen();
4543:
1.1.1.20 root 4544: process_t *process = msdos_process_info_get(current_psp);
4545: int fd = msdos_psp_get_file_table(0, current_psp);
4546:
4547: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4548: // stdin is redirected to file
4549: retry:
4550: char data;
1.1.1.20 root 4551: if(_read(fd, &data, 1) == 1) {
1.1 root 4552: char tmp = data;
4553: if(data == 0x0a) {
4554: if(prev == 0x0d) {
4555: goto retry; // CRLF -> skip LF
4556: } else {
4557: data = 0x0d; // LF only -> CR
4558: }
4559: }
4560: prev = tmp;
4561: return(data);
4562: }
4563: return(EOF);
4564: }
4565:
4566: // input from console
1.1.1.5 root 4567: int key_char, key_scan;
1.1.1.33! root 4568: if(key_recv != 0) {
1.1.1.5 root 4569: key_char = (key_code >> 0) & 0xff;
4570: key_scan = (key_code >> 8) & 0xff;
4571: key_code >>= 16;
1.1.1.33! root 4572: key_recv >>= 16;
1.1.1.5 root 4573: } else {
1.1.1.33! root 4574: while(key_buf_char != NULL && key_buf_char->count() == 0 && !m_halted) {
1.1.1.23 root 4575: if(!(fd < process->max_files && file_handler[fd].valid && file_handler[fd].atty && file_mode[file_handler[fd].mode].in)) {
4576: // NOTE: stdin is redirected to stderr when we do "type (file) | more" on freedos's command.com
4577: if(_kbhit()) {
1.1.1.32 root 4578: if(key_buf_char != NULL && key_buf_scan != NULL) {
4579: key_buf_char->write(_getch());
4580: key_buf_scan->write(0);
4581: }
1.1.1.23 root 4582: } else {
4583: Sleep(10);
4584: }
4585: } else {
4586: if(!update_key_buffer()) {
4587: Sleep(10);
4588: }
1.1.1.14 root 4589: }
4590: }
4591: if(m_halted) {
1.1.1.33! root 4592: // insert CR to terminate input loops
1.1.1.14 root 4593: key_char = 0x0d;
4594: key_scan = 0;
1.1.1.32 root 4595: } else if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.14 root 4596: key_char = key_buf_char->read();
4597: key_scan = key_buf_scan->read();
1.1.1.5 root 4598: }
1.1 root 4599: }
4600: if(echo && key_char) {
4601: msdos_putch(key_char);
4602: }
4603: return key_char ? key_char : (key_scan != 0xe0) ? key_scan : 0;
4604: }
4605:
4606: inline int msdos_getch()
4607: {
4608: return(msdos_getch_ex(0));
4609: }
4610:
4611: inline int msdos_getche()
4612: {
4613: return(msdos_getch_ex(1));
4614: }
4615:
4616: int msdos_write(int fd, const void *buffer, unsigned int count)
4617: {
4618: static int is_cr = 0;
4619:
4620: if(fd == 1 && !file_handler[1].atty) {
4621: // CR+LF -> LF
4622: UINT8 *buf = (UINT8 *)buffer;
4623: for(unsigned int i = 0; i < count; i++) {
4624: UINT8 data = buf[i];
4625: if(is_cr) {
4626: if(data != 0x0a) {
4627: UINT8 tmp = 0x0d;
4628: _write(1, &tmp, 1);
4629: }
4630: _write(1, &data, 1);
4631: is_cr = 0;
4632: } else if(data == 0x0d) {
4633: is_cr = 1;
4634: } else {
4635: _write(1, &data, 1);
4636: }
4637: }
4638: return(count);
4639: }
1.1.1.14 root 4640: vram_flush();
1.1 root 4641: return(_write(fd, buffer, count));
4642: }
4643:
4644: void msdos_putch(UINT8 data)
4645: {
4646: static int p = 0;
4647: static int is_kanji = 0;
4648: static int is_esc = 0;
4649: static int stored_x;
4650: static int stored_y;
4651: static WORD stored_a;
1.1.1.20 root 4652: static char tmp[64], out[64];
1.1 root 4653:
4654: msdos_stdio_reopen();
4655:
1.1.1.20 root 4656: process_t *process = msdos_process_info_get(current_psp);
4657: int fd = msdos_psp_get_file_table(1, current_psp);
4658:
4659: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4660: // stdout is redirected to file
1.1.1.20 root 4661: msdos_write(fd, &data, 1);
1.1 root 4662: return;
4663: }
1.1.1.23 root 4664: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 4665:
4666: // output to console
4667: tmp[p++] = data;
4668:
1.1.1.14 root 4669: vram_flush();
4670:
1.1 root 4671: if(is_kanji) {
4672: // kanji character
4673: is_kanji = 0;
4674: } else if(is_esc) {
4675: // escape sequense
4676: if((tmp[1] == ')' || tmp[1] == '(') && p == 3) {
4677: p = is_esc = 0;
4678: } else if(tmp[1] == '=' && p == 4) {
4679: COORD co;
4680: co.X = tmp[3] - 0x20;
1.1.1.14 root 4681: co.Y = tmp[2] - 0x20 + scr_top;
1.1 root 4682: SetConsoleCursorPosition(hStdout, co);
4683: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 4684: mem[0x451 + mem[0x462] * 2] = co.Y - scr_top;
1.1 root 4685: cursor_moved = false;
4686: p = is_esc = 0;
4687: } else if((data >= 'a' && data <= 'z') || (data >= 'A' && data <= 'Z') || data == '*') {
4688: CONSOLE_SCREEN_BUFFER_INFO csbi;
4689: COORD co;
4690: GetConsoleScreenBufferInfo(hStdout, &csbi);
4691: co.X = csbi.dwCursorPosition.X;
4692: co.Y = csbi.dwCursorPosition.Y;
4693: WORD wAttributes = csbi.wAttributes;
4694:
4695: if(tmp[1] == 'D') {
4696: co.Y++;
4697: } else if(tmp[1] == 'E') {
4698: co.X = 0;
4699: co.Y++;
4700: } else if(tmp[1] == 'M') {
4701: co.Y--;
4702: } else if(tmp[1] == '*') {
4703: SMALL_RECT rect;
1.1.1.14 root 4704: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
4705: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
4706: co.X = 0;
4707: co.Y = csbi.srWindow.Top;
1.1 root 4708: } else if(tmp[1] == '[') {
4709: int param[256], params = 0;
4710: memset(param, 0, sizeof(param));
4711: for(int i = 2; i < p; i++) {
4712: if(tmp[i] >= '0' && tmp[i] <= '9') {
4713: param[params] *= 10;
4714: param[params] += tmp[i] - '0';
4715: } else {
4716: params++;
4717: }
4718: }
4719: if(data == 'A') {
1.1.1.14 root 4720: co.Y -= (params == 0) ? 1 : param[0];
1.1 root 4721: } else if(data == 'B') {
1.1.1.14 root 4722: co.Y += (params == 0) ? 1 : param[0];
1.1 root 4723: } else if(data == 'C') {
1.1.1.14 root 4724: co.X += (params == 0) ? 1 : param[0];
1.1 root 4725: } else if(data == 'D') {
1.1.1.14 root 4726: co.X -= (params == 0) ? 1 : param[0];
1.1 root 4727: } else if(data == 'H' || data == 'f') {
1.1.1.14 root 4728: co.X = (param[1] == 0 ? 1 : param[1]) - 1;
4729: co.Y = (param[0] == 0 ? 1 : param[0]) - 1 + csbi.srWindow.Top;
1.1 root 4730: } else if(data == 'J') {
4731: SMALL_RECT rect;
1.1.1.14 root 4732: clear_scr_buffer(csbi.wAttributes);
1.1 root 4733: if(param[0] == 0) {
4734: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 4735: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
4736: if(co.Y < csbi.srWindow.Bottom) {
4737: SET_RECT(rect, 0, co.Y + 1, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
4738: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4739: }
4740: } else if(param[0] == 1) {
1.1.1.14 root 4741: if(co.Y > csbi.srWindow.Top) {
4742: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, co.Y - 1);
4743: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4744: }
4745: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 4746: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4747: } else if(param[0] == 2) {
1.1.1.14 root 4748: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
4749: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4750: co.X = co.Y = 0;
4751: }
4752: } else if(data == 'K') {
4753: SMALL_RECT rect;
1.1.1.14 root 4754: clear_scr_buffer(csbi.wAttributes);
1.1 root 4755: if(param[0] == 0) {
4756: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 4757: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4758: } else if(param[0] == 1) {
4759: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 4760: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4761: } else if(param[0] == 2) {
4762: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 4763: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4764: }
4765: } else if(data == 'L') {
4766: SMALL_RECT rect;
1.1.1.14 root 4767: if(params == 0) {
4768: param[0] = 1;
1.1 root 4769: }
1.1.1.14 root 4770: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
4771: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
4772: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
4773: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
4774: clear_scr_buffer(csbi.wAttributes);
1.1 root 4775: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y + param[0] - 1);
1.1.1.14 root 4776: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4777: co.X = 0;
4778: } else if(data == 'M') {
4779: SMALL_RECT rect;
1.1.1.14 root 4780: if(params == 0) {
4781: param[0] = 1;
4782: }
4783: if(co.Y + param[0] > csbi.srWindow.Bottom) {
4784: clear_scr_buffer(csbi.wAttributes);
4785: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
4786: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4787: } else {
1.1.1.14 root 4788: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
4789: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
4790: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
4791: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
4792: clear_scr_buffer(csbi.wAttributes);
1.1 root 4793: }
4794: co.X = 0;
4795: } else if(data == 'h') {
4796: if(tmp[2] == '>' && tmp[3] == '5') {
4797: CONSOLE_CURSOR_INFO cur;
4798: GetConsoleCursorInfo(hStdout, &cur);
4799: if(cur.bVisible) {
4800: cur.bVisible = FALSE;
1.1.1.14 root 4801: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 4802: }
4803: }
4804: } else if(data == 'l') {
4805: if(tmp[2] == '>' && tmp[3] == '5') {
4806: CONSOLE_CURSOR_INFO cur;
4807: GetConsoleCursorInfo(hStdout, &cur);
4808: if(!cur.bVisible) {
4809: cur.bVisible = TRUE;
1.1.1.14 root 4810: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 4811: }
4812: }
4813: } else if(data == 'm') {
4814: wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
4815: int reverse = 0, hidden = 0;
4816: for(int i = 0; i < params; i++) {
4817: if(param[i] == 1) {
4818: wAttributes |= FOREGROUND_INTENSITY;
4819: } else if(param[i] == 4) {
4820: wAttributes |= COMMON_LVB_UNDERSCORE;
4821: } else if(param[i] == 7) {
4822: reverse = 1;
4823: } else if(param[i] == 8 || param[i] == 16) {
4824: hidden = 1;
4825: } else if((param[i] >= 17 && param[i] <= 23) || (param[i] >= 30 && param[i] <= 37)) {
4826: wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
4827: if(param[i] >= 17 && param[i] <= 23) {
4828: param[i] -= 16;
4829: } else {
4830: param[i] -= 30;
4831: }
4832: if(param[i] & 1) {
4833: wAttributes |= FOREGROUND_RED;
4834: }
4835: if(param[i] & 2) {
4836: wAttributes |= FOREGROUND_GREEN;
4837: }
4838: if(param[i] & 4) {
4839: wAttributes |= FOREGROUND_BLUE;
4840: }
4841: } else if(param[i] >= 40 && param[i] <= 47) {
4842: wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
4843: if((param[i] - 40) & 1) {
4844: wAttributes |= BACKGROUND_RED;
4845: }
4846: if((param[i] - 40) & 2) {
4847: wAttributes |= BACKGROUND_GREEN;
4848: }
4849: if((param[i] - 40) & 4) {
4850: wAttributes |= BACKGROUND_BLUE;
4851: }
4852: }
4853: }
4854: if(reverse) {
4855: wAttributes &= ~0xff;
4856: wAttributes |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
4857: }
4858: if(hidden) {
4859: wAttributes &= ~0x0f;
4860: wAttributes |= (wAttributes >> 4) & 0x0f;
4861: }
4862: } else if(data == 'n') {
4863: if(param[0] == 6) {
4864: char tmp[16];
4865: sprintf(tmp, "\x1b[%d;%dR", co.Y + 1, co.X + 1);
4866: int len = strlen(tmp);
1.1.1.32 root 4867: if(key_buf_char != NULL && key_buf_scan != NULL) {
4868: for(int i = 0; i < len; i++) {
4869: key_buf_char->write(tmp[i]);
4870: key_buf_scan->write(0x00);
4871: }
1.1 root 4872: }
4873: }
4874: } else if(data == 's') {
4875: stored_x = co.X;
4876: stored_y = co.Y;
4877: stored_a = wAttributes;
4878: } else if(data == 'u') {
4879: co.X = stored_x;
4880: co.Y = stored_y;
4881: wAttributes = stored_a;
4882: }
4883: }
4884: if(co.X < 0) {
4885: co.X = 0;
4886: } else if(co.X >= csbi.dwSize.X) {
4887: co.X = csbi.dwSize.X - 1;
4888: }
1.1.1.14 root 4889: if(co.Y < csbi.srWindow.Top) {
4890: co.Y = csbi.srWindow.Top;
4891: } else if(co.Y > csbi.srWindow.Bottom) {
4892: co.Y = csbi.srWindow.Bottom;
1.1 root 4893: }
4894: if(co.X != csbi.dwCursorPosition.X || co.Y != csbi.dwCursorPosition.Y) {
4895: SetConsoleCursorPosition(hStdout, co);
4896: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 4897: mem[0x451 + mem[0x462] * 2] = co.Y - csbi.srWindow.Top;
1.1 root 4898: cursor_moved = false;
4899: }
4900: if(wAttributes != csbi.wAttributes) {
4901: SetConsoleTextAttribute(hStdout, wAttributes);
4902: }
4903: p = is_esc = 0;
4904: }
4905: return;
4906: } else {
4907: if(msdos_lead_byte_check(data)) {
4908: is_kanji = 1;
4909: return;
4910: } else if(data == 0x1b) {
4911: is_esc = 1;
4912: return;
4913: }
4914: }
1.1.1.20 root 4915:
4916: DWORD q = 0, num;
4917: is_kanji = 0;
4918: for(int i = 0; i < p; i++) {
4919: UINT8 c = tmp[i];
4920: if(is_kanji) {
4921: is_kanji = 0;
4922: } else if(msdos_lead_byte_check(data)) {
4923: is_kanji = 1;
4924: } else if(msdos_ctrl_code_check(data)) {
4925: out[q++] = '^';
4926: c += 'A' - 1;
4927: }
4928: out[q++] = c;
4929: }
4930: WriteConsole(hStdout, out, q, &num, NULL);
1.1 root 4931: p = 0;
1.1.1.14 root 4932:
1.1.1.15 root 4933: if(!restore_console_on_exit) {
4934: CONSOLE_SCREEN_BUFFER_INFO csbi;
4935: GetConsoleScreenBufferInfo(hStdout, &csbi);
4936: scr_top = csbi.srWindow.Top;
4937: }
1.1 root 4938: cursor_moved = true;
4939: }
4940:
4941: int msdos_aux_in()
4942: {
1.1.1.21 root 4943: msdos_stdio_reopen();
4944:
1.1.1.20 root 4945: process_t *process = msdos_process_info_get(current_psp);
4946: int fd = msdos_psp_get_file_table(3, current_psp);
4947:
4948: if(fd < process->max_files && file_handler[fd].valid && !eof(fd)) {
1.1 root 4949: char data = 0;
1.1.1.20 root 4950: _read(fd, &data, 1);
1.1 root 4951: return(data);
4952: } else {
4953: return(EOF);
4954: }
4955: }
4956:
4957: void msdos_aux_out(char data)
4958: {
1.1.1.21 root 4959: msdos_stdio_reopen();
4960:
1.1.1.20 root 4961: process_t *process = msdos_process_info_get(current_psp);
4962: int fd = msdos_psp_get_file_table(3, current_psp);
4963:
4964: if(fd < process->max_files && file_handler[fd].valid) {
4965: msdos_write(fd, &data, 1);
1.1 root 4966: }
4967: }
4968:
4969: void msdos_prn_out(char data)
4970: {
1.1.1.21 root 4971: msdos_stdio_reopen();
4972:
1.1.1.20 root 4973: process_t *process = msdos_process_info_get(current_psp);
4974: int fd = msdos_psp_get_file_table(4, current_psp);
4975:
4976: if(fd < process->max_files && file_handler[fd].valid) {
4977: msdos_write(fd, &data, 1);
1.1 root 4978: }
4979: }
4980:
4981: // memory control
4982:
1.1.1.19 root 4983: mcb_t *msdos_mcb_create(int mcb_seg, UINT8 mz, UINT16 psp, int paragraphs)
1.1 root 4984: {
4985: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
4986:
4987: mcb->mz = mz;
4988: mcb->psp = psp;
1.1.1.30 root 4989: mcb->paragraphs = paragraphs;
1.1 root 4990: return(mcb);
4991: }
4992:
4993: void msdos_mcb_check(mcb_t *mcb)
4994: {
4995: if(!(mcb->mz == 'M' || mcb->mz == 'Z')) {
1.1.1.28 root 4996: #if 0
4997: // shutdown now !!!
4998: fatalerror("broken memory control block\n");
4999: #else
5000: // return error code and continue
5001: throw(0x07); // broken memory control block
5002: #endif
1.1 root 5003: }
5004: }
5005:
5006: int msdos_mem_split(int seg, int paragraphs)
5007: {
5008: int mcb_seg = seg - 1;
5009: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5010: msdos_mcb_check(mcb);
5011:
1.1.1.30 root 5012: if(mcb->paragraphs > paragraphs) {
1.1 root 5013: int new_seg = mcb_seg + 1 + paragraphs;
1.1.1.30 root 5014: int new_paragraphs = mcb->paragraphs - paragraphs - 1;
1.1 root 5015:
5016: msdos_mcb_create(new_seg, mcb->mz, 0, new_paragraphs);
5017: mcb->mz = 'M';
1.1.1.30 root 5018: mcb->paragraphs = paragraphs;
1.1 root 5019: return(0);
5020: }
5021: return(-1);
5022: }
5023:
5024: void msdos_mem_merge(int seg)
5025: {
5026: int mcb_seg = seg - 1;
5027: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5028: msdos_mcb_check(mcb);
5029:
5030: while(1) {
5031: if(mcb->mz == 'Z') {
5032: break;
5033: }
1.1.1.30 root 5034: int next_seg = mcb_seg + 1 + mcb->paragraphs;
1.1 root 5035: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
5036: msdos_mcb_check(next_mcb);
5037:
5038: if(next_mcb->psp != 0) {
5039: break;
5040: }
5041: mcb->mz = next_mcb->mz;
1.1.1.30 root 5042: mcb->paragraphs = mcb->paragraphs + 1 + next_mcb->paragraphs;
1.1 root 5043: }
5044: }
5045:
1.1.1.8 root 5046: int msdos_mem_alloc(int mcb_seg, int paragraphs, int new_process)
1.1 root 5047: {
5048: while(1) {
5049: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1.1.33! root 5050: bool last_block;
1.1 root 5051:
1.1.1.14 root 5052: if(mcb->psp == 0) {
5053: msdos_mem_merge(mcb_seg + 1);
5054: } else {
5055: msdos_mcb_check(mcb);
5056: }
1.1.1.33! root 5057: if(!(last_block = (mcb->mz == 'Z'))) {
! 5058: // check if the next is dummy mcb to link to umb
! 5059: int next_seg = mcb_seg + 1 + mcb->paragraphs;
! 5060: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
! 5061: last_block = (next_mcb->mz == 'Z' && next_mcb->paragraphs == 0);
! 5062: }
! 5063: if(!(new_process && !last_block)) {
1.1.1.30 root 5064: if(mcb->psp == 0 && mcb->paragraphs >= paragraphs) {
1.1 root 5065: msdos_mem_split(mcb_seg + 1, paragraphs);
5066: mcb->psp = current_psp;
5067: return(mcb_seg + 1);
5068: }
5069: }
5070: if(mcb->mz == 'Z') {
5071: break;
5072: }
1.1.1.30 root 5073: mcb_seg += 1 + mcb->paragraphs;
1.1 root 5074: }
5075: return(-1);
5076: }
5077:
5078: int msdos_mem_realloc(int seg, int paragraphs, int *max_paragraphs)
5079: {
5080: int mcb_seg = seg - 1;
5081: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5082: msdos_mcb_check(mcb);
1.1.1.30 root 5083: int current_paragraphs = mcb->paragraphs;
1.1 root 5084:
5085: msdos_mem_merge(seg);
1.1.1.30 root 5086: if(paragraphs > mcb->paragraphs) {
1.1.1.14 root 5087: if(max_paragraphs) {
1.1.1.30 root 5088: *max_paragraphs = mcb->paragraphs;
1.1.1.14 root 5089: }
1.1 root 5090: msdos_mem_split(seg, current_paragraphs);
5091: return(-1);
5092: }
5093: msdos_mem_split(seg, paragraphs);
5094: return(0);
5095: }
5096:
5097: void msdos_mem_free(int seg)
5098: {
5099: int mcb_seg = seg - 1;
5100: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5101: msdos_mcb_check(mcb);
5102:
5103: mcb->psp = 0;
5104: msdos_mem_merge(seg);
5105: }
5106:
1.1.1.8 root 5107: int msdos_mem_get_free(int mcb_seg, int new_process)
1.1 root 5108: {
5109: int max_paragraphs = 0;
5110:
5111: while(1) {
5112: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1.1.33! root 5113: bool last_block;
! 5114:
1.1 root 5115: msdos_mcb_check(mcb);
5116:
1.1.1.33! root 5117: if(!(last_block = (mcb->mz == 'Z'))) {
! 5118: // check if the next is dummy mcb to link to umb
! 5119: int next_seg = mcb_seg + 1 + mcb->paragraphs;
! 5120: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
! 5121: last_block = (next_mcb->mz == 'Z' && next_mcb->paragraphs == 0);
! 5122: }
! 5123: if(!(new_process && !last_block)) {
1.1.1.30 root 5124: if(mcb->psp == 0 && mcb->paragraphs > max_paragraphs) {
5125: max_paragraphs = mcb->paragraphs;
1.1 root 5126: }
5127: }
5128: if(mcb->mz == 'Z') {
5129: break;
5130: }
1.1.1.30 root 5131: mcb_seg += 1 + mcb->paragraphs;
1.1 root 5132: }
1.1.1.14 root 5133: return(max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs);
1.1 root 5134: }
5135:
1.1.1.8 root 5136: int msdos_mem_get_last_mcb(int mcb_seg, UINT16 psp)
5137: {
5138: int last_seg = -1;
5139:
5140: while(1) {
5141: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5142: msdos_mcb_check(mcb);
5143:
1.1.1.14 root 5144: if(mcb->psp == psp) {
1.1.1.8 root 5145: last_seg = mcb_seg;
5146: }
1.1.1.14 root 5147: if(mcb->mz == 'Z') {
5148: break;
5149: }
1.1.1.30 root 5150: mcb_seg += 1 + mcb->paragraphs;
1.1.1.8 root 5151: }
5152: return(last_seg);
5153: }
5154:
1.1.1.19 root 5155: int msdos_mem_get_umb_linked()
5156: {
1.1.1.33! root 5157: mcb_t *mcb = (mcb_t *)(mem + MEMORY_END - 16);
! 5158: msdos_mcb_check(mcb);
1.1.1.19 root 5159:
1.1.1.33! root 5160: if(mcb->mz == 'M') {
! 5161: return(-1);
1.1.1.19 root 5162: }
5163: return(0);
5164: }
5165:
1.1.1.33! root 5166: void msdos_mem_link_umb()
1.1.1.19 root 5167: {
1.1.1.33! root 5168: mcb_t *mcb = (mcb_t *)(mem + MEMORY_END - 16);
! 5169: msdos_mcb_check(mcb);
1.1.1.19 root 5170:
1.1.1.33! root 5171: mcb->mz = 'M';
! 5172: mcb->paragraphs = (UMB_TOP >> 4) - (MEMORY_END >> 4);
1.1.1.19 root 5173: }
5174:
1.1.1.33! root 5175: void msdos_mem_unlink_umb()
1.1.1.19 root 5176: {
1.1.1.33! root 5177: mcb_t *mcb = (mcb_t *)(mem + MEMORY_END - 16);
! 5178: msdos_mcb_check(mcb);
1.1.1.19 root 5179:
1.1.1.33! root 5180: mcb->mz = 'Z';
! 5181: mcb->paragraphs = 0;
1.1.1.19 root 5182: }
5183:
1.1.1.29 root 5184: #ifdef SUPPORT_HMA
5185:
5186: hma_mcb_t *msdos_hma_mcb_create(int offset, int owner, int size, int next)
5187: {
5188: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5189:
5190: mcb->ms[0] = 'M';
5191: mcb->ms[1] = 'S';
5192: mcb->owner = owner;
5193: mcb->size = size;
5194: mcb->next = next;
5195: return(mcb);
5196: }
5197:
5198: bool msdos_is_hma_mcb_valid(hma_mcb_t *mcb)
5199: {
5200: return(mcb->ms[0] == 'M' && mcb->ms[1] == 'S');
5201: }
5202:
5203: int msdos_hma_mem_split(int offset, int size)
5204: {
5205: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5206:
5207: if(!msdos_is_hma_mcb_valid(mcb)) {
5208: return(-1);
5209: }
5210: if(mcb->size >= size + 0x10) {
5211: int new_offset = offset + 0x10 + size;
5212: int new_size = mcb->size - 0x10 - size;
5213:
5214: msdos_hma_mcb_create(new_offset, 0, new_size, mcb->next);
5215: mcb->size = size;
5216: mcb->next = new_offset;
5217: return(0);
5218: }
5219: return(-1);
5220: }
5221:
5222: void msdos_hma_mem_merge(int offset)
5223: {
5224: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5225:
5226: if(!msdos_is_hma_mcb_valid(mcb)) {
5227: return;
5228: }
5229: while(1) {
5230: if(mcb->next == 0) {
5231: break;
5232: }
5233: hma_mcb_t *next_mcb = (hma_mcb_t *)(mem + 0xffff0 + mcb->next);
5234:
5235: if(!msdos_is_hma_mcb_valid(next_mcb)) {
5236: return;
5237: }
5238: if(next_mcb->owner != 0) {
5239: break;
5240: }
5241: mcb->size += 0x10 + next_mcb->size;
5242: mcb->next = next_mcb->next;
5243: }
5244: }
5245:
5246: int msdos_hma_mem_alloc(int size, UINT16 owner)
5247: {
5248: int offset = 0x10; // first mcb in HMA
5249:
5250: while(1) {
5251: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5252:
5253: if(!msdos_is_hma_mcb_valid(mcb)) {
5254: return(-1);
5255: }
5256: if(mcb->owner == 0) {
5257: msdos_hma_mem_merge(offset);
5258: }
5259: if(mcb->owner == 0 && mcb->size >= size) {
5260: msdos_hma_mem_split(offset, size);
5261: mcb->owner = owner;
5262: return(offset);
5263: }
5264: if(mcb->next == 0) {
5265: break;
5266: }
5267: offset = mcb->next;
5268: }
5269: return(-1);
5270: }
5271:
5272: int msdos_hma_mem_realloc(int offset, int size)
5273: {
5274: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5275:
5276: if(!msdos_is_hma_mcb_valid(mcb)) {
5277: return(-1);
5278: }
5279: if(mcb->size < size) {
5280: return(-1);
5281: }
5282: msdos_hma_mem_split(offset, size);
5283: return(0);
5284: }
5285:
5286: void msdos_hma_mem_free(int offset)
5287: {
5288: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5289:
5290: if(!msdos_is_hma_mcb_valid(mcb)) {
5291: return;
5292: }
5293: mcb->owner = 0;
5294: msdos_hma_mem_merge(offset);
5295: }
5296:
5297: int msdos_hma_mem_get_free(int *available_offset)
5298: {
5299: int offset = 0x10; // first mcb in HMA
5300: int size = 0;
5301:
5302: while(1) {
5303: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5304:
5305: if(!msdos_is_hma_mcb_valid(mcb)) {
5306: return(0);
5307: }
5308: if(mcb->owner == 0 && size < mcb->size) {
5309: if(available_offset != NULL) {
5310: *available_offset = offset;
5311: }
5312: size = mcb->size;
5313: }
5314: if(mcb->next == 0) {
5315: break;
5316: }
5317: offset = mcb->next;
5318: }
5319: return(size);
5320: }
5321:
5322: #endif
5323:
1.1 root 5324: // environment
5325:
5326: void msdos_env_set_argv(int env_seg, char *argv)
5327: {
5328: char *dst = (char *)(mem + (env_seg << 4));
5329:
5330: while(1) {
5331: if(dst[0] == 0) {
5332: break;
5333: }
5334: dst += strlen(dst) + 1;
5335: }
5336: *dst++ = 0; // end of environment
5337: *dst++ = 1; // top of argv[0]
5338: *dst++ = 0;
5339: memcpy(dst, argv, strlen(argv));
5340: dst += strlen(argv);
5341: *dst++ = 0;
5342: *dst++ = 0;
5343: }
5344:
5345: char *msdos_env_get_argv(int env_seg)
5346: {
5347: static char env[ENV_SIZE];
5348: char *src = env;
5349:
5350: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
5351: while(1) {
5352: if(src[0] == 0) {
5353: if(src[1] == 1) {
5354: return(src + 3);
5355: }
5356: break;
5357: }
5358: src += strlen(src) + 1;
5359: }
5360: return(NULL);
5361: }
5362:
5363: char *msdos_env_get(int env_seg, const char *name)
5364: {
5365: static char env[ENV_SIZE];
5366: char *src = env;
5367:
5368: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
5369: while(1) {
5370: if(src[0] == 0) {
5371: break;
5372: }
5373: int len = strlen(src);
5374: char *n = my_strtok(src, "=");
5375: char *v = src + strlen(n) + 1;
5376:
5377: if(_stricmp(name, n) == 0) {
5378: return(v);
5379: }
5380: src += len + 1;
5381: }
5382: return(NULL);
5383: }
5384:
5385: void msdos_env_set(int env_seg, char *name, char *value)
5386: {
5387: char env[ENV_SIZE];
5388: char *src = env;
5389: char *dst = (char *)(mem + (env_seg << 4));
5390: char *argv = msdos_env_get_argv(env_seg);
5391: int done = 0;
5392:
5393: memcpy(src, dst, ENV_SIZE);
5394: memset(dst, 0, ENV_SIZE);
5395: while(1) {
5396: if(src[0] == 0) {
5397: break;
5398: }
5399: int len = strlen(src);
5400: char *n = my_strtok(src, "=");
5401: char *v = src + strlen(n) + 1;
5402: char tmp[1024];
5403:
5404: if(_stricmp(name, n) == 0) {
5405: sprintf(tmp, "%s=%s", n, value);
5406: done = 1;
5407: } else {
5408: sprintf(tmp, "%s=%s", n, v);
5409: }
5410: memcpy(dst, tmp, strlen(tmp));
5411: dst += strlen(tmp) + 1;
5412: src += len + 1;
5413: }
5414: if(!done) {
5415: char tmp[1024];
5416:
5417: sprintf(tmp, "%s=%s", name, value);
5418: memcpy(dst, tmp, strlen(tmp));
5419: dst += strlen(tmp) + 1;
5420: }
5421: if(argv) {
5422: *dst++ = 0; // end of environment
5423: *dst++ = 1; // top of argv[0]
5424: *dst++ = 0;
5425: memcpy(dst, argv, strlen(argv));
5426: dst += strlen(argv);
5427: *dst++ = 0;
5428: *dst++ = 0;
5429: }
5430: }
5431:
5432: // process
5433:
1.1.1.8 root 5434: psp_t *msdos_psp_create(int psp_seg, UINT16 mcb_seg, UINT16 parent_psp, UINT16 env_seg)
1.1 root 5435: {
5436: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
5437:
5438: memset(psp, 0, PSP_SIZE);
5439: psp->exit[0] = 0xcd;
5440: psp->exit[1] = 0x20;
1.1.1.8 root 5441: psp->first_mcb = mcb_seg;
1.1 root 5442: psp->far_call = 0xea;
5443: psp->cpm_entry.w.l = 0xfff1; // int 21h, retf
5444: psp->cpm_entry.w.h = 0xf000;
5445: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
5446: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
5447: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
5448: psp->parent_psp = parent_psp;
1.1.1.20 root 5449: if(parent_psp == (UINT16)-1) {
5450: for(int i = 0; i < 20; i++) {
5451: if(file_handler[i].valid) {
5452: psp->file_table[i] = i;
5453: } else {
5454: psp->file_table[i] = 0xff;
5455: }
1.1 root 5456: }
1.1.1.20 root 5457: } else {
5458: memcpy(psp->file_table, ((psp_t *)(mem + (parent_psp << 4)))->file_table, 20);
1.1 root 5459: }
5460: psp->env_seg = env_seg;
5461: psp->stack.w.l = REG16(SP);
1.1.1.3 root 5462: psp->stack.w.h = SREG(SS);
1.1.1.14 root 5463: psp->file_table_size = 20;
5464: psp->file_table_ptr.w.l = 0x18;
5465: psp->file_table_ptr.w.h = psp_seg;
1.1 root 5466: psp->service[0] = 0xcd;
5467: psp->service[1] = 0x21;
5468: psp->service[2] = 0xcb;
5469: return(psp);
5470: }
5471:
1.1.1.20 root 5472: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg)
5473: {
5474: if(psp_seg && fd < 20) {
5475: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
5476: psp->file_table[fd] = value;
5477: }
5478: }
5479:
5480: int msdos_psp_get_file_table(int fd, int psp_seg)
5481: {
5482: if(psp_seg && fd < 20) {
5483: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
5484: fd = psp->file_table[fd];
5485: }
5486: return fd;
5487: }
5488:
1.1 root 5489: int msdos_process_exec(char *cmd, param_block_t *param, UINT8 al)
5490: {
5491: // load command file
5492: int fd = -1;
5493: int dos_command = 0;
1.1.1.24 root 5494: char command[MAX_PATH], path[MAX_PATH], opt[MAX_PATH], *name = NULL, name_tmp[MAX_PATH];
1.1 root 5495:
5496: int opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
5497: int opt_len = mem[opt_ofs];
5498: memset(opt, 0, sizeof(opt));
5499: memcpy(opt, mem + opt_ofs + 1, opt_len);
5500:
1.1.1.14 root 5501: if(strlen(cmd) >= 5 && _stricmp(&cmd[strlen(cmd) - 4], ".BAT") == 0) {
5502: // this is a batch file, run command.com
5503: char tmp[MAX_PATH];
5504: if(opt_len != 0) {
5505: sprintf(tmp, "/C %s %s", cmd, opt);
5506: } else {
5507: sprintf(tmp, "/C %s", cmd);
5508: }
5509: strcpy(opt, tmp);
5510: opt_len = strlen(opt);
5511: mem[opt_ofs] = opt_len;
5512: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
5513: strcpy(command, comspec_path);
5514: strcpy(name_tmp, "COMMAND.COM");
5515: } else {
5516: if(_stricmp(cmd, "C:\\COMMAND.COM") == 0) {
5517: // redirect C:\COMMAND.COM to comspec_path
5518: strcpy(command, comspec_path);
5519: } else {
5520: strcpy(command, cmd);
5521: }
1.1.1.24 root 5522: if(GetFullPathName(command, MAX_PATH, path, &name) == 0) {
5523: return(-1);
5524: }
1.1.1.14 root 5525: memset(name_tmp, 0, sizeof(name_tmp));
5526: strcpy(name_tmp, name);
5527:
5528: // check command.com
5529: if(_stricmp(name, "COMMAND.COM") == 0 || _stricmp(name, "COMMAND") == 0) {
5530: if(opt_len == 0) {
5531: // process_t *current_process = msdos_process_info_get(current_psp);
5532: process_t *current_process = NULL;
5533: for(int i = 0; i < MAX_PROCESS; i++) {
5534: if(process[i].psp == current_psp) {
5535: current_process = &process[i];
5536: break;
5537: }
5538: }
5539: if(current_process != NULL) {
5540: param->cmd_line.dw = current_process->dta.dw;
5541: opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
5542: opt_len = mem[opt_ofs];
5543: memset(opt, 0, sizeof(opt));
5544: memcpy(opt, mem + opt_ofs + 1, opt_len);
5545: }
5546: }
5547: for(int i = 0; i < opt_len; i++) {
5548: if(opt[i] == ' ') {
5549: continue;
5550: }
5551: if(opt[i] == '/' && (opt[i + 1] == 'c' || opt[i + 1] == 'C') && opt[i + 2] == ' ') {
5552: for(int j = i + 3; j < opt_len; j++) {
5553: if(opt[j] == ' ') {
5554: continue;
5555: }
5556: char *token = my_strtok(opt + j, " ");
5557:
5558: if(strlen(token) >= 5 && _stricmp(&token[strlen(token) - 4], ".BAT") == 0) {
5559: // this is a batch file, okay to run command.com
5560: } else {
5561: // run program directly without command.com
5562: strcpy(command, token);
5563: char tmp[MAX_PATH];
5564: strcpy(tmp, token + strlen(token) + 1);
5565: strcpy(opt, tmp);
5566: opt_len = strlen(opt);
5567: mem[opt_ofs] = opt_len;
5568: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
5569: dos_command = 1;
5570: }
5571: break;
1.1 root 5572: }
5573: }
1.1.1.14 root 5574: break;
1.1 root 5575: }
5576: }
5577: }
5578:
5579: // load command file
5580: strcpy(path, command);
5581: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
5582: sprintf(path, "%s.COM", command);
5583: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
5584: sprintf(path, "%s.EXE", command);
5585: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
1.1.1.14 root 5586: sprintf(path, "%s.BAT", command);
5587: if(_access(path, 0) == 0) {
5588: // this is a batch file, run command.com
5589: char tmp[MAX_PATH];
5590: if(opt_len != 0) {
5591: sprintf(tmp, "/C %s %s", path, opt);
5592: } else {
5593: sprintf(tmp, "/C %s", path);
5594: }
5595: strcpy(opt, tmp);
5596: opt_len = strlen(opt);
5597: mem[opt_ofs] = opt_len;
5598: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
5599: strcpy(path, comspec_path);
5600: strcpy(name_tmp, "COMMAND.COM");
5601: fd = _open(path, _O_RDONLY | _O_BINARY);
5602: } else {
5603: // search path in parent environments
5604: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
5605: char *env = msdos_env_get(parent_psp->env_seg, "PATH");
5606: if(env != NULL) {
5607: char env_path[4096];
5608: strcpy(env_path, env);
5609: char *token = my_strtok(env_path, ";");
5610:
5611: while(token != NULL) {
5612: if(strlen(token) != 0) {
5613: sprintf(path, "%s", msdos_combine_path(token, command));
5614: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
5615: break;
5616: }
5617: sprintf(path, "%s.COM", msdos_combine_path(token, command));
5618: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
5619: break;
5620: }
5621: sprintf(path, "%s.EXE", msdos_combine_path(token, command));
5622: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
5623: break;
5624: }
5625: sprintf(path, "%s.BAT", msdos_combine_path(token, command));
5626: if(_access(path, 0) == 0) {
5627: // this is a batch file, run command.com
5628: char tmp[MAX_PATH];
5629: if(opt_len != 0) {
5630: sprintf(tmp, "/C %s %s", path, opt);
5631: } else {
5632: sprintf(tmp, "/C %s", path);
5633: }
5634: strcpy(opt, tmp);
5635: opt_len = strlen(opt);
5636: mem[opt_ofs] = opt_len;
5637: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
5638: strcpy(path, comspec_path);
5639: strcpy(name_tmp, "COMMAND.COM");
5640: fd = _open(path, _O_RDONLY | _O_BINARY);
5641: break;
5642: }
1.1.1.8 root 5643: }
1.1.1.14 root 5644: token = my_strtok(NULL, ";");
1.1 root 5645: }
5646: }
5647: }
5648: }
5649: }
5650: }
5651: if(fd == -1) {
5652: if(dos_command) {
5653: // may be dos command
5654: char tmp[MAX_PATH];
5655: sprintf(tmp, "%s %s", command, opt);
5656: system(tmp);
5657: return(0);
5658: } else {
5659: return(-1);
5660: }
5661: }
5662: _read(fd, file_buffer, sizeof(file_buffer));
5663: _close(fd);
5664:
5665: // copy environment
1.1.1.29 root 5666: int umb_linked, env_seg, psp_seg;
1.1 root 5667:
1.1.1.29 root 5668: if((umb_linked = msdos_mem_get_umb_linked()) != 0) {
5669: msdos_mem_unlink_umb();
5670: }
1.1.1.8 root 5671: if((env_seg = msdos_mem_alloc(first_mcb, ENV_SIZE >> 4, 1)) == -1) {
1.1.1.29 root 5672: if((env_seg = msdos_mem_alloc(UMB_TOP >> 4, ENV_SIZE >> 4, 1)) == -1) {
5673: if(umb_linked != 0) {
5674: msdos_mem_link_umb();
5675: }
5676: return(-1);
5677: }
1.1 root 5678: }
5679: if(param->env_seg == 0) {
5680: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
5681: memcpy(mem + (env_seg << 4), mem + (parent_psp->env_seg << 4), ENV_SIZE);
5682: } else {
5683: memcpy(mem + (env_seg << 4), mem + (param->env_seg << 4), ENV_SIZE);
5684: }
5685: msdos_env_set_argv(env_seg, msdos_short_full_path(path));
5686:
5687: // check exe header
5688: exe_header_t *header = (exe_header_t *)file_buffer;
1.1.1.8 root 5689: int paragraphs, free_paragraphs = msdos_mem_get_free(first_mcb, 1);
1.1 root 5690: UINT16 cs, ss, ip, sp;
5691:
5692: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
5693: // memory allocation
5694: int header_size = header->header_size * 16;
5695: int load_size = header->pages * 512 - header_size;
5696: if(header_size + load_size < 512) {
5697: load_size = 512 - header_size;
5698: }
5699: paragraphs = (PSP_SIZE + load_size) >> 4;
5700: if(paragraphs + header->min_alloc > free_paragraphs) {
5701: msdos_mem_free(env_seg);
5702: return(-1);
5703: }
5704: paragraphs += header->max_alloc ? header->max_alloc : header->min_alloc;
5705: if(paragraphs > free_paragraphs) {
5706: paragraphs = free_paragraphs;
5707: }
1.1.1.8 root 5708: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1.1.29 root 5709: if((psp_seg = msdos_mem_alloc(UMB_TOP >> 4, paragraphs, 1)) == -1) {
5710: if(umb_linked != 0) {
5711: msdos_mem_link_umb();
5712: }
5713: msdos_mem_free(env_seg);
5714: return(-1);
5715: }
1.1 root 5716: }
5717: // relocation
5718: int start_seg = psp_seg + (PSP_SIZE >> 4);
5719: for(int i = 0; i < header->relocations; i++) {
5720: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
5721: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
5722: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
5723: }
5724: memcpy(mem + (start_seg << 4), file_buffer + header_size, load_size);
5725: // segments
5726: cs = header->init_cs + start_seg;
5727: ss = header->init_ss + start_seg;
5728: ip = header->init_ip;
5729: sp = header->init_sp - 2; // for symdeb
5730: } else {
5731: // memory allocation
5732: paragraphs = free_paragraphs;
1.1.1.8 root 5733: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1.1.29 root 5734: if((psp_seg = msdos_mem_alloc(UMB_TOP >> 4, paragraphs, 1)) == -1) {
5735: if(umb_linked != 0) {
5736: msdos_mem_link_umb();
5737: }
5738: msdos_mem_free(env_seg);
5739: return(-1);
5740: }
1.1 root 5741: }
5742: int start_seg = psp_seg + (PSP_SIZE >> 4);
5743: memcpy(mem + (start_seg << 4), file_buffer, 0x10000 - PSP_SIZE);
5744: // segments
5745: cs = ss = psp_seg;
5746: ip = 0x100;
5747: sp = 0xfffe;
5748: }
1.1.1.29 root 5749: if(umb_linked != 0) {
5750: msdos_mem_link_umb();
5751: }
1.1 root 5752:
5753: // create psp
1.1.1.3 root 5754: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_eip;
5755: *(UINT16 *)(mem + 4 * 0x22 + 2) = SREG(CS);
1.1 root 5756: psp_t *psp = msdos_psp_create(psp_seg, psp_seg + paragraphs, current_psp, env_seg);
5757: memcpy(psp->fcb1, mem + (param->fcb1.w.h << 4) + param->fcb1.w.l, sizeof(psp->fcb1));
5758: memcpy(psp->fcb2, mem + (param->fcb2.w.h << 4) + param->fcb2.w.l, sizeof(psp->fcb2));
5759: memcpy(psp->buffer, mem + (param->cmd_line.w.h << 4) + param->cmd_line.w.l, sizeof(psp->buffer));
5760:
5761: mcb_t *mcb_env = (mcb_t *)(mem + ((env_seg - 1) << 4));
5762: mcb_t *mcb_psp = (mcb_t *)(mem + ((psp_seg - 1) << 4));
5763: mcb_psp->psp = mcb_env->psp = psp_seg;
5764:
1.1.1.4 root 5765: for(int i = 0; i < 8; i++) {
5766: if(name_tmp[i] == '.') {
5767: mcb_psp->prog_name[i] = '\0';
5768: break;
5769: } else if(i < 7 && msdos_lead_byte_check(name_tmp[i])) {
5770: mcb_psp->prog_name[i] = name_tmp[i];
5771: i++;
5772: mcb_psp->prog_name[i] = name_tmp[i];
5773: } else if(name_tmp[i] >= 'a' && name_tmp[i] <= 'z') {
5774: mcb_psp->prog_name[i] = name_tmp[i] - 'a' + 'A';
5775: } else {
5776: mcb_psp->prog_name[i] = name_tmp[i];
5777: }
5778: }
5779:
1.1 root 5780: // process info
5781: process_t *process = msdos_process_info_create(psp_seg);
5782: strcpy(process->module_dir, msdos_short_full_dir(path));
1.1.1.33! root 5783: #ifdef USE_DEBUGGER
! 5784: strcpy(process->module_path, path);
! 5785: #endif
1.1 root 5786: process->dta.w.l = 0x80;
5787: process->dta.w.h = psp_seg;
5788: process->switchar = '/';
5789: process->max_files = 20;
5790: process->parent_int_10h_feh_called = int_10h_feh_called;
5791: process->parent_int_10h_ffh_called = int_10h_ffh_called;
1.1.1.14 root 5792: process->parent_ds = SREG(DS);
1.1.1.31 root 5793: process->parent_es = SREG(ES);
1.1 root 5794:
5795: current_psp = psp_seg;
1.1.1.23 root 5796: msdos_sda_update(current_psp);
1.1 root 5797:
5798: if(al == 0x00) {
5799: int_10h_feh_called = int_10h_ffh_called = false;
5800:
5801: // registers and segments
5802: REG16(AX) = REG16(BX) = 0x00;
5803: REG16(CX) = 0xff;
5804: REG16(DX) = psp_seg;
5805: REG16(SI) = ip;
5806: REG16(DI) = sp;
5807: REG16(SP) = sp;
1.1.1.3 root 5808: SREG(DS) = SREG(ES) = psp_seg;
5809: SREG(SS) = ss;
5810: i386_load_segment_descriptor(DS);
5811: i386_load_segment_descriptor(ES);
5812: i386_load_segment_descriptor(SS);
1.1 root 5813:
5814: *(UINT16 *)(mem + (ss << 4) + sp) = 0;
5815: i386_jmp_far(cs, ip);
5816: } else if(al == 0x01) {
5817: // copy ss:sp and cs:ip to param block
5818: param->sp = sp;
5819: param->ss = ss;
5820: param->ip = ip;
5821: param->cs = cs;
1.1.1.31 root 5822:
5823: // the AX value to be passed to the child program is put on top of the child's stack
5824: *(UINT16 *)(mem + (ss << 4) + sp) = REG16(AX);
1.1 root 5825: }
5826: return(0);
5827: }
5828:
5829: void msdos_process_terminate(int psp_seg, int ret, int mem_free)
5830: {
5831: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
5832:
5833: *(UINT32 *)(mem + 4 * 0x22) = psp->int_22h.dw;
5834: *(UINT32 *)(mem + 4 * 0x23) = psp->int_23h.dw;
5835: *(UINT32 *)(mem + 4 * 0x24) = psp->int_24h.dw;
5836:
1.1.1.3 root 5837: SREG(SS) = psp->stack.w.h;
5838: i386_load_segment_descriptor(SS);
1.1 root 5839: REG16(SP) = psp->stack.w.l;
5840: i386_jmp_far(psp->int_22h.w.h, psp->int_22h.w.l);
5841:
1.1.1.28 root 5842: // process_t *current_process = msdos_process_info_get(psp_seg);
5843: process_t *current_process = NULL;
5844: for(int i = 0; i < MAX_PROCESS; i++) {
5845: if(process[i].psp == psp_seg) {
5846: current_process = &process[i];
5847: break;
5848: }
5849: }
5850: if(current_process == NULL) {
5851: throw(0x1f); // general failure
5852: }
5853: int_10h_feh_called = current_process->parent_int_10h_feh_called;
5854: int_10h_ffh_called = current_process->parent_int_10h_ffh_called;
5855: if(current_process->called_by_int2eh) {
5856: REG16(AX) = ret;
5857: }
5858: SREG(DS) = current_process->parent_ds;
1.1.1.31 root 5859: SREG(ES) = current_process->parent_es;
1.1.1.14 root 5860: i386_load_segment_descriptor(DS);
1.1.1.31 root 5861: i386_load_segment_descriptor(ES);
1.1 root 5862:
5863: if(mem_free) {
1.1.1.8 root 5864: int mcb_seg;
5865: while((mcb_seg = msdos_mem_get_last_mcb(first_mcb, psp_seg)) != -1) {
5866: msdos_mem_free(mcb_seg + 1);
5867: }
5868: while((mcb_seg = msdos_mem_get_last_mcb(UMB_TOP >> 4, psp_seg)) != -1) {
5869: msdos_mem_free(mcb_seg + 1);
5870: }
1.1 root 5871:
5872: for(int i = 0; i < MAX_FILES; i++) {
5873: if(file_handler[i].valid && file_handler[i].psp == psp_seg) {
5874: _close(i);
1.1.1.20 root 5875: msdos_file_handler_close(i);
5876: msdos_psp_set_file_table(i, 0x0ff, psp_seg); // FIXME: consider duplicated file handles
1.1 root 5877: }
5878: }
1.1.1.13 root 5879: msdos_dta_info_free(psp_seg);
1.1 root 5880: }
1.1.1.14 root 5881: msdos_stdio_reopen();
1.1 root 5882:
1.1.1.28 root 5883: memset(current_process, 0, sizeof(process_t));
1.1 root 5884:
5885: current_psp = psp->parent_psp;
5886: retval = ret;
1.1.1.23 root 5887: msdos_sda_update(current_psp);
1.1 root 5888: }
5889:
5890: // drive
5891:
5892: int msdos_drive_param_block_update(int drive_num, UINT16 *seg, UINT16 *ofs, int force_update)
5893: {
5894: *seg = DPB_TOP >> 4;
5895: *ofs = sizeof(dpb_t) * drive_num;
5896: dpb_t *dpb = (dpb_t *)(mem + (*seg << 4) + *ofs);
5897:
5898: if(!force_update && dpb->free_clusters != 0) {
5899: return(dpb->bytes_per_sector ? 1 : 0);
5900: }
5901: memset(dpb, 0, sizeof(dpb_t));
5902:
5903: int res = 0;
5904: char dev[64];
5905: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
5906:
1.1.1.17 root 5907: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1.1 root 5908: if(hFile != INVALID_HANDLE_VALUE) {
5909: DISK_GEOMETRY geo;
5910: DWORD dwSize;
5911: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
5912: dpb->bytes_per_sector = (UINT16)geo.BytesPerSector;
5913: dpb->highest_sector_num = (UINT8)(geo.SectorsPerTrack - 1);
5914: dpb->highest_cluster_num = (UINT16)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1.1.14 root 5915: dpb->maximum_cluster_num = (UINT32)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1 root 5916: switch(geo.MediaType) {
5917: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
5918: dpb->media_type = 0xff;
5919: break;
5920: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
5921: dpb->media_type = 0xfe;
5922: break;
5923: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
5924: dpb->media_type = 0xfd;
5925: break;
5926: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
5927: dpb->media_type = 0xfc;
5928: break;
5929: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
5930: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
5931: dpb->media_type = 0xf9;
5932: break;
5933: case FixedMedia: // hard disk
5934: case RemovableMedia:
1.1.1.19 root 5935: case Unknown:
1.1 root 5936: dpb->media_type = 0xf8;
5937: break;
5938: default:
5939: dpb->media_type = 0xf0;
5940: break;
5941: }
5942: res = 1;
5943: }
5944: dpb->drive_num = drive_num;
5945: dpb->unit_num = drive_num;
5946: dpb->next_dpb_ofs = *ofs + sizeof(dpb_t);
5947: dpb->next_dpb_seg = *seg;
1.1.1.14 root 5948: dpb->info_sector = 0xffff;
5949: dpb->backup_boot_sector = 0xffff;
1.1 root 5950: dpb->free_clusters = 0xffff;
1.1.1.14 root 5951: dpb->free_search_cluster = 0xffffffff;
1.1 root 5952: CloseHandle(hFile);
5953: }
5954: return(res);
5955: }
5956:
5957: // pc bios
5958:
1.1.1.19 root 5959: UINT32 get_ticks_since_midnight(UINT32 cur_msec)
5960: {
5961: static unsigned __int64 start_msec_since_midnight = 0;
5962: static unsigned __int64 start_msec_since_hostboot = 0;
5963:
5964: if(start_msec_since_midnight == 0) {
5965: SYSTEMTIME time;
5966: GetLocalTime(&time);
5967: start_msec_since_midnight = ((time.wHour * 60 + time.wMinute) * 60 + time.wSecond) * 1000 + time.wMilliseconds;
5968: start_msec_since_hostboot = cur_msec;
5969: }
5970: unsigned __int64 msec = (start_msec_since_midnight + cur_msec - start_msec_since_hostboot) % (24 * 60 * 60 * 1000);
5971: unsigned __int64 tick = msec * 0x1800b0 / (24 * 60 * 60 * 1000);
5972: return (UINT32)tick;
5973: }
5974:
5975: void pcbios_update_daily_timer_counter(UINT32 cur_msec)
5976: {
5977: UINT32 prev_tick = *(UINT32 *)(mem + 0x46c);
5978: UINT32 next_tick = get_ticks_since_midnight(cur_msec);
5979:
5980: if(prev_tick > next_tick) {
5981: mem[0x470] = 1;
5982: }
5983: *(UINT32 *)(mem + 0x46c) = next_tick;
5984: }
5985:
1.1.1.14 root 5986: inline void pcbios_irq0()
5987: {
5988: //++*(UINT32 *)(mem + 0x46c);
1.1.1.19 root 5989: pcbios_update_daily_timer_counter(timeGetTime());
1.1.1.14 root 5990: }
5991:
1.1.1.16 root 5992: int pcbios_get_text_vram_address(int page)
1.1 root 5993: {
5994: if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 5995: return TEXT_VRAM_TOP;
1.1 root 5996: } else {
1.1.1.14 root 5997: return TEXT_VRAM_TOP + VIDEO_REGEN * (page % vram_pages);
1.1 root 5998: }
5999: }
6000:
1.1.1.16 root 6001: int pcbios_get_shadow_buffer_address(int page)
1.1 root 6002: {
1.1.1.14 root 6003: if(!int_10h_feh_called) {
1.1.1.16 root 6004: return pcbios_get_text_vram_address(page);
1.1.1.14 root 6005: } else if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 6006: return SHADOW_BUF_TOP;
6007: } else {
1.1.1.14 root 6008: return SHADOW_BUF_TOP + VIDEO_REGEN * (page % vram_pages);
1.1.1.8 root 6009: }
6010: }
6011:
1.1.1.16 root 6012: int pcbios_get_shadow_buffer_address(int page, int x, int y)
1.1.1.8 root 6013: {
1.1.1.16 root 6014: return pcbios_get_shadow_buffer_address(page) + (x + y * scr_width) * 2;
1.1 root 6015: }
6016:
1.1.1.16 root 6017: void pcbios_set_console_size(int width, int height, bool clr_screen)
1.1 root 6018: {
1.1.1.14 root 6019: // clear the existing screen, not just the new one
6020: int clr_height = max(height, scr_height);
6021:
1.1.1.16 root 6022: if(scr_width != width || scr_height != height) {
6023: change_console_size(width, height);
1.1.1.14 root 6024: }
6025: mem[0x462] = 0;
6026: *(UINT16 *)(mem + 0x44e) = 0;
6027:
1.1.1.16 root 6028: text_vram_top_address = pcbios_get_text_vram_address(0);
6029: text_vram_end_address = text_vram_top_address + width * height * 2;
6030: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(0);
6031: shadow_buffer_end_address = shadow_buffer_top_address + width * height * 2;
1.1 root 6032:
1.1.1.23 root 6033: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.16 root 6034: if(clr_screen) {
1.1.1.14 root 6035: for(int ofs = shadow_buffer_top_address; ofs < shadow_buffer_end_address;) {
6036: mem[ofs++] = 0x20;
6037: mem[ofs++] = 0x07;
6038: }
6039:
6040: EnterCriticalSection(&vram_crit_sect);
6041: for(int y = 0; y < clr_height; y++) {
6042: for(int x = 0; x < scr_width; x++) {
6043: SCR_BUF(y,x).Char.AsciiChar = ' ';
6044: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 6045: }
6046: }
6047: SMALL_RECT rect;
1.1.1.14 root 6048: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + clr_height - 1);
6049: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
6050: vram_length_char = vram_last_length_char = 0;
6051: vram_length_attr = vram_last_length_attr = 0;
6052: LeaveCriticalSection(&vram_crit_sect);
1.1 root 6053: }
1.1.1.14 root 6054: COORD co;
6055: co.X = 0;
6056: co.Y = scr_top;
6057: SetConsoleCursorPosition(hStdout, co);
6058: cursor_moved = true;
6059: SetConsoleTextAttribute(hStdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
1.1 root 6060: }
6061:
1.1.1.16 root 6062: inline void pcbios_int_10h_00h()
6063: {
6064: switch(REG8(AL) & 0x7f) {
6065: case 0x70: // v-text mode
6066: case 0x71: // extended cga v-text mode
6067: pcbios_set_console_size(scr_width, scr_height, !(REG8(AL) & 0x80));
6068: break;
6069: default:
6070: pcbios_set_console_size(80, 25, !(REG8(AL) & 0x80));
6071: break;
6072: }
6073: if(REG8(AL) & 0x80) {
6074: mem[0x487] |= 0x80;
6075: } else {
6076: mem[0x487] &= ~0x80;
6077: }
6078: mem[0x449] = REG8(AL) & 0x7f;
6079: }
6080:
1.1 root 6081: inline void pcbios_int_10h_01h()
6082: {
1.1.1.13 root 6083: mem[0x460] = REG8(CL);
6084: mem[0x461] = REG8(CH);
1.1.1.14 root 6085:
1.1.1.23 root 6086: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 6087: CONSOLE_CURSOR_INFO ci;
6088: GetConsoleCursorInfo(hStdout, &ci);
6089: // ci.bVisible = !(REG8(CH) & 0x60) && REG8(CH) <= REG8(CL);
6090: // if(ci.bVisible) {
6091: int lines = max(8, REG8(CL) + 1);
6092: ci.dwSize = (REG8(CL) - REG8(CH) + 1) * 100 / lines;
6093: // }
6094: SetConsoleCursorInfo(hStdout, &ci);
1.1 root 6095: }
6096:
6097: inline void pcbios_int_10h_02h()
6098: {
1.1.1.14 root 6099: // continuously setting the cursor effectively stops it blinking
6100: if(mem[0x462] == REG8(BH) && (REG8(DL) != mem[0x450 + REG8(BH) * 2] || REG8(DH) != mem[0x451 + REG8(BH) * 2])) {
1.1 root 6101: COORD co;
6102: co.X = REG8(DL);
1.1.1.14 root 6103: co.Y = REG8(DH) + scr_top;
6104:
6105: // some programs hide the cursor by moving it off screen
6106: static bool hidden = false;
1.1.1.23 root 6107: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 6108: CONSOLE_CURSOR_INFO ci;
6109: GetConsoleCursorInfo(hStdout, &ci);
6110:
6111: if(REG8(DH) >= scr_height || !SetConsoleCursorPosition(hStdout, co)) {
6112: if(ci.bVisible) {
6113: ci.bVisible = FALSE;
6114: // SetConsoleCursorInfo(hStdout, &ci);
6115: hidden = true;
6116: }
6117: } else if(hidden) {
6118: if(!ci.bVisible) {
6119: ci.bVisible = TRUE;
6120: // SetConsoleCursorInfo(hStdout, &ci);
6121: }
6122: hidden = false;
6123: }
1.1 root 6124: }
1.1.1.14 root 6125: mem[0x450 + (REG8(BH) % vram_pages) * 2] = REG8(DL);
6126: mem[0x451 + (REG8(BH) % vram_pages) * 2] = REG8(DH);
1.1 root 6127: }
6128:
6129: inline void pcbios_int_10h_03h()
6130: {
1.1.1.14 root 6131: REG8(DL) = mem[0x450 + (REG8(BH) % vram_pages) * 2];
6132: REG8(DH) = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 6133: REG8(CL) = mem[0x460];
6134: REG8(CH) = mem[0x461];
6135: }
6136:
6137: inline void pcbios_int_10h_05h()
6138: {
1.1.1.14 root 6139: if(REG8(AL) >= vram_pages) {
6140: return;
6141: }
6142: if(mem[0x462] != REG8(AL)) {
6143: vram_flush();
6144:
1.1.1.23 root 6145: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6146: SMALL_RECT rect;
1.1.1.14 root 6147: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
6148: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 6149:
1.1.1.16 root 6150: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(mem[0x462]); y < scr_height; y++) {
1.1.1.14 root 6151: for(int x = 0; x < scr_width; x++) {
6152: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
6153: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 6154: }
6155: }
1.1.1.16 root 6156: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(REG8(AL)); y < scr_height; y++) {
1.1.1.14 root 6157: for(int x = 0; x < scr_width; x++) {
6158: SCR_BUF(y,x).Char.AsciiChar = mem[ofs++];
6159: SCR_BUF(y,x).Attributes = mem[ofs++];
1.1 root 6160: }
6161: }
1.1.1.14 root 6162: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 6163:
6164: COORD co;
1.1.1.14 root 6165: co.X = mem[0x450 + REG8(AL) * 2];
6166: co.Y = mem[0x451 + REG8(AL) * 2] + scr_top;
6167: if(co.Y < scr_top + scr_height) {
6168: SetConsoleCursorPosition(hStdout, co);
6169: }
1.1 root 6170: }
1.1.1.14 root 6171: mem[0x462] = REG8(AL);
6172: *(UINT16 *)(mem + 0x44e) = REG8(AL) * VIDEO_REGEN;
6173: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.16 root 6174: text_vram_top_address = pcbios_get_text_vram_address(mem[0x462]);
1.1.1.14 root 6175: text_vram_end_address = text_vram_top_address + regen;
1.1.1.16 root 6176: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(mem[0x462]);
1.1.1.14 root 6177: shadow_buffer_end_address = shadow_buffer_top_address + regen;
1.1 root 6178: }
6179:
6180: inline void pcbios_int_10h_06h()
6181: {
1.1.1.14 root 6182: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
6183: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
6184: return;
6185: }
6186: vram_flush();
6187:
1.1.1.23 root 6188: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6189: SMALL_RECT rect;
1.1.1.14 root 6190: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
6191: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
6192:
6193: int right = min(REG8(DL), scr_width - 1);
6194: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 6195:
6196: if(REG8(AL) == 0) {
1.1.1.14 root 6197: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 6198: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 6199: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
6200: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 6201: }
6202: }
6203: } else {
1.1.1.14 root 6204: for(int y = REG8(CH), y2 = min(REG8(CH) + REG8(AL), bottom + 1); y <= bottom; y++, y2++) {
1.1.1.16 root 6205: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 6206: if(y2 <= bottom) {
6207: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 6208: } else {
1.1.1.14 root 6209: SCR_BUF(y,x).Char.AsciiChar = ' ';
6210: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 6211: }
1.1.1.14 root 6212: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
6213: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 6214: }
6215: }
6216: }
1.1.1.14 root 6217: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 6218: }
6219:
6220: inline void pcbios_int_10h_07h()
6221: {
1.1.1.14 root 6222: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
6223: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
6224: return;
6225: }
6226: vram_flush();
6227:
1.1.1.23 root 6228: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6229: SMALL_RECT rect;
1.1.1.14 root 6230: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
6231: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
6232:
6233: int right = min(REG8(DL), scr_width - 1);
6234: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 6235:
6236: if(REG8(AL) == 0) {
1.1.1.14 root 6237: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 6238: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 6239: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
6240: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 6241: }
6242: }
6243: } else {
1.1.1.14 root 6244: for(int y = bottom, y2 = max(REG8(CH) - 1, bottom - REG8(AL)); y >= REG8(CH); y--, y2--) {
1.1.1.16 root 6245: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 6246: if(y2 >= REG8(CH)) {
6247: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 6248: } else {
1.1.1.14 root 6249: SCR_BUF(y,x).Char.AsciiChar = ' ';
6250: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 6251: }
1.1.1.14 root 6252: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
6253: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 6254: }
6255: }
6256: }
1.1.1.14 root 6257: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 6258: }
6259:
6260: inline void pcbios_int_10h_08h()
6261: {
6262: COORD co;
6263: DWORD num;
6264:
1.1.1.14 root 6265: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
6266: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 6267:
6268: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 6269: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 6270: co.Y += scr_top;
6271: vram_flush();
1.1 root 6272: ReadConsoleOutputCharacter(hStdout, scr_char, 1, co, &num);
6273: ReadConsoleOutputAttribute(hStdout, scr_attr, 1, co, &num);
6274: REG8(AL) = scr_char[0];
6275: REG8(AH) = scr_attr[0];
6276: } else {
1.1.1.16 root 6277: REG16(AX) = *(UINT16 *)(mem + pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y));
1.1 root 6278: }
6279: }
6280:
6281: inline void pcbios_int_10h_09h()
6282: {
6283: COORD co;
6284:
1.1.1.14 root 6285: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
6286: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
6287:
1.1.1.16 root 6288: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
6289: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 6290:
6291: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 6292: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 6293: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 6294: while(dest < end) {
6295: write_text_vram_char(dest - vram, REG8(AL));
6296: mem[dest++] = REG8(AL);
6297: write_text_vram_attr(dest - vram, REG8(BL));
6298: mem[dest++] = REG8(BL);
1.1 root 6299: }
1.1.1.14 root 6300: LeaveCriticalSection(&vram_crit_sect);
1.1 root 6301: } else {
1.1.1.14 root 6302: while(dest < end) {
1.1 root 6303: mem[dest++] = REG8(AL);
6304: mem[dest++] = REG8(BL);
6305: }
6306: }
6307: }
6308:
6309: inline void pcbios_int_10h_0ah()
6310: {
6311: COORD co;
6312:
1.1.1.14 root 6313: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
6314: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
6315:
1.1.1.16 root 6316: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
6317: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 6318:
6319: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 6320: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 6321: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 6322: while(dest < end) {
6323: write_text_vram_char(dest - vram, REG8(AL));
6324: mem[dest++] = REG8(AL);
6325: dest++;
1.1 root 6326: }
1.1.1.14 root 6327: LeaveCriticalSection(&vram_crit_sect);
1.1 root 6328: } else {
1.1.1.14 root 6329: while(dest < end) {
1.1 root 6330: mem[dest++] = REG8(AL);
6331: dest++;
6332: }
6333: }
6334: }
6335:
6336: inline void pcbios_int_10h_0eh()
6337: {
1.1.1.14 root 6338: DWORD num;
6339: COORD co;
6340:
6341: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
6342: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
6343:
6344: if(REG8(AL) == 7) {
6345: //MessageBeep(-1);
6346: } else if(REG8(AL) == 8 || REG8(AL) == 10 || REG8(AL) == 13) {
6347: if(REG8(AL) == 10) {
6348: vram_flush();
6349: }
1.1.1.23 root 6350: WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ®8(AL), 1, &num, NULL);
1.1.1.14 root 6351: cursor_moved = true;
6352: } else {
1.1.1.16 root 6353: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
1.1.1.14 root 6354: if(mem[0x462] == REG8(BH)) {
6355: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 6356: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 6357: write_text_vram_char(dest - vram, REG8(AL));
6358: LeaveCriticalSection(&vram_crit_sect);
6359:
1.1.1.23 root 6360: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 6361: if(++co.X == scr_width) {
6362: co.X = 0;
6363: if(++co.Y == scr_height) {
6364: vram_flush();
6365: WriteConsole(hStdout, "\n", 1, &num, NULL);
6366: cursor_moved = true;
6367: }
6368: }
6369: if(!cursor_moved) {
6370: co.Y += scr_top;
6371: SetConsoleCursorPosition(hStdout, co);
6372: cursor_moved = true;
6373: }
6374: }
6375: mem[dest] = REG8(AL);
6376: }
1.1 root 6377: }
6378:
6379: inline void pcbios_int_10h_0fh()
6380: {
6381: REG8(AL) = mem[0x449];
6382: REG8(AH) = mem[0x44a];
6383: REG8(BH) = mem[0x462];
6384: }
6385:
1.1.1.14 root 6386: inline void pcbios_int_10h_11h()
6387: {
6388: switch(REG8(AL)) {
1.1.1.16 root 6389: case 0x01:
1.1.1.14 root 6390: case 0x11:
1.1.1.16 root 6391: pcbios_set_console_size(80, 28, true);
1.1.1.14 root 6392: break;
1.1.1.16 root 6393: case 0x02:
1.1.1.14 root 6394: case 0x12:
1.1.1.16 root 6395: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 6396: break;
1.1.1.16 root 6397: case 0x04:
1.1.1.14 root 6398: case 0x14:
1.1.1.16 root 6399: pcbios_set_console_size(80, 25, true);
6400: break;
6401: case 0x18:
6402: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 6403: break;
6404: case 0x30:
6405: SREG(ES) = 0;
6406: i386_load_segment_descriptor(ES);
6407: REG16(BP) = 0;
6408: REG16(CX) = mem[0x485];
6409: REG8(DL) = mem[0x484];
6410: break;
6411: }
6412: }
6413:
6414: inline void pcbios_int_10h_12h()
6415: {
1.1.1.16 root 6416: switch(REG8(BL)) {
6417: case 0x10:
1.1.1.14 root 6418: REG16(BX) = 0x0003;
6419: REG16(CX) = 0x0009;
1.1.1.16 root 6420: break;
1.1.1.14 root 6421: }
6422: }
6423:
1.1 root 6424: inline void pcbios_int_10h_13h()
6425: {
1.1.1.3 root 6426: int ofs = SREG_BASE(ES) + REG16(BP);
1.1 root 6427: COORD co;
6428: DWORD num;
6429:
6430: co.X = REG8(DL);
1.1.1.14 root 6431: co.Y = REG8(DH) + scr_top;
6432:
6433: vram_flush();
1.1 root 6434:
6435: switch(REG8(AL)) {
6436: case 0x00:
6437: case 0x01:
6438: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 6439: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6440: CONSOLE_SCREEN_BUFFER_INFO csbi;
6441: GetConsoleScreenBufferInfo(hStdout, &csbi);
6442: SetConsoleCursorPosition(hStdout, co);
6443:
6444: if(csbi.wAttributes != REG8(BL)) {
6445: SetConsoleTextAttribute(hStdout, REG8(BL));
6446: }
1.1.1.14 root 6447: WriteConsole(hStdout, &mem[ofs], REG16(CX), &num, NULL);
6448:
1.1 root 6449: if(csbi.wAttributes != REG8(BL)) {
6450: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
6451: }
6452: if(REG8(AL) == 0x00) {
1.1.1.15 root 6453: if(!restore_console_on_exit) {
6454: GetConsoleScreenBufferInfo(hStdout, &csbi);
6455: scr_top = csbi.srWindow.Top;
6456: }
1.1.1.14 root 6457: co.X = mem[0x450 + REG8(BH) * 2];
6458: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 6459: SetConsoleCursorPosition(hStdout, co);
6460: } else {
6461: cursor_moved = true;
6462: }
6463: } else {
1.1.1.3 root 6464: m_CF = 1;
1.1 root 6465: }
6466: break;
6467: case 0x02:
6468: case 0x03:
6469: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 6470: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6471: CONSOLE_SCREEN_BUFFER_INFO csbi;
6472: GetConsoleScreenBufferInfo(hStdout, &csbi);
6473: SetConsoleCursorPosition(hStdout, co);
6474:
6475: WORD wAttributes = csbi.wAttributes;
6476: for(int i = 0; i < REG16(CX); i++, ofs += 2) {
6477: if(wAttributes != mem[ofs + 1]) {
6478: SetConsoleTextAttribute(hStdout, mem[ofs + 1]);
6479: wAttributes = mem[ofs + 1];
6480: }
1.1.1.14 root 6481: WriteConsole(hStdout, &mem[ofs], 1, &num, NULL);
1.1 root 6482: }
6483: if(csbi.wAttributes != wAttributes) {
6484: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
6485: }
6486: if(REG8(AL) == 0x02) {
1.1.1.14 root 6487: co.X = mem[0x450 + REG8(BH) * 2];
6488: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 6489: SetConsoleCursorPosition(hStdout, co);
6490: } else {
6491: cursor_moved = true;
6492: }
6493: } else {
1.1.1.3 root 6494: m_CF = 1;
1.1 root 6495: }
6496: break;
6497: case 0x10:
6498: case 0x11:
6499: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 6500: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6501: ReadConsoleOutputCharacter(hStdout, scr_char, REG16(CX), co, &num);
6502: ReadConsoleOutputAttribute(hStdout, scr_attr, REG16(CX), co, &num);
6503: for(int i = 0; i < num; i++) {
6504: mem[ofs++] = scr_char[i];
6505: mem[ofs++] = scr_attr[i];
6506: if(REG8(AL) == 0x11) {
6507: mem[ofs++] = 0;
6508: mem[ofs++] = 0;
6509: }
6510: }
6511: } else {
1.1.1.16 root 6512: for(int i = 0, src = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y - scr_top); i < REG16(CX); i++) {
1.1 root 6513: mem[ofs++] = mem[src++];
6514: mem[ofs++] = mem[src++];
6515: if(REG8(AL) == 0x11) {
6516: mem[ofs++] = 0;
6517: mem[ofs++] = 0;
6518: }
1.1.1.14 root 6519: if(++co.X == scr_width) {
6520: if(++co.Y == scr_height) {
1.1 root 6521: break;
6522: }
6523: co.X = 0;
6524: }
6525: }
6526: }
6527: break;
6528: case 0x20:
6529: case 0x21:
6530: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 6531: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 6532: int len = min(REG16(CX), scr_width * scr_height);
6533: for(int i = 0; i < len; i++) {
1.1 root 6534: scr_char[i] = mem[ofs++];
6535: scr_attr[i] = mem[ofs++];
6536: if(REG8(AL) == 0x21) {
6537: ofs += 2;
6538: }
6539: }
1.1.1.14 root 6540: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
6541: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 6542: } else {
1.1.1.16 root 6543: for(int i = 0, dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y - scr_top); i < REG16(CX); i++) {
1.1 root 6544: mem[dest++] = mem[ofs++];
6545: mem[dest++] = mem[ofs++];
6546: if(REG8(AL) == 0x21) {
6547: ofs += 2;
6548: }
1.1.1.14 root 6549: if(++co.X == scr_width) {
6550: if(++co.Y == scr_height) {
1.1 root 6551: break;
6552: }
6553: co.X = 0;
6554: }
6555: }
6556: }
6557: break;
6558: default:
1.1.1.22 root 6559: unimplemented_10h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x10, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.3 root 6560: m_CF = 1;
1.1 root 6561: break;
6562: }
6563: }
6564:
1.1.1.30 root 6565: inline void pcbios_int_10h_18h()
6566: {
6567: switch(REG8(AL)) {
6568: case 0x00:
6569: case 0x01:
6570: // REG8(AL) = 0x86;
6571: REG8(AL) = 0x00;
6572: break;
6573: default:
6574: unimplemented_10h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x10, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
6575: m_CF = 1;
6576: break;
6577: }
6578: }
6579:
1.1.1.14 root 6580: inline void pcbios_int_10h_1ah()
6581: {
6582: switch(REG8(AL)) {
6583: case 0x00:
6584: REG8(AL) = 0x1a;
6585: REG8(BL) = 0x08;
6586: REG8(BH) = 0x00;
6587: break;
6588: default:
1.1.1.22 root 6589: unimplemented_10h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x10, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.14 root 6590: m_CF = 1;
6591: break;
6592: }
6593: }
6594:
1.1 root 6595: inline void pcbios_int_10h_1dh()
6596: {
6597: switch(REG8(AL)) {
6598: case 0x01:
6599: break;
6600: case 0x02:
6601: REG16(BX) = 0;
6602: break;
6603: default:
1.1.1.22 root 6604: unimplemented_10h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x10, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
6605: m_CF = 1;
6606: break;
6607: }
6608: }
6609:
6610: inline void pcbios_int_10h_4fh()
6611: {
6612: switch(REG8(AL)) {
6613: case 0x00:
6614: REG8(AH) = 0x02; // not supported
6615: break;
6616: case 0x01:
6617: case 0x02:
6618: case 0x03:
6619: case 0x04:
6620: case 0x05:
6621: case 0x06:
6622: case 0x07:
6623: case 0x08:
6624: case 0x09:
6625: case 0x0a:
6626: case 0x0b:
6627: case 0x0c:
6628: REG8(AH) = 0x01; // failed
6629: break;
6630: default:
6631: unimplemented_10h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x10, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.3 root 6632: m_CF = 1;
1.1 root 6633: break;
6634: }
6635: }
6636:
6637: inline void pcbios_int_10h_82h()
6638: {
6639: static UINT8 mode = 0;
6640:
6641: switch(REG8(AL)) {
1.1.1.22 root 6642: case 0x00:
1.1 root 6643: if(REG8(BL) != 0xff) {
6644: mode = REG8(BL);
6645: }
6646: REG8(AL) = mode;
6647: break;
6648: default:
1.1.1.22 root 6649: unimplemented_10h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x10, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.3 root 6650: m_CF = 1;
1.1 root 6651: break;
6652: }
6653: }
6654:
1.1.1.22 root 6655: inline void pcbios_int_10h_83h()
6656: {
6657: static UINT8 mode = 0;
6658:
6659: switch(REG8(AL)) {
6660: case 0x00:
6661: REG16(AX) = 0; // offset???
6662: SREG(ES) = (SHADOW_BUF_TOP >> 4);
6663: i386_load_segment_descriptor(ES);
6664: REG16(BX) = (SHADOW_BUF_TOP & 0x0f);
6665: break;
6666: default:
6667: unimplemented_10h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x10, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
6668: m_CF = 1;
6669: break;
6670: }
6671: }
6672:
6673: inline void pcbios_int_10h_90h()
6674: {
6675: REG8(AL) = mem[0x449];
6676: }
6677:
6678: inline void pcbios_int_10h_91h()
6679: {
6680: REG8(AL) = 0x04; // VGA
6681: }
6682:
6683: inline void pcbios_int_10h_efh()
6684: {
6685: REG16(DX) = 0xffff;
6686: }
6687:
1.1 root 6688: inline void pcbios_int_10h_feh()
6689: {
6690: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 6691: SREG(ES) = (SHADOW_BUF_TOP >> 4);
1.1.1.3 root 6692: i386_load_segment_descriptor(ES);
1.1.1.8 root 6693: REG16(DI) = (SHADOW_BUF_TOP & 0x0f);
1.1 root 6694: }
6695: int_10h_feh_called = true;
6696: }
6697:
6698: inline void pcbios_int_10h_ffh()
6699: {
6700: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.23 root 6701: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6702: COORD co;
6703: DWORD num;
6704:
1.1.1.14 root 6705: vram_flush();
6706:
6707: co.X = (REG16(DI) >> 1) % scr_width;
6708: co.Y = (REG16(DI) >> 1) / scr_width;
1.1.1.16 root 6709: int ofs = pcbios_get_shadow_buffer_address(0, co.X, co.Y);
6710: int end = min(ofs + REG16(CX) * 2, pcbios_get_shadow_buffer_address(0, 0, scr_height));
1.1.1.14 root 6711: int len;
6712: for(len = 0; ofs < end; len++) {
6713: scr_char[len] = mem[ofs++];
6714: scr_attr[len] = mem[ofs++];
6715: }
6716: co.Y += scr_top;
6717: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
6718: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 6719: }
6720: int_10h_ffh_called = true;
6721: }
6722:
1.1.1.25 root 6723: inline void pcbios_int_14h_00h()
6724: {
1.1.1.29 root 6725: if(REG16(DX) < 4) {
1.1.1.25 root 6726: static const unsigned int rate[] = {110, 150, 300, 600, 1200, 2400, 4800, 9600};
6727: UINT8 selector = sio_read(REG16(DX), 3);
6728: selector &= ~0x3f;
6729: selector |= REG8(AL) & 0x1f;
6730: UINT16 divisor = 115200 / rate[REG8(AL) >> 5];
6731: sio_write(REG16(DX), 3, selector | 0x80);
6732: sio_write(REG16(DX), 0, divisor & 0xff);
6733: sio_write(REG16(DX), 1, divisor >> 8);
6734: sio_write(REG16(DX), 3, selector);
6735: REG8(AH) = sio_read(REG16(DX), 5);
6736: REG8(AL) = sio_read(REG16(DX), 6);
6737: } else {
6738: REG8(AH) = 0x80;
6739: }
6740: }
6741:
6742: inline void pcbios_int_14h_01h()
6743: {
1.1.1.29 root 6744: if(REG16(DX) < 4) {
1.1.1.25 root 6745: UINT8 selector = sio_read(REG16(DX), 3);
6746: sio_write(REG16(DX), 3, selector & ~0x80);
6747: sio_write(REG16(DX), 0, REG8(AL));
6748: sio_write(REG16(DX), 3, selector);
6749: REG8(AH) = sio_read(REG16(DX), 5);
6750: } else {
6751: REG8(AH) = 0x80;
6752: }
6753: }
6754:
6755: inline void pcbios_int_14h_02h()
6756: {
1.1.1.29 root 6757: if(REG16(DX) < 4) {
1.1.1.25 root 6758: UINT8 selector = sio_read(REG16(DX), 3);
6759: sio_write(REG16(DX), 3, selector & ~0x80);
6760: REG8(AL) = sio_read(REG16(DX), 0);
6761: sio_write(REG16(DX), 3, selector);
6762: REG8(AH) = sio_read(REG16(DX), 5);
6763: } else {
6764: REG8(AH) = 0x80;
6765: }
6766: }
6767:
6768: inline void pcbios_int_14h_03h()
6769: {
1.1.1.29 root 6770: if(REG16(DX) < 4) {
1.1.1.25 root 6771: REG8(AH) = sio_read(REG16(DX), 5);
6772: REG8(AL) = sio_read(REG16(DX), 6);
6773: } else {
6774: REG8(AH) = 0x80;
6775: }
6776: }
6777:
6778: inline void pcbios_int_14h_04h()
6779: {
1.1.1.29 root 6780: if(REG16(DX) < 4) {
1.1.1.25 root 6781: UINT8 selector = sio_read(REG16(DX), 3);
6782: if(REG8(CH) <= 0x03) {
6783: selector = (selector & ~0x03) | REG8(CH);
6784: }
6785: if(REG8(BL) == 0x00) {
6786: selector &= ~0x04;
6787: } else if(REG8(BL) == 0x01) {
6788: selector |= 0x04;
6789: }
6790: if(REG8(BH) == 0x00) {
6791: selector = (selector & ~0x38) | 0x00;
6792: } else if(REG8(BH) == 0x01) {
6793: selector = (selector & ~0x38) | 0x08;
6794: } else if(REG8(BH) == 0x02) {
6795: selector = (selector & ~0x38) | 0x18;
6796: } else if(REG8(BH) == 0x03) {
6797: selector = (selector & ~0x38) | 0x28;
6798: } else if(REG8(BH) == 0x04) {
6799: selector = (selector & ~0x38) | 0x38;
6800: }
6801: if(REG8(AL) == 0x00) {
6802: selector |= 0x40;
6803: } else if(REG8(AL) == 0x01) {
6804: selector &= ~0x40;
6805: }
6806: if(REG8(CL) <= 0x0b) {
6807: static const unsigned int rate[] = {110, 150, 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200};
6808: UINT16 divisor = 115200 / rate[REG8(CL)];
6809: sio_write(REG16(DX), 3, selector | 0x80);
6810: sio_write(REG16(DX), 0, divisor & 0xff);
6811: sio_write(REG16(DX), 1, divisor >> 8);
6812: }
6813: sio_write(REG16(DX), 3, selector);
6814: REG8(AH) = sio_read(REG16(DX), 5);
6815: REG8(AL) = sio_read(REG16(DX), 6);
6816: } else {
6817: REG8(AH) = 0x80;
6818: }
6819: }
6820:
6821: inline void pcbios_int_14h_05h()
6822: {
1.1.1.29 root 6823: if(REG16(DX) < 4) {
1.1.1.25 root 6824: if(REG8(AL) == 0x00) {
6825: REG8(BL) = sio_read(REG16(DX), 4);
6826: REG8(AH) = sio_read(REG16(DX), 5);
6827: REG8(AL) = sio_read(REG16(DX), 6);
6828: } else if(REG8(AL) == 0x01) {
6829: sio_write(REG16(DX), 4, REG8(BL));
6830: REG8(AH) = sio_read(REG16(DX), 5);
6831: REG8(AL) = sio_read(REG16(DX), 6);
6832: } else {
6833: unimplemented_14h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x14, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
6834: }
6835: } else {
6836: REG8(AH) = 0x80;
6837: }
6838: }
6839:
1.1.1.14 root 6840: inline void pcbios_int_15h_10h()
6841: {
1.1.1.22 root 6842: switch(REG8(AL)) {
6843: case 0x00:
1.1.1.14 root 6844: Sleep(10);
6845: hardware_update();
1.1.1.22 root 6846: break;
6847: default:
6848: unimplemented_15h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x15, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.14 root 6849: REG8(AH) = 0x86;
6850: m_CF = 1;
6851: }
6852: }
6853:
1.1 root 6854: inline void pcbios_int_15h_23h()
6855: {
6856: switch(REG8(AL)) {
1.1.1.22 root 6857: case 0x00:
1.1.1.8 root 6858: REG8(CL) = cmos_read(0x2d);
6859: REG8(CH) = cmos_read(0x2e);
1.1 root 6860: break;
1.1.1.22 root 6861: case 0x01:
1.1.1.8 root 6862: cmos_write(0x2d, REG8(CL));
6863: cmos_write(0x2e, REG8(CH));
1.1 root 6864: break;
6865: default:
1.1.1.22 root 6866: unimplemented_15h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x15, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 6867: REG8(AH) = 0x86;
1.1.1.3 root 6868: m_CF = 1;
1.1 root 6869: break;
6870: }
6871: }
6872:
6873: inline void pcbios_int_15h_24h()
6874: {
6875: switch(REG8(AL)) {
1.1.1.22 root 6876: case 0x00:
1.1.1.3 root 6877: i386_set_a20_line(0);
1.1 root 6878: REG8(AH) = 0;
6879: break;
1.1.1.22 root 6880: case 0x01:
1.1.1.3 root 6881: i386_set_a20_line(1);
1.1 root 6882: REG8(AH) = 0;
6883: break;
1.1.1.22 root 6884: case 0x02:
1.1 root 6885: REG8(AH) = 0;
1.1.1.3 root 6886: REG8(AL) = (m_a20_mask >> 20) & 1;
1.1 root 6887: REG16(CX) = 0;
6888: break;
1.1.1.22 root 6889: case 0x03:
1.1 root 6890: REG16(AX) = 0;
6891: REG16(BX) = 0;
6892: break;
1.1.1.22 root 6893: default:
6894: unimplemented_15h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x15, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
6895: REG8(AH) = 0x86;
6896: m_CF = 1;
6897: break;
1.1 root 6898: }
6899: }
6900:
6901: inline void pcbios_int_15h_49h()
6902: {
1.1.1.27 root 6903: REG8(AH) = 0x00;
6904: REG8(BL) = 0x00; // DOS/V
1.1 root 6905: }
6906:
1.1.1.22 root 6907: inline void pcbios_int_15h_50h()
6908: {
6909: switch(REG8(AL)) {
6910: case 0x00:
6911: case 0x01:
6912: if(REG8(BH) != 0x00 && REG8(BH) != 0x01) {
6913: REG8(AH) = 0x01; // invalid font type in bh
6914: m_CF = 1;
1.1.1.27 root 6915: } else if(REG8(BL) != 0x00) {
1.1.1.22 root 6916: REG8(AH) = 0x02; // bl not zero
6917: m_CF = 1;
6918: } else if(REG16(BP) != 0 && REG16(BP) != 437 && REG16(BP) != 932 && REG16(BP) != 934 && REG16(BP) != 936 && REG16(BP) != 938) {
6919: REG8(AH) = 0x04; // invalid code page
6920: m_CF = 1;
1.1.1.27 root 6921: } else if(REG8(AL) == 0x01) {
6922: REG8(AH) = 0x06; // font is read only
1.1.1.22 root 6923: m_CF = 1;
1.1.1.27 root 6924: } else {
6925: // dummy font read routine is at fffd:000d
6926: SREG(ES) = 0xfffd;
6927: i386_load_segment_descriptor(ES);
1.1.1.32 root 6928: REG16(BX) = 0x000d;
1.1.1.27 root 6929: REG8(AH) = 0x00; // success
1.1.1.22 root 6930: }
6931: break;
6932: default:
6933: unimplemented_15h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x15, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
6934: REG8(AH) = 0x86;
6935: m_CF = 1;
6936: break;
6937: }
6938: }
6939:
1.1.1.30 root 6940: inline void pcbios_int_15h_53h()
6941: {
6942: switch(REG8(AL)) {
6943: case 0x00:
6944: // APM is not installed
6945: REG8(AH) = 0x86;
6946: m_CF = 1;
6947: break;
6948: default:
6949: unimplemented_15h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x15, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
6950: REG8(AH) = 0x86;
6951: m_CF = 1;
6952: break;
6953: }
6954: }
6955:
1.1 root 6956: inline void pcbios_int_15h_86h()
6957: {
6958: UINT32 usec = (REG16(CX) << 16) | REG16(DX);
1.1.1.14 root 6959: UINT32 msec = usec / 1000;
6960:
6961: while(msec) {
6962: UINT32 tmp = min(msec, 100);
6963: if(msec - tmp < 10) {
6964: tmp = msec;
6965: }
6966: Sleep(tmp);
6967:
6968: if(m_halted) {
6969: return;
6970: }
6971: msec -= tmp;
6972: }
1.1 root 6973: }
6974:
6975: inline void pcbios_int_15h_87h()
6976: {
6977: // copy extended memory (from DOSBox)
6978: int len = REG16(CX) * 2;
1.1.1.3 root 6979: int ofs = SREG_BASE(ES) + REG16(SI);
1.1 root 6980: int src = (*(UINT32 *)(mem + ofs + 0x12) & 0xffffff); // + (mem[ofs + 0x16] << 24);
6981: int dst = (*(UINT32 *)(mem + ofs + 0x1a) & 0xffffff); // + (mem[ofs + 0x1e] << 24);
6982: memcpy(mem + dst, mem + src, len);
6983: REG16(AX) = 0x00;
6984: }
6985:
6986: inline void pcbios_int_15h_88h()
6987: {
1.1.1.17 root 6988: REG16(AX) = ((min(MAX_MEM, 0x4000000) - 0x100000) >> 10);
1.1 root 6989: }
6990:
6991: inline void pcbios_int_15h_89h()
6992: {
1.1.1.21 root 6993: #if defined(HAS_I286) || defined(HAS_I386)
1.1 root 6994: // switch to protected mode (from DOSBox)
6995: write_io_byte(0x20, 0x10);
6996: write_io_byte(0x21, REG8(BH));
6997: write_io_byte(0x21, 0x00);
6998: write_io_byte(0xa0, 0x10);
6999: write_io_byte(0xa1, REG8(BL));
7000: write_io_byte(0xa1, 0x00);
1.1.1.3 root 7001: i386_set_a20_line(1);
7002: int ofs = SREG_BASE(ES) + REG16(SI);
7003: m_gdtr.limit = *(UINT16 *)(mem + ofs + 0x08);
7004: m_gdtr.base = *(UINT32 *)(mem + ofs + 0x08 + 0x02) & 0xffffff;
7005: m_idtr.limit = *(UINT16 *)(mem + ofs + 0x10);
7006: m_idtr.base = *(UINT32 *)(mem + ofs + 0x10 + 0x02) & 0xffffff;
7007: #if defined(HAS_I386)
7008: m_cr[0] |= 1;
7009: #else
7010: m_msw |= 1;
7011: #endif
7012: SREG(DS) = 0x18;
7013: SREG(ES) = 0x20;
7014: SREG(SS) = 0x28;
7015: i386_load_segment_descriptor(DS);
7016: i386_load_segment_descriptor(ES);
7017: i386_load_segment_descriptor(SS);
1.1.1.21 root 7018: UINT16 offset = *(UINT16 *)(mem + SREG_BASE(SS) + REG16(SP));
1.1 root 7019: REG16(SP) += 6;
1.1.1.3 root 7020: #if defined(HAS_I386)
1.1.1.21 root 7021: UINT32 flags = get_flags();
7022: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
7023: set_flags(flags);
1.1.1.3 root 7024: #else
1.1.1.21 root 7025: UINT32 flags = CompressFlags();
7026: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
7027: ExpandFlags(flags);
1.1.1.3 root 7028: #endif
1.1 root 7029: REG16(AX) = 0x00;
1.1.1.21 root 7030: i386_jmp_far(0x30, /*REG16(CX)*/offset);
1.1 root 7031: #else
1.1.1.21 root 7032: // i86/i186/v30: protected mode is not supported
1.1 root 7033: REG8(AH) = 0x86;
1.1.1.3 root 7034: m_CF = 1;
1.1 root 7035: #endif
7036: }
7037:
1.1.1.21 root 7038: inline void pcbios_int_15h_8ah()
7039: {
7040: UINT32 size = MAX_MEM - 0x100000;
7041: REG16(AX) = size & 0xffff;
7042: REG16(DX) = size >> 16;
7043: }
7044:
1.1.1.3 root 7045: #if defined(HAS_I386)
1.1 root 7046: inline void pcbios_int_15h_c9h()
7047: {
7048: REG8(AH) = 0x00;
7049: REG8(CH) = cpu_type;
7050: REG8(CL) = cpu_step;
7051: }
1.1.1.3 root 7052: #endif
1.1 root 7053:
7054: inline void pcbios_int_15h_cah()
7055: {
7056: switch(REG8(AL)) {
1.1.1.22 root 7057: case 0x00:
1.1 root 7058: if(REG8(BL) > 0x3f) {
7059: REG8(AH) = 0x03;
1.1.1.3 root 7060: m_CF = 1;
1.1 root 7061: } else if(REG8(BL) < 0x0e) {
7062: REG8(AH) = 0x04;
1.1.1.3 root 7063: m_CF = 1;
1.1 root 7064: } else {
1.1.1.8 root 7065: REG8(CL) = cmos_read(REG8(BL));
1.1 root 7066: }
7067: break;
1.1.1.22 root 7068: case 0x01:
1.1 root 7069: if(REG8(BL) > 0x3f) {
7070: REG8(AH) = 0x03;
1.1.1.3 root 7071: m_CF = 1;
1.1 root 7072: } else if(REG8(BL) < 0x0e) {
7073: REG8(AH) = 0x04;
1.1.1.3 root 7074: m_CF = 1;
1.1 root 7075: } else {
1.1.1.8 root 7076: cmos_write(REG8(BL), REG8(CL));
1.1 root 7077: }
7078: break;
7079: default:
1.1.1.22 root 7080: unimplemented_15h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x15, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 7081: REG8(AH) = 0x86;
1.1.1.3 root 7082: m_CF = 1;
1.1 root 7083: break;
7084: }
7085: }
7086:
1.1.1.22 root 7087: inline void pcbios_int_15h_e8h()
1.1.1.17 root 7088: {
1.1.1.22 root 7089: switch(REG8(AL)) {
7090: #if defined(HAS_I386)
7091: case 0x01:
7092: REG16(AX) = REG16(CX) = ((min(MAX_MEM, 0x1000000) - 0x100000) >> 10);
7093: REG16(BX) = REG16(DX) = ((max(MAX_MEM, 0x1000000) - 0x1000000) >> 16);
7094: break;
1.1.1.17 root 7095: #endif
1.1.1.22 root 7096: default:
7097: unimplemented_15h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x15, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
7098: REG8(AH) = 0x86;
7099: m_CF = 1;
7100: break;
7101: }
7102: }
1.1.1.17 root 7103:
1.1.1.33! root 7104: void pcbios_update_key_code(bool wait)
1.1 root 7105: {
1.1.1.32 root 7106: if(key_buf_char != NULL && key_buf_scan != NULL) {
7107: if(key_buf_char->count() == 0) {
7108: if(!update_key_buffer()) {
1.1.1.33! root 7109: if(wait) {
1.1.1.32 root 7110: Sleep(10);
7111: } else {
7112: maybe_idle();
7113: }
1.1.1.14 root 7114: }
7115: }
1.1.1.32 root 7116: if(key_buf_char->count() != 0) {
1.1.1.33! root 7117: key_code = key_buf_char->read() | (key_buf_scan->read() << 8);
! 7118: key_recv = 0x0000ffff;
1.1.1.32 root 7119: }
7120: if(key_buf_char->count() != 0) {
1.1.1.33! root 7121: key_code |= (key_buf_char->read() << 16) | (key_buf_scan->read() << 24);
! 7122: key_recv |= 0xffff0000;
1.1.1.32 root 7123: }
1.1 root 7124: }
7125: }
7126:
7127: inline void pcbios_int_16h_00h()
7128: {
1.1.1.33! root 7129: while(key_recv == 0 && !m_halted) {
! 7130: pcbios_update_key_code(true);
1.1 root 7131: }
1.1.1.33! root 7132: if((key_recv & 0x0000ffff) && (key_recv & 0xffff0000)) {
! 7133: if((key_code & 0xffff) == 0x0000 || (key_code & 0xffff) == 0xe000) {
! 7134: if(REG8(AH) == 0x10) {
! 7135: key_code = ((key_code >> 8) & 0xff) | ((key_code >> 16) & 0xff00);
! 7136: } else {
! 7137: key_code = ((key_code >> 16) & 0xff00);
! 7138: }
! 7139: key_recv >>= 16;
1.1 root 7140: }
7141: }
7142: REG16(AX) = key_code & 0xffff;
7143: key_code >>= 16;
1.1.1.33! root 7144: key_recv >>= 16;
1.1 root 7145: }
7146:
7147: inline void pcbios_int_16h_01h()
7148: {
1.1.1.33! root 7149: if(key_recv == 0) {
! 7150: pcbios_update_key_code(false);
1.1.1.5 root 7151: }
1.1.1.33! root 7152: if(key_recv != 0) {
! 7153: UINT32 key_code_tmp = key_code;
! 7154: if((key_recv & 0x0000ffff) && (key_recv & 0xffff0000)) {
! 7155: if((key_code_tmp & 0xffff) == 0x0000 || (key_code_tmp & 0xffff) == 0xe000) {
! 7156: if(REG8(AH) == 0x11) {
! 7157: key_code_tmp = ((key_code_tmp >> 8) & 0xff) | ((key_code_tmp >> 16) & 0xff00);
! 7158: } else {
! 7159: key_code_tmp = ((key_code_tmp >> 16) & 0xff00);
! 7160: }
! 7161: }
1.1 root 7162: }
1.1.1.5 root 7163: REG16(AX) = key_code_tmp & 0xffff;
1.1.1.3 root 7164: #if defined(HAS_I386)
1.1.1.33! root 7165: m_ZF = 0;
! 7166: #else
! 7167: m_ZeroVal = 1;
! 7168: #endif
! 7169: } else {
! 7170: #if defined(HAS_I386)
! 7171: m_ZF = 1;
1.1.1.3 root 7172: #else
1.1.1.33! root 7173: m_ZeroVal = 0;
1.1.1.3 root 7174: #endif
1.1.1.33! root 7175: }
1.1 root 7176: }
7177:
7178: inline void pcbios_int_16h_02h()
7179: {
7180: REG8(AL) = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
7181: REG8(AL) |= (GetAsyncKeyState(VK_CAPITAL) & 0x0001) ? 0x40 : 0;
7182: REG8(AL) |= (GetAsyncKeyState(VK_NUMLOCK) & 0x0001) ? 0x20 : 0;
7183: REG8(AL) |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
7184: REG8(AL) |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
7185: REG8(AL) |= (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? 0x04 : 0;
7186: REG8(AL) |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
7187: REG8(AL) |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
7188: }
7189:
7190: inline void pcbios_int_16h_03h()
7191: {
7192: static UINT16 status = 0;
7193:
7194: switch(REG8(AL)) {
7195: case 0x05:
7196: status = REG16(BX);
7197: break;
7198: case 0x06:
7199: REG16(BX) = status;
7200: break;
7201: default:
1.1.1.3 root 7202: m_CF = 1;
1.1 root 7203: break;
7204: }
7205: }
7206:
7207: inline void pcbios_int_16h_05h()
7208: {
1.1.1.32 root 7209: if(key_buf_char != NULL && key_buf_scan != NULL) {
7210: key_buf_char->write(REG8(CL));
7211: key_buf_scan->write(REG8(CH));
7212: }
1.1 root 7213: REG8(AL) = 0x00;
7214: }
7215:
7216: inline void pcbios_int_16h_12h()
7217: {
7218: pcbios_int_16h_02h();
7219:
7220: REG8(AH) = 0;//(GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x80 : 0;
7221: REG8(AH) |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
7222: REG8(AH) |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
7223: REG8(AH) |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
7224: REG8(AH) |= (GetAsyncKeyState(VK_RMENU ) & 0x8000) ? 0x08 : 0;
7225: REG8(AH) |= (GetAsyncKeyState(VK_RCONTROL) & 0x8000) ? 0x04 : 0;
7226: REG8(AH) |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
7227: REG8(AH) |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
7228: }
7229:
7230: inline void pcbios_int_16h_13h()
7231: {
7232: static UINT16 status = 0;
7233:
7234: switch(REG8(AL)) {
7235: case 0x00:
7236: status = REG16(DX);
7237: break;
7238: case 0x01:
7239: REG16(DX) = status;
7240: break;
7241: default:
1.1.1.22 root 7242: unimplemented_16h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x16, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.3 root 7243: m_CF = 1;
1.1 root 7244: break;
7245: }
7246: }
7247:
7248: inline void pcbios_int_16h_14h()
7249: {
7250: static UINT8 status = 0;
7251:
7252: switch(REG8(AL)) {
7253: case 0x00:
7254: case 0x01:
7255: status = REG8(AL);
7256: break;
7257: case 0x02:
7258: REG8(AL) = status;
7259: break;
7260: default:
1.1.1.22 root 7261: unimplemented_16h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x16, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.3 root 7262: m_CF = 1;
1.1 root 7263: break;
7264: }
7265: }
7266:
1.1.1.24 root 7267: inline void pcbios_int_16h_55h()
7268: {
7269: switch(REG8(AL)) {
7270: case 0x00:
7271: // keyboard tsr is not present
7272: break;
7273: case 0xfe:
7274: // handlers for INT 08, INT 09, INT 16, INT 1B, and INT 1C are installed
7275: break;
7276: case 0xff:
7277: break;
7278: default:
7279: unimplemented_16h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x16, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
7280: m_CF = 1;
7281: break;
7282: }
7283: }
7284:
1.1.1.30 root 7285: inline void pcbios_int_16h_6fh()
7286: {
7287: switch(REG8(AL)) {
7288: case 0x00:
7289: // HP Vectra EX-BIOS - "F16_INQUIRE" - Extended BIOS is not installed
7290: break;
7291: default:
7292: unimplemented_16h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x16, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
7293: m_CF = 1;
7294: break;
7295: }
7296: }
7297:
1.1 root 7298: inline void pcbios_int_1ah_00h()
7299: {
1.1.1.19 root 7300: pcbios_update_daily_timer_counter(timeGetTime());
7301: REG16(CX) = *(UINT16 *)(mem + 0x46e);
7302: REG16(DX) = *(UINT16 *)(mem + 0x46c);
7303: REG8(AL) = mem[0x470];
7304: mem[0x470] = 0;
1.1 root 7305: }
7306:
7307: inline int to_bcd(int t)
7308: {
7309: int u = (t % 100) / 10;
7310: return (u << 4) | (t % 10);
7311: }
7312:
7313: inline void pcbios_int_1ah_02h()
7314: {
7315: SYSTEMTIME time;
7316:
7317: GetLocalTime(&time);
7318: REG8(CH) = to_bcd(time.wHour);
7319: REG8(CL) = to_bcd(time.wMinute);
7320: REG8(DH) = to_bcd(time.wSecond);
7321: REG8(DL) = 0x00;
7322: }
7323:
7324: inline void pcbios_int_1ah_04h()
7325: {
7326: SYSTEMTIME time;
7327:
7328: GetLocalTime(&time);
7329: REG8(CH) = to_bcd(time.wYear / 100);
7330: REG8(CL) = to_bcd(time.wYear);
7331: REG8(DH) = to_bcd(time.wMonth);
7332: REG8(DL) = to_bcd(time.wDay);
7333: }
7334:
7335: inline void pcbios_int_1ah_0ah()
7336: {
7337: SYSTEMTIME time;
7338: FILETIME file_time;
7339: WORD dos_date, dos_time;
7340:
7341: GetLocalTime(&time);
7342: SystemTimeToFileTime(&time, &file_time);
7343: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time);
7344: REG16(CX) = dos_date;
7345: }
7346:
7347: // msdos system call
7348:
7349: inline void msdos_int_21h_00h()
7350: {
1.1.1.3 root 7351: msdos_process_terminate(SREG(CS), retval, 1);
1.1 root 7352: }
7353:
7354: inline void msdos_int_21h_01h()
7355: {
7356: REG8(AL) = msdos_getche();
1.1.1.33! root 7357: ctrl_break_detected = ctrl_break_pressed;
1.1.1.26 root 7358:
1.1.1.8 root 7359: // some seconds may be passed in console
1.1 root 7360: hardware_update();
7361: }
7362:
7363: inline void msdos_int_21h_02h()
7364: {
1.1.1.33! root 7365: UINT8 data = REG8(DL);
! 7366: msdos_putch(data);
! 7367: REG8(AL) = data;
! 7368: ctrl_break_detected = ctrl_break_pressed;
1.1 root 7369: }
7370:
7371: inline void msdos_int_21h_03h()
7372: {
7373: REG8(AL) = msdos_aux_in();
7374: }
7375:
7376: inline void msdos_int_21h_04h()
7377: {
7378: msdos_aux_out(REG8(DL));
7379: }
7380:
7381: inline void msdos_int_21h_05h()
7382: {
7383: msdos_prn_out(REG8(DL));
7384: }
7385:
7386: inline void msdos_int_21h_06h()
7387: {
7388: if(REG8(DL) == 0xff) {
7389: if(msdos_kbhit()) {
7390: REG8(AL) = msdos_getch();
1.1.1.3 root 7391: #if defined(HAS_I386)
7392: m_ZF = 0;
7393: #else
7394: m_ZeroVal = 1;
7395: #endif
1.1 root 7396: } else {
7397: REG8(AL) = 0;
1.1.1.3 root 7398: #if defined(HAS_I386)
7399: m_ZF = 1;
7400: #else
7401: m_ZeroVal = 0;
7402: #endif
1.1.1.14 root 7403: maybe_idle();
1.1 root 7404: }
7405: } else {
1.1.1.33! root 7406: UINT8 data = REG8(DL);
! 7407: msdos_putch(data);
! 7408: REG8(AL) = data;
1.1 root 7409: }
7410: }
7411:
7412: inline void msdos_int_21h_07h()
7413: {
7414: REG8(AL) = msdos_getch();
1.1.1.26 root 7415:
1.1.1.8 root 7416: // some seconds may be passed in console
1.1 root 7417: hardware_update();
7418: }
7419:
7420: inline void msdos_int_21h_08h()
7421: {
7422: REG8(AL) = msdos_getch();
1.1.1.33! root 7423: ctrl_break_detected = ctrl_break_pressed;
1.1.1.26 root 7424:
1.1.1.8 root 7425: // some seconds may be passed in console
1.1 root 7426: hardware_update();
7427: }
7428:
7429: inline void msdos_int_21h_09h()
7430: {
1.1.1.21 root 7431: msdos_stdio_reopen();
7432:
1.1.1.20 root 7433: process_t *process = msdos_process_info_get(current_psp);
7434: int fd = msdos_psp_get_file_table(1, current_psp);
7435:
1.1.1.14 root 7436: char *str = (char *)(mem + SREG_BASE(DS) + REG16(DX));
7437: int len = 0;
1.1 root 7438:
1.1.1.14 root 7439: while(str[len] != '$' && len < 0x10000) {
7440: len++;
7441: }
1.1.1.20 root 7442: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 7443: // stdout is redirected to file
1.1.1.20 root 7444: msdos_write(fd, str, len);
1.1 root 7445: } else {
7446: for(int i = 0; i < len; i++) {
1.1.1.14 root 7447: msdos_putch(str[i]);
1.1 root 7448: }
7449: }
1.1.1.33! root 7450: REG8(AL) = '$';
! 7451: ctrl_break_detected = ctrl_break_pressed;
1.1 root 7452: }
7453:
7454: inline void msdos_int_21h_0ah()
7455: {
1.1.1.3 root 7456: int ofs = SREG_BASE(DS) + REG16(DX);
1.1 root 7457: int max = mem[ofs] - 1;
7458: UINT8 *buf = mem + ofs + 2;
7459: int chr, p = 0;
7460:
7461: while((chr = msdos_getch()) != 0x0d) {
1.1.1.33! root 7462: if((ctrl_break_checking && ctrl_break_pressed) || ctrl_c_pressed) {
1.1.1.26 root 7463: p = 0;
1.1.1.33! root 7464: msdos_putch(0x03);
! 7465: msdos_putch(0x0d);
! 7466: msdos_putch(0x0a);
1.1.1.26 root 7467: break;
1.1.1.33! root 7468: } else if(ctrl_break_pressed) {
! 7469: // skip this byte
1.1.1.26 root 7470: } else if(chr == 0x00) {
1.1 root 7471: // skip 2nd byte
7472: msdos_getch();
7473: } else if(chr == 0x08) {
7474: // back space
7475: if(p > 0) {
7476: p--;
1.1.1.20 root 7477: if(msdos_ctrl_code_check(buf[p])) {
7478: msdos_putch(chr);
7479: msdos_putch(chr);
7480: msdos_putch(' ');
7481: msdos_putch(' ');
7482: msdos_putch(chr);
7483: msdos_putch(chr);
7484: } else {
7485: msdos_putch(chr);
7486: msdos_putch(' ');
7487: msdos_putch(chr);
7488: }
1.1 root 7489: }
7490: } else if(p < max) {
7491: buf[p++] = chr;
7492: msdos_putch(chr);
7493: }
7494: }
7495: buf[p] = 0x0d;
7496: mem[ofs + 1] = p;
1.1.1.33! root 7497: ctrl_break_detected = ctrl_break_pressed;
1.1.1.26 root 7498:
1.1.1.8 root 7499: // some seconds may be passed in console
1.1 root 7500: hardware_update();
7501: }
7502:
7503: inline void msdos_int_21h_0bh()
7504: {
7505: if(msdos_kbhit()) {
7506: REG8(AL) = 0xff;
7507: } else {
7508: REG8(AL) = 0x00;
1.1.1.14 root 7509: maybe_idle();
1.1 root 7510: }
1.1.1.33! root 7511: ctrl_break_detected = ctrl_break_pressed;
1.1 root 7512: }
7513:
7514: inline void msdos_int_21h_0ch()
7515: {
7516: // clear key buffer
1.1.1.21 root 7517: msdos_stdio_reopen();
7518:
1.1.1.20 root 7519: process_t *process = msdos_process_info_get(current_psp);
7520: int fd = msdos_psp_get_file_table(0, current_psp);
7521:
7522: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 7523: // stdin is redirected to file
7524: } else {
7525: while(msdos_kbhit()) {
7526: msdos_getch();
7527: }
7528: }
7529:
7530: switch(REG8(AL)) {
7531: case 0x01:
7532: msdos_int_21h_01h();
7533: break;
7534: case 0x06:
7535: msdos_int_21h_06h();
7536: break;
7537: case 0x07:
7538: msdos_int_21h_07h();
7539: break;
7540: case 0x08:
7541: msdos_int_21h_08h();
7542: break;
7543: case 0x0a:
7544: msdos_int_21h_0ah();
7545: break;
7546: default:
1.1.1.22 root 7547: // unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
7548: // REG16(AX) = 0x01;
7549: // m_CF = 1;
1.1 root 7550: break;
7551: }
7552: }
7553:
7554: inline void msdos_int_21h_0dh()
7555: {
7556: }
7557:
7558: inline void msdos_int_21h_0eh()
7559: {
7560: if(REG8(DL) < 26) {
7561: _chdrive(REG8(DL) + 1);
7562: msdos_cds_update(REG8(DL));
1.1.1.23 root 7563: msdos_sda_update(current_psp);
1.1 root 7564: }
7565: REG8(AL) = 26; // zdrive
7566: }
7567:
1.1.1.14 root 7568: inline void msdos_int_21h_0fh()
7569: {
7570: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
7571: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
7572: char *path = msdos_fcb_path(fcb);
7573: HANDLE hFile = CreateFile(path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.16 root 7574:
1.1.1.14 root 7575: if(hFile == INVALID_HANDLE_VALUE) {
7576: REG8(AL) = 0xff;
7577: } else {
7578: REG8(AL) = 0;
7579: fcb->current_block = 0;
7580: fcb->record_size = 128;
7581: fcb->file_size = GetFileSize(hFile, NULL);
7582: fcb->handle = hFile;
7583: fcb->cur_record = 0;
7584: }
7585: }
7586:
7587: inline void msdos_int_21h_10h()
7588: {
7589: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
7590: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
7591:
7592: REG8(AL) = CloseHandle(fcb->handle) ? 0 : 0xff;
7593: }
7594:
1.1 root 7595: inline void msdos_int_21h_11h()
7596: {
1.1.1.3 root 7597: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
7598: fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 7599:
7600: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 7601: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
7602: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
7603: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 7604: char *path = msdos_fcb_path(fcb);
7605: WIN32_FIND_DATA fd;
7606:
1.1.1.13 root 7607: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
7608: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
7609: FindClose(dtainfo->find_handle);
7610: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7611: }
7612: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 7613: dtainfo->allowable_mask = (ext_fcb->flag == 0xff) ? ext_fcb->attribute : 0x20;
7614: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 7615:
1.1.1.14 root 7616: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
7617: dtainfo->allowable_mask &= ~8;
1.1 root 7618: }
1.1.1.14 root 7619: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
7620: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 7621: !msdos_find_file_has_8dot3name(&fd)) {
7622: if(!FindNextFile(dtainfo->find_handle, &fd)) {
7623: FindClose(dtainfo->find_handle);
7624: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7625: break;
7626: }
7627: }
7628: }
1.1.1.13 root 7629: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 7630: if(ext_fcb->flag == 0xff) {
7631: ext_find->flag = 0xff;
7632: memset(ext_find->reserved, 0, 5);
7633: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
7634: }
7635: find->drive = _getdrive();
1.1.1.13 root 7636: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 7637: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
7638: find->nt_res = 0;
7639: msdos_find_file_conv_local_time(&fd);
7640: find->create_time_ms = 0;
7641: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
7642: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
7643: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
7644: find->cluster_hi = find->cluster_lo = 0;
7645: find->file_size = fd.nFileSizeLow;
7646: REG8(AL) = 0x00;
1.1.1.14 root 7647: } else if(dtainfo->allowable_mask & 8) {
1.1 root 7648: if(ext_fcb->flag == 0xff) {
7649: ext_find->flag = 0xff;
7650: memset(ext_find->reserved, 0, 5);
7651: ext_find->attribute = 8;
7652: }
7653: find->drive = _getdrive();
7654: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
7655: find->attribute = 8;
7656: find->nt_res = 0;
7657: msdos_find_file_conv_local_time(&fd);
7658: find->create_time_ms = 0;
7659: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
7660: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
7661: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
7662: find->cluster_hi = find->cluster_lo = 0;
7663: find->file_size = 0;
1.1.1.14 root 7664: dtainfo->allowable_mask &= ~8;
1.1 root 7665: REG8(AL) = 0x00;
7666: } else {
7667: REG8(AL) = 0xff;
7668: }
7669: }
7670:
7671: inline void msdos_int_21h_12h()
7672: {
1.1.1.3 root 7673: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1.1.14 root 7674: // fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 7675:
7676: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 7677: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
7678: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
7679: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 7680: WIN32_FIND_DATA fd;
7681:
1.1.1.13 root 7682: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
7683: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
7684: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 7685: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 7686: !msdos_find_file_has_8dot3name(&fd)) {
7687: if(!FindNextFile(dtainfo->find_handle, &fd)) {
7688: FindClose(dtainfo->find_handle);
7689: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7690: break;
7691: }
7692: }
7693: } else {
1.1.1.13 root 7694: FindClose(dtainfo->find_handle);
7695: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7696: }
7697: }
1.1.1.13 root 7698: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 7699: if(ext_fcb->flag == 0xff) {
7700: ext_find->flag = 0xff;
7701: memset(ext_find->reserved, 0, 5);
7702: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
7703: }
7704: find->drive = _getdrive();
1.1.1.13 root 7705: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 7706: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
7707: find->nt_res = 0;
7708: msdos_find_file_conv_local_time(&fd);
7709: find->create_time_ms = 0;
7710: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
7711: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
7712: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
7713: find->cluster_hi = find->cluster_lo = 0;
7714: find->file_size = fd.nFileSizeLow;
7715: REG8(AL) = 0x00;
1.1.1.14 root 7716: } else if(dtainfo->allowable_mask & 8) {
1.1 root 7717: if(ext_fcb->flag == 0xff) {
7718: ext_find->flag = 0xff;
7719: memset(ext_find->reserved, 0, 5);
7720: ext_find->attribute = 8;
7721: }
7722: find->drive = _getdrive();
7723: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
7724: find->attribute = 8;
7725: find->nt_res = 0;
7726: msdos_find_file_conv_local_time(&fd);
7727: find->create_time_ms = 0;
7728: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
7729: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
7730: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
7731: find->cluster_hi = find->cluster_lo = 0;
7732: find->file_size = 0;
1.1.1.14 root 7733: dtainfo->allowable_mask &= ~8;
1.1 root 7734: REG8(AL) = 0x00;
7735: } else {
7736: REG8(AL) = 0xff;
7737: }
7738: }
7739:
7740: inline void msdos_int_21h_13h()
7741: {
1.1.1.3 root 7742: if(remove(msdos_fcb_path((fcb_t *)(mem + SREG_BASE(DS) + REG16(DX))))) {
1.1 root 7743: REG8(AL) = 0xff;
7744: } else {
7745: REG8(AL) = 0x00;
7746: }
7747: }
7748:
1.1.1.16 root 7749: inline void msdos_int_21h_14h()
7750: {
7751: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
7752: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
7753: process_t *process = msdos_process_info_get(current_psp);
7754: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
7755: DWORD num = 0;
7756:
7757: memset(mem + dta_laddr, 0, fcb->record_size);
7758: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
7759: REG8(AL) = 1;
7760: } else {
7761: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
7762: fcb->current_block = (position & 0xffffff) / fcb->record_size;
7763: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
7764: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
7765: }
7766: }
7767:
7768: inline void msdos_int_21h_15h()
1.1.1.14 root 7769: {
7770: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
7771: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.16 root 7772: process_t *process = msdos_process_info_get(current_psp);
7773: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
7774: DWORD num = 0;
1.1.1.14 root 7775:
1.1.1.16 root 7776: if(!WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
7777: REG8(AL) = 1;
7778: } else {
7779: fcb->file_size = GetFileSize(fcb->handle, NULL);
7780: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
7781: fcb->current_block = (position & 0xffffff) / fcb->record_size;
7782: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
7783: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
7784: }
7785: }
7786:
7787: inline void msdos_int_21h_16h()
7788: {
7789: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
7790: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.14 root 7791: char *path = msdos_fcb_path(fcb);
7792: 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);
1.1.1.16 root 7793:
1.1.1.14 root 7794: if(hFile == INVALID_HANDLE_VALUE) {
7795: REG8(AL) = 0xff;
7796: } else {
7797: REG8(AL) = 0;
7798: fcb->current_block = 0;
7799: fcb->record_size = 128;
7800: fcb->file_size = 0;
7801: fcb->handle = hFile;
7802: fcb->cur_record = 0;
7803: }
7804: }
7805:
1.1.1.16 root 7806: inline void msdos_int_21h_17h()
7807: {
7808: ext_fcb_t *ext_fcb_src = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
7809: fcb_t *fcb_src = (fcb_t *)(ext_fcb_src + (ext_fcb_src->flag == 0xff ? 1 : 0));
7810: char *path_src = msdos_fcb_path(fcb_src);
7811: ext_fcb_t *ext_fcb_dst = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + 16);
7812: fcb_t *fcb_dst = (fcb_t *)(ext_fcb_dst + (ext_fcb_dst->flag == 0xff ? 1 : 0));
7813: char *path_dst = msdos_fcb_path(fcb_dst);
7814:
7815: if(rename(path_src, path_dst)) {
7816: REG8(AL) = 0xff;
7817: } else {
7818: REG8(AL) = 0;
7819: }
7820: }
7821:
1.1 root 7822: inline void msdos_int_21h_18h()
7823: {
7824: REG8(AL) = 0x00;
7825: }
7826:
7827: inline void msdos_int_21h_19h()
7828: {
7829: REG8(AL) = _getdrive() - 1;
7830: }
7831:
7832: inline void msdos_int_21h_1ah()
7833: {
7834: process_t *process = msdos_process_info_get(current_psp);
7835:
7836: process->dta.w.l = REG16(DX);
1.1.1.3 root 7837: process->dta.w.h = SREG(DS);
1.1.1.23 root 7838: msdos_sda_update(current_psp);
1.1 root 7839: }
7840:
7841: inline void msdos_int_21h_1bh()
7842: {
7843: int drive_num = _getdrive() - 1;
7844: UINT16 seg, ofs;
7845:
7846: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
7847: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
7848: REG8(AL) = dpb->highest_sector_num + 1;
7849: REG16(CX) = dpb->bytes_per_sector;
7850: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 7851: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 7852: } else {
7853: REG8(AL) = 0xff;
1.1.1.3 root 7854: m_CF = 1;
1.1 root 7855: }
7856:
7857: }
7858:
7859: inline void msdos_int_21h_1ch()
7860: {
7861: int drive_num = REG8(DL) ? (REG8(DL) - 1) : (_getdrive() - 1);
7862: UINT16 seg, ofs;
7863:
7864: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
7865: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
7866: REG8(AL) = dpb->highest_sector_num + 1;
7867: REG16(CX) = dpb->bytes_per_sector;
7868: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 7869: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 7870: } else {
7871: REG8(AL) = 0xff;
1.1.1.3 root 7872: m_CF = 1;
1.1 root 7873: }
7874:
7875: }
7876:
7877: inline void msdos_int_21h_1dh()
7878: {
7879: REG8(AL) = 0;
7880: }
7881:
7882: inline void msdos_int_21h_1eh()
7883: {
7884: REG8(AL) = 0;
7885: }
7886:
7887: inline void msdos_int_21h_1fh()
7888: {
7889: int drive_num = _getdrive() - 1;
7890: UINT16 seg, ofs;
7891:
7892: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
7893: REG8(AL) = 0;
1.1.1.3 root 7894: SREG(DS) = seg;
7895: i386_load_segment_descriptor(DS);
1.1 root 7896: REG16(BX) = ofs;
7897: } else {
7898: REG8(AL) = 0xff;
1.1.1.3 root 7899: m_CF = 1;
1.1 root 7900: }
7901: }
7902:
7903: inline void msdos_int_21h_20h()
7904: {
7905: REG8(AL) = 0;
7906: }
7907:
1.1.1.14 root 7908: inline void msdos_int_21h_21h()
7909: {
7910: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
7911: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
7912:
7913: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
7914: REG8(AL) = 1;
7915: } else {
7916: process_t *process = msdos_process_info_get(current_psp);
7917: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
7918: memset(mem + dta_laddr, 0, fcb->record_size);
1.1.1.16 root 7919: DWORD num = 0;
1.1.1.14 root 7920: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
7921: REG8(AL) = 1;
7922: } else {
7923: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
7924: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 7925: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
1.1.1.14 root 7926: }
7927: }
7928: }
7929:
7930: inline void msdos_int_21h_22h()
7931: {
7932: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
7933: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
7934:
7935: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
7936: REG8(AL) = 0xff;
7937: } else {
7938: process_t *process = msdos_process_info_get(current_psp);
7939: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
1.1.1.16 root 7940: DWORD num = 0;
1.1.1.14 root 7941: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL);
7942: fcb->file_size = GetFileSize(fcb->handle, NULL);
7943: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
7944: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 7945: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
1.1.1.14 root 7946: }
7947: }
7948:
1.1.1.16 root 7949: inline void msdos_int_21h_23h()
7950: {
7951: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
7952: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
7953: char *path = msdos_fcb_path(fcb);
7954: HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
7955:
7956: if(hFile == INVALID_HANDLE_VALUE) {
7957: REG8(AL) = 0xff;
7958: } else {
7959: UINT32 size = GetFileSize(hFile, NULL);
7960: fcb->rand_record = size / fcb->record_size + ((size % fcb->record_size) != 0);
7961: REG8(AL) = 0;
7962: }
7963: }
7964:
7965: inline void msdos_int_21h_24h()
7966: {
7967: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
7968: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
7969:
7970: fcb->rand_record = fcb->current_block * fcb->record_size + fcb->cur_record;
7971: }
7972:
1.1 root 7973: inline void msdos_int_21h_25h()
7974: {
7975: *(UINT16 *)(mem + 4 * REG8(AL) + 0) = REG16(DX);
1.1.1.3 root 7976: *(UINT16 *)(mem + 4 * REG8(AL) + 2) = SREG(DS);
1.1 root 7977: }
7978:
7979: inline void msdos_int_21h_26h()
7980: {
7981: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
7982:
7983: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
7984: psp->first_mcb = REG16(DX) + 16;
7985: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
7986: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
7987: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
7988: psp->parent_psp = 0;
7989: }
7990:
1.1.1.16 root 7991: inline void msdos_int_21h_27h()
7992: {
7993: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
7994: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
7995:
7996: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
7997: REG8(AL) = 1;
7998: } else {
7999: process_t *process = msdos_process_info_get(current_psp);
8000: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
8001: memset(mem + dta_laddr, 0, fcb->record_size * REG16(CX));
8002: DWORD num = 0;
8003: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL) || num == 0) {
8004: REG8(AL) = 1;
8005: } else {
8006: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
8007: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
8008: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
8009: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
8010: }
8011: }
8012: }
8013:
8014: inline void msdos_int_21h_28h()
8015: {
8016: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8017: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
8018:
8019: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
8020: REG8(AL) = 0xff;
8021: } else {
8022: process_t *process = msdos_process_info_get(current_psp);
8023: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
8024: DWORD num = 0;
8025: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL);
8026: fcb->file_size = GetFileSize(fcb->handle, NULL);
8027: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
8028: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
8029: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
8030: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
8031: }
8032: }
8033:
1.1 root 8034: inline void msdos_int_21h_29h()
8035: {
1.1.1.20 root 8036: int ofs = 0;//SREG_BASE(DS) + REG16(SI);
8037: char buffer[1024], name[MAX_PATH], ext[MAX_PATH];
1.1 root 8038: UINT8 drv = 0;
8039: char sep_chars[] = ":.;,=+";
8040: char end_chars[] = "\\<>|/\"[]";
8041: char spc_chars[] = " \t";
8042:
1.1.1.20 root 8043: memcpy(buffer, mem + SREG_BASE(DS) + REG16(SI), 1023);
8044: buffer[1023] = 0;
8045: memset(name, 0x20, sizeof(name));
8046: memset(ext, 0x20, sizeof(ext));
8047:
1.1 root 8048: if(REG8(AL) & 1) {
1.1.1.20 root 8049: ofs += strspn((char *)(buffer + ofs), spc_chars);
8050: if(my_strchr(sep_chars, buffer[ofs]) && buffer[ofs] != '\0') {
1.1 root 8051: ofs++;
8052: }
8053: }
1.1.1.20 root 8054: ofs += strspn((char *)(buffer + ofs), spc_chars);
1.1 root 8055:
1.1.1.24 root 8056: if(buffer[ofs + 1] == ':') {
8057: if(buffer[ofs] >= 'a' && buffer[ofs] <= 'z') {
8058: drv = buffer[ofs] - 'a' + 1;
1.1.1.20 root 8059: ofs += 2;
1.1.1.24 root 8060: if(buffer[ofs] == '\\' || buffer[ofs] == '/') {
8061: ofs++;
8062: }
8063: } else if(buffer[ofs] >= 'A' && buffer[ofs] <= 'Z') {
8064: drv = buffer[ofs] - 'A' + 1;
1.1 root 8065: ofs += 2;
1.1.1.24 root 8066: if(buffer[ofs] == '\\' || buffer[ofs] == '/') {
8067: ofs++;
8068: }
1.1 root 8069: }
8070: }
1.1.1.20 root 8071: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
8072: UINT8 c = buffer[ofs];
8073: if(is_kanji) {
8074: is_kanji = 0;
8075: } else if(msdos_lead_byte_check(c)) {
8076: is_kanji = 1;
8077: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 8078: break;
8079: } else if(c >= 'a' && c <= 'z') {
8080: c -= 0x20;
8081: }
8082: ofs++;
8083: name[i] = c;
8084: }
1.1.1.20 root 8085: if(buffer[ofs] == '.') {
1.1 root 8086: ofs++;
1.1.1.20 root 8087: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
8088: UINT8 c = buffer[ofs];
8089: if(is_kanji) {
8090: is_kanji = 0;
8091: } else if(msdos_lead_byte_check(c)) {
8092: is_kanji = 1;
8093: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 8094: break;
8095: } else if(c >= 'a' && c <= 'z') {
8096: c -= 0x20;
8097: }
8098: ofs++;
8099: ext[i] = c;
8100: }
8101: }
1.1.1.20 root 8102: int si = REG16(SI) + ofs;
1.1.1.3 root 8103: int ds = SREG(DS);
1.1 root 8104: while(si > 0xffff) {
8105: si -= 0x10;
8106: ds++;
8107: }
8108: REG16(SI) = si;
1.1.1.3 root 8109: SREG(DS) = ds;
8110: i386_load_segment_descriptor(DS);
1.1 root 8111:
1.1.1.3 root 8112: UINT8 *fcb = mem + SREG_BASE(ES) + REG16(DI);
1.1.1.20 root 8113: if(!(REG8(AL) & 2) || drv != 0) {
8114: fcb[0] = drv;
8115: }
8116: if(!(REG8(AL) & 4) || name[0] != 0x20) {
8117: memcpy(fcb + 1, name, 8);
8118: }
8119: if(!(REG8(AL) & 8) || ext[0] != 0x20) {
8120: memcpy(fcb + 9, ext, 3);
8121: }
8122: for(int i = 1, found_star = 0; i < 1 + 8; i++) {
1.1 root 8123: if(fcb[i] == '*') {
8124: found_star = 1;
8125: }
8126: if(found_star) {
8127: fcb[i] = '?';
8128: }
8129: }
1.1.1.20 root 8130: for(int i = 9, found_star = 0; i < 9 + 3; i++) {
1.1 root 8131: if(fcb[i] == '*') {
8132: found_star = 1;
8133: }
8134: if(found_star) {
8135: fcb[i] = '?';
8136: }
8137: }
8138:
8139: if(drv == 0 || (drv > 0 && drv <= 26 && (GetLogicalDrives() & ( 1 << (drv - 1) )))) {
8140: if(memchr(fcb + 1, '?', 8 + 3)) {
8141: REG8(AL) = 0x01;
1.1.1.20 root 8142: } else {
8143: REG8(AL) = 0x00;
1.1 root 8144: }
8145: } else {
8146: REG8(AL) = 0xff;
8147: }
8148: }
8149:
8150: inline void msdos_int_21h_2ah()
8151: {
8152: SYSTEMTIME sTime;
8153:
8154: GetLocalTime(&sTime);
8155: REG16(CX) = sTime.wYear;
8156: REG8(DH) = (UINT8)sTime.wMonth;
8157: REG8(DL) = (UINT8)sTime.wDay;
8158: REG8(AL) = (UINT8)sTime.wDayOfWeek;
8159: }
8160:
8161: inline void msdos_int_21h_2bh()
8162: {
1.1.1.14 root 8163: REG8(AL) = 0xff;
1.1 root 8164: }
8165:
8166: inline void msdos_int_21h_2ch()
8167: {
8168: SYSTEMTIME sTime;
8169:
8170: GetLocalTime(&sTime);
8171: REG8(CH) = (UINT8)sTime.wHour;
8172: REG8(CL) = (UINT8)sTime.wMinute;
8173: REG8(DH) = (UINT8)sTime.wSecond;
1.1.1.14 root 8174: REG8(DL) = (UINT8)sTime.wMilliseconds / 10;
1.1 root 8175: }
8176:
8177: inline void msdos_int_21h_2dh()
8178: {
8179: REG8(AL) = 0x00;
8180: }
8181:
8182: inline void msdos_int_21h_2eh()
8183: {
8184: process_t *process = msdos_process_info_get(current_psp);
8185:
8186: process->verify = REG8(AL);
8187: }
8188:
8189: inline void msdos_int_21h_2fh()
8190: {
8191: process_t *process = msdos_process_info_get(current_psp);
8192:
8193: REG16(BX) = process->dta.w.l;
1.1.1.3 root 8194: SREG(ES) = process->dta.w.h;
8195: i386_load_segment_descriptor(ES);
1.1 root 8196: }
8197:
8198: inline void msdos_int_21h_30h()
8199: {
8200: // Version Flag / OEM
1.1.1.27 root 8201: if(REG8(AL) == 0x01) {
1.1.1.29 root 8202: #ifdef SUPPORT_HMA
8203: REG16(BX) = 0x0000;
8204: #else
8205: REG16(BX) = 0x1000; // DOS is in HMA
8206: #endif
1.1 root 8207: } else {
1.1.1.27 root 8208: // NOTE: EXDEB invites BL shows the machine type (0=PC-98, 1=PC/AT, 2=FMR),
8209: // but this is not correct on Windows 98 SE
8210: // REG16(BX) = 0xff01; // OEM = Microsoft, PC/AT
8211: REG16(BX) = 0xff00; // OEM = Microsoft
1.1 root 8212: }
1.1.1.27 root 8213: REG16(CX) = 0x0000;
1.1.1.30 root 8214: REG8(AL) = dos_major_version; // 7
8215: REG8(AH) = dos_minor_version; // 10
1.1 root 8216: }
8217:
8218: inline void msdos_int_21h_31h()
8219: {
1.1.1.29 root 8220: try {
8221: msdos_mem_realloc(current_psp, REG16(DX), NULL);
8222: } catch(...) {
8223: // recover the broken mcb
8224: int mcb_seg = current_psp - 1;
8225: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1.1.33! root 8226:
1.1.1.29 root 8227: if(mcb_seg < (MEMORY_END >> 4)) {
1.1.1.33! root 8228: mcb->mz = 'M';
! 8229: mcb->paragraphs = (MEMORY_END >> 4) - mcb_seg - 2;
! 8230:
1.1.1.29 root 8231: if(((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked & 0x01) {
1.1.1.33! root 8232: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', PSP_SYSTEM, (UMB_TOP >> 4) - (MEMORY_END >> 4));
1.1.1.29 root 8233: } else {
1.1.1.33! root 8234: msdos_mcb_create((MEMORY_END >> 4) - 1, 'Z', PSP_SYSTEM, 0);
1.1.1.29 root 8235: }
8236: } else {
8237: mcb->mz = 'Z';
1.1.1.30 root 8238: mcb->paragraphs = (UMB_END >> 4) - mcb_seg - 1;
1.1.1.29 root 8239: }
8240: msdos_mem_realloc(current_psp, REG16(DX), NULL);
8241: }
1.1 root 8242: msdos_process_terminate(current_psp, REG8(AL) | 0x300, 0);
8243: }
8244:
8245: inline void msdos_int_21h_32h()
8246: {
8247: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
8248: UINT16 seg, ofs;
8249:
8250: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
8251: REG8(AL) = 0;
1.1.1.3 root 8252: SREG(DS) = seg;
8253: i386_load_segment_descriptor(DS);
1.1 root 8254: REG16(BX) = ofs;
8255: } else {
8256: REG8(AL) = 0xff;
1.1.1.3 root 8257: m_CF = 1;
1.1 root 8258: }
8259: }
8260:
8261: inline void msdos_int_21h_33h()
8262: {
8263: char path[MAX_PATH];
8264:
8265: switch(REG8(AL)) {
8266: case 0x00:
1.1.1.33! root 8267: REG8(DL) = ctrl_break_checking;
1.1 root 8268: break;
8269: case 0x01:
1.1.1.33! root 8270: ctrl_break_checking = REG8(DL);
! 8271: break;
! 8272: case 0x02:
! 8273: {
! 8274: UINT8 old = ctrl_break_checking;
! 8275: ctrl_break_checking = REG8(DL);
! 8276: REG8(DL) = old;
! 8277: }
! 8278: break;
! 8279: case 0x03:
! 8280: case 0x04:
! 8281: // DOS 4.0+ - Unused
1.1 root 8282: break;
8283: case 0x05:
8284: GetSystemDirectory(path, MAX_PATH);
8285: if(path[0] >= 'a' && path[0] <= 'z') {
8286: REG8(DL) = path[0] - 'a' + 1;
8287: } else {
8288: REG8(DL) = path[0] - 'A' + 1;
8289: }
8290: break;
8291: case 0x06:
1.1.1.2 root 8292: // MS-DOS version (7.10)
1.1 root 8293: REG8(BL) = 7;
1.1.1.2 root 8294: REG8(BH) = 10;
1.1 root 8295: REG8(DL) = 0;
1.1.1.29 root 8296: #ifdef SUPPORT_HMA
8297: REG8(DH) = 0x00;
8298: #else
8299: REG8(DH) = 0x10; // DOS is in HMA
8300: #endif
1.1 root 8301: break;
1.1.1.6 root 8302: case 0x07:
8303: if(REG8(DL) == 0) {
8304: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag &= ~0x20;
8305: } else if(REG8(DL) == 1) {
8306: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag |= 0x20;
8307: }
8308: break;
1.1 root 8309: default:
1.1.1.22 root 8310: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 8311: REG16(AX) = 0x01;
1.1.1.3 root 8312: m_CF = 1;
1.1 root 8313: break;
8314: }
8315: }
8316:
1.1.1.23 root 8317: inline void msdos_int_21h_34h()
8318: {
8319: SREG(ES) = SDA_TOP >> 4;
8320: i386_load_segment_descriptor(ES);
8321: REG16(BX) = offsetof(sda_t, indos_flag);;
8322: }
8323:
1.1 root 8324: inline void msdos_int_21h_35h()
8325: {
8326: REG16(BX) = *(UINT16 *)(mem + 4 * REG8(AL) + 0);
1.1.1.3 root 8327: SREG(ES) = *(UINT16 *)(mem + 4 * REG8(AL) + 2);
8328: i386_load_segment_descriptor(ES);
1.1 root 8329: }
8330:
8331: inline void msdos_int_21h_36h()
8332: {
8333: struct _diskfree_t df = {0};
8334:
8335: if(_getdiskfree(REG8(DL), &df) == 0) {
8336: REG16(AX) = (UINT16)df.sectors_per_cluster;
8337: REG16(CX) = (UINT16)df.bytes_per_sector;
1.1.1.13 root 8338: REG16(BX) = df.avail_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.avail_clusters;
8339: REG16(DX) = df.total_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.total_clusters;
1.1 root 8340: } else {
8341: REG16(AX) = 0xffff;
8342: }
8343: }
8344:
8345: inline void msdos_int_21h_37h()
8346: {
1.1.1.22 root 8347: static UINT8 dev_flag = 0xff;
1.1 root 8348:
8349: switch(REG8(AL)) {
8350: case 0x00:
1.1.1.22 root 8351: {
8352: process_t *process = msdos_process_info_get(current_psp);
8353: REG8(AL) = 0x00;
8354: REG8(DL) = process->switchar;
8355: }
1.1 root 8356: break;
8357: case 0x01:
1.1.1.22 root 8358: {
8359: process_t *process = msdos_process_info_get(current_psp);
8360: REG8(AL) = 0x00;
8361: process->switchar = REG8(DL);
1.1.1.23 root 8362: msdos_sda_update(current_psp);
1.1.1.22 root 8363: }
8364: break;
8365: case 0x02:
8366: REG8(DL) = dev_flag;
8367: break;
8368: case 0x03:
8369: dev_flag = REG8(DL);
8370: break;
8371: case 0xd0:
8372: case 0xd1:
8373: case 0xd2:
8374: case 0xd3:
8375: case 0xd4:
8376: case 0xd5:
8377: case 0xd6:
8378: case 0xd7:
8379: case 0xdc:
8380: case 0xdd:
8381: case 0xde:
8382: case 0xdf:
8383: // diet ???
8384: REG16(AX) = 1;
1.1 root 8385: break;
8386: default:
1.1.1.22 root 8387: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 8388: REG16(AX) = 1;
8389: break;
8390: }
8391: }
8392:
1.1.1.19 root 8393: int get_country_info(country_info_t *ci)
1.1.1.17 root 8394: {
8395: char LCdata[80];
8396:
1.1.1.19 root 8397: ZeroMemory(ci, offsetof(country_info_t, reserved));
1.1.1.17 root 8398: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRDIGITS, LCdata, sizeof(LCdata));
8399: ci->currency_dec_digits = atoi(LCdata);
8400: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRENCY, LCdata, sizeof(LCdata));
8401: ci->currency_format = *LCdata - '0';
8402: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDATE, LCdata, sizeof(LCdata));
8403: ci->date_format = *LCdata - '0';
8404: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SCURRENCY, LCdata, sizeof(LCdata));
8405: memcpy(&ci->currency_symbol, LCdata, 4);
8406: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDATE, LCdata, sizeof(LCdata));
8407: *ci->date_sep = *LCdata;
8408: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, LCdata, sizeof(LCdata));
8409: *ci->dec_sep = *LCdata;
8410: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLIST, LCdata, sizeof(LCdata));
8411: *ci->list_sep = *LCdata;
8412: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, LCdata, sizeof(LCdata));
8413: *ci->thou_sep = *LCdata;
8414: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIME, LCdata, sizeof(LCdata));
8415: *ci->time_sep = *LCdata;
8416: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, LCdata, sizeof(LCdata));
8417: if(strchr(LCdata, 'H') != NULL) {
8418: ci->time_format = 1;
8419: }
1.1.1.27 root 8420: ci->case_map.w.l = 0x000a; // dummy case map routine is at fffd:000a
1.1.1.24 root 8421: ci->case_map.w.h = 0xfffd;
1.1.1.17 root 8422: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICOUNTRY, LCdata, sizeof(LCdata));
8423: return atoi(LCdata);
8424: }
8425:
1.1.1.14 root 8426: inline void msdos_int_21h_38h()
8427: {
8428: switch(REG8(AL)) {
8429: case 0x00:
1.1.1.19 root 8430: REG16(BX) = get_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1.1.14 root 8431: break;
8432: default:
1.1.1.22 root 8433: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.14 root 8434: REG16(AX) = 2;
8435: m_CF = 1;
8436: break;
8437: }
8438: }
8439:
1.1 root 8440: inline void msdos_int_21h_39h(int lfn)
8441: {
1.1.1.3 root 8442: if(_mkdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 8443: REG16(AX) = errno;
1.1.1.3 root 8444: m_CF = 1;
1.1 root 8445: }
8446: }
8447:
8448: inline void msdos_int_21h_3ah(int lfn)
8449: {
1.1.1.3 root 8450: if(_rmdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 8451: REG16(AX) = errno;
1.1.1.3 root 8452: m_CF = 1;
1.1 root 8453: }
8454: }
8455:
8456: inline void msdos_int_21h_3bh(int lfn)
8457: {
1.1.1.3 root 8458: if(_chdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1.1.17 root 8459: REG16(AX) = 3; // must be 3 (path not found)
1.1.1.3 root 8460: m_CF = 1;
1.1 root 8461: }
8462: }
8463:
8464: inline void msdos_int_21h_3ch()
8465: {
1.1.1.3 root 8466: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 8467: int attr = GetFileAttributes(path);
1.1.1.29 root 8468: int fd = -1, c;
1.1.1.11 root 8469: UINT16 info;
1.1 root 8470:
1.1.1.11 root 8471: if(msdos_is_con_path(path)) {
8472: fd = _open("CON", _O_WRONLY | _O_BINARY);
8473: info = 0x80d3;
1.1.1.29 root 8474: } else if((c = msdos_is_comm_path(path)) != 0 && sio_port_number[c - 1] != 0) {
8475: if((fd = _open(msdos_create_comm_path(path, sio_port_number[c - 1]), _O_WRONLY | _O_BINARY)) == -1) {
8476: fd = _open("NUL", _O_WRONLY | _O_BINARY);
8477: }
1.1.1.14 root 8478: info = 0x80d3;
1.1.1.29 root 8479: } else if(msdos_is_device_path(path)) {
1.1.1.20 root 8480: fd = _open("NUL", _O_WRONLY | _O_BINARY);
8481: info = 0x80d3;
1.1 root 8482: } else {
8483: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 8484: info = msdos_drive_number(path);
1.1 root 8485: }
8486: if(fd != -1) {
8487: if(attr == -1) {
8488: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
8489: }
8490: SetFileAttributes(path, attr);
8491: REG16(AX) = fd;
1.1.1.11 root 8492: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp);
1.1.1.20 root 8493: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 8494: } else {
8495: REG16(AX) = errno;
1.1.1.3 root 8496: m_CF = 1;
1.1 root 8497: }
8498: }
8499:
8500: inline void msdos_int_21h_3dh()
8501: {
1.1.1.3 root 8502: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 8503: int mode = REG8(AL) & 0x03;
1.1.1.29 root 8504: int fd = -1, c;
1.1.1.11 root 8505: UINT16 info;
1.1 root 8506:
8507: if(mode < 0x03) {
1.1.1.11 root 8508: if(msdos_is_con_path(path)) {
1.1.1.13 root 8509: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 8510: info = 0x80d3;
1.1.1.29 root 8511: } else if((c = msdos_is_comm_path(path)) != 0 && sio_port_number[c - 1] != 0) {
8512: if((fd = _open(msdos_create_comm_path(path, sio_port_number[c - 1]), file_mode[mode].mode)) == -1) {
8513: fd = msdos_open("NUL", file_mode[mode].mode);
8514: }
1.1.1.14 root 8515: info = 0x80d3;
1.1.1.29 root 8516: } else if(msdos_is_device_path(path)) {
1.1.1.20 root 8517: fd = msdos_open("NUL", file_mode[mode].mode);
8518: info = 0x80d3;
1.1.1.11 root 8519: } else {
1.1.1.13 root 8520: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 8521: info = msdos_drive_number(path);
8522: }
1.1 root 8523: if(fd != -1) {
8524: REG16(AX) = fd;
1.1.1.11 root 8525: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp);
1.1.1.20 root 8526: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 8527: } else {
8528: REG16(AX) = errno;
1.1.1.3 root 8529: m_CF = 1;
1.1 root 8530: }
8531: } else {
8532: REG16(AX) = 0x0c;
1.1.1.3 root 8533: m_CF = 1;
1.1 root 8534: }
8535: }
8536:
8537: inline void msdos_int_21h_3eh()
8538: {
8539: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 8540: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 8541:
1.1.1.20 root 8542: if(fd < process->max_files && file_handler[fd].valid) {
8543: _close(fd);
8544: msdos_file_handler_close(fd);
8545: msdos_psp_set_file_table(REG16(BX), 0x0ff, current_psp);
1.1 root 8546: } else {
8547: REG16(AX) = 0x06;
1.1.1.3 root 8548: m_CF = 1;
1.1 root 8549: }
8550: }
8551:
8552: inline void msdos_int_21h_3fh()
8553: {
8554: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 8555: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 8556:
1.1.1.20 root 8557: if(fd < process->max_files && file_handler[fd].valid) {
8558: if(file_mode[file_handler[fd].mode].in) {
8559: if(file_handler[fd].atty) {
1.1 root 8560: // BX is stdin or is redirected to stdin
1.1.1.3 root 8561: UINT8 *buf = mem + SREG_BASE(DS) + REG16(DX);
1.1 root 8562: int max = REG16(CX);
8563: int p = 0;
8564:
8565: while(max > p) {
8566: int chr = msdos_getch();
8567:
1.1.1.33! root 8568: if((ctrl_break_checking && ctrl_break_pressed) || ctrl_c_pressed) {
1.1.1.26 root 8569: p = 0;
8570: buf[p++] = 0x0d;
8571: if(max > p) {
8572: buf[p++] = 0x0a;
8573: }
1.1.1.33! root 8574: msdos_putch(0x03);
! 8575: msdos_putch(0x0d);
! 8576: msdos_putch(0x0a);
1.1.1.26 root 8577: break;
1.1.1.33! root 8578: } else if(ctrl_break_pressed) {
! 8579: // skip this byte
1.1.1.26 root 8580: } else if(chr == 0x00) {
1.1 root 8581: // skip 2nd byte
8582: msdos_getch();
8583: } else if(chr == 0x0d) {
8584: // carriage return
8585: buf[p++] = 0x0d;
8586: if(max > p) {
8587: buf[p++] = 0x0a;
8588: }
1.1.1.14 root 8589: msdos_putch('\n');
1.1 root 8590: break;
8591: } else if(chr == 0x08) {
8592: // back space
8593: if(p > 0) {
8594: p--;
1.1.1.20 root 8595: if(msdos_ctrl_code_check(buf[p])) {
8596: msdos_putch(chr);
8597: msdos_putch(chr);
8598: msdos_putch(' ');
8599: msdos_putch(' ');
8600: msdos_putch(chr);
8601: msdos_putch(chr);
8602: } else {
8603: msdos_putch(chr);
8604: msdos_putch(' ');
8605: msdos_putch(chr);
8606: }
1.1 root 8607: }
8608: } else {
8609: buf[p++] = chr;
8610: msdos_putch(chr);
8611: }
8612: }
8613: REG16(AX) = p;
1.1.1.26 root 8614:
1.1.1.8 root 8615: // some seconds may be passed in console
1.1 root 8616: hardware_update();
8617: } else {
1.1.1.20 root 8618: REG16(AX) = _read(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 8619: }
8620: } else {
8621: REG16(AX) = 0x05;
1.1.1.3 root 8622: m_CF = 1;
1.1 root 8623: }
8624: } else {
8625: REG16(AX) = 0x06;
1.1.1.3 root 8626: m_CF = 1;
1.1 root 8627: }
8628: }
8629:
8630: inline void msdos_int_21h_40h()
8631: {
8632: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 8633: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 8634:
1.1.1.20 root 8635: if(fd < process->max_files && file_handler[fd].valid) {
8636: if(file_mode[file_handler[fd].mode].out) {
1.1 root 8637: if(REG16(CX)) {
1.1.1.20 root 8638: if(file_handler[fd].atty) {
1.1 root 8639: // BX is stdout/stderr or is redirected to stdout
8640: for(int i = 0; i < REG16(CX); i++) {
1.1.1.3 root 8641: msdos_putch(mem[SREG_BASE(DS) + REG16(DX) + i]);
1.1 root 8642: }
8643: REG16(AX) = REG16(CX);
8644: } else {
1.1.1.20 root 8645: REG16(AX) = msdos_write(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 8646: }
8647: } else {
1.1.1.20 root 8648: UINT32 pos = _tell(fd);
8649: _lseek(fd, 0, SEEK_END);
8650: UINT32 size = _tell(fd);
1.1.1.12 root 8651: if(pos < size) {
1.1.1.20 root 8652: _lseek(fd, pos, SEEK_SET);
8653: SetEndOfFile((HANDLE)_get_osfhandle(fd));
1.1.1.12 root 8654: } else {
8655: for(UINT32 i = size; i < pos; i++) {
8656: UINT8 tmp = 0;
1.1.1.23 root 8657: msdos_write(fd, &tmp, 1);
1.1.1.12 root 8658: }
1.1.1.20 root 8659: _lseek(fd, pos, SEEK_SET);
1.1 root 8660: }
1.1.1.23 root 8661: REG16(AX) = 0;
1.1 root 8662: }
8663: } else {
8664: REG16(AX) = 0x05;
1.1.1.3 root 8665: m_CF = 1;
1.1 root 8666: }
8667: } else {
8668: REG16(AX) = 0x06;
1.1.1.3 root 8669: m_CF = 1;
1.1 root 8670: }
8671: }
8672:
8673: inline void msdos_int_21h_41h(int lfn)
8674: {
1.1.1.3 root 8675: if(remove(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 8676: REG16(AX) = errno;
1.1.1.3 root 8677: m_CF = 1;
1.1 root 8678: }
8679: }
8680:
8681: inline void msdos_int_21h_42h()
8682: {
8683: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 8684: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 8685:
1.1.1.20 root 8686: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 8687: if(REG8(AL) < 0x03) {
8688: static int ptrname[] = { SEEK_SET, SEEK_CUR, SEEK_END };
1.1.1.20 root 8689: _lseek(fd, (REG16(CX) << 16) | REG16(DX), ptrname[REG8(AL)]);
8690: UINT32 pos = _tell(fd);
1.1 root 8691: REG16(AX) = pos & 0xffff;
8692: REG16(DX) = (pos >> 16);
8693: } else {
8694: REG16(AX) = 0x01;
1.1.1.3 root 8695: m_CF = 1;
1.1 root 8696: }
8697: } else {
8698: REG16(AX) = 0x06;
1.1.1.3 root 8699: m_CF = 1;
1.1 root 8700: }
8701: }
8702:
8703: inline void msdos_int_21h_43h(int lfn)
8704: {
1.1.1.3 root 8705: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn);
1.1 root 8706: int attr;
8707:
1.1.1.14 root 8708: if(!lfn && REG8(AL) > 2) {
8709: REG16(AX) = 0x01;
8710: m_CF = 1;
8711: return;
8712: }
8713: switch(REG8(lfn ? BL : AL)) {
1.1 root 8714: case 0x00:
8715: if((attr = GetFileAttributes(path)) != -1) {
1.1.1.14 root 8716: REG16(CX) = (UINT16)msdos_file_attribute_create((UINT16)attr);
8717: } else {
8718: REG16(AX) = (UINT16)GetLastError();
8719: m_CF = 1;
8720: }
8721: break;
8722: case 0x01:
8723: if(!SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)))) {
8724: REG16(AX) = (UINT16)GetLastError();
8725: m_CF = 1;
8726: }
8727: break;
8728: case 0x02:
8729: {
8730: DWORD size = GetCompressedFileSize(path, NULL);
8731: if(size != INVALID_FILE_SIZE) {
8732: if(size != 0 && size == GetFileSize(path, NULL)) {
8733: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
8734: // this isn't correct if the file is in the NTFS MFT
8735: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
8736: size = ((size - 1) | (sectors_per_cluster * bytes_per_sector - 1)) + 1;
8737: }
8738: }
8739: REG16(AX) = LOWORD(size);
8740: REG16(DX) = HIWORD(size);
8741: } else {
8742: REG16(AX) = (UINT16)GetLastError();
8743: m_CF = 1;
1.1 root 8744: }
1.1.1.14 root 8745: }
8746: break;
8747: case 0x03:
8748: case 0x05:
8749: case 0x07:
8750: {
8751: HANDLE hFile = CreateFile(path, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
8752: if(hFile != INVALID_HANDLE_VALUE) {
8753: FILETIME local, time;
8754: DosDateTimeToFileTime(REG16(DI), /*REG8(BL) == 5 ? 0 : */REG16(CX), &local);
8755: if(REG8(BL) == 7) {
8756: ULARGE_INTEGER hund;
8757: hund.LowPart = local.dwLowDateTime;
8758: hund.HighPart = local.dwHighDateTime;
8759: hund.QuadPart += REG16(SI) * 100000;
8760: local.dwLowDateTime = hund.LowPart;
8761: local.dwHighDateTime = hund.HighPart;
8762: }
8763: LocalFileTimeToFileTime(&local, &time);
8764: if(!SetFileTime(hFile, REG8(BL) == 0x07 ? &time : NULL,
8765: REG8(BL) == 0x05 ? &time : NULL,
8766: REG8(BL) == 0x03 ? &time : NULL)) {
8767: REG16(AX) = (UINT16)GetLastError();
8768: m_CF = 1;
8769: }
8770: CloseHandle(hFile);
8771: } else {
8772: REG16(AX) = (UINT16)GetLastError();
8773: m_CF = 1;
1.1 root 8774: }
1.1.1.14 root 8775: }
8776: break;
8777: case 0x04:
8778: case 0x06:
8779: case 0x08:
8780: {
8781: WIN32_FILE_ATTRIBUTE_DATA fad;
8782: if(GetFileAttributesEx(path, GetFileExInfoStandard, (LPVOID)&fad)) {
8783: FILETIME *time, local;
8784: time = REG8(BL) == 0x04 ? &fad.ftLastWriteTime :
8785: 0x06 ? &fad.ftLastAccessTime :
8786: &fad.ftCreationTime;
8787: FileTimeToLocalFileTime(time, &local);
8788: FileTimeToDosDateTime(&local, ®16(DI), ®16(CX));
8789: if(REG8(BL) == 0x08) {
8790: ULARGE_INTEGER hund;
8791: hund.LowPart = local.dwLowDateTime;
8792: hund.HighPart = local.dwHighDateTime;
8793: hund.QuadPart /= 100000;
8794: REG16(SI) = (UINT16)(hund.QuadPart % 200);
8795: }
8796: } else {
8797: REG16(AX) = (UINT16)GetLastError();
8798: m_CF = 1;
1.1 root 8799: }
1.1.1.14 root 8800: }
8801: break;
8802: default:
1.1.1.22 root 8803: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.14 root 8804: REG16(AX) = 0x01;
8805: m_CF = 1;
8806: break;
8807: }
8808: }
8809:
8810: inline void msdos_int_21h_44h()
8811: {
1.1.1.22 root 8812: static UINT16 iteration_count = 0;
8813:
1.1.1.20 root 8814: process_t *process = msdos_process_info_get(current_psp);
8815: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
8816:
1.1.1.14 root 8817: UINT32 val = DRIVE_NO_ROOT_DIR;
8818:
8819: switch(REG8(AL)) {
8820: case 0x00:
8821: case 0x01:
8822: case 0x02:
8823: case 0x03:
8824: case 0x04:
8825: case 0x05:
8826: case 0x06:
8827: case 0x07:
1.1.1.20 root 8828: if(fd >= process->max_files || !file_handler[fd].valid) {
8829: REG16(AX) = 0x06;
8830: m_CF = 1;
8831: return;
1.1.1.14 root 8832: }
8833: break;
8834: case 0x08:
8835: case 0x09:
8836: if(REG8(BL) >= ('Z' - 'A' + 1)) {
8837: // invalid drive number
8838: REG16(AX) = 0x0f;
8839: m_CF = 1;
8840: return;
8841: } else {
8842: if(REG8(BL) == 0) {
8843: val = GetDriveType(NULL);
8844: } else {
8845: char tmp[8];
8846: sprintf(tmp, "%c:\\", 'A' + REG8(BL) - 1);
8847: val = GetDriveType(tmp);
8848: }
8849: if(val == DRIVE_NO_ROOT_DIR) {
8850: // no drive
8851: REG16(AX) = 0x0f;
8852: m_CF = 1;
8853: return;
1.1 root 8854: }
8855: }
8856: break;
8857: }
8858: switch(REG8(AL)) {
8859: case 0x00: // get ioctrl data
1.1.1.20 root 8860: REG16(DX) = file_handler[fd].info;
1.1 root 8861: break;
8862: case 0x01: // set ioctrl data
1.1.1.20 root 8863: file_handler[fd].info |= REG8(DL);
1.1 root 8864: break;
8865: case 0x02: // recv from character device
8866: case 0x03: // send to character device
8867: case 0x04: // recv from block device
8868: case 0x05: // send to block device
8869: REG16(AX) = 0x05;
1.1.1.3 root 8870: m_CF = 1;
1.1 root 8871: break;
8872: case 0x06: // get read status
1.1.1.20 root 8873: if(file_mode[file_handler[fd].mode].in) {
8874: if(file_handler[fd].atty) {
1.1.1.14 root 8875: REG8(AL) = msdos_kbhit() ? 0xff : 0x00;
1.1 root 8876: } else {
1.1.1.20 root 8877: REG8(AL) = eof(fd) ? 0x00 : 0xff;
1.1 root 8878: }
1.1.1.14 root 8879: } else {
8880: REG8(AL) = 0x00;
1.1 root 8881: }
8882: break;
8883: case 0x07: // get write status
1.1.1.20 root 8884: if(file_mode[file_handler[fd].mode].out) {
1.1.1.14 root 8885: REG8(AL) = 0xff;
8886: } else {
8887: REG8(AL) = 0x00;
1.1 root 8888: }
8889: break;
8890: case 0x08: // check removable drive
1.1.1.14 root 8891: if(val == DRIVE_REMOVABLE || val == DRIVE_CDROM) {
8892: // removable drive
8893: REG16(AX) = 0x00;
1.1 root 8894: } else {
1.1.1.14 root 8895: // fixed drive
8896: REG16(AX) = 0x01;
1.1 root 8897: }
8898: break;
8899: case 0x09: // check remote drive
1.1.1.14 root 8900: if(val == DRIVE_REMOTE) {
8901: // remote drive
8902: REG16(DX) = 0x1000;
1.1 root 8903: } else {
1.1.1.14 root 8904: // local drive
8905: REG16(DX) = 0x00;
1.1 root 8906: }
8907: break;
1.1.1.21 root 8908: case 0x0a: // check remote handle
8909: REG16(DX) = 0x00; // FIXME
8910: break;
1.1 root 8911: case 0x0b: // set retry count
8912: break;
1.1.1.22 root 8913: case 0x0c: // generic character device request
8914: if(REG8(CL) == 0x45) {
8915: // set iteration (retry) count
8916: iteration_count = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
8917: } else if(REG8(CL) == 0x4a) {
8918: // select code page
8919: active_code_page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2);
8920: msdos_nls_tables_update();
8921: } else if(REG8(CL) == 0x65) {
8922: // get iteration (retry) count
8923: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX)) = iteration_count;
8924: } else if(REG8(CL) == 0x6a) {
8925: // query selected code page
8926: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 2; // FIXME
8927: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = active_code_page;
8928:
8929: CPINFO info;
8930: GetCPInfo(active_code_page, &info);
8931:
8932: if(info.MaxCharSize != 1) {
8933: for(int i = 0;; i++) {
8934: UINT8 lo = info.LeadByte[2 * i + 0];
8935: UINT8 hi = info.LeadByte[2 * i + 1];
8936:
8937: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 0) = lo;
8938: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 2) = hi;
8939: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) + 4;
8940:
8941: if(lo == 0 && hi == 0) {
8942: break;
8943: }
8944: }
8945: }
8946: } else if(REG8(CL) == 0x7f) {
8947: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x00) = 0;
8948: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x01) = 0;
8949: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02) = 14;
8950: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x04) = 1;
8951: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x06) = 1;
8952: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x07) = 0;
8953: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x08) = 4;
8954: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0a) = 8 * (*(UINT16 *)(mem + 0x44a));
8955: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0c) = 16 * (*(UINT8 *)(mem + 0x484) + 1);
8956: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e) = *(UINT16 *)(mem + 0x44a);
8957: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x10) = *(UINT8 *)(mem + 0x484) + 1;
8958: } else {
8959: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
8960: REG16(AX) = 0x01; // invalid function
8961: m_CF = 1;
8962: }
8963: break;
8964: case 0x0d: // generic block device request
8965: if(REG8(CL) == 0x40) {
8966: // set device parameters
8967: } else if(REG8(CL) == 0x46) {
8968: // set volume serial number
8969: } else if(REG8(CL) == 0x4a) {
8970: // lock logical volume
8971: } else if(REG8(CL) == 0x4b) {
8972: // lock physical volume
8973: } else if(REG8(CL) == 0x60) {
8974: // get device parameters
8975: char dev[] = "\\\\.\\A:";
8976: dev[4] = 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
8977:
8978: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
8979: if(hFile != INVALID_HANDLE_VALUE) {
8980: DISK_GEOMETRY geo;
8981: DWORD dwSize;
8982: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
8983: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x07; // ???
8984: switch(geo.MediaType) {
8985: case F5_360_512:
8986: case F5_320_512:
8987: case F5_320_1024:
8988: case F5_180_512:
8989: case F5_160_512:
8990: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // 320K/360K disk
8991: break;
8992: case F5_1Pt2_512:
8993: case F3_1Pt2_512:
8994: case F3_1Pt23_1024:
8995: case F5_1Pt23_1024:
8996: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x01; // 1.2M disk
8997: break;
8998: case F3_720_512:
8999: case F3_640_512:
9000: case F5_640_512:
9001: case F5_720_512:
9002: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02; // 720K disk
9003: break;
9004: case F8_256_128:
9005: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x03; // single-density 8-inch disk
9006: break;
9007: case FixedMedia:
9008: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
9009: break;
9010: case F3_1Pt44_512:
9011: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07; // (DOS 3.3+) other type of block device, normally 1.44M floppy
9012: break;
9013: case F3_2Pt88_512:
9014: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09; // (DOS 5+) 2.88M floppy
9015: break;
9016: default:
9017: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
9018: // *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // (DOS 3.3+) other type of block device, normally 1.44M floppy
9019: break;
9020: }
9021: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = (geo.MediaType == FixedMedia) ? 0x01 : 0x00;
9022: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04) = (geo.Cylinders.QuadPart > 0xffff) ? 0xffff : geo.Cylinders.QuadPart;
9023: switch(geo.MediaType) {
9024: case F5_360_512:
9025: case F5_320_512:
9026: case F5_320_1024:
9027: case F5_180_512:
9028: case F5_160_512:
9029: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x01; // 320K/360K disk
9030: break;
9031: default:
9032: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x00; // other drive types
9033: break;
9034: }
9035: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x00) = geo.BytesPerSector;
9036: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x02) = geo.SectorsPerTrack * geo.TracksPerCylinder;
9037: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x03) = 0;
9038: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x05) = 0;
9039: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x06) = 0;
9040: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x08) = 0;
9041: switch(geo.MediaType) {
9042: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
9043: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xff;
9044: break;
9045: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
9046: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfe;
9047: break;
9048: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
9049: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfd;
9050: break;
9051: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
9052: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfc;
9053: break;
9054: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
9055: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
9056: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf9;
9057: break;
9058: case FixedMedia: // hard disk
9059: case RemovableMedia:
9060: case Unknown:
9061: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf8;
9062: break;
9063: default:
9064: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf0;
9065: break;
9066: }
9067: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0d) = geo.SectorsPerTrack;
9068: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0f) = 1;
9069: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x11) = 0;
9070: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x15) = geo.TracksPerCylinder * geo.Cylinders.QuadPart;
9071: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x1f) = geo.Cylinders.QuadPart;
9072: // 21h BYTE device type
9073: // 22h WORD device attributes (removable or not, etc)
9074: } else {
9075: REG16(AX) = 0x0f; // invalid drive
9076: m_CF = 1;
9077: }
9078: CloseHandle(hFile);
9079: } else {
9080: REG16(AX) = 0x0f; // invalid drive
9081: m_CF = 1;
9082: }
9083: } else if(REG8(CL) == 0x66) {
9084: // get volume serial number
9085: char path[] = "A:\\";
9086: char volume_label[MAX_PATH];
9087: DWORD serial_number = 0;
9088: char file_system[MAX_PATH];
9089:
9090: path[0] = 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
9091:
9092: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
9093: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
9094: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = serial_number;
9095: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x06, 0x20, 11);
9096: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x06, volume_label, min(strlen(volume_label), 11));
9097: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x11, 0x20, 8);
9098: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x11, file_system, min(strlen(file_system), 8));
9099: } else {
9100: REG16(AX) = 0x0f; // invalid drive
9101: m_CF = 1;
9102: }
9103: } else if(REG8(CL) == 0x67) {
9104: // get access flag
9105: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
9106: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 1;
9107: } else if(REG8(CL) == 0x68) {
9108: // sense media type
9109: char dev[64];
9110: sprintf(dev, "\\\\.\\%c:", 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1);
9111:
9112: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
9113: if(hFile != INVALID_HANDLE_VALUE) {
9114: DISK_GEOMETRY geo;
9115: DWORD dwSize;
9116: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
9117: switch(geo.MediaType) {
9118: case F3_720_512:
9119: case F5_720_512:
9120: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
9121: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02;
9122: break;
9123: case F3_1Pt44_512:
9124: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
9125: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07;
9126: break;
9127: case F3_2Pt88_512:
9128: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
9129: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09;
9130: break;
9131: default:
9132: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x00;
9133: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // ???
9134: break;
9135: }
9136: } else {
9137: REG16(AX) = 0x0f; // invalid drive
9138: m_CF = 1;
9139: }
9140: CloseHandle(hFile);
9141: } else {
9142: REG16(AX) = 0x0f; // invalid drive
9143: m_CF = 1;
9144: }
9145: } else if(REG8(CL) == 0x6a) {
9146: // unlock logical volume
9147: } else if(REG8(CL) == 0x6b) {
9148: // unlock physical volume
9149: } else {
9150: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
9151: REG16(AX) = 0x01; // invalid function
9152: m_CF = 1;
9153: }
9154: break;
9155: case 0x0e: // get logical drive map
9156: {
9157: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
9158: if(!(GetLogicalDrives() & bits)) {
9159: REG16(AX) = 0x0f; // invalid drive
9160: m_CF = 1;
9161: } else {
9162: REG8(AL) = 0;
9163: }
9164: }
9165: break;
9166: case 0x0f: // set logical drive map
9167: {
9168: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
9169: if(!(GetLogicalDrives() & bits)) {
9170: REG16(AX) = 0x0f; // invalid drive
9171: m_CF = 1;
9172: }
9173: }
9174: break;
9175: case 0x10: // query generic ioctrl capability (handle)
9176: switch(REG8(CL)) {
9177: case 0x45:
9178: case 0x4a:
9179: case 0x65:
9180: case 0x6a:
9181: case 0x7f:
9182: REG16(AX) = 0x0000; // supported
9183: break;
9184: default:
9185: REG8(AL) = 0x01; // ioctl capability not available
9186: m_CF = 1;
9187: break;
9188: }
9189: break;
9190: case 0x11: // query generic ioctrl capability (drive)
9191: switch(REG8(CL)) {
9192: case 0x40:
9193: case 0x46:
9194: case 0x4a:
9195: case 0x4b:
9196: case 0x60:
9197: case 0x66:
9198: case 0x67:
9199: case 0x68:
9200: case 0x6a:
9201: case 0x6b:
9202: REG16(AX) = 0x0000; // supported
9203: break;
9204: default:
9205: REG8(AL) = 0x01; // ioctl capability not available
9206: m_CF = 1;
9207: break;
9208: }
9209: break;
9210: case 0x12: // determine dos type
9211: case 0x51: // concurrent dos v3.2+ - installation check
9212: case 0x52: // determine dos type/get dr dos versuin
9213: REG16(AX) = 0x01; // this is not DR-DOS
9214: m_CF = 1;
9215: break;
1.1 root 9216: default:
1.1.1.22 root 9217: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 9218: REG16(AX) = 0x01;
1.1.1.3 root 9219: m_CF = 1;
1.1 root 9220: break;
9221: }
9222: }
9223:
9224: inline void msdos_int_21h_45h()
9225: {
9226: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 9227: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 9228:
1.1.1.20 root 9229: if(fd < process->max_files && file_handler[fd].valid) {
9230: int dup_fd = _dup(fd);
9231: if(dup_fd != -1) {
9232: REG16(AX) = dup_fd;
9233: msdos_file_handler_dup(dup_fd, fd, current_psp);
9234: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
9235: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 9236: } else {
9237: REG16(AX) = errno;
1.1.1.3 root 9238: m_CF = 1;
1.1 root 9239: }
9240: } else {
9241: REG16(AX) = 0x06;
1.1.1.3 root 9242: m_CF = 1;
1.1 root 9243: }
9244: }
9245:
9246: inline void msdos_int_21h_46h()
9247: {
9248: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 9249: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
9250: int dup_fd = REG16(CX);
9251: int tmp_fd = msdos_psp_get_file_table(REG16(CX), current_psp);
1.1 root 9252:
1.1.1.20 root 9253: if(REG16(BX) == REG16(CX)) {
9254: REG16(AX) = 0x06;
9255: m_CF = 1;
9256: } else if(fd < process->max_files && file_handler[fd].valid && dup_fd < process->max_files) {
9257: if(tmp_fd < process->max_files && file_handler[tmp_fd].valid) {
9258: _close(tmp_fd);
9259: msdos_file_handler_close(tmp_fd);
9260: msdos_psp_set_file_table(dup_fd, 0x0ff, current_psp);
9261: }
9262: if(_dup2(fd, dup_fd) != -1) {
9263: msdos_file_handler_dup(dup_fd, fd, current_psp);
9264: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
9265: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 9266: } else {
9267: REG16(AX) = errno;
1.1.1.3 root 9268: m_CF = 1;
1.1 root 9269: }
9270: } else {
9271: REG16(AX) = 0x06;
1.1.1.3 root 9272: m_CF = 1;
1.1 root 9273: }
9274: }
9275:
9276: inline void msdos_int_21h_47h(int lfn)
9277: {
9278: char path[MAX_PATH];
9279:
9280: if(_getdcwd(REG8(DL), path, MAX_PATH) != NULL) {
9281: if(path[1] == ':') {
9282: // the returned path does not include a drive or the initial backslash
1.1.1.3 root 9283: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), (lfn ? path : msdos_short_path(path)) + 3);
1.1 root 9284: } else {
1.1.1.3 root 9285: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn ? path : msdos_short_path(path));
1.1 root 9286: }
9287: } else {
9288: REG16(AX) = errno;
1.1.1.3 root 9289: m_CF = 1;
1.1 root 9290: }
9291: }
9292:
9293: inline void msdos_int_21h_48h()
9294: {
1.1.1.19 root 9295: int seg, umb_linked;
1.1 root 9296:
1.1.1.8 root 9297: if((malloc_strategy & 0xf0) == 0x00) {
1.1.1.19 root 9298: // unlink umb not to allocate memory in umb
9299: if((umb_linked = msdos_mem_get_umb_linked()) != 0) {
9300: msdos_mem_unlink_umb();
9301: }
1.1.1.8 root 9302: if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
9303: REG16(AX) = seg;
9304: } else {
9305: REG16(AX) = 0x08;
9306: REG16(BX) = msdos_mem_get_free(first_mcb, 0);
9307: m_CF = 1;
9308: }
1.1.1.19 root 9309: if(umb_linked != 0) {
9310: msdos_mem_link_umb();
9311: }
1.1.1.8 root 9312: } else if((malloc_strategy & 0xf0) == 0x40) {
9313: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
9314: REG16(AX) = seg;
9315: } else {
9316: REG16(AX) = 0x08;
9317: REG16(BX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
9318: m_CF = 1;
9319: }
9320: } else if((malloc_strategy & 0xf0) == 0x80) {
9321: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
9322: REG16(AX) = seg;
9323: } else if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
9324: REG16(AX) = seg;
9325: } else {
9326: REG16(AX) = 0x08;
9327: REG16(BX) = max(msdos_mem_get_free(UMB_TOP >> 4, 0), msdos_mem_get_free(first_mcb, 0));
9328: m_CF = 1;
9329: }
1.1 root 9330: }
9331: }
9332:
9333: inline void msdos_int_21h_49h()
9334: {
1.1.1.14 root 9335: int mcb_seg = SREG(ES) - 1;
9336: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
9337:
9338: if(mcb->mz == 'M' || mcb->mz == 'Z') {
9339: msdos_mem_free(SREG(ES));
9340: } else {
1.1.1.33! root 9341: REG16(AX) = 0x09; // illegal memory block address
1.1.1.14 root 9342: m_CF = 1;
9343: }
1.1 root 9344: }
9345:
9346: inline void msdos_int_21h_4ah()
9347: {
1.1.1.14 root 9348: int mcb_seg = SREG(ES) - 1;
9349: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1 root 9350: int max_paragraphs;
9351:
1.1.1.14 root 9352: if(mcb->mz == 'M' || mcb->mz == 'Z') {
9353: if(msdos_mem_realloc(SREG(ES), REG16(BX), &max_paragraphs)) {
9354: REG16(AX) = 0x08;
9355: REG16(BX) = max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs;
9356: m_CF = 1;
9357: }
9358: } else {
1.1.1.33! root 9359: REG16(AX) = 0x09; // illegal memory block address
1.1.1.3 root 9360: m_CF = 1;
1.1 root 9361: }
9362: }
9363:
9364: inline void msdos_int_21h_4bh()
9365: {
1.1.1.3 root 9366: char *command = (char *)(mem + SREG_BASE(DS) + REG16(DX));
9367: param_block_t *param = (param_block_t *)(mem + SREG_BASE(ES) + REG16(BX));
1.1 root 9368:
9369: switch(REG8(AL)) {
9370: case 0x00:
9371: case 0x01:
9372: if(msdos_process_exec(command, param, REG8(AL))) {
9373: REG16(AX) = 0x02;
1.1.1.3 root 9374: m_CF = 1;
1.1 root 9375: }
9376: break;
1.1.1.14 root 9377: case 0x03:
9378: {
9379: int fd;
9380: if((fd = _open(command, _O_RDONLY | _O_BINARY)) == -1) {
9381: REG16(AX) = 0x02;
9382: m_CF = 1;
9383: break;
9384: }
9385: int size = _read(fd, file_buffer, sizeof(file_buffer));
9386: _close(fd);
9387:
9388: UINT16 *overlay = (UINT16 *)param;
9389:
9390: // check exe header
9391: exe_header_t *header = (exe_header_t *)file_buffer;
9392: int header_size = 0;
9393: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
9394: header_size = header->header_size * 16;
9395: // relocation
9396: int start_seg = overlay[1];
9397: for(int i = 0; i < header->relocations; i++) {
9398: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
9399: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
9400: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
9401: }
9402: }
9403: memcpy(mem + (overlay[0] << 4), file_buffer + header_size, size - header_size);
9404: }
9405: break;
1.1 root 9406: default:
1.1.1.22 root 9407: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 9408: REG16(AX) = 0x01;
1.1.1.3 root 9409: m_CF = 1;
1.1 root 9410: break;
9411: }
9412: }
9413:
9414: inline void msdos_int_21h_4ch()
9415: {
9416: msdos_process_terminate(current_psp, REG8(AL), 1);
9417: }
9418:
9419: inline void msdos_int_21h_4dh()
9420: {
9421: REG16(AX) = retval;
9422: }
9423:
9424: inline void msdos_int_21h_4eh()
9425: {
9426: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 9427: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
9428: find_t *find = (find_t *)(mem + dta_laddr);
1.1.1.3 root 9429: char *path = msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 9430: WIN32_FIND_DATA fd;
9431:
1.1.1.14 root 9432: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
9433: find->find_magic = FIND_MAGIC;
9434: find->dta_index = dtainfo - dtalist;
1.1 root 9435: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 9436: dtainfo->allowable_mask = REG8(CL);
9437: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 9438:
1.1.1.14 root 9439: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
9440: dtainfo->allowable_mask &= ~8;
1.1 root 9441: }
1.1.1.14 root 9442: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
9443: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 9444: !msdos_find_file_has_8dot3name(&fd)) {
9445: if(!FindNextFile(dtainfo->find_handle, &fd)) {
9446: FindClose(dtainfo->find_handle);
9447: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 9448: break;
9449: }
9450: }
9451: }
1.1.1.13 root 9452: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 9453: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
9454: msdos_find_file_conv_local_time(&fd);
9455: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
9456: find->size = fd.nFileSizeLow;
1.1.1.13 root 9457: strcpy(find->name, msdos_short_name(&fd));
1.1 root 9458: REG16(AX) = 0;
1.1.1.14 root 9459: } else if(dtainfo->allowable_mask & 8) {
1.1 root 9460: find->attrib = 8;
9461: find->size = 0;
9462: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 9463: dtainfo->allowable_mask &= ~8;
1.1 root 9464: REG16(AX) = 0;
9465: } else {
9466: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 9467: m_CF = 1;
1.1 root 9468: }
9469: }
9470:
9471: inline void msdos_int_21h_4fh()
9472: {
9473: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 9474: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
9475: find_t *find = (find_t *)(mem + dta_laddr);
1.1 root 9476: WIN32_FIND_DATA fd;
9477:
1.1.1.14 root 9478: if(find->find_magic != FIND_MAGIC || find->dta_index >= MAX_DTAINFO) {
9479: REG16(AX) = 0x12;
9480: m_CF = 1;
9481: return;
9482: }
9483: dtainfo_t *dtainfo = &dtalist[find->dta_index];
1.1.1.13 root 9484: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
9485: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 9486: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 9487: !msdos_find_file_has_8dot3name(&fd)) {
9488: if(!FindNextFile(dtainfo->find_handle, &fd)) {
9489: FindClose(dtainfo->find_handle);
9490: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 9491: break;
9492: }
9493: }
9494: } else {
1.1.1.13 root 9495: FindClose(dtainfo->find_handle);
9496: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 9497: }
9498: }
1.1.1.13 root 9499: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 9500: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
9501: msdos_find_file_conv_local_time(&fd);
9502: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
9503: find->size = fd.nFileSizeLow;
1.1.1.13 root 9504: strcpy(find->name, msdos_short_name(&fd));
1.1 root 9505: REG16(AX) = 0;
1.1.1.14 root 9506: } else if(dtainfo->allowable_mask & 8) {
1.1 root 9507: find->attrib = 8;
9508: find->size = 0;
9509: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 9510: dtainfo->allowable_mask &= ~8;
1.1 root 9511: REG16(AX) = 0;
9512: } else {
9513: REG16(AX) = 0x12;
1.1.1.3 root 9514: m_CF = 1;
1.1 root 9515: }
9516: }
9517:
9518: inline void msdos_int_21h_50h()
9519: {
1.1.1.8 root 9520: if(current_psp != REG16(BX)) {
9521: process_t *process = msdos_process_info_get(current_psp);
9522: if(process != NULL) {
9523: process->psp = REG16(BX);
9524: }
9525: current_psp = REG16(BX);
1.1.1.23 root 9526: msdos_sda_update(current_psp);
1.1.1.8 root 9527: }
1.1 root 9528: }
9529:
9530: inline void msdos_int_21h_51h()
9531: {
9532: REG16(BX) = current_psp;
9533: }
9534:
9535: inline void msdos_int_21h_52h()
9536: {
1.1.1.25 root 9537: SREG(ES) = DOS_INFO_TOP >> 4;
1.1.1.3 root 9538: i386_load_segment_descriptor(ES);
1.1.1.25 root 9539: REG16(BX) = offsetof(dos_info_t, first_dpb);
1.1 root 9540: }
9541:
9542: inline void msdos_int_21h_54h()
9543: {
9544: process_t *process = msdos_process_info_get(current_psp);
9545:
9546: REG8(AL) = process->verify;
9547: }
9548:
9549: inline void msdos_int_21h_55h()
9550: {
9551: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
9552:
9553: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
9554: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
9555: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
9556: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
9557: psp->parent_psp = current_psp;
9558: }
9559:
9560: inline void msdos_int_21h_56h(int lfn)
9561: {
9562: char src[MAX_PATH], dst[MAX_PATH];
1.1.1.3 root 9563: strcpy(src, msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn));
9564: strcpy(dst, msdos_trimmed_path((char *)(mem + SREG_BASE(ES) + REG16(DI)), lfn));
1.1 root 9565:
9566: if(rename(src, dst)) {
9567: REG16(AX) = errno;
1.1.1.3 root 9568: m_CF = 1;
1.1 root 9569: }
9570: }
9571:
9572: inline void msdos_int_21h_57h()
9573: {
9574: FILETIME time, local;
1.1.1.14 root 9575: FILETIME *ctime, *atime, *mtime;
1.1.1.21 root 9576: HANDLE hHandle;
1.1 root 9577:
1.1.1.21 root 9578: if((hHandle = (HANDLE)_get_osfhandle(REG16(BX))) == INVALID_HANDLE_VALUE) {
1.1.1.14 root 9579: REG16(AX) = (UINT16)GetLastError();
9580: m_CF = 1;
9581: return;
9582: }
9583: ctime = atime = mtime = NULL;
9584:
1.1 root 9585: switch(REG8(AL)) {
9586: case 0x00:
1.1.1.6 root 9587: case 0x01:
1.1.1.14 root 9588: mtime = &time;
1.1.1.6 root 9589: break;
9590: case 0x04:
9591: case 0x05:
1.1.1.14 root 9592: atime = &time;
1.1 root 9593: break;
1.1.1.6 root 9594: case 0x06:
9595: case 0x07:
1.1.1.14 root 9596: ctime = &time;
9597: break;
9598: default:
1.1.1.22 root 9599: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.14 root 9600: REG16(AX) = 0x01;
9601: m_CF = 1;
9602: return;
9603: }
9604: if(REG8(AL) & 1) {
1.1 root 9605: DosDateTimeToFileTime(REG16(DX), REG16(CX), &local);
9606: LocalFileTimeToFileTime(&local, &time);
1.1.1.21 root 9607: if(!SetFileTime(hHandle, ctime, atime, mtime)) {
1.1 root 9608: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 9609: m_CF = 1;
1.1 root 9610: }
1.1.1.14 root 9611: } else {
1.1.1.21 root 9612: if(!GetFileTime(hHandle, ctime, atime, mtime)) {
1.1.1.14 root 9613: // assume a device and use the current time
9614: GetSystemTimeAsFileTime(&time);
9615: }
9616: FileTimeToLocalFileTime(&time, &local);
9617: FileTimeToDosDateTime(&local, ®16(DX), ®16(CX));
1.1 root 9618: }
9619: }
9620:
9621: inline void msdos_int_21h_58h()
9622: {
9623: switch(REG8(AL)) {
9624: case 0x00:
1.1.1.7 root 9625: REG16(AX) = malloc_strategy;
9626: break;
9627: case 0x01:
1.1.1.24 root 9628: // switch(REG16(BX)) {
9629: switch(REG8(BL)) {
1.1.1.7 root 9630: case 0x0000:
9631: case 0x0001:
9632: case 0x0002:
9633: case 0x0040:
9634: case 0x0041:
9635: case 0x0042:
9636: case 0x0080:
9637: case 0x0081:
9638: case 0x0082:
9639: malloc_strategy = REG16(BX);
1.1.1.23 root 9640: msdos_sda_update(current_psp);
1.1.1.7 root 9641: break;
9642: default:
1.1.1.22 root 9643: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.7 root 9644: REG16(AX) = 0x01;
9645: m_CF = 1;
9646: break;
9647: }
9648: break;
9649: case 0x02:
1.1.1.19 root 9650: REG8(AL) = msdos_mem_get_umb_linked() ? 1 : 0;
1.1.1.7 root 9651: break;
9652: case 0x03:
1.1.1.24 root 9653: // switch(REG16(BX)) {
9654: switch(REG8(BL)) {
1.1.1.7 root 9655: case 0x0000:
1.1.1.19 root 9656: msdos_mem_unlink_umb();
9657: break;
1.1.1.7 root 9658: case 0x0001:
1.1.1.19 root 9659: msdos_mem_link_umb();
1.1.1.7 root 9660: break;
9661: default:
1.1.1.22 root 9662: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.7 root 9663: REG16(AX) = 0x01;
9664: m_CF = 1;
9665: break;
9666: }
1.1 root 9667: break;
9668: default:
1.1.1.22 root 9669: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 9670: REG16(AX) = 0x01;
1.1.1.3 root 9671: m_CF = 1;
1.1 root 9672: break;
9673: }
9674: }
9675:
9676: inline void msdos_int_21h_59h()
9677: {
1.1.1.23 root 9678: sda_t *sda = (sda_t *)(mem + SDA_TOP);
9679:
9680: REG16(AX) = sda->extended_error_code;
9681: REG8(BH) = sda->error_class;
9682: REG8(BL) = sda->suggested_action;
9683: REG8(CH) = sda->locus_of_last_error;
1.1 root 9684: }
9685:
9686: inline void msdos_int_21h_5ah()
9687: {
1.1.1.3 root 9688: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 9689: int len = strlen(path);
9690: char tmp[MAX_PATH];
9691:
9692: if(GetTempFileName(path, "TMP", 0, tmp)) {
9693: int fd = _open(tmp, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
9694:
9695: SetFileAttributes(tmp, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
9696: REG16(AX) = fd;
9697: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 9698: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 9699:
9700: strcpy(path, tmp);
9701: int dx = REG16(DX) + len;
1.1.1.3 root 9702: int ds = SREG(DS);
1.1 root 9703: while(dx > 0xffff) {
9704: dx -= 0x10;
9705: ds++;
9706: }
9707: REG16(DX) = dx;
1.1.1.3 root 9708: SREG(DS) = ds;
9709: i386_load_segment_descriptor(DS);
1.1 root 9710: } else {
9711: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 9712: m_CF = 1;
1.1 root 9713: }
9714: }
9715:
9716: inline void msdos_int_21h_5bh()
9717: {
1.1.1.3 root 9718: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 9719:
1.1.1.24 root 9720: if(msdos_is_existing_file(path)) {
1.1 root 9721: // already exists
9722: REG16(AX) = 0x50;
1.1.1.3 root 9723: m_CF = 1;
1.1 root 9724: } else {
9725: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
9726:
9727: if(fd != -1) {
9728: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
9729: REG16(AX) = fd;
9730: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 9731: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 9732: } else {
9733: REG16(AX) = errno;
1.1.1.3 root 9734: m_CF = 1;
1.1 root 9735: }
9736: }
9737: }
9738:
9739: inline void msdos_int_21h_5ch()
9740: {
9741: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 9742: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 9743:
1.1.1.20 root 9744: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 9745: if(REG8(AL) == 0 || REG8(AL) == 1) {
9746: static int modes[2] = {_LK_LOCK, _LK_UNLCK};
1.1.1.20 root 9747: UINT32 pos = _tell(fd);
9748: _lseek(fd, (REG16(CX) << 16) | REG16(DX), SEEK_SET);
9749: if(_locking(fd, modes[REG8(AL)], (REG16(SI) << 16) | REG16(DI))) {
1.1 root 9750: REG16(AX) = errno;
1.1.1.3 root 9751: m_CF = 1;
1.1 root 9752: }
1.1.1.20 root 9753: _lseek(fd, pos, SEEK_SET);
1.1.1.26 root 9754:
1.1 root 9755: // some seconds may be passed in _locking()
9756: hardware_update();
9757: } else {
9758: REG16(AX) = 0x01;
1.1.1.3 root 9759: m_CF = 1;
1.1 root 9760: }
9761: } else {
9762: REG16(AX) = 0x06;
1.1.1.3 root 9763: m_CF = 1;
1.1 root 9764: }
9765: }
9766:
1.1.1.22 root 9767: inline void msdos_int_21h_5dh()
9768: {
9769: switch(REG8(AL)) {
9770: case 0x06: // get address of dos swappable data area
1.1.1.23 root 9771: SREG(DS) = (SDA_TOP >> 4);
9772: i386_load_segment_descriptor(DS);
9773: REG16(SI) = offsetof(sda_t, crit_error_flag);
9774: REG16(CX) = 0x80;
9775: REG16(DX) = 0x1a;
9776: break;
9777: case 0x0b: // get dos swappable data areas
1.1.1.22 root 9778: REG16(AX) = 0x01;
9779: m_CF = 1;
9780: break;
9781: case 0x08: // set redirected printer mode
9782: case 0x09: // flush redirected printer output
9783: case 0x0a: // set extended error information
9784: break;
9785: default:
9786: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
9787: REG16(AX) = 0x01;
9788: m_CF = 1;
9789: break;
9790: }
9791: }
9792:
1.1.1.30 root 9793: inline void msdos_int_21h_5fh()
9794: {
9795: switch(REG8(AL)) {
9796: case 0x02:
9797: {
9798: DWORD drives = GetLogicalDrives();
9799: for(int i = 0, index = 0; i < 26; i++) {
9800: if(drives & (1 << i)) {
9801: char volume[] = "A:\\";
9802: volume[0] = 'A' + i;
9803: if(GetDriveType(volume) == DRIVE_REMOTE) {
9804: if(index == REG16(BX)) {
9805: DWORD dwSize = 128;
9806: volume[2] = '\0';
9807: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), volume);
9808: WNetGetConnection(volume, (char *)(mem + SREG_BASE(ES) + REG16(DI)), &dwSize);
9809: REG8(BH) = 0x00; // valid
9810: REG8(BL) = 0x04; // disk drive
9811: REG16(CX) = 0x00;
9812: return;
9813: }
9814: index++;
9815: }
9816: }
9817: }
9818: }
9819: REG16(AX) = 0x12; // no more files
9820: m_CF = 1;
9821: break;
9822: default:
9823: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
9824: REG16(AX) = 0x01;
9825: m_CF = 1;
9826: break;
9827: }
9828: }
9829:
1.1 root 9830: inline void msdos_int_21h_60h(int lfn)
9831: {
1.1.1.14 root 9832: char full[MAX_PATH], *path;
9833:
1.1 root 9834: if(lfn) {
1.1.1.14 root 9835: char *name;
9836: *full = '\0';
1.1.1.3 root 9837: GetFullPathName((char *)(mem + SREG_BASE(DS) + REG16(SI)), MAX_PATH, full, &name);
1.1.1.14 root 9838: switch(REG8(CL)) {
9839: case 1:
9840: GetShortPathName(full, full, MAX_PATH);
9841: my_strupr(full);
9842: break;
9843: case 2:
9844: GetLongPathName(full, full, MAX_PATH);
9845: break;
9846: }
9847: path = full;
9848: } else {
9849: path = msdos_short_full_path((char *)(mem + SREG_BASE(DS) + REG16(SI)));
9850: }
9851: if(*path != '\0') {
9852: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path);
1.1 root 9853: } else {
1.1.1.14 root 9854: REG16(AX) = (UINT16)GetLastError();
9855: m_CF = 1;
1.1 root 9856: }
9857: }
9858:
9859: inline void msdos_int_21h_61h()
9860: {
9861: REG8(AL) = 0;
9862: }
9863:
9864: inline void msdos_int_21h_62h()
9865: {
9866: REG16(BX) = current_psp;
9867: }
9868:
9869: inline void msdos_int_21h_63h()
9870: {
9871: switch(REG8(AL)) {
9872: case 0x00:
1.1.1.3 root 9873: SREG(DS) = (DBCS_TABLE >> 4);
9874: i386_load_segment_descriptor(DS);
1.1 root 9875: REG16(SI) = (DBCS_TABLE & 0x0f);
9876: REG8(AL) = 0x00;
9877: break;
1.1.1.22 root 9878: case 0x01: // set korean input mode
9879: case 0x02: // get korean input mode
9880: REG8(AL) = 0xff; // not supported
9881: break;
1.1 root 9882: default:
1.1.1.22 root 9883: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 9884: REG16(AX) = 0x01;
1.1.1.3 root 9885: m_CF = 1;
1.1 root 9886: break;
9887: }
9888: }
9889:
1.1.1.25 root 9890: UINT16 get_extended_country_info(UINT8 func)
1.1 root 9891: {
1.1.1.25 root 9892: switch(func) {
1.1.1.17 root 9893: case 0x01:
9894: if(REG16(CX) >= 5) {
1.1.1.19 root 9895: UINT8 data[1 + 2 + 2 + 2 + sizeof(country_info_t)];
1.1.1.17 root 9896: if(REG16(CX) > sizeof(data)) // cx = actual transfer size
9897: REG16(CX) = sizeof(data);
9898: ZeroMemory(data, sizeof(data));
9899: data[0] = 0x01;
9900: *(UINT16 *)(data + 1) = REG16(CX) - 3;
1.1.1.19 root 9901: *(UINT16 *)(data + 3) = get_country_info((country_info_t*)(data + 7));
1.1.1.17 root 9902: *(UINT16 *)(data + 5) = active_code_page;
9903: memcpy(mem + SREG_BASE(ES) + REG16(DI), data, REG16(CX));
1.1.1.25 root 9904: // REG16(AX) = active_code_page;
1.1.1.17 root 9905: } else {
1.1.1.25 root 9906: return(0x08); // insufficient memory
1.1.1.17 root 9907: }
9908: break;
9909: case 0x02:
9910: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
9911: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (UPPERTABLE_TOP & 0x0f);
9912: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (UPPERTABLE_TOP >> 4);
1.1.1.25 root 9913: // REG16(AX) = active_code_page;
1.1.1.17 root 9914: REG16(CX) = 0x05;
9915: break;
1.1.1.23 root 9916: case 0x03:
9917: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
9918: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (LOWERTABLE_TOP & 0x0f);
9919: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (LOWERTABLE_TOP >> 4);
1.1.1.25 root 9920: // REG16(AX) = active_code_page;
1.1.1.23 root 9921: REG16(CX) = 0x05;
9922: break;
1.1.1.17 root 9923: case 0x04:
9924: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x04;
9925: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_UPPERTABLE_TOP & 0x0f);
9926: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_UPPERTABLE_TOP >> 4);
1.1.1.25 root 9927: // REG16(AX) = active_code_page;
1.1.1.17 root 9928: REG16(CX) = 0x05;
9929: break;
9930: case 0x05:
9931: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x05;
9932: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_TERMINATOR_TOP & 0x0f);
9933: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_TERMINATOR_TOP >> 4);
1.1.1.25 root 9934: // REG16(AX) = active_code_page;
1.1.1.17 root 9935: REG16(CX) = 0x05;
9936: break;
9937: case 0x06:
9938: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x06;
9939: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (COLLATING_TABLE_TOP & 0x0f);
9940: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (COLLATING_TABLE_TOP >> 4);
1.1.1.25 root 9941: // REG16(AX) = active_code_page;
1.1.1.17 root 9942: REG16(CX) = 0x05;
9943: break;
1.1 root 9944: case 0x07:
1.1.1.3 root 9945: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x07;
9946: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (DBCS_TOP & 0x0f);
9947: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (DBCS_TOP >> 4);
1.1.1.25 root 9948: // REG16(AX) = active_code_page;
1.1 root 9949: REG16(CX) = 0x05;
9950: break;
1.1.1.25 root 9951: default:
9952: return(0x01); // function number invalid
9953: }
9954: return(0x00);
9955: }
9956:
9957: inline void msdos_int_21h_65h()
9958: {
9959: char tmp[0x10000];
9960:
9961: switch(REG8(AL)) {
9962: case 0x01:
9963: case 0x02:
9964: case 0x03:
9965: case 0x04:
9966: case 0x05:
9967: case 0x06:
9968: case 0x07:
9969: {
9970: UINT16 result = get_extended_country_info(REG8(AL));
9971: if(result) {
9972: REG16(AX) = result;
9973: m_CF = 1;
9974: } else {
9975: REG16(AX) = active_code_page; // FIXME: is this correct???
9976: }
9977: }
9978: break;
1.1 root 9979: case 0x20:
1.1.1.25 root 9980: case 0xa0:
1.1.1.19 root 9981: memset(tmp, 0, sizeof(tmp));
9982: tmp[0] = REG8(DL);
1.1 root 9983: my_strupr(tmp);
9984: REG8(DL) = tmp[0];
9985: break;
9986: case 0x21:
1.1.1.25 root 9987: case 0xa1:
1.1 root 9988: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 9989: memcpy(tmp, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 9990: my_strupr(tmp);
1.1.1.3 root 9991: memcpy(mem + SREG_BASE(DS) + REG16(DX), tmp, REG16(CX));
1.1 root 9992: break;
9993: case 0x22:
1.1.1.25 root 9994: case 0xa2:
1.1.1.3 root 9995: my_strupr((char *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1 root 9996: break;
1.1.1.25 root 9997: case 0x23:
9998: // FIXME: need to check multi-byte (kanji) charactre?
9999: if(REG8(DL) == 'N' || REG8(DL) == 'n' || (REG8(DL) == 0x82 && REG8(DH) == 0x78) || (REG8(DL) == 0x82 && REG8(DH) == 0x99)) {
10000: // 8278h/8299h: multi-byte (kanji) Y and y
10001: REG16(AX) = 0x00;
10002: } else if(REG8(DL) == 'Y' || REG8(DL) == 'y' || (REG8(DL) == 0x82 && REG8(DH) == 0x6d) || (REG8(DL) == 0x82 && REG8(DH) == 0x8e)) {
10003: // 826dh/828eh: multi-byte (kanji) N and n
10004: REG16(AX) = 0x01;
10005: } else {
10006: REG16(AX) = 0x02;
10007: }
10008: break;
1.1 root 10009: default:
1.1.1.22 root 10010: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 10011: REG16(AX) = 0x01;
1.1.1.3 root 10012: m_CF = 1;
1.1 root 10013: break;
10014: }
10015: }
10016:
10017: inline void msdos_int_21h_66h()
10018: {
10019: switch(REG8(AL)) {
10020: case 0x01:
10021: REG16(BX) = active_code_page;
10022: REG16(DX) = system_code_page;
10023: break;
10024: case 0x02:
10025: if(active_code_page == REG16(BX)) {
10026: REG16(AX) = 0xeb41;
10027: } else if(_setmbcp(REG16(BX)) == 0) {
10028: active_code_page = REG16(BX);
1.1.1.17 root 10029: msdos_nls_tables_update();
1.1 root 10030: REG16(AX) = 0xeb41;
1.1.1.32 root 10031: SetConsoleCP(active_code_page);
10032: SetConsoleOutputCP(active_code_page);
1.1 root 10033: } else {
10034: REG16(AX) = 0x25;
1.1.1.3 root 10035: m_CF = 1;
1.1 root 10036: }
10037: break;
10038: default:
1.1.1.22 root 10039: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 10040: REG16(AX) = 0x01;
1.1.1.3 root 10041: m_CF = 1;
1.1 root 10042: break;
10043: }
10044: }
10045:
10046: inline void msdos_int_21h_67h()
10047: {
10048: process_t *process = msdos_process_info_get(current_psp);
10049:
10050: if(REG16(BX) <= MAX_FILES) {
10051: process->max_files = max(REG16(BX), 20);
10052: } else {
10053: REG16(AX) = 0x08;
1.1.1.3 root 10054: m_CF = 1;
1.1 root 10055: }
10056: }
10057:
10058: inline void msdos_int_21h_68h()
10059: {
10060: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 10061: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 10062:
1.1.1.20 root 10063: if(fd < process->max_files && file_handler[fd].valid) {
10064: // fflush(_fdopen(fd, ""));
1.1 root 10065: } else {
10066: REG16(AX) = 0x06;
1.1.1.3 root 10067: m_CF = 1;
1.1 root 10068: }
10069: }
10070:
10071: inline void msdos_int_21h_69h()
10072: {
1.1.1.3 root 10073: drive_info_t *info = (drive_info_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 10074: char path[] = "A:\\";
10075: char volume_label[MAX_PATH];
10076: DWORD serial_number = 0;
10077: char file_system[MAX_PATH];
10078:
10079: if(REG8(BL) == 0) {
10080: path[0] = 'A' + _getdrive() - 1;
10081: } else {
10082: path[0] = 'A' + REG8(BL) - 1;
10083: }
10084:
10085: switch(REG8(AL)) {
10086: case 0x00:
10087: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
10088: info->info_level = 0;
10089: info->serial_number = serial_number;
10090: memset(info->volume_label, 0x20, 11);
10091: memcpy(info->volume_label, volume_label, min(strlen(volume_label), 11));
10092: memset(info->file_system, 0x20, 8);
10093: memcpy(info->file_system, file_system, min(strlen(file_system), 8));
10094: } else {
10095: REG16(AX) = errno;
1.1.1.3 root 10096: m_CF = 1;
1.1 root 10097: }
10098: break;
10099: case 0x01:
10100: REG16(AX) = 0x03;
1.1.1.3 root 10101: m_CF = 1;
1.1 root 10102: }
10103: }
10104:
10105: inline void msdos_int_21h_6ah()
10106: {
10107: REG8(AH) = 0x68;
10108: msdos_int_21h_68h();
10109: }
10110:
10111: inline void msdos_int_21h_6bh()
10112: {
10113: REG8(AL) = 0;
10114: }
10115:
10116: inline void msdos_int_21h_6ch(int lfn)
10117: {
1.1.1.3 root 10118: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn);
1.1 root 10119: int mode = REG8(BL) & 0x03;
10120:
10121: if(mode < 0x03) {
1.1.1.29 root 10122: if(msdos_is_device_path(path) || msdos_is_existing_file(path)) {
1.1 root 10123: // file exists
10124: if(REG8(DL) & 1) {
1.1.1.29 root 10125: int fd = -1, c;
1.1.1.11 root 10126: UINT16 info;
1.1 root 10127:
1.1.1.11 root 10128: if(msdos_is_con_path(path)) {
1.1.1.13 root 10129: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 10130: info = 0x80d3;
1.1.1.29 root 10131: } else if((c = msdos_is_comm_path(path)) != 0 && sio_port_number[c - 1] != 0) {
10132: if((fd = _open(msdos_create_comm_path(path, sio_port_number[c - 1]), file_mode[mode].mode)) == -1) {
10133: fd = msdos_open("NUL", file_mode[mode].mode);
10134: }
1.1.1.14 root 10135: info = 0x80d3;
1.1.1.29 root 10136: } else if(msdos_is_device_path(path)) {
1.1.1.20 root 10137: fd = msdos_open("NUL", file_mode[mode].mode);
10138: info = 0x80d3;
1.1.1.11 root 10139: } else {
1.1.1.13 root 10140: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 10141: info = msdos_drive_number(path);
10142: }
1.1 root 10143: if(fd != -1) {
10144: REG16(AX) = fd;
10145: REG16(CX) = 1;
1.1.1.11 root 10146: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp);
1.1.1.20 root 10147: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 10148: } else {
10149: REG16(AX) = errno;
1.1.1.3 root 10150: m_CF = 1;
1.1 root 10151: }
10152: } else if(REG8(DL) & 2) {
10153: int attr = GetFileAttributes(path);
1.1.1.29 root 10154: int fd = -1, c;
1.1.1.11 root 10155: UINT16 info;
1.1 root 10156:
1.1.1.11 root 10157: if(msdos_is_con_path(path)) {
1.1.1.13 root 10158: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 10159: info = 0x80d3;
1.1.1.29 root 10160: } else if((c = msdos_is_comm_path(path)) != 0 && sio_port_number[c - 1] != 0) {
10161: if((fd = _open(msdos_create_comm_path(path, sio_port_number[c - 1]), file_mode[mode].mode)) == -1) {
10162: fd = msdos_open("NUL", file_mode[mode].mode);
10163: }
1.1.1.14 root 10164: info = 0x80d3;
1.1.1.29 root 10165: } else if(msdos_is_device_path(path)) {
1.1.1.20 root 10166: fd = msdos_open("NUL", file_mode[mode].mode);
10167: info = 0x80d3;
1.1 root 10168: } else {
10169: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 10170: info = msdos_drive_number(path);
1.1 root 10171: }
10172: if(fd != -1) {
10173: if(attr == -1) {
10174: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
10175: }
10176: SetFileAttributes(path, attr);
10177: REG16(AX) = fd;
10178: REG16(CX) = 3;
1.1.1.11 root 10179: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp);
1.1.1.20 root 10180: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 10181: } else {
10182: REG16(AX) = errno;
1.1.1.3 root 10183: m_CF = 1;
1.1 root 10184: }
10185: } else {
10186: REG16(AX) = 0x50;
1.1.1.3 root 10187: m_CF = 1;
1.1 root 10188: }
10189: } else {
10190: // file not exists
10191: if(REG8(DL) & 0x10) {
10192: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
10193:
10194: if(fd != -1) {
10195: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
10196: REG16(AX) = fd;
10197: REG16(CX) = 2;
10198: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 10199: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 10200: } else {
10201: REG16(AX) = errno;
1.1.1.3 root 10202: m_CF = 1;
1.1 root 10203: }
10204: } else {
10205: REG16(AX) = 0x02;
1.1.1.3 root 10206: m_CF = 1;
1.1 root 10207: }
10208: }
10209: } else {
10210: REG16(AX) = 0x0c;
1.1.1.3 root 10211: m_CF = 1;
1.1 root 10212: }
10213: }
10214:
10215: inline void msdos_int_21h_710dh()
10216: {
10217: // reset drive
10218: }
10219:
1.1.1.17 root 10220: inline void msdos_int_21h_7141h(int lfn)
10221: {
10222: if(REG16(SI) == 0) {
10223: msdos_int_21h_41h(lfn);
10224: return;
10225: }
10226: if(REG16(SI) != 1) {
10227: REG16(AX) = 5;
10228: m_CF = 1;
10229: }
10230: /* wild card and matching attributes... */
10231: char tmp[MAX_PATH * 2];
10232: // copy search pathname (and quick check overrun)
10233: ZeroMemory(tmp, sizeof(tmp));
10234: tmp[MAX_PATH - 1] = '\0';
10235: tmp[MAX_PATH] = 1;
10236: strncpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(DX)), MAX_PATH);
10237:
10238: if(tmp[MAX_PATH - 1] != '\0' || tmp[MAX_PATH] != 1) {
10239: REG16(AX) = 1;
10240: m_CF = 1;
10241: return;
10242: }
10243: for(char *s = tmp; *s; ++s) {
10244: if(*s == '/') {
10245: *s = '\\';
10246: }
10247: }
10248: char *tmp_name = (char *)_mbsrchr((unsigned char *)tmp, '\\');
10249: if(tmp_name) {
10250: ++tmp_name;
10251: } else {
10252: tmp_name = strchr(tmp, ':');
10253: tmp_name = tmp_name ? tmp_name + 1 : tmp;
10254: }
10255:
10256: WIN32_FIND_DATAA fd;
10257: HANDLE fh = FindFirstFileA(tmp, &fd);
10258: if(fh == INVALID_HANDLE_VALUE) {
10259: REG16(AX) = 2;
10260: m_CF = 1;
10261: return;
10262: }
10263: do {
10264: if(msdos_find_file_check_attribute(fd.dwFileAttributes, REG8(CL), REG8(CH)) && msdos_find_file_has_8dot3name(&fd)) {
10265: strcpy(tmp_name, fd.cFileName);
10266: if(remove(msdos_trimmed_path(tmp, lfn))) {
10267: REG16(AX) = 5;
10268: m_CF = 1;
10269: break;
10270: }
10271: }
10272: } while(FindNextFileA(fh, &fd));
10273: if(!m_CF) {
10274: if(GetLastError() != ERROR_NO_MORE_FILES) {
10275: m_CF = 1;
10276: REG16(AX) = 2;
10277: }
10278: }
10279: FindClose(fh);
10280: }
10281:
1.1 root 10282: inline void msdos_int_21h_714eh()
10283: {
10284: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 10285: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
10286: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 10287: WIN32_FIND_DATA fd;
10288:
1.1.1.13 root 10289: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
10290: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
10291: FindClose(dtainfo->find_handle);
10292: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 10293: }
10294: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 10295: dtainfo->allowable_mask = REG8(CL);
10296: dtainfo->required_mask = REG8(CH);
10297: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 10298:
1.1.1.14 root 10299: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
10300: dtainfo->allowable_mask &= ~8;
1.1 root 10301: }
1.1.1.14 root 10302: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
10303: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 10304: if(!FindNextFile(dtainfo->find_handle, &fd)) {
10305: FindClose(dtainfo->find_handle);
10306: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 10307: break;
10308: }
10309: }
10310: }
1.1.1.13 root 10311: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 10312: find->attrib = fd.dwFileAttributes;
10313: msdos_find_file_conv_local_time(&fd);
10314: if(REG16(SI) == 0) {
10315: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
10316: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
10317: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
10318: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
10319: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
10320: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
10321: } else {
10322: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
10323: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
10324: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
10325: }
10326: find->size_hi = fd.nFileSizeHigh;
10327: find->size_lo = fd.nFileSizeLow;
10328: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 10329: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 10330: REG16(AX) = dtainfo - dtalist + 1;
10331: } else if(dtainfo->allowable_mask & 8) {
1.1 root 10332: // volume label
10333: find->attrib = 8;
10334: find->size_hi = find->size_lo = 0;
10335: strcpy(find->full_name, process->volume_label);
10336: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 10337: dtainfo->allowable_mask &= ~8;
10338: REG16(AX) = dtainfo - dtalist + 1;
1.1 root 10339: } else {
10340: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 10341: m_CF = 1;
1.1 root 10342: }
10343: }
10344:
10345: inline void msdos_int_21h_714fh()
10346: {
10347: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 10348: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 10349: WIN32_FIND_DATA fd;
10350:
1.1.1.14 root 10351: if(REG16(BX) - 1u >= MAX_DTAINFO) {
10352: REG16(AX) = 6;
1.1.1.13 root 10353: m_CF = 1;
10354: return;
10355: }
1.1.1.14 root 10356: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 10357: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
10358: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 10359: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 10360: if(!FindNextFile(dtainfo->find_handle, &fd)) {
10361: FindClose(dtainfo->find_handle);
10362: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 10363: break;
10364: }
10365: }
10366: } else {
1.1.1.13 root 10367: FindClose(dtainfo->find_handle);
10368: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 10369: }
10370: }
1.1.1.13 root 10371: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 10372: find->attrib = fd.dwFileAttributes;
10373: msdos_find_file_conv_local_time(&fd);
10374: if(REG16(SI) == 0) {
10375: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
10376: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
10377: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
10378: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
10379: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
10380: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
10381: } else {
10382: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
10383: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
10384: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
10385: }
10386: find->size_hi = fd.nFileSizeHigh;
10387: find->size_lo = fd.nFileSizeLow;
10388: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 10389: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 10390: } else if(dtainfo->allowable_mask & 8) {
1.1 root 10391: // volume label
10392: find->attrib = 8;
10393: find->size_hi = find->size_lo = 0;
10394: strcpy(find->full_name, process->volume_label);
10395: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 10396: dtainfo->allowable_mask &= ~8;
1.1 root 10397: } else {
10398: REG16(AX) = 0x12;
1.1.1.3 root 10399: m_CF = 1;
1.1 root 10400: }
10401: }
10402:
10403: inline void msdos_int_21h_71a0h()
10404: {
10405: DWORD max_component_len, file_sys_flag;
10406:
1.1.1.14 root 10407: 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))) {
10408: REG16(BX) = (UINT16)file_sys_flag & (FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_VOLUME_IS_COMPRESSED);
10409: REG16(BX) |= 0x4000; // supports LFN functions
1.1 root 10410: REG16(CX) = (UINT16)max_component_len; // 255
10411: REG16(DX) = (UINT16)max_component_len + 5; // 260
10412: } else {
10413: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 10414: m_CF = 1;
1.1 root 10415: }
10416: }
10417:
10418: inline void msdos_int_21h_71a1h()
10419: {
1.1.1.14 root 10420: if(REG16(BX) - 1u >= MAX_DTAINFO) {
10421: REG16(AX) = 6;
1.1.1.13 root 10422: m_CF = 1;
10423: return;
10424: }
1.1.1.14 root 10425: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 10426: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
10427: FindClose(dtainfo->find_handle);
10428: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 10429: }
10430: }
10431:
10432: inline void msdos_int_21h_71a6h()
10433: {
10434: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 10435: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
10436:
1.1.1.3 root 10437: UINT8 *buffer = (UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 10438: struct _stat64 status;
10439: DWORD serial_number = 0;
10440:
1.1.1.20 root 10441: if(fd < process->max_files && file_handler[fd].valid) {
10442: if(_fstat64(fd, &status) == 0) {
10443: if(file_handler[fd].path[1] == ':') {
1.1 root 10444: // NOTE: we need to consider the network file path "\\host\share\"
10445: char volume[] = "A:\\";
1.1.1.20 root 10446: volume[0] = file_handler[fd].path[1];
1.1 root 10447: GetVolumeInformation(volume, NULL, 0, &serial_number, NULL, NULL, NULL, 0);
10448: }
1.1.1.20 root 10449: *(UINT32 *)(buffer + 0x00) = GetFileAttributes(file_handler[fd].path);
1.1 root 10450: *(UINT32 *)(buffer + 0x04) = (UINT32)(status.st_ctime & 0xffffffff);
10451: *(UINT32 *)(buffer + 0x08) = (UINT32)((status.st_ctime >> 32) & 0xffffffff);
10452: *(UINT32 *)(buffer + 0x0c) = (UINT32)(status.st_atime & 0xffffffff);
10453: *(UINT32 *)(buffer + 0x10) = (UINT32)((status.st_atime >> 32) & 0xffffffff);
10454: *(UINT32 *)(buffer + 0x14) = (UINT32)(status.st_mtime & 0xffffffff);
10455: *(UINT32 *)(buffer + 0x18) = (UINT32)((status.st_mtime >> 32) & 0xffffffff);
10456: *(UINT32 *)(buffer + 0x1c) = serial_number;
10457: *(UINT32 *)(buffer + 0x20) = (UINT32)((status.st_size >> 32) & 0xffffffff);
10458: *(UINT32 *)(buffer + 0x24) = (UINT32)(status.st_size & 0xffffffff);
10459: *(UINT32 *)(buffer + 0x28) = status.st_nlink;
1.1.1.14 root 10460: // this is dummy id and it will be changed when it is reopened...
1.1 root 10461: *(UINT32 *)(buffer + 0x2c) = 0;
1.1.1.20 root 10462: *(UINT32 *)(buffer + 0x30) = file_handler[fd].id;
1.1 root 10463: } else {
10464: REG16(AX) = errno;
1.1.1.3 root 10465: m_CF = 1;
1.1 root 10466: }
10467: } else {
10468: REG16(AX) = 0x06;
1.1.1.3 root 10469: m_CF = 1;
1.1 root 10470: }
10471: }
10472:
10473: inline void msdos_int_21h_71a7h()
10474: {
10475: switch(REG8(BL)) {
10476: case 0x00:
1.1.1.3 root 10477: if(!FileTimeToDosDateTime((FILETIME *)(mem + SREG_BASE(DS) + REG16(SI)), ®16(DX), ®16(CX))) {
1.1 root 10478: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 10479: m_CF = 1;
1.1 root 10480: }
10481: break;
10482: case 0x01:
10483: // NOTE: we need to check BH that shows 10-millisecond untils past time in CX
1.1.1.3 root 10484: if(!DosDateTimeToFileTime(REG16(DX), REG16(CX), (FILETIME *)(mem + SREG_BASE(ES) + REG16(DI)))) {
1.1 root 10485: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 10486: m_CF = 1;
1.1 root 10487: }
10488: break;
10489: default:
1.1.1.22 root 10490: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 10491: REG16(AX) = 0x01;
1.1.1.3 root 10492: m_CF = 1;
1.1 root 10493: break;
10494: }
10495: }
10496:
10497: inline void msdos_int_21h_71a8h()
10498: {
10499: if(REG8(DH) == 0) {
10500: char tmp[MAX_PATH], fcb[MAX_PATH];
1.1.1.3 root 10501: strcpy(tmp, msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 10502: memset(fcb, 0x20, sizeof(fcb));
10503: int len = strlen(tmp);
1.1.1.21 root 10504: for(int i = 0, pos = 0; i < len; i++) {
1.1 root 10505: if(tmp[i] == '.') {
10506: pos = 8;
10507: } else {
10508: if(msdos_lead_byte_check(tmp[i])) {
10509: fcb[pos++] = tmp[i++];
10510: }
10511: fcb[pos++] = tmp[i];
10512: }
10513: }
1.1.1.3 root 10514: memcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), fcb, 11);
1.1 root 10515: } else {
1.1.1.3 root 10516: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 10517: }
10518: }
10519:
1.1.1.22 root 10520: inline void msdos_int_21h_71aah()
10521: {
10522: char drv[] = "A:", path[MAX_PATH];
10523: char *hoge=(char *)(mem + SREG_BASE(DS) + REG16(DX));
10524:
10525: if(REG8(BL) == 0) {
10526: drv[0] = 'A' + _getdrive() - 1;
10527: } else {
10528: drv[0] = 'A' + REG8(BL) - 1;
10529: }
10530: switch(REG8(BH)) {
10531: case 0x00:
10532: if(DefineDosDevice(0, drv, (char *)(mem + SREG_BASE(DS) + REG16(DX))) == 0) {
10533: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
10534: if(GetLogicalDrives() & bits) {
10535: REG16(AX) = 0x0f; // invalid drive
10536: } else {
10537: REG16(AX) = 0x03; // path not found
10538: }
10539: m_CF = 1;
10540: }
10541: break;
10542: case 0x01:
10543: if(DefineDosDevice(DDD_REMOVE_DEFINITION, drv, NULL) == 0) {
10544: REG16(AX) = 0x0f; // invalid drive
10545: m_CF = 1;
10546: }
10547: break;
10548: case 0x02:
10549: if(QueryDosDevice(drv, path, MAX_PATH) == 0) {
10550: REG16(AX) = 0x0f; // invalid drive
10551: m_CF = 1;
10552: } else if(strncmp(path, "\\??\\", 4) != 0) {
10553: REG16(AX) = 0x0f; // invalid drive
10554: m_CF = 1;
10555: } else {
10556: strcpy((char *)(mem + SREG_BASE(DS) + REG16(DX)), path + 4);
10557: }
10558: break;
10559: default:
10560: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
10561: REG16(AX) = 0x01;
10562: m_CF = 1;
10563: break;
10564: }
10565: }
10566:
1.1.1.14 root 10567: inline void msdos_int_21h_7300h()
10568: {
10569: if(REG8(AL) == 0) {
10570: REG8(AL) = REG8(CL);
10571: REG8(AH) = 0;
10572: } else {
10573: REG16(AX) = 0x01;
10574: m_CF = 1;
10575: }
10576: }
10577:
10578: inline void msdos_int_21h_7302h()
10579: {
10580: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
10581: UINT16 seg, ofs;
10582:
10583: if(REG16(CX) < 0x3f) {
10584: REG8(AL) = 0x18;
10585: m_CF = 1;
10586: } else if(!msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
10587: REG8(AL) = 0xff;
10588: m_CF = 1;
10589: } else {
10590: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 2, mem + (seg << 4) + ofs, sizeof(dpb_t));
10591: }
10592: }
10593:
1.1 root 10594: inline void msdos_int_21h_7303h()
10595: {
1.1.1.3 root 10596: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
10597: ext_space_info_t *info = (ext_space_info_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 10598: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
10599:
10600: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
10601: info->size_of_structure = sizeof(ext_space_info_t);
10602: info->structure_version = 0;
10603: info->sectors_per_cluster = sectors_per_cluster;
10604: info->bytes_per_sector = bytes_per_sector;
10605: info->available_clusters_on_drive = free_clusters;
10606: info->total_clusters_on_drive = total_clusters;
10607: info->available_sectors_on_drive = sectors_per_cluster * free_clusters;
10608: info->total_sectors_on_drive = sectors_per_cluster * total_clusters;
10609: info->available_allocation_units = free_clusters; // ???
10610: info->total_allocation_units = total_clusters; // ???
10611: } else {
10612: REG16(AX) = errno;
1.1.1.3 root 10613: m_CF = 1;
1.1 root 10614: }
10615: }
10616:
1.1.1.30 root 10617: inline void msdos_int_21h_dbh()
10618: {
10619: // Novell NetWare - Workstation - Get Number of Local Drives
10620: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
10621: REG8(AL) = dos_info->last_drive;
10622: }
10623:
10624: inline void msdos_int_21h_dch()
10625: {
10626: // Novell NetWare - Connection Services - Get Connection Number
10627: REG8(AL) = 0x00;
10628: }
10629:
1.1.1.32 root 10630: inline void msdos_int_24h()
10631: {
10632: const char *message = NULL;
10633: int key = 0;
10634:
10635: for(int i = 0; i < array_length(critical_error_table); i++) {
10636: if(critical_error_table[i].code == (REG16(DI) & 0xff) || critical_error_table[i].code == (UINT16)-1) {
10637: if(active_code_page == 932) {
10638: message = critical_error_table[i].message_japanese;
10639: }
10640: if(message == NULL) {
10641: message = critical_error_table[i].message_english;
10642: }
10643: *(UINT8 *)(mem + WORK_TOP) = strlen(message);
10644: strcpy((char *)(mem + WORK_TOP + 1), message);
10645:
10646: SREG(ES) = WORK_TOP >> 4;
10647: i386_load_segment_descriptor(ES);
10648: REG16(DI) = 0x0000;
10649: break;
10650: }
10651: }
10652: fprintf(stderr, "\n%s", message);
10653: if(!(REG8(AH) & 0x80)) {
10654: if(REG8(AH) & 0x01) {
10655: fprintf(stderr, " %s %c", (active_code_page == 932) ? "�������ݒ� �h���C�u" : "writing drive", 'A' + REG8(AL));
10656: } else {
10657: fprintf(stderr, " %s %c", (active_code_page == 932) ? "�ǂݎ�蒆 �h���C�u" : "reading drive", 'A' + REG8(AL));
10658: }
10659: }
10660: fprintf(stderr, "\n");
10661:
1.1.1.33! root 10662: {
1.1.1.32 root 10663: fprintf(stderr, "%s", (active_code_page == 932) ? "���~ (A)" : "Abort");
1.1.1.33! root 10664: }
1.1.1.32 root 10665: if(REG8(AH) & 0x10) {
10666: fprintf(stderr, ", %s", (active_code_page == 932) ? "���s (R)" : "Retry");
10667: }
10668: if(REG8(AH) & 0x20) {
10669: fprintf(stderr, ", %s", (active_code_page == 932) ? "���� (I)" : "Ignore");
10670: }
10671: if(REG8(AH) & 0x08) {
10672: fprintf(stderr, ", %s", (active_code_page == 932) ? "���s (F)" : "Fail");
10673: }
10674: fprintf(stderr, "? ");
10675:
10676: while(1) {
10677: while(!_kbhit()) {
10678: Sleep(10);
10679: }
10680: key = _getch();
10681:
10682: if(key == 'I' || key == 'i') {
10683: if(REG8(AH) & 0x20) {
10684: REG8(AL) = 0;
10685: break;
10686: }
10687: } else if(key == 'R' || key == 'r') {
10688: if(REG8(AH) & 0x10) {
10689: REG8(AL) = 1;
10690: break;
10691: }
10692: } else if(key == 'A' || key == 'a') {
10693: REG8(AL) = 2;
10694: break;
10695: } else if(key == 'F' || key == 'f') {
10696: if(REG8(AH) & 0x08) {
10697: REG8(AL) = 3;
10698: break;
10699: }
10700: }
10701: }
10702: fprintf(stderr, "%c\n", key);
10703: }
10704:
1.1 root 10705: inline void msdos_int_25h()
10706: {
10707: UINT16 seg, ofs;
10708: DWORD dwSize;
10709:
1.1.1.3 root 10710: #if defined(HAS_I386)
10711: I386OP(pushf)();
10712: #else
10713: PREFIX86(_pushf());
10714: #endif
1.1 root 10715:
10716: if(!(REG8(AL) < 26)) {
10717: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 10718: m_CF = 1;
1.1 root 10719: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
10720: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 10721: m_CF = 1;
1.1 root 10722: } else {
10723: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
10724: char dev[64];
10725: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
10726:
10727: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
10728: if(hFile == INVALID_HANDLE_VALUE) {
10729: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 10730: m_CF = 1;
1.1 root 10731: } else {
1.1.1.19 root 10732: UINT32 top_sector = REG16(DX);
10733: UINT16 sector_num = REG16(CX);
10734: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
10735:
10736: if(sector_num == 0xffff) {
10737: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
10738: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
10739: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
10740: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
10741: buffer_addr = (seg << 4) + ofs;
10742: }
10743: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
10744: // REG8(AL) = 0x02; // drive not ready
10745: // m_CF = 1;
10746: // } else
10747: if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 10748: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 10749: m_CF = 1;
1.1.1.19 root 10750: } else if(ReadFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 10751: REG8(AL) = 0x0b; // read error
1.1.1.3 root 10752: m_CF = 1;
1.1 root 10753: }
10754: CloseHandle(hFile);
10755: }
10756: }
10757: }
10758:
10759: inline void msdos_int_26h()
10760: {
10761: // this operation may cause serious damage for drives, so always returns error...
10762: UINT16 seg, ofs;
10763: DWORD dwSize;
10764:
1.1.1.3 root 10765: #if defined(HAS_I386)
10766: I386OP(pushf)();
10767: #else
10768: PREFIX86(_pushf());
10769: #endif
1.1 root 10770:
10771: if(!(REG8(AL) < 26)) {
10772: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 10773: m_CF = 1;
1.1 root 10774: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
10775: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 10776: m_CF = 1;
1.1 root 10777: } else {
10778: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
10779: char dev[64];
10780: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
10781:
10782: if(dpb->media_type == 0xf8) {
10783: // this drive is not a floppy
1.1.1.6 root 10784: // if(!(((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag & 0x40)) {
10785: // fatalerror("This application tried the absolute disk write to drive %c:\n", 'A' + REG8(AL));
10786: // }
1.1 root 10787: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 10788: m_CF = 1;
1.1 root 10789: } else {
10790: HANDLE hFile = CreateFile(dev, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
10791: if(hFile == INVALID_HANDLE_VALUE) {
10792: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 10793: m_CF = 1;
1.1 root 10794: } else {
1.1.1.19 root 10795: UINT32 top_sector = REG16(DX);
10796: UINT16 sector_num = REG16(CX);
10797: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
10798:
10799: if(sector_num == 0xffff) {
10800: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
10801: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
10802: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
10803: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
10804: buffer_addr = (seg << 4) + ofs;
10805: }
1.1 root 10806: if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
10807: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 10808: m_CF = 1;
1.1.1.19 root 10809: } else if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 10810: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 10811: m_CF = 1;
1.1.1.19 root 10812: } else if(WriteFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 10813: REG8(AL) = 0x0a; // write error
1.1.1.3 root 10814: m_CF = 1;
1.1 root 10815: }
10816: CloseHandle(hFile);
10817: }
10818: }
10819: }
10820: }
10821:
10822: inline void msdos_int_27h()
10823: {
1.1.1.29 root 10824: int paragraphs = (min(REG16(DX), 0xfff0) + 15) >> 4;
10825: try {
10826: msdos_mem_realloc(SREG(CS), paragraphs, NULL);
10827: } catch(...) {
10828: // recover the broken mcb
10829: int mcb_seg = SREG(CS) - 1;
10830: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1.1.33! root 10831:
1.1.1.29 root 10832: if(mcb_seg < (MEMORY_END >> 4)) {
1.1.1.33! root 10833: mcb->mz = 'M';
! 10834: mcb->paragraphs = (MEMORY_END >> 4) - mcb_seg - 2;
! 10835:
1.1.1.29 root 10836: if(((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked & 0x01) {
1.1.1.33! root 10837: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', PSP_SYSTEM, (UMB_TOP >> 4) - (MEMORY_END >> 4));
1.1.1.29 root 10838: } else {
1.1.1.33! root 10839: msdos_mcb_create((MEMORY_END >> 4) - 1, 'Z', PSP_SYSTEM, 0);
1.1.1.29 root 10840: }
10841: } else {
10842: mcb->mz = 'Z';
1.1.1.30 root 10843: mcb->paragraphs = (UMB_END >> 4) - mcb_seg - 1;
1.1.1.29 root 10844: }
10845: msdos_mem_realloc(SREG(CS), paragraphs, NULL);
10846: }
1.1.1.3 root 10847: msdos_process_terminate(SREG(CS), retval | 0x300, 0);
1.1 root 10848: }
10849:
10850: inline void msdos_int_29h()
10851: {
1.1.1.14 root 10852: #if 1
10853: // need to check escape sequences
1.1 root 10854: msdos_putch(REG8(AL));
1.1.1.14 root 10855: #else
10856: DWORD num;
10857: vram_flush();
1.1.1.23 root 10858: WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ®8(AL), 1, &num, NULL);
1.1.1.14 root 10859: cursor_moved = true;
10860: #endif
1.1 root 10861: }
10862:
10863: inline void msdos_int_2eh()
10864: {
10865: char tmp[MAX_PATH], command[MAX_PATH], opt[MAX_PATH];
10866: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 10867: strcpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(SI)));
1.1 root 10868: char *token = my_strtok(tmp, " ");
10869: strcpy(command, token);
10870: strcpy(opt, token + strlen(token) + 1);
10871:
10872: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
10873: param->env_seg = 0;
10874: param->cmd_line.w.l = 44;
10875: param->cmd_line.w.h = (WORK_TOP >> 4);
10876: param->fcb1.w.l = 24;
10877: param->fcb1.w.h = (WORK_TOP >> 4);
10878: param->fcb2.w.l = 24;
10879: param->fcb2.w.h = (WORK_TOP >> 4);
10880:
10881: memset(mem + WORK_TOP + 24, 0x20, 20);
10882:
10883: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
10884: cmd_line->len = strlen(opt);
10885: strcpy(cmd_line->cmd, opt);
10886: cmd_line->cmd[cmd_line->len] = 0x0d;
10887:
1.1.1.28 root 10888: try {
10889: if(msdos_process_exec(command, param, 0)) {
10890: REG16(AX) = 0xffff; // error before processing command
10891: } else {
10892: // set flag to set retval to ax when the started process is terminated
10893: process_t *process = msdos_process_info_get(current_psp);
10894: process->called_by_int2eh = true;
10895: }
10896: } catch(...) {
10897: REG16(AX) = 0xffff; // error before processing command
10898: }
1.1 root 10899: }
10900:
1.1.1.29 root 10901: inline void msdos_int_2fh_05h()
10902: {
10903: switch(REG8(AL)) {
10904: case 0x00:
1.1.1.32 root 10905: REG8(AL) = 0xff;
10906: break;
10907: case 0x01:
10908: case 0x02:
10909: for(int i = 0; i < array_length(standard_error_table); i++) {
10910: if(standard_error_table[i].code == REG16(BX) || standard_error_table[i].code == (UINT16)-1) {
10911: const char *message = NULL;
10912: if(active_code_page == 932) {
10913: message = standard_error_table[i].message_japanese;
10914: }
10915: if(message == NULL) {
10916: message = standard_error_table[i].message_english;
10917: }
10918: strcpy((char *)(mem + WORK_TOP), message);
10919:
10920: SREG(ES) = WORK_TOP >> 4;
10921: i386_load_segment_descriptor(ES);
10922: REG16(DI) = 0x0000;
10923: REG8(AL) = 0x01;
10924: break;
10925: }
10926: }
1.1.1.29 root 10927: break;
10928: default:
10929: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
10930: m_CF = 1;
10931: }
10932: }
10933:
1.1.1.22 root 10934: inline void msdos_int_2fh_11h()
10935: {
10936: switch(REG8(AL)) {
10937: case 0x00:
1.1.1.29 root 10938: if(i386_read_stack() == 0xdada) {
10939: // MSCDEX is not installed
10940: // REG8(AL) = 0x00;
10941: } else {
10942: // Network Redirector is not installed
10943: // REG8(AL) = 0x00;
10944: }
1.1.1.22 root 10945: break;
10946: default:
10947: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.29 root 10948: REG16(AX) = 0x49; // network software not installed
1.1.1.22 root 10949: m_CF = 1;
10950: break;
10951: }
10952: }
10953:
1.1.1.21 root 10954: inline void msdos_int_2fh_12h()
10955: {
10956: switch(REG8(AL)) {
1.1.1.22 root 10957: case 0x00:
1.1.1.29 root 10958: // DOS 3.0+ internal functions are installed
1.1.1.22 root 10959: REG8(AL) = 0xff;
10960: break;
1.1.1.29 root 10961: // case 0x01: // DOS 3.0+ internal - Close Current File
10962: case 0x02:
10963: {
10964: UINT16 stack = i386_read_stack();
10965: REG16(BX) = *(UINT16 *)(mem + 4 * stack + 0);
10966: SREG(ES) = *(UINT16 *)(mem + 4 * stack + 2);
10967: i386_load_segment_descriptor(ES);
10968: }
10969: break;
1.1.1.30 root 10970: case 0x03:
10971: SREG(DS) = (DEVICE_TOP >> 4);
10972: i386_load_segment_descriptor(DS);
10973: break;
1.1.1.29 root 10974: case 0x04:
10975: {
10976: UINT16 stack = i386_read_stack();
10977: REG8(AL) = (stack == '/') ? '\\' : stack;
10978: #if defined(HAS_I386)
10979: m_ZF = (REG8(AL) == '\\');
10980: #else
10981: m_ZeroVal = (REG8(AL) != '\\');
10982: #endif
10983: }
10984: break;
10985: case 0x05:
10986: msdos_putch(i386_read_stack());
10987: break;
10988: // case 0x06: // DOS 3.0+ internal - Invole Critical Error
10989: // case 0x07: // DOS 3.0+ internal - Make Disk Buffer Most Recentry Used
10990: // case 0x08: // DOS 3.0+ internal - Decrement SFT Reference Count
10991: // case 0x09: // DOS 3.0+ internal - Flush and FREE Disk Buffer
10992: // case 0x0a: // DOS 3.0+ internal - Perform Critical Error Interrupt
10993: // case 0x0b: // DOS 3.0+ internal - Signal Sharing Violation to User
10994: // case 0x0c: // DOS 3.0+ internal - Open Device and Set SFT Owner/Mode
10995: case 0x0d:
10996: {
10997: SYSTEMTIME time;
10998: FILETIME file_time;
10999: WORD dos_date, dos_time;
11000: GetLocalTime(&time);
11001: SystemTimeToFileTime(&time, &file_time);
11002: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time);
11003: REG16(AX) = dos_date;
11004: REG16(DX) = dos_time;
11005: }
11006: break;
11007: // case 0x0e: // DOS 3.0+ internal - Mark All Disk Buffers Unreferenced
11008: // case 0x0f: // DOS 3.0+ internal - Make Buffer Most Recentry Used
11009: // case 0x10: // DOS 3.0+ internal - Find Unreferenced Disk Buffer
11010: case 0x11:
11011: {
11012: char path[MAX_PATH], *p;
11013: strcpy(path, (char *)(mem + SREG_BASE(DS) + REG16(SI)));
11014: my_strupr(path);
11015: while((p = my_strchr(path, '/')) != NULL) {
11016: *p = '\\';
11017: }
11018: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path);
11019: }
11020: break;
11021: case 0x12:
11022: REG16(CX) = strlen((char *)(mem + SREG_BASE(ES) + REG16(DI)));
11023: break;
11024: case 0x13:
11025: {
11026: char tmp[2] = {0};
11027: tmp[0] = i386_read_stack();
11028: my_strupr(tmp);
11029: REG8(AL) = tmp[0];
11030: }
11031: break;
11032: case 0x14:
11033: #if defined(HAS_I386)
11034: m_ZF = (SREG_BASE(DS) + REG16(SI) == SREG_BASE(ES) + REG16(DI));
11035: #else
11036: m_ZeroVal = (SREG_BASE(DS) + REG16(SI) != SREG_BASE(ES) + REG16(DI));
11037: #endif
11038: m_CF = (SREG_BASE(DS) + REG16(SI) != SREG_BASE(ES) + REG16(DI));
11039: break;
11040: // case 0x15: // DOS 3.0+ internal - Flush Buffer
1.1.1.21 root 11041: case 0x16:
11042: if(REG16(BX) < 20) {
11043: SREG(ES) = SFT_TOP >> 4;
11044: i386_load_segment_descriptor(ES);
11045: REG16(DI) = 6 + 0x3b * REG16(BX);
11046:
11047: // update system file table
11048: UINT8* sft = mem + SFT_TOP + 6 + 0x3b * REG16(BX);
11049: if(file_handler[REG16(BX)].valid) {
11050: int count = 0;
11051: for(int i = 0; i < 20; i++) {
11052: if(msdos_psp_get_file_table(i, current_psp) == REG16(BX)) {
11053: count++;
11054: }
11055: }
11056: *(UINT16 *)(sft + 0x00) = count ? count : 0xffff;
11057: *(UINT32 *)(sft + 0x15) = _tell(REG16(BX));
11058: _lseek(REG16(BX), 0, SEEK_END);
11059: *(UINT32 *)(sft + 0x11) = _tell(REG16(BX));
11060: _lseek(REG16(BX), *(UINT32 *)(sft + 0x15), SEEK_SET);
11061: } else {
11062: memset(sft, 0, 0x3b);
11063: }
11064: } else {
11065: REG16(AX) = 0x06;
11066: m_CF = 1;
11067: }
11068: break;
1.1.1.29 root 11069: // case 0x17: // DOS 3.0+ internal - Get Current Directory Structure for Drive
11070: // case 0x18: // DOS 3.0+ internal - Get Caller's Registers
11071: // case 0x19: // DOS 3.0+ internal - Set Drive???
11072: case 0x1a:
11073: {
11074: char *path = (char *)(mem + SREG_BASE(DS) + REG16(SI)), full[MAX_PATH];
11075: if(path[1] == ':') {
11076: if(path[0] >= 'a' && path[0] <= 'z') {
11077: REG8(AL) = path[0] - 'a' + 1;
11078: } else if(path[0] >= 'A' && path[0] <= 'Z') {
11079: REG8(AL) = path[0] - 'A' + 1;
11080: } else {
11081: REG8(AL) = 0xff; // invalid
11082: }
11083: strcpy(full, path);
11084: strcpy(path, full + 2);
11085: } else if(GetFullPathName(path, MAX_PATH, full, NULL) != 0 && full[1] == ':') {
11086: if(full[0] >= 'a' && full[0] <= 'z') {
11087: REG8(AL) = full[0] - 'a' + 1;
11088: } else if(full[0] >= 'A' && full[0] <= 'Z') {
11089: REG8(AL) = full[0] - 'A' + 1;
11090: } else {
11091: REG8(AL) = 0xff; // invalid
11092: }
11093: } else {
11094: REG8(AL) = 0x00; // default
11095: }
11096: }
11097: break;
11098: case 0x1b:
11099: {
11100: int year = REG16(CX) + 1980;
11101: REG8(AL) = ((year % 4) == 0 && (year % 100) != 0 && (year % 400) == 0) ? 29 : 28;
11102: }
11103: break;
11104: // case 0x1c: // DOS 3.0+ internal - Check Sum Memory
11105: // case 0x1d: // DOS 3.0+ internal - Sum Memory
11106: case 0x1e:
11107: {
11108: char *path_1st = (char *)(mem + SREG_BASE(DS) + REG16(SI)), full_1st[MAX_PATH];
11109: char *path_2nd = (char *)(mem + SREG_BASE(ES) + REG16(DI)), full_2nd[MAX_PATH];
11110: if(GetFullPathName(path_1st, MAX_PATH, full_1st, NULL) != 0 && GetFullPathName(path_2nd, MAX_PATH, full_2nd, NULL) != 0) {
11111: #if defined(HAS_I386)
11112: m_ZF = (strcmp(full_1st, full_2nd) == 0);
11113: #else
11114: m_ZeroVal = (strcmp(full_1st, full_2nd) != 0);
11115: #endif
11116: } else {
11117: #if defined(HAS_I386)
11118: m_ZF = (strcmp(path_1st, path_2nd) == 0);
11119: #else
11120: m_ZeroVal = (strcmp(path_1st, path_2nd) != 0);
11121: #endif
11122: }
11123: }
11124: break;
11125: // case 0x1f: // DOS 3.0+ internal - Build Current Directory Structure
1.1.1.21 root 11126: case 0x20:
11127: {
11128: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
11129:
11130: if(fd < 20) {
11131: SREG(ES) = current_psp;
11132: i386_load_segment_descriptor(ES);
11133: REG16(DI) = offsetof(psp_t, file_table) + fd;
11134: } else {
11135: REG16(AX) = 0x06;
11136: m_CF = 1;
11137: }
11138: }
11139: break;
1.1.1.29 root 11140: case 0x21:
11141: msdos_int_21h_60h(0);
11142: break;
11143: // case 0x22: // DOS 3.0+ internal - Set Extended Error Info
11144: // case 0x23: // DOS 3.0+ internal - Check If Character Device
11145: // case 0x24: // DOS 3.0+ internal - Sharing Retry Delay
11146: case 0x25:
11147: REG16(CX) = strlen((char *)(mem + SREG_BASE(DS) + REG16(SI)));
11148: break;
11149: case 0x26:
11150: REG8(AL) = REG8(CL);
11151: msdos_int_21h_3dh();
11152: break;
11153: case 0x27:
11154: msdos_int_21h_3eh();
11155: break;
11156: case 0x28:
11157: REG16(AX) = REG16(BP);
11158: msdos_int_21h_42h();
11159: break;
11160: case 0x29:
11161: msdos_int_21h_3fh();
11162: break;
11163: // case 0x2a: // DOS 3.0+ internal - Set Fast Open Entry Point
11164: case 0x2b:
11165: REG16(AX) = REG16(BP);
11166: msdos_int_21h_44h();
11167: break;
11168: case 0x2c:
11169: REG16(BX) = DEVICE_TOP >> 4;
11170: REG16(AX) = 22;
11171: break;
11172: case 0x2d:
11173: {
11174: sda_t *sda = (sda_t *)(mem + SDA_TOP);
11175: REG16(AX) = sda->extended_error_code;
11176: }
11177: break;
11178: case 0x2e:
11179: if(REG8(DL) == 0x00 || REG8(DL) == 0x02 || REG8(DL) == 0x04 || REG8(DL) == 0x06) {
1.1.1.32 root 11180: SREG(ES) = 0x0001;
11181: i386_load_segment_descriptor(ES);
11182: REG16(DI) = 0x00;
11183: } else if(REG8(DL) == 0x08) {
11184: // dummy parameter error message read routine is at fffd:0010
11185: SREG(ES) = 0xfffd;
1.1.1.22 root 11186: i386_load_segment_descriptor(ES);
1.1.1.32 root 11187: REG16(DI) = 0x0010;
1.1.1.22 root 11188: }
11189: break;
1.1.1.29 root 11190: case 0x2f:
11191: if(REG16(DX) != 0) {
1.1.1.30 root 11192: dos_major_version = REG8(DL);
11193: dos_minor_version = REG8(DH);
1.1.1.29 root 11194: } else {
11195: REG8(DL) = 7;
11196: REG8(DH) = 10;
11197: }
11198: break;
11199: // case 0x30: // Windows95 - Find SFT Entry in Internal File Tables
11200: // case 0x31: // Windows95 - Set/Clear "Report Windows to DOS Programs" Flag
1.1.1.22 root 11201: default:
11202: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
11203: REG16(AX) = 0x01;
11204: m_CF = 1;
11205: break;
11206: }
11207: }
11208:
1.1.1.30 root 11209: inline void msdos_int_2fh_13h()
11210: {
11211: static UINT16 prevDS = 0, prevDX = 0;
11212: static UINT16 prevES = 0, prevBX = 0;
11213: UINT16 tmp;
11214:
11215: tmp = SREG(DS); SREG(DS) = prevDS; prevDS = tmp;
11216: i386_load_segment_descriptor(DS);
11217: tmp = REG16(DX); REG16(DX) = prevDX; prevDX = tmp;
11218:
11219: tmp = SREG(ES); SREG(ES) = prevES; prevES = tmp;
11220: i386_load_segment_descriptor(ES);
11221: tmp = REG16(BX); REG16(BX) = prevBX; prevBX = tmp;
11222: }
11223:
1.1.1.22 root 11224: inline void msdos_int_2fh_14h()
11225: {
11226: switch(REG8(AL)) {
11227: case 0x00:
1.1.1.29 root 11228: // NLSFUNC.COM is installed
11229: REG8(AL) = 0xff;
1.1.1.25 root 11230: break;
11231: case 0x01:
11232: case 0x03:
11233: REG8(AL) = 0x00;
11234: active_code_page = REG16(BX);
11235: msdos_nls_tables_update();
11236: break;
11237: case 0x02:
11238: REG8(AL) = get_extended_country_info(REG16(BP));
11239: break;
11240: case 0x04:
11241: REG8(AL) = 0x00;
11242: get_country_info((country_info_t *)(mem + SREG_BASE(ES) + REG16(DI)));
1.1.1.22 root 11243: break;
11244: default:
11245: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
11246: REG16(AX) = 0x01;
11247: m_CF = 1;
11248: break;
11249: }
11250: }
11251:
11252: inline void msdos_int_2fh_15h()
11253: {
11254: switch(REG8(AL)) {
1.1.1.29 root 11255: case 0x00: // CD-ROM - Installation Check
11256: if(REG16(BX) == 0x0000) {
11257: // MSCDEX is not installed
11258: // REG8(AL) = 0x00;
11259: } else {
11260: // GRAPHICS.COM is not installed
11261: // REG8(AL) = 0x00;
11262: }
1.1.1.22 root 11263: break;
11264: case 0xff:
1.1.1.29 root 11265: if(REG16(BX) == 0x0000) {
11266: // CORELCDX is not installed
11267: } else {
11268: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
11269: REG16(AX) = 0x01;
11270: m_CF = 1;
11271: }
1.1.1.22 root 11272: break;
1.1.1.21 root 11273: default:
1.1.1.22 root 11274: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.21 root 11275: REG16(AX) = 0x01;
11276: m_CF = 1;
11277: break;
11278: }
11279: }
11280:
1.1 root 11281: inline void msdos_int_2fh_16h()
11282: {
11283: switch(REG8(AL)) {
11284: case 0x00:
1.1.1.14 root 11285: if(no_windows) {
1.1.1.29 root 11286: // neither Windows 3.x enhanced mode nor Windows/386 2.x running
11287: // REG8(AL) = 0x00;
1.1.1.14 root 11288: } else {
1.1.1.30 root 11289: REG8(AL) = win_major_version;
11290: REG8(AH) = win_minor_version;
1.1 root 11291: }
11292: break;
1.1.1.30 root 11293: case 0x05:
11294: // from DOSBox
11295: i386_set_a20_line(1);
11296: break;
1.1.1.22 root 11297: case 0x0a:
11298: if(!no_windows) {
11299: REG16(AX) = 0x0000;
1.1.1.30 root 11300: REG8(BH) = win_major_version;
11301: REG8(BL) = win_minor_version;
1.1.1.22 root 11302: REG16(CX) = 0x0003; // enhanced
11303: }
11304: break;
1.1.1.30 root 11305: case 0x0b:
11306: // no TRS, keep ES:DI = 0000h:0000h
1.1.1.22 root 11307: case 0x0e:
11308: case 0x0f:
1.1.1.30 root 11309: case 0x10:
1.1.1.22 root 11310: case 0x11:
11311: case 0x12:
11312: case 0x13:
11313: case 0x14:
1.1.1.30 root 11314: case 0x15:
1.1.1.33! root 11315: case 0x86:
1.1.1.22 root 11316: case 0x87:
1.1.1.30 root 11317: case 0x89:
1.1.1.33! root 11318: case 0x8a:
1.1.1.22 root 11319: // function not supported, do not clear AX
11320: break;
1.1.1.14 root 11321: case 0x80:
11322: Sleep(10);
11323: hardware_update();
1.1.1.29 root 11324: REG8(AL) = 0x00;
1.1.1.14 root 11325: break;
1.1.1.33! root 11326: case 0x83:
! 11327: REG16(BX) = 0x01; // system vm id
! 11328: break;
1.1.1.22 root 11329: case 0x8e:
11330: REG16(AX) = 0x00; // failed
11331: break;
1.1.1.20 root 11332: case 0x8f:
11333: switch(REG8(DH)) {
11334: case 0x00:
11335: case 0x02:
11336: case 0x03:
11337: REG16(AX) = 0x00;
11338: break;
11339: case 0x01:
11340: REG16(AX) = 0x168f;
11341: break;
11342: }
11343: break;
1.1 root 11344: default:
1.1.1.22 root 11345: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
11346: REG16(AX) = 0x01;
11347: m_CF = 1;
11348: break;
11349: }
11350: }
11351:
11352: inline void msdos_int_2fh_19h()
11353: {
11354: switch(REG8(AL)) {
11355: case 0x00:
1.1.1.29 root 11356: // SHELLB.COM is not installed
11357: // REG8(AL) = 0x00;
1.1.1.22 root 11358: break;
11359: case 0x01:
11360: case 0x02:
11361: case 0x03:
11362: case 0x04:
11363: REG16(AX) = 0x01;
11364: m_CF = 1;
11365: break;
1.1.1.29 root 11366: case 0x80:
11367: // IBM ROM-DOS v4.0 is not installed
11368: // REG8(AL) = 0x00;
11369: break;
1.1.1.22 root 11370: default:
11371: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 11372: REG16(AX) = 0x01;
1.1.1.3 root 11373: m_CF = 1;
1.1 root 11374: break;
11375: }
11376: }
11377:
11378: inline void msdos_int_2fh_1ah()
11379: {
11380: switch(REG8(AL)) {
11381: case 0x00:
1.1.1.29 root 11382: // ANSI.SYS is installed
1.1 root 11383: REG8(AL) = 0xff;
11384: break;
11385: default:
1.1.1.22 root 11386: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
11387: REG16(AX) = 0x01;
11388: m_CF = 1;
11389: break;
11390: }
11391: }
11392:
1.1.1.30 root 11393: inline void msdos_int_2fh_40h()
1.1.1.22 root 11394: {
11395: switch(REG8(AL)) {
11396: case 0x00:
1.1.1.30 root 11397: // Windows 3+ - Get Virtual Device Driver (VDD) Capabilities
11398: REG8(AL) = 0x01; // does not virtualize video access
1.1.1.22 root 11399: break;
11400: default:
11401: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 11402: REG16(AX) = 0x01;
1.1.1.3 root 11403: m_CF = 1;
1.1 root 11404: break;
11405: }
11406: }
11407:
11408: inline void msdos_int_2fh_43h()
11409: {
11410: switch(REG8(AL)) {
11411: case 0x00:
1.1.1.29 root 11412: // XMS is installed ?
1.1.1.19 root 11413: #ifdef SUPPORT_XMS
11414: if(support_xms) {
11415: REG8(AL) = 0x80;
11416: } else
11417: #endif
11418: REG8(AL) = 0x00;
11419: break;
11420: case 0x10:
11421: SREG(ES) = XMS_TOP >> 4;
11422: i386_load_segment_descriptor(ES);
1.1.1.26 root 11423: REG16(BX) = 0x15;
1.1 root 11424: break;
11425: default:
1.1.1.22 root 11426: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
11427: REG16(AX) = 0x01;
11428: m_CF = 1;
11429: break;
11430: }
11431: }
11432:
11433: inline void msdos_int_2fh_46h()
11434: {
11435: switch(REG8(AL)) {
11436: case 0x80:
1.1.1.29 root 11437: // Windows v3.0 is not installed
11438: // REG8(AL) = 0x00;
1.1.1.22 root 11439: break;
11440: default:
11441: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
11442: REG16(AX) = 0x01;
11443: m_CF = 1;
11444: break;
11445: }
11446: }
11447:
11448: inline void msdos_int_2fh_48h()
11449: {
11450: switch(REG8(AL)) {
11451: case 0x00:
1.1.1.29 root 11452: // DOSKEY is not installed
11453: // REG8(AL) = 0x00;
1.1.1.22 root 11454: break;
11455: case 0x10:
11456: msdos_int_21h_0ah();
11457: REG16(AX) = 0x00;
11458: break;
11459: default:
11460: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 11461: REG16(AX) = 0x01;
1.1.1.3 root 11462: m_CF = 1;
1.1 root 11463: break;
11464: }
11465: }
11466:
11467: inline void msdos_int_2fh_4ah()
11468: {
11469: switch(REG8(AL)) {
1.1.1.29 root 11470: #ifdef SUPPORT_HMA
11471: case 0x01: // DOS 5.0+ - Query Free HMA Space
11472: if(!is_hma_used_by_xms && !is_hma_used_by_int_2fh) {
11473: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
11474: // restore first free mcb in high memory area
11475: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
11476: }
11477: int offset = 0xffff;
11478: if((REG16(BX) = msdos_hma_mem_get_free(&offset)) != 0) {
11479: REG16(DI) = offset + 0x10;
11480: } else {
11481: REG16(DI) = 0xffff;
11482: }
11483: } else {
11484: // HMA is already used
11485: REG16(BX) = 0;
11486: REG16(DI) = 0xffff;
11487: }
11488: SREG(ES) = 0xffff;
11489: i386_load_segment_descriptor(ES);
11490: break;
11491: case 0x02: // DOS 5.0+ - Allocate HMA Space
11492: if(!is_hma_used_by_xms && !is_hma_used_by_int_2fh) {
11493: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
11494: // restore first free mcb in high memory area
11495: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
11496: }
11497: int size = REG16(BX), offset;
11498: if((size % 16) != 0) {
11499: size &= ~15;
11500: size += 16;
11501: }
11502: if((offset = msdos_hma_mem_alloc(size, current_psp)) != -1) {
11503: REG16(BX) = size;
11504: REG16(DI) = offset + 0x10;
11505: is_hma_used_by_int_2fh = true;
11506: } else {
11507: REG16(BX) = 0;
11508: REG16(DI) = 0xffff;
11509: }
11510: } else {
11511: // HMA is already used
11512: REG16(BX) = 0;
11513: REG16(DI) = 0xffff;
11514: }
11515: SREG(ES) = 0xffff;
11516: i386_load_segment_descriptor(ES);
11517: break;
11518: case 0x03: // Windows95 - (De)Allocate HMA Memory Block
11519: if(REG8(DL) == 0x00) {
11520: if(!is_hma_used_by_xms) {
11521: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
11522: // restore first free mcb in high memory area
11523: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
11524: is_hma_used_by_int_2fh = false;
11525: }
11526: int size = REG16(BX), offset;
11527: if((size % 16) != 0) {
11528: size &= ~15;
11529: size += 16;
11530: }
11531: if((offset = msdos_hma_mem_alloc(size, REG16(CX))) != -1) {
11532: // REG16(BX) = size;
11533: SREG(ES) = 0xffff;
11534: i386_load_segment_descriptor(ES);
11535: REG16(DI) = offset + 0x10;
11536: is_hma_used_by_int_2fh = true;
11537: } else {
11538: REG16(DI) = 0xffff;
11539: }
11540: } else {
11541: REG16(DI) = 0xffff;
11542: }
11543: } else if(REG8(DL) == 0x01) {
11544: if(!is_hma_used_by_xms) {
11545: int size = REG16(BX);
11546: if((size % 16) != 0) {
11547: size &= ~15;
11548: size += 16;
11549: }
11550: if(msdos_hma_mem_realloc(SREG_BASE(ES) + REG16(DI) - 0xffff0 - 0x10, size) != -1) {
11551: // memory block address is not changed
11552: } else {
11553: REG16(DI) = 0xffff;
11554: }
11555: } else {
11556: REG16(DI) = 0xffff;
11557: }
11558: } else if(REG8(DL) == 0x02) {
11559: if(!is_hma_used_by_xms) {
11560: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
11561: // restore first free mcb in high memory area
11562: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
11563: is_hma_used_by_int_2fh = false;
11564: } else {
11565: msdos_hma_mem_free(SREG_BASE(ES) + REG16(DI) - 0xffff0 - 0x10);
11566: if(msdos_hma_mem_get_free(NULL) == 0xffe0) {
11567: is_hma_used_by_int_2fh = false;
11568: }
11569: }
11570: }
11571: } else {
11572: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
11573: REG16(AX) = 0x01;
11574: m_CF = 1;
11575: }
11576: break;
11577: case 0x04: // Windows95 - Get Start of HMA Memory Chain
11578: if(!is_hma_used_by_xms) {
11579: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
11580: // restore first free mcb in high memory area
11581: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
11582: is_hma_used_by_int_2fh = false;
11583: }
11584: REG16(AX) = 0x0000;
11585: SREG(ES) = 0xffff;
11586: i386_load_segment_descriptor(ES);
11587: REG16(DI) = 0x10;
11588: }
11589: break;
11590: #else
1.1 root 11591: case 0x01:
11592: case 0x02:
1.1.1.29 root 11593: // HMA is already used
1.1.1.27 root 11594: REG16(BX) = 0x0000;
1.1.1.3 root 11595: SREG(ES) = 0xffff;
11596: i386_load_segment_descriptor(ES);
1.1 root 11597: REG16(DI) = 0xffff;
11598: break;
1.1.1.19 root 11599: case 0x03:
11600: // unable to allocate
11601: REG16(DI) = 0xffff;
11602: break;
11603: case 0x04:
11604: // function not supported, do not clear AX
11605: break;
1.1.1.29 root 11606: #endif
11607: case 0x10:
11608: if(REG16(BX) == 0x0000) {
11609: // SMARTDRV is not installed
11610: } else {
11611: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
11612: REG16(AX) = 0x01;
11613: m_CF = 1;
11614: }
11615: break;
11616: case 0x11:
11617: if(REG16(BX) == 0x0000) {
11618: // DBLSPACE.BIN is not installed
11619: } else {
11620: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
11621: REG16(AX) = 0x01;
11622: m_CF = 1;
11623: }
1.1.1.22 root 11624: break;
11625: default:
11626: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
11627: REG16(AX) = 0x01;
11628: m_CF = 1;
11629: break;
11630: }
11631: }
11632:
11633: inline void msdos_int_2fh_4bh()
11634: {
11635: switch(REG8(AL)) {
1.1.1.24 root 11636: case 0x01:
1.1.1.22 root 11637: case 0x02:
1.1.1.29 root 11638: // Task Switcher is not installed
1.1.1.24 root 11639: break;
11640: case 0x03:
11641: // this call is available from within DOSSHELL even if the task switcher is not installed
11642: REG16(AX) = REG16(BX) = 0x0000; // no more avaiable switcher id
1.1.1.22 root 11643: break;
1.1.1.30 root 11644: case 0x04:
11645: REG16(BX) = 0x0000; // free switcher id successfully
11646: break;
1.1 root 11647: default:
1.1.1.22 root 11648: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 11649: REG16(AX) = 0x01;
1.1.1.3 root 11650: m_CF = 1;
1.1 root 11651: break;
11652: }
11653: }
11654:
11655: inline void msdos_int_2fh_4fh()
11656: {
11657: switch(REG8(AL)) {
11658: case 0x00:
1.1.1.29 root 11659: // BILING is installed
1.1.1.27 root 11660: REG16(AX) = 0x0000;
11661: REG8(DL) = 0x01; // major version
11662: REG8(DH) = 0x00; // minor version
1.1 root 11663: break;
11664: case 0x01:
1.1.1.27 root 11665: REG16(AX) = 0x0000;
1.1 root 11666: REG16(BX) = active_code_page;
11667: break;
11668: default:
1.1.1.22 root 11669: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
11670: REG16(AX) = 0x01;
11671: m_CF = 1;
11672: break;
11673: }
11674: }
11675:
11676: inline void msdos_int_2fh_55h()
11677: {
11678: switch(REG8(AL)) {
11679: case 0x00:
11680: case 0x01:
11681: // unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
11682: break;
11683: default:
11684: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 11685: REG16(AX) = 0x01;
1.1.1.3 root 11686: m_CF = 1;
1.1 root 11687: break;
11688: }
11689: }
11690:
1.1.1.24 root 11691: inline void msdos_int_2fh_adh()
11692: {
11693: switch(REG8(AL)) {
11694: case 0x00:
1.1.1.29 root 11695: // DISPLAY.SYS is installed
1.1.1.24 root 11696: REG8(AL) = 0xff;
11697: REG16(BX) = 0x100; // ???
11698: break;
11699: case 0x01:
11700: active_code_page = REG16(BX);
11701: msdos_nls_tables_update();
11702: REG16(AX) = 0x01;
11703: break;
11704: case 0x02:
11705: REG16(BX) = active_code_page;
11706: break;
11707: case 0x03:
11708: // FIXME
11709: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 1;
11710: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2) = 3;
11711: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4) = 1;
11712: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 6) = active_code_page;
11713: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 8) = active_code_page;
11714: break;
11715: case 0x80:
11716: break; // keyb.com is not installed
11717: default:
11718: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
11719: REG16(AX) = 0x01;
11720: m_CF = 1;
11721: break;
11722: }
11723: }
11724:
1.1 root 11725: inline void msdos_int_2fh_aeh()
11726: {
11727: switch(REG8(AL)) {
11728: case 0x00:
1.1.1.28 root 11729: // FIXME: we need to check the given command line
11730: REG8(AL) = 0x00; // the command should be executed as usual
11731: // REG8(AL) = 0xff; // this command is a TSR extension to COMMAND.COM
1.1 root 11732: break;
11733: case 0x01:
11734: {
11735: char command[MAX_PATH];
11736: memset(command, 0, sizeof(command));
1.1.1.3 root 11737: memcpy(command, mem + SREG_BASE(DS) + REG16(SI) + 1, mem[SREG_BASE(DS) + REG16(SI)]);
1.1 root 11738:
11739: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
11740: param->env_seg = 0;
11741: param->cmd_line.w.l = 44;
11742: param->cmd_line.w.h = (WORK_TOP >> 4);
11743: param->fcb1.w.l = 24;
11744: param->fcb1.w.h = (WORK_TOP >> 4);
11745: param->fcb2.w.l = 24;
11746: param->fcb2.w.h = (WORK_TOP >> 4);
11747:
11748: memset(mem + WORK_TOP + 24, 0x20, 20);
11749:
11750: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
1.1.1.3 root 11751: cmd_line->len = mem[SREG_BASE(DS) + REG16(BX) + 1];
11752: memcpy(cmd_line->cmd, mem + SREG_BASE(DS) + REG16(BX) + 2, cmd_line->len);
1.1 root 11753: cmd_line->cmd[cmd_line->len] = 0x0d;
11754:
1.1.1.28 root 11755: try {
11756: msdos_process_exec(command, param, 0);
11757: } catch(...) {
11758: fatalerror("failed to start '%s' by int 2Fh, AX=AE01h\n", command);
1.1 root 11759: }
11760: }
11761: break;
11762: default:
1.1.1.22 root 11763: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 11764: REG16(AX) = 0x01;
1.1.1.3 root 11765: m_CF = 1;
1.1 root 11766: break;
11767: }
11768: }
11769:
1.1.1.24 root 11770: inline void msdos_int_33h_0000h()
11771: {
11772: REG16(AX) = 0xffff; // hardware/driver installed
11773: REG16(BX) = MAX_MOUSE_BUTTONS;
11774: }
11775:
11776: inline void msdos_int_33h_0001h()
11777: {
11778: if(!mouse.active) {
11779: if(!(dwConsoleMode & ENABLE_MOUSE_INPUT)) {
11780: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode | ENABLE_MOUSE_INPUT);
11781: }
11782: mouse.active = true;
11783: pic[1].imr &= ~0x10; // enable irq12
11784: }
11785: }
11786:
11787: inline void msdos_int_33h_0002h()
11788: {
11789: if(mouse.active) {
11790: if(!(dwConsoleMode & ENABLE_MOUSE_INPUT)) {
11791: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode);
11792: }
11793: mouse.active = false;
11794: pic[1].imr |= 0x10; // disable irq12
11795: }
11796: }
11797:
11798: inline void msdos_int_33h_0003h()
11799: {
11800: REG16(BX) = mouse.get_buttons();
11801: REG16(CX) = max(mouse.min_position.x, min(mouse.max_position.x, mouse.position.x));
11802: REG16(DX) = max(mouse.min_position.y, min(mouse.max_position.y, mouse.position.y));
11803: }
11804:
11805: inline void msdos_int_33h_0005h()
11806: {
11807: if(REG16(BX) < MAX_MOUSE_BUTTONS) {
11808: int idx = REG16(BX);
11809: REG16(BX) = mouse.buttons[idx].pressed_times;
11810: REG16(CX) = max(mouse.min_position.x, min(mouse.max_position.x, mouse.buttons[idx].pressed_position.x));
11811: REG16(DX) = max(mouse.min_position.y, min(mouse.max_position.y, mouse.buttons[idx].pressed_position.y));
11812: mouse.buttons[idx].pressed_times = 0;
11813: } else {
11814: REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
11815: }
11816: REG16(AX) = mouse.get_buttons();
11817: }
11818:
11819: inline void msdos_int_33h_0006h()
11820: {
11821: if(REG16(BX) < MAX_MOUSE_BUTTONS) {
11822: int idx = REG16(BX);
11823: REG16(BX) = mouse.buttons[idx].released_times;
11824: REG16(CX) = max(mouse.min_position.x, min(mouse.max_position.x, mouse.buttons[idx].released_position.x));
11825: REG16(DX) = max(mouse.min_position.y, min(mouse.max_position.y, mouse.buttons[idx].released_position.y));
11826: mouse.buttons[idx].released_times = 0;
11827: } else {
11828: REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
11829: }
11830: REG16(AX) = mouse.get_buttons();
11831: }
11832:
11833: inline void msdos_int_33h_0007h()
11834: {
11835: mouse.min_position.x = min(REG16(CX), REG16(DX));
11836: mouse.max_position.x = max(REG16(CX), REG16(DX));
11837: }
11838:
11839: inline void msdos_int_33h_0008h()
11840: {
11841: mouse.min_position.y = min(REG16(CX), REG16(DX));
11842: mouse.max_position.y = max(REG16(CX), REG16(DX));
11843: }
11844:
11845: inline void msdos_int_33h_0009h()
11846: {
11847: mouse.hot_spot[0] = REG16(BX);
11848: mouse.hot_spot[1] = REG16(CX);
11849: }
11850:
11851: inline void msdos_int_33h_000bh()
11852: {
11853: int dx = (mouse.position.x - mouse.prev_position.x) * mouse.mickey.x / 8;
11854: int dy = (mouse.position.y - mouse.prev_position.y) * mouse.mickey.y / 8;
11855: mouse.prev_position.x = mouse.position.x;
11856: mouse.prev_position.y = mouse.position.y;
11857: REG16(CX) = dx;
11858: REG16(DX) = dy;
11859: }
11860:
11861: inline void msdos_int_33h_000ch()
11862: {
11863: mouse.call_mask = REG16(CX);
11864: mouse.call_addr.w.l = REG16(DX);
11865: mouse.call_addr.w.h = SREG(ES);
11866: }
11867:
11868: inline void msdos_int_33h_000fh()
11869: {
11870: mouse.mickey.x = REG16(CX);
11871: mouse.mickey.y = REG16(DX);
11872: }
11873:
11874: inline void msdos_int_33h_0011h()
11875: {
11876: REG16(AX) = 0xffff;
11877: REG16(BX) = MAX_MOUSE_BUTTONS;
11878: }
11879:
11880: inline void msdos_int_33h_0014h()
11881: {
11882: UINT16 old_mask = mouse.call_mask;
11883: UINT16 old_ofs = mouse.call_addr.w.l;
11884: UINT16 old_seg = mouse.call_addr.w.h;
11885:
11886: mouse.call_mask = REG16(CX);
11887: mouse.call_addr.w.l = REG16(DX);
11888: mouse.call_addr.w.h = SREG(ES);
11889:
11890: REG16(CX) = old_mask;
11891: REG16(DX) = old_ofs;
11892: SREG(ES) = old_seg;
11893: i386_load_segment_descriptor(ES);
11894: }
11895:
11896: inline void msdos_int_33h_0015h()
11897: {
11898: REG16(BX) = sizeof(mouse);
11899: }
11900:
11901: inline void msdos_int_33h_0016h()
11902: {
11903: memcpy(mem + SREG_BASE(ES) + REG16(DX), &mouse, sizeof(mouse));
11904: }
11905:
11906: inline void msdos_int_33h_0017h()
11907: {
11908: memcpy(&mouse, mem + SREG_BASE(ES) + REG16(DX), sizeof(mouse));
11909: }
11910:
11911: inline void msdos_int_33h_001ah()
11912: {
11913: mouse.sensitivity[0] = REG16(BX);
11914: mouse.sensitivity[1] = REG16(CX);
11915: mouse.sensitivity[2] = REG16(DX);
11916: }
11917:
11918: inline void msdos_int_33h_001bh()
11919: {
11920: REG16(BX) = mouse.sensitivity[0];
11921: REG16(CX) = mouse.sensitivity[1];
11922: REG16(DX) = mouse.sensitivity[2];
11923: }
11924:
11925: inline void msdos_int_33h_001dh()
11926: {
11927: mouse.display_page = REG16(BX);
11928: }
11929:
11930: inline void msdos_int_33h_001eh()
11931: {
11932: REG16(BX) = mouse.display_page;
11933: }
11934:
11935: inline void msdos_int_33h_0021h()
11936: {
11937: REG16(AX) = 0xffff;
11938: REG16(BX) = MAX_MOUSE_BUTTONS;
11939: }
11940:
11941: inline void msdos_int_33h_0022h()
11942: {
11943: mouse.language = REG16(BX);
11944: }
11945:
11946: inline void msdos_int_33h_0023h()
11947: {
11948: REG16(BX) = mouse.language;
11949: }
11950:
11951: inline void msdos_int_33h_0024h()
11952: {
11953: REG16(BX) = 0x0805; // V8.05
11954: REG16(CX) = 0x0400; // PS/2
11955: }
11956:
11957: inline void msdos_int_33h_0026h()
11958: {
11959: REG16(BX) = 0x0000;
11960: REG16(CX) = mouse.max_position.x;
11961: REG16(DX) = mouse.max_position.y;
11962: }
11963:
11964: inline void msdos_int_33h_002ah()
11965: {
11966: REG16(AX) = mouse.active ? 0 : 0xffff;
11967: REG16(BX) = mouse.hot_spot[0];
11968: REG16(CX) = mouse.hot_spot[1];
11969: REG16(DX) = 4; // PS/2
11970: }
11971:
11972: inline void msdos_int_33h_0031h()
11973: {
11974: REG16(AX) = mouse.min_position.x;
11975: REG16(BX) = mouse.min_position.y;
11976: REG16(CX) = mouse.max_position.x;
11977: REG16(DX) = mouse.max_position.y;
11978: }
11979:
11980: inline void msdos_int_33h_0032h()
11981: {
11982: REG16(AX) = 0;
11983: // REG16(AX) |= 0x8000; // 0025h
11984: REG16(AX) |= 0x4000; // 0026h
11985: // REG16(AX) |= 0x2000; // 0027h
11986: // REG16(AX) |= 0x1000; // 0028h
11987: // REG16(AX) |= 0x0800; // 0029h
11988: REG16(AX) |= 0x0400; // 002ah
11989: // REG16(AX) |= 0x0200; // 002bh
11990: // REG16(AX) |= 0x0100; // 002ch
11991: // REG16(AX) |= 0x0080; // 002dh
11992: // REG16(AX) |= 0x0040; // 002eh
11993: REG16(AX) |= 0x0020; // 002fh
11994: // REG16(AX) |= 0x0010; // 0030h
11995: REG16(AX) |= 0x0008; // 0031h
11996: REG16(AX) |= 0x0004; // 0032h
11997: // REG16(AX) |= 0x0002; // 0033h
11998: // REG16(AX) |= 0x0001; // 0034h
11999: }
12000:
1.1.1.19 root 12001: inline void msdos_int_67h_40h()
12002: {
12003: if(!support_ems) {
12004: REG8(AH) = 0x84;
12005: } else {
12006: REG8(AH) = 0x00;
12007: }
12008: }
12009:
12010: inline void msdos_int_67h_41h()
12011: {
12012: if(!support_ems) {
12013: REG8(AH) = 0x84;
12014: } else {
12015: REG8(AH) = 0x00;
12016: REG16(BX) = EMS_TOP >> 4;
12017: }
12018: }
12019:
12020: inline void msdos_int_67h_42h()
12021: {
12022: if(!support_ems) {
12023: REG8(AH) = 0x84;
12024: } else {
12025: REG8(AH) = 0x00;
12026: REG16(BX) = free_ems_pages;
12027: REG16(DX) = MAX_EMS_PAGES;
12028: }
12029: }
12030:
12031: inline void msdos_int_67h_43h()
12032: {
12033: if(!support_ems) {
12034: REG8(AH) = 0x84;
12035: } else if(REG16(BX) > MAX_EMS_PAGES) {
12036: REG8(AH) = 0x87;
12037: } else if(REG16(BX) > free_ems_pages) {
12038: REG8(AH) = 0x88;
12039: } else if(REG16(BX) == 0) {
12040: REG8(AH) = 0x89;
12041: } else {
1.1.1.31 root 12042: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 12043: if(!ems_handles[i].allocated) {
12044: ems_allocate_pages(i, REG16(BX));
12045: REG8(AH) = 0x00;
12046: REG16(DX) = i;
12047: return;
12048: }
12049: }
12050: REG8(AH) = 0x85;
12051: }
12052: }
12053:
12054: inline void msdos_int_67h_44h()
12055: {
12056: if(!support_ems) {
12057: REG8(AH) = 0x84;
1.1.1.31 root 12058: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 12059: REG8(AH) = 0x83;
12060: } else if(!(REG16(BX) == 0xffff || REG16(BX) < ems_handles[REG16(DX)].pages)) {
12061: REG8(AH) = 0x8a;
12062: // } else if(!(REG8(AL) < 4)) {
12063: // REG8(AH) = 0x8b;
12064: } else if(REG16(BX) == 0xffff) {
12065: ems_unmap_page(REG8(AL) & 3);
12066: REG8(AH) = 0x00;
12067: } else {
12068: ems_map_page(REG8(AL) & 3, REG16(DX), REG16(BX));
12069: REG8(AH) = 0x00;
12070: }
12071: }
12072:
12073: inline void msdos_int_67h_45h()
12074: {
12075: if(!support_ems) {
12076: REG8(AH) = 0x84;
1.1.1.31 root 12077: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 12078: REG8(AH) = 0x83;
12079: } else {
12080: ems_release_pages(REG16(DX));
12081: REG8(AH) = 0x00;
12082: }
12083: }
12084:
12085: inline void msdos_int_67h_46h()
12086: {
12087: if(!support_ems) {
12088: REG8(AH) = 0x84;
12089: } else {
1.1.1.29 root 12090: // REG16(AX) = 0x0032; // EMS 3.2
12091: REG16(AX) = 0x0040; // EMS 4.0
1.1.1.19 root 12092: }
12093: }
12094:
12095: inline void msdos_int_67h_47h()
12096: {
12097: // NOTE: the map data should be stored in the specified ems page, not process data
12098: process_t *process = msdos_process_info_get(current_psp);
12099:
12100: if(!support_ems) {
12101: REG8(AH) = 0x84;
1.1.1.31 root 12102: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 12103: // REG8(AH) = 0x83;
12104: } else if(process->ems_pages_stored) {
12105: REG8(AH) = 0x8d;
12106: } else {
12107: for(int i = 0; i < 4; i++) {
12108: process->ems_pages[i].handle = ems_pages[i].handle;
12109: process->ems_pages[i].page = ems_pages[i].page;
12110: process->ems_pages[i].mapped = ems_pages[i].mapped;
12111: }
12112: process->ems_pages_stored = true;
12113: REG8(AH) = 0x00;
12114: }
12115: }
12116:
12117: inline void msdos_int_67h_48h()
12118: {
12119: // NOTE: the map data should be restored from the specified ems page, not process data
12120: process_t *process = msdos_process_info_get(current_psp);
12121:
12122: if(!support_ems) {
12123: REG8(AH) = 0x84;
1.1.1.31 root 12124: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 12125: // REG8(AH) = 0x83;
12126: } else if(!process->ems_pages_stored) {
12127: REG8(AH) = 0x8e;
12128: } else {
12129: for(int i = 0; i < 4; i++) {
12130: if(process->ems_pages[i].mapped) {
12131: ems_map_page(i, process->ems_pages[i].handle, process->ems_pages[i].page);
12132: } else {
12133: ems_unmap_page(i);
12134: }
12135: }
12136: process->ems_pages_stored = false;
12137: REG8(AH) = 0x00;
12138: }
12139: }
12140:
12141: inline void msdos_int_67h_4bh()
12142: {
12143: if(!support_ems) {
12144: REG8(AH) = 0x84;
12145: } else {
12146: REG8(AH) = 0x00;
12147: REG16(BX) = 0;
1.1.1.31 root 12148: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 12149: if(ems_handles[i].allocated) {
12150: REG16(BX)++;
12151: }
12152: }
12153: }
12154: }
12155:
12156: inline void msdos_int_67h_4ch()
12157: {
12158: if(!support_ems) {
12159: REG8(AH) = 0x84;
1.1.1.31 root 12160: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 12161: REG8(AH) = 0x83;
12162: } else {
12163: REG8(AH) = 0x00;
12164: REG16(BX) = ems_handles[REG16(DX)].pages;
12165: }
12166: }
12167:
12168: inline void msdos_int_67h_4dh()
12169: {
12170: if(!support_ems) {
12171: REG8(AH) = 0x84;
12172: } else {
12173: REG8(AH) = 0x00;
12174: REG16(BX) = 0;
1.1.1.31 root 12175: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 12176: if(ems_handles[i].allocated) {
12177: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 0) = i;
12178: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 2) = ems_handles[i].pages;
12179: REG16(BX)++;
12180: }
12181: }
12182: }
12183: }
12184:
1.1.1.20 root 12185: inline void msdos_int_67h_4eh()
12186: {
12187: if(!support_ems) {
12188: REG8(AH) = 0x84;
12189: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01 || REG8(AL) == 0x02) {
12190: if(REG8(AL) == 0x00 || REG8(AL) == 0x02) {
12191: // save page map
12192: for(int i = 0; i < 4; i++) {
12193: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = ems_pages[i].mapped ? ems_pages[i].handle : 0xffff;
12194: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = ems_pages[i].mapped ? ems_pages[i].page : 0xffff;
12195: }
12196: }
12197: if(REG8(AL) == 0x01 || REG8(AL) == 0x02) {
12198: // restore page map
12199: for(int i = 0; i < 4; i++) {
12200: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
12201: UINT16 page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
12202:
1.1.1.31 root 12203: if(handle >= 1 && handle <= MAX_EMS_HANDLES && ems_handles[handle].allocated && page < ems_handles[handle].pages) {
1.1.1.20 root 12204: ems_map_page(i, handle, page);
12205: } else {
12206: ems_unmap_page(i);
12207: }
12208: }
12209: }
12210: REG8(AH) = 0x00;
12211: } else if(REG8(AL) == 0x03) {
12212: REG8(AH) = 0x00;
1.1.1.21 root 12213: REG8(AL) = 4 * 4;
12214: } else {
1.1.1.22 root 12215: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.21 root 12216: REG8(AH) = 0x8f;
12217: }
12218: }
12219:
12220: inline void msdos_int_67h_4fh()
12221: {
12222: if(!support_ems) {
12223: REG8(AH) = 0x84;
12224: } else if(REG8(AL) == 0x00) {
12225: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
12226:
12227: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI)) = count;
12228: for(int i = 0; i < count; i++) {
12229: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 2 * i);
12230: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
12231:
12232: // if(!(physical < 4)) {
12233: // REG8(AH) = 0x8b;
12234: // return;
12235: // }
12236: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 0) = segment;
12237: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 2) = ems_pages[physical & 3].handle;
12238: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 4) = ems_pages[physical & 3].mapped ? ems_pages[physical & 3].page : 0xffff;
12239: }
12240: REG8(AH) = 0x00;
12241: } else if(REG8(AL) == 0x01) {
12242: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
12243:
12244: for(int i = 0; i < count; i++) {
12245: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 0);
12246: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
12247: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 2);
12248: UINT16 logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 4);
12249:
12250: // if(!(physical < 4)) {
12251: // REG8(AH) = 0x8b;
12252: // return;
12253: // } else
1.1.1.31 root 12254: if(!(handle >= 1 && handle <= MAX_EMS_HANDLES && ems_handles[handle].allocated)) {
1.1.1.21 root 12255: REG8(AH) = 0x83;
12256: return;
12257: } else if(logical == 0xffff) {
12258: ems_unmap_page(physical & 3);
12259: } else if(logical < ems_handles[handle].pages) {
12260: ems_map_page(physical & 3, handle, logical);
12261: } else {
12262: REG8(AH) = 0x8a;
12263: return;
12264: }
12265: }
12266: REG8(AH) = 0x00;
12267: } else if(REG8(AL) == 0x02) {
12268: REG8(AH) = 0x00;
12269: REG8(AL) = 2 + REG16(BX) * 6;
1.1.1.20 root 12270: } else {
1.1.1.22 root 12271: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.20 root 12272: REG8(AH) = 0x8f;
12273: }
12274: }
12275:
12276: inline void msdos_int_67h_50h()
12277: {
12278: if(!support_ems) {
12279: REG8(AH) = 0x84;
1.1.1.31 root 12280: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.20 root 12281: REG8(AH) = 0x83;
12282: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
12283: for(int i = 0; i < REG16(CX); i++) {
12284: int logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
12285: int physical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
12286:
12287: if(REG8(AL) == 0x01) {
12288: physical = ((physical << 4) - EMS_TOP) / 0x4000;
12289: }
12290: // if(!(physical < 4)) {
12291: // REG8(AH) = 0x8b;
12292: // return;
12293: // } else
12294: if(logical == 0xffff) {
12295: ems_unmap_page(physical & 3);
12296: } else if(logical < ems_handles[REG16(DX)].pages) {
12297: ems_map_page(physical & 3, REG16(DX), logical);
12298: } else {
12299: REG8(AH) = 0x8a;
12300: return;
12301: }
12302: }
12303: REG8(AH) = 0x00;
12304: } else {
1.1.1.22 root 12305: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.20 root 12306: REG8(AH) = 0x8f;
12307: }
12308: }
12309:
1.1.1.19 root 12310: inline void msdos_int_67h_51h()
12311: {
12312: if(!support_ems) {
12313: REG8(AH) = 0x84;
1.1.1.31 root 12314: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 12315: REG8(AH) = 0x83;
12316: } else if(REG16(BX) > MAX_EMS_PAGES) {
12317: REG8(AH) = 0x87;
12318: } else if(REG16(BX) > free_ems_pages + ems_handles[REG16(DX)].pages) {
12319: REG8(AH) = 0x88;
12320: } else {
12321: ems_reallocate_pages(REG16(DX), REG16(BX));
12322: REG8(AH) = 0x00;
12323: }
12324: }
12325:
1.1.1.20 root 12326: inline void msdos_int_67h_52h()
12327: {
12328: if(!support_ems) {
12329: REG8(AH) = 0x84;
1.1.1.31 root 12330: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
12331: // REG8(AH) = 0x83;
1.1.1.20 root 12332: } else if(REG8(AL) == 0x00) {
12333: REG8(AL) = 0x00; // handle is volatile
12334: REG8(AH) = 0x00;
12335: } else if(REG8(AL) == 0x01) {
12336: if(REG8(BL) == 0x00) {
12337: REG8(AH) = 0x00;
12338: } else {
12339: REG8(AH) = 0x90; // undefined attribute type
12340: }
12341: } else if(REG8(AL) == 0x02) {
12342: REG8(AL) = 0x00; // only volatile handles supported
12343: REG8(AH) = 0x00;
12344: } else {
1.1.1.22 root 12345: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.20 root 12346: REG8(AH) = 0x8f;
12347: }
12348: }
12349:
1.1.1.19 root 12350: inline void msdos_int_67h_53h()
12351: {
12352: if(!support_ems) {
12353: REG8(AH) = 0x84;
1.1.1.31 root 12354: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 12355: REG8(AH) = 0x83;
12356: } else if(REG8(AL) == 0x00) {
12357: memcpy(mem + SREG_BASE(ES) + REG16(DI), ems_handles[REG16(DX)].name, 8);
12358: REG8(AH) = 0x00;
12359: } else if(REG8(AL) == 0x01) {
1.1.1.31 root 12360: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 12361: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
12362: REG8(AH) = 0xa1;
12363: return;
12364: }
12365: }
12366: REG8(AH) = 0x00;
12367: memcpy(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8);
12368: } else {
1.1.1.22 root 12369: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.20 root 12370: REG8(AH) = 0x8f;
1.1.1.19 root 12371: }
12372: }
12373:
12374: inline void msdos_int_67h_54h()
12375: {
12376: if(!support_ems) {
12377: REG8(AH) = 0x84;
12378: } else if(REG8(AL) == 0x00) {
1.1.1.31 root 12379: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 12380: if(ems_handles[i].allocated) {
12381: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, ems_handles[i].name, 10);
12382: } else {
12383: memset(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, 0, 10);
12384: }
12385: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 0) = i;
12386: }
12387: REG8(AH) = 0x00;
12388: REG8(AL) = MAX_EMS_HANDLES;
12389: } else if(REG8(AL) == 0x01) {
12390: REG8(AH) = 0xa0; // not found
1.1.1.31 root 12391: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 12392: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
12393: REG8(AH) = 0x00;
12394: REG16(DX) = i;
12395: break;
12396: }
12397: }
12398: } else if(REG8(AL) == 0x02) {
12399: REG8(AH) = 0x00;
12400: REG16(BX) = MAX_EMS_HANDLES;
12401: } else {
1.1.1.22 root 12402: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.20 root 12403: REG8(AH) = 0x8f;
12404: }
12405: }
12406:
12407: inline void msdos_int_67h_57h_tmp()
12408: {
12409: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
12410: UINT8 src_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
12411: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x05);
12412: UINT16 src_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07);
12413: UINT16 src_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x09);
12414: UINT8 dest_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0b);
12415: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
12416: UINT16 dest_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0e);
12417: UINT16 dest_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x10);
12418:
1.1.1.32 root 12419: UINT8 *src_buffer = NULL, *dest_buffer = NULL;
1.1.1.20 root 12420: UINT32 src_addr, dest_addr;
12421: UINT32 src_addr_max, dest_addr_max;
12422:
12423: if(src_type == 0) {
12424: src_buffer = mem;
12425: src_addr = (src_seg << 4) + src_ofs;
12426: src_addr_max = MAX_MEM;
12427: } else {
1.1.1.31 root 12428: if(!(src_handle >= 1 && src_handle <= MAX_EMS_HANDLES && ems_handles[src_handle].allocated)) {
1.1.1.20 root 12429: REG8(AH) = 0x83;
12430: return;
12431: } else if(!(src_seg < ems_handles[src_handle].pages)) {
12432: REG8(AH) = 0x8a;
12433: return;
12434: }
1.1.1.32 root 12435: if(ems_handles[src_handle].buffer != NULL) {
12436: src_buffer = ems_handles[src_handle].buffer + 0x4000 * src_seg;
12437: }
1.1.1.20 root 12438: src_addr = src_ofs;
1.1.1.32 root 12439: src_addr_max = 0x4000 * (ems_handles[src_handle].pages - src_seg);
1.1.1.20 root 12440: }
12441: if(dest_type == 0) {
12442: dest_buffer = mem;
12443: dest_addr = (dest_seg << 4) + dest_ofs;
12444: dest_addr_max = MAX_MEM;
12445: } else {
1.1.1.31 root 12446: if(!(dest_handle >= 1 && dest_handle <= MAX_EMS_HANDLES && ems_handles[dest_handle].allocated)) {
1.1.1.20 root 12447: REG8(AH) = 0x83;
12448: return;
12449: } else if(!(dest_seg < ems_handles[dest_handle].pages)) {
12450: REG8(AH) = 0x8a;
12451: return;
12452: }
1.1.1.32 root 12453: if(ems_handles[dest_handle].buffer != NULL) {
12454: dest_buffer = ems_handles[dest_handle].buffer + 0x4000 * dest_seg;
12455: }
1.1.1.20 root 12456: dest_addr = dest_ofs;
1.1.1.32 root 12457: dest_addr_max = 0x4000 * (ems_handles[dest_handle].pages - dest_seg);
1.1.1.20 root 12458: }
1.1.1.32 root 12459: if(src_buffer != NULL && dest_buffer != NULL) {
12460: for(int i = 0; i < copy_length; i++) {
12461: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
12462: if(REG8(AL) == 0x00) {
12463: dest_buffer[dest_addr++] = src_buffer[src_addr++];
12464: } else if(REG8(AL) == 0x01) {
12465: UINT8 tmp = dest_buffer[dest_addr];
12466: dest_buffer[dest_addr++] = src_buffer[src_addr];
12467: src_buffer[src_addr++] = tmp;
12468: }
12469: } else {
12470: REG8(AH) = 0x93;
12471: return;
1.1.1.20 root 12472: }
12473: }
1.1.1.32 root 12474: REG8(AH) = 0x00;
12475: } else {
12476: REG8(AH) = 0x80;
1.1.1.20 root 12477: }
12478: }
12479:
12480: inline void msdos_int_67h_57h()
12481: {
12482: if(!support_ems) {
12483: REG8(AH) = 0x84;
12484: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
12485: struct {
12486: UINT16 handle;
12487: UINT16 page;
12488: bool mapped;
12489: } tmp_pages[4];
12490:
12491: // unmap pages to copy memory data to ems buffer
12492: for(int i = 0; i < 4; i++) {
12493: tmp_pages[i].handle = ems_pages[i].handle;
12494: tmp_pages[i].page = ems_pages[i].page;
12495: tmp_pages[i].mapped = ems_pages[i].mapped;
12496: ems_unmap_page(i);
12497: }
12498:
12499: // run move/exchange operation
12500: msdos_int_67h_57h_tmp();
12501:
12502: // restore unmapped pages
12503: for(int i = 0; i < 4; i++) {
12504: if(tmp_pages[i].mapped) {
12505: ems_map_page(i, tmp_pages[i].handle, tmp_pages[i].page);
12506: }
12507: }
12508: } else {
1.1.1.22 root 12509: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.20 root 12510: REG8(AH) = 0x8f;
12511: }
12512: }
12513:
12514: inline void msdos_int_67h_58h()
12515: {
12516: if(!support_ems) {
12517: REG8(AH) = 0x84;
12518: } else if(REG8(AL) == 0x00) {
12519: for(int i = 0; i < 4; i++) {
1.1.1.30 root 12520: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = (EMS_TOP + 0x4000 * i) >> 4;
12521: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = i;
1.1.1.20 root 12522: }
12523: REG8(AH) = 0x00;
12524: REG16(CX) = 4;
12525: } else if(REG8(AL) == 0x01) {
12526: REG8(AH) = 0x00;
12527: REG16(CX) = 4;
12528: } else {
1.1.1.22 root 12529: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.20 root 12530: REG8(AH) = 0x8f;
12531: }
12532: }
12533:
12534: inline void msdos_int_67h_5ah()
12535: {
12536: if(!support_ems) {
1.1.1.19 root 12537: REG8(AH) = 0x84;
1.1.1.20 root 12538: } else if(REG16(BX) > MAX_EMS_PAGES) {
12539: REG8(AH) = 0x87;
12540: } else if(REG16(BX) > free_ems_pages) {
12541: REG8(AH) = 0x88;
12542: // } else if(REG16(BX) == 0) {
12543: // REG8(AH) = 0x89;
12544: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
1.1.1.31 root 12545: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.20 root 12546: if(!ems_handles[i].allocated) {
12547: ems_allocate_pages(i, REG16(BX));
12548: REG8(AH) = 0x00;
12549: REG16(DX) = i;
12550: return;
12551: }
12552: }
12553: REG8(AH) = 0x85;
12554: } else {
1.1.1.22 root 12555: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.20 root 12556: REG8(AH) = 0x8f;
1.1.1.19 root 12557: }
12558: }
12559:
1.1.1.30 root 12560: inline void msdos_int_67h_deh()
12561: {
12562: REG8(AH) = 0x84;
12563: }
12564:
1.1.1.19 root 12565: #ifdef SUPPORT_XMS
12566:
1.1.1.32 root 12567: void msdos_xms_init()
1.1.1.26 root 12568: {
1.1.1.30 root 12569: emb_handle_top = (emb_handle_t *)calloc(1, sizeof(emb_handle_t));
12570: emb_handle_top->address = EMB_TOP;
12571: emb_handle_top->size_kb = (EMB_END - EMB_TOP) >> 10;
1.1.1.26 root 12572: xms_a20_local_enb_count = 0;
12573: }
12574:
1.1.1.32 root 12575: void msdos_xms_finish()
12576: {
12577: msdos_xms_release();
12578: }
12579:
12580: void msdos_xms_release()
1.1.1.30 root 12581: {
12582: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL;) {
12583: emb_handle_t *next_handle = emb_handle->next;
12584: free(emb_handle);
12585: emb_handle = next_handle;
12586: }
12587: }
12588:
12589: emb_handle_t *msdos_xms_get_emb_handle(int handle)
12590: {
12591: if(handle != 0) {
12592: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
12593: if(emb_handle->handle == handle) {
12594: return(emb_handle);
12595: }
12596: }
12597: }
12598: return(NULL);
12599: }
12600:
12601: int msdos_xms_get_unused_emb_handle_id()
12602: {
12603: for(int handle = 1;; handle++) {
12604: if(msdos_xms_get_emb_handle(handle) == NULL) {
12605: return(handle);
12606: }
12607: }
12608: return(0);
12609: }
12610:
12611: int msdos_xms_get_unused_emb_handle_count()
12612: {
12613: int count = 64; //255;
12614:
12615: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
12616: if(emb_handle->handle != 0) {
12617: if(--count == 1) {
12618: break;
12619: }
12620: }
12621: }
12622: return(count);
12623: }
12624:
12625: void msdos_xms_split_emb_handle(emb_handle_t *emb_handle, int size_kb)
12626: {
12627: if(emb_handle->size_kb > size_kb) {
12628: emb_handle_t *new_handle = (emb_handle_t *)calloc(1, sizeof(emb_handle_t));
12629:
12630: new_handle->address = emb_handle->address + size_kb * 1024;
12631: new_handle->size_kb = emb_handle->size_kb - size_kb;
12632: emb_handle->size_kb = size_kb;
12633:
12634: new_handle->prev = emb_handle;
12635: new_handle->next = emb_handle->next;
12636: if(emb_handle->next != NULL) {
12637: emb_handle->next->prev = new_handle;
12638: }
12639: emb_handle->next = new_handle;
12640: }
12641: }
12642:
12643: void msdos_xms_combine_emb_handles(emb_handle_t *emb_handle)
12644: {
12645: emb_handle_t *next_handle = emb_handle->next;
12646:
12647: if(next_handle != NULL) {
12648: emb_handle->size_kb += next_handle->size_kb;
12649:
12650: if(next_handle->next != NULL) {
12651: next_handle->next->prev = emb_handle;
12652: }
12653: emb_handle->next = next_handle->next;
12654: free(next_handle);
12655: }
12656: }
12657:
12658: emb_handle_t *msdos_xms_alloc_emb_handle(int size_kb)
12659: {
12660: emb_handle_t *target_handle = NULL;
12661:
12662: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
12663: if(emb_handle->handle == 0 && emb_handle->size_kb >= size_kb) {
12664: if(target_handle == NULL || target_handle->size_kb > emb_handle->size_kb) {
12665: target_handle = emb_handle;
12666: }
12667: }
12668: }
12669: if(target_handle != NULL) {
12670: if(target_handle->size_kb > size_kb) {
12671: msdos_xms_split_emb_handle(target_handle, size_kb);
12672: }
12673: // target_handle->handle = msdos_xms_get_unused_emb_handle_id();
12674: return(target_handle);
12675: }
12676: return(NULL);
12677: }
12678:
12679: void msdos_xms_free_emb_handle(emb_handle_t *emb_handle)
12680: {
12681: emb_handle_t *prev_handle = emb_handle->prev;
12682: emb_handle_t *next_handle = emb_handle->next;
12683:
12684: if(prev_handle != NULL && prev_handle->handle == 0) {
12685: msdos_xms_combine_emb_handles(prev_handle);
12686: emb_handle = prev_handle;
12687: }
12688: if(next_handle != NULL && next_handle->handle == 0) {
12689: msdos_xms_combine_emb_handles(emb_handle);
12690: }
12691: emb_handle->handle = 0;
12692: }
12693:
1.1.1.19 root 12694: inline void msdos_call_xms_00h()
12695: {
1.1.1.29 root 12696: #if defined(HAS_I386)
12697: REG16(AX) = 0x0300; // V3.00 (XMS Version)
12698: REG16(BX) = 0x035f; // V3.95 (Driver Revision)
12699: #else
12700: REG16(AX) = 0x0200; // V2.00 (XMS Version)
12701: REG16(BX) = 0x0270; // V2.70 (Driver Revision)
12702: #endif
12703: // REG16(DX) = 0x0000; // HMA does not exist
12704: REG16(DX) = 0x0001; // HMA does exist
1.1.1.19 root 12705: }
12706:
12707: inline void msdos_call_xms_01h()
12708: {
1.1.1.29 root 12709: if(REG8(AL) == 0x40) {
12710: // HIMEM.SYS will fail function 01h with error code 91h if AL=40h and
12711: // DX=KB free extended memory returned by last call of function 08h
12712: REG16(AX) = 0x0000;
12713: REG8(BL) = 0x91;
12714: REG16(DX) = xms_dx_after_call_08h;
12715: } else if(memcmp(mem + 0x100003, "VDISK", 5) == 0) {
12716: REG16(AX) = 0x0000;
12717: REG8(BL) = 0x81; // Vdisk was detected
12718: #ifdef SUPPORT_HMA
12719: } else if(is_hma_used_by_int_2fh) {
12720: REG16(AX) = 0x0000;
12721: REG8(BL) = 0x90; // HMA does not exist or is not managed by XMS provider
12722: } else if(is_hma_used_by_xms) {
12723: REG16(AX) = 0x0000;
12724: REG8(BL) = 0x91; // HMA is already in use
12725: } else {
12726: REG16(AX) = 0x0001;
12727: is_hma_used_by_xms = true;
12728: #else
12729: } else {
12730: REG16(AX) = 0x0000;
12731: REG8(BL) = 0x91; // HMA is already in use
12732: #endif
12733: }
1.1.1.19 root 12734: }
12735:
12736: inline void msdos_call_xms_02h()
12737: {
1.1.1.29 root 12738: if(memcmp(mem + 0x100003, "VDISK", 5) == 0) {
12739: REG16(AX) = 0x0000;
12740: REG8(BL) = 0x81; // Vdisk was detected
12741: #ifdef SUPPORT_HMA
12742: } else if(is_hma_used_by_int_2fh) {
12743: REG16(AX) = 0x0000;
12744: REG8(BL) = 0x90; // HMA does not exist or is not managed by XMS provider
12745: } else if(!is_hma_used_by_xms) {
12746: REG16(AX) = 0x0000;
12747: REG8(BL) = 0x93; // HMA is not allocated
12748: } else {
12749: REG16(AX) = 0x0001;
12750: is_hma_used_by_xms = false;
12751: // restore first free mcb in high memory area
12752: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
12753: #else
12754: } else {
12755: REG16(AX) = 0x0000;
12756: REG8(BL) = 0x91; // HMA is already in use
12757: #endif
12758: }
1.1.1.19 root 12759: }
12760:
12761: inline void msdos_call_xms_03h()
12762: {
12763: i386_set_a20_line(1);
12764: REG16(AX) = 0x0001;
12765: REG8(BL) = 0x00;
12766: }
12767:
12768: inline void msdos_call_xms_04h()
12769: {
1.1.1.21 root 12770: i386_set_a20_line(0);
12771: REG16(AX) = 0x0001;
12772: REG8(BL) = 0x00;
1.1.1.19 root 12773: }
12774:
12775: inline void msdos_call_xms_05h()
12776: {
12777: i386_set_a20_line(1);
12778: REG16(AX) = 0x0001;
12779: REG8(BL) = 0x00;
1.1.1.21 root 12780: xms_a20_local_enb_count++;
1.1.1.19 root 12781: }
12782:
12783: void msdos_call_xms_06h()
12784: {
1.1.1.21 root 12785: if(xms_a20_local_enb_count > 0) {
12786: xms_a20_local_enb_count--;
12787: }
12788: if(xms_a20_local_enb_count == 0) {
1.1.1.19 root 12789: i386_set_a20_line(0);
1.1.1.21 root 12790: }
12791: if((m_a20_mask >> 20) & 1) {
1.1.1.19 root 12792: REG16(AX) = 0x0000;
12793: REG8(BL) = 0x94;
1.1.1.21 root 12794: } else {
12795: REG16(AX) = 0x0001;
12796: REG8(BL) = 0x00;
1.1.1.19 root 12797: }
12798: }
12799:
12800: inline void msdos_call_xms_07h()
12801: {
12802: REG16(AX) = (m_a20_mask >> 20) & 1;
12803: REG8(BL) = 0x00;
12804: }
12805:
12806: inline void msdos_call_xms_08h()
12807: {
12808: REG16(AX) = REG16(DX) = 0x0000;
12809:
1.1.1.30 root 12810: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
12811: if(emb_handle->handle == 0) {
12812: if(REG16(AX) < emb_handle->size_kb) {
12813: REG16(AX) = emb_handle->size_kb;
1.1.1.19 root 12814: }
1.1.1.30 root 12815: REG16(DX) += emb_handle->size_kb;
1.1.1.19 root 12816: }
12817: }
12818:
12819: if(REG16(AX) == 0 && REG16(DX) == 0) {
12820: REG8(BL) = 0xa0;
12821: } else {
12822: REG8(BL) = 0x00;
12823: }
1.1.1.29 root 12824: xms_dx_after_call_08h = REG16(DX);
1.1.1.19 root 12825: }
12826:
1.1.1.30 root 12827: void msdos_call_xms_09h(int size_kb)
1.1.1.19 root 12828: {
1.1.1.30 root 12829: emb_handle_t *emb_handle = msdos_xms_alloc_emb_handle(size_kb);
12830:
12831: if(emb_handle != NULL) {
12832: emb_handle->handle = msdos_xms_get_unused_emb_handle_id();
12833:
12834: REG16(AX) = 0x0001;
12835: REG16(DX) = emb_handle->handle;
12836: REG8(BL) = 0x00;
12837: } else {
12838: REG16(AX) = REG16(DX) = 0x0000;
12839: REG8(BL) = 0xa0;
1.1.1.19 root 12840: }
1.1.1.30 root 12841: }
12842:
12843: inline void msdos_call_xms_09h()
12844: {
12845: msdos_call_xms_09h(REG16(DX));
1.1.1.19 root 12846: }
12847:
12848: inline void msdos_call_xms_0ah()
12849: {
1.1.1.30 root 12850: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
12851:
12852: if(emb_handle == NULL) {
1.1.1.19 root 12853: REG16(AX) = 0x0000;
12854: REG8(BL) = 0xa2;
1.1.1.30 root 12855: } else if(emb_handle->lock > 0) {
1.1.1.19 root 12856: REG16(AX) = 0x0000;
12857: REG8(BL) = 0xab;
12858: } else {
1.1.1.30 root 12859: msdos_xms_free_emb_handle(emb_handle);
1.1.1.19 root 12860:
12861: REG16(AX) = 0x0001;
12862: REG8(BL) = 0x00;
12863: }
12864: }
12865:
12866: inline void msdos_call_xms_0bh()
12867: {
12868: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
12869: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
12870: UINT32 src_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06);
12871: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0a);
12872: UINT32 dest_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
12873:
12874: UINT8 *src_buffer, *dest_buffer;
12875: UINT32 src_addr_max, dest_addr_max;
1.1.1.30 root 12876: emb_handle_t *emb_handle;
1.1.1.19 root 12877:
12878: if(src_handle == 0) {
12879: src_buffer = mem;
12880: src_addr = (((src_addr >> 16) & 0xffff) << 4) + (src_addr & 0xffff);
12881: src_addr_max = MAX_MEM;
1.1.1.30 root 12882:
1.1.1.19 root 12883: } else {
1.1.1.30 root 12884: if((emb_handle = msdos_xms_get_emb_handle(src_handle)) == NULL) {
1.1.1.19 root 12885: REG16(AX) = 0x0000;
12886: REG8(BL) = 0xa3;
12887: return;
12888: }
1.1.1.30 root 12889: src_buffer = mem + emb_handle->address;
12890: src_addr_max = emb_handle->size_kb * 1024;
1.1.1.19 root 12891: }
12892: if(dest_handle == 0) {
12893: dest_buffer = mem;
12894: dest_addr = (((dest_addr >> 16) & 0xffff) << 4) + (dest_addr & 0xffff);
12895: dest_addr_max = MAX_MEM;
12896: } else {
1.1.1.30 root 12897: if((emb_handle = msdos_xms_get_emb_handle(dest_handle)) == NULL) {
1.1.1.19 root 12898: REG16(AX) = 0x0000;
12899: REG8(BL) = 0xa5;
12900: return;
12901: }
1.1.1.30 root 12902: dest_buffer = mem + emb_handle->address;
12903: dest_addr_max = emb_handle->size_kb * 1024;
1.1.1.19 root 12904: }
12905: for(int i = 0; i < copy_length; i++) {
12906: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
12907: dest_buffer[dest_addr++] = src_buffer[src_addr++];
12908: } else {
12909: break;
12910: }
12911: }
12912: REG16(AX) = 0x0001;
12913: REG8(BL) = 0x00;
12914: }
12915:
12916: inline void msdos_call_xms_0ch()
12917: {
1.1.1.30 root 12918: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
12919:
12920: if(emb_handle == NULL) {
1.1.1.19 root 12921: REG16(AX) = 0x0000;
12922: REG8(BL) = 0xa2;
12923: } else {
1.1.1.30 root 12924: emb_handle->lock++;
1.1.1.19 root 12925: REG16(AX) = 0x0001;
12926: REG8(BL) = 0x00;
1.1.1.30 root 12927: REG16(DX) = (emb_handle->address >> 16) & 0xffff;
12928: REG16(BX) = (emb_handle->address ) & 0xffff;
1.1.1.19 root 12929: }
12930: }
12931:
12932: inline void msdos_call_xms_0dh()
12933: {
1.1.1.30 root 12934: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
12935:
12936: if(emb_handle == NULL) {
1.1.1.19 root 12937: REG16(AX) = 0x0000;
12938: REG8(BL) = 0xa2;
1.1.1.30 root 12939: } else if(!(emb_handle->lock > 0)) {
1.1.1.19 root 12940: REG16(AX) = 0x0000;
12941: REG8(BL) = 0xaa;
12942: } else {
1.1.1.30 root 12943: emb_handle->lock--;
1.1.1.19 root 12944: REG16(AX) = 0x0001;
12945: REG8(BL) = 0x00;
12946: }
12947: }
12948:
12949: inline void msdos_call_xms_0eh()
12950: {
1.1.1.30 root 12951: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
12952:
12953: if(emb_handle == NULL) {
1.1.1.19 root 12954: REG16(AX) = 0x0000;
12955: REG8(BL) = 0xa2;
12956: } else {
12957: REG16(AX) = 0x0001;
1.1.1.30 root 12958: REG8(BH) = emb_handle->lock;
12959: REG8(BL) = msdos_xms_get_unused_emb_handle_count();
12960: REG16(DX) = emb_handle->size_kb;
1.1.1.19 root 12961: }
12962: }
12963:
1.1.1.30 root 12964: void msdos_call_xms_0fh(int size_kb)
1.1.1.19 root 12965: {
1.1.1.30 root 12966: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
12967:
12968: if(emb_handle == NULL) {
1.1.1.19 root 12969: REG16(AX) = 0x0000;
12970: REG8(BL) = 0xa2;
1.1.1.30 root 12971: } else if(emb_handle->lock > 0) {
1.1.1.19 root 12972: REG16(AX) = 0x0000;
12973: REG8(BL) = 0xab;
12974: } else {
1.1.1.30 root 12975: if(emb_handle->size_kb < size_kb) {
12976: if(emb_handle->next != NULL && emb_handle->next->handle == 0 && (emb_handle->size_kb + emb_handle->next->size_kb) >= size_kb) {
12977: msdos_xms_combine_emb_handles(emb_handle);
12978: if(emb_handle->size_kb > size_kb) {
12979: msdos_xms_split_emb_handle(emb_handle, size_kb);
12980: }
12981: } else {
12982: int old_handle = emb_handle->handle;
12983: int old_size_kb = emb_handle->size_kb;
12984: UINT8 *buffer = (UINT8 *)malloc(old_size_kb * 1024);
12985:
12986: memcpy(buffer, mem + emb_handle->address, old_size_kb * 1024);
12987: msdos_xms_free_emb_handle(emb_handle);
12988:
12989: if((emb_handle = msdos_xms_alloc_emb_handle(size_kb)) == NULL) {
12990: emb_handle = msdos_xms_alloc_emb_handle(old_size_kb); // should be always successed
12991: }
12992: emb_handle->handle = old_handle;
12993: memcpy(mem + emb_handle->address, buffer, old_size_kb * 1024);
12994: free(buffer);
12995: }
12996: } else if(emb_handle->size_kb > size_kb) {
12997: msdos_xms_split_emb_handle(emb_handle, size_kb);
12998: }
12999: if(emb_handle->size_kb != size_kb) {
13000: REG16(AX) = 0x0000;
13001: REG8(BL) = 0xa0;
13002: } else {
13003: REG16(AX) = 0x0001;
13004: REG8(BL) = 0x00;
13005: }
1.1.1.19 root 13006: }
13007: }
13008:
1.1.1.30 root 13009: inline void msdos_call_xms_0fh()
13010: {
13011: msdos_call_xms_0fh(REG16(BX));
13012: }
13013:
1.1.1.19 root 13014: inline void msdos_call_xms_10h()
13015: {
13016: int seg;
13017:
13018: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(DX), 0)) != -1) {
13019: REG16(AX) = 0x0001;
13020: REG16(BX) = seg;
13021: } else {
13022: REG16(AX) = 0x0000;
13023: REG8(BL) = 0xb0;
13024: REG16(DX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
13025: }
13026: }
13027:
13028: inline void msdos_call_xms_11h()
13029: {
13030: int mcb_seg = REG16(DX) - 1;
13031: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
13032:
13033: if(mcb->mz == 'M' || mcb->mz == 'Z') {
13034: msdos_mem_free(REG16(DX));
13035: REG16(AX) = 0x0001;
13036: REG8(BL) = 0x00;
13037: } else {
13038: REG16(AX) = 0x0000;
13039: REG8(BL) = 0xb2;
13040: }
13041: }
13042:
13043: inline void msdos_call_xms_12h()
13044: {
13045: int mcb_seg = REG16(DX) - 1;
13046: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
13047: int max_paragraphs;
13048:
13049: if(mcb->mz == 'M' || mcb->mz == 'Z') {
13050: if(!msdos_mem_realloc(REG16(DX), REG16(BX), &max_paragraphs)) {
13051: REG16(AX) = 0x0001;
13052: REG8(BL) = 0x00;
13053: } else {
13054: REG16(AX) = 0x0000;
13055: REG8(BL) = 0xb0;
13056: REG16(DX) = max_paragraphs;
13057: }
13058: } else {
13059: REG16(AX) = 0x0000;
13060: REG8(BL) = 0xb2;
13061: }
13062: }
13063:
1.1.1.29 root 13064: #if defined(HAS_I386)
13065:
13066: inline void msdos_call_xms_88h()
13067: {
13068: REG32(EAX) = REG32(EDX) = 0x0000;
13069:
1.1.1.30 root 13070: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
13071: if(emb_handle->handle == 0) {
13072: if(REG32(EAX) < emb_handle->size_kb) {
13073: REG32(EAX) = emb_handle->size_kb;
1.1.1.29 root 13074: }
1.1.1.30 root 13075: REG32(EDX) += emb_handle->size_kb;
1.1.1.29 root 13076: }
13077: }
13078:
13079: if(REG32(EAX) == 0 && REG32(EDX) == 0) {
13080: REG8(BL) = 0xa0;
13081: } else {
13082: REG8(BL) = 0x00;
13083: }
13084: REG32(ECX) = EMB_END - 1;
13085: }
13086:
13087: inline void msdos_call_xms_89h()
13088: {
1.1.1.30 root 13089: msdos_call_xms_09h(REG32(EDX));
1.1.1.29 root 13090: }
13091:
13092: inline void msdos_call_xms_8eh()
13093: {
1.1.1.30 root 13094: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
13095:
13096: if(emb_handle == NULL) {
1.1.1.29 root 13097: REG16(AX) = 0x0000;
13098: REG8(BL) = 0xa2;
13099: } else {
13100: REG16(AX) = 0x0001;
1.1.1.30 root 13101: REG8(BH) = emb_handle->lock;
13102: REG16(CX) = msdos_xms_get_unused_emb_handle_count();
13103: REG32(EDX) = emb_handle->size_kb;
1.1.1.29 root 13104: }
13105: }
13106:
13107: inline void msdos_call_xms_8fh()
13108: {
1.1.1.30 root 13109: msdos_call_xms_0fh(REG32(EBX));
1.1.1.29 root 13110: }
13111:
13112: #endif
1.1.1.19 root 13113: #endif
13114:
1.1.1.26 root 13115: UINT16 msdos_get_equipment()
13116: {
13117: static UINT16 equip = 0;
13118:
13119: if(equip == 0) {
13120: #ifdef SUPPORT_FPU
13121: equip |= (1 << 1); // 80x87 coprocessor installed
13122: #endif
13123: equip |= (1 << 2); // pointing device installed (PS/2)
13124: equip |= (2 << 4); // initial video mode (80x25 color)
13125: // equip |= (1 << 8); // 0 if DMA installed
13126: equip |= (2 << 9); // number of serial ports
13127: equip |= (3 << 14); // number of printer ports (NOTE: this number is 3 on Windows 98 SE though only LPT1 exists)
1.1.1.28 root 13128:
13129: // check only A: and B: if it is floppy drive
13130: DWORD dwDrives = GetLogicalDrives();
13131: int n = 0;
13132: for(int i = 0; i < 2; i++) {
13133: if(dwDrives & (1 << i)) {
13134: char volume[] = "A:\\";
13135: volume[0] = 'A' + i;
13136: if(GetDriveType(volume) == DRIVE_REMOVABLE) {
13137: n++;
13138: }
13139: }
13140: }
13141: if(n != 0) {
13142: equip |= (1 << 0); // floppy disk(s) installed
13143: n--;
13144: equip |= (n << 6); // number of floppies installed less 1
13145: }
13146: // if(joyGetNumDevs() != 0) {
13147: // equip |= (1 << 12); // game port installed
13148: // }
1.1.1.26 root 13149: }
13150: return(equip);
13151: }
13152:
1.1 root 13153: void msdos_syscall(unsigned num)
13154: {
1.1.1.22 root 13155: #ifdef ENABLE_DEBUG_SYSCALL
13156: if(num == 0x68) {
13157: // dummy interrupt for EMS (int 67h)
1.1.1.33! root 13158: fprintf(fp_debug_log, "int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.22 root 13159: } else if(num == 0x69) {
13160: // dummy interrupt for XMS (call far)
1.1.1.33! root 13161: fprintf(fp_debug_log, "call XMS (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.22 root 13162: } else if(num == 0x6a) {
13163: // dummy interrupt for case map routine pointed in the country info
13164: } else {
1.1.1.33! root 13165: fprintf(fp_debug_log, "int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.22 root 13166: }
13167: #endif
1.1.1.33! root 13168: ctrl_break_detected = ctrl_break_pressed = ctrl_c_pressed = false;
1.1.1.22 root 13169:
1.1 root 13170: switch(num) {
13171: case 0x00:
1.1.1.28 root 13172: try {
13173: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
13174: error("division by zero\n");
13175: } catch(...) {
13176: fatalerror("division by zero detected, and failed to terminate current process\n");
13177: }
1.1 root 13178: break;
13179: case 0x04:
1.1.1.28 root 13180: try {
13181: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
13182: error("overflow\n");
13183: } catch(...) {
13184: fatalerror("overflow detected, and failed to terminate current process\n");
13185: }
1.1 root 13186: break;
13187: case 0x06:
13188: // NOTE: ish.com has illegal instruction...
1.1.1.14 root 13189: if(!ignore_illegal_insn) {
1.1.1.28 root 13190: try {
13191: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
13192: error("illegal instruction\n");
13193: } catch(...) {
13194: fatalerror("illegal instruction detected, and failed to terminate current process\n");
13195: }
1.1.1.14 root 13196: } else {
13197: #if defined(HAS_I386)
13198: m_eip++;
13199: #else
13200: m_pc++;
13201: #endif
13202: }
1.1 root 13203: break;
1.1.1.33! root 13204: case 0x09:
! 13205: // ctrl-break is pressed
! 13206: if(raise_int_1bh) {
! 13207: #if defined(HAS_I386)
! 13208: m_ext = 0; // not an external interrupt
! 13209: i386_trap(0x1b, 1, 0);
! 13210: m_ext = 1;
! 13211: #else
! 13212: PREFIX86(_interrupt)(0x1b);
! 13213: #endif
! 13214: raise_int_1bh = false;
! 13215: }
1.1.1.8 root 13216: case 0x08:
1.1.1.14 root 13217: // pcbios_irq0(); // this causes too slow emulation...
1.1.1.8 root 13218: case 0x0b:
13219: case 0x0c:
13220: case 0x0d:
13221: case 0x0e:
13222: case 0x0f:
13223: // EOI
13224: pic[0].isr &= ~(1 << (num - 0x08));
13225: pic_update();
13226: break;
1.1 root 13227: case 0x10:
13228: // PC BIOS - Video
1.1.1.14 root 13229: if(!restore_console_on_exit) {
1.1.1.15 root 13230: change_console_size(scr_width, scr_height);
1.1 root 13231: }
1.1.1.3 root 13232: m_CF = 0;
1.1 root 13233: switch(REG8(AH)) {
1.1.1.16 root 13234: case 0x00: pcbios_int_10h_00h(); break;
1.1 root 13235: case 0x01: pcbios_int_10h_01h(); break;
13236: case 0x02: pcbios_int_10h_02h(); break;
13237: case 0x03: pcbios_int_10h_03h(); break;
13238: case 0x05: pcbios_int_10h_05h(); break;
13239: case 0x06: pcbios_int_10h_06h(); break;
13240: case 0x07: pcbios_int_10h_07h(); break;
13241: case 0x08: pcbios_int_10h_08h(); break;
13242: case 0x09: pcbios_int_10h_09h(); break;
13243: case 0x0a: pcbios_int_10h_0ah(); break;
13244: case 0x0b: break;
13245: case 0x0c: break;
13246: case 0x0d: break;
13247: case 0x0e: pcbios_int_10h_0eh(); break;
13248: case 0x0f: pcbios_int_10h_0fh(); break;
13249: case 0x10: break;
1.1.1.14 root 13250: case 0x11: pcbios_int_10h_11h(); break;
13251: case 0x12: pcbios_int_10h_12h(); break;
1.1 root 13252: case 0x13: pcbios_int_10h_13h(); break;
1.1.1.30 root 13253: case 0x18: pcbios_int_10h_18h(); break;
1.1.1.14 root 13254: case 0x1a: pcbios_int_10h_1ah(); break;
1.1.1.24 root 13255: case 0x1b: REG8(AL) = 0x00; break; // functionality/state information is not supported
13256: case 0x1c: REG8(AL) = 0x00; break; // save/restore video state is not supported
1.1 root 13257: case 0x1d: pcbios_int_10h_1dh(); break;
1.1.1.24 root 13258: case 0x1e: REG8(AL) = 0x00; break; // flat-panel functions are not supported
13259: case 0x1f: REG8(AL) = 0x00; break; // xga functions are not supported
1.1.1.22 root 13260: case 0x4f: pcbios_int_10h_4fh(); break;
1.1.1.30 root 13261: case 0x6f: break;
1.1.1.22 root 13262: case 0x80: m_CF = 1; break; // unknown
13263: case 0x81: m_CF = 1; break; // unknown
1.1 root 13264: case 0x82: pcbios_int_10h_82h(); break;
1.1.1.22 root 13265: case 0x83: pcbios_int_10h_83h(); break;
13266: case 0x8b: break;
13267: case 0x8c: m_CF = 1; break; // unknown
13268: case 0x8d: m_CF = 1; break; // unknown
13269: case 0x8e: m_CF = 1; break; // unknown
13270: case 0x90: pcbios_int_10h_90h(); break;
13271: case 0x91: pcbios_int_10h_91h(); break;
13272: case 0x92: break;
13273: case 0x93: break;
13274: case 0xef: pcbios_int_10h_efh(); break;
1.1.1.24 root 13275: case 0xfa: break; // ega register interface library is not installed
1.1 root 13276: case 0xfe: pcbios_int_10h_feh(); break;
13277: case 0xff: pcbios_int_10h_ffh(); break;
13278: default:
1.1.1.22 root 13279: unimplemented_10h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
13280: m_CF = 1;
1.1 root 13281: break;
13282: }
13283: break;
13284: case 0x11:
13285: // PC BIOS - Get Equipment List
1.1.1.26 root 13286: REG16(AX) = msdos_get_equipment();
1.1 root 13287: break;
13288: case 0x12:
13289: // PC BIOS - Get Memory Size
1.1.1.33! root 13290: REG16(AX) = *(UINT16 *)(mem + 0x413);
1.1 root 13291: break;
13292: case 0x13:
13293: // PC BIOS - Disk
1.1.1.22 root 13294: // fatalerror("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 13295: REG8(AH) = 0xff;
1.1.1.3 root 13296: m_CF = 1;
1.1 root 13297: break;
13298: case 0x14:
13299: // PC BIOS - Serial I/O
1.1.1.25 root 13300: switch(REG8(AH)) {
13301: case 0x00: pcbios_int_14h_00h(); break;
13302: case 0x01: pcbios_int_14h_01h(); break;
13303: case 0x02: pcbios_int_14h_02h(); break;
13304: case 0x03: pcbios_int_14h_03h(); break;
13305: case 0x04: pcbios_int_14h_04h(); break;
13306: case 0x05: pcbios_int_14h_05h(); break;
13307: default:
13308: unimplemented_14h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
13309: break;
13310: }
1.1 root 13311: break;
13312: case 0x15:
13313: // PC BIOS
1.1.1.3 root 13314: m_CF = 0;
1.1 root 13315: switch(REG8(AH)) {
1.1.1.14 root 13316: case 0x10: pcbios_int_15h_10h(); break;
1.1 root 13317: case 0x23: pcbios_int_15h_23h(); break;
13318: case 0x24: pcbios_int_15h_24h(); break;
1.1.1.24 root 13319: case 0x41: break;
1.1 root 13320: case 0x49: pcbios_int_15h_49h(); break;
1.1.1.22 root 13321: case 0x50: pcbios_int_15h_50h(); break;
1.1.1.30 root 13322: case 0x53: pcbios_int_15h_53h(); break;
1.1 root 13323: case 0x86: pcbios_int_15h_86h(); break;
13324: case 0x87: pcbios_int_15h_87h(); break;
13325: case 0x88: pcbios_int_15h_88h(); break;
13326: case 0x89: pcbios_int_15h_89h(); break;
1.1.1.21 root 13327: case 0x8a: pcbios_int_15h_8ah(); break;
1.1.1.22 root 13328: case 0xc0: // PS/2 ???
13329: case 0xc1:
13330: case 0xc2:
1.1.1.30 root 13331: case 0xc3: // PS50+ ???
13332: case 0xc4:
1.1.1.22 root 13333: REG8(AH) = 0x86;
13334: m_CF = 1;
13335: break;
1.1.1.3 root 13336: #if defined(HAS_I386)
1.1 root 13337: case 0xc9: pcbios_int_15h_c9h(); break;
1.1.1.3 root 13338: #endif
1.1 root 13339: case 0xca: pcbios_int_15h_cah(); break;
1.1.1.22 root 13340: case 0xe8: pcbios_int_15h_e8h(); break;
1.1 root 13341: default:
1.1.1.22 root 13342: unimplemented_15h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
13343: REG8(AH) = 0x86;
1.1.1.3 root 13344: m_CF = 1;
1.1 root 13345: break;
13346: }
13347: break;
13348: case 0x16:
13349: // PC BIOS - Keyboard
1.1.1.3 root 13350: m_CF = 0;
1.1 root 13351: switch(REG8(AH)) {
13352: case 0x00: pcbios_int_16h_00h(); break;
13353: case 0x01: pcbios_int_16h_01h(); break;
13354: case 0x02: pcbios_int_16h_02h(); break;
13355: case 0x03: pcbios_int_16h_03h(); break;
13356: case 0x05: pcbios_int_16h_05h(); break;
13357: case 0x10: pcbios_int_16h_00h(); break;
13358: case 0x11: pcbios_int_16h_01h(); break;
13359: case 0x12: pcbios_int_16h_12h(); break;
13360: case 0x13: pcbios_int_16h_13h(); break;
13361: case 0x14: pcbios_int_16h_14h(); break;
1.1.1.24 root 13362: case 0x55: pcbios_int_16h_55h(); break;
1.1.1.30 root 13363: case 0x6f: pcbios_int_16h_6fh(); break;
1.1.1.22 root 13364: case 0xda: break; // unknown
13365: case 0xff: break; // unknown
1.1 root 13366: default:
1.1.1.22 root 13367: unimplemented_16h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 13368: break;
13369: }
13370: break;
13371: case 0x17:
13372: // PC BIOS - Printer
1.1.1.22 root 13373: // fatalerror("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 13374: break;
13375: case 0x1a:
13376: // PC BIOS - Timer
1.1.1.3 root 13377: m_CF = 0;
1.1 root 13378: switch(REG8(AH)) {
13379: case 0x00: pcbios_int_1ah_00h(); break;
13380: case 0x01: break;
13381: case 0x02: pcbios_int_1ah_02h(); break;
13382: case 0x03: break;
13383: case 0x04: pcbios_int_1ah_04h(); break;
13384: case 0x05: break;
13385: case 0x0a: pcbios_int_1ah_0ah(); break;
13386: case 0x0b: break;
1.1.1.14 root 13387: case 0x35: break; // Word Perfect Third Party Interface?
13388: case 0x36: break; // Word Perfect Third Party Interface
13389: case 0x70: break; // SNAP? (Simple Network Application Protocol)
1.1 root 13390: default:
1.1.1.22 root 13391: unimplemented_1ah("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 13392: break;
13393: }
13394: break;
1.1.1.33! root 13395: case 0x1b:
! 13396: mem[0x471] = 0x00;
! 13397: break;
1.1 root 13398: case 0x20:
1.1.1.28 root 13399: try {
13400: msdos_process_terminate(SREG(CS), retval, 1);
13401: } catch(...) {
13402: fatalerror("failed to terminate the process (PSP=%04X) by int 20h\n", SREG(CS));
13403: }
1.1 root 13404: break;
13405: case 0x21:
13406: // MS-DOS System Call
1.1.1.3 root 13407: m_CF = 0;
1.1.1.28 root 13408: try {
13409: switch(REG8(AH)) {
13410: case 0x00: msdos_int_21h_00h(); break;
13411: case 0x01: msdos_int_21h_01h(); break;
13412: case 0x02: msdos_int_21h_02h(); break;
13413: case 0x03: msdos_int_21h_03h(); break;
13414: case 0x04: msdos_int_21h_04h(); break;
13415: case 0x05: msdos_int_21h_05h(); break;
13416: case 0x06: msdos_int_21h_06h(); break;
13417: case 0x07: msdos_int_21h_07h(); break;
13418: case 0x08: msdos_int_21h_08h(); break;
13419: case 0x09: msdos_int_21h_09h(); break;
13420: case 0x0a: msdos_int_21h_0ah(); break;
13421: case 0x0b: msdos_int_21h_0bh(); break;
13422: case 0x0c: msdos_int_21h_0ch(); break;
13423: case 0x0d: msdos_int_21h_0dh(); break;
13424: case 0x0e: msdos_int_21h_0eh(); break;
13425: case 0x0f: msdos_int_21h_0fh(); break;
13426: case 0x10: msdos_int_21h_10h(); break;
13427: case 0x11: msdos_int_21h_11h(); break;
13428: case 0x12: msdos_int_21h_12h(); break;
13429: case 0x13: msdos_int_21h_13h(); break;
13430: case 0x14: msdos_int_21h_14h(); break;
13431: case 0x15: msdos_int_21h_15h(); break;
13432: case 0x16: msdos_int_21h_16h(); break;
13433: case 0x17: msdos_int_21h_17h(); break;
13434: case 0x18: msdos_int_21h_18h(); break;
13435: case 0x19: msdos_int_21h_19h(); break;
13436: case 0x1a: msdos_int_21h_1ah(); break;
13437: case 0x1b: msdos_int_21h_1bh(); break;
13438: case 0x1c: msdos_int_21h_1ch(); break;
13439: case 0x1d: msdos_int_21h_1dh(); break;
13440: case 0x1e: msdos_int_21h_1eh(); break;
13441: case 0x1f: msdos_int_21h_1fh(); break;
13442: case 0x20: msdos_int_21h_20h(); break;
13443: case 0x21: msdos_int_21h_21h(); break;
13444: case 0x22: msdos_int_21h_22h(); break;
13445: case 0x23: msdos_int_21h_23h(); break;
13446: case 0x24: msdos_int_21h_24h(); break;
13447: case 0x25: msdos_int_21h_25h(); break;
13448: case 0x26: msdos_int_21h_26h(); break;
13449: case 0x27: msdos_int_21h_27h(); break;
13450: case 0x28: msdos_int_21h_28h(); break;
13451: case 0x29: msdos_int_21h_29h(); break;
13452: case 0x2a: msdos_int_21h_2ah(); break;
13453: case 0x2b: msdos_int_21h_2bh(); break;
13454: case 0x2c: msdos_int_21h_2ch(); break;
13455: case 0x2d: msdos_int_21h_2dh(); break;
13456: case 0x2e: msdos_int_21h_2eh(); break;
13457: case 0x2f: msdos_int_21h_2fh(); break;
13458: case 0x30: msdos_int_21h_30h(); break;
13459: case 0x31: msdos_int_21h_31h(); break;
13460: case 0x32: msdos_int_21h_32h(); break;
13461: case 0x33: msdos_int_21h_33h(); break;
13462: case 0x34: msdos_int_21h_34h(); break;
13463: case 0x35: msdos_int_21h_35h(); break;
13464: case 0x36: msdos_int_21h_36h(); break;
13465: case 0x37: msdos_int_21h_37h(); break;
13466: case 0x38: msdos_int_21h_38h(); break;
13467: case 0x39: msdos_int_21h_39h(0); break;
13468: case 0x3a: msdos_int_21h_3ah(0); break;
13469: case 0x3b: msdos_int_21h_3bh(0); break;
13470: case 0x3c: msdos_int_21h_3ch(); break;
13471: case 0x3d: msdos_int_21h_3dh(); break;
13472: case 0x3e: msdos_int_21h_3eh(); break;
13473: case 0x3f: msdos_int_21h_3fh(); break;
13474: case 0x40: msdos_int_21h_40h(); break;
13475: case 0x41: msdos_int_21h_41h(0); break;
13476: case 0x42: msdos_int_21h_42h(); break;
13477: case 0x43: msdos_int_21h_43h(0); break;
13478: case 0x44: msdos_int_21h_44h(); break;
13479: case 0x45: msdos_int_21h_45h(); break;
13480: case 0x46: msdos_int_21h_46h(); break;
13481: case 0x47: msdos_int_21h_47h(0); break;
13482: case 0x48: msdos_int_21h_48h(); break;
13483: case 0x49: msdos_int_21h_49h(); break;
13484: case 0x4a: msdos_int_21h_4ah(); break;
13485: case 0x4b: msdos_int_21h_4bh(); break;
13486: case 0x4c: msdos_int_21h_4ch(); break;
13487: case 0x4d: msdos_int_21h_4dh(); break;
13488: case 0x4e: msdos_int_21h_4eh(); break;
13489: case 0x4f: msdos_int_21h_4fh(); break;
13490: case 0x50: msdos_int_21h_50h(); break;
13491: case 0x51: msdos_int_21h_51h(); break;
13492: case 0x52: msdos_int_21h_52h(); break;
1.1.1.33! root 13493: // 0x53: Translate BIOS Parameter Block to Drive Param Bock
1.1.1.28 root 13494: case 0x54: msdos_int_21h_54h(); break;
13495: case 0x55: msdos_int_21h_55h(); break;
13496: case 0x56: msdos_int_21h_56h(0); break;
13497: case 0x57: msdos_int_21h_57h(); break;
13498: case 0x58: msdos_int_21h_58h(); break;
13499: case 0x59: msdos_int_21h_59h(); break;
13500: case 0x5a: msdos_int_21h_5ah(); break;
13501: case 0x5b: msdos_int_21h_5bh(); break;
13502: case 0x5c: msdos_int_21h_5ch(); break;
13503: case 0x5d: msdos_int_21h_5dh(); break;
1.1.1.33! root 13504: // 0x5e: MS-Network
1.1.1.30 root 13505: case 0x5f: msdos_int_21h_5fh(); break;
1.1.1.28 root 13506: case 0x60: msdos_int_21h_60h(0); break;
13507: case 0x61: msdos_int_21h_61h(); break;
13508: case 0x62: msdos_int_21h_62h(); break;
13509: case 0x63: msdos_int_21h_63h(); break;
1.1.1.33! root 13510: // 0x64: Set Device Driver Lockahead Flag
1.1.1.28 root 13511: case 0x65: msdos_int_21h_65h(); break;
13512: case 0x66: msdos_int_21h_66h(); break;
13513: case 0x67: msdos_int_21h_67h(); break;
13514: case 0x68: msdos_int_21h_68h(); break;
13515: case 0x69: msdos_int_21h_69h(); break;
13516: case 0x6a: msdos_int_21h_6ah(); break;
13517: case 0x6b: msdos_int_21h_6bh(); break;
13518: case 0x6c: msdos_int_21h_6ch(0); break;
1.1.1.33! root 13519: // 0x6d: Find First ROM Program
! 13520: // 0x6e: Find Next ROM Program
! 13521: // 0x6f: Get/Set ROM Scan Start Address
! 13522: // 0x70: Windows95 - Get/Set Internationalization Information
1.1.1.28 root 13523: case 0x71:
1.1.1.33! root 13524: // Windows95 - Long Filename Functions
1.1.1.28 root 13525: switch(REG8(AL)) {
13526: case 0x0d: msdos_int_21h_710dh(); break;
13527: case 0x39: msdos_int_21h_39h(1); break;
13528: case 0x3a: msdos_int_21h_3ah(1); break;
13529: case 0x3b: msdos_int_21h_3bh(1); break;
13530: case 0x41: msdos_int_21h_7141h(1); break;
13531: case 0x43: msdos_int_21h_43h(1); break;
13532: case 0x47: msdos_int_21h_47h(1); break;
13533: case 0x4e: msdos_int_21h_714eh(); break;
13534: case 0x4f: msdos_int_21h_714fh(); break;
13535: case 0x56: msdos_int_21h_56h(1); break;
13536: case 0x60: msdos_int_21h_60h(1); break;
13537: case 0x6c: msdos_int_21h_6ch(1); break;
13538: case 0xa0: msdos_int_21h_71a0h(); break;
13539: case 0xa1: msdos_int_21h_71a1h(); break;
13540: case 0xa6: msdos_int_21h_71a6h(); break;
13541: case 0xa7: msdos_int_21h_71a7h(); break;
13542: case 0xa8: msdos_int_21h_71a8h(); break;
1.1.1.33! root 13543: // 0xa9: Server Create/Open File
1.1.1.28 root 13544: case 0xaa: msdos_int_21h_71aah(); break;
13545: default:
13546: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
13547: REG16(AX) = 0x7100;
13548: m_CF = 1;
13549: break;
13550: }
13551: break;
13552: // 0x72: Windows95 beta - LFN FindClose
13553: case 0x73:
1.1.1.33! root 13554: // Windows95 - FAT32 Functions
1.1.1.28 root 13555: switch(REG8(AL)) {
13556: case 0x00: msdos_int_21h_7300h(); break;
1.1.1.33! root 13557: // 0x01: Set Drive Locking ???
1.1.1.28 root 13558: case 0x02: msdos_int_21h_7302h(); break;
13559: case 0x03: msdos_int_21h_7303h(); break;
1.1.1.33! root 13560: // 0x04: Set DPB to Use for Formatting
! 13561: // 0x05: Extended Absolute Disk Read/Write
1.1.1.28 root 13562: default:
13563: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
13564: REG16(AX) = 0x7300;
13565: m_CF = 1;
13566: break;
13567: }
1.1 root 13568: break;
1.1.1.30 root 13569: case 0xdb: msdos_int_21h_dbh(); break;
13570: case 0xdc: msdos_int_21h_dch(); break;
1.1 root 13571: default:
1.1.1.22 root 13572: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.28 root 13573: REG16(AX) = 0x01;
1.1.1.3 root 13574: m_CF = 1;
1.1 root 13575: break;
13576: }
1.1.1.28 root 13577: } catch(int error) {
13578: REG16(AX) = error;
13579: m_CF = 1;
13580: } catch(...) {
13581: REG16(AX) = 0x1f; // general failure
1.1.1.3 root 13582: m_CF = 1;
1.1 root 13583: }
1.1.1.3 root 13584: if(m_CF) {
1.1.1.23 root 13585: sda_t *sda = (sda_t *)(mem + SDA_TOP);
13586: sda->extended_error_code = REG16(AX);
13587: switch(sda->extended_error_code) {
13588: case 4: // Too many open files
13589: case 8: // Insufficient memory
13590: sda->error_class = 1; // Out of resource
13591: break;
13592: case 5: // Access denied
13593: sda->error_class = 3; // Authorization
13594: break;
13595: case 7: // Memory control block destroyed
13596: sda->error_class = 4; // Internal
13597: break;
13598: case 2: // File not found
13599: case 3: // Path not found
13600: case 15: // Invaid drive specified
13601: case 18: // No more files
13602: sda->error_class = 8; // Not found
13603: break;
13604: case 32: // Sharing violation
13605: case 33: // Lock violation
13606: sda->error_class = 10; // Locked
13607: break;
13608: // case 16: // Removal of current directory attempted
13609: case 19: // Attempted write on protected disk
13610: case 21: // Drive not ready
13611: // case 29: // Write failure
13612: // case 30: // Read failure
13613: // case 82: // Cannot create subdirectory
13614: sda->error_class = 11; // Media
13615: break;
13616: case 80: // File already exists
13617: sda->error_class = 12; // Already exist
13618: break;
13619: default:
13620: sda->error_class = 13; // Unknown
13621: break;
13622: }
13623: sda->suggested_action = 1; // Retry
13624: sda->locus_of_last_error = 1; // Unknown
1.1 root 13625: }
1.1.1.33! root 13626: if(ctrl_break_checking && ctrl_break_detected) {
1.1.1.26 root 13627: // raise int 23h
13628: #if defined(HAS_I386)
13629: m_ext = 0; // not an external interrupt
13630: i386_trap(0x23, 1, 0);
13631: m_ext = 1;
13632: #else
13633: PREFIX86(_interrupt)(0x23);
13634: #endif
13635: }
1.1 root 13636: break;
13637: case 0x22:
13638: fatalerror("int 22h (terminate address)\n");
13639: case 0x23:
1.1.1.28 root 13640: try {
13641: msdos_process_terminate(current_psp, (retval & 0xff) | 0x100, 1);
13642: } catch(...) {
13643: fatalerror("failed to terminate the current process by int 23h\n");
13644: }
1.1 root 13645: break;
13646: case 0x24:
1.1.1.32 root 13647: /*
1.1.1.28 root 13648: try {
13649: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
13650: } catch(...) {
13651: fatalerror("failed to terminate the current process by int 24h\n");
13652: }
1.1.1.32 root 13653: */
13654: msdos_int_24h();
1.1 root 13655: break;
13656: case 0x25:
13657: msdos_int_25h();
13658: break;
13659: case 0x26:
13660: msdos_int_26h();
13661: break;
13662: case 0x27:
1.1.1.28 root 13663: try {
13664: msdos_int_27h();
13665: } catch(...) {
13666: fatalerror("failed to terminate the process (PSP=%04X) by int 27h\n", SREG(CS));
13667: }
1.1 root 13668: break;
13669: case 0x28:
13670: Sleep(10);
13671: break;
13672: case 0x29:
13673: msdos_int_29h();
13674: break;
13675: case 0x2e:
13676: msdos_int_2eh();
13677: break;
13678: case 0x2f:
13679: // multiplex interrupt
13680: switch(REG8(AH)) {
1.1.1.22 root 13681: case 0x05: msdos_int_2fh_05h(); break;
13682: case 0x11: msdos_int_2fh_11h(); break;
1.1.1.21 root 13683: case 0x12: msdos_int_2fh_12h(); break;
1.1.1.30 root 13684: case 0x13: msdos_int_2fh_13h(); break;
1.1.1.22 root 13685: case 0x14: msdos_int_2fh_14h(); break;
13686: case 0x15: msdos_int_2fh_15h(); break;
1.1 root 13687: case 0x16: msdos_int_2fh_16h(); break;
1.1.1.22 root 13688: case 0x19: msdos_int_2fh_19h(); break;
1.1 root 13689: case 0x1a: msdos_int_2fh_1ah(); break;
1.1.1.30 root 13690: case 0x40: msdos_int_2fh_40h(); break;
1.1 root 13691: case 0x43: msdos_int_2fh_43h(); break;
1.1.1.22 root 13692: case 0x46: msdos_int_2fh_46h(); break;
13693: case 0x48: msdos_int_2fh_48h(); break;
1.1 root 13694: case 0x4a: msdos_int_2fh_4ah(); break;
1.1.1.22 root 13695: case 0x4b: msdos_int_2fh_4bh(); break;
1.1 root 13696: case 0x4f: msdos_int_2fh_4fh(); break;
1.1.1.22 root 13697: case 0x55: msdos_int_2fh_55h(); break;
1.1.1.24 root 13698: case 0xad: msdos_int_2fh_adh(); break;
1.1 root 13699: case 0xae: msdos_int_2fh_aeh(); break;
1.1.1.30 root 13700: // Installation Check
13701: case 0x01: // PRINT.COM
13702: case 0x02: // PC LAN Program Redirector
13703: case 0x06: // ASSIGN
13704: case 0x08: // DRIVER.SYS
13705: case 0x10: // SHARE
13706: case 0x17: // Clibboard functions
13707: case 0x1b: // XMA2EMS.SYS
13708: case 0x23: // DR DOS 5.0 GRAFTABL
13709: case 0x27: // DR-DOR 6.0 TaskMAX
13710: case 0x2e: // Novell DOS 7 GRAFTABL
1.1.1.33! root 13711: case 0x39: // Kingswood TSR INTERFACE
! 13712: case 0x41: // DOS Enhanced LAN Manager 2.0+ MINIPOP/NETPOPUP
1.1.1.30 root 13713: case 0x45: // PROF.COM
13714: case 0x51: // ODIHELP.EXE
1.1.1.33! root 13715: case 0x52: // JAM.SYS v1.10+
1.1.1.30 root 13716: case 0x54: // POWER.EXE
13717: case 0x56: // INTERLNK
1.1.1.33! root 13718: case 0x57: // IOMEGA DRIVERS
1.1.1.30 root 13719: case 0x70: // License Service API
1.1.1.33! root 13720: case 0x72: // SRDISK v1.30+
1.1.1.30 root 13721: case 0x7a: // Novell NetWare
1.1.1.33! root 13722: case 0x7f: // PRINDIR v9.0
! 13723: case 0x80: // FAX BIOS
! 13724: case 0x81: // Nanosoft, Inc. TurboNET redirector
! 13725: case 0x82: // Nanosoft, Inc. CAPDOS
! 13726: case 0x89: // WHOA!.COM
! 13727: case 0x90: // Resident AID
1.1.1.30 root 13728: case 0x94: // MICRO.EXE
1.1.1.33! root 13729: case 0x97: // Micro Focus COBOL v3.1.31
! 13730: case 0x98: // Micro Focus COBOL v3.1.31
! 13731: case 0x99: // DOS Navigator II
! 13732: case 0x9e: // INTMON v2.1
! 13733: case 0x9f: // INTCFG v2.1
! 13734: case 0xa9: // METZTSR.COM
! 13735: case 0xab: // SRSoft MODAL PC v2
1.1.1.30 root 13736: case 0xac: // GRAPHICS.COM
1.1.1.33! root 13737: case 0xaf: // WinDOS v2.11
1.1.1.30 root 13738: case 0xb0: // GRAFTABLE.COM
1.1.1.33! root 13739: case 0xb4: // IBM PC3270 EMULATION PROG v3
! 13740: case 0xb7: // APPEND
1.1.1.30 root 13741: case 0xb8: // NETWORK
13742: case 0xb9: // RECEIVER.COM
13743: case 0xbc: // EGA.SYS
1.1.1.33! root 13744: case 0xbe: // REDVIEW
1.1.1.30 root 13745: case 0xbf: // PC LAN Program - REDIRIFS.EXE
13746: case 0xc0: // Novell LSL.COM
1.1.1.33! root 13747: case 0xc1: // Personal NetWare - STPIPX v1.00
! 13748: case 0xc3: // SETWPR.COM
! 13749: case 0xc5: // PC-DOS Econet v1.05
! 13750: case 0xc7: // COLAP.COM
! 13751: case 0xc9: // ThunderByte???
! 13752: case 0xca: // TBSCANX
! 13753: case 0xcb: // Communicating Applications Specification
! 13754: case 0xcc: // Tsoft NFSDRVR
! 13755: case 0xcd: // SWELL.EXE
! 13756: case 0xcf: // TEMPLEXX 1.0
! 13757: case 0xd0: // Lotus CD/Networker
1.1.1.30 root 13758: case 0xd2: // PCL-838.EXE
1.1.1.33! root 13759: case 0xd3: // TeleReplica
! 13760: case 0xd6: // VEDIT VSWAP
! 13761: case 0xd7: // Banyan VINES v4+
1.1.1.30 root 13762: case 0xd8: // Novell NetWare Lite - CLIENT.EXE
1.1.1.33! root 13763: case 0xda: // ZyXEL ZFAX v1.x
! 13764: case 0xdb: // ZyXEL ZFAX v2+
! 13765: case 0xdc: // GOLD.COM
! 13766: case 0xdd: // MIXFIX.EXE
! 13767: case 0xde: // Novell Netware - RPRINTER, NPRINTER
! 13768: case 0xdf: // HyperWare programs
! 13769: case 0xe0: // SETDRVER.COM v2.10+
! 13770: case 0xe1: // Phantom2 v1.1+
! 13771: case 0xe3: // ANARKEY.COM
! 13772: case 0xed: // Phar Lap DOS EXTENDERS
! 13773: case 0xee: // XVIEW
! 13774: case 0xf0: // 4MAP
! 13775: case 0xf1: // DOS EXTENDER
! 13776: case 0xf2: // WINX
! 13777: case 0xf4: // FINDIRQ.COM
! 13778: case 0xf7: // AUTOPARK.COM
! 13779: case 0xf8: // SuperStor PRO 2XON.COM
! 13780: case 0xfb: // AutoBraille v1.1A
! 13781: case 0xfe: // PC-NFS ???
! 13782: case 0xff: // Topware Network Operating System
1.1.1.30 root 13783: switch(REG8(AL)) {
13784: case 0x00:
13785: // This is not installed
13786: // REG8(AL) = 0x00;
13787: break;
1.1.1.33! root 13788: case 0x01:
! 13789: // Banyan VINES v4+ is not installed
! 13790: if(REG8(AH) == 0xd7 && REG16(BX) == 0x0000) {
! 13791: break;
! 13792: }
1.1.1.30 root 13793: default:
13794: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
13795: REG16(AX) = 0x01;
13796: m_CF = 1;
13797: break;
13798: }
13799: break;
1.1.1.22 root 13800: default:
13801: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
13802: break;
1.1 root 13803: }
13804: break;
1.1.1.24 root 13805: case 0x33:
13806: switch(REG8(AH)) {
13807: case 0x00:
13808: // Mouse
13809: switch(REG8(AL)) {
13810: case 0x00: msdos_int_33h_0000h(); break;
13811: case 0x01: msdos_int_33h_0001h(); break;
13812: case 0x02: msdos_int_33h_0002h(); break;
13813: case 0x03: msdos_int_33h_0003h(); break;
13814: case 0x04: break; // position mouse cursor
13815: case 0x05: msdos_int_33h_0005h(); break;
13816: case 0x06: msdos_int_33h_0006h(); break;
13817: case 0x07: msdos_int_33h_0007h(); break;
13818: case 0x08: msdos_int_33h_0008h(); break;
13819: case 0x09: msdos_int_33h_0009h(); break;
13820: case 0x0a: break; // define text cursor
13821: case 0x0b: msdos_int_33h_000bh(); break;
13822: case 0x0c: msdos_int_33h_000ch(); break;
13823: case 0x0d: break; // light pen emulation on
13824: case 0x0e: break; // light pen emulation off
13825: case 0x0f: msdos_int_33h_000fh(); break;
13826: case 0x10: break; // define screen region for updating
13827: case 0x11: msdos_int_33h_0011h(); break;
13828: case 0x12: REG16(AX) = 0xffff; break; // set large graphics cursor block
13829: case 0x13: break; // define double-speed threshold
13830: case 0x14: msdos_int_33h_0014h(); break;
13831: case 0x15: msdos_int_33h_0015h(); break;
13832: case 0x16: msdos_int_33h_0016h(); break;
13833: case 0x17: msdos_int_33h_0017h(); break;
13834: case 0x1a: msdos_int_33h_001ah(); break;
13835: case 0x1b: msdos_int_33h_001bh(); break;
13836: case 0x1d: msdos_int_33h_001dh(); break;
13837: case 0x1e: msdos_int_33h_001eh(); break;
13838: case 0x21: msdos_int_33h_0021h(); break;
13839: case 0x22: msdos_int_33h_0022h(); break;
13840: case 0x23: msdos_int_33h_0023h(); break;
13841: case 0x24: msdos_int_33h_0024h(); break;
13842: case 0x26: msdos_int_33h_0026h(); break;
13843: case 0x2a: msdos_int_33h_002ah(); break;
13844: case 0x2f: break; // mouse hardware reset
13845: case 0x31: msdos_int_33h_0031h(); break;
13846: case 0x32: msdos_int_33h_0032h(); break;
13847: default:
13848: unimplemented_33h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
13849: break;
13850: }
13851: break;
13852: default:
13853: unimplemented_33h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
13854: break;
13855: }
13856: break;
1.1.1.19 root 13857: case 0x68:
13858: // dummy interrupt for EMS (int 67h)
13859: switch(REG8(AH)) {
13860: case 0x40: msdos_int_67h_40h(); break;
13861: case 0x41: msdos_int_67h_41h(); break;
13862: case 0x42: msdos_int_67h_42h(); break;
13863: case 0x43: msdos_int_67h_43h(); break;
13864: case 0x44: msdos_int_67h_44h(); break;
13865: case 0x45: msdos_int_67h_45h(); break;
13866: case 0x46: msdos_int_67h_46h(); break;
13867: case 0x47: msdos_int_67h_47h(); break;
13868: case 0x48: msdos_int_67h_48h(); break;
1.1.1.20 root 13869: // 0x49: LIM EMS - Reserved - Get I/O Port Address (Undocumented in EMS 3.2)
13870: // 0x4a: LIM EMS - Reserved - Get Translation Array (Undocumented in EMS 3.2)
1.1.1.19 root 13871: case 0x4b: msdos_int_67h_4bh(); break;
13872: case 0x4c: msdos_int_67h_4ch(); break;
13873: case 0x4d: msdos_int_67h_4dh(); break;
1.1.1.20 root 13874: case 0x4e: msdos_int_67h_4eh(); break;
1.1.1.21 root 13875: case 0x4f: msdos_int_67h_4fh(); break;
1.1.1.20 root 13876: case 0x50: msdos_int_67h_50h(); break;
1.1.1.19 root 13877: case 0x51: msdos_int_67h_51h(); break;
1.1.1.20 root 13878: case 0x52: msdos_int_67h_52h(); break;
1.1.1.19 root 13879: case 0x53: msdos_int_67h_53h(); break;
13880: case 0x54: msdos_int_67h_54h(); break;
1.1.1.20 root 13881: // 0x55: LIM EMS 4.0 - Alter Page Map And JUMP
13882: // 0x56: LIM EMS 4.0 - Alter Page Map And CALL
13883: case 0x57: msdos_int_67h_57h(); break;
13884: case 0x58: msdos_int_67h_58h(); break;
13885: // 0x59: LIM EMS 4.0 - Get Expanded Memory Hardware Information (for DOS Kernel)
13886: case 0x5a: msdos_int_67h_5ah(); break;
13887: // 0x5b: LIM EMS 4.0 - Alternate Map Register Set (for DOS Kernel)
13888: // 0x5c: LIM EMS 4.0 - Prepate Expanded Memory Hardware For Warm Boot
13889: // 0x5d: LIM EMS 4.0 - Enable/Disable OS Function Set Functions (for DOS Kernel)
1.1.1.31 root 13890: // 0x60: EEMS - Get Physical Window Array
13891: // 0x61: EEMS - Generic Accelerator Card Support
13892: // 0x68: EEMS - Get Address of All Pge Frames om System
13893: // 0x69: EEMS - Map Page into Frame
13894: // 0x6a: EEMS - Page Mapping
13895: // 0xde: VCPI
1.1.1.30 root 13896: case 0xde: msdos_int_67h_deh(); break;
1.1.1.19 root 13897: default:
1.1.1.22 root 13898: unimplemented_67h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1.1.19 root 13899: REG8(AH) = 0x84;
13900: break;
13901: }
13902: break;
13903: #ifdef SUPPORT_XMS
13904: case 0x69:
13905: // dummy interrupt for XMS (call far)
1.1.1.28 root 13906: try {
13907: switch(REG8(AH)) {
13908: case 0x00: msdos_call_xms_00h(); break;
13909: case 0x01: msdos_call_xms_01h(); break;
13910: case 0x02: msdos_call_xms_02h(); break;
13911: case 0x03: msdos_call_xms_03h(); break;
13912: case 0x04: msdos_call_xms_04h(); break;
13913: case 0x05: msdos_call_xms_05h(); break;
13914: case 0x06: msdos_call_xms_06h(); break;
13915: case 0x07: msdos_call_xms_07h(); break;
13916: case 0x08: msdos_call_xms_08h(); break;
13917: case 0x09: msdos_call_xms_09h(); break;
13918: case 0x0a: msdos_call_xms_0ah(); break;
13919: case 0x0b: msdos_call_xms_0bh(); break;
13920: case 0x0c: msdos_call_xms_0ch(); break;
13921: case 0x0d: msdos_call_xms_0dh(); break;
13922: case 0x0e: msdos_call_xms_0eh(); break;
13923: case 0x0f: msdos_call_xms_0fh(); break;
13924: case 0x10: msdos_call_xms_10h(); break;
13925: case 0x11: msdos_call_xms_11h(); break;
13926: case 0x12: msdos_call_xms_12h(); break;
1.1.1.29 root 13927: #if defined(HAS_I386)
13928: case 0x88: msdos_call_xms_88h(); break;
13929: case 0x89: msdos_call_xms_89h(); break;
13930: case 0x8e: msdos_call_xms_8eh(); break;
13931: case 0x8f: msdos_call_xms_8fh(); break;
13932: #endif
1.1.1.28 root 13933: default:
13934: unimplemented_xms("call XMS (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
13935: REG16(AX) = 0x0000;
13936: REG8(BL) = 0x80; // function not implemented
13937: break;
13938: }
13939: } catch(...) {
1.1.1.19 root 13940: REG16(AX) = 0x0000;
1.1.1.28 root 13941: REG8(BL) = 0x8f; // unrecoverable driver error
1.1.1.19 root 13942: }
13943: break;
13944: #endif
13945: case 0x6a:
1.1.1.24 root 13946: // irq12 (mouse)
13947: mouse_push_ax = REG16(AX);
13948: mouse_push_bx = REG16(BX);
13949: mouse_push_cx = REG16(CX);
13950: mouse_push_dx = REG16(DX);
13951: mouse_push_si = REG16(SI);
13952: mouse_push_di = REG16(DI);
13953:
13954: if(mouse.active && mouse.call_addr.dw != 0) {
13955: REG16(AX) = mouse.status_irq;
13956: REG16(BX) = mouse.get_buttons();
13957: REG16(CX) = max(mouse.min_position.x, min(mouse.max_position.x, mouse.position.x));
13958: REG16(DX) = max(mouse.min_position.y, min(mouse.max_position.y, mouse.position.y));
13959: REG16(SI) = REG16(CX) * mouse.mickey.x / 8;
13960: REG16(DI) = REG16(DX) * mouse.mickey.y / 8;
13961:
13962: mem[0xfffd0 + 0x02] = 0x9a; // call far
13963: mem[0xfffd0 + 0x03] = mouse.call_addr.w.l & 0xff;
13964: mem[0xfffd0 + 0x04] = mouse.call_addr.w.l >> 8;
13965: mem[0xfffd0 + 0x05] = mouse.call_addr.w.h & 0xff;
13966: mem[0xfffd0 + 0x06] = mouse.call_addr.w.h >> 8;
13967: } else {
13968: mem[0xfffd0 + 0x02] = 0x90; // nop
13969: mem[0xfffd0 + 0x03] = 0x90; // nop
13970: mem[0xfffd0 + 0x04] = 0x90; // nop
13971: mem[0xfffd0 + 0x05] = 0x90; // nop
13972: mem[0xfffd0 + 0x06] = 0x90; // nop
13973: }
13974: break;
13975: case 0x6b:
13976: // end of irq12 (mouse)
13977: REG16(AX) = mouse_push_ax;
13978: REG16(BX) = mouse_push_bx;
13979: REG16(CX) = mouse_push_cx;
13980: REG16(DX) = mouse_push_dx;
13981: REG16(SI) = mouse_push_si;
13982: REG16(DI) = mouse_push_di;
13983:
13984: // EOI
13985: if((pic[1].isr &= ~(1 << 4)) == 0) {
13986: pic[0].isr &= ~(1 << 2); // master
13987: }
13988: pic_update();
13989: break;
13990: case 0x6c:
1.1.1.19 root 13991: // dummy interrupt for case map routine pointed in the country info
13992: if(REG8(AL) >= 0x80) {
13993: char tmp[2] = {0};
13994: tmp[0] = REG8(AL);
13995: my_strupr(tmp);
13996: REG8(AL) = tmp[0];
13997: }
13998: break;
1.1.1.27 root 13999: case 0x6d:
14000: // dummy interrupt for font read routine pointed by int 15h, ax=5000h
14001: REG8(AL) = 0x86; // not supported
14002: m_CF = 1;
14003: break;
1.1.1.32 root 14004: case 0x6e:
14005: // dummy interrupt for parameter error message read routine pointed by int 2fh, ax=122eh, dl=08h
14006: {
14007: UINT16 code = REG16(AX);
14008: if(code & 0xf0) {
14009: code = (code & 7) | ((code & 0x10) >> 1);
14010: }
14011: for(int i = 0; i < array_length(param_error_table); i++) {
14012: if(param_error_table[i].code == code || param_error_table[i].code == (UINT16)-1) {
14013: const char *message = NULL;
14014: if(active_code_page == 932) {
14015: message = param_error_table[i].message_japanese;
14016: }
14017: if(message == NULL) {
14018: message = param_error_table[i].message_english;
14019: }
14020: *(UINT8 *)(mem + WORK_TOP) = strlen(message);
14021: strcpy((char *)(mem + WORK_TOP + 1), message);
14022:
14023: SREG(ES) = WORK_TOP >> 4;
14024: i386_load_segment_descriptor(ES);
14025: REG16(DI) = 0x0000;
14026: break;
14027: }
14028: }
14029: }
14030: break;
1.1.1.8 root 14031: case 0x70:
14032: case 0x71:
14033: case 0x72:
14034: case 0x73:
14035: case 0x74:
14036: case 0x75:
14037: case 0x76:
14038: case 0x77:
14039: // EOI
14040: if((pic[1].isr &= ~(1 << (num - 0x70))) == 0) {
14041: pic[0].isr &= ~(1 << 2); // master
14042: }
14043: pic_update();
14044: break;
1.1 root 14045: default:
1.1.1.22 root 14046: // fatalerror("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 14047: break;
14048: }
14049:
14050: // update cursor position
14051: if(cursor_moved) {
14052: CONSOLE_SCREEN_BUFFER_INFO csbi;
1.1.1.23 root 14053: GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
1.1.1.15 root 14054: if(!restore_console_on_exit) {
14055: scr_top = csbi.srWindow.Top;
14056: }
1.1 root 14057: mem[0x450 + mem[0x462] * 2] = csbi.dwCursorPosition.X;
1.1.1.14 root 14058: mem[0x451 + mem[0x462] * 2] = csbi.dwCursorPosition.Y - scr_top;
1.1 root 14059: cursor_moved = false;
14060: }
14061: }
14062:
14063: // init
14064:
14065: int msdos_init(int argc, char *argv[], char *envp[], int standard_env)
14066: {
14067: // init file handler
14068: memset(file_handler, 0, sizeof(file_handler));
14069: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
14070: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
14071: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
1.1.1.21 root 14072: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 14073: if(_open("stdaux.txt", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
1.1.1.21 root 14074: #else
14075: if(_open("NUL", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
14076: #endif
14077: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
1.1 root 14078: }
1.1.1.21 root 14079: #ifdef MAP_PRN_DEVICE_TO_FILE
1.1 root 14080: if(_open("stdprn.txt", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
1.1.1.21 root 14081: #else
14082: if(_open("NUL", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
1.1 root 14083: #endif
1.1.1.21 root 14084: msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0);
14085: }
1.1 root 14086: _dup2(0, DUP_STDIN);
14087: _dup2(1, DUP_STDOUT);
14088: _dup2(2, DUP_STDERR);
1.1.1.21 root 14089: _dup2(3, DUP_STDAUX);
14090: _dup2(4, DUP_STDPRN);
1.1 root 14091:
1.1.1.24 root 14092: // init mouse
14093: memset(&mouse, 0, sizeof(mouse));
14094: mouse.max_position.x = 8 * scr_width - 1;
14095: mouse.max_position.y = 8 * scr_height - 1;
14096: mouse.mickey.x = 8;
14097: mouse.mickey.y = 16;
14098:
1.1.1.26 root 14099: #ifdef SUPPORT_XMS
14100: // init xms
14101: msdos_xms_init();
14102: #endif
14103:
1.1 root 14104: // init process
14105: memset(process, 0, sizeof(process));
14106:
1.1.1.13 root 14107: // init dtainfo
14108: msdos_dta_info_init();
14109:
1.1 root 14110: // init memory
14111: memset(mem, 0, sizeof(mem));
14112:
14113: // bios data area
1.1.1.23 root 14114: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 14115: CONSOLE_SCREEN_BUFFER_INFO csbi;
14116: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 14117: CONSOLE_FONT_INFO cfi;
14118: GetCurrentConsoleFont(hStdout, FALSE, &cfi);
14119:
14120: int regen = min(scr_width * scr_height * 2, 0x8000);
14121: text_vram_top_address = TEXT_VRAM_TOP;
14122: text_vram_end_address = text_vram_top_address + regen;
14123: shadow_buffer_top_address = SHADOW_BUF_TOP;
14124: shadow_buffer_end_address = shadow_buffer_top_address + regen;
14125:
14126: if(regen > 0x4000) {
14127: regen = 0x8000;
14128: vram_pages = 1;
14129: } else if(regen > 0x2000) {
14130: regen = 0x4000;
14131: vram_pages = 2;
14132: } else if(regen > 0x1000) {
14133: regen = 0x2000;
14134: vram_pages = 4;
14135: } else {
14136: regen = 0x1000;
14137: vram_pages = 8;
14138: }
1.1 root 14139:
1.1.1.25 root 14140: *(UINT16 *)(mem + 0x400) = 0x3f8; // com1 port address
14141: *(UINT16 *)(mem + 0x402) = 0x2f8; // com2 port address
1.1.1.29 root 14142: *(UINT16 *)(mem + 0x404) = 0x3e8; // com3 port address
14143: *(UINT16 *)(mem + 0x406) = 0x2e8; // com4 port address
1.1.1.25 root 14144: *(UINT16 *)(mem + 0x408) = 0x378; // lpt1 port address
1.1.1.26 root 14145: // *(UINT16 *)(mem + 0x40a) = 0x278; // lpt2 port address
1.1.1.25 root 14146: // *(UINT16 *)(mem + 0x40c) = 0x3bc; // lpt3 port address
1.1.1.32 root 14147: #ifdef EXT_BIOS_TOP
1.1.1.25 root 14148: *(UINT16 *)(mem + 0x40e) = EXT_BIOS_TOP >> 4;
1.1.1.32 root 14149: #endif
1.1.1.26 root 14150: *(UINT16 *)(mem + 0x410) = msdos_get_equipment();
1.1.1.33! root 14151: *(UINT16 *)(mem + 0x413) = MEMORY_END >> 10;
1.1 root 14152: *(UINT8 *)(mem + 0x449) = 0x03;//0x73;
1.1.1.14 root 14153: *(UINT16 *)(mem + 0x44a) = csbi.dwSize.X;
14154: *(UINT16 *)(mem + 0x44c) = regen;
1.1 root 14155: *(UINT16 *)(mem + 0x44e) = 0;
14156: *(UINT8 *)(mem + 0x450) = csbi.dwCursorPosition.X;
1.1.1.14 root 14157: *(UINT8 *)(mem + 0x451) = csbi.dwCursorPosition.Y - scr_top;
1.1 root 14158: *(UINT8 *)(mem + 0x460) = 7;
14159: *(UINT8 *)(mem + 0x461) = 7;
14160: *(UINT8 *)(mem + 0x462) = 0;
14161: *(UINT16 *)(mem + 0x463) = 0x3d4;
1.1.1.19 root 14162: *(UINT8 *)(mem + 0x465) = 0x09;
14163: *(UINT32 *)(mem + 0x46c) = get_ticks_since_midnight(timeGetTime());
1.1.1.14 root 14164: *(UINT8 *)(mem + 0x484) = csbi.srWindow.Bottom - csbi.srWindow.Top;
14165: *(UINT8 *)(mem + 0x485) = cfi.dwFontSize.Y;
14166: *(UINT8 *)(mem + 0x487) = 0x60;
14167: *(UINT8 *)(mem + 0x496) = 0x10; // enhanced keyboard installed
1.1.1.32 root 14168: #ifdef EXT_BIOS_TOP
1.1.1.25 root 14169: *(UINT16 *)(mem + EXT_BIOS_TOP) = 1;
1.1.1.32 root 14170: #endif
1.1.1.14 root 14171:
14172: // initial screen
14173: SMALL_RECT rect;
14174: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
14175: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
14176: for(int y = 0, ofs1 = TEXT_VRAM_TOP, ofs2 = SHADOW_BUF_TOP; y < scr_height; y++) {
14177: for(int x = 0; x < scr_width; x++) {
14178: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Char.AsciiChar;
14179: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Attributes;
14180: }
14181: }
1.1 root 14182:
1.1.1.19 root 14183: // init mcb
1.1 root 14184: int seg = MEMORY_TOP >> 4;
1.1.1.19 root 14185:
14186: // iret table
14187: // note: int 2eh vector should address the routine in command.com,
14188: // and some softwares invite (int 2eh vector segment) - 1 must address the mcb of command.com.
14189: // so move iret table into allocated memory block
14190: // http://www5c.biglobe.ne.jp/~ecb/assembler2/2_6.html
1.1.1.33! root 14191: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, IRET_SIZE >> 4);
1.1.1.19 root 14192: IRET_TOP = seg << 4;
14193: seg += IRET_SIZE >> 4;
1.1.1.25 root 14194: memset(mem + IRET_TOP, 0xcf, IRET_SIZE); // iret
1.1.1.19 root 14195:
14196: // dummy xms/ems device
1.1.1.33! root 14197: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, XMS_SIZE >> 4);
1.1.1.19 root 14198: XMS_TOP = seg << 4;
14199: seg += XMS_SIZE >> 4;
14200:
14201: // environment
1.1.1.33! root 14202: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, ENV_SIZE >> 4);
1.1 root 14203: int env_seg = seg;
14204: int ofs = 0;
1.1.1.32 root 14205: char env_append[ENV_SIZE] = {0}, append_added = 0;
14206: char comspec_added = 0;
1.1.1.33! root 14207: char lastdrive_added = 0;
1.1.1.32 root 14208: char env_msdos_path[ENV_SIZE] = {0};
14209: char env_path[ENV_SIZE] = {0}, path_added = 0;
1.1.1.33! root 14210: char prompt_added = 0;
1.1.1.32 root 14211: char env_temp[ENV_SIZE] = {0}, temp_added = 0, tmp_added = 0;
1.1.1.33! root 14212: char tz_added = 0;
1.1.1.32 root 14213: char *path, *short_path;
14214:
14215: if((path = getenv("MSDOS_APPEND")) != NULL) {
14216: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
14217: strcpy(env_append, short_path);
14218: }
14219: }
14220: if((path = getenv("APPEND")) != NULL) {
14221: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
14222: if(env_append[0] != '\0') {
14223: strcat(env_append, ";");
14224: }
14225: strcat(env_append, short_path);
14226: }
14227: }
14228:
14229: if((path = msdos_search_command_com(argv[0], env_path)) != NULL) {
14230: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
14231: strcpy(comspec_path, short_path);
14232: }
14233: }
14234: if((path = getenv("MSDOS_COMSPEC")) != NULL && _access(path, 0) == 0) {
14235: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
14236: strcpy(comspec_path, short_path);
14237: }
14238: }
1.1 root 14239:
1.1.1.28 root 14240: if((path = getenv("MSDOS_PATH")) != NULL) {
1.1.1.32 root 14241: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
14242: strcpy(env_msdos_path, short_path);
14243: strcpy(env_path, short_path);
1.1.1.14 root 14244: }
14245: }
1.1.1.28 root 14246: if((path = getenv("PATH")) != NULL) {
1.1.1.32 root 14247: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
14248: if(env_path[0] != '\0') {
14249: strcat(env_path, ";");
14250: }
14251: strcat(env_path, short_path);
1.1.1.9 root 14252: }
14253: }
1.1.1.32 root 14254:
14255: if(GetTempPath(ENV_SIZE, env_temp) != 0) {
14256: strcpy(env_temp, msdos_get_multiple_short_path(env_temp));
1.1.1.15 root 14257: }
1.1.1.32 root 14258: for(int i = 0; i < 4; i++) {
14259: static const char *name[4] = {"MSDOS_TEMP", "MSDOS_TMP", "TEMP", "TMP"};
14260: if((path = getenv(name[i])) != NULL && _access(path, 0) == 0) {
14261: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
14262: strcpy(env_temp, short_path);
14263: break;
14264: }
14265: }
1.1.1.24 root 14266: }
1.1.1.32 root 14267:
1.1.1.9 root 14268: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1 root 14269: // lower to upper
1.1.1.28 root 14270: char tmp[ENV_SIZE], name[ENV_SIZE];
1.1 root 14271: strcpy(tmp, *p);
14272: for(int i = 0;; i++) {
14273: if(tmp[i] == '=') {
14274: tmp[i] = '\0';
14275: sprintf(name, ";%s;", tmp);
1.1.1.25 root 14276: my_strupr(name);
1.1 root 14277: tmp[i] = '=';
14278: break;
14279: } else if(tmp[i] >= 'a' && tmp[i] <= 'z') {
1.1.1.28 root 14280: tmp[i] = (tmp[i] - 'a') + 'A';
1.1 root 14281: }
14282: }
1.1.1.33! root 14283: if(strstr(";MSDOS_APPEND;MSDOS_COMSPEC;MSDOS_LASTDRIVE;MSDOS_TEMP;MSDOS_TMP;MSDOS_TZ;", name) != NULL) {
! 14284: // ignore MSDOS_(APPEND/COMSPEC/LASTDRIVE/TEMP/TMP/TZ)
! 14285: } else if(standard_env && strstr(";APPEND;COMSPEC;LASTDRIVE;MSDOS_PATH;PATH;PROMPT;TEMP;TMP;TZ;", name) == NULL) {
1.1.1.18 root 14286: // ignore non standard environments
14287: } else {
1.1.1.33! root 14288: if(strncmp(tmp, "APPEND=", 7) == 0) {
1.1.1.32 root 14289: if(env_append[0] != '\0') {
14290: sprintf(tmp, "APPEND=%s", env_append);
14291: } else {
14292: sprintf(tmp, "APPEND=%s", msdos_get_multiple_short_path(tmp + 7));
14293: }
14294: append_added = 1;
14295: } else if(strncmp(tmp, "COMSPEC=", 8) == 0) {
1.1.1.14 root 14296: strcpy(tmp, "COMSPEC=C:\\COMMAND.COM");
1.1.1.32 root 14297: comspec_added = 1;
1.1.1.33! root 14298: } else if(strncmp(tmp, "LASTDRIVE=", 10) == 0) {
! 14299: char *env = getenv("MSDOS_LASTDRIVE");
! 14300: if(env != NULL) {
! 14301: sprintf(tmp, "LASTDRIVE=%s", env);
! 14302: }
! 14303: lastdrive_added = 1;
! 14304: } else if(strncmp(tmp, "MSDOS_PATH=", 11) == 0) {
1.1.1.28 root 14305: if(env_msdos_path[0] != '\0') {
14306: sprintf(tmp, "MSDOS_PATH=%s", env_msdos_path);
14307: } else {
14308: sprintf(tmp, "MSDOS_PATH=%s", msdos_get_multiple_short_path(tmp + 11));
14309: }
1.1.1.33! root 14310: } else if(strncmp(tmp, "PATH=", 5) == 0) {
1.1.1.28 root 14311: if(env_path[0] != '\0') {
14312: sprintf(tmp, "PATH=%s", env_path);
14313: } else {
14314: sprintf(tmp, "PATH=%s", msdos_get_multiple_short_path(tmp + 5));
14315: }
1.1.1.32 root 14316: path_added = 1;
1.1.1.33! root 14317: } else if(strncmp(tmp, "PROMPT=", 7) == 0) {
! 14318: prompt_added = 1;
1.1.1.28 root 14319: } else if(strncmp(tmp, "TEMP=", 5) == 0) {
14320: if(env_temp[0] != '\0') {
14321: sprintf(tmp, "TEMP=%s", env_temp);
14322: } else {
14323: sprintf(tmp, "TEMP=%s", msdos_get_multiple_short_path(tmp + 5));
14324: }
1.1.1.32 root 14325: temp_added = 1;
1.1.1.33! root 14326: } else if(strncmp(tmp, "TMP=", 4) == 0) {
1.1.1.28 root 14327: if(env_temp[0] != '\0') {
14328: sprintf(tmp, "TMP=%s", env_temp);
14329: } else {
14330: sprintf(tmp, "TMP=%s", msdos_get_multiple_short_path(tmp + 4));
1.1 root 14331: }
1.1.1.32 root 14332: tmp_added = 1;
1.1.1.33! root 14333: } else if(strncmp(tmp, "TZ=", 3) == 0) {
! 14334: char *env = getenv("MSDOS_TZ");
! 14335: if(env != NULL) {
! 14336: sprintf(tmp, "TZ=%s", env);
! 14337: }
! 14338: tz_added = 1;
1.1 root 14339: }
14340: int len = strlen(tmp);
1.1.1.14 root 14341: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) {
1.1 root 14342: fatalerror("too many environments\n");
14343: }
14344: memcpy(mem + (seg << 4) + ofs, tmp, len);
14345: ofs += len + 1;
14346: }
14347: }
1.1.1.32 root 14348: if(!append_added && env_append[0] != '\0') {
14349: #define SET_ENV(name, value) { \
14350: char tmp[ENV_SIZE]; \
14351: sprintf(tmp, "%s=%s", name, value); \
14352: int len = strlen(tmp); \
14353: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) { \
14354: fatalerror("too many environments\n"); \
14355: } \
14356: memcpy(mem + (seg << 4) + ofs, tmp, len); \
14357: ofs += len + 1; \
14358: }
14359: SET_ENV("APPEND", env_append);
14360: }
14361: if(!comspec_added) {
14362: SET_ENV("COMSPEC", "C:\\COMMAND.COM");
14363: }
1.1.1.33! root 14364: if(!lastdrive_added) {
! 14365: SET_ENV("LASTDRIVE", "Z");
! 14366: }
1.1.1.32 root 14367: if(!path_added) {
14368: SET_ENV("PATH", env_path);
14369: }
1.1.1.33! root 14370: if(!prompt_added) {
! 14371: SET_ENV("PROMPT", "$P$G");
! 14372: }
1.1.1.32 root 14373: if(!temp_added) {
14374: SET_ENV("TEMP", env_temp);
14375: }
14376: if(!tmp_added) {
14377: SET_ENV("TMP", env_temp);
14378: }
1.1.1.33! root 14379: if(!tz_added) {
! 14380: TIME_ZONE_INFORMATION tzi;
! 14381: HKEY hKey, hSubKey;
! 14382: char tzi_std_name[64];
! 14383: char tz_std[8] = "GMT";
! 14384: char tz_dlt[8] = "GST";
! 14385: char tz_value[32];
! 14386:
! 14387: // timezone name from GetTimeZoneInformation may not be english
! 14388: bool daylight = (GetTimeZoneInformation(&tzi) != TIME_ZONE_ID_UNKNOWN);
! 14389: setlocale(LC_CTYPE, "");
! 14390: wcstombs(tzi_std_name, tzi.StandardName, sizeof(tzi_std_name));
! 14391:
! 14392: // get english timezone name from registry
! 14393: if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones", 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
! 14394: for(DWORD i = 0; !tz_added; i++) {
! 14395: char reg_name[256], sub_key[1024], std_name[256];
! 14396: DWORD size;
! 14397: FILETIME ftTime;
! 14398: LONG result = RegEnumKeyEx(hKey, i, reg_name, &(size = array_length(reg_name)), NULL, NULL, NULL, &ftTime);
! 14399:
! 14400: if(result == ERROR_SUCCESS) {
! 14401: sprintf(sub_key, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\%s", reg_name);
! 14402: if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, sub_key, 0, KEY_QUERY_VALUE, &hSubKey) == ERROR_SUCCESS) {
! 14403: if(RegQueryValueEx(hSubKey, "Std", NULL, NULL, (LPBYTE)std_name, &(size = array_length(std_name))) == ERROR_SUCCESS) {
! 14404: // search english timezone name from table
! 14405: if (strcmp(std_name, tzi_std_name) == 0) {
! 14406: for(int j = 0; j < array_length(tz_table); j++) {
! 14407: if(strcmp(reg_name, tz_table[j].name) == 0 && (tz_table[j].lcid == 0 || tz_table[j].lcid == GetUserDefaultLCID())) {
! 14408: if(tz_table[j].std != NULL) {
! 14409: strcpy(tz_std, tz_table[j].std);
! 14410: }
! 14411: if(tz_table[j].dlt != NULL) {
! 14412: strcpy(tz_dlt, tz_table[j].dlt);
! 14413: }
! 14414: tz_added = 1;
! 14415: break;
! 14416: }
! 14417: }
! 14418: }
! 14419: }
! 14420: RegCloseKey(hSubKey);
! 14421: }
! 14422: } else if(result == ERROR_NO_MORE_ITEMS) {
! 14423: break;
! 14424: }
! 14425: }
! 14426: RegCloseKey(hKey);
! 14427: }
! 14428: if((tzi.Bias % 60) != 0) {
! 14429: sprintf(tz_value, "%s%d:%2d", tz_std, tzi.Bias / 60, abs(tzi.Bias % 60));
! 14430: } else {
! 14431: sprintf(tz_value, "%s%d", tz_std, tzi.Bias / 60);
! 14432: }
! 14433: if(daylight) {
! 14434: strcat(tz_value, tz_dlt);
! 14435: }
! 14436: SET_ENV("TZ", tz_value);
! 14437: }
1.1 root 14438: seg += (ENV_SIZE >> 4);
14439:
14440: // psp
1.1.1.33! root 14441: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, PSP_SIZE >> 4);
1.1 root 14442: current_psp = seg;
1.1.1.14 root 14443: msdos_psp_create(seg, seg + (PSP_SIZE >> 4), -1, env_seg);
1.1 root 14444: seg += (PSP_SIZE >> 4);
14445:
1.1.1.19 root 14446: // first free mcb in conventional memory
1.1.1.33! root 14447: msdos_mcb_create(seg, 'M', 0, (MEMORY_END >> 4) - seg - 2);
1.1.1.8 root 14448: first_mcb = seg;
14449:
1.1.1.19 root 14450: // dummy mcb to link to umb
1.1.1.33! root 14451: #if 0
! 14452: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', PSP_SYSTEM, (UMB_TOP >> 4) - (MEMORY_END >> 4)); // link umb
! 14453: #else
! 14454: msdos_mcb_create((MEMORY_END >> 4) - 1, 'Z', PSP_SYSTEM, 0); // unlink umb
! 14455: #endif
1.1.1.19 root 14456:
14457: // first free mcb in upper memory block
1.1.1.8 root 14458: msdos_mcb_create(UMB_TOP >> 4, 'Z', 0, (UMB_END >> 4) - (UMB_TOP >> 4) - 1);
1.1 root 14459:
1.1.1.29 root 14460: #ifdef SUPPORT_HMA
14461: // first free mcb in high memory area
14462: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
14463: #endif
14464:
1.1.1.26 root 14465: // interrupt vector
14466: for(int i = 0; i < 0x80; i++) {
14467: *(UINT16 *)(mem + 4 * i + 0) = i;
14468: *(UINT16 *)(mem + 4 * i + 2) = (IRET_TOP >> 4);
14469: }
1.1.1.32 root 14470: *(UINT16 *)(mem + 4 * 0x08 + 0) = 0x0019; // fffd:0019 irq0 (system timer)
1.1.1.26 root 14471: *(UINT16 *)(mem + 4 * 0x08 + 2) = 0xfffd;
14472: *(UINT16 *)(mem + 4 * 0x22 + 0) = 0x0000; // ffff:0000 boot
14473: *(UINT16 *)(mem + 4 * 0x22 + 2) = 0xffff;
14474: *(UINT16 *)(mem + 4 * 0x67 + 0) = 0x0012; // xxxx:0012 ems
14475: *(UINT16 *)(mem + 4 * 0x67 + 2) = XMS_TOP >> 4;
14476: *(UINT16 *)(mem + 4 * 0x74 + 0) = 0x0000; // fffd:0000 irq12 (mouse)
14477: *(UINT16 *)(mem + 4 * 0x74 + 2) = 0xfffd;
14478:
1.1.1.29 root 14479: // dummy devices (NUL -> CON -> ... -> CONFIG$ -> EMMXXXX0)
1.1.1.26 root 14480: static const struct {
14481: UINT16 attributes;
14482: char *dev_name;
14483: } dummy_devices[] = {
14484: {0x8013, "CON "},
14485: {0x8000, "AUX "},
14486: {0xa0c0, "PRN "},
14487: {0x8008, "CLOCK$ "},
14488: {0x8000, "COM1 "},
14489: {0xa0c0, "LPT1 "},
14490: {0xa0c0, "LPT2 "},
14491: {0xa0c0, "LPT3 "},
14492: {0x8000, "COM2 "},
14493: {0x8000, "COM3 "},
14494: {0x8000, "COM4 "},
1.1.1.30 root 14495: // {0xc000, "CONFIG$ "},
14496: {0xc000, "$IBMADSP"}, // for windows3.1 setup.exe
1.1.1.26 root 14497: };
14498: static const UINT8 dummy_device_routine[] = {
14499: // from NUL device of Windows 98 SE
14500: // or word ptr ES:[BX+03],0100
14501: 0x26, 0x81, 0x4f, 0x03, 0x00, 0x01,
14502: // retf
14503: 0xcb,
14504: };
1.1.1.29 root 14505: device_t *last = NULL;
1.1.1.32 root 14506: for(int i = 0; i < array_length(dummy_devices); i++) {
1.1.1.26 root 14507: device_t *device = (device_t *)(mem + DEVICE_TOP + 22 + 18 * i);
1.1.1.29 root 14508: device->next_driver.w.l = 22 + 18 * (i + 1);
14509: device->next_driver.w.h = DEVICE_TOP >> 4;
1.1.1.26 root 14510: device->attributes = dummy_devices[i].attributes;
1.1.1.29 root 14511: device->strategy = DEVICE_SIZE - sizeof(dummy_device_routine);
14512: device->interrupt = DEVICE_SIZE - sizeof(dummy_device_routine) + 6;
1.1.1.26 root 14513: memcpy(device->dev_name, dummy_devices[i].dev_name, 8);
1.1.1.29 root 14514: last = device;
14515: }
14516: if(last != NULL) {
14517: last->next_driver.w.l = 0;
14518: last->next_driver.w.h = XMS_TOP >> 4;
1.1.1.26 root 14519: }
1.1.1.29 root 14520: memcpy(mem + DEVICE_TOP + DEVICE_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.26 root 14521:
1.1.1.25 root 14522: // dos info
14523: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
14524: dos_info->magic_word = 1;
14525: dos_info->first_mcb = MEMORY_TOP >> 4;
14526: dos_info->first_dpb.w.l = 0;
14527: dos_info->first_dpb.w.h = DPB_TOP >> 4;
14528: dos_info->first_sft.w.l = 0;
14529: dos_info->first_sft.w.h = SFT_TOP >> 4;
1.1.1.26 root 14530: dos_info->clock_device.w.l = 22 + 18 * 3; // CLOCK$ is the 3rd device in IO.SYS
1.1.1.25 root 14531: dos_info->clock_device.w.h = DEVICE_TOP >> 4;
1.1.1.26 root 14532: dos_info->con_device.w.l = 22 + 18 * 0; // CON is the 1st device in IO.SYS
1.1.1.25 root 14533: dos_info->con_device.w.h = DEVICE_TOP >> 4;
14534: dos_info->max_sector_len = 512;
14535: dos_info->disk_buf_info.w.l = offsetof(dos_info_t, disk_buf_heads);
14536: dos_info->disk_buf_info.w.h = DOS_INFO_TOP >> 4;
14537: dos_info->cds.w.l = 0;
14538: dos_info->cds.w.h = CDS_TOP >> 4;
14539: dos_info->fcb_table.w.l = 0;
14540: dos_info->fcb_table.w.h = FCB_TABLE_TOP >> 4;
14541: dos_info->last_drive = 'Z' - 'A' + 1;
14542: dos_info->buffers_x = 20;
14543: dos_info->buffers_y = 0;
14544: dos_info->boot_drive = 'C' - 'A' + 1;
1.1.1.29 root 14545: dos_info->nul_device.next_driver.w.l = 22;
14546: dos_info->nul_device.next_driver.w.h = DEVICE_TOP >> 4;
1.1.1.25 root 14547: dos_info->nul_device.attributes = 0x8004;
1.1.1.29 root 14548: dos_info->nul_device.strategy = DOS_INFO_SIZE - sizeof(dummy_device_routine);
14549: dos_info->nul_device.interrupt = DOS_INFO_SIZE - sizeof(dummy_device_routine) + 6;
1.1.1.25 root 14550: memcpy(dos_info->nul_device.dev_name, "NUL ", 8);
14551: dos_info->disk_buf_heads.w.l = 0;
14552: dos_info->disk_buf_heads.w.h = DISK_BUF_TOP >> 4;
14553: dos_info->first_umb_fcb = UMB_TOP >> 4;
14554: dos_info->first_mcb_2 = MEMORY_TOP >> 4;
1.1.1.29 root 14555: memcpy(mem + DOS_INFO_TOP + DOS_INFO_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.25 root 14556:
14557: char *env;
14558: if((env = getenv("LASTDRIVE")) != NULL) {
14559: if(env[0] >= 'A' && env[0] <= 'Z') {
14560: dos_info->last_drive = env[0] - 'A' + 1;
14561: } else if(env[0] >= 'a' && env[0] <= 'z') {
14562: dos_info->last_drive = env[0] - 'a' + 1;
14563: }
14564: }
14565: if((env = getenv("windir")) != NULL) {
14566: if(env[0] >= 'A' && env[0] <= 'Z') {
14567: dos_info->boot_drive = env[0] - 'A' + 1;
14568: } else if(env[0] >= 'a' && env[0] <= 'z') {
14569: dos_info->boot_drive = env[0] - 'a' + 1;
14570: }
14571: }
14572: #if defined(HAS_I386)
14573: dos_info->i386_or_later = 1;
14574: #else
14575: dos_info->i386_or_later = 0;
14576: #endif
14577: dos_info->ext_mem_size = (min(MAX_MEM, 0x4000000) - 0x100000) >> 10;
14578:
1.1.1.27 root 14579: // ems (int 67h) and xms
1.1.1.25 root 14580: device_t *xms_device = (device_t *)(mem + XMS_TOP);
14581: xms_device->next_driver.w.l = 0xffff;
14582: xms_device->next_driver.w.h = 0xffff;
14583: xms_device->attributes = 0xc000;
1.1.1.29 root 14584: xms_device->strategy = XMS_SIZE - sizeof(dummy_device_routine);
14585: xms_device->interrupt = XMS_SIZE - sizeof(dummy_device_routine) + 6;
1.1.1.25 root 14586: memcpy(xms_device->dev_name, "EMMXXXX0", 8);
14587:
1.1.1.26 root 14588: mem[XMS_TOP + 0x12] = 0xcd; // int 68h (dummy)
14589: mem[XMS_TOP + 0x13] = 0x68;
14590: mem[XMS_TOP + 0x14] = 0xcf; // iret
1.1.1.19 root 14591: #ifdef SUPPORT_XMS
14592: if(support_xms) {
1.1.1.26 root 14593: mem[XMS_TOP + 0x15] = 0xcd; // int 69h (dummy)
14594: mem[XMS_TOP + 0x16] = 0x69;
14595: mem[XMS_TOP + 0x17] = 0xcb; // retf
1.1.1.19 root 14596: } else
14597: #endif
1.1.1.26 root 14598: mem[XMS_TOP + 0x15] = 0xcb; // retf
1.1.1.29 root 14599: memcpy(mem + XMS_TOP + XMS_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.19 root 14600:
1.1.1.26 root 14601: // irq12 routine (mouse)
1.1.1.24 root 14602: mem[0xfffd0 + 0x00] = 0xcd; // int 6ah (dummy)
14603: mem[0xfffd0 + 0x01] = 0x6a;
14604: mem[0xfffd0 + 0x02] = 0x9a; // call far mouse
14605: mem[0xfffd0 + 0x03] = 0xff;
14606: mem[0xfffd0 + 0x04] = 0xff;
14607: mem[0xfffd0 + 0x05] = 0xff;
14608: mem[0xfffd0 + 0x06] = 0xff;
14609: mem[0xfffd0 + 0x07] = 0xcd; // int 6bh (dummy)
14610: mem[0xfffd0 + 0x08] = 0x6b;
14611: mem[0xfffd0 + 0x09] = 0xcf; // iret
14612:
1.1.1.27 root 14613: // case map routine
14614: mem[0xfffd0 + 0x0a] = 0xcd; // int 6ch (dummy)
14615: mem[0xfffd0 + 0x0b] = 0x6c;
14616: mem[0xfffd0 + 0x0c] = 0xcb; // retf
14617:
14618: // font read routine
14619: mem[0xfffd0 + 0x0d] = 0xcd; // int 6dh (dummy)
14620: mem[0xfffd0 + 0x0e] = 0x6d;
14621: mem[0xfffd0 + 0x0f] = 0xcb; // retf
1.1.1.19 root 14622:
1.1.1.32 root 14623: // error message read routine
14624: mem[0xfffd0 + 0x10] = 0xcd; // int 6eh (dummy)
14625: mem[0xfffd0 + 0x11] = 0x6e;
14626: mem[0xfffd0 + 0x12] = 0xcb; // retf
14627:
1.1.1.26 root 14628: // irq0 routine (system time)
1.1.1.32 root 14629: mem[0xfffd0 + 0x19] = 0xcd; // int 1ch
14630: mem[0xfffd0 + 0x1a] = 0x1c;
14631: mem[0xfffd0 + 0x1b] = 0xea; // jmp far (IRET_TOP >> 4):0008
14632: mem[0xfffd0 + 0x1c] = 0x08;
14633: mem[0xfffd0 + 0x1d] = 0x00;
14634: mem[0xfffd0 + 0x1e] = ((IRET_TOP >> 4) ) & 0xff;
14635: mem[0xfffd0 + 0x1f] = ((IRET_TOP >> 4) >> 8) & 0xff;
1.1.1.14 root 14636:
1.1.1.26 root 14637: // boot routine
1.1 root 14638: mem[0xffff0] = 0xf4; // halt
14639: mem[0xffff1] = 0xcd; // int 21h
14640: mem[0xffff2] = 0x21;
14641: mem[0xffff3] = 0xcb; // retf
14642:
1.1.1.24 root 14643: mem[0xffff5] = '0'; // rom date
14644: mem[0xffff6] = '2';
14645: mem[0xffff7] = '/';
14646: mem[0xffff8] = '2';
14647: mem[0xffff9] = '2';
14648: mem[0xffffa] = '/';
14649: mem[0xffffb] = '0';
14650: mem[0xffffc] = '6';
14651: mem[0xffffe] = 0xfc; // machine id
14652: mem[0xfffff] = 0x00;
14653:
1.1 root 14654: // param block
14655: // + 0: param block (22bytes)
14656: // +24: fcb1/2 (20bytes)
14657: // +44: command tail (128bytes)
14658: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
14659: param->env_seg = 0;
14660: param->cmd_line.w.l = 44;
14661: param->cmd_line.w.h = (WORK_TOP >> 4);
14662: param->fcb1.w.l = 24;
14663: param->fcb1.w.h = (WORK_TOP >> 4);
14664: param->fcb2.w.l = 24;
14665: param->fcb2.w.h = (WORK_TOP >> 4);
14666:
14667: memset(mem + WORK_TOP + 24, 0x20, 20);
14668:
14669: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
14670: if(argc > 1) {
14671: sprintf(cmd_line->cmd, " %s", argv[1]);
14672: for(int i = 2; i < argc; i++) {
14673: char tmp[128];
14674: sprintf(tmp, "%s %s", cmd_line->cmd, argv[i]);
14675: strcpy(cmd_line->cmd, tmp);
14676: }
14677: cmd_line->len = (UINT8)strlen(cmd_line->cmd);
14678: } else {
14679: cmd_line->len = 0;
14680: }
14681: cmd_line->cmd[cmd_line->len] = 0x0d;
14682:
14683: // system file table
1.1.1.21 root 14684: *(UINT32 *)(mem + SFT_TOP + 0) = 0xffffffff;
14685: *(UINT16 *)(mem + SFT_TOP + 4) = 20;
1.1 root 14686:
1.1.1.19 root 14687: // disk buffer header (from DOSBox)
14688: *(UINT16 *)(mem + DISK_BUF_TOP + 0) = 0xffff; // forward ptr
14689: *(UINT16 *)(mem + DISK_BUF_TOP + 2) = 0xffff; // backward ptr
14690: *(UINT8 *)(mem + DISK_BUF_TOP + 4) = 0xff; // not in use
14691: *(UINT8 *)(mem + DISK_BUF_TOP + 10) = 0x01; // number of FATs
14692: *(UINT32 *)(mem + DISK_BUF_TOP + 13) = 0xffffffff; // pointer to DPB
14693:
1.1 root 14694: // current directory structure
14695: msdos_cds_update(_getdrive() - 1);
14696:
14697: // fcb table
14698: *(UINT32 *)(mem + FCB_TABLE_TOP + 0) = 0xffffffff;
1.1.1.14 root 14699: *(UINT16 *)(mem + FCB_TABLE_TOP + 4) = 0;
1.1 root 14700:
1.1.1.17 root 14701: // nls stuff
14702: msdos_nls_tables_init();
1.1 root 14703:
14704: // execute command
1.1.1.28 root 14705: try {
14706: if(msdos_process_exec(argv[0], param, 0)) {
14707: fatalerror("'%s' not found\n", argv[0]);
14708: }
14709: } catch(...) {
14710: // we should not reach here :-(
14711: fatalerror("failed to start '%s' because of unexpected exeption\n", argv[0]);
1.1 root 14712: }
14713: retval = 0;
14714: return(0);
14715: }
14716:
14717: #define remove_std_file(path) { \
14718: int fd = _open(path, _O_RDONLY | _O_BINARY); \
14719: if(fd != -1) { \
14720: _lseek(fd, 0, SEEK_END); \
14721: int size = _tell(fd); \
14722: _close(fd); \
14723: if(size == 0) { \
14724: remove(path); \
14725: } \
14726: } \
14727: }
14728:
14729: void msdos_finish()
14730: {
14731: for(int i = 0; i < MAX_FILES; i++) {
14732: if(file_handler[i].valid) {
14733: _close(i);
14734: }
14735: }
1.1.1.21 root 14736: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 14737: remove_std_file("stdaux.txt");
1.1.1.21 root 14738: #endif
14739: #ifdef MAP_PRN_DEVICE_TO_FILE
1.1 root 14740: remove_std_file("stdprn.txt");
14741: #endif
1.1.1.30 root 14742: #ifdef SUPPORT_XMS
14743: msdos_xms_finish();
14744: #endif
1.1 root 14745: msdos_dbcs_table_finish();
14746: }
14747:
14748: /* ----------------------------------------------------------------------------
14749: PC/AT hardware emulation
14750: ---------------------------------------------------------------------------- */
14751:
14752: void hardware_init()
14753: {
1.1.1.3 root 14754: CPU_INIT_CALL(CPU_MODEL);
1.1 root 14755: CPU_RESET_CALL(CPU_MODEL);
1.1.1.14 root 14756: m_IF = 1;
1.1.1.3 root 14757: #if defined(HAS_I386)
1.1 root 14758: cpu_type = (REG32(EDX) >> 8) & 0x0f;
14759: cpu_step = (REG32(EDX) >> 0) & 0x0f;
1.1.1.3 root 14760: #endif
14761: i386_set_a20_line(0);
1.1.1.14 root 14762:
1.1.1.19 root 14763: ems_init();
1.1.1.25 root 14764: dma_init();
1.1 root 14765: pic_init();
1.1.1.25 root 14766: pio_init();
1.1.1.8 root 14767: #ifdef PIT_ALWAYS_RUNNING
14768: pit_init();
14769: #else
1.1 root 14770: pit_active = 0;
14771: #endif
1.1.1.25 root 14772: sio_init();
1.1.1.8 root 14773: cmos_init();
14774: kbd_init();
1.1 root 14775: }
14776:
1.1.1.10 root 14777: void hardware_finish()
14778: {
14779: #if defined(HAS_I386)
14780: vtlb_free(m_vtlb);
14781: #endif
1.1.1.19 root 14782: ems_finish();
1.1.1.25 root 14783: sio_finish();
1.1.1.10 root 14784: }
14785:
1.1.1.28 root 14786: void hardware_release()
14787: {
14788: // release hardware resources when this program will be terminated abnormally
14789: #ifdef EXPORT_DEBUG_TO_FILE
1.1.1.33! root 14790: if(fp_debug_log != NULL) {
! 14791: fclose(fp_debug_log);
! 14792: fp_debug_log = NULL;
1.1.1.28 root 14793: }
14794: #endif
14795: #if defined(HAS_I386)
14796: vtlb_free(m_vtlb);
14797: #endif
14798: ems_release();
14799: sio_release();
14800: }
14801:
1.1 root 14802: void hardware_run()
14803: {
14804: int ops = 0;
14805:
1.1.1.22 root 14806: #ifdef EXPORT_DEBUG_TO_FILE
1.1.1.28 root 14807: // open debug log file after msdos_init() is done not to use the standard file handlers
1.1.1.33! root 14808: fp_debug_log = fopen("debug.log", "w");
1.1.1.22 root 14809: #endif
1.1.1.3 root 14810: while(!m_halted) {
14811: #if defined(HAS_I386)
14812: m_cycles = 1;
1.1 root 14813: CPU_EXECUTE_CALL(i386);
1.1.1.3 root 14814: #else
14815: CPU_EXECUTE_CALL(CPU_MODEL);
14816: #endif
1.1.1.14 root 14817: #if defined(HAS_I386)
14818: if(m_eip != m_prev_eip) {
14819: #else
14820: if(m_pc != m_prevpc) {
14821: #endif
14822: iops++;
14823: }
1.1.1.8 root 14824: if(++ops == 16384) {
1.1 root 14825: hardware_update();
14826: ops = 0;
14827: }
14828: }
1.1.1.22 root 14829: #ifdef EXPORT_DEBUG_TO_FILE
1.1.1.33! root 14830: if(fp_debug_log != NULL) {
! 14831: fclose(fp_debug_log);
! 14832: fp_debug_log = NULL;
1.1.1.28 root 14833: }
1.1.1.22 root 14834: #endif
1.1 root 14835: }
14836:
14837: void hardware_update()
14838: {
1.1.1.8 root 14839: static UINT32 prev_time = 0;
14840: UINT32 cur_time = timeGetTime();
14841:
14842: if(prev_time != cur_time) {
14843: // update pit and raise irq0
14844: #ifndef PIT_ALWAYS_RUNNING
14845: if(pit_active)
14846: #endif
14847: {
14848: if(pit_run(0, cur_time)) {
14849: pic_req(0, 0, 1);
14850: }
14851: pit_run(1, cur_time);
14852: pit_run(2, cur_time);
14853: }
1.1.1.24 root 14854:
1.1.1.25 root 14855: // update sio and raise irq4/3
1.1.1.29 root 14856: for(int c = 0; c < 4; c++) {
1.1.1.25 root 14857: sio_update(c);
14858: }
14859:
1.1.1.24 root 14860: // update keyboard and mouse
1.1.1.14 root 14861: static UINT32 prev_tick = 0;
14862: UINT32 cur_tick = cur_time / 32;
1.1.1.25 root 14863:
1.1.1.14 root 14864: if(prev_tick != cur_tick) {
14865: // update keyboard flags
14866: UINT8 state;
1.1.1.24 root 14867: state = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
14868: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x0001) ? 0x40 : 0;
14869: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x0001) ? 0x20 : 0;
14870: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
14871: state |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
14872: state |= (GetAsyncKeyState(VK_CONTROL ) & 0x8000) ? 0x04 : 0;
14873: state |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
14874: state |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
1.1.1.14 root 14875: mem[0x417] = state;
14876: state = (GetAsyncKeyState(VK_INSERT ) & 0x8000) ? 0x80 : 0;
14877: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
14878: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
14879: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
1.1.1.24 root 14880: // state |= (GetAsyncKeyState(VK_PAUSE ) & 0x0001) ? 0x08 : 0;
14881: // state |= (GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x04 : 0;
1.1.1.14 root 14882: state |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
14883: state |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
14884: mem[0x418] = state;
14885:
1.1.1.24 root 14886: // update console input if needed
14887: if(!key_changed || mouse.active) {
14888: update_console_input();
14889: }
14890:
14891: // raise irq1 if key is pressed/released
14892: if(key_changed) {
1.1.1.8 root 14893: pic_req(0, 1, 1);
1.1.1.24 root 14894: key_changed = false;
14895: }
14896:
14897: // raise irq12 if mouse status is changed
14898: if(mouse.status & mouse.call_mask) {
14899: if(mouse.active) {
14900: pic_req(1, 4, 1);
14901: mouse.status_irq = mouse.status & mouse.call_mask;
14902: }
14903: mouse.status &= ~mouse.call_mask;
1.1.1.8 root 14904: }
1.1.1.24 root 14905:
1.1.1.14 root 14906: prev_tick = cur_tick;
1.1.1.8 root 14907: }
1.1.1.24 root 14908:
1.1.1.19 root 14909: // update daily timer counter
14910: pcbios_update_daily_timer_counter(cur_time);
1.1.1.25 root 14911:
1.1.1.8 root 14912: prev_time = cur_time;
1.1 root 14913: }
14914: }
14915:
1.1.1.19 root 14916: // ems
14917:
14918: void ems_init()
14919: {
14920: memset(ems_handles, 0, sizeof(ems_handles));
14921: memset(ems_pages, 0, sizeof(ems_pages));
14922: free_ems_pages = MAX_EMS_PAGES;
14923: }
14924:
14925: void ems_finish()
14926: {
1.1.1.28 root 14927: ems_release();
14928: }
14929:
14930: void ems_release()
14931: {
1.1.1.31 root 14932: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.28 root 14933: if(ems_handles[i].buffer != NULL) {
1.1.1.19 root 14934: free(ems_handles[i].buffer);
14935: ems_handles[i].buffer = NULL;
14936: }
14937: }
14938: }
14939:
14940: void ems_allocate_pages(int handle, int pages)
14941: {
14942: if(pages > 0) {
14943: ems_handles[handle].buffer = (UINT8 *)calloc(1, 0x4000 * pages);
14944: } else {
14945: ems_handles[handle].buffer = NULL;
14946: }
14947: ems_handles[handle].pages = pages;
14948: ems_handles[handle].allocated = true;
14949: free_ems_pages -= pages;
14950: }
14951:
14952: void ems_reallocate_pages(int handle, int pages)
14953: {
14954: if(ems_handles[handle].allocated) {
14955: if(ems_handles[handle].pages != pages) {
14956: UINT8 *new_buffer = NULL;
14957:
14958: if(pages > 0) {
14959: new_buffer = (UINT8 *)calloc(1, 0x4000 * pages);
14960: }
1.1.1.32 root 14961: if(ems_handles[handle].buffer != NULL) {
14962: if(new_buffer != NULL) {
1.1.1.19 root 14963: if(pages > ems_handles[handle].pages) {
14964: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * ems_handles[handle].pages);
14965: } else {
14966: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * pages);
14967: }
14968: }
14969: free(ems_handles[handle].buffer);
14970: ems_handles[handle].buffer = NULL;
14971: }
14972: free_ems_pages += ems_handles[handle].pages;
14973:
14974: ems_handles[handle].buffer = new_buffer;
14975: ems_handles[handle].pages = pages;
14976: free_ems_pages -= pages;
14977: }
14978: } else {
14979: ems_allocate_pages(handle, pages);
14980: }
14981: }
14982:
14983: void ems_release_pages(int handle)
14984: {
14985: if(ems_handles[handle].allocated) {
1.1.1.32 root 14986: if(ems_handles[handle].buffer != NULL) {
1.1.1.19 root 14987: free(ems_handles[handle].buffer);
14988: ems_handles[handle].buffer = NULL;
14989: }
14990: free_ems_pages += ems_handles[handle].pages;
14991: ems_handles[handle].allocated = false;
14992: }
14993: }
14994:
14995: void ems_map_page(int physical, int handle, int logical)
14996: {
14997: if(ems_pages[physical].mapped) {
14998: if(ems_pages[physical].handle == handle && ems_pages[physical].page == logical) {
14999: return;
15000: }
15001: ems_unmap_page(physical);
15002: }
1.1.1.32 root 15003: if(ems_handles[handle].allocated && ems_handles[handle].buffer != NULL && logical < ems_handles[handle].pages) {
1.1.1.19 root 15004: memcpy(mem + EMS_TOP + 0x4000 * physical, ems_handles[handle].buffer + 0x4000 * logical, 0x4000);
15005: }
15006: ems_pages[physical].handle = handle;
15007: ems_pages[physical].page = logical;
15008: ems_pages[physical].mapped = true;
15009: }
15010:
15011: void ems_unmap_page(int physical)
15012: {
15013: if(ems_pages[physical].mapped) {
15014: int handle = ems_pages[physical].handle;
15015: int logical = ems_pages[physical].page;
15016:
1.1.1.32 root 15017: if(ems_handles[handle].allocated && ems_handles[handle].buffer != NULL && logical < ems_handles[handle].pages) {
1.1.1.19 root 15018: memcpy(ems_handles[handle].buffer + 0x4000 * logical, mem + EMS_TOP + 0x4000 * physical, 0x4000);
15019: }
15020: ems_pages[physical].mapped = false;
15021: }
15022: }
15023:
1.1.1.25 root 15024: // dma
1.1 root 15025:
1.1.1.25 root 15026: void dma_init()
1.1 root 15027: {
1.1.1.26 root 15028: memset(dma, 0, sizeof(dma));
1.1.1.25 root 15029: for(int c = 0; c < 2; c++) {
1.1.1.26 root 15030: // for(int ch = 0; ch < 4; ch++) {
15031: // dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w = 0xffff;
15032: // }
1.1.1.25 root 15033: dma_reset(c);
15034: }
1.1 root 15035: }
15036:
1.1.1.25 root 15037: void dma_reset(int c)
1.1 root 15038: {
1.1.1.25 root 15039: dma[c].low_high = false;
15040: dma[c].cmd = dma[c].req = dma[c].tc = 0;
15041: dma[c].mask = 0xff;
15042: }
15043:
15044: void dma_write(int c, UINT32 addr, UINT8 data)
15045: {
15046: int ch = (addr >> 1) & 3;
15047: UINT8 bit = 1 << (data & 3);
15048:
15049: switch(addr & 0x0f) {
15050: case 0x00: case 0x02: case 0x04: case 0x06:
15051: if(dma[c].low_high) {
15052: dma[c].ch[ch].bareg.b.h = data;
1.1 root 15053: } else {
1.1.1.25 root 15054: dma[c].ch[ch].bareg.b.l = data;
15055: }
15056: dma[c].ch[ch].areg.w = dma[c].ch[ch].bareg.w;
15057: dma[c].low_high = !dma[c].low_high;
15058: break;
15059: case 0x01: case 0x03: case 0x05: case 0x07:
15060: if(dma[c].low_high) {
15061: dma[c].ch[ch].bcreg.b.h = data;
15062: } else {
15063: dma[c].ch[ch].bcreg.b.l = data;
15064: }
15065: dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w;
15066: dma[c].low_high = !dma[c].low_high;
15067: break;
15068: case 0x08:
15069: // command register
15070: dma[c].cmd = data;
15071: break;
15072: case 0x09:
15073: // dma[c].request register
15074: if(data & 4) {
15075: if(!(dma[c].req & bit)) {
15076: dma[c].req |= bit;
15077: // dma_run(c, ch);
15078: }
15079: } else {
15080: dma[c].req &= ~bit;
15081: }
15082: break;
15083: case 0x0a:
15084: // single mask register
15085: if(data & 4) {
15086: dma[c].mask |= bit;
15087: } else {
15088: dma[c].mask &= ~bit;
15089: }
15090: break;
15091: case 0x0b:
15092: // mode register
15093: dma[c].ch[data & 3].mode = data;
15094: break;
15095: case 0x0c:
15096: dma[c].low_high = false;
15097: break;
15098: case 0x0d:
15099: // clear master
15100: dma_reset(c);
15101: break;
15102: case 0x0e:
15103: // clear mask register
15104: dma[c].mask = 0;
15105: break;
15106: case 0x0f:
15107: // all mask register
15108: dma[c].mask = data & 0x0f;
15109: break;
15110: }
15111: }
15112:
15113: UINT8 dma_read(int c, UINT32 addr)
15114: {
15115: int ch = (addr >> 1) & 3;
15116: UINT8 val = 0xff;
15117:
15118: switch(addr & 0x0f) {
15119: case 0x00: case 0x02: case 0x04: case 0x06:
15120: if(dma[c].low_high) {
15121: val = dma[c].ch[ch].areg.b.h;
15122: } else {
15123: val = dma[c].ch[ch].areg.b.l;
15124: }
15125: dma[c].low_high = !dma[c].low_high;
15126: return(val);
15127: case 0x01: case 0x03: case 0x05: case 0x07:
15128: if(dma[c].low_high) {
15129: val = dma[c].ch[ch].creg.b.h;
15130: } else {
15131: val = dma[c].ch[ch].creg.b.l;
15132: }
15133: dma[c].low_high = !dma[c].low_high;
15134: return(val);
15135: case 0x08:
15136: // status register
15137: val = (dma[c].req << 4) | dma[c].tc;
15138: dma[c].tc = 0;
15139: return(val);
15140: case 0x0d:
1.1.1.26 root 15141: // temporary register (intel 82374 does not support)
1.1.1.25 root 15142: return(dma[c].tmp & 0xff);
1.1.1.26 root 15143: case 0x0f:
15144: // mask register (intel 82374 does support)
15145: return(dma[c].mask);
1.1.1.25 root 15146: }
15147: return(0xff);
15148: }
15149:
15150: void dma_page_write(int c, int ch, UINT8 data)
15151: {
15152: dma[c].ch[ch].pagereg = data;
15153: }
15154:
15155: UINT8 dma_page_read(int c, int ch)
15156: {
15157: return(dma[c].ch[ch].pagereg);
15158: }
15159:
15160: void dma_run(int c, int ch)
15161: {
15162: UINT8 bit = 1 << ch;
15163:
15164: if((dma[c].req & bit) && !(dma[c].mask & bit)) {
15165: // execute dma
15166: while(dma[c].req & bit) {
15167: if(ch == 0 && (dma[c].cmd & 0x01)) {
15168: // memory -> memory
15169: UINT32 saddr = dma[c].ch[0].areg.w | (dma[c].ch[0].pagereg << 16);
15170: UINT32 daddr = dma[c].ch[1].areg.w | (dma[c].ch[1].pagereg << 16);
15171:
15172: if(c == 0) {
15173: dma[c].tmp = read_byte(saddr);
15174: write_byte(daddr, dma[c].tmp);
15175: } else {
15176: dma[c].tmp = read_word(saddr << 1);
15177: write_word(daddr << 1, dma[c].tmp);
15178: }
15179: if(!(dma[c].cmd & 0x02)) {
15180: if(dma[c].ch[0].mode & 0x20) {
15181: dma[c].ch[0].areg.w--;
15182: if(dma[c].ch[0].areg.w == 0xffff) {
15183: dma[c].ch[0].pagereg--;
15184: }
15185: } else {
15186: dma[c].ch[0].areg.w++;
15187: if(dma[c].ch[0].areg.w == 0) {
15188: dma[c].ch[0].pagereg++;
15189: }
15190: }
15191: }
15192: if(dma[c].ch[1].mode & 0x20) {
15193: dma[c].ch[1].areg.w--;
15194: if(dma[c].ch[1].areg.w == 0xffff) {
15195: dma[c].ch[1].pagereg--;
15196: }
15197: } else {
15198: dma[c].ch[1].areg.w++;
15199: if(dma[c].ch[1].areg.w == 0) {
15200: dma[c].ch[1].pagereg++;
15201: }
15202: }
15203:
15204: // check dma condition
15205: if(dma[c].ch[0].creg.w-- == 0) {
15206: if(dma[c].ch[0].mode & 0x10) {
15207: // self initialize
15208: dma[c].ch[0].areg.w = dma[c].ch[0].bareg.w;
15209: dma[c].ch[0].creg.w = dma[c].ch[0].bcreg.w;
15210: } else {
15211: // dma[c].mask |= bit;
15212: }
15213: }
15214: if(dma[c].ch[1].creg.w-- == 0) {
15215: // terminal count
15216: if(dma[c].ch[1].mode & 0x10) {
15217: // self initialize
15218: dma[c].ch[1].areg.w = dma[c].ch[1].bareg.w;
15219: dma[c].ch[1].creg.w = dma[c].ch[1].bcreg.w;
15220: } else {
15221: dma[c].mask |= bit;
15222: }
15223: dma[c].req &= ~bit;
15224: dma[c].tc |= bit;
15225: }
15226: } else {
15227: UINT32 addr = dma[c].ch[ch].areg.w | (dma[c].ch[ch].pagereg << 16);
15228:
15229: if((dma[c].ch[ch].mode & 0x0c) == 0x00) {
15230: // verify
15231: } else if((dma[c].ch[ch].mode & 0x0c) == 0x04) {
15232: // io -> memory
15233: if(c == 0) {
15234: dma[c].tmp = read_io_byte(dma[c].ch[ch].port);
15235: write_byte(addr, dma[c].tmp);
15236: } else {
15237: dma[c].tmp = read_io_word(dma[c].ch[ch].port);
15238: write_word(addr << 1, dma[c].tmp);
15239: }
15240: } else if((dma[c].ch[ch].mode & 0x0c) == 0x08) {
15241: // memory -> io
15242: if(c == 0) {
15243: dma[c].tmp = read_byte(addr);
15244: write_io_byte(dma[c].ch[ch].port, dma[c].tmp);
15245: } else {
15246: dma[c].tmp = read_word(addr << 1);
15247: write_io_word(dma[c].ch[ch].port, dma[c].tmp);
15248: }
15249: }
15250: if(dma[c].ch[ch].mode & 0x20) {
15251: dma[c].ch[ch].areg.w--;
15252: if(dma[c].ch[ch].areg.w == 0xffff) {
15253: dma[c].ch[ch].pagereg--;
15254: }
15255: } else {
15256: dma[c].ch[ch].areg.w++;
15257: if(dma[c].ch[ch].areg.w == 0) {
15258: dma[c].ch[ch].pagereg++;
15259: }
15260: }
15261:
15262: // check dma condition
15263: if(dma[c].ch[ch].creg.w-- == 0) {
15264: // terminal count
15265: if(dma[c].ch[ch].mode & 0x10) {
15266: // self initialize
15267: dma[c].ch[ch].areg.w = dma[c].ch[ch].bareg.w;
15268: dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w;
15269: } else {
15270: dma[c].mask |= bit;
15271: }
15272: dma[c].req &= ~bit;
15273: dma[c].tc |= bit;
15274: } else if((dma[c].ch[ch].mode & 0xc0) == 0x40) {
15275: // single mode
15276: break;
15277: }
15278: }
15279: }
15280: }
15281: }
15282:
15283: // pic
15284:
15285: void pic_init()
15286: {
15287: memset(pic, 0, sizeof(pic));
15288: pic[0].imr = pic[1].imr = 0xff;
15289:
15290: // from bochs bios
15291: pic_write(0, 0, 0x11); // icw1 = 11h
15292: pic_write(0, 1, 0x08); // icw2 = 08h
15293: pic_write(0, 1, 0x04); // icw3 = 04h
15294: pic_write(0, 1, 0x01); // icw4 = 01h
15295: pic_write(0, 1, 0xb8); // ocw1 = b8h
15296: pic_write(1, 0, 0x11); // icw1 = 11h
15297: pic_write(1, 1, 0x70); // icw2 = 70h
15298: pic_write(1, 1, 0x02); // icw3 = 02h
15299: pic_write(1, 1, 0x01); // icw4 = 01h
15300: }
15301:
15302: void pic_write(int c, UINT32 addr, UINT8 data)
15303: {
15304: if(addr & 1) {
15305: if(pic[c].icw2_r) {
15306: // icw2
15307: pic[c].icw2 = data;
15308: pic[c].icw2_r = 0;
15309: } else if(pic[c].icw3_r) {
15310: // icw3
15311: pic[c].icw3 = data;
15312: pic[c].icw3_r = 0;
15313: } else if(pic[c].icw4_r) {
15314: // icw4
15315: pic[c].icw4 = data;
15316: pic[c].icw4_r = 0;
15317: } else {
15318: // ocw1
1.1 root 15319: pic[c].imr = data;
15320: }
15321: } else {
15322: if(data & 0x10) {
15323: // icw1
15324: pic[c].icw1 = data;
15325: pic[c].icw2_r = 1;
15326: pic[c].icw3_r = (data & 2) ? 0 : 1;
15327: pic[c].icw4_r = data & 1;
15328: pic[c].irr = 0;
15329: pic[c].isr = 0;
15330: pic[c].imr = 0;
15331: pic[c].prio = 0;
15332: if(!(pic[c].icw1 & 1)) {
15333: pic[c].icw4 = 0;
15334: }
15335: pic[c].ocw3 = 0;
15336: } else if(data & 8) {
15337: // ocw3
15338: if(!(data & 2)) {
15339: data = (data & ~1) | (pic[c].ocw3 & 1);
15340: }
15341: if(!(data & 0x40)) {
15342: data = (data & ~0x20) | (pic[c].ocw3 & 0x20);
15343: }
15344: pic[c].ocw3 = data;
15345: } else {
15346: // ocw2
15347: int level = 0;
15348: if(data & 0x40) {
15349: level = data & 7;
15350: } else {
15351: if(!pic[c].isr) {
15352: return;
15353: }
15354: level = pic[c].prio;
15355: while(!(pic[c].isr & (1 << level))) {
15356: level = (level + 1) & 7;
15357: }
15358: }
15359: if(data & 0x80) {
15360: pic[c].prio = (level + 1) & 7;
15361: }
15362: if(data & 0x20) {
15363: pic[c].isr &= ~(1 << level);
15364: }
15365: }
15366: }
15367: pic_update();
15368: }
15369:
15370: UINT8 pic_read(int c, UINT32 addr)
15371: {
15372: if(addr & 1) {
15373: return(pic[c].imr);
15374: } else {
15375: // polling mode is not supported...
15376: //if(pic[c].ocw3 & 4) {
15377: // return ???;
15378: //}
15379: if(pic[c].ocw3 & 1) {
15380: return(pic[c].isr);
15381: } else {
15382: return(pic[c].irr);
15383: }
15384: }
15385: }
15386:
15387: void pic_req(int c, int level, int signal)
15388: {
15389: if(signal) {
15390: pic[c].irr |= (1 << level);
15391: } else {
15392: pic[c].irr &= ~(1 << level);
15393: }
15394: pic_update();
15395: }
15396:
15397: int pic_ack()
15398: {
15399: // ack (INTA=L)
15400: pic[pic_req_chip].isr |= pic_req_bit;
15401: pic[pic_req_chip].irr &= ~pic_req_bit;
15402: if(pic_req_chip > 0) {
15403: // update isr and irr of master
15404: UINT8 slave = 1 << (pic[pic_req_chip].icw3 & 7);
15405: pic[pic_req_chip - 1].isr |= slave;
15406: pic[pic_req_chip - 1].irr &= ~slave;
15407: }
15408: //if(pic[pic_req_chip].icw4 & 1) {
15409: // 8086 mode
15410: int vector = (pic[pic_req_chip].icw2 & 0xf8) | pic_req_level;
15411: //} else {
15412: // // 8080 mode
15413: // UINT16 addr = (UINT16)pic[pic_req_chip].icw2 << 8;
15414: // if(pic[pic_req_chip].icw1 & 4) {
15415: // addr |= (pic[pic_req_chip].icw1 & 0xe0) | (pic_req_level << 2);
15416: // } else {
15417: // addr |= (pic[pic_req_chip].icw1 & 0xc0) | (pic_req_level << 3);
15418: // }
15419: // vector = 0xcd | (addr << 8);
15420: //}
15421: if(pic[pic_req_chip].icw4 & 2) {
15422: // auto eoi
15423: pic[pic_req_chip].isr &= ~pic_req_bit;
15424: }
15425: return(vector);
15426: }
15427:
15428: void pic_update()
15429: {
15430: for(int c = 0; c < 2; c++) {
15431: UINT8 irr = pic[c].irr;
15432: if(c + 1 < 2) {
15433: // this is master
15434: if(pic[c + 1].irr & (~pic[c + 1].imr)) {
15435: // request from slave
15436: irr |= 1 << (pic[c + 1].icw3 & 7);
15437: }
15438: }
15439: irr &= (~pic[c].imr);
15440: if(!irr) {
15441: break;
15442: }
15443: if(!(pic[c].ocw3 & 0x20)) {
15444: irr |= pic[c].isr;
15445: }
15446: int level = pic[c].prio;
15447: UINT8 bit = 1 << level;
15448: while(!(irr & bit)) {
15449: level = (level + 1) & 7;
15450: bit = 1 << level;
15451: }
15452: if((c + 1 < 2) && (pic[c].icw3 & bit)) {
15453: // check slave
15454: continue;
15455: }
15456: if(pic[c].isr & bit) {
15457: break;
15458: }
15459: // interrupt request
15460: pic_req_chip = c;
15461: pic_req_level = level;
15462: pic_req_bit = bit;
1.1.1.3 root 15463: i386_set_irq_line(INPUT_LINE_IRQ, HOLD_LINE);
1.1 root 15464: return;
15465: }
1.1.1.3 root 15466: i386_set_irq_line(INPUT_LINE_IRQ, CLEAR_LINE);
1.1.1.2 root 15467: }
1.1 root 15468:
1.1.1.25 root 15469: // pio
15470:
15471: void pio_init()
15472: {
1.1.1.26 root 15473: memset(pio, 0, sizeof(pio));
1.1.1.25 root 15474: for(int c = 0; c < 2; c++) {
15475: pio[c].stat = 0xde;
15476: pio[c].ctrl = 0x0c;
15477: }
15478: }
15479:
15480: void pio_write(int c, UINT32 addr, UINT8 data)
15481: {
15482: switch(addr & 3) {
15483: case 0:
15484: pio[c].data = data;
15485: break;
15486: case 2:
15487: pio[c].ctrl = data;
15488: break;
15489: }
15490: }
15491:
15492: UINT8 pio_read(int c, UINT32 addr)
15493: {
15494: switch(addr & 3) {
15495: case 0:
15496: return(pio[c].data);
15497: case 1:
15498: return(pio[c].stat);
15499: case 2:
15500: return(pio[c].ctrl);
15501: }
15502: return(0xff);
15503: }
15504:
1.1 root 15505: // pit
15506:
1.1.1.22 root 15507: #define PIT_FREQ 1193182ULL
1.1 root 15508: #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)
15509:
15510: void pit_init()
15511: {
1.1.1.8 root 15512: memset(pit, 0, sizeof(pit));
1.1 root 15513: for(int ch = 0; ch < 3; ch++) {
15514: pit[ch].count = 0x10000;
15515: pit[ch].ctrl_reg = 0x34;
15516: pit[ch].mode = 3;
15517: }
15518:
15519: // from bochs bios
15520: pit_write(3, 0x34);
15521: pit_write(0, 0x00);
15522: pit_write(0, 0x00);
15523: }
15524:
15525: void pit_write(int ch, UINT8 val)
15526: {
1.1.1.8 root 15527: #ifndef PIT_ALWAYS_RUNNING
1.1 root 15528: if(!pit_active) {
15529: pit_active = 1;
15530: pit_init();
15531: }
1.1.1.8 root 15532: #endif
1.1 root 15533: switch(ch) {
15534: case 0:
15535: case 1:
15536: case 2:
15537: // write count register
15538: if(!pit[ch].low_write && !pit[ch].high_write) {
15539: if(pit[ch].ctrl_reg & 0x10) {
15540: pit[ch].low_write = 1;
15541: }
15542: if(pit[ch].ctrl_reg & 0x20) {
15543: pit[ch].high_write = 1;
15544: }
15545: }
15546: if(pit[ch].low_write) {
15547: pit[ch].count_reg = val;
15548: pit[ch].low_write = 0;
15549: } else if(pit[ch].high_write) {
15550: if((pit[ch].ctrl_reg & 0x30) == 0x20) {
15551: pit[ch].count_reg = val << 8;
15552: } else {
15553: pit[ch].count_reg |= val << 8;
15554: }
15555: pit[ch].high_write = 0;
15556: }
15557: // start count
1.1.1.8 root 15558: if(!pit[ch].low_write && !pit[ch].high_write) {
15559: if(pit[ch].mode == 0 || pit[ch].mode == 4 || pit[ch].prev_time == 0) {
15560: pit[ch].count = PIT_COUNT_VALUE(ch);
15561: pit[ch].prev_time = timeGetTime();
15562: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 15563: }
15564: }
15565: break;
15566: case 3: // ctrl reg
15567: if((val & 0xc0) == 0xc0) {
15568: // i8254 read-back command
15569: for(ch = 0; ch < 3; ch++) {
15570: if(!(val & 0x10) && !pit[ch].status_latched) {
15571: pit[ch].status = pit[ch].ctrl_reg & 0x3f;
15572: pit[ch].status_latched = 1;
15573: }
15574: if(!(val & 0x20) && !pit[ch].count_latched) {
15575: pit_latch_count(ch);
15576: }
15577: }
15578: break;
15579: }
15580: ch = (val >> 6) & 3;
15581: if(val & 0x30) {
15582: static int modes[8] = {0, 1, 2, 3, 4, 5, 2, 3};
15583: pit[ch].mode = modes[(val >> 1) & 7];
15584: pit[ch].count_latched = 0;
15585: pit[ch].low_read = pit[ch].high_read = 0;
15586: pit[ch].low_write = pit[ch].high_write = 0;
15587: pit[ch].ctrl_reg = val;
15588: // stop count
1.1.1.8 root 15589: pit[ch].prev_time = pit[ch].expired_time = 0;
1.1 root 15590: pit[ch].count_reg = 0;
15591: } else if(!pit[ch].count_latched) {
15592: pit_latch_count(ch);
15593: }
15594: break;
15595: }
15596: }
15597:
15598: UINT8 pit_read(int ch)
15599: {
1.1.1.8 root 15600: #ifndef PIT_ALWAYS_RUNNING
1.1 root 15601: if(!pit_active) {
15602: pit_active = 1;
15603: pit_init();
15604: }
1.1.1.8 root 15605: #endif
1.1 root 15606: switch(ch) {
15607: case 0:
15608: case 1:
15609: case 2:
15610: if(pit[ch].status_latched) {
15611: pit[ch].status_latched = 0;
15612: return(pit[ch].status);
15613: }
15614: // if not latched, through current count
15615: if(!pit[ch].count_latched) {
15616: if(!pit[ch].low_read && !pit[ch].high_read) {
15617: pit_latch_count(ch);
15618: }
15619: }
15620: // return latched count
15621: if(pit[ch].low_read) {
15622: pit[ch].low_read = 0;
15623: if(!pit[ch].high_read) {
15624: pit[ch].count_latched = 0;
15625: }
15626: return(pit[ch].latch & 0xff);
15627: } else if(pit[ch].high_read) {
15628: pit[ch].high_read = 0;
15629: pit[ch].count_latched = 0;
15630: return((pit[ch].latch >> 8) & 0xff);
15631: }
15632: }
15633: return(0xff);
15634: }
15635:
1.1.1.8 root 15636: int pit_run(int ch, UINT32 cur_time)
1.1 root 15637: {
1.1.1.8 root 15638: if(pit[ch].expired_time != 0 && cur_time >= pit[ch].expired_time) {
1.1 root 15639: pit[ch].count = PIT_COUNT_VALUE(ch);
1.1.1.8 root 15640: pit[ch].prev_time = pit[ch].expired_time;
15641: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
15642: if(cur_time >= pit[ch].expired_time) {
15643: pit[ch].prev_time = cur_time;
15644: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 15645: }
1.1.1.8 root 15646: return(1);
1.1 root 15647: }
1.1.1.8 root 15648: return(0);
1.1 root 15649: }
15650:
15651: void pit_latch_count(int ch)
15652: {
1.1.1.8 root 15653: if(pit[ch].expired_time != 0) {
1.1.1.26 root 15654: UINT32 cur_time = timeGetTime();
1.1.1.8 root 15655: pit_run(ch, cur_time);
15656: UINT32 tmp = (pit[ch].count * (pit[ch].expired_time - cur_time)) / (pit[ch].expired_time - pit[ch].prev_time);
1.1.1.26 root 15657: UINT16 latch = (tmp != 0) ? (UINT16)tmp : 1;
15658:
15659: if(pit[ch].prev_latch == latch && pit[ch].expired_time > cur_time) {
15660: // decrement counter in 1msec period
15661: if(pit[ch].next_latch == 0) {
15662: tmp = (pit[ch].count * (pit[ch].expired_time - cur_time - 1)) / (pit[ch].expired_time - pit[ch].prev_time);
15663: pit[ch].next_latch = (tmp != 0) ? (UINT16)tmp : 1;
15664: }
15665: if(pit[ch].latch > pit[ch].next_latch) {
15666: pit[ch].latch--;
15667: }
15668: } else {
15669: pit[ch].prev_latch = pit[ch].latch = latch;
15670: pit[ch].next_latch = 0;
15671: }
1.1.1.8 root 15672: } else {
15673: pit[ch].latch = (UINT16)pit[ch].count;
1.1.1.26 root 15674: pit[ch].prev_latch = pit[ch].next_latch = 0;
1.1 root 15675: }
15676: pit[ch].count_latched = 1;
15677: if((pit[ch].ctrl_reg & 0x30) == 0x10) {
15678: // lower byte
15679: pit[ch].low_read = 1;
15680: pit[ch].high_read = 0;
15681: } else if((pit[ch].ctrl_reg & 0x30) == 0x20) {
15682: // upper byte
15683: pit[ch].low_read = 0;
15684: pit[ch].high_read = 1;
15685: } else {
15686: // lower -> upper
1.1.1.14 root 15687: pit[ch].low_read = pit[ch].high_read = 1;
1.1 root 15688: }
15689: }
15690:
1.1.1.8 root 15691: int pit_get_expired_time(int ch)
1.1 root 15692: {
1.1.1.22 root 15693: pit[ch].accum += 1024ULL * 1000ULL * (UINT64)pit[ch].count / PIT_FREQ;
15694: UINT64 val = pit[ch].accum >> 10;
15695: pit[ch].accum -= val << 10;
15696: return((val != 0) ? val : 1);
1.1.1.8 root 15697: }
15698:
1.1.1.25 root 15699: // sio
15700:
15701: void sio_init()
15702: {
1.1.1.26 root 15703: memset(sio, 0, sizeof(sio));
15704: memset(sio_mt, 0, sizeof(sio_mt));
15705:
1.1.1.29 root 15706: for(int c = 0; c < 4; c++) {
1.1.1.25 root 15707: sio[c].send_buffer = new FIFO(SIO_BUFFER_SIZE);
15708: sio[c].recv_buffer = new FIFO(SIO_BUFFER_SIZE);
15709:
15710: sio[c].divisor.w = 12; // 115200Hz / 9600Baud
15711: sio[c].line_ctrl = 0x03; // 8bit, stop 1bit, non parity
1.1.1.26 root 15712: sio[c].modem_ctrl = 0x03; // rts=on, dtr=on
15713: sio[c].set_rts = sio[c].set_dtr = true;
1.1.1.25 root 15714: sio[c].line_stat_buf = 0x60; // send/recv buffers are empty
15715: sio[c].irq_identify = 0x01; // no pending irq
15716:
15717: InitializeCriticalSection(&sio_mt[c].csSendData);
15718: InitializeCriticalSection(&sio_mt[c].csRecvData);
15719: InitializeCriticalSection(&sio_mt[c].csLineCtrl);
15720: InitializeCriticalSection(&sio_mt[c].csLineStat);
15721: InitializeCriticalSection(&sio_mt[c].csModemCtrl);
15722: InitializeCriticalSection(&sio_mt[c].csModemStat);
15723:
1.1.1.26 root 15724: if(sio_port_number[c] != 0) {
1.1.1.25 root 15725: sio[c].channel = c;
15726: sio_mt[c].hThread = CreateThread(NULL, 0, sio_thread, &sio[c], 0, NULL);
15727: }
15728: }
15729: }
15730:
15731: void sio_finish()
15732: {
1.1.1.29 root 15733: for(int c = 0; c < 4; c++) {
1.1.1.25 root 15734: if(sio_mt[c].hThread != NULL) {
15735: WaitForSingleObject(sio_mt[c].hThread, INFINITE);
15736: CloseHandle(sio_mt[c].hThread);
1.1.1.28 root 15737: sio_mt[c].hThread = NULL;
1.1.1.25 root 15738: }
15739: DeleteCriticalSection(&sio_mt[c].csSendData);
15740: DeleteCriticalSection(&sio_mt[c].csRecvData);
15741: DeleteCriticalSection(&sio_mt[c].csLineCtrl);
15742: DeleteCriticalSection(&sio_mt[c].csLineStat);
15743: DeleteCriticalSection(&sio_mt[c].csModemCtrl);
15744: DeleteCriticalSection(&sio_mt[c].csModemStat);
1.1.1.28 root 15745: }
15746: sio_release();
15747: }
15748:
15749: void sio_release()
15750: {
1.1.1.29 root 15751: for(int c = 0; c < 4; c++) {
1.1.1.28 root 15752: // sio_thread() may access the resources :-(
1.1.1.32 root 15753: bool running = (sio_mt[c].hThread != NULL);
15754:
15755: if(running) {
15756: EnterCriticalSection(&sio_mt[c].csSendData);
15757: }
15758: if(sio[c].send_buffer != NULL) {
15759: sio[c].send_buffer->release();
15760: delete sio[c].send_buffer;
15761: sio[c].send_buffer = NULL;
15762: }
15763: if(running) {
15764: LeaveCriticalSection(&sio_mt[c].csSendData);
15765: EnterCriticalSection(&sio_mt[c].csRecvData);
15766: }
15767: if(sio[c].recv_buffer != NULL) {
15768: sio[c].recv_buffer->release();
15769: delete sio[c].recv_buffer;
15770: sio[c].recv_buffer = NULL;
15771: }
15772: if(running) {
15773: LeaveCriticalSection(&sio_mt[c].csRecvData);
1.1.1.28 root 15774: }
1.1.1.25 root 15775: }
15776: }
15777:
15778: void sio_write(int c, UINT32 addr, UINT8 data)
15779: {
15780: switch(addr & 7) {
15781: case 0:
15782: if(sio[c].selector & 0x80) {
15783: if(sio[c].divisor.b.l != data) {
15784: EnterCriticalSection(&sio_mt[c].csLineCtrl);
15785: sio[c].divisor.b.l = data;
15786: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
15787: }
15788: } else {
15789: EnterCriticalSection(&sio_mt[c].csSendData);
1.1.1.32 root 15790: if(sio[c].send_buffer != NULL) {
15791: sio[c].send_buffer->write(data);
15792: }
1.1.1.25 root 15793: // transmitter holding/shift registers are not empty
15794: sio[c].line_stat_buf &= ~0x60;
15795: LeaveCriticalSection(&sio_mt[c].csSendData);
15796:
15797: if(sio[c].irq_enable & 0x02) {
15798: sio_update_irq(c);
15799: }
15800: }
15801: break;
15802: case 1:
15803: if(sio[c].selector & 0x80) {
15804: if(sio[c].divisor.b.h != data) {
15805: EnterCriticalSection(&sio_mt[c].csLineCtrl);
15806: sio[c].divisor.b.h = data;
15807: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
15808: }
15809: } else {
15810: if(sio[c].irq_enable != data) {
15811: sio[c].irq_enable = data;
15812: sio_update_irq(c);
15813: }
15814: }
15815: break;
15816: case 3:
15817: {
15818: UINT8 line_ctrl = data & 0x3f;
15819: bool set_brk = ((data & 0x40) != 0);
15820:
15821: if(sio[c].line_ctrl != line_ctrl) {
15822: EnterCriticalSection(&sio_mt[c].csLineCtrl);
15823: sio[c].line_ctrl = line_ctrl;
15824: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
15825: }
15826: if(sio[c].set_brk != set_brk) {
15827: EnterCriticalSection(&sio_mt[c].csModemCtrl);
15828: sio[c].set_brk = set_brk;
15829: LeaveCriticalSection(&sio_mt[c].csModemCtrl);
15830: }
15831: }
15832: sio[c].selector = data;
15833: break;
15834: case 4:
15835: {
15836: bool set_dtr = ((data & 0x01) != 0);
15837: bool set_rts = ((data & 0x02) != 0);
15838:
15839: if(sio[c].set_dtr != set_dtr || sio[c].set_rts != set_rts) {
1.1.1.26 root 15840: // EnterCriticalSection(&sio_mt[c].csModemCtrl);
1.1.1.25 root 15841: sio[c].set_dtr = set_dtr;
15842: sio[c].set_rts = set_rts;
1.1.1.26 root 15843: // LeaveCriticalSection(&sio_mt[c].csModemCtrl);
15844:
15845: bool state_changed = false;
15846:
15847: EnterCriticalSection(&sio_mt[c].csModemStat);
15848: if(set_dtr) {
15849: sio[c].modem_stat |= 0x20; // dsr on
15850: } else {
15851: sio[c].modem_stat &= ~0x20; // dsr off
15852: }
15853: if(set_rts) {
15854: sio[c].modem_stat |= 0x10; // cts on
15855: } else {
15856: sio[c].modem_stat &= ~0x10; // cts off
15857: }
15858: if((sio[c].prev_modem_stat & 0x20) != (sio[c].modem_stat & 0x20)) {
15859: if(!(sio[c].modem_stat & 0x02)) {
15860: if(sio[c].irq_enable & 0x08) {
15861: state_changed = true;
15862: }
15863: sio[c].modem_stat |= 0x02;
15864: }
15865: }
15866: if((sio[c].prev_modem_stat & 0x10) != (sio[c].modem_stat & 0x10)) {
15867: if(!(sio[c].modem_stat & 0x01)) {
15868: if(sio[c].irq_enable & 0x08) {
15869: state_changed = true;
15870: }
15871: sio[c].modem_stat |= 0x01;
15872: }
15873: }
15874: LeaveCriticalSection(&sio_mt[c].csModemStat);
15875:
15876: if(state_changed) {
15877: sio_update_irq(c);
15878: }
1.1.1.25 root 15879: }
15880: }
15881: sio[c].modem_ctrl = data;
15882: break;
15883: case 7:
15884: sio[c].scratch = data;
15885: break;
15886: }
15887: }
15888:
15889: UINT8 sio_read(int c, UINT32 addr)
15890: {
15891: switch(addr & 7) {
15892: case 0:
15893: if(sio[c].selector & 0x80) {
15894: return(sio[c].divisor.b.l);
15895: } else {
15896: EnterCriticalSection(&sio_mt[c].csRecvData);
1.1.1.32 root 15897: UINT8 data = 0;
15898: if(sio[c].recv_buffer != NULL) {
15899: data = sio[c].recv_buffer->read();
15900: }
1.1.1.25 root 15901: // data is not ready
15902: sio[c].line_stat_buf &= ~0x01;
15903: LeaveCriticalSection(&sio_mt[c].csRecvData);
15904:
15905: if(sio[c].irq_enable & 0x01) {
15906: sio_update_irq(c);
15907: }
15908: return(data);
15909: }
15910: case 1:
15911: if(sio[c].selector & 0x80) {
15912: return(sio[c].divisor.b.h);
15913: } else {
15914: return(sio[c].irq_enable);
15915: }
15916: case 2:
15917: return(sio[c].irq_identify);
15918: case 3:
15919: return(sio[c].selector);
15920: case 4:
15921: return(sio[c].modem_ctrl);
15922: case 5:
15923: {
15924: EnterCriticalSection(&sio_mt[c].csLineStat);
15925: UINT8 val = sio[c].line_stat_err | sio[c].line_stat_buf;
15926: sio[c].line_stat_err = 0x00;
15927: LeaveCriticalSection(&sio_mt[c].csLineStat);
15928:
15929: bool state_changed = false;
15930:
15931: if((sio[c].line_stat_buf & 0x60) == 0x00) {
15932: EnterCriticalSection(&sio_mt[c].csSendData);
1.1.1.32 root 15933: if(sio[c].send_buffer != NULL && !sio[c].send_buffer->full()) {
1.1.1.25 root 15934: // transmitter holding register will be empty first
15935: if(sio[c].irq_enable & 0x02) {
15936: state_changed = true;
15937: }
15938: sio[c].line_stat_buf |= 0x20;
15939: }
15940: LeaveCriticalSection(&sio_mt[c].csSendData);
15941: } else if((sio[c].line_stat_buf & 0x60) == 0x20) {
15942: // transmitter shift register will be empty later
15943: sio[c].line_stat_buf |= 0x40;
15944: }
15945: if(!(sio[c].line_stat_buf & 0x01)) {
15946: EnterCriticalSection(&sio_mt[c].csRecvData);
1.1.1.32 root 15947: if(sio[c].recv_buffer != NULL && !sio[c].recv_buffer->empty()) {
1.1.1.25 root 15948: // data is ready
15949: if(sio[c].irq_enable & 0x01) {
15950: state_changed = true;
15951: }
15952: sio[c].line_stat_buf |= 0x01;
15953: }
15954: LeaveCriticalSection(&sio_mt[c].csRecvData);
15955: }
15956: if(state_changed) {
15957: sio_update_irq(c);
15958: }
15959: return(val);
15960: }
15961: case 6:
15962: {
15963: EnterCriticalSection(&sio_mt[c].csModemStat);
15964: UINT8 val = sio[c].modem_stat;
15965: sio[c].modem_stat &= 0xf0;
15966: sio[c].prev_modem_stat = sio[c].modem_stat;
15967: LeaveCriticalSection(&sio_mt[c].csModemStat);
15968:
15969: if(sio[c].modem_ctrl & 0x10) {
15970: // loop-back
15971: val &= 0x0f;
15972: val |= (sio[c].modem_ctrl & 0x0c) << 4;
15973: val |= (sio[c].modem_ctrl & 0x01) << 5;
15974: val |= (sio[c].modem_ctrl & 0x02) << 3;
15975: }
15976: return(val);
15977: }
15978: case 7:
15979: return(sio[c].scratch);
15980: }
15981: return(0xff);
15982: }
15983:
15984: void sio_update(int c)
15985: {
15986: if((sio[c].line_stat_buf & 0x60) == 0x00) {
15987: EnterCriticalSection(&sio_mt[c].csSendData);
1.1.1.32 root 15988: if(sio[c].send_buffer != NULL && !sio[c].send_buffer->full()) {
1.1.1.25 root 15989: // transmitter holding/shift registers will be empty
15990: sio[c].line_stat_buf |= 0x60;
15991: }
15992: LeaveCriticalSection(&sio_mt[c].csSendData);
15993: } else if((sio[c].line_stat_buf & 0x60) == 0x20) {
15994: // transmitter shift register will be empty
15995: sio[c].line_stat_buf |= 0x40;
15996: }
15997: if(!(sio[c].line_stat_buf & 0x01)) {
15998: EnterCriticalSection(&sio_mt[c].csRecvData);
1.1.1.32 root 15999: if(sio[c].recv_buffer != NULL && !sio[c].recv_buffer->empty()) {
1.1.1.25 root 16000: // data is ready
16001: sio[c].line_stat_buf |= 0x01;
16002: }
16003: LeaveCriticalSection(&sio_mt[c].csRecvData);
16004: }
16005: sio_update_irq(c);
16006: }
16007:
16008: void sio_update_irq(int c)
16009: {
16010: int level = -1;
16011:
16012: if(sio[c].irq_enable & 0x08) {
16013: EnterCriticalSection(&sio_mt[c].csModemStat);
16014: if((sio[c].modem_stat & 0x0f) != 0) {
16015: level = 0;
16016: }
16017: EnterCriticalSection(&sio_mt[c].csModemStat);
16018: }
16019: if(sio[c].irq_enable & 0x02) {
16020: if(sio[c].line_stat_buf & 0x20) {
16021: level = 1;
16022: }
16023: }
16024: if(sio[c].irq_enable & 0x01) {
16025: if(sio[c].line_stat_buf & 0x01) {
16026: level = 2;
16027: }
16028: }
16029: if(sio[c].irq_enable & 0x04) {
16030: EnterCriticalSection(&sio_mt[c].csLineStat);
16031: if(sio[c].line_stat_err != 0) {
16032: level = 3;
16033: }
16034: LeaveCriticalSection(&sio_mt[c].csLineStat);
16035: }
1.1.1.29 root 16036:
16037: // COM1 and COM3 shares IRQ4, COM2 and COM4 shares IRQ3
1.1.1.25 root 16038: if(level != -1) {
16039: sio[c].irq_identify = level << 1;
1.1.1.29 root 16040: pic_req(0, (c == 0 || c == 2) ? 4 : 3, 1);
1.1.1.25 root 16041: } else {
16042: sio[c].irq_identify = 1;
1.1.1.29 root 16043: pic_req(0, (c == 0 || c == 2) ? 4 : 3, 0);
1.1.1.25 root 16044: }
16045: }
16046:
16047: DWORD WINAPI sio_thread(void *lpx)
16048: {
16049: volatile sio_t *p = (sio_t *)lpx;
16050: sio_mt_t *q = &sio_mt[p->channel];
16051:
16052: char name[] = "COM1";
1.1.1.26 root 16053: name[3] = '0' + sio_port_number[p->channel];
16054: HANDLE hComm = NULL;
16055: COMMPROP commProp;
16056: DCB dcb;
16057: DWORD dwSettableBaud = 0xffb; // 75, 110, 150, 300, 600, 1200, 1800, 2400, 4800, 7200, and 9600bps
16058: BYTE bytBuffer[SIO_BUFFER_SIZE];
16059:
16060: if((hComm = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE) {
16061: if(GetCommProperties(hComm, &commProp)) {
16062: dwSettableBaud = commProp.dwSettableBaud;
16063: }
1.1.1.25 root 16064: EscapeCommFunction(hComm, CLRBREAK);
1.1.1.26 root 16065: // EscapeCommFunction(hComm, SETRTS);
16066: // EscapeCommFunction(hComm, SETDTR);
1.1.1.25 root 16067:
16068: while(!m_halted) {
16069: // setup comm port
16070: bool comm_state_changed = false;
16071:
16072: EnterCriticalSection(&q->csLineCtrl);
16073: if((p->prev_divisor != p->divisor.w || p->prev_line_ctrl != p->line_ctrl) && p->divisor.w != 0) {
16074: p->prev_divisor = p->divisor.w;
16075: p->prev_line_ctrl = p->line_ctrl;
16076: comm_state_changed = true;
16077: }
16078: LeaveCriticalSection(&q->csLineCtrl);
16079:
16080: if(comm_state_changed) {
1.1.1.26 root 16081: if(GetCommState(hComm, &dcb)) {
16082: // dcb.BaudRate = min(9600, 115200 / p->prev_divisor);
16083: DWORD baud = 115200 / p->prev_divisor;
16084: dcb.BaudRate = 9600; // default
16085:
16086: if((dwSettableBaud & BAUD_075 ) && baud >= 75 ) dcb.BaudRate = 75;
16087: if((dwSettableBaud & BAUD_110 ) && baud >= 110 ) dcb.BaudRate = 110;
16088: // 134.5bps is not supported ???
16089: // if((dwSettableBaud & BAUD_134_5) && baud >= 134.5) dcb.BaudRate = 134.5;
16090: if((dwSettableBaud & BAUD_150 ) && baud >= 150 ) dcb.BaudRate = 150;
16091: if((dwSettableBaud & BAUD_300 ) && baud >= 300 ) dcb.BaudRate = 300;
16092: if((dwSettableBaud & BAUD_600 ) && baud >= 600 ) dcb.BaudRate = 600;
16093: if((dwSettableBaud & BAUD_1200 ) && baud >= 1200 ) dcb.BaudRate = 1200;
16094: if((dwSettableBaud & BAUD_1800 ) && baud >= 1800 ) dcb.BaudRate = 1800;
16095: if((dwSettableBaud & BAUD_2400 ) && baud >= 2400 ) dcb.BaudRate = 2400;
16096: if((dwSettableBaud & BAUD_4800 ) && baud >= 4800 ) dcb.BaudRate = 4800;
16097: if((dwSettableBaud & BAUD_7200 ) && baud >= 7200 ) dcb.BaudRate = 7200;
16098: if((dwSettableBaud & BAUD_9600 ) && baud >= 9600 ) dcb.BaudRate = 9600;
16099: // if((dwSettableBaud & BAUD_14400) && baud >= 14400) dcb.BaudRate = 14400;
16100: // if((dwSettableBaud & BAUD_19200) && baud >= 19200) dcb.BaudRate = 19200;
16101: // if((dwSettableBaud & BAUD_38400) && baud >= 38400) dcb.BaudRate = 38400;
16102:
16103: switch(p->prev_line_ctrl & 0x03) {
16104: case 0x00: dcb.ByteSize = 5; break;
16105: case 0x01: dcb.ByteSize = 6; break;
16106: case 0x02: dcb.ByteSize = 7; break;
16107: case 0x03: dcb.ByteSize = 8; break;
16108: }
16109: switch(p->prev_line_ctrl & 0x04) {
16110: case 0x00: dcb.StopBits = ONESTOPBIT; break;
16111: case 0x04: dcb.StopBits = (dcb.ByteSize == 5) ? ONE5STOPBITS : TWOSTOPBITS; break;
16112: }
16113: switch(p->prev_line_ctrl & 0x38) {
16114: case 0x08: dcb.Parity = ODDPARITY; break;
16115: case 0x18: dcb.Parity = EVENPARITY; break;
16116: case 0x28: dcb.Parity = MARKPARITY; break;
16117: case 0x38: dcb.Parity = SPACEPARITY; break;
16118: default: dcb.Parity = NOPARITY; break;
16119: }
16120: dcb.fBinary = TRUE;
16121: dcb.fParity = (dcb.Parity != NOPARITY);
16122: dcb.fOutxCtsFlow = dcb.fOutxDsrFlow = TRUE;
16123: dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
16124: dcb.fDsrSensitivity = FALSE;//TRUE;
16125: dcb.fTXContinueOnXoff = TRUE;
16126: dcb.fOutX = dcb.fInX = FALSE;
16127: dcb.fErrorChar = FALSE;
16128: dcb.fNull = FALSE;
16129: dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
16130: dcb.fAbortOnError = FALSE;
16131:
16132: SetCommState(hComm, &dcb);
1.1.1.25 root 16133: }
16134:
16135: // check again to apply all comm state changes
16136: Sleep(10);
16137: continue;
16138: }
16139:
16140: // set comm pins
16141: bool change_brk = false;
1.1.1.26 root 16142: // bool change_rts = false;
16143: // bool change_dtr = false;
1.1.1.25 root 16144:
16145: EnterCriticalSection(&q->csModemCtrl);
16146: if(p->prev_set_brk != p->set_brk) {
16147: p->prev_set_brk = p->set_brk;
16148: change_brk = true;
16149: }
1.1.1.26 root 16150: // if(p->prev_set_rts != p->set_rts) {
16151: // p->prev_set_rts = p->set_rts;
16152: // change_rts = true;
16153: // }
16154: // if(p->prev_set_dtr != p->set_dtr) {
16155: // p->prev_set_dtr = p->set_dtr;
16156: // change_dtr = true;
16157: // }
1.1.1.25 root 16158: LeaveCriticalSection(&q->csModemCtrl);
16159:
16160: if(change_brk) {
1.1.1.26 root 16161: static UINT32 clear_time = 0;
16162: if(p->prev_set_brk) {
16163: EscapeCommFunction(hComm, SETBREAK);
16164: clear_time = timeGetTime() + 200;
16165: } else {
16166: // keep break for at least 200msec
16167: UINT32 cur_time = timeGetTime();
16168: if(clear_time > cur_time) {
16169: Sleep(clear_time - cur_time);
16170: }
16171: EscapeCommFunction(hComm, CLRBREAK);
16172: }
1.1.1.25 root 16173: }
1.1.1.26 root 16174: // if(change_rts) {
16175: // if(p->prev_set_rts) {
16176: // EscapeCommFunction(hComm, SETRTS);
16177: // } else {
16178: // EscapeCommFunction(hComm, CLRRTS);
16179: // }
16180: // }
16181: // if(change_dtr) {
16182: // if(p->prev_set_dtr) {
16183: // EscapeCommFunction(hComm, SETDTR);
16184: // } else {
16185: // EscapeCommFunction(hComm, CLRDTR);
16186: // }
16187: // }
1.1.1.25 root 16188:
16189: // get comm pins
16190: DWORD dwModemStat = 0;
16191:
16192: if(GetCommModemStatus(hComm, &dwModemStat)) {
16193: EnterCriticalSection(&q->csModemStat);
16194: if(dwModemStat & MS_RLSD_ON) {
16195: p->modem_stat |= 0x80;
16196: } else {
16197: p->modem_stat &= ~0x80;
16198: }
16199: if(dwModemStat & MS_RING_ON) {
16200: p->modem_stat |= 0x40;
16201: } else {
16202: p->modem_stat &= ~0x40;
16203: }
1.1.1.26 root 16204: // if(dwModemStat & MS_DSR_ON) {
16205: // p->modem_stat |= 0x20;
16206: // } else {
16207: // p->modem_stat &= ~0x20;
16208: // }
16209: // if(dwModemStat & MS_CTS_ON) {
16210: // p->modem_stat |= 0x10;
16211: // } else {
16212: // p->modem_stat &= ~0x10;
16213: // }
1.1.1.25 root 16214: if((p->prev_modem_stat & 0x80) != (p->modem_stat & 0x80)) {
16215: p->modem_stat |= 0x08;
16216: }
16217: if((p->prev_modem_stat & 0x40) && !(p->modem_stat & 0x40)) {
16218: p->modem_stat |= 0x04;
16219: }
1.1.1.26 root 16220: // if((p->prev_modem_stat & 0x20) != (p->modem_stat & 0x20)) {
16221: // p->modem_stat |= 0x02;
16222: // }
16223: // if((p->prev_modem_stat & 0x10) != (p->modem_stat & 0x10)) {
16224: // p->modem_stat |= 0x01;
16225: // }
1.1.1.25 root 16226: LeaveCriticalSection(&q->csModemStat);
16227: }
16228:
16229: // send data
16230: DWORD dwSend = 0;
16231:
16232: EnterCriticalSection(&q->csSendData);
1.1.1.32 root 16233: while(p->send_buffer != NULL && !p->send_buffer->empty()) {
1.1.1.25 root 16234: bytBuffer[dwSend++] = p->send_buffer->read();
16235: }
16236: LeaveCriticalSection(&q->csSendData);
16237:
16238: if(dwSend != 0) {
16239: DWORD dwWritten = 0;
16240: WriteFile(hComm, bytBuffer, dwSend, &dwWritten, NULL);
16241: }
16242:
16243: // get line status and recv data
16244: DWORD dwLineStat = 0;
16245: COMSTAT comStat;
16246:
16247: if(ClearCommError(hComm, &dwLineStat, &comStat)) {
16248: EnterCriticalSection(&q->csLineStat);
16249: if(dwLineStat & CE_BREAK) {
16250: p->line_stat_err |= 0x10;
16251: }
16252: if(dwLineStat & CE_FRAME) {
16253: p->line_stat_err |= 0x08;
16254: }
16255: if(dwLineStat & CE_RXPARITY) {
16256: p->line_stat_err |= 0x04;
16257: }
16258: if(dwLineStat & CE_OVERRUN) {
16259: p->line_stat_err |= 0x02;
16260: }
16261: LeaveCriticalSection(&q->csLineStat);
16262:
16263: if(comStat.cbInQue != 0) {
16264: EnterCriticalSection(&q->csRecvData);
1.1.1.32 root 16265: DWORD dwRecv = 0;
16266: if(p->recv_buffer != NULL) {
16267: dwRecv = min(comStat.cbInQue, p->recv_buffer->remain());
16268: }
1.1.1.25 root 16269: LeaveCriticalSection(&q->csRecvData);
16270:
16271: if(dwRecv != 0) {
16272: DWORD dwRead = 0;
16273: if(ReadFile(hComm, bytBuffer, dwRecv, &dwRead, NULL) && dwRead != 0) {
16274: EnterCriticalSection(&q->csRecvData);
1.1.1.32 root 16275: if(p->recv_buffer != NULL) {
16276: for(int i = 0; i < dwRead; i++) {
16277: p->recv_buffer->write(bytBuffer[i]);
16278: }
1.1.1.25 root 16279: }
16280: LeaveCriticalSection(&q->csRecvData);
16281: }
16282: }
16283: }
16284: }
16285: Sleep(10);
16286: }
16287: CloseHandle(hComm);
16288: }
16289: return 0;
16290: }
16291:
1.1.1.8 root 16292: // cmos
16293:
16294: void cmos_init()
16295: {
16296: memset(cmos, 0, sizeof(cmos));
16297: cmos_addr = 0;
1.1 root 16298:
1.1.1.8 root 16299: // from DOSBox
16300: cmos_write(0x0a, 0x26);
16301: cmos_write(0x0b, 0x02);
16302: cmos_write(0x0d, 0x80);
1.1 root 16303: }
16304:
1.1.1.8 root 16305: void cmos_write(int addr, UINT8 val)
1.1 root 16306: {
1.1.1.8 root 16307: cmos[addr & 0x7f] = val;
16308: }
16309:
16310: #define CMOS_GET_TIME() { \
16311: UINT32 cur_sec = timeGetTime() / 1000 ; \
16312: if(prev_sec != cur_sec) { \
16313: GetLocalTime(&time); \
16314: prev_sec = cur_sec; \
16315: } \
1.1 root 16316: }
1.1.1.8 root 16317: #define CMOS_BCD(v) ((cmos[0x0b] & 4) ? (v) : to_bcd(v))
1.1 root 16318:
1.1.1.8 root 16319: UINT8 cmos_read(int addr)
1.1 root 16320: {
1.1.1.8 root 16321: static SYSTEMTIME time;
16322: static UINT32 prev_sec = 0;
1.1 root 16323:
1.1.1.8 root 16324: switch(addr & 0x7f) {
16325: case 0x00: CMOS_GET_TIME(); return(CMOS_BCD(time.wSecond));
16326: case 0x02: CMOS_GET_TIME(); return(CMOS_BCD(time.wMinute));
16327: case 0x04: CMOS_GET_TIME(); return(CMOS_BCD(time.wHour));
16328: case 0x06: CMOS_GET_TIME(); return(time.wDayOfWeek + 1);
16329: case 0x07: CMOS_GET_TIME(); return(CMOS_BCD(time.wDay));
16330: case 0x08: CMOS_GET_TIME(); return(CMOS_BCD(time.wMonth));
16331: case 0x09: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear));
16332: // case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 2 ? 0x80 : 0)); // 2msec
16333: case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 20 ? 0x80 : 0)); // precision of timeGetTime() may not be 1msec
16334: case 0x15: return((MEMORY_END >> 10) & 0xff);
16335: case 0x16: return((MEMORY_END >> 18) & 0xff);
16336: case 0x17: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
16337: case 0x18: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
16338: case 0x30: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
16339: case 0x31: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
16340: case 0x32: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear / 100));
1.1 root 16341: }
1.1.1.8 root 16342: return(cmos[addr & 0x7f]);
1.1 root 16343: }
16344:
1.1.1.7 root 16345: // kbd (a20)
16346:
16347: void kbd_init()
16348: {
1.1.1.8 root 16349: kbd_data = kbd_command = 0;
1.1.1.7 root 16350: kbd_status = 0x18;
16351: }
16352:
16353: UINT8 kbd_read_data()
16354: {
1.1.1.8 root 16355: kbd_status &= ~1;
1.1.1.7 root 16356: return(kbd_data);
16357: }
16358:
16359: void kbd_write_data(UINT8 val)
16360: {
16361: switch(kbd_command) {
16362: case 0xd1:
16363: i386_set_a20_line((val >> 1) & 1);
16364: break;
16365: }
16366: kbd_command = 0;
1.1.1.8 root 16367: kbd_status &= ~8;
1.1.1.7 root 16368: }
16369:
16370: UINT8 kbd_read_status()
16371: {
16372: return(kbd_status);
16373: }
16374:
16375: void kbd_write_command(UINT8 val)
16376: {
16377: switch(val) {
16378: case 0xd0:
16379: kbd_data = ((m_a20_mask >> 19) & 2) | 1;
1.1.1.8 root 16380: kbd_status |= 1;
1.1.1.7 root 16381: break;
16382: case 0xdd:
16383: i386_set_a20_line(0);
16384: break;
16385: case 0xdf:
16386: i386_set_a20_line(1);
16387: break;
1.1.1.26 root 16388: case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
16389: case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
1.1.1.7 root 16390: if(!(val & 1)) {
1.1.1.8 root 16391: if((cmos[0x0f] & 0x7f) == 5) {
1.1.1.7 root 16392: // reset pic
16393: pic_init();
16394: pic[0].irr = pic[1].irr = 0x00;
16395: pic[0].imr = pic[1].imr = 0xff;
16396: }
16397: CPU_RESET_CALL(CPU_MODEL);
16398: i386_jmp_far(0x40, 0x67);
16399: }
16400: i386_set_a20_line((val >> 1) & 1);
16401: break;
16402: }
16403: kbd_command = val;
1.1.1.8 root 16404: kbd_status |= 8;
1.1.1.7 root 16405: }
16406:
1.1.1.9 root 16407: // vga
16408:
16409: UINT8 vga_read_status()
16410: {
16411: // 60hz
16412: static const int period[3] = {16, 17, 17};
16413: static int index = 0;
16414: UINT32 time = timeGetTime() % period[index];
16415:
16416: index = (index + 1) % 3;
1.1.1.14 root 16417: return((time < 4 ? 0x08 : 0) | (time == 0 ? 0 : 0x01));
1.1.1.9 root 16418: }
16419:
1.1 root 16420: // i/o bus
16421:
1.1.1.29 root 16422: // this is ugly patch for SW1US.EXE, it sometimes mistakely read/write 01h-10h for serial I/O
16423: //#define SW1US_PATCH
16424:
1.1.1.25 root 16425: UINT8 read_io_byte(offs_t addr)
1.1.1.33! root 16426: #ifdef USE_DEBUGGER
1.1.1.25 root 16427: {
1.1.1.33! root 16428: if(now_debugging) {
! 16429: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
! 16430: if(in_break_point.table[i].status == 1) {
! 16431: if(addr == in_break_point.table[i].addr) {
! 16432: in_break_point.hit = i + 1;
! 16433: now_suspended = true;
! 16434: break;
! 16435: }
! 16436: }
! 16437: }
1.1.1.25 root 16438: }
1.1.1.33! root 16439: return(debugger_read_io_byte(addr));
1.1.1.25 root 16440: }
1.1.1.33! root 16441: UINT8 debugger_read_io_byte(offs_t addr)
1.1.1.25 root 16442: #endif
1.1 root 16443: {
1.1.1.33! root 16444: UINT8 val = 0xff;
! 16445:
1.1 root 16446: switch(addr) {
1.1.1.29 root 16447: #ifdef SW1US_PATCH
16448: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08:
16449: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: case 0x10:
1.1.1.33! root 16450: val = sio_read(0, addr - 1);
! 16451: break;
1.1.1.29 root 16452: #else
1.1.1.25 root 16453: case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
16454: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
1.1.1.33! root 16455: val = dma_read(0, addr);
! 16456: break;
1.1.1.29 root 16457: #endif
1.1.1.25 root 16458: case 0x20: case 0x21:
1.1.1.33! root 16459: val = pic_read(0, addr);
! 16460: break;
1.1.1.25 root 16461: case 0x40: case 0x41: case 0x42: case 0x43:
1.1.1.33! root 16462: val = pit_read(addr & 0x03);
! 16463: break;
1.1.1.7 root 16464: case 0x60:
1.1.1.33! root 16465: val = kbd_read_data();
! 16466: break;
1.1.1.9 root 16467: case 0x61:
1.1.1.33! root 16468: val = system_port;
! 16469: break;
1.1.1.7 root 16470: case 0x64:
1.1.1.33! root 16471: val = kbd_read_status();
! 16472: break;
1.1 root 16473: case 0x71:
1.1.1.33! root 16474: val = cmos_read(cmos_addr);
! 16475: break;
1.1.1.25 root 16476: case 0x81:
1.1.1.33! root 16477: val = dma_page_read(0, 2);
! 16478: break;
1.1.1.25 root 16479: case 0x82:
1.1.1.33! root 16480: val = dma_page_read(0, 3);
! 16481: break;
1.1.1.25 root 16482: case 0x83:
1.1.1.33! root 16483: val = dma_page_read(0, 1);
! 16484: break;
1.1.1.25 root 16485: case 0x87:
1.1.1.33! root 16486: val = dma_page_read(0, 0);
! 16487: break;
1.1.1.25 root 16488: case 0x89:
1.1.1.33! root 16489: val = dma_page_read(1, 2);
! 16490: break;
1.1.1.25 root 16491: case 0x8a:
1.1.1.33! root 16492: val = dma_page_read(1, 3);
! 16493: break;
1.1.1.25 root 16494: case 0x8b:
1.1.1.33! root 16495: val = dma_page_read(1, 1);
! 16496: break;
1.1.1.25 root 16497: case 0x8f:
1.1.1.33! root 16498: val = dma_page_read(1, 0);
! 16499: break;
1.1 root 16500: case 0x92:
1.1.1.33! root 16501: val = (m_a20_mask >> 19) & 2;
! 16502: break;
1.1.1.25 root 16503: case 0xa0: case 0xa1:
1.1.1.33! root 16504: val = pic_read(1, addr);
! 16505: break;
1.1.1.25 root 16506: case 0xc0: case 0xc2: case 0xc4: case 0xc6: case 0xc8: case 0xca: case 0xcc: case 0xce:
16507: case 0xd0: case 0xd2: case 0xd4: case 0xd6: case 0xd8: case 0xda: case 0xdc: case 0xde:
1.1.1.33! root 16508: val = dma_read(1, (addr - 0xc0) >> 1);
! 16509: break;
1.1.1.26 root 16510: // case 0x278: case 0x279: case 0x27a:
1.1.1.33! root 16511: // val = pio_read(1, addr);
! 16512: // break;
1.1.1.29 root 16513: case 0x2e8: case 0x2e9: case 0x2ea: case 0x2eb: case 0x2ec: case 0x2ed: case 0x2ee: case 0x2ef:
1.1.1.33! root 16514: val = sio_read(3, addr);
! 16515: break;
1.1.1.25 root 16516: case 0x2f8: case 0x2f9: case 0x2fa: case 0x2fb: case 0x2fc: case 0x2fd: case 0x2fe: case 0x2ff:
1.1.1.33! root 16517: val = sio_read(1, addr);
! 16518: break;
1.1.1.25 root 16519: case 0x378: case 0x379: case 0x37a:
1.1.1.33! root 16520: val = pio_read(0, addr);
! 16521: break;
1.1.1.25 root 16522: case 0x3ba: case 0x3da:
1.1.1.33! root 16523: val = vga_read_status();
! 16524: break;
1.1.1.29 root 16525: case 0x3e8: case 0x3e9: case 0x3ea: case 0x3eb: case 0x3ec: case 0x3ed: case 0x3ee: case 0x3ef:
1.1.1.33! root 16526: val = sio_read(2, addr);
! 16527: break;
1.1.1.25 root 16528: case 0x3f8: case 0x3f9: case 0x3fa: case 0x3fb: case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff:
1.1.1.33! root 16529: val = sio_read(0, addr);
! 16530: break;
1.1 root 16531: default:
1.1.1.33! root 16532: // fatalerror("unknown inb %4x\n", addr);
1.1 root 16533: break;
16534: }
1.1.1.33! root 16535: #ifdef ENABLE_DEBUG_IOPORT
! 16536: if(fp_debug_log != NULL) {
! 16537: fprintf(fp_debug_log, "inb %04X, %02X\n", addr, val);
! 16538: }
! 16539: #endif
! 16540: return(val);
1.1 root 16541: }
16542:
16543: UINT16 read_io_word(offs_t addr)
16544: {
16545: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8));
16546: }
16547:
1.1.1.33! root 16548: #ifdef USE_DEBUGGER
! 16549: UINT16 debugger_read_io_word(offs_t addr)
! 16550: {
! 16551: return(debugger_read_io_byte(addr) | (debugger_read_io_byte(addr + 1) << 8));
! 16552: }
! 16553: #endif
! 16554:
1.1 root 16555: UINT32 read_io_dword(offs_t addr)
16556: {
16557: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8) | (read_io_byte(addr + 2) << 16) | (read_io_byte(addr + 3) << 24));
16558: }
16559:
1.1.1.33! root 16560: #ifdef USE_DEBUGGER
! 16561: UINT32 debugger_read_io_dword(offs_t addr)
! 16562: {
! 16563: return(debugger_read_io_byte(addr) | (debugger_read_io_byte(addr + 1) << 8) | (debugger_read_io_byte(addr + 2) << 16) | (debugger_read_io_byte(addr + 3) << 24));
! 16564: }
! 16565: #endif
! 16566:
1.1 root 16567: void write_io_byte(offs_t addr, UINT8 val)
1.1.1.33! root 16568: #ifdef USE_DEBUGGER
! 16569: {
! 16570: if(now_debugging) {
! 16571: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
! 16572: if(out_break_point.table[i].status == 1) {
! 16573: if(addr == out_break_point.table[i].addr) {
! 16574: out_break_point.hit = i + 1;
! 16575: now_suspended = true;
! 16576: break;
! 16577: }
! 16578: }
! 16579: }
! 16580: }
! 16581: debugger_write_io_byte(addr, val);
! 16582: }
! 16583: void debugger_write_io_byte(offs_t addr, UINT8 val)
! 16584: #endif
1.1 root 16585: {
1.1.1.25 root 16586: #ifdef ENABLE_DEBUG_IOPORT
1.1.1.33! root 16587: if(fp_debug_log != NULL) {
! 16588: fprintf(fp_debug_log, "outb %04X, %02X\n", addr, val);
1.1.1.25 root 16589: }
16590: #endif
1.1 root 16591: switch(addr) {
1.1.1.29 root 16592: #ifdef SW1US_PATCH
16593: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08:
16594: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: case 0x10:
16595: sio_write(0, addr - 1, val);
16596: break;
16597: #else
1.1.1.25 root 16598: case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
16599: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
16600: dma_write(0, addr, val);
16601: break;
1.1.1.29 root 16602: #endif
1.1.1.25 root 16603: case 0x20: case 0x21:
1.1 root 16604: pic_write(0, addr, val);
16605: break;
1.1.1.25 root 16606: case 0x40: case 0x41: case 0x42: case 0x43:
1.1 root 16607: pit_write(addr & 0x03, val);
16608: break;
1.1.1.7 root 16609: case 0x60:
16610: kbd_write_data(val);
16611: break;
1.1.1.9 root 16612: case 0x61:
16613: if((system_port & 3) != 3 && (val & 3) == 3) {
16614: // beep on
16615: // MessageBeep(-1);
16616: } else if((system_port & 3) == 3 && (val & 3) != 3) {
16617: // beep off
16618: }
16619: system_port = val;
16620: break;
1.1 root 16621: case 0x64:
1.1.1.7 root 16622: kbd_write_command(val);
1.1 root 16623: break;
16624: case 0x70:
16625: cmos_addr = val;
16626: break;
16627: case 0x71:
1.1.1.8 root 16628: cmos_write(cmos_addr, val);
1.1 root 16629: break;
1.1.1.25 root 16630: case 0x81:
16631: dma_page_write(0, 2, val);
16632: case 0x82:
16633: dma_page_write(0, 3, val);
16634: case 0x83:
16635: dma_page_write(0, 1, val);
16636: case 0x87:
16637: dma_page_write(0, 0, val);
16638: case 0x89:
16639: dma_page_write(1, 2, val);
16640: case 0x8a:
16641: dma_page_write(1, 3, val);
16642: case 0x8b:
16643: dma_page_write(1, 1, val);
16644: case 0x8f:
16645: dma_page_write(1, 0, val);
1.1 root 16646: case 0x92:
1.1.1.7 root 16647: i386_set_a20_line((val >> 1) & 1);
1.1 root 16648: break;
1.1.1.25 root 16649: case 0xa0: case 0xa1:
1.1 root 16650: pic_write(1, addr, val);
16651: break;
1.1.1.25 root 16652: case 0xc0: case 0xc2: case 0xc4: case 0xc6: case 0xc8: case 0xca: case 0xcc: case 0xce:
16653: case 0xd0: case 0xd2: case 0xd4: case 0xd6: case 0xd8: case 0xda: case 0xdc: case 0xde:
1.1.1.26 root 16654: dma_write(1, (addr - 0xc0) >> 1, val);
1.1.1.25 root 16655: break;
1.1.1.26 root 16656: // case 0x278: case 0x279: case 0x27a:
16657: // pio_write(1, addr, val);
16658: // break;
1.1.1.29 root 16659: case 0x2e8: case 0x2e9: case 0x2ea: case 0x2eb: case 0x2ec: case 0x2ed: case 0x2ee: case 0x2ef:
16660: sio_write(3, addr, val);
16661: break;
1.1.1.25 root 16662: case 0x2f8: case 0x2f9: case 0x2fa: case 0x2fb: case 0x2fc: case 0x2fd: case 0x2fe: case 0x2ff:
16663: sio_write(1, addr, val);
16664: break;
16665: case 0x378: case 0x379: case 0x37a:
16666: pio_write(0, addr, val);
16667: break;
1.1.1.29 root 16668: case 0x3e8: case 0x3e9: case 0x3ea: case 0x3eb: case 0x3ec: case 0x3ed: case 0x3ee: case 0x3ef:
16669: sio_write(2, addr, val);
16670: break;
1.1.1.25 root 16671: case 0x3f8: case 0x3f9: case 0x3fa: case 0x3fb: case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff:
16672: sio_write(0, addr, val);
16673: break;
1.1 root 16674: default:
1.1.1.33! root 16675: // fatalerror("unknown outb %4x,%2x\n", addr, val);
1.1 root 16676: break;
16677: }
16678: }
16679:
16680: void write_io_word(offs_t addr, UINT16 val)
16681: {
16682: write_io_byte(addr + 0, (val >> 0) & 0xff);
16683: write_io_byte(addr + 1, (val >> 8) & 0xff);
16684: }
16685:
1.1.1.33! root 16686: #ifdef USE_DEBUGGER
! 16687: void debugger_write_io_word(offs_t addr, UINT16 val)
! 16688: {
! 16689: debugger_write_io_byte(addr + 0, (val >> 0) & 0xff);
! 16690: debugger_write_io_byte(addr + 1, (val >> 8) & 0xff);
! 16691: }
! 16692: #endif
! 16693:
1.1 root 16694: void write_io_dword(offs_t addr, UINT32 val)
16695: {
16696: write_io_byte(addr + 0, (val >> 0) & 0xff);
16697: write_io_byte(addr + 1, (val >> 8) & 0xff);
16698: write_io_byte(addr + 2, (val >> 16) & 0xff);
16699: write_io_byte(addr + 3, (val >> 24) & 0xff);
16700: }
1.1.1.33! root 16701:
! 16702: #ifdef USE_DEBUGGER
! 16703: void debugger_write_io_dword(offs_t addr, UINT32 val)
! 16704: {
! 16705: debugger_write_io_byte(addr + 0, (val >> 0) & 0xff);
! 16706: debugger_write_io_byte(addr + 1, (val >> 8) & 0xff);
! 16707: debugger_write_io_byte(addr + 2, (val >> 16) & 0xff);
! 16708: debugger_write_io_byte(addr + 3, (val >> 24) & 0xff);
! 16709: }
! 16710: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.