|
|
1.1 root 1: /*
2: MS-DOS Player for Win32 console
3:
4: Author : Takeda.Toshiya
5: Date : 2009.11.09-
6: */
7:
8: #include "msdos.h"
9:
10: #define fatalerror(...) { \
11: fprintf(stderr, __VA_ARGS__); \
12: exit(1); \
13: }
14: #define error(...) fprintf(stderr, "error: " __VA_ARGS__)
1.1.1.22 root 15: #define nolog(...)
16:
17: //#define ENABLE_DEBUG
18: #ifdef ENABLE_DEBUG
19: #define EXPORT_DEBUG_TO_FILE
20: #define ENABLE_DEBUG_DASM
21: #define ENABLE_DEBUG_SYSCALL
22: #define ENABLE_DEBUG_UNIMPLEMENTED
23:
24: #ifdef EXPORT_DEBUG_TO_FILE
25: FILE* fdebug = NULL;
26: #else
27: #define fdebug stderr
28: #endif
29: #ifdef ENABLE_DEBUG_UNIMPLEMENTED
30: #define unimplemented_10h fatalerror
31: #define unimplemented_15h fatalerror
32: #define unimplemented_16h fatalerror
33: #define unimplemented_1ah fatalerror
34: #define unimplemented_21h fatalerror
35: #define unimplemented_2fh fatalerror
1.1.1.24! root 36: #define unimplemented_33h fatalerror
1.1.1.22 root 37: #define unimplemented_67h fatalerror
38: #define unimplemented_xms fatalerror
39: #endif
40: #endif
41: #ifndef unimplemented_10h
42: #define unimplemented_10h nolog
43: #endif
44: #ifndef unimplemented_15h
45: #define unimplemented_15h nolog
46: #endif
47: #ifndef unimplemented_16h
48: #define unimplemented_16h nolog
49: #endif
50: #ifndef unimplemented_1ah
51: #define unimplemented_1ah nolog
52: #endif
53: #ifndef unimplemented_21h
54: #define unimplemented_21h nolog
55: #endif
56: #ifndef unimplemented_2fh
57: #define unimplemented_2fh nolog
58: #endif
1.1.1.24! root 59: #ifndef unimplemented_33h
! 60: #define unimplemented_33h nolog
! 61: #endif
1.1.1.22 root 62: #ifndef unimplemented_67h
63: #define unimplemented_67h nolog
64: #endif
65: #ifndef unimplemented_xms
66: #define unimplemented_xms nolog
67: #endif
68:
69: #define my_strchr(str, chr) (char *)_mbschr((unsigned char *)(str), (unsigned int)(chr))
70: #define my_strtok(tok, del) (char *)_mbstok((unsigned char *)(tok), (const unsigned char *)(del))
71: #define my_strupr(str) (char *)_mbsupr((unsigned char *)(str))
1.1 root 72:
1.1.1.12 root 73: #if defined(__MINGW32__)
74: extern "C" int _CRT_glob = 0;
75: #endif
76:
77: /*
78: kludge for "more-standardized" C++
79: */
80: #if !defined(_MSC_VER)
81: inline int kludge_min(int a, int b) { return (a<b ? a:b); }
82: inline int kludge_max(int a, int b) { return (a>b ? a:b); }
83: #define min(a,b) kludge_min(a,b)
84: #define max(a,b) kludge_max(a,b)
1.1.1.14 root 85: #elif _MSC_VER >= 1400
86: void ignore_invalid_parameters(const wchar_t *, const wchar_t *, const wchar_t *, unsigned int, uintptr_t)
87: {
88: }
89: #endif
90:
91: #define USE_THREAD
92:
93: #ifdef USE_THREAD
94: static CRITICAL_SECTION vram_crit_sect;
95: #else
96: #define EnterCriticalSection(x)
97: #define LeaveCriticalSection(x)
98: #define vram_flush()
1.1.1.12 root 99: #endif
100:
1.1.1.14 root 101: #define VIDEO_REGEN *(UINT16 *)(mem + 0x44c)
102: #define SCR_BUF(y,x) scr_buf[(y) * scr_buf_size.X + (x)]
103:
104: void change_console_size(int width, int height);
105: void clear_scr_buffer(WORD attr);
106:
107: static UINT32 vram_length_char = 0, vram_length_attr = 0;
108: static UINT32 vram_last_length_char = 0, vram_last_length_attr = 0;
109: static COORD vram_coord_char, vram_coord_attr;
110:
111: bool ignore_illegal_insn = false;
112: bool limit_max_memory = false;
113: bool no_windows = false;
114: //bool ctrl_break = false;
115: bool stay_busy = false;
116: UINT32 iops = 0;
1.1.1.19 root 117: bool support_ems = false;
118: #ifdef SUPPORT_XMS
119: bool support_xms = false;
120: #endif
1.1.1.14 root 121:
122: BOOL is_vista_or_later;
123:
124: inline void maybe_idle()
125: {
126: // if it appears to be in a tight loop, assume waiting for input
127: // allow for one updated video character, for a spinning cursor
128: if(!stay_busy && iops < 1000 && vram_length_char <= 1 && vram_length_attr <= 1) {
129: Sleep(10);
130: }
131: iops = 0;
132: }
1.1.1.12 root 133:
1.1 root 134: /* ----------------------------------------------------------------------------
1.1.1.3 root 135: MAME i86/i386
1.1 root 136: ---------------------------------------------------------------------------- */
137:
1.1.1.10 root 138: #ifndef __BIG_ENDIAN__
1.1 root 139: #define LSB_FIRST
1.1.1.10 root 140: #endif
1.1 root 141:
142: #ifndef INLINE
143: #define INLINE inline
144: #endif
145: #define U64(v) UINT64(v)
146:
147: //#define logerror(...) fprintf(stderr, __VA_ARGS__)
148: #define logerror(...)
149: //#define popmessage(...) fprintf(stderr, __VA_ARGS__)
150: #define popmessage(...)
151:
152: /*****************************************************************************/
1.1.1.10 root 153: /* src/emu/devcpu.h */
154:
155: // CPU interface functions
156: #define CPU_INIT_NAME(name) cpu_init_##name
157: #define CPU_INIT(name) void CPU_INIT_NAME(name)()
158: #define CPU_INIT_CALL(name) CPU_INIT_NAME(name)()
159:
160: #define CPU_RESET_NAME(name) cpu_reset_##name
161: #define CPU_RESET(name) void CPU_RESET_NAME(name)()
162: #define CPU_RESET_CALL(name) CPU_RESET_NAME(name)()
163:
164: #define CPU_EXECUTE_NAME(name) cpu_execute_##name
165: #define CPU_EXECUTE(name) void CPU_EXECUTE_NAME(name)()
166: #define CPU_EXECUTE_CALL(name) CPU_EXECUTE_NAME(name)()
167:
168: #define CPU_TRANSLATE_NAME(name) cpu_translate_##name
169: #define CPU_TRANSLATE(name) int CPU_TRANSLATE_NAME(name)(address_spacenum space, int intention, offs_t *address)
170: #define CPU_TRANSLATE_CALL(name) CPU_TRANSLATE_NAME(name)(space, intention, address)
171:
172: #define CPU_DISASSEMBLE_NAME(name) cpu_disassemble_##name
173: #define CPU_DISASSEMBLE(name) int CPU_DISASSEMBLE_NAME(name)(char *buffer, offs_t eip, const UINT8 *oprom)
174: #define CPU_DISASSEMBLE_CALL(name) CPU_DISASSEMBLE_NAME(name)(buffer, eip, oprom)
175:
1.1.1.14 root 176: #define CPU_MODEL_STR(name) #name
177: #define CPU_MODEL_NAME(name) CPU_MODEL_STR(name)
178:
1.1.1.10 root 179: /*****************************************************************************/
180: /* src/emu/didisasm.h */
181:
182: // Disassembler constants
183: const UINT32 DASMFLAG_SUPPORTED = 0x80000000; // are disassembly flags supported?
184: const UINT32 DASMFLAG_STEP_OUT = 0x40000000; // this instruction should be the end of a step out sequence
185: const UINT32 DASMFLAG_STEP_OVER = 0x20000000; // this instruction should be stepped over by setting a breakpoint afterwards
186: const UINT32 DASMFLAG_OVERINSTMASK = 0x18000000; // number of extra instructions to skip when stepping over
187: const UINT32 DASMFLAG_OVERINSTSHIFT = 27; // bits to shift after masking to get the value
188: const UINT32 DASMFLAG_LENGTHMASK = 0x0000ffff; // the low 16-bits contain the actual length
189:
190: /*****************************************************************************/
1.1 root 191: /* src/emu/diexec.h */
192:
193: // I/O line states
194: enum line_state
195: {
196: CLEAR_LINE = 0, // clear (a fired or held) line
197: ASSERT_LINE, // assert an interrupt immediately
198: HOLD_LINE, // hold interrupt line until acknowledged
199: PULSE_LINE // pulse interrupt line instantaneously (only for NMI, RESET)
200: };
201:
202: // I/O line definitions
203: enum
204: {
205: INPUT_LINE_IRQ = 0,
206: INPUT_LINE_NMI
207: };
208:
209: /*****************************************************************************/
1.1.1.10 root 210: /* src/emu/dimemory.h */
1.1 root 211:
1.1.1.10 root 212: // Translation intentions
213: const int TRANSLATE_TYPE_MASK = 0x03; // read write or fetch
214: const int TRANSLATE_USER_MASK = 0x04; // user mode or fully privileged
215: const int TRANSLATE_DEBUG_MASK = 0x08; // debug mode (no side effects)
216:
217: const int TRANSLATE_READ = 0; // translate for read
218: const int TRANSLATE_WRITE = 1; // translate for write
219: const int TRANSLATE_FETCH = 2; // translate for instruction fetch
220: const int TRANSLATE_READ_USER = (TRANSLATE_READ | TRANSLATE_USER_MASK);
221: const int TRANSLATE_WRITE_USER = (TRANSLATE_WRITE | TRANSLATE_USER_MASK);
222: const int TRANSLATE_FETCH_USER = (TRANSLATE_FETCH | TRANSLATE_USER_MASK);
223: const int TRANSLATE_READ_DEBUG = (TRANSLATE_READ | TRANSLATE_DEBUG_MASK);
224: const int TRANSLATE_WRITE_DEBUG = (TRANSLATE_WRITE | TRANSLATE_DEBUG_MASK);
225: const int TRANSLATE_FETCH_DEBUG = (TRANSLATE_FETCH | TRANSLATE_DEBUG_MASK);
1.1 root 226:
1.1.1.10 root 227: /*****************************************************************************/
228: /* src/emu/emucore.h */
1.1 root 229:
1.1.1.10 root 230: // constants for expression endianness
231: enum endianness_t
232: {
233: ENDIANNESS_LITTLE,
234: ENDIANNESS_BIG
235: };
1.1 root 236:
1.1.1.10 root 237: // declare native endianness to be one or the other
238: #ifdef LSB_FIRST
239: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_LITTLE;
240: #else
241: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_BIG;
242: #endif
243:
244: // endian-based value: first value is if 'endian' is little-endian, second is if 'endian' is big-endian
245: #define ENDIAN_VALUE_LE_BE(endian,leval,beval) (((endian) == ENDIANNESS_LITTLE) ? (leval) : (beval))
246:
247: // endian-based value: first value is if native endianness is little-endian, second is if native is big-endian
248: #define NATIVE_ENDIAN_VALUE_LE_BE(leval,beval) ENDIAN_VALUE_LE_BE(ENDIANNESS_NATIVE, leval, beval)
249:
250: // endian-based value: first value is if 'endian' matches native, second is if 'endian' doesn't match native
251: #define ENDIAN_VALUE_NE_NNE(endian,leval,beval) (((endian) == ENDIANNESS_NATIVE) ? (neval) : (nneval))
1.1 root 252:
253: /*****************************************************************************/
254: /* src/emu/memory.h */
255:
1.1.1.10 root 256: // address spaces
257: enum address_spacenum
258: {
259: AS_0, // first address space
260: AS_1, // second address space
261: AS_2, // third address space
262: AS_3, // fourth address space
263: ADDRESS_SPACES, // maximum number of address spaces
264:
265: // alternate address space names for common use
266: AS_PROGRAM = AS_0, // program address space
267: AS_DATA = AS_1, // data address space
268: AS_IO = AS_2 // I/O address space
269: };
270:
1.1 root 271: // offsets and addresses are 32-bit (for now...)
272: typedef UINT32 offs_t;
273:
274: // read accessors
275: UINT8 read_byte(offs_t byteaddress)
276: {
1.1.1.4 root 277: #if defined(HAS_I386)
1.1 root 278: if(byteaddress < MAX_MEM) {
279: return mem[byteaddress];
1.1.1.3 root 280: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
281: // return read_byte(byteaddress & 0xfffff);
1.1 root 282: }
283: return 0;
1.1.1.4 root 284: #else
285: return mem[byteaddress];
286: #endif
1.1 root 287: }
288:
289: UINT16 read_word(offs_t byteaddress)
290: {
1.1.1.14 root 291: if(byteaddress == 0x41c) {
292: // pointer to first free slot in keyboard buffer
293: // XXX: the buffer itself doesn't actually exist in DOS memory
294: if(key_buf_char->count() == 0) {
295: maybe_idle();
296: }
297: return (UINT16)key_buf_char->count();
298: }
1.1.1.4 root 299: #if defined(HAS_I386)
1.1 root 300: if(byteaddress < MAX_MEM - 1) {
301: return *(UINT16 *)(mem + byteaddress);
1.1.1.3 root 302: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
303: // return read_word(byteaddress & 0xfffff);
1.1 root 304: }
305: return 0;
1.1.1.4 root 306: #else
307: return *(UINT16 *)(mem + byteaddress);
308: #endif
1.1 root 309: }
310:
311: UINT32 read_dword(offs_t byteaddress)
312: {
1.1.1.4 root 313: #if defined(HAS_I386)
1.1 root 314: if(byteaddress < MAX_MEM - 3) {
315: return *(UINT32 *)(mem + byteaddress);
1.1.1.3 root 316: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
317: // return read_dword(byteaddress & 0xfffff);
1.1 root 318: }
319: return 0;
1.1.1.4 root 320: #else
321: return *(UINT32 *)(mem + byteaddress);
322: #endif
1.1 root 323: }
324:
325: // write accessors
1.1.1.14 root 326: #ifdef USE_THREAD
327: void vram_flush_char()
328: {
329: if(vram_length_char != 0) {
330: DWORD num;
1.1.1.23 root 331: WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), scr_char, vram_length_char, vram_coord_char, &num);
1.1.1.14 root 332: vram_length_char = vram_last_length_char = 0;
333: }
334: }
335:
336: void vram_flush_attr()
337: {
338: if(vram_length_attr != 0) {
339: DWORD num;
1.1.1.23 root 340: WriteConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), scr_attr, vram_length_attr, vram_coord_attr, &num);
1.1.1.14 root 341: vram_length_attr = vram_last_length_attr = 0;
342: }
343: }
344:
345: void vram_flush()
346: {
347: if(vram_length_char != 0 || vram_length_attr != 0) {
348: EnterCriticalSection(&vram_crit_sect);
349: vram_flush_char();
350: vram_flush_attr();
351: LeaveCriticalSection(&vram_crit_sect);
352: }
353: }
354: #endif
355:
356: void write_text_vram_char(offs_t offset, UINT8 data)
1.1.1.8 root 357: {
1.1.1.14 root 358: #ifdef USE_THREAD
359: static offs_t first_offset_char, last_offset_char;
360:
361: if(vram_length_char != 0) {
362: if(offset <= last_offset_char && offset >= first_offset_char) {
363: scr_char[(offset - first_offset_char) >> 1] = data;
364: return;
365: }
366: if(offset != last_offset_char + 2) {
367: vram_flush_char();
368: }
369: }
370: if(vram_length_char == 0) {
371: first_offset_char = offset;
372: vram_coord_char.X = (offset >> 1) % scr_width;
373: vram_coord_char.Y = (offset >> 1) / scr_width + scr_top;
374: }
375: scr_char[vram_length_char++] = data;
376: last_offset_char = offset;
377: #else
1.1.1.8 root 378: COORD co;
379: DWORD num;
380:
1.1.1.14 root 381: co.X = (offset >> 1) % scr_width;
382: co.Y = (offset >> 1) / scr_width;
383: scr_char[0] = data;
1.1.1.23 root 384: WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), scr_char, 1, co, &num);
1.1.1.14 root 385: #endif
386: }
387:
388: void write_text_vram_attr(offs_t offset, UINT8 data)
389: {
390: #ifdef USE_THREAD
391: static offs_t first_offset_attr, last_offset_attr;
392:
393: if(vram_length_attr != 0) {
394: if(offset <= last_offset_attr && offset >= first_offset_attr) {
395: scr_attr[(offset - first_offset_attr) >> 1] = data;
396: return;
397: }
398: if(offset != last_offset_attr + 2) {
399: vram_flush_attr();
400: }
401: }
402: if(vram_length_attr == 0) {
403: first_offset_attr = offset;
404: vram_coord_attr.X = (offset >> 1) % scr_width;
405: vram_coord_attr.Y = (offset >> 1) / scr_width + scr_top;
406: }
407: scr_attr[vram_length_attr++] = data;
408: last_offset_attr = offset;
409: #else
410: COORD co;
411: DWORD num;
1.1.1.8 root 412:
1.1.1.14 root 413: co.X = (offset >> 1) % scr_width;
414: co.Y = (offset >> 1) / scr_width;
415: scr_attr[0] = data;
1.1.1.23 root 416: WriteConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), scr_attr, 1, co, &num);
1.1.1.14 root 417: #endif
418: }
419:
420: void write_text_vram_byte(offs_t offset, UINT8 data)
421: {
422: EnterCriticalSection(&vram_crit_sect);
1.1.1.8 root 423: if(offset & 1) {
1.1.1.14 root 424: write_text_vram_attr(offset, data);
1.1.1.8 root 425: } else {
1.1.1.14 root 426: write_text_vram_char(offset, data);
1.1.1.8 root 427: }
1.1.1.14 root 428: LeaveCriticalSection(&vram_crit_sect);
1.1.1.8 root 429: }
430:
431: void write_text_vram_word(offs_t offset, UINT16 data)
432: {
1.1.1.14 root 433: EnterCriticalSection(&vram_crit_sect);
1.1.1.8 root 434: if(offset & 1) {
1.1.1.14 root 435: write_text_vram_attr(offset , (data ) & 0xff);
436: write_text_vram_char(offset + 1, (data >> 8) & 0xff);
1.1.1.8 root 437: } else {
1.1.1.14 root 438: write_text_vram_char(offset , (data ) & 0xff);
439: write_text_vram_attr(offset + 1, (data >> 8) & 0xff);
1.1.1.8 root 440: }
1.1.1.14 root 441: LeaveCriticalSection(&vram_crit_sect);
1.1.1.8 root 442: }
443:
444: void write_text_vram_dword(offs_t offset, UINT32 data)
445: {
1.1.1.14 root 446: EnterCriticalSection(&vram_crit_sect);
1.1.1.8 root 447: if(offset & 1) {
1.1.1.14 root 448: write_text_vram_attr(offset , (data ) & 0xff);
449: write_text_vram_char(offset + 1, (data >> 8) & 0xff);
450: write_text_vram_attr(offset + 2, (data >> 16) & 0xff);
451: write_text_vram_char(offset + 3, (data >> 24) & 0xff);
452: } else {
453: write_text_vram_char(offset , (data ) & 0xff);
454: write_text_vram_attr(offset + 1, (data >> 8) & 0xff);
455: write_text_vram_char(offset + 2, (data >> 16) & 0xff);
456: write_text_vram_attr(offset + 3, (data >> 24) & 0xff);
1.1.1.8 root 457: }
1.1.1.14 root 458: LeaveCriticalSection(&vram_crit_sect);
1.1.1.8 root 459: }
460:
1.1 root 461: void write_byte(offs_t byteaddress, UINT8 data)
462: {
1.1.1.8 root 463: if(byteaddress < MEMORY_END) {
1.1.1.3 root 464: mem[byteaddress] = data;
1.1.1.8 root 465: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 466: if(!restore_console_on_exit) {
467: change_console_size(scr_width, scr_height);
1.1.1.12 root 468: }
1.1.1.8 root 469: write_text_vram_byte(byteaddress - text_vram_top_address, data);
470: mem[byteaddress] = data;
471: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
472: if(int_10h_feh_called && !int_10h_ffh_called) {
473: write_text_vram_byte(byteaddress - shadow_buffer_top_address, data);
1.1 root 474: }
475: mem[byteaddress] = data;
1.1.1.4 root 476: #if defined(HAS_I386)
1.1.1.3 root 477: } else if(byteaddress < MAX_MEM) {
1.1.1.4 root 478: #else
479: } else {
480: #endif
1.1.1.3 root 481: mem[byteaddress] = data;
1.1 root 482: }
483: }
484:
485: void write_word(offs_t byteaddress, UINT16 data)
486: {
1.1.1.8 root 487: if(byteaddress < MEMORY_END) {
1.1.1.14 root 488: if(byteaddress == 0x450 + mem[0x462] * 2) {
489: COORD co;
490: co.X = data & 0xff;
491: co.Y = (data >> 8) + scr_top;
1.1.1.23 root 492: SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), co);
1.1.1.14 root 493: }
1.1.1.3 root 494: *(UINT16 *)(mem + byteaddress) = data;
1.1.1.8 root 495: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 496: if(!restore_console_on_exit) {
497: change_console_size(scr_width, scr_height);
1.1.1.12 root 498: }
1.1.1.8 root 499: write_text_vram_word(byteaddress - text_vram_top_address, data);
500: *(UINT16 *)(mem + byteaddress) = data;
501: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
502: if(int_10h_feh_called && !int_10h_ffh_called) {
503: write_text_vram_word(byteaddress - shadow_buffer_top_address, data);
1.1 root 504: }
505: *(UINT16 *)(mem + byteaddress) = data;
1.1.1.4 root 506: #if defined(HAS_I386)
1.1.1.3 root 507: } else if(byteaddress < MAX_MEM - 1) {
1.1.1.4 root 508: #else
509: } else {
510: #endif
1.1.1.3 root 511: *(UINT16 *)(mem + byteaddress) = data;
1.1 root 512: }
513: }
514:
515: void write_dword(offs_t byteaddress, UINT32 data)
516: {
1.1.1.8 root 517: if(byteaddress < MEMORY_END) {
1.1.1.3 root 518: *(UINT32 *)(mem + byteaddress) = data;
1.1.1.8 root 519: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 520: if(!restore_console_on_exit) {
521: change_console_size(scr_width, scr_height);
1.1.1.12 root 522: }
1.1.1.8 root 523: write_text_vram_dword(byteaddress - text_vram_top_address, data);
524: *(UINT32 *)(mem + byteaddress) = data;
525: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
526: if(int_10h_feh_called && !int_10h_ffh_called) {
527: write_text_vram_dword(byteaddress - shadow_buffer_top_address, data);
1.1 root 528: }
529: *(UINT32 *)(mem + byteaddress) = data;
1.1.1.4 root 530: #if defined(HAS_I386)
1.1.1.3 root 531: } else if(byteaddress < MAX_MEM - 3) {
1.1.1.4 root 532: #else
533: } else {
534: #endif
1.1.1.3 root 535: *(UINT32 *)(mem + byteaddress) = data;
1.1 root 536: }
537: }
538:
539: #define read_decrypted_byte read_byte
540: #define read_decrypted_word read_word
541: #define read_decrypted_dword read_dword
542:
1.1.1.3 root 543: #define read_raw_byte read_byte
544: #define write_raw_byte write_byte
545:
546: #define read_word_unaligned read_word
547: #define write_word_unaligned write_word
548:
549: #define read_io_word_unaligned read_io_word
550: #define write_io_word_unaligned write_io_word
551:
1.1 root 552: UINT8 read_io_byte(offs_t byteaddress);
553: UINT16 read_io_word(offs_t byteaddress);
554: UINT32 read_io_dword(offs_t byteaddress);
555:
556: void write_io_byte(offs_t byteaddress, UINT8 data);
557: void write_io_word(offs_t byteaddress, UINT16 data);
558: void write_io_dword(offs_t byteaddress, UINT32 data);
559:
560: /*****************************************************************************/
561: /* src/osd/osdcomm.h */
562:
563: /* Highly useful macro for compile-time knowledge of an array size */
564: #define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0]))
565:
1.1.1.3 root 566: #if defined(HAS_I386)
1.1.1.10 root 567: static CPU_TRANSLATE(i386);
568: #include "mame/lib/softfloat/softfloat.c"
569: #include "mame/emu/cpu/i386/i386.c"
1.1.1.12 root 570: #include "mame/emu/cpu/vtlb.c"
1.1.1.3 root 571: #elif defined(HAS_I286)
1.1.1.10 root 572: #include "mame/emu/cpu/i86/i286.c"
1.1.1.3 root 573: #else
1.1.1.10 root 574: #include "mame/emu/cpu/i86/i86.c"
1.1.1.3 root 575: #endif
1.1.1.22 root 576: #ifdef ENABLE_DEBUG_DASM
1.1.1.10 root 577: #include "mame/emu/cpu/i386/i386dasm.c"
1.1.1.22 root 578: int dasm = 0;
1.1 root 579: #endif
580:
1.1.1.3 root 581: #if defined(HAS_I386)
582: #define SREG(x) m_sreg[x].selector
583: #define SREG_BASE(x) m_sreg[x].base
584:
585: int cpu_type, cpu_step;
586: #else
587: #define REG8(x) m_regs.b[x]
588: #define REG16(x) m_regs.w[x]
589: #define SREG(x) m_sregs[x]
590: #define SREG_BASE(x) m_base[x]
591: #define m_CF m_CarryVal
592: #define m_a20_mask AMASK
593: #define i386_load_segment_descriptor(x) m_base[x] = SegBase(x)
594: #if defined(HAS_I286)
595: #define i386_set_a20_line(x) i80286_set_a20_line(x)
596: #else
597: #define i386_set_a20_line(x)
598: #endif
599: #define i386_set_irq_line(x, y) set_irq_line(x, y)
600: #endif
1.1 root 601:
602: void i386_jmp_far(UINT16 selector, UINT32 address)
603: {
1.1.1.3 root 604: #if defined(HAS_I386)
1.1 root 605: if(PROTECTED_MODE && !V8086_MODE) {
1.1.1.3 root 606: i386_protected_mode_jump(selector, address, 1, m_operand_size);
1.1 root 607: } else {
1.1.1.3 root 608: SREG(CS) = selector;
609: m_performed_intersegment_jump = 1;
610: i386_load_segment_descriptor(CS);
611: m_eip = address;
612: CHANGE_PC(m_eip);
1.1 root 613: }
1.1.1.3 root 614: #elif defined(HAS_I286)
615: i80286_code_descriptor(selector, address, 1);
616: #else
617: SREG(CS) = selector;
618: i386_load_segment_descriptor(CS);
619: m_pc = (SREG_BASE(CS) + address) & m_a20_mask;
620: #endif
1.1 root 621: }
622:
1.1.1.24! root 623: /*
! 624: void i386_call_far(UINT16 selector, UINT32 address)
! 625: {
! 626: #if defined(HAS_I386)
! 627: if(PROTECTED_MODE && !V8086_MODE) {
! 628: i386_protected_mode_call(selector, address, 1, m_operand_size);
! 629: } else {
! 630: PUSH16(SREG(CS));
! 631: PUSH16(m_eip);
! 632: SREG(CS) = selector;
! 633: m_performed_intersegment_jump = 1;
! 634: i386_load_segment_descriptor(CS);
! 635: m_eip = address;
! 636: CHANGE_PC(m_eip);
! 637: }
! 638: #else
! 639: UINT16 ip = m_pc - SREG_BASE(CS);
! 640: UINT16 cs = SREG(CS);
! 641: #if defined(HAS_I286)
! 642: i80286_code_descriptor(selector, address, 2);
! 643: #else
! 644: SREG(CS) = selector;
! 645: i386_load_segment_descriptor(CS);
! 646: m_pc = (SREG_BASE(CS) + address) & m_a20_mask;
! 647: #endif
! 648: PUSH(cs);
! 649: PUSH(ip);
! 650: CHANGE_PC(m_pc);
! 651: #endif
! 652: }
! 653: */
! 654:
1.1 root 655: /* ----------------------------------------------------------------------------
656: main
657: ---------------------------------------------------------------------------- */
658:
1.1.1.10 root 659: bool is_started_from_command_prompt()
660: {
1.1.1.18 root 661: bool ret = false;
662:
663: HMODULE hLibrary = LoadLibrary(_T("Kernel32.dll"));
664: if(hLibrary) {
665: typedef DWORD (WINAPI *GetConsoleProcessListFunction)(__out LPDWORD lpdwProcessList, __in DWORD dwProcessCount);
666: GetConsoleProcessListFunction lpfnGetConsoleProcessList;
667: lpfnGetConsoleProcessList = reinterpret_cast<GetConsoleProcessListFunction>(::GetProcAddress(hLibrary, "GetConsoleProcessList"));
668: if(lpfnGetConsoleProcessList) {
669: DWORD pl;
670: ret = (lpfnGetConsoleProcessList(&pl, 1) > 1);
671: FreeLibrary(hLibrary);
672: return(ret);
673: }
674: FreeLibrary(hLibrary);
675: }
676:
677: HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
678: if(hSnapshot != INVALID_HANDLE_VALUE) {
679: DWORD dwParentProcessID = 0;
680: PROCESSENTRY32 pe32;
681: pe32.dwSize = sizeof(PROCESSENTRY32);
682: if(Process32First(hSnapshot, &pe32)) {
683: do {
684: if(pe32.th32ProcessID == GetCurrentProcessId()) {
685: dwParentProcessID = pe32.th32ParentProcessID;
686: break;
687: }
688: } while(Process32Next(hSnapshot, &pe32));
689: }
690: CloseHandle(hSnapshot);
691: if(dwParentProcessID != 0) {
692: HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwParentProcessID);
693: if(hProcess != NULL) {
694: HMODULE hMod;
695: DWORD cbNeeded;
696: if(EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {
697: char module_name[MAX_PATH];
698: if(GetModuleBaseName(hProcess, hMod, module_name, sizeof(module_name))) {
699: ret = (_strnicmp(module_name, "cmd.exe", 7) == 0);
700: }
701: }
702: CloseHandle(hProcess);
703: }
704: }
705: }
706: return(ret);
1.1.1.14 root 707: }
708:
709: BOOL is_greater_windows_version(DWORD dwMajorVersion, DWORD dwMinorVersion, WORD wServicePackMajor, WORD wServicePackMinor)
710: {
1.1.1.24! root 711: // https://msdn.microsoft.com/en-us/library/windows/desktop/ms725491(v=vs.85).aspx
1.1.1.14 root 712: OSVERSIONINFOEX osvi;
713: DWORDLONG dwlConditionMask = 0;
714: int op = VER_GREATER_EQUAL;
715:
716: // Initialize the OSVERSIONINFOEX structure.
717: ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
718: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
719: osvi.dwMajorVersion = dwMajorVersion;
720: osvi.dwMinorVersion = dwMinorVersion;
721: osvi.wServicePackMajor = wServicePackMajor;
722: osvi.wServicePackMinor = wServicePackMinor;
723:
724: // Initialize the condition mask.
725: VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, op );
726: VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, op );
727: VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, op );
728: VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMINOR, op );
729:
730: // Perform the test.
731: return VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, dwlConditionMask);
732: }
733:
734: BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
735: {
736: if(dwCtrlType == CTRL_BREAK_EVENT || dwCtrlType == CTRL_C_EVENT) {
737: m_halted = 1;
738: return TRUE;
739: }
740: return FALSE;
741: }
742:
743: #ifdef USE_THREAD
744: DWORD WINAPI vram_thread(LPVOID)
745: {
746: while(!m_halted) {
747: EnterCriticalSection(&vram_crit_sect);
748: if(vram_length_char != 0 && vram_length_char == vram_last_length_char) {
749: vram_flush_char();
750: }
751: if(vram_length_attr != 0 && vram_length_attr == vram_last_length_attr) {
752: vram_flush_attr();
753: }
754: vram_last_length_char = vram_length_char;
755: vram_last_length_attr = vram_length_attr;
756: LeaveCriticalSection(&vram_crit_sect);
757: // this is about half the maximum keyboard repeat rate - any
758: // lower tends to be jerky, any higher misses updates
759: Sleep(15);
1.1.1.10 root 760: }
1.1.1.14 root 761: return 0;
1.1.1.10 root 762: }
1.1.1.14 root 763: #endif
1.1.1.10 root 764:
1.1.1.9 root 765: #define IS_NUMERIC(c) ((c) >= '0' && (c) <= '9')
766:
1.1 root 767: int main(int argc, char *argv[], char *envp[])
768: {
1.1.1.9 root 769: int arg_offset = 0;
770: int standard_env = 0;
1.1.1.14 root 771: int buf_width = 0, buf_height = 0;
1.1.1.15 root 772: BOOL bSuccess, bChangeScreenSize = FALSE;
1.1 root 773:
1.1.1.9 root 774: for(int i = 1; i < argc; i++) {
775: if(_strnicmp(argv[i], "-e", 2) == 0) {
776: standard_env = 1;
777: arg_offset++;
1.1.1.14 root 778: } else if(_strnicmp(argv[i], "-i", 2) == 0) {
779: ignore_illegal_insn = true;
780: arg_offset++;
781: } else if(_strnicmp(argv[i], "-m", 2) == 0) {
782: limit_max_memory = true;
783: arg_offset++;
784: } else if(_strnicmp(argv[i], "-d", 2) == 0) {
785: no_windows = true;
786: arg_offset++;
787: } else if(_strnicmp(argv[i], "-b", 2) == 0) {
788: stay_busy = true;
789: arg_offset++;
1.1.1.19 root 790: } else if(_strnicmp(argv[i], "-x", 2) == 0) {
791: UMB_TOP = EMS_TOP + EMS_SIZE;
792: support_ems = true;
793: #ifdef SUPPORT_XMS
794: support_xms = true;
795: #endif
796: arg_offset++;
1.1.1.14 root 797: } else if(_strnicmp(argv[i], "-n", 2) == 0) {
1.1.1.17 root 798: if(sscanf(argv[1] + 2, "%d,%d", &buf_height, &buf_width) != 2) {
799: buf_width = buf_height = 0;
800: }
801: if(buf_width <= 0 || buf_width > 0x7fff) {
802: buf_width = 80;
803: }
804: if(buf_height <= 0 || buf_height > 0x7fff) {
805: buf_height = 25;
806: }
1.1.1.14 root 807: arg_offset++;
1.1.1.9 root 808: } else if(_strnicmp(argv[i], "-v", 2) == 0) {
1.1.1.17 root 809: 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 810: major_version = argv[i][2] - '0';
1.1.1.17 root 811: minor_version = (argv[i][4] - '0') * 10 + (argv[i][5] ? (argv[i][5] - '0') : 0);
1.1.1.9 root 812: }
813: arg_offset++;
814: } else {
815: break;
816: }
817: }
818:
819: if(argc < 2 + arg_offset) {
1.1 root 820: #ifdef _WIN64
1.1.1.14 root 821: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32-x64 console\n\n");
1.1 root 822: #else
1.1.1.14 root 823: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32 console\n\n");
1.1 root 824: #endif
1.1.1.19 root 825: fprintf(stderr, "Usage: MSDOS [-b] [-d] [-e] [-i] [-m] [-n[L[,C]]] [-vX.XX] [-x] (command file) [options]\n"
1.1.1.14 root 826: "\n"
827: "\t-b\tstay busy during keyboard polling\n"
828: "\t-d\tpretend running under straight DOS, not Windows\n"
829: "\t-e\tuse a reduced environment block\n"
830: "\t-i\tignore invalid instructions\n"
831: "\t-m\trestrict free memory to 0x7FFF paragraphs\n"
832: "\t-n\tcreate a new buffer (25 lines, 80 columns by default)\n"
1.1.1.19 root 833: "\t-v\tset the DOS version\n"
834: #ifdef SUPPORT_XMS
835: "\t-x\tenable XMS/EMS\n"
836: #else
837: "\t-x\tenable EMS\n"
838: #endif
839: );
1.1.1.10 root 840:
841: if(!is_started_from_command_prompt()) {
842: fprintf(stderr, "\nStart this program from a command prompt!\n\nHit any key to quit...");
843: while(!_kbhit()) {
844: Sleep(10);
845: }
846: }
1.1.1.20 root 847: #ifdef _DEBUG
848: _CrtDumpMemoryLeaks();
849: #endif
1.1 root 850: return(EXIT_FAILURE);
851: }
852:
1.1.1.14 root 853: is_vista_or_later = is_greater_windows_version(6, 0, 0, 0);
854:
1.1.1.23 root 855: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 856: CONSOLE_SCREEN_BUFFER_INFO csbi;
1.1.1.14 root 857: CONSOLE_CURSOR_INFO ci;
1.1.1.23 root 858:
1.1.1.12 root 859: bSuccess = GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 860: GetConsoleCursorInfo(hStdout, &ci);
1.1.1.24! root 861: GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwConsoleMode);
1.1 root 862:
1.1.1.14 root 863: for(int y = 0; y < SCR_BUF_WIDTH; y++) {
864: for(int x = 0; x < SCR_BUF_HEIGHT; x++) {
865: SCR_BUF(y,x).Char.AsciiChar = ' ';
866: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 867: }
868: }
1.1.1.12 root 869: if(bSuccess) {
870: scr_width = csbi.dwSize.X;
1.1.1.14 root 871: scr_height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
872:
873: // v-text shadow buffer size is 0x7ff0
874: if((scr_width > SCR_BUF_WIDTH) || (scr_height > SCR_BUF_HEIGHT) || (scr_width * scr_height * 2 > 0x7ff0) ||
875: (buf_width != 0 && buf_width != scr_width) || (buf_height != 0 && buf_height != scr_height)) {
876: scr_width = min(buf_width != 0 ? buf_width : scr_width, SCR_BUF_WIDTH);
877: scr_height = min(buf_height != 0 ? buf_height : scr_height, SCR_BUF_HEIGHT);
878: if(scr_width * scr_height * 2 > 0x7ff0) {
879: scr_width = 80;
880: scr_height = 25;
881: }
1.1.1.15 root 882: bChangeScreenSize = TRUE;
1.1.1.14 root 883: }
1.1.1.12 root 884: } else {
885: // for a proof (not a console)
886: scr_width = 80;
887: scr_height = 25;
888: }
1.1.1.14 root 889: scr_buf_size.X = scr_width;
890: scr_buf_size.Y = scr_height;
891: scr_buf_pos.X = scr_buf_pos.Y = 0;
892: scr_top = csbi.srWindow.Top;
1.1 root 893: cursor_moved = false;
894:
895: key_buf_char = new FIFO();
896: key_buf_scan = new FIFO();
897:
898: hardware_init();
899:
1.1.1.9 root 900: if(msdos_init(argc - (arg_offset + 1), argv + (arg_offset + 1), envp, standard_env)) {
1.1 root 901: retval = EXIT_FAILURE;
902: } else {
1.1.1.14 root 903: #if defined(_MSC_VER) && _MSC_VER >= 1400
904: _set_invalid_parameter_handler((_invalid_parameter_handler)ignore_invalid_parameters);
905: #endif
906: SetConsoleCtrlHandler(ctrl_handler, TRUE);
907:
1.1.1.24! root 908: if(bChangeScreenSize) {
! 909: change_console_size(scr_width, scr_height);
! 910: }
1.1.1.8 root 911: TIMECAPS caps;
912: timeGetDevCaps(&caps, sizeof(TIMECAPS));
913: timeBeginPeriod(caps.wPeriodMin);
1.1.1.14 root 914: #ifdef USE_THREAD
915: InitializeCriticalSection(&vram_crit_sect);
916: CloseHandle(CreateThread(NULL, 4096, vram_thread, NULL, 0, NULL));
917: #endif
1.1 root 918: hardware_run();
1.1.1.14 root 919: #ifdef USE_THREAD
920: vram_flush();
921: DeleteCriticalSection(&vram_crit_sect);
922: #endif
1.1.1.24! root 923: timeEndPeriod(caps.wPeriodMin);
1.1.1.14 root 924:
1.1.1.24! root 925: // hStdin/hStdout (and all handles) will be closed in msdos_finish()...
1.1.1.12 root 926: if(bSuccess) {
1.1.1.23 root 927: hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.12 root 928: if(restore_console_on_exit) {
1.1.1.14 root 929: // window can't be bigger than buffer,
930: // buffer can't be smaller than window,
931: // so make a tiny window,
932: // set the required buffer,
933: // then set the required window
934: SMALL_RECT rect;
935: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
936: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.12 root 937: SetConsoleScreenBufferSize(hStdout, csbi.dwSize);
1.1.1.14 root 938: SET_RECT(rect, 0, 0, csbi.srWindow.Right - csbi.srWindow.Left, csbi.srWindow.Bottom - csbi.srWindow.Top);
1.1.1.12 root 939: SetConsoleWindowInfo(hStdout, TRUE, &rect);
940: }
1.1.1.14 root 941: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
942: SetConsoleCursorInfo(hStdout, &ci);
1.1.1.12 root 943: }
1.1.1.24! root 944: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode);
! 945:
1.1 root 946: msdos_finish();
1.1.1.14 root 947:
948: SetConsoleCtrlHandler(ctrl_handler, FALSE);
1.1 root 949: }
950:
1.1.1.10 root 951: hardware_finish();
952:
1.1 root 953: delete key_buf_char;
954: delete key_buf_scan;
955:
1.1.1.12 root 956: // SetConsoleTextAttribute(hStdout, csbi.wAttributes);
1.1 root 957:
1.1.1.20 root 958: #ifdef _DEBUG
959: _CrtDumpMemoryLeaks();
960: #endif
1.1 root 961: return(retval);
962: }
963:
1.1.1.20 root 964: /* ----------------------------------------------------------------------------
965: console
966: ---------------------------------------------------------------------------- */
967:
1.1.1.14 root 968: void change_console_size(int width, int height)
1.1.1.12 root 969: {
1.1.1.23 root 970: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.12 root 971: CONSOLE_SCREEN_BUFFER_INFO csbi;
972: SMALL_RECT rect;
973: COORD co;
974:
975: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 976: if(csbi.srWindow.Top != 0 || csbi.dwCursorPosition.Y > height - 1) {
977: if(csbi.srWindow.Right - csbi.srWindow.Left + 1 == width && csbi.srWindow.Bottom - csbi.srWindow.Top + 1 == height) {
978: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &csbi.srWindow);
979: SET_RECT(rect, 0, 0, width - 1, height - 1);
980: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
981: } else if(csbi.dwCursorPosition.Y > height - 1) {
982: SET_RECT(rect, 0, csbi.dwCursorPosition.Y - (height - 1), width - 1, csbi.dwCursorPosition.Y);
983: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
984: SET_RECT(rect, 0, 0, width - 1, height - 1);
985: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1.1.12 root 986: }
987: }
1.1.1.14 root 988: if(csbi.dwCursorPosition.Y > height - 1) {
1.1.1.12 root 989: co.X = csbi.dwCursorPosition.X;
1.1.1.14 root 990: co.Y = min(height - 1, csbi.dwCursorPosition.Y - csbi.srWindow.Top);
1.1.1.12 root 991: SetConsoleCursorPosition(hStdout, co);
992: cursor_moved = true;
993: }
1.1.1.14 root 994:
995: // window can't be bigger than buffer,
996: // buffer can't be smaller than window,
997: // so make a tiny window,
998: // set the required buffer,
999: // then set the required window
1000: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
1.1.1.12 root 1001: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.14 root 1002: co.X = width;
1003: co.Y = height;
1.1.1.12 root 1004: SetConsoleScreenBufferSize(hStdout, co);
1.1.1.14 root 1005: SET_RECT(rect, 0, 0, width - 1, height - 1);
1006: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1007:
1008: scr_width = scr_buf_size.X = width;
1009: scr_height = scr_buf_size.Y = height;
1010: scr_top = 0;
1011:
1012: clear_scr_buffer(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
1013:
1014: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.15 root 1015: text_vram_end_address = text_vram_top_address + regen;
1016: shadow_buffer_end_address = shadow_buffer_top_address + regen;
1017:
1.1.1.14 root 1018: if(regen > 0x4000) {
1019: regen = 0x8000;
1020: vram_pages = 1;
1021: } else if(regen > 0x2000) {
1022: regen = 0x4000;
1023: vram_pages = 2;
1024: } else if(regen > 0x1000) {
1025: regen = 0x2000;
1026: vram_pages = 4;
1027: } else {
1028: regen = 0x1000;
1029: vram_pages = 8;
1030: }
1.1.1.15 root 1031: *(UINT16 *)(mem + 0x44a) = scr_width;
1032: *(UINT16 *)(mem + 0x44c) = regen;
1033: *(UINT8 *)(mem + 0x484) = scr_height - 1;
1034:
1.1.1.24! root 1035: mouse.min_position.x = 0;
! 1036: mouse.min_position.y = 0;
! 1037: mouse.max_position.x = 8 * scr_width - 1;
! 1038: mouse.max_position.y = 8 * scr_height - 1;
! 1039:
1.1.1.15 root 1040: restore_console_on_exit = true;
1.1.1.14 root 1041: }
1042:
1043: void clear_scr_buffer(WORD attr)
1044: {
1045: for(int y = 0; y < scr_height; y++) {
1046: for(int x = 0; x < scr_width; x++) {
1047: SCR_BUF(y,x).Char.AsciiChar = ' ';
1048: SCR_BUF(y,x).Attributes = attr;
1049: }
1050: }
1.1.1.12 root 1051: }
1052:
1.1.1.24! root 1053: bool update_console_input()
1.1 root 1054: {
1.1.1.23 root 1055: HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
1.1.1.8 root 1056: DWORD dwNumberOfEvents = 0;
1.1 root 1057: DWORD dwRead;
1058: INPUT_RECORD ir[16];
1.1.1.24! root 1059: CONSOLE_SCREEN_BUFFER_INFO csbi = {0};
! 1060: bool result = false;
1.1 root 1061:
1.1.1.8 root 1062: if(GetNumberOfConsoleInputEvents(hStdin, &dwNumberOfEvents) && dwNumberOfEvents != 0) {
1063: if(ReadConsoleInputA(hStdin, ir, 16, &dwRead)) {
1064: for(int i = 0; i < dwRead; i++) {
1.1.1.24! root 1065: if(ir[i].EventType & MOUSE_EVENT) {
! 1066: if(mouse.active) {
! 1067: if(ir[i].Event.MouseEvent.dwEventFlags == 0) {
! 1068: for(int i = 0; i < MAX_MOUSE_BUTTONS; i++) {
! 1069: static const DWORD bits[] = {
! 1070: FROM_LEFT_1ST_BUTTON_PRESSED, // left
! 1071: RIGHTMOST_BUTTON_PRESSED, // right
! 1072: FROM_LEFT_2ND_BUTTON_PRESSED, // middle
1.1.1.14 root 1073: };
1.1.1.24! root 1074: bool prev_status = mouse.buttons[i].status;
! 1075: mouse.buttons[i].status = ((ir[i].Event.MouseEvent.dwButtonState & bits[i]) != 0);
! 1076:
! 1077: if(!prev_status && mouse.buttons[i].status) {
! 1078: mouse.buttons[i].pressed_times++;
! 1079: mouse.buttons[i].pressed_position.x = mouse.position.x;
! 1080: mouse.buttons[i].pressed_position.y = mouse.position.y;
! 1081: mouse.status |= 2 << (i * 2);
! 1082: } else if(prev_status && !mouse.buttons[i].status) {
! 1083: mouse.buttons[i].released_times++;
! 1084: mouse.buttons[i].released_position.x = mouse.position.x;
! 1085: mouse.buttons[i].released_position.y = mouse.position.y;
! 1086: mouse.status |= 4 << (i * 2);
! 1087: }
1.1.1.14 root 1088: }
1.1.1.24! root 1089: } else if(ir[i].Event.MouseEvent.dwEventFlags & MOUSE_MOVED) {
! 1090: // NOTE: if restore_console_on_exit, console is not scrolled
! 1091: if(!restore_console_on_exit && csbi.srWindow.Bottom == 0) {
! 1092: GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
1.1.1.14 root 1093: }
1.1.1.24! root 1094: // FIXME: character is always 8x8 ???
! 1095: int x = 8 * (ir[i].Event.MouseEvent.dwMousePosition.X);
! 1096: int y = 8 * (ir[i].Event.MouseEvent.dwMousePosition.Y - csbi.srWindow.Top);
! 1097: if(mouse.position.x != x || mouse.position.y != y) {
! 1098: mouse.position.x = x;
! 1099: mouse.position.y = y;
! 1100: mouse.status |= 1;
1.1.1.14 root 1101: }
1102: }
1103: }
1.1.1.24! root 1104: } else if(ir[i].EventType & KEY_EVENT) {
! 1105: kbd_data = ir[i].Event.KeyEvent.wVirtualScanCode;
1.1.1.14 root 1106: if(!ir[i].Event.KeyEvent.bKeyDown) {
1107: kbd_data |= 0x80;
1.1.1.24! root 1108: } else {
! 1109: kbd_data &= 0x7f;
! 1110:
! 1111: // update dos key buffer
! 1112: UINT8 chr = ir[i].Event.KeyEvent.uChar.AsciiChar;
! 1113: UINT8 scn = ir[i].Event.KeyEvent.wVirtualScanCode & 0xff;
! 1114:
! 1115: if(chr == 0) {
! 1116: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
! 1117: if(scn >= 0x3b && scn <= 0x44) {
! 1118: scn += 0x68 - 0x3b; // F1 to F10
! 1119: } else if(scn == 0x57 || scn == 0x58) {
! 1120: scn += 0x8b - 0x57; // F11 & F12
! 1121: } else if(scn >= 0x47 && scn <= 0x53) {
! 1122: scn += 0x97 - 0x47; // edit/arrow clusters
! 1123: } else if(scn == 0x35) {
! 1124: scn = 0xa4; // keypad /
! 1125: }
! 1126: } else if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
! 1127: if(scn == 0x07) {
! 1128: chr = 0x1e; // Ctrl+^
! 1129: } else if(scn == 0x0c) {
! 1130: chr = 0x1f; // Ctrl+_
! 1131: } else if(scn >= 0x35 && scn <= 0x58) {
! 1132: static const UINT8 ctrl_map[] = {
! 1133: 0x95, // keypad /
! 1134: 0,
! 1135: 0x96, // keypad *
! 1136: 0, 0, 0,
! 1137: 0x5e, // F1
! 1138: 0x5f, // F2
! 1139: 0x60, // F3
! 1140: 0x61, // F4
! 1141: 0x62, // F5
! 1142: 0x63, // F6
! 1143: 0x64, // F7
! 1144: 0x65, // F8
! 1145: 0x66, // F9
! 1146: 0x67, // F10
! 1147: 0,
! 1148: 0,
! 1149: 0x77, // Home
! 1150: 0x8d, // Up
! 1151: 0x84, // PgUp
! 1152: 0x8e, // keypad -
! 1153: 0x73, // Left
! 1154: 0x8f, // keypad center
! 1155: 0x74, // Right
! 1156: 0x90, // keyapd +
! 1157: 0x75, // End
! 1158: 0x91, // Down
! 1159: 0x76, // PgDn
! 1160: 0x92, // Insert
! 1161: 0x93, // Delete
! 1162: 0, 0, 0,
! 1163: 0x89, // F11
! 1164: 0x8a, // F12
! 1165: };
! 1166: scn = ctrl_map[scn - 0x35];
! 1167: }
! 1168: } else if(ir[i].Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
! 1169: if(scn >= 0x3b && scn <= 0x44) {
! 1170: scn += 0x54 - 0x3b; // F1 to F10
! 1171: } else if(scn == 0x57 || scn == 0x58) {
! 1172: scn += 0x87 - 0x57; // F11 & F12
! 1173: }
! 1174: } else if(scn == 0x57 || scn == 0x58) {
! 1175: scn += 0x85 - 0x57;
! 1176: }
! 1177: // ignore shift, ctrl, alt, win and menu keys
! 1178: if(scn != 0x1d && scn != 0x2a && scn != 0x36 && scn != 0x38 && (scn < 0x5b || scn > 0x5e)) {
! 1179: if(chr == 0) {
! 1180: key_buf_char->write(0x00);
! 1181: key_buf_scan->write(ir[i].Event.KeyEvent.dwControlKeyState & ENHANCED_KEY ? 0xe0 : 0x00);
! 1182: }
! 1183: key_buf_char->write(chr);
! 1184: key_buf_scan->write(scn);
! 1185: }
! 1186: } else {
! 1187: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
! 1188: chr = 0;
! 1189: if(scn >= 0x02 && scn <= 0x0e) {
! 1190: scn += 0x78 - 0x02; // 1 to 0 - =
! 1191: }
! 1192: }
! 1193: key_buf_char->write(chr);
! 1194: key_buf_scan->write(scn);
! 1195: }
1.1 root 1196: }
1.1.1.24! root 1197: result = key_changed = true;
1.1 root 1198: }
1199: }
1200: }
1201: }
1.1.1.24! root 1202: return(result);
1.1.1.8 root 1203: }
1204:
1.1.1.14 root 1205: bool update_key_buffer()
1.1.1.8 root 1206: {
1.1.1.24! root 1207: return(update_console_input() || key_buf_char->count() != 0);
1.1.1.8 root 1208: }
1209:
1.1.1.20 root 1210: /* ----------------------------------------------------------------------------
1211: MS-DOS virtual machine
1212: ---------------------------------------------------------------------------- */
1213:
1214: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg);
1215: int msdos_psp_get_file_table(int fd, int psp_seg);
1216: void msdos_putch(UINT8 data);
1217:
1.1 root 1218: // process info
1219:
1220: process_t *msdos_process_info_create(UINT16 psp_seg)
1221: {
1222: for(int i = 0; i < MAX_PROCESS; i++) {
1223: if(process[i].psp == 0 || process[i].psp == psp_seg) {
1224: memset(&process[i], 0, sizeof(process_t));
1225: process[i].psp = psp_seg;
1226: return(&process[i]);
1227: }
1228: }
1229: fatalerror("too many processes\n");
1230: return(NULL);
1231: }
1232:
1233: process_t *msdos_process_info_get(UINT16 psp_seg)
1234: {
1235: for(int i = 0; i < MAX_PROCESS; i++) {
1236: if(process[i].psp == psp_seg) {
1237: return(&process[i]);
1238: }
1239: }
1240: fatalerror("invalid psp address\n");
1241: return(NULL);
1242: }
1243:
1.1.1.23 root 1244: void msdos_sda_update(int psp_seg)
1245: {
1246: sda_t *sda = (sda_t *)(mem + SDA_TOP);
1247:
1248: for(int i = 0; i < MAX_PROCESS; i++) {
1249: if(process[i].psp == psp_seg) {
1250: sda->switchar = process[i].switchar;
1251: sda->current_dta.w.l = process[i].dta.w.l;
1252: sda->current_dta.w.h = process[i].dta.w.h;
1253: sda->current_psp = process[i].psp;
1254: break;
1255: }
1256: }
1257: sda->malloc_strategy = malloc_strategy;
1258: sda->return_code = retval;
1259: sda->current_drive = _getdrive();
1260: }
1261:
1.1.1.13 root 1262: // dta info
1263:
1264: void msdos_dta_info_init()
1265: {
1.1.1.14 root 1266: for(int i = 0; i < MAX_DTAINFO; i++) {
1.1.1.13 root 1267: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
1268: }
1269: }
1270:
1271: dtainfo_t *msdos_dta_info_get(UINT16 psp_seg, UINT32 dta_laddr)
1272: {
1273: dtainfo_t *free_dta = NULL;
1.1.1.14 root 1274: for(int i = 0; i < MAX_DTAINFO; i++) {
1275: if(dtalist[i].find_handle == INVALID_HANDLE_VALUE) {
1276: if(free_dta == NULL) {
1.1.1.13 root 1277: free_dta = &dtalist[i];
1278: }
1.1.1.14 root 1279: } else if(dta_laddr < LFN_DTA_LADDR && dtalist[i].dta == dta_laddr) {
1.1.1.13 root 1280: return(&dtalist[i]);
1281: }
1282: }
1.1.1.14 root 1283: if(free_dta) {
1.1.1.13 root 1284: free_dta->psp = psp_seg;
1285: free_dta->dta = dta_laddr;
1286: return(free_dta);
1287: }
1288: fatalerror("too many dta\n");
1289: return(NULL);
1290: }
1291:
1292: void msdos_dta_info_free(UINT16 psp_seg)
1293: {
1.1.1.14 root 1294: for(int i = 0; i < MAX_DTAINFO; i++) {
1295: if(dtalist[i].psp == psp_seg && dtalist[i].find_handle != INVALID_HANDLE_VALUE) {
1.1.1.13 root 1296: FindClose(dtalist[i].find_handle);
1297: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
1298: }
1299: }
1300: }
1301:
1.1 root 1302: void msdos_cds_update(int drv)
1303: {
1304: cds_t *cds = (cds_t *)(mem + CDS_TOP);
1305:
1306: memset(mem + CDS_TOP, 0, CDS_SIZE);
1307: sprintf(cds->path_name, "%c:\\", 'A' + drv);
1308: cds->drive_attrib = 0x4000; // physical drive
1309: cds->physical_drive_number = drv;
1310: }
1311:
1.1.1.17 root 1312: // nls information tables
1313:
1314: // uppercase table (func 6502h)
1315: void msdos_upper_table_update()
1316: {
1317: *(UINT16 *)(mem + UPPERTABLE_TOP) = 0x80;
1.1.1.22 root 1318: for(unsigned i = 0; i < 0x80; ++i) {
1.1.1.17 root 1319: UINT8 c[4];
1320: *(UINT32 *)c = 0; // reset internal conversion state
1321: CharUpperBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
1322: c[0] = 0x80 + i;
1323: DWORD rc = CharUpperBuffA((LPSTR)c, 1);
1324: mem[UPPERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
1325: }
1326: }
1327:
1.1.1.23 root 1328: // lowercase table (func 6503h)
1329: void msdos_lower_table_update()
1330: {
1331: *(UINT16 *)(mem + LOWERTABLE_TOP) = 0x80;
1332: for(unsigned i = 0; i < 0x80; ++i) {
1333: UINT8 c[4];
1334: *(UINT32 *)c = 0; // reset internal conversion state
1335: CharLowerBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
1336: c[0] = 0x80 + i;
1337: DWORD rc = CharLowerBuffA((LPSTR)c, 1);
1338: mem[LOWERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
1339: }
1340: }
1341:
1.1.1.17 root 1342: // filename uppercase table (func 6504h)
1343: void msdos_filename_upper_table_init()
1344: {
1345: // depended on (file)system, not on active codepage
1346: // temporary solution: just filling data
1347: *(UINT16 *)(mem + FILENAME_UPPERTABLE_TOP) = 0x80;
1.1.1.22 root 1348: for(unsigned i = 0; i < 0x80; ++i) {
1.1.1.17 root 1349: mem[FILENAME_UPPERTABLE_TOP + 2 + i] = 0x80 + i;
1350: }
1351: }
1352:
1353: // filaname terminator table (func 6505h)
1354: void msdos_filename_terminator_table_init()
1355: {
1356: const char illegal_chars[] = ".\"/\\[]:|<>+=;,"; // for standard MS-DOS fs.
1357: UINT8 *data = mem + FILENAME_TERMINATOR_TOP;
1358:
1359: data[2] = 1; // marker? (permissible character value)
1360: data[3] = 0x00; // 00h...FFh
1361: data[4] = 0xff;
1362: data[5] = 0; // marker? (excluded character)
1363: data[6] = 0x00; // 00h...20h
1364: data[7] = 0x20;
1365: data[8] = 2; // marker? (illegal characters for filename)
1366: data[9] = (UINT8)strlen(illegal_chars);
1367: memcpy(data + 10, illegal_chars, data[9]);
1368:
1369: // total length
1370: *(UINT16 *)data = (10 - 2) + data[9];
1371: }
1372:
1373: // collating table (func 6506h)
1374: void msdos_collating_table_update()
1375: {
1376: // temporary solution: just filling data
1377: *(UINT16 *)(mem + COLLATING_TABLE_TOP) = 0x100;
1.1.1.22 root 1378: for(unsigned i = 0; i < 256; ++i) {
1.1.1.17 root 1379: mem[COLLATING_TABLE_TOP + 2 + i] = i;
1380: }
1381: }
1382:
1.1 root 1383: // dbcs
1384:
1385: void msdos_dbcs_table_update()
1386: {
1387: UINT8 dbcs_data[DBCS_SIZE];
1388: memset(dbcs_data, 0, sizeof(dbcs_data));
1389:
1390: CPINFO info;
1391: GetCPInfo(active_code_page, &info);
1392:
1393: if(info.MaxCharSize != 1) {
1394: for(int i = 0;; i += 2) {
1395: UINT8 lo = info.LeadByte[i + 0];
1396: UINT8 hi = info.LeadByte[i + 1];
1397: dbcs_data[2 + i + 0] = lo;
1398: dbcs_data[2 + i + 1] = hi;
1399: if(lo == 0 && hi == 0) {
1400: dbcs_data[0] = i + 2;
1401: break;
1402: }
1403: }
1404: } else {
1405: dbcs_data[0] = 2; // ???
1406: }
1407: memcpy(mem + DBCS_TOP, dbcs_data, sizeof(dbcs_data));
1408: }
1409:
1.1.1.17 root 1410: void msdos_dbcs_table_finish()
1411: {
1412: if(active_code_page != system_code_page) {
1413: _setmbcp(system_code_page);
1414: }
1415: }
1416:
1417: void msdos_nls_tables_init()
1.1 root 1418: {
1419: system_code_page = active_code_page = _getmbcp();
1.1.1.17 root 1420: msdos_upper_table_update();
1.1.1.23 root 1421: msdos_lower_table_update();
1.1.1.17 root 1422: msdos_filename_terminator_table_init();
1423: msdos_filename_upper_table_init();
1424: msdos_collating_table_update();
1.1 root 1425: msdos_dbcs_table_update();
1426: }
1427:
1.1.1.17 root 1428: void msdos_nls_tables_update()
1.1 root 1429: {
1.1.1.17 root 1430: msdos_dbcs_table_update();
1431: msdos_upper_table_update();
1.1.1.23 root 1432: msdos_lower_table_update();
1433: // msdos_collating_table_update();
1.1 root 1434: }
1435:
1436: int msdos_lead_byte_check(UINT8 code)
1437: {
1438: UINT8 *dbcs_table = mem + DBCS_TABLE;
1439:
1440: for(int i = 0;; i += 2) {
1441: UINT8 lo = dbcs_table[i + 0];
1442: UINT8 hi = dbcs_table[i + 1];
1443: if(lo == 0 && hi == 0) {
1444: break;
1445: }
1446: if(lo <= code && code <= hi) {
1447: return(1);
1448: }
1449: }
1450: return(0);
1451: }
1452:
1.1.1.20 root 1453: int msdos_ctrl_code_check(UINT8 code)
1454: {
1.1.1.22 root 1455: return (code >= 0x01 && code <= 0x1a && code != 0x07 && code != 0x08 && code != 0x09 && code != 0x0a && code != 0x0d);
1.1.1.20 root 1456: }
1457:
1.1 root 1458: // file control
1459:
1.1.1.14 root 1460: char *msdos_remove_double_quote(char *path)
1461: {
1462: static char tmp[MAX_PATH];
1463:
1464: memset(tmp, 0, sizeof(tmp));
1465: if(strlen(path) >= 2 && path[0] == '"' && path[strlen(path) - 1] == '"') {
1466: memcpy(tmp, path + 1, strlen(path) - 2);
1467: } else {
1468: strcpy(tmp, path);
1469: }
1470: return(tmp);
1471: }
1472:
1473: char *msdos_combine_path(char *dir, const char *file)
1474: {
1475: static char tmp[MAX_PATH];
1476: char *tmp_dir = msdos_remove_double_quote(dir);
1477:
1478: if(strlen(tmp_dir) == 0) {
1479: strcpy(tmp, file);
1480: } else if(tmp_dir[strlen(tmp_dir) - 1] == '\\') {
1481: sprintf(tmp, "%s%s", tmp_dir, file);
1482: } else {
1483: sprintf(tmp, "%s\\%s", tmp_dir, file);
1484: }
1485: return(tmp);
1486: }
1487:
1.1 root 1488: char *msdos_trimmed_path(char *path, int lfn)
1489: {
1490: static char tmp[MAX_PATH];
1491:
1492: if(lfn) {
1493: strcpy(tmp, path);
1494: } else {
1495: // remove space in the path
1496: char *src = path, *dst = tmp;
1497:
1498: while(*src != '\0') {
1499: if(msdos_lead_byte_check(*src)) {
1500: *dst++ = *src++;
1501: *dst++ = *src++;
1502: } else if(*src != ' ') {
1503: *dst++ = *src++;
1504: } else {
1505: src++; // skip space
1506: }
1507: }
1508: *dst = '\0';
1509: }
1.1.1.14 root 1510: if(_stricmp(tmp, "C:\\COMMAND.COM") == 0) {
1511: // redirect C:\COMMAND.COM to comspec_path
1512: strcpy(tmp, comspec_path);
1513: } else if(is_vista_or_later && _access(tmp, 0) != 0) {
1514: // redirect new files (without wildcards) in C:\ to %TEMP%, since C:\ is not usually writable
1515: static int root_drive_protected = -1;
1516: char temp[MAX_PATH], name[MAX_PATH], *name_temp = NULL;
1517: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
1518:
1519: if(GetFullPathName(tmp, MAX_PATH, temp, &name_temp) != 0 &&
1520: name_temp != NULL && strstr(name_temp, "?") == NULL && strstr(name_temp, "*") == NULL) {
1521: strcpy(name, name_temp);
1522: name_temp[0] = '\0';
1523:
1524: if((temp[0] == 'A' + dos_info->boot_drive - 1 || temp[0] == 'a' + dos_info->boot_drive - 1) &&
1525: (temp[1] == ':') && (temp[2] == '\\' || temp[2] == '/') && (temp[3] == '\0')) {
1526: if(root_drive_protected == -1) {
1527: FILE *fp = NULL;
1528:
1529: sprintf(temp, "%c:\\MS-DOS_Player.$$$", 'A' + dos_info->boot_drive - 1);
1530: root_drive_protected = 1;
1531: try {
1532: if((fp = fopen(temp, "w")) != NULL) {
1533: if(fprintf(fp, "TEST") == 4) {
1534: root_drive_protected = 0;
1535: }
1536: }
1537: } catch(...) {
1538: }
1539: if(fp != NULL) {
1540: fclose(fp);
1541: }
1542: if(_access(temp, 0) == 0) {
1543: remove(temp);
1544: }
1545: }
1546: if(root_drive_protected == 1) {
1547: if(GetEnvironmentVariable("TEMP", temp, MAX_PATH) != 0 ||
1548: GetEnvironmentVariable("TMP", temp, MAX_PATH) != 0) {
1549: strcpy(tmp, msdos_combine_path(temp, name));
1550: }
1551: }
1552: }
1553: }
1554: }
1.1 root 1555: return(tmp);
1556: }
1557:
1558: bool match(char *text, char *pattern)
1559: {
1.1.1.24! root 1560: // http://www.prefield.com/algorithm/string/wildcard.html
1.1.1.14 root 1561: switch(*pattern) {
1.1 root 1562: case '\0':
1563: return !*text;
1564: case '*':
1.1.1.14 root 1565: return match(text, pattern + 1) || (*text && match(text + 1, pattern));
1.1 root 1566: case '?':
1567: return *text && match(text + 1, pattern + 1);
1568: default:
1569: return (*text == *pattern) && match(text + 1, pattern + 1);
1570: }
1571: }
1572:
1573: bool msdos_match_volume_label(char *path, char *volume)
1574: {
1575: char *p;
1576:
1.1.1.14 root 1577: if(!*volume) {
1578: return false;
1579: } else if((p = my_strchr(path, ':')) != NULL) {
1.1 root 1580: return msdos_match_volume_label(p + 1, volume);
1581: } else if((p = my_strchr(path, '\\')) != NULL) {
1582: return msdos_match_volume_label(p + 1, volume);
1583: } else if((p = my_strchr(path, '.')) != NULL) {
1.1.1.14 root 1584: char tmp[MAX_PATH];
1585: sprintf(tmp, "%.*s%s", (int)(p - path), path, p + 1);
1586: return match(volume, tmp);
1.1 root 1587: } else {
1588: return match(volume, path);
1589: }
1590: }
1591:
1592: char *msdos_fcb_path(fcb_t *fcb)
1593: {
1594: static char tmp[MAX_PATH];
1595: char name[9], ext[4];
1596:
1597: memset(name, 0, sizeof(name));
1598: memcpy(name, fcb->file_name, 8);
1599: strcpy(name, msdos_trimmed_path(name, 0));
1600:
1601: memset(ext, 0, sizeof(ext));
1602: memcpy(ext, fcb->file_name + 8, 3);
1603: strcpy(ext, msdos_trimmed_path(ext, 0));
1604:
1605: if(name[0] == '\0' || strcmp(name, "????????") == 0) {
1606: strcpy(name, "*");
1607: }
1608: if(ext[0] == '\0') {
1609: strcpy(tmp, name);
1610: } else {
1611: if(strcmp(ext, "???") == 0) {
1612: strcpy(ext, "*");
1613: }
1614: sprintf(tmp, "%s.%s", name, ext);
1615: }
1616: return(tmp);
1617: }
1618:
1619: void msdos_set_fcb_path(fcb_t *fcb, char *path)
1620: {
1621: char *ext = my_strchr(path, '.');
1622:
1623: memset(fcb->file_name, 0x20, 8 + 3);
1624: if(ext != NULL && path[0] != '.') {
1625: *ext = '\0';
1626: memcpy(fcb->file_name + 8, ext + 1, strlen(ext + 1));
1627: }
1628: memcpy(fcb->file_name, path, strlen(path));
1629: }
1630:
1631: char *msdos_short_path(char *path)
1632: {
1633: static char tmp[MAX_PATH];
1634:
1.1.1.24! root 1635: if(GetShortPathName(path, tmp, MAX_PATH) == 0) {
! 1636: strcpy(tmp, path);
! 1637: }
1.1 root 1638: my_strupr(tmp);
1639: return(tmp);
1640: }
1641:
1.1.1.13 root 1642: char *msdos_short_name(WIN32_FIND_DATA *fd)
1643: {
1644: static char tmp[MAX_PATH];
1645:
1.1.1.14 root 1646: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 1647: strcpy(tmp, fd->cAlternateFileName);
1648: } else {
1649: strcpy(tmp, fd->cFileName);
1650: }
1651: my_strupr(tmp);
1652: return(tmp);
1653: }
1654:
1.1 root 1655: char *msdos_short_full_path(char *path)
1656: {
1657: static char tmp[MAX_PATH];
1658: char full[MAX_PATH], *name;
1659:
1.1.1.14 root 1660: // Full works with non-existent files, but Short does not
1.1 root 1661: GetFullPathName(path, MAX_PATH, full, &name);
1.1.1.14 root 1662: *tmp = '\0';
1663: if(GetShortPathName(full, tmp, MAX_PATH) == 0 && name > path) {
1664: name[-1] = '\0';
1665: DWORD len = GetShortPathName(full, tmp, MAX_PATH);
1666: if(len == 0) {
1667: strcpy(tmp, full);
1668: } else {
1669: tmp[len++] = '\\';
1670: strcpy(tmp + len, name);
1671: }
1672: }
1.1 root 1673: my_strupr(tmp);
1674: return(tmp);
1675: }
1676:
1677: char *msdos_short_full_dir(char *path)
1678: {
1679: static char tmp[MAX_PATH];
1680: char full[MAX_PATH], *name;
1681:
1682: GetFullPathName(path, MAX_PATH, full, &name);
1683: name[-1] = '\0';
1.1.1.24! root 1684: if(GetShortPathName(full, tmp, MAX_PATH) == 0) {
! 1685: strcpy(tmp, full);
! 1686: }
1.1 root 1687: my_strupr(tmp);
1688: return(tmp);
1689: }
1690:
1691: char *msdos_local_file_path(char *path, int lfn)
1692: {
1693: char *trimmed = msdos_trimmed_path(path, lfn);
1.1.1.14 root 1694: #if 0
1695: // I have forgotten the reason of this routine... :-(
1.1 root 1696: if(_access(trimmed, 0) != 0) {
1697: process_t *process = msdos_process_info_get(current_psp);
1698: static char tmp[MAX_PATH];
1699:
1700: sprintf(tmp, "%s\\%s", process->module_dir, trimmed);
1701: if(_access(tmp, 0) == 0) {
1702: return(tmp);
1703: }
1704: }
1.1.1.14 root 1705: #endif
1.1 root 1706: return(trimmed);
1707: }
1708:
1.1.1.11 root 1709: bool msdos_is_con_path(char *path)
1710: {
1711: char full[MAX_PATH], *name;
1712:
1.1.1.24! root 1713: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
! 1714: return(_stricmp(full, "\\\\.\\CON") == 0);
! 1715: }
! 1716: return(false);
1.1.1.11 root 1717: }
1718:
1.1.1.14 root 1719: bool msdos_is_nul_path(char *path)
1.1.1.8 root 1720: {
1.1.1.14 root 1721: char full[MAX_PATH], *name;
1.1.1.8 root 1722:
1.1.1.24! root 1723: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
! 1724: return(_stricmp(full, "\\\\.\\NUL") == 0);
! 1725: }
! 1726: return(false);
! 1727: }
! 1728:
! 1729: bool msdos_is_driver_name(char *path)
! 1730: {
! 1731: char full[MAX_PATH], *name;
! 1732:
! 1733: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
! 1734: if(_stricmp(name, "EMMXXXX0") == 0) {
! 1735: return(true);
! 1736: }
! 1737: }
! 1738: return(false);
! 1739: }
! 1740:
! 1741: bool msdos_is_existing_file(char *path)
! 1742: {
! 1743: // http://d.hatena.ne.jp/yu-hr/20100317/1268826458
! 1744: WIN32_FIND_DATA FindData;
! 1745: HANDLE hFind;
! 1746:
! 1747: if((hFind = FindFirstFile(path, &FindData)) != INVALID_HANDLE_VALUE) {
! 1748: FindClose(hFind);
! 1749: return(!(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
! 1750: }
! 1751: return(false);
1.1.1.8 root 1752: }
1753:
1.1.1.9 root 1754: char *msdos_search_command_com(char *command_path, char *env_path)
1755: {
1756: static char tmp[MAX_PATH];
1757: char path[MAX_PATH], *file_name;
1758:
1759: if(GetFullPathName(command_path, MAX_PATH, tmp, &file_name) != 0) {
1760: sprintf(file_name, "COMMAND.COM");
1761: if(_access(tmp, 0) == 0) {
1762: return(tmp);
1763: }
1764: }
1765: if(GetModuleFileName(NULL, path, MAX_PATH) != 0 && GetFullPathName(path, MAX_PATH, tmp, &file_name) != 0) {
1766: sprintf(file_name, "COMMAND.COM");
1767: if(_access(tmp, 0) == 0) {
1768: return(tmp);
1769: }
1770: }
1771: if(GetFullPathName("COMMAND.COM", MAX_PATH, tmp, &file_name) != 0) {
1772: if(_access(tmp, 0) == 0) {
1773: return(tmp);
1774: }
1775: }
1776: char *token = my_strtok(env_path, ";");
1777: while(token != NULL) {
1.1.1.14 root 1778: if(strlen(token) != 0 && token[0] != '%') {
1.1.1.9 root 1779: strcpy(tmp, msdos_combine_path(token, "COMMAND.COM"));
1780: if(_access(tmp, 0) == 0) {
1781: return(tmp);
1782: }
1783: }
1784: token = my_strtok(NULL, ";");
1785: }
1786: return(NULL);
1787: }
1788:
1.1.1.14 root 1789: int msdos_drive_number(const char *path)
1.1 root 1790: {
1791: char tmp[MAX_PATH], *name;
1792:
1793: GetFullPathName(path, MAX_PATH, tmp, &name);
1794: if(tmp[0] >= 'a' && tmp[0] <= 'z') {
1795: return(tmp[0] - 'a');
1796: } else {
1797: return(tmp[0] - 'A');
1798: }
1799: }
1800:
1801: char *msdos_volume_label(char *path)
1802: {
1803: static char tmp[MAX_PATH];
1804: char volume[] = "A:\\";
1805:
1806: if(path[1] == ':') {
1807: volume[0] = path[0];
1808: } else {
1809: volume[0] = 'A' + _getdrive() - 1;
1810: }
1811: if(!GetVolumeInformation(volume, tmp, MAX_PATH, NULL, NULL, NULL, NULL, 0)) {
1812: memset(tmp, 0, sizeof(tmp));
1813: }
1814: return(tmp);
1815: }
1816:
1817: char *msdos_short_volume_label(char *label)
1818: {
1819: static char tmp[(8 + 1 + 3) + 1];
1820: char *src = label;
1821: int remain = strlen(label);
1822: char *dst_n = tmp;
1823: char *dst_e = tmp + 9;
1824:
1825: strcpy(tmp, " . ");
1826: for(int i = 0; i < 8 && remain > 0; i++) {
1827: if(msdos_lead_byte_check(*src)) {
1828: if(++i == 8) {
1829: break;
1830: }
1831: *dst_n++ = *src++;
1832: remain--;
1833: }
1834: *dst_n++ = *src++;
1835: remain--;
1836: }
1837: if(remain > 0) {
1838: for(int i = 0; i < 3 && remain > 0; i++) {
1839: if(msdos_lead_byte_check(*src)) {
1840: if(++i == 3) {
1841: break;
1842: }
1843: *dst_e++ = *src++;
1844: remain--;
1845: }
1846: *dst_e++ = *src++;
1847: remain--;
1848: }
1849: *dst_e = '\0';
1850: } else {
1851: *dst_n = '\0';
1852: }
1853: my_strupr(tmp);
1854: return(tmp);
1855: }
1856:
1.1.1.13 root 1857: errno_t msdos_maperr(unsigned long oserrno)
1858: {
1859: _doserrno = oserrno;
1.1.1.14 root 1860: switch(oserrno) {
1.1.1.13 root 1861: case ERROR_FILE_NOT_FOUND: // 2
1862: case ERROR_PATH_NOT_FOUND: // 3
1863: case ERROR_INVALID_DRIVE: // 15
1864: case ERROR_NO_MORE_FILES: // 18
1865: case ERROR_BAD_NETPATH: // 53
1866: case ERROR_BAD_NET_NAME: // 67
1867: case ERROR_BAD_PATHNAME: // 161
1868: case ERROR_FILENAME_EXCED_RANGE: // 206
1869: return ENOENT;
1870: case ERROR_TOO_MANY_OPEN_FILES: // 4
1871: return EMFILE;
1872: case ERROR_ACCESS_DENIED: // 5
1873: case ERROR_CURRENT_DIRECTORY: // 16
1874: case ERROR_NETWORK_ACCESS_DENIED: // 65
1875: case ERROR_CANNOT_MAKE: // 82
1876: case ERROR_FAIL_I24: // 83
1877: case ERROR_DRIVE_LOCKED: // 108
1878: case ERROR_SEEK_ON_DEVICE: // 132
1879: case ERROR_NOT_LOCKED: // 158
1880: case ERROR_LOCK_FAILED: // 167
1881: return EACCES;
1882: case ERROR_INVALID_HANDLE: // 6
1883: case ERROR_INVALID_TARGET_HANDLE: // 114
1884: case ERROR_DIRECT_ACCESS_HANDLE: // 130
1885: return EBADF;
1886: case ERROR_ARENA_TRASHED: // 7
1887: case ERROR_NOT_ENOUGH_MEMORY: // 8
1888: case ERROR_INVALID_BLOCK: // 9
1889: case ERROR_NOT_ENOUGH_QUOTA: // 1816
1890: return ENOMEM;
1891: case ERROR_BAD_ENVIRONMENT: // 10
1892: return E2BIG;
1893: case ERROR_BAD_FORMAT: // 11
1894: return ENOEXEC;
1895: case ERROR_NOT_SAME_DEVICE: // 17
1896: return EXDEV;
1897: case ERROR_FILE_EXISTS: // 80
1898: case ERROR_ALREADY_EXISTS: // 183
1899: return EEXIST;
1900: case ERROR_NO_PROC_SLOTS: // 89
1901: case ERROR_MAX_THRDS_REACHED: // 164
1902: case ERROR_NESTING_NOT_ALLOWED: // 215
1903: return EAGAIN;
1904: case ERROR_BROKEN_PIPE: // 109
1905: return EPIPE;
1906: case ERROR_DISK_FULL: // 112
1907: return ENOSPC;
1908: case ERROR_WAIT_NO_CHILDREN: // 128
1909: case ERROR_CHILD_NOT_COMPLETE: // 129
1910: return ECHILD;
1911: case ERROR_DIR_NOT_EMPTY: // 145
1912: return ENOTEMPTY;
1913: }
1.1.1.14 root 1914: if(oserrno >= ERROR_WRITE_PROTECT /* 19 */ &&
1.1.1.13 root 1915: oserrno <= ERROR_SHARING_BUFFER_EXCEEDED /* 36 */) {
1916: return EACCES;
1917: }
1.1.1.14 root 1918: if(oserrno >= ERROR_INVALID_STARTING_CODESEG /* 188 */ &&
1.1.1.13 root 1919: oserrno <= ERROR_INFLOOP_IN_RELOC_CHAIN /* 202 */) {
1920: return ENOEXEC;
1921: }
1922: return EINVAL;
1923: }
1924:
1925: int msdos_open(const char *filename, int oflag)
1926: {
1.1.1.14 root 1927: if((oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) != _O_RDONLY) {
1.1.1.13 root 1928: return _open(filename, oflag);
1929: }
1.1.1.14 root 1930:
1931: SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, !(oflag & _O_NOINHERIT) };
1.1.1.13 root 1932: DWORD disposition;
1.1.1.14 root 1933: switch(oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
1934: default:
1.1.1.13 root 1935: case _O_EXCL:
1936: disposition = OPEN_EXISTING;
1937: break;
1938: case _O_CREAT:
1939: disposition = OPEN_ALWAYS;
1940: break;
1941: case _O_CREAT | _O_EXCL:
1942: case _O_CREAT | _O_TRUNC | _O_EXCL:
1943: disposition = CREATE_NEW;
1944: break;
1945: case _O_TRUNC:
1946: case _O_TRUNC | _O_EXCL:
1947: disposition = TRUNCATE_EXISTING;
1948: break;
1949: case _O_CREAT | _O_TRUNC:
1950: disposition = CREATE_ALWAYS;
1951: break;
1952: }
1.1.1.14 root 1953:
1.1.1.13 root 1954: HANDLE h = CreateFile(filename, GENERIC_READ | FILE_WRITE_ATTRIBUTES,
1955: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
1956: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 1957: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 1958: // FILE_WRITE_ATTRIBUTES may not be granted for standard users.
1959: // Retry without FILE_WRITE_ATTRIBUTES.
1960: h = CreateFile(filename, GENERIC_READ,
1961: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
1962: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 1963: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 1964: errno = msdos_maperr(GetLastError());
1965: return -1;
1966: }
1967: }
1.1.1.14 root 1968:
1.1.1.13 root 1969: int fd = _open_osfhandle((intptr_t) h, oflag);
1.1.1.14 root 1970: if(fd == -1) {
1.1.1.13 root 1971: CloseHandle(h);
1972: }
1973: return fd;
1974: }
1975:
1.1.1.14 root 1976: void msdos_file_handler_open(int fd, const char *path, int atty, int mode, UINT16 info, UINT16 psp_seg)
1.1 root 1977: {
1978: static int id = 0;
1979: char full[MAX_PATH], *name;
1980:
1981: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1982: strcpy(file_handler[fd].path, full);
1983: } else {
1984: strcpy(file_handler[fd].path, path);
1985: }
1.1.1.14 root 1986: // isatty makes no distinction between CON & NUL
1987: // GetFileSize fails on CON, succeeds on NUL
1988: if(atty && (info != 0x80d3 || GetFileSize((HANDLE)_get_osfhandle(fd), NULL) == 0)) {
1989: info = 0x8084;
1990: atty = 0;
1991: } else if(!atty && info == 0x80d3) {
1992: info = msdos_drive_number(".");
1993: }
1.1 root 1994: file_handler[fd].valid = 1;
1995: file_handler[fd].id = id++; // dummy id for int 21h ax=71a6h
1996: file_handler[fd].atty = atty;
1997: file_handler[fd].mode = mode;
1998: file_handler[fd].info = info;
1999: file_handler[fd].psp = psp_seg;
1.1.1.21 root 2000:
2001: // init system file table
2002: if(fd < 20) {
2003: UINT8 *sft = mem + SFT_TOP + 6 + 0x3b * fd;
2004:
2005: memset(sft, 0, 0x3b);
2006:
2007: *(UINT16 *)(sft + 0x00) = 1;
2008: *(UINT16 *)(sft + 0x02) = file_handler[fd].mode;
2009: *(UINT8 *)(sft + 0x04) = GetFileAttributes(file_handler[fd].path) & 0xff;
2010: *(UINT16 *)(sft + 0x05) = file_handler[fd].info & 0xff;
2011:
2012: if(!(file_handler[fd].info & 0x80)) {
2013: *(UINT16 *)(sft + 0x07) = sizeof(dpb_t) * (file_handler[fd].info & 0x1f);
2014: *(UINT16 *)(sft + 0x09) = DPB_TOP >> 4;
2015:
2016: FILETIME time, local;
2017: HANDLE hHandle;
2018: WORD dos_date = 0, dos_time = 0;
2019: DWORD file_size = 0;
2020: if((hHandle = (HANDLE)_get_osfhandle(fd)) != INVALID_HANDLE_VALUE) {
2021: if(GetFileTime(hHandle, NULL, NULL, &time)) {
2022: FileTimeToLocalFileTime(&time, &local);
2023: FileTimeToDosDateTime(&local, &dos_date, &dos_time);
2024: }
2025: file_size = GetFileSize(hHandle, NULL);
2026: }
2027: *(UINT16 *)(sft + 0x0d) = dos_time;
2028: *(UINT16 *)(sft + 0x0f) = dos_date;
2029: *(UINT32 *)(sft + 0x11) = file_size;
2030: }
2031:
2032: char fname[MAX_PATH] = {0}, ext[MAX_PATH] = {0};
2033: _splitpath(file_handler[fd].path, NULL, NULL, fname, ext);
2034: my_strupr(fname);
2035: my_strupr(ext);
2036: memset(sft + 0x20, 0x20, 11);
2037: memcpy(sft + 0x20, fname, min(strlen(fname), 8));
2038: memcpy(sft + 0x28, ext + 1, min(strlen(ext + 1), 3));
2039:
2040: *(UINT16 *)(sft + 0x31) = psp_seg;
2041: }
1.1 root 2042: }
2043:
2044: void msdos_file_handler_dup(int dst, int src, UINT16 psp_seg)
2045: {
2046: strcpy(file_handler[dst].path, file_handler[src].path);
2047: file_handler[dst].valid = 1;
2048: file_handler[dst].id = file_handler[src].id;
2049: file_handler[dst].atty = file_handler[src].atty;
2050: file_handler[dst].mode = file_handler[src].mode;
2051: file_handler[dst].info = file_handler[src].info;
2052: file_handler[dst].psp = psp_seg;
2053: }
2054:
1.1.1.20 root 2055: void msdos_file_handler_close(int fd)
1.1 root 2056: {
2057: file_handler[fd].valid = 0;
1.1.1.21 root 2058:
2059: if(fd < 20) {
2060: memset(mem + SFT_TOP + 6 + 0x3b * fd, 0, 0x3b);
2061: }
1.1 root 2062: }
2063:
1.1.1.14 root 2064: inline int msdos_file_attribute_create(UINT16 new_attr)
1.1 root 2065: {
1.1.1.14 root 2066: return(new_attr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
2067: FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE |
2068: FILE_ATTRIBUTE_DIRECTORY));
1.1 root 2069: }
2070:
2071: // find file
2072:
2073: int msdos_find_file_check_attribute(int attribute, int allowed_mask, int required_mask)
2074: {
2075: if((allowed_mask & 0x08) && !(attribute & FILE_ATTRIBUTE_DIRECTORY)) {
2076: return(0); // search directory only !!!
2077: } else if(!(allowed_mask & 0x02) && (attribute & FILE_ATTRIBUTE_HIDDEN)) {
2078: return(0);
2079: } else if(!(allowed_mask & 0x04) && (attribute & FILE_ATTRIBUTE_SYSTEM)) {
2080: return(0);
2081: } else if(!(allowed_mask & 0x10) && (attribute & FILE_ATTRIBUTE_DIRECTORY)) {
2082: return(0);
2083: } else if((attribute & required_mask) != required_mask) {
2084: return(0);
2085: } else {
2086: return(1);
2087: }
2088: }
2089:
1.1.1.13 root 2090: int msdos_find_file_has_8dot3name(WIN32_FIND_DATA *fd)
2091: {
1.1.1.14 root 2092: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 2093: return 1;
2094: }
2095: size_t len = strlen(fd->cFileName);
1.1.1.14 root 2096: if(len > 12) {
1.1.1.13 root 2097: return 0;
2098: }
2099: const char *ext = strrchr(fd->cFileName, '.');
1.1.1.14 root 2100: if((ext ? ext - fd->cFileName : len) > 8) {
1.1.1.13 root 2101: return 0;
2102: }
2103: return 1;
2104: }
2105:
1.1 root 2106: void msdos_find_file_conv_local_time(WIN32_FIND_DATA *fd)
2107: {
2108: FILETIME local;
2109:
2110: FileTimeToLocalFileTime(&fd->ftCreationTime, &local);
2111: fd->ftCreationTime.dwLowDateTime = local.dwLowDateTime;
2112: fd->ftCreationTime.dwHighDateTime = local.dwHighDateTime;
2113:
2114: FileTimeToLocalFileTime(&fd->ftLastAccessTime, &local);
2115: fd->ftLastAccessTime.dwLowDateTime = local.dwLowDateTime;
2116: fd->ftLastAccessTime.dwHighDateTime = local.dwHighDateTime;
2117:
2118: FileTimeToLocalFileTime(&fd->ftLastWriteTime, &local);
2119: fd->ftLastWriteTime.dwLowDateTime = local.dwLowDateTime;
2120: fd->ftLastWriteTime.dwHighDateTime = local.dwHighDateTime;
2121: }
2122:
2123: // i/o
2124:
2125: void msdos_stdio_reopen()
2126: {
2127: if(!file_handler[0].valid) {
2128: _dup2(DUP_STDIN, 0);
2129: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
2130: }
2131: if(!file_handler[1].valid) {
2132: _dup2(DUP_STDOUT, 1);
2133: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
2134: }
2135: if(!file_handler[2].valid) {
2136: _dup2(DUP_STDERR, 2);
2137: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
2138: }
1.1.1.21 root 2139: if(!file_handler[3].valid) {
2140: _dup2(DUP_STDAUX, 3);
2141: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
2142: }
2143: if(!file_handler[4].valid) {
2144: _dup2(DUP_STDPRN, 4);
2145: msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0);
2146: }
2147: for(int i = 0; i < 5; i++) {
2148: if(msdos_psp_get_file_table(i, current_psp) == 0xff) {
2149: msdos_psp_set_file_table(i, i, current_psp);
2150: }
2151: }
1.1 root 2152: }
2153:
2154: int msdos_kbhit()
2155: {
2156: msdos_stdio_reopen();
2157:
1.1.1.20 root 2158: process_t *process = msdos_process_info_get(current_psp);
2159: int fd = msdos_psp_get_file_table(0, current_psp);
2160:
2161: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 2162: // stdin is redirected to file
1.1.1.20 root 2163: return(eof(fd) == 0);
1.1 root 2164: }
2165:
2166: // check keyboard status
1.1.1.5 root 2167: if(key_buf_char->count() != 0 || key_code != 0) {
1.1 root 2168: return(1);
2169: } else {
2170: return(_kbhit());
2171: }
2172: }
2173:
2174: int msdos_getch_ex(int echo)
2175: {
2176: static char prev = 0;
2177:
2178: msdos_stdio_reopen();
2179:
1.1.1.20 root 2180: process_t *process = msdos_process_info_get(current_psp);
2181: int fd = msdos_psp_get_file_table(0, current_psp);
2182:
2183: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 2184: // stdin is redirected to file
2185: retry:
2186: char data;
1.1.1.20 root 2187: if(_read(fd, &data, 1) == 1) {
1.1 root 2188: char tmp = data;
2189: if(data == 0x0a) {
2190: if(prev == 0x0d) {
2191: goto retry; // CRLF -> skip LF
2192: } else {
2193: data = 0x0d; // LF only -> CR
2194: }
2195: }
2196: prev = tmp;
2197: return(data);
2198: }
2199: return(EOF);
2200: }
2201:
2202: // input from console
1.1.1.5 root 2203: int key_char, key_scan;
2204: if(key_code != 0) {
2205: key_char = (key_code >> 0) & 0xff;
2206: key_scan = (key_code >> 8) & 0xff;
2207: key_code >>= 16;
2208: } else {
1.1.1.14 root 2209: while(key_buf_char->count() == 0 && !m_halted) {
1.1.1.23 root 2210: if(!(fd < process->max_files && file_handler[fd].valid && file_handler[fd].atty && file_mode[file_handler[fd].mode].in)) {
2211: // NOTE: stdin is redirected to stderr when we do "type (file) | more" on freedos's command.com
2212: if(_kbhit()) {
2213: key_buf_char->write(_getch());
2214: key_buf_scan->write(0);
2215: } else {
2216: Sleep(10);
2217: }
2218: } else {
2219: if(!update_key_buffer()) {
2220: Sleep(10);
2221: }
1.1.1.14 root 2222: }
2223: }
2224: if(m_halted) {
2225: // ctrl-c pressed - insert CR to terminate input loops
2226: key_char = 0x0d;
2227: key_scan = 0;
2228: } else {
2229: key_char = key_buf_char->read();
2230: key_scan = key_buf_scan->read();
1.1.1.5 root 2231: }
1.1 root 2232: }
2233: if(echo && key_char) {
2234: msdos_putch(key_char);
2235: }
2236: return key_char ? key_char : (key_scan != 0xe0) ? key_scan : 0;
2237: }
2238:
2239: inline int msdos_getch()
2240: {
2241: return(msdos_getch_ex(0));
2242: }
2243:
2244: inline int msdos_getche()
2245: {
2246: return(msdos_getch_ex(1));
2247: }
2248:
2249: int msdos_write(int fd, const void *buffer, unsigned int count)
2250: {
2251: static int is_cr = 0;
2252:
2253: if(fd == 1 && !file_handler[1].atty) {
2254: // CR+LF -> LF
2255: UINT8 *buf = (UINT8 *)buffer;
2256: for(unsigned int i = 0; i < count; i++) {
2257: UINT8 data = buf[i];
2258: if(is_cr) {
2259: if(data != 0x0a) {
2260: UINT8 tmp = 0x0d;
2261: _write(1, &tmp, 1);
2262: }
2263: _write(1, &data, 1);
2264: is_cr = 0;
2265: } else if(data == 0x0d) {
2266: is_cr = 1;
2267: } else {
2268: _write(1, &data, 1);
2269: }
2270: }
2271: return(count);
2272: }
1.1.1.14 root 2273: vram_flush();
1.1 root 2274: return(_write(fd, buffer, count));
2275: }
2276:
2277: void msdos_putch(UINT8 data)
2278: {
2279: static int p = 0;
2280: static int is_kanji = 0;
2281: static int is_esc = 0;
2282: static int stored_x;
2283: static int stored_y;
2284: static WORD stored_a;
1.1.1.20 root 2285: static char tmp[64], out[64];
1.1 root 2286:
2287: msdos_stdio_reopen();
2288:
1.1.1.20 root 2289: process_t *process = msdos_process_info_get(current_psp);
2290: int fd = msdos_psp_get_file_table(1, current_psp);
2291:
2292: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 2293: // stdout is redirected to file
1.1.1.20 root 2294: msdos_write(fd, &data, 1);
1.1 root 2295: return;
2296: }
1.1.1.23 root 2297: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 2298:
2299: // output to console
2300: tmp[p++] = data;
2301:
1.1.1.14 root 2302: vram_flush();
2303:
1.1 root 2304: if(is_kanji) {
2305: // kanji character
2306: is_kanji = 0;
2307: } else if(is_esc) {
2308: // escape sequense
2309: if((tmp[1] == ')' || tmp[1] == '(') && p == 3) {
2310: p = is_esc = 0;
2311: } else if(tmp[1] == '=' && p == 4) {
2312: COORD co;
2313: co.X = tmp[3] - 0x20;
1.1.1.14 root 2314: co.Y = tmp[2] - 0x20 + scr_top;
1.1 root 2315: SetConsoleCursorPosition(hStdout, co);
2316: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 2317: mem[0x451 + mem[0x462] * 2] = co.Y - scr_top;
1.1 root 2318: cursor_moved = false;
2319: p = is_esc = 0;
2320: } else if((data >= 'a' && data <= 'z') || (data >= 'A' && data <= 'Z') || data == '*') {
2321: CONSOLE_SCREEN_BUFFER_INFO csbi;
2322: COORD co;
2323: GetConsoleScreenBufferInfo(hStdout, &csbi);
2324: co.X = csbi.dwCursorPosition.X;
2325: co.Y = csbi.dwCursorPosition.Y;
2326: WORD wAttributes = csbi.wAttributes;
2327:
2328: if(tmp[1] == 'D') {
2329: co.Y++;
2330: } else if(tmp[1] == 'E') {
2331: co.X = 0;
2332: co.Y++;
2333: } else if(tmp[1] == 'M') {
2334: co.Y--;
2335: } else if(tmp[1] == '*') {
2336: SMALL_RECT rect;
1.1.1.14 root 2337: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2338: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2339: co.X = 0;
2340: co.Y = csbi.srWindow.Top;
1.1 root 2341: } else if(tmp[1] == '[') {
2342: int param[256], params = 0;
2343: memset(param, 0, sizeof(param));
2344: for(int i = 2; i < p; i++) {
2345: if(tmp[i] >= '0' && tmp[i] <= '9') {
2346: param[params] *= 10;
2347: param[params] += tmp[i] - '0';
2348: } else {
2349: params++;
2350: }
2351: }
2352: if(data == 'A') {
1.1.1.14 root 2353: co.Y -= (params == 0) ? 1 : param[0];
1.1 root 2354: } else if(data == 'B') {
1.1.1.14 root 2355: co.Y += (params == 0) ? 1 : param[0];
1.1 root 2356: } else if(data == 'C') {
1.1.1.14 root 2357: co.X += (params == 0) ? 1 : param[0];
1.1 root 2358: } else if(data == 'D') {
1.1.1.14 root 2359: co.X -= (params == 0) ? 1 : param[0];
1.1 root 2360: } else if(data == 'H' || data == 'f') {
1.1.1.14 root 2361: co.X = (param[1] == 0 ? 1 : param[1]) - 1;
2362: co.Y = (param[0] == 0 ? 1 : param[0]) - 1 + csbi.srWindow.Top;
1.1 root 2363: } else if(data == 'J') {
2364: SMALL_RECT rect;
1.1.1.14 root 2365: clear_scr_buffer(csbi.wAttributes);
1.1 root 2366: if(param[0] == 0) {
2367: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 2368: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2369: if(co.Y < csbi.srWindow.Bottom) {
2370: SET_RECT(rect, 0, co.Y + 1, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2371: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2372: }
2373: } else if(param[0] == 1) {
1.1.1.14 root 2374: if(co.Y > csbi.srWindow.Top) {
2375: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, co.Y - 1);
2376: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2377: }
2378: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 2379: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2380: } else if(param[0] == 2) {
1.1.1.14 root 2381: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2382: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2383: co.X = co.Y = 0;
2384: }
2385: } else if(data == 'K') {
2386: SMALL_RECT rect;
1.1.1.14 root 2387: clear_scr_buffer(csbi.wAttributes);
1.1 root 2388: if(param[0] == 0) {
2389: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 2390: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2391: } else if(param[0] == 1) {
2392: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 2393: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2394: } else if(param[0] == 2) {
2395: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 2396: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2397: }
2398: } else if(data == 'L') {
2399: SMALL_RECT rect;
1.1.1.14 root 2400: if(params == 0) {
2401: param[0] = 1;
1.1 root 2402: }
1.1.1.14 root 2403: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2404: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2405: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2406: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2407: clear_scr_buffer(csbi.wAttributes);
1.1 root 2408: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y + param[0] - 1);
1.1.1.14 root 2409: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2410: co.X = 0;
2411: } else if(data == 'M') {
2412: SMALL_RECT rect;
1.1.1.14 root 2413: if(params == 0) {
2414: param[0] = 1;
2415: }
2416: if(co.Y + param[0] > csbi.srWindow.Bottom) {
2417: clear_scr_buffer(csbi.wAttributes);
2418: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2419: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2420: } else {
1.1.1.14 root 2421: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2422: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2423: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2424: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2425: clear_scr_buffer(csbi.wAttributes);
1.1 root 2426: }
2427: co.X = 0;
2428: } else if(data == 'h') {
2429: if(tmp[2] == '>' && tmp[3] == '5') {
2430: CONSOLE_CURSOR_INFO cur;
2431: GetConsoleCursorInfo(hStdout, &cur);
2432: if(cur.bVisible) {
2433: cur.bVisible = FALSE;
1.1.1.14 root 2434: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 2435: }
2436: }
2437: } else if(data == 'l') {
2438: if(tmp[2] == '>' && tmp[3] == '5') {
2439: CONSOLE_CURSOR_INFO cur;
2440: GetConsoleCursorInfo(hStdout, &cur);
2441: if(!cur.bVisible) {
2442: cur.bVisible = TRUE;
1.1.1.14 root 2443: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 2444: }
2445: }
2446: } else if(data == 'm') {
2447: wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
2448: int reverse = 0, hidden = 0;
2449: for(int i = 0; i < params; i++) {
2450: if(param[i] == 1) {
2451: wAttributes |= FOREGROUND_INTENSITY;
2452: } else if(param[i] == 4) {
2453: wAttributes |= COMMON_LVB_UNDERSCORE;
2454: } else if(param[i] == 7) {
2455: reverse = 1;
2456: } else if(param[i] == 8 || param[i] == 16) {
2457: hidden = 1;
2458: } else if((param[i] >= 17 && param[i] <= 23) || (param[i] >= 30 && param[i] <= 37)) {
2459: wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
2460: if(param[i] >= 17 && param[i] <= 23) {
2461: param[i] -= 16;
2462: } else {
2463: param[i] -= 30;
2464: }
2465: if(param[i] & 1) {
2466: wAttributes |= FOREGROUND_RED;
2467: }
2468: if(param[i] & 2) {
2469: wAttributes |= FOREGROUND_GREEN;
2470: }
2471: if(param[i] & 4) {
2472: wAttributes |= FOREGROUND_BLUE;
2473: }
2474: } else if(param[i] >= 40 && param[i] <= 47) {
2475: wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
2476: if((param[i] - 40) & 1) {
2477: wAttributes |= BACKGROUND_RED;
2478: }
2479: if((param[i] - 40) & 2) {
2480: wAttributes |= BACKGROUND_GREEN;
2481: }
2482: if((param[i] - 40) & 4) {
2483: wAttributes |= BACKGROUND_BLUE;
2484: }
2485: }
2486: }
2487: if(reverse) {
2488: wAttributes &= ~0xff;
2489: wAttributes |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
2490: }
2491: if(hidden) {
2492: wAttributes &= ~0x0f;
2493: wAttributes |= (wAttributes >> 4) & 0x0f;
2494: }
2495: } else if(data == 'n') {
2496: if(param[0] == 6) {
2497: char tmp[16];
2498: sprintf(tmp, "\x1b[%d;%dR", co.Y + 1, co.X + 1);
2499: int len = strlen(tmp);
2500: for(int i = 0; i < len; i++) {
2501: key_buf_char->write(tmp[i]);
2502: key_buf_scan->write(0x00);
2503: }
2504: }
2505: } else if(data == 's') {
2506: stored_x = co.X;
2507: stored_y = co.Y;
2508: stored_a = wAttributes;
2509: } else if(data == 'u') {
2510: co.X = stored_x;
2511: co.Y = stored_y;
2512: wAttributes = stored_a;
2513: }
2514: }
2515: if(co.X < 0) {
2516: co.X = 0;
2517: } else if(co.X >= csbi.dwSize.X) {
2518: co.X = csbi.dwSize.X - 1;
2519: }
1.1.1.14 root 2520: if(co.Y < csbi.srWindow.Top) {
2521: co.Y = csbi.srWindow.Top;
2522: } else if(co.Y > csbi.srWindow.Bottom) {
2523: co.Y = csbi.srWindow.Bottom;
1.1 root 2524: }
2525: if(co.X != csbi.dwCursorPosition.X || co.Y != csbi.dwCursorPosition.Y) {
2526: SetConsoleCursorPosition(hStdout, co);
2527: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 2528: mem[0x451 + mem[0x462] * 2] = co.Y - csbi.srWindow.Top;
1.1 root 2529: cursor_moved = false;
2530: }
2531: if(wAttributes != csbi.wAttributes) {
2532: SetConsoleTextAttribute(hStdout, wAttributes);
2533: }
2534: p = is_esc = 0;
2535: }
2536: return;
2537: } else {
2538: if(msdos_lead_byte_check(data)) {
2539: is_kanji = 1;
2540: return;
2541: } else if(data == 0x1b) {
2542: is_esc = 1;
2543: return;
2544: }
2545: }
1.1.1.20 root 2546:
2547: DWORD q = 0, num;
2548: is_kanji = 0;
2549: for(int i = 0; i < p; i++) {
2550: UINT8 c = tmp[i];
2551: if(is_kanji) {
2552: is_kanji = 0;
2553: } else if(msdos_lead_byte_check(data)) {
2554: is_kanji = 1;
2555: } else if(msdos_ctrl_code_check(data)) {
2556: out[q++] = '^';
2557: c += 'A' - 1;
2558: }
2559: out[q++] = c;
2560: }
2561: WriteConsole(hStdout, out, q, &num, NULL);
1.1 root 2562: p = 0;
1.1.1.14 root 2563:
1.1.1.15 root 2564: if(!restore_console_on_exit) {
2565: CONSOLE_SCREEN_BUFFER_INFO csbi;
2566: GetConsoleScreenBufferInfo(hStdout, &csbi);
2567: scr_top = csbi.srWindow.Top;
2568: }
1.1 root 2569: cursor_moved = true;
2570: }
2571:
2572: int msdos_aux_in()
2573: {
1.1.1.21 root 2574: msdos_stdio_reopen();
2575:
1.1.1.20 root 2576: process_t *process = msdos_process_info_get(current_psp);
2577: int fd = msdos_psp_get_file_table(3, current_psp);
2578:
2579: if(fd < process->max_files && file_handler[fd].valid && !eof(fd)) {
1.1 root 2580: char data = 0;
1.1.1.20 root 2581: _read(fd, &data, 1);
1.1 root 2582: return(data);
2583: } else {
2584: return(EOF);
2585: }
2586: }
2587:
2588: void msdos_aux_out(char data)
2589: {
1.1.1.21 root 2590: msdos_stdio_reopen();
2591:
1.1.1.20 root 2592: process_t *process = msdos_process_info_get(current_psp);
2593: int fd = msdos_psp_get_file_table(3, current_psp);
2594:
2595: if(fd < process->max_files && file_handler[fd].valid) {
2596: msdos_write(fd, &data, 1);
1.1 root 2597: }
2598: }
2599:
2600: void msdos_prn_out(char data)
2601: {
1.1.1.21 root 2602: msdos_stdio_reopen();
2603:
1.1.1.20 root 2604: process_t *process = msdos_process_info_get(current_psp);
2605: int fd = msdos_psp_get_file_table(4, current_psp);
2606:
2607: if(fd < process->max_files && file_handler[fd].valid) {
2608: msdos_write(fd, &data, 1);
1.1 root 2609: }
2610: }
2611:
2612: // memory control
2613:
1.1.1.19 root 2614: mcb_t *msdos_mcb_create(int mcb_seg, UINT8 mz, UINT16 psp, int paragraphs)
1.1 root 2615: {
2616: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2617:
2618: mcb->mz = mz;
2619: mcb->psp = psp;
1.1.1.19 root 2620: mcb->paragraphs32 = paragraphs;
1.1 root 2621: return(mcb);
2622: }
2623:
2624: void msdos_mcb_check(mcb_t *mcb)
2625: {
2626: if(!(mcb->mz == 'M' || mcb->mz == 'Z')) {
2627: fatalerror("broken mcb\n");
2628: }
2629: }
2630:
2631: int msdos_mem_split(int seg, int paragraphs)
2632: {
2633: int mcb_seg = seg - 1;
2634: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2635: msdos_mcb_check(mcb);
2636:
1.1.1.19 root 2637: if(mcb->paragraphs() > paragraphs) {
1.1 root 2638: int new_seg = mcb_seg + 1 + paragraphs;
1.1.1.19 root 2639: int new_paragraphs = mcb->paragraphs() - paragraphs - 1;
1.1 root 2640:
2641: msdos_mcb_create(new_seg, mcb->mz, 0, new_paragraphs);
2642: mcb->mz = 'M';
1.1.1.19 root 2643: mcb->paragraphs32 = paragraphs;
1.1 root 2644: return(0);
2645: }
2646: return(-1);
2647: }
2648:
2649: void msdos_mem_merge(int seg)
2650: {
2651: int mcb_seg = seg - 1;
2652: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2653: msdos_mcb_check(mcb);
2654:
2655: while(1) {
2656: if(mcb->mz == 'Z') {
2657: break;
2658: }
1.1.1.19 root 2659: int next_seg = mcb_seg + 1 + mcb->paragraphs();
1.1 root 2660: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
2661: msdos_mcb_check(next_mcb);
2662:
2663: if(next_mcb->psp != 0) {
2664: break;
2665: }
2666: mcb->mz = next_mcb->mz;
1.1.1.19 root 2667: mcb->paragraphs32 = mcb->paragraphs() + 1 + next_mcb->paragraphs();
1.1 root 2668: }
2669: }
2670:
1.1.1.8 root 2671: int msdos_mem_alloc(int mcb_seg, int paragraphs, int new_process)
1.1 root 2672: {
2673: while(1) {
2674: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2675:
1.1.1.14 root 2676: if(mcb->psp == 0) {
2677: msdos_mem_merge(mcb_seg + 1);
2678: } else {
2679: msdos_mcb_check(mcb);
2680: }
1.1.1.8 root 2681: if(!(new_process && mcb->mz != 'Z')) {
1.1.1.19 root 2682: if(mcb->psp == 0 && mcb->paragraphs() >= paragraphs) {
1.1 root 2683: msdos_mem_split(mcb_seg + 1, paragraphs);
2684: mcb->psp = current_psp;
2685: return(mcb_seg + 1);
2686: }
2687: }
2688: if(mcb->mz == 'Z') {
2689: break;
2690: }
1.1.1.19 root 2691: mcb_seg += 1 + mcb->paragraphs();
1.1 root 2692: }
2693: return(-1);
2694: }
2695:
2696: int msdos_mem_realloc(int seg, int paragraphs, int *max_paragraphs)
2697: {
2698: int mcb_seg = seg - 1;
2699: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2700: msdos_mcb_check(mcb);
1.1.1.19 root 2701: int current_paragraphs = mcb->paragraphs();
1.1 root 2702:
2703: msdos_mem_merge(seg);
1.1.1.19 root 2704: if(paragraphs > mcb->paragraphs()) {
1.1.1.14 root 2705: if(max_paragraphs) {
1.1.1.19 root 2706: *max_paragraphs = mcb->paragraphs();
1.1.1.14 root 2707: }
1.1 root 2708: msdos_mem_split(seg, current_paragraphs);
2709: return(-1);
2710: }
2711: msdos_mem_split(seg, paragraphs);
2712: return(0);
2713: }
2714:
2715: void msdos_mem_free(int seg)
2716: {
2717: int mcb_seg = seg - 1;
2718: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2719: msdos_mcb_check(mcb);
2720:
2721: mcb->psp = 0;
2722: msdos_mem_merge(seg);
2723: }
2724:
1.1.1.8 root 2725: int msdos_mem_get_free(int mcb_seg, int new_process)
1.1 root 2726: {
2727: int max_paragraphs = 0;
2728:
2729: while(1) {
2730: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2731: msdos_mcb_check(mcb);
2732:
1.1.1.8 root 2733: if(!(new_process && mcb->mz != 'Z')) {
1.1.1.19 root 2734: if(mcb->psp == 0 && mcb->paragraphs() > max_paragraphs) {
2735: max_paragraphs = mcb->paragraphs();
1.1 root 2736: }
2737: }
2738: if(mcb->mz == 'Z') {
2739: break;
2740: }
1.1.1.19 root 2741: mcb_seg += 1 + mcb->paragraphs();
1.1 root 2742: }
1.1.1.14 root 2743: return(max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs);
1.1 root 2744: }
2745:
1.1.1.8 root 2746: int msdos_mem_get_last_mcb(int mcb_seg, UINT16 psp)
2747: {
2748: int last_seg = -1;
2749:
2750: while(1) {
2751: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2752: msdos_mcb_check(mcb);
2753:
1.1.1.14 root 2754: if(mcb->psp == psp) {
1.1.1.8 root 2755: last_seg = mcb_seg;
2756: }
1.1.1.14 root 2757: if(mcb->mz == 'Z') {
2758: break;
2759: }
1.1.1.19 root 2760: mcb_seg += 1 + mcb->paragraphs();
1.1.1.8 root 2761: }
2762: return(last_seg);
2763: }
2764:
1.1.1.19 root 2765: int msdos_mem_get_umb_linked()
2766: {
2767: int mcb_seg = first_mcb;
2768:
2769: while(1) {
2770: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2771: msdos_mcb_check(mcb);
2772:
2773: if(mcb->mz == 'Z') {
2774: if(mcb_seg >= (UMB_TOP >> 4)) {
2775: return(-1);
2776: }
2777: break;
2778: }
2779: mcb_seg += 1 + mcb->paragraphs();
2780: }
2781: return(0);
2782: }
2783:
2784: int msdos_mem_link_umb()
2785: {
2786: int mcb_seg = first_mcb;
2787:
2788: while(1) {
2789: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2790: msdos_mcb_check(mcb);
2791: mcb_seg += 1 + mcb->paragraphs();
2792:
2793: if(mcb->mz == 'Z') {
2794: if(mcb_seg == (MEMORY_END >> 4) - 1) {
2795: mcb->mz = 'M';
1.1.1.20 root 2796: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked |= 0x01;
1.1.1.19 root 2797: return(-1);
2798: }
2799: break;
2800: }
2801: }
2802: return(0);
2803: }
2804:
2805: int msdos_mem_unlink_umb()
2806: {
2807: int mcb_seg = first_mcb;
2808:
2809: while(1) {
2810: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2811: msdos_mcb_check(mcb);
2812: mcb_seg += 1 + mcb->paragraphs();
2813:
2814: if(mcb->mz == 'Z') {
2815: break;
2816: } else {
2817: if(mcb_seg == (MEMORY_END >> 4) - 1) {
2818: mcb->mz = 'Z';
1.1.1.20 root 2819: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked &= ~0x01;
1.1.1.19 root 2820: return(-1);
2821: }
2822: }
2823: }
2824: return(0);
2825: }
2826:
1.1 root 2827: // environment
2828:
2829: void msdos_env_set_argv(int env_seg, char *argv)
2830: {
2831: char *dst = (char *)(mem + (env_seg << 4));
2832:
2833: while(1) {
2834: if(dst[0] == 0) {
2835: break;
2836: }
2837: dst += strlen(dst) + 1;
2838: }
2839: *dst++ = 0; // end of environment
2840: *dst++ = 1; // top of argv[0]
2841: *dst++ = 0;
2842: memcpy(dst, argv, strlen(argv));
2843: dst += strlen(argv);
2844: *dst++ = 0;
2845: *dst++ = 0;
2846: }
2847:
2848: char *msdos_env_get_argv(int env_seg)
2849: {
2850: static char env[ENV_SIZE];
2851: char *src = env;
2852:
2853: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
2854: while(1) {
2855: if(src[0] == 0) {
2856: if(src[1] == 1) {
2857: return(src + 3);
2858: }
2859: break;
2860: }
2861: src += strlen(src) + 1;
2862: }
2863: return(NULL);
2864: }
2865:
2866: char *msdos_env_get(int env_seg, const char *name)
2867: {
2868: static char env[ENV_SIZE];
2869: char *src = env;
2870:
2871: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
2872: while(1) {
2873: if(src[0] == 0) {
2874: break;
2875: }
2876: int len = strlen(src);
2877: char *n = my_strtok(src, "=");
2878: char *v = src + strlen(n) + 1;
2879:
2880: if(_stricmp(name, n) == 0) {
2881: return(v);
2882: }
2883: src += len + 1;
2884: }
2885: return(NULL);
2886: }
2887:
2888: void msdos_env_set(int env_seg, char *name, char *value)
2889: {
2890: char env[ENV_SIZE];
2891: char *src = env;
2892: char *dst = (char *)(mem + (env_seg << 4));
2893: char *argv = msdos_env_get_argv(env_seg);
2894: int done = 0;
2895:
2896: memcpy(src, dst, ENV_SIZE);
2897: memset(dst, 0, ENV_SIZE);
2898: while(1) {
2899: if(src[0] == 0) {
2900: break;
2901: }
2902: int len = strlen(src);
2903: char *n = my_strtok(src, "=");
2904: char *v = src + strlen(n) + 1;
2905: char tmp[1024];
2906:
2907: if(_stricmp(name, n) == 0) {
2908: sprintf(tmp, "%s=%s", n, value);
2909: done = 1;
2910: } else {
2911: sprintf(tmp, "%s=%s", n, v);
2912: }
2913: memcpy(dst, tmp, strlen(tmp));
2914: dst += strlen(tmp) + 1;
2915: src += len + 1;
2916: }
2917: if(!done) {
2918: char tmp[1024];
2919:
2920: sprintf(tmp, "%s=%s", name, value);
2921: memcpy(dst, tmp, strlen(tmp));
2922: dst += strlen(tmp) + 1;
2923: }
2924: if(argv) {
2925: *dst++ = 0; // end of environment
2926: *dst++ = 1; // top of argv[0]
2927: *dst++ = 0;
2928: memcpy(dst, argv, strlen(argv));
2929: dst += strlen(argv);
2930: *dst++ = 0;
2931: *dst++ = 0;
2932: }
2933: }
2934:
2935: // process
2936:
1.1.1.8 root 2937: psp_t *msdos_psp_create(int psp_seg, UINT16 mcb_seg, UINT16 parent_psp, UINT16 env_seg)
1.1 root 2938: {
2939: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
2940:
2941: memset(psp, 0, PSP_SIZE);
2942: psp->exit[0] = 0xcd;
2943: psp->exit[1] = 0x20;
1.1.1.8 root 2944: psp->first_mcb = mcb_seg;
1.1 root 2945: psp->far_call = 0xea;
2946: psp->cpm_entry.w.l = 0xfff1; // int 21h, retf
2947: psp->cpm_entry.w.h = 0xf000;
2948: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
2949: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
2950: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
2951: psp->parent_psp = parent_psp;
1.1.1.20 root 2952: if(parent_psp == (UINT16)-1) {
2953: for(int i = 0; i < 20; i++) {
2954: if(file_handler[i].valid) {
2955: psp->file_table[i] = i;
2956: } else {
2957: psp->file_table[i] = 0xff;
2958: }
1.1 root 2959: }
1.1.1.20 root 2960: } else {
2961: memcpy(psp->file_table, ((psp_t *)(mem + (parent_psp << 4)))->file_table, 20);
1.1 root 2962: }
2963: psp->env_seg = env_seg;
2964: psp->stack.w.l = REG16(SP);
1.1.1.3 root 2965: psp->stack.w.h = SREG(SS);
1.1.1.14 root 2966: psp->file_table_size = 20;
2967: psp->file_table_ptr.w.l = 0x18;
2968: psp->file_table_ptr.w.h = psp_seg;
1.1 root 2969: psp->service[0] = 0xcd;
2970: psp->service[1] = 0x21;
2971: psp->service[2] = 0xcb;
2972: return(psp);
2973: }
2974:
1.1.1.20 root 2975: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg)
2976: {
2977: if(psp_seg && fd < 20) {
2978: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
2979: psp->file_table[fd] = value;
2980: }
2981: }
2982:
2983: int msdos_psp_get_file_table(int fd, int psp_seg)
2984: {
2985: if(psp_seg && fd < 20) {
2986: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
2987: fd = psp->file_table[fd];
2988: }
2989: return fd;
2990: }
2991:
1.1 root 2992: int msdos_process_exec(char *cmd, param_block_t *param, UINT8 al)
2993: {
2994: // load command file
2995: int fd = -1;
2996: int dos_command = 0;
1.1.1.24! root 2997: char command[MAX_PATH], path[MAX_PATH], opt[MAX_PATH], *name = NULL, name_tmp[MAX_PATH];
1.1 root 2998:
2999: int opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
3000: int opt_len = mem[opt_ofs];
3001: memset(opt, 0, sizeof(opt));
3002: memcpy(opt, mem + opt_ofs + 1, opt_len);
3003:
1.1.1.14 root 3004: if(strlen(cmd) >= 5 && _stricmp(&cmd[strlen(cmd) - 4], ".BAT") == 0) {
3005: // this is a batch file, run command.com
3006: char tmp[MAX_PATH];
3007: if(opt_len != 0) {
3008: sprintf(tmp, "/C %s %s", cmd, opt);
3009: } else {
3010: sprintf(tmp, "/C %s", cmd);
3011: }
3012: strcpy(opt, tmp);
3013: opt_len = strlen(opt);
3014: mem[opt_ofs] = opt_len;
3015: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
3016: strcpy(command, comspec_path);
3017: strcpy(name_tmp, "COMMAND.COM");
3018: } else {
3019: if(_stricmp(cmd, "C:\\COMMAND.COM") == 0) {
3020: // redirect C:\COMMAND.COM to comspec_path
3021: strcpy(command, comspec_path);
3022: } else {
3023: strcpy(command, cmd);
3024: }
1.1.1.24! root 3025: if(GetFullPathName(command, MAX_PATH, path, &name) == 0) {
! 3026: return(-1);
! 3027: }
1.1.1.14 root 3028: memset(name_tmp, 0, sizeof(name_tmp));
3029: strcpy(name_tmp, name);
3030:
3031: // check command.com
3032: if(_stricmp(name, "COMMAND.COM") == 0 || _stricmp(name, "COMMAND") == 0) {
3033: if(opt_len == 0) {
3034: // process_t *current_process = msdos_process_info_get(current_psp);
3035: process_t *current_process = NULL;
3036: for(int i = 0; i < MAX_PROCESS; i++) {
3037: if(process[i].psp == current_psp) {
3038: current_process = &process[i];
3039: break;
3040: }
3041: }
3042: if(current_process != NULL) {
3043: param->cmd_line.dw = current_process->dta.dw;
3044: opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
3045: opt_len = mem[opt_ofs];
3046: memset(opt, 0, sizeof(opt));
3047: memcpy(opt, mem + opt_ofs + 1, opt_len);
3048: }
3049: }
3050: for(int i = 0; i < opt_len; i++) {
3051: if(opt[i] == ' ') {
3052: continue;
3053: }
3054: if(opt[i] == '/' && (opt[i + 1] == 'c' || opt[i + 1] == 'C') && opt[i + 2] == ' ') {
3055: for(int j = i + 3; j < opt_len; j++) {
3056: if(opt[j] == ' ') {
3057: continue;
3058: }
3059: char *token = my_strtok(opt + j, " ");
3060:
3061: if(strlen(token) >= 5 && _stricmp(&token[strlen(token) - 4], ".BAT") == 0) {
3062: // this is a batch file, okay to run command.com
3063: } else {
3064: // run program directly without command.com
3065: strcpy(command, token);
3066: char tmp[MAX_PATH];
3067: strcpy(tmp, token + strlen(token) + 1);
3068: strcpy(opt, tmp);
3069: opt_len = strlen(opt);
3070: mem[opt_ofs] = opt_len;
3071: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
3072: dos_command = 1;
3073: }
3074: break;
1.1 root 3075: }
3076: }
1.1.1.14 root 3077: break;
1.1 root 3078: }
3079: }
3080: }
3081:
3082: // load command file
3083: strcpy(path, command);
3084: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
3085: sprintf(path, "%s.COM", command);
3086: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
3087: sprintf(path, "%s.EXE", command);
3088: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
1.1.1.14 root 3089: sprintf(path, "%s.BAT", command);
3090: if(_access(path, 0) == 0) {
3091: // this is a batch file, run command.com
3092: char tmp[MAX_PATH];
3093: if(opt_len != 0) {
3094: sprintf(tmp, "/C %s %s", path, opt);
3095: } else {
3096: sprintf(tmp, "/C %s", path);
3097: }
3098: strcpy(opt, tmp);
3099: opt_len = strlen(opt);
3100: mem[opt_ofs] = opt_len;
3101: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
3102: strcpy(path, comspec_path);
3103: strcpy(name_tmp, "COMMAND.COM");
3104: fd = _open(path, _O_RDONLY | _O_BINARY);
3105: } else {
3106: // search path in parent environments
3107: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
3108: char *env = msdos_env_get(parent_psp->env_seg, "PATH");
3109: if(env != NULL) {
3110: char env_path[4096];
3111: strcpy(env_path, env);
3112: char *token = my_strtok(env_path, ";");
3113:
3114: while(token != NULL) {
3115: if(strlen(token) != 0) {
3116: sprintf(path, "%s", msdos_combine_path(token, command));
3117: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
3118: break;
3119: }
3120: sprintf(path, "%s.COM", msdos_combine_path(token, command));
3121: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
3122: break;
3123: }
3124: sprintf(path, "%s.EXE", msdos_combine_path(token, command));
3125: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
3126: break;
3127: }
3128: sprintf(path, "%s.BAT", msdos_combine_path(token, command));
3129: if(_access(path, 0) == 0) {
3130: // this is a batch file, run command.com
3131: char tmp[MAX_PATH];
3132: if(opt_len != 0) {
3133: sprintf(tmp, "/C %s %s", path, opt);
3134: } else {
3135: sprintf(tmp, "/C %s", path);
3136: }
3137: strcpy(opt, tmp);
3138: opt_len = strlen(opt);
3139: mem[opt_ofs] = opt_len;
3140: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
3141: strcpy(path, comspec_path);
3142: strcpy(name_tmp, "COMMAND.COM");
3143: fd = _open(path, _O_RDONLY | _O_BINARY);
3144: break;
3145: }
1.1.1.8 root 3146: }
1.1.1.14 root 3147: token = my_strtok(NULL, ";");
1.1 root 3148: }
3149: }
3150: }
3151: }
3152: }
3153: }
3154: if(fd == -1) {
3155: if(dos_command) {
3156: // may be dos command
3157: char tmp[MAX_PATH];
3158: sprintf(tmp, "%s %s", command, opt);
3159: system(tmp);
3160: return(0);
3161: } else {
3162: return(-1);
3163: }
3164: }
3165: _read(fd, file_buffer, sizeof(file_buffer));
3166: _close(fd);
3167:
3168: // copy environment
3169: int env_seg, psp_seg;
3170:
1.1.1.8 root 3171: if((env_seg = msdos_mem_alloc(first_mcb, ENV_SIZE >> 4, 1)) == -1) {
1.1 root 3172: return(-1);
3173: }
3174: if(param->env_seg == 0) {
3175: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
3176: memcpy(mem + (env_seg << 4), mem + (parent_psp->env_seg << 4), ENV_SIZE);
3177: } else {
3178: memcpy(mem + (env_seg << 4), mem + (param->env_seg << 4), ENV_SIZE);
3179: }
3180: msdos_env_set_argv(env_seg, msdos_short_full_path(path));
3181:
3182: // check exe header
3183: exe_header_t *header = (exe_header_t *)file_buffer;
1.1.1.8 root 3184: int paragraphs, free_paragraphs = msdos_mem_get_free(first_mcb, 1);
1.1 root 3185: UINT16 cs, ss, ip, sp;
3186:
3187: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
3188: // memory allocation
3189: int header_size = header->header_size * 16;
3190: int load_size = header->pages * 512 - header_size;
3191: if(header_size + load_size < 512) {
3192: load_size = 512 - header_size;
3193: }
3194: paragraphs = (PSP_SIZE + load_size) >> 4;
3195: if(paragraphs + header->min_alloc > free_paragraphs) {
3196: msdos_mem_free(env_seg);
3197: return(-1);
3198: }
3199: paragraphs += header->max_alloc ? header->max_alloc : header->min_alloc;
3200: if(paragraphs > free_paragraphs) {
3201: paragraphs = free_paragraphs;
3202: }
1.1.1.8 root 3203: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1 root 3204: msdos_mem_free(env_seg);
3205: return(-1);
3206: }
3207: // relocation
3208: int start_seg = psp_seg + (PSP_SIZE >> 4);
3209: for(int i = 0; i < header->relocations; i++) {
3210: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
3211: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
3212: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
3213: }
3214: memcpy(mem + (start_seg << 4), file_buffer + header_size, load_size);
3215: // segments
3216: cs = header->init_cs + start_seg;
3217: ss = header->init_ss + start_seg;
3218: ip = header->init_ip;
3219: sp = header->init_sp - 2; // for symdeb
3220: } else {
3221: // memory allocation
3222: paragraphs = free_paragraphs;
1.1.1.8 root 3223: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1 root 3224: msdos_mem_free(env_seg);
3225: return(-1);
3226: }
3227: int start_seg = psp_seg + (PSP_SIZE >> 4);
3228: memcpy(mem + (start_seg << 4), file_buffer, 0x10000 - PSP_SIZE);
3229: // segments
3230: cs = ss = psp_seg;
3231: ip = 0x100;
3232: sp = 0xfffe;
3233: }
3234:
3235: // create psp
1.1.1.3 root 3236: #if defined(HAS_I386)
3237: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_eip;
3238: #else
3239: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_pc - SREG_BASE(CS);
3240: #endif
3241: *(UINT16 *)(mem + 4 * 0x22 + 2) = SREG(CS);
1.1 root 3242: psp_t *psp = msdos_psp_create(psp_seg, psp_seg + paragraphs, current_psp, env_seg);
3243: memcpy(psp->fcb1, mem + (param->fcb1.w.h << 4) + param->fcb1.w.l, sizeof(psp->fcb1));
3244: memcpy(psp->fcb2, mem + (param->fcb2.w.h << 4) + param->fcb2.w.l, sizeof(psp->fcb2));
3245: memcpy(psp->buffer, mem + (param->cmd_line.w.h << 4) + param->cmd_line.w.l, sizeof(psp->buffer));
3246:
3247: mcb_t *mcb_env = (mcb_t *)(mem + ((env_seg - 1) << 4));
3248: mcb_t *mcb_psp = (mcb_t *)(mem + ((psp_seg - 1) << 4));
3249: mcb_psp->psp = mcb_env->psp = psp_seg;
3250:
1.1.1.4 root 3251: for(int i = 0; i < 8; i++) {
3252: if(name_tmp[i] == '.') {
3253: mcb_psp->prog_name[i] = '\0';
3254: break;
3255: } else if(i < 7 && msdos_lead_byte_check(name_tmp[i])) {
3256: mcb_psp->prog_name[i] = name_tmp[i];
3257: i++;
3258: mcb_psp->prog_name[i] = name_tmp[i];
3259: } else if(name_tmp[i] >= 'a' && name_tmp[i] <= 'z') {
3260: mcb_psp->prog_name[i] = name_tmp[i] - 'a' + 'A';
3261: } else {
3262: mcb_psp->prog_name[i] = name_tmp[i];
3263: }
3264: }
3265:
1.1 root 3266: // process info
3267: process_t *process = msdos_process_info_create(psp_seg);
3268: strcpy(process->module_dir, msdos_short_full_dir(path));
3269: process->dta.w.l = 0x80;
3270: process->dta.w.h = psp_seg;
3271: process->switchar = '/';
3272: process->max_files = 20;
3273: process->parent_int_10h_feh_called = int_10h_feh_called;
3274: process->parent_int_10h_ffh_called = int_10h_ffh_called;
1.1.1.14 root 3275: process->parent_ds = SREG(DS);
1.1 root 3276:
3277: current_psp = psp_seg;
1.1.1.23 root 3278: msdos_sda_update(current_psp);
1.1 root 3279:
3280: if(al == 0x00) {
3281: int_10h_feh_called = int_10h_ffh_called = false;
3282:
3283: // registers and segments
3284: REG16(AX) = REG16(BX) = 0x00;
3285: REG16(CX) = 0xff;
3286: REG16(DX) = psp_seg;
3287: REG16(SI) = ip;
3288: REG16(DI) = sp;
3289: REG16(SP) = sp;
1.1.1.3 root 3290: SREG(DS) = SREG(ES) = psp_seg;
3291: SREG(SS) = ss;
3292: i386_load_segment_descriptor(DS);
3293: i386_load_segment_descriptor(ES);
3294: i386_load_segment_descriptor(SS);
1.1 root 3295:
3296: *(UINT16 *)(mem + (ss << 4) + sp) = 0;
3297: i386_jmp_far(cs, ip);
3298: } else if(al == 0x01) {
3299: // copy ss:sp and cs:ip to param block
3300: param->sp = sp;
3301: param->ss = ss;
3302: param->ip = ip;
3303: param->cs = cs;
3304: }
3305: return(0);
3306: }
3307:
3308: void msdos_process_terminate(int psp_seg, int ret, int mem_free)
3309: {
3310: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
3311:
3312: *(UINT32 *)(mem + 4 * 0x22) = psp->int_22h.dw;
3313: *(UINT32 *)(mem + 4 * 0x23) = psp->int_23h.dw;
3314: *(UINT32 *)(mem + 4 * 0x24) = psp->int_24h.dw;
3315:
1.1.1.3 root 3316: SREG(SS) = psp->stack.w.h;
3317: i386_load_segment_descriptor(SS);
1.1 root 3318: REG16(SP) = psp->stack.w.l;
3319: i386_jmp_far(psp->int_22h.w.h, psp->int_22h.w.l);
3320:
3321: process_t *process = msdos_process_info_get(psp_seg);
3322: int_10h_feh_called = process->parent_int_10h_feh_called;
3323: int_10h_ffh_called = process->parent_int_10h_ffh_called;
1.1.1.14 root 3324: SREG(DS) = process->parent_ds;
3325: i386_load_segment_descriptor(DS);
1.1 root 3326:
3327: if(mem_free) {
1.1.1.8 root 3328: int mcb_seg;
3329: while((mcb_seg = msdos_mem_get_last_mcb(first_mcb, psp_seg)) != -1) {
3330: msdos_mem_free(mcb_seg + 1);
3331: }
3332: while((mcb_seg = msdos_mem_get_last_mcb(UMB_TOP >> 4, psp_seg)) != -1) {
3333: msdos_mem_free(mcb_seg + 1);
3334: }
1.1 root 3335:
3336: for(int i = 0; i < MAX_FILES; i++) {
3337: if(file_handler[i].valid && file_handler[i].psp == psp_seg) {
3338: _close(i);
1.1.1.20 root 3339: msdos_file_handler_close(i);
3340: msdos_psp_set_file_table(i, 0x0ff, psp_seg); // FIXME: consider duplicated file handles
1.1 root 3341: }
3342: }
1.1.1.13 root 3343: msdos_dta_info_free(psp_seg);
1.1 root 3344: }
1.1.1.14 root 3345: msdos_stdio_reopen();
1.1 root 3346:
3347: memset(process, 0, sizeof(process_t));
3348:
3349: current_psp = psp->parent_psp;
3350: retval = ret;
1.1.1.23 root 3351: msdos_sda_update(current_psp);
1.1 root 3352: }
3353:
3354: // drive
3355:
3356: int msdos_drive_param_block_update(int drive_num, UINT16 *seg, UINT16 *ofs, int force_update)
3357: {
3358: *seg = DPB_TOP >> 4;
3359: *ofs = sizeof(dpb_t) * drive_num;
3360: dpb_t *dpb = (dpb_t *)(mem + (*seg << 4) + *ofs);
3361:
3362: if(!force_update && dpb->free_clusters != 0) {
3363: return(dpb->bytes_per_sector ? 1 : 0);
3364: }
3365: memset(dpb, 0, sizeof(dpb_t));
3366:
3367: int res = 0;
3368: char dev[64];
3369: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
3370:
1.1.1.17 root 3371: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1.1 root 3372: if(hFile != INVALID_HANDLE_VALUE) {
3373: DISK_GEOMETRY geo;
3374: DWORD dwSize;
3375: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
3376: dpb->bytes_per_sector = (UINT16)geo.BytesPerSector;
3377: dpb->highest_sector_num = (UINT8)(geo.SectorsPerTrack - 1);
3378: dpb->highest_cluster_num = (UINT16)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1.1.14 root 3379: dpb->maximum_cluster_num = (UINT32)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1 root 3380: switch(geo.MediaType) {
3381: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
3382: dpb->media_type = 0xff;
3383: break;
3384: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
3385: dpb->media_type = 0xfe;
3386: break;
3387: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
3388: dpb->media_type = 0xfd;
3389: break;
3390: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
3391: dpb->media_type = 0xfc;
3392: break;
3393: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
3394: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
3395: dpb->media_type = 0xf9;
3396: break;
3397: case FixedMedia: // hard disk
3398: case RemovableMedia:
1.1.1.19 root 3399: case Unknown:
1.1 root 3400: dpb->media_type = 0xf8;
3401: break;
3402: default:
3403: dpb->media_type = 0xf0;
3404: break;
3405: }
3406: res = 1;
3407: }
3408: dpb->drive_num = drive_num;
3409: dpb->unit_num = drive_num;
3410: dpb->next_dpb_ofs = *ofs + sizeof(dpb_t);
3411: dpb->next_dpb_seg = *seg;
1.1.1.14 root 3412: dpb->info_sector = 0xffff;
3413: dpb->backup_boot_sector = 0xffff;
1.1 root 3414: dpb->free_clusters = 0xffff;
1.1.1.14 root 3415: dpb->free_search_cluster = 0xffffffff;
1.1 root 3416: CloseHandle(hFile);
3417: }
3418: return(res);
3419: }
3420:
3421: // pc bios
3422:
1.1.1.19 root 3423: UINT32 get_ticks_since_midnight(UINT32 cur_msec)
3424: {
3425: static unsigned __int64 start_msec_since_midnight = 0;
3426: static unsigned __int64 start_msec_since_hostboot = 0;
3427:
3428: if(start_msec_since_midnight == 0) {
3429: SYSTEMTIME time;
3430: GetLocalTime(&time);
3431: start_msec_since_midnight = ((time.wHour * 60 + time.wMinute) * 60 + time.wSecond) * 1000 + time.wMilliseconds;
3432: start_msec_since_hostboot = cur_msec;
3433: }
3434: unsigned __int64 msec = (start_msec_since_midnight + cur_msec - start_msec_since_hostboot) % (24 * 60 * 60 * 1000);
3435: unsigned __int64 tick = msec * 0x1800b0 / (24 * 60 * 60 * 1000);
3436: return (UINT32)tick;
3437: }
3438:
3439: void pcbios_update_daily_timer_counter(UINT32 cur_msec)
3440: {
3441: UINT32 prev_tick = *(UINT32 *)(mem + 0x46c);
3442: UINT32 next_tick = get_ticks_since_midnight(cur_msec);
3443:
3444: if(prev_tick > next_tick) {
3445: mem[0x470] = 1;
3446: }
3447: *(UINT32 *)(mem + 0x46c) = next_tick;
3448: }
3449:
1.1.1.14 root 3450: inline void pcbios_irq0()
3451: {
3452: //++*(UINT32 *)(mem + 0x46c);
1.1.1.19 root 3453: pcbios_update_daily_timer_counter(timeGetTime());
1.1.1.14 root 3454: }
3455:
1.1.1.16 root 3456: int pcbios_get_text_vram_address(int page)
1.1 root 3457: {
3458: if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 3459: return TEXT_VRAM_TOP;
1.1 root 3460: } else {
1.1.1.14 root 3461: return TEXT_VRAM_TOP + VIDEO_REGEN * (page % vram_pages);
1.1 root 3462: }
3463: }
3464:
1.1.1.16 root 3465: int pcbios_get_shadow_buffer_address(int page)
1.1 root 3466: {
1.1.1.14 root 3467: if(!int_10h_feh_called) {
1.1.1.16 root 3468: return pcbios_get_text_vram_address(page);
1.1.1.14 root 3469: } else if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 3470: return SHADOW_BUF_TOP;
3471: } else {
1.1.1.14 root 3472: return SHADOW_BUF_TOP + VIDEO_REGEN * (page % vram_pages);
1.1.1.8 root 3473: }
3474: }
3475:
1.1.1.16 root 3476: int pcbios_get_shadow_buffer_address(int page, int x, int y)
1.1.1.8 root 3477: {
1.1.1.16 root 3478: return pcbios_get_shadow_buffer_address(page) + (x + y * scr_width) * 2;
1.1 root 3479: }
3480:
1.1.1.16 root 3481: void pcbios_set_console_size(int width, int height, bool clr_screen)
1.1 root 3482: {
1.1.1.14 root 3483: // clear the existing screen, not just the new one
3484: int clr_height = max(height, scr_height);
3485:
1.1.1.16 root 3486: if(scr_width != width || scr_height != height) {
3487: change_console_size(width, height);
1.1.1.14 root 3488: }
3489: mem[0x462] = 0;
3490: *(UINT16 *)(mem + 0x44e) = 0;
3491:
1.1.1.16 root 3492: text_vram_top_address = pcbios_get_text_vram_address(0);
3493: text_vram_end_address = text_vram_top_address + width * height * 2;
3494: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(0);
3495: shadow_buffer_end_address = shadow_buffer_top_address + width * height * 2;
1.1 root 3496:
1.1.1.23 root 3497: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.16 root 3498: if(clr_screen) {
1.1.1.14 root 3499: for(int ofs = shadow_buffer_top_address; ofs < shadow_buffer_end_address;) {
3500: mem[ofs++] = 0x20;
3501: mem[ofs++] = 0x07;
3502: }
3503:
3504: EnterCriticalSection(&vram_crit_sect);
3505: for(int y = 0; y < clr_height; y++) {
3506: for(int x = 0; x < scr_width; x++) {
3507: SCR_BUF(y,x).Char.AsciiChar = ' ';
3508: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 3509: }
3510: }
3511: SMALL_RECT rect;
1.1.1.14 root 3512: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + clr_height - 1);
3513: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3514: vram_length_char = vram_last_length_char = 0;
3515: vram_length_attr = vram_last_length_attr = 0;
3516: LeaveCriticalSection(&vram_crit_sect);
1.1 root 3517: }
1.1.1.14 root 3518: COORD co;
3519: co.X = 0;
3520: co.Y = scr_top;
3521: SetConsoleCursorPosition(hStdout, co);
3522: cursor_moved = true;
3523: SetConsoleTextAttribute(hStdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
1.1 root 3524: }
3525:
1.1.1.16 root 3526: inline void pcbios_int_10h_00h()
3527: {
3528: switch(REG8(AL) & 0x7f) {
3529: case 0x70: // v-text mode
3530: case 0x71: // extended cga v-text mode
3531: pcbios_set_console_size(scr_width, scr_height, !(REG8(AL) & 0x80));
3532: break;
3533: default:
3534: pcbios_set_console_size(80, 25, !(REG8(AL) & 0x80));
3535: break;
3536: }
3537: if(REG8(AL) & 0x80) {
3538: mem[0x487] |= 0x80;
3539: } else {
3540: mem[0x487] &= ~0x80;
3541: }
3542: mem[0x449] = REG8(AL) & 0x7f;
3543: }
3544:
1.1 root 3545: inline void pcbios_int_10h_01h()
3546: {
1.1.1.13 root 3547: mem[0x460] = REG8(CL);
3548: mem[0x461] = REG8(CH);
1.1.1.14 root 3549:
1.1.1.23 root 3550: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 3551: CONSOLE_CURSOR_INFO ci;
3552: GetConsoleCursorInfo(hStdout, &ci);
3553: // ci.bVisible = !(REG8(CH) & 0x60) && REG8(CH) <= REG8(CL);
3554: // if(ci.bVisible) {
3555: int lines = max(8, REG8(CL) + 1);
3556: ci.dwSize = (REG8(CL) - REG8(CH) + 1) * 100 / lines;
3557: // }
3558: SetConsoleCursorInfo(hStdout, &ci);
1.1 root 3559: }
3560:
3561: inline void pcbios_int_10h_02h()
3562: {
1.1.1.14 root 3563: // continuously setting the cursor effectively stops it blinking
3564: if(mem[0x462] == REG8(BH) && (REG8(DL) != mem[0x450 + REG8(BH) * 2] || REG8(DH) != mem[0x451 + REG8(BH) * 2])) {
1.1 root 3565: COORD co;
3566: co.X = REG8(DL);
1.1.1.14 root 3567: co.Y = REG8(DH) + scr_top;
3568:
3569: // some programs hide the cursor by moving it off screen
3570: static bool hidden = false;
1.1.1.23 root 3571: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 3572: CONSOLE_CURSOR_INFO ci;
3573: GetConsoleCursorInfo(hStdout, &ci);
3574:
3575: if(REG8(DH) >= scr_height || !SetConsoleCursorPosition(hStdout, co)) {
3576: if(ci.bVisible) {
3577: ci.bVisible = FALSE;
3578: // SetConsoleCursorInfo(hStdout, &ci);
3579: hidden = true;
3580: }
3581: } else if(hidden) {
3582: if(!ci.bVisible) {
3583: ci.bVisible = TRUE;
3584: // SetConsoleCursorInfo(hStdout, &ci);
3585: }
3586: hidden = false;
3587: }
1.1 root 3588: }
1.1.1.14 root 3589: mem[0x450 + (REG8(BH) % vram_pages) * 2] = REG8(DL);
3590: mem[0x451 + (REG8(BH) % vram_pages) * 2] = REG8(DH);
1.1 root 3591: }
3592:
3593: inline void pcbios_int_10h_03h()
3594: {
1.1.1.14 root 3595: REG8(DL) = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3596: REG8(DH) = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 3597: REG8(CL) = mem[0x460];
3598: REG8(CH) = mem[0x461];
3599: }
3600:
3601: inline void pcbios_int_10h_05h()
3602: {
1.1.1.14 root 3603: if(REG8(AL) >= vram_pages) {
3604: return;
3605: }
3606: if(mem[0x462] != REG8(AL)) {
3607: vram_flush();
3608:
1.1.1.23 root 3609: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 3610: SMALL_RECT rect;
1.1.1.14 root 3611: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
3612: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3613:
1.1.1.16 root 3614: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(mem[0x462]); y < scr_height; y++) {
1.1.1.14 root 3615: for(int x = 0; x < scr_width; x++) {
3616: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
3617: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 3618: }
3619: }
1.1.1.16 root 3620: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(REG8(AL)); y < scr_height; y++) {
1.1.1.14 root 3621: for(int x = 0; x < scr_width; x++) {
3622: SCR_BUF(y,x).Char.AsciiChar = mem[ofs++];
3623: SCR_BUF(y,x).Attributes = mem[ofs++];
1.1 root 3624: }
3625: }
1.1.1.14 root 3626: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3627:
3628: COORD co;
1.1.1.14 root 3629: co.X = mem[0x450 + REG8(AL) * 2];
3630: co.Y = mem[0x451 + REG8(AL) * 2] + scr_top;
3631: if(co.Y < scr_top + scr_height) {
3632: SetConsoleCursorPosition(hStdout, co);
3633: }
1.1 root 3634: }
1.1.1.14 root 3635: mem[0x462] = REG8(AL);
3636: *(UINT16 *)(mem + 0x44e) = REG8(AL) * VIDEO_REGEN;
3637: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.16 root 3638: text_vram_top_address = pcbios_get_text_vram_address(mem[0x462]);
1.1.1.14 root 3639: text_vram_end_address = text_vram_top_address + regen;
1.1.1.16 root 3640: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(mem[0x462]);
1.1.1.14 root 3641: shadow_buffer_end_address = shadow_buffer_top_address + regen;
1.1 root 3642: }
3643:
3644: inline void pcbios_int_10h_06h()
3645: {
1.1.1.14 root 3646: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
3647: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
3648: return;
3649: }
3650: vram_flush();
3651:
1.1.1.23 root 3652: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 3653: SMALL_RECT rect;
1.1.1.14 root 3654: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
3655: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3656:
3657: int right = min(REG8(DL), scr_width - 1);
3658: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 3659:
3660: if(REG8(AL) == 0) {
1.1.1.14 root 3661: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 3662: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 3663: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
3664: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3665: }
3666: }
3667: } else {
1.1.1.14 root 3668: for(int y = REG8(CH), y2 = min(REG8(CH) + REG8(AL), bottom + 1); y <= bottom; y++, y2++) {
1.1.1.16 root 3669: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 3670: if(y2 <= bottom) {
3671: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 3672: } else {
1.1.1.14 root 3673: SCR_BUF(y,x).Char.AsciiChar = ' ';
3674: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3675: }
1.1.1.14 root 3676: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
3677: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 3678: }
3679: }
3680: }
1.1.1.14 root 3681: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3682: }
3683:
3684: inline void pcbios_int_10h_07h()
3685: {
1.1.1.14 root 3686: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
3687: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
3688: return;
3689: }
3690: vram_flush();
3691:
1.1.1.23 root 3692: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 3693: SMALL_RECT rect;
1.1.1.14 root 3694: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
3695: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3696:
3697: int right = min(REG8(DL), scr_width - 1);
3698: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 3699:
3700: if(REG8(AL) == 0) {
1.1.1.14 root 3701: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 3702: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 3703: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
3704: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3705: }
3706: }
3707: } else {
1.1.1.14 root 3708: for(int y = bottom, y2 = max(REG8(CH) - 1, bottom - REG8(AL)); y >= REG8(CH); y--, y2--) {
1.1.1.16 root 3709: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 3710: if(y2 >= REG8(CH)) {
3711: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 3712: } else {
1.1.1.14 root 3713: SCR_BUF(y,x).Char.AsciiChar = ' ';
3714: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3715: }
1.1.1.14 root 3716: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
3717: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 3718: }
3719: }
3720: }
1.1.1.14 root 3721: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3722: }
3723:
3724: inline void pcbios_int_10h_08h()
3725: {
3726: COORD co;
3727: DWORD num;
3728:
1.1.1.14 root 3729: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3730: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 3731:
3732: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 3733: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 3734: co.Y += scr_top;
3735: vram_flush();
1.1 root 3736: ReadConsoleOutputCharacter(hStdout, scr_char, 1, co, &num);
3737: ReadConsoleOutputAttribute(hStdout, scr_attr, 1, co, &num);
3738: REG8(AL) = scr_char[0];
3739: REG8(AH) = scr_attr[0];
3740: } else {
1.1.1.16 root 3741: REG16(AX) = *(UINT16 *)(mem + pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y));
1.1 root 3742: }
3743: }
3744:
3745: inline void pcbios_int_10h_09h()
3746: {
3747: COORD co;
3748:
1.1.1.14 root 3749: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3750: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
3751:
1.1.1.16 root 3752: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
3753: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 3754:
3755: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 3756: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 3757: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 3758: while(dest < end) {
3759: write_text_vram_char(dest - vram, REG8(AL));
3760: mem[dest++] = REG8(AL);
3761: write_text_vram_attr(dest - vram, REG8(BL));
3762: mem[dest++] = REG8(BL);
1.1 root 3763: }
1.1.1.14 root 3764: LeaveCriticalSection(&vram_crit_sect);
1.1 root 3765: } else {
1.1.1.14 root 3766: while(dest < end) {
1.1 root 3767: mem[dest++] = REG8(AL);
3768: mem[dest++] = REG8(BL);
3769: }
3770: }
3771: }
3772:
3773: inline void pcbios_int_10h_0ah()
3774: {
3775: COORD co;
3776:
1.1.1.14 root 3777: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3778: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
3779:
1.1.1.16 root 3780: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
3781: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 3782:
3783: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 3784: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 3785: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 3786: while(dest < end) {
3787: write_text_vram_char(dest - vram, REG8(AL));
3788: mem[dest++] = REG8(AL);
3789: dest++;
1.1 root 3790: }
1.1.1.14 root 3791: LeaveCriticalSection(&vram_crit_sect);
1.1 root 3792: } else {
1.1.1.14 root 3793: while(dest < end) {
1.1 root 3794: mem[dest++] = REG8(AL);
3795: dest++;
3796: }
3797: }
3798: }
3799:
3800: inline void pcbios_int_10h_0eh()
3801: {
1.1.1.14 root 3802: DWORD num;
3803: COORD co;
3804:
3805: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3806: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
3807:
3808: if(REG8(AL) == 7) {
3809: //MessageBeep(-1);
3810: } else if(REG8(AL) == 8 || REG8(AL) == 10 || REG8(AL) == 13) {
3811: if(REG8(AL) == 10) {
3812: vram_flush();
3813: }
1.1.1.23 root 3814: WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ®8(AL), 1, &num, NULL);
1.1.1.14 root 3815: cursor_moved = true;
3816: } else {
1.1.1.16 root 3817: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
1.1.1.14 root 3818: if(mem[0x462] == REG8(BH)) {
3819: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 3820: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 3821: write_text_vram_char(dest - vram, REG8(AL));
3822: LeaveCriticalSection(&vram_crit_sect);
3823:
1.1.1.23 root 3824: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 3825: if(++co.X == scr_width) {
3826: co.X = 0;
3827: if(++co.Y == scr_height) {
3828: vram_flush();
3829: WriteConsole(hStdout, "\n", 1, &num, NULL);
3830: cursor_moved = true;
3831: }
3832: }
3833: if(!cursor_moved) {
3834: co.Y += scr_top;
3835: SetConsoleCursorPosition(hStdout, co);
3836: cursor_moved = true;
3837: }
3838: }
3839: mem[dest] = REG8(AL);
3840: }
1.1 root 3841: }
3842:
3843: inline void pcbios_int_10h_0fh()
3844: {
3845: REG8(AL) = mem[0x449];
3846: REG8(AH) = mem[0x44a];
3847: REG8(BH) = mem[0x462];
3848: }
3849:
1.1.1.14 root 3850: inline void pcbios_int_10h_11h()
3851: {
3852: switch(REG8(AL)) {
1.1.1.16 root 3853: case 0x01:
1.1.1.14 root 3854: case 0x11:
1.1.1.16 root 3855: pcbios_set_console_size(80, 28, true);
1.1.1.14 root 3856: break;
1.1.1.16 root 3857: case 0x02:
1.1.1.14 root 3858: case 0x12:
1.1.1.16 root 3859: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 3860: break;
1.1.1.16 root 3861: case 0x04:
1.1.1.14 root 3862: case 0x14:
1.1.1.16 root 3863: pcbios_set_console_size(80, 25, true);
3864: break;
3865: case 0x18:
3866: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 3867: break;
3868: case 0x30:
3869: SREG(ES) = 0;
3870: i386_load_segment_descriptor(ES);
3871: REG16(BP) = 0;
3872: REG16(CX) = mem[0x485];
3873: REG8(DL) = mem[0x484];
3874: break;
3875: }
3876: }
3877:
3878: inline void pcbios_int_10h_12h()
3879: {
1.1.1.16 root 3880: switch(REG8(BL)) {
3881: case 0x10:
1.1.1.14 root 3882: REG16(BX) = 0x0003;
3883: REG16(CX) = 0x0009;
1.1.1.16 root 3884: break;
1.1.1.14 root 3885: }
3886: }
3887:
1.1 root 3888: inline void pcbios_int_10h_13h()
3889: {
1.1.1.3 root 3890: int ofs = SREG_BASE(ES) + REG16(BP);
1.1 root 3891: COORD co;
3892: DWORD num;
3893:
3894: co.X = REG8(DL);
1.1.1.14 root 3895: co.Y = REG8(DH) + scr_top;
3896:
3897: vram_flush();
1.1 root 3898:
3899: switch(REG8(AL)) {
3900: case 0x00:
3901: case 0x01:
3902: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 3903: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 3904: CONSOLE_SCREEN_BUFFER_INFO csbi;
3905: GetConsoleScreenBufferInfo(hStdout, &csbi);
3906: SetConsoleCursorPosition(hStdout, co);
3907:
3908: if(csbi.wAttributes != REG8(BL)) {
3909: SetConsoleTextAttribute(hStdout, REG8(BL));
3910: }
1.1.1.14 root 3911: WriteConsole(hStdout, &mem[ofs], REG16(CX), &num, NULL);
3912:
1.1 root 3913: if(csbi.wAttributes != REG8(BL)) {
3914: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
3915: }
3916: if(REG8(AL) == 0x00) {
1.1.1.15 root 3917: if(!restore_console_on_exit) {
3918: GetConsoleScreenBufferInfo(hStdout, &csbi);
3919: scr_top = csbi.srWindow.Top;
3920: }
1.1.1.14 root 3921: co.X = mem[0x450 + REG8(BH) * 2];
3922: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 3923: SetConsoleCursorPosition(hStdout, co);
3924: } else {
3925: cursor_moved = true;
3926: }
3927: } else {
1.1.1.3 root 3928: m_CF = 1;
1.1 root 3929: }
3930: break;
3931: case 0x02:
3932: case 0x03:
3933: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 3934: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 3935: CONSOLE_SCREEN_BUFFER_INFO csbi;
3936: GetConsoleScreenBufferInfo(hStdout, &csbi);
3937: SetConsoleCursorPosition(hStdout, co);
3938:
3939: WORD wAttributes = csbi.wAttributes;
3940: for(int i = 0; i < REG16(CX); i++, ofs += 2) {
3941: if(wAttributes != mem[ofs + 1]) {
3942: SetConsoleTextAttribute(hStdout, mem[ofs + 1]);
3943: wAttributes = mem[ofs + 1];
3944: }
1.1.1.14 root 3945: WriteConsole(hStdout, &mem[ofs], 1, &num, NULL);
1.1 root 3946: }
3947: if(csbi.wAttributes != wAttributes) {
3948: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
3949: }
3950: if(REG8(AL) == 0x02) {
1.1.1.14 root 3951: co.X = mem[0x450 + REG8(BH) * 2];
3952: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 3953: SetConsoleCursorPosition(hStdout, co);
3954: } else {
3955: cursor_moved = true;
3956: }
3957: } else {
1.1.1.3 root 3958: m_CF = 1;
1.1 root 3959: }
3960: break;
3961: case 0x10:
3962: case 0x11:
3963: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 3964: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 3965: ReadConsoleOutputCharacter(hStdout, scr_char, REG16(CX), co, &num);
3966: ReadConsoleOutputAttribute(hStdout, scr_attr, REG16(CX), co, &num);
3967: for(int i = 0; i < num; i++) {
3968: mem[ofs++] = scr_char[i];
3969: mem[ofs++] = scr_attr[i];
3970: if(REG8(AL) == 0x11) {
3971: mem[ofs++] = 0;
3972: mem[ofs++] = 0;
3973: }
3974: }
3975: } else {
1.1.1.16 root 3976: 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 3977: mem[ofs++] = mem[src++];
3978: mem[ofs++] = mem[src++];
3979: if(REG8(AL) == 0x11) {
3980: mem[ofs++] = 0;
3981: mem[ofs++] = 0;
3982: }
1.1.1.14 root 3983: if(++co.X == scr_width) {
3984: if(++co.Y == scr_height) {
1.1 root 3985: break;
3986: }
3987: co.X = 0;
3988: }
3989: }
3990: }
3991: break;
3992: case 0x20:
3993: case 0x21:
3994: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 3995: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 3996: int len = min(REG16(CX), scr_width * scr_height);
3997: for(int i = 0; i < len; i++) {
1.1 root 3998: scr_char[i] = mem[ofs++];
3999: scr_attr[i] = mem[ofs++];
4000: if(REG8(AL) == 0x21) {
4001: ofs += 2;
4002: }
4003: }
1.1.1.14 root 4004: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
4005: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 4006: } else {
1.1.1.16 root 4007: 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 4008: mem[dest++] = mem[ofs++];
4009: mem[dest++] = mem[ofs++];
4010: if(REG8(AL) == 0x21) {
4011: ofs += 2;
4012: }
1.1.1.14 root 4013: if(++co.X == scr_width) {
4014: if(++co.Y == scr_height) {
1.1 root 4015: break;
4016: }
4017: co.X = 0;
4018: }
4019: }
4020: }
4021: break;
4022: default:
1.1.1.22 root 4023: 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 4024: m_CF = 1;
1.1 root 4025: break;
4026: }
4027: }
4028:
1.1.1.14 root 4029: inline void pcbios_int_10h_1ah()
4030: {
4031: switch(REG8(AL)) {
4032: case 0x00:
4033: REG8(AL) = 0x1a;
4034: REG8(BL) = 0x08;
4035: REG8(BH) = 0x00;
4036: break;
4037: default:
1.1.1.22 root 4038: 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 4039: m_CF = 1;
4040: break;
4041: }
4042: }
4043:
1.1 root 4044: inline void pcbios_int_10h_1dh()
4045: {
4046: switch(REG8(AL)) {
4047: case 0x01:
4048: break;
4049: case 0x02:
4050: REG16(BX) = 0;
4051: break;
4052: default:
1.1.1.22 root 4053: 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));
4054: m_CF = 1;
4055: break;
4056: }
4057: }
4058:
4059: inline void pcbios_int_10h_4fh()
4060: {
4061: switch(REG8(AL)) {
4062: case 0x00:
4063: REG8(AH) = 0x02; // not supported
4064: break;
4065: case 0x01:
4066: case 0x02:
4067: case 0x03:
4068: case 0x04:
4069: case 0x05:
4070: case 0x06:
4071: case 0x07:
4072: case 0x08:
4073: case 0x09:
4074: case 0x0a:
4075: case 0x0b:
4076: case 0x0c:
4077: REG8(AH) = 0x01; // failed
4078: break;
4079: default:
4080: 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 4081: m_CF = 1;
1.1 root 4082: break;
4083: }
4084: }
4085:
4086: inline void pcbios_int_10h_82h()
4087: {
4088: static UINT8 mode = 0;
4089:
4090: switch(REG8(AL)) {
1.1.1.22 root 4091: case 0x00:
1.1 root 4092: if(REG8(BL) != 0xff) {
4093: mode = REG8(BL);
4094: }
4095: REG8(AL) = mode;
4096: break;
4097: default:
1.1.1.22 root 4098: 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 4099: m_CF = 1;
1.1 root 4100: break;
4101: }
4102: }
4103:
1.1.1.22 root 4104: inline void pcbios_int_10h_83h()
4105: {
4106: static UINT8 mode = 0;
4107:
4108: switch(REG8(AL)) {
4109: case 0x00:
4110: REG16(AX) = 0; // offset???
4111: SREG(ES) = (SHADOW_BUF_TOP >> 4);
4112: i386_load_segment_descriptor(ES);
4113: REG16(BX) = (SHADOW_BUF_TOP & 0x0f);
4114: break;
4115: default:
4116: 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));
4117: m_CF = 1;
4118: break;
4119: }
4120: }
4121:
4122: inline void pcbios_int_10h_90h()
4123: {
4124: REG8(AL) = mem[0x449];
4125: }
4126:
4127: inline void pcbios_int_10h_91h()
4128: {
4129: REG8(AL) = 0x04; // VGA
4130: }
4131:
4132: inline void pcbios_int_10h_efh()
4133: {
4134: REG16(DX) = 0xffff;
4135: }
4136:
1.1 root 4137: inline void pcbios_int_10h_feh()
4138: {
4139: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 4140: SREG(ES) = (SHADOW_BUF_TOP >> 4);
1.1.1.3 root 4141: i386_load_segment_descriptor(ES);
1.1.1.8 root 4142: REG16(DI) = (SHADOW_BUF_TOP & 0x0f);
1.1 root 4143: }
4144: int_10h_feh_called = true;
4145: }
4146:
4147: inline void pcbios_int_10h_ffh()
4148: {
4149: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.23 root 4150: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 4151: COORD co;
4152: DWORD num;
4153:
1.1.1.14 root 4154: vram_flush();
4155:
4156: co.X = (REG16(DI) >> 1) % scr_width;
4157: co.Y = (REG16(DI) >> 1) / scr_width;
1.1.1.16 root 4158: int ofs = pcbios_get_shadow_buffer_address(0, co.X, co.Y);
4159: int end = min(ofs + REG16(CX) * 2, pcbios_get_shadow_buffer_address(0, 0, scr_height));
1.1.1.14 root 4160: int len;
4161: for(len = 0; ofs < end; len++) {
4162: scr_char[len] = mem[ofs++];
4163: scr_attr[len] = mem[ofs++];
4164: }
4165: co.Y += scr_top;
4166: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
4167: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 4168: }
4169: int_10h_ffh_called = true;
4170: }
4171:
1.1.1.14 root 4172: inline void pcbios_int_15h_10h()
4173: {
1.1.1.22 root 4174: switch(REG8(AL)) {
4175: case 0x00:
1.1.1.14 root 4176: Sleep(10);
4177: hardware_update();
1.1.1.22 root 4178: break;
4179: default:
4180: 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 4181: REG8(AH) = 0x86;
4182: m_CF = 1;
4183: }
4184: }
4185:
1.1 root 4186: inline void pcbios_int_15h_23h()
4187: {
4188: switch(REG8(AL)) {
1.1.1.22 root 4189: case 0x00:
1.1.1.8 root 4190: REG8(CL) = cmos_read(0x2d);
4191: REG8(CH) = cmos_read(0x2e);
1.1 root 4192: break;
1.1.1.22 root 4193: case 0x01:
1.1.1.8 root 4194: cmos_write(0x2d, REG8(CL));
4195: cmos_write(0x2e, REG8(CH));
1.1 root 4196: break;
4197: default:
1.1.1.22 root 4198: 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 4199: REG8(AH) = 0x86;
1.1.1.3 root 4200: m_CF = 1;
1.1 root 4201: break;
4202: }
4203: }
4204:
4205: inline void pcbios_int_15h_24h()
4206: {
4207: switch(REG8(AL)) {
1.1.1.22 root 4208: case 0x00:
1.1.1.3 root 4209: i386_set_a20_line(0);
1.1 root 4210: REG8(AH) = 0;
4211: break;
1.1.1.22 root 4212: case 0x01:
1.1.1.3 root 4213: i386_set_a20_line(1);
1.1 root 4214: REG8(AH) = 0;
4215: break;
1.1.1.22 root 4216: case 0x02:
1.1 root 4217: REG8(AH) = 0;
1.1.1.3 root 4218: REG8(AL) = (m_a20_mask >> 20) & 1;
1.1 root 4219: REG16(CX) = 0;
4220: break;
1.1.1.22 root 4221: case 0x03:
1.1 root 4222: REG16(AX) = 0;
4223: REG16(BX) = 0;
4224: break;
1.1.1.22 root 4225: default:
4226: 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));
4227: REG8(AH) = 0x86;
4228: m_CF = 1;
4229: break;
1.1 root 4230: }
4231: }
4232:
4233: inline void pcbios_int_15h_49h()
4234: {
1.1.1.14 root 4235: REG8(AH) = 0;
4236: REG8(BL) = 0; // DOS/V
1.1 root 4237: }
4238:
1.1.1.22 root 4239: inline void pcbios_int_15h_50h()
4240: {
4241: switch(REG8(AL)) {
4242: case 0x00:
4243: case 0x01:
4244: if(REG8(BH) != 0x00 && REG8(BH) != 0x01) {
4245: REG8(AH) = 0x01; // invalid font type in bh
4246: m_CF = 1;
4247: } else if(REG8(BL) != 0) {
4248: REG8(AH) = 0x02; // bl not zero
4249: m_CF = 1;
4250: } else if(REG16(BP) != 0 && REG16(BP) != 437 && REG16(BP) != 932 && REG16(BP) != 934 && REG16(BP) != 936 && REG16(BP) != 938) {
4251: REG8(AH) = 0x04; // invalid code page
4252: m_CF = 1;
4253: } else {
4254: REG8(AH) = 0x86; // finally, this function is not supported
4255: m_CF = 1;
4256: }
4257: break;
4258: default:
4259: 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));
4260: REG8(AH) = 0x86;
4261: m_CF = 1;
4262: break;
4263: }
4264: }
4265:
1.1 root 4266: inline void pcbios_int_15h_86h()
4267: {
4268: UINT32 usec = (REG16(CX) << 16) | REG16(DX);
1.1.1.14 root 4269: UINT32 msec = usec / 1000;
4270:
4271: while(msec) {
4272: UINT32 tmp = min(msec, 100);
4273: if(msec - tmp < 10) {
4274: tmp = msec;
4275: }
4276: Sleep(tmp);
4277:
4278: if(m_halted) {
4279: return;
4280: }
4281: msec -= tmp;
4282: }
1.1 root 4283: }
4284:
4285: inline void pcbios_int_15h_87h()
4286: {
4287: // copy extended memory (from DOSBox)
4288: int len = REG16(CX) * 2;
1.1.1.3 root 4289: int ofs = SREG_BASE(ES) + REG16(SI);
1.1 root 4290: int src = (*(UINT32 *)(mem + ofs + 0x12) & 0xffffff); // + (mem[ofs + 0x16] << 24);
4291: int dst = (*(UINT32 *)(mem + ofs + 0x1a) & 0xffffff); // + (mem[ofs + 0x1e] << 24);
4292: memcpy(mem + dst, mem + src, len);
4293: REG16(AX) = 0x00;
4294: }
4295:
4296: inline void pcbios_int_15h_88h()
4297: {
1.1.1.17 root 4298: REG16(AX) = ((min(MAX_MEM, 0x4000000) - 0x100000) >> 10);
1.1 root 4299: }
4300:
4301: inline void pcbios_int_15h_89h()
4302: {
1.1.1.21 root 4303: #if defined(HAS_I286) || defined(HAS_I386)
1.1 root 4304: // switch to protected mode (from DOSBox)
4305: write_io_byte(0x20, 0x10);
4306: write_io_byte(0x21, REG8(BH));
4307: write_io_byte(0x21, 0x00);
4308: write_io_byte(0xa0, 0x10);
4309: write_io_byte(0xa1, REG8(BL));
4310: write_io_byte(0xa1, 0x00);
1.1.1.3 root 4311: i386_set_a20_line(1);
4312: int ofs = SREG_BASE(ES) + REG16(SI);
4313: m_gdtr.limit = *(UINT16 *)(mem + ofs + 0x08);
4314: m_gdtr.base = *(UINT32 *)(mem + ofs + 0x08 + 0x02) & 0xffffff;
4315: m_idtr.limit = *(UINT16 *)(mem + ofs + 0x10);
4316: m_idtr.base = *(UINT32 *)(mem + ofs + 0x10 + 0x02) & 0xffffff;
4317: #if defined(HAS_I386)
4318: m_cr[0] |= 1;
4319: #else
4320: m_msw |= 1;
4321: #endif
4322: SREG(DS) = 0x18;
4323: SREG(ES) = 0x20;
4324: SREG(SS) = 0x28;
4325: i386_load_segment_descriptor(DS);
4326: i386_load_segment_descriptor(ES);
4327: i386_load_segment_descriptor(SS);
1.1.1.21 root 4328: UINT16 offset = *(UINT16 *)(mem + SREG_BASE(SS) + REG16(SP));
1.1 root 4329: REG16(SP) += 6;
1.1.1.3 root 4330: #if defined(HAS_I386)
1.1.1.21 root 4331: UINT32 flags = get_flags();
4332: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
4333: set_flags(flags);
1.1.1.3 root 4334: #else
1.1.1.21 root 4335: UINT32 flags = CompressFlags();
4336: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
4337: ExpandFlags(flags);
1.1.1.3 root 4338: #endif
1.1 root 4339: REG16(AX) = 0x00;
1.1.1.21 root 4340: i386_jmp_far(0x30, /*REG16(CX)*/offset);
1.1 root 4341: #else
1.1.1.21 root 4342: // i86/i186/v30: protected mode is not supported
1.1 root 4343: REG8(AH) = 0x86;
1.1.1.3 root 4344: m_CF = 1;
1.1 root 4345: #endif
4346: }
4347:
1.1.1.21 root 4348: inline void pcbios_int_15h_8ah()
4349: {
4350: UINT32 size = MAX_MEM - 0x100000;
4351: REG16(AX) = size & 0xffff;
4352: REG16(DX) = size >> 16;
4353: }
4354:
1.1.1.3 root 4355: #if defined(HAS_I386)
1.1 root 4356: inline void pcbios_int_15h_c9h()
4357: {
4358: REG8(AH) = 0x00;
4359: REG8(CH) = cpu_type;
4360: REG8(CL) = cpu_step;
4361: }
1.1.1.3 root 4362: #endif
1.1 root 4363:
4364: inline void pcbios_int_15h_cah()
4365: {
4366: switch(REG8(AL)) {
1.1.1.22 root 4367: case 0x00:
1.1 root 4368: if(REG8(BL) > 0x3f) {
4369: REG8(AH) = 0x03;
1.1.1.3 root 4370: m_CF = 1;
1.1 root 4371: } else if(REG8(BL) < 0x0e) {
4372: REG8(AH) = 0x04;
1.1.1.3 root 4373: m_CF = 1;
1.1 root 4374: } else {
1.1.1.8 root 4375: REG8(CL) = cmos_read(REG8(BL));
1.1 root 4376: }
4377: break;
1.1.1.22 root 4378: case 0x01:
1.1 root 4379: if(REG8(BL) > 0x3f) {
4380: REG8(AH) = 0x03;
1.1.1.3 root 4381: m_CF = 1;
1.1 root 4382: } else if(REG8(BL) < 0x0e) {
4383: REG8(AH) = 0x04;
1.1.1.3 root 4384: m_CF = 1;
1.1 root 4385: } else {
1.1.1.8 root 4386: cmos_write(REG8(BL), REG8(CL));
1.1 root 4387: }
4388: break;
4389: default:
1.1.1.22 root 4390: 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 4391: REG8(AH) = 0x86;
1.1.1.3 root 4392: m_CF = 1;
1.1 root 4393: break;
4394: }
4395: }
4396:
1.1.1.22 root 4397: inline void pcbios_int_15h_e8h()
1.1.1.17 root 4398: {
1.1.1.22 root 4399: switch(REG8(AL)) {
4400: #if defined(HAS_I386)
4401: case 0x01:
4402: REG16(AX) = REG16(CX) = ((min(MAX_MEM, 0x1000000) - 0x100000) >> 10);
4403: REG16(BX) = REG16(DX) = ((max(MAX_MEM, 0x1000000) - 0x1000000) >> 16);
4404: break;
1.1.1.17 root 4405: #endif
1.1.1.22 root 4406: default:
4407: 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));
4408: REG8(AH) = 0x86;
4409: m_CF = 1;
4410: break;
4411: }
4412: }
1.1.1.17 root 4413:
1.1.1.16 root 4414: UINT32 pcbios_get_key_code(bool clear_buffer)
1.1 root 4415: {
4416: UINT32 code = 0;
4417:
4418: if(key_buf_char->count() == 0) {
1.1.1.14 root 4419: if(!update_key_buffer()) {
4420: if(clear_buffer) {
4421: Sleep(10);
4422: } else {
4423: maybe_idle();
4424: }
4425: }
1.1 root 4426: }
4427: if(!clear_buffer) {
4428: key_buf_char->store_buffer();
4429: key_buf_scan->store_buffer();
4430: }
4431: if(key_buf_char->count() != 0) {
4432: code = key_buf_char->read() | (key_buf_scan->read() << 8);
4433: }
4434: if(key_buf_char->count() != 0) {
4435: code |= (key_buf_char->read() << 16) | (key_buf_scan->read() << 24);
4436: }
4437: if(!clear_buffer) {
4438: key_buf_char->restore_buffer();
4439: key_buf_scan->restore_buffer();
4440: }
4441: return code;
4442: }
4443:
4444: inline void pcbios_int_16h_00h()
4445: {
1.1.1.14 root 4446: while(key_code == 0 && !m_halted) {
1.1.1.16 root 4447: key_code = pcbios_get_key_code(true);
1.1 root 4448: }
4449: if((key_code & 0xffff) == 0x0000 || (key_code & 0xffff) == 0xe000) {
4450: if(REG8(AH) == 0x10) {
4451: key_code = ((key_code >> 8) & 0xff) | ((key_code >> 16) & 0xff00);
4452: } else {
4453: key_code = ((key_code >> 16) & 0xff00);
4454: }
4455: }
4456: REG16(AX) = key_code & 0xffff;
4457: key_code >>= 16;
4458: }
4459:
4460: inline void pcbios_int_16h_01h()
4461: {
1.1.1.5 root 4462: UINT32 key_code_tmp = key_code;
1.1 root 4463:
1.1.1.5 root 4464: if(key_code_tmp == 0) {
1.1.1.16 root 4465: key_code_tmp = pcbios_get_key_code(false);
1.1.1.5 root 4466: }
1.1.1.14 root 4467: if((key_code_tmp & 0xffff) == 0x0000 || (key_code_tmp & 0xffff) == 0xe000) {
4468: if(REG8(AH) == 0x11) {
4469: key_code_tmp = ((key_code_tmp >> 8) & 0xff) | ((key_code_tmp >> 16) & 0xff00);
4470: } else {
4471: key_code_tmp = ((key_code_tmp >> 16) & 0xff00);
1.1 root 4472: }
4473: }
1.1.1.5 root 4474: if(key_code_tmp != 0) {
4475: REG16(AX) = key_code_tmp & 0xffff;
1.1 root 4476: }
1.1.1.3 root 4477: #if defined(HAS_I386)
1.1.1.5 root 4478: m_ZF = (key_code_tmp == 0);
1.1.1.3 root 4479: #else
1.1.1.5 root 4480: m_ZeroVal = (key_code_tmp != 0);
1.1.1.3 root 4481: #endif
1.1 root 4482: }
4483:
4484: inline void pcbios_int_16h_02h()
4485: {
4486: REG8(AL) = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
4487: REG8(AL) |= (GetAsyncKeyState(VK_CAPITAL) & 0x0001) ? 0x40 : 0;
4488: REG8(AL) |= (GetAsyncKeyState(VK_NUMLOCK) & 0x0001) ? 0x20 : 0;
4489: REG8(AL) |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
4490: REG8(AL) |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
4491: REG8(AL) |= (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? 0x04 : 0;
4492: REG8(AL) |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
4493: REG8(AL) |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
4494: }
4495:
4496: inline void pcbios_int_16h_03h()
4497: {
4498: static UINT16 status = 0;
4499:
4500: switch(REG8(AL)) {
4501: case 0x05:
4502: status = REG16(BX);
4503: break;
4504: case 0x06:
4505: REG16(BX) = status;
4506: break;
4507: default:
1.1.1.3 root 4508: m_CF = 1;
1.1 root 4509: break;
4510: }
4511: }
4512:
4513: inline void pcbios_int_16h_05h()
4514: {
1.1.1.14 root 4515: key_buf_char->write(REG8(CL));
4516: key_buf_scan->write(REG8(CH));
1.1 root 4517: REG8(AL) = 0x00;
4518: }
4519:
4520: inline void pcbios_int_16h_12h()
4521: {
4522: pcbios_int_16h_02h();
4523:
4524: REG8(AH) = 0;//(GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x80 : 0;
4525: REG8(AH) |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
4526: REG8(AH) |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
4527: REG8(AH) |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
4528: REG8(AH) |= (GetAsyncKeyState(VK_RMENU ) & 0x8000) ? 0x08 : 0;
4529: REG8(AH) |= (GetAsyncKeyState(VK_RCONTROL) & 0x8000) ? 0x04 : 0;
4530: REG8(AH) |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
4531: REG8(AH) |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
4532: }
4533:
4534: inline void pcbios_int_16h_13h()
4535: {
4536: static UINT16 status = 0;
4537:
4538: switch(REG8(AL)) {
4539: case 0x00:
4540: status = REG16(DX);
4541: break;
4542: case 0x01:
4543: REG16(DX) = status;
4544: break;
4545: default:
1.1.1.22 root 4546: 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 4547: m_CF = 1;
1.1 root 4548: break;
4549: }
4550: }
4551:
4552: inline void pcbios_int_16h_14h()
4553: {
4554: static UINT8 status = 0;
4555:
4556: switch(REG8(AL)) {
4557: case 0x00:
4558: case 0x01:
4559: status = REG8(AL);
4560: break;
4561: case 0x02:
4562: REG8(AL) = status;
4563: break;
4564: default:
1.1.1.22 root 4565: 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 4566: m_CF = 1;
1.1 root 4567: break;
4568: }
4569: }
4570:
1.1.1.24! root 4571: inline void pcbios_int_16h_55h()
! 4572: {
! 4573: switch(REG8(AL)) {
! 4574: case 0x00:
! 4575: // keyboard tsr is not present
! 4576: break;
! 4577: case 0xfe:
! 4578: // handlers for INT 08, INT 09, INT 16, INT 1B, and INT 1C are installed
! 4579: break;
! 4580: case 0xff:
! 4581: break;
! 4582: default:
! 4583: 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));
! 4584: m_CF = 1;
! 4585: break;
! 4586: }
! 4587: }
! 4588:
1.1 root 4589: inline void pcbios_int_1ah_00h()
4590: {
1.1.1.19 root 4591: pcbios_update_daily_timer_counter(timeGetTime());
4592: REG16(CX) = *(UINT16 *)(mem + 0x46e);
4593: REG16(DX) = *(UINT16 *)(mem + 0x46c);
4594: REG8(AL) = mem[0x470];
4595: mem[0x470] = 0;
1.1 root 4596: }
4597:
4598: inline int to_bcd(int t)
4599: {
4600: int u = (t % 100) / 10;
4601: return (u << 4) | (t % 10);
4602: }
4603:
4604: inline void pcbios_int_1ah_02h()
4605: {
4606: SYSTEMTIME time;
4607:
4608: GetLocalTime(&time);
4609: REG8(CH) = to_bcd(time.wHour);
4610: REG8(CL) = to_bcd(time.wMinute);
4611: REG8(DH) = to_bcd(time.wSecond);
4612: REG8(DL) = 0x00;
4613: }
4614:
4615: inline void pcbios_int_1ah_04h()
4616: {
4617: SYSTEMTIME time;
4618:
4619: GetLocalTime(&time);
4620: REG8(CH) = to_bcd(time.wYear / 100);
4621: REG8(CL) = to_bcd(time.wYear);
4622: REG8(DH) = to_bcd(time.wMonth);
4623: REG8(DL) = to_bcd(time.wDay);
4624: }
4625:
4626: inline void pcbios_int_1ah_0ah()
4627: {
4628: SYSTEMTIME time;
4629: FILETIME file_time;
4630: WORD dos_date, dos_time;
4631:
4632: GetLocalTime(&time);
4633: SystemTimeToFileTime(&time, &file_time);
4634: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time);
4635: REG16(CX) = dos_date;
4636: }
4637:
4638: // msdos system call
4639:
4640: inline void msdos_int_21h_00h()
4641: {
1.1.1.3 root 4642: msdos_process_terminate(SREG(CS), retval, 1);
1.1 root 4643: }
4644:
4645: inline void msdos_int_21h_01h()
4646: {
4647: REG8(AL) = msdos_getche();
1.1.1.8 root 4648: // some seconds may be passed in console
1.1 root 4649: hardware_update();
4650: }
4651:
4652: inline void msdos_int_21h_02h()
4653: {
4654: msdos_putch(REG8(DL));
4655: }
4656:
4657: inline void msdos_int_21h_03h()
4658: {
4659: REG8(AL) = msdos_aux_in();
4660: }
4661:
4662: inline void msdos_int_21h_04h()
4663: {
4664: msdos_aux_out(REG8(DL));
4665: }
4666:
4667: inline void msdos_int_21h_05h()
4668: {
4669: msdos_prn_out(REG8(DL));
4670: }
4671:
4672: inline void msdos_int_21h_06h()
4673: {
4674: if(REG8(DL) == 0xff) {
4675: if(msdos_kbhit()) {
4676: REG8(AL) = msdos_getch();
1.1.1.3 root 4677: #if defined(HAS_I386)
4678: m_ZF = 0;
4679: #else
4680: m_ZeroVal = 1;
4681: #endif
1.1 root 4682: } else {
4683: REG8(AL) = 0;
1.1.1.3 root 4684: #if defined(HAS_I386)
4685: m_ZF = 1;
4686: #else
4687: m_ZeroVal = 0;
4688: #endif
1.1.1.14 root 4689: maybe_idle();
1.1 root 4690: }
4691: } else {
4692: msdos_putch(REG8(DL));
4693: }
4694: }
4695:
4696: inline void msdos_int_21h_07h()
4697: {
4698: REG8(AL) = msdos_getch();
1.1.1.8 root 4699: // some seconds may be passed in console
1.1 root 4700: hardware_update();
4701: }
4702:
4703: inline void msdos_int_21h_08h()
4704: {
4705: REG8(AL) = msdos_getch();
1.1.1.8 root 4706: // some seconds may be passed in console
1.1 root 4707: hardware_update();
4708: }
4709:
4710: inline void msdos_int_21h_09h()
4711: {
1.1.1.21 root 4712: msdos_stdio_reopen();
4713:
1.1.1.20 root 4714: process_t *process = msdos_process_info_get(current_psp);
4715: int fd = msdos_psp_get_file_table(1, current_psp);
4716:
1.1.1.14 root 4717: char *str = (char *)(mem + SREG_BASE(DS) + REG16(DX));
4718: int len = 0;
1.1 root 4719:
1.1.1.14 root 4720: while(str[len] != '$' && len < 0x10000) {
4721: len++;
4722: }
1.1.1.20 root 4723: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4724: // stdout is redirected to file
1.1.1.20 root 4725: msdos_write(fd, str, len);
1.1 root 4726: } else {
4727: for(int i = 0; i < len; i++) {
1.1.1.14 root 4728: msdos_putch(str[i]);
1.1 root 4729: }
4730: }
4731: }
4732:
4733: inline void msdos_int_21h_0ah()
4734: {
1.1.1.3 root 4735: int ofs = SREG_BASE(DS) + REG16(DX);
1.1 root 4736: int max = mem[ofs] - 1;
4737: UINT8 *buf = mem + ofs + 2;
4738: int chr, p = 0;
4739:
4740: while((chr = msdos_getch()) != 0x0d) {
4741: if(chr == 0x00) {
4742: // skip 2nd byte
4743: msdos_getch();
4744: } else if(chr == 0x08) {
4745: // back space
4746: if(p > 0) {
4747: p--;
1.1.1.20 root 4748: if(msdos_ctrl_code_check(buf[p])) {
4749: msdos_putch(chr);
4750: msdos_putch(chr);
4751: msdos_putch(' ');
4752: msdos_putch(' ');
4753: msdos_putch(chr);
4754: msdos_putch(chr);
4755: } else {
4756: msdos_putch(chr);
4757: msdos_putch(' ');
4758: msdos_putch(chr);
4759: }
1.1 root 4760: }
4761: } else if(p < max) {
4762: buf[p++] = chr;
4763: msdos_putch(chr);
4764: }
4765: }
4766: buf[p] = 0x0d;
4767: mem[ofs + 1] = p;
1.1.1.8 root 4768: // some seconds may be passed in console
1.1 root 4769: hardware_update();
4770: }
4771:
4772: inline void msdos_int_21h_0bh()
4773: {
4774: if(msdos_kbhit()) {
4775: REG8(AL) = 0xff;
4776: } else {
4777: REG8(AL) = 0x00;
1.1.1.14 root 4778: maybe_idle();
1.1 root 4779: }
4780: }
4781:
4782: inline void msdos_int_21h_0ch()
4783: {
4784: // clear key buffer
1.1.1.21 root 4785: msdos_stdio_reopen();
4786:
1.1.1.20 root 4787: process_t *process = msdos_process_info_get(current_psp);
4788: int fd = msdos_psp_get_file_table(0, current_psp);
4789:
4790: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4791: // stdin is redirected to file
4792: } else {
4793: while(msdos_kbhit()) {
4794: msdos_getch();
4795: }
4796: }
4797:
4798: switch(REG8(AL)) {
4799: case 0x01:
4800: msdos_int_21h_01h();
4801: break;
4802: case 0x06:
4803: msdos_int_21h_06h();
4804: break;
4805: case 0x07:
4806: msdos_int_21h_07h();
4807: break;
4808: case 0x08:
4809: msdos_int_21h_08h();
4810: break;
4811: case 0x0a:
4812: msdos_int_21h_0ah();
4813: break;
4814: default:
1.1.1.22 root 4815: // 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));
4816: // REG16(AX) = 0x01;
4817: // m_CF = 1;
1.1 root 4818: break;
4819: }
4820: }
4821:
4822: inline void msdos_int_21h_0dh()
4823: {
4824: }
4825:
4826: inline void msdos_int_21h_0eh()
4827: {
4828: if(REG8(DL) < 26) {
4829: _chdrive(REG8(DL) + 1);
4830: msdos_cds_update(REG8(DL));
1.1.1.23 root 4831: msdos_sda_update(current_psp);
1.1 root 4832: }
4833: REG8(AL) = 26; // zdrive
4834: }
4835:
1.1.1.14 root 4836: inline void msdos_int_21h_0fh()
4837: {
4838: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4839: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4840: char *path = msdos_fcb_path(fcb);
4841: 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 4842:
1.1.1.14 root 4843: if(hFile == INVALID_HANDLE_VALUE) {
4844: REG8(AL) = 0xff;
4845: } else {
4846: REG8(AL) = 0;
4847: fcb->current_block = 0;
4848: fcb->record_size = 128;
4849: fcb->file_size = GetFileSize(hFile, NULL);
4850: fcb->handle = hFile;
4851: fcb->cur_record = 0;
4852: }
4853: }
4854:
4855: inline void msdos_int_21h_10h()
4856: {
4857: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4858: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4859:
4860: REG8(AL) = CloseHandle(fcb->handle) ? 0 : 0xff;
4861: }
4862:
1.1 root 4863: inline void msdos_int_21h_11h()
4864: {
1.1.1.3 root 4865: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4866: fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 4867:
4868: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 4869: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4870: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
4871: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 4872: char *path = msdos_fcb_path(fcb);
4873: WIN32_FIND_DATA fd;
4874:
1.1.1.13 root 4875: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
4876: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
4877: FindClose(dtainfo->find_handle);
4878: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 4879: }
4880: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 4881: dtainfo->allowable_mask = (ext_fcb->flag == 0xff) ? ext_fcb->attribute : 0x20;
4882: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 4883:
1.1.1.14 root 4884: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
4885: dtainfo->allowable_mask &= ~8;
1.1 root 4886: }
1.1.1.14 root 4887: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
4888: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 4889: !msdos_find_file_has_8dot3name(&fd)) {
4890: if(!FindNextFile(dtainfo->find_handle, &fd)) {
4891: FindClose(dtainfo->find_handle);
4892: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 4893: break;
4894: }
4895: }
4896: }
1.1.1.13 root 4897: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 4898: if(ext_fcb->flag == 0xff) {
4899: ext_find->flag = 0xff;
4900: memset(ext_find->reserved, 0, 5);
4901: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
4902: }
4903: find->drive = _getdrive();
1.1.1.13 root 4904: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 4905: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
4906: find->nt_res = 0;
4907: msdos_find_file_conv_local_time(&fd);
4908: find->create_time_ms = 0;
4909: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
4910: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
4911: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
4912: find->cluster_hi = find->cluster_lo = 0;
4913: find->file_size = fd.nFileSizeLow;
4914: REG8(AL) = 0x00;
1.1.1.14 root 4915: } else if(dtainfo->allowable_mask & 8) {
1.1 root 4916: if(ext_fcb->flag == 0xff) {
4917: ext_find->flag = 0xff;
4918: memset(ext_find->reserved, 0, 5);
4919: ext_find->attribute = 8;
4920: }
4921: find->drive = _getdrive();
4922: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
4923: find->attribute = 8;
4924: find->nt_res = 0;
4925: msdos_find_file_conv_local_time(&fd);
4926: find->create_time_ms = 0;
4927: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
4928: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
4929: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
4930: find->cluster_hi = find->cluster_lo = 0;
4931: find->file_size = 0;
1.1.1.14 root 4932: dtainfo->allowable_mask &= ~8;
1.1 root 4933: REG8(AL) = 0x00;
4934: } else {
4935: REG8(AL) = 0xff;
4936: }
4937: }
4938:
4939: inline void msdos_int_21h_12h()
4940: {
1.1.1.3 root 4941: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1.1.14 root 4942: // fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 4943:
4944: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 4945: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4946: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
4947: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 4948: WIN32_FIND_DATA fd;
4949:
1.1.1.13 root 4950: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
4951: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
4952: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 4953: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 4954: !msdos_find_file_has_8dot3name(&fd)) {
4955: if(!FindNextFile(dtainfo->find_handle, &fd)) {
4956: FindClose(dtainfo->find_handle);
4957: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 4958: break;
4959: }
4960: }
4961: } else {
1.1.1.13 root 4962: FindClose(dtainfo->find_handle);
4963: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 4964: }
4965: }
1.1.1.13 root 4966: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 4967: if(ext_fcb->flag == 0xff) {
4968: ext_find->flag = 0xff;
4969: memset(ext_find->reserved, 0, 5);
4970: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
4971: }
4972: find->drive = _getdrive();
1.1.1.13 root 4973: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 4974: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
4975: find->nt_res = 0;
4976: msdos_find_file_conv_local_time(&fd);
4977: find->create_time_ms = 0;
4978: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
4979: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
4980: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
4981: find->cluster_hi = find->cluster_lo = 0;
4982: find->file_size = fd.nFileSizeLow;
4983: REG8(AL) = 0x00;
1.1.1.14 root 4984: } else if(dtainfo->allowable_mask & 8) {
1.1 root 4985: if(ext_fcb->flag == 0xff) {
4986: ext_find->flag = 0xff;
4987: memset(ext_find->reserved, 0, 5);
4988: ext_find->attribute = 8;
4989: }
4990: find->drive = _getdrive();
4991: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
4992: find->attribute = 8;
4993: find->nt_res = 0;
4994: msdos_find_file_conv_local_time(&fd);
4995: find->create_time_ms = 0;
4996: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
4997: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
4998: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
4999: find->cluster_hi = find->cluster_lo = 0;
5000: find->file_size = 0;
1.1.1.14 root 5001: dtainfo->allowable_mask &= ~8;
1.1 root 5002: REG8(AL) = 0x00;
5003: } else {
5004: REG8(AL) = 0xff;
5005: }
5006: }
5007:
5008: inline void msdos_int_21h_13h()
5009: {
1.1.1.3 root 5010: if(remove(msdos_fcb_path((fcb_t *)(mem + SREG_BASE(DS) + REG16(DX))))) {
1.1 root 5011: REG8(AL) = 0xff;
5012: } else {
5013: REG8(AL) = 0x00;
5014: }
5015: }
5016:
1.1.1.16 root 5017: inline void msdos_int_21h_14h()
5018: {
5019: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5020: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5021: process_t *process = msdos_process_info_get(current_psp);
5022: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5023: DWORD num = 0;
5024:
5025: memset(mem + dta_laddr, 0, fcb->record_size);
5026: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
5027: REG8(AL) = 1;
5028: } else {
5029: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
5030: fcb->current_block = (position & 0xffffff) / fcb->record_size;
5031: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
5032: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
5033: }
5034: }
5035:
5036: inline void msdos_int_21h_15h()
1.1.1.14 root 5037: {
5038: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5039: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.16 root 5040: process_t *process = msdos_process_info_get(current_psp);
5041: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5042: DWORD num = 0;
1.1.1.14 root 5043:
1.1.1.16 root 5044: if(!WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
5045: REG8(AL) = 1;
5046: } else {
5047: fcb->file_size = GetFileSize(fcb->handle, NULL);
5048: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
5049: fcb->current_block = (position & 0xffffff) / fcb->record_size;
5050: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
5051: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
5052: }
5053: }
5054:
5055: inline void msdos_int_21h_16h()
5056: {
5057: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5058: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.14 root 5059: char *path = msdos_fcb_path(fcb);
5060: 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 5061:
1.1.1.14 root 5062: if(hFile == INVALID_HANDLE_VALUE) {
5063: REG8(AL) = 0xff;
5064: } else {
5065: REG8(AL) = 0;
5066: fcb->current_block = 0;
5067: fcb->record_size = 128;
5068: fcb->file_size = 0;
5069: fcb->handle = hFile;
5070: fcb->cur_record = 0;
5071: }
5072: }
5073:
1.1.1.16 root 5074: inline void msdos_int_21h_17h()
5075: {
5076: ext_fcb_t *ext_fcb_src = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5077: fcb_t *fcb_src = (fcb_t *)(ext_fcb_src + (ext_fcb_src->flag == 0xff ? 1 : 0));
5078: char *path_src = msdos_fcb_path(fcb_src);
5079: ext_fcb_t *ext_fcb_dst = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + 16);
5080: fcb_t *fcb_dst = (fcb_t *)(ext_fcb_dst + (ext_fcb_dst->flag == 0xff ? 1 : 0));
5081: char *path_dst = msdos_fcb_path(fcb_dst);
5082:
5083: if(rename(path_src, path_dst)) {
5084: REG8(AL) = 0xff;
5085: } else {
5086: REG8(AL) = 0;
5087: }
5088: }
5089:
1.1 root 5090: inline void msdos_int_21h_18h()
5091: {
5092: REG8(AL) = 0x00;
5093: }
5094:
5095: inline void msdos_int_21h_19h()
5096: {
5097: REG8(AL) = _getdrive() - 1;
5098: }
5099:
5100: inline void msdos_int_21h_1ah()
5101: {
5102: process_t *process = msdos_process_info_get(current_psp);
5103:
5104: process->dta.w.l = REG16(DX);
1.1.1.3 root 5105: process->dta.w.h = SREG(DS);
1.1.1.23 root 5106: msdos_sda_update(current_psp);
1.1 root 5107: }
5108:
5109: inline void msdos_int_21h_1bh()
5110: {
5111: int drive_num = _getdrive() - 1;
5112: UINT16 seg, ofs;
5113:
5114: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
5115: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
5116: REG8(AL) = dpb->highest_sector_num + 1;
5117: REG16(CX) = dpb->bytes_per_sector;
5118: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 5119: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 5120: } else {
5121: REG8(AL) = 0xff;
1.1.1.3 root 5122: m_CF = 1;
1.1 root 5123: }
5124:
5125: }
5126:
5127: inline void msdos_int_21h_1ch()
5128: {
5129: int drive_num = REG8(DL) ? (REG8(DL) - 1) : (_getdrive() - 1);
5130: UINT16 seg, ofs;
5131:
5132: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
5133: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
5134: REG8(AL) = dpb->highest_sector_num + 1;
5135: REG16(CX) = dpb->bytes_per_sector;
5136: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 5137: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 5138: } else {
5139: REG8(AL) = 0xff;
1.1.1.3 root 5140: m_CF = 1;
1.1 root 5141: }
5142:
5143: }
5144:
5145: inline void msdos_int_21h_1dh()
5146: {
5147: REG8(AL) = 0;
5148: }
5149:
5150: inline void msdos_int_21h_1eh()
5151: {
5152: REG8(AL) = 0;
5153: }
5154:
5155: inline void msdos_int_21h_1fh()
5156: {
5157: int drive_num = _getdrive() - 1;
5158: UINT16 seg, ofs;
5159:
5160: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
5161: REG8(AL) = 0;
1.1.1.3 root 5162: SREG(DS) = seg;
5163: i386_load_segment_descriptor(DS);
1.1 root 5164: REG16(BX) = ofs;
5165: } else {
5166: REG8(AL) = 0xff;
1.1.1.3 root 5167: m_CF = 1;
1.1 root 5168: }
5169: }
5170:
5171: inline void msdos_int_21h_20h()
5172: {
5173: REG8(AL) = 0;
5174: }
5175:
1.1.1.14 root 5176: inline void msdos_int_21h_21h()
5177: {
5178: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5179: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5180:
5181: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
5182: REG8(AL) = 1;
5183: } else {
5184: process_t *process = msdos_process_info_get(current_psp);
5185: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5186: memset(mem + dta_laddr, 0, fcb->record_size);
1.1.1.16 root 5187: DWORD num = 0;
1.1.1.14 root 5188: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
5189: REG8(AL) = 1;
5190: } else {
5191: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
5192: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 5193: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
1.1.1.14 root 5194: }
5195: }
5196: }
5197:
5198: inline void msdos_int_21h_22h()
5199: {
5200: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5201: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5202:
5203: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
5204: REG8(AL) = 0xff;
5205: } else {
5206: process_t *process = msdos_process_info_get(current_psp);
5207: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
1.1.1.16 root 5208: DWORD num = 0;
1.1.1.14 root 5209: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL);
5210: fcb->file_size = GetFileSize(fcb->handle, NULL);
5211: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
5212: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 5213: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
1.1.1.14 root 5214: }
5215: }
5216:
1.1.1.16 root 5217: inline void msdos_int_21h_23h()
5218: {
5219: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5220: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5221: char *path = msdos_fcb_path(fcb);
5222: HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
5223:
5224: if(hFile == INVALID_HANDLE_VALUE) {
5225: REG8(AL) = 0xff;
5226: } else {
5227: UINT32 size = GetFileSize(hFile, NULL);
5228: fcb->rand_record = size / fcb->record_size + ((size % fcb->record_size) != 0);
5229: REG8(AL) = 0;
5230: }
5231: }
5232:
5233: inline void msdos_int_21h_24h()
5234: {
5235: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5236: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5237:
5238: fcb->rand_record = fcb->current_block * fcb->record_size + fcb->cur_record;
5239: }
5240:
1.1 root 5241: inline void msdos_int_21h_25h()
5242: {
5243: *(UINT16 *)(mem + 4 * REG8(AL) + 0) = REG16(DX);
1.1.1.3 root 5244: *(UINT16 *)(mem + 4 * REG8(AL) + 2) = SREG(DS);
1.1 root 5245: }
5246:
5247: inline void msdos_int_21h_26h()
5248: {
5249: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
5250:
5251: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
5252: psp->first_mcb = REG16(DX) + 16;
5253: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
5254: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
5255: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
5256: psp->parent_psp = 0;
5257: }
5258:
1.1.1.16 root 5259: inline void msdos_int_21h_27h()
5260: {
5261: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5262: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5263:
5264: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
5265: REG8(AL) = 1;
5266: } else {
5267: process_t *process = msdos_process_info_get(current_psp);
5268: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5269: memset(mem + dta_laddr, 0, fcb->record_size * REG16(CX));
5270: DWORD num = 0;
5271: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL) || num == 0) {
5272: REG8(AL) = 1;
5273: } else {
5274: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
5275: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
5276: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
5277: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
5278: }
5279: }
5280: }
5281:
5282: inline void msdos_int_21h_28h()
5283: {
5284: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5285: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5286:
5287: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
5288: REG8(AL) = 0xff;
5289: } else {
5290: process_t *process = msdos_process_info_get(current_psp);
5291: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5292: DWORD num = 0;
5293: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL);
5294: fcb->file_size = GetFileSize(fcb->handle, NULL);
5295: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
5296: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
5297: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
5298: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
5299: }
5300: }
5301:
1.1 root 5302: inline void msdos_int_21h_29h()
5303: {
1.1.1.20 root 5304: int ofs = 0;//SREG_BASE(DS) + REG16(SI);
5305: char buffer[1024], name[MAX_PATH], ext[MAX_PATH];
1.1 root 5306: UINT8 drv = 0;
5307: char sep_chars[] = ":.;,=+";
5308: char end_chars[] = "\\<>|/\"[]";
5309: char spc_chars[] = " \t";
5310:
1.1.1.20 root 5311: memcpy(buffer, mem + SREG_BASE(DS) + REG16(SI), 1023);
5312: buffer[1023] = 0;
5313: memset(name, 0x20, sizeof(name));
5314: memset(ext, 0x20, sizeof(ext));
5315:
1.1 root 5316: if(REG8(AL) & 1) {
1.1.1.20 root 5317: ofs += strspn((char *)(buffer + ofs), spc_chars);
5318: if(my_strchr(sep_chars, buffer[ofs]) && buffer[ofs] != '\0') {
1.1 root 5319: ofs++;
5320: }
5321: }
1.1.1.20 root 5322: ofs += strspn((char *)(buffer + ofs), spc_chars);
1.1 root 5323:
1.1.1.24! root 5324: if(buffer[ofs + 1] == ':') {
! 5325: if(buffer[ofs] >= 'a' && buffer[ofs] <= 'z') {
! 5326: drv = buffer[ofs] - 'a' + 1;
1.1.1.20 root 5327: ofs += 2;
1.1.1.24! root 5328: if(buffer[ofs] == '\\' || buffer[ofs] == '/') {
! 5329: ofs++;
! 5330: }
! 5331: } else if(buffer[ofs] >= 'A' && buffer[ofs] <= 'Z') {
! 5332: drv = buffer[ofs] - 'A' + 1;
1.1 root 5333: ofs += 2;
1.1.1.24! root 5334: if(buffer[ofs] == '\\' || buffer[ofs] == '/') {
! 5335: ofs++;
! 5336: }
1.1 root 5337: }
5338: }
1.1.1.20 root 5339: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
5340: UINT8 c = buffer[ofs];
5341: if(is_kanji) {
5342: is_kanji = 0;
5343: } else if(msdos_lead_byte_check(c)) {
5344: is_kanji = 1;
5345: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 5346: break;
5347: } else if(c >= 'a' && c <= 'z') {
5348: c -= 0x20;
5349: }
5350: ofs++;
5351: name[i] = c;
5352: }
1.1.1.20 root 5353: if(buffer[ofs] == '.') {
1.1 root 5354: ofs++;
1.1.1.20 root 5355: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
5356: UINT8 c = buffer[ofs];
5357: if(is_kanji) {
5358: is_kanji = 0;
5359: } else if(msdos_lead_byte_check(c)) {
5360: is_kanji = 1;
5361: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 5362: break;
5363: } else if(c >= 'a' && c <= 'z') {
5364: c -= 0x20;
5365: }
5366: ofs++;
5367: ext[i] = c;
5368: }
5369: }
1.1.1.20 root 5370: int si = REG16(SI) + ofs;
1.1.1.3 root 5371: int ds = SREG(DS);
1.1 root 5372: while(si > 0xffff) {
5373: si -= 0x10;
5374: ds++;
5375: }
5376: REG16(SI) = si;
1.1.1.3 root 5377: SREG(DS) = ds;
5378: i386_load_segment_descriptor(DS);
1.1 root 5379:
1.1.1.3 root 5380: UINT8 *fcb = mem + SREG_BASE(ES) + REG16(DI);
1.1.1.20 root 5381: if(!(REG8(AL) & 2) || drv != 0) {
5382: fcb[0] = drv;
5383: }
5384: if(!(REG8(AL) & 4) || name[0] != 0x20) {
5385: memcpy(fcb + 1, name, 8);
5386: }
5387: if(!(REG8(AL) & 8) || ext[0] != 0x20) {
5388: memcpy(fcb + 9, ext, 3);
5389: }
5390: for(int i = 1, found_star = 0; i < 1 + 8; i++) {
1.1 root 5391: if(fcb[i] == '*') {
5392: found_star = 1;
5393: }
5394: if(found_star) {
5395: fcb[i] = '?';
5396: }
5397: }
1.1.1.20 root 5398: for(int i = 9, found_star = 0; i < 9 + 3; i++) {
1.1 root 5399: if(fcb[i] == '*') {
5400: found_star = 1;
5401: }
5402: if(found_star) {
5403: fcb[i] = '?';
5404: }
5405: }
5406:
5407: if(drv == 0 || (drv > 0 && drv <= 26 && (GetLogicalDrives() & ( 1 << (drv - 1) )))) {
5408: if(memchr(fcb + 1, '?', 8 + 3)) {
5409: REG8(AL) = 0x01;
1.1.1.20 root 5410: } else {
5411: REG8(AL) = 0x00;
1.1 root 5412: }
5413: } else {
5414: REG8(AL) = 0xff;
5415: }
5416: }
5417:
5418: inline void msdos_int_21h_2ah()
5419: {
5420: SYSTEMTIME sTime;
5421:
5422: GetLocalTime(&sTime);
5423: REG16(CX) = sTime.wYear;
5424: REG8(DH) = (UINT8)sTime.wMonth;
5425: REG8(DL) = (UINT8)sTime.wDay;
5426: REG8(AL) = (UINT8)sTime.wDayOfWeek;
5427: }
5428:
5429: inline void msdos_int_21h_2bh()
5430: {
1.1.1.14 root 5431: REG8(AL) = 0xff;
1.1 root 5432: }
5433:
5434: inline void msdos_int_21h_2ch()
5435: {
5436: SYSTEMTIME sTime;
5437:
5438: GetLocalTime(&sTime);
5439: REG8(CH) = (UINT8)sTime.wHour;
5440: REG8(CL) = (UINT8)sTime.wMinute;
5441: REG8(DH) = (UINT8)sTime.wSecond;
1.1.1.14 root 5442: REG8(DL) = (UINT8)sTime.wMilliseconds / 10;
1.1 root 5443: }
5444:
5445: inline void msdos_int_21h_2dh()
5446: {
5447: REG8(AL) = 0x00;
5448: }
5449:
5450: inline void msdos_int_21h_2eh()
5451: {
5452: process_t *process = msdos_process_info_get(current_psp);
5453:
5454: process->verify = REG8(AL);
5455: }
5456:
5457: inline void msdos_int_21h_2fh()
5458: {
5459: process_t *process = msdos_process_info_get(current_psp);
5460:
5461: REG16(BX) = process->dta.w.l;
1.1.1.3 root 5462: SREG(ES) = process->dta.w.h;
5463: i386_load_segment_descriptor(ES);
1.1 root 5464: }
5465:
5466: inline void msdos_int_21h_30h()
5467: {
5468: // Version Flag / OEM
5469: if(REG8(AL) == 1) {
5470: REG8(BH) = 0x00; // not in ROM
5471: } else {
5472: REG8(BH) = 0xff; // OEM = Microsoft
5473: }
1.1.1.9 root 5474: REG8(AL) = major_version; // 7
5475: REG8(AH) = minor_version; // 10
1.1 root 5476: }
5477:
5478: inline void msdos_int_21h_31h()
5479: {
1.1.1.14 root 5480: msdos_mem_realloc(current_psp, REG16(DX), NULL);
1.1 root 5481: msdos_process_terminate(current_psp, REG8(AL) | 0x300, 0);
5482: }
5483:
5484: inline void msdos_int_21h_32h()
5485: {
5486: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
5487: UINT16 seg, ofs;
5488:
5489: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
5490: REG8(AL) = 0;
1.1.1.3 root 5491: SREG(DS) = seg;
5492: i386_load_segment_descriptor(DS);
1.1 root 5493: REG16(BX) = ofs;
5494: } else {
5495: REG8(AL) = 0xff;
1.1.1.3 root 5496: m_CF = 1;
1.1 root 5497: }
5498: }
5499:
5500: inline void msdos_int_21h_33h()
5501: {
5502: static UINT8 state = 0x00;
5503: char path[MAX_PATH];
5504:
5505: switch(REG8(AL)) {
5506: case 0x00:
5507: REG8(DL) = state;
5508: break;
5509: case 0x01:
5510: state = REG8(DL);
5511: break;
5512: case 0x05:
5513: GetSystemDirectory(path, MAX_PATH);
5514: if(path[0] >= 'a' && path[0] <= 'z') {
5515: REG8(DL) = path[0] - 'a' + 1;
5516: } else {
5517: REG8(DL) = path[0] - 'A' + 1;
5518: }
5519: break;
5520: case 0x06:
1.1.1.2 root 5521: // MS-DOS version (7.10)
1.1 root 5522: REG8(BL) = 7;
1.1.1.2 root 5523: REG8(BH) = 10;
1.1 root 5524: REG8(DL) = 0;
5525: REG8(DH) = 0x10; // in HMA
5526: break;
1.1.1.6 root 5527: case 0x07:
5528: if(REG8(DL) == 0) {
5529: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag &= ~0x20;
5530: } else if(REG8(DL) == 1) {
5531: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag |= 0x20;
5532: }
5533: break;
1.1 root 5534: default:
1.1.1.22 root 5535: 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 5536: REG16(AX) = 0x01;
1.1.1.3 root 5537: m_CF = 1;
1.1 root 5538: break;
5539: }
5540: }
5541:
1.1.1.23 root 5542: inline void msdos_int_21h_34h()
5543: {
5544: SREG(ES) = SDA_TOP >> 4;
5545: i386_load_segment_descriptor(ES);
5546: REG16(BX) = offsetof(sda_t, indos_flag);;
5547: }
5548:
1.1 root 5549: inline void msdos_int_21h_35h()
5550: {
5551: REG16(BX) = *(UINT16 *)(mem + 4 * REG8(AL) + 0);
1.1.1.3 root 5552: SREG(ES) = *(UINT16 *)(mem + 4 * REG8(AL) + 2);
5553: i386_load_segment_descriptor(ES);
1.1 root 5554: }
5555:
5556: inline void msdos_int_21h_36h()
5557: {
5558: struct _diskfree_t df = {0};
5559:
5560: if(_getdiskfree(REG8(DL), &df) == 0) {
5561: REG16(AX) = (UINT16)df.sectors_per_cluster;
5562: REG16(CX) = (UINT16)df.bytes_per_sector;
1.1.1.13 root 5563: REG16(BX) = df.avail_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.avail_clusters;
5564: REG16(DX) = df.total_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.total_clusters;
1.1 root 5565: } else {
5566: REG16(AX) = 0xffff;
5567: }
5568: }
5569:
5570: inline void msdos_int_21h_37h()
5571: {
1.1.1.22 root 5572: static UINT8 dev_flag = 0xff;
1.1 root 5573:
5574: switch(REG8(AL)) {
5575: case 0x00:
1.1.1.22 root 5576: {
5577: process_t *process = msdos_process_info_get(current_psp);
5578: REG8(AL) = 0x00;
5579: REG8(DL) = process->switchar;
5580: }
1.1 root 5581: break;
5582: case 0x01:
1.1.1.22 root 5583: {
5584: process_t *process = msdos_process_info_get(current_psp);
5585: REG8(AL) = 0x00;
5586: process->switchar = REG8(DL);
1.1.1.23 root 5587: msdos_sda_update(current_psp);
1.1.1.22 root 5588: }
5589: break;
5590: case 0x02:
5591: REG8(DL) = dev_flag;
5592: break;
5593: case 0x03:
5594: dev_flag = REG8(DL);
5595: break;
5596: case 0xd0:
5597: case 0xd1:
5598: case 0xd2:
5599: case 0xd3:
5600: case 0xd4:
5601: case 0xd5:
5602: case 0xd6:
5603: case 0xd7:
5604: case 0xdc:
5605: case 0xdd:
5606: case 0xde:
5607: case 0xdf:
5608: // diet ???
5609: REG16(AX) = 1;
1.1 root 5610: break;
5611: default:
1.1.1.22 root 5612: 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 5613: REG16(AX) = 1;
5614: break;
5615: }
5616: }
5617:
1.1.1.19 root 5618: int get_country_info(country_info_t *ci)
1.1.1.17 root 5619: {
5620: char LCdata[80];
5621:
1.1.1.19 root 5622: ZeroMemory(ci, offsetof(country_info_t, reserved));
1.1.1.17 root 5623: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRDIGITS, LCdata, sizeof(LCdata));
5624: ci->currency_dec_digits = atoi(LCdata);
5625: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRENCY, LCdata, sizeof(LCdata));
5626: ci->currency_format = *LCdata - '0';
5627: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDATE, LCdata, sizeof(LCdata));
5628: ci->date_format = *LCdata - '0';
5629: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SCURRENCY, LCdata, sizeof(LCdata));
5630: memcpy(&ci->currency_symbol, LCdata, 4);
5631: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDATE, LCdata, sizeof(LCdata));
5632: *ci->date_sep = *LCdata;
5633: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, LCdata, sizeof(LCdata));
5634: *ci->dec_sep = *LCdata;
5635: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLIST, LCdata, sizeof(LCdata));
5636: *ci->list_sep = *LCdata;
5637: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, LCdata, sizeof(LCdata));
5638: *ci->thou_sep = *LCdata;
5639: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIME, LCdata, sizeof(LCdata));
5640: *ci->time_sep = *LCdata;
5641: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, LCdata, sizeof(LCdata));
5642: if(strchr(LCdata, 'H') != NULL) {
5643: ci->time_format = 1;
5644: }
1.1.1.24! root 5645: ci->case_map.w.l = 0x000c; // FFFD:000C
! 5646: ci->case_map.w.h = 0xfffd;
1.1.1.17 root 5647: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICOUNTRY, LCdata, sizeof(LCdata));
5648: return atoi(LCdata);
5649: }
5650:
1.1.1.14 root 5651: inline void msdos_int_21h_38h()
5652: {
5653: switch(REG8(AL)) {
5654: case 0x00:
1.1.1.19 root 5655: REG16(BX) = get_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1.1.14 root 5656: break;
5657: default:
1.1.1.22 root 5658: 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 5659: REG16(AX) = 2;
5660: m_CF = 1;
5661: break;
5662: }
5663: }
5664:
1.1 root 5665: inline void msdos_int_21h_39h(int lfn)
5666: {
1.1.1.3 root 5667: if(_mkdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 5668: REG16(AX) = errno;
1.1.1.3 root 5669: m_CF = 1;
1.1 root 5670: }
5671: }
5672:
5673: inline void msdos_int_21h_3ah(int lfn)
5674: {
1.1.1.3 root 5675: if(_rmdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 5676: REG16(AX) = errno;
1.1.1.3 root 5677: m_CF = 1;
1.1 root 5678: }
5679: }
5680:
5681: inline void msdos_int_21h_3bh(int lfn)
5682: {
1.1.1.3 root 5683: if(_chdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1.1.17 root 5684: REG16(AX) = 3; // must be 3 (path not found)
1.1.1.3 root 5685: m_CF = 1;
1.1 root 5686: }
5687: }
5688:
5689: inline void msdos_int_21h_3ch()
5690: {
1.1.1.3 root 5691: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 5692: int attr = GetFileAttributes(path);
5693: int fd = -1;
1.1.1.11 root 5694: UINT16 info;
1.1 root 5695:
1.1.1.11 root 5696: if(msdos_is_con_path(path)) {
5697: fd = _open("CON", _O_WRONLY | _O_BINARY);
5698: info = 0x80d3;
1.1.1.14 root 5699: } else if(msdos_is_nul_path(path)) {
5700: fd = _open("NUL", _O_WRONLY | _O_BINARY);
5701: info = 0x80d3;
1.1.1.24! root 5702: } else if(msdos_is_driver_name(path)) {
1.1.1.20 root 5703: fd = _open("NUL", _O_WRONLY | _O_BINARY);
5704: info = 0x80d3;
1.1 root 5705: } else {
5706: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 5707: info = msdos_drive_number(path);
1.1 root 5708: }
5709: if(fd != -1) {
5710: if(attr == -1) {
5711: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
5712: }
5713: SetFileAttributes(path, attr);
5714: REG16(AX) = fd;
1.1.1.11 root 5715: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp);
1.1.1.20 root 5716: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 5717: } else {
5718: REG16(AX) = errno;
1.1.1.3 root 5719: m_CF = 1;
1.1 root 5720: }
5721: }
5722:
5723: inline void msdos_int_21h_3dh()
5724: {
1.1.1.3 root 5725: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 5726: int mode = REG8(AL) & 0x03;
1.1.1.11 root 5727: int fd = -1;
5728: UINT16 info;
1.1 root 5729:
5730: if(mode < 0x03) {
1.1.1.11 root 5731: if(msdos_is_con_path(path)) {
1.1.1.13 root 5732: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 5733: info = 0x80d3;
1.1.1.14 root 5734: } else if(msdos_is_nul_path(path)) {
5735: fd = msdos_open("NUL", file_mode[mode].mode);
5736: info = 0x80d3;
1.1.1.24! root 5737: } else if(msdos_is_driver_name(path)) {
1.1.1.20 root 5738: fd = msdos_open("NUL", file_mode[mode].mode);
5739: info = 0x80d3;
1.1.1.11 root 5740: } else {
1.1.1.13 root 5741: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 5742: info = msdos_drive_number(path);
5743: }
1.1 root 5744: if(fd != -1) {
5745: REG16(AX) = fd;
1.1.1.11 root 5746: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp);
1.1.1.20 root 5747: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 5748: } else {
5749: REG16(AX) = errno;
1.1.1.3 root 5750: m_CF = 1;
1.1 root 5751: }
5752: } else {
5753: REG16(AX) = 0x0c;
1.1.1.3 root 5754: m_CF = 1;
1.1 root 5755: }
5756: }
5757:
5758: inline void msdos_int_21h_3eh()
5759: {
5760: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 5761: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 5762:
1.1.1.20 root 5763: if(fd < process->max_files && file_handler[fd].valid) {
5764: _close(fd);
5765: msdos_file_handler_close(fd);
5766: msdos_psp_set_file_table(REG16(BX), 0x0ff, current_psp);
1.1 root 5767: } else {
5768: REG16(AX) = 0x06;
1.1.1.3 root 5769: m_CF = 1;
1.1 root 5770: }
5771: }
5772:
5773: inline void msdos_int_21h_3fh()
5774: {
5775: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 5776: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 5777:
1.1.1.20 root 5778: if(fd < process->max_files && file_handler[fd].valid) {
5779: if(file_mode[file_handler[fd].mode].in) {
5780: if(file_handler[fd].atty) {
1.1 root 5781: // BX is stdin or is redirected to stdin
1.1.1.3 root 5782: UINT8 *buf = mem + SREG_BASE(DS) + REG16(DX);
1.1 root 5783: int max = REG16(CX);
5784: int p = 0;
5785:
5786: while(max > p) {
5787: int chr = msdos_getch();
5788:
5789: if(chr == 0x00) {
5790: // skip 2nd byte
5791: msdos_getch();
5792: } else if(chr == 0x0d) {
5793: // carriage return
5794: buf[p++] = 0x0d;
5795: if(max > p) {
5796: buf[p++] = 0x0a;
5797: }
1.1.1.14 root 5798: msdos_putch('\n');
1.1 root 5799: break;
5800: } else if(chr == 0x08) {
5801: // back space
5802: if(p > 0) {
5803: p--;
1.1.1.20 root 5804: if(msdos_ctrl_code_check(buf[p])) {
5805: msdos_putch(chr);
5806: msdos_putch(chr);
5807: msdos_putch(' ');
5808: msdos_putch(' ');
5809: msdos_putch(chr);
5810: msdos_putch(chr);
5811: } else {
5812: msdos_putch(chr);
5813: msdos_putch(' ');
5814: msdos_putch(chr);
5815: }
1.1 root 5816: }
5817: } else {
5818: buf[p++] = chr;
5819: msdos_putch(chr);
5820: }
5821: }
5822: REG16(AX) = p;
1.1.1.8 root 5823: // some seconds may be passed in console
1.1 root 5824: hardware_update();
5825: } else {
1.1.1.20 root 5826: REG16(AX) = _read(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 5827: }
5828: } else {
5829: REG16(AX) = 0x05;
1.1.1.3 root 5830: m_CF = 1;
1.1 root 5831: }
5832: } else {
5833: REG16(AX) = 0x06;
1.1.1.3 root 5834: m_CF = 1;
1.1 root 5835: }
5836: }
5837:
5838: inline void msdos_int_21h_40h()
5839: {
5840: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 5841: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 5842:
1.1.1.20 root 5843: if(fd < process->max_files && file_handler[fd].valid) {
5844: if(file_mode[file_handler[fd].mode].out) {
1.1 root 5845: if(REG16(CX)) {
1.1.1.20 root 5846: if(file_handler[fd].atty) {
1.1 root 5847: // BX is stdout/stderr or is redirected to stdout
5848: for(int i = 0; i < REG16(CX); i++) {
1.1.1.3 root 5849: msdos_putch(mem[SREG_BASE(DS) + REG16(DX) + i]);
1.1 root 5850: }
5851: REG16(AX) = REG16(CX);
5852: } else {
1.1.1.20 root 5853: REG16(AX) = msdos_write(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 5854: }
5855: } else {
1.1.1.20 root 5856: UINT32 pos = _tell(fd);
5857: _lseek(fd, 0, SEEK_END);
5858: UINT32 size = _tell(fd);
1.1.1.12 root 5859: if(pos < size) {
1.1.1.20 root 5860: _lseek(fd, pos, SEEK_SET);
5861: SetEndOfFile((HANDLE)_get_osfhandle(fd));
1.1.1.12 root 5862: } else {
5863: for(UINT32 i = size; i < pos; i++) {
5864: UINT8 tmp = 0;
1.1.1.23 root 5865: msdos_write(fd, &tmp, 1);
1.1.1.12 root 5866: }
1.1.1.20 root 5867: _lseek(fd, pos, SEEK_SET);
1.1 root 5868: }
1.1.1.23 root 5869: REG16(AX) = 0;
1.1 root 5870: }
5871: } else {
5872: REG16(AX) = 0x05;
1.1.1.3 root 5873: m_CF = 1;
1.1 root 5874: }
5875: } else {
5876: REG16(AX) = 0x06;
1.1.1.3 root 5877: m_CF = 1;
1.1 root 5878: }
5879: }
5880:
5881: inline void msdos_int_21h_41h(int lfn)
5882: {
1.1.1.3 root 5883: if(remove(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 5884: REG16(AX) = errno;
1.1.1.3 root 5885: m_CF = 1;
1.1 root 5886: }
5887: }
5888:
5889: inline void msdos_int_21h_42h()
5890: {
5891: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 5892: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 5893:
1.1.1.20 root 5894: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 5895: if(REG8(AL) < 0x03) {
5896: static int ptrname[] = { SEEK_SET, SEEK_CUR, SEEK_END };
1.1.1.20 root 5897: _lseek(fd, (REG16(CX) << 16) | REG16(DX), ptrname[REG8(AL)]);
5898: UINT32 pos = _tell(fd);
1.1 root 5899: REG16(AX) = pos & 0xffff;
5900: REG16(DX) = (pos >> 16);
5901: } else {
5902: REG16(AX) = 0x01;
1.1.1.3 root 5903: m_CF = 1;
1.1 root 5904: }
5905: } else {
5906: REG16(AX) = 0x06;
1.1.1.3 root 5907: m_CF = 1;
1.1 root 5908: }
5909: }
5910:
5911: inline void msdos_int_21h_43h(int lfn)
5912: {
1.1.1.3 root 5913: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn);
1.1 root 5914: int attr;
5915:
1.1.1.14 root 5916: if(!lfn && REG8(AL) > 2) {
5917: REG16(AX) = 0x01;
5918: m_CF = 1;
5919: return;
5920: }
5921: switch(REG8(lfn ? BL : AL)) {
1.1 root 5922: case 0x00:
5923: if((attr = GetFileAttributes(path)) != -1) {
1.1.1.14 root 5924: REG16(CX) = (UINT16)msdos_file_attribute_create((UINT16)attr);
5925: } else {
5926: REG16(AX) = (UINT16)GetLastError();
5927: m_CF = 1;
5928: }
5929: break;
5930: case 0x01:
5931: if(!SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)))) {
5932: REG16(AX) = (UINT16)GetLastError();
5933: m_CF = 1;
5934: }
5935: break;
5936: case 0x02:
5937: {
5938: DWORD size = GetCompressedFileSize(path, NULL);
5939: if(size != INVALID_FILE_SIZE) {
5940: if(size != 0 && size == GetFileSize(path, NULL)) {
5941: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
5942: // this isn't correct if the file is in the NTFS MFT
5943: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
5944: size = ((size - 1) | (sectors_per_cluster * bytes_per_sector - 1)) + 1;
5945: }
5946: }
5947: REG16(AX) = LOWORD(size);
5948: REG16(DX) = HIWORD(size);
5949: } else {
5950: REG16(AX) = (UINT16)GetLastError();
5951: m_CF = 1;
1.1 root 5952: }
1.1.1.14 root 5953: }
5954: break;
5955: case 0x03:
5956: case 0x05:
5957: case 0x07:
5958: {
5959: HANDLE hFile = CreateFile(path, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
5960: if(hFile != INVALID_HANDLE_VALUE) {
5961: FILETIME local, time;
5962: DosDateTimeToFileTime(REG16(DI), /*REG8(BL) == 5 ? 0 : */REG16(CX), &local);
5963: if(REG8(BL) == 7) {
5964: ULARGE_INTEGER hund;
5965: hund.LowPart = local.dwLowDateTime;
5966: hund.HighPart = local.dwHighDateTime;
5967: hund.QuadPart += REG16(SI) * 100000;
5968: local.dwLowDateTime = hund.LowPart;
5969: local.dwHighDateTime = hund.HighPart;
5970: }
5971: LocalFileTimeToFileTime(&local, &time);
5972: if(!SetFileTime(hFile, REG8(BL) == 0x07 ? &time : NULL,
5973: REG8(BL) == 0x05 ? &time : NULL,
5974: REG8(BL) == 0x03 ? &time : NULL)) {
5975: REG16(AX) = (UINT16)GetLastError();
5976: m_CF = 1;
5977: }
5978: CloseHandle(hFile);
5979: } else {
5980: REG16(AX) = (UINT16)GetLastError();
5981: m_CF = 1;
1.1 root 5982: }
1.1.1.14 root 5983: }
5984: break;
5985: case 0x04:
5986: case 0x06:
5987: case 0x08:
5988: {
5989: WIN32_FILE_ATTRIBUTE_DATA fad;
5990: if(GetFileAttributesEx(path, GetFileExInfoStandard, (LPVOID)&fad)) {
5991: FILETIME *time, local;
5992: time = REG8(BL) == 0x04 ? &fad.ftLastWriteTime :
5993: 0x06 ? &fad.ftLastAccessTime :
5994: &fad.ftCreationTime;
5995: FileTimeToLocalFileTime(time, &local);
5996: FileTimeToDosDateTime(&local, ®16(DI), ®16(CX));
5997: if(REG8(BL) == 0x08) {
5998: ULARGE_INTEGER hund;
5999: hund.LowPart = local.dwLowDateTime;
6000: hund.HighPart = local.dwHighDateTime;
6001: hund.QuadPart /= 100000;
6002: REG16(SI) = (UINT16)(hund.QuadPart % 200);
6003: }
6004: } else {
6005: REG16(AX) = (UINT16)GetLastError();
6006: m_CF = 1;
1.1 root 6007: }
1.1.1.14 root 6008: }
6009: break;
6010: default:
1.1.1.22 root 6011: 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 6012: REG16(AX) = 0x01;
6013: m_CF = 1;
6014: break;
6015: }
6016: }
6017:
6018: inline void msdos_int_21h_44h()
6019: {
1.1.1.22 root 6020: static UINT16 iteration_count = 0;
6021:
1.1.1.20 root 6022: process_t *process = msdos_process_info_get(current_psp);
6023: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
6024:
1.1.1.14 root 6025: UINT32 val = DRIVE_NO_ROOT_DIR;
6026:
6027: switch(REG8(AL)) {
6028: case 0x00:
6029: case 0x01:
6030: case 0x02:
6031: case 0x03:
6032: case 0x04:
6033: case 0x05:
6034: case 0x06:
6035: case 0x07:
1.1.1.20 root 6036: if(fd >= process->max_files || !file_handler[fd].valid) {
6037: REG16(AX) = 0x06;
6038: m_CF = 1;
6039: return;
1.1.1.14 root 6040: }
6041: break;
6042: case 0x08:
6043: case 0x09:
6044: if(REG8(BL) >= ('Z' - 'A' + 1)) {
6045: // invalid drive number
6046: REG16(AX) = 0x0f;
6047: m_CF = 1;
6048: return;
6049: } else {
6050: if(REG8(BL) == 0) {
6051: val = GetDriveType(NULL);
6052: } else {
6053: char tmp[8];
6054: sprintf(tmp, "%c:\\", 'A' + REG8(BL) - 1);
6055: val = GetDriveType(tmp);
6056: }
6057: if(val == DRIVE_NO_ROOT_DIR) {
6058: // no drive
6059: REG16(AX) = 0x0f;
6060: m_CF = 1;
6061: return;
1.1 root 6062: }
6063: }
6064: break;
6065: }
6066: switch(REG8(AL)) {
6067: case 0x00: // get ioctrl data
1.1.1.20 root 6068: REG16(DX) = file_handler[fd].info;
1.1 root 6069: break;
6070: case 0x01: // set ioctrl data
1.1.1.20 root 6071: file_handler[fd].info |= REG8(DL);
1.1 root 6072: break;
6073: case 0x02: // recv from character device
6074: case 0x03: // send to character device
6075: case 0x04: // recv from block device
6076: case 0x05: // send to block device
6077: REG16(AX) = 0x05;
1.1.1.3 root 6078: m_CF = 1;
1.1 root 6079: break;
6080: case 0x06: // get read status
1.1.1.20 root 6081: if(file_mode[file_handler[fd].mode].in) {
6082: if(file_handler[fd].atty) {
1.1.1.14 root 6083: REG8(AL) = msdos_kbhit() ? 0xff : 0x00;
1.1 root 6084: } else {
1.1.1.20 root 6085: REG8(AL) = eof(fd) ? 0x00 : 0xff;
1.1 root 6086: }
1.1.1.14 root 6087: } else {
6088: REG8(AL) = 0x00;
1.1 root 6089: }
6090: break;
6091: case 0x07: // get write status
1.1.1.20 root 6092: if(file_mode[file_handler[fd].mode].out) {
1.1.1.14 root 6093: REG8(AL) = 0xff;
6094: } else {
6095: REG8(AL) = 0x00;
1.1 root 6096: }
6097: break;
6098: case 0x08: // check removable drive
1.1.1.14 root 6099: if(val == DRIVE_REMOVABLE || val == DRIVE_CDROM) {
6100: // removable drive
6101: REG16(AX) = 0x00;
1.1 root 6102: } else {
1.1.1.14 root 6103: // fixed drive
6104: REG16(AX) = 0x01;
1.1 root 6105: }
6106: break;
6107: case 0x09: // check remote drive
1.1.1.14 root 6108: if(val == DRIVE_REMOTE) {
6109: // remote drive
6110: REG16(DX) = 0x1000;
1.1 root 6111: } else {
1.1.1.14 root 6112: // local drive
6113: REG16(DX) = 0x00;
1.1 root 6114: }
6115: break;
1.1.1.21 root 6116: case 0x0a: // check remote handle
6117: REG16(DX) = 0x00; // FIXME
6118: break;
1.1 root 6119: case 0x0b: // set retry count
6120: break;
1.1.1.22 root 6121: case 0x0c: // generic character device request
6122: if(REG8(CL) == 0x45) {
6123: // set iteration (retry) count
6124: iteration_count = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
6125: } else if(REG8(CL) == 0x4a) {
6126: // select code page
6127: active_code_page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2);
6128: msdos_nls_tables_update();
6129: } else if(REG8(CL) == 0x65) {
6130: // get iteration (retry) count
6131: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX)) = iteration_count;
6132: } else if(REG8(CL) == 0x6a) {
6133: // query selected code page
6134: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 2; // FIXME
6135: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = active_code_page;
6136:
6137: CPINFO info;
6138: GetCPInfo(active_code_page, &info);
6139:
6140: if(info.MaxCharSize != 1) {
6141: for(int i = 0;; i++) {
6142: UINT8 lo = info.LeadByte[2 * i + 0];
6143: UINT8 hi = info.LeadByte[2 * i + 1];
6144:
6145: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 0) = lo;
6146: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 2) = hi;
6147: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) + 4;
6148:
6149: if(lo == 0 && hi == 0) {
6150: break;
6151: }
6152: }
6153: }
6154: } else if(REG8(CL) == 0x7f) {
6155: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x00) = 0;
6156: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x01) = 0;
6157: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02) = 14;
6158: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x04) = 1;
6159: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x06) = 1;
6160: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x07) = 0;
6161: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x08) = 4;
6162: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0a) = 8 * (*(UINT16 *)(mem + 0x44a));
6163: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0c) = 16 * (*(UINT8 *)(mem + 0x484) + 1);
6164: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e) = *(UINT16 *)(mem + 0x44a);
6165: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x10) = *(UINT8 *)(mem + 0x484) + 1;
6166: } else {
6167: 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));
6168: REG16(AX) = 0x01; // invalid function
6169: m_CF = 1;
6170: }
6171: break;
6172: case 0x0d: // generic block device request
6173: if(REG8(CL) == 0x40) {
6174: // set device parameters
6175: } else if(REG8(CL) == 0x46) {
6176: // set volume serial number
6177: } else if(REG8(CL) == 0x4a) {
6178: // lock logical volume
6179: } else if(REG8(CL) == 0x4b) {
6180: // lock physical volume
6181: } else if(REG8(CL) == 0x60) {
6182: // get device parameters
6183: char dev[] = "\\\\.\\A:";
6184: dev[4] = 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
6185:
6186: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
6187: if(hFile != INVALID_HANDLE_VALUE) {
6188: DISK_GEOMETRY geo;
6189: DWORD dwSize;
6190: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
6191: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x07; // ???
6192: switch(geo.MediaType) {
6193: case F5_360_512:
6194: case F5_320_512:
6195: case F5_320_1024:
6196: case F5_180_512:
6197: case F5_160_512:
6198: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // 320K/360K disk
6199: break;
6200: case F5_1Pt2_512:
6201: case F3_1Pt2_512:
6202: case F3_1Pt23_1024:
6203: case F5_1Pt23_1024:
6204: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x01; // 1.2M disk
6205: break;
6206: case F3_720_512:
6207: case F3_640_512:
6208: case F5_640_512:
6209: case F5_720_512:
6210: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02; // 720K disk
6211: break;
6212: case F8_256_128:
6213: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x03; // single-density 8-inch disk
6214: break;
6215: case FixedMedia:
6216: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
6217: break;
6218: case F3_1Pt44_512:
6219: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07; // (DOS 3.3+) other type of block device, normally 1.44M floppy
6220: break;
6221: case F3_2Pt88_512:
6222: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09; // (DOS 5+) 2.88M floppy
6223: break;
6224: default:
6225: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
6226: // *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // (DOS 3.3+) other type of block device, normally 1.44M floppy
6227: break;
6228: }
6229: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = (geo.MediaType == FixedMedia) ? 0x01 : 0x00;
6230: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04) = (geo.Cylinders.QuadPart > 0xffff) ? 0xffff : geo.Cylinders.QuadPart;
6231: switch(geo.MediaType) {
6232: case F5_360_512:
6233: case F5_320_512:
6234: case F5_320_1024:
6235: case F5_180_512:
6236: case F5_160_512:
6237: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x01; // 320K/360K disk
6238: break;
6239: default:
6240: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x00; // other drive types
6241: break;
6242: }
6243: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x00) = geo.BytesPerSector;
6244: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x02) = geo.SectorsPerTrack * geo.TracksPerCylinder;
6245: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x03) = 0;
6246: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x05) = 0;
6247: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x06) = 0;
6248: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x08) = 0;
6249: switch(geo.MediaType) {
6250: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
6251: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xff;
6252: break;
6253: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
6254: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfe;
6255: break;
6256: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
6257: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfd;
6258: break;
6259: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
6260: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfc;
6261: break;
6262: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
6263: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
6264: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf9;
6265: break;
6266: case FixedMedia: // hard disk
6267: case RemovableMedia:
6268: case Unknown:
6269: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf8;
6270: break;
6271: default:
6272: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf0;
6273: break;
6274: }
6275: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0d) = geo.SectorsPerTrack;
6276: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0f) = 1;
6277: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x11) = 0;
6278: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x15) = geo.TracksPerCylinder * geo.Cylinders.QuadPart;
6279: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x1f) = geo.Cylinders.QuadPart;
6280: // 21h BYTE device type
6281: // 22h WORD device attributes (removable or not, etc)
6282: } else {
6283: REG16(AX) = 0x0f; // invalid drive
6284: m_CF = 1;
6285: }
6286: CloseHandle(hFile);
6287: } else {
6288: REG16(AX) = 0x0f; // invalid drive
6289: m_CF = 1;
6290: }
6291: } else if(REG8(CL) == 0x66) {
6292: // get volume serial number
6293: char path[] = "A:\\";
6294: char volume_label[MAX_PATH];
6295: DWORD serial_number = 0;
6296: char file_system[MAX_PATH];
6297:
6298: path[0] = 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
6299:
6300: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
6301: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
6302: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = serial_number;
6303: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x06, 0x20, 11);
6304: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x06, volume_label, min(strlen(volume_label), 11));
6305: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x11, 0x20, 8);
6306: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x11, file_system, min(strlen(file_system), 8));
6307: } else {
6308: REG16(AX) = 0x0f; // invalid drive
6309: m_CF = 1;
6310: }
6311: } else if(REG8(CL) == 0x67) {
6312: // get access flag
6313: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
6314: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 1;
6315: } else if(REG8(CL) == 0x68) {
6316: // sense media type
6317: char dev[64];
6318: sprintf(dev, "\\\\.\\%c:", 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1);
6319:
6320: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
6321: if(hFile != INVALID_HANDLE_VALUE) {
6322: DISK_GEOMETRY geo;
6323: DWORD dwSize;
6324: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
6325: switch(geo.MediaType) {
6326: case F3_720_512:
6327: case F5_720_512:
6328: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
6329: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02;
6330: break;
6331: case F3_1Pt44_512:
6332: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
6333: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07;
6334: break;
6335: case F3_2Pt88_512:
6336: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
6337: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09;
6338: break;
6339: default:
6340: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x00;
6341: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // ???
6342: break;
6343: }
6344: } else {
6345: REG16(AX) = 0x0f; // invalid drive
6346: m_CF = 1;
6347: }
6348: CloseHandle(hFile);
6349: } else {
6350: REG16(AX) = 0x0f; // invalid drive
6351: m_CF = 1;
6352: }
6353: } else if(REG8(CL) == 0x6a) {
6354: // unlock logical volume
6355: } else if(REG8(CL) == 0x6b) {
6356: // unlock physical volume
6357: } else {
6358: 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));
6359: REG16(AX) = 0x01; // invalid function
6360: m_CF = 1;
6361: }
6362: break;
6363: case 0x0e: // get logical drive map
6364: {
6365: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
6366: if(!(GetLogicalDrives() & bits)) {
6367: REG16(AX) = 0x0f; // invalid drive
6368: m_CF = 1;
6369: } else {
6370: REG8(AL) = 0;
6371: }
6372: }
6373: break;
6374: case 0x0f: // set logical drive map
6375: {
6376: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
6377: if(!(GetLogicalDrives() & bits)) {
6378: REG16(AX) = 0x0f; // invalid drive
6379: m_CF = 1;
6380: }
6381: }
6382: break;
6383: case 0x10: // query generic ioctrl capability (handle)
6384: switch(REG8(CL)) {
6385: case 0x45:
6386: case 0x4a:
6387: case 0x65:
6388: case 0x6a:
6389: case 0x7f:
6390: REG16(AX) = 0x0000; // supported
6391: break;
6392: default:
6393: REG8(AL) = 0x01; // ioctl capability not available
6394: m_CF = 1;
6395: break;
6396: }
6397: break;
6398: case 0x11: // query generic ioctrl capability (drive)
6399: switch(REG8(CL)) {
6400: case 0x40:
6401: case 0x46:
6402: case 0x4a:
6403: case 0x4b:
6404: case 0x60:
6405: case 0x66:
6406: case 0x67:
6407: case 0x68:
6408: case 0x6a:
6409: case 0x6b:
6410: REG16(AX) = 0x0000; // supported
6411: break;
6412: default:
6413: REG8(AL) = 0x01; // ioctl capability not available
6414: m_CF = 1;
6415: break;
6416: }
6417: break;
6418: case 0x12: // determine dos type
6419: case 0x51: // concurrent dos v3.2+ - installation check
6420: case 0x52: // determine dos type/get dr dos versuin
6421: REG16(AX) = 0x01; // this is not DR-DOS
6422: m_CF = 1;
6423: break;
1.1 root 6424: default:
1.1.1.22 root 6425: 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 6426: REG16(AX) = 0x01;
1.1.1.3 root 6427: m_CF = 1;
1.1 root 6428: break;
6429: }
6430: }
6431:
6432: inline void msdos_int_21h_45h()
6433: {
6434: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 6435: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 6436:
1.1.1.20 root 6437: if(fd < process->max_files && file_handler[fd].valid) {
6438: int dup_fd = _dup(fd);
6439: if(dup_fd != -1) {
6440: REG16(AX) = dup_fd;
6441: msdos_file_handler_dup(dup_fd, fd, current_psp);
6442: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
6443: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 6444: } else {
6445: REG16(AX) = errno;
1.1.1.3 root 6446: m_CF = 1;
1.1 root 6447: }
6448: } else {
6449: REG16(AX) = 0x06;
1.1.1.3 root 6450: m_CF = 1;
1.1 root 6451: }
6452: }
6453:
6454: inline void msdos_int_21h_46h()
6455: {
6456: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 6457: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
6458: int dup_fd = REG16(CX);
6459: int tmp_fd = msdos_psp_get_file_table(REG16(CX), current_psp);
1.1 root 6460:
1.1.1.20 root 6461: if(REG16(BX) == REG16(CX)) {
6462: REG16(AX) = 0x06;
6463: m_CF = 1;
6464: } else if(fd < process->max_files && file_handler[fd].valid && dup_fd < process->max_files) {
6465: if(tmp_fd < process->max_files && file_handler[tmp_fd].valid) {
6466: _close(tmp_fd);
6467: msdos_file_handler_close(tmp_fd);
6468: msdos_psp_set_file_table(dup_fd, 0x0ff, current_psp);
6469: }
6470: if(_dup2(fd, dup_fd) != -1) {
6471: msdos_file_handler_dup(dup_fd, fd, current_psp);
6472: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
6473: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 6474: } else {
6475: REG16(AX) = errno;
1.1.1.3 root 6476: m_CF = 1;
1.1 root 6477: }
6478: } else {
6479: REG16(AX) = 0x06;
1.1.1.3 root 6480: m_CF = 1;
1.1 root 6481: }
6482: }
6483:
6484: inline void msdos_int_21h_47h(int lfn)
6485: {
6486: char path[MAX_PATH];
6487:
6488: if(_getdcwd(REG8(DL), path, MAX_PATH) != NULL) {
6489: if(path[1] == ':') {
6490: // the returned path does not include a drive or the initial backslash
1.1.1.3 root 6491: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), (lfn ? path : msdos_short_path(path)) + 3);
1.1 root 6492: } else {
1.1.1.3 root 6493: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn ? path : msdos_short_path(path));
1.1 root 6494: }
6495: } else {
6496: REG16(AX) = errno;
1.1.1.3 root 6497: m_CF = 1;
1.1 root 6498: }
6499: }
6500:
6501: inline void msdos_int_21h_48h()
6502: {
1.1.1.19 root 6503: int seg, umb_linked;
1.1 root 6504:
1.1.1.8 root 6505: if((malloc_strategy & 0xf0) == 0x00) {
1.1.1.19 root 6506: // unlink umb not to allocate memory in umb
6507: if((umb_linked = msdos_mem_get_umb_linked()) != 0) {
6508: msdos_mem_unlink_umb();
6509: }
1.1.1.8 root 6510: if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
6511: REG16(AX) = seg;
6512: } else {
6513: REG16(AX) = 0x08;
6514: REG16(BX) = msdos_mem_get_free(first_mcb, 0);
6515: m_CF = 1;
6516: }
1.1.1.19 root 6517: if(umb_linked != 0) {
6518: msdos_mem_link_umb();
6519: }
1.1.1.8 root 6520: } else if((malloc_strategy & 0xf0) == 0x40) {
6521: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
6522: REG16(AX) = seg;
6523: } else {
6524: REG16(AX) = 0x08;
6525: REG16(BX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
6526: m_CF = 1;
6527: }
6528: } else if((malloc_strategy & 0xf0) == 0x80) {
6529: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
6530: REG16(AX) = seg;
6531: } else if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
6532: REG16(AX) = seg;
6533: } else {
6534: REG16(AX) = 0x08;
6535: REG16(BX) = max(msdos_mem_get_free(UMB_TOP >> 4, 0), msdos_mem_get_free(first_mcb, 0));
6536: m_CF = 1;
6537: }
1.1 root 6538: }
6539: }
6540:
6541: inline void msdos_int_21h_49h()
6542: {
1.1.1.14 root 6543: int mcb_seg = SREG(ES) - 1;
6544: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
6545:
6546: if(mcb->mz == 'M' || mcb->mz == 'Z') {
6547: msdos_mem_free(SREG(ES));
6548: } else {
6549: REG16(AX) = 9;
6550: m_CF = 1;
6551: }
1.1 root 6552: }
6553:
6554: inline void msdos_int_21h_4ah()
6555: {
1.1.1.14 root 6556: int mcb_seg = SREG(ES) - 1;
6557: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1 root 6558: int max_paragraphs;
6559:
1.1.1.14 root 6560: if(mcb->mz == 'M' || mcb->mz == 'Z') {
6561: if(msdos_mem_realloc(SREG(ES), REG16(BX), &max_paragraphs)) {
6562: REG16(AX) = 0x08;
6563: REG16(BX) = max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs;
6564: m_CF = 1;
6565: }
6566: } else {
6567: REG16(AX) = 7;
1.1.1.3 root 6568: m_CF = 1;
1.1 root 6569: }
6570: }
6571:
6572: inline void msdos_int_21h_4bh()
6573: {
1.1.1.3 root 6574: char *command = (char *)(mem + SREG_BASE(DS) + REG16(DX));
6575: param_block_t *param = (param_block_t *)(mem + SREG_BASE(ES) + REG16(BX));
1.1 root 6576:
6577: switch(REG8(AL)) {
6578: case 0x00:
6579: case 0x01:
6580: if(msdos_process_exec(command, param, REG8(AL))) {
6581: REG16(AX) = 0x02;
1.1.1.3 root 6582: m_CF = 1;
1.1 root 6583: }
6584: break;
1.1.1.14 root 6585: case 0x03:
6586: {
6587: int fd;
6588: if((fd = _open(command, _O_RDONLY | _O_BINARY)) == -1) {
6589: REG16(AX) = 0x02;
6590: m_CF = 1;
6591: break;
6592: }
6593: int size = _read(fd, file_buffer, sizeof(file_buffer));
6594: _close(fd);
6595:
6596: UINT16 *overlay = (UINT16 *)param;
6597:
6598: // check exe header
6599: exe_header_t *header = (exe_header_t *)file_buffer;
6600: int header_size = 0;
6601: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
6602: header_size = header->header_size * 16;
6603: // relocation
6604: int start_seg = overlay[1];
6605: for(int i = 0; i < header->relocations; i++) {
6606: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
6607: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
6608: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
6609: }
6610: }
6611: memcpy(mem + (overlay[0] << 4), file_buffer + header_size, size - header_size);
6612: }
6613: break;
1.1 root 6614: default:
1.1.1.22 root 6615: 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 6616: REG16(AX) = 0x01;
1.1.1.3 root 6617: m_CF = 1;
1.1 root 6618: break;
6619: }
6620: }
6621:
6622: inline void msdos_int_21h_4ch()
6623: {
6624: msdos_process_terminate(current_psp, REG8(AL), 1);
6625: }
6626:
6627: inline void msdos_int_21h_4dh()
6628: {
6629: REG16(AX) = retval;
6630: }
6631:
6632: inline void msdos_int_21h_4eh()
6633: {
6634: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 6635: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
6636: find_t *find = (find_t *)(mem + dta_laddr);
1.1.1.3 root 6637: char *path = msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 6638: WIN32_FIND_DATA fd;
6639:
1.1.1.14 root 6640: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
6641: find->find_magic = FIND_MAGIC;
6642: find->dta_index = dtainfo - dtalist;
1.1 root 6643: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 6644: dtainfo->allowable_mask = REG8(CL);
6645: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 6646:
1.1.1.14 root 6647: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
6648: dtainfo->allowable_mask &= ~8;
1.1 root 6649: }
1.1.1.14 root 6650: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
6651: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 6652: !msdos_find_file_has_8dot3name(&fd)) {
6653: if(!FindNextFile(dtainfo->find_handle, &fd)) {
6654: FindClose(dtainfo->find_handle);
6655: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6656: break;
6657: }
6658: }
6659: }
1.1.1.13 root 6660: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 6661: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
6662: msdos_find_file_conv_local_time(&fd);
6663: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
6664: find->size = fd.nFileSizeLow;
1.1.1.13 root 6665: strcpy(find->name, msdos_short_name(&fd));
1.1 root 6666: REG16(AX) = 0;
1.1.1.14 root 6667: } else if(dtainfo->allowable_mask & 8) {
1.1 root 6668: find->attrib = 8;
6669: find->size = 0;
6670: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 6671: dtainfo->allowable_mask &= ~8;
1.1 root 6672: REG16(AX) = 0;
6673: } else {
6674: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 6675: m_CF = 1;
1.1 root 6676: }
6677: }
6678:
6679: inline void msdos_int_21h_4fh()
6680: {
6681: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 6682: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
6683: find_t *find = (find_t *)(mem + dta_laddr);
1.1 root 6684: WIN32_FIND_DATA fd;
6685:
1.1.1.14 root 6686: if(find->find_magic != FIND_MAGIC || find->dta_index >= MAX_DTAINFO) {
6687: REG16(AX) = 0x12;
6688: m_CF = 1;
6689: return;
6690: }
6691: dtainfo_t *dtainfo = &dtalist[find->dta_index];
1.1.1.13 root 6692: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
6693: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 6694: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 6695: !msdos_find_file_has_8dot3name(&fd)) {
6696: if(!FindNextFile(dtainfo->find_handle, &fd)) {
6697: FindClose(dtainfo->find_handle);
6698: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6699: break;
6700: }
6701: }
6702: } else {
1.1.1.13 root 6703: FindClose(dtainfo->find_handle);
6704: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6705: }
6706: }
1.1.1.13 root 6707: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 6708: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
6709: msdos_find_file_conv_local_time(&fd);
6710: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
6711: find->size = fd.nFileSizeLow;
1.1.1.13 root 6712: strcpy(find->name, msdos_short_name(&fd));
1.1 root 6713: REG16(AX) = 0;
1.1.1.14 root 6714: } else if(dtainfo->allowable_mask & 8) {
1.1 root 6715: find->attrib = 8;
6716: find->size = 0;
6717: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 6718: dtainfo->allowable_mask &= ~8;
1.1 root 6719: REG16(AX) = 0;
6720: } else {
6721: REG16(AX) = 0x12;
1.1.1.3 root 6722: m_CF = 1;
1.1 root 6723: }
6724: }
6725:
6726: inline void msdos_int_21h_50h()
6727: {
1.1.1.8 root 6728: if(current_psp != REG16(BX)) {
6729: process_t *process = msdos_process_info_get(current_psp);
6730: if(process != NULL) {
6731: process->psp = REG16(BX);
6732: }
6733: current_psp = REG16(BX);
1.1.1.23 root 6734: msdos_sda_update(current_psp);
1.1.1.8 root 6735: }
1.1 root 6736: }
6737:
6738: inline void msdos_int_21h_51h()
6739: {
6740: REG16(BX) = current_psp;
6741: }
6742:
6743: inline void msdos_int_21h_52h()
6744: {
1.1.1.3 root 6745: SREG(ES) = (DOS_INFO_BASE >> 4);
6746: i386_load_segment_descriptor(ES);
1.1 root 6747: REG16(BX) = (DOS_INFO_BASE & 0x0f);
6748: }
6749:
6750: inline void msdos_int_21h_54h()
6751: {
6752: process_t *process = msdos_process_info_get(current_psp);
6753:
6754: REG8(AL) = process->verify;
6755: }
6756:
6757: inline void msdos_int_21h_55h()
6758: {
6759: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
6760:
6761: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
6762: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
6763: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
6764: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
6765: psp->parent_psp = current_psp;
6766: }
6767:
6768: inline void msdos_int_21h_56h(int lfn)
6769: {
6770: char src[MAX_PATH], dst[MAX_PATH];
1.1.1.3 root 6771: strcpy(src, msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn));
6772: strcpy(dst, msdos_trimmed_path((char *)(mem + SREG_BASE(ES) + REG16(DI)), lfn));
1.1 root 6773:
6774: if(rename(src, dst)) {
6775: REG16(AX) = errno;
1.1.1.3 root 6776: m_CF = 1;
1.1 root 6777: }
6778: }
6779:
6780: inline void msdos_int_21h_57h()
6781: {
6782: FILETIME time, local;
1.1.1.14 root 6783: FILETIME *ctime, *atime, *mtime;
1.1.1.21 root 6784: HANDLE hHandle;
1.1 root 6785:
1.1.1.21 root 6786: if((hHandle = (HANDLE)_get_osfhandle(REG16(BX))) == INVALID_HANDLE_VALUE) {
1.1.1.14 root 6787: REG16(AX) = (UINT16)GetLastError();
6788: m_CF = 1;
6789: return;
6790: }
6791: ctime = atime = mtime = NULL;
6792:
1.1 root 6793: switch(REG8(AL)) {
6794: case 0x00:
1.1.1.6 root 6795: case 0x01:
1.1.1.14 root 6796: mtime = &time;
1.1.1.6 root 6797: break;
6798: case 0x04:
6799: case 0x05:
1.1.1.14 root 6800: atime = &time;
1.1 root 6801: break;
1.1.1.6 root 6802: case 0x06:
6803: case 0x07:
1.1.1.14 root 6804: ctime = &time;
6805: break;
6806: default:
1.1.1.22 root 6807: 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 6808: REG16(AX) = 0x01;
6809: m_CF = 1;
6810: return;
6811: }
6812: if(REG8(AL) & 1) {
1.1 root 6813: DosDateTimeToFileTime(REG16(DX), REG16(CX), &local);
6814: LocalFileTimeToFileTime(&local, &time);
1.1.1.21 root 6815: if(!SetFileTime(hHandle, ctime, atime, mtime)) {
1.1 root 6816: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 6817: m_CF = 1;
1.1 root 6818: }
1.1.1.14 root 6819: } else {
1.1.1.21 root 6820: if(!GetFileTime(hHandle, ctime, atime, mtime)) {
1.1.1.14 root 6821: // assume a device and use the current time
6822: GetSystemTimeAsFileTime(&time);
6823: }
6824: FileTimeToLocalFileTime(&time, &local);
6825: FileTimeToDosDateTime(&local, ®16(DX), ®16(CX));
1.1 root 6826: }
6827: }
6828:
6829: inline void msdos_int_21h_58h()
6830: {
6831: switch(REG8(AL)) {
6832: case 0x00:
1.1.1.7 root 6833: REG16(AX) = malloc_strategy;
6834: break;
6835: case 0x01:
1.1.1.24! root 6836: // switch(REG16(BX)) {
! 6837: switch(REG8(BL)) {
1.1.1.7 root 6838: case 0x0000:
6839: case 0x0001:
6840: case 0x0002:
6841: case 0x0040:
6842: case 0x0041:
6843: case 0x0042:
6844: case 0x0080:
6845: case 0x0081:
6846: case 0x0082:
6847: malloc_strategy = REG16(BX);
1.1.1.23 root 6848: msdos_sda_update(current_psp);
1.1.1.7 root 6849: break;
6850: default:
1.1.1.22 root 6851: 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 6852: REG16(AX) = 0x01;
6853: m_CF = 1;
6854: break;
6855: }
6856: break;
6857: case 0x02:
1.1.1.19 root 6858: REG8(AL) = msdos_mem_get_umb_linked() ? 1 : 0;
1.1.1.7 root 6859: break;
6860: case 0x03:
1.1.1.24! root 6861: // switch(REG16(BX)) {
! 6862: switch(REG8(BL)) {
1.1.1.7 root 6863: case 0x0000:
1.1.1.19 root 6864: msdos_mem_unlink_umb();
6865: break;
1.1.1.7 root 6866: case 0x0001:
1.1.1.19 root 6867: msdos_mem_link_umb();
1.1.1.7 root 6868: break;
6869: default:
1.1.1.22 root 6870: 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 6871: REG16(AX) = 0x01;
6872: m_CF = 1;
6873: break;
6874: }
1.1 root 6875: break;
6876: default:
1.1.1.22 root 6877: 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 6878: REG16(AX) = 0x01;
1.1.1.3 root 6879: m_CF = 1;
1.1 root 6880: break;
6881: }
6882: }
6883:
6884: inline void msdos_int_21h_59h()
6885: {
1.1.1.23 root 6886: sda_t *sda = (sda_t *)(mem + SDA_TOP);
6887:
6888: REG16(AX) = sda->extended_error_code;
6889: REG8(BH) = sda->error_class;
6890: REG8(BL) = sda->suggested_action;
6891: REG8(CH) = sda->locus_of_last_error;
1.1 root 6892: }
6893:
6894: inline void msdos_int_21h_5ah()
6895: {
1.1.1.3 root 6896: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 6897: int len = strlen(path);
6898: char tmp[MAX_PATH];
6899:
6900: if(GetTempFileName(path, "TMP", 0, tmp)) {
6901: int fd = _open(tmp, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
6902:
6903: SetFileAttributes(tmp, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
6904: REG16(AX) = fd;
6905: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 6906: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 6907:
6908: strcpy(path, tmp);
6909: int dx = REG16(DX) + len;
1.1.1.3 root 6910: int ds = SREG(DS);
1.1 root 6911: while(dx > 0xffff) {
6912: dx -= 0x10;
6913: ds++;
6914: }
6915: REG16(DX) = dx;
1.1.1.3 root 6916: SREG(DS) = ds;
6917: i386_load_segment_descriptor(DS);
1.1 root 6918: } else {
6919: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 6920: m_CF = 1;
1.1 root 6921: }
6922: }
6923:
6924: inline void msdos_int_21h_5bh()
6925: {
1.1.1.3 root 6926: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 6927:
1.1.1.24! root 6928: if(msdos_is_existing_file(path)) {
1.1 root 6929: // already exists
6930: REG16(AX) = 0x50;
1.1.1.3 root 6931: m_CF = 1;
1.1 root 6932: } else {
6933: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
6934:
6935: if(fd != -1) {
6936: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
6937: REG16(AX) = fd;
6938: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 6939: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 6940: } else {
6941: REG16(AX) = errno;
1.1.1.3 root 6942: m_CF = 1;
1.1 root 6943: }
6944: }
6945: }
6946:
6947: inline void msdos_int_21h_5ch()
6948: {
6949: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 6950: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 6951:
1.1.1.20 root 6952: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 6953: if(REG8(AL) == 0 || REG8(AL) == 1) {
6954: static int modes[2] = {_LK_LOCK, _LK_UNLCK};
1.1.1.20 root 6955: UINT32 pos = _tell(fd);
6956: _lseek(fd, (REG16(CX) << 16) | REG16(DX), SEEK_SET);
6957: if(_locking(fd, modes[REG8(AL)], (REG16(SI) << 16) | REG16(DI))) {
1.1 root 6958: REG16(AX) = errno;
1.1.1.3 root 6959: m_CF = 1;
1.1 root 6960: }
1.1.1.20 root 6961: _lseek(fd, pos, SEEK_SET);
1.1 root 6962: // some seconds may be passed in _locking()
6963: hardware_update();
6964: } else {
6965: REG16(AX) = 0x01;
1.1.1.3 root 6966: m_CF = 1;
1.1 root 6967: }
6968: } else {
6969: REG16(AX) = 0x06;
1.1.1.3 root 6970: m_CF = 1;
1.1 root 6971: }
6972: }
6973:
1.1.1.22 root 6974: inline void msdos_int_21h_5dh()
6975: {
6976: switch(REG8(AL)) {
6977: case 0x06: // get address of dos swappable data area
1.1.1.23 root 6978: SREG(DS) = (SDA_TOP >> 4);
6979: i386_load_segment_descriptor(DS);
6980: REG16(SI) = offsetof(sda_t, crit_error_flag);
6981: REG16(CX) = 0x80;
6982: REG16(DX) = 0x1a;
6983: break;
6984: case 0x0b: // get dos swappable data areas
1.1.1.22 root 6985: REG16(AX) = 0x01;
6986: m_CF = 1;
6987: break;
6988: case 0x08: // set redirected printer mode
6989: case 0x09: // flush redirected printer output
6990: case 0x0a: // set extended error information
6991: break;
6992: default:
6993: 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));
6994: REG16(AX) = 0x01;
6995: m_CF = 1;
6996: break;
6997: }
6998: }
6999:
1.1 root 7000: inline void msdos_int_21h_60h(int lfn)
7001: {
1.1.1.14 root 7002: char full[MAX_PATH], *path;
7003:
1.1 root 7004: if(lfn) {
1.1.1.14 root 7005: char *name;
7006: *full = '\0';
1.1.1.3 root 7007: GetFullPathName((char *)(mem + SREG_BASE(DS) + REG16(SI)), MAX_PATH, full, &name);
1.1.1.14 root 7008: switch(REG8(CL)) {
7009: case 1:
7010: GetShortPathName(full, full, MAX_PATH);
7011: my_strupr(full);
7012: break;
7013: case 2:
7014: GetLongPathName(full, full, MAX_PATH);
7015: break;
7016: }
7017: path = full;
7018: } else {
7019: path = msdos_short_full_path((char *)(mem + SREG_BASE(DS) + REG16(SI)));
7020: }
7021: if(*path != '\0') {
7022: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path);
1.1 root 7023: } else {
1.1.1.14 root 7024: REG16(AX) = (UINT16)GetLastError();
7025: m_CF = 1;
1.1 root 7026: }
7027: }
7028:
7029: inline void msdos_int_21h_61h()
7030: {
7031: REG8(AL) = 0;
7032: }
7033:
7034: inline void msdos_int_21h_62h()
7035: {
7036: REG16(BX) = current_psp;
7037: }
7038:
7039: inline void msdos_int_21h_63h()
7040: {
7041: switch(REG8(AL)) {
7042: case 0x00:
1.1.1.3 root 7043: SREG(DS) = (DBCS_TABLE >> 4);
7044: i386_load_segment_descriptor(DS);
1.1 root 7045: REG16(SI) = (DBCS_TABLE & 0x0f);
7046: REG8(AL) = 0x00;
7047: break;
1.1.1.22 root 7048: case 0x01: // set korean input mode
7049: case 0x02: // get korean input mode
7050: REG8(AL) = 0xff; // not supported
7051: break;
1.1 root 7052: default:
1.1.1.22 root 7053: 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 7054: REG16(AX) = 0x01;
1.1.1.3 root 7055: m_CF = 1;
1.1 root 7056: break;
7057: }
7058: }
7059:
7060: inline void msdos_int_21h_65h()
7061: {
7062: char tmp[0x10000];
7063:
7064: switch(REG8(AL)) {
1.1.1.17 root 7065: case 0x01:
7066: if(REG16(CX) >= 5) {
1.1.1.19 root 7067: UINT8 data[1 + 2 + 2 + 2 + sizeof(country_info_t)];
1.1.1.17 root 7068: if(REG16(CX) > sizeof(data)) // cx = actual transfer size
7069: REG16(CX) = sizeof(data);
7070: ZeroMemory(data, sizeof(data));
7071: data[0] = 0x01;
7072: *(UINT16 *)(data + 1) = REG16(CX) - 3;
1.1.1.19 root 7073: *(UINT16 *)(data + 3) = get_country_info((country_info_t*)(data + 7));
1.1.1.17 root 7074: *(UINT16 *)(data + 5) = active_code_page;
7075: memcpy(mem + SREG_BASE(ES) + REG16(DI), data, REG16(CX));
7076: REG16(AX) = active_code_page;
7077: } else {
7078: REG16(AX) = 1;
7079: m_CF = 1;
7080: }
7081: break;
7082: case 0x02:
7083: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
7084: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (UPPERTABLE_TOP & 0x0f);
7085: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (UPPERTABLE_TOP >> 4);
7086: REG16(AX) = active_code_page;
7087: REG16(CX) = 0x05;
7088: break;
1.1.1.23 root 7089: case 0x03:
7090: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
7091: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (LOWERTABLE_TOP & 0x0f);
7092: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (LOWERTABLE_TOP >> 4);
7093: REG16(AX) = active_code_page;
7094: REG16(CX) = 0x05;
7095: break;
1.1.1.17 root 7096: case 0x04:
7097: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x04;
7098: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_UPPERTABLE_TOP & 0x0f);
7099: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_UPPERTABLE_TOP >> 4);
7100: REG16(AX) = active_code_page;
7101: REG16(CX) = 0x05;
7102: break;
7103: case 0x05:
7104: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x05;
7105: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_TERMINATOR_TOP & 0x0f);
7106: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_TERMINATOR_TOP >> 4);
7107: REG16(AX) = active_code_page;
7108: REG16(CX) = 0x05;
7109: break;
7110: case 0x06:
7111: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x06;
7112: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (COLLATING_TABLE_TOP & 0x0f);
7113: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (COLLATING_TABLE_TOP >> 4);
7114: REG16(AX) = active_code_page;
7115: REG16(CX) = 0x05;
7116: break;
1.1 root 7117: case 0x07:
1.1.1.3 root 7118: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x07;
7119: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (DBCS_TOP & 0x0f);
7120: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (DBCS_TOP >> 4);
1.1.1.17 root 7121: REG16(AX) = active_code_page;
1.1 root 7122: REG16(CX) = 0x05;
7123: break;
7124: case 0x20:
1.1.1.19 root 7125: memset(tmp, 0, sizeof(tmp));
7126: tmp[0] = REG8(DL);
1.1 root 7127: my_strupr(tmp);
7128: REG8(DL) = tmp[0];
7129: break;
7130: case 0x21:
7131: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 7132: memcpy(tmp, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 7133: my_strupr(tmp);
1.1.1.3 root 7134: memcpy(mem + SREG_BASE(DS) + REG16(DX), tmp, REG16(CX));
1.1 root 7135: break;
7136: case 0x22:
1.1.1.3 root 7137: my_strupr((char *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1 root 7138: break;
7139: default:
1.1.1.22 root 7140: 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 7141: REG16(AX) = 0x01;
1.1.1.3 root 7142: m_CF = 1;
1.1 root 7143: break;
7144: }
7145: }
7146:
7147: inline void msdos_int_21h_66h()
7148: {
7149: switch(REG8(AL)) {
7150: case 0x01:
7151: REG16(BX) = active_code_page;
7152: REG16(DX) = system_code_page;
7153: break;
7154: case 0x02:
7155: if(active_code_page == REG16(BX)) {
7156: REG16(AX) = 0xeb41;
7157: } else if(_setmbcp(REG16(BX)) == 0) {
7158: active_code_page = REG16(BX);
1.1.1.17 root 7159: msdos_nls_tables_update();
1.1 root 7160: REG16(AX) = 0xeb41;
7161: } else {
7162: REG16(AX) = 0x25;
1.1.1.3 root 7163: m_CF = 1;
1.1 root 7164: }
7165: break;
7166: default:
1.1.1.22 root 7167: 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 7168: REG16(AX) = 0x01;
1.1.1.3 root 7169: m_CF = 1;
1.1 root 7170: break;
7171: }
7172: }
7173:
7174: inline void msdos_int_21h_67h()
7175: {
7176: process_t *process = msdos_process_info_get(current_psp);
7177:
7178: if(REG16(BX) <= MAX_FILES) {
7179: process->max_files = max(REG16(BX), 20);
7180: } else {
7181: REG16(AX) = 0x08;
1.1.1.3 root 7182: m_CF = 1;
1.1 root 7183: }
7184: }
7185:
7186: inline void msdos_int_21h_68h()
7187: {
7188: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 7189: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 7190:
1.1.1.20 root 7191: if(fd < process->max_files && file_handler[fd].valid) {
7192: // fflush(_fdopen(fd, ""));
1.1 root 7193: } else {
7194: REG16(AX) = 0x06;
1.1.1.3 root 7195: m_CF = 1;
1.1 root 7196: }
7197: }
7198:
7199: inline void msdos_int_21h_69h()
7200: {
1.1.1.3 root 7201: drive_info_t *info = (drive_info_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 7202: char path[] = "A:\\";
7203: char volume_label[MAX_PATH];
7204: DWORD serial_number = 0;
7205: char file_system[MAX_PATH];
7206:
7207: if(REG8(BL) == 0) {
7208: path[0] = 'A' + _getdrive() - 1;
7209: } else {
7210: path[0] = 'A' + REG8(BL) - 1;
7211: }
7212:
7213: switch(REG8(AL)) {
7214: case 0x00:
7215: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
7216: info->info_level = 0;
7217: info->serial_number = serial_number;
7218: memset(info->volume_label, 0x20, 11);
7219: memcpy(info->volume_label, volume_label, min(strlen(volume_label), 11));
7220: memset(info->file_system, 0x20, 8);
7221: memcpy(info->file_system, file_system, min(strlen(file_system), 8));
7222: } else {
7223: REG16(AX) = errno;
1.1.1.3 root 7224: m_CF = 1;
1.1 root 7225: }
7226: break;
7227: case 0x01:
7228: REG16(AX) = 0x03;
1.1.1.3 root 7229: m_CF = 1;
1.1 root 7230: }
7231: }
7232:
7233: inline void msdos_int_21h_6ah()
7234: {
7235: REG8(AH) = 0x68;
7236: msdos_int_21h_68h();
7237: }
7238:
7239: inline void msdos_int_21h_6bh()
7240: {
7241: REG8(AL) = 0;
7242: }
7243:
7244: inline void msdos_int_21h_6ch(int lfn)
7245: {
1.1.1.3 root 7246: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn);
1.1 root 7247: int mode = REG8(BL) & 0x03;
7248:
7249: if(mode < 0x03) {
1.1.1.24! root 7250: if(msdos_is_existing_file(path) || msdos_is_driver_name(path)) {
1.1 root 7251: // file exists
7252: if(REG8(DL) & 1) {
1.1.1.11 root 7253: int fd = -1;
7254: UINT16 info;
1.1 root 7255:
1.1.1.11 root 7256: if(msdos_is_con_path(path)) {
1.1.1.13 root 7257: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 7258: info = 0x80d3;
1.1.1.14 root 7259: } else if(msdos_is_nul_path(path)) {
7260: fd = msdos_open("NUL", file_mode[mode].mode);
7261: info = 0x80d3;
1.1.1.24! root 7262: } else if(msdos_is_driver_name(path)) {
1.1.1.20 root 7263: fd = msdos_open("NUL", file_mode[mode].mode);
7264: info = 0x80d3;
1.1.1.11 root 7265: } else {
1.1.1.13 root 7266: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 7267: info = msdos_drive_number(path);
7268: }
1.1 root 7269: if(fd != -1) {
7270: REG16(AX) = fd;
7271: REG16(CX) = 1;
1.1.1.11 root 7272: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp);
1.1.1.20 root 7273: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 7274: } else {
7275: REG16(AX) = errno;
1.1.1.3 root 7276: m_CF = 1;
1.1 root 7277: }
7278: } else if(REG8(DL) & 2) {
7279: int attr = GetFileAttributes(path);
7280: int fd = -1;
1.1.1.11 root 7281: UINT16 info;
1.1 root 7282:
1.1.1.11 root 7283: if(msdos_is_con_path(path)) {
1.1.1.13 root 7284: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 7285: info = 0x80d3;
1.1.1.14 root 7286: } else if(msdos_is_nul_path(path)) {
7287: fd = msdos_open("NUL", file_mode[mode].mode);
7288: info = 0x80d3;
1.1.1.24! root 7289: } else if(msdos_is_driver_name(path)) {
1.1.1.20 root 7290: fd = msdos_open("NUL", file_mode[mode].mode);
7291: info = 0x80d3;
1.1 root 7292: } else {
7293: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 7294: info = msdos_drive_number(path);
1.1 root 7295: }
7296: if(fd != -1) {
7297: if(attr == -1) {
7298: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
7299: }
7300: SetFileAttributes(path, attr);
7301: REG16(AX) = fd;
7302: REG16(CX) = 3;
1.1.1.11 root 7303: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp);
1.1.1.20 root 7304: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 7305: } else {
7306: REG16(AX) = errno;
1.1.1.3 root 7307: m_CF = 1;
1.1 root 7308: }
7309: } else {
7310: REG16(AX) = 0x50;
1.1.1.3 root 7311: m_CF = 1;
1.1 root 7312: }
7313: } else {
7314: // file not exists
7315: if(REG8(DL) & 0x10) {
7316: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
7317:
7318: if(fd != -1) {
7319: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
7320: REG16(AX) = fd;
7321: REG16(CX) = 2;
7322: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 7323: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 7324: } else {
7325: REG16(AX) = errno;
1.1.1.3 root 7326: m_CF = 1;
1.1 root 7327: }
7328: } else {
7329: REG16(AX) = 0x02;
1.1.1.3 root 7330: m_CF = 1;
1.1 root 7331: }
7332: }
7333: } else {
7334: REG16(AX) = 0x0c;
1.1.1.3 root 7335: m_CF = 1;
1.1 root 7336: }
7337: }
7338:
7339: inline void msdos_int_21h_710dh()
7340: {
7341: // reset drive
7342: }
7343:
1.1.1.17 root 7344: inline void msdos_int_21h_7141h(int lfn)
7345: {
7346: if(REG16(SI) == 0) {
7347: msdos_int_21h_41h(lfn);
7348: return;
7349: }
7350: if(REG16(SI) != 1) {
7351: REG16(AX) = 5;
7352: m_CF = 1;
7353: }
7354: /* wild card and matching attributes... */
7355: char tmp[MAX_PATH * 2];
7356: // copy search pathname (and quick check overrun)
7357: ZeroMemory(tmp, sizeof(tmp));
7358: tmp[MAX_PATH - 1] = '\0';
7359: tmp[MAX_PATH] = 1;
7360: strncpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(DX)), MAX_PATH);
7361:
7362: if(tmp[MAX_PATH - 1] != '\0' || tmp[MAX_PATH] != 1) {
7363: REG16(AX) = 1;
7364: m_CF = 1;
7365: return;
7366: }
7367: for(char *s = tmp; *s; ++s) {
7368: if(*s == '/') {
7369: *s = '\\';
7370: }
7371: }
7372: char *tmp_name = (char *)_mbsrchr((unsigned char *)tmp, '\\');
7373: if(tmp_name) {
7374: ++tmp_name;
7375: } else {
7376: tmp_name = strchr(tmp, ':');
7377: tmp_name = tmp_name ? tmp_name + 1 : tmp;
7378: }
7379:
7380: WIN32_FIND_DATAA fd;
7381: HANDLE fh = FindFirstFileA(tmp, &fd);
7382: if(fh == INVALID_HANDLE_VALUE) {
7383: REG16(AX) = 2;
7384: m_CF = 1;
7385: return;
7386: }
7387: do {
7388: if(msdos_find_file_check_attribute(fd.dwFileAttributes, REG8(CL), REG8(CH)) && msdos_find_file_has_8dot3name(&fd)) {
7389: strcpy(tmp_name, fd.cFileName);
7390: if(remove(msdos_trimmed_path(tmp, lfn))) {
7391: REG16(AX) = 5;
7392: m_CF = 1;
7393: break;
7394: }
7395: }
7396: } while(FindNextFileA(fh, &fd));
7397: if(!m_CF) {
7398: if(GetLastError() != ERROR_NO_MORE_FILES) {
7399: m_CF = 1;
7400: REG16(AX) = 2;
7401: }
7402: }
7403: FindClose(fh);
7404: }
7405:
1.1 root 7406: inline void msdos_int_21h_714eh()
7407: {
7408: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 7409: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
7410: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 7411: WIN32_FIND_DATA fd;
7412:
1.1.1.13 root 7413: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
7414: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
7415: FindClose(dtainfo->find_handle);
7416: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7417: }
7418: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 7419: dtainfo->allowable_mask = REG8(CL);
7420: dtainfo->required_mask = REG8(CH);
7421: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 7422:
1.1.1.14 root 7423: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
7424: dtainfo->allowable_mask &= ~8;
1.1 root 7425: }
1.1.1.14 root 7426: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
7427: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 7428: if(!FindNextFile(dtainfo->find_handle, &fd)) {
7429: FindClose(dtainfo->find_handle);
7430: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7431: break;
7432: }
7433: }
7434: }
1.1.1.13 root 7435: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 7436: find->attrib = fd.dwFileAttributes;
7437: msdos_find_file_conv_local_time(&fd);
7438: if(REG16(SI) == 0) {
7439: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
7440: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
7441: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
7442: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
7443: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
7444: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
7445: } else {
7446: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
7447: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
7448: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
7449: }
7450: find->size_hi = fd.nFileSizeHigh;
7451: find->size_lo = fd.nFileSizeLow;
7452: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 7453: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 7454: REG16(AX) = dtainfo - dtalist + 1;
7455: } else if(dtainfo->allowable_mask & 8) {
1.1 root 7456: // volume label
7457: find->attrib = 8;
7458: find->size_hi = find->size_lo = 0;
7459: strcpy(find->full_name, process->volume_label);
7460: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 7461: dtainfo->allowable_mask &= ~8;
7462: REG16(AX) = dtainfo - dtalist + 1;
1.1 root 7463: } else {
7464: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 7465: m_CF = 1;
1.1 root 7466: }
7467: }
7468:
7469: inline void msdos_int_21h_714fh()
7470: {
7471: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 7472: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 7473: WIN32_FIND_DATA fd;
7474:
1.1.1.14 root 7475: if(REG16(BX) - 1u >= MAX_DTAINFO) {
7476: REG16(AX) = 6;
1.1.1.13 root 7477: m_CF = 1;
7478: return;
7479: }
1.1.1.14 root 7480: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 7481: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
7482: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 7483: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 7484: if(!FindNextFile(dtainfo->find_handle, &fd)) {
7485: FindClose(dtainfo->find_handle);
7486: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7487: break;
7488: }
7489: }
7490: } else {
1.1.1.13 root 7491: FindClose(dtainfo->find_handle);
7492: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7493: }
7494: }
1.1.1.13 root 7495: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 7496: find->attrib = fd.dwFileAttributes;
7497: msdos_find_file_conv_local_time(&fd);
7498: if(REG16(SI) == 0) {
7499: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
7500: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
7501: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
7502: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
7503: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
7504: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
7505: } else {
7506: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
7507: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
7508: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
7509: }
7510: find->size_hi = fd.nFileSizeHigh;
7511: find->size_lo = fd.nFileSizeLow;
7512: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 7513: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 7514: } else if(dtainfo->allowable_mask & 8) {
1.1 root 7515: // volume label
7516: find->attrib = 8;
7517: find->size_hi = find->size_lo = 0;
7518: strcpy(find->full_name, process->volume_label);
7519: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 7520: dtainfo->allowable_mask &= ~8;
1.1 root 7521: } else {
7522: REG16(AX) = 0x12;
1.1.1.3 root 7523: m_CF = 1;
1.1 root 7524: }
7525: }
7526:
7527: inline void msdos_int_21h_71a0h()
7528: {
7529: DWORD max_component_len, file_sys_flag;
7530:
1.1.1.14 root 7531: 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))) {
7532: REG16(BX) = (UINT16)file_sys_flag & (FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_VOLUME_IS_COMPRESSED);
7533: REG16(BX) |= 0x4000; // supports LFN functions
1.1 root 7534: REG16(CX) = (UINT16)max_component_len; // 255
7535: REG16(DX) = (UINT16)max_component_len + 5; // 260
7536: } else {
7537: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 7538: m_CF = 1;
1.1 root 7539: }
7540: }
7541:
7542: inline void msdos_int_21h_71a1h()
7543: {
1.1.1.14 root 7544: if(REG16(BX) - 1u >= MAX_DTAINFO) {
7545: REG16(AX) = 6;
1.1.1.13 root 7546: m_CF = 1;
7547: return;
7548: }
1.1.1.14 root 7549: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 7550: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
7551: FindClose(dtainfo->find_handle);
7552: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7553: }
7554: }
7555:
7556: inline void msdos_int_21h_71a6h()
7557: {
7558: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 7559: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
7560:
1.1.1.3 root 7561: UINT8 *buffer = (UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 7562: struct _stat64 status;
7563: DWORD serial_number = 0;
7564:
1.1.1.20 root 7565: if(fd < process->max_files && file_handler[fd].valid) {
7566: if(_fstat64(fd, &status) == 0) {
7567: if(file_handler[fd].path[1] == ':') {
1.1 root 7568: // NOTE: we need to consider the network file path "\\host\share\"
7569: char volume[] = "A:\\";
1.1.1.20 root 7570: volume[0] = file_handler[fd].path[1];
1.1 root 7571: GetVolumeInformation(volume, NULL, 0, &serial_number, NULL, NULL, NULL, 0);
7572: }
1.1.1.20 root 7573: *(UINT32 *)(buffer + 0x00) = GetFileAttributes(file_handler[fd].path);
1.1 root 7574: *(UINT32 *)(buffer + 0x04) = (UINT32)(status.st_ctime & 0xffffffff);
7575: *(UINT32 *)(buffer + 0x08) = (UINT32)((status.st_ctime >> 32) & 0xffffffff);
7576: *(UINT32 *)(buffer + 0x0c) = (UINT32)(status.st_atime & 0xffffffff);
7577: *(UINT32 *)(buffer + 0x10) = (UINT32)((status.st_atime >> 32) & 0xffffffff);
7578: *(UINT32 *)(buffer + 0x14) = (UINT32)(status.st_mtime & 0xffffffff);
7579: *(UINT32 *)(buffer + 0x18) = (UINT32)((status.st_mtime >> 32) & 0xffffffff);
7580: *(UINT32 *)(buffer + 0x1c) = serial_number;
7581: *(UINT32 *)(buffer + 0x20) = (UINT32)((status.st_size >> 32) & 0xffffffff);
7582: *(UINT32 *)(buffer + 0x24) = (UINT32)(status.st_size & 0xffffffff);
7583: *(UINT32 *)(buffer + 0x28) = status.st_nlink;
1.1.1.14 root 7584: // this is dummy id and it will be changed when it is reopened...
1.1 root 7585: *(UINT32 *)(buffer + 0x2c) = 0;
1.1.1.20 root 7586: *(UINT32 *)(buffer + 0x30) = file_handler[fd].id;
1.1 root 7587: } else {
7588: REG16(AX) = errno;
1.1.1.3 root 7589: m_CF = 1;
1.1 root 7590: }
7591: } else {
7592: REG16(AX) = 0x06;
1.1.1.3 root 7593: m_CF = 1;
1.1 root 7594: }
7595: }
7596:
7597: inline void msdos_int_21h_71a7h()
7598: {
7599: switch(REG8(BL)) {
7600: case 0x00:
1.1.1.3 root 7601: if(!FileTimeToDosDateTime((FILETIME *)(mem + SREG_BASE(DS) + REG16(SI)), ®16(DX), ®16(CX))) {
1.1 root 7602: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 7603: m_CF = 1;
1.1 root 7604: }
7605: break;
7606: case 0x01:
7607: // NOTE: we need to check BH that shows 10-millisecond untils past time in CX
1.1.1.3 root 7608: if(!DosDateTimeToFileTime(REG16(DX), REG16(CX), (FILETIME *)(mem + SREG_BASE(ES) + REG16(DI)))) {
1.1 root 7609: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 7610: m_CF = 1;
1.1 root 7611: }
7612: break;
7613: default:
1.1.1.22 root 7614: 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 7615: REG16(AX) = 0x01;
1.1.1.3 root 7616: m_CF = 1;
1.1 root 7617: break;
7618: }
7619: }
7620:
7621: inline void msdos_int_21h_71a8h()
7622: {
7623: if(REG8(DH) == 0) {
7624: char tmp[MAX_PATH], fcb[MAX_PATH];
1.1.1.3 root 7625: strcpy(tmp, msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 7626: memset(fcb, 0x20, sizeof(fcb));
7627: int len = strlen(tmp);
1.1.1.21 root 7628: for(int i = 0, pos = 0; i < len; i++) {
1.1 root 7629: if(tmp[i] == '.') {
7630: pos = 8;
7631: } else {
7632: if(msdos_lead_byte_check(tmp[i])) {
7633: fcb[pos++] = tmp[i++];
7634: }
7635: fcb[pos++] = tmp[i];
7636: }
7637: }
1.1.1.3 root 7638: memcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), fcb, 11);
1.1 root 7639: } else {
1.1.1.3 root 7640: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 7641: }
7642: }
7643:
1.1.1.22 root 7644: inline void msdos_int_21h_71aah()
7645: {
7646: char drv[] = "A:", path[MAX_PATH];
7647: char *hoge=(char *)(mem + SREG_BASE(DS) + REG16(DX));
7648:
7649: if(REG8(BL) == 0) {
7650: drv[0] = 'A' + _getdrive() - 1;
7651: } else {
7652: drv[0] = 'A' + REG8(BL) - 1;
7653: }
7654: switch(REG8(BH)) {
7655: case 0x00:
7656: if(DefineDosDevice(0, drv, (char *)(mem + SREG_BASE(DS) + REG16(DX))) == 0) {
7657: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
7658: if(GetLogicalDrives() & bits) {
7659: REG16(AX) = 0x0f; // invalid drive
7660: } else {
7661: REG16(AX) = 0x03; // path not found
7662: }
7663: m_CF = 1;
7664: }
7665: break;
7666: case 0x01:
7667: if(DefineDosDevice(DDD_REMOVE_DEFINITION, drv, NULL) == 0) {
7668: REG16(AX) = 0x0f; // invalid drive
7669: m_CF = 1;
7670: }
7671: break;
7672: case 0x02:
7673: if(QueryDosDevice(drv, path, MAX_PATH) == 0) {
7674: REG16(AX) = 0x0f; // invalid drive
7675: m_CF = 1;
7676: } else if(strncmp(path, "\\??\\", 4) != 0) {
7677: REG16(AX) = 0x0f; // invalid drive
7678: m_CF = 1;
7679: } else {
7680: strcpy((char *)(mem + SREG_BASE(DS) + REG16(DX)), path + 4);
7681: }
7682: break;
7683: default:
7684: 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));
7685: REG16(AX) = 0x01;
7686: m_CF = 1;
7687: break;
7688: }
7689: }
7690:
1.1.1.14 root 7691: inline void msdos_int_21h_7300h()
7692: {
7693: if(REG8(AL) == 0) {
7694: REG8(AL) = REG8(CL);
7695: REG8(AH) = 0;
7696: } else {
7697: REG16(AX) = 0x01;
7698: m_CF = 1;
7699: }
7700: }
7701:
7702: inline void msdos_int_21h_7302h()
7703: {
7704: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
7705: UINT16 seg, ofs;
7706:
7707: if(REG16(CX) < 0x3f) {
7708: REG8(AL) = 0x18;
7709: m_CF = 1;
7710: } else if(!msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
7711: REG8(AL) = 0xff;
7712: m_CF = 1;
7713: } else {
7714: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 2, mem + (seg << 4) + ofs, sizeof(dpb_t));
7715: }
7716: }
7717:
1.1 root 7718: inline void msdos_int_21h_7303h()
7719: {
1.1.1.3 root 7720: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
7721: ext_space_info_t *info = (ext_space_info_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 7722: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
7723:
7724: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
7725: info->size_of_structure = sizeof(ext_space_info_t);
7726: info->structure_version = 0;
7727: info->sectors_per_cluster = sectors_per_cluster;
7728: info->bytes_per_sector = bytes_per_sector;
7729: info->available_clusters_on_drive = free_clusters;
7730: info->total_clusters_on_drive = total_clusters;
7731: info->available_sectors_on_drive = sectors_per_cluster * free_clusters;
7732: info->total_sectors_on_drive = sectors_per_cluster * total_clusters;
7733: info->available_allocation_units = free_clusters; // ???
7734: info->total_allocation_units = total_clusters; // ???
7735: } else {
7736: REG16(AX) = errno;
1.1.1.3 root 7737: m_CF = 1;
1.1 root 7738: }
7739: }
7740:
7741: inline void msdos_int_25h()
7742: {
7743: UINT16 seg, ofs;
7744: DWORD dwSize;
7745:
1.1.1.3 root 7746: #if defined(HAS_I386)
7747: I386OP(pushf)();
7748: #else
7749: PREFIX86(_pushf());
7750: #endif
1.1 root 7751:
7752: if(!(REG8(AL) < 26)) {
7753: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 7754: m_CF = 1;
1.1 root 7755: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
7756: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 7757: m_CF = 1;
1.1 root 7758: } else {
7759: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
7760: char dev[64];
7761: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
7762:
7763: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
7764: if(hFile == INVALID_HANDLE_VALUE) {
7765: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 7766: m_CF = 1;
1.1 root 7767: } else {
1.1.1.19 root 7768: UINT32 top_sector = REG16(DX);
7769: UINT16 sector_num = REG16(CX);
7770: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
7771:
7772: if(sector_num == 0xffff) {
7773: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
7774: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
7775: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
7776: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
7777: buffer_addr = (seg << 4) + ofs;
7778: }
7779: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
7780: // REG8(AL) = 0x02; // drive not ready
7781: // m_CF = 1;
7782: // } else
7783: if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 7784: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 7785: m_CF = 1;
1.1.1.19 root 7786: } else if(ReadFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 7787: REG8(AL) = 0x0b; // read error
1.1.1.3 root 7788: m_CF = 1;
1.1 root 7789: }
7790: CloseHandle(hFile);
7791: }
7792: }
7793: }
7794:
7795: inline void msdos_int_26h()
7796: {
7797: // this operation may cause serious damage for drives, so always returns error...
7798: UINT16 seg, ofs;
7799: DWORD dwSize;
7800:
1.1.1.3 root 7801: #if defined(HAS_I386)
7802: I386OP(pushf)();
7803: #else
7804: PREFIX86(_pushf());
7805: #endif
1.1 root 7806:
7807: if(!(REG8(AL) < 26)) {
7808: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 7809: m_CF = 1;
1.1 root 7810: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
7811: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 7812: m_CF = 1;
1.1 root 7813: } else {
7814: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
7815: char dev[64];
7816: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
7817:
7818: if(dpb->media_type == 0xf8) {
7819: // this drive is not a floppy
1.1.1.6 root 7820: // if(!(((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag & 0x40)) {
7821: // fatalerror("This application tried the absolute disk write to drive %c:\n", 'A' + REG8(AL));
7822: // }
1.1 root 7823: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 7824: m_CF = 1;
1.1 root 7825: } else {
7826: HANDLE hFile = CreateFile(dev, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
7827: if(hFile == INVALID_HANDLE_VALUE) {
7828: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 7829: m_CF = 1;
1.1 root 7830: } else {
1.1.1.19 root 7831: UINT32 top_sector = REG16(DX);
7832: UINT16 sector_num = REG16(CX);
7833: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
7834:
7835: if(sector_num == 0xffff) {
7836: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
7837: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
7838: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
7839: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
7840: buffer_addr = (seg << 4) + ofs;
7841: }
1.1 root 7842: if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
7843: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 7844: m_CF = 1;
1.1.1.19 root 7845: } else if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 7846: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 7847: m_CF = 1;
1.1.1.19 root 7848: } else if(WriteFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 7849: REG8(AL) = 0x0a; // write error
1.1.1.3 root 7850: m_CF = 1;
1.1 root 7851: }
7852: CloseHandle(hFile);
7853: }
7854: }
7855: }
7856: }
7857:
7858: inline void msdos_int_27h()
7859: {
1.1.1.14 root 7860: msdos_mem_realloc(SREG(CS), (REG16(DX) + 15) >> 4, NULL);
1.1.1.3 root 7861: msdos_process_terminate(SREG(CS), retval | 0x300, 0);
1.1.1.14 root 7862:
7863: // int_21h_4bh succeeded
7864: m_CF = 0;
1.1 root 7865: }
7866:
7867: inline void msdos_int_29h()
7868: {
1.1.1.14 root 7869: #if 1
7870: // need to check escape sequences
1.1 root 7871: msdos_putch(REG8(AL));
1.1.1.14 root 7872: #else
7873: DWORD num;
7874: vram_flush();
1.1.1.23 root 7875: WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ®8(AL), 1, &num, NULL);
1.1.1.14 root 7876: cursor_moved = true;
7877: #endif
1.1 root 7878: }
7879:
7880: inline void msdos_int_2eh()
7881: {
7882: char tmp[MAX_PATH], command[MAX_PATH], opt[MAX_PATH];
7883: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 7884: strcpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(SI)));
1.1 root 7885: char *token = my_strtok(tmp, " ");
7886: strcpy(command, token);
7887: strcpy(opt, token + strlen(token) + 1);
7888:
7889: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
7890: param->env_seg = 0;
7891: param->cmd_line.w.l = 44;
7892: param->cmd_line.w.h = (WORK_TOP >> 4);
7893: param->fcb1.w.l = 24;
7894: param->fcb1.w.h = (WORK_TOP >> 4);
7895: param->fcb2.w.l = 24;
7896: param->fcb2.w.h = (WORK_TOP >> 4);
7897:
7898: memset(mem + WORK_TOP + 24, 0x20, 20);
7899:
7900: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
7901: cmd_line->len = strlen(opt);
7902: strcpy(cmd_line->cmd, opt);
7903: cmd_line->cmd[cmd_line->len] = 0x0d;
7904:
7905: msdos_process_exec(command, param, 0);
7906: REG8(AL) = 0;
7907: }
7908:
1.1.1.22 root 7909: inline void msdos_int_2fh_01h()
7910: {
7911: switch(REG8(AL)) {
7912: case 0x00:
7913: REG8(AL) = 0x01; // print.com is not installed, can't install
7914: break;
7915: default:
7916: 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));
7917: REG16(AX) = 0x01;
7918: m_CF = 1;
7919: break;
7920: }
7921: }
7922:
7923: inline void msdos_int_2fh_05h()
7924: {
7925: switch(REG8(AL)) {
7926: case 0x00:
7927: REG8(AL) = 0x01; // critical error handler is not installed, can't install
7928: break;
7929: default:
7930: 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));
7931: REG16(AX) = 0x01;
7932: m_CF = 1;
7933: break;
7934: }
7935: }
7936:
7937: inline void msdos_int_2fh_06h()
7938: {
7939: switch(REG8(AL)) {
7940: case 0x00:
7941: REG8(AL) = 0x01; // assign is not installed, can't install
7942: break;
7943: default:
7944: 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));
7945: REG16(AX) = 0x01;
7946: m_CF = 1;
7947: break;
7948: }
7949: }
7950:
7951: inline void msdos_int_2fh_08h()
7952: {
7953: switch(REG8(AL)) {
7954: case 0x00:
7955: REG8(AL) = 0x01; // driver.sys is not installed, can't install
7956: break;
7957: default:
7958: 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));
7959: REG16(AX) = 0x01;
7960: m_CF = 1;
7961: break;
7962: }
7963: }
7964:
7965: inline void msdos_int_2fh_10h()
7966: {
7967: switch(REG8(AL)) {
7968: case 0x00:
7969: REG8(AL) = 0x01; // share is not installed, can't install
7970: break;
7971: default:
7972: 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));
7973: REG16(AX) = 0x01;
7974: m_CF = 1;
7975: break;
7976: }
7977: }
7978:
7979: inline void msdos_int_2fh_11h()
7980: {
7981: switch(REG8(AL)) {
7982: case 0x00:
7983: REG8(AL) = 0x01; // mscdex is not installed, can't install
7984: break;
7985: default:
7986: 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));
7987: REG16(AX) = 0x01;
7988: m_CF = 1;
7989: break;
7990: }
7991: }
7992:
1.1.1.21 root 7993: inline void msdos_int_2fh_12h()
7994: {
7995: switch(REG8(AL)) {
1.1.1.22 root 7996: case 0x00:
7997: REG8(AL) = 0xff;
7998: break;
1.1.1.21 root 7999: case 0x16:
8000: if(REG16(BX) < 20) {
8001: SREG(ES) = SFT_TOP >> 4;
8002: i386_load_segment_descriptor(ES);
8003: REG16(DI) = 6 + 0x3b * REG16(BX);
8004:
8005: // update system file table
8006: UINT8* sft = mem + SFT_TOP + 6 + 0x3b * REG16(BX);
8007: if(file_handler[REG16(BX)].valid) {
8008: int count = 0;
8009: for(int i = 0; i < 20; i++) {
8010: if(msdos_psp_get_file_table(i, current_psp) == REG16(BX)) {
8011: count++;
8012: }
8013: }
8014: *(UINT16 *)(sft + 0x00) = count ? count : 0xffff;
8015: *(UINT32 *)(sft + 0x15) = _tell(REG16(BX));
8016: _lseek(REG16(BX), 0, SEEK_END);
8017: *(UINT32 *)(sft + 0x11) = _tell(REG16(BX));
8018: _lseek(REG16(BX), *(UINT32 *)(sft + 0x15), SEEK_SET);
8019: } else {
8020: memset(sft, 0, 0x3b);
8021: }
8022: } else {
8023: REG16(AX) = 0x06;
8024: m_CF = 1;
8025: }
8026: break;
8027: case 0x20:
8028: {
8029: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
8030:
8031: if(fd < 20) {
8032: SREG(ES) = current_psp;
8033: i386_load_segment_descriptor(ES);
8034: REG16(DI) = offsetof(psp_t, file_table) + fd;
8035: } else {
8036: REG16(AX) = 0x06;
8037: m_CF = 1;
8038: }
8039: }
8040: break;
1.1.1.22 root 8041: case 0x2e:
8042: if(REG8(DL) == 0x00 || REG8(DL) == 0x02 || REG8(DL) == 0x04 || REG8(DL) == 0x06) {
8043: SREG(ES) = ERR_TABLE_TOP >> 4;
8044: i386_load_segment_descriptor(ES);
8045: REG16(DI) = 0;
8046: }
8047: break;
8048: default:
8049: 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));
8050: REG16(AX) = 0x01;
8051: m_CF = 1;
8052: break;
8053: }
8054: }
8055:
8056: inline void msdos_int_2fh_14h()
8057: {
8058: switch(REG8(AL)) {
8059: case 0x00:
8060: REG8(AL) = 0x01; // nlsfunc.com is not installed, can't install
8061: break;
8062: default:
8063: 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));
8064: REG16(AX) = 0x01;
8065: m_CF = 1;
8066: break;
8067: }
8068: }
8069:
8070: inline void msdos_int_2fh_15h()
8071: {
8072: switch(REG8(AL)) {
8073: case 0x00:
8074: // function not supported, do not clear AX
8075: break;
8076: case 0x0b:
8077: // mscdex.exe is not installed
8078: break;
8079: case 0xff:
8080: // corelcdx is not installed
8081: break;
1.1.1.21 root 8082: default:
1.1.1.22 root 8083: 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 8084: REG16(AX) = 0x01;
8085: m_CF = 1;
8086: break;
8087: }
8088: }
8089:
1.1 root 8090: inline void msdos_int_2fh_16h()
8091: {
8092: switch(REG8(AL)) {
8093: case 0x00:
1.1.1.14 root 8094: if(no_windows) {
8095: REG8(AL) = 0;
8096: } else {
1.1 root 8097: OSVERSIONINFO osvi;
8098: ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
8099: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
8100: GetVersionEx(&osvi);
8101: REG8(AL) = osvi.dwMajorVersion;
8102: REG8(AH) = osvi.dwMinorVersion;
8103: }
8104: break;
1.1.1.22 root 8105: case 0x0a:
8106: if(!no_windows) {
8107: OSVERSIONINFO osvi;
8108: ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
8109: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
8110: GetVersionEx(&osvi);
8111: REG16(AX) = 0x0000;
8112: REG8(BH) = osvi.dwMajorVersion;
8113: REG8(BL) = osvi.dwMinorVersion;
8114: REG16(CX) = 0x0003; // enhanced
8115: }
8116: break;
8117: case 0x0e:
8118: case 0x0f:
8119: case 0x11:
8120: case 0x12:
8121: case 0x13:
8122: case 0x14:
8123: case 0x87:
8124: // function not supported, do not clear AX
8125: break;
1.1.1.14 root 8126: case 0x80:
8127: Sleep(10);
8128: hardware_update();
8129: REG8(AL) = 0;
8130: break;
1.1.1.22 root 8131: case 0x8e:
8132: REG16(AX) = 0x00; // failed
8133: break;
1.1.1.20 root 8134: case 0x8f:
8135: switch(REG8(DH)) {
8136: case 0x00:
8137: case 0x02:
8138: case 0x03:
8139: REG16(AX) = 0x00;
8140: break;
8141: case 0x01:
8142: REG16(AX) = 0x168f;
8143: break;
8144: }
8145: break;
1.1 root 8146: default:
1.1.1.22 root 8147: 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));
8148: REG16(AX) = 0x01;
8149: m_CF = 1;
8150: break;
8151: }
8152: }
8153:
8154: inline void msdos_int_2fh_19h()
8155: {
8156: switch(REG8(AL)) {
8157: case 0x00:
8158: // shellb.com is not installed
8159: REG8(AL) = 0x00;
8160: break;
8161: case 0x01:
8162: case 0x02:
8163: case 0x03:
8164: case 0x04:
8165: REG16(AX) = 0x01;
8166: m_CF = 1;
8167: break;
8168: default:
8169: 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 8170: REG16(AX) = 0x01;
1.1.1.3 root 8171: m_CF = 1;
1.1 root 8172: break;
8173: }
8174: }
8175:
8176: inline void msdos_int_2fh_1ah()
8177: {
8178: switch(REG8(AL)) {
8179: case 0x00:
8180: // ansi.sys is installed
8181: REG8(AL) = 0xff;
8182: break;
8183: default:
1.1.1.22 root 8184: 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));
8185: REG16(AX) = 0x01;
8186: m_CF = 1;
8187: break;
8188: }
8189: }
8190:
8191: inline void msdos_int_2fh_1bh()
8192: {
8193: switch(REG8(AL)) {
8194: case 0x00:
8195: // xma2ems.sys is not installed
8196: REG8(AL) = 0x00;
8197: break;
8198: default:
8199: 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 8200: REG16(AX) = 0x01;
1.1.1.3 root 8201: m_CF = 1;
1.1 root 8202: break;
8203: }
8204: }
8205:
8206: inline void msdos_int_2fh_43h()
8207: {
8208: switch(REG8(AL)) {
8209: case 0x00:
1.1.1.19 root 8210: // xms is installed ?
8211: #ifdef SUPPORT_XMS
8212: if(support_xms) {
8213: REG8(AL) = 0x80;
8214: } else
8215: #endif
8216: REG8(AL) = 0x00;
8217: break;
8218: case 0x10:
8219: REG16(BX) = XMS_OFFSET;
8220: SREG(ES) = XMS_TOP >> 4;
8221: i386_load_segment_descriptor(ES);
1.1 root 8222: break;
8223: default:
1.1.1.22 root 8224: 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));
8225: REG16(AX) = 0x01;
8226: m_CF = 1;
8227: break;
8228: }
8229: }
8230:
8231: inline void msdos_int_2fh_46h()
8232: {
8233: switch(REG8(AL)) {
8234: case 0x80:
8235: // windows v3.0 is not installed
8236: break;
8237: default:
8238: 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));
8239: REG16(AX) = 0x01;
8240: m_CF = 1;
8241: break;
8242: }
8243: }
8244:
8245: inline void msdos_int_2fh_48h()
8246: {
8247: switch(REG8(AL)) {
8248: case 0x00:
8249: // doskey is not installed
8250: break;
8251: case 0x10:
8252: msdos_int_21h_0ah();
8253: REG16(AX) = 0x00;
8254: break;
8255: default:
8256: 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 8257: REG16(AX) = 0x01;
1.1.1.3 root 8258: m_CF = 1;
1.1 root 8259: break;
8260: }
8261: }
8262:
8263: inline void msdos_int_2fh_4ah()
8264: {
1.1.1.19 root 8265: // hma is not installed
1.1 root 8266: switch(REG8(AL)) {
8267: case 0x01:
8268: case 0x02:
1.1.1.19 root 8269: // hma is not used
1.1 root 8270: REG16(BX) = 0;
1.1.1.3 root 8271: SREG(ES) = 0xffff;
8272: i386_load_segment_descriptor(ES);
1.1 root 8273: REG16(DI) = 0xffff;
8274: break;
1.1.1.19 root 8275: case 0x03:
8276: // unable to allocate
8277: REG16(DI) = 0xffff;
8278: break;
8279: case 0x04:
8280: // function not supported, do not clear AX
8281: break;
1.1.1.22 root 8282: case 0x10: // smartdrv installation check
8283: case 0x11: // dblspace installation check
8284: break;
8285: default:
8286: 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));
8287: REG16(AX) = 0x01;
8288: m_CF = 1;
8289: break;
8290: }
8291: }
8292:
8293: inline void msdos_int_2fh_4bh()
8294: {
8295: switch(REG8(AL)) {
1.1.1.24! root 8296: case 0x01:
1.1.1.22 root 8297: case 0x02:
1.1.1.24! root 8298: // task switcher not loaded
! 8299: break;
! 8300: case 0x03:
! 8301: // this call is available from within DOSSHELL even if the task switcher is not installed
! 8302: REG16(AX) = REG16(BX) = 0x0000; // no more avaiable switcher id
1.1.1.22 root 8303: break;
1.1 root 8304: default:
1.1.1.22 root 8305: 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 8306: REG16(AX) = 0x01;
1.1.1.3 root 8307: m_CF = 1;
1.1 root 8308: break;
8309: }
8310: }
8311:
8312: inline void msdos_int_2fh_4fh()
8313: {
8314: switch(REG8(AL)) {
8315: case 0x00:
8316: REG16(AX) = 0;
8317: REG8(DL) = 1; // major version
8318: REG8(DH) = 0; // minor version
8319: break;
8320: case 0x01:
8321: REG16(AX) = 0;
8322: REG16(BX) = active_code_page;
8323: break;
8324: default:
1.1.1.22 root 8325: 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));
8326: REG16(AX) = 0x01;
8327: m_CF = 1;
8328: break;
8329: }
8330: }
8331:
8332: inline void msdos_int_2fh_55h()
8333: {
8334: switch(REG8(AL)) {
8335: case 0x00:
8336: case 0x01:
8337: // 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));
8338: break;
8339: default:
8340: 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 8341: REG16(AX) = 0x01;
1.1.1.3 root 8342: m_CF = 1;
1.1 root 8343: break;
8344: }
8345: }
8346:
1.1.1.24! root 8347: inline void msdos_int_2fh_adh()
! 8348: {
! 8349: switch(REG8(AL)) {
! 8350: case 0x00:
! 8351: // display.sys is installed
! 8352: REG8(AL) = 0xff;
! 8353: REG16(BX) = 0x100; // ???
! 8354: break;
! 8355: case 0x01:
! 8356: active_code_page = REG16(BX);
! 8357: msdos_nls_tables_update();
! 8358: REG16(AX) = 0x01;
! 8359: break;
! 8360: case 0x02:
! 8361: REG16(BX) = active_code_page;
! 8362: break;
! 8363: case 0x03:
! 8364: // FIXME
! 8365: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 1;
! 8366: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2) = 3;
! 8367: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4) = 1;
! 8368: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 6) = active_code_page;
! 8369: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 8) = active_code_page;
! 8370: break;
! 8371: case 0x80:
! 8372: break; // keyb.com is not installed
! 8373: default:
! 8374: 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));
! 8375: REG16(AX) = 0x01;
! 8376: m_CF = 1;
! 8377: break;
! 8378: }
! 8379: }
! 8380:
1.1 root 8381: inline void msdos_int_2fh_aeh()
8382: {
8383: switch(REG8(AL)) {
8384: case 0x00:
8385: REG8(AL) = 0;
8386: break;
8387: case 0x01:
8388: {
8389: char command[MAX_PATH];
8390: memset(command, 0, sizeof(command));
1.1.1.3 root 8391: memcpy(command, mem + SREG_BASE(DS) + REG16(SI) + 1, mem[SREG_BASE(DS) + REG16(SI)]);
1.1 root 8392:
8393: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
8394: param->env_seg = 0;
8395: param->cmd_line.w.l = 44;
8396: param->cmd_line.w.h = (WORK_TOP >> 4);
8397: param->fcb1.w.l = 24;
8398: param->fcb1.w.h = (WORK_TOP >> 4);
8399: param->fcb2.w.l = 24;
8400: param->fcb2.w.h = (WORK_TOP >> 4);
8401:
8402: memset(mem + WORK_TOP + 24, 0x20, 20);
8403:
8404: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
1.1.1.3 root 8405: cmd_line->len = mem[SREG_BASE(DS) + REG16(BX) + 1];
8406: memcpy(cmd_line->cmd, mem + SREG_BASE(DS) + REG16(BX) + 2, cmd_line->len);
1.1 root 8407: cmd_line->cmd[cmd_line->len] = 0x0d;
8408:
8409: if(msdos_process_exec(command, param, 0)) {
8410: REG16(AX) = 0x02;
1.1.1.3 root 8411: m_CF = 1;
1.1 root 8412: }
8413: }
8414: break;
8415: default:
1.1.1.22 root 8416: 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 8417: REG16(AX) = 0x01;
1.1.1.3 root 8418: m_CF = 1;
1.1 root 8419: break;
8420: }
8421: }
8422:
8423: inline void msdos_int_2fh_b7h()
8424: {
8425: switch(REG8(AL)) {
8426: case 0x00:
8427: // append is not installed
8428: REG8(AL) = 0;
8429: break;
1.1.1.22 root 8430: case 0x07:
8431: case 0x11:
8432: break;
1.1 root 8433: default:
1.1.1.22 root 8434: 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 8435: REG16(AX) = 0x01;
1.1.1.3 root 8436: m_CF = 1;
1.1 root 8437: break;
8438: }
8439: }
8440:
1.1.1.24! root 8441: inline void msdos_int_33h_0000h()
! 8442: {
! 8443: REG16(AX) = 0xffff; // hardware/driver installed
! 8444: REG16(BX) = MAX_MOUSE_BUTTONS;
! 8445: }
! 8446:
! 8447: inline void msdos_int_33h_0001h()
! 8448: {
! 8449: if(!mouse.active) {
! 8450: if(!(dwConsoleMode & ENABLE_MOUSE_INPUT)) {
! 8451: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode | ENABLE_MOUSE_INPUT);
! 8452: }
! 8453: mouse.active = true;
! 8454: pic[1].imr &= ~0x10; // enable irq12
! 8455: }
! 8456: }
! 8457:
! 8458: inline void msdos_int_33h_0002h()
! 8459: {
! 8460: if(mouse.active) {
! 8461: if(!(dwConsoleMode & ENABLE_MOUSE_INPUT)) {
! 8462: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode);
! 8463: }
! 8464: mouse.active = false;
! 8465: pic[1].imr |= 0x10; // disable irq12
! 8466: }
! 8467: }
! 8468:
! 8469: inline void msdos_int_33h_0003h()
! 8470: {
! 8471: REG16(BX) = mouse.get_buttons();
! 8472: REG16(CX) = max(mouse.min_position.x, min(mouse.max_position.x, mouse.position.x));
! 8473: REG16(DX) = max(mouse.min_position.y, min(mouse.max_position.y, mouse.position.y));
! 8474: }
! 8475:
! 8476: inline void msdos_int_33h_0005h()
! 8477: {
! 8478: if(REG16(BX) < MAX_MOUSE_BUTTONS) {
! 8479: int idx = REG16(BX);
! 8480: REG16(BX) = mouse.buttons[idx].pressed_times;
! 8481: REG16(CX) = max(mouse.min_position.x, min(mouse.max_position.x, mouse.buttons[idx].pressed_position.x));
! 8482: REG16(DX) = max(mouse.min_position.y, min(mouse.max_position.y, mouse.buttons[idx].pressed_position.y));
! 8483: mouse.buttons[idx].pressed_times = 0;
! 8484: } else {
! 8485: REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
! 8486: }
! 8487: REG16(AX) = mouse.get_buttons();
! 8488: }
! 8489:
! 8490: inline void msdos_int_33h_0006h()
! 8491: {
! 8492: if(REG16(BX) < MAX_MOUSE_BUTTONS) {
! 8493: int idx = REG16(BX);
! 8494: REG16(BX) = mouse.buttons[idx].released_times;
! 8495: REG16(CX) = max(mouse.min_position.x, min(mouse.max_position.x, mouse.buttons[idx].released_position.x));
! 8496: REG16(DX) = max(mouse.min_position.y, min(mouse.max_position.y, mouse.buttons[idx].released_position.y));
! 8497: mouse.buttons[idx].released_times = 0;
! 8498: } else {
! 8499: REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
! 8500: }
! 8501: REG16(AX) = mouse.get_buttons();
! 8502: }
! 8503:
! 8504: inline void msdos_int_33h_0007h()
! 8505: {
! 8506: mouse.min_position.x = min(REG16(CX), REG16(DX));
! 8507: mouse.max_position.x = max(REG16(CX), REG16(DX));
! 8508: }
! 8509:
! 8510: inline void msdos_int_33h_0008h()
! 8511: {
! 8512: mouse.min_position.y = min(REG16(CX), REG16(DX));
! 8513: mouse.max_position.y = max(REG16(CX), REG16(DX));
! 8514: }
! 8515:
! 8516: inline void msdos_int_33h_0009h()
! 8517: {
! 8518: mouse.hot_spot[0] = REG16(BX);
! 8519: mouse.hot_spot[1] = REG16(CX);
! 8520: }
! 8521:
! 8522: inline void msdos_int_33h_000bh()
! 8523: {
! 8524: int dx = (mouse.position.x - mouse.prev_position.x) * mouse.mickey.x / 8;
! 8525: int dy = (mouse.position.y - mouse.prev_position.y) * mouse.mickey.y / 8;
! 8526: mouse.prev_position.x = mouse.position.x;
! 8527: mouse.prev_position.y = mouse.position.y;
! 8528: REG16(CX) = dx;
! 8529: REG16(DX) = dy;
! 8530: }
! 8531:
! 8532: inline void msdos_int_33h_000ch()
! 8533: {
! 8534: mouse.call_mask = REG16(CX);
! 8535: mouse.call_addr.w.l = REG16(DX);
! 8536: mouse.call_addr.w.h = SREG(ES);
! 8537: }
! 8538:
! 8539: inline void msdos_int_33h_000fh()
! 8540: {
! 8541: mouse.mickey.x = REG16(CX);
! 8542: mouse.mickey.y = REG16(DX);
! 8543: }
! 8544:
! 8545: inline void msdos_int_33h_0011h()
! 8546: {
! 8547: REG16(AX) = 0xffff;
! 8548: REG16(BX) = MAX_MOUSE_BUTTONS;
! 8549: }
! 8550:
! 8551: inline void msdos_int_33h_0014h()
! 8552: {
! 8553: UINT16 old_mask = mouse.call_mask;
! 8554: UINT16 old_ofs = mouse.call_addr.w.l;
! 8555: UINT16 old_seg = mouse.call_addr.w.h;
! 8556:
! 8557: mouse.call_mask = REG16(CX);
! 8558: mouse.call_addr.w.l = REG16(DX);
! 8559: mouse.call_addr.w.h = SREG(ES);
! 8560:
! 8561: REG16(CX) = old_mask;
! 8562: REG16(DX) = old_ofs;
! 8563: SREG(ES) = old_seg;
! 8564: i386_load_segment_descriptor(ES);
! 8565: }
! 8566:
! 8567: inline void msdos_int_33h_0015h()
! 8568: {
! 8569: REG16(BX) = sizeof(mouse);
! 8570: }
! 8571:
! 8572: inline void msdos_int_33h_0016h()
! 8573: {
! 8574: memcpy(mem + SREG_BASE(ES) + REG16(DX), &mouse, sizeof(mouse));
! 8575: }
! 8576:
! 8577: inline void msdos_int_33h_0017h()
! 8578: {
! 8579: memcpy(&mouse, mem + SREG_BASE(ES) + REG16(DX), sizeof(mouse));
! 8580: }
! 8581:
! 8582: inline void msdos_int_33h_001ah()
! 8583: {
! 8584: mouse.sensitivity[0] = REG16(BX);
! 8585: mouse.sensitivity[1] = REG16(CX);
! 8586: mouse.sensitivity[2] = REG16(DX);
! 8587: }
! 8588:
! 8589: inline void msdos_int_33h_001bh()
! 8590: {
! 8591: REG16(BX) = mouse.sensitivity[0];
! 8592: REG16(CX) = mouse.sensitivity[1];
! 8593: REG16(DX) = mouse.sensitivity[2];
! 8594: }
! 8595:
! 8596: inline void msdos_int_33h_001dh()
! 8597: {
! 8598: mouse.display_page = REG16(BX);
! 8599: }
! 8600:
! 8601: inline void msdos_int_33h_001eh()
! 8602: {
! 8603: REG16(BX) = mouse.display_page;
! 8604: }
! 8605:
! 8606: inline void msdos_int_33h_0021h()
! 8607: {
! 8608: REG16(AX) = 0xffff;
! 8609: REG16(BX) = MAX_MOUSE_BUTTONS;
! 8610: }
! 8611:
! 8612: inline void msdos_int_33h_0022h()
! 8613: {
! 8614: mouse.language = REG16(BX);
! 8615: }
! 8616:
! 8617: inline void msdos_int_33h_0023h()
! 8618: {
! 8619: REG16(BX) = mouse.language;
! 8620: }
! 8621:
! 8622: inline void msdos_int_33h_0024h()
! 8623: {
! 8624: REG16(BX) = 0x0805; // V8.05
! 8625: REG16(CX) = 0x0400; // PS/2
! 8626: }
! 8627:
! 8628: inline void msdos_int_33h_0026h()
! 8629: {
! 8630: REG16(BX) = 0x0000;
! 8631: REG16(CX) = mouse.max_position.x;
! 8632: REG16(DX) = mouse.max_position.y;
! 8633: }
! 8634:
! 8635: inline void msdos_int_33h_002ah()
! 8636: {
! 8637: REG16(AX) = mouse.active ? 0 : 0xffff;
! 8638: REG16(BX) = mouse.hot_spot[0];
! 8639: REG16(CX) = mouse.hot_spot[1];
! 8640: REG16(DX) = 4; // PS/2
! 8641: }
! 8642:
! 8643: inline void msdos_int_33h_0031h()
! 8644: {
! 8645: REG16(AX) = mouse.min_position.x;
! 8646: REG16(BX) = mouse.min_position.y;
! 8647: REG16(CX) = mouse.max_position.x;
! 8648: REG16(DX) = mouse.max_position.y;
! 8649: }
! 8650:
! 8651: inline void msdos_int_33h_0032h()
! 8652: {
! 8653: REG16(AX) = 0;
! 8654: // REG16(AX) |= 0x8000; // 0025h
! 8655: REG16(AX) |= 0x4000; // 0026h
! 8656: // REG16(AX) |= 0x2000; // 0027h
! 8657: // REG16(AX) |= 0x1000; // 0028h
! 8658: // REG16(AX) |= 0x0800; // 0029h
! 8659: REG16(AX) |= 0x0400; // 002ah
! 8660: // REG16(AX) |= 0x0200; // 002bh
! 8661: // REG16(AX) |= 0x0100; // 002ch
! 8662: // REG16(AX) |= 0x0080; // 002dh
! 8663: // REG16(AX) |= 0x0040; // 002eh
! 8664: REG16(AX) |= 0x0020; // 002fh
! 8665: // REG16(AX) |= 0x0010; // 0030h
! 8666: REG16(AX) |= 0x0008; // 0031h
! 8667: REG16(AX) |= 0x0004; // 0032h
! 8668: // REG16(AX) |= 0x0002; // 0033h
! 8669: // REG16(AX) |= 0x0001; // 0034h
! 8670: }
! 8671:
1.1.1.19 root 8672: inline void msdos_int_67h_40h()
8673: {
8674: if(!support_ems) {
8675: REG8(AH) = 0x84;
8676: } else {
8677: REG8(AH) = 0x00;
8678: }
8679: }
8680:
8681: inline void msdos_int_67h_41h()
8682: {
8683: if(!support_ems) {
8684: REG8(AH) = 0x84;
8685: } else {
8686: REG8(AH) = 0x00;
8687: REG16(BX) = EMS_TOP >> 4;
8688: }
8689: }
8690:
8691: inline void msdos_int_67h_42h()
8692: {
8693: if(!support_ems) {
8694: REG8(AH) = 0x84;
8695: } else {
8696: REG8(AH) = 0x00;
8697: REG16(BX) = free_ems_pages;
8698: REG16(DX) = MAX_EMS_PAGES;
8699: }
8700: }
8701:
8702: inline void msdos_int_67h_43h()
8703: {
8704: if(!support_ems) {
8705: REG8(AH) = 0x84;
8706: } else if(REG16(BX) > MAX_EMS_PAGES) {
8707: REG8(AH) = 0x87;
8708: } else if(REG16(BX) > free_ems_pages) {
8709: REG8(AH) = 0x88;
8710: } else if(REG16(BX) == 0) {
8711: REG8(AH) = 0x89;
8712: } else {
8713: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
8714: if(!ems_handles[i].allocated) {
8715: ems_allocate_pages(i, REG16(BX));
8716: REG8(AH) = 0x00;
8717: REG16(DX) = i;
8718: return;
8719: }
8720: }
8721: REG8(AH) = 0x85;
8722: }
8723: }
8724:
8725: inline void msdos_int_67h_44h()
8726: {
8727: if(!support_ems) {
8728: REG8(AH) = 0x84;
8729: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
8730: REG8(AH) = 0x83;
8731: } else if(!(REG16(BX) == 0xffff || REG16(BX) < ems_handles[REG16(DX)].pages)) {
8732: REG8(AH) = 0x8a;
8733: // } else if(!(REG8(AL) < 4)) {
8734: // REG8(AH) = 0x8b;
8735: } else if(REG16(BX) == 0xffff) {
8736: ems_unmap_page(REG8(AL) & 3);
8737: REG8(AH) = 0x00;
8738: } else {
8739: ems_map_page(REG8(AL) & 3, REG16(DX), REG16(BX));
8740: REG8(AH) = 0x00;
8741: }
8742: }
8743:
8744: inline void msdos_int_67h_45h()
8745: {
8746: if(!support_ems) {
8747: REG8(AH) = 0x84;
8748: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
8749: REG8(AH) = 0x83;
8750: } else {
8751: ems_release_pages(REG16(DX));
8752: REG8(AH) = 0x00;
8753: }
8754: }
8755:
8756: inline void msdos_int_67h_46h()
8757: {
8758: if(!support_ems) {
8759: REG8(AH) = 0x84;
8760: } else {
8761: REG16(AX) = 0x0032; // EMS 3.2
8762: // REG16(AX) = 0x0040; // EMS 4.0
8763: }
8764: }
8765:
8766: inline void msdos_int_67h_47h()
8767: {
8768: // NOTE: the map data should be stored in the specified ems page, not process data
8769: process_t *process = msdos_process_info_get(current_psp);
8770:
8771: if(!support_ems) {
8772: REG8(AH) = 0x84;
8773: // } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
8774: // REG8(AH) = 0x83;
8775: } else if(process->ems_pages_stored) {
8776: REG8(AH) = 0x8d;
8777: } else {
8778: for(int i = 0; i < 4; i++) {
8779: process->ems_pages[i].handle = ems_pages[i].handle;
8780: process->ems_pages[i].page = ems_pages[i].page;
8781: process->ems_pages[i].mapped = ems_pages[i].mapped;
8782: }
8783: process->ems_pages_stored = true;
8784: REG8(AH) = 0x00;
8785: }
8786: }
8787:
8788: inline void msdos_int_67h_48h()
8789: {
8790: // NOTE: the map data should be restored from the specified ems page, not process data
8791: process_t *process = msdos_process_info_get(current_psp);
8792:
8793: if(!support_ems) {
8794: REG8(AH) = 0x84;
8795: // } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
8796: // REG8(AH) = 0x83;
8797: } else if(!process->ems_pages_stored) {
8798: REG8(AH) = 0x8e;
8799: } else {
8800: for(int i = 0; i < 4; i++) {
8801: if(process->ems_pages[i].mapped) {
8802: ems_map_page(i, process->ems_pages[i].handle, process->ems_pages[i].page);
8803: } else {
8804: ems_unmap_page(i);
8805: }
8806: }
8807: process->ems_pages_stored = false;
8808: REG8(AH) = 0x00;
8809: }
8810: }
8811:
8812: inline void msdos_int_67h_4bh()
8813: {
8814: if(!support_ems) {
8815: REG8(AH) = 0x84;
8816: } else {
8817: REG8(AH) = 0x00;
8818: REG16(BX) = 0;
8819: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
8820: if(ems_handles[i].allocated) {
8821: REG16(BX)++;
8822: }
8823: }
8824: }
8825: }
8826:
8827: inline void msdos_int_67h_4ch()
8828: {
8829: if(!support_ems) {
8830: REG8(AH) = 0x84;
8831: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
8832: REG8(AH) = 0x83;
8833: } else {
8834: REG8(AH) = 0x00;
8835: REG16(BX) = ems_handles[REG16(DX)].pages;
8836: }
8837: }
8838:
8839: inline void msdos_int_67h_4dh()
8840: {
8841: if(!support_ems) {
8842: REG8(AH) = 0x84;
8843: } else {
8844: REG8(AH) = 0x00;
8845: REG16(BX) = 0;
8846: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
8847: if(ems_handles[i].allocated) {
8848: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 0) = i;
8849: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 2) = ems_handles[i].pages;
8850: REG16(BX)++;
8851: }
8852: }
8853: }
8854: }
8855:
1.1.1.20 root 8856: inline void msdos_int_67h_4eh()
8857: {
8858: if(!support_ems) {
8859: REG8(AH) = 0x84;
8860: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01 || REG8(AL) == 0x02) {
8861: if(REG8(AL) == 0x00 || REG8(AL) == 0x02) {
8862: // save page map
8863: for(int i = 0; i < 4; i++) {
8864: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = ems_pages[i].mapped ? ems_pages[i].handle : 0xffff;
8865: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = ems_pages[i].mapped ? ems_pages[i].page : 0xffff;
8866: }
8867: }
8868: if(REG8(AL) == 0x01 || REG8(AL) == 0x02) {
8869: // restore page map
8870: for(int i = 0; i < 4; i++) {
8871: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
8872: UINT16 page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
8873:
8874: if(handle < MAX_EMS_HANDLES && ems_handles[handle].allocated && page < ems_handles[handle].pages) {
8875: ems_map_page(i, handle, page);
8876: } else {
8877: ems_unmap_page(i);
8878: }
8879: }
8880: }
8881: REG8(AH) = 0x00;
8882: } else if(REG8(AL) == 0x03) {
8883: REG8(AH) = 0x00;
1.1.1.21 root 8884: REG8(AL) = 4 * 4;
8885: } else {
1.1.1.22 root 8886: 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 8887: REG8(AH) = 0x8f;
8888: }
8889: }
8890:
8891: inline void msdos_int_67h_4fh()
8892: {
8893: if(!support_ems) {
8894: REG8(AH) = 0x84;
8895: } else if(REG8(AL) == 0x00) {
8896: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
8897:
8898: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI)) = count;
8899: for(int i = 0; i < count; i++) {
8900: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 2 * i);
8901: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
8902:
8903: // if(!(physical < 4)) {
8904: // REG8(AH) = 0x8b;
8905: // return;
8906: // }
8907: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 0) = segment;
8908: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 2) = ems_pages[physical & 3].handle;
8909: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 4) = ems_pages[physical & 3].mapped ? ems_pages[physical & 3].page : 0xffff;
8910: }
8911: REG8(AH) = 0x00;
8912: } else if(REG8(AL) == 0x01) {
8913: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
8914:
8915: for(int i = 0; i < count; i++) {
8916: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 0);
8917: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
8918: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 2);
8919: UINT16 logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 4);
8920:
8921: // if(!(physical < 4)) {
8922: // REG8(AH) = 0x8b;
8923: // return;
8924: // } else
8925: if(!(handle < MAX_EMS_HANDLES && ems_handles[handle].allocated)) {
8926: REG8(AH) = 0x83;
8927: return;
8928: } else if(logical == 0xffff) {
8929: ems_unmap_page(physical & 3);
8930: } else if(logical < ems_handles[handle].pages) {
8931: ems_map_page(physical & 3, handle, logical);
8932: } else {
8933: REG8(AH) = 0x8a;
8934: return;
8935: }
8936: }
8937: REG8(AH) = 0x00;
8938: } else if(REG8(AL) == 0x02) {
8939: REG8(AH) = 0x00;
8940: REG8(AL) = 2 + REG16(BX) * 6;
1.1.1.20 root 8941: } else {
1.1.1.22 root 8942: 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 8943: REG8(AH) = 0x8f;
8944: }
8945: }
8946:
8947: inline void msdos_int_67h_50h()
8948: {
8949: if(!support_ems) {
8950: REG8(AH) = 0x84;
8951: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
8952: REG8(AH) = 0x83;
8953: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
8954: for(int i = 0; i < REG16(CX); i++) {
8955: int logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
8956: int physical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
8957:
8958: if(REG8(AL) == 0x01) {
8959: physical = ((physical << 4) - EMS_TOP) / 0x4000;
8960: }
8961: // if(!(physical < 4)) {
8962: // REG8(AH) = 0x8b;
8963: // return;
8964: // } else
8965: if(logical == 0xffff) {
8966: ems_unmap_page(physical & 3);
8967: } else if(logical < ems_handles[REG16(DX)].pages) {
8968: ems_map_page(physical & 3, REG16(DX), logical);
8969: } else {
8970: REG8(AH) = 0x8a;
8971: return;
8972: }
8973: }
8974: REG8(AH) = 0x00;
8975: } else {
1.1.1.22 root 8976: 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 8977: REG8(AH) = 0x8f;
8978: }
8979: }
8980:
1.1.1.19 root 8981: inline void msdos_int_67h_51h()
8982: {
8983: if(!support_ems) {
8984: REG8(AH) = 0x84;
8985: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
8986: REG8(AH) = 0x83;
8987: } else if(REG16(BX) > MAX_EMS_PAGES) {
8988: REG8(AH) = 0x87;
8989: } else if(REG16(BX) > free_ems_pages + ems_handles[REG16(DX)].pages) {
8990: REG8(AH) = 0x88;
8991: } else {
8992: ems_reallocate_pages(REG16(DX), REG16(BX));
8993: REG8(AH) = 0x00;
8994: }
8995: }
8996:
1.1.1.20 root 8997: inline void msdos_int_67h_52h()
8998: {
8999: if(!support_ems) {
9000: REG8(AH) = 0x84;
9001: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
9002: REG8(AH) = 0x83;
9003: } else if(REG8(AL) == 0x00) {
9004: REG8(AL) = 0x00; // handle is volatile
9005: REG8(AH) = 0x00;
9006: } else if(REG8(AL) == 0x01) {
9007: if(REG8(BL) == 0x00) {
9008: REG8(AH) = 0x00;
9009: } else {
9010: REG8(AH) = 0x90; // undefined attribute type
9011: }
9012: } else if(REG8(AL) == 0x02) {
9013: REG8(AL) = 0x00; // only volatile handles supported
9014: REG8(AH) = 0x00;
9015: } else {
1.1.1.22 root 9016: 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 9017: REG8(AH) = 0x8f;
9018: }
9019: }
9020:
1.1.1.19 root 9021: inline void msdos_int_67h_53h()
9022: {
9023: if(!support_ems) {
9024: REG8(AH) = 0x84;
9025: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
9026: REG8(AH) = 0x83;
9027: } else if(REG8(AL) == 0x00) {
9028: memcpy(mem + SREG_BASE(ES) + REG16(DI), ems_handles[REG16(DX)].name, 8);
9029: REG8(AH) = 0x00;
9030: } else if(REG8(AL) == 0x01) {
9031: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
9032: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
9033: REG8(AH) = 0xa1;
9034: return;
9035: }
9036: }
9037: REG8(AH) = 0x00;
9038: memcpy(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8);
9039: } else {
1.1.1.22 root 9040: 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 9041: REG8(AH) = 0x8f;
1.1.1.19 root 9042: }
9043: }
9044:
9045: inline void msdos_int_67h_54h()
9046: {
9047: if(!support_ems) {
9048: REG8(AH) = 0x84;
9049: } else if(REG8(AL) == 0x00) {
9050: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
9051: if(ems_handles[i].allocated) {
9052: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, ems_handles[i].name, 10);
9053: } else {
9054: memset(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, 0, 10);
9055: }
9056: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 0) = i;
9057: }
9058: REG8(AH) = 0x00;
9059: REG8(AL) = MAX_EMS_HANDLES;
9060: } else if(REG8(AL) == 0x01) {
9061: REG8(AH) = 0xa0; // not found
9062: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
9063: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
9064: REG8(AH) = 0x00;
9065: REG16(DX) = i;
9066: break;
9067: }
9068: }
9069: } else if(REG8(AL) == 0x02) {
9070: REG8(AH) = 0x00;
9071: REG16(BX) = MAX_EMS_HANDLES;
9072: } else {
1.1.1.22 root 9073: 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 9074: REG8(AH) = 0x8f;
9075: }
9076: }
9077:
9078: inline void msdos_int_67h_57h_tmp()
9079: {
9080: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
9081: UINT8 src_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
9082: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x05);
9083: UINT16 src_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07);
9084: UINT16 src_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x09);
9085: UINT8 dest_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0b);
9086: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
9087: UINT16 dest_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0e);
9088: UINT16 dest_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x10);
9089:
9090: UINT8 *src_buffer, *dest_buffer;
9091: UINT32 src_addr, dest_addr;
9092: UINT32 src_addr_max, dest_addr_max;
9093:
9094: if(src_type == 0) {
9095: src_buffer = mem;
9096: src_addr = (src_seg << 4) + src_ofs;
9097: src_addr_max = MAX_MEM;
9098: } else {
9099: if(!(src_handle < MAX_EMS_HANDLES && ems_handles[src_handle].allocated)) {
9100: REG8(AH) = 0x83;
9101: return;
9102: } else if(!(src_seg < ems_handles[src_handle].pages)) {
9103: REG8(AH) = 0x8a;
9104: return;
9105: }
9106: src_buffer = ems_handles[src_handle].buffer + 0x4000 * src_seg;
9107: src_addr = src_ofs;
9108: src_addr_max = 0x4000;
9109: }
9110: if(dest_type == 0) {
9111: dest_buffer = mem;
9112: dest_addr = (dest_seg << 4) + dest_ofs;
9113: dest_addr_max = MAX_MEM;
9114: } else {
9115: if(!(dest_handle < MAX_EMS_HANDLES && ems_handles[dest_handle].allocated)) {
9116: REG8(AH) = 0x83;
9117: return;
9118: } else if(!(dest_seg < ems_handles[dest_handle].pages)) {
9119: REG8(AH) = 0x8a;
9120: return;
9121: }
9122: dest_buffer = ems_handles[dest_handle].buffer + 0x4000 * dest_seg;
9123: dest_addr = dest_ofs;
9124: dest_addr_max = 0x4000;
9125: }
9126: for(int i = 0; i < copy_length; i++) {
9127: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
9128: if(REG8(AL) == 0x00) {
9129: dest_buffer[dest_addr++] = src_buffer[src_addr++];
9130: } else if(REG8(AL) == 0x01) {
9131: UINT8 tmp = dest_buffer[dest_addr];
9132: dest_buffer[dest_addr++] = src_buffer[src_addr];
9133: src_buffer[src_addr++] = tmp;
9134: }
9135: } else {
9136: REG8(AH) = 0x93;
9137: return;
9138: }
9139: }
9140: REG8(AH) = 0x80;
9141: }
9142:
9143: inline void msdos_int_67h_57h()
9144: {
9145: if(!support_ems) {
9146: REG8(AH) = 0x84;
9147: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
9148: struct {
9149: UINT16 handle;
9150: UINT16 page;
9151: bool mapped;
9152: } tmp_pages[4];
9153:
9154: // unmap pages to copy memory data to ems buffer
9155: for(int i = 0; i < 4; i++) {
9156: tmp_pages[i].handle = ems_pages[i].handle;
9157: tmp_pages[i].page = ems_pages[i].page;
9158: tmp_pages[i].mapped = ems_pages[i].mapped;
9159: ems_unmap_page(i);
9160: }
9161:
9162: // run move/exchange operation
9163: msdos_int_67h_57h_tmp();
9164:
9165: // restore unmapped pages
9166: for(int i = 0; i < 4; i++) {
9167: if(tmp_pages[i].mapped) {
9168: ems_map_page(i, tmp_pages[i].handle, tmp_pages[i].page);
9169: }
9170: }
9171: } else {
1.1.1.22 root 9172: 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 9173: REG8(AH) = 0x8f;
9174: }
9175: }
9176:
9177: inline void msdos_int_67h_58h()
9178: {
9179: if(!support_ems) {
9180: REG8(AH) = 0x84;
9181: } else if(REG8(AL) == 0x00) {
9182: for(int i = 0; i < 4; i++) {
9183: *(UINT16 *)(mem +SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = (EMS_TOP + 0x4000 * i) >> 4;
9184: *(UINT16 *)(mem +SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = i;
9185: }
9186: REG8(AH) = 0x00;
9187: REG16(CX) = 4;
9188: } else if(REG8(AL) == 0x01) {
9189: REG8(AH) = 0x00;
9190: REG16(CX) = 4;
9191: } else {
1.1.1.22 root 9192: 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 9193: REG8(AH) = 0x8f;
9194: }
9195: }
9196:
9197: inline void msdos_int_67h_5ah()
9198: {
9199: if(!support_ems) {
1.1.1.19 root 9200: REG8(AH) = 0x84;
1.1.1.20 root 9201: } else if(REG16(BX) > MAX_EMS_PAGES) {
9202: REG8(AH) = 0x87;
9203: } else if(REG16(BX) > free_ems_pages) {
9204: REG8(AH) = 0x88;
9205: // } else if(REG16(BX) == 0) {
9206: // REG8(AH) = 0x89;
9207: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
9208: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
9209: if(!ems_handles[i].allocated) {
9210: ems_allocate_pages(i, REG16(BX));
9211: REG8(AH) = 0x00;
9212: REG16(DX) = i;
9213: return;
9214: }
9215: }
9216: REG8(AH) = 0x85;
9217: } else {
1.1.1.22 root 9218: 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 9219: REG8(AH) = 0x8f;
1.1.1.19 root 9220: }
9221: }
9222:
9223: #ifdef SUPPORT_XMS
9224:
9225: inline void msdos_call_xms_00h()
9226: {
9227: REG16(AX) = 0x0270; // V2.70
9228: REG16(BX) = 0x0000;
9229: // REG16(DX) = 0x0000; // hma does not exist
9230: REG16(DX) = 0x0001; // hma does exist
9231: }
9232:
9233: inline void msdos_call_xms_01h()
9234: {
9235: REG16(AX) = 0x0000;
9236: // REG8(BL) = 0x90; // hma does not exist
9237: REG8(BL) = 0x91; // hma is already used
9238: }
9239:
9240: inline void msdos_call_xms_02h()
9241: {
9242: REG16(AX) = 0x0000;
9243: // REG8(BL) = 0x90; // hma does not exist
9244: REG8(BL) = 0x91; // hma is already used
9245: }
9246:
9247: inline void msdos_call_xms_03h()
9248: {
9249: i386_set_a20_line(1);
9250: REG16(AX) = 0x0001;
9251: REG8(BL) = 0x00;
9252: }
9253:
9254: inline void msdos_call_xms_04h()
9255: {
1.1.1.21 root 9256: i386_set_a20_line(0);
9257: REG16(AX) = 0x0001;
9258: REG8(BL) = 0x00;
1.1.1.19 root 9259: }
9260:
9261: inline void msdos_call_xms_05h()
9262: {
9263: i386_set_a20_line(1);
9264: REG16(AX) = 0x0001;
9265: REG8(BL) = 0x00;
1.1.1.21 root 9266: xms_a20_local_enb_count++;
1.1.1.19 root 9267: }
9268:
9269: void msdos_call_xms_06h()
9270: {
1.1.1.21 root 9271: if(xms_a20_local_enb_count > 0) {
9272: xms_a20_local_enb_count--;
9273: }
9274: if(xms_a20_local_enb_count == 0) {
1.1.1.19 root 9275: i386_set_a20_line(0);
1.1.1.21 root 9276: }
9277: if((m_a20_mask >> 20) & 1) {
1.1.1.19 root 9278: REG16(AX) = 0x0000;
9279: REG8(BL) = 0x94;
1.1.1.21 root 9280: } else {
9281: REG16(AX) = 0x0001;
9282: REG8(BL) = 0x00;
1.1.1.19 root 9283: }
9284: }
9285:
9286: inline void msdos_call_xms_07h()
9287: {
9288: REG16(AX) = (m_a20_mask >> 20) & 1;
9289: REG8(BL) = 0x00;
9290: }
9291:
9292: inline void msdos_call_xms_08h()
9293: {
9294: REG16(AX) = REG16(DX) = 0x0000;
9295:
9296: int mcb_seg = EMB_TOP >> 4;
9297:
9298: while(1) {
9299: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
9300:
9301: if(mcb->psp == 0) {
9302: if(REG16(AX) < mcb->size_kb()) {
9303: REG16(AX) = mcb->size_kb();
9304: }
9305: REG16(DX) += mcb->size_kb();
9306: }
9307: if(mcb->mz == 'Z') {
9308: break;
9309: }
9310: mcb_seg += 1 + mcb->paragraphs();
9311: }
9312:
9313: if(REG16(AX) == 0 && REG16(DX) == 0) {
9314: REG8(BL) = 0xa0;
9315: } else {
9316: REG8(BL) = 0x00;
9317: }
9318: }
9319:
9320: inline void msdos_call_xms_09h()
9321: {
9322: for(int i = 1; i <= MAX_XMS_HANDLES; i++) {
9323: if(!xms_handles[i].allocated) {
9324: if((xms_handles[i].seg = msdos_mem_alloc(EMB_TOP >> 4, REG16(DX) * 64, 0)) != -1) {
9325: xms_handles[i].size_kb = REG16(DX);
9326: xms_handles[i].lock = 0;
9327: xms_handles[i].allocated = true;
9328:
9329: REG16(AX) = 0x0001;
9330: REG16(DX) = i;
9331: REG8(BL) = 0x00;
9332: } else {
9333: REG16(AX) = REG16(DX) = 0x0000;
9334: REG8(BL) = 0xa0;
9335: }
9336: return;
9337: }
9338: }
9339: REG16(AX) = REG16(DX) = 0x0000;
9340: REG8(BL) = 0xa1;
9341: }
9342:
9343: inline void msdos_call_xms_0ah()
9344: {
9345: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
9346: REG16(AX) = 0x0000;
9347: REG8(BL) = 0xa2;
9348: } else if(xms_handles[REG16(DX)].lock > 0) {
9349: REG16(AX) = 0x0000;
9350: REG8(BL) = 0xab;
9351: } else {
9352: msdos_mem_free(xms_handles[REG16(DX)].seg);
9353: xms_handles[REG16(DX)].allocated = false;
9354:
9355: REG16(AX) = 0x0001;
9356: REG8(BL) = 0x00;
9357: }
9358: }
9359:
9360: inline void msdos_call_xms_0bh()
9361: {
9362: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
9363: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
9364: UINT32 src_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06);
9365: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0a);
9366: UINT32 dest_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
9367:
9368: UINT8 *src_buffer, *dest_buffer;
9369: UINT32 src_addr_max, dest_addr_max;
9370:
9371: if(src_handle == 0) {
9372: src_buffer = mem;
9373: src_addr = (((src_addr >> 16) & 0xffff) << 4) + (src_addr & 0xffff);
9374: src_addr_max = MAX_MEM;
9375: } else {
9376: if(!(src_handle >= 1 && src_handle <= MAX_XMS_HANDLES && xms_handles[src_handle].allocated)) {
9377: REG16(AX) = 0x0000;
9378: REG8(BL) = 0xa3;
9379: return;
9380: }
9381: src_buffer = mem + (xms_handles[src_handle].seg << 4);
9382: src_addr_max = xms_handles[src_handle].size_kb * 1024;
9383: }
9384: if(dest_handle == 0) {
9385: dest_buffer = mem;
9386: dest_addr = (((dest_addr >> 16) & 0xffff) << 4) + (dest_addr & 0xffff);
9387: dest_addr_max = MAX_MEM;
9388: } else {
9389: if(!(dest_handle >= 1 && dest_handle <= MAX_XMS_HANDLES && xms_handles[dest_handle].allocated)) {
9390: REG16(AX) = 0x0000;
9391: REG8(BL) = 0xa5;
9392: return;
9393: }
9394: dest_buffer = mem + (xms_handles[dest_handle].seg << 4);
9395: dest_addr_max = xms_handles[dest_handle].size_kb * 1024;
9396: }
9397: for(int i = 0; i < copy_length; i++) {
9398: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
9399: dest_buffer[dest_addr++] = src_buffer[src_addr++];
9400: } else {
9401: break;
9402: }
9403: }
9404: REG16(AX) = 0x0001;
9405: REG8(BL) = 0x00;
9406: }
9407:
9408: inline void msdos_call_xms_0ch()
9409: {
9410: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
9411: REG16(AX) = 0x0000;
9412: REG8(BL) = 0xa2;
9413: } else {
9414: xms_handles[REG16(DX)].lock++;
9415: REG16(AX) = 0x0001;
9416: REG8(BL) = 0x00;
9417: UINT32 addr = xms_handles[REG16(DX)].seg << 4;
9418: REG16(DX) = (addr >> 16) & 0xffff;
9419: REG16(BX) = (addr ) & 0xffff;
9420: }
9421: }
9422:
9423: inline void msdos_call_xms_0dh()
9424: {
9425: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
9426: REG16(AX) = 0x0000;
9427: REG8(BL) = 0xa2;
9428: } else if(!(xms_handles[REG16(DX)].lock > 0)) {
9429: REG16(AX) = 0x0000;
9430: REG8(BL) = 0xaa;
9431: } else {
9432: xms_handles[REG16(DX)].lock--;
9433: REG16(AX) = 0x0001;
9434: REG8(BL) = 0x00;
9435: }
9436: }
9437:
9438: inline void msdos_call_xms_0eh()
9439: {
9440: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
9441: REG16(AX) = 0x0000;
9442: REG8(BL) = 0xa2;
9443: } else {
9444: REG16(AX) = 0x0001;
9445: REG8(BH) = xms_handles[REG16(DX)].lock;
9446: REG8(BL) = 0x00;
9447: for(int i = 1; i <= MAX_XMS_HANDLES; i++) {
9448: if(!xms_handles[i].allocated) {
9449: REG8(BL)++;
9450: }
9451: }
9452: REG16(DX) = xms_handles[REG16(DX)].size_kb;
9453: }
9454: }
9455:
9456: inline void msdos_call_xms_0fh()
9457: {
9458: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
9459: REG16(AX) = 0x0000;
9460: REG8(BL) = 0xa2;
9461: } else if(xms_handles[REG16(DX)].lock > 0) {
9462: REG16(AX) = 0x0000;
9463: REG8(BL) = 0xab;
9464: } else if(msdos_mem_realloc(xms_handles[REG16(DX)].seg, REG16(BX) * 64, NULL)) {
9465: REG16(AX) = 0x0000;
9466: REG8(BL) = 0xa0;
9467: } else {
9468: REG16(AX) = 0x0001;
9469: REG8(BL) = 0x00;
9470: }
9471: }
9472:
9473: inline void msdos_call_xms_10h()
9474: {
9475: int seg;
9476:
9477: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(DX), 0)) != -1) {
9478: REG16(AX) = 0x0001;
9479: REG16(BX) = seg;
9480: } else {
9481: REG16(AX) = 0x0000;
9482: REG8(BL) = 0xb0;
9483: REG16(DX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
9484: }
9485: }
9486:
9487: inline void msdos_call_xms_11h()
9488: {
9489: int mcb_seg = REG16(DX) - 1;
9490: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
9491:
9492: if(mcb->mz == 'M' || mcb->mz == 'Z') {
9493: msdos_mem_free(REG16(DX));
9494: REG16(AX) = 0x0001;
9495: REG8(BL) = 0x00;
9496: } else {
9497: REG16(AX) = 0x0000;
9498: REG8(BL) = 0xb2;
9499: }
9500: }
9501:
9502: inline void msdos_call_xms_12h()
9503: {
9504: int mcb_seg = REG16(DX) - 1;
9505: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
9506: int max_paragraphs;
9507:
9508: if(mcb->mz == 'M' || mcb->mz == 'Z') {
9509: if(!msdos_mem_realloc(REG16(DX), REG16(BX), &max_paragraphs)) {
9510: REG16(AX) = 0x0001;
9511: REG8(BL) = 0x00;
9512: } else {
9513: REG16(AX) = 0x0000;
9514: REG8(BL) = 0xb0;
9515: REG16(DX) = max_paragraphs;
9516: }
9517: } else {
9518: REG16(AX) = 0x0000;
9519: REG8(BL) = 0xb2;
9520: }
9521: }
9522:
9523: #endif
9524:
1.1 root 9525: void msdos_syscall(unsigned num)
9526: {
1.1.1.22 root 9527: #ifdef ENABLE_DEBUG_SYSCALL
9528: if(num == 0x68) {
9529: // dummy interrupt for EMS (int 67h)
9530: 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));
9531: } else if(num == 0x69) {
9532: // dummy interrupt for XMS (call far)
9533: 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));
9534: } else if(num == 0x6a) {
9535: // dummy interrupt for case map routine pointed in the country info
9536: } else {
9537: 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));
9538: }
9539: #endif
9540:
1.1 root 9541: switch(num) {
9542: case 0x00:
9543: error("division by zero\n");
9544: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
9545: break;
9546: case 0x04:
9547: error("overflow\n");
9548: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
9549: break;
9550: case 0x06:
9551: // NOTE: ish.com has illegal instruction...
1.1.1.14 root 9552: if(!ignore_illegal_insn) {
9553: error("illegal instruction\n");
9554: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
9555: } else {
9556: #if defined(HAS_I386)
9557: m_eip++;
9558: #else
9559: m_pc++;
9560: #endif
9561: }
1.1 root 9562: break;
1.1.1.8 root 9563: case 0x08:
1.1.1.14 root 9564: // pcbios_irq0(); // this causes too slow emulation...
1.1.1.8 root 9565: case 0x09:
9566: case 0x0a:
9567: case 0x0b:
9568: case 0x0c:
9569: case 0x0d:
9570: case 0x0e:
9571: case 0x0f:
9572: // EOI
9573: pic[0].isr &= ~(1 << (num - 0x08));
9574: pic_update();
9575: break;
1.1 root 9576: case 0x10:
9577: // PC BIOS - Video
1.1.1.14 root 9578: if(!restore_console_on_exit) {
1.1.1.15 root 9579: change_console_size(scr_width, scr_height);
1.1 root 9580: }
1.1.1.3 root 9581: m_CF = 0;
1.1 root 9582: switch(REG8(AH)) {
1.1.1.16 root 9583: case 0x00: pcbios_int_10h_00h(); break;
1.1 root 9584: case 0x01: pcbios_int_10h_01h(); break;
9585: case 0x02: pcbios_int_10h_02h(); break;
9586: case 0x03: pcbios_int_10h_03h(); break;
9587: case 0x05: pcbios_int_10h_05h(); break;
9588: case 0x06: pcbios_int_10h_06h(); break;
9589: case 0x07: pcbios_int_10h_07h(); break;
9590: case 0x08: pcbios_int_10h_08h(); break;
9591: case 0x09: pcbios_int_10h_09h(); break;
9592: case 0x0a: pcbios_int_10h_0ah(); break;
9593: case 0x0b: break;
9594: case 0x0c: break;
9595: case 0x0d: break;
9596: case 0x0e: pcbios_int_10h_0eh(); break;
9597: case 0x0f: pcbios_int_10h_0fh(); break;
9598: case 0x10: break;
1.1.1.14 root 9599: case 0x11: pcbios_int_10h_11h(); break;
9600: case 0x12: pcbios_int_10h_12h(); break;
1.1 root 9601: case 0x13: pcbios_int_10h_13h(); break;
9602: case 0x18: REG8(AL) = 0x86; break;
1.1.1.14 root 9603: case 0x1a: pcbios_int_10h_1ah(); break;
1.1.1.24! root 9604: case 0x1b: REG8(AL) = 0x00; break; // functionality/state information is not supported
! 9605: case 0x1c: REG8(AL) = 0x00; break; // save/restore video state is not supported
1.1 root 9606: case 0x1d: pcbios_int_10h_1dh(); break;
1.1.1.24! root 9607: case 0x1e: REG8(AL) = 0x00; break; // flat-panel functions are not supported
! 9608: case 0x1f: REG8(AL) = 0x00; break; // xga functions are not supported
1.1.1.22 root 9609: case 0x4f: pcbios_int_10h_4fh(); break;
9610: case 0x80: m_CF = 1; break; // unknown
9611: case 0x81: m_CF = 1; break; // unknown
1.1 root 9612: case 0x82: pcbios_int_10h_82h(); break;
1.1.1.22 root 9613: case 0x83: pcbios_int_10h_83h(); break;
9614: case 0x8b: break;
9615: case 0x8c: m_CF = 1; break; // unknown
9616: case 0x8d: m_CF = 1; break; // unknown
9617: case 0x8e: m_CF = 1; break; // unknown
9618: case 0x90: pcbios_int_10h_90h(); break;
9619: case 0x91: pcbios_int_10h_91h(); break;
9620: case 0x92: break;
9621: case 0x93: break;
9622: case 0xef: pcbios_int_10h_efh(); break;
1.1.1.24! root 9623: case 0xfa: break; // ega register interface library is not installed
1.1 root 9624: case 0xfe: pcbios_int_10h_feh(); break;
9625: case 0xff: pcbios_int_10h_ffh(); break;
9626: default:
1.1.1.22 root 9627: 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));
9628: m_CF = 1;
1.1 root 9629: break;
9630: }
9631: break;
9632: case 0x11:
9633: // PC BIOS - Get Equipment List
1.1.1.11 root 9634: #ifdef SUPPORT_FPU
9635: REG16(AX) = 0x22;
9636: #else
1.1 root 9637: REG16(AX) = 0x20;
1.1.1.11 root 9638: #endif
1.1 root 9639: break;
9640: case 0x12:
9641: // PC BIOS - Get Memory Size
9642: REG16(AX) = MEMORY_END / 1024;
9643: break;
9644: case 0x13:
9645: // PC BIOS - Disk
1.1.1.22 root 9646: // 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 9647: REG8(AH) = 0xff;
1.1.1.3 root 9648: m_CF = 1;
1.1 root 9649: break;
9650: case 0x14:
9651: // PC BIOS - Serial I/O
1.1.1.22 root 9652: // 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 9653: REG8(AH) = 0xff;
1.1.1.3 root 9654: m_CF = 1;
1.1 root 9655: break;
9656: case 0x15:
9657: // PC BIOS
1.1.1.3 root 9658: m_CF = 0;
1.1 root 9659: switch(REG8(AH)) {
1.1.1.14 root 9660: case 0x10: pcbios_int_15h_10h(); break;
1.1 root 9661: case 0x23: pcbios_int_15h_23h(); break;
9662: case 0x24: pcbios_int_15h_24h(); break;
1.1.1.24! root 9663: case 0x41: break;
1.1 root 9664: case 0x49: pcbios_int_15h_49h(); break;
1.1.1.22 root 9665: case 0x50: pcbios_int_15h_50h(); break;
1.1 root 9666: case 0x86: pcbios_int_15h_86h(); break;
9667: case 0x87: pcbios_int_15h_87h(); break;
9668: case 0x88: pcbios_int_15h_88h(); break;
9669: case 0x89: pcbios_int_15h_89h(); break;
1.1.1.21 root 9670: case 0x8a: pcbios_int_15h_8ah(); break;
1.1.1.22 root 9671: case 0xc0: // PS/2 ???
9672: case 0xc1:
9673: case 0xc2:
9674: REG8(AH) = 0x86;
9675: m_CF = 1;
9676: break;
1.1.1.3 root 9677: #if defined(HAS_I386)
1.1 root 9678: case 0xc9: pcbios_int_15h_c9h(); break;
1.1.1.3 root 9679: #endif
1.1 root 9680: case 0xca: pcbios_int_15h_cah(); break;
1.1.1.22 root 9681: case 0xe8: pcbios_int_15h_e8h(); break;
1.1 root 9682: default:
1.1.1.22 root 9683: 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));
9684: REG8(AH) = 0x86;
1.1.1.3 root 9685: m_CF = 1;
1.1 root 9686: break;
9687: }
9688: break;
9689: case 0x16:
9690: // PC BIOS - Keyboard
1.1.1.3 root 9691: m_CF = 0;
1.1 root 9692: switch(REG8(AH)) {
9693: case 0x00: pcbios_int_16h_00h(); break;
9694: case 0x01: pcbios_int_16h_01h(); break;
9695: case 0x02: pcbios_int_16h_02h(); break;
9696: case 0x03: pcbios_int_16h_03h(); break;
9697: case 0x05: pcbios_int_16h_05h(); break;
9698: case 0x10: pcbios_int_16h_00h(); break;
9699: case 0x11: pcbios_int_16h_01h(); break;
9700: case 0x12: pcbios_int_16h_12h(); break;
9701: case 0x13: pcbios_int_16h_13h(); break;
9702: case 0x14: pcbios_int_16h_14h(); break;
1.1.1.24! root 9703: case 0x55: pcbios_int_16h_55h(); break;
1.1.1.22 root 9704: case 0xda: break; // unknown
9705: case 0xff: break; // unknown
1.1 root 9706: default:
1.1.1.22 root 9707: 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 9708: break;
9709: }
9710: break;
9711: case 0x17:
9712: // PC BIOS - Printer
1.1.1.22 root 9713: // 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 9714: break;
9715: case 0x1a:
9716: // PC BIOS - Timer
1.1.1.3 root 9717: m_CF = 0;
1.1 root 9718: switch(REG8(AH)) {
9719: case 0x00: pcbios_int_1ah_00h(); break;
9720: case 0x01: break;
9721: case 0x02: pcbios_int_1ah_02h(); break;
9722: case 0x03: break;
9723: case 0x04: pcbios_int_1ah_04h(); break;
9724: case 0x05: break;
9725: case 0x0a: pcbios_int_1ah_0ah(); break;
9726: case 0x0b: break;
1.1.1.14 root 9727: case 0x35: break; // Word Perfect Third Party Interface?
9728: case 0x36: break; // Word Perfect Third Party Interface
9729: case 0x70: break; // SNAP? (Simple Network Application Protocol)
1.1 root 9730: default:
1.1.1.22 root 9731: 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 9732: break;
9733: }
9734: break;
9735: case 0x20:
1.1.1.3 root 9736: msdos_process_terminate(SREG(CS), retval, 1);
1.1 root 9737: break;
9738: case 0x21:
9739: // MS-DOS System Call
1.1.1.3 root 9740: m_CF = 0;
1.1 root 9741: switch(REG8(AH)) {
9742: case 0x00: msdos_int_21h_00h(); break;
9743: case 0x01: msdos_int_21h_01h(); break;
9744: case 0x02: msdos_int_21h_02h(); break;
9745: case 0x03: msdos_int_21h_03h(); break;
9746: case 0x04: msdos_int_21h_04h(); break;
9747: case 0x05: msdos_int_21h_05h(); break;
9748: case 0x06: msdos_int_21h_06h(); break;
9749: case 0x07: msdos_int_21h_07h(); break;
9750: case 0x08: msdos_int_21h_08h(); break;
9751: case 0x09: msdos_int_21h_09h(); break;
9752: case 0x0a: msdos_int_21h_0ah(); break;
9753: case 0x0b: msdos_int_21h_0bh(); break;
9754: case 0x0c: msdos_int_21h_0ch(); break;
9755: case 0x0d: msdos_int_21h_0dh(); break;
9756: case 0x0e: msdos_int_21h_0eh(); break;
1.1.1.14 root 9757: case 0x0f: msdos_int_21h_0fh(); break;
9758: case 0x10: msdos_int_21h_10h(); break;
1.1 root 9759: case 0x11: msdos_int_21h_11h(); break;
9760: case 0x12: msdos_int_21h_12h(); break;
9761: case 0x13: msdos_int_21h_13h(); break;
1.1.1.16 root 9762: case 0x14: msdos_int_21h_14h(); break;
9763: case 0x15: msdos_int_21h_15h(); break;
1.1.1.14 root 9764: case 0x16: msdos_int_21h_16h(); break;
1.1.1.16 root 9765: case 0x17: msdos_int_21h_17h(); break;
1.1 root 9766: case 0x18: msdos_int_21h_18h(); break;
9767: case 0x19: msdos_int_21h_19h(); break;
9768: case 0x1a: msdos_int_21h_1ah(); break;
9769: case 0x1b: msdos_int_21h_1bh(); break;
9770: case 0x1c: msdos_int_21h_1ch(); break;
9771: case 0x1d: msdos_int_21h_1dh(); break;
9772: case 0x1e: msdos_int_21h_1eh(); break;
9773: case 0x1f: msdos_int_21h_1fh(); break;
9774: case 0x20: msdos_int_21h_20h(); break;
1.1.1.14 root 9775: case 0x21: msdos_int_21h_21h(); break;
9776: case 0x22: msdos_int_21h_22h(); break;
1.1.1.16 root 9777: case 0x23: msdos_int_21h_23h(); break;
9778: case 0x24: msdos_int_21h_24h(); break;
1.1 root 9779: case 0x25: msdos_int_21h_25h(); break;
9780: case 0x26: msdos_int_21h_26h(); break;
1.1.1.16 root 9781: case 0x27: msdos_int_21h_27h(); break;
9782: case 0x28: msdos_int_21h_28h(); break;
1.1 root 9783: case 0x29: msdos_int_21h_29h(); break;
9784: case 0x2a: msdos_int_21h_2ah(); break;
9785: case 0x2b: msdos_int_21h_2bh(); break;
9786: case 0x2c: msdos_int_21h_2ch(); break;
9787: case 0x2d: msdos_int_21h_2dh(); break;
9788: case 0x2e: msdos_int_21h_2eh(); break;
9789: case 0x2f: msdos_int_21h_2fh(); break;
9790: case 0x30: msdos_int_21h_30h(); break;
9791: case 0x31: msdos_int_21h_31h(); break;
9792: case 0x32: msdos_int_21h_32h(); break;
9793: case 0x33: msdos_int_21h_33h(); break;
1.1.1.23 root 9794: case 0x34: msdos_int_21h_34h(); break;
1.1 root 9795: case 0x35: msdos_int_21h_35h(); break;
9796: case 0x36: msdos_int_21h_36h(); break;
9797: case 0x37: msdos_int_21h_37h(); break;
1.1.1.14 root 9798: case 0x38: msdos_int_21h_38h(); break;
1.1 root 9799: case 0x39: msdos_int_21h_39h(0); break;
9800: case 0x3a: msdos_int_21h_3ah(0); break;
9801: case 0x3b: msdos_int_21h_3bh(0); break;
9802: case 0x3c: msdos_int_21h_3ch(); break;
9803: case 0x3d: msdos_int_21h_3dh(); break;
9804: case 0x3e: msdos_int_21h_3eh(); break;
9805: case 0x3f: msdos_int_21h_3fh(); break;
9806: case 0x40: msdos_int_21h_40h(); break;
9807: case 0x41: msdos_int_21h_41h(0); break;
9808: case 0x42: msdos_int_21h_42h(); break;
9809: case 0x43: msdos_int_21h_43h(0); break;
9810: case 0x44: msdos_int_21h_44h(); break;
9811: case 0x45: msdos_int_21h_45h(); break;
9812: case 0x46: msdos_int_21h_46h(); break;
9813: case 0x47: msdos_int_21h_47h(0); break;
9814: case 0x48: msdos_int_21h_48h(); break;
9815: case 0x49: msdos_int_21h_49h(); break;
9816: case 0x4a: msdos_int_21h_4ah(); break;
9817: case 0x4b: msdos_int_21h_4bh(); break;
9818: case 0x4c: msdos_int_21h_4ch(); break;
9819: case 0x4d: msdos_int_21h_4dh(); break;
9820: case 0x4e: msdos_int_21h_4eh(); break;
9821: case 0x4f: msdos_int_21h_4fh(); break;
9822: case 0x50: msdos_int_21h_50h(); break;
9823: case 0x51: msdos_int_21h_51h(); break;
9824: case 0x52: msdos_int_21h_52h(); break;
9825: // 0x53: translate bios parameter block to drive param bock
9826: case 0x54: msdos_int_21h_54h(); break;
9827: case 0x55: msdos_int_21h_55h(); break;
9828: case 0x56: msdos_int_21h_56h(0); break;
9829: case 0x57: msdos_int_21h_57h(); break;
9830: case 0x58: msdos_int_21h_58h(); break;
9831: case 0x59: msdos_int_21h_59h(); break;
9832: case 0x5a: msdos_int_21h_5ah(); break;
9833: case 0x5b: msdos_int_21h_5bh(); break;
9834: case 0x5c: msdos_int_21h_5ch(); break;
1.1.1.22 root 9835: case 0x5d: msdos_int_21h_5dh(); break;
1.1 root 9836: // 0x5e: ms-network
9837: // 0x5f: ms-network
9838: case 0x60: msdos_int_21h_60h(0); break;
9839: case 0x61: msdos_int_21h_61h(); break;
9840: case 0x62: msdos_int_21h_62h(); break;
9841: case 0x63: msdos_int_21h_63h(); break;
9842: // 0x64: set device driver lockahead flag
9843: case 0x65: msdos_int_21h_65h(); break;
9844: case 0x66: msdos_int_21h_66h(); break;
9845: case 0x67: msdos_int_21h_67h(); break;
9846: case 0x68: msdos_int_21h_68h(); break;
9847: case 0x69: msdos_int_21h_69h(); break;
9848: case 0x6a: msdos_int_21h_6ah(); break;
9849: case 0x6b: msdos_int_21h_6bh(); break;
9850: case 0x6c: msdos_int_21h_6ch(0); break;
9851: // 0x6d: find first rom program
9852: // 0x6e: find next rom program
9853: // 0x6f: get/set rom scan start address
9854: // 0x70: windows95 get/set internationalization information
9855: case 0x71:
9856: // windows95 long filename functions
9857: switch(REG8(AL)) {
9858: case 0x0d: msdos_int_21h_710dh(); break;
9859: case 0x39: msdos_int_21h_39h(1); break;
9860: case 0x3a: msdos_int_21h_3ah(1); break;
9861: case 0x3b: msdos_int_21h_3bh(1); break;
1.1.1.17 root 9862: case 0x41: msdos_int_21h_7141h(1); break;
1.1 root 9863: case 0x43: msdos_int_21h_43h(1); break;
9864: case 0x47: msdos_int_21h_47h(1); break;
9865: case 0x4e: msdos_int_21h_714eh(); break;
9866: case 0x4f: msdos_int_21h_714fh(); break;
9867: case 0x56: msdos_int_21h_56h(1); break;
9868: case 0x60: msdos_int_21h_60h(1); break;
9869: case 0x6c: msdos_int_21h_6ch(1); break;
9870: case 0xa0: msdos_int_21h_71a0h(); break;
9871: case 0xa1: msdos_int_21h_71a1h(); break;
9872: case 0xa6: msdos_int_21h_71a6h(); break;
9873: case 0xa7: msdos_int_21h_71a7h(); break;
9874: case 0xa8: msdos_int_21h_71a8h(); break;
9875: // 0xa9: server create/open file
1.1.1.22 root 9876: case 0xaa: msdos_int_21h_71aah(); break;
1.1 root 9877: default:
1.1.1.22 root 9878: 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 root 9879: REG16(AX) = 0x7100;
1.1.1.3 root 9880: m_CF = 1;
1.1 root 9881: break;
9882: }
9883: break;
9884: // 0x72: Windows95 beta - LFN FindClose
9885: case 0x73:
9886: // windows95 fat32 functions
9887: switch(REG8(AL)) {
1.1.1.14 root 9888: case 0x00: msdos_int_21h_7300h(); break;
9889: // 0x01: set drive locking ???
9890: case 0x02: msdos_int_21h_7302h(); break;
1.1 root 9891: case 0x03: msdos_int_21h_7303h(); break;
9892: // 0x04: set dpb to use for formatting
9893: default:
1.1.1.22 root 9894: 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 root 9895: REG16(AX) = 0x7300;
1.1.1.3 root 9896: m_CF = 1;
1.1 root 9897: break;
9898: }
9899: break;
9900: default:
1.1.1.22 root 9901: 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 root 9902: REG16(AX) = 0x01;
1.1.1.3 root 9903: m_CF = 1;
1.1 root 9904: break;
9905: }
1.1.1.3 root 9906: if(m_CF) {
1.1.1.23 root 9907: sda_t *sda = (sda_t *)(mem + SDA_TOP);
9908: sda->extended_error_code = REG16(AX);
9909: switch(sda->extended_error_code) {
9910: case 4: // Too many open files
9911: case 8: // Insufficient memory
9912: sda->error_class = 1; // Out of resource
9913: break;
9914: case 5: // Access denied
9915: sda->error_class = 3; // Authorization
9916: break;
9917: case 7: // Memory control block destroyed
9918: sda->error_class = 4; // Internal
9919: break;
9920: case 2: // File not found
9921: case 3: // Path not found
9922: case 15: // Invaid drive specified
9923: case 18: // No more files
9924: sda->error_class = 8; // Not found
9925: break;
9926: case 32: // Sharing violation
9927: case 33: // Lock violation
9928: sda->error_class = 10; // Locked
9929: break;
9930: // case 16: // Removal of current directory attempted
9931: case 19: // Attempted write on protected disk
9932: case 21: // Drive not ready
9933: // case 29: // Write failure
9934: // case 30: // Read failure
9935: // case 82: // Cannot create subdirectory
9936: sda->error_class = 11; // Media
9937: break;
9938: case 80: // File already exists
9939: sda->error_class = 12; // Already exist
9940: break;
9941: default:
9942: sda->error_class = 13; // Unknown
9943: break;
9944: }
9945: sda->suggested_action = 1; // Retry
9946: sda->locus_of_last_error = 1; // Unknown
1.1 root 9947: }
9948: break;
9949: case 0x22:
9950: fatalerror("int 22h (terminate address)\n");
9951: case 0x23:
9952: msdos_process_terminate(current_psp, (retval & 0xff) | 0x100, 1);
9953: break;
9954: case 0x24:
9955: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
9956: break;
9957: case 0x25:
9958: msdos_int_25h();
9959: break;
9960: case 0x26:
9961: msdos_int_26h();
9962: break;
9963: case 0x27:
9964: msdos_int_27h();
9965: break;
9966: case 0x28:
9967: Sleep(10);
9968: break;
9969: case 0x29:
9970: msdos_int_29h();
9971: break;
9972: case 0x2e:
9973: msdos_int_2eh();
9974: break;
9975: case 0x2f:
9976: // multiplex interrupt
9977: switch(REG8(AH)) {
1.1.1.22 root 9978: case 0x00: break;
9979: case 0x01: msdos_int_2fh_01h(); break;
9980: case 0x05: msdos_int_2fh_05h(); break;
9981: case 0x06: msdos_int_2fh_06h(); break;
9982: case 0x08: msdos_int_2fh_08h(); break;
9983: case 0x10: msdos_int_2fh_10h(); break;
9984: case 0x11: msdos_int_2fh_11h(); break;
1.1.1.21 root 9985: case 0x12: msdos_int_2fh_12h(); break;
1.1.1.22 root 9986: case 0x14: msdos_int_2fh_14h(); break;
9987: case 0x15: msdos_int_2fh_15h(); break;
1.1 root 9988: case 0x16: msdos_int_2fh_16h(); break;
1.1.1.22 root 9989: case 0x19: msdos_int_2fh_19h(); break;
1.1 root 9990: case 0x1a: msdos_int_2fh_1ah(); break;
1.1.1.22 root 9991: case 0x1b: msdos_int_2fh_1bh(); break;
1.1 root 9992: case 0x43: msdos_int_2fh_43h(); break;
1.1.1.22 root 9993: case 0x46: msdos_int_2fh_46h(); break;
9994: case 0x48: msdos_int_2fh_48h(); break;
1.1 root 9995: case 0x4a: msdos_int_2fh_4ah(); break;
1.1.1.22 root 9996: case 0x4b: msdos_int_2fh_4bh(); break;
9997: case 0x4c: break; // unknown
9998: case 0x4d: break; // unknown
9999: case 0x4e: break; // unknown
1.1 root 10000: case 0x4f: msdos_int_2fh_4fh(); break;
1.1.1.22 root 10001: case 0x55: msdos_int_2fh_55h(); break;
10002: case 0x58: break; // unknown
10003: case 0x74: break; // unknown
1.1.1.24! root 10004: case 0xad: msdos_int_2fh_adh(); break;
1.1 root 10005: case 0xae: msdos_int_2fh_aeh(); break;
10006: case 0xb7: msdos_int_2fh_b7h(); break;
1.1.1.22 root 10007: case 0xe9: break; // unknown
10008: case 0xfe: break; // norton utilities ???
10009: default:
10010: 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));
10011: break;
1.1 root 10012: }
10013: break;
1.1.1.24! root 10014: case 0x33:
! 10015: switch(REG8(AH)) {
! 10016: case 0x00:
! 10017: // Mouse
! 10018: switch(REG8(AL)) {
! 10019: case 0x00: msdos_int_33h_0000h(); break;
! 10020: case 0x01: msdos_int_33h_0001h(); break;
! 10021: case 0x02: msdos_int_33h_0002h(); break;
! 10022: case 0x03: msdos_int_33h_0003h(); break;
! 10023: case 0x04: break; // position mouse cursor
! 10024: case 0x05: msdos_int_33h_0005h(); break;
! 10025: case 0x06: msdos_int_33h_0006h(); break;
! 10026: case 0x07: msdos_int_33h_0007h(); break;
! 10027: case 0x08: msdos_int_33h_0008h(); break;
! 10028: case 0x09: msdos_int_33h_0009h(); break;
! 10029: case 0x0a: break; // define text cursor
! 10030: case 0x0b: msdos_int_33h_000bh(); break;
! 10031: case 0x0c: msdos_int_33h_000ch(); break;
! 10032: case 0x0d: break; // light pen emulation on
! 10033: case 0x0e: break; // light pen emulation off
! 10034: case 0x0f: msdos_int_33h_000fh(); break;
! 10035: case 0x10: break; // define screen region for updating
! 10036: case 0x11: msdos_int_33h_0011h(); break;
! 10037: case 0x12: REG16(AX) = 0xffff; break; // set large graphics cursor block
! 10038: case 0x13: break; // define double-speed threshold
! 10039: case 0x14: msdos_int_33h_0014h(); break;
! 10040: case 0x15: msdos_int_33h_0015h(); break;
! 10041: case 0x16: msdos_int_33h_0016h(); break;
! 10042: case 0x17: msdos_int_33h_0017h(); break;
! 10043: case 0x1a: msdos_int_33h_001ah(); break;
! 10044: case 0x1b: msdos_int_33h_001bh(); break;
! 10045: case 0x1d: msdos_int_33h_001dh(); break;
! 10046: case 0x1e: msdos_int_33h_001eh(); break;
! 10047: case 0x21: msdos_int_33h_0021h(); break;
! 10048: case 0x22: msdos_int_33h_0022h(); break;
! 10049: case 0x23: msdos_int_33h_0023h(); break;
! 10050: case 0x24: msdos_int_33h_0024h(); break;
! 10051: case 0x26: msdos_int_33h_0026h(); break;
! 10052: case 0x2a: msdos_int_33h_002ah(); break;
! 10053: case 0x2f: break; // mouse hardware reset
! 10054: case 0x31: msdos_int_33h_0031h(); break;
! 10055: case 0x32: msdos_int_33h_0032h(); break;
! 10056: default:
! 10057: 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));
! 10058: break;
! 10059: }
! 10060: break;
! 10061: default:
! 10062: 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));
! 10063: break;
! 10064: }
! 10065: break;
1.1.1.19 root 10066: case 0x68:
10067: // dummy interrupt for EMS (int 67h)
10068: switch(REG8(AH)) {
10069: case 0x40: msdos_int_67h_40h(); break;
10070: case 0x41: msdos_int_67h_41h(); break;
10071: case 0x42: msdos_int_67h_42h(); break;
10072: case 0x43: msdos_int_67h_43h(); break;
10073: case 0x44: msdos_int_67h_44h(); break;
10074: case 0x45: msdos_int_67h_45h(); break;
10075: case 0x46: msdos_int_67h_46h(); break;
10076: case 0x47: msdos_int_67h_47h(); break;
10077: case 0x48: msdos_int_67h_48h(); break;
1.1.1.20 root 10078: // 0x49: LIM EMS - Reserved - Get I/O Port Address (Undocumented in EMS 3.2)
10079: // 0x4a: LIM EMS - Reserved - Get Translation Array (Undocumented in EMS 3.2)
1.1.1.19 root 10080: case 0x4b: msdos_int_67h_4bh(); break;
10081: case 0x4c: msdos_int_67h_4ch(); break;
10082: case 0x4d: msdos_int_67h_4dh(); break;
1.1.1.20 root 10083: case 0x4e: msdos_int_67h_4eh(); break;
1.1.1.21 root 10084: case 0x4f: msdos_int_67h_4fh(); break;
1.1.1.20 root 10085: case 0x50: msdos_int_67h_50h(); break;
1.1.1.19 root 10086: case 0x51: msdos_int_67h_51h(); break;
1.1.1.20 root 10087: case 0x52: msdos_int_67h_52h(); break;
1.1.1.19 root 10088: case 0x53: msdos_int_67h_53h(); break;
10089: case 0x54: msdos_int_67h_54h(); break;
1.1.1.20 root 10090: // 0x55: LIM EMS 4.0 - Alter Page Map And JUMP
10091: // 0x56: LIM EMS 4.0 - Alter Page Map And CALL
10092: case 0x57: msdos_int_67h_57h(); break;
10093: case 0x58: msdos_int_67h_58h(); break;
10094: // 0x59: LIM EMS 4.0 - Get Expanded Memory Hardware Information (for DOS Kernel)
10095: case 0x5a: msdos_int_67h_5ah(); break;
10096: // 0x5b: LIM EMS 4.0 - Alternate Map Register Set (for DOS Kernel)
10097: // 0x5c: LIM EMS 4.0 - Prepate Expanded Memory Hardware For Warm Boot
10098: // 0x5d: LIM EMS 4.0 - Enable/Disable OS Function Set Functions (for DOS Kernel)
1.1.1.19 root 10099: default:
1.1.1.22 root 10100: 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 10101: REG8(AH) = 0x84;
10102: break;
10103: }
10104: break;
10105: #ifdef SUPPORT_XMS
10106: case 0x69:
10107: // dummy interrupt for XMS (call far)
10108: switch(REG8(AH)) {
10109: case 0x00: msdos_call_xms_00h(); break;
10110: case 0x01: msdos_call_xms_01h(); break;
10111: case 0x02: msdos_call_xms_02h(); break;
10112: case 0x03: msdos_call_xms_03h(); break;
10113: case 0x04: msdos_call_xms_04h(); break;
10114: case 0x05: msdos_call_xms_05h(); break;
10115: case 0x06: msdos_call_xms_06h(); break;
10116: case 0x07: msdos_call_xms_07h(); break;
10117: case 0x08: msdos_call_xms_08h(); break;
10118: case 0x09: msdos_call_xms_09h(); break;
10119: case 0x0a: msdos_call_xms_0ah(); break;
10120: case 0x0b: msdos_call_xms_0bh(); break;
10121: case 0x0c: msdos_call_xms_0ch(); break;
10122: case 0x0d: msdos_call_xms_0dh(); break;
10123: case 0x0e: msdos_call_xms_0eh(); break;
10124: case 0x0f: msdos_call_xms_0fh(); break;
10125: case 0x10: msdos_call_xms_10h(); break;
10126: case 0x11: msdos_call_xms_11h(); break;
10127: case 0x12: msdos_call_xms_12h(); break;
10128: // 0x88: XMS 3.0 - Query free extended memory
10129: // 0x89: XMS 3.0 - Allocate any extended memory
10130: // 0x8e: XMS 3.0 - Get extended EMB handle information
10131: // 0x8f: XMS 3.0 - Reallocate any extended memory block
10132: default:
1.1.1.22 root 10133: 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));
1.1.1.19 root 10134: REG16(AX) = 0x0000;
10135: REG8(BL) = 0x80;
10136: break;
10137: }
10138: break;
10139: #endif
10140: case 0x6a:
1.1.1.24! root 10141: // irq12 (mouse)
! 10142: mouse_push_ax = REG16(AX);
! 10143: mouse_push_bx = REG16(BX);
! 10144: mouse_push_cx = REG16(CX);
! 10145: mouse_push_dx = REG16(DX);
! 10146: mouse_push_si = REG16(SI);
! 10147: mouse_push_di = REG16(DI);
! 10148:
! 10149: if(mouse.active && mouse.call_addr.dw != 0) {
! 10150: REG16(AX) = mouse.status_irq;
! 10151: REG16(BX) = mouse.get_buttons();
! 10152: REG16(CX) = max(mouse.min_position.x, min(mouse.max_position.x, mouse.position.x));
! 10153: REG16(DX) = max(mouse.min_position.y, min(mouse.max_position.y, mouse.position.y));
! 10154: REG16(SI) = REG16(CX) * mouse.mickey.x / 8;
! 10155: REG16(DI) = REG16(DX) * mouse.mickey.y / 8;
! 10156:
! 10157: mem[0xfffd0 + 0x02] = 0x9a; // call far
! 10158: mem[0xfffd0 + 0x03] = mouse.call_addr.w.l & 0xff;
! 10159: mem[0xfffd0 + 0x04] = mouse.call_addr.w.l >> 8;
! 10160: mem[0xfffd0 + 0x05] = mouse.call_addr.w.h & 0xff;
! 10161: mem[0xfffd0 + 0x06] = mouse.call_addr.w.h >> 8;
! 10162: } else {
! 10163: mem[0xfffd0 + 0x02] = 0x90; // nop
! 10164: mem[0xfffd0 + 0x03] = 0x90; // nop
! 10165: mem[0xfffd0 + 0x04] = 0x90; // nop
! 10166: mem[0xfffd0 + 0x05] = 0x90; // nop
! 10167: mem[0xfffd0 + 0x06] = 0x90; // nop
! 10168: }
! 10169: break;
! 10170: case 0x6b:
! 10171: // end of irq12 (mouse)
! 10172: REG16(AX) = mouse_push_ax;
! 10173: REG16(BX) = mouse_push_bx;
! 10174: REG16(CX) = mouse_push_cx;
! 10175: REG16(DX) = mouse_push_dx;
! 10176: REG16(SI) = mouse_push_si;
! 10177: REG16(DI) = mouse_push_di;
! 10178:
! 10179: // EOI
! 10180: if((pic[1].isr &= ~(1 << 4)) == 0) {
! 10181: pic[0].isr &= ~(1 << 2); // master
! 10182: }
! 10183: pic_update();
! 10184: break;
! 10185: case 0x6c:
1.1.1.19 root 10186: // dummy interrupt for case map routine pointed in the country info
10187: if(REG8(AL) >= 0x80) {
10188: char tmp[2] = {0};
10189: tmp[0] = REG8(AL);
10190: my_strupr(tmp);
10191: REG8(AL) = tmp[0];
10192: }
10193: break;
1.1.1.8 root 10194: case 0x70:
10195: case 0x71:
10196: case 0x72:
10197: case 0x73:
10198: case 0x74:
10199: case 0x75:
10200: case 0x76:
10201: case 0x77:
10202: // EOI
10203: if((pic[1].isr &= ~(1 << (num - 0x70))) == 0) {
10204: pic[0].isr &= ~(1 << 2); // master
10205: }
10206: pic_update();
10207: break;
1.1 root 10208: default:
1.1.1.22 root 10209: // 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 10210: break;
10211: }
10212:
10213: // update cursor position
10214: if(cursor_moved) {
10215: CONSOLE_SCREEN_BUFFER_INFO csbi;
1.1.1.23 root 10216: GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
1.1.1.15 root 10217: if(!restore_console_on_exit) {
10218: scr_top = csbi.srWindow.Top;
10219: }
1.1 root 10220: mem[0x450 + mem[0x462] * 2] = csbi.dwCursorPosition.X;
1.1.1.14 root 10221: mem[0x451 + mem[0x462] * 2] = csbi.dwCursorPosition.Y - scr_top;
1.1 root 10222: cursor_moved = false;
10223: }
10224: }
10225:
10226: // init
10227:
10228: int msdos_init(int argc, char *argv[], char *envp[], int standard_env)
10229: {
10230: // init file handler
10231: memset(file_handler, 0, sizeof(file_handler));
10232: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
10233: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
10234: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
1.1.1.21 root 10235: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 10236: if(_open("stdaux.txt", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
1.1.1.21 root 10237: #else
10238: if(_open("NUL", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
10239: #endif
10240: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
1.1 root 10241: }
1.1.1.21 root 10242: #ifdef MAP_PRN_DEVICE_TO_FILE
1.1 root 10243: if(_open("stdprn.txt", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
1.1.1.21 root 10244: #else
10245: if(_open("NUL", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
1.1 root 10246: #endif
1.1.1.21 root 10247: msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0);
10248: }
1.1 root 10249: _dup2(0, DUP_STDIN);
10250: _dup2(1, DUP_STDOUT);
10251: _dup2(2, DUP_STDERR);
1.1.1.21 root 10252: _dup2(3, DUP_STDAUX);
10253: _dup2(4, DUP_STDPRN);
1.1 root 10254:
1.1.1.24! root 10255: // init mouse
! 10256: memset(&mouse, 0, sizeof(mouse));
! 10257: mouse.max_position.x = 8 * scr_width - 1;
! 10258: mouse.max_position.y = 8 * scr_height - 1;
! 10259: mouse.mickey.x = 8;
! 10260: mouse.mickey.y = 16;
! 10261:
1.1 root 10262: // init process
10263: memset(process, 0, sizeof(process));
10264:
1.1.1.13 root 10265: // init dtainfo
10266: msdos_dta_info_init();
10267:
1.1 root 10268: // init memory
10269: memset(mem, 0, sizeof(mem));
10270:
10271: // bios data area
1.1.1.23 root 10272: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 10273: CONSOLE_SCREEN_BUFFER_INFO csbi;
10274: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 10275: CONSOLE_FONT_INFO cfi;
10276: GetCurrentConsoleFont(hStdout, FALSE, &cfi);
10277:
10278: int regen = min(scr_width * scr_height * 2, 0x8000);
10279: text_vram_top_address = TEXT_VRAM_TOP;
10280: text_vram_end_address = text_vram_top_address + regen;
10281: shadow_buffer_top_address = SHADOW_BUF_TOP;
10282: shadow_buffer_end_address = shadow_buffer_top_address + regen;
10283:
10284: if(regen > 0x4000) {
10285: regen = 0x8000;
10286: vram_pages = 1;
10287: } else if(regen > 0x2000) {
10288: regen = 0x4000;
10289: vram_pages = 2;
10290: } else if(regen > 0x1000) {
10291: regen = 0x2000;
10292: vram_pages = 4;
10293: } else {
10294: regen = 0x1000;
10295: vram_pages = 8;
10296: }
1.1 root 10297:
1.1.1.14 root 10298: #ifdef SUPPORT_FPU
10299: *(UINT16 *)(mem + 0x410) = 0x22;
10300: #else
1.1 root 10301: *(UINT16 *)(mem + 0x410) = 0x20;
1.1.1.14 root 10302: #endif
1.1 root 10303: *(UINT16 *)(mem + 0x413) = MEMORY_END / 1024;
10304: *(UINT8 *)(mem + 0x449) = 0x03;//0x73;
1.1.1.14 root 10305: *(UINT16 *)(mem + 0x44a) = csbi.dwSize.X;
10306: *(UINT16 *)(mem + 0x44c) = regen;
1.1 root 10307: *(UINT16 *)(mem + 0x44e) = 0;
10308: *(UINT8 *)(mem + 0x450) = csbi.dwCursorPosition.X;
1.1.1.14 root 10309: *(UINT8 *)(mem + 0x451) = csbi.dwCursorPosition.Y - scr_top;
1.1 root 10310: *(UINT8 *)(mem + 0x460) = 7;
10311: *(UINT8 *)(mem + 0x461) = 7;
10312: *(UINT8 *)(mem + 0x462) = 0;
10313: *(UINT16 *)(mem + 0x463) = 0x3d4;
1.1.1.19 root 10314: *(UINT8 *)(mem + 0x465) = 0x09;
10315: *(UINT32 *)(mem + 0x46c) = get_ticks_since_midnight(timeGetTime());
1.1.1.14 root 10316: *(UINT8 *)(mem + 0x484) = csbi.srWindow.Bottom - csbi.srWindow.Top;
10317: *(UINT8 *)(mem + 0x485) = cfi.dwFontSize.Y;
10318: *(UINT8 *)(mem + 0x487) = 0x60;
10319: *(UINT8 *)(mem + 0x496) = 0x10; // enhanced keyboard installed
10320:
10321: // initial screen
10322: SMALL_RECT rect;
10323: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
10324: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
10325: for(int y = 0, ofs1 = TEXT_VRAM_TOP, ofs2 = SHADOW_BUF_TOP; y < scr_height; y++) {
10326: for(int x = 0; x < scr_width; x++) {
10327: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Char.AsciiChar;
10328: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Attributes;
10329: }
10330: }
1.1 root 10331:
10332: // dos info
10333: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
1.1.1.19 root 10334: dos_info->magic_word = 1;
1.1 root 10335: dos_info->first_mcb = MEMORY_TOP >> 4;
10336: dos_info->first_dpb.w.l = 0;
10337: dos_info->first_dpb.w.h = DPB_TOP >> 4;
10338: dos_info->first_sft.w.l = 0;
1.1.1.21 root 10339: dos_info->first_sft.w.h = SFT_TOP >> 4;
1.1.1.19 root 10340: dos_info->max_sector_len = 512;
10341: dos_info->disk_buf_info.w.l = offsetof(dos_info_t, disk_buf_heads);
10342: dos_info->disk_buf_info.w.h = DOS_INFO_TOP >> 4;
1.1 root 10343: dos_info->cds.w.l = 0;
10344: dos_info->cds.w.h = CDS_TOP >> 4;
10345: dos_info->fcb_table.w.l = 0;
10346: dos_info->fcb_table.w.h = FCB_TABLE_TOP >> 4;
10347: dos_info->last_drive = 'Z' - 'A' + 1;
10348: dos_info->buffers_x = 20;
10349: dos_info->buffers_y = 0;
1.1.1.14 root 10350: dos_info->boot_drive = 'C' - 'A' + 1;
1.1.1.19 root 10351: dos_info->nul_device.next_driver = 0xffffffffU;
10352: dos_info->nul_device.attributes = 0x8004U;
10353: dos_info->nul_device.strategy = 0xffffU;
10354: dos_info->nul_device.interrupt = 0xffffU;
10355: memcpy(dos_info->nul_device.dev_name, "NUL ", 8);
10356: dos_info->disk_buf_heads.w.l = 0;
10357: dos_info->disk_buf_heads.w.h = DISK_BUF_TOP >> 4;
1.1.1.20 root 10358: dos_info->first_umb_fcb = UMB_TOP >> 4;
10359: dos_info->first_mcb_2 = MEMORY_TOP >> 4;
1.1.1.17 root 10360:
1.1 root 10361: char *env;
10362: if((env = getenv("LASTDRIVE")) != NULL) {
10363: if(env[0] >= 'A' && env[0] <= 'Z') {
10364: dos_info->last_drive = env[0] - 'A' + 1;
10365: } else if(env[0] >= 'a' && env[0] <= 'z') {
10366: dos_info->last_drive = env[0] - 'a' + 1;
10367: }
10368: }
10369: if((env = getenv("windir")) != NULL) {
10370: if(env[0] >= 'A' && env[0] <= 'Z') {
10371: dos_info->boot_drive = env[0] - 'A' + 1;
10372: } else if(env[0] >= 'a' && env[0] <= 'z') {
10373: dos_info->boot_drive = env[0] - 'a' + 1;
10374: }
10375: }
1.1.1.3 root 10376: #if defined(HAS_I386)
1.1 root 10377: dos_info->i386_or_later = 1;
1.1.1.3 root 10378: #else
10379: dos_info->i386_or_later = 0;
10380: #endif
1.1.1.17 root 10381: dos_info->ext_mem_size = (min(MAX_MEM, 0x4000000) - 0x100000) >> 10;
1.1 root 10382:
1.1.1.19 root 10383: // init mcb
1.1 root 10384: int seg = MEMORY_TOP >> 4;
1.1.1.19 root 10385:
10386: // iret table
10387: // note: int 2eh vector should address the routine in command.com,
10388: // and some softwares invite (int 2eh vector segment) - 1 must address the mcb of command.com.
10389: // so move iret table into allocated memory block
10390: // http://www5c.biglobe.ne.jp/~ecb/assembler2/2_6.html
10391: msdos_mcb_create(seg++, 'M', -1, IRET_SIZE >> 4);
10392: IRET_TOP = seg << 4;
10393: seg += IRET_SIZE >> 4;
10394: memset(mem + IRET_TOP, 0xcf, IRET_SIZE);
10395:
10396: // dummy xms/ems device
10397: msdos_mcb_create(seg++, 'M', -1, XMS_SIZE >> 4);
10398: XMS_TOP = seg << 4;
10399: seg += XMS_SIZE >> 4;
10400:
10401: // environment
1.1 root 10402: msdos_mcb_create(seg++, 'M', -1, ENV_SIZE >> 4);
10403: int env_seg = seg;
10404: int ofs = 0;
1.1.1.24! root 10405: char env_path[8192] = "", *path, temp_path[MAX_PATH] = {0};
1.1 root 10406:
10407: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1.1.14 root 10408: if(_strnicmp(*p, "MSDOS_PATH=", 11) == 0) {
10409: sprintf(env_path, "%s;", *p + 11);
10410: break;
10411: }
10412: }
10413: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1.1.9 root 10414: if(_strnicmp(*p, "PATH=", 5) == 0) {
1.1.1.14 root 10415: strcat(env_path, *p + 5);
1.1.1.9 root 10416: break;
10417: }
10418: }
1.1.1.18 root 10419: if((path = getenv("MSDOS_COMSPEC")) != NULL ||
10420: (path = msdos_search_command_com(argv[0], env_path)) != NULL) {
1.1.1.15 root 10421: strcpy(comspec_path, path);
10422: }
1.1.1.24! root 10423: if((path = getenv("MSDOS_TEMP")) != NULL) {
! 10424: if(GetShortPathName(path, temp_path, MAX_PATH) == 0) {
! 10425: strcpy(temp_path, path);
! 10426: }
! 10427: }
1.1.1.15 root 10428:
1.1.1.9 root 10429: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1 root 10430: // lower to upper
10431: char tmp[ENV_SIZE], name[ENV_SIZE], value[ENV_SIZE];
10432: int value_pos = 0;
10433: strcpy(tmp, *p);
10434: for(int i = 0;; i++) {
10435: if(tmp[i] == '=') {
10436: tmp[i] = '\0';
10437: sprintf(name, ";%s;", tmp);
10438: strcpy(value, tmp + (value_pos = i + 1));
10439: tmp[i] = '=';
10440: break;
10441: } else if(tmp[i] >= 'a' && tmp[i] <= 'z') {
10442: tmp[i] = tmp[i] - 'a' + 'A';
10443: }
10444: }
1.1.1.18 root 10445: if(strncmp(tmp, "MSDOS_COMSPEC=", 14) == 0) {
10446: // ignore MSDOS_COMSPEC
1.1.1.24! root 10447: } else if(strncmp(tmp, "MSDOS_TEMP=", 11) == 0) {
! 10448: // ignore MSDOS_TEMP
1.1.1.18 root 10449: } else if(standard_env && strstr(";COMSPEC;INCLUDE;LIB;PATH;PROMPT;TEMP;TMP;TZ;", name) == NULL) {
10450: // ignore non standard environments
10451: } else {
1.1 root 10452: if(strncmp(tmp, "COMSPEC=", 8) == 0) {
1.1.1.14 root 10453: strcpy(tmp, "COMSPEC=C:\\COMMAND.COM");
1.1.1.24! root 10454: } else if(strncmp(tmp, "TEMP=", 5) == 0 && temp_path[0] != '\0') {
! 10455: sprintf(tmp, "TEMP=%s", temp_path);
! 10456: } else if(strncmp(tmp, "TMP=", 4) == 0 && temp_path[0] != '\0') {
! 10457: sprintf(tmp, "TMP=%s", temp_path);
1.1 root 10458: } else if(strncmp(tmp, "PATH=", 5) == 0 || strncmp(tmp, "TEMP=", 5) == 0 || strncmp(tmp, "TMP=", 4) == 0) {
10459: tmp[value_pos] = '\0';
10460: char *token = my_strtok(value, ";");
10461: while(token != NULL) {
10462: if(strlen(token) != 0) {
1.1.1.24! root 10463: char *path = msdos_remove_double_quote(token), short_path[MAX_PATH];
1.1.1.8 root 10464: if(strlen(path) != 0) {
1.1.1.24! root 10465: if(GetShortPathName(path, short_path, MAX_PATH) == 0) {
! 10466: strcat(tmp, path);
! 10467: } else {
! 10468: strcat(tmp, short_path);
! 10469: }
1.1.1.8 root 10470: strcat(tmp, ";");
1.1 root 10471: }
10472: }
10473: token = my_strtok(NULL, ";");
10474: }
10475: tmp[strlen(tmp) - 1] = '\0';
10476: my_strupr(tmp);
10477: }
10478: int len = strlen(tmp);
1.1.1.14 root 10479: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) {
1.1 root 10480: fatalerror("too many environments\n");
10481: }
10482: memcpy(mem + (seg << 4) + ofs, tmp, len);
10483: ofs += len + 1;
10484: }
10485: }
10486: seg += (ENV_SIZE >> 4);
10487:
10488: // psp
10489: msdos_mcb_create(seg++, 'M', -1, PSP_SIZE >> 4);
10490: current_psp = seg;
1.1.1.14 root 10491: msdos_psp_create(seg, seg + (PSP_SIZE >> 4), -1, env_seg);
1.1 root 10492: seg += (PSP_SIZE >> 4);
10493:
1.1.1.19 root 10494: // first free mcb in conventional memory
10495: msdos_mcb_create(seg, 'Z', 0, (MEMORY_END >> 4) - seg - 2);
1.1.1.8 root 10496: first_mcb = seg;
10497:
1.1.1.19 root 10498: // dummy mcb to link to umb
10499: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', -1, (UMB_TOP >> 4) - (MEMORY_END >> 4));
10500:
10501: // first free mcb in upper memory block
1.1.1.8 root 10502: msdos_mcb_create(UMB_TOP >> 4, 'Z', 0, (UMB_END >> 4) - (UMB_TOP >> 4) - 1);
1.1 root 10503:
1.1.1.19 root 10504: #ifdef SUPPORT_XMS
10505: // first free mcb in extended memory block
10506: msdos_mcb_create(EMB_TOP >> 4, 'Z', 0, (EMB_END >> 4) - (EMB_TOP >> 4) - 1);
10507: #endif
10508:
10509: // interrupt vector
10510: for(int i = 0; i < 0x80; i++) {
10511: *(UINT16 *)(mem + 4 * i + 0) = i;
10512: *(UINT16 *)(mem + 4 * i + 2) = (IRET_TOP >> 4);
10513: }
1.1.1.24! root 10514: *(UINT16 *)(mem + 4 * 0x08 + 0) = 0x0010; // FFFD:0010 irq0
! 10515: *(UINT16 *)(mem + 4 * 0x08 + 2) = 0xfffd;
! 10516: *(UINT16 *)(mem + 4 * 0x22 + 0) = 0x0000; // FFFF:0000 boot
1.1.1.19 root 10517: *(UINT16 *)(mem + 4 * 0x22 + 2) = 0xffff;
10518: *(UINT16 *)(mem + 4 * 0x67 + 0) = 0x0000; // ems
10519: *(UINT16 *)(mem + 4 * 0x67 + 2) = XMS_TOP >> 4;
1.1.1.24! root 10520: *(UINT16 *)(mem + 4 * 0x74 + 0) = 0x0000; // FFFD:0000 irq12
! 10521: *(UINT16 *)(mem + 4 * 0x74 + 2) = 0xfffd;
1.1.1.19 root 10522:
10523: // ems (int 67h) and xms (call far)
10524: mem[XMS_TOP + 0] = 0xcd; // int 68h (dummy)
10525: mem[XMS_TOP + 1] = 0x68;
10526: mem[XMS_TOP + 2] = 0xcf; // iret
10527: #ifdef SUPPORT_XMS
10528: if(support_xms) {
10529: mem[XMS_TOP + 4] = 0xcd; // int 69h (dummy)
10530: mem[XMS_TOP + 5] = 0x69;
10531: mem[XMS_TOP + 6] = 0xcb; // retf
10532: } else
10533: #endif
10534: mem[XMS_TOP + 4] = 0xcb; // retf
10535: memcpy(mem + XMS_TOP + 0x0a, "EMMXXXX0", 8);
10536:
1.1.1.24! root 10537: // irq12 (mouse)
! 10538: mem[0xfffd0 + 0x00] = 0xcd; // int 6ah (dummy)
! 10539: mem[0xfffd0 + 0x01] = 0x6a;
! 10540: mem[0xfffd0 + 0x02] = 0x9a; // call far mouse
! 10541: mem[0xfffd0 + 0x03] = 0xff;
! 10542: mem[0xfffd0 + 0x04] = 0xff;
! 10543: mem[0xfffd0 + 0x05] = 0xff;
! 10544: mem[0xfffd0 + 0x06] = 0xff;
! 10545: mem[0xfffd0 + 0x07] = 0xcd; // int 6bh (dummy)
! 10546: mem[0xfffd0 + 0x08] = 0x6b;
! 10547: mem[0xfffd0 + 0x09] = 0xcf; // iret
! 10548:
1.1.1.19 root 10549: // case map routine (call far)
1.1.1.24! root 10550: mem[0xfffd0 + 0x0c] = 0xcd; // int 6ch (dummy)
! 10551: mem[0xfffd0 + 0x0d] = 0x6b;
! 10552: mem[0xfffd0 + 0x0e] = 0xcb; // retf
1.1.1.19 root 10553:
1.1.1.14 root 10554: // have irq0 call system timer tick
1.1.1.24! root 10555: mem[0xfffd0 + 0x10] = 0xcd; // int 1ch
! 10556: mem[0xfffd0 + 0x11] = 0x1c;
! 10557: mem[0xfffd0 + 0x12] = 0xea; // jmp far (IRET_TOP >> 4):0008
! 10558: mem[0xfffd0 + 0x13] = 0x08;
! 10559: mem[0xfffd0 + 0x14] = 0x00;
! 10560: mem[0xfffd0 + 0x15] = ((IRET_TOP >> 4) ) & 0xff;
! 10561: mem[0xfffd0 + 0x16] = ((IRET_TOP >> 4) >> 8) & 0xff;
1.1.1.14 root 10562:
1.1 root 10563: // boot
10564: mem[0xffff0] = 0xf4; // halt
10565: mem[0xffff1] = 0xcd; // int 21h
10566: mem[0xffff2] = 0x21;
10567: mem[0xffff3] = 0xcb; // retf
10568:
1.1.1.24! root 10569: mem[0xffff5] = '0'; // rom date
! 10570: mem[0xffff6] = '2';
! 10571: mem[0xffff7] = '/';
! 10572: mem[0xffff8] = '2';
! 10573: mem[0xffff9] = '2';
! 10574: mem[0xffffa] = '/';
! 10575: mem[0xffffb] = '0';
! 10576: mem[0xffffc] = '6';
! 10577: mem[0xffffe] = 0xfc; // machine id
! 10578: mem[0xfffff] = 0x00;
! 10579:
1.1 root 10580: // param block
10581: // + 0: param block (22bytes)
10582: // +24: fcb1/2 (20bytes)
10583: // +44: command tail (128bytes)
10584: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
10585: param->env_seg = 0;
10586: param->cmd_line.w.l = 44;
10587: param->cmd_line.w.h = (WORK_TOP >> 4);
10588: param->fcb1.w.l = 24;
10589: param->fcb1.w.h = (WORK_TOP >> 4);
10590: param->fcb2.w.l = 24;
10591: param->fcb2.w.h = (WORK_TOP >> 4);
10592:
10593: memset(mem + WORK_TOP + 24, 0x20, 20);
10594:
10595: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
10596: if(argc > 1) {
10597: sprintf(cmd_line->cmd, " %s", argv[1]);
10598: for(int i = 2; i < argc; i++) {
10599: char tmp[128];
10600: sprintf(tmp, "%s %s", cmd_line->cmd, argv[i]);
10601: strcpy(cmd_line->cmd, tmp);
10602: }
10603: cmd_line->len = (UINT8)strlen(cmd_line->cmd);
10604: } else {
10605: cmd_line->len = 0;
10606: }
10607: cmd_line->cmd[cmd_line->len] = 0x0d;
10608:
10609: // system file table
1.1.1.21 root 10610: *(UINT32 *)(mem + SFT_TOP + 0) = 0xffffffff;
10611: *(UINT16 *)(mem + SFT_TOP + 4) = 20;
1.1 root 10612:
1.1.1.19 root 10613: // disk buffer header (from DOSBox)
10614: *(UINT16 *)(mem + DISK_BUF_TOP + 0) = 0xffff; // forward ptr
10615: *(UINT16 *)(mem + DISK_BUF_TOP + 2) = 0xffff; // backward ptr
10616: *(UINT8 *)(mem + DISK_BUF_TOP + 4) = 0xff; // not in use
10617: *(UINT8 *)(mem + DISK_BUF_TOP + 10) = 0x01; // number of FATs
10618: *(UINT32 *)(mem + DISK_BUF_TOP + 13) = 0xffffffff; // pointer to DPB
10619:
1.1 root 10620: // current directory structure
10621: msdos_cds_update(_getdrive() - 1);
10622:
10623: // fcb table
10624: *(UINT32 *)(mem + FCB_TABLE_TOP + 0) = 0xffffffff;
1.1.1.14 root 10625: *(UINT16 *)(mem + FCB_TABLE_TOP + 4) = 0;
1.1 root 10626:
1.1.1.22 root 10627: // error table
10628: *(UINT8 *)(mem + ERR_TABLE_TOP + 0) = 0xff;
10629: *(UINT8 *)(mem + ERR_TABLE_TOP + 1) = 0x04;
10630: *(UINT8 *)(mem + ERR_TABLE_TOP + 2) = 0x00;
10631: *(UINT8 *)(mem + ERR_TABLE_TOP + 3) = 0x00;
10632:
1.1.1.17 root 10633: // nls stuff
10634: msdos_nls_tables_init();
1.1 root 10635:
10636: // execute command
10637: if(msdos_process_exec(argv[0], param, 0)) {
10638: fatalerror("'%s' not found\n", argv[0]);
10639: }
10640: retval = 0;
10641: return(0);
10642: }
10643:
10644: #define remove_std_file(path) { \
10645: int fd = _open(path, _O_RDONLY | _O_BINARY); \
10646: if(fd != -1) { \
10647: _lseek(fd, 0, SEEK_END); \
10648: int size = _tell(fd); \
10649: _close(fd); \
10650: if(size == 0) { \
10651: remove(path); \
10652: } \
10653: } \
10654: }
10655:
10656: void msdos_finish()
10657: {
10658: for(int i = 0; i < MAX_FILES; i++) {
10659: if(file_handler[i].valid) {
10660: _close(i);
10661: }
10662: }
1.1.1.21 root 10663: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 10664: remove_std_file("stdaux.txt");
1.1.1.21 root 10665: #endif
10666: #ifdef MAP_PRN_DEVICE_TO_FILE
1.1 root 10667: remove_std_file("stdprn.txt");
10668: #endif
10669: msdos_dbcs_table_finish();
10670: }
10671:
10672: /* ----------------------------------------------------------------------------
10673: PC/AT hardware emulation
10674: ---------------------------------------------------------------------------- */
10675:
10676: void hardware_init()
10677: {
1.1.1.3 root 10678: CPU_INIT_CALL(CPU_MODEL);
1.1 root 10679: CPU_RESET_CALL(CPU_MODEL);
1.1.1.14 root 10680: m_IF = 1;
1.1.1.3 root 10681: #if defined(HAS_I386)
1.1 root 10682: cpu_type = (REG32(EDX) >> 8) & 0x0f;
10683: cpu_step = (REG32(EDX) >> 0) & 0x0f;
1.1.1.3 root 10684: #endif
10685: i386_set_a20_line(0);
1.1.1.14 root 10686:
1.1.1.19 root 10687: ems_init();
1.1 root 10688: pic_init();
1.1.1.8 root 10689: #ifdef PIT_ALWAYS_RUNNING
10690: pit_init();
10691: #else
1.1 root 10692: pit_active = 0;
10693: #endif
1.1.1.8 root 10694: cmos_init();
10695: kbd_init();
1.1 root 10696: }
10697:
1.1.1.10 root 10698: void hardware_finish()
10699: {
10700: #if defined(HAS_I386)
10701: vtlb_free(m_vtlb);
10702: #endif
1.1.1.19 root 10703: ems_finish();
1.1.1.10 root 10704: }
10705:
1.1 root 10706: void hardware_run()
10707: {
10708: int ops = 0;
10709:
1.1.1.22 root 10710: #ifdef EXPORT_DEBUG_TO_FILE
10711: fdebug = fopen("debug.log", "w");
10712: #endif
1.1.1.3 root 10713: while(!m_halted) {
1.1.1.22 root 10714: #ifdef ENABLE_DEBUG_DASM
10715: if(dasm > 0) {
1.1 root 10716: char buffer[256];
1.1.1.3 root 10717: #if defined(HAS_I386)
1.1.1.22 root 10718: UINT32 flags = get_flags();
1.1.1.19 root 10719: UINT32 eip = m_eip;
1.1.1.3 root 10720: #else
1.1.1.22 root 10721: UINT32 flags = CompressFlags();
1.1.1.19 root 10722: UINT32 eip = m_pc - SREG_BASE(CS);
1.1.1.3 root 10723: #endif
10724: UINT8 *oprom = mem + SREG_BASE(CS) + eip;
1.1 root 10725:
1.1.1.3 root 10726: #if defined(HAS_I386)
10727: if(m_operand_size) {
1.1 root 10728: CPU_DISASSEMBLE_CALL(x86_32);
1.1.1.3 root 10729: } else
10730: #endif
10731: CPU_DISASSEMBLE_CALL(x86_16);
1.1.1.22 root 10732:
10733: 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",
10734: 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,
10735: #if defined(HAS_I386)
10736: PROTECTED_MODE ? "PE" : "--",
10737: #else
10738: "--",
10739: #endif
10740: (flags & 0x40000) ? 'A' : '-',
10741: (flags & 0x20000) ? 'V' : '-',
10742: (flags & 0x10000) ? 'R' : '-',
10743: (flags & 0x04000) ? 'N' : '-',
10744: (flags & 0x02000) ? '1' : '0',
10745: (flags & 0x01000) ? '1' : '0',
10746: (flags & 0x00800) ? 'O' : '-',
10747: (flags & 0x00400) ? 'D' : '-',
10748: (flags & 0x00200) ? 'I' : '-',
10749: (flags & 0x00100) ? 'T' : '-',
10750: (flags & 0x00080) ? 'S' : '-',
10751: (flags & 0x00040) ? 'Z' : '-',
10752: (flags & 0x00010) ? 'A' : '-',
10753: (flags & 0x00004) ? 'P' : '-',
10754: (flags & 0x00001) ? 'C' : '-');
10755: fprintf(fdebug, "%04X:%04X\t%s\n", SREG(CS), (unsigned)eip, buffer);
10756: dasm--;
1.1 root 10757: }
10758: #endif
1.1.1.3 root 10759: #if defined(HAS_I386)
10760: m_cycles = 1;
1.1 root 10761: CPU_EXECUTE_CALL(i386);
1.1.1.3 root 10762: #else
10763: CPU_EXECUTE_CALL(CPU_MODEL);
10764: #endif
1.1.1.14 root 10765: #if defined(HAS_I386)
10766: if(m_eip != m_prev_eip) {
10767: #else
10768: if(m_pc != m_prevpc) {
10769: #endif
10770: iops++;
10771: }
1.1.1.8 root 10772: if(++ops == 16384) {
1.1 root 10773: hardware_update();
10774: ops = 0;
10775: }
10776: }
1.1.1.22 root 10777: #ifdef EXPORT_DEBUG_TO_FILE
10778: fclose(fdebug);
10779: #endif
1.1 root 10780: }
10781:
10782: void hardware_update()
10783: {
1.1.1.8 root 10784: static UINT32 prev_time = 0;
10785: UINT32 cur_time = timeGetTime();
10786:
10787: if(prev_time != cur_time) {
10788: // update pit and raise irq0
10789: #ifndef PIT_ALWAYS_RUNNING
10790: if(pit_active)
10791: #endif
10792: {
10793: if(pit_run(0, cur_time)) {
10794: pic_req(0, 0, 1);
10795: }
10796: pit_run(1, cur_time);
10797: pit_run(2, cur_time);
10798: }
1.1.1.24! root 10799:
! 10800: // update keyboard and mouse
1.1.1.14 root 10801: static UINT32 prev_tick = 0;
10802: UINT32 cur_tick = cur_time / 32;
10803: if(prev_tick != cur_tick) {
10804: // update keyboard flags
10805: UINT8 state;
1.1.1.24! root 10806: state = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
! 10807: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x0001) ? 0x40 : 0;
! 10808: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x0001) ? 0x20 : 0;
! 10809: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
! 10810: state |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
! 10811: state |= (GetAsyncKeyState(VK_CONTROL ) & 0x8000) ? 0x04 : 0;
! 10812: state |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
! 10813: state |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
1.1.1.14 root 10814: mem[0x417] = state;
10815: state = (GetAsyncKeyState(VK_INSERT ) & 0x8000) ? 0x80 : 0;
10816: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
10817: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
10818: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
1.1.1.24! root 10819: // state |= (GetAsyncKeyState(VK_PAUSE ) & 0x0001) ? 0x08 : 0;
! 10820: // state |= (GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x04 : 0;
1.1.1.14 root 10821: state |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
10822: state |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
10823: mem[0x418] = state;
10824:
1.1.1.24! root 10825: // update console input if needed
! 10826: if(!key_changed || mouse.active) {
! 10827: update_console_input();
! 10828: }
! 10829:
! 10830: // raise irq1 if key is pressed/released
! 10831: if(key_changed) {
1.1.1.8 root 10832: pic_req(0, 1, 1);
1.1.1.24! root 10833: key_changed = false;
! 10834: }
! 10835:
! 10836: // raise irq12 if mouse status is changed
! 10837: if(mouse.status & mouse.call_mask) {
! 10838: if(mouse.active) {
! 10839: pic_req(1, 4, 1);
! 10840: mouse.status_irq = mouse.status & mouse.call_mask;
! 10841: }
! 10842: mouse.status &= ~mouse.call_mask;
1.1.1.8 root 10843: }
1.1.1.24! root 10844:
1.1.1.14 root 10845: prev_tick = cur_tick;
1.1.1.8 root 10846: }
1.1.1.24! root 10847:
1.1.1.19 root 10848: // update daily timer counter
10849: pcbios_update_daily_timer_counter(cur_time);
1.1.1.8 root 10850: prev_time = cur_time;
1.1 root 10851: }
10852: }
10853:
1.1.1.19 root 10854: // ems
10855:
10856: void ems_init()
10857: {
10858: memset(ems_handles, 0, sizeof(ems_handles));
10859: memset(ems_pages, 0, sizeof(ems_pages));
10860: free_ems_pages = MAX_EMS_PAGES;
10861: }
10862:
10863: void ems_finish()
10864: {
10865: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
10866: if(ems_handles[i].buffer) {
10867: free(ems_handles[i].buffer);
10868: ems_handles[i].buffer = NULL;
10869: }
10870: }
10871: }
10872:
10873: void ems_allocate_pages(int handle, int pages)
10874: {
10875: if(pages > 0) {
10876: ems_handles[handle].buffer = (UINT8 *)calloc(1, 0x4000 * pages);
10877: } else {
10878: ems_handles[handle].buffer = NULL;
10879: }
10880: ems_handles[handle].pages = pages;
10881: ems_handles[handle].allocated = true;
10882: free_ems_pages -= pages;
10883: }
10884:
10885: void ems_reallocate_pages(int handle, int pages)
10886: {
10887: if(ems_handles[handle].allocated) {
10888: if(ems_handles[handle].pages != pages) {
10889: UINT8 *new_buffer = NULL;
10890:
10891: if(pages > 0) {
10892: new_buffer = (UINT8 *)calloc(1, 0x4000 * pages);
10893: }
10894: if(ems_handles[handle].buffer) {
10895: if(new_buffer) {
10896: if(pages > ems_handles[handle].pages) {
10897: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * ems_handles[handle].pages);
10898: } else {
10899: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * pages);
10900: }
10901: }
10902: free(ems_handles[handle].buffer);
10903: ems_handles[handle].buffer = NULL;
10904: }
10905: free_ems_pages += ems_handles[handle].pages;
10906:
10907: ems_handles[handle].buffer = new_buffer;
10908: ems_handles[handle].pages = pages;
10909: free_ems_pages -= pages;
10910: }
10911: } else {
10912: ems_allocate_pages(handle, pages);
10913: }
10914: }
10915:
10916: void ems_release_pages(int handle)
10917: {
10918: if(ems_handles[handle].allocated) {
10919: if(ems_handles[handle].buffer) {
10920: free(ems_handles[handle].buffer);
10921: ems_handles[handle].buffer = NULL;
10922: }
10923: free_ems_pages += ems_handles[handle].pages;
10924: ems_handles[handle].allocated = false;
10925: }
10926: }
10927:
10928: void ems_map_page(int physical, int handle, int logical)
10929: {
10930: if(ems_pages[physical].mapped) {
10931: if(ems_pages[physical].handle == handle && ems_pages[physical].page == logical) {
10932: return;
10933: }
10934: ems_unmap_page(physical);
10935: }
10936: if(ems_handles[handle].allocated && ems_handles[handle].buffer && logical < ems_handles[handle].pages) {
10937: memcpy(mem + EMS_TOP + 0x4000 * physical, ems_handles[handle].buffer + 0x4000 * logical, 0x4000);
10938: }
10939: ems_pages[physical].handle = handle;
10940: ems_pages[physical].page = logical;
10941: ems_pages[physical].mapped = true;
10942: }
10943:
10944: void ems_unmap_page(int physical)
10945: {
10946: if(ems_pages[physical].mapped) {
10947: int handle = ems_pages[physical].handle;
10948: int logical = ems_pages[physical].page;
10949:
10950: if(ems_handles[handle].allocated && ems_handles[handle].buffer && logical < ems_handles[handle].pages) {
10951: memcpy(ems_handles[handle].buffer + 0x4000 * logical, mem + EMS_TOP + 0x4000 * physical, 0x4000);
10952: }
10953: ems_pages[physical].mapped = false;
10954: }
10955: }
10956:
1.1 root 10957: // pic
10958:
10959: void pic_init()
10960: {
1.1.1.8 root 10961: memset(pic, 0, sizeof(pic));
10962: pic[0].imr = pic[1].imr = 0xff;
1.1 root 10963:
10964: // from bochs bios
10965: pic_write(0, 0, 0x11); // icw1 = 11h
10966: pic_write(0, 1, 0x08); // icw2 = 08h
10967: pic_write(0, 1, 0x04); // icw3 = 04h
10968: pic_write(0, 1, 0x01); // icw4 = 01h
10969: pic_write(0, 1, 0xb8); // ocw1 = b8h
10970: pic_write(1, 0, 0x11); // icw1 = 11h
10971: pic_write(1, 1, 0x70); // icw2 = 70h
10972: pic_write(1, 1, 0x02); // icw3 = 02h
10973: pic_write(1, 1, 0x01); // icw4 = 01h
10974: }
10975:
10976: void pic_write(int c, UINT32 addr, UINT8 data)
10977: {
10978: if(addr & 1) {
10979: if(pic[c].icw2_r) {
10980: // icw2
10981: pic[c].icw2 = data;
10982: pic[c].icw2_r = 0;
10983: } else if(pic[c].icw3_r) {
10984: // icw3
10985: pic[c].icw3 = data;
10986: pic[c].icw3_r = 0;
10987: } else if(pic[c].icw4_r) {
10988: // icw4
10989: pic[c].icw4 = data;
10990: pic[c].icw4_r = 0;
10991: } else {
10992: // ocw1
10993: pic[c].imr = data;
10994: }
10995: } else {
10996: if(data & 0x10) {
10997: // icw1
10998: pic[c].icw1 = data;
10999: pic[c].icw2_r = 1;
11000: pic[c].icw3_r = (data & 2) ? 0 : 1;
11001: pic[c].icw4_r = data & 1;
11002: pic[c].irr = 0;
11003: pic[c].isr = 0;
11004: pic[c].imr = 0;
11005: pic[c].prio = 0;
11006: if(!(pic[c].icw1 & 1)) {
11007: pic[c].icw4 = 0;
11008: }
11009: pic[c].ocw3 = 0;
11010: } else if(data & 8) {
11011: // ocw3
11012: if(!(data & 2)) {
11013: data = (data & ~1) | (pic[c].ocw3 & 1);
11014: }
11015: if(!(data & 0x40)) {
11016: data = (data & ~0x20) | (pic[c].ocw3 & 0x20);
11017: }
11018: pic[c].ocw3 = data;
11019: } else {
11020: // ocw2
11021: int level = 0;
11022: if(data & 0x40) {
11023: level = data & 7;
11024: } else {
11025: if(!pic[c].isr) {
11026: return;
11027: }
11028: level = pic[c].prio;
11029: while(!(pic[c].isr & (1 << level))) {
11030: level = (level + 1) & 7;
11031: }
11032: }
11033: if(data & 0x80) {
11034: pic[c].prio = (level + 1) & 7;
11035: }
11036: if(data & 0x20) {
11037: pic[c].isr &= ~(1 << level);
11038: }
11039: }
11040: }
11041: pic_update();
11042: }
11043:
11044: UINT8 pic_read(int c, UINT32 addr)
11045: {
11046: if(addr & 1) {
11047: return(pic[c].imr);
11048: } else {
11049: // polling mode is not supported...
11050: //if(pic[c].ocw3 & 4) {
11051: // return ???;
11052: //}
11053: if(pic[c].ocw3 & 1) {
11054: return(pic[c].isr);
11055: } else {
11056: return(pic[c].irr);
11057: }
11058: }
11059: }
11060:
11061: void pic_req(int c, int level, int signal)
11062: {
11063: if(signal) {
11064: pic[c].irr |= (1 << level);
11065: } else {
11066: pic[c].irr &= ~(1 << level);
11067: }
11068: pic_update();
11069: }
11070:
11071: int pic_ack()
11072: {
11073: // ack (INTA=L)
11074: pic[pic_req_chip].isr |= pic_req_bit;
11075: pic[pic_req_chip].irr &= ~pic_req_bit;
11076: if(pic_req_chip > 0) {
11077: // update isr and irr of master
11078: UINT8 slave = 1 << (pic[pic_req_chip].icw3 & 7);
11079: pic[pic_req_chip - 1].isr |= slave;
11080: pic[pic_req_chip - 1].irr &= ~slave;
11081: }
11082: //if(pic[pic_req_chip].icw4 & 1) {
11083: // 8086 mode
11084: int vector = (pic[pic_req_chip].icw2 & 0xf8) | pic_req_level;
11085: //} else {
11086: // // 8080 mode
11087: // UINT16 addr = (UINT16)pic[pic_req_chip].icw2 << 8;
11088: // if(pic[pic_req_chip].icw1 & 4) {
11089: // addr |= (pic[pic_req_chip].icw1 & 0xe0) | (pic_req_level << 2);
11090: // } else {
11091: // addr |= (pic[pic_req_chip].icw1 & 0xc0) | (pic_req_level << 3);
11092: // }
11093: // vector = 0xcd | (addr << 8);
11094: //}
11095: if(pic[pic_req_chip].icw4 & 2) {
11096: // auto eoi
11097: pic[pic_req_chip].isr &= ~pic_req_bit;
11098: }
11099: return(vector);
11100: }
11101:
11102: void pic_update()
11103: {
11104: for(int c = 0; c < 2; c++) {
11105: UINT8 irr = pic[c].irr;
11106: if(c + 1 < 2) {
11107: // this is master
11108: if(pic[c + 1].irr & (~pic[c + 1].imr)) {
11109: // request from slave
11110: irr |= 1 << (pic[c + 1].icw3 & 7);
11111: }
11112: }
11113: irr &= (~pic[c].imr);
11114: if(!irr) {
11115: break;
11116: }
11117: if(!(pic[c].ocw3 & 0x20)) {
11118: irr |= pic[c].isr;
11119: }
11120: int level = pic[c].prio;
11121: UINT8 bit = 1 << level;
11122: while(!(irr & bit)) {
11123: level = (level + 1) & 7;
11124: bit = 1 << level;
11125: }
11126: if((c + 1 < 2) && (pic[c].icw3 & bit)) {
11127: // check slave
11128: continue;
11129: }
11130: if(pic[c].isr & bit) {
11131: break;
11132: }
11133: // interrupt request
11134: pic_req_chip = c;
11135: pic_req_level = level;
11136: pic_req_bit = bit;
1.1.1.3 root 11137: i386_set_irq_line(INPUT_LINE_IRQ, HOLD_LINE);
1.1 root 11138: return;
11139: }
1.1.1.3 root 11140: i386_set_irq_line(INPUT_LINE_IRQ, CLEAR_LINE);
1.1.1.2 root 11141: }
1.1 root 11142:
11143: // pit
11144:
1.1.1.22 root 11145: #define PIT_FREQ 1193182ULL
1.1 root 11146: #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)
11147:
11148: void pit_init()
11149: {
1.1.1.8 root 11150: memset(pit, 0, sizeof(pit));
1.1 root 11151: for(int ch = 0; ch < 3; ch++) {
11152: pit[ch].count = 0x10000;
11153: pit[ch].ctrl_reg = 0x34;
11154: pit[ch].mode = 3;
11155: }
11156:
11157: // from bochs bios
11158: pit_write(3, 0x34);
11159: pit_write(0, 0x00);
11160: pit_write(0, 0x00);
11161: }
11162:
11163: void pit_write(int ch, UINT8 val)
11164: {
1.1.1.8 root 11165: #ifndef PIT_ALWAYS_RUNNING
1.1 root 11166: if(!pit_active) {
11167: pit_active = 1;
11168: pit_init();
11169: }
1.1.1.8 root 11170: #endif
1.1 root 11171: switch(ch) {
11172: case 0:
11173: case 1:
11174: case 2:
11175: // write count register
11176: if(!pit[ch].low_write && !pit[ch].high_write) {
11177: if(pit[ch].ctrl_reg & 0x10) {
11178: pit[ch].low_write = 1;
11179: }
11180: if(pit[ch].ctrl_reg & 0x20) {
11181: pit[ch].high_write = 1;
11182: }
11183: }
11184: if(pit[ch].low_write) {
11185: pit[ch].count_reg = val;
11186: pit[ch].low_write = 0;
11187: } else if(pit[ch].high_write) {
11188: if((pit[ch].ctrl_reg & 0x30) == 0x20) {
11189: pit[ch].count_reg = val << 8;
11190: } else {
11191: pit[ch].count_reg |= val << 8;
11192: }
11193: pit[ch].high_write = 0;
11194: }
11195: // start count
1.1.1.8 root 11196: if(!pit[ch].low_write && !pit[ch].high_write) {
11197: if(pit[ch].mode == 0 || pit[ch].mode == 4 || pit[ch].prev_time == 0) {
11198: pit[ch].count = PIT_COUNT_VALUE(ch);
11199: pit[ch].prev_time = timeGetTime();
11200: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 11201: }
11202: }
11203: break;
11204: case 3: // ctrl reg
11205: if((val & 0xc0) == 0xc0) {
11206: // i8254 read-back command
11207: for(ch = 0; ch < 3; ch++) {
11208: if(!(val & 0x10) && !pit[ch].status_latched) {
11209: pit[ch].status = pit[ch].ctrl_reg & 0x3f;
11210: pit[ch].status_latched = 1;
11211: }
11212: if(!(val & 0x20) && !pit[ch].count_latched) {
11213: pit_latch_count(ch);
11214: }
11215: }
11216: break;
11217: }
11218: ch = (val >> 6) & 3;
11219: if(val & 0x30) {
11220: static int modes[8] = {0, 1, 2, 3, 4, 5, 2, 3};
11221: pit[ch].mode = modes[(val >> 1) & 7];
11222: pit[ch].count_latched = 0;
11223: pit[ch].low_read = pit[ch].high_read = 0;
11224: pit[ch].low_write = pit[ch].high_write = 0;
11225: pit[ch].ctrl_reg = val;
11226: // stop count
1.1.1.8 root 11227: pit[ch].prev_time = pit[ch].expired_time = 0;
1.1 root 11228: pit[ch].count_reg = 0;
11229: } else if(!pit[ch].count_latched) {
11230: pit_latch_count(ch);
11231: }
11232: break;
11233: }
11234: }
11235:
11236: UINT8 pit_read(int ch)
11237: {
1.1.1.8 root 11238: #ifndef PIT_ALWAYS_RUNNING
1.1 root 11239: if(!pit_active) {
11240: pit_active = 1;
11241: pit_init();
11242: }
1.1.1.8 root 11243: #endif
1.1 root 11244: switch(ch) {
11245: case 0:
11246: case 1:
11247: case 2:
11248: if(pit[ch].status_latched) {
11249: pit[ch].status_latched = 0;
11250: return(pit[ch].status);
11251: }
11252: // if not latched, through current count
11253: if(!pit[ch].count_latched) {
11254: if(!pit[ch].low_read && !pit[ch].high_read) {
11255: pit_latch_count(ch);
11256: }
11257: }
11258: // return latched count
11259: if(pit[ch].low_read) {
11260: pit[ch].low_read = 0;
11261: if(!pit[ch].high_read) {
11262: pit[ch].count_latched = 0;
11263: }
11264: return(pit[ch].latch & 0xff);
11265: } else if(pit[ch].high_read) {
11266: pit[ch].high_read = 0;
11267: pit[ch].count_latched = 0;
11268: return((pit[ch].latch >> 8) & 0xff);
11269: }
11270: }
11271: return(0xff);
11272: }
11273:
1.1.1.8 root 11274: int pit_run(int ch, UINT32 cur_time)
1.1 root 11275: {
1.1.1.8 root 11276: if(pit[ch].expired_time != 0 && cur_time >= pit[ch].expired_time) {
1.1 root 11277: pit[ch].count = PIT_COUNT_VALUE(ch);
1.1.1.8 root 11278: pit[ch].prev_time = pit[ch].expired_time;
11279: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
11280: if(cur_time >= pit[ch].expired_time) {
11281: pit[ch].prev_time = cur_time;
11282: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 11283: }
1.1.1.8 root 11284: return(1);
1.1 root 11285: }
1.1.1.8 root 11286: return(0);
1.1 root 11287: }
11288:
11289: void pit_latch_count(int ch)
11290: {
1.1.1.8 root 11291: UINT32 cur_time = timeGetTime();
11292:
11293: if(pit[ch].expired_time != 0) {
11294: pit_run(ch, cur_time);
11295: UINT32 tmp = (pit[ch].count * (pit[ch].expired_time - cur_time)) / (pit[ch].expired_time - pit[ch].prev_time);
11296: pit[ch].latch = (tmp != 0) ? (UINT16)tmp : 1;
11297: } else {
11298: pit[ch].latch = (UINT16)pit[ch].count;
1.1 root 11299: }
11300: pit[ch].count_latched = 1;
11301: if((pit[ch].ctrl_reg & 0x30) == 0x10) {
11302: // lower byte
11303: pit[ch].low_read = 1;
11304: pit[ch].high_read = 0;
11305: } else if((pit[ch].ctrl_reg & 0x30) == 0x20) {
11306: // upper byte
11307: pit[ch].low_read = 0;
11308: pit[ch].high_read = 1;
11309: } else {
11310: // lower -> upper
1.1.1.14 root 11311: pit[ch].low_read = pit[ch].high_read = 1;
1.1 root 11312: }
11313: }
11314:
1.1.1.8 root 11315: int pit_get_expired_time(int ch)
1.1 root 11316: {
1.1.1.22 root 11317: pit[ch].accum += 1024ULL * 1000ULL * (UINT64)pit[ch].count / PIT_FREQ;
11318: UINT64 val = pit[ch].accum >> 10;
11319: pit[ch].accum -= val << 10;
11320: return((val != 0) ? val : 1);
1.1.1.8 root 11321: }
11322:
11323: // cmos
11324:
11325: void cmos_init()
11326: {
11327: memset(cmos, 0, sizeof(cmos));
11328: cmos_addr = 0;
1.1 root 11329:
1.1.1.8 root 11330: // from DOSBox
11331: cmos_write(0x0a, 0x26);
11332: cmos_write(0x0b, 0x02);
11333: cmos_write(0x0d, 0x80);
1.1 root 11334: }
11335:
1.1.1.8 root 11336: void cmos_write(int addr, UINT8 val)
1.1 root 11337: {
1.1.1.8 root 11338: cmos[addr & 0x7f] = val;
11339: }
11340:
11341: #define CMOS_GET_TIME() { \
11342: UINT32 cur_sec = timeGetTime() / 1000 ; \
11343: if(prev_sec != cur_sec) { \
11344: GetLocalTime(&time); \
11345: prev_sec = cur_sec; \
11346: } \
1.1 root 11347: }
1.1.1.8 root 11348: #define CMOS_BCD(v) ((cmos[0x0b] & 4) ? (v) : to_bcd(v))
1.1 root 11349:
1.1.1.8 root 11350: UINT8 cmos_read(int addr)
1.1 root 11351: {
1.1.1.8 root 11352: static SYSTEMTIME time;
11353: static UINT32 prev_sec = 0;
1.1 root 11354:
1.1.1.8 root 11355: switch(addr & 0x7f) {
11356: case 0x00: CMOS_GET_TIME(); return(CMOS_BCD(time.wSecond));
11357: case 0x02: CMOS_GET_TIME(); return(CMOS_BCD(time.wMinute));
11358: case 0x04: CMOS_GET_TIME(); return(CMOS_BCD(time.wHour));
11359: case 0x06: CMOS_GET_TIME(); return(time.wDayOfWeek + 1);
11360: case 0x07: CMOS_GET_TIME(); return(CMOS_BCD(time.wDay));
11361: case 0x08: CMOS_GET_TIME(); return(CMOS_BCD(time.wMonth));
11362: case 0x09: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear));
11363: // case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 2 ? 0x80 : 0)); // 2msec
11364: case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 20 ? 0x80 : 0)); // precision of timeGetTime() may not be 1msec
11365: case 0x15: return((MEMORY_END >> 10) & 0xff);
11366: case 0x16: return((MEMORY_END >> 18) & 0xff);
11367: case 0x17: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
11368: case 0x18: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
11369: case 0x30: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
11370: case 0x31: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
11371: case 0x32: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear / 100));
1.1 root 11372: }
1.1.1.8 root 11373: return(cmos[addr & 0x7f]);
1.1 root 11374: }
11375:
1.1.1.7 root 11376: // kbd (a20)
11377:
11378: void kbd_init()
11379: {
1.1.1.8 root 11380: kbd_data = kbd_command = 0;
1.1.1.7 root 11381: kbd_status = 0x18;
11382: }
11383:
11384: UINT8 kbd_read_data()
11385: {
1.1.1.8 root 11386: kbd_status &= ~1;
1.1.1.7 root 11387: return(kbd_data);
11388: }
11389:
11390: void kbd_write_data(UINT8 val)
11391: {
11392: switch(kbd_command) {
11393: case 0xd1:
11394: i386_set_a20_line((val >> 1) & 1);
11395: break;
11396: }
11397: kbd_command = 0;
1.1.1.8 root 11398: kbd_status &= ~8;
1.1.1.7 root 11399: }
11400:
11401: UINT8 kbd_read_status()
11402: {
11403: return(kbd_status);
11404: }
11405:
11406: void kbd_write_command(UINT8 val)
11407: {
11408: switch(val) {
11409: case 0xd0:
11410: kbd_data = ((m_a20_mask >> 19) & 2) | 1;
1.1.1.8 root 11411: kbd_status |= 1;
1.1.1.7 root 11412: break;
11413: case 0xdd:
11414: i386_set_a20_line(0);
11415: break;
11416: case 0xdf:
11417: i386_set_a20_line(1);
11418: break;
11419: case 0xf0:
11420: case 0xf1:
11421: case 0xf2:
11422: case 0xf3:
11423: case 0xf4:
11424: case 0xf5:
11425: case 0xf6:
11426: case 0xf7:
11427: case 0xf8:
11428: case 0xf9:
11429: case 0xfa:
11430: case 0xfb:
11431: case 0xfc:
11432: case 0xfd:
11433: case 0xfe:
11434: case 0xff:
11435: if(!(val & 1)) {
1.1.1.8 root 11436: if((cmos[0x0f] & 0x7f) == 5) {
1.1.1.7 root 11437: // reset pic
11438: pic_init();
11439: pic[0].irr = pic[1].irr = 0x00;
11440: pic[0].imr = pic[1].imr = 0xff;
11441: }
11442: CPU_RESET_CALL(CPU_MODEL);
11443: i386_jmp_far(0x40, 0x67);
11444: }
11445: i386_set_a20_line((val >> 1) & 1);
11446: break;
11447: }
11448: kbd_command = val;
1.1.1.8 root 11449: kbd_status |= 8;
1.1.1.7 root 11450: }
11451:
1.1.1.9 root 11452: // vga
11453:
11454: UINT8 vga_read_status()
11455: {
11456: // 60hz
11457: static const int period[3] = {16, 17, 17};
11458: static int index = 0;
11459: UINT32 time = timeGetTime() % period[index];
11460:
11461: index = (index + 1) % 3;
1.1.1.14 root 11462: return((time < 4 ? 0x08 : 0) | (time == 0 ? 0 : 0x01));
1.1.1.9 root 11463: }
11464:
1.1 root 11465: // i/o bus
11466:
11467: UINT8 read_io_byte(offs_t addr)
11468: {
11469: switch(addr) {
11470: case 0x20:
11471: case 0x21:
11472: return(pic_read(0, addr));
11473: case 0x40:
11474: case 0x41:
11475: case 0x42:
11476: case 0x43:
11477: return(pit_read(addr & 0x03));
1.1.1.7 root 11478: case 0x60:
11479: return(kbd_read_data());
1.1.1.9 root 11480: case 0x61:
11481: return(system_port);
1.1.1.7 root 11482: case 0x64:
11483: return(kbd_read_status());
1.1 root 11484: case 0x71:
1.1.1.8 root 11485: return(cmos_read(cmos_addr));
1.1 root 11486: case 0x92:
1.1.1.3 root 11487: return((m_a20_mask >> 19) & 2);
1.1 root 11488: case 0xa0:
11489: case 0xa1:
11490: return(pic_read(1, addr));
1.1.1.9 root 11491: case 0x3ba:
11492: case 0x3da:
11493: return(vga_read_status());
1.1 root 11494: default:
11495: // error("inb %4x\n", addr);
11496: break;
11497: }
11498: return(0xff);
11499: }
11500:
11501: UINT16 read_io_word(offs_t addr)
11502: {
11503: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8));
11504: }
11505:
11506: UINT32 read_io_dword(offs_t addr)
11507: {
11508: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8) | (read_io_byte(addr + 2) << 16) | (read_io_byte(addr + 3) << 24));
11509: }
11510:
11511: void write_io_byte(offs_t addr, UINT8 val)
11512: {
11513: switch(addr) {
11514: case 0x20:
11515: case 0x21:
11516: pic_write(0, addr, val);
11517: break;
11518: case 0x40:
11519: case 0x41:
11520: case 0x42:
11521: case 0x43:
11522: pit_write(addr & 0x03, val);
11523: break;
1.1.1.7 root 11524: case 0x60:
11525: kbd_write_data(val);
11526: break;
1.1.1.9 root 11527: case 0x61:
11528: if((system_port & 3) != 3 && (val & 3) == 3) {
11529: // beep on
11530: // MessageBeep(-1);
11531: } else if((system_port & 3) == 3 && (val & 3) != 3) {
11532: // beep off
11533: }
11534: system_port = val;
11535: break;
1.1 root 11536: case 0x64:
1.1.1.7 root 11537: kbd_write_command(val);
1.1 root 11538: break;
11539: case 0x70:
11540: cmos_addr = val;
11541: break;
11542: case 0x71:
1.1.1.8 root 11543: cmos_write(cmos_addr, val);
1.1 root 11544: break;
11545: case 0x92:
1.1.1.7 root 11546: i386_set_a20_line((val >> 1) & 1);
1.1 root 11547: break;
11548: case 0xa0:
11549: case 0xa1:
11550: pic_write(1, addr, val);
11551: break;
11552: default:
11553: // error("outb %4x,%2x\n", addr, val);
11554: break;
11555: }
11556: }
11557:
11558: void write_io_word(offs_t addr, UINT16 val)
11559: {
11560: write_io_byte(addr + 0, (val >> 0) & 0xff);
11561: write_io_byte(addr + 1, (val >> 8) & 0xff);
11562: }
11563:
11564: void write_io_dword(offs_t addr, UINT32 val)
11565: {
11566: write_io_byte(addr + 0, (val >> 0) & 0xff);
11567: write_io_byte(addr + 1, (val >> 8) & 0xff);
11568: write_io_byte(addr + 2, (val >> 16) & 0xff);
11569: write_io_byte(addr + 3, (val >> 24) & 0xff);
11570: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.