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