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