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