|
|
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:
20: //#define ENABLE_DEBUG
21: #ifdef ENABLE_DEBUG
22: #define EXPORT_DEBUG_TO_FILE
23: #define ENABLE_DEBUG_DASM
24: #define ENABLE_DEBUG_SYSCALL
25: #define ENABLE_DEBUG_UNIMPLEMENTED
1.1.1.25 root 26: #define ENABLE_DEBUG_IOPORT
1.1.1.22 root 27:
28: #ifdef EXPORT_DEBUG_TO_FILE
29: FILE* fdebug = NULL;
30: #else
31: #define fdebug stderr
32: #endif
33: #ifdef ENABLE_DEBUG_UNIMPLEMENTED
34: #define unimplemented_10h fatalerror
1.1.1.25 root 35: #define unimplemented_14h fatalerror
1.1.1.22 root 36: #define unimplemented_15h fatalerror
37: #define unimplemented_16h fatalerror
38: #define unimplemented_1ah fatalerror
39: #define unimplemented_21h fatalerror
40: #define unimplemented_2fh fatalerror
1.1.1.24 root 41: #define unimplemented_33h fatalerror
1.1.1.22 root 42: #define unimplemented_67h fatalerror
43: #define unimplemented_xms fatalerror
44: #endif
45: #endif
46: #ifndef unimplemented_10h
47: #define unimplemented_10h nolog
48: #endif
1.1.1.25 root 49: #ifndef unimplemented_14h
50: #define unimplemented_14h nolog
51: #endif
1.1.1.22 root 52: #ifndef unimplemented_15h
53: #define unimplemented_15h nolog
54: #endif
55: #ifndef unimplemented_16h
56: #define unimplemented_16h nolog
57: #endif
58: #ifndef unimplemented_1ah
59: #define unimplemented_1ah nolog
60: #endif
61: #ifndef unimplemented_21h
62: #define unimplemented_21h nolog
63: #endif
64: #ifndef unimplemented_2fh
65: #define unimplemented_2fh nolog
66: #endif
1.1.1.24 root 67: #ifndef unimplemented_33h
68: #define unimplemented_33h nolog
69: #endif
1.1.1.22 root 70: #ifndef unimplemented_67h
71: #define unimplemented_67h nolog
72: #endif
73: #ifndef unimplemented_xms
74: #define unimplemented_xms nolog
75: #endif
76:
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 ctrl_break = false;
126: bool stay_busy = false;
127: UINT32 iops = 0;
1.1.1.19 root 128: bool support_ems = false;
129: #ifdef SUPPORT_XMS
130: bool support_xms = false;
131: #endif
1.1.1.29! root 132: int sio_port_number[4] = {0, 0, 0, 0};
1.1.1.14 root 133:
134: BOOL is_vista_or_later;
135:
136: inline void maybe_idle()
137: {
138: // if it appears to be in a tight loop, assume waiting for input
139: // allow for one updated video character, for a spinning cursor
140: if(!stay_busy && iops < 1000 && vram_length_char <= 1 && vram_length_attr <= 1) {
141: Sleep(10);
142: }
143: iops = 0;
144: }
1.1.1.12 root 145:
1.1 root 146: /* ----------------------------------------------------------------------------
1.1.1.3 root 147: MAME i86/i386
1.1 root 148: ---------------------------------------------------------------------------- */
149:
1.1.1.10 root 150: #ifndef __BIG_ENDIAN__
1.1 root 151: #define LSB_FIRST
1.1.1.10 root 152: #endif
1.1 root 153:
154: #ifndef INLINE
155: #define INLINE inline
156: #endif
157: #define U64(v) UINT64(v)
158:
159: //#define logerror(...) fprintf(stderr, __VA_ARGS__)
160: #define logerror(...)
161: //#define popmessage(...) fprintf(stderr, __VA_ARGS__)
162: #define popmessage(...)
163:
164: /*****************************************************************************/
1.1.1.10 root 165: /* src/emu/devcpu.h */
166:
167: // CPU interface functions
168: #define CPU_INIT_NAME(name) cpu_init_##name
169: #define CPU_INIT(name) void CPU_INIT_NAME(name)()
170: #define CPU_INIT_CALL(name) CPU_INIT_NAME(name)()
171:
172: #define CPU_RESET_NAME(name) cpu_reset_##name
173: #define CPU_RESET(name) void CPU_RESET_NAME(name)()
174: #define CPU_RESET_CALL(name) CPU_RESET_NAME(name)()
175:
176: #define CPU_EXECUTE_NAME(name) cpu_execute_##name
177: #define CPU_EXECUTE(name) void CPU_EXECUTE_NAME(name)()
178: #define CPU_EXECUTE_CALL(name) CPU_EXECUTE_NAME(name)()
179:
180: #define CPU_TRANSLATE_NAME(name) cpu_translate_##name
181: #define CPU_TRANSLATE(name) int CPU_TRANSLATE_NAME(name)(address_spacenum space, int intention, offs_t *address)
182: #define CPU_TRANSLATE_CALL(name) CPU_TRANSLATE_NAME(name)(space, intention, address)
183:
184: #define CPU_DISASSEMBLE_NAME(name) cpu_disassemble_##name
185: #define CPU_DISASSEMBLE(name) int CPU_DISASSEMBLE_NAME(name)(char *buffer, offs_t eip, const UINT8 *oprom)
186: #define CPU_DISASSEMBLE_CALL(name) CPU_DISASSEMBLE_NAME(name)(buffer, eip, oprom)
187:
1.1.1.14 root 188: #define CPU_MODEL_STR(name) #name
189: #define CPU_MODEL_NAME(name) CPU_MODEL_STR(name)
190:
1.1.1.10 root 191: /*****************************************************************************/
192: /* src/emu/didisasm.h */
193:
194: // Disassembler constants
195: const UINT32 DASMFLAG_SUPPORTED = 0x80000000; // are disassembly flags supported?
196: const UINT32 DASMFLAG_STEP_OUT = 0x40000000; // this instruction should be the end of a step out sequence
197: const UINT32 DASMFLAG_STEP_OVER = 0x20000000; // this instruction should be stepped over by setting a breakpoint afterwards
198: const UINT32 DASMFLAG_OVERINSTMASK = 0x18000000; // number of extra instructions to skip when stepping over
199: const UINT32 DASMFLAG_OVERINSTSHIFT = 27; // bits to shift after masking to get the value
200: const UINT32 DASMFLAG_LENGTHMASK = 0x0000ffff; // the low 16-bits contain the actual length
201:
202: /*****************************************************************************/
1.1 root 203: /* src/emu/diexec.h */
204:
205: // I/O line states
206: enum line_state
207: {
208: CLEAR_LINE = 0, // clear (a fired or held) line
209: ASSERT_LINE, // assert an interrupt immediately
210: HOLD_LINE, // hold interrupt line until acknowledged
211: PULSE_LINE // pulse interrupt line instantaneously (only for NMI, RESET)
212: };
213:
214: // I/O line definitions
215: enum
216: {
217: INPUT_LINE_IRQ = 0,
218: INPUT_LINE_NMI
219: };
220:
221: /*****************************************************************************/
1.1.1.10 root 222: /* src/emu/dimemory.h */
1.1 root 223:
1.1.1.10 root 224: // Translation intentions
225: const int TRANSLATE_TYPE_MASK = 0x03; // read write or fetch
226: const int TRANSLATE_USER_MASK = 0x04; // user mode or fully privileged
227: const int TRANSLATE_DEBUG_MASK = 0x08; // debug mode (no side effects)
228:
229: const int TRANSLATE_READ = 0; // translate for read
230: const int TRANSLATE_WRITE = 1; // translate for write
231: const int TRANSLATE_FETCH = 2; // translate for instruction fetch
232: const int TRANSLATE_READ_USER = (TRANSLATE_READ | TRANSLATE_USER_MASK);
233: const int TRANSLATE_WRITE_USER = (TRANSLATE_WRITE | TRANSLATE_USER_MASK);
234: const int TRANSLATE_FETCH_USER = (TRANSLATE_FETCH | TRANSLATE_USER_MASK);
235: const int TRANSLATE_READ_DEBUG = (TRANSLATE_READ | TRANSLATE_DEBUG_MASK);
236: const int TRANSLATE_WRITE_DEBUG = (TRANSLATE_WRITE | TRANSLATE_DEBUG_MASK);
237: const int TRANSLATE_FETCH_DEBUG = (TRANSLATE_FETCH | TRANSLATE_DEBUG_MASK);
1.1 root 238:
1.1.1.10 root 239: /*****************************************************************************/
240: /* src/emu/emucore.h */
1.1 root 241:
1.1.1.10 root 242: // constants for expression endianness
243: enum endianness_t
244: {
245: ENDIANNESS_LITTLE,
246: ENDIANNESS_BIG
247: };
1.1 root 248:
1.1.1.10 root 249: // declare native endianness to be one or the other
250: #ifdef LSB_FIRST
251: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_LITTLE;
252: #else
253: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_BIG;
254: #endif
255:
256: // endian-based value: first value is if 'endian' is little-endian, second is if 'endian' is big-endian
257: #define ENDIAN_VALUE_LE_BE(endian,leval,beval) (((endian) == ENDIANNESS_LITTLE) ? (leval) : (beval))
258:
259: // endian-based value: first value is if native endianness is little-endian, second is if native is big-endian
260: #define NATIVE_ENDIAN_VALUE_LE_BE(leval,beval) ENDIAN_VALUE_LE_BE(ENDIANNESS_NATIVE, leval, beval)
261:
262: // endian-based value: first value is if 'endian' matches native, second is if 'endian' doesn't match native
263: #define ENDIAN_VALUE_NE_NNE(endian,leval,beval) (((endian) == ENDIANNESS_NATIVE) ? (neval) : (nneval))
1.1 root 264:
265: /*****************************************************************************/
266: /* src/emu/memory.h */
267:
1.1.1.10 root 268: // address spaces
269: enum address_spacenum
270: {
271: AS_0, // first address space
272: AS_1, // second address space
273: AS_2, // third address space
274: AS_3, // fourth address space
275: ADDRESS_SPACES, // maximum number of address spaces
276:
277: // alternate address space names for common use
278: AS_PROGRAM = AS_0, // program address space
279: AS_DATA = AS_1, // data address space
280: AS_IO = AS_2 // I/O address space
281: };
282:
1.1 root 283: // offsets and addresses are 32-bit (for now...)
284: typedef UINT32 offs_t;
285:
286: // read accessors
287: UINT8 read_byte(offs_t byteaddress)
288: {
1.1.1.4 root 289: #if defined(HAS_I386)
1.1 root 290: if(byteaddress < MAX_MEM) {
291: return mem[byteaddress];
1.1.1.3 root 292: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
293: // return read_byte(byteaddress & 0xfffff);
1.1 root 294: }
295: return 0;
1.1.1.4 root 296: #else
297: return mem[byteaddress];
298: #endif
1.1 root 299: }
300:
301: UINT16 read_word(offs_t byteaddress)
302: {
1.1.1.14 root 303: if(byteaddress == 0x41c) {
304: // pointer to first free slot in keyboard buffer
305: // XXX: the buffer itself doesn't actually exist in DOS memory
306: if(key_buf_char->count() == 0) {
307: maybe_idle();
308: }
309: return (UINT16)key_buf_char->count();
310: }
1.1.1.4 root 311: #if defined(HAS_I386)
1.1 root 312: if(byteaddress < MAX_MEM - 1) {
313: return *(UINT16 *)(mem + byteaddress);
1.1.1.3 root 314: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
315: // return read_word(byteaddress & 0xfffff);
1.1 root 316: }
317: return 0;
1.1.1.4 root 318: #else
319: return *(UINT16 *)(mem + byteaddress);
320: #endif
1.1 root 321: }
322:
323: UINT32 read_dword(offs_t byteaddress)
324: {
1.1.1.4 root 325: #if defined(HAS_I386)
1.1 root 326: if(byteaddress < MAX_MEM - 3) {
327: return *(UINT32 *)(mem + byteaddress);
1.1.1.3 root 328: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
329: // return read_dword(byteaddress & 0xfffff);
1.1 root 330: }
331: return 0;
1.1.1.4 root 332: #else
333: return *(UINT32 *)(mem + byteaddress);
334: #endif
1.1 root 335: }
336:
337: // write accessors
1.1.1.14 root 338: #ifdef USE_THREAD
339: void vram_flush_char()
340: {
341: if(vram_length_char != 0) {
342: DWORD num;
1.1.1.23 root 343: WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), scr_char, vram_length_char, vram_coord_char, &num);
1.1.1.14 root 344: vram_length_char = vram_last_length_char = 0;
345: }
346: }
347:
348: void vram_flush_attr()
349: {
350: if(vram_length_attr != 0) {
351: DWORD num;
1.1.1.23 root 352: WriteConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), scr_attr, vram_length_attr, vram_coord_attr, &num);
1.1.1.14 root 353: vram_length_attr = vram_last_length_attr = 0;
354: }
355: }
356:
357: void vram_flush()
358: {
359: if(vram_length_char != 0 || vram_length_attr != 0) {
360: EnterCriticalSection(&vram_crit_sect);
361: vram_flush_char();
362: vram_flush_attr();
363: LeaveCriticalSection(&vram_crit_sect);
364: }
365: }
366: #endif
367:
368: void write_text_vram_char(offs_t offset, UINT8 data)
1.1.1.8 root 369: {
1.1.1.14 root 370: #ifdef USE_THREAD
371: static offs_t first_offset_char, last_offset_char;
372:
373: if(vram_length_char != 0) {
374: if(offset <= last_offset_char && offset >= first_offset_char) {
375: scr_char[(offset - first_offset_char) >> 1] = data;
376: return;
377: }
378: if(offset != last_offset_char + 2) {
379: vram_flush_char();
380: }
381: }
382: if(vram_length_char == 0) {
383: first_offset_char = offset;
384: vram_coord_char.X = (offset >> 1) % scr_width;
385: vram_coord_char.Y = (offset >> 1) / scr_width + scr_top;
386: }
387: scr_char[vram_length_char++] = data;
388: last_offset_char = offset;
389: #else
1.1.1.8 root 390: COORD co;
391: DWORD num;
392:
1.1.1.14 root 393: co.X = (offset >> 1) % scr_width;
394: co.Y = (offset >> 1) / scr_width;
395: scr_char[0] = data;
1.1.1.23 root 396: WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), scr_char, 1, co, &num);
1.1.1.14 root 397: #endif
398: }
399:
400: void write_text_vram_attr(offs_t offset, UINT8 data)
401: {
402: #ifdef USE_THREAD
403: static offs_t first_offset_attr, last_offset_attr;
404:
405: if(vram_length_attr != 0) {
406: if(offset <= last_offset_attr && offset >= first_offset_attr) {
407: scr_attr[(offset - first_offset_attr) >> 1] = data;
408: return;
409: }
410: if(offset != last_offset_attr + 2) {
411: vram_flush_attr();
412: }
413: }
414: if(vram_length_attr == 0) {
415: first_offset_attr = offset;
416: vram_coord_attr.X = (offset >> 1) % scr_width;
417: vram_coord_attr.Y = (offset >> 1) / scr_width + scr_top;
418: }
419: scr_attr[vram_length_attr++] = data;
420: last_offset_attr = offset;
421: #else
422: COORD co;
423: DWORD num;
1.1.1.8 root 424:
1.1.1.14 root 425: co.X = (offset >> 1) % scr_width;
426: co.Y = (offset >> 1) / scr_width;
427: scr_attr[0] = data;
1.1.1.23 root 428: WriteConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), scr_attr, 1, co, &num);
1.1.1.14 root 429: #endif
430: }
431:
432: void write_text_vram_byte(offs_t offset, UINT8 data)
433: {
434: EnterCriticalSection(&vram_crit_sect);
1.1.1.8 root 435: if(offset & 1) {
1.1.1.14 root 436: write_text_vram_attr(offset, data);
1.1.1.8 root 437: } else {
1.1.1.14 root 438: write_text_vram_char(offset, data);
1.1.1.8 root 439: }
1.1.1.14 root 440: LeaveCriticalSection(&vram_crit_sect);
1.1.1.8 root 441: }
442:
443: void write_text_vram_word(offs_t offset, UINT16 data)
444: {
1.1.1.14 root 445: EnterCriticalSection(&vram_crit_sect);
1.1.1.8 root 446: if(offset & 1) {
1.1.1.14 root 447: write_text_vram_attr(offset , (data ) & 0xff);
448: write_text_vram_char(offset + 1, (data >> 8) & 0xff);
1.1.1.8 root 449: } else {
1.1.1.14 root 450: write_text_vram_char(offset , (data ) & 0xff);
451: write_text_vram_attr(offset + 1, (data >> 8) & 0xff);
1.1.1.8 root 452: }
1.1.1.14 root 453: LeaveCriticalSection(&vram_crit_sect);
1.1.1.8 root 454: }
455:
456: void write_text_vram_dword(offs_t offset, UINT32 data)
457: {
1.1.1.14 root 458: EnterCriticalSection(&vram_crit_sect);
1.1.1.8 root 459: if(offset & 1) {
1.1.1.14 root 460: write_text_vram_attr(offset , (data ) & 0xff);
461: write_text_vram_char(offset + 1, (data >> 8) & 0xff);
462: write_text_vram_attr(offset + 2, (data >> 16) & 0xff);
463: write_text_vram_char(offset + 3, (data >> 24) & 0xff);
464: } else {
465: write_text_vram_char(offset , (data ) & 0xff);
466: write_text_vram_attr(offset + 1, (data >> 8) & 0xff);
467: write_text_vram_char(offset + 2, (data >> 16) & 0xff);
468: write_text_vram_attr(offset + 3, (data >> 24) & 0xff);
1.1.1.8 root 469: }
1.1.1.14 root 470: LeaveCriticalSection(&vram_crit_sect);
1.1.1.8 root 471: }
472:
1.1 root 473: void write_byte(offs_t byteaddress, UINT8 data)
474: {
1.1.1.8 root 475: if(byteaddress < MEMORY_END) {
1.1.1.3 root 476: mem[byteaddress] = data;
1.1.1.8 root 477: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 478: if(!restore_console_on_exit) {
479: change_console_size(scr_width, scr_height);
1.1.1.12 root 480: }
1.1.1.8 root 481: write_text_vram_byte(byteaddress - text_vram_top_address, data);
482: mem[byteaddress] = data;
483: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
484: if(int_10h_feh_called && !int_10h_ffh_called) {
485: write_text_vram_byte(byteaddress - shadow_buffer_top_address, data);
1.1 root 486: }
487: mem[byteaddress] = data;
1.1.1.4 root 488: #if defined(HAS_I386)
1.1.1.3 root 489: } else if(byteaddress < MAX_MEM) {
1.1.1.4 root 490: #else
491: } else {
492: #endif
1.1.1.3 root 493: mem[byteaddress] = data;
1.1 root 494: }
495: }
496:
497: void write_word(offs_t byteaddress, UINT16 data)
498: {
1.1.1.8 root 499: if(byteaddress < MEMORY_END) {
1.1.1.14 root 500: if(byteaddress == 0x450 + mem[0x462] * 2) {
501: COORD co;
502: co.X = data & 0xff;
503: co.Y = (data >> 8) + scr_top;
1.1.1.23 root 504: SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), co);
1.1.1.14 root 505: }
1.1.1.3 root 506: *(UINT16 *)(mem + byteaddress) = data;
1.1.1.8 root 507: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 508: if(!restore_console_on_exit) {
509: change_console_size(scr_width, scr_height);
1.1.1.12 root 510: }
1.1.1.8 root 511: write_text_vram_word(byteaddress - text_vram_top_address, data);
512: *(UINT16 *)(mem + byteaddress) = data;
513: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
514: if(int_10h_feh_called && !int_10h_ffh_called) {
515: write_text_vram_word(byteaddress - shadow_buffer_top_address, data);
1.1 root 516: }
517: *(UINT16 *)(mem + byteaddress) = data;
1.1.1.4 root 518: #if defined(HAS_I386)
1.1.1.3 root 519: } else if(byteaddress < MAX_MEM - 1) {
1.1.1.4 root 520: #else
521: } else {
522: #endif
1.1.1.3 root 523: *(UINT16 *)(mem + byteaddress) = data;
1.1 root 524: }
525: }
526:
527: void write_dword(offs_t byteaddress, UINT32 data)
528: {
1.1.1.8 root 529: if(byteaddress < MEMORY_END) {
1.1.1.3 root 530: *(UINT32 *)(mem + byteaddress) = data;
1.1.1.8 root 531: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 532: if(!restore_console_on_exit) {
533: change_console_size(scr_width, scr_height);
1.1.1.12 root 534: }
1.1.1.8 root 535: write_text_vram_dword(byteaddress - text_vram_top_address, data);
536: *(UINT32 *)(mem + byteaddress) = data;
537: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
538: if(int_10h_feh_called && !int_10h_ffh_called) {
539: write_text_vram_dword(byteaddress - shadow_buffer_top_address, data);
1.1 root 540: }
541: *(UINT32 *)(mem + byteaddress) = data;
1.1.1.4 root 542: #if defined(HAS_I386)
1.1.1.3 root 543: } else if(byteaddress < MAX_MEM - 3) {
1.1.1.4 root 544: #else
545: } else {
546: #endif
1.1.1.3 root 547: *(UINT32 *)(mem + byteaddress) = data;
1.1 root 548: }
549: }
550:
551: #define read_decrypted_byte read_byte
552: #define read_decrypted_word read_word
553: #define read_decrypted_dword read_dword
554:
1.1.1.3 root 555: #define read_raw_byte read_byte
556: #define write_raw_byte write_byte
557:
558: #define read_word_unaligned read_word
559: #define write_word_unaligned write_word
560:
561: #define read_io_word_unaligned read_io_word
562: #define write_io_word_unaligned write_io_word
563:
1.1 root 564: UINT8 read_io_byte(offs_t byteaddress);
565: UINT16 read_io_word(offs_t byteaddress);
566: UINT32 read_io_dword(offs_t byteaddress);
567:
568: void write_io_byte(offs_t byteaddress, UINT8 data);
569: void write_io_word(offs_t byteaddress, UINT16 data);
570: void write_io_dword(offs_t byteaddress, UINT32 data);
571:
572: /*****************************************************************************/
573: /* src/osd/osdcomm.h */
574:
575: /* Highly useful macro for compile-time knowledge of an array size */
576: #define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0]))
577:
1.1.1.3 root 578: #if defined(HAS_I386)
1.1.1.10 root 579: static CPU_TRANSLATE(i386);
580: #include "mame/lib/softfloat/softfloat.c"
581: #include "mame/emu/cpu/i386/i386.c"
1.1.1.12 root 582: #include "mame/emu/cpu/vtlb.c"
1.1.1.3 root 583: #elif defined(HAS_I286)
1.1.1.10 root 584: #include "mame/emu/cpu/i86/i286.c"
1.1.1.3 root 585: #else
1.1.1.10 root 586: #include "mame/emu/cpu/i86/i86.c"
1.1.1.3 root 587: #endif
1.1.1.22 root 588: #ifdef ENABLE_DEBUG_DASM
1.1.1.10 root 589: #include "mame/emu/cpu/i386/i386dasm.c"
1.1.1.22 root 590: int dasm = 0;
1.1 root 591: #endif
592:
1.1.1.3 root 593: #if defined(HAS_I386)
594: #define SREG(x) m_sreg[x].selector
595: #define SREG_BASE(x) m_sreg[x].base
596:
597: int cpu_type, cpu_step;
598: #else
599: #define REG8(x) m_regs.b[x]
600: #define REG16(x) m_regs.w[x]
601: #define SREG(x) m_sregs[x]
602: #define SREG_BASE(x) m_base[x]
603: #define m_CF m_CarryVal
604: #define m_a20_mask AMASK
605: #define i386_load_segment_descriptor(x) m_base[x] = SegBase(x)
606: #if defined(HAS_I286)
607: #define i386_set_a20_line(x) i80286_set_a20_line(x)
608: #else
609: #define i386_set_a20_line(x)
610: #endif
611: #define i386_set_irq_line(x, y) set_irq_line(x, y)
612: #endif
1.1 root 613:
614: void i386_jmp_far(UINT16 selector, UINT32 address)
615: {
1.1.1.3 root 616: #if defined(HAS_I386)
1.1 root 617: if(PROTECTED_MODE && !V8086_MODE) {
1.1.1.3 root 618: i386_protected_mode_jump(selector, address, 1, m_operand_size);
1.1 root 619: } else {
1.1.1.3 root 620: SREG(CS) = selector;
621: m_performed_intersegment_jump = 1;
622: i386_load_segment_descriptor(CS);
623: m_eip = address;
624: CHANGE_PC(m_eip);
1.1 root 625: }
1.1.1.3 root 626: #elif defined(HAS_I286)
627: i80286_code_descriptor(selector, address, 1);
628: #else
629: SREG(CS) = selector;
630: i386_load_segment_descriptor(CS);
631: m_pc = (SREG_BASE(CS) + address) & m_a20_mask;
632: #endif
1.1 root 633: }
634:
1.1.1.24 root 635: /*
636: void i386_call_far(UINT16 selector, UINT32 address)
637: {
638: #if defined(HAS_I386)
639: if(PROTECTED_MODE && !V8086_MODE) {
640: i386_protected_mode_call(selector, address, 1, m_operand_size);
641: } else {
642: PUSH16(SREG(CS));
643: PUSH16(m_eip);
644: SREG(CS) = selector;
645: m_performed_intersegment_jump = 1;
646: i386_load_segment_descriptor(CS);
647: m_eip = address;
648: CHANGE_PC(m_eip);
649: }
650: #else
651: UINT16 ip = m_pc - SREG_BASE(CS);
652: UINT16 cs = SREG(CS);
653: #if defined(HAS_I286)
654: i80286_code_descriptor(selector, address, 2);
655: #else
656: SREG(CS) = selector;
657: i386_load_segment_descriptor(CS);
658: m_pc = (SREG_BASE(CS) + address) & m_a20_mask;
659: #endif
660: PUSH(cs);
661: PUSH(ip);
662: CHANGE_PC(m_pc);
663: #endif
664: }
665: */
666:
1.1.1.29! root 667: UINT16 i386_read_stack()
! 668: {
! 669: #if defined(HAS_I386)
! 670: UINT32 ea, new_esp;
! 671: if( STACK_32BIT ) {
! 672: new_esp = REG32(ESP) + 2;
! 673: ea = i386_translate(SS, new_esp - 2, 0);
! 674: } else {
! 675: new_esp = REG16(SP) + 2;
! 676: ea = i386_translate(SS, (new_esp - 2) & 0xffff, 0);
! 677: }
! 678: return READ16(ea);
! 679: #else
! 680: UINT16 sp = m_regs.w[SP] + 2;
! 681: return ReadWord(((m_base[SS] + ((sp - 2) & 0xffff)) & AMASK));
! 682: #endif
! 683: }
! 684:
1.1 root 685: /* ----------------------------------------------------------------------------
686: main
687: ---------------------------------------------------------------------------- */
688:
1.1.1.28 root 689: BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
690: {
691: if(dwCtrlType == CTRL_BREAK_EVENT) {
692: // try to finish this program normally
693: m_halted = true;
694: return TRUE;
695: } else if(dwCtrlType == CTRL_C_EVENT) {
696: ctrl_c_pressed = true;
697: return TRUE;
698: } else if(dwCtrlType == CTRL_CLOSE_EVENT) {
699: // this program will be terminated abnormally, do minimum end process
700: exit_handler();
701: exit(1);
702: }
703: return FALSE;
704: }
705:
706: void exit_handler()
707: {
708: if(temp_file_created) {
709: DeleteFile(temp_file_path);
710: temp_file_created = false;
711: }
712: if(key_buf_char != NULL) {
713: key_buf_char->release();
714: delete key_buf_char;
715: key_buf_char = NULL;
716: }
717: if(key_buf_scan != NULL) {
718: key_buf_scan->release();
719: delete key_buf_scan;
720: key_buf_scan = NULL;
721: }
722: hardware_release();
723: }
724:
725: #ifdef USE_THREAD
726: DWORD WINAPI vram_thread(LPVOID)
727: {
728: while(!m_halted) {
729: EnterCriticalSection(&vram_crit_sect);
730: if(vram_length_char != 0 && vram_length_char == vram_last_length_char) {
731: vram_flush_char();
732: }
733: if(vram_length_attr != 0 && vram_length_attr == vram_last_length_attr) {
734: vram_flush_attr();
735: }
736: vram_last_length_char = vram_length_char;
737: vram_last_length_attr = vram_length_attr;
738: LeaveCriticalSection(&vram_crit_sect);
739: // this is about half the maximum keyboard repeat rate - any
740: // lower tends to be jerky, any higher misses updates
741: Sleep(15);
742: }
743: return 0;
744: }
745: #endif
746:
747: long get_section_in_exec_file(FILE *fp, char *name)
748: {
749: UINT8 header[0x400];
750:
751: long position = ftell(fp);
752: fseek(fp, 0, SEEK_SET);
753: fread(header, sizeof(header), 1, fp);
754: fseek(fp, position, SEEK_SET);
755:
756: try {
757: _IMAGE_DOS_HEADER *dosHeader = (_IMAGE_DOS_HEADER *)(header + 0);
758: DWORD dwTopOfSignature = dosHeader->e_lfanew;
759: DWORD dwTopOfCoffHeader = dwTopOfSignature + 4;
760: _IMAGE_FILE_HEADER *coffHeader = (_IMAGE_FILE_HEADER *)(header + dwTopOfCoffHeader);
761: DWORD dwTopOfOptionalHeader = dwTopOfCoffHeader + sizeof(_IMAGE_FILE_HEADER);
762: DWORD dwTopOfFirstSectionHeader = dwTopOfOptionalHeader + coffHeader->SizeOfOptionalHeader;
763:
764: for(int i = 0; i < coffHeader->NumberOfSections; i++) {
765: _IMAGE_SECTION_HEADER *sectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * i);
766: if(memcmp(sectionHeader->Name, name, strlen(name)) == 0) {
767: return(sectionHeader->PointerToRawData);
768: }
769: }
770: } catch(...) {
771: }
772: return(0);
773: }
774:
1.1.1.10 root 775: bool is_started_from_command_prompt()
776: {
1.1.1.18 root 777: bool ret = false;
778:
779: HMODULE hLibrary = LoadLibrary(_T("Kernel32.dll"));
780: if(hLibrary) {
781: typedef DWORD (WINAPI *GetConsoleProcessListFunction)(__out LPDWORD lpdwProcessList, __in DWORD dwProcessCount);
782: GetConsoleProcessListFunction lpfnGetConsoleProcessList;
783: lpfnGetConsoleProcessList = reinterpret_cast<GetConsoleProcessListFunction>(::GetProcAddress(hLibrary, "GetConsoleProcessList"));
784: if(lpfnGetConsoleProcessList) {
785: DWORD pl;
786: ret = (lpfnGetConsoleProcessList(&pl, 1) > 1);
787: FreeLibrary(hLibrary);
788: return(ret);
789: }
790: FreeLibrary(hLibrary);
791: }
792:
793: HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
794: if(hSnapshot != INVALID_HANDLE_VALUE) {
795: DWORD dwParentProcessID = 0;
796: PROCESSENTRY32 pe32;
797: pe32.dwSize = sizeof(PROCESSENTRY32);
798: if(Process32First(hSnapshot, &pe32)) {
799: do {
800: if(pe32.th32ProcessID == GetCurrentProcessId()) {
801: dwParentProcessID = pe32.th32ParentProcessID;
802: break;
803: }
804: } while(Process32Next(hSnapshot, &pe32));
805: }
806: CloseHandle(hSnapshot);
807: if(dwParentProcessID != 0) {
808: HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwParentProcessID);
809: if(hProcess != NULL) {
810: HMODULE hMod;
811: DWORD cbNeeded;
812: if(EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {
813: char module_name[MAX_PATH];
814: if(GetModuleBaseName(hProcess, hMod, module_name, sizeof(module_name))) {
815: ret = (_strnicmp(module_name, "cmd.exe", 7) == 0);
816: }
817: }
818: CloseHandle(hProcess);
819: }
820: }
821: }
822: return(ret);
1.1.1.14 root 823: }
824:
825: BOOL is_greater_windows_version(DWORD dwMajorVersion, DWORD dwMinorVersion, WORD wServicePackMajor, WORD wServicePackMinor)
826: {
1.1.1.24 root 827: // https://msdn.microsoft.com/en-us/library/windows/desktop/ms725491(v=vs.85).aspx
1.1.1.14 root 828: OSVERSIONINFOEX osvi;
829: DWORDLONG dwlConditionMask = 0;
830: int op = VER_GREATER_EQUAL;
831:
832: // Initialize the OSVERSIONINFOEX structure.
833: ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
834: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
835: osvi.dwMajorVersion = dwMajorVersion;
836: osvi.dwMinorVersion = dwMinorVersion;
837: osvi.wServicePackMajor = wServicePackMajor;
838: osvi.wServicePackMinor = wServicePackMinor;
839:
840: // Initialize the condition mask.
841: VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, op );
842: VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, op );
843: VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, op );
844: VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMINOR, op );
845:
846: // Perform the test.
847: return VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, dwlConditionMask);
848: }
849:
1.1.1.27 root 850: void get_sio_port_numbers()
851: {
852: SP_DEVINFO_DATA DeviceInfoData = {sizeof(SP_DEVINFO_DATA)};
853: HDEVINFO hDevInfo = 0;
854: HKEY hKey = 0;
855: if((hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_COMPORT, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE))) != 0) {
856: for(int i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData); i++) {
857: if((hKey = SetupDiOpenDevRegKey(hDevInfo, &DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE)) != INVALID_HANDLE_VALUE) {
858: char chData[256];
859: DWORD dwType = 0;
860: DWORD dwSize = sizeof(chData);
861: int port_number = 0;
862:
863: if(RegQueryValueEx(hKey, _T("PortName"), NULL, &dwType, (BYTE *)chData, &dwSize) == ERROR_SUCCESS) {
864: if(_strnicmp(chData, "COM", 3) == 0) {
865: port_number = atoi(chData + 3);
866: }
867: }
868: RegCloseKey(hKey);
869:
1.1.1.29! root 870: 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 871: continue;
872: }
873: if(sio_port_number[0] == 0) {
874: sio_port_number[0] = port_number;
875: } else if(sio_port_number[1] == 0) {
876: sio_port_number[1] = port_number;
1.1.1.29! root 877: } else if(sio_port_number[2] == 0) {
! 878: sio_port_number[2] = port_number;
! 879: } else if(sio_port_number[3] == 0) {
! 880: sio_port_number[3] = port_number;
1.1.1.27 root 881: }
1.1.1.29! root 882: 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 883: break;
884: }
885: }
886: }
887: }
888: }
889:
1.1.1.28 root 890: #define IS_NUMERIC(c) ((c) >= '0' && (c) <= '9')
891:
1.1 root 892: int main(int argc, char *argv[], char *envp[])
893: {
1.1.1.9 root 894: int arg_offset = 0;
895: int standard_env = 0;
1.1.1.14 root 896: int buf_width = 0, buf_height = 0;
1.1.1.28 root 897: bool get_console_info_success = false;
898: bool screen_size_changed = false;
899:
900: _TCHAR path[MAX_PATH], full[MAX_PATH], *name = NULL;
901: GetModuleFileName(NULL, path, MAX_PATH);
902: GetFullPathName(path, MAX_PATH, full, &name);
1.1 root 903:
1.1.1.27 root 904: char dummy_argv_0[] = "msdos.exe";
905: char dummy_argv_1[MAX_PATH];
906: char *dummy_argv[256] = {dummy_argv_0, dummy_argv_1, 0};
907: char new_exec_file[MAX_PATH];
908: bool convert_cmd_file = false;
1.1.1.28 root 909: unsigned int code_page = 0;
1.1.1.27 root 910:
911: if(name != NULL && stricmp(name, "msdos.exe") != 0) {
1.1.1.28 root 912: // check if command file is embedded to this execution file
913: // if this execution file name is msdos.exe, don't check
1.1.1.27 root 914: FILE* fp = fopen(full, "rb");
1.1.1.28 root 915: long offset = get_section_in_exec_file(fp, ".msdos");
916: if(offset != 0) {
917: UINT8 buffer[14];
918: fseek(fp, offset, SEEK_SET);
919: fread(buffer, sizeof(buffer), 1, fp);
920:
921: // restore flags
922: stay_busy = ((buffer[0] & 0x01) != 0);
923: no_windows = ((buffer[0] & 0x02) != 0);
924: standard_env = ((buffer[0] & 0x04) != 0);
925: ignore_illegal_insn = ((buffer[0] & 0x08) != 0);
926: limit_max_memory = ((buffer[0] & 0x10) != 0);
927: if((buffer[0] & 0x20) != 0) {
928: get_sio_port_numbers();
929: }
930: if((buffer[0] & 0x40) != 0) {
931: UMB_TOP = EMS_TOP + EMS_SIZE;
932: support_ems = true;
1.1.1.27 root 933: #ifdef SUPPORT_XMS
1.1.1.28 root 934: support_xms = true;
1.1.1.27 root 935: #endif
1.1.1.28 root 936: }
937: if((buffer[1] != 0 || buffer[2] != 0) && (buffer[3] != 0 || buffer[4] != 0)) {
938: buf_width = buffer[1] | (buffer[2] << 8);
939: buf_height = buffer[3] | (buffer[4] << 8);
940: }
941: if(buffer[5] != 0) {
942: major_version = buffer[5];
943: minor_version = buffer[6];
944: }
945: if((code_page = buffer[7] | (buffer[8] << 8)) != 0) {
946: SetConsoleCP(code_page);
947: SetConsoleOutputCP(code_page);
948: }
949: int name_len = buffer[9];
950: int file_len = buffer[10] | (buffer[11] << 8) | (buffer[12] << 16) | (buffer[13] << 24);
951:
952: // restore command file name
953: memset(dummy_argv_1, 0, sizeof(dummy_argv_1));
954: fread(dummy_argv_1, name_len, 1, fp);
955:
956: if(name_len != 0 && _access(dummy_argv_1, 0) == 0) {
957: // if original command file exists, create a temporary file name
958: if(GetTempFileName(_T("."), _T("DOS"), 0, dummy_argv_1) != 0) {
959: // create a temporary command file in the current director
960: DeleteFile(dummy_argv_1);
1.1.1.27 root 961: } else {
1.1.1.28 root 962: // create a temporary command file in the temporary folder
963: GetTempPath(MAX_PATH, path);
964: if(GetTempFileName(path, _T("DOS"), 0, dummy_argv_1) != 0) {
965: DeleteFile(dummy_argv_1);
966: } else {
967: sprintf(dummy_argv_1, "%s$DOSPRG$.TMP", path);
968: }
1.1.1.27 root 969: }
1.1.1.28 root 970: // check the command file type
971: fread(buffer, 2, 1, fp);
972: fseek(fp, -2, SEEK_CUR);
973: if(memcmp(buffer, "MZ", 2) != 0) {
974: memcpy(dummy_argv_1 + strlen(dummy_argv_1) - 4, ".COM", 4);
975: } else {
976: memcpy(dummy_argv_1 + strlen(dummy_argv_1) - 4, ".EXE", 4);
1.1.1.27 root 977: }
978: }
1.1.1.28 root 979:
980: // restore command file
981: FILE* fo = fopen(dummy_argv_1, "wb");
982: for(int i = 0; i < file_len; i++) {
983: fputc(fgetc(fp), fo);
984: }
985: fclose(fo);
986:
987: GetFullPathName(dummy_argv_1, MAX_PATH, temp_file_path, NULL);
988: temp_file_created = true;
989: SetFileAttributes(temp_file_path, FILE_ATTRIBUTE_HIDDEN);
990:
991: // adjust argc/argv
992: for(int i = 1; i < argc && (i + 1) < 256; i++) {
993: dummy_argv[i + 1] = argv[i];
994: }
995: argc++;
996: argv = dummy_argv;
1.1.1.27 root 997: }
998: fclose(fp);
999: }
1.1.1.9 root 1000: for(int i = 1; i < argc; i++) {
1.1.1.25 root 1001: if(_strnicmp(argv[i], "-b", 2) == 0) {
1002: stay_busy = true;
1003: arg_offset++;
1.1.1.27 root 1004: } else if(_strnicmp(argv[i], "-c", 2) == 0) {
1005: if(argv[i][2] != '\0') {
1006: strcpy(new_exec_file, &argv[i][2]);
1007: } else {
1008: strcpy(new_exec_file, "new_exec_file.exe");
1009: }
1010: convert_cmd_file = true;
1011: arg_offset++;
1.1.1.28 root 1012: } else if(_strnicmp(argv[i], "-p", 2) == 0) {
1013: if(IS_NUMERIC(argv[i][2])) {
1014: code_page = atoi(&argv[i][2]);
1015: } else {
1016: code_page = GetConsoleCP();
1017: }
1018: arg_offset++;
1.1.1.25 root 1019: } else if(_strnicmp(argv[i], "-d", 2) == 0) {
1020: no_windows = true;
1021: arg_offset++;
1022: } else if(_strnicmp(argv[i], "-e", 2) == 0) {
1.1.1.9 root 1023: standard_env = 1;
1024: arg_offset++;
1.1.1.14 root 1025: } else if(_strnicmp(argv[i], "-i", 2) == 0) {
1026: ignore_illegal_insn = true;
1027: arg_offset++;
1028: } else if(_strnicmp(argv[i], "-m", 2) == 0) {
1029: limit_max_memory = true;
1030: arg_offset++;
1031: } else if(_strnicmp(argv[i], "-n", 2) == 0) {
1.1.1.17 root 1032: if(sscanf(argv[1] + 2, "%d,%d", &buf_height, &buf_width) != 2) {
1033: buf_width = buf_height = 0;
1034: }
1035: if(buf_width <= 0 || buf_width > 0x7fff) {
1036: buf_width = 80;
1037: }
1038: if(buf_height <= 0 || buf_height > 0x7fff) {
1039: buf_height = 25;
1040: }
1.1.1.14 root 1041: arg_offset++;
1.1.1.25 root 1042: } else if(_strnicmp(argv[i], "-s", 2) == 0) {
1.1.1.28 root 1043: if(IS_NUMERIC(argv[i][2])) {
1.1.1.29! root 1044: char *p0 = &argv[i][2], *p1, *p2, *p3;
! 1045: if((p1 = strchr(p0, ',')) != NULL && IS_NUMERIC(p1[1])) {
! 1046: sio_port_number[1] = atoi(p1 + 1);
! 1047: if((p2 = strchr(p1, ',')) != NULL && IS_NUMERIC(p2[1])) {
! 1048: sio_port_number[2] = atoi(p2 + 1);
! 1049: if((p3 = strchr(p2, ',')) != NULL && IS_NUMERIC(p3[1])) {
! 1050: sio_port_number[3] = atoi(p3 + 1);
! 1051: }
! 1052: }
1.1.1.25 root 1053: }
1.1.1.29! root 1054: sio_port_number[0] = atoi(p0);
1.1.1.25 root 1055: }
1.1.1.29! root 1056: 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 1057: get_sio_port_numbers();
1.1.1.25 root 1058: }
1059: arg_offset++;
1.1.1.9 root 1060: } else if(_strnicmp(argv[i], "-v", 2) == 0) {
1.1.1.17 root 1061: 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.9 root 1062: major_version = argv[i][2] - '0';
1.1.1.17 root 1063: minor_version = (argv[i][4] - '0') * 10 + (argv[i][5] ? (argv[i][5] - '0') : 0);
1.1.1.9 root 1064: }
1065: arg_offset++;
1.1.1.25 root 1066: } else if(_strnicmp(argv[i], "-x", 2) == 0) {
1067: UMB_TOP = EMS_TOP + EMS_SIZE;
1068: support_ems = true;
1069: #ifdef SUPPORT_XMS
1070: support_xms = true;
1071: #endif
1072: arg_offset++;
1.1.1.9 root 1073: } else {
1074: break;
1075: }
1076: }
1077: if(argc < 2 + arg_offset) {
1.1 root 1078: #ifdef _WIN64
1.1.1.14 root 1079: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32-x64 console\n\n");
1.1 root 1080: #else
1.1.1.14 root 1081: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32 console\n\n");
1.1 root 1082: #endif
1.1.1.25 root 1083: fprintf(stderr,
1.1.1.28 root 1084: "Usage: MSDOS [-b] [-c[(new exec file)] [-p[P]]] [-d] [-e] [-i] [-m] [-n[L[,C]]]\n"
1.1.1.29! root 1085: " [-s[P1[,P2[,P3[,P4]]]]] [-vX.XX] [-x] (command file) [options]\n"
1.1.1.25 root 1086: "\n"
1087: "\t-b\tstay busy during keyboard polling\n"
1.1.1.28 root 1088: #ifdef _WIN64
1.1.1.27 root 1089: "\t-c\tconvert command file to 64bit execution file\n"
1.1.1.28 root 1090: #else
1.1.1.27 root 1091: "\t-c\tconvert command file to 32bit execution file\n"
1092: #endif
1.1.1.28 root 1093: "\t-p\trecord current code page when convert command file\n"
1.1.1.25 root 1094: "\t-d\tpretend running under straight DOS, not Windows\n"
1095: "\t-e\tuse a reduced environment block\n"
1096: "\t-i\tignore invalid instructions\n"
1097: "\t-m\trestrict free memory to 0x7FFF paragraphs\n"
1098: "\t-n\tcreate a new buffer (25 lines, 80 columns by default)\n"
1099: "\t-s\tenable serial I/O and set host's COM port numbers\n"
1100: "\t-v\tset the DOS version\n"
1.1.1.19 root 1101: #ifdef SUPPORT_XMS
1.1.1.28 root 1102: "\t-x\tenable XMS and LIM EMS\n"
1.1.1.19 root 1103: #else
1.1.1.28 root 1104: "\t-x\tenable LIM EMS\n"
1.1.1.19 root 1105: #endif
1106: );
1.1.1.10 root 1107:
1108: if(!is_started_from_command_prompt()) {
1109: fprintf(stderr, "\nStart this program from a command prompt!\n\nHit any key to quit...");
1110: while(!_kbhit()) {
1111: Sleep(10);
1112: }
1113: }
1.1.1.20 root 1114: #ifdef _DEBUG
1115: _CrtDumpMemoryLeaks();
1116: #endif
1.1 root 1117: return(EXIT_FAILURE);
1118: }
1.1.1.27 root 1119: if(convert_cmd_file) {
1120: retval = EXIT_FAILURE;
1.1.1.28 root 1121: if(name != NULL/* && stricmp(name, "msdos.exe") == 0*/) {
1.1.1.27 root 1122: FILE *fp = NULL, *fs = NULL, *fo = NULL;
1.1.1.28 root 1123: int len = strlen(argv[arg_offset + 1]), data;
1.1.1.27 root 1124:
1.1.1.28 root 1125: if(!(len > 4 && (stricmp(argv[arg_offset + 1] + len - 4, ".COM") == 0 || stricmp(argv[arg_offset + 1] + len - 4, ".EXE") == 0))) {
1126: fprintf(stderr, "Specify command file with extenstion (.COM or .EXE)\n");
1127: } else if((fp = fopen(full, "rb")) == NULL) {
1128: fprintf(stderr, "Can't open '%s'\n", name);
1.1.1.27 root 1129: } else {
1.1.1.28 root 1130: long offset = get_section_in_exec_file(fp, ".msdos");
1131: if(offset != 0) {
1132: UINT8 buffer[14];
1133: fseek(fp, offset, SEEK_SET);
1134: fread(buffer, sizeof(buffer), 1, fp);
1135: memset(path, 0, sizeof(path));
1136: fread(path, buffer[9], 1, fp);
1137: fprintf(stderr, "Command file '%s' was already embedded to '%s'\n", path, name);
1138: } else if((fs = fopen(argv[arg_offset + 1], "rb")) == NULL) {
1139: fprintf(stderr, "Can't open '%s'\n", argv[arg_offset + 1]);
1140: } else if((fo = fopen(new_exec_file, "wb")) == NULL) {
1141: fprintf(stderr, "Can't open '%s'\n", new_exec_file);
1142: } else {
1143: // read pe header of msdos.exe
1144: UINT8 header[0x400];
1145: fseek(fp, 0, SEEK_SET);
1146: fread(header, sizeof(header), 1, fp);
1147:
1148: _IMAGE_DOS_HEADER *dosHeader = (_IMAGE_DOS_HEADER *)(header + 0);
1149: DWORD dwTopOfSignature = dosHeader->e_lfanew;
1150: DWORD dwTopOfCoffHeader = dwTopOfSignature + 4;
1151: _IMAGE_FILE_HEADER *coffHeader = (_IMAGE_FILE_HEADER *)(header + dwTopOfCoffHeader);
1152: DWORD dwTopOfOptionalHeader = dwTopOfCoffHeader + sizeof(_IMAGE_FILE_HEADER);
1153: _IMAGE_OPTIONAL_HEADER *optionalHeader = (_IMAGE_OPTIONAL_HEADER *)(header + dwTopOfOptionalHeader);
1154: DWORD dwTopOfFirstSectionHeader = dwTopOfOptionalHeader + coffHeader->SizeOfOptionalHeader;
1155:
1156: _IMAGE_SECTION_HEADER *lastSectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * (coffHeader->NumberOfSections - 1));
1157: DWORD dwEndOfFile = lastSectionHeader->PointerToRawData + lastSectionHeader->SizeOfRawData;
1158: DWORD dwLastSectionSize = lastSectionHeader->SizeOfRawData;
1159: DWORD dwExtraLastSectionBytes = dwLastSectionSize % optionalHeader->SectionAlignment;
1160: if(dwExtraLastSectionBytes != 0) {
1161: DWORD dwRemain = optionalHeader->SectionAlignment - dwExtraLastSectionBytes;
1162: dwLastSectionSize += dwRemain;
1163: }
1164: DWORD dwVirtualAddress = lastSectionHeader->VirtualAddress + dwLastSectionSize;
1165:
1166: // store msdos.exe
1167: fseek(fp, 0, SEEK_SET);
1168: for(int i = 0; i < dwEndOfFile; i++) {
1169: if((data = fgetc(fp)) != EOF) {
1170: fputc(data, fo);
1171: } else {
1172: // we should not reach here :-(
1173: fputc(0, fo);
1174: }
1175: }
1176:
1177: // store options
1178: UINT8 flags = 0;
1179: if(stay_busy) {
1180: flags |= 0x01;
1181: }
1182: if(no_windows) {
1183: flags |= 0x02;
1184: }
1185: if(standard_env) {
1186: flags |= 0x04;
1187: }
1188: if(ignore_illegal_insn) {
1189: flags |= 0x08;
1190: }
1191: if(limit_max_memory) {
1192: flags |= 0x10;
1193: }
1.1.1.29! root 1194: 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 1195: flags |= 0x20;
1196: }
1197: if(support_ems) {
1198: flags |= 0x40;
1199: }
1200:
1201: fputc(flags, fo);
1202: fputc((buf_width >> 0) & 0xff, fo);
1203: fputc((buf_width >> 8) & 0xff, fo);
1204: fputc((buf_height >> 0) & 0xff, fo);
1205: fputc((buf_height >> 8) & 0xff, fo);
1206: fputc(major_version, fo);
1207: fputc(minor_version, fo);
1208: fputc((code_page >> 0) & 0xff, fo);
1209: fputc((code_page >> 8) & 0xff, fo);
1210:
1211: // store command file info
1212: GetFullPathName(argv[arg_offset + 1], MAX_PATH, full, &name);
1213: int name_len = strlen(name);
1214: fseek(fs, 0, SEEK_END);
1215: long file_size = ftell(fs);
1216:
1217: fputc(name_len, fo);
1218: fputc((file_size >> 0) & 0xff, fo);
1219: fputc((file_size >> 8) & 0xff, fo);
1220: fputc((file_size >> 16) & 0xff, fo);
1221: fputc((file_size >> 24) & 0xff, fo);
1222: fwrite(name, name_len, 1, fo);
1223:
1224: // store command file
1225: fseek(fs, 0, SEEK_SET);
1226: for(int i = 0; i < file_size; i++) {
1227: if((data = fgetc(fs)) != EOF) {
1228: fputc(data, fo);
1229: } else {
1230: // we should not reach here :-(
1231: fputc(0, fo);
1232: }
1233: }
1234:
1235: // store padding data and update pe header
1.1.1.29! root 1236: _IMAGE_SECTION_HEADER *newSectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * coffHeader->NumberOfSections);
! 1237: coffHeader->NumberOfSections++;
! 1238: memset(newSectionHeader, 0, IMAGE_SIZEOF_SECTION_HEADER);
! 1239: memcpy(newSectionHeader->Name, ".msdos", 6);
! 1240: newSectionHeader->VirtualAddress = dwVirtualAddress;
! 1241: newSectionHeader->PointerToRawData = dwEndOfFile;
! 1242: newSectionHeader->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE;
1.1.1.28 root 1243: newSectionHeader->SizeOfRawData = 14 + name_len + file_size;
1244: DWORD dwExtraRawBytes = newSectionHeader->SizeOfRawData % optionalHeader->FileAlignment;
1245: if(dwExtraRawBytes != 0) {
1.1.1.29! root 1246: static const char padding[] = "PADDINGXXPADDING";
1.1.1.28 root 1247: DWORD dwRemain = optionalHeader->FileAlignment - dwExtraRawBytes;
1248: for(int i = 0; i < dwRemain; i++) {
1.1.1.29! root 1249: if(i < 2) {
! 1250: fputc(padding[i & 15], fo);
! 1251: } else {
! 1252: fputc(padding[(i - 2) & 15], fo);
! 1253: }
1.1.1.28 root 1254: }
1255: newSectionHeader->SizeOfRawData += dwRemain;
1256: }
1257: newSectionHeader->Misc.VirtualSize = newSectionHeader->SizeOfRawData;
1258:
1259: DWORD dwNewSectionSize = newSectionHeader->SizeOfRawData;
1260: DWORD dwExtraNewSectionBytes = dwNewSectionSize % optionalHeader->SectionAlignment;
1261: if(dwExtraNewSectionBytes != 0) {
1262: DWORD dwRemain = optionalHeader->SectionAlignment - dwExtraNewSectionBytes;
1263: dwNewSectionSize += dwRemain;
1264: }
1265: optionalHeader->SizeOfImage += dwNewSectionSize;
1266:
1267: fseek(fo, 0, SEEK_SET);
1268: fwrite(header, sizeof(header), 1, fo);
1269:
1270: fprintf(stderr, "'%s' is successfully created\n", new_exec_file);
1271: retval = EXIT_SUCCESS;
1.1.1.27 root 1272: }
1273: }
1274: if(fp != NULL) {
1275: fclose(fp);
1276: }
1277: if(fs != NULL) {
1278: fclose(fs);
1279: }
1280: if(fo != NULL) {
1281: fclose(fo);
1282: }
1283: }
1284: #ifdef _DEBUG
1285: _CrtDumpMemoryLeaks();
1286: #endif
1287: return(retval);
1288: }
1.1 root 1289:
1.1.1.14 root 1290: is_vista_or_later = is_greater_windows_version(6, 0, 0, 0);
1291:
1.1.1.23 root 1292: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 1293: CONSOLE_SCREEN_BUFFER_INFO csbi;
1.1.1.14 root 1294: CONSOLE_CURSOR_INFO ci;
1.1.1.23 root 1295:
1.1.1.28 root 1296: get_console_info_success = (GetConsoleScreenBufferInfo(hStdout, &csbi) != 0);
1.1.1.14 root 1297: GetConsoleCursorInfo(hStdout, &ci);
1.1.1.24 root 1298: GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwConsoleMode);
1.1 root 1299:
1.1.1.14 root 1300: for(int y = 0; y < SCR_BUF_WIDTH; y++) {
1301: for(int x = 0; x < SCR_BUF_HEIGHT; x++) {
1302: SCR_BUF(y,x).Char.AsciiChar = ' ';
1303: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 1304: }
1305: }
1.1.1.28 root 1306: if(get_console_info_success) {
1.1.1.12 root 1307: scr_width = csbi.dwSize.X;
1.1.1.14 root 1308: scr_height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
1309:
1.1.1.28 root 1310: // v-text shadow buffer size must be lesser than 0x7fd0
1311: if((scr_width > SCR_BUF_WIDTH) || (scr_height > SCR_BUF_HEIGHT) || (scr_width * scr_height * 2 > 0x7fd0) ||
1.1.1.14 root 1312: (buf_width != 0 && buf_width != scr_width) || (buf_height != 0 && buf_height != scr_height)) {
1313: scr_width = min(buf_width != 0 ? buf_width : scr_width, SCR_BUF_WIDTH);
1314: scr_height = min(buf_height != 0 ? buf_height : scr_height, SCR_BUF_HEIGHT);
1.1.1.28 root 1315: if(scr_width * scr_height * 2 > 0x7fd0) {
1.1.1.14 root 1316: scr_width = 80;
1317: scr_height = 25;
1318: }
1.1.1.28 root 1319: screen_size_changed = true;
1.1.1.14 root 1320: }
1.1.1.12 root 1321: } else {
1322: // for a proof (not a console)
1323: scr_width = 80;
1324: scr_height = 25;
1325: }
1.1.1.14 root 1326: scr_buf_size.X = scr_width;
1327: scr_buf_size.Y = scr_height;
1328: scr_buf_pos.X = scr_buf_pos.Y = 0;
1329: scr_top = csbi.srWindow.Top;
1.1 root 1330: cursor_moved = false;
1331:
1.1.1.25 root 1332: key_buf_char = new FIFO(256);
1333: key_buf_scan = new FIFO(256);
1.1 root 1334:
1335: hardware_init();
1336:
1.1.1.9 root 1337: if(msdos_init(argc - (arg_offset + 1), argv + (arg_offset + 1), envp, standard_env)) {
1.1 root 1338: retval = EXIT_FAILURE;
1339: } else {
1.1.1.27 root 1340: #if defined(_MSC_VER) && (_MSC_VER >= 1400)
1.1.1.14 root 1341: _set_invalid_parameter_handler((_invalid_parameter_handler)ignore_invalid_parameters);
1342: #endif
1343: SetConsoleCtrlHandler(ctrl_handler, TRUE);
1344:
1.1.1.28 root 1345: if(screen_size_changed) {
1.1.1.24 root 1346: change_console_size(scr_width, scr_height);
1347: }
1.1.1.8 root 1348: TIMECAPS caps;
1349: timeGetDevCaps(&caps, sizeof(TIMECAPS));
1350: timeBeginPeriod(caps.wPeriodMin);
1.1.1.14 root 1351: #ifdef USE_THREAD
1352: InitializeCriticalSection(&vram_crit_sect);
1353: CloseHandle(CreateThread(NULL, 4096, vram_thread, NULL, 0, NULL));
1354: #endif
1.1 root 1355: hardware_run();
1.1.1.14 root 1356: #ifdef USE_THREAD
1357: vram_flush();
1358: DeleteCriticalSection(&vram_crit_sect);
1359: #endif
1.1.1.24 root 1360: timeEndPeriod(caps.wPeriodMin);
1.1.1.14 root 1361:
1.1.1.24 root 1362: // hStdin/hStdout (and all handles) will be closed in msdos_finish()...
1.1.1.28 root 1363: if(get_console_info_success) {
1.1.1.23 root 1364: hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.12 root 1365: if(restore_console_on_exit) {
1.1.1.14 root 1366: // window can't be bigger than buffer,
1367: // buffer can't be smaller than window,
1368: // so make a tiny window,
1369: // set the required buffer,
1370: // then set the required window
1371: SMALL_RECT rect;
1372: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
1373: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.12 root 1374: SetConsoleScreenBufferSize(hStdout, csbi.dwSize);
1.1.1.14 root 1375: SET_RECT(rect, 0, 0, csbi.srWindow.Right - csbi.srWindow.Left, csbi.srWindow.Bottom - csbi.srWindow.Top);
1.1.1.12 root 1376: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1377: }
1.1.1.14 root 1378: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
1379: SetConsoleCursorInfo(hStdout, &ci);
1.1.1.12 root 1380: }
1.1.1.24 root 1381: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode);
1382:
1.1 root 1383: msdos_finish();
1.1.1.14 root 1384:
1385: SetConsoleCtrlHandler(ctrl_handler, FALSE);
1.1 root 1386: }
1387:
1.1.1.10 root 1388: hardware_finish();
1389:
1.1.1.28 root 1390: if(key_buf_char != NULL) {
1391: key_buf_char->release();
1392: delete key_buf_char;
1393: key_buf_char = NULL;
1394: }
1395: if(key_buf_scan != NULL) {
1396: key_buf_scan->release();
1397: delete key_buf_scan;
1398: key_buf_scan = NULL;
1399: }
1400: if(temp_file_created) {
1401: DeleteFile(temp_file_path);
1402: temp_file_created = false;
1403: }
1404: // if(argv == dummy_argv) {
1405: // if(!is_started_from_command_prompt()) {
1406: // fprintf(stderr, "\nHit any key to quit...");
1407: // while(!_kbhit()) {
1408: // Sleep(10);
1409: // }
1410: // }
1411: // }
1.1.1.20 root 1412: #ifdef _DEBUG
1413: _CrtDumpMemoryLeaks();
1414: #endif
1.1 root 1415: return(retval);
1416: }
1417:
1.1.1.20 root 1418: /* ----------------------------------------------------------------------------
1419: console
1420: ---------------------------------------------------------------------------- */
1421:
1.1.1.14 root 1422: void change_console_size(int width, int height)
1.1.1.12 root 1423: {
1.1.1.23 root 1424: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.12 root 1425: CONSOLE_SCREEN_BUFFER_INFO csbi;
1426: SMALL_RECT rect;
1427: COORD co;
1428:
1429: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 1430: if(csbi.srWindow.Top != 0 || csbi.dwCursorPosition.Y > height - 1) {
1431: if(csbi.srWindow.Right - csbi.srWindow.Left + 1 == width && csbi.srWindow.Bottom - csbi.srWindow.Top + 1 == height) {
1432: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &csbi.srWindow);
1433: SET_RECT(rect, 0, 0, width - 1, height - 1);
1434: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1435: } else if(csbi.dwCursorPosition.Y > height - 1) {
1436: SET_RECT(rect, 0, csbi.dwCursorPosition.Y - (height - 1), width - 1, csbi.dwCursorPosition.Y);
1437: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1438: SET_RECT(rect, 0, 0, width - 1, height - 1);
1439: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1.1.12 root 1440: }
1441: }
1.1.1.14 root 1442: if(csbi.dwCursorPosition.Y > height - 1) {
1.1.1.12 root 1443: co.X = csbi.dwCursorPosition.X;
1.1.1.14 root 1444: co.Y = min(height - 1, csbi.dwCursorPosition.Y - csbi.srWindow.Top);
1.1.1.12 root 1445: SetConsoleCursorPosition(hStdout, co);
1446: cursor_moved = true;
1447: }
1.1.1.14 root 1448:
1449: // window can't be bigger than buffer,
1450: // buffer can't be smaller than window,
1451: // so make a tiny window,
1452: // set the required buffer,
1453: // then set the required window
1454: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
1.1.1.12 root 1455: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.14 root 1456: co.X = width;
1457: co.Y = height;
1.1.1.12 root 1458: SetConsoleScreenBufferSize(hStdout, co);
1.1.1.14 root 1459: SET_RECT(rect, 0, 0, width - 1, height - 1);
1460: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1461:
1462: scr_width = scr_buf_size.X = width;
1463: scr_height = scr_buf_size.Y = height;
1464: scr_top = 0;
1465:
1466: clear_scr_buffer(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
1467:
1468: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.15 root 1469: text_vram_end_address = text_vram_top_address + regen;
1470: shadow_buffer_end_address = shadow_buffer_top_address + regen;
1471:
1.1.1.14 root 1472: if(regen > 0x4000) {
1473: regen = 0x8000;
1474: vram_pages = 1;
1475: } else if(regen > 0x2000) {
1476: regen = 0x4000;
1477: vram_pages = 2;
1478: } else if(regen > 0x1000) {
1479: regen = 0x2000;
1480: vram_pages = 4;
1481: } else {
1482: regen = 0x1000;
1483: vram_pages = 8;
1484: }
1.1.1.15 root 1485: *(UINT16 *)(mem + 0x44a) = scr_width;
1486: *(UINT16 *)(mem + 0x44c) = regen;
1487: *(UINT8 *)(mem + 0x484) = scr_height - 1;
1488:
1.1.1.24 root 1489: mouse.min_position.x = 0;
1490: mouse.min_position.y = 0;
1491: mouse.max_position.x = 8 * scr_width - 1;
1492: mouse.max_position.y = 8 * scr_height - 1;
1493:
1.1.1.15 root 1494: restore_console_on_exit = true;
1.1.1.14 root 1495: }
1496:
1497: void clear_scr_buffer(WORD attr)
1498: {
1499: for(int y = 0; y < scr_height; y++) {
1500: for(int x = 0; x < scr_width; x++) {
1501: SCR_BUF(y,x).Char.AsciiChar = ' ';
1502: SCR_BUF(y,x).Attributes = attr;
1503: }
1504: }
1.1.1.12 root 1505: }
1506:
1.1.1.24 root 1507: bool update_console_input()
1.1 root 1508: {
1.1.1.23 root 1509: HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
1.1.1.8 root 1510: DWORD dwNumberOfEvents = 0;
1.1 root 1511: DWORD dwRead;
1512: INPUT_RECORD ir[16];
1.1.1.24 root 1513: CONSOLE_SCREEN_BUFFER_INFO csbi = {0};
1514: bool result = false;
1.1 root 1515:
1.1.1.8 root 1516: if(GetNumberOfConsoleInputEvents(hStdin, &dwNumberOfEvents) && dwNumberOfEvents != 0) {
1517: if(ReadConsoleInputA(hStdin, ir, 16, &dwRead)) {
1518: for(int i = 0; i < dwRead; i++) {
1.1.1.24 root 1519: if(ir[i].EventType & MOUSE_EVENT) {
1520: if(mouse.active) {
1521: if(ir[i].Event.MouseEvent.dwEventFlags == 0) {
1522: for(int i = 0; i < MAX_MOUSE_BUTTONS; i++) {
1523: static const DWORD bits[] = {
1524: FROM_LEFT_1ST_BUTTON_PRESSED, // left
1525: RIGHTMOST_BUTTON_PRESSED, // right
1526: FROM_LEFT_2ND_BUTTON_PRESSED, // middle
1.1.1.14 root 1527: };
1.1.1.24 root 1528: bool prev_status = mouse.buttons[i].status;
1529: mouse.buttons[i].status = ((ir[i].Event.MouseEvent.dwButtonState & bits[i]) != 0);
1530:
1531: if(!prev_status && mouse.buttons[i].status) {
1532: mouse.buttons[i].pressed_times++;
1533: mouse.buttons[i].pressed_position.x = mouse.position.x;
1534: mouse.buttons[i].pressed_position.y = mouse.position.y;
1535: mouse.status |= 2 << (i * 2);
1536: } else if(prev_status && !mouse.buttons[i].status) {
1537: mouse.buttons[i].released_times++;
1538: mouse.buttons[i].released_position.x = mouse.position.x;
1539: mouse.buttons[i].released_position.y = mouse.position.y;
1540: mouse.status |= 4 << (i * 2);
1541: }
1.1.1.14 root 1542: }
1.1.1.24 root 1543: } else if(ir[i].Event.MouseEvent.dwEventFlags & MOUSE_MOVED) {
1544: // NOTE: if restore_console_on_exit, console is not scrolled
1545: if(!restore_console_on_exit && csbi.srWindow.Bottom == 0) {
1546: GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
1.1.1.14 root 1547: }
1.1.1.28 root 1548: // FIXME: character size is always 8x8 ???
1549: int x = 3 + 8 * (ir[i].Event.MouseEvent.dwMousePosition.X);
1550: int y = 4 + 8 * (ir[i].Event.MouseEvent.dwMousePosition.Y - csbi.srWindow.Top);
1.1.1.24 root 1551: if(mouse.position.x != x || mouse.position.y != y) {
1552: mouse.position.x = x;
1553: mouse.position.y = y;
1554: mouse.status |= 1;
1.1.1.14 root 1555: }
1556: }
1557: }
1.1.1.24 root 1558: } else if(ir[i].EventType & KEY_EVENT) {
1.1.1.28 root 1559: // set scan code of last pressed/release key to kbd_data (in-port 60h)
1.1.1.24 root 1560: kbd_data = ir[i].Event.KeyEvent.wVirtualScanCode;
1.1.1.14 root 1561: if(!ir[i].Event.KeyEvent.bKeyDown) {
1.1.1.28 root 1562: // break
1.1.1.14 root 1563: kbd_data |= 0x80;
1.1.1.24 root 1564: } else {
1.1.1.28 root 1565: // make
1.1.1.24 root 1566: kbd_data &= 0x7f;
1567:
1568: // update dos key buffer
1569: UINT8 chr = ir[i].Event.KeyEvent.uChar.AsciiChar;
1570: UINT8 scn = ir[i].Event.KeyEvent.wVirtualScanCode & 0xff;
1571:
1572: if(chr == 0) {
1573: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
1574: if(scn >= 0x3b && scn <= 0x44) {
1575: scn += 0x68 - 0x3b; // F1 to F10
1576: } else if(scn == 0x57 || scn == 0x58) {
1577: scn += 0x8b - 0x57; // F11 & F12
1578: } else if(scn >= 0x47 && scn <= 0x53) {
1579: scn += 0x97 - 0x47; // edit/arrow clusters
1580: } else if(scn == 0x35) {
1581: scn = 0xa4; // keypad /
1582: }
1583: } else if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
1584: if(scn == 0x07) {
1585: chr = 0x1e; // Ctrl+^
1586: } else if(scn == 0x0c) {
1587: chr = 0x1f; // Ctrl+_
1588: } else if(scn >= 0x35 && scn <= 0x58) {
1589: static const UINT8 ctrl_map[] = {
1590: 0x95, // keypad /
1591: 0,
1592: 0x96, // keypad *
1593: 0, 0, 0,
1594: 0x5e, // F1
1595: 0x5f, // F2
1596: 0x60, // F3
1597: 0x61, // F4
1598: 0x62, // F5
1599: 0x63, // F6
1600: 0x64, // F7
1601: 0x65, // F8
1602: 0x66, // F9
1603: 0x67, // F10
1604: 0,
1605: 0,
1606: 0x77, // Home
1607: 0x8d, // Up
1608: 0x84, // PgUp
1609: 0x8e, // keypad -
1610: 0x73, // Left
1611: 0x8f, // keypad center
1612: 0x74, // Right
1613: 0x90, // keyapd +
1614: 0x75, // End
1615: 0x91, // Down
1616: 0x76, // PgDn
1617: 0x92, // Insert
1618: 0x93, // Delete
1619: 0, 0, 0,
1620: 0x89, // F11
1621: 0x8a, // F12
1622: };
1623: scn = ctrl_map[scn - 0x35];
1624: }
1625: } else if(ir[i].Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
1626: if(scn >= 0x3b && scn <= 0x44) {
1627: scn += 0x54 - 0x3b; // F1 to F10
1628: } else if(scn == 0x57 || scn == 0x58) {
1629: scn += 0x87 - 0x57; // F11 & F12
1630: }
1631: } else if(scn == 0x57 || scn == 0x58) {
1632: scn += 0x85 - 0x57;
1633: }
1634: // ignore shift, ctrl, alt, win and menu keys
1635: if(scn != 0x1d && scn != 0x2a && scn != 0x36 && scn != 0x38 && (scn < 0x5b || scn > 0x5e)) {
1636: if(chr == 0) {
1637: key_buf_char->write(0x00);
1638: key_buf_scan->write(ir[i].Event.KeyEvent.dwControlKeyState & ENHANCED_KEY ? 0xe0 : 0x00);
1639: }
1640: key_buf_char->write(chr);
1641: key_buf_scan->write(scn);
1642: }
1643: } else {
1644: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
1645: chr = 0;
1646: if(scn >= 0x02 && scn <= 0x0e) {
1647: scn += 0x78 - 0x02; // 1 to 0 - =
1648: }
1649: }
1650: key_buf_char->write(chr);
1651: key_buf_scan->write(scn);
1652: }
1.1 root 1653: }
1.1.1.24 root 1654: result = key_changed = true;
1.1 root 1655: }
1656: }
1657: }
1658: }
1.1.1.24 root 1659: return(result);
1.1.1.8 root 1660: }
1661:
1.1.1.14 root 1662: bool update_key_buffer()
1.1.1.8 root 1663: {
1.1.1.24 root 1664: return(update_console_input() || key_buf_char->count() != 0);
1.1.1.8 root 1665: }
1666:
1.1.1.20 root 1667: /* ----------------------------------------------------------------------------
1668: MS-DOS virtual machine
1669: ---------------------------------------------------------------------------- */
1670:
1671: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg);
1672: int msdos_psp_get_file_table(int fd, int psp_seg);
1673: void msdos_putch(UINT8 data);
1674:
1.1 root 1675: // process info
1676:
1677: process_t *msdos_process_info_create(UINT16 psp_seg)
1678: {
1679: for(int i = 0; i < MAX_PROCESS; i++) {
1680: if(process[i].psp == 0 || process[i].psp == psp_seg) {
1681: memset(&process[i], 0, sizeof(process_t));
1682: process[i].psp = psp_seg;
1683: return(&process[i]);
1684: }
1685: }
1686: fatalerror("too many processes\n");
1687: return(NULL);
1688: }
1689:
1690: process_t *msdos_process_info_get(UINT16 psp_seg)
1691: {
1692: for(int i = 0; i < MAX_PROCESS; i++) {
1693: if(process[i].psp == psp_seg) {
1694: return(&process[i]);
1695: }
1696: }
1697: fatalerror("invalid psp address\n");
1698: return(NULL);
1699: }
1700:
1.1.1.23 root 1701: void msdos_sda_update(int psp_seg)
1702: {
1703: sda_t *sda = (sda_t *)(mem + SDA_TOP);
1704:
1705: for(int i = 0; i < MAX_PROCESS; i++) {
1706: if(process[i].psp == psp_seg) {
1707: sda->switchar = process[i].switchar;
1708: sda->current_dta.w.l = process[i].dta.w.l;
1709: sda->current_dta.w.h = process[i].dta.w.h;
1710: sda->current_psp = process[i].psp;
1711: break;
1712: }
1713: }
1714: sda->malloc_strategy = malloc_strategy;
1715: sda->return_code = retval;
1716: sda->current_drive = _getdrive();
1717: }
1718:
1.1.1.13 root 1719: // dta info
1720:
1721: void msdos_dta_info_init()
1722: {
1.1.1.14 root 1723: for(int i = 0; i < MAX_DTAINFO; i++) {
1.1.1.13 root 1724: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
1725: }
1726: }
1727:
1728: dtainfo_t *msdos_dta_info_get(UINT16 psp_seg, UINT32 dta_laddr)
1729: {
1730: dtainfo_t *free_dta = NULL;
1.1.1.14 root 1731: for(int i = 0; i < MAX_DTAINFO; i++) {
1732: if(dtalist[i].find_handle == INVALID_HANDLE_VALUE) {
1733: if(free_dta == NULL) {
1.1.1.13 root 1734: free_dta = &dtalist[i];
1735: }
1.1.1.14 root 1736: } else if(dta_laddr < LFN_DTA_LADDR && dtalist[i].dta == dta_laddr) {
1.1.1.13 root 1737: return(&dtalist[i]);
1738: }
1739: }
1.1.1.14 root 1740: if(free_dta) {
1.1.1.13 root 1741: free_dta->psp = psp_seg;
1742: free_dta->dta = dta_laddr;
1743: return(free_dta);
1744: }
1745: fatalerror("too many dta\n");
1746: return(NULL);
1747: }
1748:
1749: void msdos_dta_info_free(UINT16 psp_seg)
1750: {
1.1.1.14 root 1751: for(int i = 0; i < MAX_DTAINFO; i++) {
1752: if(dtalist[i].psp == psp_seg && dtalist[i].find_handle != INVALID_HANDLE_VALUE) {
1.1.1.13 root 1753: FindClose(dtalist[i].find_handle);
1754: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
1755: }
1756: }
1757: }
1758:
1.1 root 1759: void msdos_cds_update(int drv)
1760: {
1761: cds_t *cds = (cds_t *)(mem + CDS_TOP);
1762:
1763: memset(mem + CDS_TOP, 0, CDS_SIZE);
1764: sprintf(cds->path_name, "%c:\\", 'A' + drv);
1765: cds->drive_attrib = 0x4000; // physical drive
1766: cds->physical_drive_number = drv;
1767: }
1768:
1.1.1.17 root 1769: // nls information tables
1770:
1771: // uppercase table (func 6502h)
1772: void msdos_upper_table_update()
1773: {
1774: *(UINT16 *)(mem + UPPERTABLE_TOP) = 0x80;
1.1.1.22 root 1775: for(unsigned i = 0; i < 0x80; ++i) {
1.1.1.17 root 1776: UINT8 c[4];
1777: *(UINT32 *)c = 0; // reset internal conversion state
1778: CharUpperBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
1779: c[0] = 0x80 + i;
1780: DWORD rc = CharUpperBuffA((LPSTR)c, 1);
1781: mem[UPPERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
1782: }
1783: }
1784:
1.1.1.23 root 1785: // lowercase table (func 6503h)
1786: void msdos_lower_table_update()
1787: {
1788: *(UINT16 *)(mem + LOWERTABLE_TOP) = 0x80;
1789: for(unsigned i = 0; i < 0x80; ++i) {
1790: UINT8 c[4];
1791: *(UINT32 *)c = 0; // reset internal conversion state
1792: CharLowerBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
1793: c[0] = 0x80 + i;
1794: DWORD rc = CharLowerBuffA((LPSTR)c, 1);
1795: mem[LOWERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
1796: }
1797: }
1798:
1.1.1.17 root 1799: // filename uppercase table (func 6504h)
1800: void msdos_filename_upper_table_init()
1801: {
1802: // depended on (file)system, not on active codepage
1803: // temporary solution: just filling data
1804: *(UINT16 *)(mem + FILENAME_UPPERTABLE_TOP) = 0x80;
1.1.1.22 root 1805: for(unsigned i = 0; i < 0x80; ++i) {
1.1.1.17 root 1806: mem[FILENAME_UPPERTABLE_TOP + 2 + i] = 0x80 + i;
1807: }
1808: }
1809:
1810: // filaname terminator table (func 6505h)
1811: void msdos_filename_terminator_table_init()
1812: {
1813: const char illegal_chars[] = ".\"/\\[]:|<>+=;,"; // for standard MS-DOS fs.
1814: UINT8 *data = mem + FILENAME_TERMINATOR_TOP;
1815:
1816: data[2] = 1; // marker? (permissible character value)
1817: data[3] = 0x00; // 00h...FFh
1818: data[4] = 0xff;
1819: data[5] = 0; // marker? (excluded character)
1820: data[6] = 0x00; // 00h...20h
1821: data[7] = 0x20;
1822: data[8] = 2; // marker? (illegal characters for filename)
1823: data[9] = (UINT8)strlen(illegal_chars);
1824: memcpy(data + 10, illegal_chars, data[9]);
1825:
1826: // total length
1827: *(UINT16 *)data = (10 - 2) + data[9];
1828: }
1829:
1830: // collating table (func 6506h)
1831: void msdos_collating_table_update()
1832: {
1833: // temporary solution: just filling data
1834: *(UINT16 *)(mem + COLLATING_TABLE_TOP) = 0x100;
1.1.1.22 root 1835: for(unsigned i = 0; i < 256; ++i) {
1.1.1.17 root 1836: mem[COLLATING_TABLE_TOP + 2 + i] = i;
1837: }
1838: }
1839:
1.1 root 1840: // dbcs
1841:
1842: void msdos_dbcs_table_update()
1843: {
1844: UINT8 dbcs_data[DBCS_SIZE];
1845: memset(dbcs_data, 0, sizeof(dbcs_data));
1846:
1847: CPINFO info;
1848: GetCPInfo(active_code_page, &info);
1849:
1850: if(info.MaxCharSize != 1) {
1851: for(int i = 0;; i += 2) {
1852: UINT8 lo = info.LeadByte[i + 0];
1853: UINT8 hi = info.LeadByte[i + 1];
1854: dbcs_data[2 + i + 0] = lo;
1855: dbcs_data[2 + i + 1] = hi;
1856: if(lo == 0 && hi == 0) {
1857: dbcs_data[0] = i + 2;
1858: break;
1859: }
1860: }
1861: } else {
1862: dbcs_data[0] = 2; // ???
1863: }
1864: memcpy(mem + DBCS_TOP, dbcs_data, sizeof(dbcs_data));
1865: }
1866:
1.1.1.17 root 1867: void msdos_dbcs_table_finish()
1868: {
1869: if(active_code_page != system_code_page) {
1870: _setmbcp(system_code_page);
1871: }
1872: }
1873:
1874: void msdos_nls_tables_init()
1.1 root 1875: {
1876: system_code_page = active_code_page = _getmbcp();
1.1.1.17 root 1877: msdos_upper_table_update();
1.1.1.23 root 1878: msdos_lower_table_update();
1.1.1.17 root 1879: msdos_filename_terminator_table_init();
1880: msdos_filename_upper_table_init();
1881: msdos_collating_table_update();
1.1 root 1882: msdos_dbcs_table_update();
1883: }
1884:
1.1.1.17 root 1885: void msdos_nls_tables_update()
1.1 root 1886: {
1.1.1.17 root 1887: msdos_dbcs_table_update();
1888: msdos_upper_table_update();
1.1.1.23 root 1889: msdos_lower_table_update();
1890: // msdos_collating_table_update();
1.1 root 1891: }
1892:
1893: int msdos_lead_byte_check(UINT8 code)
1894: {
1895: UINT8 *dbcs_table = mem + DBCS_TABLE;
1896:
1897: for(int i = 0;; i += 2) {
1898: UINT8 lo = dbcs_table[i + 0];
1899: UINT8 hi = dbcs_table[i + 1];
1900: if(lo == 0 && hi == 0) {
1901: break;
1902: }
1903: if(lo <= code && code <= hi) {
1904: return(1);
1905: }
1906: }
1907: return(0);
1908: }
1909:
1.1.1.20 root 1910: int msdos_ctrl_code_check(UINT8 code)
1911: {
1.1.1.22 root 1912: return (code >= 0x01 && code <= 0x1a && code != 0x07 && code != 0x08 && code != 0x09 && code != 0x0a && code != 0x0d);
1.1.1.20 root 1913: }
1914:
1.1 root 1915: // file control
1916:
1.1.1.14 root 1917: char *msdos_remove_double_quote(char *path)
1918: {
1919: static char tmp[MAX_PATH];
1920:
1921: memset(tmp, 0, sizeof(tmp));
1922: if(strlen(path) >= 2 && path[0] == '"' && path[strlen(path) - 1] == '"') {
1923: memcpy(tmp, path + 1, strlen(path) - 2);
1924: } else {
1925: strcpy(tmp, path);
1926: }
1927: return(tmp);
1928: }
1929:
1930: char *msdos_combine_path(char *dir, const char *file)
1931: {
1932: static char tmp[MAX_PATH];
1933: char *tmp_dir = msdos_remove_double_quote(dir);
1934:
1935: if(strlen(tmp_dir) == 0) {
1936: strcpy(tmp, file);
1937: } else if(tmp_dir[strlen(tmp_dir) - 1] == '\\') {
1938: sprintf(tmp, "%s%s", tmp_dir, file);
1939: } else {
1940: sprintf(tmp, "%s\\%s", tmp_dir, file);
1941: }
1942: return(tmp);
1943: }
1944:
1.1 root 1945: char *msdos_trimmed_path(char *path, int lfn)
1946: {
1947: static char tmp[MAX_PATH];
1948:
1949: if(lfn) {
1950: strcpy(tmp, path);
1951: } else {
1952: // remove space in the path
1953: char *src = path, *dst = tmp;
1954:
1955: while(*src != '\0') {
1956: if(msdos_lead_byte_check(*src)) {
1957: *dst++ = *src++;
1958: *dst++ = *src++;
1959: } else if(*src != ' ') {
1960: *dst++ = *src++;
1961: } else {
1962: src++; // skip space
1963: }
1964: }
1965: *dst = '\0';
1966: }
1.1.1.14 root 1967: if(_stricmp(tmp, "C:\\COMMAND.COM") == 0) {
1968: // redirect C:\COMMAND.COM to comspec_path
1969: strcpy(tmp, comspec_path);
1970: } else if(is_vista_or_later && _access(tmp, 0) != 0) {
1971: // redirect new files (without wildcards) in C:\ to %TEMP%, since C:\ is not usually writable
1972: static int root_drive_protected = -1;
1973: char temp[MAX_PATH], name[MAX_PATH], *name_temp = NULL;
1974: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
1975:
1976: if(GetFullPathName(tmp, MAX_PATH, temp, &name_temp) != 0 &&
1977: name_temp != NULL && strstr(name_temp, "?") == NULL && strstr(name_temp, "*") == NULL) {
1978: strcpy(name, name_temp);
1979: name_temp[0] = '\0';
1980:
1981: if((temp[0] == 'A' + dos_info->boot_drive - 1 || temp[0] == 'a' + dos_info->boot_drive - 1) &&
1982: (temp[1] == ':') && (temp[2] == '\\' || temp[2] == '/') && (temp[3] == '\0')) {
1983: if(root_drive_protected == -1) {
1984: FILE *fp = NULL;
1985:
1986: sprintf(temp, "%c:\\MS-DOS_Player.$$$", 'A' + dos_info->boot_drive - 1);
1987: root_drive_protected = 1;
1988: try {
1989: if((fp = fopen(temp, "w")) != NULL) {
1990: if(fprintf(fp, "TEST") == 4) {
1991: root_drive_protected = 0;
1992: }
1993: }
1994: } catch(...) {
1995: }
1996: if(fp != NULL) {
1997: fclose(fp);
1998: }
1999: if(_access(temp, 0) == 0) {
2000: remove(temp);
2001: }
2002: }
2003: if(root_drive_protected == 1) {
2004: if(GetEnvironmentVariable("TEMP", temp, MAX_PATH) != 0 ||
2005: GetEnvironmentVariable("TMP", temp, MAX_PATH) != 0) {
2006: strcpy(tmp, msdos_combine_path(temp, name));
2007: }
2008: }
2009: }
2010: }
2011: }
1.1 root 2012: return(tmp);
2013: }
2014:
1.1.1.28 root 2015: char *msdos_get_multiple_short_path(char *src)
2016: {
2017: // LONGPATH;LONGPATH;LONGPATH to SHORTPATH;SHORTPATH;SHORTPATH
2018: static char env_path[ENV_SIZE];
2019: char tmp[ENV_SIZE], *token;
2020:
2021: memset(env_path, 0, sizeof(env_path));
2022: strcpy(tmp, src);
2023: token = my_strtok(tmp, ";");
2024:
2025: while(token != NULL) {
2026: if(token[0] != '\0') {
2027: char *path = msdos_remove_double_quote(token), short_path[MAX_PATH];
2028: if(strlen(path) != 0) {
2029: if(GetShortPathName(path, short_path, MAX_PATH) == 0) {
2030: strcat(env_path, path);
2031: } else {
2032: my_strupr(short_path);
2033: strcat(env_path, short_path);
2034: }
2035: strcat(env_path, ";");
2036: }
2037: }
2038: token = my_strtok(NULL, ";");
2039: }
2040: int len = strlen(env_path);
2041: if(len != 0 && env_path[len - 1] == ';') {
2042: env_path[len - 1] = '\0';
2043: }
2044: return(env_path);
2045: }
2046:
1.1 root 2047: bool match(char *text, char *pattern)
2048: {
1.1.1.24 root 2049: // http://www.prefield.com/algorithm/string/wildcard.html
1.1.1.14 root 2050: switch(*pattern) {
1.1 root 2051: case '\0':
2052: return !*text;
2053: case '*':
1.1.1.14 root 2054: return match(text, pattern + 1) || (*text && match(text + 1, pattern));
1.1 root 2055: case '?':
2056: return *text && match(text + 1, pattern + 1);
2057: default:
2058: return (*text == *pattern) && match(text + 1, pattern + 1);
2059: }
2060: }
2061:
2062: bool msdos_match_volume_label(char *path, char *volume)
2063: {
2064: char *p;
2065:
1.1.1.14 root 2066: if(!*volume) {
2067: return false;
2068: } else if((p = my_strchr(path, ':')) != NULL) {
1.1 root 2069: return msdos_match_volume_label(p + 1, volume);
2070: } else if((p = my_strchr(path, '\\')) != NULL) {
2071: return msdos_match_volume_label(p + 1, volume);
2072: } else if((p = my_strchr(path, '.')) != NULL) {
1.1.1.14 root 2073: char tmp[MAX_PATH];
2074: sprintf(tmp, "%.*s%s", (int)(p - path), path, p + 1);
2075: return match(volume, tmp);
1.1 root 2076: } else {
2077: return match(volume, path);
2078: }
2079: }
2080:
2081: char *msdos_fcb_path(fcb_t *fcb)
2082: {
2083: static char tmp[MAX_PATH];
2084: char name[9], ext[4];
2085:
2086: memset(name, 0, sizeof(name));
2087: memcpy(name, fcb->file_name, 8);
2088: strcpy(name, msdos_trimmed_path(name, 0));
2089:
2090: memset(ext, 0, sizeof(ext));
2091: memcpy(ext, fcb->file_name + 8, 3);
2092: strcpy(ext, msdos_trimmed_path(ext, 0));
2093:
2094: if(name[0] == '\0' || strcmp(name, "????????") == 0) {
2095: strcpy(name, "*");
2096: }
2097: if(ext[0] == '\0') {
2098: strcpy(tmp, name);
2099: } else {
2100: if(strcmp(ext, "???") == 0) {
2101: strcpy(ext, "*");
2102: }
2103: sprintf(tmp, "%s.%s", name, ext);
2104: }
2105: return(tmp);
2106: }
2107:
2108: void msdos_set_fcb_path(fcb_t *fcb, char *path)
2109: {
2110: char *ext = my_strchr(path, '.');
2111:
2112: memset(fcb->file_name, 0x20, 8 + 3);
2113: if(ext != NULL && path[0] != '.') {
2114: *ext = '\0';
2115: memcpy(fcb->file_name + 8, ext + 1, strlen(ext + 1));
2116: }
2117: memcpy(fcb->file_name, path, strlen(path));
2118: }
2119:
2120: char *msdos_short_path(char *path)
2121: {
2122: static char tmp[MAX_PATH];
2123:
1.1.1.24 root 2124: if(GetShortPathName(path, tmp, MAX_PATH) == 0) {
2125: strcpy(tmp, path);
2126: }
1.1 root 2127: my_strupr(tmp);
2128: return(tmp);
2129: }
2130:
1.1.1.13 root 2131: char *msdos_short_name(WIN32_FIND_DATA *fd)
2132: {
2133: static char tmp[MAX_PATH];
2134:
1.1.1.14 root 2135: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 2136: strcpy(tmp, fd->cAlternateFileName);
2137: } else {
2138: strcpy(tmp, fd->cFileName);
2139: }
2140: my_strupr(tmp);
2141: return(tmp);
2142: }
2143:
1.1 root 2144: char *msdos_short_full_path(char *path)
2145: {
2146: static char tmp[MAX_PATH];
2147: char full[MAX_PATH], *name;
2148:
1.1.1.14 root 2149: // Full works with non-existent files, but Short does not
1.1 root 2150: GetFullPathName(path, MAX_PATH, full, &name);
1.1.1.14 root 2151: *tmp = '\0';
2152: if(GetShortPathName(full, tmp, MAX_PATH) == 0 && name > path) {
2153: name[-1] = '\0';
2154: DWORD len = GetShortPathName(full, tmp, MAX_PATH);
2155: if(len == 0) {
2156: strcpy(tmp, full);
2157: } else {
2158: tmp[len++] = '\\';
2159: strcpy(tmp + len, name);
2160: }
2161: }
1.1 root 2162: my_strupr(tmp);
2163: return(tmp);
2164: }
2165:
2166: char *msdos_short_full_dir(char *path)
2167: {
2168: static char tmp[MAX_PATH];
2169: char full[MAX_PATH], *name;
2170:
2171: GetFullPathName(path, MAX_PATH, full, &name);
2172: name[-1] = '\0';
1.1.1.24 root 2173: if(GetShortPathName(full, tmp, MAX_PATH) == 0) {
2174: strcpy(tmp, full);
2175: }
1.1 root 2176: my_strupr(tmp);
2177: return(tmp);
2178: }
2179:
2180: char *msdos_local_file_path(char *path, int lfn)
2181: {
2182: char *trimmed = msdos_trimmed_path(path, lfn);
1.1.1.14 root 2183: #if 0
2184: // I have forgotten the reason of this routine... :-(
1.1 root 2185: if(_access(trimmed, 0) != 0) {
2186: process_t *process = msdos_process_info_get(current_psp);
2187: static char tmp[MAX_PATH];
2188:
2189: sprintf(tmp, "%s\\%s", process->module_dir, trimmed);
2190: if(_access(tmp, 0) == 0) {
2191: return(tmp);
2192: }
2193: }
1.1.1.14 root 2194: #endif
1.1 root 2195: return(trimmed);
2196: }
2197:
1.1.1.29! root 2198: bool msdos_is_device_path(char *path)
1.1.1.11 root 2199: {
2200: char full[MAX_PATH], *name;
2201:
1.1.1.24 root 2202: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1.1.1.29! root 2203: if(_stricmp(full, "\\\\.\\AUX" ) == 0 ||
! 2204: _stricmp(full, "\\\\.\\CON" ) == 0 ||
! 2205: _stricmp(full, "\\\\.\\NUL" ) == 0 ||
! 2206: _stricmp(full, "\\\\.\\PRN" ) == 0 ||
! 2207: _stricmp(full, "\\\\.\\COM1") == 0 ||
! 2208: _stricmp(full, "\\\\.\\COM2") == 0 ||
! 2209: _stricmp(full, "\\\\.\\COM3") == 0 ||
! 2210: _stricmp(full, "\\\\.\\COM4") == 0 ||
! 2211: _stricmp(full, "\\\\.\\COM5") == 0 ||
! 2212: _stricmp(full, "\\\\.\\COM6") == 0 ||
! 2213: _stricmp(full, "\\\\.\\COM7") == 0 ||
! 2214: _stricmp(full, "\\\\.\\COM8") == 0 ||
! 2215: _stricmp(full, "\\\\.\\COM9") == 0 ||
! 2216: _stricmp(full, "\\\\.\\LPT1") == 0 ||
! 2217: _stricmp(full, "\\\\.\\LPT2") == 0 ||
! 2218: _stricmp(full, "\\\\.\\LPT3") == 0 ||
! 2219: _stricmp(full, "\\\\.\\LPT4") == 0 ||
! 2220: _stricmp(full, "\\\\.\\LPT5") == 0 ||
! 2221: _stricmp(full, "\\\\.\\LPT6") == 0 ||
! 2222: _stricmp(full, "\\\\.\\LPT7") == 0 ||
! 2223: _stricmp(full, "\\\\.\\LPT8") == 0 ||
! 2224: _stricmp(full, "\\\\.\\LPT9") == 0) {
! 2225: return(true);
! 2226: } else if(name != NULL) {
! 2227: if(_stricmp(name, "CLOCK$" ) == 0 ||
! 2228: _stricmp(name, "CONFIG$" ) == 0 ||
! 2229: _stricmp(name, "EMMXXXX0") == 0) {
! 2230: return(true);
! 2231: }
! 2232: }
1.1.1.24 root 2233: }
2234: return(false);
1.1.1.11 root 2235: }
2236:
1.1.1.29! root 2237: bool msdos_is_con_path(char *path)
1.1.1.8 root 2238: {
1.1.1.14 root 2239: char full[MAX_PATH], *name;
1.1.1.8 root 2240:
1.1.1.24 root 2241: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1.1.1.29! root 2242: return(_stricmp(full, "\\\\.\\CON") == 0);
1.1.1.24 root 2243: }
2244: return(false);
2245: }
2246:
1.1.1.29! root 2247: int msdos_is_comm_path(char *path)
1.1.1.24 root 2248: {
2249: char full[MAX_PATH], *name;
2250:
2251: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1.1.1.29! root 2252: if(_stricmp(full, "\\\\.\\COM1") == 0) {
! 2253: return(1);
! 2254: } else if(_stricmp(full, "\\\\.\\COM2") == 0) {
! 2255: return(2);
! 2256: } else if(_stricmp(full, "\\\\.\\COM3") == 0) {
! 2257: return(3);
! 2258: } else if(_stricmp(full, "\\\\.\\COM4") == 0) {
! 2259: return(4);
1.1.1.24 root 2260: }
2261: }
1.1.1.29! root 2262: return(0);
! 2263: }
! 2264:
! 2265: char *msdos_create_comm_path(char *path, int port)
! 2266: {
! 2267: static char tmp[MAX_PATH];
! 2268: char *p = NULL;
! 2269:
! 2270: sprintf(tmp, "COM%d", port);
! 2271: if((p = strchr(path, ':')) != NULL) {
! 2272: strcat(tmp, p);
! 2273: }
! 2274: return(tmp);
1.1.1.24 root 2275: }
2276:
2277: bool msdos_is_existing_file(char *path)
2278: {
2279: // http://d.hatena.ne.jp/yu-hr/20100317/1268826458
2280: WIN32_FIND_DATA FindData;
2281: HANDLE hFind;
2282:
2283: if((hFind = FindFirstFile(path, &FindData)) != INVALID_HANDLE_VALUE) {
2284: FindClose(hFind);
2285: return(!(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
2286: }
2287: return(false);
1.1.1.8 root 2288: }
2289:
1.1.1.9 root 2290: char *msdos_search_command_com(char *command_path, char *env_path)
2291: {
2292: static char tmp[MAX_PATH];
1.1.1.28 root 2293: char path[ENV_SIZE], *file_name;
1.1.1.9 root 2294:
1.1.1.28 root 2295: // check if COMMAND.COM is in the same directory as the target program file
1.1.1.9 root 2296: if(GetFullPathName(command_path, MAX_PATH, tmp, &file_name) != 0) {
2297: sprintf(file_name, "COMMAND.COM");
2298: if(_access(tmp, 0) == 0) {
2299: return(tmp);
2300: }
2301: }
1.1.1.28 root 2302:
2303: // check if COMMAND.COM is in the same directory as the running msdos.exe
1.1.1.9 root 2304: if(GetModuleFileName(NULL, path, MAX_PATH) != 0 && GetFullPathName(path, MAX_PATH, tmp, &file_name) != 0) {
2305: sprintf(file_name, "COMMAND.COM");
2306: if(_access(tmp, 0) == 0) {
2307: return(tmp);
2308: }
2309: }
1.1.1.28 root 2310:
2311: // check if COMMAND.COM is in the current directory
1.1.1.9 root 2312: if(GetFullPathName("COMMAND.COM", MAX_PATH, tmp, &file_name) != 0) {
2313: if(_access(tmp, 0) == 0) {
2314: return(tmp);
2315: }
2316: }
1.1.1.28 root 2317:
2318: // cehck if COMMAND.COM is in the directory that is in MSDOS_PATH and PATH environment variables
2319: strcpy(path, env_path);
2320: char *token = my_strtok(path, ";");
1.1.1.9 root 2321: while(token != NULL) {
1.1.1.14 root 2322: if(strlen(token) != 0 && token[0] != '%') {
1.1.1.9 root 2323: strcpy(tmp, msdos_combine_path(token, "COMMAND.COM"));
2324: if(_access(tmp, 0) == 0) {
2325: return(tmp);
2326: }
2327: }
2328: token = my_strtok(NULL, ";");
2329: }
2330: return(NULL);
2331: }
2332:
1.1.1.14 root 2333: int msdos_drive_number(const char *path)
1.1 root 2334: {
2335: char tmp[MAX_PATH], *name;
2336:
2337: GetFullPathName(path, MAX_PATH, tmp, &name);
2338: if(tmp[0] >= 'a' && tmp[0] <= 'z') {
2339: return(tmp[0] - 'a');
2340: } else {
2341: return(tmp[0] - 'A');
2342: }
2343: }
2344:
2345: char *msdos_volume_label(char *path)
2346: {
2347: static char tmp[MAX_PATH];
2348: char volume[] = "A:\\";
2349:
2350: if(path[1] == ':') {
2351: volume[0] = path[0];
2352: } else {
2353: volume[0] = 'A' + _getdrive() - 1;
2354: }
2355: if(!GetVolumeInformation(volume, tmp, MAX_PATH, NULL, NULL, NULL, NULL, 0)) {
2356: memset(tmp, 0, sizeof(tmp));
2357: }
2358: return(tmp);
2359: }
2360:
2361: char *msdos_short_volume_label(char *label)
2362: {
2363: static char tmp[(8 + 1 + 3) + 1];
2364: char *src = label;
2365: int remain = strlen(label);
2366: char *dst_n = tmp;
2367: char *dst_e = tmp + 9;
2368:
2369: strcpy(tmp, " . ");
2370: for(int i = 0; i < 8 && remain > 0; i++) {
2371: if(msdos_lead_byte_check(*src)) {
2372: if(++i == 8) {
2373: break;
2374: }
2375: *dst_n++ = *src++;
2376: remain--;
2377: }
2378: *dst_n++ = *src++;
2379: remain--;
2380: }
2381: if(remain > 0) {
2382: for(int i = 0; i < 3 && remain > 0; i++) {
2383: if(msdos_lead_byte_check(*src)) {
2384: if(++i == 3) {
2385: break;
2386: }
2387: *dst_e++ = *src++;
2388: remain--;
2389: }
2390: *dst_e++ = *src++;
2391: remain--;
2392: }
2393: *dst_e = '\0';
2394: } else {
2395: *dst_n = '\0';
2396: }
2397: my_strupr(tmp);
2398: return(tmp);
2399: }
2400:
1.1.1.13 root 2401: errno_t msdos_maperr(unsigned long oserrno)
2402: {
2403: _doserrno = oserrno;
1.1.1.14 root 2404: switch(oserrno) {
1.1.1.13 root 2405: case ERROR_FILE_NOT_FOUND: // 2
2406: case ERROR_PATH_NOT_FOUND: // 3
2407: case ERROR_INVALID_DRIVE: // 15
2408: case ERROR_NO_MORE_FILES: // 18
2409: case ERROR_BAD_NETPATH: // 53
2410: case ERROR_BAD_NET_NAME: // 67
2411: case ERROR_BAD_PATHNAME: // 161
2412: case ERROR_FILENAME_EXCED_RANGE: // 206
2413: return ENOENT;
2414: case ERROR_TOO_MANY_OPEN_FILES: // 4
2415: return EMFILE;
2416: case ERROR_ACCESS_DENIED: // 5
2417: case ERROR_CURRENT_DIRECTORY: // 16
2418: case ERROR_NETWORK_ACCESS_DENIED: // 65
2419: case ERROR_CANNOT_MAKE: // 82
2420: case ERROR_FAIL_I24: // 83
2421: case ERROR_DRIVE_LOCKED: // 108
2422: case ERROR_SEEK_ON_DEVICE: // 132
2423: case ERROR_NOT_LOCKED: // 158
2424: case ERROR_LOCK_FAILED: // 167
2425: return EACCES;
2426: case ERROR_INVALID_HANDLE: // 6
2427: case ERROR_INVALID_TARGET_HANDLE: // 114
2428: case ERROR_DIRECT_ACCESS_HANDLE: // 130
2429: return EBADF;
2430: case ERROR_ARENA_TRASHED: // 7
2431: case ERROR_NOT_ENOUGH_MEMORY: // 8
2432: case ERROR_INVALID_BLOCK: // 9
2433: case ERROR_NOT_ENOUGH_QUOTA: // 1816
2434: return ENOMEM;
2435: case ERROR_BAD_ENVIRONMENT: // 10
2436: return E2BIG;
2437: case ERROR_BAD_FORMAT: // 11
2438: return ENOEXEC;
2439: case ERROR_NOT_SAME_DEVICE: // 17
2440: return EXDEV;
2441: case ERROR_FILE_EXISTS: // 80
2442: case ERROR_ALREADY_EXISTS: // 183
2443: return EEXIST;
2444: case ERROR_NO_PROC_SLOTS: // 89
2445: case ERROR_MAX_THRDS_REACHED: // 164
2446: case ERROR_NESTING_NOT_ALLOWED: // 215
2447: return EAGAIN;
2448: case ERROR_BROKEN_PIPE: // 109
2449: return EPIPE;
2450: case ERROR_DISK_FULL: // 112
2451: return ENOSPC;
2452: case ERROR_WAIT_NO_CHILDREN: // 128
2453: case ERROR_CHILD_NOT_COMPLETE: // 129
2454: return ECHILD;
2455: case ERROR_DIR_NOT_EMPTY: // 145
2456: return ENOTEMPTY;
2457: }
1.1.1.14 root 2458: if(oserrno >= ERROR_WRITE_PROTECT /* 19 */ &&
1.1.1.13 root 2459: oserrno <= ERROR_SHARING_BUFFER_EXCEEDED /* 36 */) {
2460: return EACCES;
2461: }
1.1.1.14 root 2462: if(oserrno >= ERROR_INVALID_STARTING_CODESEG /* 188 */ &&
1.1.1.13 root 2463: oserrno <= ERROR_INFLOOP_IN_RELOC_CHAIN /* 202 */) {
2464: return ENOEXEC;
2465: }
2466: return EINVAL;
2467: }
2468:
2469: int msdos_open(const char *filename, int oflag)
2470: {
1.1.1.14 root 2471: if((oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) != _O_RDONLY) {
1.1.1.13 root 2472: return _open(filename, oflag);
2473: }
1.1.1.14 root 2474:
2475: SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, !(oflag & _O_NOINHERIT) };
1.1.1.13 root 2476: DWORD disposition;
1.1.1.14 root 2477: switch(oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
2478: default:
1.1.1.13 root 2479: case _O_EXCL:
2480: disposition = OPEN_EXISTING;
2481: break;
2482: case _O_CREAT:
2483: disposition = OPEN_ALWAYS;
2484: break;
2485: case _O_CREAT | _O_EXCL:
2486: case _O_CREAT | _O_TRUNC | _O_EXCL:
2487: disposition = CREATE_NEW;
2488: break;
2489: case _O_TRUNC:
2490: case _O_TRUNC | _O_EXCL:
2491: disposition = TRUNCATE_EXISTING;
2492: break;
2493: case _O_CREAT | _O_TRUNC:
2494: disposition = CREATE_ALWAYS;
2495: break;
2496: }
1.1.1.14 root 2497:
1.1.1.13 root 2498: HANDLE h = CreateFile(filename, GENERIC_READ | FILE_WRITE_ATTRIBUTES,
2499: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
2500: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 2501: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 2502: // FILE_WRITE_ATTRIBUTES may not be granted for standard users.
2503: // Retry without FILE_WRITE_ATTRIBUTES.
2504: h = CreateFile(filename, GENERIC_READ,
2505: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
2506: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 2507: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 2508: errno = msdos_maperr(GetLastError());
2509: return -1;
2510: }
2511: }
1.1.1.14 root 2512:
1.1.1.13 root 2513: int fd = _open_osfhandle((intptr_t) h, oflag);
1.1.1.14 root 2514: if(fd == -1) {
1.1.1.13 root 2515: CloseHandle(h);
2516: }
2517: return fd;
2518: }
2519:
1.1.1.14 root 2520: void msdos_file_handler_open(int fd, const char *path, int atty, int mode, UINT16 info, UINT16 psp_seg)
1.1 root 2521: {
2522: static int id = 0;
2523: char full[MAX_PATH], *name;
2524:
2525: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
2526: strcpy(file_handler[fd].path, full);
2527: } else {
2528: strcpy(file_handler[fd].path, path);
2529: }
1.1.1.14 root 2530: // isatty makes no distinction between CON & NUL
2531: // GetFileSize fails on CON, succeeds on NUL
2532: if(atty && (info != 0x80d3 || GetFileSize((HANDLE)_get_osfhandle(fd), NULL) == 0)) {
2533: info = 0x8084;
2534: atty = 0;
2535: } else if(!atty && info == 0x80d3) {
2536: info = msdos_drive_number(".");
2537: }
1.1 root 2538: file_handler[fd].valid = 1;
2539: file_handler[fd].id = id++; // dummy id for int 21h ax=71a6h
2540: file_handler[fd].atty = atty;
2541: file_handler[fd].mode = mode;
2542: file_handler[fd].info = info;
2543: file_handler[fd].psp = psp_seg;
1.1.1.21 root 2544:
2545: // init system file table
2546: if(fd < 20) {
2547: UINT8 *sft = mem + SFT_TOP + 6 + 0x3b * fd;
2548:
2549: memset(sft, 0, 0x3b);
2550:
2551: *(UINT16 *)(sft + 0x00) = 1;
2552: *(UINT16 *)(sft + 0x02) = file_handler[fd].mode;
2553: *(UINT8 *)(sft + 0x04) = GetFileAttributes(file_handler[fd].path) & 0xff;
2554: *(UINT16 *)(sft + 0x05) = file_handler[fd].info & 0xff;
2555:
2556: if(!(file_handler[fd].info & 0x80)) {
2557: *(UINT16 *)(sft + 0x07) = sizeof(dpb_t) * (file_handler[fd].info & 0x1f);
2558: *(UINT16 *)(sft + 0x09) = DPB_TOP >> 4;
2559:
2560: FILETIME time, local;
2561: HANDLE hHandle;
2562: WORD dos_date = 0, dos_time = 0;
2563: DWORD file_size = 0;
2564: if((hHandle = (HANDLE)_get_osfhandle(fd)) != INVALID_HANDLE_VALUE) {
2565: if(GetFileTime(hHandle, NULL, NULL, &time)) {
2566: FileTimeToLocalFileTime(&time, &local);
2567: FileTimeToDosDateTime(&local, &dos_date, &dos_time);
2568: }
2569: file_size = GetFileSize(hHandle, NULL);
2570: }
2571: *(UINT16 *)(sft + 0x0d) = dos_time;
2572: *(UINT16 *)(sft + 0x0f) = dos_date;
2573: *(UINT32 *)(sft + 0x11) = file_size;
2574: }
2575:
2576: char fname[MAX_PATH] = {0}, ext[MAX_PATH] = {0};
2577: _splitpath(file_handler[fd].path, NULL, NULL, fname, ext);
2578: my_strupr(fname);
2579: my_strupr(ext);
2580: memset(sft + 0x20, 0x20, 11);
2581: memcpy(sft + 0x20, fname, min(strlen(fname), 8));
2582: memcpy(sft + 0x28, ext + 1, min(strlen(ext + 1), 3));
2583:
2584: *(UINT16 *)(sft + 0x31) = psp_seg;
2585: }
1.1 root 2586: }
2587:
2588: void msdos_file_handler_dup(int dst, int src, UINT16 psp_seg)
2589: {
2590: strcpy(file_handler[dst].path, file_handler[src].path);
2591: file_handler[dst].valid = 1;
2592: file_handler[dst].id = file_handler[src].id;
2593: file_handler[dst].atty = file_handler[src].atty;
2594: file_handler[dst].mode = file_handler[src].mode;
2595: file_handler[dst].info = file_handler[src].info;
2596: file_handler[dst].psp = psp_seg;
2597: }
2598:
1.1.1.20 root 2599: void msdos_file_handler_close(int fd)
1.1 root 2600: {
2601: file_handler[fd].valid = 0;
1.1.1.21 root 2602:
2603: if(fd < 20) {
2604: memset(mem + SFT_TOP + 6 + 0x3b * fd, 0, 0x3b);
2605: }
1.1 root 2606: }
2607:
1.1.1.14 root 2608: inline int msdos_file_attribute_create(UINT16 new_attr)
1.1 root 2609: {
1.1.1.14 root 2610: return(new_attr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
2611: FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE |
2612: FILE_ATTRIBUTE_DIRECTORY));
1.1 root 2613: }
2614:
2615: // find file
2616:
2617: int msdos_find_file_check_attribute(int attribute, int allowed_mask, int required_mask)
2618: {
2619: if((allowed_mask & 0x08) && !(attribute & FILE_ATTRIBUTE_DIRECTORY)) {
2620: return(0); // search directory only !!!
2621: } else if(!(allowed_mask & 0x02) && (attribute & FILE_ATTRIBUTE_HIDDEN)) {
2622: return(0);
2623: } else if(!(allowed_mask & 0x04) && (attribute & FILE_ATTRIBUTE_SYSTEM)) {
2624: return(0);
2625: } else if(!(allowed_mask & 0x10) && (attribute & FILE_ATTRIBUTE_DIRECTORY)) {
2626: return(0);
2627: } else if((attribute & required_mask) != required_mask) {
2628: return(0);
2629: } else {
2630: return(1);
2631: }
2632: }
2633:
1.1.1.13 root 2634: int msdos_find_file_has_8dot3name(WIN32_FIND_DATA *fd)
2635: {
1.1.1.14 root 2636: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 2637: return 1;
2638: }
2639: size_t len = strlen(fd->cFileName);
1.1.1.14 root 2640: if(len > 12) {
1.1.1.13 root 2641: return 0;
2642: }
2643: const char *ext = strrchr(fd->cFileName, '.');
1.1.1.14 root 2644: if((ext ? ext - fd->cFileName : len) > 8) {
1.1.1.13 root 2645: return 0;
2646: }
2647: return 1;
2648: }
2649:
1.1 root 2650: void msdos_find_file_conv_local_time(WIN32_FIND_DATA *fd)
2651: {
2652: FILETIME local;
2653:
2654: FileTimeToLocalFileTime(&fd->ftCreationTime, &local);
2655: fd->ftCreationTime.dwLowDateTime = local.dwLowDateTime;
2656: fd->ftCreationTime.dwHighDateTime = local.dwHighDateTime;
2657:
2658: FileTimeToLocalFileTime(&fd->ftLastAccessTime, &local);
2659: fd->ftLastAccessTime.dwLowDateTime = local.dwLowDateTime;
2660: fd->ftLastAccessTime.dwHighDateTime = local.dwHighDateTime;
2661:
2662: FileTimeToLocalFileTime(&fd->ftLastWriteTime, &local);
2663: fd->ftLastWriteTime.dwLowDateTime = local.dwLowDateTime;
2664: fd->ftLastWriteTime.dwHighDateTime = local.dwHighDateTime;
2665: }
2666:
2667: // i/o
2668:
2669: void msdos_stdio_reopen()
2670: {
2671: if(!file_handler[0].valid) {
2672: _dup2(DUP_STDIN, 0);
2673: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
2674: }
2675: if(!file_handler[1].valid) {
2676: _dup2(DUP_STDOUT, 1);
2677: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
2678: }
2679: if(!file_handler[2].valid) {
2680: _dup2(DUP_STDERR, 2);
2681: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
2682: }
1.1.1.21 root 2683: if(!file_handler[3].valid) {
2684: _dup2(DUP_STDAUX, 3);
2685: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
2686: }
2687: if(!file_handler[4].valid) {
2688: _dup2(DUP_STDPRN, 4);
2689: msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0);
2690: }
2691: for(int i = 0; i < 5; i++) {
2692: if(msdos_psp_get_file_table(i, current_psp) == 0xff) {
2693: msdos_psp_set_file_table(i, i, current_psp);
2694: }
2695: }
1.1 root 2696: }
2697:
2698: int msdos_kbhit()
2699: {
2700: msdos_stdio_reopen();
2701:
1.1.1.20 root 2702: process_t *process = msdos_process_info_get(current_psp);
2703: int fd = msdos_psp_get_file_table(0, current_psp);
2704:
2705: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 2706: // stdin is redirected to file
1.1.1.20 root 2707: return(eof(fd) == 0);
1.1 root 2708: }
2709:
2710: // check keyboard status
1.1.1.5 root 2711: if(key_buf_char->count() != 0 || key_code != 0) {
1.1 root 2712: return(1);
2713: } else {
2714: return(_kbhit());
2715: }
2716: }
2717:
2718: int msdos_getch_ex(int echo)
2719: {
2720: static char prev = 0;
2721:
2722: msdos_stdio_reopen();
2723:
1.1.1.20 root 2724: process_t *process = msdos_process_info_get(current_psp);
2725: int fd = msdos_psp_get_file_table(0, current_psp);
2726:
2727: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 2728: // stdin is redirected to file
2729: retry:
2730: char data;
1.1.1.20 root 2731: if(_read(fd, &data, 1) == 1) {
1.1 root 2732: char tmp = data;
2733: if(data == 0x0a) {
2734: if(prev == 0x0d) {
2735: goto retry; // CRLF -> skip LF
2736: } else {
2737: data = 0x0d; // LF only -> CR
2738: }
2739: }
2740: prev = tmp;
2741: return(data);
2742: }
2743: return(EOF);
2744: }
2745:
2746: // input from console
1.1.1.5 root 2747: int key_char, key_scan;
2748: if(key_code != 0) {
2749: key_char = (key_code >> 0) & 0xff;
2750: key_scan = (key_code >> 8) & 0xff;
2751: key_code >>= 16;
2752: } else {
1.1.1.26 root 2753: while(key_buf_char->count() == 0 && !m_halted && !ctrl_c_pressed) {
1.1.1.23 root 2754: if(!(fd < process->max_files && file_handler[fd].valid && file_handler[fd].atty && file_mode[file_handler[fd].mode].in)) {
2755: // NOTE: stdin is redirected to stderr when we do "type (file) | more" on freedos's command.com
2756: if(_kbhit()) {
2757: key_buf_char->write(_getch());
2758: key_buf_scan->write(0);
2759: } else {
2760: Sleep(10);
2761: }
2762: } else {
2763: if(!update_key_buffer()) {
2764: Sleep(10);
2765: }
1.1.1.14 root 2766: }
2767: }
2768: if(m_halted) {
1.1.1.26 root 2769: // ctrl-break pressed - insert CR to terminate input loops
1.1.1.14 root 2770: key_char = 0x0d;
2771: key_scan = 0;
1.1.1.26 root 2772: } else if(ctrl_c_pressed) {
2773: // ctrl-c pressed
2774: key_char = 0x03;
2775: key_scan = 0;
1.1.1.14 root 2776: } else {
2777: key_char = key_buf_char->read();
2778: key_scan = key_buf_scan->read();
1.1.1.5 root 2779: }
1.1 root 2780: }
2781: if(echo && key_char) {
2782: msdos_putch(key_char);
2783: }
2784: return key_char ? key_char : (key_scan != 0xe0) ? key_scan : 0;
2785: }
2786:
2787: inline int msdos_getch()
2788: {
2789: return(msdos_getch_ex(0));
2790: }
2791:
2792: inline int msdos_getche()
2793: {
2794: return(msdos_getch_ex(1));
2795: }
2796:
2797: int msdos_write(int fd, const void *buffer, unsigned int count)
2798: {
2799: static int is_cr = 0;
2800:
2801: if(fd == 1 && !file_handler[1].atty) {
2802: // CR+LF -> LF
2803: UINT8 *buf = (UINT8 *)buffer;
2804: for(unsigned int i = 0; i < count; i++) {
2805: UINT8 data = buf[i];
2806: if(is_cr) {
2807: if(data != 0x0a) {
2808: UINT8 tmp = 0x0d;
2809: _write(1, &tmp, 1);
2810: }
2811: _write(1, &data, 1);
2812: is_cr = 0;
2813: } else if(data == 0x0d) {
2814: is_cr = 1;
2815: } else {
2816: _write(1, &data, 1);
2817: }
2818: }
2819: return(count);
2820: }
1.1.1.14 root 2821: vram_flush();
1.1 root 2822: return(_write(fd, buffer, count));
2823: }
2824:
2825: void msdos_putch(UINT8 data)
2826: {
2827: static int p = 0;
2828: static int is_kanji = 0;
2829: static int is_esc = 0;
2830: static int stored_x;
2831: static int stored_y;
2832: static WORD stored_a;
1.1.1.20 root 2833: static char tmp[64], out[64];
1.1 root 2834:
2835: msdos_stdio_reopen();
2836:
1.1.1.20 root 2837: process_t *process = msdos_process_info_get(current_psp);
2838: int fd = msdos_psp_get_file_table(1, current_psp);
2839:
2840: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 2841: // stdout is redirected to file
1.1.1.20 root 2842: msdos_write(fd, &data, 1);
1.1 root 2843: return;
2844: }
1.1.1.23 root 2845: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 2846:
2847: // output to console
2848: tmp[p++] = data;
2849:
1.1.1.14 root 2850: vram_flush();
2851:
1.1 root 2852: if(is_kanji) {
2853: // kanji character
2854: is_kanji = 0;
2855: } else if(is_esc) {
2856: // escape sequense
2857: if((tmp[1] == ')' || tmp[1] == '(') && p == 3) {
2858: p = is_esc = 0;
2859: } else if(tmp[1] == '=' && p == 4) {
2860: COORD co;
2861: co.X = tmp[3] - 0x20;
1.1.1.14 root 2862: co.Y = tmp[2] - 0x20 + scr_top;
1.1 root 2863: SetConsoleCursorPosition(hStdout, co);
2864: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 2865: mem[0x451 + mem[0x462] * 2] = co.Y - scr_top;
1.1 root 2866: cursor_moved = false;
2867: p = is_esc = 0;
2868: } else if((data >= 'a' && data <= 'z') || (data >= 'A' && data <= 'Z') || data == '*') {
2869: CONSOLE_SCREEN_BUFFER_INFO csbi;
2870: COORD co;
2871: GetConsoleScreenBufferInfo(hStdout, &csbi);
2872: co.X = csbi.dwCursorPosition.X;
2873: co.Y = csbi.dwCursorPosition.Y;
2874: WORD wAttributes = csbi.wAttributes;
2875:
2876: if(tmp[1] == 'D') {
2877: co.Y++;
2878: } else if(tmp[1] == 'E') {
2879: co.X = 0;
2880: co.Y++;
2881: } else if(tmp[1] == 'M') {
2882: co.Y--;
2883: } else if(tmp[1] == '*') {
2884: SMALL_RECT rect;
1.1.1.14 root 2885: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2886: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2887: co.X = 0;
2888: co.Y = csbi.srWindow.Top;
1.1 root 2889: } else if(tmp[1] == '[') {
2890: int param[256], params = 0;
2891: memset(param, 0, sizeof(param));
2892: for(int i = 2; i < p; i++) {
2893: if(tmp[i] >= '0' && tmp[i] <= '9') {
2894: param[params] *= 10;
2895: param[params] += tmp[i] - '0';
2896: } else {
2897: params++;
2898: }
2899: }
2900: if(data == 'A') {
1.1.1.14 root 2901: co.Y -= (params == 0) ? 1 : param[0];
1.1 root 2902: } else if(data == 'B') {
1.1.1.14 root 2903: co.Y += (params == 0) ? 1 : param[0];
1.1 root 2904: } else if(data == 'C') {
1.1.1.14 root 2905: co.X += (params == 0) ? 1 : param[0];
1.1 root 2906: } else if(data == 'D') {
1.1.1.14 root 2907: co.X -= (params == 0) ? 1 : param[0];
1.1 root 2908: } else if(data == 'H' || data == 'f') {
1.1.1.14 root 2909: co.X = (param[1] == 0 ? 1 : param[1]) - 1;
2910: co.Y = (param[0] == 0 ? 1 : param[0]) - 1 + csbi.srWindow.Top;
1.1 root 2911: } else if(data == 'J') {
2912: SMALL_RECT rect;
1.1.1.14 root 2913: clear_scr_buffer(csbi.wAttributes);
1.1 root 2914: if(param[0] == 0) {
2915: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 2916: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2917: if(co.Y < csbi.srWindow.Bottom) {
2918: SET_RECT(rect, 0, co.Y + 1, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2919: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2920: }
2921: } else if(param[0] == 1) {
1.1.1.14 root 2922: if(co.Y > csbi.srWindow.Top) {
2923: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, co.Y - 1);
2924: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2925: }
2926: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 2927: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2928: } else if(param[0] == 2) {
1.1.1.14 root 2929: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2930: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2931: co.X = co.Y = 0;
2932: }
2933: } else if(data == 'K') {
2934: SMALL_RECT rect;
1.1.1.14 root 2935: clear_scr_buffer(csbi.wAttributes);
1.1 root 2936: if(param[0] == 0) {
2937: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 2938: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2939: } else if(param[0] == 1) {
2940: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 2941: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2942: } else if(param[0] == 2) {
2943: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 2944: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2945: }
2946: } else if(data == 'L') {
2947: SMALL_RECT rect;
1.1.1.14 root 2948: if(params == 0) {
2949: param[0] = 1;
1.1 root 2950: }
1.1.1.14 root 2951: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2952: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2953: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2954: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2955: clear_scr_buffer(csbi.wAttributes);
1.1 root 2956: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y + param[0] - 1);
1.1.1.14 root 2957: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2958: co.X = 0;
2959: } else if(data == 'M') {
2960: SMALL_RECT rect;
1.1.1.14 root 2961: if(params == 0) {
2962: param[0] = 1;
2963: }
2964: if(co.Y + param[0] > csbi.srWindow.Bottom) {
2965: clear_scr_buffer(csbi.wAttributes);
2966: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2967: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2968: } else {
1.1.1.14 root 2969: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2970: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2971: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2972: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2973: clear_scr_buffer(csbi.wAttributes);
1.1 root 2974: }
2975: co.X = 0;
2976: } else if(data == 'h') {
2977: if(tmp[2] == '>' && tmp[3] == '5') {
2978: CONSOLE_CURSOR_INFO cur;
2979: GetConsoleCursorInfo(hStdout, &cur);
2980: if(cur.bVisible) {
2981: cur.bVisible = FALSE;
1.1.1.14 root 2982: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 2983: }
2984: }
2985: } else if(data == 'l') {
2986: if(tmp[2] == '>' && tmp[3] == '5') {
2987: CONSOLE_CURSOR_INFO cur;
2988: GetConsoleCursorInfo(hStdout, &cur);
2989: if(!cur.bVisible) {
2990: cur.bVisible = TRUE;
1.1.1.14 root 2991: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 2992: }
2993: }
2994: } else if(data == 'm') {
2995: wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
2996: int reverse = 0, hidden = 0;
2997: for(int i = 0; i < params; i++) {
2998: if(param[i] == 1) {
2999: wAttributes |= FOREGROUND_INTENSITY;
3000: } else if(param[i] == 4) {
3001: wAttributes |= COMMON_LVB_UNDERSCORE;
3002: } else if(param[i] == 7) {
3003: reverse = 1;
3004: } else if(param[i] == 8 || param[i] == 16) {
3005: hidden = 1;
3006: } else if((param[i] >= 17 && param[i] <= 23) || (param[i] >= 30 && param[i] <= 37)) {
3007: wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
3008: if(param[i] >= 17 && param[i] <= 23) {
3009: param[i] -= 16;
3010: } else {
3011: param[i] -= 30;
3012: }
3013: if(param[i] & 1) {
3014: wAttributes |= FOREGROUND_RED;
3015: }
3016: if(param[i] & 2) {
3017: wAttributes |= FOREGROUND_GREEN;
3018: }
3019: if(param[i] & 4) {
3020: wAttributes |= FOREGROUND_BLUE;
3021: }
3022: } else if(param[i] >= 40 && param[i] <= 47) {
3023: wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
3024: if((param[i] - 40) & 1) {
3025: wAttributes |= BACKGROUND_RED;
3026: }
3027: if((param[i] - 40) & 2) {
3028: wAttributes |= BACKGROUND_GREEN;
3029: }
3030: if((param[i] - 40) & 4) {
3031: wAttributes |= BACKGROUND_BLUE;
3032: }
3033: }
3034: }
3035: if(reverse) {
3036: wAttributes &= ~0xff;
3037: wAttributes |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
3038: }
3039: if(hidden) {
3040: wAttributes &= ~0x0f;
3041: wAttributes |= (wAttributes >> 4) & 0x0f;
3042: }
3043: } else if(data == 'n') {
3044: if(param[0] == 6) {
3045: char tmp[16];
3046: sprintf(tmp, "\x1b[%d;%dR", co.Y + 1, co.X + 1);
3047: int len = strlen(tmp);
3048: for(int i = 0; i < len; i++) {
3049: key_buf_char->write(tmp[i]);
3050: key_buf_scan->write(0x00);
3051: }
3052: }
3053: } else if(data == 's') {
3054: stored_x = co.X;
3055: stored_y = co.Y;
3056: stored_a = wAttributes;
3057: } else if(data == 'u') {
3058: co.X = stored_x;
3059: co.Y = stored_y;
3060: wAttributes = stored_a;
3061: }
3062: }
3063: if(co.X < 0) {
3064: co.X = 0;
3065: } else if(co.X >= csbi.dwSize.X) {
3066: co.X = csbi.dwSize.X - 1;
3067: }
1.1.1.14 root 3068: if(co.Y < csbi.srWindow.Top) {
3069: co.Y = csbi.srWindow.Top;
3070: } else if(co.Y > csbi.srWindow.Bottom) {
3071: co.Y = csbi.srWindow.Bottom;
1.1 root 3072: }
3073: if(co.X != csbi.dwCursorPosition.X || co.Y != csbi.dwCursorPosition.Y) {
3074: SetConsoleCursorPosition(hStdout, co);
3075: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 3076: mem[0x451 + mem[0x462] * 2] = co.Y - csbi.srWindow.Top;
1.1 root 3077: cursor_moved = false;
3078: }
3079: if(wAttributes != csbi.wAttributes) {
3080: SetConsoleTextAttribute(hStdout, wAttributes);
3081: }
3082: p = is_esc = 0;
3083: }
3084: return;
3085: } else {
3086: if(msdos_lead_byte_check(data)) {
3087: is_kanji = 1;
3088: return;
3089: } else if(data == 0x1b) {
3090: is_esc = 1;
3091: return;
3092: }
3093: }
1.1.1.20 root 3094:
3095: DWORD q = 0, num;
3096: is_kanji = 0;
3097: for(int i = 0; i < p; i++) {
3098: UINT8 c = tmp[i];
3099: if(is_kanji) {
3100: is_kanji = 0;
3101: } else if(msdos_lead_byte_check(data)) {
3102: is_kanji = 1;
3103: } else if(msdos_ctrl_code_check(data)) {
3104: out[q++] = '^';
3105: c += 'A' - 1;
3106: }
3107: out[q++] = c;
3108: }
3109: WriteConsole(hStdout, out, q, &num, NULL);
1.1 root 3110: p = 0;
1.1.1.14 root 3111:
1.1.1.15 root 3112: if(!restore_console_on_exit) {
3113: CONSOLE_SCREEN_BUFFER_INFO csbi;
3114: GetConsoleScreenBufferInfo(hStdout, &csbi);
3115: scr_top = csbi.srWindow.Top;
3116: }
1.1 root 3117: cursor_moved = true;
3118: }
3119:
3120: int msdos_aux_in()
3121: {
1.1.1.21 root 3122: msdos_stdio_reopen();
3123:
1.1.1.20 root 3124: process_t *process = msdos_process_info_get(current_psp);
3125: int fd = msdos_psp_get_file_table(3, current_psp);
3126:
3127: if(fd < process->max_files && file_handler[fd].valid && !eof(fd)) {
1.1 root 3128: char data = 0;
1.1.1.20 root 3129: _read(fd, &data, 1);
1.1 root 3130: return(data);
3131: } else {
3132: return(EOF);
3133: }
3134: }
3135:
3136: void msdos_aux_out(char data)
3137: {
1.1.1.21 root 3138: msdos_stdio_reopen();
3139:
1.1.1.20 root 3140: process_t *process = msdos_process_info_get(current_psp);
3141: int fd = msdos_psp_get_file_table(3, current_psp);
3142:
3143: if(fd < process->max_files && file_handler[fd].valid) {
3144: msdos_write(fd, &data, 1);
1.1 root 3145: }
3146: }
3147:
3148: void msdos_prn_out(char data)
3149: {
1.1.1.21 root 3150: msdos_stdio_reopen();
3151:
1.1.1.20 root 3152: process_t *process = msdos_process_info_get(current_psp);
3153: int fd = msdos_psp_get_file_table(4, current_psp);
3154:
3155: if(fd < process->max_files && file_handler[fd].valid) {
3156: msdos_write(fd, &data, 1);
1.1 root 3157: }
3158: }
3159:
3160: // memory control
3161:
1.1.1.19 root 3162: mcb_t *msdos_mcb_create(int mcb_seg, UINT8 mz, UINT16 psp, int paragraphs)
1.1 root 3163: {
3164: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
3165:
3166: mcb->mz = mz;
3167: mcb->psp = psp;
1.1.1.19 root 3168: mcb->paragraphs32 = paragraphs;
1.1 root 3169: return(mcb);
3170: }
3171:
3172: void msdos_mcb_check(mcb_t *mcb)
3173: {
3174: if(!(mcb->mz == 'M' || mcb->mz == 'Z')) {
1.1.1.28 root 3175: #if 0
3176: // shutdown now !!!
3177: fatalerror("broken memory control block\n");
3178: #else
3179: // return error code and continue
3180: throw(0x07); // broken memory control block
3181: #endif
1.1 root 3182: }
3183: }
3184:
3185: int msdos_mem_split(int seg, int paragraphs)
3186: {
3187: int mcb_seg = seg - 1;
3188: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
3189: msdos_mcb_check(mcb);
3190:
1.1.1.19 root 3191: if(mcb->paragraphs() > paragraphs) {
1.1 root 3192: int new_seg = mcb_seg + 1 + paragraphs;
1.1.1.19 root 3193: int new_paragraphs = mcb->paragraphs() - paragraphs - 1;
1.1 root 3194:
3195: msdos_mcb_create(new_seg, mcb->mz, 0, new_paragraphs);
3196: mcb->mz = 'M';
1.1.1.19 root 3197: mcb->paragraphs32 = paragraphs;
1.1 root 3198: return(0);
3199: }
3200: return(-1);
3201: }
3202:
3203: void msdos_mem_merge(int seg)
3204: {
3205: int mcb_seg = seg - 1;
3206: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
3207: msdos_mcb_check(mcb);
3208:
3209: while(1) {
3210: if(mcb->mz == 'Z') {
3211: break;
3212: }
1.1.1.19 root 3213: int next_seg = mcb_seg + 1 + mcb->paragraphs();
1.1 root 3214: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
3215: msdos_mcb_check(next_mcb);
3216:
3217: if(next_mcb->psp != 0) {
3218: break;
3219: }
3220: mcb->mz = next_mcb->mz;
1.1.1.19 root 3221: mcb->paragraphs32 = mcb->paragraphs() + 1 + next_mcb->paragraphs();
1.1 root 3222: }
3223: }
3224:
1.1.1.8 root 3225: int msdos_mem_alloc(int mcb_seg, int paragraphs, int new_process)
1.1 root 3226: {
3227: while(1) {
3228: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
3229:
1.1.1.14 root 3230: if(mcb->psp == 0) {
3231: msdos_mem_merge(mcb_seg + 1);
3232: } else {
3233: msdos_mcb_check(mcb);
3234: }
1.1.1.8 root 3235: if(!(new_process && mcb->mz != 'Z')) {
1.1.1.19 root 3236: if(mcb->psp == 0 && mcb->paragraphs() >= paragraphs) {
1.1 root 3237: msdos_mem_split(mcb_seg + 1, paragraphs);
3238: mcb->psp = current_psp;
3239: return(mcb_seg + 1);
3240: }
3241: }
3242: if(mcb->mz == 'Z') {
3243: break;
3244: }
1.1.1.19 root 3245: mcb_seg += 1 + mcb->paragraphs();
1.1 root 3246: }
3247: return(-1);
3248: }
3249:
3250: int msdos_mem_realloc(int seg, int paragraphs, int *max_paragraphs)
3251: {
3252: int mcb_seg = seg - 1;
3253: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
3254: msdos_mcb_check(mcb);
1.1.1.19 root 3255: int current_paragraphs = mcb->paragraphs();
1.1 root 3256:
3257: msdos_mem_merge(seg);
1.1.1.19 root 3258: if(paragraphs > mcb->paragraphs()) {
1.1.1.14 root 3259: if(max_paragraphs) {
1.1.1.19 root 3260: *max_paragraphs = mcb->paragraphs();
1.1.1.14 root 3261: }
1.1 root 3262: msdos_mem_split(seg, current_paragraphs);
3263: return(-1);
3264: }
3265: msdos_mem_split(seg, paragraphs);
3266: return(0);
3267: }
3268:
3269: void msdos_mem_free(int seg)
3270: {
3271: int mcb_seg = seg - 1;
3272: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
3273: msdos_mcb_check(mcb);
3274:
3275: mcb->psp = 0;
3276: msdos_mem_merge(seg);
3277: }
3278:
1.1.1.8 root 3279: int msdos_mem_get_free(int mcb_seg, int new_process)
1.1 root 3280: {
3281: int max_paragraphs = 0;
3282:
3283: while(1) {
3284: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
3285: msdos_mcb_check(mcb);
3286:
1.1.1.8 root 3287: if(!(new_process && mcb->mz != 'Z')) {
1.1.1.19 root 3288: if(mcb->psp == 0 && mcb->paragraphs() > max_paragraphs) {
3289: max_paragraphs = mcb->paragraphs();
1.1 root 3290: }
3291: }
3292: if(mcb->mz == 'Z') {
3293: break;
3294: }
1.1.1.19 root 3295: mcb_seg += 1 + mcb->paragraphs();
1.1 root 3296: }
1.1.1.14 root 3297: return(max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs);
1.1 root 3298: }
3299:
1.1.1.8 root 3300: int msdos_mem_get_last_mcb(int mcb_seg, UINT16 psp)
3301: {
3302: int last_seg = -1;
3303:
3304: while(1) {
3305: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
3306: msdos_mcb_check(mcb);
3307:
1.1.1.14 root 3308: if(mcb->psp == psp) {
1.1.1.8 root 3309: last_seg = mcb_seg;
3310: }
1.1.1.14 root 3311: if(mcb->mz == 'Z') {
3312: break;
3313: }
1.1.1.19 root 3314: mcb_seg += 1 + mcb->paragraphs();
1.1.1.8 root 3315: }
3316: return(last_seg);
3317: }
3318:
1.1.1.19 root 3319: int msdos_mem_get_umb_linked()
3320: {
3321: int mcb_seg = first_mcb;
3322:
3323: while(1) {
3324: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
3325: msdos_mcb_check(mcb);
3326:
3327: if(mcb->mz == 'Z') {
3328: if(mcb_seg >= (UMB_TOP >> 4)) {
3329: return(-1);
3330: }
3331: break;
3332: }
3333: mcb_seg += 1 + mcb->paragraphs();
3334: }
3335: return(0);
3336: }
3337:
3338: int msdos_mem_link_umb()
3339: {
3340: int mcb_seg = first_mcb;
3341:
3342: while(1) {
3343: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
3344: msdos_mcb_check(mcb);
3345: mcb_seg += 1 + mcb->paragraphs();
3346:
3347: if(mcb->mz == 'Z') {
3348: if(mcb_seg == (MEMORY_END >> 4) - 1) {
3349: mcb->mz = 'M';
1.1.1.20 root 3350: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked |= 0x01;
1.1.1.19 root 3351: return(-1);
3352: }
3353: break;
3354: }
3355: }
3356: return(0);
3357: }
3358:
3359: int msdos_mem_unlink_umb()
3360: {
3361: int mcb_seg = first_mcb;
3362:
3363: while(1) {
3364: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
3365: msdos_mcb_check(mcb);
3366: mcb_seg += 1 + mcb->paragraphs();
3367:
3368: if(mcb->mz == 'Z') {
3369: break;
3370: } else {
3371: if(mcb_seg == (MEMORY_END >> 4) - 1) {
3372: mcb->mz = 'Z';
1.1.1.20 root 3373: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked &= ~0x01;
1.1.1.19 root 3374: return(-1);
3375: }
3376: }
3377: }
3378: return(0);
3379: }
3380:
1.1.1.29! root 3381: #ifdef SUPPORT_HMA
! 3382:
! 3383: hma_mcb_t *msdos_hma_mcb_create(int offset, int owner, int size, int next)
! 3384: {
! 3385: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
! 3386:
! 3387: mcb->ms[0] = 'M';
! 3388: mcb->ms[1] = 'S';
! 3389: mcb->owner = owner;
! 3390: mcb->size = size;
! 3391: mcb->next = next;
! 3392: return(mcb);
! 3393: }
! 3394:
! 3395: bool msdos_is_hma_mcb_valid(hma_mcb_t *mcb)
! 3396: {
! 3397: return(mcb->ms[0] == 'M' && mcb->ms[1] == 'S');
! 3398: }
! 3399:
! 3400: int msdos_hma_mem_split(int offset, int size)
! 3401: {
! 3402: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
! 3403:
! 3404: if(!msdos_is_hma_mcb_valid(mcb)) {
! 3405: return(-1);
! 3406: }
! 3407: if(mcb->size >= size + 0x10) {
! 3408: int new_offset = offset + 0x10 + size;
! 3409: int new_size = mcb->size - 0x10 - size;
! 3410:
! 3411: msdos_hma_mcb_create(new_offset, 0, new_size, mcb->next);
! 3412: mcb->size = size;
! 3413: mcb->next = new_offset;
! 3414: return(0);
! 3415: }
! 3416: return(-1);
! 3417: }
! 3418:
! 3419: void msdos_hma_mem_merge(int offset)
! 3420: {
! 3421: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
! 3422:
! 3423: if(!msdos_is_hma_mcb_valid(mcb)) {
! 3424: return;
! 3425: }
! 3426: while(1) {
! 3427: if(mcb->next == 0) {
! 3428: break;
! 3429: }
! 3430: hma_mcb_t *next_mcb = (hma_mcb_t *)(mem + 0xffff0 + mcb->next);
! 3431:
! 3432: if(!msdos_is_hma_mcb_valid(next_mcb)) {
! 3433: return;
! 3434: }
! 3435: if(next_mcb->owner != 0) {
! 3436: break;
! 3437: }
! 3438: mcb->size += 0x10 + next_mcb->size;
! 3439: mcb->next = next_mcb->next;
! 3440: }
! 3441: }
! 3442:
! 3443: int msdos_hma_mem_alloc(int size, UINT16 owner)
! 3444: {
! 3445: int offset = 0x10; // first mcb in HMA
! 3446:
! 3447: while(1) {
! 3448: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
! 3449:
! 3450: if(!msdos_is_hma_mcb_valid(mcb)) {
! 3451: return(-1);
! 3452: }
! 3453: if(mcb->owner == 0) {
! 3454: msdos_hma_mem_merge(offset);
! 3455: }
! 3456: if(mcb->owner == 0 && mcb->size >= size) {
! 3457: msdos_hma_mem_split(offset, size);
! 3458: mcb->owner = owner;
! 3459: return(offset);
! 3460: }
! 3461: if(mcb->next == 0) {
! 3462: break;
! 3463: }
! 3464: offset = mcb->next;
! 3465: }
! 3466: return(-1);
! 3467: }
! 3468:
! 3469: int msdos_hma_mem_realloc(int offset, int size)
! 3470: {
! 3471: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
! 3472:
! 3473: if(!msdos_is_hma_mcb_valid(mcb)) {
! 3474: return(-1);
! 3475: }
! 3476: if(mcb->size < size) {
! 3477: return(-1);
! 3478: }
! 3479: msdos_hma_mem_split(offset, size);
! 3480: return(0);
! 3481: }
! 3482:
! 3483: void msdos_hma_mem_free(int offset)
! 3484: {
! 3485: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
! 3486:
! 3487: if(!msdos_is_hma_mcb_valid(mcb)) {
! 3488: return;
! 3489: }
! 3490: mcb->owner = 0;
! 3491: msdos_hma_mem_merge(offset);
! 3492: }
! 3493:
! 3494: int msdos_hma_mem_get_free(int *available_offset)
! 3495: {
! 3496: int offset = 0x10; // first mcb in HMA
! 3497: int size = 0;
! 3498:
! 3499: while(1) {
! 3500: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
! 3501:
! 3502: if(!msdos_is_hma_mcb_valid(mcb)) {
! 3503: return(0);
! 3504: }
! 3505: if(mcb->owner == 0 && size < mcb->size) {
! 3506: if(available_offset != NULL) {
! 3507: *available_offset = offset;
! 3508: }
! 3509: size = mcb->size;
! 3510: }
! 3511: if(mcb->next == 0) {
! 3512: break;
! 3513: }
! 3514: offset = mcb->next;
! 3515: }
! 3516: return(size);
! 3517: }
! 3518:
! 3519: #endif
! 3520:
1.1 root 3521: // environment
3522:
3523: void msdos_env_set_argv(int env_seg, char *argv)
3524: {
3525: char *dst = (char *)(mem + (env_seg << 4));
3526:
3527: while(1) {
3528: if(dst[0] == 0) {
3529: break;
3530: }
3531: dst += strlen(dst) + 1;
3532: }
3533: *dst++ = 0; // end of environment
3534: *dst++ = 1; // top of argv[0]
3535: *dst++ = 0;
3536: memcpy(dst, argv, strlen(argv));
3537: dst += strlen(argv);
3538: *dst++ = 0;
3539: *dst++ = 0;
3540: }
3541:
3542: char *msdos_env_get_argv(int env_seg)
3543: {
3544: static char env[ENV_SIZE];
3545: char *src = env;
3546:
3547: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
3548: while(1) {
3549: if(src[0] == 0) {
3550: if(src[1] == 1) {
3551: return(src + 3);
3552: }
3553: break;
3554: }
3555: src += strlen(src) + 1;
3556: }
3557: return(NULL);
3558: }
3559:
3560: char *msdos_env_get(int env_seg, const char *name)
3561: {
3562: static char env[ENV_SIZE];
3563: char *src = env;
3564:
3565: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
3566: while(1) {
3567: if(src[0] == 0) {
3568: break;
3569: }
3570: int len = strlen(src);
3571: char *n = my_strtok(src, "=");
3572: char *v = src + strlen(n) + 1;
3573:
3574: if(_stricmp(name, n) == 0) {
3575: return(v);
3576: }
3577: src += len + 1;
3578: }
3579: return(NULL);
3580: }
3581:
3582: void msdos_env_set(int env_seg, char *name, char *value)
3583: {
3584: char env[ENV_SIZE];
3585: char *src = env;
3586: char *dst = (char *)(mem + (env_seg << 4));
3587: char *argv = msdos_env_get_argv(env_seg);
3588: int done = 0;
3589:
3590: memcpy(src, dst, ENV_SIZE);
3591: memset(dst, 0, ENV_SIZE);
3592: while(1) {
3593: if(src[0] == 0) {
3594: break;
3595: }
3596: int len = strlen(src);
3597: char *n = my_strtok(src, "=");
3598: char *v = src + strlen(n) + 1;
3599: char tmp[1024];
3600:
3601: if(_stricmp(name, n) == 0) {
3602: sprintf(tmp, "%s=%s", n, value);
3603: done = 1;
3604: } else {
3605: sprintf(tmp, "%s=%s", n, v);
3606: }
3607: memcpy(dst, tmp, strlen(tmp));
3608: dst += strlen(tmp) + 1;
3609: src += len + 1;
3610: }
3611: if(!done) {
3612: char tmp[1024];
3613:
3614: sprintf(tmp, "%s=%s", name, value);
3615: memcpy(dst, tmp, strlen(tmp));
3616: dst += strlen(tmp) + 1;
3617: }
3618: if(argv) {
3619: *dst++ = 0; // end of environment
3620: *dst++ = 1; // top of argv[0]
3621: *dst++ = 0;
3622: memcpy(dst, argv, strlen(argv));
3623: dst += strlen(argv);
3624: *dst++ = 0;
3625: *dst++ = 0;
3626: }
3627: }
3628:
3629: // process
3630:
1.1.1.8 root 3631: psp_t *msdos_psp_create(int psp_seg, UINT16 mcb_seg, UINT16 parent_psp, UINT16 env_seg)
1.1 root 3632: {
3633: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
3634:
3635: memset(psp, 0, PSP_SIZE);
3636: psp->exit[0] = 0xcd;
3637: psp->exit[1] = 0x20;
1.1.1.8 root 3638: psp->first_mcb = mcb_seg;
1.1 root 3639: psp->far_call = 0xea;
3640: psp->cpm_entry.w.l = 0xfff1; // int 21h, retf
3641: psp->cpm_entry.w.h = 0xf000;
3642: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
3643: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
3644: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
3645: psp->parent_psp = parent_psp;
1.1.1.20 root 3646: if(parent_psp == (UINT16)-1) {
3647: for(int i = 0; i < 20; i++) {
3648: if(file_handler[i].valid) {
3649: psp->file_table[i] = i;
3650: } else {
3651: psp->file_table[i] = 0xff;
3652: }
1.1 root 3653: }
1.1.1.20 root 3654: } else {
3655: memcpy(psp->file_table, ((psp_t *)(mem + (parent_psp << 4)))->file_table, 20);
1.1 root 3656: }
3657: psp->env_seg = env_seg;
3658: psp->stack.w.l = REG16(SP);
1.1.1.3 root 3659: psp->stack.w.h = SREG(SS);
1.1.1.14 root 3660: psp->file_table_size = 20;
3661: psp->file_table_ptr.w.l = 0x18;
3662: psp->file_table_ptr.w.h = psp_seg;
1.1 root 3663: psp->service[0] = 0xcd;
3664: psp->service[1] = 0x21;
3665: psp->service[2] = 0xcb;
3666: return(psp);
3667: }
3668:
1.1.1.20 root 3669: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg)
3670: {
3671: if(psp_seg && fd < 20) {
3672: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
3673: psp->file_table[fd] = value;
3674: }
3675: }
3676:
3677: int msdos_psp_get_file_table(int fd, int psp_seg)
3678: {
3679: if(psp_seg && fd < 20) {
3680: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
3681: fd = psp->file_table[fd];
3682: }
3683: return fd;
3684: }
3685:
1.1 root 3686: int msdos_process_exec(char *cmd, param_block_t *param, UINT8 al)
3687: {
3688: // load command file
3689: int fd = -1;
3690: int dos_command = 0;
1.1.1.24 root 3691: char command[MAX_PATH], path[MAX_PATH], opt[MAX_PATH], *name = NULL, name_tmp[MAX_PATH];
1.1 root 3692:
3693: int opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
3694: int opt_len = mem[opt_ofs];
3695: memset(opt, 0, sizeof(opt));
3696: memcpy(opt, mem + opt_ofs + 1, opt_len);
3697:
1.1.1.14 root 3698: if(strlen(cmd) >= 5 && _stricmp(&cmd[strlen(cmd) - 4], ".BAT") == 0) {
3699: // this is a batch file, run command.com
3700: char tmp[MAX_PATH];
3701: if(opt_len != 0) {
3702: sprintf(tmp, "/C %s %s", cmd, opt);
3703: } else {
3704: sprintf(tmp, "/C %s", cmd);
3705: }
3706: strcpy(opt, tmp);
3707: opt_len = strlen(opt);
3708: mem[opt_ofs] = opt_len;
3709: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
3710: strcpy(command, comspec_path);
3711: strcpy(name_tmp, "COMMAND.COM");
3712: } else {
3713: if(_stricmp(cmd, "C:\\COMMAND.COM") == 0) {
3714: // redirect C:\COMMAND.COM to comspec_path
3715: strcpy(command, comspec_path);
3716: } else {
3717: strcpy(command, cmd);
3718: }
1.1.1.24 root 3719: if(GetFullPathName(command, MAX_PATH, path, &name) == 0) {
3720: return(-1);
3721: }
1.1.1.14 root 3722: memset(name_tmp, 0, sizeof(name_tmp));
3723: strcpy(name_tmp, name);
3724:
3725: // check command.com
3726: if(_stricmp(name, "COMMAND.COM") == 0 || _stricmp(name, "COMMAND") == 0) {
3727: if(opt_len == 0) {
3728: // process_t *current_process = msdos_process_info_get(current_psp);
3729: process_t *current_process = NULL;
3730: for(int i = 0; i < MAX_PROCESS; i++) {
3731: if(process[i].psp == current_psp) {
3732: current_process = &process[i];
3733: break;
3734: }
3735: }
3736: if(current_process != NULL) {
3737: param->cmd_line.dw = current_process->dta.dw;
3738: opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
3739: opt_len = mem[opt_ofs];
3740: memset(opt, 0, sizeof(opt));
3741: memcpy(opt, mem + opt_ofs + 1, opt_len);
3742: }
3743: }
3744: for(int i = 0; i < opt_len; i++) {
3745: if(opt[i] == ' ') {
3746: continue;
3747: }
3748: if(opt[i] == '/' && (opt[i + 1] == 'c' || opt[i + 1] == 'C') && opt[i + 2] == ' ') {
3749: for(int j = i + 3; j < opt_len; j++) {
3750: if(opt[j] == ' ') {
3751: continue;
3752: }
3753: char *token = my_strtok(opt + j, " ");
3754:
3755: if(strlen(token) >= 5 && _stricmp(&token[strlen(token) - 4], ".BAT") == 0) {
3756: // this is a batch file, okay to run command.com
3757: } else {
3758: // run program directly without command.com
3759: strcpy(command, token);
3760: char tmp[MAX_PATH];
3761: strcpy(tmp, token + strlen(token) + 1);
3762: strcpy(opt, tmp);
3763: opt_len = strlen(opt);
3764: mem[opt_ofs] = opt_len;
3765: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
3766: dos_command = 1;
3767: }
3768: break;
1.1 root 3769: }
3770: }
1.1.1.14 root 3771: break;
1.1 root 3772: }
3773: }
3774: }
3775:
3776: // load command file
3777: strcpy(path, command);
3778: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
3779: sprintf(path, "%s.COM", command);
3780: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
3781: sprintf(path, "%s.EXE", command);
3782: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
1.1.1.14 root 3783: sprintf(path, "%s.BAT", command);
3784: if(_access(path, 0) == 0) {
3785: // this is a batch file, run command.com
3786: char tmp[MAX_PATH];
3787: if(opt_len != 0) {
3788: sprintf(tmp, "/C %s %s", path, opt);
3789: } else {
3790: sprintf(tmp, "/C %s", path);
3791: }
3792: strcpy(opt, tmp);
3793: opt_len = strlen(opt);
3794: mem[opt_ofs] = opt_len;
3795: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
3796: strcpy(path, comspec_path);
3797: strcpy(name_tmp, "COMMAND.COM");
3798: fd = _open(path, _O_RDONLY | _O_BINARY);
3799: } else {
3800: // search path in parent environments
3801: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
3802: char *env = msdos_env_get(parent_psp->env_seg, "PATH");
3803: if(env != NULL) {
3804: char env_path[4096];
3805: strcpy(env_path, env);
3806: char *token = my_strtok(env_path, ";");
3807:
3808: while(token != NULL) {
3809: if(strlen(token) != 0) {
3810: sprintf(path, "%s", msdos_combine_path(token, command));
3811: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
3812: break;
3813: }
3814: sprintf(path, "%s.COM", msdos_combine_path(token, command));
3815: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
3816: break;
3817: }
3818: sprintf(path, "%s.EXE", msdos_combine_path(token, command));
3819: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
3820: break;
3821: }
3822: sprintf(path, "%s.BAT", msdos_combine_path(token, command));
3823: if(_access(path, 0) == 0) {
3824: // this is a batch file, run command.com
3825: char tmp[MAX_PATH];
3826: if(opt_len != 0) {
3827: sprintf(tmp, "/C %s %s", path, opt);
3828: } else {
3829: sprintf(tmp, "/C %s", path);
3830: }
3831: strcpy(opt, tmp);
3832: opt_len = strlen(opt);
3833: mem[opt_ofs] = opt_len;
3834: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
3835: strcpy(path, comspec_path);
3836: strcpy(name_tmp, "COMMAND.COM");
3837: fd = _open(path, _O_RDONLY | _O_BINARY);
3838: break;
3839: }
1.1.1.8 root 3840: }
1.1.1.14 root 3841: token = my_strtok(NULL, ";");
1.1 root 3842: }
3843: }
3844: }
3845: }
3846: }
3847: }
3848: if(fd == -1) {
3849: if(dos_command) {
3850: // may be dos command
3851: char tmp[MAX_PATH];
3852: sprintf(tmp, "%s %s", command, opt);
3853: system(tmp);
3854: return(0);
3855: } else {
3856: return(-1);
3857: }
3858: }
3859: _read(fd, file_buffer, sizeof(file_buffer));
3860: _close(fd);
3861:
3862: // copy environment
1.1.1.29! root 3863: int umb_linked, env_seg, psp_seg;
1.1 root 3864:
1.1.1.29! root 3865: if((umb_linked = msdos_mem_get_umb_linked()) != 0) {
! 3866: msdos_mem_unlink_umb();
! 3867: }
1.1.1.8 root 3868: if((env_seg = msdos_mem_alloc(first_mcb, ENV_SIZE >> 4, 1)) == -1) {
1.1.1.29! root 3869: if((env_seg = msdos_mem_alloc(UMB_TOP >> 4, ENV_SIZE >> 4, 1)) == -1) {
! 3870: if(umb_linked != 0) {
! 3871: msdos_mem_link_umb();
! 3872: }
! 3873: return(-1);
! 3874: }
1.1 root 3875: }
3876: if(param->env_seg == 0) {
3877: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
3878: memcpy(mem + (env_seg << 4), mem + (parent_psp->env_seg << 4), ENV_SIZE);
3879: } else {
3880: memcpy(mem + (env_seg << 4), mem + (param->env_seg << 4), ENV_SIZE);
3881: }
3882: msdos_env_set_argv(env_seg, msdos_short_full_path(path));
3883:
3884: // check exe header
3885: exe_header_t *header = (exe_header_t *)file_buffer;
1.1.1.8 root 3886: int paragraphs, free_paragraphs = msdos_mem_get_free(first_mcb, 1);
1.1 root 3887: UINT16 cs, ss, ip, sp;
3888:
3889: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
3890: // memory allocation
3891: int header_size = header->header_size * 16;
3892: int load_size = header->pages * 512 - header_size;
3893: if(header_size + load_size < 512) {
3894: load_size = 512 - header_size;
3895: }
3896: paragraphs = (PSP_SIZE + load_size) >> 4;
3897: if(paragraphs + header->min_alloc > free_paragraphs) {
3898: msdos_mem_free(env_seg);
3899: return(-1);
3900: }
3901: paragraphs += header->max_alloc ? header->max_alloc : header->min_alloc;
3902: if(paragraphs > free_paragraphs) {
3903: paragraphs = free_paragraphs;
3904: }
1.1.1.8 root 3905: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1.1.29! root 3906: if((psp_seg = msdos_mem_alloc(UMB_TOP >> 4, paragraphs, 1)) == -1) {
! 3907: if(umb_linked != 0) {
! 3908: msdos_mem_link_umb();
! 3909: }
! 3910: msdos_mem_free(env_seg);
! 3911: return(-1);
! 3912: }
1.1 root 3913: }
3914: // relocation
3915: int start_seg = psp_seg + (PSP_SIZE >> 4);
3916: for(int i = 0; i < header->relocations; i++) {
3917: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
3918: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
3919: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
3920: }
3921: memcpy(mem + (start_seg << 4), file_buffer + header_size, load_size);
3922: // segments
3923: cs = header->init_cs + start_seg;
3924: ss = header->init_ss + start_seg;
3925: ip = header->init_ip;
3926: sp = header->init_sp - 2; // for symdeb
3927: } else {
3928: // memory allocation
3929: paragraphs = free_paragraphs;
1.1.1.8 root 3930: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1.1.29! root 3931: if((psp_seg = msdos_mem_alloc(UMB_TOP >> 4, paragraphs, 1)) == -1) {
! 3932: if(umb_linked != 0) {
! 3933: msdos_mem_link_umb();
! 3934: }
! 3935: msdos_mem_free(env_seg);
! 3936: return(-1);
! 3937: }
1.1 root 3938: }
3939: int start_seg = psp_seg + (PSP_SIZE >> 4);
3940: memcpy(mem + (start_seg << 4), file_buffer, 0x10000 - PSP_SIZE);
3941: // segments
3942: cs = ss = psp_seg;
3943: ip = 0x100;
3944: sp = 0xfffe;
3945: }
1.1.1.29! root 3946: if(umb_linked != 0) {
! 3947: msdos_mem_link_umb();
! 3948: }
1.1 root 3949:
3950: // create psp
1.1.1.3 root 3951: #if defined(HAS_I386)
3952: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_eip;
3953: #else
3954: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_pc - SREG_BASE(CS);
3955: #endif
3956: *(UINT16 *)(mem + 4 * 0x22 + 2) = SREG(CS);
1.1 root 3957: psp_t *psp = msdos_psp_create(psp_seg, psp_seg + paragraphs, current_psp, env_seg);
3958: memcpy(psp->fcb1, mem + (param->fcb1.w.h << 4) + param->fcb1.w.l, sizeof(psp->fcb1));
3959: memcpy(psp->fcb2, mem + (param->fcb2.w.h << 4) + param->fcb2.w.l, sizeof(psp->fcb2));
3960: memcpy(psp->buffer, mem + (param->cmd_line.w.h << 4) + param->cmd_line.w.l, sizeof(psp->buffer));
3961:
3962: mcb_t *mcb_env = (mcb_t *)(mem + ((env_seg - 1) << 4));
3963: mcb_t *mcb_psp = (mcb_t *)(mem + ((psp_seg - 1) << 4));
3964: mcb_psp->psp = mcb_env->psp = psp_seg;
3965:
1.1.1.4 root 3966: for(int i = 0; i < 8; i++) {
3967: if(name_tmp[i] == '.') {
3968: mcb_psp->prog_name[i] = '\0';
3969: break;
3970: } else if(i < 7 && msdos_lead_byte_check(name_tmp[i])) {
3971: mcb_psp->prog_name[i] = name_tmp[i];
3972: i++;
3973: mcb_psp->prog_name[i] = name_tmp[i];
3974: } else if(name_tmp[i] >= 'a' && name_tmp[i] <= 'z') {
3975: mcb_psp->prog_name[i] = name_tmp[i] - 'a' + 'A';
3976: } else {
3977: mcb_psp->prog_name[i] = name_tmp[i];
3978: }
3979: }
3980:
1.1 root 3981: // process info
3982: process_t *process = msdos_process_info_create(psp_seg);
3983: strcpy(process->module_dir, msdos_short_full_dir(path));
3984: process->dta.w.l = 0x80;
3985: process->dta.w.h = psp_seg;
3986: process->switchar = '/';
3987: process->max_files = 20;
3988: process->parent_int_10h_feh_called = int_10h_feh_called;
3989: process->parent_int_10h_ffh_called = int_10h_ffh_called;
1.1.1.14 root 3990: process->parent_ds = SREG(DS);
1.1 root 3991:
3992: current_psp = psp_seg;
1.1.1.23 root 3993: msdos_sda_update(current_psp);
1.1 root 3994:
3995: if(al == 0x00) {
3996: int_10h_feh_called = int_10h_ffh_called = false;
3997:
3998: // registers and segments
3999: REG16(AX) = REG16(BX) = 0x00;
4000: REG16(CX) = 0xff;
4001: REG16(DX) = psp_seg;
4002: REG16(SI) = ip;
4003: REG16(DI) = sp;
4004: REG16(SP) = sp;
1.1.1.3 root 4005: SREG(DS) = SREG(ES) = psp_seg;
4006: SREG(SS) = ss;
4007: i386_load_segment_descriptor(DS);
4008: i386_load_segment_descriptor(ES);
4009: i386_load_segment_descriptor(SS);
1.1 root 4010:
4011: *(UINT16 *)(mem + (ss << 4) + sp) = 0;
4012: i386_jmp_far(cs, ip);
4013: } else if(al == 0x01) {
4014: // copy ss:sp and cs:ip to param block
4015: param->sp = sp;
4016: param->ss = ss;
4017: param->ip = ip;
4018: param->cs = cs;
4019: }
4020: return(0);
4021: }
4022:
4023: void msdos_process_terminate(int psp_seg, int ret, int mem_free)
4024: {
4025: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
4026:
4027: *(UINT32 *)(mem + 4 * 0x22) = psp->int_22h.dw;
4028: *(UINT32 *)(mem + 4 * 0x23) = psp->int_23h.dw;
4029: *(UINT32 *)(mem + 4 * 0x24) = psp->int_24h.dw;
4030:
1.1.1.3 root 4031: SREG(SS) = psp->stack.w.h;
4032: i386_load_segment_descriptor(SS);
1.1 root 4033: REG16(SP) = psp->stack.w.l;
4034: i386_jmp_far(psp->int_22h.w.h, psp->int_22h.w.l);
4035:
1.1.1.28 root 4036: // process_t *current_process = msdos_process_info_get(psp_seg);
4037: process_t *current_process = NULL;
4038: for(int i = 0; i < MAX_PROCESS; i++) {
4039: if(process[i].psp == psp_seg) {
4040: current_process = &process[i];
4041: break;
4042: }
4043: }
4044: if(current_process == NULL) {
4045: throw(0x1f); // general failure
4046: }
4047: int_10h_feh_called = current_process->parent_int_10h_feh_called;
4048: int_10h_ffh_called = current_process->parent_int_10h_ffh_called;
4049: if(current_process->called_by_int2eh) {
4050: REG16(AX) = ret;
4051: }
4052: SREG(DS) = current_process->parent_ds;
1.1.1.14 root 4053: i386_load_segment_descriptor(DS);
1.1 root 4054:
4055: if(mem_free) {
1.1.1.8 root 4056: int mcb_seg;
4057: while((mcb_seg = msdos_mem_get_last_mcb(first_mcb, psp_seg)) != -1) {
4058: msdos_mem_free(mcb_seg + 1);
4059: }
4060: while((mcb_seg = msdos_mem_get_last_mcb(UMB_TOP >> 4, psp_seg)) != -1) {
4061: msdos_mem_free(mcb_seg + 1);
4062: }
1.1 root 4063:
4064: for(int i = 0; i < MAX_FILES; i++) {
4065: if(file_handler[i].valid && file_handler[i].psp == psp_seg) {
4066: _close(i);
1.1.1.20 root 4067: msdos_file_handler_close(i);
4068: msdos_psp_set_file_table(i, 0x0ff, psp_seg); // FIXME: consider duplicated file handles
1.1 root 4069: }
4070: }
1.1.1.13 root 4071: msdos_dta_info_free(psp_seg);
1.1 root 4072: }
1.1.1.14 root 4073: msdos_stdio_reopen();
1.1 root 4074:
1.1.1.28 root 4075: memset(current_process, 0, sizeof(process_t));
1.1 root 4076:
4077: current_psp = psp->parent_psp;
4078: retval = ret;
1.1.1.23 root 4079: msdos_sda_update(current_psp);
1.1 root 4080: }
4081:
4082: // drive
4083:
4084: int msdos_drive_param_block_update(int drive_num, UINT16 *seg, UINT16 *ofs, int force_update)
4085: {
4086: *seg = DPB_TOP >> 4;
4087: *ofs = sizeof(dpb_t) * drive_num;
4088: dpb_t *dpb = (dpb_t *)(mem + (*seg << 4) + *ofs);
4089:
4090: if(!force_update && dpb->free_clusters != 0) {
4091: return(dpb->bytes_per_sector ? 1 : 0);
4092: }
4093: memset(dpb, 0, sizeof(dpb_t));
4094:
4095: int res = 0;
4096: char dev[64];
4097: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
4098:
1.1.1.17 root 4099: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1.1 root 4100: if(hFile != INVALID_HANDLE_VALUE) {
4101: DISK_GEOMETRY geo;
4102: DWORD dwSize;
4103: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
4104: dpb->bytes_per_sector = (UINT16)geo.BytesPerSector;
4105: dpb->highest_sector_num = (UINT8)(geo.SectorsPerTrack - 1);
4106: dpb->highest_cluster_num = (UINT16)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1.1.14 root 4107: dpb->maximum_cluster_num = (UINT32)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1 root 4108: switch(geo.MediaType) {
4109: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
4110: dpb->media_type = 0xff;
4111: break;
4112: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
4113: dpb->media_type = 0xfe;
4114: break;
4115: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
4116: dpb->media_type = 0xfd;
4117: break;
4118: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
4119: dpb->media_type = 0xfc;
4120: break;
4121: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
4122: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
4123: dpb->media_type = 0xf9;
4124: break;
4125: case FixedMedia: // hard disk
4126: case RemovableMedia:
1.1.1.19 root 4127: case Unknown:
1.1 root 4128: dpb->media_type = 0xf8;
4129: break;
4130: default:
4131: dpb->media_type = 0xf0;
4132: break;
4133: }
4134: res = 1;
4135: }
4136: dpb->drive_num = drive_num;
4137: dpb->unit_num = drive_num;
4138: dpb->next_dpb_ofs = *ofs + sizeof(dpb_t);
4139: dpb->next_dpb_seg = *seg;
1.1.1.14 root 4140: dpb->info_sector = 0xffff;
4141: dpb->backup_boot_sector = 0xffff;
1.1 root 4142: dpb->free_clusters = 0xffff;
1.1.1.14 root 4143: dpb->free_search_cluster = 0xffffffff;
1.1 root 4144: CloseHandle(hFile);
4145: }
4146: return(res);
4147: }
4148:
4149: // pc bios
4150:
1.1.1.19 root 4151: UINT32 get_ticks_since_midnight(UINT32 cur_msec)
4152: {
4153: static unsigned __int64 start_msec_since_midnight = 0;
4154: static unsigned __int64 start_msec_since_hostboot = 0;
4155:
4156: if(start_msec_since_midnight == 0) {
4157: SYSTEMTIME time;
4158: GetLocalTime(&time);
4159: start_msec_since_midnight = ((time.wHour * 60 + time.wMinute) * 60 + time.wSecond) * 1000 + time.wMilliseconds;
4160: start_msec_since_hostboot = cur_msec;
4161: }
4162: unsigned __int64 msec = (start_msec_since_midnight + cur_msec - start_msec_since_hostboot) % (24 * 60 * 60 * 1000);
4163: unsigned __int64 tick = msec * 0x1800b0 / (24 * 60 * 60 * 1000);
4164: return (UINT32)tick;
4165: }
4166:
4167: void pcbios_update_daily_timer_counter(UINT32 cur_msec)
4168: {
4169: UINT32 prev_tick = *(UINT32 *)(mem + 0x46c);
4170: UINT32 next_tick = get_ticks_since_midnight(cur_msec);
4171:
4172: if(prev_tick > next_tick) {
4173: mem[0x470] = 1;
4174: }
4175: *(UINT32 *)(mem + 0x46c) = next_tick;
4176: }
4177:
1.1.1.14 root 4178: inline void pcbios_irq0()
4179: {
4180: //++*(UINT32 *)(mem + 0x46c);
1.1.1.19 root 4181: pcbios_update_daily_timer_counter(timeGetTime());
1.1.1.14 root 4182: }
4183:
1.1.1.16 root 4184: int pcbios_get_text_vram_address(int page)
1.1 root 4185: {
4186: if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 4187: return TEXT_VRAM_TOP;
1.1 root 4188: } else {
1.1.1.14 root 4189: return TEXT_VRAM_TOP + VIDEO_REGEN * (page % vram_pages);
1.1 root 4190: }
4191: }
4192:
1.1.1.16 root 4193: int pcbios_get_shadow_buffer_address(int page)
1.1 root 4194: {
1.1.1.14 root 4195: if(!int_10h_feh_called) {
1.1.1.16 root 4196: return pcbios_get_text_vram_address(page);
1.1.1.14 root 4197: } else if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 4198: return SHADOW_BUF_TOP;
4199: } else {
1.1.1.14 root 4200: return SHADOW_BUF_TOP + VIDEO_REGEN * (page % vram_pages);
1.1.1.8 root 4201: }
4202: }
4203:
1.1.1.16 root 4204: int pcbios_get_shadow_buffer_address(int page, int x, int y)
1.1.1.8 root 4205: {
1.1.1.16 root 4206: return pcbios_get_shadow_buffer_address(page) + (x + y * scr_width) * 2;
1.1 root 4207: }
4208:
1.1.1.16 root 4209: void pcbios_set_console_size(int width, int height, bool clr_screen)
1.1 root 4210: {
1.1.1.14 root 4211: // clear the existing screen, not just the new one
4212: int clr_height = max(height, scr_height);
4213:
1.1.1.16 root 4214: if(scr_width != width || scr_height != height) {
4215: change_console_size(width, height);
1.1.1.14 root 4216: }
4217: mem[0x462] = 0;
4218: *(UINT16 *)(mem + 0x44e) = 0;
4219:
1.1.1.16 root 4220: text_vram_top_address = pcbios_get_text_vram_address(0);
4221: text_vram_end_address = text_vram_top_address + width * height * 2;
4222: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(0);
4223: shadow_buffer_end_address = shadow_buffer_top_address + width * height * 2;
1.1 root 4224:
1.1.1.23 root 4225: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.16 root 4226: if(clr_screen) {
1.1.1.14 root 4227: for(int ofs = shadow_buffer_top_address; ofs < shadow_buffer_end_address;) {
4228: mem[ofs++] = 0x20;
4229: mem[ofs++] = 0x07;
4230: }
4231:
4232: EnterCriticalSection(&vram_crit_sect);
4233: for(int y = 0; y < clr_height; y++) {
4234: for(int x = 0; x < scr_width; x++) {
4235: SCR_BUF(y,x).Char.AsciiChar = ' ';
4236: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 4237: }
4238: }
4239: SMALL_RECT rect;
1.1.1.14 root 4240: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + clr_height - 1);
4241: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
4242: vram_length_char = vram_last_length_char = 0;
4243: vram_length_attr = vram_last_length_attr = 0;
4244: LeaveCriticalSection(&vram_crit_sect);
1.1 root 4245: }
1.1.1.14 root 4246: COORD co;
4247: co.X = 0;
4248: co.Y = scr_top;
4249: SetConsoleCursorPosition(hStdout, co);
4250: cursor_moved = true;
4251: SetConsoleTextAttribute(hStdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
1.1 root 4252: }
4253:
1.1.1.16 root 4254: inline void pcbios_int_10h_00h()
4255: {
4256: switch(REG8(AL) & 0x7f) {
4257: case 0x70: // v-text mode
4258: case 0x71: // extended cga v-text mode
4259: pcbios_set_console_size(scr_width, scr_height, !(REG8(AL) & 0x80));
4260: break;
4261: default:
4262: pcbios_set_console_size(80, 25, !(REG8(AL) & 0x80));
4263: break;
4264: }
4265: if(REG8(AL) & 0x80) {
4266: mem[0x487] |= 0x80;
4267: } else {
4268: mem[0x487] &= ~0x80;
4269: }
4270: mem[0x449] = REG8(AL) & 0x7f;
4271: }
4272:
1.1 root 4273: inline void pcbios_int_10h_01h()
4274: {
1.1.1.13 root 4275: mem[0x460] = REG8(CL);
4276: mem[0x461] = REG8(CH);
1.1.1.14 root 4277:
1.1.1.23 root 4278: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 4279: CONSOLE_CURSOR_INFO ci;
4280: GetConsoleCursorInfo(hStdout, &ci);
4281: // ci.bVisible = !(REG8(CH) & 0x60) && REG8(CH) <= REG8(CL);
4282: // if(ci.bVisible) {
4283: int lines = max(8, REG8(CL) + 1);
4284: ci.dwSize = (REG8(CL) - REG8(CH) + 1) * 100 / lines;
4285: // }
4286: SetConsoleCursorInfo(hStdout, &ci);
1.1 root 4287: }
4288:
4289: inline void pcbios_int_10h_02h()
4290: {
1.1.1.14 root 4291: // continuously setting the cursor effectively stops it blinking
4292: if(mem[0x462] == REG8(BH) && (REG8(DL) != mem[0x450 + REG8(BH) * 2] || REG8(DH) != mem[0x451 + REG8(BH) * 2])) {
1.1 root 4293: COORD co;
4294: co.X = REG8(DL);
1.1.1.14 root 4295: co.Y = REG8(DH) + scr_top;
4296:
4297: // some programs hide the cursor by moving it off screen
4298: static bool hidden = false;
1.1.1.23 root 4299: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 4300: CONSOLE_CURSOR_INFO ci;
4301: GetConsoleCursorInfo(hStdout, &ci);
4302:
4303: if(REG8(DH) >= scr_height || !SetConsoleCursorPosition(hStdout, co)) {
4304: if(ci.bVisible) {
4305: ci.bVisible = FALSE;
4306: // SetConsoleCursorInfo(hStdout, &ci);
4307: hidden = true;
4308: }
4309: } else if(hidden) {
4310: if(!ci.bVisible) {
4311: ci.bVisible = TRUE;
4312: // SetConsoleCursorInfo(hStdout, &ci);
4313: }
4314: hidden = false;
4315: }
1.1 root 4316: }
1.1.1.14 root 4317: mem[0x450 + (REG8(BH) % vram_pages) * 2] = REG8(DL);
4318: mem[0x451 + (REG8(BH) % vram_pages) * 2] = REG8(DH);
1.1 root 4319: }
4320:
4321: inline void pcbios_int_10h_03h()
4322: {
1.1.1.14 root 4323: REG8(DL) = mem[0x450 + (REG8(BH) % vram_pages) * 2];
4324: REG8(DH) = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 4325: REG8(CL) = mem[0x460];
4326: REG8(CH) = mem[0x461];
4327: }
4328:
4329: inline void pcbios_int_10h_05h()
4330: {
1.1.1.14 root 4331: if(REG8(AL) >= vram_pages) {
4332: return;
4333: }
4334: if(mem[0x462] != REG8(AL)) {
4335: vram_flush();
4336:
1.1.1.23 root 4337: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 4338: SMALL_RECT rect;
1.1.1.14 root 4339: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
4340: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4341:
1.1.1.16 root 4342: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(mem[0x462]); y < scr_height; y++) {
1.1.1.14 root 4343: for(int x = 0; x < scr_width; x++) {
4344: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
4345: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 4346: }
4347: }
1.1.1.16 root 4348: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(REG8(AL)); y < scr_height; y++) {
1.1.1.14 root 4349: for(int x = 0; x < scr_width; x++) {
4350: SCR_BUF(y,x).Char.AsciiChar = mem[ofs++];
4351: SCR_BUF(y,x).Attributes = mem[ofs++];
1.1 root 4352: }
4353: }
1.1.1.14 root 4354: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4355:
4356: COORD co;
1.1.1.14 root 4357: co.X = mem[0x450 + REG8(AL) * 2];
4358: co.Y = mem[0x451 + REG8(AL) * 2] + scr_top;
4359: if(co.Y < scr_top + scr_height) {
4360: SetConsoleCursorPosition(hStdout, co);
4361: }
1.1 root 4362: }
1.1.1.14 root 4363: mem[0x462] = REG8(AL);
4364: *(UINT16 *)(mem + 0x44e) = REG8(AL) * VIDEO_REGEN;
4365: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.16 root 4366: text_vram_top_address = pcbios_get_text_vram_address(mem[0x462]);
1.1.1.14 root 4367: text_vram_end_address = text_vram_top_address + regen;
1.1.1.16 root 4368: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(mem[0x462]);
1.1.1.14 root 4369: shadow_buffer_end_address = shadow_buffer_top_address + regen;
1.1 root 4370: }
4371:
4372: inline void pcbios_int_10h_06h()
4373: {
1.1.1.14 root 4374: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
4375: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
4376: return;
4377: }
4378: vram_flush();
4379:
1.1.1.23 root 4380: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 4381: SMALL_RECT rect;
1.1.1.14 root 4382: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
4383: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
4384:
4385: int right = min(REG8(DL), scr_width - 1);
4386: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 4387:
4388: if(REG8(AL) == 0) {
1.1.1.14 root 4389: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 4390: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 4391: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
4392: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 4393: }
4394: }
4395: } else {
1.1.1.14 root 4396: for(int y = REG8(CH), y2 = min(REG8(CH) + REG8(AL), bottom + 1); y <= bottom; y++, y2++) {
1.1.1.16 root 4397: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 4398: if(y2 <= bottom) {
4399: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 4400: } else {
1.1.1.14 root 4401: SCR_BUF(y,x).Char.AsciiChar = ' ';
4402: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 4403: }
1.1.1.14 root 4404: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
4405: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 4406: }
4407: }
4408: }
1.1.1.14 root 4409: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4410: }
4411:
4412: inline void pcbios_int_10h_07h()
4413: {
1.1.1.14 root 4414: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
4415: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
4416: return;
4417: }
4418: vram_flush();
4419:
1.1.1.23 root 4420: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 4421: SMALL_RECT rect;
1.1.1.14 root 4422: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
4423: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
4424:
4425: int right = min(REG8(DL), scr_width - 1);
4426: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 4427:
4428: if(REG8(AL) == 0) {
1.1.1.14 root 4429: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 4430: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 4431: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
4432: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 4433: }
4434: }
4435: } else {
1.1.1.14 root 4436: for(int y = bottom, y2 = max(REG8(CH) - 1, bottom - REG8(AL)); y >= REG8(CH); y--, y2--) {
1.1.1.16 root 4437: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 4438: if(y2 >= REG8(CH)) {
4439: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 4440: } else {
1.1.1.14 root 4441: SCR_BUF(y,x).Char.AsciiChar = ' ';
4442: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 4443: }
1.1.1.14 root 4444: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
4445: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 4446: }
4447: }
4448: }
1.1.1.14 root 4449: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4450: }
4451:
4452: inline void pcbios_int_10h_08h()
4453: {
4454: COORD co;
4455: DWORD num;
4456:
1.1.1.14 root 4457: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
4458: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 4459:
4460: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 4461: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 4462: co.Y += scr_top;
4463: vram_flush();
1.1 root 4464: ReadConsoleOutputCharacter(hStdout, scr_char, 1, co, &num);
4465: ReadConsoleOutputAttribute(hStdout, scr_attr, 1, co, &num);
4466: REG8(AL) = scr_char[0];
4467: REG8(AH) = scr_attr[0];
4468: } else {
1.1.1.16 root 4469: REG16(AX) = *(UINT16 *)(mem + pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y));
1.1 root 4470: }
4471: }
4472:
4473: inline void pcbios_int_10h_09h()
4474: {
4475: COORD co;
4476:
1.1.1.14 root 4477: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
4478: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
4479:
1.1.1.16 root 4480: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
4481: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 4482:
4483: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 4484: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 4485: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 4486: while(dest < end) {
4487: write_text_vram_char(dest - vram, REG8(AL));
4488: mem[dest++] = REG8(AL);
4489: write_text_vram_attr(dest - vram, REG8(BL));
4490: mem[dest++] = REG8(BL);
1.1 root 4491: }
1.1.1.14 root 4492: LeaveCriticalSection(&vram_crit_sect);
1.1 root 4493: } else {
1.1.1.14 root 4494: while(dest < end) {
1.1 root 4495: mem[dest++] = REG8(AL);
4496: mem[dest++] = REG8(BL);
4497: }
4498: }
4499: }
4500:
4501: inline void pcbios_int_10h_0ah()
4502: {
4503: COORD co;
4504:
1.1.1.14 root 4505: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
4506: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
4507:
1.1.1.16 root 4508: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
4509: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 4510:
4511: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 4512: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 4513: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 4514: while(dest < end) {
4515: write_text_vram_char(dest - vram, REG8(AL));
4516: mem[dest++] = REG8(AL);
4517: dest++;
1.1 root 4518: }
1.1.1.14 root 4519: LeaveCriticalSection(&vram_crit_sect);
1.1 root 4520: } else {
1.1.1.14 root 4521: while(dest < end) {
1.1 root 4522: mem[dest++] = REG8(AL);
4523: dest++;
4524: }
4525: }
4526: }
4527:
4528: inline void pcbios_int_10h_0eh()
4529: {
1.1.1.14 root 4530: DWORD num;
4531: COORD co;
4532:
4533: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
4534: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
4535:
4536: if(REG8(AL) == 7) {
4537: //MessageBeep(-1);
4538: } else if(REG8(AL) == 8 || REG8(AL) == 10 || REG8(AL) == 13) {
4539: if(REG8(AL) == 10) {
4540: vram_flush();
4541: }
1.1.1.23 root 4542: WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ®8(AL), 1, &num, NULL);
1.1.1.14 root 4543: cursor_moved = true;
4544: } else {
1.1.1.16 root 4545: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
1.1.1.14 root 4546: if(mem[0x462] == REG8(BH)) {
4547: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 4548: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 4549: write_text_vram_char(dest - vram, REG8(AL));
4550: LeaveCriticalSection(&vram_crit_sect);
4551:
1.1.1.23 root 4552: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 4553: if(++co.X == scr_width) {
4554: co.X = 0;
4555: if(++co.Y == scr_height) {
4556: vram_flush();
4557: WriteConsole(hStdout, "\n", 1, &num, NULL);
4558: cursor_moved = true;
4559: }
4560: }
4561: if(!cursor_moved) {
4562: co.Y += scr_top;
4563: SetConsoleCursorPosition(hStdout, co);
4564: cursor_moved = true;
4565: }
4566: }
4567: mem[dest] = REG8(AL);
4568: }
1.1 root 4569: }
4570:
4571: inline void pcbios_int_10h_0fh()
4572: {
4573: REG8(AL) = mem[0x449];
4574: REG8(AH) = mem[0x44a];
4575: REG8(BH) = mem[0x462];
4576: }
4577:
1.1.1.14 root 4578: inline void pcbios_int_10h_11h()
4579: {
4580: switch(REG8(AL)) {
1.1.1.16 root 4581: case 0x01:
1.1.1.14 root 4582: case 0x11:
1.1.1.16 root 4583: pcbios_set_console_size(80, 28, true);
1.1.1.14 root 4584: break;
1.1.1.16 root 4585: case 0x02:
1.1.1.14 root 4586: case 0x12:
1.1.1.16 root 4587: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 4588: break;
1.1.1.16 root 4589: case 0x04:
1.1.1.14 root 4590: case 0x14:
1.1.1.16 root 4591: pcbios_set_console_size(80, 25, true);
4592: break;
4593: case 0x18:
4594: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 4595: break;
4596: case 0x30:
4597: SREG(ES) = 0;
4598: i386_load_segment_descriptor(ES);
4599: REG16(BP) = 0;
4600: REG16(CX) = mem[0x485];
4601: REG8(DL) = mem[0x484];
4602: break;
4603: }
4604: }
4605:
4606: inline void pcbios_int_10h_12h()
4607: {
1.1.1.16 root 4608: switch(REG8(BL)) {
4609: case 0x10:
1.1.1.14 root 4610: REG16(BX) = 0x0003;
4611: REG16(CX) = 0x0009;
1.1.1.16 root 4612: break;
1.1.1.14 root 4613: }
4614: }
4615:
1.1 root 4616: inline void pcbios_int_10h_13h()
4617: {
1.1.1.3 root 4618: int ofs = SREG_BASE(ES) + REG16(BP);
1.1 root 4619: COORD co;
4620: DWORD num;
4621:
4622: co.X = REG8(DL);
1.1.1.14 root 4623: co.Y = REG8(DH) + scr_top;
4624:
4625: vram_flush();
1.1 root 4626:
4627: switch(REG8(AL)) {
4628: case 0x00:
4629: case 0x01:
4630: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 4631: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 4632: CONSOLE_SCREEN_BUFFER_INFO csbi;
4633: GetConsoleScreenBufferInfo(hStdout, &csbi);
4634: SetConsoleCursorPosition(hStdout, co);
4635:
4636: if(csbi.wAttributes != REG8(BL)) {
4637: SetConsoleTextAttribute(hStdout, REG8(BL));
4638: }
1.1.1.14 root 4639: WriteConsole(hStdout, &mem[ofs], REG16(CX), &num, NULL);
4640:
1.1 root 4641: if(csbi.wAttributes != REG8(BL)) {
4642: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
4643: }
4644: if(REG8(AL) == 0x00) {
1.1.1.15 root 4645: if(!restore_console_on_exit) {
4646: GetConsoleScreenBufferInfo(hStdout, &csbi);
4647: scr_top = csbi.srWindow.Top;
4648: }
1.1.1.14 root 4649: co.X = mem[0x450 + REG8(BH) * 2];
4650: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 4651: SetConsoleCursorPosition(hStdout, co);
4652: } else {
4653: cursor_moved = true;
4654: }
4655: } else {
1.1.1.3 root 4656: m_CF = 1;
1.1 root 4657: }
4658: break;
4659: case 0x02:
4660: case 0x03:
4661: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 4662: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 4663: CONSOLE_SCREEN_BUFFER_INFO csbi;
4664: GetConsoleScreenBufferInfo(hStdout, &csbi);
4665: SetConsoleCursorPosition(hStdout, co);
4666:
4667: WORD wAttributes = csbi.wAttributes;
4668: for(int i = 0; i < REG16(CX); i++, ofs += 2) {
4669: if(wAttributes != mem[ofs + 1]) {
4670: SetConsoleTextAttribute(hStdout, mem[ofs + 1]);
4671: wAttributes = mem[ofs + 1];
4672: }
1.1.1.14 root 4673: WriteConsole(hStdout, &mem[ofs], 1, &num, NULL);
1.1 root 4674: }
4675: if(csbi.wAttributes != wAttributes) {
4676: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
4677: }
4678: if(REG8(AL) == 0x02) {
1.1.1.14 root 4679: co.X = mem[0x450 + REG8(BH) * 2];
4680: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 4681: SetConsoleCursorPosition(hStdout, co);
4682: } else {
4683: cursor_moved = true;
4684: }
4685: } else {
1.1.1.3 root 4686: m_CF = 1;
1.1 root 4687: }
4688: break;
4689: case 0x10:
4690: case 0x11:
4691: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 4692: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 4693: ReadConsoleOutputCharacter(hStdout, scr_char, REG16(CX), co, &num);
4694: ReadConsoleOutputAttribute(hStdout, scr_attr, REG16(CX), co, &num);
4695: for(int i = 0; i < num; i++) {
4696: mem[ofs++] = scr_char[i];
4697: mem[ofs++] = scr_attr[i];
4698: if(REG8(AL) == 0x11) {
4699: mem[ofs++] = 0;
4700: mem[ofs++] = 0;
4701: }
4702: }
4703: } else {
1.1.1.16 root 4704: 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 4705: mem[ofs++] = mem[src++];
4706: mem[ofs++] = mem[src++];
4707: if(REG8(AL) == 0x11) {
4708: mem[ofs++] = 0;
4709: mem[ofs++] = 0;
4710: }
1.1.1.14 root 4711: if(++co.X == scr_width) {
4712: if(++co.Y == scr_height) {
1.1 root 4713: break;
4714: }
4715: co.X = 0;
4716: }
4717: }
4718: }
4719: break;
4720: case 0x20:
4721: case 0x21:
4722: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 4723: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 4724: int len = min(REG16(CX), scr_width * scr_height);
4725: for(int i = 0; i < len; i++) {
1.1 root 4726: scr_char[i] = mem[ofs++];
4727: scr_attr[i] = mem[ofs++];
4728: if(REG8(AL) == 0x21) {
4729: ofs += 2;
4730: }
4731: }
1.1.1.14 root 4732: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
4733: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 4734: } else {
1.1.1.16 root 4735: 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 4736: mem[dest++] = mem[ofs++];
4737: mem[dest++] = mem[ofs++];
4738: if(REG8(AL) == 0x21) {
4739: ofs += 2;
4740: }
1.1.1.14 root 4741: if(++co.X == scr_width) {
4742: if(++co.Y == scr_height) {
1.1 root 4743: break;
4744: }
4745: co.X = 0;
4746: }
4747: }
4748: }
4749: break;
4750: default:
1.1.1.22 root 4751: 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 4752: m_CF = 1;
1.1 root 4753: break;
4754: }
4755: }
4756:
1.1.1.14 root 4757: inline void pcbios_int_10h_1ah()
4758: {
4759: switch(REG8(AL)) {
4760: case 0x00:
4761: REG8(AL) = 0x1a;
4762: REG8(BL) = 0x08;
4763: REG8(BH) = 0x00;
4764: break;
4765: default:
1.1.1.22 root 4766: 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 4767: m_CF = 1;
4768: break;
4769: }
4770: }
4771:
1.1 root 4772: inline void pcbios_int_10h_1dh()
4773: {
4774: switch(REG8(AL)) {
4775: case 0x01:
4776: break;
4777: case 0x02:
4778: REG16(BX) = 0;
4779: break;
4780: default:
1.1.1.22 root 4781: 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));
4782: m_CF = 1;
4783: break;
4784: }
4785: }
4786:
4787: inline void pcbios_int_10h_4fh()
4788: {
4789: switch(REG8(AL)) {
4790: case 0x00:
4791: REG8(AH) = 0x02; // not supported
4792: break;
4793: case 0x01:
4794: case 0x02:
4795: case 0x03:
4796: case 0x04:
4797: case 0x05:
4798: case 0x06:
4799: case 0x07:
4800: case 0x08:
4801: case 0x09:
4802: case 0x0a:
4803: case 0x0b:
4804: case 0x0c:
4805: REG8(AH) = 0x01; // failed
4806: break;
4807: default:
4808: 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 4809: m_CF = 1;
1.1 root 4810: break;
4811: }
4812: }
4813:
4814: inline void pcbios_int_10h_82h()
4815: {
4816: static UINT8 mode = 0;
4817:
4818: switch(REG8(AL)) {
1.1.1.22 root 4819: case 0x00:
1.1 root 4820: if(REG8(BL) != 0xff) {
4821: mode = REG8(BL);
4822: }
4823: REG8(AL) = mode;
4824: break;
4825: default:
1.1.1.22 root 4826: 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 4827: m_CF = 1;
1.1 root 4828: break;
4829: }
4830: }
4831:
1.1.1.22 root 4832: inline void pcbios_int_10h_83h()
4833: {
4834: static UINT8 mode = 0;
4835:
4836: switch(REG8(AL)) {
4837: case 0x00:
4838: REG16(AX) = 0; // offset???
4839: SREG(ES) = (SHADOW_BUF_TOP >> 4);
4840: i386_load_segment_descriptor(ES);
4841: REG16(BX) = (SHADOW_BUF_TOP & 0x0f);
4842: break;
4843: default:
4844: 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));
4845: m_CF = 1;
4846: break;
4847: }
4848: }
4849:
4850: inline void pcbios_int_10h_90h()
4851: {
4852: REG8(AL) = mem[0x449];
4853: }
4854:
4855: inline void pcbios_int_10h_91h()
4856: {
4857: REG8(AL) = 0x04; // VGA
4858: }
4859:
4860: inline void pcbios_int_10h_efh()
4861: {
4862: REG16(DX) = 0xffff;
4863: }
4864:
1.1 root 4865: inline void pcbios_int_10h_feh()
4866: {
4867: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 4868: SREG(ES) = (SHADOW_BUF_TOP >> 4);
1.1.1.3 root 4869: i386_load_segment_descriptor(ES);
1.1.1.8 root 4870: REG16(DI) = (SHADOW_BUF_TOP & 0x0f);
1.1 root 4871: }
4872: int_10h_feh_called = true;
4873: }
4874:
4875: inline void pcbios_int_10h_ffh()
4876: {
4877: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.23 root 4878: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 4879: COORD co;
4880: DWORD num;
4881:
1.1.1.14 root 4882: vram_flush();
4883:
4884: co.X = (REG16(DI) >> 1) % scr_width;
4885: co.Y = (REG16(DI) >> 1) / scr_width;
1.1.1.16 root 4886: int ofs = pcbios_get_shadow_buffer_address(0, co.X, co.Y);
4887: int end = min(ofs + REG16(CX) * 2, pcbios_get_shadow_buffer_address(0, 0, scr_height));
1.1.1.14 root 4888: int len;
4889: for(len = 0; ofs < end; len++) {
4890: scr_char[len] = mem[ofs++];
4891: scr_attr[len] = mem[ofs++];
4892: }
4893: co.Y += scr_top;
4894: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
4895: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 4896: }
4897: int_10h_ffh_called = true;
4898: }
4899:
1.1.1.25 root 4900: inline void pcbios_int_14h_00h()
4901: {
1.1.1.29! root 4902: if(REG16(DX) < 4) {
1.1.1.25 root 4903: static const unsigned int rate[] = {110, 150, 300, 600, 1200, 2400, 4800, 9600};
4904: UINT8 selector = sio_read(REG16(DX), 3);
4905: selector &= ~0x3f;
4906: selector |= REG8(AL) & 0x1f;
4907: UINT16 divisor = 115200 / rate[REG8(AL) >> 5];
4908: sio_write(REG16(DX), 3, selector | 0x80);
4909: sio_write(REG16(DX), 0, divisor & 0xff);
4910: sio_write(REG16(DX), 1, divisor >> 8);
4911: sio_write(REG16(DX), 3, selector);
4912: REG8(AH) = sio_read(REG16(DX), 5);
4913: REG8(AL) = sio_read(REG16(DX), 6);
4914: } else {
4915: REG8(AH) = 0x80;
4916: }
4917: }
4918:
4919: inline void pcbios_int_14h_01h()
4920: {
1.1.1.29! root 4921: if(REG16(DX) < 4) {
1.1.1.25 root 4922: UINT8 selector = sio_read(REG16(DX), 3);
4923: sio_write(REG16(DX), 3, selector & ~0x80);
4924: sio_write(REG16(DX), 0, REG8(AL));
4925: sio_write(REG16(DX), 3, selector);
4926: REG8(AH) = sio_read(REG16(DX), 5);
4927: } else {
4928: REG8(AH) = 0x80;
4929: }
4930: }
4931:
4932: inline void pcbios_int_14h_02h()
4933: {
1.1.1.29! root 4934: if(REG16(DX) < 4) {
1.1.1.25 root 4935: UINT8 selector = sio_read(REG16(DX), 3);
4936: sio_write(REG16(DX), 3, selector & ~0x80);
4937: REG8(AL) = sio_read(REG16(DX), 0);
4938: sio_write(REG16(DX), 3, selector);
4939: REG8(AH) = sio_read(REG16(DX), 5);
4940: } else {
4941: REG8(AH) = 0x80;
4942: }
4943: }
4944:
4945: inline void pcbios_int_14h_03h()
4946: {
1.1.1.29! root 4947: if(REG16(DX) < 4) {
1.1.1.25 root 4948: REG8(AH) = sio_read(REG16(DX), 5);
4949: REG8(AL) = sio_read(REG16(DX), 6);
4950: } else {
4951: REG8(AH) = 0x80;
4952: }
4953: }
4954:
4955: inline void pcbios_int_14h_04h()
4956: {
1.1.1.29! root 4957: if(REG16(DX) < 4) {
1.1.1.25 root 4958: UINT8 selector = sio_read(REG16(DX), 3);
4959: if(REG8(CH) <= 0x03) {
4960: selector = (selector & ~0x03) | REG8(CH);
4961: }
4962: if(REG8(BL) == 0x00) {
4963: selector &= ~0x04;
4964: } else if(REG8(BL) == 0x01) {
4965: selector |= 0x04;
4966: }
4967: if(REG8(BH) == 0x00) {
4968: selector = (selector & ~0x38) | 0x00;
4969: } else if(REG8(BH) == 0x01) {
4970: selector = (selector & ~0x38) | 0x08;
4971: } else if(REG8(BH) == 0x02) {
4972: selector = (selector & ~0x38) | 0x18;
4973: } else if(REG8(BH) == 0x03) {
4974: selector = (selector & ~0x38) | 0x28;
4975: } else if(REG8(BH) == 0x04) {
4976: selector = (selector & ~0x38) | 0x38;
4977: }
4978: if(REG8(AL) == 0x00) {
4979: selector |= 0x40;
4980: } else if(REG8(AL) == 0x01) {
4981: selector &= ~0x40;
4982: }
4983: if(REG8(CL) <= 0x0b) {
4984: static const unsigned int rate[] = {110, 150, 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200};
4985: UINT16 divisor = 115200 / rate[REG8(CL)];
4986: sio_write(REG16(DX), 3, selector | 0x80);
4987: sio_write(REG16(DX), 0, divisor & 0xff);
4988: sio_write(REG16(DX), 1, divisor >> 8);
4989: }
4990: sio_write(REG16(DX), 3, selector);
4991: REG8(AH) = sio_read(REG16(DX), 5);
4992: REG8(AL) = sio_read(REG16(DX), 6);
4993: } else {
4994: REG8(AH) = 0x80;
4995: }
4996: }
4997:
4998: inline void pcbios_int_14h_05h()
4999: {
1.1.1.29! root 5000: if(REG16(DX) < 4) {
1.1.1.25 root 5001: if(REG8(AL) == 0x00) {
5002: REG8(BL) = sio_read(REG16(DX), 4);
5003: REG8(AH) = sio_read(REG16(DX), 5);
5004: REG8(AL) = sio_read(REG16(DX), 6);
5005: } else if(REG8(AL) == 0x01) {
5006: sio_write(REG16(DX), 4, REG8(BL));
5007: REG8(AH) = sio_read(REG16(DX), 5);
5008: REG8(AL) = sio_read(REG16(DX), 6);
5009: } else {
5010: 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));
5011: }
5012: } else {
5013: REG8(AH) = 0x80;
5014: }
5015: }
5016:
1.1.1.14 root 5017: inline void pcbios_int_15h_10h()
5018: {
1.1.1.22 root 5019: switch(REG8(AL)) {
5020: case 0x00:
1.1.1.14 root 5021: Sleep(10);
5022: hardware_update();
1.1.1.22 root 5023: break;
5024: default:
5025: 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 5026: REG8(AH) = 0x86;
5027: m_CF = 1;
5028: }
5029: }
5030:
1.1 root 5031: inline void pcbios_int_15h_23h()
5032: {
5033: switch(REG8(AL)) {
1.1.1.22 root 5034: case 0x00:
1.1.1.8 root 5035: REG8(CL) = cmos_read(0x2d);
5036: REG8(CH) = cmos_read(0x2e);
1.1 root 5037: break;
1.1.1.22 root 5038: case 0x01:
1.1.1.8 root 5039: cmos_write(0x2d, REG8(CL));
5040: cmos_write(0x2e, REG8(CH));
1.1 root 5041: break;
5042: default:
1.1.1.22 root 5043: 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 5044: REG8(AH) = 0x86;
1.1.1.3 root 5045: m_CF = 1;
1.1 root 5046: break;
5047: }
5048: }
5049:
5050: inline void pcbios_int_15h_24h()
5051: {
5052: switch(REG8(AL)) {
1.1.1.22 root 5053: case 0x00:
1.1.1.3 root 5054: i386_set_a20_line(0);
1.1 root 5055: REG8(AH) = 0;
5056: break;
1.1.1.22 root 5057: case 0x01:
1.1.1.3 root 5058: i386_set_a20_line(1);
1.1 root 5059: REG8(AH) = 0;
5060: break;
1.1.1.22 root 5061: case 0x02:
1.1 root 5062: REG8(AH) = 0;
1.1.1.3 root 5063: REG8(AL) = (m_a20_mask >> 20) & 1;
1.1 root 5064: REG16(CX) = 0;
5065: break;
1.1.1.22 root 5066: case 0x03:
1.1 root 5067: REG16(AX) = 0;
5068: REG16(BX) = 0;
5069: break;
1.1.1.22 root 5070: default:
5071: 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));
5072: REG8(AH) = 0x86;
5073: m_CF = 1;
5074: break;
1.1 root 5075: }
5076: }
5077:
5078: inline void pcbios_int_15h_49h()
5079: {
1.1.1.27 root 5080: REG8(AH) = 0x00;
5081: REG8(BL) = 0x00; // DOS/V
1.1 root 5082: }
5083:
1.1.1.22 root 5084: inline void pcbios_int_15h_50h()
5085: {
5086: switch(REG8(AL)) {
5087: case 0x00:
5088: case 0x01:
5089: if(REG8(BH) != 0x00 && REG8(BH) != 0x01) {
5090: REG8(AH) = 0x01; // invalid font type in bh
5091: m_CF = 1;
1.1.1.27 root 5092: } else if(REG8(BL) != 0x00) {
1.1.1.22 root 5093: REG8(AH) = 0x02; // bl not zero
5094: m_CF = 1;
5095: } else if(REG16(BP) != 0 && REG16(BP) != 437 && REG16(BP) != 932 && REG16(BP) != 934 && REG16(BP) != 936 && REG16(BP) != 938) {
5096: REG8(AH) = 0x04; // invalid code page
5097: m_CF = 1;
1.1.1.27 root 5098: } else if(REG8(AL) == 0x01) {
5099: REG8(AH) = 0x06; // font is read only
1.1.1.22 root 5100: m_CF = 1;
1.1.1.27 root 5101: } else {
5102: // dummy font read routine is at fffd:000d
5103: SREG(ES) = 0xfffd;
5104: i386_load_segment_descriptor(ES);
5105: REG16(BX) = 0x0d;
5106: REG8(AH) = 0x00; // success
1.1.1.22 root 5107: }
5108: break;
5109: default:
5110: 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));
5111: REG8(AH) = 0x86;
5112: m_CF = 1;
5113: break;
5114: }
5115: }
5116:
1.1 root 5117: inline void pcbios_int_15h_86h()
5118: {
5119: UINT32 usec = (REG16(CX) << 16) | REG16(DX);
1.1.1.14 root 5120: UINT32 msec = usec / 1000;
5121:
5122: while(msec) {
5123: UINT32 tmp = min(msec, 100);
5124: if(msec - tmp < 10) {
5125: tmp = msec;
5126: }
5127: Sleep(tmp);
5128:
5129: if(m_halted) {
5130: return;
5131: }
5132: msec -= tmp;
5133: }
1.1 root 5134: }
5135:
5136: inline void pcbios_int_15h_87h()
5137: {
5138: // copy extended memory (from DOSBox)
5139: int len = REG16(CX) * 2;
1.1.1.3 root 5140: int ofs = SREG_BASE(ES) + REG16(SI);
1.1 root 5141: int src = (*(UINT32 *)(mem + ofs + 0x12) & 0xffffff); // + (mem[ofs + 0x16] << 24);
5142: int dst = (*(UINT32 *)(mem + ofs + 0x1a) & 0xffffff); // + (mem[ofs + 0x1e] << 24);
5143: memcpy(mem + dst, mem + src, len);
5144: REG16(AX) = 0x00;
5145: }
5146:
5147: inline void pcbios_int_15h_88h()
5148: {
1.1.1.17 root 5149: REG16(AX) = ((min(MAX_MEM, 0x4000000) - 0x100000) >> 10);
1.1 root 5150: }
5151:
5152: inline void pcbios_int_15h_89h()
5153: {
1.1.1.21 root 5154: #if defined(HAS_I286) || defined(HAS_I386)
1.1 root 5155: // switch to protected mode (from DOSBox)
5156: write_io_byte(0x20, 0x10);
5157: write_io_byte(0x21, REG8(BH));
5158: write_io_byte(0x21, 0x00);
5159: write_io_byte(0xa0, 0x10);
5160: write_io_byte(0xa1, REG8(BL));
5161: write_io_byte(0xa1, 0x00);
1.1.1.3 root 5162: i386_set_a20_line(1);
5163: int ofs = SREG_BASE(ES) + REG16(SI);
5164: m_gdtr.limit = *(UINT16 *)(mem + ofs + 0x08);
5165: m_gdtr.base = *(UINT32 *)(mem + ofs + 0x08 + 0x02) & 0xffffff;
5166: m_idtr.limit = *(UINT16 *)(mem + ofs + 0x10);
5167: m_idtr.base = *(UINT32 *)(mem + ofs + 0x10 + 0x02) & 0xffffff;
5168: #if defined(HAS_I386)
5169: m_cr[0] |= 1;
5170: #else
5171: m_msw |= 1;
5172: #endif
5173: SREG(DS) = 0x18;
5174: SREG(ES) = 0x20;
5175: SREG(SS) = 0x28;
5176: i386_load_segment_descriptor(DS);
5177: i386_load_segment_descriptor(ES);
5178: i386_load_segment_descriptor(SS);
1.1.1.21 root 5179: UINT16 offset = *(UINT16 *)(mem + SREG_BASE(SS) + REG16(SP));
1.1 root 5180: REG16(SP) += 6;
1.1.1.3 root 5181: #if defined(HAS_I386)
1.1.1.21 root 5182: UINT32 flags = get_flags();
5183: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
5184: set_flags(flags);
1.1.1.3 root 5185: #else
1.1.1.21 root 5186: UINT32 flags = CompressFlags();
5187: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
5188: ExpandFlags(flags);
1.1.1.3 root 5189: #endif
1.1 root 5190: REG16(AX) = 0x00;
1.1.1.21 root 5191: i386_jmp_far(0x30, /*REG16(CX)*/offset);
1.1 root 5192: #else
1.1.1.21 root 5193: // i86/i186/v30: protected mode is not supported
1.1 root 5194: REG8(AH) = 0x86;
1.1.1.3 root 5195: m_CF = 1;
1.1 root 5196: #endif
5197: }
5198:
1.1.1.21 root 5199: inline void pcbios_int_15h_8ah()
5200: {
5201: UINT32 size = MAX_MEM - 0x100000;
5202: REG16(AX) = size & 0xffff;
5203: REG16(DX) = size >> 16;
5204: }
5205:
1.1.1.3 root 5206: #if defined(HAS_I386)
1.1 root 5207: inline void pcbios_int_15h_c9h()
5208: {
5209: REG8(AH) = 0x00;
5210: REG8(CH) = cpu_type;
5211: REG8(CL) = cpu_step;
5212: }
1.1.1.3 root 5213: #endif
1.1 root 5214:
5215: inline void pcbios_int_15h_cah()
5216: {
5217: switch(REG8(AL)) {
1.1.1.22 root 5218: case 0x00:
1.1 root 5219: if(REG8(BL) > 0x3f) {
5220: REG8(AH) = 0x03;
1.1.1.3 root 5221: m_CF = 1;
1.1 root 5222: } else if(REG8(BL) < 0x0e) {
5223: REG8(AH) = 0x04;
1.1.1.3 root 5224: m_CF = 1;
1.1 root 5225: } else {
1.1.1.8 root 5226: REG8(CL) = cmos_read(REG8(BL));
1.1 root 5227: }
5228: break;
1.1.1.22 root 5229: case 0x01:
1.1 root 5230: if(REG8(BL) > 0x3f) {
5231: REG8(AH) = 0x03;
1.1.1.3 root 5232: m_CF = 1;
1.1 root 5233: } else if(REG8(BL) < 0x0e) {
5234: REG8(AH) = 0x04;
1.1.1.3 root 5235: m_CF = 1;
1.1 root 5236: } else {
1.1.1.8 root 5237: cmos_write(REG8(BL), REG8(CL));
1.1 root 5238: }
5239: break;
5240: default:
1.1.1.22 root 5241: 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 5242: REG8(AH) = 0x86;
1.1.1.3 root 5243: m_CF = 1;
1.1 root 5244: break;
5245: }
5246: }
5247:
1.1.1.22 root 5248: inline void pcbios_int_15h_e8h()
1.1.1.17 root 5249: {
1.1.1.22 root 5250: switch(REG8(AL)) {
5251: #if defined(HAS_I386)
5252: case 0x01:
5253: REG16(AX) = REG16(CX) = ((min(MAX_MEM, 0x1000000) - 0x100000) >> 10);
5254: REG16(BX) = REG16(DX) = ((max(MAX_MEM, 0x1000000) - 0x1000000) >> 16);
5255: break;
1.1.1.17 root 5256: #endif
1.1.1.22 root 5257: default:
5258: 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));
5259: REG8(AH) = 0x86;
5260: m_CF = 1;
5261: break;
5262: }
5263: }
1.1.1.17 root 5264:
1.1.1.16 root 5265: UINT32 pcbios_get_key_code(bool clear_buffer)
1.1 root 5266: {
5267: UINT32 code = 0;
5268:
5269: if(key_buf_char->count() == 0) {
1.1.1.14 root 5270: if(!update_key_buffer()) {
5271: if(clear_buffer) {
5272: Sleep(10);
5273: } else {
5274: maybe_idle();
5275: }
5276: }
1.1 root 5277: }
5278: if(!clear_buffer) {
5279: key_buf_char->store_buffer();
5280: key_buf_scan->store_buffer();
5281: }
5282: if(key_buf_char->count() != 0) {
5283: code = key_buf_char->read() | (key_buf_scan->read() << 8);
5284: }
5285: if(key_buf_char->count() != 0) {
5286: code |= (key_buf_char->read() << 16) | (key_buf_scan->read() << 24);
5287: }
5288: if(!clear_buffer) {
5289: key_buf_char->restore_buffer();
5290: key_buf_scan->restore_buffer();
5291: }
5292: return code;
5293: }
5294:
5295: inline void pcbios_int_16h_00h()
5296: {
1.1.1.14 root 5297: while(key_code == 0 && !m_halted) {
1.1.1.16 root 5298: key_code = pcbios_get_key_code(true);
1.1 root 5299: }
5300: if((key_code & 0xffff) == 0x0000 || (key_code & 0xffff) == 0xe000) {
5301: if(REG8(AH) == 0x10) {
5302: key_code = ((key_code >> 8) & 0xff) | ((key_code >> 16) & 0xff00);
5303: } else {
5304: key_code = ((key_code >> 16) & 0xff00);
5305: }
5306: }
5307: REG16(AX) = key_code & 0xffff;
5308: key_code >>= 16;
5309: }
5310:
5311: inline void pcbios_int_16h_01h()
5312: {
1.1.1.5 root 5313: UINT32 key_code_tmp = key_code;
1.1 root 5314:
1.1.1.5 root 5315: if(key_code_tmp == 0) {
1.1.1.16 root 5316: key_code_tmp = pcbios_get_key_code(false);
1.1.1.5 root 5317: }
1.1.1.14 root 5318: if((key_code_tmp & 0xffff) == 0x0000 || (key_code_tmp & 0xffff) == 0xe000) {
5319: if(REG8(AH) == 0x11) {
5320: key_code_tmp = ((key_code_tmp >> 8) & 0xff) | ((key_code_tmp >> 16) & 0xff00);
5321: } else {
5322: key_code_tmp = ((key_code_tmp >> 16) & 0xff00);
1.1 root 5323: }
5324: }
1.1.1.5 root 5325: if(key_code_tmp != 0) {
5326: REG16(AX) = key_code_tmp & 0xffff;
1.1 root 5327: }
1.1.1.3 root 5328: #if defined(HAS_I386)
1.1.1.5 root 5329: m_ZF = (key_code_tmp == 0);
1.1.1.3 root 5330: #else
1.1.1.5 root 5331: m_ZeroVal = (key_code_tmp != 0);
1.1.1.3 root 5332: #endif
1.1 root 5333: }
5334:
5335: inline void pcbios_int_16h_02h()
5336: {
5337: REG8(AL) = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
5338: REG8(AL) |= (GetAsyncKeyState(VK_CAPITAL) & 0x0001) ? 0x40 : 0;
5339: REG8(AL) |= (GetAsyncKeyState(VK_NUMLOCK) & 0x0001) ? 0x20 : 0;
5340: REG8(AL) |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
5341: REG8(AL) |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
5342: REG8(AL) |= (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? 0x04 : 0;
5343: REG8(AL) |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
5344: REG8(AL) |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
5345: }
5346:
5347: inline void pcbios_int_16h_03h()
5348: {
5349: static UINT16 status = 0;
5350:
5351: switch(REG8(AL)) {
5352: case 0x05:
5353: status = REG16(BX);
5354: break;
5355: case 0x06:
5356: REG16(BX) = status;
5357: break;
5358: default:
1.1.1.3 root 5359: m_CF = 1;
1.1 root 5360: break;
5361: }
5362: }
5363:
5364: inline void pcbios_int_16h_05h()
5365: {
1.1.1.14 root 5366: key_buf_char->write(REG8(CL));
5367: key_buf_scan->write(REG8(CH));
1.1 root 5368: REG8(AL) = 0x00;
5369: }
5370:
5371: inline void pcbios_int_16h_12h()
5372: {
5373: pcbios_int_16h_02h();
5374:
5375: REG8(AH) = 0;//(GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x80 : 0;
5376: REG8(AH) |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
5377: REG8(AH) |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
5378: REG8(AH) |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
5379: REG8(AH) |= (GetAsyncKeyState(VK_RMENU ) & 0x8000) ? 0x08 : 0;
5380: REG8(AH) |= (GetAsyncKeyState(VK_RCONTROL) & 0x8000) ? 0x04 : 0;
5381: REG8(AH) |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
5382: REG8(AH) |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
5383: }
5384:
5385: inline void pcbios_int_16h_13h()
5386: {
5387: static UINT16 status = 0;
5388:
5389: switch(REG8(AL)) {
5390: case 0x00:
5391: status = REG16(DX);
5392: break;
5393: case 0x01:
5394: REG16(DX) = status;
5395: break;
5396: default:
1.1.1.22 root 5397: 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 5398: m_CF = 1;
1.1 root 5399: break;
5400: }
5401: }
5402:
5403: inline void pcbios_int_16h_14h()
5404: {
5405: static UINT8 status = 0;
5406:
5407: switch(REG8(AL)) {
5408: case 0x00:
5409: case 0x01:
5410: status = REG8(AL);
5411: break;
5412: case 0x02:
5413: REG8(AL) = status;
5414: break;
5415: default:
1.1.1.22 root 5416: 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 5417: m_CF = 1;
1.1 root 5418: break;
5419: }
5420: }
5421:
1.1.1.24 root 5422: inline void pcbios_int_16h_55h()
5423: {
5424: switch(REG8(AL)) {
5425: case 0x00:
5426: // keyboard tsr is not present
5427: break;
5428: case 0xfe:
5429: // handlers for INT 08, INT 09, INT 16, INT 1B, and INT 1C are installed
5430: break;
5431: case 0xff:
5432: break;
5433: default:
5434: 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));
5435: m_CF = 1;
5436: break;
5437: }
5438: }
5439:
1.1 root 5440: inline void pcbios_int_1ah_00h()
5441: {
1.1.1.19 root 5442: pcbios_update_daily_timer_counter(timeGetTime());
5443: REG16(CX) = *(UINT16 *)(mem + 0x46e);
5444: REG16(DX) = *(UINT16 *)(mem + 0x46c);
5445: REG8(AL) = mem[0x470];
5446: mem[0x470] = 0;
1.1 root 5447: }
5448:
5449: inline int to_bcd(int t)
5450: {
5451: int u = (t % 100) / 10;
5452: return (u << 4) | (t % 10);
5453: }
5454:
5455: inline void pcbios_int_1ah_02h()
5456: {
5457: SYSTEMTIME time;
5458:
5459: GetLocalTime(&time);
5460: REG8(CH) = to_bcd(time.wHour);
5461: REG8(CL) = to_bcd(time.wMinute);
5462: REG8(DH) = to_bcd(time.wSecond);
5463: REG8(DL) = 0x00;
5464: }
5465:
5466: inline void pcbios_int_1ah_04h()
5467: {
5468: SYSTEMTIME time;
5469:
5470: GetLocalTime(&time);
5471: REG8(CH) = to_bcd(time.wYear / 100);
5472: REG8(CL) = to_bcd(time.wYear);
5473: REG8(DH) = to_bcd(time.wMonth);
5474: REG8(DL) = to_bcd(time.wDay);
5475: }
5476:
5477: inline void pcbios_int_1ah_0ah()
5478: {
5479: SYSTEMTIME time;
5480: FILETIME file_time;
5481: WORD dos_date, dos_time;
5482:
5483: GetLocalTime(&time);
5484: SystemTimeToFileTime(&time, &file_time);
5485: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time);
5486: REG16(CX) = dos_date;
5487: }
5488:
5489: // msdos system call
5490:
5491: inline void msdos_int_21h_00h()
5492: {
1.1.1.3 root 5493: msdos_process_terminate(SREG(CS), retval, 1);
1.1 root 5494: }
5495:
5496: inline void msdos_int_21h_01h()
5497: {
5498: REG8(AL) = msdos_getche();
1.1.1.26 root 5499: ctrl_c_detected = ctrl_c_pressed;
5500:
1.1.1.8 root 5501: // some seconds may be passed in console
1.1 root 5502: hardware_update();
5503: }
5504:
5505: inline void msdos_int_21h_02h()
5506: {
5507: msdos_putch(REG8(DL));
1.1.1.26 root 5508: ctrl_c_detected = ctrl_c_pressed;
1.1 root 5509: }
5510:
5511: inline void msdos_int_21h_03h()
5512: {
5513: REG8(AL) = msdos_aux_in();
5514: }
5515:
5516: inline void msdos_int_21h_04h()
5517: {
5518: msdos_aux_out(REG8(DL));
5519: }
5520:
5521: inline void msdos_int_21h_05h()
5522: {
5523: msdos_prn_out(REG8(DL));
5524: }
5525:
5526: inline void msdos_int_21h_06h()
5527: {
5528: if(REG8(DL) == 0xff) {
5529: if(msdos_kbhit()) {
5530: REG8(AL) = msdos_getch();
1.1.1.3 root 5531: #if defined(HAS_I386)
5532: m_ZF = 0;
5533: #else
5534: m_ZeroVal = 1;
5535: #endif
1.1 root 5536: } else {
5537: REG8(AL) = 0;
1.1.1.3 root 5538: #if defined(HAS_I386)
5539: m_ZF = 1;
5540: #else
5541: m_ZeroVal = 0;
5542: #endif
1.1.1.14 root 5543: maybe_idle();
1.1 root 5544: }
5545: } else {
5546: msdos_putch(REG8(DL));
5547: }
5548: }
5549:
5550: inline void msdos_int_21h_07h()
5551: {
5552: REG8(AL) = msdos_getch();
1.1.1.26 root 5553:
1.1.1.8 root 5554: // some seconds may be passed in console
1.1 root 5555: hardware_update();
5556: }
5557:
5558: inline void msdos_int_21h_08h()
5559: {
5560: REG8(AL) = msdos_getch();
1.1.1.26 root 5561: ctrl_c_detected = ctrl_c_pressed;
5562:
1.1.1.8 root 5563: // some seconds may be passed in console
1.1 root 5564: hardware_update();
5565: }
5566:
5567: inline void msdos_int_21h_09h()
5568: {
1.1.1.21 root 5569: msdos_stdio_reopen();
5570:
1.1.1.20 root 5571: process_t *process = msdos_process_info_get(current_psp);
5572: int fd = msdos_psp_get_file_table(1, current_psp);
5573:
1.1.1.14 root 5574: char *str = (char *)(mem + SREG_BASE(DS) + REG16(DX));
5575: int len = 0;
1.1 root 5576:
1.1.1.14 root 5577: while(str[len] != '$' && len < 0x10000) {
5578: len++;
5579: }
1.1.1.20 root 5580: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 5581: // stdout is redirected to file
1.1.1.20 root 5582: msdos_write(fd, str, len);
1.1 root 5583: } else {
5584: for(int i = 0; i < len; i++) {
1.1.1.14 root 5585: msdos_putch(str[i]);
1.1 root 5586: }
5587: }
1.1.1.26 root 5588: ctrl_c_detected = ctrl_c_pressed;
1.1 root 5589: }
5590:
5591: inline void msdos_int_21h_0ah()
5592: {
1.1.1.3 root 5593: int ofs = SREG_BASE(DS) + REG16(DX);
1.1 root 5594: int max = mem[ofs] - 1;
5595: UINT8 *buf = mem + ofs + 2;
5596: int chr, p = 0;
5597:
5598: while((chr = msdos_getch()) != 0x0d) {
1.1.1.26 root 5599: if(ctrl_c_pressed) {
5600: p = 0;
5601: msdos_putch(chr);
5602: break;
5603: } else if(chr == 0x00) {
1.1 root 5604: // skip 2nd byte
5605: msdos_getch();
5606: } else if(chr == 0x08) {
5607: // back space
5608: if(p > 0) {
5609: p--;
1.1.1.20 root 5610: if(msdos_ctrl_code_check(buf[p])) {
5611: msdos_putch(chr);
5612: msdos_putch(chr);
5613: msdos_putch(' ');
5614: msdos_putch(' ');
5615: msdos_putch(chr);
5616: msdos_putch(chr);
5617: } else {
5618: msdos_putch(chr);
5619: msdos_putch(' ');
5620: msdos_putch(chr);
5621: }
1.1 root 5622: }
5623: } else if(p < max) {
5624: buf[p++] = chr;
5625: msdos_putch(chr);
5626: }
5627: }
5628: buf[p] = 0x0d;
5629: mem[ofs + 1] = p;
1.1.1.26 root 5630: ctrl_c_detected = ctrl_c_pressed;
5631:
1.1.1.8 root 5632: // some seconds may be passed in console
1.1 root 5633: hardware_update();
5634: }
5635:
5636: inline void msdos_int_21h_0bh()
5637: {
5638: if(msdos_kbhit()) {
5639: REG8(AL) = 0xff;
5640: } else {
5641: REG8(AL) = 0x00;
1.1.1.14 root 5642: maybe_idle();
1.1 root 5643: }
1.1.1.26 root 5644: ctrl_c_detected = ctrl_c_pressed;
1.1 root 5645: }
5646:
5647: inline void msdos_int_21h_0ch()
5648: {
5649: // clear key buffer
1.1.1.21 root 5650: msdos_stdio_reopen();
5651:
1.1.1.20 root 5652: process_t *process = msdos_process_info_get(current_psp);
5653: int fd = msdos_psp_get_file_table(0, current_psp);
5654:
5655: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 5656: // stdin is redirected to file
5657: } else {
5658: while(msdos_kbhit()) {
5659: msdos_getch();
5660: }
5661: }
5662:
5663: switch(REG8(AL)) {
5664: case 0x01:
5665: msdos_int_21h_01h();
5666: break;
5667: case 0x06:
5668: msdos_int_21h_06h();
5669: break;
5670: case 0x07:
5671: msdos_int_21h_07h();
5672: break;
5673: case 0x08:
5674: msdos_int_21h_08h();
5675: break;
5676: case 0x0a:
5677: msdos_int_21h_0ah();
5678: break;
5679: default:
1.1.1.22 root 5680: // 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));
5681: // REG16(AX) = 0x01;
5682: // m_CF = 1;
1.1 root 5683: break;
5684: }
5685: }
5686:
5687: inline void msdos_int_21h_0dh()
5688: {
5689: }
5690:
5691: inline void msdos_int_21h_0eh()
5692: {
5693: if(REG8(DL) < 26) {
5694: _chdrive(REG8(DL) + 1);
5695: msdos_cds_update(REG8(DL));
1.1.1.23 root 5696: msdos_sda_update(current_psp);
1.1 root 5697: }
5698: REG8(AL) = 26; // zdrive
5699: }
5700:
1.1.1.14 root 5701: inline void msdos_int_21h_0fh()
5702: {
5703: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5704: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5705: char *path = msdos_fcb_path(fcb);
5706: 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 5707:
1.1.1.14 root 5708: if(hFile == INVALID_HANDLE_VALUE) {
5709: REG8(AL) = 0xff;
5710: } else {
5711: REG8(AL) = 0;
5712: fcb->current_block = 0;
5713: fcb->record_size = 128;
5714: fcb->file_size = GetFileSize(hFile, NULL);
5715: fcb->handle = hFile;
5716: fcb->cur_record = 0;
5717: }
5718: }
5719:
5720: inline void msdos_int_21h_10h()
5721: {
5722: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5723: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5724:
5725: REG8(AL) = CloseHandle(fcb->handle) ? 0 : 0xff;
5726: }
5727:
1.1 root 5728: inline void msdos_int_21h_11h()
5729: {
1.1.1.3 root 5730: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5731: fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 5732:
5733: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 5734: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5735: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
5736: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 5737: char *path = msdos_fcb_path(fcb);
5738: WIN32_FIND_DATA fd;
5739:
1.1.1.13 root 5740: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
5741: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
5742: FindClose(dtainfo->find_handle);
5743: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 5744: }
5745: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 5746: dtainfo->allowable_mask = (ext_fcb->flag == 0xff) ? ext_fcb->attribute : 0x20;
5747: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 5748:
1.1.1.14 root 5749: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
5750: dtainfo->allowable_mask &= ~8;
1.1 root 5751: }
1.1.1.14 root 5752: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
5753: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 5754: !msdos_find_file_has_8dot3name(&fd)) {
5755: if(!FindNextFile(dtainfo->find_handle, &fd)) {
5756: FindClose(dtainfo->find_handle);
5757: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 5758: break;
5759: }
5760: }
5761: }
1.1.1.13 root 5762: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 5763: if(ext_fcb->flag == 0xff) {
5764: ext_find->flag = 0xff;
5765: memset(ext_find->reserved, 0, 5);
5766: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
5767: }
5768: find->drive = _getdrive();
1.1.1.13 root 5769: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 5770: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
5771: find->nt_res = 0;
5772: msdos_find_file_conv_local_time(&fd);
5773: find->create_time_ms = 0;
5774: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
5775: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
5776: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
5777: find->cluster_hi = find->cluster_lo = 0;
5778: find->file_size = fd.nFileSizeLow;
5779: REG8(AL) = 0x00;
1.1.1.14 root 5780: } else if(dtainfo->allowable_mask & 8) {
1.1 root 5781: if(ext_fcb->flag == 0xff) {
5782: ext_find->flag = 0xff;
5783: memset(ext_find->reserved, 0, 5);
5784: ext_find->attribute = 8;
5785: }
5786: find->drive = _getdrive();
5787: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
5788: find->attribute = 8;
5789: find->nt_res = 0;
5790: msdos_find_file_conv_local_time(&fd);
5791: find->create_time_ms = 0;
5792: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
5793: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
5794: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
5795: find->cluster_hi = find->cluster_lo = 0;
5796: find->file_size = 0;
1.1.1.14 root 5797: dtainfo->allowable_mask &= ~8;
1.1 root 5798: REG8(AL) = 0x00;
5799: } else {
5800: REG8(AL) = 0xff;
5801: }
5802: }
5803:
5804: inline void msdos_int_21h_12h()
5805: {
1.1.1.3 root 5806: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1.1.14 root 5807: // fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 5808:
5809: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 5810: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5811: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
5812: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 5813: WIN32_FIND_DATA fd;
5814:
1.1.1.13 root 5815: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
5816: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
5817: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 5818: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 5819: !msdos_find_file_has_8dot3name(&fd)) {
5820: if(!FindNextFile(dtainfo->find_handle, &fd)) {
5821: FindClose(dtainfo->find_handle);
5822: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 5823: break;
5824: }
5825: }
5826: } else {
1.1.1.13 root 5827: FindClose(dtainfo->find_handle);
5828: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 5829: }
5830: }
1.1.1.13 root 5831: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 5832: if(ext_fcb->flag == 0xff) {
5833: ext_find->flag = 0xff;
5834: memset(ext_find->reserved, 0, 5);
5835: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
5836: }
5837: find->drive = _getdrive();
1.1.1.13 root 5838: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 5839: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
5840: find->nt_res = 0;
5841: msdos_find_file_conv_local_time(&fd);
5842: find->create_time_ms = 0;
5843: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
5844: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
5845: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
5846: find->cluster_hi = find->cluster_lo = 0;
5847: find->file_size = fd.nFileSizeLow;
5848: REG8(AL) = 0x00;
1.1.1.14 root 5849: } else if(dtainfo->allowable_mask & 8) {
1.1 root 5850: if(ext_fcb->flag == 0xff) {
5851: ext_find->flag = 0xff;
5852: memset(ext_find->reserved, 0, 5);
5853: ext_find->attribute = 8;
5854: }
5855: find->drive = _getdrive();
5856: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
5857: find->attribute = 8;
5858: find->nt_res = 0;
5859: msdos_find_file_conv_local_time(&fd);
5860: find->create_time_ms = 0;
5861: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
5862: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
5863: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
5864: find->cluster_hi = find->cluster_lo = 0;
5865: find->file_size = 0;
1.1.1.14 root 5866: dtainfo->allowable_mask &= ~8;
1.1 root 5867: REG8(AL) = 0x00;
5868: } else {
5869: REG8(AL) = 0xff;
5870: }
5871: }
5872:
5873: inline void msdos_int_21h_13h()
5874: {
1.1.1.3 root 5875: if(remove(msdos_fcb_path((fcb_t *)(mem + SREG_BASE(DS) + REG16(DX))))) {
1.1 root 5876: REG8(AL) = 0xff;
5877: } else {
5878: REG8(AL) = 0x00;
5879: }
5880: }
5881:
1.1.1.16 root 5882: inline void msdos_int_21h_14h()
5883: {
5884: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5885: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5886: process_t *process = msdos_process_info_get(current_psp);
5887: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5888: DWORD num = 0;
5889:
5890: memset(mem + dta_laddr, 0, fcb->record_size);
5891: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
5892: REG8(AL) = 1;
5893: } else {
5894: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
5895: fcb->current_block = (position & 0xffffff) / fcb->record_size;
5896: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
5897: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
5898: }
5899: }
5900:
5901: inline void msdos_int_21h_15h()
1.1.1.14 root 5902: {
5903: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5904: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.16 root 5905: process_t *process = msdos_process_info_get(current_psp);
5906: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5907: DWORD num = 0;
1.1.1.14 root 5908:
1.1.1.16 root 5909: if(!WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
5910: REG8(AL) = 1;
5911: } else {
5912: fcb->file_size = GetFileSize(fcb->handle, NULL);
5913: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
5914: fcb->current_block = (position & 0xffffff) / fcb->record_size;
5915: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
5916: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
5917: }
5918: }
5919:
5920: inline void msdos_int_21h_16h()
5921: {
5922: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5923: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.14 root 5924: char *path = msdos_fcb_path(fcb);
5925: 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 5926:
1.1.1.14 root 5927: if(hFile == INVALID_HANDLE_VALUE) {
5928: REG8(AL) = 0xff;
5929: } else {
5930: REG8(AL) = 0;
5931: fcb->current_block = 0;
5932: fcb->record_size = 128;
5933: fcb->file_size = 0;
5934: fcb->handle = hFile;
5935: fcb->cur_record = 0;
5936: }
5937: }
5938:
1.1.1.16 root 5939: inline void msdos_int_21h_17h()
5940: {
5941: ext_fcb_t *ext_fcb_src = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5942: fcb_t *fcb_src = (fcb_t *)(ext_fcb_src + (ext_fcb_src->flag == 0xff ? 1 : 0));
5943: char *path_src = msdos_fcb_path(fcb_src);
5944: ext_fcb_t *ext_fcb_dst = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + 16);
5945: fcb_t *fcb_dst = (fcb_t *)(ext_fcb_dst + (ext_fcb_dst->flag == 0xff ? 1 : 0));
5946: char *path_dst = msdos_fcb_path(fcb_dst);
5947:
5948: if(rename(path_src, path_dst)) {
5949: REG8(AL) = 0xff;
5950: } else {
5951: REG8(AL) = 0;
5952: }
5953: }
5954:
1.1 root 5955: inline void msdos_int_21h_18h()
5956: {
5957: REG8(AL) = 0x00;
5958: }
5959:
5960: inline void msdos_int_21h_19h()
5961: {
5962: REG8(AL) = _getdrive() - 1;
5963: }
5964:
5965: inline void msdos_int_21h_1ah()
5966: {
5967: process_t *process = msdos_process_info_get(current_psp);
5968:
5969: process->dta.w.l = REG16(DX);
1.1.1.3 root 5970: process->dta.w.h = SREG(DS);
1.1.1.23 root 5971: msdos_sda_update(current_psp);
1.1 root 5972: }
5973:
5974: inline void msdos_int_21h_1bh()
5975: {
5976: int drive_num = _getdrive() - 1;
5977: UINT16 seg, ofs;
5978:
5979: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
5980: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
5981: REG8(AL) = dpb->highest_sector_num + 1;
5982: REG16(CX) = dpb->bytes_per_sector;
5983: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 5984: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 5985: } else {
5986: REG8(AL) = 0xff;
1.1.1.3 root 5987: m_CF = 1;
1.1 root 5988: }
5989:
5990: }
5991:
5992: inline void msdos_int_21h_1ch()
5993: {
5994: int drive_num = REG8(DL) ? (REG8(DL) - 1) : (_getdrive() - 1);
5995: UINT16 seg, ofs;
5996:
5997: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
5998: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
5999: REG8(AL) = dpb->highest_sector_num + 1;
6000: REG16(CX) = dpb->bytes_per_sector;
6001: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 6002: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 6003: } else {
6004: REG8(AL) = 0xff;
1.1.1.3 root 6005: m_CF = 1;
1.1 root 6006: }
6007:
6008: }
6009:
6010: inline void msdos_int_21h_1dh()
6011: {
6012: REG8(AL) = 0;
6013: }
6014:
6015: inline void msdos_int_21h_1eh()
6016: {
6017: REG8(AL) = 0;
6018: }
6019:
6020: inline void msdos_int_21h_1fh()
6021: {
6022: int drive_num = _getdrive() - 1;
6023: UINT16 seg, ofs;
6024:
6025: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
6026: REG8(AL) = 0;
1.1.1.3 root 6027: SREG(DS) = seg;
6028: i386_load_segment_descriptor(DS);
1.1 root 6029: REG16(BX) = ofs;
6030: } else {
6031: REG8(AL) = 0xff;
1.1.1.3 root 6032: m_CF = 1;
1.1 root 6033: }
6034: }
6035:
6036: inline void msdos_int_21h_20h()
6037: {
6038: REG8(AL) = 0;
6039: }
6040:
1.1.1.14 root 6041: inline void msdos_int_21h_21h()
6042: {
6043: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
6044: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
6045:
6046: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
6047: REG8(AL) = 1;
6048: } else {
6049: process_t *process = msdos_process_info_get(current_psp);
6050: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
6051: memset(mem + dta_laddr, 0, fcb->record_size);
1.1.1.16 root 6052: DWORD num = 0;
1.1.1.14 root 6053: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
6054: REG8(AL) = 1;
6055: } else {
6056: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
6057: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 6058: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
1.1.1.14 root 6059: }
6060: }
6061: }
6062:
6063: inline void msdos_int_21h_22h()
6064: {
6065: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
6066: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
6067:
6068: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
6069: REG8(AL) = 0xff;
6070: } else {
6071: process_t *process = msdos_process_info_get(current_psp);
6072: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
1.1.1.16 root 6073: DWORD num = 0;
1.1.1.14 root 6074: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL);
6075: fcb->file_size = GetFileSize(fcb->handle, NULL);
6076: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
6077: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 6078: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
1.1.1.14 root 6079: }
6080: }
6081:
1.1.1.16 root 6082: inline void msdos_int_21h_23h()
6083: {
6084: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
6085: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
6086: char *path = msdos_fcb_path(fcb);
6087: HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
6088:
6089: if(hFile == INVALID_HANDLE_VALUE) {
6090: REG8(AL) = 0xff;
6091: } else {
6092: UINT32 size = GetFileSize(hFile, NULL);
6093: fcb->rand_record = size / fcb->record_size + ((size % fcb->record_size) != 0);
6094: REG8(AL) = 0;
6095: }
6096: }
6097:
6098: inline void msdos_int_21h_24h()
6099: {
6100: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
6101: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
6102:
6103: fcb->rand_record = fcb->current_block * fcb->record_size + fcb->cur_record;
6104: }
6105:
1.1 root 6106: inline void msdos_int_21h_25h()
6107: {
6108: *(UINT16 *)(mem + 4 * REG8(AL) + 0) = REG16(DX);
1.1.1.3 root 6109: *(UINT16 *)(mem + 4 * REG8(AL) + 2) = SREG(DS);
1.1 root 6110: }
6111:
6112: inline void msdos_int_21h_26h()
6113: {
6114: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
6115:
6116: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
6117: psp->first_mcb = REG16(DX) + 16;
6118: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
6119: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
6120: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
6121: psp->parent_psp = 0;
6122: }
6123:
1.1.1.16 root 6124: inline void msdos_int_21h_27h()
6125: {
6126: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
6127: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
6128:
6129: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
6130: REG8(AL) = 1;
6131: } else {
6132: process_t *process = msdos_process_info_get(current_psp);
6133: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
6134: memset(mem + dta_laddr, 0, fcb->record_size * REG16(CX));
6135: DWORD num = 0;
6136: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL) || num == 0) {
6137: REG8(AL) = 1;
6138: } else {
6139: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
6140: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
6141: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
6142: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
6143: }
6144: }
6145: }
6146:
6147: inline void msdos_int_21h_28h()
6148: {
6149: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
6150: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
6151:
6152: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
6153: REG8(AL) = 0xff;
6154: } else {
6155: process_t *process = msdos_process_info_get(current_psp);
6156: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
6157: DWORD num = 0;
6158: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL);
6159: fcb->file_size = GetFileSize(fcb->handle, NULL);
6160: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
6161: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
6162: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
6163: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
6164: }
6165: }
6166:
1.1 root 6167: inline void msdos_int_21h_29h()
6168: {
1.1.1.20 root 6169: int ofs = 0;//SREG_BASE(DS) + REG16(SI);
6170: char buffer[1024], name[MAX_PATH], ext[MAX_PATH];
1.1 root 6171: UINT8 drv = 0;
6172: char sep_chars[] = ":.;,=+";
6173: char end_chars[] = "\\<>|/\"[]";
6174: char spc_chars[] = " \t";
6175:
1.1.1.20 root 6176: memcpy(buffer, mem + SREG_BASE(DS) + REG16(SI), 1023);
6177: buffer[1023] = 0;
6178: memset(name, 0x20, sizeof(name));
6179: memset(ext, 0x20, sizeof(ext));
6180:
1.1 root 6181: if(REG8(AL) & 1) {
1.1.1.20 root 6182: ofs += strspn((char *)(buffer + ofs), spc_chars);
6183: if(my_strchr(sep_chars, buffer[ofs]) && buffer[ofs] != '\0') {
1.1 root 6184: ofs++;
6185: }
6186: }
1.1.1.20 root 6187: ofs += strspn((char *)(buffer + ofs), spc_chars);
1.1 root 6188:
1.1.1.24 root 6189: if(buffer[ofs + 1] == ':') {
6190: if(buffer[ofs] >= 'a' && buffer[ofs] <= 'z') {
6191: drv = buffer[ofs] - 'a' + 1;
1.1.1.20 root 6192: ofs += 2;
1.1.1.24 root 6193: if(buffer[ofs] == '\\' || buffer[ofs] == '/') {
6194: ofs++;
6195: }
6196: } else if(buffer[ofs] >= 'A' && buffer[ofs] <= 'Z') {
6197: drv = buffer[ofs] - 'A' + 1;
1.1 root 6198: ofs += 2;
1.1.1.24 root 6199: if(buffer[ofs] == '\\' || buffer[ofs] == '/') {
6200: ofs++;
6201: }
1.1 root 6202: }
6203: }
1.1.1.20 root 6204: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
6205: UINT8 c = buffer[ofs];
6206: if(is_kanji) {
6207: is_kanji = 0;
6208: } else if(msdos_lead_byte_check(c)) {
6209: is_kanji = 1;
6210: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 6211: break;
6212: } else if(c >= 'a' && c <= 'z') {
6213: c -= 0x20;
6214: }
6215: ofs++;
6216: name[i] = c;
6217: }
1.1.1.20 root 6218: if(buffer[ofs] == '.') {
1.1 root 6219: ofs++;
1.1.1.20 root 6220: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
6221: UINT8 c = buffer[ofs];
6222: if(is_kanji) {
6223: is_kanji = 0;
6224: } else if(msdos_lead_byte_check(c)) {
6225: is_kanji = 1;
6226: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 6227: break;
6228: } else if(c >= 'a' && c <= 'z') {
6229: c -= 0x20;
6230: }
6231: ofs++;
6232: ext[i] = c;
6233: }
6234: }
1.1.1.20 root 6235: int si = REG16(SI) + ofs;
1.1.1.3 root 6236: int ds = SREG(DS);
1.1 root 6237: while(si > 0xffff) {
6238: si -= 0x10;
6239: ds++;
6240: }
6241: REG16(SI) = si;
1.1.1.3 root 6242: SREG(DS) = ds;
6243: i386_load_segment_descriptor(DS);
1.1 root 6244:
1.1.1.3 root 6245: UINT8 *fcb = mem + SREG_BASE(ES) + REG16(DI);
1.1.1.20 root 6246: if(!(REG8(AL) & 2) || drv != 0) {
6247: fcb[0] = drv;
6248: }
6249: if(!(REG8(AL) & 4) || name[0] != 0x20) {
6250: memcpy(fcb + 1, name, 8);
6251: }
6252: if(!(REG8(AL) & 8) || ext[0] != 0x20) {
6253: memcpy(fcb + 9, ext, 3);
6254: }
6255: for(int i = 1, found_star = 0; i < 1 + 8; i++) {
1.1 root 6256: if(fcb[i] == '*') {
6257: found_star = 1;
6258: }
6259: if(found_star) {
6260: fcb[i] = '?';
6261: }
6262: }
1.1.1.20 root 6263: for(int i = 9, found_star = 0; i < 9 + 3; i++) {
1.1 root 6264: if(fcb[i] == '*') {
6265: found_star = 1;
6266: }
6267: if(found_star) {
6268: fcb[i] = '?';
6269: }
6270: }
6271:
6272: if(drv == 0 || (drv > 0 && drv <= 26 && (GetLogicalDrives() & ( 1 << (drv - 1) )))) {
6273: if(memchr(fcb + 1, '?', 8 + 3)) {
6274: REG8(AL) = 0x01;
1.1.1.20 root 6275: } else {
6276: REG8(AL) = 0x00;
1.1 root 6277: }
6278: } else {
6279: REG8(AL) = 0xff;
6280: }
6281: }
6282:
6283: inline void msdos_int_21h_2ah()
6284: {
6285: SYSTEMTIME sTime;
6286:
6287: GetLocalTime(&sTime);
6288: REG16(CX) = sTime.wYear;
6289: REG8(DH) = (UINT8)sTime.wMonth;
6290: REG8(DL) = (UINT8)sTime.wDay;
6291: REG8(AL) = (UINT8)sTime.wDayOfWeek;
6292: }
6293:
6294: inline void msdos_int_21h_2bh()
6295: {
1.1.1.14 root 6296: REG8(AL) = 0xff;
1.1 root 6297: }
6298:
6299: inline void msdos_int_21h_2ch()
6300: {
6301: SYSTEMTIME sTime;
6302:
6303: GetLocalTime(&sTime);
6304: REG8(CH) = (UINT8)sTime.wHour;
6305: REG8(CL) = (UINT8)sTime.wMinute;
6306: REG8(DH) = (UINT8)sTime.wSecond;
1.1.1.14 root 6307: REG8(DL) = (UINT8)sTime.wMilliseconds / 10;
1.1 root 6308: }
6309:
6310: inline void msdos_int_21h_2dh()
6311: {
6312: REG8(AL) = 0x00;
6313: }
6314:
6315: inline void msdos_int_21h_2eh()
6316: {
6317: process_t *process = msdos_process_info_get(current_psp);
6318:
6319: process->verify = REG8(AL);
6320: }
6321:
6322: inline void msdos_int_21h_2fh()
6323: {
6324: process_t *process = msdos_process_info_get(current_psp);
6325:
6326: REG16(BX) = process->dta.w.l;
1.1.1.3 root 6327: SREG(ES) = process->dta.w.h;
6328: i386_load_segment_descriptor(ES);
1.1 root 6329: }
6330:
6331: inline void msdos_int_21h_30h()
6332: {
6333: // Version Flag / OEM
1.1.1.27 root 6334: if(REG8(AL) == 0x01) {
1.1.1.29! root 6335: #ifdef SUPPORT_HMA
! 6336: REG16(BX) = 0x0000;
! 6337: #else
! 6338: REG16(BX) = 0x1000; // DOS is in HMA
! 6339: #endif
1.1 root 6340: } else {
1.1.1.27 root 6341: // NOTE: EXDEB invites BL shows the machine type (0=PC-98, 1=PC/AT, 2=FMR),
6342: // but this is not correct on Windows 98 SE
6343: // REG16(BX) = 0xff01; // OEM = Microsoft, PC/AT
6344: REG16(BX) = 0xff00; // OEM = Microsoft
1.1 root 6345: }
1.1.1.27 root 6346: REG16(CX) = 0x0000;
1.1.1.9 root 6347: REG8(AL) = major_version; // 7
6348: REG8(AH) = minor_version; // 10
1.1 root 6349: }
6350:
6351: inline void msdos_int_21h_31h()
6352: {
1.1.1.29! root 6353: try {
! 6354: msdos_mem_realloc(current_psp, REG16(DX), NULL);
! 6355: } catch(...) {
! 6356: // recover the broken mcb
! 6357: int mcb_seg = current_psp - 1;
! 6358: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
! 6359: if(mcb_seg < (MEMORY_END >> 4)) {
! 6360: if(((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked & 0x01) {
! 6361: mcb->mz = 'M';
! 6362: } else {
! 6363: mcb->mz = 'Z';
! 6364: }
! 6365: mcb->paragraphs32 = (MEMORY_END >> 4) - mcb_seg - 2;
! 6366: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', -1, (UMB_TOP >> 4) - (MEMORY_END >> 4));
! 6367: } else {
! 6368: mcb->mz = 'Z';
! 6369: mcb->paragraphs32 = (UMB_END >> 4) - mcb_seg - 1;
! 6370: }
! 6371: msdos_mem_realloc(current_psp, REG16(DX), NULL);
! 6372: }
1.1 root 6373: msdos_process_terminate(current_psp, REG8(AL) | 0x300, 0);
6374: }
6375:
6376: inline void msdos_int_21h_32h()
6377: {
6378: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
6379: UINT16 seg, ofs;
6380:
6381: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
6382: REG8(AL) = 0;
1.1.1.3 root 6383: SREG(DS) = seg;
6384: i386_load_segment_descriptor(DS);
1.1 root 6385: REG16(BX) = ofs;
6386: } else {
6387: REG8(AL) = 0xff;
1.1.1.3 root 6388: m_CF = 1;
1.1 root 6389: }
6390: }
6391:
6392: inline void msdos_int_21h_33h()
6393: {
6394: char path[MAX_PATH];
6395:
6396: switch(REG8(AL)) {
6397: case 0x00:
1.1.1.26 root 6398: REG8(DL) = ctrl_c_checking;
1.1 root 6399: break;
6400: case 0x01:
1.1.1.26 root 6401: ctrl_c_checking = REG8(DL);
1.1 root 6402: break;
6403: case 0x05:
6404: GetSystemDirectory(path, MAX_PATH);
6405: if(path[0] >= 'a' && path[0] <= 'z') {
6406: REG8(DL) = path[0] - 'a' + 1;
6407: } else {
6408: REG8(DL) = path[0] - 'A' + 1;
6409: }
6410: break;
6411: case 0x06:
1.1.1.2 root 6412: // MS-DOS version (7.10)
1.1 root 6413: REG8(BL) = 7;
1.1.1.2 root 6414: REG8(BH) = 10;
1.1 root 6415: REG8(DL) = 0;
1.1.1.29! root 6416: #ifdef SUPPORT_HMA
! 6417: REG8(DH) = 0x00;
! 6418: #else
! 6419: REG8(DH) = 0x10; // DOS is in HMA
! 6420: #endif
1.1 root 6421: break;
1.1.1.6 root 6422: case 0x07:
6423: if(REG8(DL) == 0) {
6424: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag &= ~0x20;
6425: } else if(REG8(DL) == 1) {
6426: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag |= 0x20;
6427: }
6428: break;
1.1 root 6429: default:
1.1.1.22 root 6430: 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 6431: REG16(AX) = 0x01;
1.1.1.3 root 6432: m_CF = 1;
1.1 root 6433: break;
6434: }
6435: }
6436:
1.1.1.23 root 6437: inline void msdos_int_21h_34h()
6438: {
6439: SREG(ES) = SDA_TOP >> 4;
6440: i386_load_segment_descriptor(ES);
6441: REG16(BX) = offsetof(sda_t, indos_flag);;
6442: }
6443:
1.1 root 6444: inline void msdos_int_21h_35h()
6445: {
6446: REG16(BX) = *(UINT16 *)(mem + 4 * REG8(AL) + 0);
1.1.1.3 root 6447: SREG(ES) = *(UINT16 *)(mem + 4 * REG8(AL) + 2);
6448: i386_load_segment_descriptor(ES);
1.1 root 6449: }
6450:
6451: inline void msdos_int_21h_36h()
6452: {
6453: struct _diskfree_t df = {0};
6454:
6455: if(_getdiskfree(REG8(DL), &df) == 0) {
6456: REG16(AX) = (UINT16)df.sectors_per_cluster;
6457: REG16(CX) = (UINT16)df.bytes_per_sector;
1.1.1.13 root 6458: REG16(BX) = df.avail_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.avail_clusters;
6459: REG16(DX) = df.total_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.total_clusters;
1.1 root 6460: } else {
6461: REG16(AX) = 0xffff;
6462: }
6463: }
6464:
6465: inline void msdos_int_21h_37h()
6466: {
1.1.1.22 root 6467: static UINT8 dev_flag = 0xff;
1.1 root 6468:
6469: switch(REG8(AL)) {
6470: case 0x00:
1.1.1.22 root 6471: {
6472: process_t *process = msdos_process_info_get(current_psp);
6473: REG8(AL) = 0x00;
6474: REG8(DL) = process->switchar;
6475: }
1.1 root 6476: break;
6477: case 0x01:
1.1.1.22 root 6478: {
6479: process_t *process = msdos_process_info_get(current_psp);
6480: REG8(AL) = 0x00;
6481: process->switchar = REG8(DL);
1.1.1.23 root 6482: msdos_sda_update(current_psp);
1.1.1.22 root 6483: }
6484: break;
6485: case 0x02:
6486: REG8(DL) = dev_flag;
6487: break;
6488: case 0x03:
6489: dev_flag = REG8(DL);
6490: break;
6491: case 0xd0:
6492: case 0xd1:
6493: case 0xd2:
6494: case 0xd3:
6495: case 0xd4:
6496: case 0xd5:
6497: case 0xd6:
6498: case 0xd7:
6499: case 0xdc:
6500: case 0xdd:
6501: case 0xde:
6502: case 0xdf:
6503: // diet ???
6504: REG16(AX) = 1;
1.1 root 6505: break;
6506: default:
1.1.1.22 root 6507: 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 6508: REG16(AX) = 1;
6509: break;
6510: }
6511: }
6512:
1.1.1.19 root 6513: int get_country_info(country_info_t *ci)
1.1.1.17 root 6514: {
6515: char LCdata[80];
6516:
1.1.1.19 root 6517: ZeroMemory(ci, offsetof(country_info_t, reserved));
1.1.1.17 root 6518: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRDIGITS, LCdata, sizeof(LCdata));
6519: ci->currency_dec_digits = atoi(LCdata);
6520: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRENCY, LCdata, sizeof(LCdata));
6521: ci->currency_format = *LCdata - '0';
6522: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDATE, LCdata, sizeof(LCdata));
6523: ci->date_format = *LCdata - '0';
6524: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SCURRENCY, LCdata, sizeof(LCdata));
6525: memcpy(&ci->currency_symbol, LCdata, 4);
6526: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDATE, LCdata, sizeof(LCdata));
6527: *ci->date_sep = *LCdata;
6528: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, LCdata, sizeof(LCdata));
6529: *ci->dec_sep = *LCdata;
6530: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLIST, LCdata, sizeof(LCdata));
6531: *ci->list_sep = *LCdata;
6532: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, LCdata, sizeof(LCdata));
6533: *ci->thou_sep = *LCdata;
6534: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIME, LCdata, sizeof(LCdata));
6535: *ci->time_sep = *LCdata;
6536: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, LCdata, sizeof(LCdata));
6537: if(strchr(LCdata, 'H') != NULL) {
6538: ci->time_format = 1;
6539: }
1.1.1.27 root 6540: ci->case_map.w.l = 0x000a; // dummy case map routine is at fffd:000a
1.1.1.24 root 6541: ci->case_map.w.h = 0xfffd;
1.1.1.17 root 6542: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICOUNTRY, LCdata, sizeof(LCdata));
6543: return atoi(LCdata);
6544: }
6545:
1.1.1.14 root 6546: inline void msdos_int_21h_38h()
6547: {
6548: switch(REG8(AL)) {
6549: case 0x00:
1.1.1.19 root 6550: REG16(BX) = get_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1.1.14 root 6551: break;
6552: default:
1.1.1.22 root 6553: 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 6554: REG16(AX) = 2;
6555: m_CF = 1;
6556: break;
6557: }
6558: }
6559:
1.1 root 6560: inline void msdos_int_21h_39h(int lfn)
6561: {
1.1.1.3 root 6562: if(_mkdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 6563: REG16(AX) = errno;
1.1.1.3 root 6564: m_CF = 1;
1.1 root 6565: }
6566: }
6567:
6568: inline void msdos_int_21h_3ah(int lfn)
6569: {
1.1.1.3 root 6570: if(_rmdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 6571: REG16(AX) = errno;
1.1.1.3 root 6572: m_CF = 1;
1.1 root 6573: }
6574: }
6575:
6576: inline void msdos_int_21h_3bh(int lfn)
6577: {
1.1.1.3 root 6578: if(_chdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1.1.17 root 6579: REG16(AX) = 3; // must be 3 (path not found)
1.1.1.3 root 6580: m_CF = 1;
1.1 root 6581: }
6582: }
6583:
6584: inline void msdos_int_21h_3ch()
6585: {
1.1.1.3 root 6586: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 6587: int attr = GetFileAttributes(path);
1.1.1.29! root 6588: int fd = -1, c;
1.1.1.11 root 6589: UINT16 info;
1.1 root 6590:
1.1.1.11 root 6591: if(msdos_is_con_path(path)) {
6592: fd = _open("CON", _O_WRONLY | _O_BINARY);
6593: info = 0x80d3;
1.1.1.29! root 6594: } else if((c = msdos_is_comm_path(path)) != 0 && sio_port_number[c - 1] != 0) {
! 6595: if((fd = _open(msdos_create_comm_path(path, sio_port_number[c - 1]), _O_WRONLY | _O_BINARY)) == -1) {
! 6596: fd = _open("NUL", _O_WRONLY | _O_BINARY);
! 6597: }
1.1.1.14 root 6598: info = 0x80d3;
1.1.1.29! root 6599: } else if(msdos_is_device_path(path)) {
1.1.1.20 root 6600: fd = _open("NUL", _O_WRONLY | _O_BINARY);
6601: info = 0x80d3;
1.1 root 6602: } else {
6603: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 6604: info = msdos_drive_number(path);
1.1 root 6605: }
6606: if(fd != -1) {
6607: if(attr == -1) {
6608: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
6609: }
6610: SetFileAttributes(path, attr);
6611: REG16(AX) = fd;
1.1.1.11 root 6612: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp);
1.1.1.20 root 6613: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 6614: } else {
6615: REG16(AX) = errno;
1.1.1.3 root 6616: m_CF = 1;
1.1 root 6617: }
6618: }
6619:
6620: inline void msdos_int_21h_3dh()
6621: {
1.1.1.3 root 6622: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 6623: int mode = REG8(AL) & 0x03;
1.1.1.29! root 6624: int fd = -1, c;
1.1.1.11 root 6625: UINT16 info;
1.1 root 6626:
6627: if(mode < 0x03) {
1.1.1.11 root 6628: if(msdos_is_con_path(path)) {
1.1.1.13 root 6629: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 6630: info = 0x80d3;
1.1.1.29! root 6631: } else if((c = msdos_is_comm_path(path)) != 0 && sio_port_number[c - 1] != 0) {
! 6632: if((fd = _open(msdos_create_comm_path(path, sio_port_number[c - 1]), file_mode[mode].mode)) == -1) {
! 6633: fd = msdos_open("NUL", file_mode[mode].mode);
! 6634: }
1.1.1.14 root 6635: info = 0x80d3;
1.1.1.29! root 6636: } else if(msdos_is_device_path(path)) {
1.1.1.20 root 6637: fd = msdos_open("NUL", file_mode[mode].mode);
6638: info = 0x80d3;
1.1.1.11 root 6639: } else {
1.1.1.13 root 6640: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 6641: info = msdos_drive_number(path);
6642: }
1.1 root 6643: if(fd != -1) {
6644: REG16(AX) = fd;
1.1.1.11 root 6645: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp);
1.1.1.20 root 6646: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 6647: } else {
6648: REG16(AX) = errno;
1.1.1.3 root 6649: m_CF = 1;
1.1 root 6650: }
6651: } else {
6652: REG16(AX) = 0x0c;
1.1.1.3 root 6653: m_CF = 1;
1.1 root 6654: }
6655: }
6656:
6657: inline void msdos_int_21h_3eh()
6658: {
6659: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 6660: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 6661:
1.1.1.20 root 6662: if(fd < process->max_files && file_handler[fd].valid) {
6663: _close(fd);
6664: msdos_file_handler_close(fd);
6665: msdos_psp_set_file_table(REG16(BX), 0x0ff, current_psp);
1.1 root 6666: } else {
6667: REG16(AX) = 0x06;
1.1.1.3 root 6668: m_CF = 1;
1.1 root 6669: }
6670: }
6671:
6672: inline void msdos_int_21h_3fh()
6673: {
6674: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 6675: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 6676:
1.1.1.20 root 6677: if(fd < process->max_files && file_handler[fd].valid) {
6678: if(file_mode[file_handler[fd].mode].in) {
6679: if(file_handler[fd].atty) {
1.1 root 6680: // BX is stdin or is redirected to stdin
1.1.1.3 root 6681: UINT8 *buf = mem + SREG_BASE(DS) + REG16(DX);
1.1 root 6682: int max = REG16(CX);
6683: int p = 0;
6684:
6685: while(max > p) {
6686: int chr = msdos_getch();
6687:
1.1.1.26 root 6688: if(ctrl_c_pressed) {
6689: p = 0;
6690: buf[p++] = 0x0d;
6691: if(max > p) {
6692: buf[p++] = 0x0a;
6693: }
6694: msdos_putch(chr);
6695: msdos_putch('\n');
6696: break;
6697: } else if(chr == 0x00) {
1.1 root 6698: // skip 2nd byte
6699: msdos_getch();
6700: } else if(chr == 0x0d) {
6701: // carriage return
6702: buf[p++] = 0x0d;
6703: if(max > p) {
6704: buf[p++] = 0x0a;
6705: }
1.1.1.14 root 6706: msdos_putch('\n');
1.1 root 6707: break;
6708: } else if(chr == 0x08) {
6709: // back space
6710: if(p > 0) {
6711: p--;
1.1.1.20 root 6712: if(msdos_ctrl_code_check(buf[p])) {
6713: msdos_putch(chr);
6714: msdos_putch(chr);
6715: msdos_putch(' ');
6716: msdos_putch(' ');
6717: msdos_putch(chr);
6718: msdos_putch(chr);
6719: } else {
6720: msdos_putch(chr);
6721: msdos_putch(' ');
6722: msdos_putch(chr);
6723: }
1.1 root 6724: }
6725: } else {
6726: buf[p++] = chr;
6727: msdos_putch(chr);
6728: }
6729: }
6730: REG16(AX) = p;
1.1.1.26 root 6731:
1.1.1.8 root 6732: // some seconds may be passed in console
1.1 root 6733: hardware_update();
6734: } else {
1.1.1.20 root 6735: REG16(AX) = _read(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 6736: }
6737: } else {
6738: REG16(AX) = 0x05;
1.1.1.3 root 6739: m_CF = 1;
1.1 root 6740: }
6741: } else {
6742: REG16(AX) = 0x06;
1.1.1.3 root 6743: m_CF = 1;
1.1 root 6744: }
6745: }
6746:
6747: inline void msdos_int_21h_40h()
6748: {
6749: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 6750: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 6751:
1.1.1.20 root 6752: if(fd < process->max_files && file_handler[fd].valid) {
6753: if(file_mode[file_handler[fd].mode].out) {
1.1 root 6754: if(REG16(CX)) {
1.1.1.20 root 6755: if(file_handler[fd].atty) {
1.1 root 6756: // BX is stdout/stderr or is redirected to stdout
6757: for(int i = 0; i < REG16(CX); i++) {
1.1.1.3 root 6758: msdos_putch(mem[SREG_BASE(DS) + REG16(DX) + i]);
1.1 root 6759: }
6760: REG16(AX) = REG16(CX);
6761: } else {
1.1.1.20 root 6762: REG16(AX) = msdos_write(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 6763: }
6764: } else {
1.1.1.20 root 6765: UINT32 pos = _tell(fd);
6766: _lseek(fd, 0, SEEK_END);
6767: UINT32 size = _tell(fd);
1.1.1.12 root 6768: if(pos < size) {
1.1.1.20 root 6769: _lseek(fd, pos, SEEK_SET);
6770: SetEndOfFile((HANDLE)_get_osfhandle(fd));
1.1.1.12 root 6771: } else {
6772: for(UINT32 i = size; i < pos; i++) {
6773: UINT8 tmp = 0;
1.1.1.23 root 6774: msdos_write(fd, &tmp, 1);
1.1.1.12 root 6775: }
1.1.1.20 root 6776: _lseek(fd, pos, SEEK_SET);
1.1 root 6777: }
1.1.1.23 root 6778: REG16(AX) = 0;
1.1 root 6779: }
6780: } else {
6781: REG16(AX) = 0x05;
1.1.1.3 root 6782: m_CF = 1;
1.1 root 6783: }
6784: } else {
6785: REG16(AX) = 0x06;
1.1.1.3 root 6786: m_CF = 1;
1.1 root 6787: }
6788: }
6789:
6790: inline void msdos_int_21h_41h(int lfn)
6791: {
1.1.1.3 root 6792: if(remove(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 6793: REG16(AX) = errno;
1.1.1.3 root 6794: m_CF = 1;
1.1 root 6795: }
6796: }
6797:
6798: inline void msdos_int_21h_42h()
6799: {
6800: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 6801: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 6802:
1.1.1.20 root 6803: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 6804: if(REG8(AL) < 0x03) {
6805: static int ptrname[] = { SEEK_SET, SEEK_CUR, SEEK_END };
1.1.1.20 root 6806: _lseek(fd, (REG16(CX) << 16) | REG16(DX), ptrname[REG8(AL)]);
6807: UINT32 pos = _tell(fd);
1.1 root 6808: REG16(AX) = pos & 0xffff;
6809: REG16(DX) = (pos >> 16);
6810: } else {
6811: REG16(AX) = 0x01;
1.1.1.3 root 6812: m_CF = 1;
1.1 root 6813: }
6814: } else {
6815: REG16(AX) = 0x06;
1.1.1.3 root 6816: m_CF = 1;
1.1 root 6817: }
6818: }
6819:
6820: inline void msdos_int_21h_43h(int lfn)
6821: {
1.1.1.3 root 6822: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn);
1.1 root 6823: int attr;
6824:
1.1.1.14 root 6825: if(!lfn && REG8(AL) > 2) {
6826: REG16(AX) = 0x01;
6827: m_CF = 1;
6828: return;
6829: }
6830: switch(REG8(lfn ? BL : AL)) {
1.1 root 6831: case 0x00:
6832: if((attr = GetFileAttributes(path)) != -1) {
1.1.1.14 root 6833: REG16(CX) = (UINT16)msdos_file_attribute_create((UINT16)attr);
6834: } else {
6835: REG16(AX) = (UINT16)GetLastError();
6836: m_CF = 1;
6837: }
6838: break;
6839: case 0x01:
6840: if(!SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)))) {
6841: REG16(AX) = (UINT16)GetLastError();
6842: m_CF = 1;
6843: }
6844: break;
6845: case 0x02:
6846: {
6847: DWORD size = GetCompressedFileSize(path, NULL);
6848: if(size != INVALID_FILE_SIZE) {
6849: if(size != 0 && size == GetFileSize(path, NULL)) {
6850: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
6851: // this isn't correct if the file is in the NTFS MFT
6852: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
6853: size = ((size - 1) | (sectors_per_cluster * bytes_per_sector - 1)) + 1;
6854: }
6855: }
6856: REG16(AX) = LOWORD(size);
6857: REG16(DX) = HIWORD(size);
6858: } else {
6859: REG16(AX) = (UINT16)GetLastError();
6860: m_CF = 1;
1.1 root 6861: }
1.1.1.14 root 6862: }
6863: break;
6864: case 0x03:
6865: case 0x05:
6866: case 0x07:
6867: {
6868: HANDLE hFile = CreateFile(path, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
6869: if(hFile != INVALID_HANDLE_VALUE) {
6870: FILETIME local, time;
6871: DosDateTimeToFileTime(REG16(DI), /*REG8(BL) == 5 ? 0 : */REG16(CX), &local);
6872: if(REG8(BL) == 7) {
6873: ULARGE_INTEGER hund;
6874: hund.LowPart = local.dwLowDateTime;
6875: hund.HighPart = local.dwHighDateTime;
6876: hund.QuadPart += REG16(SI) * 100000;
6877: local.dwLowDateTime = hund.LowPart;
6878: local.dwHighDateTime = hund.HighPart;
6879: }
6880: LocalFileTimeToFileTime(&local, &time);
6881: if(!SetFileTime(hFile, REG8(BL) == 0x07 ? &time : NULL,
6882: REG8(BL) == 0x05 ? &time : NULL,
6883: REG8(BL) == 0x03 ? &time : NULL)) {
6884: REG16(AX) = (UINT16)GetLastError();
6885: m_CF = 1;
6886: }
6887: CloseHandle(hFile);
6888: } else {
6889: REG16(AX) = (UINT16)GetLastError();
6890: m_CF = 1;
1.1 root 6891: }
1.1.1.14 root 6892: }
6893: break;
6894: case 0x04:
6895: case 0x06:
6896: case 0x08:
6897: {
6898: WIN32_FILE_ATTRIBUTE_DATA fad;
6899: if(GetFileAttributesEx(path, GetFileExInfoStandard, (LPVOID)&fad)) {
6900: FILETIME *time, local;
6901: time = REG8(BL) == 0x04 ? &fad.ftLastWriteTime :
6902: 0x06 ? &fad.ftLastAccessTime :
6903: &fad.ftCreationTime;
6904: FileTimeToLocalFileTime(time, &local);
6905: FileTimeToDosDateTime(&local, ®16(DI), ®16(CX));
6906: if(REG8(BL) == 0x08) {
6907: ULARGE_INTEGER hund;
6908: hund.LowPart = local.dwLowDateTime;
6909: hund.HighPart = local.dwHighDateTime;
6910: hund.QuadPart /= 100000;
6911: REG16(SI) = (UINT16)(hund.QuadPart % 200);
6912: }
6913: } else {
6914: REG16(AX) = (UINT16)GetLastError();
6915: m_CF = 1;
1.1 root 6916: }
1.1.1.14 root 6917: }
6918: break;
6919: default:
1.1.1.22 root 6920: 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 6921: REG16(AX) = 0x01;
6922: m_CF = 1;
6923: break;
6924: }
6925: }
6926:
6927: inline void msdos_int_21h_44h()
6928: {
1.1.1.22 root 6929: static UINT16 iteration_count = 0;
6930:
1.1.1.20 root 6931: process_t *process = msdos_process_info_get(current_psp);
6932: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
6933:
1.1.1.14 root 6934: UINT32 val = DRIVE_NO_ROOT_DIR;
6935:
6936: switch(REG8(AL)) {
6937: case 0x00:
6938: case 0x01:
6939: case 0x02:
6940: case 0x03:
6941: case 0x04:
6942: case 0x05:
6943: case 0x06:
6944: case 0x07:
1.1.1.20 root 6945: if(fd >= process->max_files || !file_handler[fd].valid) {
6946: REG16(AX) = 0x06;
6947: m_CF = 1;
6948: return;
1.1.1.14 root 6949: }
6950: break;
6951: case 0x08:
6952: case 0x09:
6953: if(REG8(BL) >= ('Z' - 'A' + 1)) {
6954: // invalid drive number
6955: REG16(AX) = 0x0f;
6956: m_CF = 1;
6957: return;
6958: } else {
6959: if(REG8(BL) == 0) {
6960: val = GetDriveType(NULL);
6961: } else {
6962: char tmp[8];
6963: sprintf(tmp, "%c:\\", 'A' + REG8(BL) - 1);
6964: val = GetDriveType(tmp);
6965: }
6966: if(val == DRIVE_NO_ROOT_DIR) {
6967: // no drive
6968: REG16(AX) = 0x0f;
6969: m_CF = 1;
6970: return;
1.1 root 6971: }
6972: }
6973: break;
6974: }
6975: switch(REG8(AL)) {
6976: case 0x00: // get ioctrl data
1.1.1.20 root 6977: REG16(DX) = file_handler[fd].info;
1.1 root 6978: break;
6979: case 0x01: // set ioctrl data
1.1.1.20 root 6980: file_handler[fd].info |= REG8(DL);
1.1 root 6981: break;
6982: case 0x02: // recv from character device
6983: case 0x03: // send to character device
6984: case 0x04: // recv from block device
6985: case 0x05: // send to block device
6986: REG16(AX) = 0x05;
1.1.1.3 root 6987: m_CF = 1;
1.1 root 6988: break;
6989: case 0x06: // get read status
1.1.1.20 root 6990: if(file_mode[file_handler[fd].mode].in) {
6991: if(file_handler[fd].atty) {
1.1.1.14 root 6992: REG8(AL) = msdos_kbhit() ? 0xff : 0x00;
1.1 root 6993: } else {
1.1.1.20 root 6994: REG8(AL) = eof(fd) ? 0x00 : 0xff;
1.1 root 6995: }
1.1.1.14 root 6996: } else {
6997: REG8(AL) = 0x00;
1.1 root 6998: }
6999: break;
7000: case 0x07: // get write status
1.1.1.20 root 7001: if(file_mode[file_handler[fd].mode].out) {
1.1.1.14 root 7002: REG8(AL) = 0xff;
7003: } else {
7004: REG8(AL) = 0x00;
1.1 root 7005: }
7006: break;
7007: case 0x08: // check removable drive
1.1.1.14 root 7008: if(val == DRIVE_REMOVABLE || val == DRIVE_CDROM) {
7009: // removable drive
7010: REG16(AX) = 0x00;
1.1 root 7011: } else {
1.1.1.14 root 7012: // fixed drive
7013: REG16(AX) = 0x01;
1.1 root 7014: }
7015: break;
7016: case 0x09: // check remote drive
1.1.1.14 root 7017: if(val == DRIVE_REMOTE) {
7018: // remote drive
7019: REG16(DX) = 0x1000;
1.1 root 7020: } else {
1.1.1.14 root 7021: // local drive
7022: REG16(DX) = 0x00;
1.1 root 7023: }
7024: break;
1.1.1.21 root 7025: case 0x0a: // check remote handle
7026: REG16(DX) = 0x00; // FIXME
7027: break;
1.1 root 7028: case 0x0b: // set retry count
7029: break;
1.1.1.22 root 7030: case 0x0c: // generic character device request
7031: if(REG8(CL) == 0x45) {
7032: // set iteration (retry) count
7033: iteration_count = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
7034: } else if(REG8(CL) == 0x4a) {
7035: // select code page
7036: active_code_page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2);
7037: msdos_nls_tables_update();
7038: } else if(REG8(CL) == 0x65) {
7039: // get iteration (retry) count
7040: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX)) = iteration_count;
7041: } else if(REG8(CL) == 0x6a) {
7042: // query selected code page
7043: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 2; // FIXME
7044: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = active_code_page;
7045:
7046: CPINFO info;
7047: GetCPInfo(active_code_page, &info);
7048:
7049: if(info.MaxCharSize != 1) {
7050: for(int i = 0;; i++) {
7051: UINT8 lo = info.LeadByte[2 * i + 0];
7052: UINT8 hi = info.LeadByte[2 * i + 1];
7053:
7054: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 0) = lo;
7055: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 2) = hi;
7056: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) + 4;
7057:
7058: if(lo == 0 && hi == 0) {
7059: break;
7060: }
7061: }
7062: }
7063: } else if(REG8(CL) == 0x7f) {
7064: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x00) = 0;
7065: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x01) = 0;
7066: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02) = 14;
7067: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x04) = 1;
7068: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x06) = 1;
7069: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x07) = 0;
7070: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x08) = 4;
7071: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0a) = 8 * (*(UINT16 *)(mem + 0x44a));
7072: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0c) = 16 * (*(UINT8 *)(mem + 0x484) + 1);
7073: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e) = *(UINT16 *)(mem + 0x44a);
7074: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x10) = *(UINT8 *)(mem + 0x484) + 1;
7075: } else {
7076: 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));
7077: REG16(AX) = 0x01; // invalid function
7078: m_CF = 1;
7079: }
7080: break;
7081: case 0x0d: // generic block device request
7082: if(REG8(CL) == 0x40) {
7083: // set device parameters
7084: } else if(REG8(CL) == 0x46) {
7085: // set volume serial number
7086: } else if(REG8(CL) == 0x4a) {
7087: // lock logical volume
7088: } else if(REG8(CL) == 0x4b) {
7089: // lock physical volume
7090: } else if(REG8(CL) == 0x60) {
7091: // get device parameters
7092: char dev[] = "\\\\.\\A:";
7093: dev[4] = 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
7094:
7095: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
7096: if(hFile != INVALID_HANDLE_VALUE) {
7097: DISK_GEOMETRY geo;
7098: DWORD dwSize;
7099: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
7100: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x07; // ???
7101: switch(geo.MediaType) {
7102: case F5_360_512:
7103: case F5_320_512:
7104: case F5_320_1024:
7105: case F5_180_512:
7106: case F5_160_512:
7107: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // 320K/360K disk
7108: break;
7109: case F5_1Pt2_512:
7110: case F3_1Pt2_512:
7111: case F3_1Pt23_1024:
7112: case F5_1Pt23_1024:
7113: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x01; // 1.2M disk
7114: break;
7115: case F3_720_512:
7116: case F3_640_512:
7117: case F5_640_512:
7118: case F5_720_512:
7119: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02; // 720K disk
7120: break;
7121: case F8_256_128:
7122: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x03; // single-density 8-inch disk
7123: break;
7124: case FixedMedia:
7125: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
7126: break;
7127: case F3_1Pt44_512:
7128: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07; // (DOS 3.3+) other type of block device, normally 1.44M floppy
7129: break;
7130: case F3_2Pt88_512:
7131: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09; // (DOS 5+) 2.88M floppy
7132: break;
7133: default:
7134: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
7135: // *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // (DOS 3.3+) other type of block device, normally 1.44M floppy
7136: break;
7137: }
7138: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = (geo.MediaType == FixedMedia) ? 0x01 : 0x00;
7139: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04) = (geo.Cylinders.QuadPart > 0xffff) ? 0xffff : geo.Cylinders.QuadPart;
7140: switch(geo.MediaType) {
7141: case F5_360_512:
7142: case F5_320_512:
7143: case F5_320_1024:
7144: case F5_180_512:
7145: case F5_160_512:
7146: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x01; // 320K/360K disk
7147: break;
7148: default:
7149: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x00; // other drive types
7150: break;
7151: }
7152: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x00) = geo.BytesPerSector;
7153: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x02) = geo.SectorsPerTrack * geo.TracksPerCylinder;
7154: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x03) = 0;
7155: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x05) = 0;
7156: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x06) = 0;
7157: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x08) = 0;
7158: switch(geo.MediaType) {
7159: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
7160: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xff;
7161: break;
7162: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
7163: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfe;
7164: break;
7165: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
7166: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfd;
7167: break;
7168: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
7169: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfc;
7170: break;
7171: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
7172: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
7173: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf9;
7174: break;
7175: case FixedMedia: // hard disk
7176: case RemovableMedia:
7177: case Unknown:
7178: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf8;
7179: break;
7180: default:
7181: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf0;
7182: break;
7183: }
7184: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0d) = geo.SectorsPerTrack;
7185: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0f) = 1;
7186: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x11) = 0;
7187: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x15) = geo.TracksPerCylinder * geo.Cylinders.QuadPart;
7188: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x1f) = geo.Cylinders.QuadPart;
7189: // 21h BYTE device type
7190: // 22h WORD device attributes (removable or not, etc)
7191: } else {
7192: REG16(AX) = 0x0f; // invalid drive
7193: m_CF = 1;
7194: }
7195: CloseHandle(hFile);
7196: } else {
7197: REG16(AX) = 0x0f; // invalid drive
7198: m_CF = 1;
7199: }
7200: } else if(REG8(CL) == 0x66) {
7201: // get volume serial number
7202: char path[] = "A:\\";
7203: char volume_label[MAX_PATH];
7204: DWORD serial_number = 0;
7205: char file_system[MAX_PATH];
7206:
7207: path[0] = 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
7208:
7209: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
7210: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
7211: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = serial_number;
7212: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x06, 0x20, 11);
7213: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x06, volume_label, min(strlen(volume_label), 11));
7214: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x11, 0x20, 8);
7215: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x11, file_system, min(strlen(file_system), 8));
7216: } else {
7217: REG16(AX) = 0x0f; // invalid drive
7218: m_CF = 1;
7219: }
7220: } else if(REG8(CL) == 0x67) {
7221: // get access flag
7222: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
7223: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 1;
7224: } else if(REG8(CL) == 0x68) {
7225: // sense media type
7226: char dev[64];
7227: sprintf(dev, "\\\\.\\%c:", 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1);
7228:
7229: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
7230: if(hFile != INVALID_HANDLE_VALUE) {
7231: DISK_GEOMETRY geo;
7232: DWORD dwSize;
7233: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
7234: switch(geo.MediaType) {
7235: case F3_720_512:
7236: case F5_720_512:
7237: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
7238: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02;
7239: break;
7240: case F3_1Pt44_512:
7241: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
7242: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07;
7243: break;
7244: case F3_2Pt88_512:
7245: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
7246: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09;
7247: break;
7248: default:
7249: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x00;
7250: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // ???
7251: break;
7252: }
7253: } else {
7254: REG16(AX) = 0x0f; // invalid drive
7255: m_CF = 1;
7256: }
7257: CloseHandle(hFile);
7258: } else {
7259: REG16(AX) = 0x0f; // invalid drive
7260: m_CF = 1;
7261: }
7262: } else if(REG8(CL) == 0x6a) {
7263: // unlock logical volume
7264: } else if(REG8(CL) == 0x6b) {
7265: // unlock physical volume
7266: } else {
7267: 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));
7268: REG16(AX) = 0x01; // invalid function
7269: m_CF = 1;
7270: }
7271: break;
7272: case 0x0e: // get logical drive map
7273: {
7274: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
7275: if(!(GetLogicalDrives() & bits)) {
7276: REG16(AX) = 0x0f; // invalid drive
7277: m_CF = 1;
7278: } else {
7279: REG8(AL) = 0;
7280: }
7281: }
7282: break;
7283: case 0x0f: // set logical drive map
7284: {
7285: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
7286: if(!(GetLogicalDrives() & bits)) {
7287: REG16(AX) = 0x0f; // invalid drive
7288: m_CF = 1;
7289: }
7290: }
7291: break;
7292: case 0x10: // query generic ioctrl capability (handle)
7293: switch(REG8(CL)) {
7294: case 0x45:
7295: case 0x4a:
7296: case 0x65:
7297: case 0x6a:
7298: case 0x7f:
7299: REG16(AX) = 0x0000; // supported
7300: break;
7301: default:
7302: REG8(AL) = 0x01; // ioctl capability not available
7303: m_CF = 1;
7304: break;
7305: }
7306: break;
7307: case 0x11: // query generic ioctrl capability (drive)
7308: switch(REG8(CL)) {
7309: case 0x40:
7310: case 0x46:
7311: case 0x4a:
7312: case 0x4b:
7313: case 0x60:
7314: case 0x66:
7315: case 0x67:
7316: case 0x68:
7317: case 0x6a:
7318: case 0x6b:
7319: REG16(AX) = 0x0000; // supported
7320: break;
7321: default:
7322: REG8(AL) = 0x01; // ioctl capability not available
7323: m_CF = 1;
7324: break;
7325: }
7326: break;
7327: case 0x12: // determine dos type
7328: case 0x51: // concurrent dos v3.2+ - installation check
7329: case 0x52: // determine dos type/get dr dos versuin
7330: REG16(AX) = 0x01; // this is not DR-DOS
7331: m_CF = 1;
7332: break;
1.1 root 7333: default:
1.1.1.22 root 7334: 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 7335: REG16(AX) = 0x01;
1.1.1.3 root 7336: m_CF = 1;
1.1 root 7337: break;
7338: }
7339: }
7340:
7341: inline void msdos_int_21h_45h()
7342: {
7343: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 7344: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 7345:
1.1.1.20 root 7346: if(fd < process->max_files && file_handler[fd].valid) {
7347: int dup_fd = _dup(fd);
7348: if(dup_fd != -1) {
7349: REG16(AX) = dup_fd;
7350: msdos_file_handler_dup(dup_fd, fd, current_psp);
7351: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
7352: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 7353: } else {
7354: REG16(AX) = errno;
1.1.1.3 root 7355: m_CF = 1;
1.1 root 7356: }
7357: } else {
7358: REG16(AX) = 0x06;
1.1.1.3 root 7359: m_CF = 1;
1.1 root 7360: }
7361: }
7362:
7363: inline void msdos_int_21h_46h()
7364: {
7365: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 7366: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
7367: int dup_fd = REG16(CX);
7368: int tmp_fd = msdos_psp_get_file_table(REG16(CX), current_psp);
1.1 root 7369:
1.1.1.20 root 7370: if(REG16(BX) == REG16(CX)) {
7371: REG16(AX) = 0x06;
7372: m_CF = 1;
7373: } else if(fd < process->max_files && file_handler[fd].valid && dup_fd < process->max_files) {
7374: if(tmp_fd < process->max_files && file_handler[tmp_fd].valid) {
7375: _close(tmp_fd);
7376: msdos_file_handler_close(tmp_fd);
7377: msdos_psp_set_file_table(dup_fd, 0x0ff, current_psp);
7378: }
7379: if(_dup2(fd, dup_fd) != -1) {
7380: msdos_file_handler_dup(dup_fd, fd, current_psp);
7381: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
7382: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 7383: } else {
7384: REG16(AX) = errno;
1.1.1.3 root 7385: m_CF = 1;
1.1 root 7386: }
7387: } else {
7388: REG16(AX) = 0x06;
1.1.1.3 root 7389: m_CF = 1;
1.1 root 7390: }
7391: }
7392:
7393: inline void msdos_int_21h_47h(int lfn)
7394: {
7395: char path[MAX_PATH];
7396:
7397: if(_getdcwd(REG8(DL), path, MAX_PATH) != NULL) {
7398: if(path[1] == ':') {
7399: // the returned path does not include a drive or the initial backslash
1.1.1.3 root 7400: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), (lfn ? path : msdos_short_path(path)) + 3);
1.1 root 7401: } else {
1.1.1.3 root 7402: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn ? path : msdos_short_path(path));
1.1 root 7403: }
7404: } else {
7405: REG16(AX) = errno;
1.1.1.3 root 7406: m_CF = 1;
1.1 root 7407: }
7408: }
7409:
7410: inline void msdos_int_21h_48h()
7411: {
1.1.1.19 root 7412: int seg, umb_linked;
1.1 root 7413:
1.1.1.8 root 7414: if((malloc_strategy & 0xf0) == 0x00) {
1.1.1.19 root 7415: // unlink umb not to allocate memory in umb
7416: if((umb_linked = msdos_mem_get_umb_linked()) != 0) {
7417: msdos_mem_unlink_umb();
7418: }
1.1.1.8 root 7419: if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
7420: REG16(AX) = seg;
7421: } else {
7422: REG16(AX) = 0x08;
7423: REG16(BX) = msdos_mem_get_free(first_mcb, 0);
7424: m_CF = 1;
7425: }
1.1.1.19 root 7426: if(umb_linked != 0) {
7427: msdos_mem_link_umb();
7428: }
1.1.1.8 root 7429: } else if((malloc_strategy & 0xf0) == 0x40) {
7430: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
7431: REG16(AX) = seg;
7432: } else {
7433: REG16(AX) = 0x08;
7434: REG16(BX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
7435: m_CF = 1;
7436: }
7437: } else if((malloc_strategy & 0xf0) == 0x80) {
7438: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
7439: REG16(AX) = seg;
7440: } else if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
7441: REG16(AX) = seg;
7442: } else {
7443: REG16(AX) = 0x08;
7444: REG16(BX) = max(msdos_mem_get_free(UMB_TOP >> 4, 0), msdos_mem_get_free(first_mcb, 0));
7445: m_CF = 1;
7446: }
1.1 root 7447: }
7448: }
7449:
7450: inline void msdos_int_21h_49h()
7451: {
1.1.1.14 root 7452: int mcb_seg = SREG(ES) - 1;
7453: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
7454:
7455: if(mcb->mz == 'M' || mcb->mz == 'Z') {
7456: msdos_mem_free(SREG(ES));
7457: } else {
1.1.1.28 root 7458: REG16(AX) = 0x09; // illegal memory block address
1.1.1.14 root 7459: m_CF = 1;
7460: }
1.1 root 7461: }
7462:
7463: inline void msdos_int_21h_4ah()
7464: {
1.1.1.14 root 7465: int mcb_seg = SREG(ES) - 1;
7466: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1 root 7467: int max_paragraphs;
7468:
1.1.1.14 root 7469: if(mcb->mz == 'M' || mcb->mz == 'Z') {
7470: if(msdos_mem_realloc(SREG(ES), REG16(BX), &max_paragraphs)) {
7471: REG16(AX) = 0x08;
7472: REG16(BX) = max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs;
7473: m_CF = 1;
7474: }
7475: } else {
1.1.1.28 root 7476: REG16(AX) = 0x09; // illegal memory block address
1.1.1.3 root 7477: m_CF = 1;
1.1 root 7478: }
7479: }
7480:
7481: inline void msdos_int_21h_4bh()
7482: {
1.1.1.3 root 7483: char *command = (char *)(mem + SREG_BASE(DS) + REG16(DX));
7484: param_block_t *param = (param_block_t *)(mem + SREG_BASE(ES) + REG16(BX));
1.1 root 7485:
7486: switch(REG8(AL)) {
7487: case 0x00:
7488: case 0x01:
7489: if(msdos_process_exec(command, param, REG8(AL))) {
7490: REG16(AX) = 0x02;
1.1.1.3 root 7491: m_CF = 1;
1.1 root 7492: }
7493: break;
1.1.1.14 root 7494: case 0x03:
7495: {
7496: int fd;
7497: if((fd = _open(command, _O_RDONLY | _O_BINARY)) == -1) {
7498: REG16(AX) = 0x02;
7499: m_CF = 1;
7500: break;
7501: }
7502: int size = _read(fd, file_buffer, sizeof(file_buffer));
7503: _close(fd);
7504:
7505: UINT16 *overlay = (UINT16 *)param;
7506:
7507: // check exe header
7508: exe_header_t *header = (exe_header_t *)file_buffer;
7509: int header_size = 0;
7510: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
7511: header_size = header->header_size * 16;
7512: // relocation
7513: int start_seg = overlay[1];
7514: for(int i = 0; i < header->relocations; i++) {
7515: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
7516: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
7517: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
7518: }
7519: }
7520: memcpy(mem + (overlay[0] << 4), file_buffer + header_size, size - header_size);
7521: }
7522: break;
1.1 root 7523: default:
1.1.1.22 root 7524: 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 7525: REG16(AX) = 0x01;
1.1.1.3 root 7526: m_CF = 1;
1.1 root 7527: break;
7528: }
7529: }
7530:
7531: inline void msdos_int_21h_4ch()
7532: {
7533: msdos_process_terminate(current_psp, REG8(AL), 1);
7534: }
7535:
7536: inline void msdos_int_21h_4dh()
7537: {
7538: REG16(AX) = retval;
7539: }
7540:
7541: inline void msdos_int_21h_4eh()
7542: {
7543: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 7544: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
7545: find_t *find = (find_t *)(mem + dta_laddr);
1.1.1.3 root 7546: char *path = msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 7547: WIN32_FIND_DATA fd;
7548:
1.1.1.14 root 7549: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
7550: find->find_magic = FIND_MAGIC;
7551: find->dta_index = dtainfo - dtalist;
1.1 root 7552: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 7553: dtainfo->allowable_mask = REG8(CL);
7554: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 7555:
1.1.1.14 root 7556: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
7557: dtainfo->allowable_mask &= ~8;
1.1 root 7558: }
1.1.1.14 root 7559: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
7560: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 7561: !msdos_find_file_has_8dot3name(&fd)) {
7562: if(!FindNextFile(dtainfo->find_handle, &fd)) {
7563: FindClose(dtainfo->find_handle);
7564: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7565: break;
7566: }
7567: }
7568: }
1.1.1.13 root 7569: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 7570: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
7571: msdos_find_file_conv_local_time(&fd);
7572: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
7573: find->size = fd.nFileSizeLow;
1.1.1.13 root 7574: strcpy(find->name, msdos_short_name(&fd));
1.1 root 7575: REG16(AX) = 0;
1.1.1.14 root 7576: } else if(dtainfo->allowable_mask & 8) {
1.1 root 7577: find->attrib = 8;
7578: find->size = 0;
7579: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 7580: dtainfo->allowable_mask &= ~8;
1.1 root 7581: REG16(AX) = 0;
7582: } else {
7583: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 7584: m_CF = 1;
1.1 root 7585: }
7586: }
7587:
7588: inline void msdos_int_21h_4fh()
7589: {
7590: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 7591: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
7592: find_t *find = (find_t *)(mem + dta_laddr);
1.1 root 7593: WIN32_FIND_DATA fd;
7594:
1.1.1.14 root 7595: if(find->find_magic != FIND_MAGIC || find->dta_index >= MAX_DTAINFO) {
7596: REG16(AX) = 0x12;
7597: m_CF = 1;
7598: return;
7599: }
7600: dtainfo_t *dtainfo = &dtalist[find->dta_index];
1.1.1.13 root 7601: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
7602: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 7603: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 7604: !msdos_find_file_has_8dot3name(&fd)) {
7605: if(!FindNextFile(dtainfo->find_handle, &fd)) {
7606: FindClose(dtainfo->find_handle);
7607: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7608: break;
7609: }
7610: }
7611: } else {
1.1.1.13 root 7612: FindClose(dtainfo->find_handle);
7613: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7614: }
7615: }
1.1.1.13 root 7616: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 7617: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
7618: msdos_find_file_conv_local_time(&fd);
7619: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
7620: find->size = fd.nFileSizeLow;
1.1.1.13 root 7621: strcpy(find->name, msdos_short_name(&fd));
1.1 root 7622: REG16(AX) = 0;
1.1.1.14 root 7623: } else if(dtainfo->allowable_mask & 8) {
1.1 root 7624: find->attrib = 8;
7625: find->size = 0;
7626: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 7627: dtainfo->allowable_mask &= ~8;
1.1 root 7628: REG16(AX) = 0;
7629: } else {
7630: REG16(AX) = 0x12;
1.1.1.3 root 7631: m_CF = 1;
1.1 root 7632: }
7633: }
7634:
7635: inline void msdos_int_21h_50h()
7636: {
1.1.1.8 root 7637: if(current_psp != REG16(BX)) {
7638: process_t *process = msdos_process_info_get(current_psp);
7639: if(process != NULL) {
7640: process->psp = REG16(BX);
7641: }
7642: current_psp = REG16(BX);
1.1.1.23 root 7643: msdos_sda_update(current_psp);
1.1.1.8 root 7644: }
1.1 root 7645: }
7646:
7647: inline void msdos_int_21h_51h()
7648: {
7649: REG16(BX) = current_psp;
7650: }
7651:
7652: inline void msdos_int_21h_52h()
7653: {
1.1.1.25 root 7654: SREG(ES) = DOS_INFO_TOP >> 4;
1.1.1.3 root 7655: i386_load_segment_descriptor(ES);
1.1.1.25 root 7656: REG16(BX) = offsetof(dos_info_t, first_dpb);
1.1 root 7657: }
7658:
7659: inline void msdos_int_21h_54h()
7660: {
7661: process_t *process = msdos_process_info_get(current_psp);
7662:
7663: REG8(AL) = process->verify;
7664: }
7665:
7666: inline void msdos_int_21h_55h()
7667: {
7668: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
7669:
7670: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
7671: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
7672: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
7673: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
7674: psp->parent_psp = current_psp;
7675: }
7676:
7677: inline void msdos_int_21h_56h(int lfn)
7678: {
7679: char src[MAX_PATH], dst[MAX_PATH];
1.1.1.3 root 7680: strcpy(src, msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn));
7681: strcpy(dst, msdos_trimmed_path((char *)(mem + SREG_BASE(ES) + REG16(DI)), lfn));
1.1 root 7682:
7683: if(rename(src, dst)) {
7684: REG16(AX) = errno;
1.1.1.3 root 7685: m_CF = 1;
1.1 root 7686: }
7687: }
7688:
7689: inline void msdos_int_21h_57h()
7690: {
7691: FILETIME time, local;
1.1.1.14 root 7692: FILETIME *ctime, *atime, *mtime;
1.1.1.21 root 7693: HANDLE hHandle;
1.1 root 7694:
1.1.1.21 root 7695: if((hHandle = (HANDLE)_get_osfhandle(REG16(BX))) == INVALID_HANDLE_VALUE) {
1.1.1.14 root 7696: REG16(AX) = (UINT16)GetLastError();
7697: m_CF = 1;
7698: return;
7699: }
7700: ctime = atime = mtime = NULL;
7701:
1.1 root 7702: switch(REG8(AL)) {
7703: case 0x00:
1.1.1.6 root 7704: case 0x01:
1.1.1.14 root 7705: mtime = &time;
1.1.1.6 root 7706: break;
7707: case 0x04:
7708: case 0x05:
1.1.1.14 root 7709: atime = &time;
1.1 root 7710: break;
1.1.1.6 root 7711: case 0x06:
7712: case 0x07:
1.1.1.14 root 7713: ctime = &time;
7714: break;
7715: default:
1.1.1.22 root 7716: 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 7717: REG16(AX) = 0x01;
7718: m_CF = 1;
7719: return;
7720: }
7721: if(REG8(AL) & 1) {
1.1 root 7722: DosDateTimeToFileTime(REG16(DX), REG16(CX), &local);
7723: LocalFileTimeToFileTime(&local, &time);
1.1.1.21 root 7724: if(!SetFileTime(hHandle, ctime, atime, mtime)) {
1.1 root 7725: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 7726: m_CF = 1;
1.1 root 7727: }
1.1.1.14 root 7728: } else {
1.1.1.21 root 7729: if(!GetFileTime(hHandle, ctime, atime, mtime)) {
1.1.1.14 root 7730: // assume a device and use the current time
7731: GetSystemTimeAsFileTime(&time);
7732: }
7733: FileTimeToLocalFileTime(&time, &local);
7734: FileTimeToDosDateTime(&local, ®16(DX), ®16(CX));
1.1 root 7735: }
7736: }
7737:
7738: inline void msdos_int_21h_58h()
7739: {
7740: switch(REG8(AL)) {
7741: case 0x00:
1.1.1.7 root 7742: REG16(AX) = malloc_strategy;
7743: break;
7744: case 0x01:
1.1.1.24 root 7745: // switch(REG16(BX)) {
7746: switch(REG8(BL)) {
1.1.1.7 root 7747: case 0x0000:
7748: case 0x0001:
7749: case 0x0002:
7750: case 0x0040:
7751: case 0x0041:
7752: case 0x0042:
7753: case 0x0080:
7754: case 0x0081:
7755: case 0x0082:
7756: malloc_strategy = REG16(BX);
1.1.1.23 root 7757: msdos_sda_update(current_psp);
1.1.1.7 root 7758: break;
7759: default:
1.1.1.22 root 7760: 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 7761: REG16(AX) = 0x01;
7762: m_CF = 1;
7763: break;
7764: }
7765: break;
7766: case 0x02:
1.1.1.19 root 7767: REG8(AL) = msdos_mem_get_umb_linked() ? 1 : 0;
1.1.1.7 root 7768: break;
7769: case 0x03:
1.1.1.24 root 7770: // switch(REG16(BX)) {
7771: switch(REG8(BL)) {
1.1.1.7 root 7772: case 0x0000:
1.1.1.19 root 7773: msdos_mem_unlink_umb();
7774: break;
1.1.1.7 root 7775: case 0x0001:
1.1.1.19 root 7776: msdos_mem_link_umb();
1.1.1.7 root 7777: break;
7778: default:
1.1.1.22 root 7779: 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 7780: REG16(AX) = 0x01;
7781: m_CF = 1;
7782: break;
7783: }
1.1 root 7784: break;
7785: default:
1.1.1.22 root 7786: 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 7787: REG16(AX) = 0x01;
1.1.1.3 root 7788: m_CF = 1;
1.1 root 7789: break;
7790: }
7791: }
7792:
7793: inline void msdos_int_21h_59h()
7794: {
1.1.1.23 root 7795: sda_t *sda = (sda_t *)(mem + SDA_TOP);
7796:
7797: REG16(AX) = sda->extended_error_code;
7798: REG8(BH) = sda->error_class;
7799: REG8(BL) = sda->suggested_action;
7800: REG8(CH) = sda->locus_of_last_error;
1.1 root 7801: }
7802:
7803: inline void msdos_int_21h_5ah()
7804: {
1.1.1.3 root 7805: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 7806: int len = strlen(path);
7807: char tmp[MAX_PATH];
7808:
7809: if(GetTempFileName(path, "TMP", 0, tmp)) {
7810: int fd = _open(tmp, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
7811:
7812: SetFileAttributes(tmp, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
7813: REG16(AX) = fd;
7814: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 7815: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 7816:
7817: strcpy(path, tmp);
7818: int dx = REG16(DX) + len;
1.1.1.3 root 7819: int ds = SREG(DS);
1.1 root 7820: while(dx > 0xffff) {
7821: dx -= 0x10;
7822: ds++;
7823: }
7824: REG16(DX) = dx;
1.1.1.3 root 7825: SREG(DS) = ds;
7826: i386_load_segment_descriptor(DS);
1.1 root 7827: } else {
7828: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 7829: m_CF = 1;
1.1 root 7830: }
7831: }
7832:
7833: inline void msdos_int_21h_5bh()
7834: {
1.1.1.3 root 7835: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 7836:
1.1.1.24 root 7837: if(msdos_is_existing_file(path)) {
1.1 root 7838: // already exists
7839: REG16(AX) = 0x50;
1.1.1.3 root 7840: m_CF = 1;
1.1 root 7841: } else {
7842: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
7843:
7844: if(fd != -1) {
7845: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
7846: REG16(AX) = fd;
7847: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 7848: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 7849: } else {
7850: REG16(AX) = errno;
1.1.1.3 root 7851: m_CF = 1;
1.1 root 7852: }
7853: }
7854: }
7855:
7856: inline void msdos_int_21h_5ch()
7857: {
7858: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 7859: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 7860:
1.1.1.20 root 7861: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 7862: if(REG8(AL) == 0 || REG8(AL) == 1) {
7863: static int modes[2] = {_LK_LOCK, _LK_UNLCK};
1.1.1.20 root 7864: UINT32 pos = _tell(fd);
7865: _lseek(fd, (REG16(CX) << 16) | REG16(DX), SEEK_SET);
7866: if(_locking(fd, modes[REG8(AL)], (REG16(SI) << 16) | REG16(DI))) {
1.1 root 7867: REG16(AX) = errno;
1.1.1.3 root 7868: m_CF = 1;
1.1 root 7869: }
1.1.1.20 root 7870: _lseek(fd, pos, SEEK_SET);
1.1.1.26 root 7871:
1.1 root 7872: // some seconds may be passed in _locking()
7873: hardware_update();
7874: } else {
7875: REG16(AX) = 0x01;
1.1.1.3 root 7876: m_CF = 1;
1.1 root 7877: }
7878: } else {
7879: REG16(AX) = 0x06;
1.1.1.3 root 7880: m_CF = 1;
1.1 root 7881: }
7882: }
7883:
1.1.1.22 root 7884: inline void msdos_int_21h_5dh()
7885: {
7886: switch(REG8(AL)) {
7887: case 0x06: // get address of dos swappable data area
1.1.1.23 root 7888: SREG(DS) = (SDA_TOP >> 4);
7889: i386_load_segment_descriptor(DS);
7890: REG16(SI) = offsetof(sda_t, crit_error_flag);
7891: REG16(CX) = 0x80;
7892: REG16(DX) = 0x1a;
7893: break;
7894: case 0x0b: // get dos swappable data areas
1.1.1.22 root 7895: REG16(AX) = 0x01;
7896: m_CF = 1;
7897: break;
7898: case 0x08: // set redirected printer mode
7899: case 0x09: // flush redirected printer output
7900: case 0x0a: // set extended error information
7901: break;
7902: default:
7903: 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));
7904: REG16(AX) = 0x01;
7905: m_CF = 1;
7906: break;
7907: }
7908: }
7909:
1.1 root 7910: inline void msdos_int_21h_60h(int lfn)
7911: {
1.1.1.14 root 7912: char full[MAX_PATH], *path;
7913:
1.1 root 7914: if(lfn) {
1.1.1.14 root 7915: char *name;
7916: *full = '\0';
1.1.1.3 root 7917: GetFullPathName((char *)(mem + SREG_BASE(DS) + REG16(SI)), MAX_PATH, full, &name);
1.1.1.14 root 7918: switch(REG8(CL)) {
7919: case 1:
7920: GetShortPathName(full, full, MAX_PATH);
7921: my_strupr(full);
7922: break;
7923: case 2:
7924: GetLongPathName(full, full, MAX_PATH);
7925: break;
7926: }
7927: path = full;
7928: } else {
7929: path = msdos_short_full_path((char *)(mem + SREG_BASE(DS) + REG16(SI)));
7930: }
7931: if(*path != '\0') {
7932: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path);
1.1 root 7933: } else {
1.1.1.14 root 7934: REG16(AX) = (UINT16)GetLastError();
7935: m_CF = 1;
1.1 root 7936: }
7937: }
7938:
7939: inline void msdos_int_21h_61h()
7940: {
7941: REG8(AL) = 0;
7942: }
7943:
7944: inline void msdos_int_21h_62h()
7945: {
7946: REG16(BX) = current_psp;
7947: }
7948:
7949: inline void msdos_int_21h_63h()
7950: {
7951: switch(REG8(AL)) {
7952: case 0x00:
1.1.1.3 root 7953: SREG(DS) = (DBCS_TABLE >> 4);
7954: i386_load_segment_descriptor(DS);
1.1 root 7955: REG16(SI) = (DBCS_TABLE & 0x0f);
7956: REG8(AL) = 0x00;
7957: break;
1.1.1.22 root 7958: case 0x01: // set korean input mode
7959: case 0x02: // get korean input mode
7960: REG8(AL) = 0xff; // not supported
7961: break;
1.1 root 7962: default:
1.1.1.22 root 7963: 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 7964: REG16(AX) = 0x01;
1.1.1.3 root 7965: m_CF = 1;
1.1 root 7966: break;
7967: }
7968: }
7969:
1.1.1.25 root 7970: UINT16 get_extended_country_info(UINT8 func)
1.1 root 7971: {
1.1.1.25 root 7972: switch(func) {
1.1.1.17 root 7973: case 0x01:
7974: if(REG16(CX) >= 5) {
1.1.1.19 root 7975: UINT8 data[1 + 2 + 2 + 2 + sizeof(country_info_t)];
1.1.1.17 root 7976: if(REG16(CX) > sizeof(data)) // cx = actual transfer size
7977: REG16(CX) = sizeof(data);
7978: ZeroMemory(data, sizeof(data));
7979: data[0] = 0x01;
7980: *(UINT16 *)(data + 1) = REG16(CX) - 3;
1.1.1.19 root 7981: *(UINT16 *)(data + 3) = get_country_info((country_info_t*)(data + 7));
1.1.1.17 root 7982: *(UINT16 *)(data + 5) = active_code_page;
7983: memcpy(mem + SREG_BASE(ES) + REG16(DI), data, REG16(CX));
1.1.1.25 root 7984: // REG16(AX) = active_code_page;
1.1.1.17 root 7985: } else {
1.1.1.25 root 7986: return(0x08); // insufficient memory
1.1.1.17 root 7987: }
7988: break;
7989: case 0x02:
7990: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
7991: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (UPPERTABLE_TOP & 0x0f);
7992: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (UPPERTABLE_TOP >> 4);
1.1.1.25 root 7993: // REG16(AX) = active_code_page;
1.1.1.17 root 7994: REG16(CX) = 0x05;
7995: break;
1.1.1.23 root 7996: case 0x03:
7997: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
7998: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (LOWERTABLE_TOP & 0x0f);
7999: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (LOWERTABLE_TOP >> 4);
1.1.1.25 root 8000: // REG16(AX) = active_code_page;
1.1.1.23 root 8001: REG16(CX) = 0x05;
8002: break;
1.1.1.17 root 8003: case 0x04:
8004: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x04;
8005: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_UPPERTABLE_TOP & 0x0f);
8006: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_UPPERTABLE_TOP >> 4);
1.1.1.25 root 8007: // REG16(AX) = active_code_page;
1.1.1.17 root 8008: REG16(CX) = 0x05;
8009: break;
8010: case 0x05:
8011: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x05;
8012: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_TERMINATOR_TOP & 0x0f);
8013: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_TERMINATOR_TOP >> 4);
1.1.1.25 root 8014: // REG16(AX) = active_code_page;
1.1.1.17 root 8015: REG16(CX) = 0x05;
8016: break;
8017: case 0x06:
8018: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x06;
8019: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (COLLATING_TABLE_TOP & 0x0f);
8020: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (COLLATING_TABLE_TOP >> 4);
1.1.1.25 root 8021: // REG16(AX) = active_code_page;
1.1.1.17 root 8022: REG16(CX) = 0x05;
8023: break;
1.1 root 8024: case 0x07:
1.1.1.3 root 8025: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x07;
8026: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (DBCS_TOP & 0x0f);
8027: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (DBCS_TOP >> 4);
1.1.1.25 root 8028: // REG16(AX) = active_code_page;
1.1 root 8029: REG16(CX) = 0x05;
8030: break;
1.1.1.25 root 8031: default:
8032: return(0x01); // function number invalid
8033: }
8034: return(0x00);
8035: }
8036:
8037: inline void msdos_int_21h_65h()
8038: {
8039: char tmp[0x10000];
8040:
8041: switch(REG8(AL)) {
8042: case 0x01:
8043: case 0x02:
8044: case 0x03:
8045: case 0x04:
8046: case 0x05:
8047: case 0x06:
8048: case 0x07:
8049: {
8050: UINT16 result = get_extended_country_info(REG8(AL));
8051: if(result) {
8052: REG16(AX) = result;
8053: m_CF = 1;
8054: } else {
8055: REG16(AX) = active_code_page; // FIXME: is this correct???
8056: }
8057: }
8058: break;
1.1 root 8059: case 0x20:
1.1.1.25 root 8060: case 0xa0:
1.1.1.19 root 8061: memset(tmp, 0, sizeof(tmp));
8062: tmp[0] = REG8(DL);
1.1 root 8063: my_strupr(tmp);
8064: REG8(DL) = tmp[0];
8065: break;
8066: case 0x21:
1.1.1.25 root 8067: case 0xa1:
1.1 root 8068: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 8069: memcpy(tmp, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 8070: my_strupr(tmp);
1.1.1.3 root 8071: memcpy(mem + SREG_BASE(DS) + REG16(DX), tmp, REG16(CX));
1.1 root 8072: break;
8073: case 0x22:
1.1.1.25 root 8074: case 0xa2:
1.1.1.3 root 8075: my_strupr((char *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1 root 8076: break;
1.1.1.25 root 8077: case 0x23:
8078: // FIXME: need to check multi-byte (kanji) charactre?
8079: if(REG8(DL) == 'N' || REG8(DL) == 'n' || (REG8(DL) == 0x82 && REG8(DH) == 0x78) || (REG8(DL) == 0x82 && REG8(DH) == 0x99)) {
8080: // 8278h/8299h: multi-byte (kanji) Y and y
8081: REG16(AX) = 0x00;
8082: } else if(REG8(DL) == 'Y' || REG8(DL) == 'y' || (REG8(DL) == 0x82 && REG8(DH) == 0x6d) || (REG8(DL) == 0x82 && REG8(DH) == 0x8e)) {
8083: // 826dh/828eh: multi-byte (kanji) N and n
8084: REG16(AX) = 0x01;
8085: } else {
8086: REG16(AX) = 0x02;
8087: }
8088: break;
1.1 root 8089: default:
1.1.1.22 root 8090: 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 8091: REG16(AX) = 0x01;
1.1.1.3 root 8092: m_CF = 1;
1.1 root 8093: break;
8094: }
8095: }
8096:
8097: inline void msdos_int_21h_66h()
8098: {
8099: switch(REG8(AL)) {
8100: case 0x01:
8101: REG16(BX) = active_code_page;
8102: REG16(DX) = system_code_page;
8103: break;
8104: case 0x02:
8105: if(active_code_page == REG16(BX)) {
8106: REG16(AX) = 0xeb41;
8107: } else if(_setmbcp(REG16(BX)) == 0) {
8108: active_code_page = REG16(BX);
1.1.1.17 root 8109: msdos_nls_tables_update();
1.1 root 8110: REG16(AX) = 0xeb41;
8111: } else {
8112: REG16(AX) = 0x25;
1.1.1.3 root 8113: m_CF = 1;
1.1 root 8114: }
8115: break;
8116: default:
1.1.1.22 root 8117: 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 8118: REG16(AX) = 0x01;
1.1.1.3 root 8119: m_CF = 1;
1.1 root 8120: break;
8121: }
8122: }
8123:
8124: inline void msdos_int_21h_67h()
8125: {
8126: process_t *process = msdos_process_info_get(current_psp);
8127:
8128: if(REG16(BX) <= MAX_FILES) {
8129: process->max_files = max(REG16(BX), 20);
8130: } else {
8131: REG16(AX) = 0x08;
1.1.1.3 root 8132: m_CF = 1;
1.1 root 8133: }
8134: }
8135:
8136: inline void msdos_int_21h_68h()
8137: {
8138: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 8139: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 8140:
1.1.1.20 root 8141: if(fd < process->max_files && file_handler[fd].valid) {
8142: // fflush(_fdopen(fd, ""));
1.1 root 8143: } else {
8144: REG16(AX) = 0x06;
1.1.1.3 root 8145: m_CF = 1;
1.1 root 8146: }
8147: }
8148:
8149: inline void msdos_int_21h_69h()
8150: {
1.1.1.3 root 8151: drive_info_t *info = (drive_info_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 8152: char path[] = "A:\\";
8153: char volume_label[MAX_PATH];
8154: DWORD serial_number = 0;
8155: char file_system[MAX_PATH];
8156:
8157: if(REG8(BL) == 0) {
8158: path[0] = 'A' + _getdrive() - 1;
8159: } else {
8160: path[0] = 'A' + REG8(BL) - 1;
8161: }
8162:
8163: switch(REG8(AL)) {
8164: case 0x00:
8165: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
8166: info->info_level = 0;
8167: info->serial_number = serial_number;
8168: memset(info->volume_label, 0x20, 11);
8169: memcpy(info->volume_label, volume_label, min(strlen(volume_label), 11));
8170: memset(info->file_system, 0x20, 8);
8171: memcpy(info->file_system, file_system, min(strlen(file_system), 8));
8172: } else {
8173: REG16(AX) = errno;
1.1.1.3 root 8174: m_CF = 1;
1.1 root 8175: }
8176: break;
8177: case 0x01:
8178: REG16(AX) = 0x03;
1.1.1.3 root 8179: m_CF = 1;
1.1 root 8180: }
8181: }
8182:
8183: inline void msdos_int_21h_6ah()
8184: {
8185: REG8(AH) = 0x68;
8186: msdos_int_21h_68h();
8187: }
8188:
8189: inline void msdos_int_21h_6bh()
8190: {
8191: REG8(AL) = 0;
8192: }
8193:
8194: inline void msdos_int_21h_6ch(int lfn)
8195: {
1.1.1.3 root 8196: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn);
1.1 root 8197: int mode = REG8(BL) & 0x03;
8198:
8199: if(mode < 0x03) {
1.1.1.29! root 8200: if(msdos_is_device_path(path) || msdos_is_existing_file(path)) {
1.1 root 8201: // file exists
8202: if(REG8(DL) & 1) {
1.1.1.29! root 8203: int fd = -1, c;
1.1.1.11 root 8204: UINT16 info;
1.1 root 8205:
1.1.1.11 root 8206: if(msdos_is_con_path(path)) {
1.1.1.13 root 8207: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 8208: info = 0x80d3;
1.1.1.29! root 8209: } else if((c = msdos_is_comm_path(path)) != 0 && sio_port_number[c - 1] != 0) {
! 8210: if((fd = _open(msdos_create_comm_path(path, sio_port_number[c - 1]), file_mode[mode].mode)) == -1) {
! 8211: fd = msdos_open("NUL", file_mode[mode].mode);
! 8212: }
1.1.1.14 root 8213: info = 0x80d3;
1.1.1.29! root 8214: } else if(msdos_is_device_path(path)) {
1.1.1.20 root 8215: fd = msdos_open("NUL", file_mode[mode].mode);
8216: info = 0x80d3;
1.1.1.11 root 8217: } else {
1.1.1.13 root 8218: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 8219: info = msdos_drive_number(path);
8220: }
1.1 root 8221: if(fd != -1) {
8222: REG16(AX) = fd;
8223: REG16(CX) = 1;
1.1.1.11 root 8224: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp);
1.1.1.20 root 8225: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 8226: } else {
8227: REG16(AX) = errno;
1.1.1.3 root 8228: m_CF = 1;
1.1 root 8229: }
8230: } else if(REG8(DL) & 2) {
8231: int attr = GetFileAttributes(path);
1.1.1.29! root 8232: int fd = -1, c;
1.1.1.11 root 8233: UINT16 info;
1.1 root 8234:
1.1.1.11 root 8235: if(msdos_is_con_path(path)) {
1.1.1.13 root 8236: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 8237: info = 0x80d3;
1.1.1.29! root 8238: } else if((c = msdos_is_comm_path(path)) != 0 && sio_port_number[c - 1] != 0) {
! 8239: if((fd = _open(msdos_create_comm_path(path, sio_port_number[c - 1]), file_mode[mode].mode)) == -1) {
! 8240: fd = msdos_open("NUL", file_mode[mode].mode);
! 8241: }
1.1.1.14 root 8242: info = 0x80d3;
1.1.1.29! root 8243: } else if(msdos_is_device_path(path)) {
1.1.1.20 root 8244: fd = msdos_open("NUL", file_mode[mode].mode);
8245: info = 0x80d3;
1.1 root 8246: } else {
8247: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 8248: info = msdos_drive_number(path);
1.1 root 8249: }
8250: if(fd != -1) {
8251: if(attr == -1) {
8252: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
8253: }
8254: SetFileAttributes(path, attr);
8255: REG16(AX) = fd;
8256: REG16(CX) = 3;
1.1.1.11 root 8257: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp);
1.1.1.20 root 8258: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 8259: } else {
8260: REG16(AX) = errno;
1.1.1.3 root 8261: m_CF = 1;
1.1 root 8262: }
8263: } else {
8264: REG16(AX) = 0x50;
1.1.1.3 root 8265: m_CF = 1;
1.1 root 8266: }
8267: } else {
8268: // file not exists
8269: if(REG8(DL) & 0x10) {
8270: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
8271:
8272: if(fd != -1) {
8273: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
8274: REG16(AX) = fd;
8275: REG16(CX) = 2;
8276: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 8277: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 8278: } else {
8279: REG16(AX) = errno;
1.1.1.3 root 8280: m_CF = 1;
1.1 root 8281: }
8282: } else {
8283: REG16(AX) = 0x02;
1.1.1.3 root 8284: m_CF = 1;
1.1 root 8285: }
8286: }
8287: } else {
8288: REG16(AX) = 0x0c;
1.1.1.3 root 8289: m_CF = 1;
1.1 root 8290: }
8291: }
8292:
8293: inline void msdos_int_21h_710dh()
8294: {
8295: // reset drive
8296: }
8297:
1.1.1.17 root 8298: inline void msdos_int_21h_7141h(int lfn)
8299: {
8300: if(REG16(SI) == 0) {
8301: msdos_int_21h_41h(lfn);
8302: return;
8303: }
8304: if(REG16(SI) != 1) {
8305: REG16(AX) = 5;
8306: m_CF = 1;
8307: }
8308: /* wild card and matching attributes... */
8309: char tmp[MAX_PATH * 2];
8310: // copy search pathname (and quick check overrun)
8311: ZeroMemory(tmp, sizeof(tmp));
8312: tmp[MAX_PATH - 1] = '\0';
8313: tmp[MAX_PATH] = 1;
8314: strncpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(DX)), MAX_PATH);
8315:
8316: if(tmp[MAX_PATH - 1] != '\0' || tmp[MAX_PATH] != 1) {
8317: REG16(AX) = 1;
8318: m_CF = 1;
8319: return;
8320: }
8321: for(char *s = tmp; *s; ++s) {
8322: if(*s == '/') {
8323: *s = '\\';
8324: }
8325: }
8326: char *tmp_name = (char *)_mbsrchr((unsigned char *)tmp, '\\');
8327: if(tmp_name) {
8328: ++tmp_name;
8329: } else {
8330: tmp_name = strchr(tmp, ':');
8331: tmp_name = tmp_name ? tmp_name + 1 : tmp;
8332: }
8333:
8334: WIN32_FIND_DATAA fd;
8335: HANDLE fh = FindFirstFileA(tmp, &fd);
8336: if(fh == INVALID_HANDLE_VALUE) {
8337: REG16(AX) = 2;
8338: m_CF = 1;
8339: return;
8340: }
8341: do {
8342: if(msdos_find_file_check_attribute(fd.dwFileAttributes, REG8(CL), REG8(CH)) && msdos_find_file_has_8dot3name(&fd)) {
8343: strcpy(tmp_name, fd.cFileName);
8344: if(remove(msdos_trimmed_path(tmp, lfn))) {
8345: REG16(AX) = 5;
8346: m_CF = 1;
8347: break;
8348: }
8349: }
8350: } while(FindNextFileA(fh, &fd));
8351: if(!m_CF) {
8352: if(GetLastError() != ERROR_NO_MORE_FILES) {
8353: m_CF = 1;
8354: REG16(AX) = 2;
8355: }
8356: }
8357: FindClose(fh);
8358: }
8359:
1.1 root 8360: inline void msdos_int_21h_714eh()
8361: {
8362: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 8363: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
8364: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 8365: WIN32_FIND_DATA fd;
8366:
1.1.1.13 root 8367: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
8368: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
8369: FindClose(dtainfo->find_handle);
8370: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 8371: }
8372: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 8373: dtainfo->allowable_mask = REG8(CL);
8374: dtainfo->required_mask = REG8(CH);
8375: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 8376:
1.1.1.14 root 8377: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
8378: dtainfo->allowable_mask &= ~8;
1.1 root 8379: }
1.1.1.14 root 8380: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
8381: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 8382: if(!FindNextFile(dtainfo->find_handle, &fd)) {
8383: FindClose(dtainfo->find_handle);
8384: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 8385: break;
8386: }
8387: }
8388: }
1.1.1.13 root 8389: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 8390: find->attrib = fd.dwFileAttributes;
8391: msdos_find_file_conv_local_time(&fd);
8392: if(REG16(SI) == 0) {
8393: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
8394: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
8395: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
8396: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
8397: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
8398: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
8399: } else {
8400: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
8401: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
8402: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
8403: }
8404: find->size_hi = fd.nFileSizeHigh;
8405: find->size_lo = fd.nFileSizeLow;
8406: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 8407: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 8408: REG16(AX) = dtainfo - dtalist + 1;
8409: } else if(dtainfo->allowable_mask & 8) {
1.1 root 8410: // volume label
8411: find->attrib = 8;
8412: find->size_hi = find->size_lo = 0;
8413: strcpy(find->full_name, process->volume_label);
8414: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 8415: dtainfo->allowable_mask &= ~8;
8416: REG16(AX) = dtainfo - dtalist + 1;
1.1 root 8417: } else {
8418: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 8419: m_CF = 1;
1.1 root 8420: }
8421: }
8422:
8423: inline void msdos_int_21h_714fh()
8424: {
8425: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 8426: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 8427: WIN32_FIND_DATA fd;
8428:
1.1.1.14 root 8429: if(REG16(BX) - 1u >= MAX_DTAINFO) {
8430: REG16(AX) = 6;
1.1.1.13 root 8431: m_CF = 1;
8432: return;
8433: }
1.1.1.14 root 8434: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 8435: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
8436: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 8437: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 8438: if(!FindNextFile(dtainfo->find_handle, &fd)) {
8439: FindClose(dtainfo->find_handle);
8440: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 8441: break;
8442: }
8443: }
8444: } else {
1.1.1.13 root 8445: FindClose(dtainfo->find_handle);
8446: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 8447: }
8448: }
1.1.1.13 root 8449: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 8450: find->attrib = fd.dwFileAttributes;
8451: msdos_find_file_conv_local_time(&fd);
8452: if(REG16(SI) == 0) {
8453: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
8454: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
8455: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
8456: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
8457: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
8458: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
8459: } else {
8460: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
8461: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
8462: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
8463: }
8464: find->size_hi = fd.nFileSizeHigh;
8465: find->size_lo = fd.nFileSizeLow;
8466: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 8467: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 8468: } else if(dtainfo->allowable_mask & 8) {
1.1 root 8469: // volume label
8470: find->attrib = 8;
8471: find->size_hi = find->size_lo = 0;
8472: strcpy(find->full_name, process->volume_label);
8473: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 8474: dtainfo->allowable_mask &= ~8;
1.1 root 8475: } else {
8476: REG16(AX) = 0x12;
1.1.1.3 root 8477: m_CF = 1;
1.1 root 8478: }
8479: }
8480:
8481: inline void msdos_int_21h_71a0h()
8482: {
8483: DWORD max_component_len, file_sys_flag;
8484:
1.1.1.14 root 8485: 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))) {
8486: REG16(BX) = (UINT16)file_sys_flag & (FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_VOLUME_IS_COMPRESSED);
8487: REG16(BX) |= 0x4000; // supports LFN functions
1.1 root 8488: REG16(CX) = (UINT16)max_component_len; // 255
8489: REG16(DX) = (UINT16)max_component_len + 5; // 260
8490: } else {
8491: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 8492: m_CF = 1;
1.1 root 8493: }
8494: }
8495:
8496: inline void msdos_int_21h_71a1h()
8497: {
1.1.1.14 root 8498: if(REG16(BX) - 1u >= MAX_DTAINFO) {
8499: REG16(AX) = 6;
1.1.1.13 root 8500: m_CF = 1;
8501: return;
8502: }
1.1.1.14 root 8503: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 8504: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
8505: FindClose(dtainfo->find_handle);
8506: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 8507: }
8508: }
8509:
8510: inline void msdos_int_21h_71a6h()
8511: {
8512: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 8513: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
8514:
1.1.1.3 root 8515: UINT8 *buffer = (UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 8516: struct _stat64 status;
8517: DWORD serial_number = 0;
8518:
1.1.1.20 root 8519: if(fd < process->max_files && file_handler[fd].valid) {
8520: if(_fstat64(fd, &status) == 0) {
8521: if(file_handler[fd].path[1] == ':') {
1.1 root 8522: // NOTE: we need to consider the network file path "\\host\share\"
8523: char volume[] = "A:\\";
1.1.1.20 root 8524: volume[0] = file_handler[fd].path[1];
1.1 root 8525: GetVolumeInformation(volume, NULL, 0, &serial_number, NULL, NULL, NULL, 0);
8526: }
1.1.1.20 root 8527: *(UINT32 *)(buffer + 0x00) = GetFileAttributes(file_handler[fd].path);
1.1 root 8528: *(UINT32 *)(buffer + 0x04) = (UINT32)(status.st_ctime & 0xffffffff);
8529: *(UINT32 *)(buffer + 0x08) = (UINT32)((status.st_ctime >> 32) & 0xffffffff);
8530: *(UINT32 *)(buffer + 0x0c) = (UINT32)(status.st_atime & 0xffffffff);
8531: *(UINT32 *)(buffer + 0x10) = (UINT32)((status.st_atime >> 32) & 0xffffffff);
8532: *(UINT32 *)(buffer + 0x14) = (UINT32)(status.st_mtime & 0xffffffff);
8533: *(UINT32 *)(buffer + 0x18) = (UINT32)((status.st_mtime >> 32) & 0xffffffff);
8534: *(UINT32 *)(buffer + 0x1c) = serial_number;
8535: *(UINT32 *)(buffer + 0x20) = (UINT32)((status.st_size >> 32) & 0xffffffff);
8536: *(UINT32 *)(buffer + 0x24) = (UINT32)(status.st_size & 0xffffffff);
8537: *(UINT32 *)(buffer + 0x28) = status.st_nlink;
1.1.1.14 root 8538: // this is dummy id and it will be changed when it is reopened...
1.1 root 8539: *(UINT32 *)(buffer + 0x2c) = 0;
1.1.1.20 root 8540: *(UINT32 *)(buffer + 0x30) = file_handler[fd].id;
1.1 root 8541: } else {
8542: REG16(AX) = errno;
1.1.1.3 root 8543: m_CF = 1;
1.1 root 8544: }
8545: } else {
8546: REG16(AX) = 0x06;
1.1.1.3 root 8547: m_CF = 1;
1.1 root 8548: }
8549: }
8550:
8551: inline void msdos_int_21h_71a7h()
8552: {
8553: switch(REG8(BL)) {
8554: case 0x00:
1.1.1.3 root 8555: if(!FileTimeToDosDateTime((FILETIME *)(mem + SREG_BASE(DS) + REG16(SI)), ®16(DX), ®16(CX))) {
1.1 root 8556: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 8557: m_CF = 1;
1.1 root 8558: }
8559: break;
8560: case 0x01:
8561: // NOTE: we need to check BH that shows 10-millisecond untils past time in CX
1.1.1.3 root 8562: if(!DosDateTimeToFileTime(REG16(DX), REG16(CX), (FILETIME *)(mem + SREG_BASE(ES) + REG16(DI)))) {
1.1 root 8563: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 8564: m_CF = 1;
1.1 root 8565: }
8566: break;
8567: default:
1.1.1.22 root 8568: 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 8569: REG16(AX) = 0x01;
1.1.1.3 root 8570: m_CF = 1;
1.1 root 8571: break;
8572: }
8573: }
8574:
8575: inline void msdos_int_21h_71a8h()
8576: {
8577: if(REG8(DH) == 0) {
8578: char tmp[MAX_PATH], fcb[MAX_PATH];
1.1.1.3 root 8579: strcpy(tmp, msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 8580: memset(fcb, 0x20, sizeof(fcb));
8581: int len = strlen(tmp);
1.1.1.21 root 8582: for(int i = 0, pos = 0; i < len; i++) {
1.1 root 8583: if(tmp[i] == '.') {
8584: pos = 8;
8585: } else {
8586: if(msdos_lead_byte_check(tmp[i])) {
8587: fcb[pos++] = tmp[i++];
8588: }
8589: fcb[pos++] = tmp[i];
8590: }
8591: }
1.1.1.3 root 8592: memcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), fcb, 11);
1.1 root 8593: } else {
1.1.1.3 root 8594: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 8595: }
8596: }
8597:
1.1.1.22 root 8598: inline void msdos_int_21h_71aah()
8599: {
8600: char drv[] = "A:", path[MAX_PATH];
8601: char *hoge=(char *)(mem + SREG_BASE(DS) + REG16(DX));
8602:
8603: if(REG8(BL) == 0) {
8604: drv[0] = 'A' + _getdrive() - 1;
8605: } else {
8606: drv[0] = 'A' + REG8(BL) - 1;
8607: }
8608: switch(REG8(BH)) {
8609: case 0x00:
8610: if(DefineDosDevice(0, drv, (char *)(mem + SREG_BASE(DS) + REG16(DX))) == 0) {
8611: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
8612: if(GetLogicalDrives() & bits) {
8613: REG16(AX) = 0x0f; // invalid drive
8614: } else {
8615: REG16(AX) = 0x03; // path not found
8616: }
8617: m_CF = 1;
8618: }
8619: break;
8620: case 0x01:
8621: if(DefineDosDevice(DDD_REMOVE_DEFINITION, drv, NULL) == 0) {
8622: REG16(AX) = 0x0f; // invalid drive
8623: m_CF = 1;
8624: }
8625: break;
8626: case 0x02:
8627: if(QueryDosDevice(drv, path, MAX_PATH) == 0) {
8628: REG16(AX) = 0x0f; // invalid drive
8629: m_CF = 1;
8630: } else if(strncmp(path, "\\??\\", 4) != 0) {
8631: REG16(AX) = 0x0f; // invalid drive
8632: m_CF = 1;
8633: } else {
8634: strcpy((char *)(mem + SREG_BASE(DS) + REG16(DX)), path + 4);
8635: }
8636: break;
8637: default:
8638: 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));
8639: REG16(AX) = 0x01;
8640: m_CF = 1;
8641: break;
8642: }
8643: }
8644:
1.1.1.14 root 8645: inline void msdos_int_21h_7300h()
8646: {
8647: if(REG8(AL) == 0) {
8648: REG8(AL) = REG8(CL);
8649: REG8(AH) = 0;
8650: } else {
8651: REG16(AX) = 0x01;
8652: m_CF = 1;
8653: }
8654: }
8655:
8656: inline void msdos_int_21h_7302h()
8657: {
8658: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
8659: UINT16 seg, ofs;
8660:
8661: if(REG16(CX) < 0x3f) {
8662: REG8(AL) = 0x18;
8663: m_CF = 1;
8664: } else if(!msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
8665: REG8(AL) = 0xff;
8666: m_CF = 1;
8667: } else {
8668: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 2, mem + (seg << 4) + ofs, sizeof(dpb_t));
8669: }
8670: }
8671:
1.1 root 8672: inline void msdos_int_21h_7303h()
8673: {
1.1.1.3 root 8674: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
8675: ext_space_info_t *info = (ext_space_info_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 8676: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
8677:
8678: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
8679: info->size_of_structure = sizeof(ext_space_info_t);
8680: info->structure_version = 0;
8681: info->sectors_per_cluster = sectors_per_cluster;
8682: info->bytes_per_sector = bytes_per_sector;
8683: info->available_clusters_on_drive = free_clusters;
8684: info->total_clusters_on_drive = total_clusters;
8685: info->available_sectors_on_drive = sectors_per_cluster * free_clusters;
8686: info->total_sectors_on_drive = sectors_per_cluster * total_clusters;
8687: info->available_allocation_units = free_clusters; // ???
8688: info->total_allocation_units = total_clusters; // ???
8689: } else {
8690: REG16(AX) = errno;
1.1.1.3 root 8691: m_CF = 1;
1.1 root 8692: }
8693: }
8694:
8695: inline void msdos_int_25h()
8696: {
8697: UINT16 seg, ofs;
8698: DWORD dwSize;
8699:
1.1.1.3 root 8700: #if defined(HAS_I386)
8701: I386OP(pushf)();
8702: #else
8703: PREFIX86(_pushf());
8704: #endif
1.1 root 8705:
8706: if(!(REG8(AL) < 26)) {
8707: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 8708: m_CF = 1;
1.1 root 8709: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
8710: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 8711: m_CF = 1;
1.1 root 8712: } else {
8713: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
8714: char dev[64];
8715: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
8716:
8717: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
8718: if(hFile == INVALID_HANDLE_VALUE) {
8719: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 8720: m_CF = 1;
1.1 root 8721: } else {
1.1.1.19 root 8722: UINT32 top_sector = REG16(DX);
8723: UINT16 sector_num = REG16(CX);
8724: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
8725:
8726: if(sector_num == 0xffff) {
8727: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
8728: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
8729: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
8730: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
8731: buffer_addr = (seg << 4) + ofs;
8732: }
8733: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
8734: // REG8(AL) = 0x02; // drive not ready
8735: // m_CF = 1;
8736: // } else
8737: if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 8738: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 8739: m_CF = 1;
1.1.1.19 root 8740: } else if(ReadFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 8741: REG8(AL) = 0x0b; // read error
1.1.1.3 root 8742: m_CF = 1;
1.1 root 8743: }
8744: CloseHandle(hFile);
8745: }
8746: }
8747: }
8748:
8749: inline void msdos_int_26h()
8750: {
8751: // this operation may cause serious damage for drives, so always returns error...
8752: UINT16 seg, ofs;
8753: DWORD dwSize;
8754:
1.1.1.3 root 8755: #if defined(HAS_I386)
8756: I386OP(pushf)();
8757: #else
8758: PREFIX86(_pushf());
8759: #endif
1.1 root 8760:
8761: if(!(REG8(AL) < 26)) {
8762: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 8763: m_CF = 1;
1.1 root 8764: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
8765: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 8766: m_CF = 1;
1.1 root 8767: } else {
8768: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
8769: char dev[64];
8770: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
8771:
8772: if(dpb->media_type == 0xf8) {
8773: // this drive is not a floppy
1.1.1.6 root 8774: // if(!(((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag & 0x40)) {
8775: // fatalerror("This application tried the absolute disk write to drive %c:\n", 'A' + REG8(AL));
8776: // }
1.1 root 8777: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 8778: m_CF = 1;
1.1 root 8779: } else {
8780: HANDLE hFile = CreateFile(dev, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
8781: if(hFile == INVALID_HANDLE_VALUE) {
8782: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 8783: m_CF = 1;
1.1 root 8784: } else {
1.1.1.19 root 8785: UINT32 top_sector = REG16(DX);
8786: UINT16 sector_num = REG16(CX);
8787: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
8788:
8789: if(sector_num == 0xffff) {
8790: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
8791: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
8792: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
8793: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
8794: buffer_addr = (seg << 4) + ofs;
8795: }
1.1 root 8796: if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
8797: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 8798: m_CF = 1;
1.1.1.19 root 8799: } else if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 8800: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 8801: m_CF = 1;
1.1.1.19 root 8802: } else if(WriteFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 8803: REG8(AL) = 0x0a; // write error
1.1.1.3 root 8804: m_CF = 1;
1.1 root 8805: }
8806: CloseHandle(hFile);
8807: }
8808: }
8809: }
8810: }
8811:
8812: inline void msdos_int_27h()
8813: {
1.1.1.29! root 8814: int paragraphs = (min(REG16(DX), 0xfff0) + 15) >> 4;
! 8815: try {
! 8816: msdos_mem_realloc(SREG(CS), paragraphs, NULL);
! 8817: } catch(...) {
! 8818: // recover the broken mcb
! 8819: int mcb_seg = SREG(CS) - 1;
! 8820: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
! 8821: if(mcb_seg < (MEMORY_END >> 4)) {
! 8822: if(((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked & 0x01) {
! 8823: mcb->mz = 'M';
! 8824: } else {
! 8825: mcb->mz = 'Z';
! 8826: }
! 8827: mcb->paragraphs32 = (MEMORY_END >> 4) - mcb_seg - 2;
! 8828: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', -1, (UMB_TOP >> 4) - (MEMORY_END >> 4));
! 8829: } else {
! 8830: mcb->mz = 'Z';
! 8831: mcb->paragraphs32 = (UMB_END >> 4) - mcb_seg - 1;
! 8832: }
! 8833: msdos_mem_realloc(SREG(CS), paragraphs, NULL);
! 8834: }
1.1.1.3 root 8835: msdos_process_terminate(SREG(CS), retval | 0x300, 0);
1.1 root 8836: }
8837:
8838: inline void msdos_int_29h()
8839: {
1.1.1.14 root 8840: #if 1
8841: // need to check escape sequences
1.1 root 8842: msdos_putch(REG8(AL));
1.1.1.14 root 8843: #else
8844: DWORD num;
8845: vram_flush();
1.1.1.23 root 8846: WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ®8(AL), 1, &num, NULL);
1.1.1.14 root 8847: cursor_moved = true;
8848: #endif
1.1 root 8849: }
8850:
8851: inline void msdos_int_2eh()
8852: {
8853: char tmp[MAX_PATH], command[MAX_PATH], opt[MAX_PATH];
8854: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 8855: strcpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(SI)));
1.1 root 8856: char *token = my_strtok(tmp, " ");
8857: strcpy(command, token);
8858: strcpy(opt, token + strlen(token) + 1);
8859:
8860: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
8861: param->env_seg = 0;
8862: param->cmd_line.w.l = 44;
8863: param->cmd_line.w.h = (WORK_TOP >> 4);
8864: param->fcb1.w.l = 24;
8865: param->fcb1.w.h = (WORK_TOP >> 4);
8866: param->fcb2.w.l = 24;
8867: param->fcb2.w.h = (WORK_TOP >> 4);
8868:
8869: memset(mem + WORK_TOP + 24, 0x20, 20);
8870:
8871: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
8872: cmd_line->len = strlen(opt);
8873: strcpy(cmd_line->cmd, opt);
8874: cmd_line->cmd[cmd_line->len] = 0x0d;
8875:
1.1.1.28 root 8876: try {
8877: if(msdos_process_exec(command, param, 0)) {
8878: REG16(AX) = 0xffff; // error before processing command
8879: } else {
8880: // set flag to set retval to ax when the started process is terminated
8881: process_t *process = msdos_process_info_get(current_psp);
8882: process->called_by_int2eh = true;
8883: }
8884: } catch(...) {
8885: REG16(AX) = 0xffff; // error before processing command
8886: }
1.1 root 8887: }
8888:
1.1.1.22 root 8889: inline void msdos_int_2fh_01h()
8890: {
8891: switch(REG8(AL)) {
8892: case 0x00:
1.1.1.29! root 8893: // PRINT.COM is not installed
! 8894: // REG8(AL) = 0x00;
1.1.1.22 root 8895: break;
8896: default:
8897: 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));
8898: REG16(AX) = 0x01;
8899: m_CF = 1;
8900: break;
8901: }
8902: }
8903:
1.1.1.29! root 8904: inline void msdos_int_2fh_02h()
1.1.1.22 root 8905: {
8906: switch(REG8(AL)) {
8907: case 0x00:
1.1.1.29! root 8908: // PC LAN Program Redirector is not installed
! 8909: // REG8(AL) = 0x00;
1.1.1.22 root 8910: break;
8911: default:
8912: 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));
8913: REG16(AX) = 0x01;
8914: m_CF = 1;
8915: break;
8916: }
8917: }
8918:
1.1.1.29! root 8919: inline void msdos_int_2fh_05h()
! 8920: {
! 8921: switch(REG8(AL)) {
! 8922: case 0x00:
! 8923: // Critical Error Handler is not installed
! 8924: // REG8(AL) = 0x00;
! 8925: break;
! 8926: default:
! 8927: 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));
! 8928: // error code can't be converted to string
! 8929: // REG16(AX) = 0x01;
! 8930: m_CF = 1;
! 8931: break;
! 8932: }
! 8933: }
! 8934:
1.1.1.22 root 8935: inline void msdos_int_2fh_06h()
8936: {
8937: switch(REG8(AL)) {
8938: case 0x00:
1.1.1.29! root 8939: // ASSIGN is not installed
! 8940: // REG8(AL) = 0x00;
1.1.1.22 root 8941: break;
8942: default:
8943: 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));
8944: REG16(AX) = 0x01;
8945: m_CF = 1;
8946: break;
8947: }
8948: }
8949:
8950: inline void msdos_int_2fh_08h()
8951: {
8952: switch(REG8(AL)) {
8953: case 0x00:
1.1.1.29! root 8954: // DRIVER.SYS is not installed
! 8955: // REG8(AL) = 0x00;
1.1.1.22 root 8956: break;
8957: default:
8958: 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));
8959: REG16(AX) = 0x01;
8960: m_CF = 1;
8961: break;
8962: }
8963: }
8964:
8965: inline void msdos_int_2fh_10h()
8966: {
8967: switch(REG8(AL)) {
8968: case 0x00:
1.1.1.29! root 8969: // SHARE is not installed
! 8970: // REG8(AL) = 0x00;
1.1.1.22 root 8971: break;
8972: default:
8973: 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));
8974: REG16(AX) = 0x01;
8975: m_CF = 1;
8976: break;
8977: }
8978: }
8979:
8980: inline void msdos_int_2fh_11h()
8981: {
8982: switch(REG8(AL)) {
8983: case 0x00:
1.1.1.29! root 8984: if(i386_read_stack() == 0xdada) {
! 8985: // MSCDEX is not installed
! 8986: // REG8(AL) = 0x00;
! 8987: } else {
! 8988: // Network Redirector is not installed
! 8989: // REG8(AL) = 0x00;
! 8990: }
1.1.1.22 root 8991: break;
8992: default:
8993: 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 8994: REG16(AX) = 0x49; // network software not installed
1.1.1.22 root 8995: m_CF = 1;
8996: break;
8997: }
8998: }
8999:
1.1.1.21 root 9000: inline void msdos_int_2fh_12h()
9001: {
9002: switch(REG8(AL)) {
1.1.1.22 root 9003: case 0x00:
1.1.1.29! root 9004: // DOS 3.0+ internal functions are installed
1.1.1.22 root 9005: REG8(AL) = 0xff;
9006: break;
1.1.1.29! root 9007: // case 0x01: // DOS 3.0+ internal - Close Current File
! 9008: case 0x02:
! 9009: {
! 9010: UINT16 stack = i386_read_stack();
! 9011: REG16(BX) = *(UINT16 *)(mem + 4 * stack + 0);
! 9012: SREG(ES) = *(UINT16 *)(mem + 4 * stack + 2);
! 9013: i386_load_segment_descriptor(ES);
! 9014: }
! 9015: break;
! 9016: // case 0x03: // DOS 3.0+ internal - Get DOS Data Segment
! 9017: case 0x04:
! 9018: {
! 9019: UINT16 stack = i386_read_stack();
! 9020: REG8(AL) = (stack == '/') ? '\\' : stack;
! 9021: #if defined(HAS_I386)
! 9022: m_ZF = (REG8(AL) == '\\');
! 9023: #else
! 9024: m_ZeroVal = (REG8(AL) != '\\');
! 9025: #endif
! 9026: }
! 9027: break;
! 9028: case 0x05:
! 9029: msdos_putch(i386_read_stack());
! 9030: break;
! 9031: // case 0x06: // DOS 3.0+ internal - Invole Critical Error
! 9032: // case 0x07: // DOS 3.0+ internal - Make Disk Buffer Most Recentry Used
! 9033: // case 0x08: // DOS 3.0+ internal - Decrement SFT Reference Count
! 9034: // case 0x09: // DOS 3.0+ internal - Flush and FREE Disk Buffer
! 9035: // case 0x0a: // DOS 3.0+ internal - Perform Critical Error Interrupt
! 9036: // case 0x0b: // DOS 3.0+ internal - Signal Sharing Violation to User
! 9037: // case 0x0c: // DOS 3.0+ internal - Open Device and Set SFT Owner/Mode
! 9038: case 0x0d:
! 9039: {
! 9040: SYSTEMTIME time;
! 9041: FILETIME file_time;
! 9042: WORD dos_date, dos_time;
! 9043: GetLocalTime(&time);
! 9044: SystemTimeToFileTime(&time, &file_time);
! 9045: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time);
! 9046: REG16(AX) = dos_date;
! 9047: REG16(DX) = dos_time;
! 9048: }
! 9049: break;
! 9050: // case 0x0e: // DOS 3.0+ internal - Mark All Disk Buffers Unreferenced
! 9051: // case 0x0f: // DOS 3.0+ internal - Make Buffer Most Recentry Used
! 9052: // case 0x10: // DOS 3.0+ internal - Find Unreferenced Disk Buffer
! 9053: case 0x11:
! 9054: {
! 9055: char path[MAX_PATH], *p;
! 9056: strcpy(path, (char *)(mem + SREG_BASE(DS) + REG16(SI)));
! 9057: my_strupr(path);
! 9058: while((p = my_strchr(path, '/')) != NULL) {
! 9059: *p = '\\';
! 9060: }
! 9061: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path);
! 9062: }
! 9063: break;
! 9064: case 0x12:
! 9065: REG16(CX) = strlen((char *)(mem + SREG_BASE(ES) + REG16(DI)));
! 9066: break;
! 9067: case 0x13:
! 9068: {
! 9069: char tmp[2] = {0};
! 9070: tmp[0] = i386_read_stack();
! 9071: my_strupr(tmp);
! 9072: REG8(AL) = tmp[0];
! 9073: }
! 9074: break;
! 9075: case 0x14:
! 9076: #if defined(HAS_I386)
! 9077: m_ZF = (SREG_BASE(DS) + REG16(SI) == SREG_BASE(ES) + REG16(DI));
! 9078: #else
! 9079: m_ZeroVal = (SREG_BASE(DS) + REG16(SI) != SREG_BASE(ES) + REG16(DI));
! 9080: #endif
! 9081: m_CF = (SREG_BASE(DS) + REG16(SI) != SREG_BASE(ES) + REG16(DI));
! 9082: break;
! 9083: // case 0x15: // DOS 3.0+ internal - Flush Buffer
1.1.1.21 root 9084: case 0x16:
9085: if(REG16(BX) < 20) {
9086: SREG(ES) = SFT_TOP >> 4;
9087: i386_load_segment_descriptor(ES);
9088: REG16(DI) = 6 + 0x3b * REG16(BX);
9089:
9090: // update system file table
9091: UINT8* sft = mem + SFT_TOP + 6 + 0x3b * REG16(BX);
9092: if(file_handler[REG16(BX)].valid) {
9093: int count = 0;
9094: for(int i = 0; i < 20; i++) {
9095: if(msdos_psp_get_file_table(i, current_psp) == REG16(BX)) {
9096: count++;
9097: }
9098: }
9099: *(UINT16 *)(sft + 0x00) = count ? count : 0xffff;
9100: *(UINT32 *)(sft + 0x15) = _tell(REG16(BX));
9101: _lseek(REG16(BX), 0, SEEK_END);
9102: *(UINT32 *)(sft + 0x11) = _tell(REG16(BX));
9103: _lseek(REG16(BX), *(UINT32 *)(sft + 0x15), SEEK_SET);
9104: } else {
9105: memset(sft, 0, 0x3b);
9106: }
9107: } else {
9108: REG16(AX) = 0x06;
9109: m_CF = 1;
9110: }
9111: break;
1.1.1.29! root 9112: // case 0x17: // DOS 3.0+ internal - Get Current Directory Structure for Drive
! 9113: // case 0x18: // DOS 3.0+ internal - Get Caller's Registers
! 9114: // case 0x19: // DOS 3.0+ internal - Set Drive???
! 9115: case 0x1a:
! 9116: {
! 9117: char *path = (char *)(mem + SREG_BASE(DS) + REG16(SI)), full[MAX_PATH];
! 9118: if(path[1] == ':') {
! 9119: if(path[0] >= 'a' && path[0] <= 'z') {
! 9120: REG8(AL) = path[0] - 'a' + 1;
! 9121: } else if(path[0] >= 'A' && path[0] <= 'Z') {
! 9122: REG8(AL) = path[0] - 'A' + 1;
! 9123: } else {
! 9124: REG8(AL) = 0xff; // invalid
! 9125: }
! 9126: strcpy(full, path);
! 9127: strcpy(path, full + 2);
! 9128: } else if(GetFullPathName(path, MAX_PATH, full, NULL) != 0 && full[1] == ':') {
! 9129: if(full[0] >= 'a' && full[0] <= 'z') {
! 9130: REG8(AL) = full[0] - 'a' + 1;
! 9131: } else if(full[0] >= 'A' && full[0] <= 'Z') {
! 9132: REG8(AL) = full[0] - 'A' + 1;
! 9133: } else {
! 9134: REG8(AL) = 0xff; // invalid
! 9135: }
! 9136: } else {
! 9137: REG8(AL) = 0x00; // default
! 9138: }
! 9139: }
! 9140: break;
! 9141: case 0x1b:
! 9142: {
! 9143: int year = REG16(CX) + 1980;
! 9144: REG8(AL) = ((year % 4) == 0 && (year % 100) != 0 && (year % 400) == 0) ? 29 : 28;
! 9145: }
! 9146: break;
! 9147: // case 0x1c: // DOS 3.0+ internal - Check Sum Memory
! 9148: // case 0x1d: // DOS 3.0+ internal - Sum Memory
! 9149: case 0x1e:
! 9150: {
! 9151: char *path_1st = (char *)(mem + SREG_BASE(DS) + REG16(SI)), full_1st[MAX_PATH];
! 9152: char *path_2nd = (char *)(mem + SREG_BASE(ES) + REG16(DI)), full_2nd[MAX_PATH];
! 9153: if(GetFullPathName(path_1st, MAX_PATH, full_1st, NULL) != 0 && GetFullPathName(path_2nd, MAX_PATH, full_2nd, NULL) != 0) {
! 9154: #if defined(HAS_I386)
! 9155: m_ZF = (strcmp(full_1st, full_2nd) == 0);
! 9156: #else
! 9157: m_ZeroVal = (strcmp(full_1st, full_2nd) != 0);
! 9158: #endif
! 9159: } else {
! 9160: #if defined(HAS_I386)
! 9161: m_ZF = (strcmp(path_1st, path_2nd) == 0);
! 9162: #else
! 9163: m_ZeroVal = (strcmp(path_1st, path_2nd) != 0);
! 9164: #endif
! 9165: }
! 9166: }
! 9167: break;
! 9168: // case 0x1f: // DOS 3.0+ internal - Build Current Directory Structure
1.1.1.21 root 9169: case 0x20:
9170: {
9171: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
9172:
9173: if(fd < 20) {
9174: SREG(ES) = current_psp;
9175: i386_load_segment_descriptor(ES);
9176: REG16(DI) = offsetof(psp_t, file_table) + fd;
9177: } else {
9178: REG16(AX) = 0x06;
9179: m_CF = 1;
9180: }
9181: }
9182: break;
1.1.1.29! root 9183: case 0x21:
! 9184: msdos_int_21h_60h(0);
! 9185: break;
! 9186: // case 0x22: // DOS 3.0+ internal - Set Extended Error Info
! 9187: // case 0x23: // DOS 3.0+ internal - Check If Character Device
! 9188: // case 0x24: // DOS 3.0+ internal - Sharing Retry Delay
! 9189: case 0x25:
! 9190: REG16(CX) = strlen((char *)(mem + SREG_BASE(DS) + REG16(SI)));
! 9191: break;
! 9192: case 0x26:
! 9193: REG8(AL) = REG8(CL);
! 9194: msdos_int_21h_3dh();
! 9195: break;
! 9196: case 0x27:
! 9197: msdos_int_21h_3eh();
! 9198: break;
! 9199: case 0x28:
! 9200: REG16(AX) = REG16(BP);
! 9201: msdos_int_21h_42h();
! 9202: break;
! 9203: case 0x29:
! 9204: msdos_int_21h_3fh();
! 9205: break;
! 9206: // case 0x2a: // DOS 3.0+ internal - Set Fast Open Entry Point
! 9207: case 0x2b:
! 9208: REG16(AX) = REG16(BP);
! 9209: msdos_int_21h_44h();
! 9210: break;
! 9211: case 0x2c:
! 9212: REG16(BX) = DEVICE_TOP >> 4;
! 9213: REG16(AX) = 22;
! 9214: break;
! 9215: case 0x2d:
! 9216: {
! 9217: sda_t *sda = (sda_t *)(mem + SDA_TOP);
! 9218: REG16(AX) = sda->extended_error_code;
! 9219: }
! 9220: break;
! 9221: case 0x2e:
! 9222: if(REG8(DL) == 0x00 || REG8(DL) == 0x02 || REG8(DL) == 0x04 || REG8(DL) == 0x06) {
! 9223: SREG(ES) = ERR_TABLE_TOP >> 4;
1.1.1.22 root 9224: i386_load_segment_descriptor(ES);
9225: REG16(DI) = 0;
9226: }
9227: break;
1.1.1.29! root 9228: case 0x2f:
! 9229: if(REG16(DX) != 0) {
! 9230: major_version = REG8(DL);
! 9231: minor_version = REG8(DH);
! 9232: } else {
! 9233: REG8(DL) = 7;
! 9234: REG8(DH) = 10;
! 9235: }
! 9236: break;
! 9237: // case 0x30: // Windows95 - Find SFT Entry in Internal File Tables
! 9238: // case 0x31: // Windows95 - Set/Clear "Report Windows to DOS Programs" Flag
1.1.1.22 root 9239: default:
9240: 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));
9241: REG16(AX) = 0x01;
9242: m_CF = 1;
9243: break;
9244: }
9245: }
9246:
9247: inline void msdos_int_2fh_14h()
9248: {
9249: switch(REG8(AL)) {
9250: case 0x00:
1.1.1.29! root 9251: // NLSFUNC.COM is installed
! 9252: REG8(AL) = 0xff;
1.1.1.25 root 9253: break;
9254: case 0x01:
9255: case 0x03:
9256: REG8(AL) = 0x00;
9257: active_code_page = REG16(BX);
9258: msdos_nls_tables_update();
9259: break;
9260: case 0x02:
9261: REG8(AL) = get_extended_country_info(REG16(BP));
9262: break;
9263: case 0x04:
9264: REG8(AL) = 0x00;
9265: get_country_info((country_info_t *)(mem + SREG_BASE(ES) + REG16(DI)));
1.1.1.22 root 9266: break;
9267: default:
9268: 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));
9269: REG16(AX) = 0x01;
9270: m_CF = 1;
9271: break;
9272: }
9273: }
9274:
9275: inline void msdos_int_2fh_15h()
9276: {
9277: switch(REG8(AL)) {
1.1.1.29! root 9278: case 0x00: // CD-ROM - Installation Check
! 9279: if(REG16(BX) == 0x0000) {
! 9280: // MSCDEX is not installed
! 9281: // REG8(AL) = 0x00;
! 9282: } else {
! 9283: // GRAPHICS.COM is not installed
! 9284: // REG8(AL) = 0x00;
! 9285: }
1.1.1.22 root 9286: break;
9287: case 0xff:
1.1.1.29! root 9288: if(REG16(BX) == 0x0000) {
! 9289: // CORELCDX is not installed
! 9290: } else {
! 9291: 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));
! 9292: REG16(AX) = 0x01;
! 9293: m_CF = 1;
! 9294: }
1.1.1.22 root 9295: break;
1.1.1.21 root 9296: default:
1.1.1.22 root 9297: 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 9298: REG16(AX) = 0x01;
9299: m_CF = 1;
9300: break;
9301: }
9302: }
9303:
1.1 root 9304: inline void msdos_int_2fh_16h()
9305: {
9306: switch(REG8(AL)) {
9307: case 0x00:
1.1.1.14 root 9308: if(no_windows) {
1.1.1.29! root 9309: // neither Windows 3.x enhanced mode nor Windows/386 2.x running
! 9310: // REG8(AL) = 0x00;
1.1.1.14 root 9311: } else {
1.1 root 9312: OSVERSIONINFO osvi;
9313: ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
9314: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
9315: GetVersionEx(&osvi);
9316: REG8(AL) = osvi.dwMajorVersion;
9317: REG8(AH) = osvi.dwMinorVersion;
9318: }
9319: break;
1.1.1.22 root 9320: case 0x0a:
9321: if(!no_windows) {
9322: OSVERSIONINFO osvi;
9323: ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
9324: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
9325: GetVersionEx(&osvi);
9326: REG16(AX) = 0x0000;
9327: REG8(BH) = osvi.dwMajorVersion;
9328: REG8(BL) = osvi.dwMinorVersion;
9329: REG16(CX) = 0x0003; // enhanced
9330: }
9331: break;
9332: case 0x0e:
9333: case 0x0f:
9334: case 0x11:
9335: case 0x12:
9336: case 0x13:
9337: case 0x14:
9338: case 0x87:
9339: // function not supported, do not clear AX
9340: break;
1.1.1.14 root 9341: case 0x80:
9342: Sleep(10);
9343: hardware_update();
1.1.1.29! root 9344: REG8(AL) = 0x00;
1.1.1.14 root 9345: break;
1.1.1.22 root 9346: case 0x8e:
9347: REG16(AX) = 0x00; // failed
9348: break;
1.1.1.20 root 9349: case 0x8f:
9350: switch(REG8(DH)) {
9351: case 0x00:
9352: case 0x02:
9353: case 0x03:
9354: REG16(AX) = 0x00;
9355: break;
9356: case 0x01:
9357: REG16(AX) = 0x168f;
9358: break;
9359: }
9360: break;
1.1 root 9361: default:
1.1.1.22 root 9362: 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));
9363: REG16(AX) = 0x01;
9364: m_CF = 1;
9365: break;
9366: }
9367: }
9368:
1.1.1.29! root 9369: inline void msdos_int_2fh_17h()
! 9370: {
! 9371: switch(REG8(AL)) {
! 9372: case 0x00:
! 9373: // Clibboard functions are not supported
! 9374: // REG8(AL) = 0x00;
! 9375: break;
! 9376: default:
! 9377: 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));
! 9378: REG16(AX) = 0x01;
! 9379: m_CF = 1;
! 9380: break;
! 9381: }
! 9382: }
! 9383:
1.1.1.22 root 9384: inline void msdos_int_2fh_19h()
9385: {
9386: switch(REG8(AL)) {
9387: case 0x00:
1.1.1.29! root 9388: // SHELLB.COM is not installed
! 9389: // REG8(AL) = 0x00;
1.1.1.22 root 9390: break;
9391: case 0x01:
9392: case 0x02:
9393: case 0x03:
9394: case 0x04:
9395: REG16(AX) = 0x01;
9396: m_CF = 1;
9397: break;
1.1.1.29! root 9398: case 0x80:
! 9399: // IBM ROM-DOS v4.0 is not installed
! 9400: // REG8(AL) = 0x00;
! 9401: break;
1.1.1.22 root 9402: default:
9403: 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 9404: REG16(AX) = 0x01;
1.1.1.3 root 9405: m_CF = 1;
1.1 root 9406: break;
9407: }
9408: }
9409:
9410: inline void msdos_int_2fh_1ah()
9411: {
9412: switch(REG8(AL)) {
9413: case 0x00:
1.1.1.29! root 9414: // ANSI.SYS is installed
1.1 root 9415: REG8(AL) = 0xff;
9416: break;
9417: default:
1.1.1.22 root 9418: 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));
9419: REG16(AX) = 0x01;
9420: m_CF = 1;
9421: break;
9422: }
9423: }
9424:
9425: inline void msdos_int_2fh_1bh()
9426: {
9427: switch(REG8(AL)) {
9428: case 0x00:
1.1.1.29! root 9429: // XMA2EMS.SYS is not installed
! 9430: // REG8(AL) = 0x00;
! 9431: break;
! 9432: default:
! 9433: 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));
! 9434: REG16(AX) = 0x01;
! 9435: m_CF = 1;
! 9436: break;
! 9437: }
! 9438: }
! 9439:
! 9440: inline void msdos_int_2fh_27h()
! 9441: {
! 9442: switch(REG8(AL)) {
! 9443: case 0x00:
! 9444: // DR-DOR 6.0 TaskMAX is not installed
! 9445: // REG8(AL) = 0x00;
! 9446: break;
! 9447: default:
! 9448: 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));
! 9449: REG16(AX) = 0x01;
! 9450: m_CF = 1;
! 9451: break;
! 9452: }
! 9453: }
! 9454:
! 9455: inline void msdos_int_2fh_2eh()
! 9456: {
! 9457: switch(REG8(AL)) {
! 9458: case 0x00:
! 9459: // Novell DOS 7 GRAFTABL is not installed
! 9460: // REG8(AL) = 0x00;
1.1.1.22 root 9461: break;
9462: default:
9463: 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 9464: REG16(AX) = 0x01;
1.1.1.3 root 9465: m_CF = 1;
1.1 root 9466: break;
9467: }
9468: }
9469:
9470: inline void msdos_int_2fh_43h()
9471: {
9472: switch(REG8(AL)) {
9473: case 0x00:
1.1.1.29! root 9474: // XMS is installed ?
1.1.1.19 root 9475: #ifdef SUPPORT_XMS
9476: if(support_xms) {
9477: REG8(AL) = 0x80;
9478: } else
9479: #endif
9480: REG8(AL) = 0x00;
9481: break;
9482: case 0x10:
9483: SREG(ES) = XMS_TOP >> 4;
9484: i386_load_segment_descriptor(ES);
1.1.1.26 root 9485: REG16(BX) = 0x15;
1.1 root 9486: break;
9487: default:
1.1.1.22 root 9488: 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));
9489: REG16(AX) = 0x01;
9490: m_CF = 1;
9491: break;
9492: }
9493: }
9494:
1.1.1.29! root 9495: inline void msdos_int_2fh_45h()
! 9496: {
! 9497: switch(REG8(AL)) {
! 9498: case 0x00:
! 9499: // PROF.COM is not installed
! 9500: // REG8(AL) = 0x00;
! 9501: break;
! 9502: default:
! 9503: 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));
! 9504: REG16(AX) = 0x01;
! 9505: m_CF = 1;
! 9506: break;
! 9507: }
! 9508: }
! 9509:
1.1.1.22 root 9510: inline void msdos_int_2fh_46h()
9511: {
9512: switch(REG8(AL)) {
9513: case 0x80:
1.1.1.29! root 9514: // Windows v3.0 is not installed
! 9515: // REG8(AL) = 0x00;
1.1.1.22 root 9516: break;
9517: default:
9518: 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));
9519: REG16(AX) = 0x01;
9520: m_CF = 1;
9521: break;
9522: }
9523: }
9524:
9525: inline void msdos_int_2fh_48h()
9526: {
9527: switch(REG8(AL)) {
9528: case 0x00:
1.1.1.29! root 9529: // DOSKEY is not installed
! 9530: // REG8(AL) = 0x00;
1.1.1.22 root 9531: break;
9532: case 0x10:
9533: msdos_int_21h_0ah();
9534: REG16(AX) = 0x00;
9535: break;
9536: default:
9537: 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 9538: REG16(AX) = 0x01;
1.1.1.3 root 9539: m_CF = 1;
1.1 root 9540: break;
9541: }
9542: }
9543:
9544: inline void msdos_int_2fh_4ah()
9545: {
9546: switch(REG8(AL)) {
1.1.1.29! root 9547: #ifdef SUPPORT_HMA
! 9548: case 0x01: // DOS 5.0+ - Query Free HMA Space
! 9549: if(!is_hma_used_by_xms && !is_hma_used_by_int_2fh) {
! 9550: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
! 9551: // restore first free mcb in high memory area
! 9552: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
! 9553: }
! 9554: int offset = 0xffff;
! 9555: if((REG16(BX) = msdos_hma_mem_get_free(&offset)) != 0) {
! 9556: REG16(DI) = offset + 0x10;
! 9557: } else {
! 9558: REG16(DI) = 0xffff;
! 9559: }
! 9560: } else {
! 9561: // HMA is already used
! 9562: REG16(BX) = 0;
! 9563: REG16(DI) = 0xffff;
! 9564: }
! 9565: SREG(ES) = 0xffff;
! 9566: i386_load_segment_descriptor(ES);
! 9567: break;
! 9568: case 0x02: // DOS 5.0+ - Allocate HMA Space
! 9569: if(!is_hma_used_by_xms && !is_hma_used_by_int_2fh) {
! 9570: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
! 9571: // restore first free mcb in high memory area
! 9572: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
! 9573: }
! 9574: int size = REG16(BX), offset;
! 9575: if((size % 16) != 0) {
! 9576: size &= ~15;
! 9577: size += 16;
! 9578: }
! 9579: if((offset = msdos_hma_mem_alloc(size, current_psp)) != -1) {
! 9580: REG16(BX) = size;
! 9581: REG16(DI) = offset + 0x10;
! 9582: is_hma_used_by_int_2fh = true;
! 9583: } else {
! 9584: REG16(BX) = 0;
! 9585: REG16(DI) = 0xffff;
! 9586: }
! 9587: } else {
! 9588: // HMA is already used
! 9589: REG16(BX) = 0;
! 9590: REG16(DI) = 0xffff;
! 9591: }
! 9592: SREG(ES) = 0xffff;
! 9593: i386_load_segment_descriptor(ES);
! 9594: break;
! 9595: case 0x03: // Windows95 - (De)Allocate HMA Memory Block
! 9596: if(REG8(DL) == 0x00) {
! 9597: if(!is_hma_used_by_xms) {
! 9598: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
! 9599: // restore first free mcb in high memory area
! 9600: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
! 9601: is_hma_used_by_int_2fh = false;
! 9602: }
! 9603: int size = REG16(BX), offset;
! 9604: if((size % 16) != 0) {
! 9605: size &= ~15;
! 9606: size += 16;
! 9607: }
! 9608: if((offset = msdos_hma_mem_alloc(size, REG16(CX))) != -1) {
! 9609: // REG16(BX) = size;
! 9610: SREG(ES) = 0xffff;
! 9611: i386_load_segment_descriptor(ES);
! 9612: REG16(DI) = offset + 0x10;
! 9613: is_hma_used_by_int_2fh = true;
! 9614: } else {
! 9615: REG16(DI) = 0xffff;
! 9616: }
! 9617: } else {
! 9618: REG16(DI) = 0xffff;
! 9619: }
! 9620: } else if(REG8(DL) == 0x01) {
! 9621: if(!is_hma_used_by_xms) {
! 9622: int size = REG16(BX);
! 9623: if((size % 16) != 0) {
! 9624: size &= ~15;
! 9625: size += 16;
! 9626: }
! 9627: if(msdos_hma_mem_realloc(SREG_BASE(ES) + REG16(DI) - 0xffff0 - 0x10, size) != -1) {
! 9628: // memory block address is not changed
! 9629: } else {
! 9630: REG16(DI) = 0xffff;
! 9631: }
! 9632: } else {
! 9633: REG16(DI) = 0xffff;
! 9634: }
! 9635: } else if(REG8(DL) == 0x02) {
! 9636: if(!is_hma_used_by_xms) {
! 9637: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
! 9638: // restore first free mcb in high memory area
! 9639: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
! 9640: is_hma_used_by_int_2fh = false;
! 9641: } else {
! 9642: msdos_hma_mem_free(SREG_BASE(ES) + REG16(DI) - 0xffff0 - 0x10);
! 9643: if(msdos_hma_mem_get_free(NULL) == 0xffe0) {
! 9644: is_hma_used_by_int_2fh = false;
! 9645: }
! 9646: }
! 9647: }
! 9648: } else {
! 9649: 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));
! 9650: REG16(AX) = 0x01;
! 9651: m_CF = 1;
! 9652: }
! 9653: break;
! 9654: case 0x04: // Windows95 - Get Start of HMA Memory Chain
! 9655: if(!is_hma_used_by_xms) {
! 9656: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
! 9657: // restore first free mcb in high memory area
! 9658: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
! 9659: is_hma_used_by_int_2fh = false;
! 9660: }
! 9661: REG16(AX) = 0x0000;
! 9662: SREG(ES) = 0xffff;
! 9663: i386_load_segment_descriptor(ES);
! 9664: REG16(DI) = 0x10;
! 9665: }
! 9666: break;
! 9667: #else
1.1 root 9668: case 0x01:
9669: case 0x02:
1.1.1.29! root 9670: // HMA is already used
1.1.1.27 root 9671: REG16(BX) = 0x0000;
1.1.1.3 root 9672: SREG(ES) = 0xffff;
9673: i386_load_segment_descriptor(ES);
1.1 root 9674: REG16(DI) = 0xffff;
9675: break;
1.1.1.19 root 9676: case 0x03:
9677: // unable to allocate
9678: REG16(DI) = 0xffff;
9679: break;
9680: case 0x04:
9681: // function not supported, do not clear AX
9682: break;
1.1.1.29! root 9683: #endif
! 9684: case 0x10:
! 9685: if(REG16(BX) == 0x0000) {
! 9686: // SMARTDRV is not installed
! 9687: } else {
! 9688: 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));
! 9689: REG16(AX) = 0x01;
! 9690: m_CF = 1;
! 9691: }
! 9692: break;
! 9693: case 0x11:
! 9694: if(REG16(BX) == 0x0000) {
! 9695: // DBLSPACE.BIN is not installed
! 9696: } else {
! 9697: 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));
! 9698: REG16(AX) = 0x01;
! 9699: m_CF = 1;
! 9700: }
1.1.1.22 root 9701: break;
9702: default:
9703: 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));
9704: REG16(AX) = 0x01;
9705: m_CF = 1;
9706: break;
9707: }
9708: }
9709:
9710: inline void msdos_int_2fh_4bh()
9711: {
9712: switch(REG8(AL)) {
1.1.1.24 root 9713: case 0x01:
1.1.1.22 root 9714: case 0x02:
1.1.1.29! root 9715: // Task Switcher is not installed
1.1.1.24 root 9716: break;
9717: case 0x03:
9718: // this call is available from within DOSSHELL even if the task switcher is not installed
9719: REG16(AX) = REG16(BX) = 0x0000; // no more avaiable switcher id
1.1.1.22 root 9720: break;
1.1 root 9721: default:
1.1.1.22 root 9722: 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 9723: REG16(AX) = 0x01;
1.1.1.3 root 9724: m_CF = 1;
1.1 root 9725: break;
9726: }
9727: }
9728:
9729: inline void msdos_int_2fh_4fh()
9730: {
9731: switch(REG8(AL)) {
9732: case 0x00:
1.1.1.29! root 9733: // BILING is installed
1.1.1.27 root 9734: REG16(AX) = 0x0000;
9735: REG8(DL) = 0x01; // major version
9736: REG8(DH) = 0x00; // minor version
1.1 root 9737: break;
9738: case 0x01:
1.1.1.27 root 9739: REG16(AX) = 0x0000;
1.1 root 9740: REG16(BX) = active_code_page;
9741: break;
9742: default:
1.1.1.22 root 9743: 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));
9744: REG16(AX) = 0x01;
9745: m_CF = 1;
9746: break;
9747: }
9748: }
9749:
1.1.1.29! root 9750: inline void msdos_int_2fh_54h()
! 9751: {
! 9752: switch(REG8(AL)) {
! 9753: case 0x00:
! 9754: // POWER.EXE is not installed
! 9755: // REG8(AL) = 0x00;
! 9756: break;
! 9757: default:
! 9758: 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));
! 9759: REG16(AX) = 0x01;
! 9760: m_CF = 1;
! 9761: break;
! 9762: }
! 9763: }
! 9764:
1.1.1.22 root 9765: inline void msdos_int_2fh_55h()
9766: {
9767: switch(REG8(AL)) {
9768: case 0x00:
9769: case 0x01:
9770: // 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));
9771: break;
9772: default:
9773: 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 9774: REG16(AX) = 0x01;
1.1.1.3 root 9775: m_CF = 1;
1.1 root 9776: break;
9777: }
9778: }
9779:
1.1.1.29! root 9780: inline void msdos_int_2fh_56h()
! 9781: {
! 9782: switch(REG8(AL)) {
! 9783: case 0x00:
! 9784: // INTERLNK is not installed
! 9785: // REG8(AL) = 0x00;
! 9786: break;
! 9787: default:
! 9788: 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));
! 9789: REG16(AX) = 0x01;
! 9790: m_CF = 1;
! 9791: break;
! 9792: }
! 9793: }
! 9794:
! 9795: inline void msdos_int_2fh_ach()
! 9796: {
! 9797: switch(REG8(AL)) {
! 9798: case 0x00:
! 9799: // GRAPHICS.COM is not installed
! 9800: // REG8(AL) = 0x00;
! 9801: break;
! 9802: default:
! 9803: 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));
! 9804: REG16(AX) = 0x01;
! 9805: m_CF = 1;
! 9806: break;
! 9807: }
! 9808: }
! 9809:
1.1.1.24 root 9810: inline void msdos_int_2fh_adh()
9811: {
9812: switch(REG8(AL)) {
9813: case 0x00:
1.1.1.29! root 9814: // DISPLAY.SYS is installed
1.1.1.24 root 9815: REG8(AL) = 0xff;
9816: REG16(BX) = 0x100; // ???
9817: break;
9818: case 0x01:
9819: active_code_page = REG16(BX);
9820: msdos_nls_tables_update();
9821: REG16(AX) = 0x01;
9822: break;
9823: case 0x02:
9824: REG16(BX) = active_code_page;
9825: break;
9826: case 0x03:
9827: // FIXME
9828: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 1;
9829: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2) = 3;
9830: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4) = 1;
9831: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 6) = active_code_page;
9832: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 8) = active_code_page;
9833: break;
9834: case 0x80:
9835: break; // keyb.com is not installed
9836: default:
9837: 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));
9838: REG16(AX) = 0x01;
9839: m_CF = 1;
9840: break;
9841: }
9842: }
9843:
1.1 root 9844: inline void msdos_int_2fh_aeh()
9845: {
9846: switch(REG8(AL)) {
9847: case 0x00:
1.1.1.28 root 9848: // FIXME: we need to check the given command line
9849: REG8(AL) = 0x00; // the command should be executed as usual
9850: // REG8(AL) = 0xff; // this command is a TSR extension to COMMAND.COM
1.1 root 9851: break;
9852: case 0x01:
9853: {
9854: char command[MAX_PATH];
9855: memset(command, 0, sizeof(command));
1.1.1.3 root 9856: memcpy(command, mem + SREG_BASE(DS) + REG16(SI) + 1, mem[SREG_BASE(DS) + REG16(SI)]);
1.1 root 9857:
9858: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
9859: param->env_seg = 0;
9860: param->cmd_line.w.l = 44;
9861: param->cmd_line.w.h = (WORK_TOP >> 4);
9862: param->fcb1.w.l = 24;
9863: param->fcb1.w.h = (WORK_TOP >> 4);
9864: param->fcb2.w.l = 24;
9865: param->fcb2.w.h = (WORK_TOP >> 4);
9866:
9867: memset(mem + WORK_TOP + 24, 0x20, 20);
9868:
9869: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
1.1.1.3 root 9870: cmd_line->len = mem[SREG_BASE(DS) + REG16(BX) + 1];
9871: memcpy(cmd_line->cmd, mem + SREG_BASE(DS) + REG16(BX) + 2, cmd_line->len);
1.1 root 9872: cmd_line->cmd[cmd_line->len] = 0x0d;
9873:
1.1.1.28 root 9874: try {
9875: msdos_process_exec(command, param, 0);
9876: } catch(...) {
9877: fatalerror("failed to start '%s' by int 2Fh, AX=AE01h\n", command);
1.1 root 9878: }
9879: }
9880: break;
9881: default:
1.1.1.22 root 9882: 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 9883: REG16(AX) = 0x01;
1.1.1.3 root 9884: m_CF = 1;
1.1 root 9885: break;
9886: }
9887: }
9888:
1.1.1.29! root 9889: inline void msdos_int_2fh_b0h()
! 9890: {
! 9891: switch(REG8(AL)) {
! 9892: case 0x00:
! 9893: // GRAFTABLE.COM is not installed
! 9894: // REG8(AL) = 0x00;
! 9895: break;
! 9896: default:
! 9897: 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));
! 9898: REG16(AX) = 0x01;
! 9899: m_CF = 1;
! 9900: break;
! 9901: }
! 9902: }
! 9903:
1.1 root 9904: inline void msdos_int_2fh_b7h()
9905: {
9906: switch(REG8(AL)) {
9907: case 0x00:
9908: // append is not installed
1.1.1.29! root 9909: // REG8(AL) = 0x00;
1.1 root 9910: break;
1.1.1.22 root 9911: case 0x07:
9912: case 0x11:
9913: break;
1.1 root 9914: default:
1.1.1.22 root 9915: 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 9916: REG16(AX) = 0x01;
1.1.1.3 root 9917: m_CF = 1;
1.1 root 9918: break;
9919: }
9920: }
9921:
1.1.1.29! root 9922: inline void msdos_int_2fh_b8h()
! 9923: {
! 9924: switch(REG8(AL)) {
! 9925: case 0x00:
! 9926: // network is not installed
! 9927: // REG8(AL) = 0x00;
! 9928: break;
! 9929: default:
! 9930: 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));
! 9931: REG16(AX) = 0x01;
! 9932: m_CF = 1;
! 9933: break;
! 9934: }
! 9935: }
! 9936:
! 9937: inline void msdos_int_2fh_b9h()
! 9938: {
! 9939: switch(REG8(AL)) {
! 9940: case 0x00:
! 9941: // RECEIVER.COM is not installed
! 9942: // REG8(AL) = 0x00;
! 9943: break;
! 9944: default:
! 9945: 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));
! 9946: REG16(AX) = 0x01;
! 9947: m_CF = 1;
! 9948: break;
! 9949: }
! 9950: }
! 9951:
! 9952: inline void msdos_int_2fh_bch()
! 9953: {
! 9954: switch(REG8(AL)) {
! 9955: case 0x00:
! 9956: // EGA.SYS is not installed
! 9957: // REG8(AL) = 0x00;
! 9958: break;
! 9959: default:
! 9960: 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));
! 9961: REG16(AX) = 0x01;
! 9962: m_CF = 1;
! 9963: break;
! 9964: }
! 9965: }
! 9966:
1.1.1.24 root 9967: inline void msdos_int_33h_0000h()
9968: {
9969: REG16(AX) = 0xffff; // hardware/driver installed
9970: REG16(BX) = MAX_MOUSE_BUTTONS;
9971: }
9972:
9973: inline void msdos_int_33h_0001h()
9974: {
9975: if(!mouse.active) {
9976: if(!(dwConsoleMode & ENABLE_MOUSE_INPUT)) {
9977: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode | ENABLE_MOUSE_INPUT);
9978: }
9979: mouse.active = true;
9980: pic[1].imr &= ~0x10; // enable irq12
9981: }
9982: }
9983:
9984: inline void msdos_int_33h_0002h()
9985: {
9986: if(mouse.active) {
9987: if(!(dwConsoleMode & ENABLE_MOUSE_INPUT)) {
9988: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode);
9989: }
9990: mouse.active = false;
9991: pic[1].imr |= 0x10; // disable irq12
9992: }
9993: }
9994:
9995: inline void msdos_int_33h_0003h()
9996: {
9997: REG16(BX) = mouse.get_buttons();
9998: REG16(CX) = max(mouse.min_position.x, min(mouse.max_position.x, mouse.position.x));
9999: REG16(DX) = max(mouse.min_position.y, min(mouse.max_position.y, mouse.position.y));
10000: }
10001:
10002: inline void msdos_int_33h_0005h()
10003: {
10004: if(REG16(BX) < MAX_MOUSE_BUTTONS) {
10005: int idx = REG16(BX);
10006: REG16(BX) = mouse.buttons[idx].pressed_times;
10007: REG16(CX) = max(mouse.min_position.x, min(mouse.max_position.x, mouse.buttons[idx].pressed_position.x));
10008: REG16(DX) = max(mouse.min_position.y, min(mouse.max_position.y, mouse.buttons[idx].pressed_position.y));
10009: mouse.buttons[idx].pressed_times = 0;
10010: } else {
10011: REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
10012: }
10013: REG16(AX) = mouse.get_buttons();
10014: }
10015:
10016: inline void msdos_int_33h_0006h()
10017: {
10018: if(REG16(BX) < MAX_MOUSE_BUTTONS) {
10019: int idx = REG16(BX);
10020: REG16(BX) = mouse.buttons[idx].released_times;
10021: REG16(CX) = max(mouse.min_position.x, min(mouse.max_position.x, mouse.buttons[idx].released_position.x));
10022: REG16(DX) = max(mouse.min_position.y, min(mouse.max_position.y, mouse.buttons[idx].released_position.y));
10023: mouse.buttons[idx].released_times = 0;
10024: } else {
10025: REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
10026: }
10027: REG16(AX) = mouse.get_buttons();
10028: }
10029:
10030: inline void msdos_int_33h_0007h()
10031: {
10032: mouse.min_position.x = min(REG16(CX), REG16(DX));
10033: mouse.max_position.x = max(REG16(CX), REG16(DX));
10034: }
10035:
10036: inline void msdos_int_33h_0008h()
10037: {
10038: mouse.min_position.y = min(REG16(CX), REG16(DX));
10039: mouse.max_position.y = max(REG16(CX), REG16(DX));
10040: }
10041:
10042: inline void msdos_int_33h_0009h()
10043: {
10044: mouse.hot_spot[0] = REG16(BX);
10045: mouse.hot_spot[1] = REG16(CX);
10046: }
10047:
10048: inline void msdos_int_33h_000bh()
10049: {
10050: int dx = (mouse.position.x - mouse.prev_position.x) * mouse.mickey.x / 8;
10051: int dy = (mouse.position.y - mouse.prev_position.y) * mouse.mickey.y / 8;
10052: mouse.prev_position.x = mouse.position.x;
10053: mouse.prev_position.y = mouse.position.y;
10054: REG16(CX) = dx;
10055: REG16(DX) = dy;
10056: }
10057:
10058: inline void msdos_int_33h_000ch()
10059: {
10060: mouse.call_mask = REG16(CX);
10061: mouse.call_addr.w.l = REG16(DX);
10062: mouse.call_addr.w.h = SREG(ES);
10063: }
10064:
10065: inline void msdos_int_33h_000fh()
10066: {
10067: mouse.mickey.x = REG16(CX);
10068: mouse.mickey.y = REG16(DX);
10069: }
10070:
10071: inline void msdos_int_33h_0011h()
10072: {
10073: REG16(AX) = 0xffff;
10074: REG16(BX) = MAX_MOUSE_BUTTONS;
10075: }
10076:
10077: inline void msdos_int_33h_0014h()
10078: {
10079: UINT16 old_mask = mouse.call_mask;
10080: UINT16 old_ofs = mouse.call_addr.w.l;
10081: UINT16 old_seg = mouse.call_addr.w.h;
10082:
10083: mouse.call_mask = REG16(CX);
10084: mouse.call_addr.w.l = REG16(DX);
10085: mouse.call_addr.w.h = SREG(ES);
10086:
10087: REG16(CX) = old_mask;
10088: REG16(DX) = old_ofs;
10089: SREG(ES) = old_seg;
10090: i386_load_segment_descriptor(ES);
10091: }
10092:
10093: inline void msdos_int_33h_0015h()
10094: {
10095: REG16(BX) = sizeof(mouse);
10096: }
10097:
10098: inline void msdos_int_33h_0016h()
10099: {
10100: memcpy(mem + SREG_BASE(ES) + REG16(DX), &mouse, sizeof(mouse));
10101: }
10102:
10103: inline void msdos_int_33h_0017h()
10104: {
10105: memcpy(&mouse, mem + SREG_BASE(ES) + REG16(DX), sizeof(mouse));
10106: }
10107:
10108: inline void msdos_int_33h_001ah()
10109: {
10110: mouse.sensitivity[0] = REG16(BX);
10111: mouse.sensitivity[1] = REG16(CX);
10112: mouse.sensitivity[2] = REG16(DX);
10113: }
10114:
10115: inline void msdos_int_33h_001bh()
10116: {
10117: REG16(BX) = mouse.sensitivity[0];
10118: REG16(CX) = mouse.sensitivity[1];
10119: REG16(DX) = mouse.sensitivity[2];
10120: }
10121:
10122: inline void msdos_int_33h_001dh()
10123: {
10124: mouse.display_page = REG16(BX);
10125: }
10126:
10127: inline void msdos_int_33h_001eh()
10128: {
10129: REG16(BX) = mouse.display_page;
10130: }
10131:
10132: inline void msdos_int_33h_0021h()
10133: {
10134: REG16(AX) = 0xffff;
10135: REG16(BX) = MAX_MOUSE_BUTTONS;
10136: }
10137:
10138: inline void msdos_int_33h_0022h()
10139: {
10140: mouse.language = REG16(BX);
10141: }
10142:
10143: inline void msdos_int_33h_0023h()
10144: {
10145: REG16(BX) = mouse.language;
10146: }
10147:
10148: inline void msdos_int_33h_0024h()
10149: {
10150: REG16(BX) = 0x0805; // V8.05
10151: REG16(CX) = 0x0400; // PS/2
10152: }
10153:
10154: inline void msdos_int_33h_0026h()
10155: {
10156: REG16(BX) = 0x0000;
10157: REG16(CX) = mouse.max_position.x;
10158: REG16(DX) = mouse.max_position.y;
10159: }
10160:
10161: inline void msdos_int_33h_002ah()
10162: {
10163: REG16(AX) = mouse.active ? 0 : 0xffff;
10164: REG16(BX) = mouse.hot_spot[0];
10165: REG16(CX) = mouse.hot_spot[1];
10166: REG16(DX) = 4; // PS/2
10167: }
10168:
10169: inline void msdos_int_33h_0031h()
10170: {
10171: REG16(AX) = mouse.min_position.x;
10172: REG16(BX) = mouse.min_position.y;
10173: REG16(CX) = mouse.max_position.x;
10174: REG16(DX) = mouse.max_position.y;
10175: }
10176:
10177: inline void msdos_int_33h_0032h()
10178: {
10179: REG16(AX) = 0;
10180: // REG16(AX) |= 0x8000; // 0025h
10181: REG16(AX) |= 0x4000; // 0026h
10182: // REG16(AX) |= 0x2000; // 0027h
10183: // REG16(AX) |= 0x1000; // 0028h
10184: // REG16(AX) |= 0x0800; // 0029h
10185: REG16(AX) |= 0x0400; // 002ah
10186: // REG16(AX) |= 0x0200; // 002bh
10187: // REG16(AX) |= 0x0100; // 002ch
10188: // REG16(AX) |= 0x0080; // 002dh
10189: // REG16(AX) |= 0x0040; // 002eh
10190: REG16(AX) |= 0x0020; // 002fh
10191: // REG16(AX) |= 0x0010; // 0030h
10192: REG16(AX) |= 0x0008; // 0031h
10193: REG16(AX) |= 0x0004; // 0032h
10194: // REG16(AX) |= 0x0002; // 0033h
10195: // REG16(AX) |= 0x0001; // 0034h
10196: }
10197:
1.1.1.19 root 10198: inline void msdos_int_67h_40h()
10199: {
10200: if(!support_ems) {
10201: REG8(AH) = 0x84;
10202: } else {
10203: REG8(AH) = 0x00;
10204: }
10205: }
10206:
10207: inline void msdos_int_67h_41h()
10208: {
10209: if(!support_ems) {
10210: REG8(AH) = 0x84;
10211: } else {
10212: REG8(AH) = 0x00;
10213: REG16(BX) = EMS_TOP >> 4;
10214: }
10215: }
10216:
10217: inline void msdos_int_67h_42h()
10218: {
10219: if(!support_ems) {
10220: REG8(AH) = 0x84;
10221: } else {
10222: REG8(AH) = 0x00;
10223: REG16(BX) = free_ems_pages;
10224: REG16(DX) = MAX_EMS_PAGES;
10225: }
10226: }
10227:
10228: inline void msdos_int_67h_43h()
10229: {
10230: if(!support_ems) {
10231: REG8(AH) = 0x84;
10232: } else if(REG16(BX) > MAX_EMS_PAGES) {
10233: REG8(AH) = 0x87;
10234: } else if(REG16(BX) > free_ems_pages) {
10235: REG8(AH) = 0x88;
10236: } else if(REG16(BX) == 0) {
10237: REG8(AH) = 0x89;
10238: } else {
10239: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
10240: if(!ems_handles[i].allocated) {
10241: ems_allocate_pages(i, REG16(BX));
10242: REG8(AH) = 0x00;
10243: REG16(DX) = i;
10244: return;
10245: }
10246: }
10247: REG8(AH) = 0x85;
10248: }
10249: }
10250:
10251: inline void msdos_int_67h_44h()
10252: {
10253: if(!support_ems) {
10254: REG8(AH) = 0x84;
10255: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
10256: REG8(AH) = 0x83;
10257: } else if(!(REG16(BX) == 0xffff || REG16(BX) < ems_handles[REG16(DX)].pages)) {
10258: REG8(AH) = 0x8a;
10259: // } else if(!(REG8(AL) < 4)) {
10260: // REG8(AH) = 0x8b;
10261: } else if(REG16(BX) == 0xffff) {
10262: ems_unmap_page(REG8(AL) & 3);
10263: REG8(AH) = 0x00;
10264: } else {
10265: ems_map_page(REG8(AL) & 3, REG16(DX), REG16(BX));
10266: REG8(AH) = 0x00;
10267: }
10268: }
10269:
10270: inline void msdos_int_67h_45h()
10271: {
10272: if(!support_ems) {
10273: REG8(AH) = 0x84;
10274: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
10275: REG8(AH) = 0x83;
10276: } else {
10277: ems_release_pages(REG16(DX));
10278: REG8(AH) = 0x00;
10279: }
10280: }
10281:
10282: inline void msdos_int_67h_46h()
10283: {
10284: if(!support_ems) {
10285: REG8(AH) = 0x84;
10286: } else {
1.1.1.29! root 10287: // REG16(AX) = 0x0032; // EMS 3.2
! 10288: REG16(AX) = 0x0040; // EMS 4.0
1.1.1.19 root 10289: }
10290: }
10291:
10292: inline void msdos_int_67h_47h()
10293: {
10294: // NOTE: the map data should be stored in the specified ems page, not process data
10295: process_t *process = msdos_process_info_get(current_psp);
10296:
10297: if(!support_ems) {
10298: REG8(AH) = 0x84;
10299: // } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
10300: // REG8(AH) = 0x83;
10301: } else if(process->ems_pages_stored) {
10302: REG8(AH) = 0x8d;
10303: } else {
10304: for(int i = 0; i < 4; i++) {
10305: process->ems_pages[i].handle = ems_pages[i].handle;
10306: process->ems_pages[i].page = ems_pages[i].page;
10307: process->ems_pages[i].mapped = ems_pages[i].mapped;
10308: }
10309: process->ems_pages_stored = true;
10310: REG8(AH) = 0x00;
10311: }
10312: }
10313:
10314: inline void msdos_int_67h_48h()
10315: {
10316: // NOTE: the map data should be restored from the specified ems page, not process data
10317: process_t *process = msdos_process_info_get(current_psp);
10318:
10319: if(!support_ems) {
10320: REG8(AH) = 0x84;
10321: // } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
10322: // REG8(AH) = 0x83;
10323: } else if(!process->ems_pages_stored) {
10324: REG8(AH) = 0x8e;
10325: } else {
10326: for(int i = 0; i < 4; i++) {
10327: if(process->ems_pages[i].mapped) {
10328: ems_map_page(i, process->ems_pages[i].handle, process->ems_pages[i].page);
10329: } else {
10330: ems_unmap_page(i);
10331: }
10332: }
10333: process->ems_pages_stored = false;
10334: REG8(AH) = 0x00;
10335: }
10336: }
10337:
10338: inline void msdos_int_67h_4bh()
10339: {
10340: if(!support_ems) {
10341: REG8(AH) = 0x84;
10342: } else {
10343: REG8(AH) = 0x00;
10344: REG16(BX) = 0;
10345: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
10346: if(ems_handles[i].allocated) {
10347: REG16(BX)++;
10348: }
10349: }
10350: }
10351: }
10352:
10353: inline void msdos_int_67h_4ch()
10354: {
10355: if(!support_ems) {
10356: REG8(AH) = 0x84;
10357: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
10358: REG8(AH) = 0x83;
10359: } else {
10360: REG8(AH) = 0x00;
10361: REG16(BX) = ems_handles[REG16(DX)].pages;
10362: }
10363: }
10364:
10365: inline void msdos_int_67h_4dh()
10366: {
10367: if(!support_ems) {
10368: REG8(AH) = 0x84;
10369: } else {
10370: REG8(AH) = 0x00;
10371: REG16(BX) = 0;
10372: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
10373: if(ems_handles[i].allocated) {
10374: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 0) = i;
10375: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 2) = ems_handles[i].pages;
10376: REG16(BX)++;
10377: }
10378: }
10379: }
10380: }
10381:
1.1.1.20 root 10382: inline void msdos_int_67h_4eh()
10383: {
10384: if(!support_ems) {
10385: REG8(AH) = 0x84;
10386: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01 || REG8(AL) == 0x02) {
10387: if(REG8(AL) == 0x00 || REG8(AL) == 0x02) {
10388: // save page map
10389: for(int i = 0; i < 4; i++) {
10390: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = ems_pages[i].mapped ? ems_pages[i].handle : 0xffff;
10391: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = ems_pages[i].mapped ? ems_pages[i].page : 0xffff;
10392: }
10393: }
10394: if(REG8(AL) == 0x01 || REG8(AL) == 0x02) {
10395: // restore page map
10396: for(int i = 0; i < 4; i++) {
10397: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
10398: UINT16 page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
10399:
10400: if(handle < MAX_EMS_HANDLES && ems_handles[handle].allocated && page < ems_handles[handle].pages) {
10401: ems_map_page(i, handle, page);
10402: } else {
10403: ems_unmap_page(i);
10404: }
10405: }
10406: }
10407: REG8(AH) = 0x00;
10408: } else if(REG8(AL) == 0x03) {
10409: REG8(AH) = 0x00;
1.1.1.21 root 10410: REG8(AL) = 4 * 4;
10411: } else {
1.1.1.22 root 10412: 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 10413: REG8(AH) = 0x8f;
10414: }
10415: }
10416:
10417: inline void msdos_int_67h_4fh()
10418: {
10419: if(!support_ems) {
10420: REG8(AH) = 0x84;
10421: } else if(REG8(AL) == 0x00) {
10422: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
10423:
10424: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI)) = count;
10425: for(int i = 0; i < count; i++) {
10426: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 2 * i);
10427: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
10428:
10429: // if(!(physical < 4)) {
10430: // REG8(AH) = 0x8b;
10431: // return;
10432: // }
10433: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 0) = segment;
10434: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 2) = ems_pages[physical & 3].handle;
10435: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 4) = ems_pages[physical & 3].mapped ? ems_pages[physical & 3].page : 0xffff;
10436: }
10437: REG8(AH) = 0x00;
10438: } else if(REG8(AL) == 0x01) {
10439: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
10440:
10441: for(int i = 0; i < count; i++) {
10442: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 0);
10443: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
10444: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 2);
10445: UINT16 logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 4);
10446:
10447: // if(!(physical < 4)) {
10448: // REG8(AH) = 0x8b;
10449: // return;
10450: // } else
10451: if(!(handle < MAX_EMS_HANDLES && ems_handles[handle].allocated)) {
10452: REG8(AH) = 0x83;
10453: return;
10454: } else if(logical == 0xffff) {
10455: ems_unmap_page(physical & 3);
10456: } else if(logical < ems_handles[handle].pages) {
10457: ems_map_page(physical & 3, handle, logical);
10458: } else {
10459: REG8(AH) = 0x8a;
10460: return;
10461: }
10462: }
10463: REG8(AH) = 0x00;
10464: } else if(REG8(AL) == 0x02) {
10465: REG8(AH) = 0x00;
10466: REG8(AL) = 2 + REG16(BX) * 6;
1.1.1.20 root 10467: } else {
1.1.1.22 root 10468: 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 10469: REG8(AH) = 0x8f;
10470: }
10471: }
10472:
10473: inline void msdos_int_67h_50h()
10474: {
10475: if(!support_ems) {
10476: REG8(AH) = 0x84;
10477: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
10478: REG8(AH) = 0x83;
10479: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
10480: for(int i = 0; i < REG16(CX); i++) {
10481: int logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
10482: int physical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
10483:
10484: if(REG8(AL) == 0x01) {
10485: physical = ((physical << 4) - EMS_TOP) / 0x4000;
10486: }
10487: // if(!(physical < 4)) {
10488: // REG8(AH) = 0x8b;
10489: // return;
10490: // } else
10491: if(logical == 0xffff) {
10492: ems_unmap_page(physical & 3);
10493: } else if(logical < ems_handles[REG16(DX)].pages) {
10494: ems_map_page(physical & 3, REG16(DX), logical);
10495: } else {
10496: REG8(AH) = 0x8a;
10497: return;
10498: }
10499: }
10500: REG8(AH) = 0x00;
10501: } else {
1.1.1.22 root 10502: 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 10503: REG8(AH) = 0x8f;
10504: }
10505: }
10506:
1.1.1.19 root 10507: inline void msdos_int_67h_51h()
10508: {
10509: if(!support_ems) {
10510: REG8(AH) = 0x84;
10511: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
10512: REG8(AH) = 0x83;
10513: } else if(REG16(BX) > MAX_EMS_PAGES) {
10514: REG8(AH) = 0x87;
10515: } else if(REG16(BX) > free_ems_pages + ems_handles[REG16(DX)].pages) {
10516: REG8(AH) = 0x88;
10517: } else {
10518: ems_reallocate_pages(REG16(DX), REG16(BX));
10519: REG8(AH) = 0x00;
10520: }
10521: }
10522:
1.1.1.20 root 10523: inline void msdos_int_67h_52h()
10524: {
10525: if(!support_ems) {
10526: REG8(AH) = 0x84;
10527: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
10528: REG8(AH) = 0x83;
10529: } else if(REG8(AL) == 0x00) {
10530: REG8(AL) = 0x00; // handle is volatile
10531: REG8(AH) = 0x00;
10532: } else if(REG8(AL) == 0x01) {
10533: if(REG8(BL) == 0x00) {
10534: REG8(AH) = 0x00;
10535: } else {
10536: REG8(AH) = 0x90; // undefined attribute type
10537: }
10538: } else if(REG8(AL) == 0x02) {
10539: REG8(AL) = 0x00; // only volatile handles supported
10540: REG8(AH) = 0x00;
10541: } else {
1.1.1.22 root 10542: 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 10543: REG8(AH) = 0x8f;
10544: }
10545: }
10546:
1.1.1.19 root 10547: inline void msdos_int_67h_53h()
10548: {
10549: if(!support_ems) {
10550: REG8(AH) = 0x84;
10551: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
10552: REG8(AH) = 0x83;
10553: } else if(REG8(AL) == 0x00) {
10554: memcpy(mem + SREG_BASE(ES) + REG16(DI), ems_handles[REG16(DX)].name, 8);
10555: REG8(AH) = 0x00;
10556: } else if(REG8(AL) == 0x01) {
10557: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
10558: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
10559: REG8(AH) = 0xa1;
10560: return;
10561: }
10562: }
10563: REG8(AH) = 0x00;
10564: memcpy(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8);
10565: } else {
1.1.1.22 root 10566: 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 10567: REG8(AH) = 0x8f;
1.1.1.19 root 10568: }
10569: }
10570:
10571: inline void msdos_int_67h_54h()
10572: {
10573: if(!support_ems) {
10574: REG8(AH) = 0x84;
10575: } else if(REG8(AL) == 0x00) {
10576: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
10577: if(ems_handles[i].allocated) {
10578: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, ems_handles[i].name, 10);
10579: } else {
10580: memset(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, 0, 10);
10581: }
10582: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 0) = i;
10583: }
10584: REG8(AH) = 0x00;
10585: REG8(AL) = MAX_EMS_HANDLES;
10586: } else if(REG8(AL) == 0x01) {
10587: REG8(AH) = 0xa0; // not found
10588: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
10589: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
10590: REG8(AH) = 0x00;
10591: REG16(DX) = i;
10592: break;
10593: }
10594: }
10595: } else if(REG8(AL) == 0x02) {
10596: REG8(AH) = 0x00;
10597: REG16(BX) = MAX_EMS_HANDLES;
10598: } else {
1.1.1.22 root 10599: 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 10600: REG8(AH) = 0x8f;
10601: }
10602: }
10603:
10604: inline void msdos_int_67h_57h_tmp()
10605: {
10606: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
10607: UINT8 src_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
10608: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x05);
10609: UINT16 src_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07);
10610: UINT16 src_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x09);
10611: UINT8 dest_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0b);
10612: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
10613: UINT16 dest_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0e);
10614: UINT16 dest_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x10);
10615:
10616: UINT8 *src_buffer, *dest_buffer;
10617: UINT32 src_addr, dest_addr;
10618: UINT32 src_addr_max, dest_addr_max;
10619:
10620: if(src_type == 0) {
10621: src_buffer = mem;
10622: src_addr = (src_seg << 4) + src_ofs;
10623: src_addr_max = MAX_MEM;
10624: } else {
10625: if(!(src_handle < MAX_EMS_HANDLES && ems_handles[src_handle].allocated)) {
10626: REG8(AH) = 0x83;
10627: return;
10628: } else if(!(src_seg < ems_handles[src_handle].pages)) {
10629: REG8(AH) = 0x8a;
10630: return;
10631: }
10632: src_buffer = ems_handles[src_handle].buffer + 0x4000 * src_seg;
10633: src_addr = src_ofs;
10634: src_addr_max = 0x4000;
10635: }
10636: if(dest_type == 0) {
10637: dest_buffer = mem;
10638: dest_addr = (dest_seg << 4) + dest_ofs;
10639: dest_addr_max = MAX_MEM;
10640: } else {
10641: if(!(dest_handle < MAX_EMS_HANDLES && ems_handles[dest_handle].allocated)) {
10642: REG8(AH) = 0x83;
10643: return;
10644: } else if(!(dest_seg < ems_handles[dest_handle].pages)) {
10645: REG8(AH) = 0x8a;
10646: return;
10647: }
10648: dest_buffer = ems_handles[dest_handle].buffer + 0x4000 * dest_seg;
10649: dest_addr = dest_ofs;
10650: dest_addr_max = 0x4000;
10651: }
10652: for(int i = 0; i < copy_length; i++) {
10653: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
10654: if(REG8(AL) == 0x00) {
10655: dest_buffer[dest_addr++] = src_buffer[src_addr++];
10656: } else if(REG8(AL) == 0x01) {
10657: UINT8 tmp = dest_buffer[dest_addr];
10658: dest_buffer[dest_addr++] = src_buffer[src_addr];
10659: src_buffer[src_addr++] = tmp;
10660: }
10661: } else {
10662: REG8(AH) = 0x93;
10663: return;
10664: }
10665: }
10666: REG8(AH) = 0x80;
10667: }
10668:
10669: inline void msdos_int_67h_57h()
10670: {
10671: if(!support_ems) {
10672: REG8(AH) = 0x84;
10673: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
10674: struct {
10675: UINT16 handle;
10676: UINT16 page;
10677: bool mapped;
10678: } tmp_pages[4];
10679:
10680: // unmap pages to copy memory data to ems buffer
10681: for(int i = 0; i < 4; i++) {
10682: tmp_pages[i].handle = ems_pages[i].handle;
10683: tmp_pages[i].page = ems_pages[i].page;
10684: tmp_pages[i].mapped = ems_pages[i].mapped;
10685: ems_unmap_page(i);
10686: }
10687:
10688: // run move/exchange operation
10689: msdos_int_67h_57h_tmp();
10690:
10691: // restore unmapped pages
10692: for(int i = 0; i < 4; i++) {
10693: if(tmp_pages[i].mapped) {
10694: ems_map_page(i, tmp_pages[i].handle, tmp_pages[i].page);
10695: }
10696: }
10697: } else {
1.1.1.22 root 10698: 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 10699: REG8(AH) = 0x8f;
10700: }
10701: }
10702:
10703: inline void msdos_int_67h_58h()
10704: {
10705: if(!support_ems) {
10706: REG8(AH) = 0x84;
10707: } else if(REG8(AL) == 0x00) {
10708: for(int i = 0; i < 4; i++) {
10709: *(UINT16 *)(mem +SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = (EMS_TOP + 0x4000 * i) >> 4;
10710: *(UINT16 *)(mem +SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = i;
10711: }
10712: REG8(AH) = 0x00;
10713: REG16(CX) = 4;
10714: } else if(REG8(AL) == 0x01) {
10715: REG8(AH) = 0x00;
10716: REG16(CX) = 4;
10717: } else {
1.1.1.22 root 10718: 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 10719: REG8(AH) = 0x8f;
10720: }
10721: }
10722:
10723: inline void msdos_int_67h_5ah()
10724: {
10725: if(!support_ems) {
1.1.1.19 root 10726: REG8(AH) = 0x84;
1.1.1.20 root 10727: } else if(REG16(BX) > MAX_EMS_PAGES) {
10728: REG8(AH) = 0x87;
10729: } else if(REG16(BX) > free_ems_pages) {
10730: REG8(AH) = 0x88;
10731: // } else if(REG16(BX) == 0) {
10732: // REG8(AH) = 0x89;
10733: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
10734: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
10735: if(!ems_handles[i].allocated) {
10736: ems_allocate_pages(i, REG16(BX));
10737: REG8(AH) = 0x00;
10738: REG16(DX) = i;
10739: return;
10740: }
10741: }
10742: REG8(AH) = 0x85;
10743: } else {
1.1.1.22 root 10744: 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 10745: REG8(AH) = 0x8f;
1.1.1.19 root 10746: }
10747: }
10748:
10749: #ifdef SUPPORT_XMS
10750:
1.1.1.26 root 10751: inline void msdos_xms_init()
10752: {
10753: memset(xms_handles, 0, sizeof(xms_handles));
10754: xms_a20_local_enb_count = 0;
10755: }
10756:
1.1.1.19 root 10757: inline void msdos_call_xms_00h()
10758: {
1.1.1.29! root 10759: #if defined(HAS_I386)
! 10760: REG16(AX) = 0x0300; // V3.00 (XMS Version)
! 10761: REG16(BX) = 0x035f; // V3.95 (Driver Revision)
! 10762: #else
! 10763: REG16(AX) = 0x0200; // V2.00 (XMS Version)
! 10764: REG16(BX) = 0x0270; // V2.70 (Driver Revision)
! 10765: #endif
! 10766: // REG16(DX) = 0x0000; // HMA does not exist
! 10767: REG16(DX) = 0x0001; // HMA does exist
1.1.1.19 root 10768: }
10769:
10770: inline void msdos_call_xms_01h()
10771: {
1.1.1.29! root 10772: if(REG8(AL) == 0x40) {
! 10773: // HIMEM.SYS will fail function 01h with error code 91h if AL=40h and
! 10774: // DX=KB free extended memory returned by last call of function 08h
! 10775: REG16(AX) = 0x0000;
! 10776: REG8(BL) = 0x91;
! 10777: REG16(DX) = xms_dx_after_call_08h;
! 10778: } else if(memcmp(mem + 0x100003, "VDISK", 5) == 0) {
! 10779: REG16(AX) = 0x0000;
! 10780: REG8(BL) = 0x81; // Vdisk was detected
! 10781: #ifdef SUPPORT_HMA
! 10782: } else if(is_hma_used_by_int_2fh) {
! 10783: REG16(AX) = 0x0000;
! 10784: REG8(BL) = 0x90; // HMA does not exist or is not managed by XMS provider
! 10785: } else if(is_hma_used_by_xms) {
! 10786: REG16(AX) = 0x0000;
! 10787: REG8(BL) = 0x91; // HMA is already in use
! 10788: } else {
! 10789: REG16(AX) = 0x0001;
! 10790: is_hma_used_by_xms = true;
! 10791: #else
! 10792: } else {
! 10793: REG16(AX) = 0x0000;
! 10794: REG8(BL) = 0x91; // HMA is already in use
! 10795: #endif
! 10796: }
1.1.1.19 root 10797: }
10798:
10799: inline void msdos_call_xms_02h()
10800: {
1.1.1.29! root 10801: if(memcmp(mem + 0x100003, "VDISK", 5) == 0) {
! 10802: REG16(AX) = 0x0000;
! 10803: REG8(BL) = 0x81; // Vdisk was detected
! 10804: #ifdef SUPPORT_HMA
! 10805: } else if(is_hma_used_by_int_2fh) {
! 10806: REG16(AX) = 0x0000;
! 10807: REG8(BL) = 0x90; // HMA does not exist or is not managed by XMS provider
! 10808: } else if(!is_hma_used_by_xms) {
! 10809: REG16(AX) = 0x0000;
! 10810: REG8(BL) = 0x93; // HMA is not allocated
! 10811: } else {
! 10812: REG16(AX) = 0x0001;
! 10813: is_hma_used_by_xms = false;
! 10814: // restore first free mcb in high memory area
! 10815: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
! 10816: #else
! 10817: } else {
! 10818: REG16(AX) = 0x0000;
! 10819: REG8(BL) = 0x91; // HMA is already in use
! 10820: #endif
! 10821: }
1.1.1.19 root 10822: }
10823:
10824: inline void msdos_call_xms_03h()
10825: {
10826: i386_set_a20_line(1);
10827: REG16(AX) = 0x0001;
10828: REG8(BL) = 0x00;
10829: }
10830:
10831: inline void msdos_call_xms_04h()
10832: {
1.1.1.21 root 10833: i386_set_a20_line(0);
10834: REG16(AX) = 0x0001;
10835: REG8(BL) = 0x00;
1.1.1.19 root 10836: }
10837:
10838: inline void msdos_call_xms_05h()
10839: {
10840: i386_set_a20_line(1);
10841: REG16(AX) = 0x0001;
10842: REG8(BL) = 0x00;
1.1.1.21 root 10843: xms_a20_local_enb_count++;
1.1.1.19 root 10844: }
10845:
10846: void msdos_call_xms_06h()
10847: {
1.1.1.21 root 10848: if(xms_a20_local_enb_count > 0) {
10849: xms_a20_local_enb_count--;
10850: }
10851: if(xms_a20_local_enb_count == 0) {
1.1.1.19 root 10852: i386_set_a20_line(0);
1.1.1.21 root 10853: }
10854: if((m_a20_mask >> 20) & 1) {
1.1.1.19 root 10855: REG16(AX) = 0x0000;
10856: REG8(BL) = 0x94;
1.1.1.21 root 10857: } else {
10858: REG16(AX) = 0x0001;
10859: REG8(BL) = 0x00;
1.1.1.19 root 10860: }
10861: }
10862:
10863: inline void msdos_call_xms_07h()
10864: {
10865: REG16(AX) = (m_a20_mask >> 20) & 1;
10866: REG8(BL) = 0x00;
10867: }
10868:
10869: inline void msdos_call_xms_08h()
10870: {
10871: REG16(AX) = REG16(DX) = 0x0000;
10872:
10873: int mcb_seg = EMB_TOP >> 4;
10874:
10875: while(1) {
10876: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
10877:
10878: if(mcb->psp == 0) {
10879: if(REG16(AX) < mcb->size_kb()) {
10880: REG16(AX) = mcb->size_kb();
10881: }
10882: REG16(DX) += mcb->size_kb();
10883: }
10884: if(mcb->mz == 'Z') {
10885: break;
10886: }
10887: mcb_seg += 1 + mcb->paragraphs();
10888: }
10889:
10890: if(REG16(AX) == 0 && REG16(DX) == 0) {
10891: REG8(BL) = 0xa0;
10892: } else {
10893: REG8(BL) = 0x00;
10894: }
1.1.1.29! root 10895: xms_dx_after_call_08h = REG16(DX);
1.1.1.19 root 10896: }
10897:
10898: inline void msdos_call_xms_09h()
10899: {
10900: for(int i = 1; i <= MAX_XMS_HANDLES; i++) {
10901: if(!xms_handles[i].allocated) {
10902: if((xms_handles[i].seg = msdos_mem_alloc(EMB_TOP >> 4, REG16(DX) * 64, 0)) != -1) {
10903: xms_handles[i].size_kb = REG16(DX);
10904: xms_handles[i].lock = 0;
10905: xms_handles[i].allocated = true;
10906:
10907: REG16(AX) = 0x0001;
10908: REG16(DX) = i;
10909: REG8(BL) = 0x00;
10910: } else {
10911: REG16(AX) = REG16(DX) = 0x0000;
10912: REG8(BL) = 0xa0;
10913: }
10914: return;
10915: }
10916: }
10917: REG16(AX) = REG16(DX) = 0x0000;
10918: REG8(BL) = 0xa1;
10919: }
10920:
10921: inline void msdos_call_xms_0ah()
10922: {
10923: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
10924: REG16(AX) = 0x0000;
10925: REG8(BL) = 0xa2;
10926: } else if(xms_handles[REG16(DX)].lock > 0) {
10927: REG16(AX) = 0x0000;
10928: REG8(BL) = 0xab;
10929: } else {
10930: msdos_mem_free(xms_handles[REG16(DX)].seg);
10931: xms_handles[REG16(DX)].allocated = false;
10932:
10933: REG16(AX) = 0x0001;
10934: REG8(BL) = 0x00;
10935: }
10936: }
10937:
10938: inline void msdos_call_xms_0bh()
10939: {
10940: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
10941: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
10942: UINT32 src_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06);
10943: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0a);
10944: UINT32 dest_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
10945:
10946: UINT8 *src_buffer, *dest_buffer;
10947: UINT32 src_addr_max, dest_addr_max;
10948:
10949: if(src_handle == 0) {
10950: src_buffer = mem;
10951: src_addr = (((src_addr >> 16) & 0xffff) << 4) + (src_addr & 0xffff);
10952: src_addr_max = MAX_MEM;
10953: } else {
10954: if(!(src_handle >= 1 && src_handle <= MAX_XMS_HANDLES && xms_handles[src_handle].allocated)) {
10955: REG16(AX) = 0x0000;
10956: REG8(BL) = 0xa3;
10957: return;
10958: }
10959: src_buffer = mem + (xms_handles[src_handle].seg << 4);
10960: src_addr_max = xms_handles[src_handle].size_kb * 1024;
10961: }
10962: if(dest_handle == 0) {
10963: dest_buffer = mem;
10964: dest_addr = (((dest_addr >> 16) & 0xffff) << 4) + (dest_addr & 0xffff);
10965: dest_addr_max = MAX_MEM;
10966: } else {
10967: if(!(dest_handle >= 1 && dest_handle <= MAX_XMS_HANDLES && xms_handles[dest_handle].allocated)) {
10968: REG16(AX) = 0x0000;
10969: REG8(BL) = 0xa5;
10970: return;
10971: }
10972: dest_buffer = mem + (xms_handles[dest_handle].seg << 4);
10973: dest_addr_max = xms_handles[dest_handle].size_kb * 1024;
10974: }
10975: for(int i = 0; i < copy_length; i++) {
10976: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
10977: dest_buffer[dest_addr++] = src_buffer[src_addr++];
10978: } else {
10979: break;
10980: }
10981: }
10982: REG16(AX) = 0x0001;
10983: REG8(BL) = 0x00;
10984: }
10985:
10986: inline void msdos_call_xms_0ch()
10987: {
10988: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
10989: REG16(AX) = 0x0000;
10990: REG8(BL) = 0xa2;
10991: } else {
10992: xms_handles[REG16(DX)].lock++;
10993: REG16(AX) = 0x0001;
10994: REG8(BL) = 0x00;
10995: UINT32 addr = xms_handles[REG16(DX)].seg << 4;
10996: REG16(DX) = (addr >> 16) & 0xffff;
10997: REG16(BX) = (addr ) & 0xffff;
10998: }
10999: }
11000:
11001: inline void msdos_call_xms_0dh()
11002: {
11003: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
11004: REG16(AX) = 0x0000;
11005: REG8(BL) = 0xa2;
11006: } else if(!(xms_handles[REG16(DX)].lock > 0)) {
11007: REG16(AX) = 0x0000;
11008: REG8(BL) = 0xaa;
11009: } else {
11010: xms_handles[REG16(DX)].lock--;
11011: REG16(AX) = 0x0001;
11012: REG8(BL) = 0x00;
11013: }
11014: }
11015:
11016: inline void msdos_call_xms_0eh()
11017: {
11018: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
11019: REG16(AX) = 0x0000;
11020: REG8(BL) = 0xa2;
11021: } else {
11022: REG16(AX) = 0x0001;
11023: REG8(BH) = xms_handles[REG16(DX)].lock;
11024: REG8(BL) = 0x00;
11025: for(int i = 1; i <= MAX_XMS_HANDLES; i++) {
11026: if(!xms_handles[i].allocated) {
11027: REG8(BL)++;
11028: }
11029: }
11030: REG16(DX) = xms_handles[REG16(DX)].size_kb;
11031: }
11032: }
11033:
11034: inline void msdos_call_xms_0fh()
11035: {
11036: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
11037: REG16(AX) = 0x0000;
11038: REG8(BL) = 0xa2;
11039: } else if(xms_handles[REG16(DX)].lock > 0) {
11040: REG16(AX) = 0x0000;
11041: REG8(BL) = 0xab;
11042: } else if(msdos_mem_realloc(xms_handles[REG16(DX)].seg, REG16(BX) * 64, NULL)) {
11043: REG16(AX) = 0x0000;
11044: REG8(BL) = 0xa0;
11045: } else {
11046: REG16(AX) = 0x0001;
11047: REG8(BL) = 0x00;
11048: }
11049: }
11050:
11051: inline void msdos_call_xms_10h()
11052: {
11053: int seg;
11054:
11055: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(DX), 0)) != -1) {
11056: REG16(AX) = 0x0001;
11057: REG16(BX) = seg;
11058: } else {
11059: REG16(AX) = 0x0000;
11060: REG8(BL) = 0xb0;
11061: REG16(DX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
11062: }
11063: }
11064:
11065: inline void msdos_call_xms_11h()
11066: {
11067: int mcb_seg = REG16(DX) - 1;
11068: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
11069:
11070: if(mcb->mz == 'M' || mcb->mz == 'Z') {
11071: msdos_mem_free(REG16(DX));
11072: REG16(AX) = 0x0001;
11073: REG8(BL) = 0x00;
11074: } else {
11075: REG16(AX) = 0x0000;
11076: REG8(BL) = 0xb2;
11077: }
11078: }
11079:
11080: inline void msdos_call_xms_12h()
11081: {
11082: int mcb_seg = REG16(DX) - 1;
11083: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
11084: int max_paragraphs;
11085:
11086: if(mcb->mz == 'M' || mcb->mz == 'Z') {
11087: if(!msdos_mem_realloc(REG16(DX), REG16(BX), &max_paragraphs)) {
11088: REG16(AX) = 0x0001;
11089: REG8(BL) = 0x00;
11090: } else {
11091: REG16(AX) = 0x0000;
11092: REG8(BL) = 0xb0;
11093: REG16(DX) = max_paragraphs;
11094: }
11095: } else {
11096: REG16(AX) = 0x0000;
11097: REG8(BL) = 0xb2;
11098: }
11099: }
11100:
1.1.1.29! root 11101: #if defined(HAS_I386)
! 11102:
! 11103: inline void msdos_call_xms_88h()
! 11104: {
! 11105: REG32(EAX) = REG32(EDX) = 0x0000;
! 11106:
! 11107: int mcb_seg = EMB_TOP >> 4;
! 11108:
! 11109: while(1) {
! 11110: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
! 11111:
! 11112: if(mcb->psp == 0) {
! 11113: if(REG32(EAX) < mcb->size_kb()) {
! 11114: REG32(EAX) = mcb->size_kb();
! 11115: }
! 11116: REG32(EDX) += mcb->size_kb();
! 11117: }
! 11118: if(mcb->mz == 'Z') {
! 11119: break;
! 11120: }
! 11121: mcb_seg += 1 + mcb->paragraphs();
! 11122: }
! 11123:
! 11124: if(REG32(EAX) == 0 && REG32(EDX) == 0) {
! 11125: REG8(BL) = 0xa0;
! 11126: } else {
! 11127: REG8(BL) = 0x00;
! 11128: }
! 11129: REG32(ECX) = EMB_END - 1;
! 11130: }
! 11131:
! 11132: inline void msdos_call_xms_89h()
! 11133: {
! 11134: for(int i = 1; i <= MAX_XMS_HANDLES; i++) {
! 11135: if(!xms_handles[i].allocated) {
! 11136: if((xms_handles[i].seg = msdos_mem_alloc(EMB_TOP >> 4, REG32(EDX) * 64, 0)) != -1) {
! 11137: xms_handles[i].size_kb = REG32(EDX);
! 11138: xms_handles[i].lock = 0;
! 11139: xms_handles[i].allocated = true;
! 11140:
! 11141: REG16(AX) = 0x0001;
! 11142: REG16(DX) = i;
! 11143: REG8(BL) = 0x00;
! 11144: } else {
! 11145: REG16(AX) = REG16(DX) = 0x0000;
! 11146: REG8(BL) = 0xa0;
! 11147: }
! 11148: return;
! 11149: }
! 11150: }
! 11151: REG16(AX) = REG16(DX) = 0x0000;
! 11152: REG8(BL) = 0xa1;
! 11153: }
! 11154:
! 11155: inline void msdos_call_xms_8eh()
! 11156: {
! 11157: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
! 11158: REG16(AX) = 0x0000;
! 11159: REG8(BL) = 0xa2;
! 11160: } else {
! 11161: REG16(AX) = 0x0001;
! 11162: REG8(BH) = xms_handles[REG16(DX)].lock;
! 11163: REG16(CX) = 0x00;
! 11164: for(int i = 1; i <= MAX_XMS_HANDLES; i++) {
! 11165: if(!xms_handles[i].allocated) {
! 11166: REG16(CX)++;
! 11167: }
! 11168: }
! 11169: REG32(EDX) = xms_handles[REG16(DX)].size_kb;
! 11170: }
! 11171: }
! 11172:
! 11173: inline void msdos_call_xms_8fh()
! 11174: {
! 11175: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
! 11176: REG16(AX) = 0x0000;
! 11177: REG8(BL) = 0xa2;
! 11178: } else if(xms_handles[REG16(DX)].lock > 0) {
! 11179: REG16(AX) = 0x0000;
! 11180: REG8(BL) = 0xab;
! 11181: } else if(msdos_mem_realloc(xms_handles[REG16(DX)].seg, REG32(EBX) * 64, NULL)) {
! 11182: REG16(AX) = 0x0000;
! 11183: REG8(BL) = 0xa0;
! 11184: } else {
! 11185: REG16(AX) = 0x0001;
! 11186: REG8(BL) = 0x00;
! 11187: }
! 11188: }
! 11189:
! 11190: #endif
1.1.1.19 root 11191: #endif
11192:
1.1.1.26 root 11193: UINT16 msdos_get_equipment()
11194: {
11195: static UINT16 equip = 0;
11196:
11197: if(equip == 0) {
11198: #ifdef SUPPORT_FPU
11199: equip |= (1 << 1); // 80x87 coprocessor installed
11200: #endif
11201: equip |= (1 << 2); // pointing device installed (PS/2)
11202: equip |= (2 << 4); // initial video mode (80x25 color)
11203: // equip |= (1 << 8); // 0 if DMA installed
11204: equip |= (2 << 9); // number of serial ports
11205: 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 11206:
11207: // check only A: and B: if it is floppy drive
11208: DWORD dwDrives = GetLogicalDrives();
11209: int n = 0;
11210: for(int i = 0; i < 2; i++) {
11211: if(dwDrives & (1 << i)) {
11212: char volume[] = "A:\\";
11213: volume[0] = 'A' + i;
11214: if(GetDriveType(volume) == DRIVE_REMOVABLE) {
11215: n++;
11216: }
11217: }
11218: }
11219: if(n != 0) {
11220: equip |= (1 << 0); // floppy disk(s) installed
11221: n--;
11222: equip |= (n << 6); // number of floppies installed less 1
11223: }
11224: // if(joyGetNumDevs() != 0) {
11225: // equip |= (1 << 12); // game port installed
11226: // }
1.1.1.26 root 11227: }
11228: return(equip);
11229: }
11230:
1.1 root 11231: void msdos_syscall(unsigned num)
11232: {
1.1.1.22 root 11233: #ifdef ENABLE_DEBUG_SYSCALL
11234: if(num == 0x68) {
11235: // dummy interrupt for EMS (int 67h)
11236: fprintf(fdebug, "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));
11237: } else if(num == 0x69) {
11238: // dummy interrupt for XMS (call far)
11239: fprintf(fdebug, "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));
11240: } else if(num == 0x6a) {
11241: // dummy interrupt for case map routine pointed in the country info
11242: } else {
11243: fprintf(fdebug, "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));
11244: }
11245: #endif
1.1.1.26 root 11246: ctrl_c_pressed = ctrl_c_detected = false;
1.1.1.22 root 11247:
1.1 root 11248: switch(num) {
11249: case 0x00:
1.1.1.28 root 11250: try {
11251: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
11252: error("division by zero\n");
11253: } catch(...) {
11254: fatalerror("division by zero detected, and failed to terminate current process\n");
11255: }
1.1 root 11256: break;
11257: case 0x04:
1.1.1.28 root 11258: try {
11259: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
11260: error("overflow\n");
11261: } catch(...) {
11262: fatalerror("overflow detected, and failed to terminate current process\n");
11263: }
1.1 root 11264: break;
11265: case 0x06:
11266: // NOTE: ish.com has illegal instruction...
1.1.1.14 root 11267: if(!ignore_illegal_insn) {
1.1.1.28 root 11268: try {
11269: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
11270: error("illegal instruction\n");
11271: } catch(...) {
11272: fatalerror("illegal instruction detected, and failed to terminate current process\n");
11273: }
1.1.1.14 root 11274: } else {
11275: #if defined(HAS_I386)
11276: m_eip++;
11277: #else
11278: m_pc++;
11279: #endif
11280: }
1.1 root 11281: break;
1.1.1.8 root 11282: case 0x08:
1.1.1.14 root 11283: // pcbios_irq0(); // this causes too slow emulation...
1.1.1.8 root 11284: case 0x09:
11285: case 0x0a:
11286: case 0x0b:
11287: case 0x0c:
11288: case 0x0d:
11289: case 0x0e:
11290: case 0x0f:
11291: // EOI
11292: pic[0].isr &= ~(1 << (num - 0x08));
11293: pic_update();
11294: break;
1.1 root 11295: case 0x10:
11296: // PC BIOS - Video
1.1.1.14 root 11297: if(!restore_console_on_exit) {
1.1.1.15 root 11298: change_console_size(scr_width, scr_height);
1.1 root 11299: }
1.1.1.3 root 11300: m_CF = 0;
1.1 root 11301: switch(REG8(AH)) {
1.1.1.16 root 11302: case 0x00: pcbios_int_10h_00h(); break;
1.1 root 11303: case 0x01: pcbios_int_10h_01h(); break;
11304: case 0x02: pcbios_int_10h_02h(); break;
11305: case 0x03: pcbios_int_10h_03h(); break;
11306: case 0x05: pcbios_int_10h_05h(); break;
11307: case 0x06: pcbios_int_10h_06h(); break;
11308: case 0x07: pcbios_int_10h_07h(); break;
11309: case 0x08: pcbios_int_10h_08h(); break;
11310: case 0x09: pcbios_int_10h_09h(); break;
11311: case 0x0a: pcbios_int_10h_0ah(); break;
11312: case 0x0b: break;
11313: case 0x0c: break;
11314: case 0x0d: break;
11315: case 0x0e: pcbios_int_10h_0eh(); break;
11316: case 0x0f: pcbios_int_10h_0fh(); break;
11317: case 0x10: break;
1.1.1.14 root 11318: case 0x11: pcbios_int_10h_11h(); break;
11319: case 0x12: pcbios_int_10h_12h(); break;
1.1 root 11320: case 0x13: pcbios_int_10h_13h(); break;
11321: case 0x18: REG8(AL) = 0x86; break;
1.1.1.14 root 11322: case 0x1a: pcbios_int_10h_1ah(); break;
1.1.1.24 root 11323: case 0x1b: REG8(AL) = 0x00; break; // functionality/state information is not supported
11324: case 0x1c: REG8(AL) = 0x00; break; // save/restore video state is not supported
1.1 root 11325: case 0x1d: pcbios_int_10h_1dh(); break;
1.1.1.24 root 11326: case 0x1e: REG8(AL) = 0x00; break; // flat-panel functions are not supported
11327: case 0x1f: REG8(AL) = 0x00; break; // xga functions are not supported
1.1.1.22 root 11328: case 0x4f: pcbios_int_10h_4fh(); break;
11329: case 0x80: m_CF = 1; break; // unknown
11330: case 0x81: m_CF = 1; break; // unknown
1.1 root 11331: case 0x82: pcbios_int_10h_82h(); break;
1.1.1.22 root 11332: case 0x83: pcbios_int_10h_83h(); break;
11333: case 0x8b: break;
11334: case 0x8c: m_CF = 1; break; // unknown
11335: case 0x8d: m_CF = 1; break; // unknown
11336: case 0x8e: m_CF = 1; break; // unknown
11337: case 0x90: pcbios_int_10h_90h(); break;
11338: case 0x91: pcbios_int_10h_91h(); break;
11339: case 0x92: break;
11340: case 0x93: break;
11341: case 0xef: pcbios_int_10h_efh(); break;
1.1.1.24 root 11342: case 0xfa: break; // ega register interface library is not installed
1.1 root 11343: case 0xfe: pcbios_int_10h_feh(); break;
11344: case 0xff: pcbios_int_10h_ffh(); break;
11345: default:
1.1.1.22 root 11346: 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));
11347: m_CF = 1;
1.1 root 11348: break;
11349: }
11350: break;
11351: case 0x11:
11352: // PC BIOS - Get Equipment List
1.1.1.26 root 11353: REG16(AX) = msdos_get_equipment();
1.1 root 11354: break;
11355: case 0x12:
11356: // PC BIOS - Get Memory Size
11357: REG16(AX) = MEMORY_END / 1024;
11358: break;
11359: case 0x13:
11360: // PC BIOS - Disk
1.1.1.22 root 11361: // 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 11362: REG8(AH) = 0xff;
1.1.1.3 root 11363: m_CF = 1;
1.1 root 11364: break;
11365: case 0x14:
11366: // PC BIOS - Serial I/O
1.1.1.25 root 11367: switch(REG8(AH)) {
11368: case 0x00: pcbios_int_14h_00h(); break;
11369: case 0x01: pcbios_int_14h_01h(); break;
11370: case 0x02: pcbios_int_14h_02h(); break;
11371: case 0x03: pcbios_int_14h_03h(); break;
11372: case 0x04: pcbios_int_14h_04h(); break;
11373: case 0x05: pcbios_int_14h_05h(); break;
11374: default:
11375: 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));
11376: break;
11377: }
1.1 root 11378: break;
11379: case 0x15:
11380: // PC BIOS
1.1.1.3 root 11381: m_CF = 0;
1.1 root 11382: switch(REG8(AH)) {
1.1.1.14 root 11383: case 0x10: pcbios_int_15h_10h(); break;
1.1 root 11384: case 0x23: pcbios_int_15h_23h(); break;
11385: case 0x24: pcbios_int_15h_24h(); break;
1.1.1.24 root 11386: case 0x41: break;
1.1 root 11387: case 0x49: pcbios_int_15h_49h(); break;
1.1.1.22 root 11388: case 0x50: pcbios_int_15h_50h(); break;
1.1 root 11389: case 0x86: pcbios_int_15h_86h(); break;
11390: case 0x87: pcbios_int_15h_87h(); break;
11391: case 0x88: pcbios_int_15h_88h(); break;
11392: case 0x89: pcbios_int_15h_89h(); break;
1.1.1.21 root 11393: case 0x8a: pcbios_int_15h_8ah(); break;
1.1.1.22 root 11394: case 0xc0: // PS/2 ???
11395: case 0xc1:
11396: case 0xc2:
11397: REG8(AH) = 0x86;
11398: m_CF = 1;
11399: break;
1.1.1.3 root 11400: #if defined(HAS_I386)
1.1 root 11401: case 0xc9: pcbios_int_15h_c9h(); break;
1.1.1.3 root 11402: #endif
1.1 root 11403: case 0xca: pcbios_int_15h_cah(); break;
1.1.1.22 root 11404: case 0xe8: pcbios_int_15h_e8h(); break;
1.1 root 11405: default:
1.1.1.22 root 11406: 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));
11407: REG8(AH) = 0x86;
1.1.1.3 root 11408: m_CF = 1;
1.1 root 11409: break;
11410: }
11411: break;
11412: case 0x16:
11413: // PC BIOS - Keyboard
1.1.1.3 root 11414: m_CF = 0;
1.1 root 11415: switch(REG8(AH)) {
11416: case 0x00: pcbios_int_16h_00h(); break;
11417: case 0x01: pcbios_int_16h_01h(); break;
11418: case 0x02: pcbios_int_16h_02h(); break;
11419: case 0x03: pcbios_int_16h_03h(); break;
11420: case 0x05: pcbios_int_16h_05h(); break;
11421: case 0x10: pcbios_int_16h_00h(); break;
11422: case 0x11: pcbios_int_16h_01h(); break;
11423: case 0x12: pcbios_int_16h_12h(); break;
11424: case 0x13: pcbios_int_16h_13h(); break;
11425: case 0x14: pcbios_int_16h_14h(); break;
1.1.1.24 root 11426: case 0x55: pcbios_int_16h_55h(); break;
1.1.1.22 root 11427: case 0xda: break; // unknown
11428: case 0xff: break; // unknown
1.1 root 11429: default:
1.1.1.22 root 11430: 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 11431: break;
11432: }
11433: break;
11434: case 0x17:
11435: // PC BIOS - Printer
1.1.1.22 root 11436: // 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 11437: break;
11438: case 0x1a:
11439: // PC BIOS - Timer
1.1.1.3 root 11440: m_CF = 0;
1.1 root 11441: switch(REG8(AH)) {
11442: case 0x00: pcbios_int_1ah_00h(); break;
11443: case 0x01: break;
11444: case 0x02: pcbios_int_1ah_02h(); break;
11445: case 0x03: break;
11446: case 0x04: pcbios_int_1ah_04h(); break;
11447: case 0x05: break;
11448: case 0x0a: pcbios_int_1ah_0ah(); break;
11449: case 0x0b: break;
1.1.1.14 root 11450: case 0x35: break; // Word Perfect Third Party Interface?
11451: case 0x36: break; // Word Perfect Third Party Interface
11452: case 0x70: break; // SNAP? (Simple Network Application Protocol)
1.1 root 11453: default:
1.1.1.22 root 11454: 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 11455: break;
11456: }
11457: break;
11458: case 0x20:
1.1.1.28 root 11459: try {
11460: msdos_process_terminate(SREG(CS), retval, 1);
11461: } catch(...) {
11462: fatalerror("failed to terminate the process (PSP=%04X) by int 20h\n", SREG(CS));
11463: }
1.1 root 11464: break;
11465: case 0x21:
11466: // MS-DOS System Call
1.1.1.3 root 11467: m_CF = 0;
1.1.1.28 root 11468: try {
11469: switch(REG8(AH)) {
11470: case 0x00: msdos_int_21h_00h(); break;
11471: case 0x01: msdos_int_21h_01h(); break;
11472: case 0x02: msdos_int_21h_02h(); break;
11473: case 0x03: msdos_int_21h_03h(); break;
11474: case 0x04: msdos_int_21h_04h(); break;
11475: case 0x05: msdos_int_21h_05h(); break;
11476: case 0x06: msdos_int_21h_06h(); break;
11477: case 0x07: msdos_int_21h_07h(); break;
11478: case 0x08: msdos_int_21h_08h(); break;
11479: case 0x09: msdos_int_21h_09h(); break;
11480: case 0x0a: msdos_int_21h_0ah(); break;
11481: case 0x0b: msdos_int_21h_0bh(); break;
11482: case 0x0c: msdos_int_21h_0ch(); break;
11483: case 0x0d: msdos_int_21h_0dh(); break;
11484: case 0x0e: msdos_int_21h_0eh(); break;
11485: case 0x0f: msdos_int_21h_0fh(); break;
11486: case 0x10: msdos_int_21h_10h(); break;
11487: case 0x11: msdos_int_21h_11h(); break;
11488: case 0x12: msdos_int_21h_12h(); break;
11489: case 0x13: msdos_int_21h_13h(); break;
11490: case 0x14: msdos_int_21h_14h(); break;
11491: case 0x15: msdos_int_21h_15h(); break;
11492: case 0x16: msdos_int_21h_16h(); break;
11493: case 0x17: msdos_int_21h_17h(); break;
11494: case 0x18: msdos_int_21h_18h(); break;
11495: case 0x19: msdos_int_21h_19h(); break;
11496: case 0x1a: msdos_int_21h_1ah(); break;
11497: case 0x1b: msdos_int_21h_1bh(); break;
11498: case 0x1c: msdos_int_21h_1ch(); break;
11499: case 0x1d: msdos_int_21h_1dh(); break;
11500: case 0x1e: msdos_int_21h_1eh(); break;
11501: case 0x1f: msdos_int_21h_1fh(); break;
11502: case 0x20: msdos_int_21h_20h(); break;
11503: case 0x21: msdos_int_21h_21h(); break;
11504: case 0x22: msdos_int_21h_22h(); break;
11505: case 0x23: msdos_int_21h_23h(); break;
11506: case 0x24: msdos_int_21h_24h(); break;
11507: case 0x25: msdos_int_21h_25h(); break;
11508: case 0x26: msdos_int_21h_26h(); break;
11509: case 0x27: msdos_int_21h_27h(); break;
11510: case 0x28: msdos_int_21h_28h(); break;
11511: case 0x29: msdos_int_21h_29h(); break;
11512: case 0x2a: msdos_int_21h_2ah(); break;
11513: case 0x2b: msdos_int_21h_2bh(); break;
11514: case 0x2c: msdos_int_21h_2ch(); break;
11515: case 0x2d: msdos_int_21h_2dh(); break;
11516: case 0x2e: msdos_int_21h_2eh(); break;
11517: case 0x2f: msdos_int_21h_2fh(); break;
11518: case 0x30: msdos_int_21h_30h(); break;
11519: case 0x31: msdos_int_21h_31h(); break;
11520: case 0x32: msdos_int_21h_32h(); break;
11521: case 0x33: msdos_int_21h_33h(); break;
11522: case 0x34: msdos_int_21h_34h(); break;
11523: case 0x35: msdos_int_21h_35h(); break;
11524: case 0x36: msdos_int_21h_36h(); break;
11525: case 0x37: msdos_int_21h_37h(); break;
11526: case 0x38: msdos_int_21h_38h(); break;
11527: case 0x39: msdos_int_21h_39h(0); break;
11528: case 0x3a: msdos_int_21h_3ah(0); break;
11529: case 0x3b: msdos_int_21h_3bh(0); break;
11530: case 0x3c: msdos_int_21h_3ch(); break;
11531: case 0x3d: msdos_int_21h_3dh(); break;
11532: case 0x3e: msdos_int_21h_3eh(); break;
11533: case 0x3f: msdos_int_21h_3fh(); break;
11534: case 0x40: msdos_int_21h_40h(); break;
11535: case 0x41: msdos_int_21h_41h(0); break;
11536: case 0x42: msdos_int_21h_42h(); break;
11537: case 0x43: msdos_int_21h_43h(0); break;
11538: case 0x44: msdos_int_21h_44h(); break;
11539: case 0x45: msdos_int_21h_45h(); break;
11540: case 0x46: msdos_int_21h_46h(); break;
11541: case 0x47: msdos_int_21h_47h(0); break;
11542: case 0x48: msdos_int_21h_48h(); break;
11543: case 0x49: msdos_int_21h_49h(); break;
11544: case 0x4a: msdos_int_21h_4ah(); break;
11545: case 0x4b: msdos_int_21h_4bh(); break;
11546: case 0x4c: msdos_int_21h_4ch(); break;
11547: case 0x4d: msdos_int_21h_4dh(); break;
11548: case 0x4e: msdos_int_21h_4eh(); break;
11549: case 0x4f: msdos_int_21h_4fh(); break;
11550: case 0x50: msdos_int_21h_50h(); break;
11551: case 0x51: msdos_int_21h_51h(); break;
11552: case 0x52: msdos_int_21h_52h(); break;
11553: // 0x53: translate bios parameter block to drive param bock
11554: case 0x54: msdos_int_21h_54h(); break;
11555: case 0x55: msdos_int_21h_55h(); break;
11556: case 0x56: msdos_int_21h_56h(0); break;
11557: case 0x57: msdos_int_21h_57h(); break;
11558: case 0x58: msdos_int_21h_58h(); break;
11559: case 0x59: msdos_int_21h_59h(); break;
11560: case 0x5a: msdos_int_21h_5ah(); break;
11561: case 0x5b: msdos_int_21h_5bh(); break;
11562: case 0x5c: msdos_int_21h_5ch(); break;
11563: case 0x5d: msdos_int_21h_5dh(); break;
11564: // 0x5e: ms-network
11565: // 0x5f: ms-network
11566: case 0x60: msdos_int_21h_60h(0); break;
11567: case 0x61: msdos_int_21h_61h(); break;
11568: case 0x62: msdos_int_21h_62h(); break;
11569: case 0x63: msdos_int_21h_63h(); break;
11570: // 0x64: set device driver lockahead flag
11571: case 0x65: msdos_int_21h_65h(); break;
11572: case 0x66: msdos_int_21h_66h(); break;
11573: case 0x67: msdos_int_21h_67h(); break;
11574: case 0x68: msdos_int_21h_68h(); break;
11575: case 0x69: msdos_int_21h_69h(); break;
11576: case 0x6a: msdos_int_21h_6ah(); break;
11577: case 0x6b: msdos_int_21h_6bh(); break;
11578: case 0x6c: msdos_int_21h_6ch(0); break;
11579: // 0x6d: find first rom program
11580: // 0x6e: find next rom program
11581: // 0x6f: get/set rom scan start address
11582: // 0x70: windows95 get/set internationalization information
11583: case 0x71:
11584: // windows95 long filename functions
11585: switch(REG8(AL)) {
11586: case 0x0d: msdos_int_21h_710dh(); break;
11587: case 0x39: msdos_int_21h_39h(1); break;
11588: case 0x3a: msdos_int_21h_3ah(1); break;
11589: case 0x3b: msdos_int_21h_3bh(1); break;
11590: case 0x41: msdos_int_21h_7141h(1); break;
11591: case 0x43: msdos_int_21h_43h(1); break;
11592: case 0x47: msdos_int_21h_47h(1); break;
11593: case 0x4e: msdos_int_21h_714eh(); break;
11594: case 0x4f: msdos_int_21h_714fh(); break;
11595: case 0x56: msdos_int_21h_56h(1); break;
11596: case 0x60: msdos_int_21h_60h(1); break;
11597: case 0x6c: msdos_int_21h_6ch(1); break;
11598: case 0xa0: msdos_int_21h_71a0h(); break;
11599: case 0xa1: msdos_int_21h_71a1h(); break;
11600: case 0xa6: msdos_int_21h_71a6h(); break;
11601: case 0xa7: msdos_int_21h_71a7h(); break;
11602: case 0xa8: msdos_int_21h_71a8h(); break;
11603: // 0xa9: server create/open file
11604: case 0xaa: msdos_int_21h_71aah(); break;
11605: default:
11606: 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));
11607: REG16(AX) = 0x7100;
11608: m_CF = 1;
11609: break;
11610: }
11611: break;
11612: // 0x72: Windows95 beta - LFN FindClose
11613: case 0x73:
11614: // windows95 fat32 functions
11615: switch(REG8(AL)) {
11616: case 0x00: msdos_int_21h_7300h(); break;
11617: // 0x01: set drive locking ???
11618: case 0x02: msdos_int_21h_7302h(); break;
11619: case 0x03: msdos_int_21h_7303h(); break;
11620: // 0x04: set dpb to use for formatting
11621: // 0x05: extended absolute disk read/write
11622: default:
11623: 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));
11624: REG16(AX) = 0x7300;
11625: m_CF = 1;
11626: break;
11627: }
1.1 root 11628: break;
11629: default:
1.1.1.22 root 11630: 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 11631: REG16(AX) = 0x01;
1.1.1.3 root 11632: m_CF = 1;
1.1 root 11633: break;
11634: }
1.1.1.28 root 11635: } catch(int error) {
11636: REG16(AX) = error;
11637: m_CF = 1;
11638: } catch(...) {
11639: REG16(AX) = 0x1f; // general failure
1.1.1.3 root 11640: m_CF = 1;
1.1 root 11641: }
1.1.1.3 root 11642: if(m_CF) {
1.1.1.23 root 11643: sda_t *sda = (sda_t *)(mem + SDA_TOP);
11644: sda->extended_error_code = REG16(AX);
11645: switch(sda->extended_error_code) {
11646: case 4: // Too many open files
11647: case 8: // Insufficient memory
11648: sda->error_class = 1; // Out of resource
11649: break;
11650: case 5: // Access denied
11651: sda->error_class = 3; // Authorization
11652: break;
11653: case 7: // Memory control block destroyed
11654: sda->error_class = 4; // Internal
11655: break;
11656: case 2: // File not found
11657: case 3: // Path not found
11658: case 15: // Invaid drive specified
11659: case 18: // No more files
11660: sda->error_class = 8; // Not found
11661: break;
11662: case 32: // Sharing violation
11663: case 33: // Lock violation
11664: sda->error_class = 10; // Locked
11665: break;
11666: // case 16: // Removal of current directory attempted
11667: case 19: // Attempted write on protected disk
11668: case 21: // Drive not ready
11669: // case 29: // Write failure
11670: // case 30: // Read failure
11671: // case 82: // Cannot create subdirectory
11672: sda->error_class = 11; // Media
11673: break;
11674: case 80: // File already exists
11675: sda->error_class = 12; // Already exist
11676: break;
11677: default:
11678: sda->error_class = 13; // Unknown
11679: break;
11680: }
11681: sda->suggested_action = 1; // Retry
11682: sda->locus_of_last_error = 1; // Unknown
1.1 root 11683: }
1.1.1.26 root 11684: if(ctrl_c_checking && ctrl_c_detected) {
11685: // raise int 23h
11686: #if defined(HAS_I386)
11687: m_ext = 0; // not an external interrupt
11688: i386_trap(0x23, 1, 0);
11689: m_ext = 1;
11690: #else
11691: PREFIX86(_interrupt)(0x23);
11692: #endif
11693: }
1.1 root 11694: break;
11695: case 0x22:
11696: fatalerror("int 22h (terminate address)\n");
11697: case 0x23:
1.1.1.28 root 11698: try {
11699: msdos_process_terminate(current_psp, (retval & 0xff) | 0x100, 1);
11700: } catch(...) {
11701: fatalerror("failed to terminate the current process by int 23h\n");
11702: }
1.1 root 11703: break;
11704: case 0x24:
1.1.1.28 root 11705: try {
11706: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
11707: } catch(...) {
11708: fatalerror("failed to terminate the current process by int 24h\n");
11709: }
1.1 root 11710: break;
11711: case 0x25:
11712: msdos_int_25h();
11713: break;
11714: case 0x26:
11715: msdos_int_26h();
11716: break;
11717: case 0x27:
1.1.1.28 root 11718: try {
11719: msdos_int_27h();
11720: } catch(...) {
11721: fatalerror("failed to terminate the process (PSP=%04X) by int 27h\n", SREG(CS));
11722: }
1.1 root 11723: break;
11724: case 0x28:
11725: Sleep(10);
11726: break;
11727: case 0x29:
11728: msdos_int_29h();
11729: break;
11730: case 0x2e:
11731: msdos_int_2eh();
11732: break;
11733: case 0x2f:
11734: // multiplex interrupt
11735: switch(REG8(AH)) {
1.1.1.22 root 11736: case 0x00: break;
11737: case 0x01: msdos_int_2fh_01h(); break;
1.1.1.29! root 11738: case 0x02: msdos_int_2fh_02h(); break;
1.1.1.22 root 11739: case 0x05: msdos_int_2fh_05h(); break;
11740: case 0x06: msdos_int_2fh_06h(); break;
11741: case 0x08: msdos_int_2fh_08h(); break;
11742: case 0x10: msdos_int_2fh_10h(); break;
11743: case 0x11: msdos_int_2fh_11h(); break;
1.1.1.21 root 11744: case 0x12: msdos_int_2fh_12h(); break;
1.1.1.22 root 11745: case 0x14: msdos_int_2fh_14h(); break;
11746: case 0x15: msdos_int_2fh_15h(); break;
1.1 root 11747: case 0x16: msdos_int_2fh_16h(); break;
1.1.1.29! root 11748: case 0x17: msdos_int_2fh_17h(); break;
1.1.1.22 root 11749: case 0x19: msdos_int_2fh_19h(); break;
1.1 root 11750: case 0x1a: msdos_int_2fh_1ah(); break;
1.1.1.22 root 11751: case 0x1b: msdos_int_2fh_1bh(); break;
1.1.1.29! root 11752: case 0x27: msdos_int_2fh_27h(); break;
! 11753: case 0x2e: msdos_int_2fh_2eh(); break;
1.1 root 11754: case 0x43: msdos_int_2fh_43h(); break;
1.1.1.29! root 11755: case 0x45: msdos_int_2fh_45h(); break;
1.1.1.22 root 11756: case 0x46: msdos_int_2fh_46h(); break;
11757: case 0x48: msdos_int_2fh_48h(); break;
1.1 root 11758: case 0x4a: msdos_int_2fh_4ah(); break;
1.1.1.22 root 11759: case 0x4b: msdos_int_2fh_4bh(); break;
11760: case 0x4c: break; // unknown
11761: case 0x4d: break; // unknown
11762: case 0x4e: break; // unknown
1.1 root 11763: case 0x4f: msdos_int_2fh_4fh(); break;
1.1.1.29! root 11764: case 0x54: msdos_int_2fh_54h(); break;
1.1.1.22 root 11765: case 0x55: msdos_int_2fh_55h(); break;
1.1.1.29! root 11766: case 0x56: msdos_int_2fh_56h(); break;
1.1.1.22 root 11767: case 0x58: break; // unknown
11768: case 0x74: break; // unknown
1.1.1.29! root 11769: case 0xac: msdos_int_2fh_ach(); break;
1.1.1.24 root 11770: case 0xad: msdos_int_2fh_adh(); break;
1.1 root 11771: case 0xae: msdos_int_2fh_aeh(); break;
1.1.1.29! root 11772: case 0xb0: msdos_int_2fh_b0h(); break;
1.1 root 11773: case 0xb7: msdos_int_2fh_b7h(); break;
1.1.1.29! root 11774: case 0xb8: msdos_int_2fh_b8h(); break;
! 11775: case 0xb9: msdos_int_2fh_b9h(); break;
! 11776: case 0xbc: msdos_int_2fh_bch(); break;
1.1.1.22 root 11777: case 0xe9: break; // unknown
11778: case 0xfe: break; // norton utilities ???
11779: default:
11780: 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));
11781: break;
1.1 root 11782: }
11783: break;
1.1.1.24 root 11784: case 0x33:
11785: switch(REG8(AH)) {
11786: case 0x00:
11787: // Mouse
11788: switch(REG8(AL)) {
11789: case 0x00: msdos_int_33h_0000h(); break;
11790: case 0x01: msdos_int_33h_0001h(); break;
11791: case 0x02: msdos_int_33h_0002h(); break;
11792: case 0x03: msdos_int_33h_0003h(); break;
11793: case 0x04: break; // position mouse cursor
11794: case 0x05: msdos_int_33h_0005h(); break;
11795: case 0x06: msdos_int_33h_0006h(); break;
11796: case 0x07: msdos_int_33h_0007h(); break;
11797: case 0x08: msdos_int_33h_0008h(); break;
11798: case 0x09: msdos_int_33h_0009h(); break;
11799: case 0x0a: break; // define text cursor
11800: case 0x0b: msdos_int_33h_000bh(); break;
11801: case 0x0c: msdos_int_33h_000ch(); break;
11802: case 0x0d: break; // light pen emulation on
11803: case 0x0e: break; // light pen emulation off
11804: case 0x0f: msdos_int_33h_000fh(); break;
11805: case 0x10: break; // define screen region for updating
11806: case 0x11: msdos_int_33h_0011h(); break;
11807: case 0x12: REG16(AX) = 0xffff; break; // set large graphics cursor block
11808: case 0x13: break; // define double-speed threshold
11809: case 0x14: msdos_int_33h_0014h(); break;
11810: case 0x15: msdos_int_33h_0015h(); break;
11811: case 0x16: msdos_int_33h_0016h(); break;
11812: case 0x17: msdos_int_33h_0017h(); break;
11813: case 0x1a: msdos_int_33h_001ah(); break;
11814: case 0x1b: msdos_int_33h_001bh(); break;
11815: case 0x1d: msdos_int_33h_001dh(); break;
11816: case 0x1e: msdos_int_33h_001eh(); break;
11817: case 0x21: msdos_int_33h_0021h(); break;
11818: case 0x22: msdos_int_33h_0022h(); break;
11819: case 0x23: msdos_int_33h_0023h(); break;
11820: case 0x24: msdos_int_33h_0024h(); break;
11821: case 0x26: msdos_int_33h_0026h(); break;
11822: case 0x2a: msdos_int_33h_002ah(); break;
11823: case 0x2f: break; // mouse hardware reset
11824: case 0x31: msdos_int_33h_0031h(); break;
11825: case 0x32: msdos_int_33h_0032h(); break;
11826: default:
11827: 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));
11828: break;
11829: }
11830: break;
11831: default:
11832: 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));
11833: break;
11834: }
11835: break;
1.1.1.19 root 11836: case 0x68:
11837: // dummy interrupt for EMS (int 67h)
11838: switch(REG8(AH)) {
11839: case 0x40: msdos_int_67h_40h(); break;
11840: case 0x41: msdos_int_67h_41h(); break;
11841: case 0x42: msdos_int_67h_42h(); break;
11842: case 0x43: msdos_int_67h_43h(); break;
11843: case 0x44: msdos_int_67h_44h(); break;
11844: case 0x45: msdos_int_67h_45h(); break;
11845: case 0x46: msdos_int_67h_46h(); break;
11846: case 0x47: msdos_int_67h_47h(); break;
11847: case 0x48: msdos_int_67h_48h(); break;
1.1.1.20 root 11848: // 0x49: LIM EMS - Reserved - Get I/O Port Address (Undocumented in EMS 3.2)
11849: // 0x4a: LIM EMS - Reserved - Get Translation Array (Undocumented in EMS 3.2)
1.1.1.19 root 11850: case 0x4b: msdos_int_67h_4bh(); break;
11851: case 0x4c: msdos_int_67h_4ch(); break;
11852: case 0x4d: msdos_int_67h_4dh(); break;
1.1.1.20 root 11853: case 0x4e: msdos_int_67h_4eh(); break;
1.1.1.21 root 11854: case 0x4f: msdos_int_67h_4fh(); break;
1.1.1.20 root 11855: case 0x50: msdos_int_67h_50h(); break;
1.1.1.19 root 11856: case 0x51: msdos_int_67h_51h(); break;
1.1.1.20 root 11857: case 0x52: msdos_int_67h_52h(); break;
1.1.1.19 root 11858: case 0x53: msdos_int_67h_53h(); break;
11859: case 0x54: msdos_int_67h_54h(); break;
1.1.1.20 root 11860: // 0x55: LIM EMS 4.0 - Alter Page Map And JUMP
11861: // 0x56: LIM EMS 4.0 - Alter Page Map And CALL
11862: case 0x57: msdos_int_67h_57h(); break;
11863: case 0x58: msdos_int_67h_58h(); break;
11864: // 0x59: LIM EMS 4.0 - Get Expanded Memory Hardware Information (for DOS Kernel)
11865: case 0x5a: msdos_int_67h_5ah(); break;
11866: // 0x5b: LIM EMS 4.0 - Alternate Map Register Set (for DOS Kernel)
11867: // 0x5c: LIM EMS 4.0 - Prepate Expanded Memory Hardware For Warm Boot
11868: // 0x5d: LIM EMS 4.0 - Enable/Disable OS Function Set Functions (for DOS Kernel)
1.1.1.19 root 11869: default:
1.1.1.22 root 11870: 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 11871: REG8(AH) = 0x84;
11872: break;
11873: }
11874: break;
11875: #ifdef SUPPORT_XMS
11876: case 0x69:
11877: // dummy interrupt for XMS (call far)
1.1.1.28 root 11878: try {
11879: switch(REG8(AH)) {
11880: case 0x00: msdos_call_xms_00h(); break;
11881: case 0x01: msdos_call_xms_01h(); break;
11882: case 0x02: msdos_call_xms_02h(); break;
11883: case 0x03: msdos_call_xms_03h(); break;
11884: case 0x04: msdos_call_xms_04h(); break;
11885: case 0x05: msdos_call_xms_05h(); break;
11886: case 0x06: msdos_call_xms_06h(); break;
11887: case 0x07: msdos_call_xms_07h(); break;
11888: case 0x08: msdos_call_xms_08h(); break;
11889: case 0x09: msdos_call_xms_09h(); break;
11890: case 0x0a: msdos_call_xms_0ah(); break;
11891: case 0x0b: msdos_call_xms_0bh(); break;
11892: case 0x0c: msdos_call_xms_0ch(); break;
11893: case 0x0d: msdos_call_xms_0dh(); break;
11894: case 0x0e: msdos_call_xms_0eh(); break;
11895: case 0x0f: msdos_call_xms_0fh(); break;
11896: case 0x10: msdos_call_xms_10h(); break;
11897: case 0x11: msdos_call_xms_11h(); break;
11898: case 0x12: msdos_call_xms_12h(); break;
1.1.1.29! root 11899: #if defined(HAS_I386)
! 11900: case 0x88: msdos_call_xms_88h(); break;
! 11901: case 0x89: msdos_call_xms_89h(); break;
! 11902: case 0x8e: msdos_call_xms_8eh(); break;
! 11903: case 0x8f: msdos_call_xms_8fh(); break;
! 11904: #endif
1.1.1.28 root 11905: default:
11906: 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));
11907: REG16(AX) = 0x0000;
11908: REG8(BL) = 0x80; // function not implemented
11909: break;
11910: }
11911: } catch(...) {
1.1.1.19 root 11912: REG16(AX) = 0x0000;
1.1.1.28 root 11913: REG8(BL) = 0x8f; // unrecoverable driver error
1.1.1.19 root 11914: }
11915: break;
11916: #endif
11917: case 0x6a:
1.1.1.24 root 11918: // irq12 (mouse)
11919: mouse_push_ax = REG16(AX);
11920: mouse_push_bx = REG16(BX);
11921: mouse_push_cx = REG16(CX);
11922: mouse_push_dx = REG16(DX);
11923: mouse_push_si = REG16(SI);
11924: mouse_push_di = REG16(DI);
11925:
11926: if(mouse.active && mouse.call_addr.dw != 0) {
11927: REG16(AX) = mouse.status_irq;
11928: REG16(BX) = mouse.get_buttons();
11929: REG16(CX) = max(mouse.min_position.x, min(mouse.max_position.x, mouse.position.x));
11930: REG16(DX) = max(mouse.min_position.y, min(mouse.max_position.y, mouse.position.y));
11931: REG16(SI) = REG16(CX) * mouse.mickey.x / 8;
11932: REG16(DI) = REG16(DX) * mouse.mickey.y / 8;
11933:
11934: mem[0xfffd0 + 0x02] = 0x9a; // call far
11935: mem[0xfffd0 + 0x03] = mouse.call_addr.w.l & 0xff;
11936: mem[0xfffd0 + 0x04] = mouse.call_addr.w.l >> 8;
11937: mem[0xfffd0 + 0x05] = mouse.call_addr.w.h & 0xff;
11938: mem[0xfffd0 + 0x06] = mouse.call_addr.w.h >> 8;
11939: } else {
11940: mem[0xfffd0 + 0x02] = 0x90; // nop
11941: mem[0xfffd0 + 0x03] = 0x90; // nop
11942: mem[0xfffd0 + 0x04] = 0x90; // nop
11943: mem[0xfffd0 + 0x05] = 0x90; // nop
11944: mem[0xfffd0 + 0x06] = 0x90; // nop
11945: }
11946: break;
11947: case 0x6b:
11948: // end of irq12 (mouse)
11949: REG16(AX) = mouse_push_ax;
11950: REG16(BX) = mouse_push_bx;
11951: REG16(CX) = mouse_push_cx;
11952: REG16(DX) = mouse_push_dx;
11953: REG16(SI) = mouse_push_si;
11954: REG16(DI) = mouse_push_di;
11955:
11956: // EOI
11957: if((pic[1].isr &= ~(1 << 4)) == 0) {
11958: pic[0].isr &= ~(1 << 2); // master
11959: }
11960: pic_update();
11961: break;
11962: case 0x6c:
1.1.1.19 root 11963: // dummy interrupt for case map routine pointed in the country info
11964: if(REG8(AL) >= 0x80) {
11965: char tmp[2] = {0};
11966: tmp[0] = REG8(AL);
11967: my_strupr(tmp);
11968: REG8(AL) = tmp[0];
11969: }
11970: break;
1.1.1.27 root 11971: case 0x6d:
11972: // dummy interrupt for font read routine pointed by int 15h, ax=5000h
11973: REG8(AL) = 0x86; // not supported
11974: m_CF = 1;
11975: break;
1.1.1.8 root 11976: case 0x70:
11977: case 0x71:
11978: case 0x72:
11979: case 0x73:
11980: case 0x74:
11981: case 0x75:
11982: case 0x76:
11983: case 0x77:
11984: // EOI
11985: if((pic[1].isr &= ~(1 << (num - 0x70))) == 0) {
11986: pic[0].isr &= ~(1 << 2); // master
11987: }
11988: pic_update();
11989: break;
1.1 root 11990: default:
1.1.1.22 root 11991: // 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 11992: break;
11993: }
11994:
11995: // update cursor position
11996: if(cursor_moved) {
11997: CONSOLE_SCREEN_BUFFER_INFO csbi;
1.1.1.23 root 11998: GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
1.1.1.15 root 11999: if(!restore_console_on_exit) {
12000: scr_top = csbi.srWindow.Top;
12001: }
1.1 root 12002: mem[0x450 + mem[0x462] * 2] = csbi.dwCursorPosition.X;
1.1.1.14 root 12003: mem[0x451 + mem[0x462] * 2] = csbi.dwCursorPosition.Y - scr_top;
1.1 root 12004: cursor_moved = false;
12005: }
12006: }
12007:
12008: // init
12009:
12010: int msdos_init(int argc, char *argv[], char *envp[], int standard_env)
12011: {
12012: // init file handler
12013: memset(file_handler, 0, sizeof(file_handler));
12014: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
12015: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
12016: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
1.1.1.21 root 12017: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 12018: if(_open("stdaux.txt", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
1.1.1.21 root 12019: #else
12020: if(_open("NUL", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
12021: #endif
12022: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
1.1 root 12023: }
1.1.1.21 root 12024: #ifdef MAP_PRN_DEVICE_TO_FILE
1.1 root 12025: if(_open("stdprn.txt", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
1.1.1.21 root 12026: #else
12027: if(_open("NUL", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
1.1 root 12028: #endif
1.1.1.21 root 12029: msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0);
12030: }
1.1 root 12031: _dup2(0, DUP_STDIN);
12032: _dup2(1, DUP_STDOUT);
12033: _dup2(2, DUP_STDERR);
1.1.1.21 root 12034: _dup2(3, DUP_STDAUX);
12035: _dup2(4, DUP_STDPRN);
1.1 root 12036:
1.1.1.24 root 12037: // init mouse
12038: memset(&mouse, 0, sizeof(mouse));
12039: mouse.max_position.x = 8 * scr_width - 1;
12040: mouse.max_position.y = 8 * scr_height - 1;
12041: mouse.mickey.x = 8;
12042: mouse.mickey.y = 16;
12043:
1.1.1.26 root 12044: #ifdef SUPPORT_XMS
12045: // init xms
12046: msdos_xms_init();
12047: #endif
12048:
1.1 root 12049: // init process
12050: memset(process, 0, sizeof(process));
12051:
1.1.1.13 root 12052: // init dtainfo
12053: msdos_dta_info_init();
12054:
1.1 root 12055: // init memory
12056: memset(mem, 0, sizeof(mem));
12057:
12058: // bios data area
1.1.1.23 root 12059: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 12060: CONSOLE_SCREEN_BUFFER_INFO csbi;
12061: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 12062: CONSOLE_FONT_INFO cfi;
12063: GetCurrentConsoleFont(hStdout, FALSE, &cfi);
12064:
12065: int regen = min(scr_width * scr_height * 2, 0x8000);
12066: text_vram_top_address = TEXT_VRAM_TOP;
12067: text_vram_end_address = text_vram_top_address + regen;
12068: shadow_buffer_top_address = SHADOW_BUF_TOP;
12069: shadow_buffer_end_address = shadow_buffer_top_address + regen;
12070:
12071: if(regen > 0x4000) {
12072: regen = 0x8000;
12073: vram_pages = 1;
12074: } else if(regen > 0x2000) {
12075: regen = 0x4000;
12076: vram_pages = 2;
12077: } else if(regen > 0x1000) {
12078: regen = 0x2000;
12079: vram_pages = 4;
12080: } else {
12081: regen = 0x1000;
12082: vram_pages = 8;
12083: }
1.1 root 12084:
1.1.1.25 root 12085: *(UINT16 *)(mem + 0x400) = 0x3f8; // com1 port address
12086: *(UINT16 *)(mem + 0x402) = 0x2f8; // com2 port address
1.1.1.29! root 12087: *(UINT16 *)(mem + 0x404) = 0x3e8; // com3 port address
! 12088: *(UINT16 *)(mem + 0x406) = 0x2e8; // com4 port address
1.1.1.25 root 12089: *(UINT16 *)(mem + 0x408) = 0x378; // lpt1 port address
1.1.1.26 root 12090: // *(UINT16 *)(mem + 0x40a) = 0x278; // lpt2 port address
1.1.1.25 root 12091: // *(UINT16 *)(mem + 0x40c) = 0x3bc; // lpt3 port address
12092: *(UINT16 *)(mem + 0x40e) = EXT_BIOS_TOP >> 4;
1.1.1.26 root 12093: *(UINT16 *)(mem + 0x410) = msdos_get_equipment();
1.1 root 12094: *(UINT16 *)(mem + 0x413) = MEMORY_END / 1024;
12095: *(UINT8 *)(mem + 0x449) = 0x03;//0x73;
1.1.1.14 root 12096: *(UINT16 *)(mem + 0x44a) = csbi.dwSize.X;
12097: *(UINT16 *)(mem + 0x44c) = regen;
1.1 root 12098: *(UINT16 *)(mem + 0x44e) = 0;
12099: *(UINT8 *)(mem + 0x450) = csbi.dwCursorPosition.X;
1.1.1.14 root 12100: *(UINT8 *)(mem + 0x451) = csbi.dwCursorPosition.Y - scr_top;
1.1 root 12101: *(UINT8 *)(mem + 0x460) = 7;
12102: *(UINT8 *)(mem + 0x461) = 7;
12103: *(UINT8 *)(mem + 0x462) = 0;
12104: *(UINT16 *)(mem + 0x463) = 0x3d4;
1.1.1.19 root 12105: *(UINT8 *)(mem + 0x465) = 0x09;
12106: *(UINT32 *)(mem + 0x46c) = get_ticks_since_midnight(timeGetTime());
1.1.1.14 root 12107: *(UINT8 *)(mem + 0x484) = csbi.srWindow.Bottom - csbi.srWindow.Top;
12108: *(UINT8 *)(mem + 0x485) = cfi.dwFontSize.Y;
12109: *(UINT8 *)(mem + 0x487) = 0x60;
12110: *(UINT8 *)(mem + 0x496) = 0x10; // enhanced keyboard installed
1.1.1.25 root 12111: *(UINT16 *)(mem + EXT_BIOS_TOP) = 1;
1.1.1.14 root 12112:
12113: // initial screen
12114: SMALL_RECT rect;
12115: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
12116: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
12117: for(int y = 0, ofs1 = TEXT_VRAM_TOP, ofs2 = SHADOW_BUF_TOP; y < scr_height; y++) {
12118: for(int x = 0; x < scr_width; x++) {
12119: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Char.AsciiChar;
12120: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Attributes;
12121: }
12122: }
1.1 root 12123:
1.1.1.19 root 12124: // init mcb
1.1 root 12125: int seg = MEMORY_TOP >> 4;
1.1.1.19 root 12126:
12127: // iret table
12128: // note: int 2eh vector should address the routine in command.com,
12129: // and some softwares invite (int 2eh vector segment) - 1 must address the mcb of command.com.
12130: // so move iret table into allocated memory block
12131: // http://www5c.biglobe.ne.jp/~ecb/assembler2/2_6.html
12132: msdos_mcb_create(seg++, 'M', -1, IRET_SIZE >> 4);
12133: IRET_TOP = seg << 4;
12134: seg += IRET_SIZE >> 4;
1.1.1.25 root 12135: memset(mem + IRET_TOP, 0xcf, IRET_SIZE); // iret
1.1.1.19 root 12136:
12137: // dummy xms/ems device
12138: msdos_mcb_create(seg++, 'M', -1, XMS_SIZE >> 4);
12139: XMS_TOP = seg << 4;
12140: seg += XMS_SIZE >> 4;
12141:
12142: // environment
1.1 root 12143: msdos_mcb_create(seg++, 'M', -1, ENV_SIZE >> 4);
12144: int env_seg = seg;
12145: int ofs = 0;
1.1.1.28 root 12146: char env_msdos_path[ENV_SIZE] = "", env_path[ENV_SIZE] = "", env_temp[ENV_SIZE] = "", *path;
1.1 root 12147:
1.1.1.28 root 12148: if((path = getenv("MSDOS_PATH")) != NULL) {
12149: strcpy(env_msdos_path, msdos_get_multiple_short_path(path));
12150: if(env_msdos_path[0] != '\0') {
12151: strcat(env_path, env_msdos_path);
1.1.1.14 root 12152: }
12153: }
1.1.1.28 root 12154: if((path = getenv("PATH")) != NULL) {
12155: if(env_path[0] != '\0') {
12156: strcat(env_path, ";");
1.1.1.9 root 12157: }
1.1.1.28 root 12158: strcat(env_path, msdos_get_multiple_short_path(path));
1.1.1.9 root 12159: }
1.1.1.28 root 12160: if((path = getenv("MSDOS_TEMP")) != NULL || (path = getenv("TEMP")) != NULL || (path = getenv("TMP")) != NULL) {
12161: strcpy(env_temp, msdos_get_multiple_short_path(path));
1.1.1.15 root 12162: }
1.1.1.28 root 12163: if((path = getenv("MSDOS_COMSPEC")) != NULL || (path = msdos_search_command_com(argv[0], env_path)) != NULL) {
12164: strcpy(comspec_path, msdos_get_multiple_short_path(path));
1.1.1.24 root 12165: }
1.1.1.9 root 12166: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1 root 12167: // lower to upper
1.1.1.28 root 12168: char tmp[ENV_SIZE], name[ENV_SIZE];
1.1 root 12169: strcpy(tmp, *p);
12170: for(int i = 0;; i++) {
12171: if(tmp[i] == '=') {
12172: tmp[i] = '\0';
12173: sprintf(name, ";%s;", tmp);
1.1.1.25 root 12174: my_strupr(name);
1.1 root 12175: tmp[i] = '=';
12176: break;
12177: } else if(tmp[i] >= 'a' && tmp[i] <= 'z') {
1.1.1.28 root 12178: tmp[i] = (tmp[i] - 'a') + 'A';
1.1 root 12179: }
12180: }
1.1.1.18 root 12181: if(strncmp(tmp, "MSDOS_COMSPEC=", 14) == 0) {
12182: // ignore MSDOS_COMSPEC
1.1.1.24 root 12183: } else if(strncmp(tmp, "MSDOS_TEMP=", 11) == 0) {
12184: // ignore MSDOS_TEMP
1.1.1.28 root 12185: } else if(standard_env && strstr(";COMSPEC;INCLUDE;LIB;MSDOS_PATH;PATH;PROMPT;TEMP;TMP;TZ;", name) == NULL) {
1.1.1.18 root 12186: // ignore non standard environments
12187: } else {
1.1 root 12188: if(strncmp(tmp, "COMSPEC=", 8) == 0) {
1.1.1.14 root 12189: strcpy(tmp, "COMSPEC=C:\\COMMAND.COM");
1.1.1.28 root 12190: } else if(strncmp(tmp, "MSDOS_PATH=", 11) == 0) {
12191: if(env_msdos_path[0] != '\0') {
12192: sprintf(tmp, "MSDOS_PATH=%s", env_msdos_path);
12193: } else {
12194: sprintf(tmp, "MSDOS_PATH=%s", msdos_get_multiple_short_path(tmp + 11));
12195: }
12196: } else if(strncmp(tmp, "PATH=", 5) == 0) {
12197: if(env_path[0] != '\0') {
12198: sprintf(tmp, "PATH=%s", env_path);
12199: } else {
12200: sprintf(tmp, "PATH=%s", msdos_get_multiple_short_path(tmp + 5));
12201: }
12202: } else if(strncmp(tmp, "TEMP=", 5) == 0) {
12203: if(env_temp[0] != '\0') {
12204: sprintf(tmp, "TEMP=%s", env_temp);
12205: } else {
12206: sprintf(tmp, "TEMP=%s", msdos_get_multiple_short_path(tmp + 5));
12207: }
12208: } else if(strncmp(tmp, "TMP=", 4) == 0) {
12209: if(env_temp[0] != '\0') {
12210: sprintf(tmp, "TMP=%s", env_temp);
12211: } else {
12212: sprintf(tmp, "TMP=%s", msdos_get_multiple_short_path(tmp + 4));
1.1 root 12213: }
12214: }
12215: int len = strlen(tmp);
1.1.1.14 root 12216: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) {
1.1 root 12217: fatalerror("too many environments\n");
12218: }
12219: memcpy(mem + (seg << 4) + ofs, tmp, len);
12220: ofs += len + 1;
12221: }
12222: }
12223: seg += (ENV_SIZE >> 4);
12224:
12225: // psp
12226: msdos_mcb_create(seg++, 'M', -1, PSP_SIZE >> 4);
12227: current_psp = seg;
1.1.1.14 root 12228: msdos_psp_create(seg, seg + (PSP_SIZE >> 4), -1, env_seg);
1.1 root 12229: seg += (PSP_SIZE >> 4);
12230:
1.1.1.19 root 12231: // first free mcb in conventional memory
12232: msdos_mcb_create(seg, 'Z', 0, (MEMORY_END >> 4) - seg - 2);
1.1.1.8 root 12233: first_mcb = seg;
12234:
1.1.1.19 root 12235: // dummy mcb to link to umb
12236: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', -1, (UMB_TOP >> 4) - (MEMORY_END >> 4));
12237:
12238: // first free mcb in upper memory block
1.1.1.8 root 12239: msdos_mcb_create(UMB_TOP >> 4, 'Z', 0, (UMB_END >> 4) - (UMB_TOP >> 4) - 1);
1.1 root 12240:
1.1.1.29! root 12241: #ifdef SUPPORT_HMA
! 12242: // first free mcb in high memory area
! 12243: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
! 12244: #endif
! 12245:
1.1.1.19 root 12246: #ifdef SUPPORT_XMS
12247: // first free mcb in extended memory block
12248: msdos_mcb_create(EMB_TOP >> 4, 'Z', 0, (EMB_END >> 4) - (EMB_TOP >> 4) - 1);
12249: #endif
12250:
1.1.1.26 root 12251: // interrupt vector
12252: for(int i = 0; i < 0x80; i++) {
12253: *(UINT16 *)(mem + 4 * i + 0) = i;
12254: *(UINT16 *)(mem + 4 * i + 2) = (IRET_TOP >> 4);
12255: }
12256: *(UINT16 *)(mem + 4 * 0x08 + 0) = 0x0010; // fffd:0010 irq0 (system timer)
12257: *(UINT16 *)(mem + 4 * 0x08 + 2) = 0xfffd;
12258: *(UINT16 *)(mem + 4 * 0x22 + 0) = 0x0000; // ffff:0000 boot
12259: *(UINT16 *)(mem + 4 * 0x22 + 2) = 0xffff;
12260: *(UINT16 *)(mem + 4 * 0x67 + 0) = 0x0012; // xxxx:0012 ems
12261: *(UINT16 *)(mem + 4 * 0x67 + 2) = XMS_TOP >> 4;
12262: *(UINT16 *)(mem + 4 * 0x74 + 0) = 0x0000; // fffd:0000 irq12 (mouse)
12263: *(UINT16 *)(mem + 4 * 0x74 + 2) = 0xfffd;
12264:
1.1.1.29! root 12265: // dummy devices (NUL -> CON -> ... -> CONFIG$ -> EMMXXXX0)
1.1.1.26 root 12266: static const struct {
12267: UINT16 attributes;
12268: char *dev_name;
12269: } dummy_devices[] = {
12270: {0x8013, "CON "},
12271: {0x8000, "AUX "},
12272: {0xa0c0, "PRN "},
12273: {0x8008, "CLOCK$ "},
12274: {0x8000, "COM1 "},
12275: {0xa0c0, "LPT1 "},
12276: {0xa0c0, "LPT2 "},
12277: {0xa0c0, "LPT3 "},
12278: {0x8000, "COM2 "},
12279: {0x8000, "COM3 "},
12280: {0x8000, "COM4 "},
12281: {0xc000, "CONFIG$ "},
12282: };
12283: static const UINT8 dummy_device_routine[] = {
12284: // from NUL device of Windows 98 SE
12285: // or word ptr ES:[BX+03],0100
12286: 0x26, 0x81, 0x4f, 0x03, 0x00, 0x01,
12287: // retf
12288: 0xcb,
12289: };
1.1.1.29! root 12290: device_t *last = NULL;
1.1.1.26 root 12291: for(int i = 0; i < 12; i++) {
12292: device_t *device = (device_t *)(mem + DEVICE_TOP + 22 + 18 * i);
1.1.1.29! root 12293: device->next_driver.w.l = 22 + 18 * (i + 1);
! 12294: device->next_driver.w.h = DEVICE_TOP >> 4;
1.1.1.26 root 12295: device->attributes = dummy_devices[i].attributes;
1.1.1.29! root 12296: device->strategy = DEVICE_SIZE - sizeof(dummy_device_routine);
! 12297: device->interrupt = DEVICE_SIZE - sizeof(dummy_device_routine) + 6;
1.1.1.26 root 12298: memcpy(device->dev_name, dummy_devices[i].dev_name, 8);
1.1.1.29! root 12299: last = device;
! 12300: }
! 12301: if(last != NULL) {
! 12302: last->next_driver.w.l = 0;
! 12303: last->next_driver.w.h = XMS_TOP >> 4;
1.1.1.26 root 12304: }
1.1.1.29! root 12305: memcpy(mem + DEVICE_TOP + DEVICE_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.26 root 12306:
1.1.1.25 root 12307: // dos info
12308: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
12309: dos_info->magic_word = 1;
12310: dos_info->first_mcb = MEMORY_TOP >> 4;
12311: dos_info->first_dpb.w.l = 0;
12312: dos_info->first_dpb.w.h = DPB_TOP >> 4;
12313: dos_info->first_sft.w.l = 0;
12314: dos_info->first_sft.w.h = SFT_TOP >> 4;
1.1.1.26 root 12315: dos_info->clock_device.w.l = 22 + 18 * 3; // CLOCK$ is the 3rd device in IO.SYS
1.1.1.25 root 12316: dos_info->clock_device.w.h = DEVICE_TOP >> 4;
1.1.1.26 root 12317: dos_info->con_device.w.l = 22 + 18 * 0; // CON is the 1st device in IO.SYS
1.1.1.25 root 12318: dos_info->con_device.w.h = DEVICE_TOP >> 4;
12319: dos_info->max_sector_len = 512;
12320: dos_info->disk_buf_info.w.l = offsetof(dos_info_t, disk_buf_heads);
12321: dos_info->disk_buf_info.w.h = DOS_INFO_TOP >> 4;
12322: dos_info->cds.w.l = 0;
12323: dos_info->cds.w.h = CDS_TOP >> 4;
12324: dos_info->fcb_table.w.l = 0;
12325: dos_info->fcb_table.w.h = FCB_TABLE_TOP >> 4;
12326: dos_info->last_drive = 'Z' - 'A' + 1;
12327: dos_info->buffers_x = 20;
12328: dos_info->buffers_y = 0;
12329: dos_info->boot_drive = 'C' - 'A' + 1;
1.1.1.29! root 12330: dos_info->nul_device.next_driver.w.l = 22;
! 12331: dos_info->nul_device.next_driver.w.h = DEVICE_TOP >> 4;
1.1.1.25 root 12332: dos_info->nul_device.attributes = 0x8004;
1.1.1.29! root 12333: dos_info->nul_device.strategy = DOS_INFO_SIZE - sizeof(dummy_device_routine);
! 12334: dos_info->nul_device.interrupt = DOS_INFO_SIZE - sizeof(dummy_device_routine) + 6;
1.1.1.25 root 12335: memcpy(dos_info->nul_device.dev_name, "NUL ", 8);
12336: dos_info->disk_buf_heads.w.l = 0;
12337: dos_info->disk_buf_heads.w.h = DISK_BUF_TOP >> 4;
12338: dos_info->first_umb_fcb = UMB_TOP >> 4;
12339: dos_info->first_mcb_2 = MEMORY_TOP >> 4;
1.1.1.29! root 12340: memcpy(mem + DOS_INFO_TOP + DOS_INFO_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.25 root 12341:
12342: char *env;
12343: if((env = getenv("LASTDRIVE")) != NULL) {
12344: if(env[0] >= 'A' && env[0] <= 'Z') {
12345: dos_info->last_drive = env[0] - 'A' + 1;
12346: } else if(env[0] >= 'a' && env[0] <= 'z') {
12347: dos_info->last_drive = env[0] - 'a' + 1;
12348: }
12349: }
12350: if((env = getenv("windir")) != NULL) {
12351: if(env[0] >= 'A' && env[0] <= 'Z') {
12352: dos_info->boot_drive = env[0] - 'A' + 1;
12353: } else if(env[0] >= 'a' && env[0] <= 'z') {
12354: dos_info->boot_drive = env[0] - 'a' + 1;
12355: }
12356: }
12357: #if defined(HAS_I386)
12358: dos_info->i386_or_later = 1;
12359: #else
12360: dos_info->i386_or_later = 0;
12361: #endif
12362: dos_info->ext_mem_size = (min(MAX_MEM, 0x4000000) - 0x100000) >> 10;
12363:
1.1.1.27 root 12364: // ems (int 67h) and xms
1.1.1.25 root 12365: device_t *xms_device = (device_t *)(mem + XMS_TOP);
12366: xms_device->next_driver.w.l = 0xffff;
12367: xms_device->next_driver.w.h = 0xffff;
12368: xms_device->attributes = 0xc000;
1.1.1.29! root 12369: xms_device->strategy = XMS_SIZE - sizeof(dummy_device_routine);
! 12370: xms_device->interrupt = XMS_SIZE - sizeof(dummy_device_routine) + 6;
1.1.1.25 root 12371: memcpy(xms_device->dev_name, "EMMXXXX0", 8);
12372:
1.1.1.26 root 12373: mem[XMS_TOP + 0x12] = 0xcd; // int 68h (dummy)
12374: mem[XMS_TOP + 0x13] = 0x68;
12375: mem[XMS_TOP + 0x14] = 0xcf; // iret
1.1.1.19 root 12376: #ifdef SUPPORT_XMS
12377: if(support_xms) {
1.1.1.26 root 12378: mem[XMS_TOP + 0x15] = 0xcd; // int 69h (dummy)
12379: mem[XMS_TOP + 0x16] = 0x69;
12380: mem[XMS_TOP + 0x17] = 0xcb; // retf
1.1.1.19 root 12381: } else
12382: #endif
1.1.1.26 root 12383: mem[XMS_TOP + 0x15] = 0xcb; // retf
1.1.1.29! root 12384: memcpy(mem + XMS_TOP + XMS_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.19 root 12385:
1.1.1.26 root 12386: // irq12 routine (mouse)
1.1.1.24 root 12387: mem[0xfffd0 + 0x00] = 0xcd; // int 6ah (dummy)
12388: mem[0xfffd0 + 0x01] = 0x6a;
12389: mem[0xfffd0 + 0x02] = 0x9a; // call far mouse
12390: mem[0xfffd0 + 0x03] = 0xff;
12391: mem[0xfffd0 + 0x04] = 0xff;
12392: mem[0xfffd0 + 0x05] = 0xff;
12393: mem[0xfffd0 + 0x06] = 0xff;
12394: mem[0xfffd0 + 0x07] = 0xcd; // int 6bh (dummy)
12395: mem[0xfffd0 + 0x08] = 0x6b;
12396: mem[0xfffd0 + 0x09] = 0xcf; // iret
12397:
1.1.1.27 root 12398: // case map routine
12399: mem[0xfffd0 + 0x0a] = 0xcd; // int 6ch (dummy)
12400: mem[0xfffd0 + 0x0b] = 0x6c;
12401: mem[0xfffd0 + 0x0c] = 0xcb; // retf
12402:
12403: // font read routine
12404: mem[0xfffd0 + 0x0d] = 0xcd; // int 6dh (dummy)
12405: mem[0xfffd0 + 0x0e] = 0x6d;
12406: mem[0xfffd0 + 0x0f] = 0xcb; // retf
1.1.1.19 root 12407:
1.1.1.26 root 12408: // irq0 routine (system time)
1.1.1.24 root 12409: mem[0xfffd0 + 0x10] = 0xcd; // int 1ch
12410: mem[0xfffd0 + 0x11] = 0x1c;
12411: mem[0xfffd0 + 0x12] = 0xea; // jmp far (IRET_TOP >> 4):0008
12412: mem[0xfffd0 + 0x13] = 0x08;
12413: mem[0xfffd0 + 0x14] = 0x00;
12414: mem[0xfffd0 + 0x15] = ((IRET_TOP >> 4) ) & 0xff;
12415: mem[0xfffd0 + 0x16] = ((IRET_TOP >> 4) >> 8) & 0xff;
1.1.1.14 root 12416:
1.1.1.26 root 12417: // boot routine
1.1 root 12418: mem[0xffff0] = 0xf4; // halt
12419: mem[0xffff1] = 0xcd; // int 21h
12420: mem[0xffff2] = 0x21;
12421: mem[0xffff3] = 0xcb; // retf
12422:
1.1.1.24 root 12423: mem[0xffff5] = '0'; // rom date
12424: mem[0xffff6] = '2';
12425: mem[0xffff7] = '/';
12426: mem[0xffff8] = '2';
12427: mem[0xffff9] = '2';
12428: mem[0xffffa] = '/';
12429: mem[0xffffb] = '0';
12430: mem[0xffffc] = '6';
12431: mem[0xffffe] = 0xfc; // machine id
12432: mem[0xfffff] = 0x00;
12433:
1.1 root 12434: // param block
12435: // + 0: param block (22bytes)
12436: // +24: fcb1/2 (20bytes)
12437: // +44: command tail (128bytes)
12438: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
12439: param->env_seg = 0;
12440: param->cmd_line.w.l = 44;
12441: param->cmd_line.w.h = (WORK_TOP >> 4);
12442: param->fcb1.w.l = 24;
12443: param->fcb1.w.h = (WORK_TOP >> 4);
12444: param->fcb2.w.l = 24;
12445: param->fcb2.w.h = (WORK_TOP >> 4);
12446:
12447: memset(mem + WORK_TOP + 24, 0x20, 20);
12448:
12449: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
12450: if(argc > 1) {
12451: sprintf(cmd_line->cmd, " %s", argv[1]);
12452: for(int i = 2; i < argc; i++) {
12453: char tmp[128];
12454: sprintf(tmp, "%s %s", cmd_line->cmd, argv[i]);
12455: strcpy(cmd_line->cmd, tmp);
12456: }
12457: cmd_line->len = (UINT8)strlen(cmd_line->cmd);
12458: } else {
12459: cmd_line->len = 0;
12460: }
12461: cmd_line->cmd[cmd_line->len] = 0x0d;
12462:
12463: // system file table
1.1.1.21 root 12464: *(UINT32 *)(mem + SFT_TOP + 0) = 0xffffffff;
12465: *(UINT16 *)(mem + SFT_TOP + 4) = 20;
1.1 root 12466:
1.1.1.19 root 12467: // disk buffer header (from DOSBox)
12468: *(UINT16 *)(mem + DISK_BUF_TOP + 0) = 0xffff; // forward ptr
12469: *(UINT16 *)(mem + DISK_BUF_TOP + 2) = 0xffff; // backward ptr
12470: *(UINT8 *)(mem + DISK_BUF_TOP + 4) = 0xff; // not in use
12471: *(UINT8 *)(mem + DISK_BUF_TOP + 10) = 0x01; // number of FATs
12472: *(UINT32 *)(mem + DISK_BUF_TOP + 13) = 0xffffffff; // pointer to DPB
12473:
1.1 root 12474: // current directory structure
12475: msdos_cds_update(_getdrive() - 1);
12476:
12477: // fcb table
12478: *(UINT32 *)(mem + FCB_TABLE_TOP + 0) = 0xffffffff;
1.1.1.14 root 12479: *(UINT16 *)(mem + FCB_TABLE_TOP + 4) = 0;
1.1 root 12480:
1.1.1.22 root 12481: // error table
12482: *(UINT8 *)(mem + ERR_TABLE_TOP + 0) = 0xff;
12483: *(UINT8 *)(mem + ERR_TABLE_TOP + 1) = 0x04;
12484: *(UINT8 *)(mem + ERR_TABLE_TOP + 2) = 0x00;
12485: *(UINT8 *)(mem + ERR_TABLE_TOP + 3) = 0x00;
12486:
1.1.1.17 root 12487: // nls stuff
12488: msdos_nls_tables_init();
1.1 root 12489:
12490: // execute command
1.1.1.28 root 12491: try {
12492: if(msdos_process_exec(argv[0], param, 0)) {
12493: fatalerror("'%s' not found\n", argv[0]);
12494: }
12495: } catch(...) {
12496: // we should not reach here :-(
12497: fatalerror("failed to start '%s' because of unexpected exeption\n", argv[0]);
1.1 root 12498: }
12499: retval = 0;
12500: return(0);
12501: }
12502:
12503: #define remove_std_file(path) { \
12504: int fd = _open(path, _O_RDONLY | _O_BINARY); \
12505: if(fd != -1) { \
12506: _lseek(fd, 0, SEEK_END); \
12507: int size = _tell(fd); \
12508: _close(fd); \
12509: if(size == 0) { \
12510: remove(path); \
12511: } \
12512: } \
12513: }
12514:
12515: void msdos_finish()
12516: {
12517: for(int i = 0; i < MAX_FILES; i++) {
12518: if(file_handler[i].valid) {
12519: _close(i);
12520: }
12521: }
1.1.1.21 root 12522: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 12523: remove_std_file("stdaux.txt");
1.1.1.21 root 12524: #endif
12525: #ifdef MAP_PRN_DEVICE_TO_FILE
1.1 root 12526: remove_std_file("stdprn.txt");
12527: #endif
12528: msdos_dbcs_table_finish();
12529: }
12530:
12531: /* ----------------------------------------------------------------------------
12532: PC/AT hardware emulation
12533: ---------------------------------------------------------------------------- */
12534:
12535: void hardware_init()
12536: {
1.1.1.3 root 12537: CPU_INIT_CALL(CPU_MODEL);
1.1 root 12538: CPU_RESET_CALL(CPU_MODEL);
1.1.1.14 root 12539: m_IF = 1;
1.1.1.3 root 12540: #if defined(HAS_I386)
1.1 root 12541: cpu_type = (REG32(EDX) >> 8) & 0x0f;
12542: cpu_step = (REG32(EDX) >> 0) & 0x0f;
1.1.1.3 root 12543: #endif
12544: i386_set_a20_line(0);
1.1.1.14 root 12545:
1.1.1.19 root 12546: ems_init();
1.1.1.25 root 12547: dma_init();
1.1 root 12548: pic_init();
1.1.1.25 root 12549: pio_init();
1.1.1.8 root 12550: #ifdef PIT_ALWAYS_RUNNING
12551: pit_init();
12552: #else
1.1 root 12553: pit_active = 0;
12554: #endif
1.1.1.25 root 12555: sio_init();
1.1.1.8 root 12556: cmos_init();
12557: kbd_init();
1.1 root 12558: }
12559:
1.1.1.10 root 12560: void hardware_finish()
12561: {
12562: #if defined(HAS_I386)
12563: vtlb_free(m_vtlb);
12564: #endif
1.1.1.19 root 12565: ems_finish();
1.1.1.25 root 12566: sio_finish();
1.1.1.10 root 12567: }
12568:
1.1.1.28 root 12569: void hardware_release()
12570: {
12571: // release hardware resources when this program will be terminated abnormally
12572: #ifdef EXPORT_DEBUG_TO_FILE
12573: if(fdebug != NULL) {
12574: fclose(fdebug);
12575: fdebug = NULL;
12576: }
12577: #endif
12578: #if defined(HAS_I386)
12579: vtlb_free(m_vtlb);
12580: #endif
12581: ems_release();
12582: sio_release();
12583: }
12584:
1.1 root 12585: void hardware_run()
12586: {
12587: int ops = 0;
12588:
1.1.1.22 root 12589: #ifdef EXPORT_DEBUG_TO_FILE
1.1.1.28 root 12590: // open debug log file after msdos_init() is done not to use the standard file handlers
1.1.1.22 root 12591: fdebug = fopen("debug.log", "w");
12592: #endif
1.1.1.3 root 12593: while(!m_halted) {
1.1.1.22 root 12594: #ifdef ENABLE_DEBUG_DASM
12595: if(dasm > 0) {
1.1 root 12596: char buffer[256];
1.1.1.3 root 12597: #if defined(HAS_I386)
1.1.1.22 root 12598: UINT32 flags = get_flags();
1.1.1.19 root 12599: UINT32 eip = m_eip;
1.1.1.3 root 12600: #else
1.1.1.22 root 12601: UINT32 flags = CompressFlags();
1.1.1.19 root 12602: UINT32 eip = m_pc - SREG_BASE(CS);
1.1.1.3 root 12603: #endif
12604: UINT8 *oprom = mem + SREG_BASE(CS) + eip;
1.1 root 12605:
1.1.1.3 root 12606: #if defined(HAS_I386)
12607: if(m_operand_size) {
1.1 root 12608: CPU_DISASSEMBLE_CALL(x86_32);
1.1.1.3 root 12609: } else
12610: #endif
12611: CPU_DISASSEMBLE_CALL(x86_16);
1.1.1.22 root 12612:
12613: fprintf(fdebug, "AX=%04X BX=%04X CX=%04X DX=%04X SP=%04X BP=%04X SI=%04X DI=%04X\nDS=%04X ES=%04X SS=%04X CS=%04X IP=%04X FLAG=[%s %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c]\n",
12614: REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SP), REG16(BP), REG16(SI), REG16(DI), SREG(DS), SREG(ES), SREG(SS), SREG(CS), eip,
12615: #if defined(HAS_I386)
12616: PROTECTED_MODE ? "PE" : "--",
12617: #else
12618: "--",
12619: #endif
12620: (flags & 0x40000) ? 'A' : '-',
12621: (flags & 0x20000) ? 'V' : '-',
12622: (flags & 0x10000) ? 'R' : '-',
12623: (flags & 0x04000) ? 'N' : '-',
12624: (flags & 0x02000) ? '1' : '0',
12625: (flags & 0x01000) ? '1' : '0',
12626: (flags & 0x00800) ? 'O' : '-',
12627: (flags & 0x00400) ? 'D' : '-',
12628: (flags & 0x00200) ? 'I' : '-',
12629: (flags & 0x00100) ? 'T' : '-',
12630: (flags & 0x00080) ? 'S' : '-',
12631: (flags & 0x00040) ? 'Z' : '-',
12632: (flags & 0x00010) ? 'A' : '-',
12633: (flags & 0x00004) ? 'P' : '-',
12634: (flags & 0x00001) ? 'C' : '-');
12635: fprintf(fdebug, "%04X:%04X\t%s\n", SREG(CS), (unsigned)eip, buffer);
12636: dasm--;
1.1 root 12637: }
12638: #endif
1.1.1.3 root 12639: #if defined(HAS_I386)
12640: m_cycles = 1;
1.1 root 12641: CPU_EXECUTE_CALL(i386);
1.1.1.3 root 12642: #else
12643: CPU_EXECUTE_CALL(CPU_MODEL);
12644: #endif
1.1.1.14 root 12645: #if defined(HAS_I386)
12646: if(m_eip != m_prev_eip) {
12647: #else
12648: if(m_pc != m_prevpc) {
12649: #endif
12650: iops++;
12651: }
1.1.1.8 root 12652: if(++ops == 16384) {
1.1 root 12653: hardware_update();
12654: ops = 0;
12655: }
12656: }
1.1.1.22 root 12657: #ifdef EXPORT_DEBUG_TO_FILE
1.1.1.28 root 12658: if(fdebug != NULL) {
12659: fclose(fdebug);
12660: fdebug = NULL;
12661: }
1.1.1.22 root 12662: #endif
1.1 root 12663: }
12664:
12665: void hardware_update()
12666: {
1.1.1.8 root 12667: static UINT32 prev_time = 0;
12668: UINT32 cur_time = timeGetTime();
12669:
12670: if(prev_time != cur_time) {
12671: // update pit and raise irq0
12672: #ifndef PIT_ALWAYS_RUNNING
12673: if(pit_active)
12674: #endif
12675: {
12676: if(pit_run(0, cur_time)) {
12677: pic_req(0, 0, 1);
12678: }
12679: pit_run(1, cur_time);
12680: pit_run(2, cur_time);
12681: }
1.1.1.24 root 12682:
1.1.1.25 root 12683: // update sio and raise irq4/3
1.1.1.29! root 12684: for(int c = 0; c < 4; c++) {
1.1.1.25 root 12685: sio_update(c);
12686: }
12687:
1.1.1.24 root 12688: // update keyboard and mouse
1.1.1.14 root 12689: static UINT32 prev_tick = 0;
12690: UINT32 cur_tick = cur_time / 32;
1.1.1.25 root 12691:
1.1.1.14 root 12692: if(prev_tick != cur_tick) {
12693: // update keyboard flags
12694: UINT8 state;
1.1.1.24 root 12695: state = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
12696: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x0001) ? 0x40 : 0;
12697: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x0001) ? 0x20 : 0;
12698: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
12699: state |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
12700: state |= (GetAsyncKeyState(VK_CONTROL ) & 0x8000) ? 0x04 : 0;
12701: state |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
12702: state |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
1.1.1.14 root 12703: mem[0x417] = state;
12704: state = (GetAsyncKeyState(VK_INSERT ) & 0x8000) ? 0x80 : 0;
12705: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
12706: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
12707: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
1.1.1.24 root 12708: // state |= (GetAsyncKeyState(VK_PAUSE ) & 0x0001) ? 0x08 : 0;
12709: // state |= (GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x04 : 0;
1.1.1.14 root 12710: state |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
12711: state |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
12712: mem[0x418] = state;
12713:
1.1.1.24 root 12714: // update console input if needed
12715: if(!key_changed || mouse.active) {
12716: update_console_input();
12717: }
12718:
12719: // raise irq1 if key is pressed/released
12720: if(key_changed) {
1.1.1.8 root 12721: pic_req(0, 1, 1);
1.1.1.24 root 12722: key_changed = false;
12723: }
12724:
12725: // raise irq12 if mouse status is changed
12726: if(mouse.status & mouse.call_mask) {
12727: if(mouse.active) {
12728: pic_req(1, 4, 1);
12729: mouse.status_irq = mouse.status & mouse.call_mask;
12730: }
12731: mouse.status &= ~mouse.call_mask;
1.1.1.8 root 12732: }
1.1.1.24 root 12733:
1.1.1.14 root 12734: prev_tick = cur_tick;
1.1.1.8 root 12735: }
1.1.1.24 root 12736:
1.1.1.19 root 12737: // update daily timer counter
12738: pcbios_update_daily_timer_counter(cur_time);
1.1.1.25 root 12739:
1.1.1.8 root 12740: prev_time = cur_time;
1.1 root 12741: }
12742: }
12743:
1.1.1.19 root 12744: // ems
12745:
12746: void ems_init()
12747: {
12748: memset(ems_handles, 0, sizeof(ems_handles));
12749: memset(ems_pages, 0, sizeof(ems_pages));
12750: free_ems_pages = MAX_EMS_PAGES;
12751: }
12752:
12753: void ems_finish()
12754: {
1.1.1.28 root 12755: ems_release();
12756: }
12757:
12758: void ems_release()
12759: {
1.1.1.19 root 12760: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
1.1.1.28 root 12761: if(ems_handles[i].buffer != NULL) {
1.1.1.19 root 12762: free(ems_handles[i].buffer);
12763: ems_handles[i].buffer = NULL;
12764: }
12765: }
12766: }
12767:
12768: void ems_allocate_pages(int handle, int pages)
12769: {
12770: if(pages > 0) {
12771: ems_handles[handle].buffer = (UINT8 *)calloc(1, 0x4000 * pages);
12772: } else {
12773: ems_handles[handle].buffer = NULL;
12774: }
12775: ems_handles[handle].pages = pages;
12776: ems_handles[handle].allocated = true;
12777: free_ems_pages -= pages;
12778: }
12779:
12780: void ems_reallocate_pages(int handle, int pages)
12781: {
12782: if(ems_handles[handle].allocated) {
12783: if(ems_handles[handle].pages != pages) {
12784: UINT8 *new_buffer = NULL;
12785:
12786: if(pages > 0) {
12787: new_buffer = (UINT8 *)calloc(1, 0x4000 * pages);
12788: }
12789: if(ems_handles[handle].buffer) {
12790: if(new_buffer) {
12791: if(pages > ems_handles[handle].pages) {
12792: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * ems_handles[handle].pages);
12793: } else {
12794: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * pages);
12795: }
12796: }
12797: free(ems_handles[handle].buffer);
12798: ems_handles[handle].buffer = NULL;
12799: }
12800: free_ems_pages += ems_handles[handle].pages;
12801:
12802: ems_handles[handle].buffer = new_buffer;
12803: ems_handles[handle].pages = pages;
12804: free_ems_pages -= pages;
12805: }
12806: } else {
12807: ems_allocate_pages(handle, pages);
12808: }
12809: }
12810:
12811: void ems_release_pages(int handle)
12812: {
12813: if(ems_handles[handle].allocated) {
12814: if(ems_handles[handle].buffer) {
12815: free(ems_handles[handle].buffer);
12816: ems_handles[handle].buffer = NULL;
12817: }
12818: free_ems_pages += ems_handles[handle].pages;
12819: ems_handles[handle].allocated = false;
12820: }
12821: }
12822:
12823: void ems_map_page(int physical, int handle, int logical)
12824: {
12825: if(ems_pages[physical].mapped) {
12826: if(ems_pages[physical].handle == handle && ems_pages[physical].page == logical) {
12827: return;
12828: }
12829: ems_unmap_page(physical);
12830: }
12831: if(ems_handles[handle].allocated && ems_handles[handle].buffer && logical < ems_handles[handle].pages) {
12832: memcpy(mem + EMS_TOP + 0x4000 * physical, ems_handles[handle].buffer + 0x4000 * logical, 0x4000);
12833: }
12834: ems_pages[physical].handle = handle;
12835: ems_pages[physical].page = logical;
12836: ems_pages[physical].mapped = true;
12837: }
12838:
12839: void ems_unmap_page(int physical)
12840: {
12841: if(ems_pages[physical].mapped) {
12842: int handle = ems_pages[physical].handle;
12843: int logical = ems_pages[physical].page;
12844:
12845: if(ems_handles[handle].allocated && ems_handles[handle].buffer && logical < ems_handles[handle].pages) {
12846: memcpy(ems_handles[handle].buffer + 0x4000 * logical, mem + EMS_TOP + 0x4000 * physical, 0x4000);
12847: }
12848: ems_pages[physical].mapped = false;
12849: }
12850: }
12851:
1.1.1.25 root 12852: // dma
1.1 root 12853:
1.1.1.25 root 12854: void dma_init()
1.1 root 12855: {
1.1.1.26 root 12856: memset(dma, 0, sizeof(dma));
1.1.1.25 root 12857: for(int c = 0; c < 2; c++) {
1.1.1.26 root 12858: // for(int ch = 0; ch < 4; ch++) {
12859: // dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w = 0xffff;
12860: // }
1.1.1.25 root 12861: dma_reset(c);
12862: }
1.1 root 12863: }
12864:
1.1.1.25 root 12865: void dma_reset(int c)
1.1 root 12866: {
1.1.1.25 root 12867: dma[c].low_high = false;
12868: dma[c].cmd = dma[c].req = dma[c].tc = 0;
12869: dma[c].mask = 0xff;
12870: }
12871:
12872: void dma_write(int c, UINT32 addr, UINT8 data)
12873: {
12874: int ch = (addr >> 1) & 3;
12875: UINT8 bit = 1 << (data & 3);
12876:
12877: switch(addr & 0x0f) {
12878: case 0x00: case 0x02: case 0x04: case 0x06:
12879: if(dma[c].low_high) {
12880: dma[c].ch[ch].bareg.b.h = data;
1.1 root 12881: } else {
1.1.1.25 root 12882: dma[c].ch[ch].bareg.b.l = data;
12883: }
12884: dma[c].ch[ch].areg.w = dma[c].ch[ch].bareg.w;
12885: dma[c].low_high = !dma[c].low_high;
12886: break;
12887: case 0x01: case 0x03: case 0x05: case 0x07:
12888: if(dma[c].low_high) {
12889: dma[c].ch[ch].bcreg.b.h = data;
12890: } else {
12891: dma[c].ch[ch].bcreg.b.l = data;
12892: }
12893: dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w;
12894: dma[c].low_high = !dma[c].low_high;
12895: break;
12896: case 0x08:
12897: // command register
12898: dma[c].cmd = data;
12899: break;
12900: case 0x09:
12901: // dma[c].request register
12902: if(data & 4) {
12903: if(!(dma[c].req & bit)) {
12904: dma[c].req |= bit;
12905: // dma_run(c, ch);
12906: }
12907: } else {
12908: dma[c].req &= ~bit;
12909: }
12910: break;
12911: case 0x0a:
12912: // single mask register
12913: if(data & 4) {
12914: dma[c].mask |= bit;
12915: } else {
12916: dma[c].mask &= ~bit;
12917: }
12918: break;
12919: case 0x0b:
12920: // mode register
12921: dma[c].ch[data & 3].mode = data;
12922: break;
12923: case 0x0c:
12924: dma[c].low_high = false;
12925: break;
12926: case 0x0d:
12927: // clear master
12928: dma_reset(c);
12929: break;
12930: case 0x0e:
12931: // clear mask register
12932: dma[c].mask = 0;
12933: break;
12934: case 0x0f:
12935: // all mask register
12936: dma[c].mask = data & 0x0f;
12937: break;
12938: }
12939: }
12940:
12941: UINT8 dma_read(int c, UINT32 addr)
12942: {
12943: int ch = (addr >> 1) & 3;
12944: UINT8 val = 0xff;
12945:
12946: switch(addr & 0x0f) {
12947: case 0x00: case 0x02: case 0x04: case 0x06:
12948: if(dma[c].low_high) {
12949: val = dma[c].ch[ch].areg.b.h;
12950: } else {
12951: val = dma[c].ch[ch].areg.b.l;
12952: }
12953: dma[c].low_high = !dma[c].low_high;
12954: return(val);
12955: case 0x01: case 0x03: case 0x05: case 0x07:
12956: if(dma[c].low_high) {
12957: val = dma[c].ch[ch].creg.b.h;
12958: } else {
12959: val = dma[c].ch[ch].creg.b.l;
12960: }
12961: dma[c].low_high = !dma[c].low_high;
12962: return(val);
12963: case 0x08:
12964: // status register
12965: val = (dma[c].req << 4) | dma[c].tc;
12966: dma[c].tc = 0;
12967: return(val);
12968: case 0x0d:
1.1.1.26 root 12969: // temporary register (intel 82374 does not support)
1.1.1.25 root 12970: return(dma[c].tmp & 0xff);
1.1.1.26 root 12971: case 0x0f:
12972: // mask register (intel 82374 does support)
12973: return(dma[c].mask);
1.1.1.25 root 12974: }
12975: return(0xff);
12976: }
12977:
12978: void dma_page_write(int c, int ch, UINT8 data)
12979: {
12980: dma[c].ch[ch].pagereg = data;
12981: }
12982:
12983: UINT8 dma_page_read(int c, int ch)
12984: {
12985: return(dma[c].ch[ch].pagereg);
12986: }
12987:
12988: void dma_run(int c, int ch)
12989: {
12990: UINT8 bit = 1 << ch;
12991:
12992: if((dma[c].req & bit) && !(dma[c].mask & bit)) {
12993: // execute dma
12994: while(dma[c].req & bit) {
12995: if(ch == 0 && (dma[c].cmd & 0x01)) {
12996: // memory -> memory
12997: UINT32 saddr = dma[c].ch[0].areg.w | (dma[c].ch[0].pagereg << 16);
12998: UINT32 daddr = dma[c].ch[1].areg.w | (dma[c].ch[1].pagereg << 16);
12999:
13000: if(c == 0) {
13001: dma[c].tmp = read_byte(saddr);
13002: write_byte(daddr, dma[c].tmp);
13003: } else {
13004: dma[c].tmp = read_word(saddr << 1);
13005: write_word(daddr << 1, dma[c].tmp);
13006: }
13007: if(!(dma[c].cmd & 0x02)) {
13008: if(dma[c].ch[0].mode & 0x20) {
13009: dma[c].ch[0].areg.w--;
13010: if(dma[c].ch[0].areg.w == 0xffff) {
13011: dma[c].ch[0].pagereg--;
13012: }
13013: } else {
13014: dma[c].ch[0].areg.w++;
13015: if(dma[c].ch[0].areg.w == 0) {
13016: dma[c].ch[0].pagereg++;
13017: }
13018: }
13019: }
13020: if(dma[c].ch[1].mode & 0x20) {
13021: dma[c].ch[1].areg.w--;
13022: if(dma[c].ch[1].areg.w == 0xffff) {
13023: dma[c].ch[1].pagereg--;
13024: }
13025: } else {
13026: dma[c].ch[1].areg.w++;
13027: if(dma[c].ch[1].areg.w == 0) {
13028: dma[c].ch[1].pagereg++;
13029: }
13030: }
13031:
13032: // check dma condition
13033: if(dma[c].ch[0].creg.w-- == 0) {
13034: if(dma[c].ch[0].mode & 0x10) {
13035: // self initialize
13036: dma[c].ch[0].areg.w = dma[c].ch[0].bareg.w;
13037: dma[c].ch[0].creg.w = dma[c].ch[0].bcreg.w;
13038: } else {
13039: // dma[c].mask |= bit;
13040: }
13041: }
13042: if(dma[c].ch[1].creg.w-- == 0) {
13043: // terminal count
13044: if(dma[c].ch[1].mode & 0x10) {
13045: // self initialize
13046: dma[c].ch[1].areg.w = dma[c].ch[1].bareg.w;
13047: dma[c].ch[1].creg.w = dma[c].ch[1].bcreg.w;
13048: } else {
13049: dma[c].mask |= bit;
13050: }
13051: dma[c].req &= ~bit;
13052: dma[c].tc |= bit;
13053: }
13054: } else {
13055: UINT32 addr = dma[c].ch[ch].areg.w | (dma[c].ch[ch].pagereg << 16);
13056:
13057: if((dma[c].ch[ch].mode & 0x0c) == 0x00) {
13058: // verify
13059: } else if((dma[c].ch[ch].mode & 0x0c) == 0x04) {
13060: // io -> memory
13061: if(c == 0) {
13062: dma[c].tmp = read_io_byte(dma[c].ch[ch].port);
13063: write_byte(addr, dma[c].tmp);
13064: } else {
13065: dma[c].tmp = read_io_word(dma[c].ch[ch].port);
13066: write_word(addr << 1, dma[c].tmp);
13067: }
13068: } else if((dma[c].ch[ch].mode & 0x0c) == 0x08) {
13069: // memory -> io
13070: if(c == 0) {
13071: dma[c].tmp = read_byte(addr);
13072: write_io_byte(dma[c].ch[ch].port, dma[c].tmp);
13073: } else {
13074: dma[c].tmp = read_word(addr << 1);
13075: write_io_word(dma[c].ch[ch].port, dma[c].tmp);
13076: }
13077: }
13078: if(dma[c].ch[ch].mode & 0x20) {
13079: dma[c].ch[ch].areg.w--;
13080: if(dma[c].ch[ch].areg.w == 0xffff) {
13081: dma[c].ch[ch].pagereg--;
13082: }
13083: } else {
13084: dma[c].ch[ch].areg.w++;
13085: if(dma[c].ch[ch].areg.w == 0) {
13086: dma[c].ch[ch].pagereg++;
13087: }
13088: }
13089:
13090: // check dma condition
13091: if(dma[c].ch[ch].creg.w-- == 0) {
13092: // terminal count
13093: if(dma[c].ch[ch].mode & 0x10) {
13094: // self initialize
13095: dma[c].ch[ch].areg.w = dma[c].ch[ch].bareg.w;
13096: dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w;
13097: } else {
13098: dma[c].mask |= bit;
13099: }
13100: dma[c].req &= ~bit;
13101: dma[c].tc |= bit;
13102: } else if((dma[c].ch[ch].mode & 0xc0) == 0x40) {
13103: // single mode
13104: break;
13105: }
13106: }
13107: }
13108: }
13109: }
13110:
13111: // pic
13112:
13113: void pic_init()
13114: {
13115: memset(pic, 0, sizeof(pic));
13116: pic[0].imr = pic[1].imr = 0xff;
13117:
13118: // from bochs bios
13119: pic_write(0, 0, 0x11); // icw1 = 11h
13120: pic_write(0, 1, 0x08); // icw2 = 08h
13121: pic_write(0, 1, 0x04); // icw3 = 04h
13122: pic_write(0, 1, 0x01); // icw4 = 01h
13123: pic_write(0, 1, 0xb8); // ocw1 = b8h
13124: pic_write(1, 0, 0x11); // icw1 = 11h
13125: pic_write(1, 1, 0x70); // icw2 = 70h
13126: pic_write(1, 1, 0x02); // icw3 = 02h
13127: pic_write(1, 1, 0x01); // icw4 = 01h
13128: }
13129:
13130: void pic_write(int c, UINT32 addr, UINT8 data)
13131: {
13132: if(addr & 1) {
13133: if(pic[c].icw2_r) {
13134: // icw2
13135: pic[c].icw2 = data;
13136: pic[c].icw2_r = 0;
13137: } else if(pic[c].icw3_r) {
13138: // icw3
13139: pic[c].icw3 = data;
13140: pic[c].icw3_r = 0;
13141: } else if(pic[c].icw4_r) {
13142: // icw4
13143: pic[c].icw4 = data;
13144: pic[c].icw4_r = 0;
13145: } else {
13146: // ocw1
1.1 root 13147: pic[c].imr = data;
13148: }
13149: } else {
13150: if(data & 0x10) {
13151: // icw1
13152: pic[c].icw1 = data;
13153: pic[c].icw2_r = 1;
13154: pic[c].icw3_r = (data & 2) ? 0 : 1;
13155: pic[c].icw4_r = data & 1;
13156: pic[c].irr = 0;
13157: pic[c].isr = 0;
13158: pic[c].imr = 0;
13159: pic[c].prio = 0;
13160: if(!(pic[c].icw1 & 1)) {
13161: pic[c].icw4 = 0;
13162: }
13163: pic[c].ocw3 = 0;
13164: } else if(data & 8) {
13165: // ocw3
13166: if(!(data & 2)) {
13167: data = (data & ~1) | (pic[c].ocw3 & 1);
13168: }
13169: if(!(data & 0x40)) {
13170: data = (data & ~0x20) | (pic[c].ocw3 & 0x20);
13171: }
13172: pic[c].ocw3 = data;
13173: } else {
13174: // ocw2
13175: int level = 0;
13176: if(data & 0x40) {
13177: level = data & 7;
13178: } else {
13179: if(!pic[c].isr) {
13180: return;
13181: }
13182: level = pic[c].prio;
13183: while(!(pic[c].isr & (1 << level))) {
13184: level = (level + 1) & 7;
13185: }
13186: }
13187: if(data & 0x80) {
13188: pic[c].prio = (level + 1) & 7;
13189: }
13190: if(data & 0x20) {
13191: pic[c].isr &= ~(1 << level);
13192: }
13193: }
13194: }
13195: pic_update();
13196: }
13197:
13198: UINT8 pic_read(int c, UINT32 addr)
13199: {
13200: if(addr & 1) {
13201: return(pic[c].imr);
13202: } else {
13203: // polling mode is not supported...
13204: //if(pic[c].ocw3 & 4) {
13205: // return ???;
13206: //}
13207: if(pic[c].ocw3 & 1) {
13208: return(pic[c].isr);
13209: } else {
13210: return(pic[c].irr);
13211: }
13212: }
13213: }
13214:
13215: void pic_req(int c, int level, int signal)
13216: {
13217: if(signal) {
13218: pic[c].irr |= (1 << level);
13219: } else {
13220: pic[c].irr &= ~(1 << level);
13221: }
13222: pic_update();
13223: }
13224:
13225: int pic_ack()
13226: {
13227: // ack (INTA=L)
13228: pic[pic_req_chip].isr |= pic_req_bit;
13229: pic[pic_req_chip].irr &= ~pic_req_bit;
13230: if(pic_req_chip > 0) {
13231: // update isr and irr of master
13232: UINT8 slave = 1 << (pic[pic_req_chip].icw3 & 7);
13233: pic[pic_req_chip - 1].isr |= slave;
13234: pic[pic_req_chip - 1].irr &= ~slave;
13235: }
13236: //if(pic[pic_req_chip].icw4 & 1) {
13237: // 8086 mode
13238: int vector = (pic[pic_req_chip].icw2 & 0xf8) | pic_req_level;
13239: //} else {
13240: // // 8080 mode
13241: // UINT16 addr = (UINT16)pic[pic_req_chip].icw2 << 8;
13242: // if(pic[pic_req_chip].icw1 & 4) {
13243: // addr |= (pic[pic_req_chip].icw1 & 0xe0) | (pic_req_level << 2);
13244: // } else {
13245: // addr |= (pic[pic_req_chip].icw1 & 0xc0) | (pic_req_level << 3);
13246: // }
13247: // vector = 0xcd | (addr << 8);
13248: //}
13249: if(pic[pic_req_chip].icw4 & 2) {
13250: // auto eoi
13251: pic[pic_req_chip].isr &= ~pic_req_bit;
13252: }
13253: return(vector);
13254: }
13255:
13256: void pic_update()
13257: {
13258: for(int c = 0; c < 2; c++) {
13259: UINT8 irr = pic[c].irr;
13260: if(c + 1 < 2) {
13261: // this is master
13262: if(pic[c + 1].irr & (~pic[c + 1].imr)) {
13263: // request from slave
13264: irr |= 1 << (pic[c + 1].icw3 & 7);
13265: }
13266: }
13267: irr &= (~pic[c].imr);
13268: if(!irr) {
13269: break;
13270: }
13271: if(!(pic[c].ocw3 & 0x20)) {
13272: irr |= pic[c].isr;
13273: }
13274: int level = pic[c].prio;
13275: UINT8 bit = 1 << level;
13276: while(!(irr & bit)) {
13277: level = (level + 1) & 7;
13278: bit = 1 << level;
13279: }
13280: if((c + 1 < 2) && (pic[c].icw3 & bit)) {
13281: // check slave
13282: continue;
13283: }
13284: if(pic[c].isr & bit) {
13285: break;
13286: }
13287: // interrupt request
13288: pic_req_chip = c;
13289: pic_req_level = level;
13290: pic_req_bit = bit;
1.1.1.3 root 13291: i386_set_irq_line(INPUT_LINE_IRQ, HOLD_LINE);
1.1 root 13292: return;
13293: }
1.1.1.3 root 13294: i386_set_irq_line(INPUT_LINE_IRQ, CLEAR_LINE);
1.1.1.2 root 13295: }
1.1 root 13296:
1.1.1.25 root 13297: // pio
13298:
13299: void pio_init()
13300: {
1.1.1.26 root 13301: memset(pio, 0, sizeof(pio));
1.1.1.25 root 13302: for(int c = 0; c < 2; c++) {
13303: pio[c].stat = 0xde;
13304: pio[c].ctrl = 0x0c;
13305: }
13306: }
13307:
13308: void pio_write(int c, UINT32 addr, UINT8 data)
13309: {
13310: switch(addr & 3) {
13311: case 0:
13312: pio[c].data = data;
13313: break;
13314: case 2:
13315: pio[c].ctrl = data;
13316: break;
13317: }
13318: }
13319:
13320: UINT8 pio_read(int c, UINT32 addr)
13321: {
13322: switch(addr & 3) {
13323: case 0:
13324: return(pio[c].data);
13325: case 1:
13326: return(pio[c].stat);
13327: case 2:
13328: return(pio[c].ctrl);
13329: }
13330: return(0xff);
13331: }
13332:
1.1 root 13333: // pit
13334:
1.1.1.22 root 13335: #define PIT_FREQ 1193182ULL
1.1 root 13336: #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)
13337:
13338: void pit_init()
13339: {
1.1.1.8 root 13340: memset(pit, 0, sizeof(pit));
1.1 root 13341: for(int ch = 0; ch < 3; ch++) {
13342: pit[ch].count = 0x10000;
13343: pit[ch].ctrl_reg = 0x34;
13344: pit[ch].mode = 3;
13345: }
13346:
13347: // from bochs bios
13348: pit_write(3, 0x34);
13349: pit_write(0, 0x00);
13350: pit_write(0, 0x00);
13351: }
13352:
13353: void pit_write(int ch, UINT8 val)
13354: {
1.1.1.8 root 13355: #ifndef PIT_ALWAYS_RUNNING
1.1 root 13356: if(!pit_active) {
13357: pit_active = 1;
13358: pit_init();
13359: }
1.1.1.8 root 13360: #endif
1.1 root 13361: switch(ch) {
13362: case 0:
13363: case 1:
13364: case 2:
13365: // write count register
13366: if(!pit[ch].low_write && !pit[ch].high_write) {
13367: if(pit[ch].ctrl_reg & 0x10) {
13368: pit[ch].low_write = 1;
13369: }
13370: if(pit[ch].ctrl_reg & 0x20) {
13371: pit[ch].high_write = 1;
13372: }
13373: }
13374: if(pit[ch].low_write) {
13375: pit[ch].count_reg = val;
13376: pit[ch].low_write = 0;
13377: } else if(pit[ch].high_write) {
13378: if((pit[ch].ctrl_reg & 0x30) == 0x20) {
13379: pit[ch].count_reg = val << 8;
13380: } else {
13381: pit[ch].count_reg |= val << 8;
13382: }
13383: pit[ch].high_write = 0;
13384: }
13385: // start count
1.1.1.8 root 13386: if(!pit[ch].low_write && !pit[ch].high_write) {
13387: if(pit[ch].mode == 0 || pit[ch].mode == 4 || pit[ch].prev_time == 0) {
13388: pit[ch].count = PIT_COUNT_VALUE(ch);
13389: pit[ch].prev_time = timeGetTime();
13390: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 13391: }
13392: }
13393: break;
13394: case 3: // ctrl reg
13395: if((val & 0xc0) == 0xc0) {
13396: // i8254 read-back command
13397: for(ch = 0; ch < 3; ch++) {
13398: if(!(val & 0x10) && !pit[ch].status_latched) {
13399: pit[ch].status = pit[ch].ctrl_reg & 0x3f;
13400: pit[ch].status_latched = 1;
13401: }
13402: if(!(val & 0x20) && !pit[ch].count_latched) {
13403: pit_latch_count(ch);
13404: }
13405: }
13406: break;
13407: }
13408: ch = (val >> 6) & 3;
13409: if(val & 0x30) {
13410: static int modes[8] = {0, 1, 2, 3, 4, 5, 2, 3};
13411: pit[ch].mode = modes[(val >> 1) & 7];
13412: pit[ch].count_latched = 0;
13413: pit[ch].low_read = pit[ch].high_read = 0;
13414: pit[ch].low_write = pit[ch].high_write = 0;
13415: pit[ch].ctrl_reg = val;
13416: // stop count
1.1.1.8 root 13417: pit[ch].prev_time = pit[ch].expired_time = 0;
1.1 root 13418: pit[ch].count_reg = 0;
13419: } else if(!pit[ch].count_latched) {
13420: pit_latch_count(ch);
13421: }
13422: break;
13423: }
13424: }
13425:
13426: UINT8 pit_read(int ch)
13427: {
1.1.1.8 root 13428: #ifndef PIT_ALWAYS_RUNNING
1.1 root 13429: if(!pit_active) {
13430: pit_active = 1;
13431: pit_init();
13432: }
1.1.1.8 root 13433: #endif
1.1 root 13434: switch(ch) {
13435: case 0:
13436: case 1:
13437: case 2:
13438: if(pit[ch].status_latched) {
13439: pit[ch].status_latched = 0;
13440: return(pit[ch].status);
13441: }
13442: // if not latched, through current count
13443: if(!pit[ch].count_latched) {
13444: if(!pit[ch].low_read && !pit[ch].high_read) {
13445: pit_latch_count(ch);
13446: }
13447: }
13448: // return latched count
13449: if(pit[ch].low_read) {
13450: pit[ch].low_read = 0;
13451: if(!pit[ch].high_read) {
13452: pit[ch].count_latched = 0;
13453: }
13454: return(pit[ch].latch & 0xff);
13455: } else if(pit[ch].high_read) {
13456: pit[ch].high_read = 0;
13457: pit[ch].count_latched = 0;
13458: return((pit[ch].latch >> 8) & 0xff);
13459: }
13460: }
13461: return(0xff);
13462: }
13463:
1.1.1.8 root 13464: int pit_run(int ch, UINT32 cur_time)
1.1 root 13465: {
1.1.1.8 root 13466: if(pit[ch].expired_time != 0 && cur_time >= pit[ch].expired_time) {
1.1 root 13467: pit[ch].count = PIT_COUNT_VALUE(ch);
1.1.1.8 root 13468: pit[ch].prev_time = pit[ch].expired_time;
13469: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
13470: if(cur_time >= pit[ch].expired_time) {
13471: pit[ch].prev_time = cur_time;
13472: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 13473: }
1.1.1.8 root 13474: return(1);
1.1 root 13475: }
1.1.1.8 root 13476: return(0);
1.1 root 13477: }
13478:
13479: void pit_latch_count(int ch)
13480: {
1.1.1.8 root 13481: if(pit[ch].expired_time != 0) {
1.1.1.26 root 13482: UINT32 cur_time = timeGetTime();
1.1.1.8 root 13483: pit_run(ch, cur_time);
13484: UINT32 tmp = (pit[ch].count * (pit[ch].expired_time - cur_time)) / (pit[ch].expired_time - pit[ch].prev_time);
1.1.1.26 root 13485: UINT16 latch = (tmp != 0) ? (UINT16)tmp : 1;
13486:
13487: if(pit[ch].prev_latch == latch && pit[ch].expired_time > cur_time) {
13488: // decrement counter in 1msec period
13489: if(pit[ch].next_latch == 0) {
13490: tmp = (pit[ch].count * (pit[ch].expired_time - cur_time - 1)) / (pit[ch].expired_time - pit[ch].prev_time);
13491: pit[ch].next_latch = (tmp != 0) ? (UINT16)tmp : 1;
13492: }
13493: if(pit[ch].latch > pit[ch].next_latch) {
13494: pit[ch].latch--;
13495: }
13496: } else {
13497: pit[ch].prev_latch = pit[ch].latch = latch;
13498: pit[ch].next_latch = 0;
13499: }
1.1.1.8 root 13500: } else {
13501: pit[ch].latch = (UINT16)pit[ch].count;
1.1.1.26 root 13502: pit[ch].prev_latch = pit[ch].next_latch = 0;
1.1 root 13503: }
13504: pit[ch].count_latched = 1;
13505: if((pit[ch].ctrl_reg & 0x30) == 0x10) {
13506: // lower byte
13507: pit[ch].low_read = 1;
13508: pit[ch].high_read = 0;
13509: } else if((pit[ch].ctrl_reg & 0x30) == 0x20) {
13510: // upper byte
13511: pit[ch].low_read = 0;
13512: pit[ch].high_read = 1;
13513: } else {
13514: // lower -> upper
1.1.1.14 root 13515: pit[ch].low_read = pit[ch].high_read = 1;
1.1 root 13516: }
13517: }
13518:
1.1.1.8 root 13519: int pit_get_expired_time(int ch)
1.1 root 13520: {
1.1.1.22 root 13521: pit[ch].accum += 1024ULL * 1000ULL * (UINT64)pit[ch].count / PIT_FREQ;
13522: UINT64 val = pit[ch].accum >> 10;
13523: pit[ch].accum -= val << 10;
13524: return((val != 0) ? val : 1);
1.1.1.8 root 13525: }
13526:
1.1.1.25 root 13527: // sio
13528:
13529: void sio_init()
13530: {
1.1.1.26 root 13531: memset(sio, 0, sizeof(sio));
13532: memset(sio_mt, 0, sizeof(sio_mt));
13533:
1.1.1.29! root 13534: for(int c = 0; c < 4; c++) {
1.1.1.25 root 13535: sio[c].send_buffer = new FIFO(SIO_BUFFER_SIZE);
13536: sio[c].recv_buffer = new FIFO(SIO_BUFFER_SIZE);
13537:
13538: sio[c].divisor.w = 12; // 115200Hz / 9600Baud
13539: sio[c].line_ctrl = 0x03; // 8bit, stop 1bit, non parity
1.1.1.26 root 13540: sio[c].modem_ctrl = 0x03; // rts=on, dtr=on
13541: sio[c].set_rts = sio[c].set_dtr = true;
1.1.1.25 root 13542: sio[c].line_stat_buf = 0x60; // send/recv buffers are empty
13543: sio[c].irq_identify = 0x01; // no pending irq
13544:
13545: InitializeCriticalSection(&sio_mt[c].csSendData);
13546: InitializeCriticalSection(&sio_mt[c].csRecvData);
13547: InitializeCriticalSection(&sio_mt[c].csLineCtrl);
13548: InitializeCriticalSection(&sio_mt[c].csLineStat);
13549: InitializeCriticalSection(&sio_mt[c].csModemCtrl);
13550: InitializeCriticalSection(&sio_mt[c].csModemStat);
13551:
1.1.1.26 root 13552: if(sio_port_number[c] != 0) {
1.1.1.25 root 13553: sio[c].channel = c;
13554: sio_mt[c].hThread = CreateThread(NULL, 0, sio_thread, &sio[c], 0, NULL);
13555: }
13556: }
13557: }
13558:
13559: void sio_finish()
13560: {
1.1.1.29! root 13561: for(int c = 0; c < 4; c++) {
1.1.1.25 root 13562: if(sio_mt[c].hThread != NULL) {
13563: WaitForSingleObject(sio_mt[c].hThread, INFINITE);
13564: CloseHandle(sio_mt[c].hThread);
1.1.1.28 root 13565: sio_mt[c].hThread = NULL;
1.1.1.25 root 13566: }
13567: DeleteCriticalSection(&sio_mt[c].csSendData);
13568: DeleteCriticalSection(&sio_mt[c].csRecvData);
13569: DeleteCriticalSection(&sio_mt[c].csLineCtrl);
13570: DeleteCriticalSection(&sio_mt[c].csLineStat);
13571: DeleteCriticalSection(&sio_mt[c].csModemCtrl);
13572: DeleteCriticalSection(&sio_mt[c].csModemStat);
1.1.1.28 root 13573: }
13574: sio_release();
13575: }
13576:
13577: void sio_release()
13578: {
1.1.1.29! root 13579: for(int c = 0; c < 4; c++) {
1.1.1.28 root 13580: // sio_thread() may access the resources :-(
13581: if(sio_mt[c].hThread == NULL) {
13582: if(sio[c].send_buffer != NULL) {
13583: sio[c].send_buffer->release();
13584: delete sio[c].send_buffer;
13585: sio[c].send_buffer = NULL;
13586: }
13587: if(sio[c].recv_buffer != NULL) {
13588: sio[c].recv_buffer->release();
13589: delete sio[c].recv_buffer;
13590: sio[c].recv_buffer = NULL;
13591: }
13592: }
1.1.1.25 root 13593: }
13594: }
13595:
13596: void sio_write(int c, UINT32 addr, UINT8 data)
13597: {
13598: switch(addr & 7) {
13599: case 0:
13600: if(sio[c].selector & 0x80) {
13601: if(sio[c].divisor.b.l != data) {
13602: EnterCriticalSection(&sio_mt[c].csLineCtrl);
13603: sio[c].divisor.b.l = data;
13604: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
13605: }
13606: } else {
13607: EnterCriticalSection(&sio_mt[c].csSendData);
13608: sio[c].send_buffer->write(data);
13609: // transmitter holding/shift registers are not empty
13610: sio[c].line_stat_buf &= ~0x60;
13611: LeaveCriticalSection(&sio_mt[c].csSendData);
13612:
13613: if(sio[c].irq_enable & 0x02) {
13614: sio_update_irq(c);
13615: }
13616: }
13617: break;
13618: case 1:
13619: if(sio[c].selector & 0x80) {
13620: if(sio[c].divisor.b.h != data) {
13621: EnterCriticalSection(&sio_mt[c].csLineCtrl);
13622: sio[c].divisor.b.h = data;
13623: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
13624: }
13625: } else {
13626: if(sio[c].irq_enable != data) {
13627: sio[c].irq_enable = data;
13628: sio_update_irq(c);
13629: }
13630: }
13631: break;
13632: case 3:
13633: {
13634: UINT8 line_ctrl = data & 0x3f;
13635: bool set_brk = ((data & 0x40) != 0);
13636:
13637: if(sio[c].line_ctrl != line_ctrl) {
13638: EnterCriticalSection(&sio_mt[c].csLineCtrl);
13639: sio[c].line_ctrl = line_ctrl;
13640: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
13641: }
13642: if(sio[c].set_brk != set_brk) {
13643: EnterCriticalSection(&sio_mt[c].csModemCtrl);
13644: sio[c].set_brk = set_brk;
13645: LeaveCriticalSection(&sio_mt[c].csModemCtrl);
13646: }
13647: }
13648: sio[c].selector = data;
13649: break;
13650: case 4:
13651: {
13652: bool set_dtr = ((data & 0x01) != 0);
13653: bool set_rts = ((data & 0x02) != 0);
13654:
13655: if(sio[c].set_dtr != set_dtr || sio[c].set_rts != set_rts) {
1.1.1.26 root 13656: // EnterCriticalSection(&sio_mt[c].csModemCtrl);
1.1.1.25 root 13657: sio[c].set_dtr = set_dtr;
13658: sio[c].set_rts = set_rts;
1.1.1.26 root 13659: // LeaveCriticalSection(&sio_mt[c].csModemCtrl);
13660:
13661: bool state_changed = false;
13662:
13663: EnterCriticalSection(&sio_mt[c].csModemStat);
13664: if(set_dtr) {
13665: sio[c].modem_stat |= 0x20; // dsr on
13666: } else {
13667: sio[c].modem_stat &= ~0x20; // dsr off
13668: }
13669: if(set_rts) {
13670: sio[c].modem_stat |= 0x10; // cts on
13671: } else {
13672: sio[c].modem_stat &= ~0x10; // cts off
13673: }
13674: if((sio[c].prev_modem_stat & 0x20) != (sio[c].modem_stat & 0x20)) {
13675: if(!(sio[c].modem_stat & 0x02)) {
13676: if(sio[c].irq_enable & 0x08) {
13677: state_changed = true;
13678: }
13679: sio[c].modem_stat |= 0x02;
13680: }
13681: }
13682: if((sio[c].prev_modem_stat & 0x10) != (sio[c].modem_stat & 0x10)) {
13683: if(!(sio[c].modem_stat & 0x01)) {
13684: if(sio[c].irq_enable & 0x08) {
13685: state_changed = true;
13686: }
13687: sio[c].modem_stat |= 0x01;
13688: }
13689: }
13690: LeaveCriticalSection(&sio_mt[c].csModemStat);
13691:
13692: if(state_changed) {
13693: sio_update_irq(c);
13694: }
1.1.1.25 root 13695: }
13696: }
13697: sio[c].modem_ctrl = data;
13698: break;
13699: case 7:
13700: sio[c].scratch = data;
13701: break;
13702: }
13703: }
13704:
13705: UINT8 sio_read(int c, UINT32 addr)
13706: {
13707: switch(addr & 7) {
13708: case 0:
13709: if(sio[c].selector & 0x80) {
13710: return(sio[c].divisor.b.l);
13711: } else {
13712: EnterCriticalSection(&sio_mt[c].csRecvData);
13713: UINT8 data = sio[c].recv_buffer->read();
13714: // data is not ready
13715: sio[c].line_stat_buf &= ~0x01;
13716: LeaveCriticalSection(&sio_mt[c].csRecvData);
13717:
13718: if(sio[c].irq_enable & 0x01) {
13719: sio_update_irq(c);
13720: }
13721: return(data);
13722: }
13723: case 1:
13724: if(sio[c].selector & 0x80) {
13725: return(sio[c].divisor.b.h);
13726: } else {
13727: return(sio[c].irq_enable);
13728: }
13729: case 2:
13730: return(sio[c].irq_identify);
13731: case 3:
13732: return(sio[c].selector);
13733: case 4:
13734: return(sio[c].modem_ctrl);
13735: case 5:
13736: {
13737: EnterCriticalSection(&sio_mt[c].csLineStat);
13738: UINT8 val = sio[c].line_stat_err | sio[c].line_stat_buf;
13739: sio[c].line_stat_err = 0x00;
13740: LeaveCriticalSection(&sio_mt[c].csLineStat);
13741:
13742: bool state_changed = false;
13743:
13744: if((sio[c].line_stat_buf & 0x60) == 0x00) {
13745: EnterCriticalSection(&sio_mt[c].csSendData);
13746: if(!sio[c].send_buffer->full()) {
13747: // transmitter holding register will be empty first
13748: if(sio[c].irq_enable & 0x02) {
13749: state_changed = true;
13750: }
13751: sio[c].line_stat_buf |= 0x20;
13752: }
13753: LeaveCriticalSection(&sio_mt[c].csSendData);
13754: } else if((sio[c].line_stat_buf & 0x60) == 0x20) {
13755: // transmitter shift register will be empty later
13756: sio[c].line_stat_buf |= 0x40;
13757: }
13758: if(!(sio[c].line_stat_buf & 0x01)) {
13759: EnterCriticalSection(&sio_mt[c].csRecvData);
13760: if(!sio[c].recv_buffer->empty()) {
13761: // data is ready
13762: if(sio[c].irq_enable & 0x01) {
13763: state_changed = true;
13764: }
13765: sio[c].line_stat_buf |= 0x01;
13766: }
13767: LeaveCriticalSection(&sio_mt[c].csRecvData);
13768: }
13769: if(state_changed) {
13770: sio_update_irq(c);
13771: }
13772: return(val);
13773: }
13774: case 6:
13775: {
13776: EnterCriticalSection(&sio_mt[c].csModemStat);
13777: UINT8 val = sio[c].modem_stat;
13778: sio[c].modem_stat &= 0xf0;
13779: sio[c].prev_modem_stat = sio[c].modem_stat;
13780: LeaveCriticalSection(&sio_mt[c].csModemStat);
13781:
13782: if(sio[c].modem_ctrl & 0x10) {
13783: // loop-back
13784: val &= 0x0f;
13785: val |= (sio[c].modem_ctrl & 0x0c) << 4;
13786: val |= (sio[c].modem_ctrl & 0x01) << 5;
13787: val |= (sio[c].modem_ctrl & 0x02) << 3;
13788: }
13789: return(val);
13790: }
13791: case 7:
13792: return(sio[c].scratch);
13793: }
13794: return(0xff);
13795: }
13796:
13797: void sio_update(int c)
13798: {
13799: if((sio[c].line_stat_buf & 0x60) == 0x00) {
13800: EnterCriticalSection(&sio_mt[c].csSendData);
13801: if(!sio[c].send_buffer->full()) {
13802: // transmitter holding/shift registers will be empty
13803: sio[c].line_stat_buf |= 0x60;
13804: }
13805: LeaveCriticalSection(&sio_mt[c].csSendData);
13806: } else if((sio[c].line_stat_buf & 0x60) == 0x20) {
13807: // transmitter shift register will be empty
13808: sio[c].line_stat_buf |= 0x40;
13809: }
13810: if(!(sio[c].line_stat_buf & 0x01)) {
13811: EnterCriticalSection(&sio_mt[c].csRecvData);
13812: if(!sio[c].recv_buffer->empty()) {
13813: // data is ready
13814: sio[c].line_stat_buf |= 0x01;
13815: }
13816: LeaveCriticalSection(&sio_mt[c].csRecvData);
13817: }
13818: sio_update_irq(c);
13819: }
13820:
13821: void sio_update_irq(int c)
13822: {
13823: int level = -1;
13824:
13825: if(sio[c].irq_enable & 0x08) {
13826: EnterCriticalSection(&sio_mt[c].csModemStat);
13827: if((sio[c].modem_stat & 0x0f) != 0) {
13828: level = 0;
13829: }
13830: EnterCriticalSection(&sio_mt[c].csModemStat);
13831: }
13832: if(sio[c].irq_enable & 0x02) {
13833: if(sio[c].line_stat_buf & 0x20) {
13834: level = 1;
13835: }
13836: }
13837: if(sio[c].irq_enable & 0x01) {
13838: if(sio[c].line_stat_buf & 0x01) {
13839: level = 2;
13840: }
13841: }
13842: if(sio[c].irq_enable & 0x04) {
13843: EnterCriticalSection(&sio_mt[c].csLineStat);
13844: if(sio[c].line_stat_err != 0) {
13845: level = 3;
13846: }
13847: LeaveCriticalSection(&sio_mt[c].csLineStat);
13848: }
1.1.1.29! root 13849:
! 13850: // COM1 and COM3 shares IRQ4, COM2 and COM4 shares IRQ3
1.1.1.25 root 13851: if(level != -1) {
13852: sio[c].irq_identify = level << 1;
1.1.1.29! root 13853: pic_req(0, (c == 0 || c == 2) ? 4 : 3, 1);
1.1.1.25 root 13854: } else {
13855: sio[c].irq_identify = 1;
1.1.1.29! root 13856: pic_req(0, (c == 0 || c == 2) ? 4 : 3, 0);
1.1.1.25 root 13857: }
13858: }
13859:
13860: DWORD WINAPI sio_thread(void *lpx)
13861: {
13862: volatile sio_t *p = (sio_t *)lpx;
13863: sio_mt_t *q = &sio_mt[p->channel];
13864:
13865: char name[] = "COM1";
1.1.1.26 root 13866: name[3] = '0' + sio_port_number[p->channel];
13867: HANDLE hComm = NULL;
13868: COMMPROP commProp;
13869: DCB dcb;
13870: DWORD dwSettableBaud = 0xffb; // 75, 110, 150, 300, 600, 1200, 1800, 2400, 4800, 7200, and 9600bps
13871: BYTE bytBuffer[SIO_BUFFER_SIZE];
13872:
13873: if((hComm = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE) {
13874: if(GetCommProperties(hComm, &commProp)) {
13875: dwSettableBaud = commProp.dwSettableBaud;
13876: }
1.1.1.25 root 13877: EscapeCommFunction(hComm, CLRBREAK);
1.1.1.26 root 13878: // EscapeCommFunction(hComm, SETRTS);
13879: // EscapeCommFunction(hComm, SETDTR);
1.1.1.25 root 13880:
13881: while(!m_halted) {
13882: // setup comm port
13883: bool comm_state_changed = false;
13884:
13885: EnterCriticalSection(&q->csLineCtrl);
13886: if((p->prev_divisor != p->divisor.w || p->prev_line_ctrl != p->line_ctrl) && p->divisor.w != 0) {
13887: p->prev_divisor = p->divisor.w;
13888: p->prev_line_ctrl = p->line_ctrl;
13889: comm_state_changed = true;
13890: }
13891: LeaveCriticalSection(&q->csLineCtrl);
13892:
13893: if(comm_state_changed) {
1.1.1.26 root 13894: if(GetCommState(hComm, &dcb)) {
13895: // dcb.BaudRate = min(9600, 115200 / p->prev_divisor);
13896: DWORD baud = 115200 / p->prev_divisor;
13897: dcb.BaudRate = 9600; // default
13898:
13899: if((dwSettableBaud & BAUD_075 ) && baud >= 75 ) dcb.BaudRate = 75;
13900: if((dwSettableBaud & BAUD_110 ) && baud >= 110 ) dcb.BaudRate = 110;
13901: // 134.5bps is not supported ???
13902: // if((dwSettableBaud & BAUD_134_5) && baud >= 134.5) dcb.BaudRate = 134.5;
13903: if((dwSettableBaud & BAUD_150 ) && baud >= 150 ) dcb.BaudRate = 150;
13904: if((dwSettableBaud & BAUD_300 ) && baud >= 300 ) dcb.BaudRate = 300;
13905: if((dwSettableBaud & BAUD_600 ) && baud >= 600 ) dcb.BaudRate = 600;
13906: if((dwSettableBaud & BAUD_1200 ) && baud >= 1200 ) dcb.BaudRate = 1200;
13907: if((dwSettableBaud & BAUD_1800 ) && baud >= 1800 ) dcb.BaudRate = 1800;
13908: if((dwSettableBaud & BAUD_2400 ) && baud >= 2400 ) dcb.BaudRate = 2400;
13909: if((dwSettableBaud & BAUD_4800 ) && baud >= 4800 ) dcb.BaudRate = 4800;
13910: if((dwSettableBaud & BAUD_7200 ) && baud >= 7200 ) dcb.BaudRate = 7200;
13911: if((dwSettableBaud & BAUD_9600 ) && baud >= 9600 ) dcb.BaudRate = 9600;
13912: // if((dwSettableBaud & BAUD_14400) && baud >= 14400) dcb.BaudRate = 14400;
13913: // if((dwSettableBaud & BAUD_19200) && baud >= 19200) dcb.BaudRate = 19200;
13914: // if((dwSettableBaud & BAUD_38400) && baud >= 38400) dcb.BaudRate = 38400;
13915:
13916: switch(p->prev_line_ctrl & 0x03) {
13917: case 0x00: dcb.ByteSize = 5; break;
13918: case 0x01: dcb.ByteSize = 6; break;
13919: case 0x02: dcb.ByteSize = 7; break;
13920: case 0x03: dcb.ByteSize = 8; break;
13921: }
13922: switch(p->prev_line_ctrl & 0x04) {
13923: case 0x00: dcb.StopBits = ONESTOPBIT; break;
13924: case 0x04: dcb.StopBits = (dcb.ByteSize == 5) ? ONE5STOPBITS : TWOSTOPBITS; break;
13925: }
13926: switch(p->prev_line_ctrl & 0x38) {
13927: case 0x08: dcb.Parity = ODDPARITY; break;
13928: case 0x18: dcb.Parity = EVENPARITY; break;
13929: case 0x28: dcb.Parity = MARKPARITY; break;
13930: case 0x38: dcb.Parity = SPACEPARITY; break;
13931: default: dcb.Parity = NOPARITY; break;
13932: }
13933: dcb.fBinary = TRUE;
13934: dcb.fParity = (dcb.Parity != NOPARITY);
13935: dcb.fOutxCtsFlow = dcb.fOutxDsrFlow = TRUE;
13936: dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
13937: dcb.fDsrSensitivity = FALSE;//TRUE;
13938: dcb.fTXContinueOnXoff = TRUE;
13939: dcb.fOutX = dcb.fInX = FALSE;
13940: dcb.fErrorChar = FALSE;
13941: dcb.fNull = FALSE;
13942: dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
13943: dcb.fAbortOnError = FALSE;
13944:
13945: SetCommState(hComm, &dcb);
1.1.1.25 root 13946: }
13947:
13948: // check again to apply all comm state changes
13949: Sleep(10);
13950: continue;
13951: }
13952:
13953: // set comm pins
13954: bool change_brk = false;
1.1.1.26 root 13955: // bool change_rts = false;
13956: // bool change_dtr = false;
1.1.1.25 root 13957:
13958: EnterCriticalSection(&q->csModemCtrl);
13959: if(p->prev_set_brk != p->set_brk) {
13960: p->prev_set_brk = p->set_brk;
13961: change_brk = true;
13962: }
1.1.1.26 root 13963: // if(p->prev_set_rts != p->set_rts) {
13964: // p->prev_set_rts = p->set_rts;
13965: // change_rts = true;
13966: // }
13967: // if(p->prev_set_dtr != p->set_dtr) {
13968: // p->prev_set_dtr = p->set_dtr;
13969: // change_dtr = true;
13970: // }
1.1.1.25 root 13971: LeaveCriticalSection(&q->csModemCtrl);
13972:
13973: if(change_brk) {
1.1.1.26 root 13974: static UINT32 clear_time = 0;
13975: if(p->prev_set_brk) {
13976: EscapeCommFunction(hComm, SETBREAK);
13977: clear_time = timeGetTime() + 200;
13978: } else {
13979: // keep break for at least 200msec
13980: UINT32 cur_time = timeGetTime();
13981: if(clear_time > cur_time) {
13982: Sleep(clear_time - cur_time);
13983: }
13984: EscapeCommFunction(hComm, CLRBREAK);
13985: }
1.1.1.25 root 13986: }
1.1.1.26 root 13987: // if(change_rts) {
13988: // if(p->prev_set_rts) {
13989: // EscapeCommFunction(hComm, SETRTS);
13990: // } else {
13991: // EscapeCommFunction(hComm, CLRRTS);
13992: // }
13993: // }
13994: // if(change_dtr) {
13995: // if(p->prev_set_dtr) {
13996: // EscapeCommFunction(hComm, SETDTR);
13997: // } else {
13998: // EscapeCommFunction(hComm, CLRDTR);
13999: // }
14000: // }
1.1.1.25 root 14001:
14002: // get comm pins
14003: DWORD dwModemStat = 0;
14004:
14005: if(GetCommModemStatus(hComm, &dwModemStat)) {
14006: EnterCriticalSection(&q->csModemStat);
14007: if(dwModemStat & MS_RLSD_ON) {
14008: p->modem_stat |= 0x80;
14009: } else {
14010: p->modem_stat &= ~0x80;
14011: }
14012: if(dwModemStat & MS_RING_ON) {
14013: p->modem_stat |= 0x40;
14014: } else {
14015: p->modem_stat &= ~0x40;
14016: }
1.1.1.26 root 14017: // if(dwModemStat & MS_DSR_ON) {
14018: // p->modem_stat |= 0x20;
14019: // } else {
14020: // p->modem_stat &= ~0x20;
14021: // }
14022: // if(dwModemStat & MS_CTS_ON) {
14023: // p->modem_stat |= 0x10;
14024: // } else {
14025: // p->modem_stat &= ~0x10;
14026: // }
1.1.1.25 root 14027: if((p->prev_modem_stat & 0x80) != (p->modem_stat & 0x80)) {
14028: p->modem_stat |= 0x08;
14029: }
14030: if((p->prev_modem_stat & 0x40) && !(p->modem_stat & 0x40)) {
14031: p->modem_stat |= 0x04;
14032: }
1.1.1.26 root 14033: // if((p->prev_modem_stat & 0x20) != (p->modem_stat & 0x20)) {
14034: // p->modem_stat |= 0x02;
14035: // }
14036: // if((p->prev_modem_stat & 0x10) != (p->modem_stat & 0x10)) {
14037: // p->modem_stat |= 0x01;
14038: // }
1.1.1.25 root 14039: LeaveCriticalSection(&q->csModemStat);
14040: }
14041:
14042: // send data
14043: DWORD dwSend = 0;
14044:
14045: EnterCriticalSection(&q->csSendData);
14046: while(!p->send_buffer->empty()) {
14047: bytBuffer[dwSend++] = p->send_buffer->read();
14048: }
14049: LeaveCriticalSection(&q->csSendData);
14050:
14051: if(dwSend != 0) {
14052: DWORD dwWritten = 0;
14053: WriteFile(hComm, bytBuffer, dwSend, &dwWritten, NULL);
14054: }
14055:
14056: // get line status and recv data
14057: DWORD dwLineStat = 0;
14058: COMSTAT comStat;
14059:
14060: if(ClearCommError(hComm, &dwLineStat, &comStat)) {
14061: EnterCriticalSection(&q->csLineStat);
14062: if(dwLineStat & CE_BREAK) {
14063: p->line_stat_err |= 0x10;
14064: }
14065: if(dwLineStat & CE_FRAME) {
14066: p->line_stat_err |= 0x08;
14067: }
14068: if(dwLineStat & CE_RXPARITY) {
14069: p->line_stat_err |= 0x04;
14070: }
14071: if(dwLineStat & CE_OVERRUN) {
14072: p->line_stat_err |= 0x02;
14073: }
14074: LeaveCriticalSection(&q->csLineStat);
14075:
14076: if(comStat.cbInQue != 0) {
14077: EnterCriticalSection(&q->csRecvData);
14078: DWORD dwRecv = min(comStat.cbInQue, p->recv_buffer->remain());
14079: LeaveCriticalSection(&q->csRecvData);
14080:
14081: if(dwRecv != 0) {
14082: DWORD dwRead = 0;
14083: if(ReadFile(hComm, bytBuffer, dwRecv, &dwRead, NULL) && dwRead != 0) {
14084: EnterCriticalSection(&q->csRecvData);
14085: for(int i = 0; i < dwRead; i++) {
14086: p->recv_buffer->write(bytBuffer[i]);
14087: }
14088: LeaveCriticalSection(&q->csRecvData);
14089: }
14090: }
14091: }
14092: }
14093: Sleep(10);
14094: }
14095: CloseHandle(hComm);
14096: }
14097: return 0;
14098: }
14099:
1.1.1.8 root 14100: // cmos
14101:
14102: void cmos_init()
14103: {
14104: memset(cmos, 0, sizeof(cmos));
14105: cmos_addr = 0;
1.1 root 14106:
1.1.1.8 root 14107: // from DOSBox
14108: cmos_write(0x0a, 0x26);
14109: cmos_write(0x0b, 0x02);
14110: cmos_write(0x0d, 0x80);
1.1 root 14111: }
14112:
1.1.1.8 root 14113: void cmos_write(int addr, UINT8 val)
1.1 root 14114: {
1.1.1.8 root 14115: cmos[addr & 0x7f] = val;
14116: }
14117:
14118: #define CMOS_GET_TIME() { \
14119: UINT32 cur_sec = timeGetTime() / 1000 ; \
14120: if(prev_sec != cur_sec) { \
14121: GetLocalTime(&time); \
14122: prev_sec = cur_sec; \
14123: } \
1.1 root 14124: }
1.1.1.8 root 14125: #define CMOS_BCD(v) ((cmos[0x0b] & 4) ? (v) : to_bcd(v))
1.1 root 14126:
1.1.1.8 root 14127: UINT8 cmos_read(int addr)
1.1 root 14128: {
1.1.1.8 root 14129: static SYSTEMTIME time;
14130: static UINT32 prev_sec = 0;
1.1 root 14131:
1.1.1.8 root 14132: switch(addr & 0x7f) {
14133: case 0x00: CMOS_GET_TIME(); return(CMOS_BCD(time.wSecond));
14134: case 0x02: CMOS_GET_TIME(); return(CMOS_BCD(time.wMinute));
14135: case 0x04: CMOS_GET_TIME(); return(CMOS_BCD(time.wHour));
14136: case 0x06: CMOS_GET_TIME(); return(time.wDayOfWeek + 1);
14137: case 0x07: CMOS_GET_TIME(); return(CMOS_BCD(time.wDay));
14138: case 0x08: CMOS_GET_TIME(); return(CMOS_BCD(time.wMonth));
14139: case 0x09: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear));
14140: // case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 2 ? 0x80 : 0)); // 2msec
14141: case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 20 ? 0x80 : 0)); // precision of timeGetTime() may not be 1msec
14142: case 0x15: return((MEMORY_END >> 10) & 0xff);
14143: case 0x16: return((MEMORY_END >> 18) & 0xff);
14144: case 0x17: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
14145: case 0x18: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
14146: case 0x30: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
14147: case 0x31: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
14148: case 0x32: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear / 100));
1.1 root 14149: }
1.1.1.8 root 14150: return(cmos[addr & 0x7f]);
1.1 root 14151: }
14152:
1.1.1.7 root 14153: // kbd (a20)
14154:
14155: void kbd_init()
14156: {
1.1.1.8 root 14157: kbd_data = kbd_command = 0;
1.1.1.7 root 14158: kbd_status = 0x18;
14159: }
14160:
14161: UINT8 kbd_read_data()
14162: {
1.1.1.8 root 14163: kbd_status &= ~1;
1.1.1.7 root 14164: return(kbd_data);
14165: }
14166:
14167: void kbd_write_data(UINT8 val)
14168: {
14169: switch(kbd_command) {
14170: case 0xd1:
14171: i386_set_a20_line((val >> 1) & 1);
14172: break;
14173: }
14174: kbd_command = 0;
1.1.1.8 root 14175: kbd_status &= ~8;
1.1.1.7 root 14176: }
14177:
14178: UINT8 kbd_read_status()
14179: {
14180: return(kbd_status);
14181: }
14182:
14183: void kbd_write_command(UINT8 val)
14184: {
14185: switch(val) {
14186: case 0xd0:
14187: kbd_data = ((m_a20_mask >> 19) & 2) | 1;
1.1.1.8 root 14188: kbd_status |= 1;
1.1.1.7 root 14189: break;
14190: case 0xdd:
14191: i386_set_a20_line(0);
14192: break;
14193: case 0xdf:
14194: i386_set_a20_line(1);
14195: break;
1.1.1.26 root 14196: case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
14197: case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
1.1.1.7 root 14198: if(!(val & 1)) {
1.1.1.8 root 14199: if((cmos[0x0f] & 0x7f) == 5) {
1.1.1.7 root 14200: // reset pic
14201: pic_init();
14202: pic[0].irr = pic[1].irr = 0x00;
14203: pic[0].imr = pic[1].imr = 0xff;
14204: }
14205: CPU_RESET_CALL(CPU_MODEL);
14206: i386_jmp_far(0x40, 0x67);
14207: }
14208: i386_set_a20_line((val >> 1) & 1);
14209: break;
14210: }
14211: kbd_command = val;
1.1.1.8 root 14212: kbd_status |= 8;
1.1.1.7 root 14213: }
14214:
1.1.1.9 root 14215: // vga
14216:
14217: UINT8 vga_read_status()
14218: {
14219: // 60hz
14220: static const int period[3] = {16, 17, 17};
14221: static int index = 0;
14222: UINT32 time = timeGetTime() % period[index];
14223:
14224: index = (index + 1) % 3;
1.1.1.14 root 14225: return((time < 4 ? 0x08 : 0) | (time == 0 ? 0 : 0x01));
1.1.1.9 root 14226: }
14227:
1.1 root 14228: // i/o bus
14229:
1.1.1.29! root 14230: // this is ugly patch for SW1US.EXE, it sometimes mistakely read/write 01h-10h for serial I/O
! 14231: //#define SW1US_PATCH
! 14232:
1.1.1.25 root 14233: #ifdef ENABLE_DEBUG_IOPORT
14234: UINT8 read_io_byte_debug(offs_t addr);
14235:
14236: UINT8 read_io_byte(offs_t addr)
14237: {
14238: UINT8 val = read_io_byte_debug(addr);
14239: if(fdebug != NULL) {
14240: fprintf(fdebug, "inb %04X, %02X\n", addr, val);
14241: }
14242: return(val);
14243: }
14244:
14245: UINT8 read_io_byte_debug(offs_t addr)
14246: #else
1.1 root 14247: UINT8 read_io_byte(offs_t addr)
1.1.1.25 root 14248: #endif
1.1 root 14249: {
14250: switch(addr) {
1.1.1.29! root 14251: #ifdef SW1US_PATCH
! 14252: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08:
! 14253: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: case 0x10:
! 14254: return(sio_read(0, addr - 1));
! 14255: #else
1.1.1.25 root 14256: case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
14257: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
14258: return(dma_read(0, addr));
1.1.1.29! root 14259: #endif
1.1.1.25 root 14260: case 0x20: case 0x21:
1.1 root 14261: return(pic_read(0, addr));
1.1.1.25 root 14262: case 0x40: case 0x41: case 0x42: case 0x43:
1.1 root 14263: return(pit_read(addr & 0x03));
1.1.1.7 root 14264: case 0x60:
14265: return(kbd_read_data());
1.1.1.9 root 14266: case 0x61:
14267: return(system_port);
1.1.1.7 root 14268: case 0x64:
14269: return(kbd_read_status());
1.1 root 14270: case 0x71:
1.1.1.8 root 14271: return(cmos_read(cmos_addr));
1.1.1.25 root 14272: case 0x81:
14273: return(dma_page_read(0, 2));
14274: case 0x82:
14275: return(dma_page_read(0, 3));
14276: case 0x83:
14277: return(dma_page_read(0, 1));
14278: case 0x87:
14279: return(dma_page_read(0, 0));
14280: case 0x89:
14281: return(dma_page_read(1, 2));
14282: case 0x8a:
14283: return(dma_page_read(1, 3));
14284: case 0x8b:
14285: return(dma_page_read(1, 1));
14286: case 0x8f:
14287: return(dma_page_read(1, 0));
1.1 root 14288: case 0x92:
1.1.1.3 root 14289: return((m_a20_mask >> 19) & 2);
1.1.1.25 root 14290: case 0xa0: case 0xa1:
1.1 root 14291: return(pic_read(1, addr));
1.1.1.25 root 14292: case 0xc0: case 0xc2: case 0xc4: case 0xc6: case 0xc8: case 0xca: case 0xcc: case 0xce:
14293: case 0xd0: case 0xd2: case 0xd4: case 0xd6: case 0xd8: case 0xda: case 0xdc: case 0xde:
1.1.1.26 root 14294: return(dma_read(1, (addr - 0xc0) >> 1));
14295: // case 0x278: case 0x279: case 0x27a:
14296: // return(pio_read(1, addr));
1.1.1.29! root 14297: case 0x2e8: case 0x2e9: case 0x2ea: case 0x2eb: case 0x2ec: case 0x2ed: case 0x2ee: case 0x2ef:
! 14298: return(sio_read(3, addr));
1.1.1.25 root 14299: case 0x2f8: case 0x2f9: case 0x2fa: case 0x2fb: case 0x2fc: case 0x2fd: case 0x2fe: case 0x2ff:
14300: return(sio_read(1, addr));
14301: case 0x378: case 0x379: case 0x37a:
14302: return(pio_read(0, addr));
14303: case 0x3ba: case 0x3da:
1.1.1.9 root 14304: return(vga_read_status());
1.1.1.29! root 14305: case 0x3e8: case 0x3e9: case 0x3ea: case 0x3eb: case 0x3ec: case 0x3ed: case 0x3ee: case 0x3ef:
! 14306: return(sio_read(2, addr));
1.1.1.25 root 14307: case 0x3f8: case 0x3f9: case 0x3fa: case 0x3fb: case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff:
14308: return(sio_read(0, addr));
1.1 root 14309: default:
14310: // error("inb %4x\n", addr);
14311: break;
14312: }
14313: return(0xff);
14314: }
14315:
14316: UINT16 read_io_word(offs_t addr)
14317: {
14318: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8));
14319: }
14320:
14321: UINT32 read_io_dword(offs_t addr)
14322: {
14323: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8) | (read_io_byte(addr + 2) << 16) | (read_io_byte(addr + 3) << 24));
14324: }
14325:
14326: void write_io_byte(offs_t addr, UINT8 val)
14327: {
1.1.1.25 root 14328: #ifdef ENABLE_DEBUG_IOPORT
14329: if(fdebug != NULL) {
14330: fprintf(fdebug, "outb %04X, %02X\n", addr, val);
14331: }
14332: #endif
1.1 root 14333: switch(addr) {
1.1.1.29! root 14334: #ifdef SW1US_PATCH
! 14335: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08:
! 14336: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: case 0x10:
! 14337: sio_write(0, addr - 1, val);
! 14338: break;
! 14339: #else
1.1.1.25 root 14340: case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
14341: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
14342: dma_write(0, addr, val);
14343: break;
1.1.1.29! root 14344: #endif
1.1.1.25 root 14345: case 0x20: case 0x21:
1.1 root 14346: pic_write(0, addr, val);
14347: break;
1.1.1.25 root 14348: case 0x40: case 0x41: case 0x42: case 0x43:
1.1 root 14349: pit_write(addr & 0x03, val);
14350: break;
1.1.1.7 root 14351: case 0x60:
14352: kbd_write_data(val);
14353: break;
1.1.1.9 root 14354: case 0x61:
14355: if((system_port & 3) != 3 && (val & 3) == 3) {
14356: // beep on
14357: // MessageBeep(-1);
14358: } else if((system_port & 3) == 3 && (val & 3) != 3) {
14359: // beep off
14360: }
14361: system_port = val;
14362: break;
1.1 root 14363: case 0x64:
1.1.1.7 root 14364: kbd_write_command(val);
1.1 root 14365: break;
14366: case 0x70:
14367: cmos_addr = val;
14368: break;
14369: case 0x71:
1.1.1.8 root 14370: cmos_write(cmos_addr, val);
1.1 root 14371: break;
1.1.1.25 root 14372: case 0x81:
14373: dma_page_write(0, 2, val);
14374: case 0x82:
14375: dma_page_write(0, 3, val);
14376: case 0x83:
14377: dma_page_write(0, 1, val);
14378: case 0x87:
14379: dma_page_write(0, 0, val);
14380: case 0x89:
14381: dma_page_write(1, 2, val);
14382: case 0x8a:
14383: dma_page_write(1, 3, val);
14384: case 0x8b:
14385: dma_page_write(1, 1, val);
14386: case 0x8f:
14387: dma_page_write(1, 0, val);
1.1 root 14388: case 0x92:
1.1.1.7 root 14389: i386_set_a20_line((val >> 1) & 1);
1.1 root 14390: break;
1.1.1.25 root 14391: case 0xa0: case 0xa1:
1.1 root 14392: pic_write(1, addr, val);
14393: break;
1.1.1.25 root 14394: case 0xc0: case 0xc2: case 0xc4: case 0xc6: case 0xc8: case 0xca: case 0xcc: case 0xce:
14395: case 0xd0: case 0xd2: case 0xd4: case 0xd6: case 0xd8: case 0xda: case 0xdc: case 0xde:
1.1.1.26 root 14396: dma_write(1, (addr - 0xc0) >> 1, val);
1.1.1.25 root 14397: break;
1.1.1.26 root 14398: // case 0x278: case 0x279: case 0x27a:
14399: // pio_write(1, addr, val);
14400: // break;
1.1.1.29! root 14401: case 0x2e8: case 0x2e9: case 0x2ea: case 0x2eb: case 0x2ec: case 0x2ed: case 0x2ee: case 0x2ef:
! 14402: sio_write(3, addr, val);
! 14403: break;
1.1.1.25 root 14404: case 0x2f8: case 0x2f9: case 0x2fa: case 0x2fb: case 0x2fc: case 0x2fd: case 0x2fe: case 0x2ff:
14405: sio_write(1, addr, val);
14406: break;
14407: case 0x378: case 0x379: case 0x37a:
14408: pio_write(0, addr, val);
14409: break;
1.1.1.29! root 14410: case 0x3e8: case 0x3e9: case 0x3ea: case 0x3eb: case 0x3ec: case 0x3ed: case 0x3ee: case 0x3ef:
! 14411: sio_write(2, addr, val);
! 14412: break;
1.1.1.25 root 14413: case 0x3f8: case 0x3f9: case 0x3fa: case 0x3fb: case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff:
14414: sio_write(0, addr, val);
14415: break;
1.1 root 14416: default:
14417: // error("outb %4x,%2x\n", addr, val);
14418: break;
14419: }
14420: }
14421:
14422: void write_io_word(offs_t addr, UINT16 val)
14423: {
14424: write_io_byte(addr + 0, (val >> 0) & 0xff);
14425: write_io_byte(addr + 1, (val >> 8) & 0xff);
14426: }
14427:
14428: void write_io_dword(offs_t addr, UINT32 val)
14429: {
14430: write_io_byte(addr + 0, (val >> 0) & 0xff);
14431: write_io_byte(addr + 1, (val >> 8) & 0xff);
14432: write_io_byte(addr + 2, (val >> 16) & 0xff);
14433: write_io_byte(addr + 3, (val >> 24) & 0xff);
14434: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.