|
|
1.1 root 1: /*
2: MS-DOS Player for Win32 console
3:
4: Author : Takeda.Toshiya
5: Date : 2009.11.09-
6: */
7:
8: #include "msdos.h"
9:
10: #define my_strchr(str, chr) (char *)_mbschr((unsigned char *)(str), (unsigned int)(chr))
11: #define my_strtok(tok, del) (char *)_mbstok((unsigned char *)(tok), (const unsigned char *)(del))
12: #define my_strupr(str) (char *)_mbsupr((unsigned char *)(str))
13:
14: #define fatalerror(...) { \
15: fprintf(stderr, __VA_ARGS__); \
16: exit(1); \
17: }
18: #define error(...) fprintf(stderr, "error: " __VA_ARGS__)
19:
1.1.1.12 root 20: #if defined(__MINGW32__)
21: extern "C" int _CRT_glob = 0;
22: #endif
23:
24: /*
25: kludge for "more-standardized" C++
26: */
27: #if !defined(_MSC_VER)
28: inline int kludge_min(int a, int b) { return (a<b ? a:b); }
29: inline int kludge_max(int a, int b) { return (a>b ? a:b); }
30: #define min(a,b) kludge_min(a,b)
31: #define max(a,b) kludge_max(a,b)
1.1.1.14 root 32: #elif _MSC_VER >= 1400
33: void ignore_invalid_parameters(const wchar_t *, const wchar_t *, const wchar_t *, unsigned int, uintptr_t)
34: {
35: }
36: #endif
37:
38: #define USE_THREAD
39:
40: #ifdef USE_THREAD
41: static CRITICAL_SECTION vram_crit_sect;
42: #else
43: #define EnterCriticalSection(x)
44: #define LeaveCriticalSection(x)
45: #define vram_flush()
1.1.1.12 root 46: #endif
47:
1.1.1.14 root 48: #define VIDEO_REGEN *(UINT16 *)(mem + 0x44c)
49: #define SCR_BUF(y,x) scr_buf[(y) * scr_buf_size.X + (x)]
50:
51: void change_console_size(int width, int height);
52: void clear_scr_buffer(WORD attr);
53:
54: static UINT32 vram_length_char = 0, vram_length_attr = 0;
55: static UINT32 vram_last_length_char = 0, vram_last_length_attr = 0;
56: static COORD vram_coord_char, vram_coord_attr;
57:
58: bool ignore_illegal_insn = false;
59: bool limit_max_memory = false;
60: bool no_windows = false;
61: //bool ctrl_break = false;
62: bool stay_busy = false;
63: UINT32 iops = 0;
1.1.1.19 root 64: bool support_ems = false;
65: #ifdef SUPPORT_XMS
66: bool support_xms = false;
67: #endif
1.1.1.14 root 68:
69: BOOL is_vista_or_later;
70:
71: inline void maybe_idle()
72: {
73: // if it appears to be in a tight loop, assume waiting for input
74: // allow for one updated video character, for a spinning cursor
75: if(!stay_busy && iops < 1000 && vram_length_char <= 1 && vram_length_attr <= 1) {
76: Sleep(10);
77: }
78: iops = 0;
79: }
1.1.1.12 root 80:
1.1 root 81: /* ----------------------------------------------------------------------------
1.1.1.3 root 82: MAME i86/i386
1.1 root 83: ---------------------------------------------------------------------------- */
84:
85: //#define SUPPORT_DISASSEMBLER
86:
1.1.1.10 root 87: #ifndef __BIG_ENDIAN__
1.1 root 88: #define LSB_FIRST
1.1.1.10 root 89: #endif
1.1 root 90:
91: #ifndef INLINE
92: #define INLINE inline
93: #endif
94: #define U64(v) UINT64(v)
95:
96: //#define logerror(...) fprintf(stderr, __VA_ARGS__)
97: #define logerror(...)
98: //#define popmessage(...) fprintf(stderr, __VA_ARGS__)
99: #define popmessage(...)
100:
101: /*****************************************************************************/
1.1.1.10 root 102: /* src/emu/devcpu.h */
103:
104: // CPU interface functions
105: #define CPU_INIT_NAME(name) cpu_init_##name
106: #define CPU_INIT(name) void CPU_INIT_NAME(name)()
107: #define CPU_INIT_CALL(name) CPU_INIT_NAME(name)()
108:
109: #define CPU_RESET_NAME(name) cpu_reset_##name
110: #define CPU_RESET(name) void CPU_RESET_NAME(name)()
111: #define CPU_RESET_CALL(name) CPU_RESET_NAME(name)()
112:
113: #define CPU_EXECUTE_NAME(name) cpu_execute_##name
114: #define CPU_EXECUTE(name) void CPU_EXECUTE_NAME(name)()
115: #define CPU_EXECUTE_CALL(name) CPU_EXECUTE_NAME(name)()
116:
117: #define CPU_TRANSLATE_NAME(name) cpu_translate_##name
118: #define CPU_TRANSLATE(name) int CPU_TRANSLATE_NAME(name)(address_spacenum space, int intention, offs_t *address)
119: #define CPU_TRANSLATE_CALL(name) CPU_TRANSLATE_NAME(name)(space, intention, address)
120:
121: #define CPU_DISASSEMBLE_NAME(name) cpu_disassemble_##name
122: #define CPU_DISASSEMBLE(name) int CPU_DISASSEMBLE_NAME(name)(char *buffer, offs_t eip, const UINT8 *oprom)
123: #define CPU_DISASSEMBLE_CALL(name) CPU_DISASSEMBLE_NAME(name)(buffer, eip, oprom)
124:
1.1.1.14 root 125: #define CPU_MODEL_STR(name) #name
126: #define CPU_MODEL_NAME(name) CPU_MODEL_STR(name)
127:
1.1.1.10 root 128: /*****************************************************************************/
129: /* src/emu/didisasm.h */
130:
131: // Disassembler constants
132: const UINT32 DASMFLAG_SUPPORTED = 0x80000000; // are disassembly flags supported?
133: const UINT32 DASMFLAG_STEP_OUT = 0x40000000; // this instruction should be the end of a step out sequence
134: const UINT32 DASMFLAG_STEP_OVER = 0x20000000; // this instruction should be stepped over by setting a breakpoint afterwards
135: const UINT32 DASMFLAG_OVERINSTMASK = 0x18000000; // number of extra instructions to skip when stepping over
136: const UINT32 DASMFLAG_OVERINSTSHIFT = 27; // bits to shift after masking to get the value
137: const UINT32 DASMFLAG_LENGTHMASK = 0x0000ffff; // the low 16-bits contain the actual length
138:
139: /*****************************************************************************/
1.1 root 140: /* src/emu/diexec.h */
141:
142: // I/O line states
143: enum line_state
144: {
145: CLEAR_LINE = 0, // clear (a fired or held) line
146: ASSERT_LINE, // assert an interrupt immediately
147: HOLD_LINE, // hold interrupt line until acknowledged
148: PULSE_LINE // pulse interrupt line instantaneously (only for NMI, RESET)
149: };
150:
151: // I/O line definitions
152: enum
153: {
154: INPUT_LINE_IRQ = 0,
155: INPUT_LINE_NMI
156: };
157:
158: /*****************************************************************************/
1.1.1.10 root 159: /* src/emu/dimemory.h */
1.1 root 160:
1.1.1.10 root 161: // Translation intentions
162: const int TRANSLATE_TYPE_MASK = 0x03; // read write or fetch
163: const int TRANSLATE_USER_MASK = 0x04; // user mode or fully privileged
164: const int TRANSLATE_DEBUG_MASK = 0x08; // debug mode (no side effects)
165:
166: const int TRANSLATE_READ = 0; // translate for read
167: const int TRANSLATE_WRITE = 1; // translate for write
168: const int TRANSLATE_FETCH = 2; // translate for instruction fetch
169: const int TRANSLATE_READ_USER = (TRANSLATE_READ | TRANSLATE_USER_MASK);
170: const int TRANSLATE_WRITE_USER = (TRANSLATE_WRITE | TRANSLATE_USER_MASK);
171: const int TRANSLATE_FETCH_USER = (TRANSLATE_FETCH | TRANSLATE_USER_MASK);
172: const int TRANSLATE_READ_DEBUG = (TRANSLATE_READ | TRANSLATE_DEBUG_MASK);
173: const int TRANSLATE_WRITE_DEBUG = (TRANSLATE_WRITE | TRANSLATE_DEBUG_MASK);
174: const int TRANSLATE_FETCH_DEBUG = (TRANSLATE_FETCH | TRANSLATE_DEBUG_MASK);
1.1 root 175:
1.1.1.10 root 176: /*****************************************************************************/
177: /* src/emu/emucore.h */
1.1 root 178:
1.1.1.10 root 179: // constants for expression endianness
180: enum endianness_t
181: {
182: ENDIANNESS_LITTLE,
183: ENDIANNESS_BIG
184: };
1.1 root 185:
1.1.1.10 root 186: // declare native endianness to be one or the other
187: #ifdef LSB_FIRST
188: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_LITTLE;
189: #else
190: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_BIG;
191: #endif
192:
193: // endian-based value: first value is if 'endian' is little-endian, second is if 'endian' is big-endian
194: #define ENDIAN_VALUE_LE_BE(endian,leval,beval) (((endian) == ENDIANNESS_LITTLE) ? (leval) : (beval))
195:
196: // endian-based value: first value is if native endianness is little-endian, second is if native is big-endian
197: #define NATIVE_ENDIAN_VALUE_LE_BE(leval,beval) ENDIAN_VALUE_LE_BE(ENDIANNESS_NATIVE, leval, beval)
198:
199: // endian-based value: first value is if 'endian' matches native, second is if 'endian' doesn't match native
200: #define ENDIAN_VALUE_NE_NNE(endian,leval,beval) (((endian) == ENDIANNESS_NATIVE) ? (neval) : (nneval))
1.1 root 201:
202: /*****************************************************************************/
203: /* src/emu/memory.h */
204:
1.1.1.10 root 205: // address spaces
206: enum address_spacenum
207: {
208: AS_0, // first address space
209: AS_1, // second address space
210: AS_2, // third address space
211: AS_3, // fourth address space
212: ADDRESS_SPACES, // maximum number of address spaces
213:
214: // alternate address space names for common use
215: AS_PROGRAM = AS_0, // program address space
216: AS_DATA = AS_1, // data address space
217: AS_IO = AS_2 // I/O address space
218: };
219:
1.1 root 220: // offsets and addresses are 32-bit (for now...)
221: typedef UINT32 offs_t;
222:
223: // read accessors
224: UINT8 read_byte(offs_t byteaddress)
225: {
1.1.1.4 root 226: #if defined(HAS_I386)
1.1 root 227: if(byteaddress < MAX_MEM) {
228: return mem[byteaddress];
1.1.1.3 root 229: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
230: // return read_byte(byteaddress & 0xfffff);
1.1 root 231: }
232: return 0;
1.1.1.4 root 233: #else
234: return mem[byteaddress];
235: #endif
1.1 root 236: }
237:
238: UINT16 read_word(offs_t byteaddress)
239: {
1.1.1.14 root 240: if(byteaddress == 0x41c) {
241: // pointer to first free slot in keyboard buffer
242: // XXX: the buffer itself doesn't actually exist in DOS memory
243: if(key_buf_char->count() == 0) {
244: maybe_idle();
245: }
246: return (UINT16)key_buf_char->count();
247: }
1.1.1.4 root 248: #if defined(HAS_I386)
1.1 root 249: if(byteaddress < MAX_MEM - 1) {
250: return *(UINT16 *)(mem + byteaddress);
1.1.1.3 root 251: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
252: // return read_word(byteaddress & 0xfffff);
1.1 root 253: }
254: return 0;
1.1.1.4 root 255: #else
256: return *(UINT16 *)(mem + byteaddress);
257: #endif
1.1 root 258: }
259:
260: UINT32 read_dword(offs_t byteaddress)
261: {
1.1.1.4 root 262: #if defined(HAS_I386)
1.1 root 263: if(byteaddress < MAX_MEM - 3) {
264: return *(UINT32 *)(mem + byteaddress);
1.1.1.3 root 265: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
266: // return read_dword(byteaddress & 0xfffff);
1.1 root 267: }
268: return 0;
1.1.1.4 root 269: #else
270: return *(UINT32 *)(mem + byteaddress);
271: #endif
1.1 root 272: }
273:
274: // write accessors
1.1.1.14 root 275: #ifdef USE_THREAD
276: void vram_flush_char()
277: {
278: if(vram_length_char != 0) {
279: DWORD num;
280: WriteConsoleOutputCharacter(hStdout, scr_char, vram_length_char, vram_coord_char, &num);
281: vram_length_char = vram_last_length_char = 0;
282: }
283: }
284:
285: void vram_flush_attr()
286: {
287: if(vram_length_attr != 0) {
288: DWORD num;
289: WriteConsoleOutputAttribute(hStdout, scr_attr, vram_length_attr, vram_coord_attr, &num);
290: vram_length_attr = vram_last_length_attr = 0;
291: }
292: }
293:
294: void vram_flush()
295: {
296: if(vram_length_char != 0 || vram_length_attr != 0) {
297: EnterCriticalSection(&vram_crit_sect);
298: vram_flush_char();
299: vram_flush_attr();
300: LeaveCriticalSection(&vram_crit_sect);
301: }
302: }
303: #endif
304:
305: void write_text_vram_char(offs_t offset, UINT8 data)
1.1.1.8 root 306: {
1.1.1.14 root 307: #ifdef USE_THREAD
308: static offs_t first_offset_char, last_offset_char;
309:
310: if(vram_length_char != 0) {
311: if(offset <= last_offset_char && offset >= first_offset_char) {
312: scr_char[(offset - first_offset_char) >> 1] = data;
313: return;
314: }
315: if(offset != last_offset_char + 2) {
316: vram_flush_char();
317: }
318: }
319: if(vram_length_char == 0) {
320: first_offset_char = offset;
321: vram_coord_char.X = (offset >> 1) % scr_width;
322: vram_coord_char.Y = (offset >> 1) / scr_width + scr_top;
323: }
324: scr_char[vram_length_char++] = data;
325: last_offset_char = offset;
326: #else
1.1.1.8 root 327: COORD co;
328: DWORD num;
329:
1.1.1.14 root 330: co.X = (offset >> 1) % scr_width;
331: co.Y = (offset >> 1) / scr_width;
332: scr_char[0] = data;
333: WriteConsoleOutputCharacter(hStdout, scr_char, 1, co, &num);
334: #endif
335: }
336:
337: void write_text_vram_attr(offs_t offset, UINT8 data)
338: {
339: #ifdef USE_THREAD
340: static offs_t first_offset_attr, last_offset_attr;
341:
342: if(vram_length_attr != 0) {
343: if(offset <= last_offset_attr && offset >= first_offset_attr) {
344: scr_attr[(offset - first_offset_attr) >> 1] = data;
345: return;
346: }
347: if(offset != last_offset_attr + 2) {
348: vram_flush_attr();
349: }
350: }
351: if(vram_length_attr == 0) {
352: first_offset_attr = offset;
353: vram_coord_attr.X = (offset >> 1) % scr_width;
354: vram_coord_attr.Y = (offset >> 1) / scr_width + scr_top;
355: }
356: scr_attr[vram_length_attr++] = data;
357: last_offset_attr = offset;
358: #else
359: COORD co;
360: DWORD num;
1.1.1.8 root 361:
1.1.1.14 root 362: co.X = (offset >> 1) % scr_width;
363: co.Y = (offset >> 1) / scr_width;
364: scr_attr[0] = data;
365: WriteConsoleOutputAttribute(hStdout, scr_attr, 1, co, &num);
366: #endif
367: }
368:
369: void write_text_vram_byte(offs_t offset, UINT8 data)
370: {
371: EnterCriticalSection(&vram_crit_sect);
1.1.1.8 root 372: if(offset & 1) {
1.1.1.14 root 373: write_text_vram_attr(offset, data);
1.1.1.8 root 374: } else {
1.1.1.14 root 375: write_text_vram_char(offset, data);
1.1.1.8 root 376: }
1.1.1.14 root 377: LeaveCriticalSection(&vram_crit_sect);
1.1.1.8 root 378: }
379:
380: void write_text_vram_word(offs_t offset, UINT16 data)
381: {
1.1.1.14 root 382: EnterCriticalSection(&vram_crit_sect);
1.1.1.8 root 383: if(offset & 1) {
1.1.1.14 root 384: write_text_vram_attr(offset , (data ) & 0xff);
385: write_text_vram_char(offset + 1, (data >> 8) & 0xff);
1.1.1.8 root 386: } else {
1.1.1.14 root 387: write_text_vram_char(offset , (data ) & 0xff);
388: write_text_vram_attr(offset + 1, (data >> 8) & 0xff);
1.1.1.8 root 389: }
1.1.1.14 root 390: LeaveCriticalSection(&vram_crit_sect);
1.1.1.8 root 391: }
392:
393: void write_text_vram_dword(offs_t offset, UINT32 data)
394: {
1.1.1.14 root 395: EnterCriticalSection(&vram_crit_sect);
1.1.1.8 root 396: if(offset & 1) {
1.1.1.14 root 397: write_text_vram_attr(offset , (data ) & 0xff);
398: write_text_vram_char(offset + 1, (data >> 8) & 0xff);
399: write_text_vram_attr(offset + 2, (data >> 16) & 0xff);
400: write_text_vram_char(offset + 3, (data >> 24) & 0xff);
401: } else {
402: write_text_vram_char(offset , (data ) & 0xff);
403: write_text_vram_attr(offset + 1, (data >> 8) & 0xff);
404: write_text_vram_char(offset + 2, (data >> 16) & 0xff);
405: write_text_vram_attr(offset + 3, (data >> 24) & 0xff);
1.1.1.8 root 406: }
1.1.1.14 root 407: LeaveCriticalSection(&vram_crit_sect);
1.1.1.8 root 408: }
409:
1.1 root 410: void write_byte(offs_t byteaddress, UINT8 data)
411: {
1.1.1.8 root 412: if(byteaddress < MEMORY_END) {
1.1.1.3 root 413: mem[byteaddress] = data;
1.1.1.8 root 414: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 415: if(!restore_console_on_exit) {
416: change_console_size(scr_width, scr_height);
1.1.1.12 root 417: }
1.1.1.8 root 418: write_text_vram_byte(byteaddress - text_vram_top_address, data);
419: mem[byteaddress] = data;
420: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
421: if(int_10h_feh_called && !int_10h_ffh_called) {
422: write_text_vram_byte(byteaddress - shadow_buffer_top_address, data);
1.1 root 423: }
424: mem[byteaddress] = data;
1.1.1.4 root 425: #if defined(HAS_I386)
1.1.1.3 root 426: } else if(byteaddress < MAX_MEM) {
1.1.1.4 root 427: #else
428: } else {
429: #endif
1.1.1.3 root 430: mem[byteaddress] = data;
1.1 root 431: }
432: }
433:
434: void write_word(offs_t byteaddress, UINT16 data)
435: {
1.1.1.8 root 436: if(byteaddress < MEMORY_END) {
1.1.1.14 root 437: if(byteaddress == 0x450 + mem[0x462] * 2) {
438: COORD co;
439: co.X = data & 0xff;
440: co.Y = (data >> 8) + scr_top;
441: SetConsoleCursorPosition(hStdout, co);
442: }
1.1.1.3 root 443: *(UINT16 *)(mem + byteaddress) = data;
1.1.1.8 root 444: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 445: if(!restore_console_on_exit) {
446: change_console_size(scr_width, scr_height);
1.1.1.12 root 447: }
1.1.1.8 root 448: write_text_vram_word(byteaddress - text_vram_top_address, data);
449: *(UINT16 *)(mem + byteaddress) = data;
450: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
451: if(int_10h_feh_called && !int_10h_ffh_called) {
452: write_text_vram_word(byteaddress - shadow_buffer_top_address, data);
1.1 root 453: }
454: *(UINT16 *)(mem + byteaddress) = data;
1.1.1.4 root 455: #if defined(HAS_I386)
1.1.1.3 root 456: } else if(byteaddress < MAX_MEM - 1) {
1.1.1.4 root 457: #else
458: } else {
459: #endif
1.1.1.3 root 460: *(UINT16 *)(mem + byteaddress) = data;
1.1 root 461: }
462: }
463:
464: void write_dword(offs_t byteaddress, UINT32 data)
465: {
1.1.1.8 root 466: if(byteaddress < MEMORY_END) {
1.1.1.3 root 467: *(UINT32 *)(mem + byteaddress) = data;
1.1.1.8 root 468: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 469: if(!restore_console_on_exit) {
470: change_console_size(scr_width, scr_height);
1.1.1.12 root 471: }
1.1.1.8 root 472: write_text_vram_dword(byteaddress - text_vram_top_address, data);
473: *(UINT32 *)(mem + byteaddress) = data;
474: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
475: if(int_10h_feh_called && !int_10h_ffh_called) {
476: write_text_vram_dword(byteaddress - shadow_buffer_top_address, data);
1.1 root 477: }
478: *(UINT32 *)(mem + byteaddress) = data;
1.1.1.4 root 479: #if defined(HAS_I386)
1.1.1.3 root 480: } else if(byteaddress < MAX_MEM - 3) {
1.1.1.4 root 481: #else
482: } else {
483: #endif
1.1.1.3 root 484: *(UINT32 *)(mem + byteaddress) = data;
1.1 root 485: }
486: }
487:
488: #define read_decrypted_byte read_byte
489: #define read_decrypted_word read_word
490: #define read_decrypted_dword read_dword
491:
1.1.1.3 root 492: #define read_raw_byte read_byte
493: #define write_raw_byte write_byte
494:
495: #define read_word_unaligned read_word
496: #define write_word_unaligned write_word
497:
498: #define read_io_word_unaligned read_io_word
499: #define write_io_word_unaligned write_io_word
500:
1.1 root 501: UINT8 read_io_byte(offs_t byteaddress);
502: UINT16 read_io_word(offs_t byteaddress);
503: UINT32 read_io_dword(offs_t byteaddress);
504:
505: void write_io_byte(offs_t byteaddress, UINT8 data);
506: void write_io_word(offs_t byteaddress, UINT16 data);
507: void write_io_dword(offs_t byteaddress, UINT32 data);
508:
509: /*****************************************************************************/
510: /* src/osd/osdcomm.h */
511:
512: /* Highly useful macro for compile-time knowledge of an array size */
513: #define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0]))
514:
1.1.1.3 root 515: #if defined(HAS_I386)
1.1.1.10 root 516: static CPU_TRANSLATE(i386);
517: #include "mame/lib/softfloat/softfloat.c"
518: #include "mame/emu/cpu/i386/i386.c"
1.1.1.12 root 519: #include "mame/emu/cpu/vtlb.c"
1.1.1.3 root 520: #elif defined(HAS_I286)
1.1.1.10 root 521: #include "mame/emu/cpu/i86/i286.c"
1.1.1.3 root 522: #else
1.1.1.10 root 523: #include "mame/emu/cpu/i86/i86.c"
1.1.1.3 root 524: #endif
1.1 root 525: #ifdef SUPPORT_DISASSEMBLER
1.1.1.10 root 526: #include "mame/emu/cpu/i386/i386dasm.c"
1.1.1.3 root 527: bool dasm = false;
1.1 root 528: #endif
529:
1.1.1.3 root 530: #if defined(HAS_I386)
531: #define SREG(x) m_sreg[x].selector
532: #define SREG_BASE(x) m_sreg[x].base
533:
534: int cpu_type, cpu_step;
535: #else
536: #define REG8(x) m_regs.b[x]
537: #define REG16(x) m_regs.w[x]
538: #define SREG(x) m_sregs[x]
539: #define SREG_BASE(x) m_base[x]
540: #define m_CF m_CarryVal
541: #define m_a20_mask AMASK
542: #define i386_load_segment_descriptor(x) m_base[x] = SegBase(x)
543: #if defined(HAS_I286)
544: #define i386_set_a20_line(x) i80286_set_a20_line(x)
545: #else
546: #define i386_set_a20_line(x)
547: #endif
548: #define i386_set_irq_line(x, y) set_irq_line(x, y)
549: #endif
1.1 root 550:
551: void i386_jmp_far(UINT16 selector, UINT32 address)
552: {
1.1.1.3 root 553: #if defined(HAS_I386)
1.1 root 554: if(PROTECTED_MODE && !V8086_MODE) {
1.1.1.3 root 555: i386_protected_mode_jump(selector, address, 1, m_operand_size);
1.1 root 556: } else {
1.1.1.3 root 557: SREG(CS) = selector;
558: m_performed_intersegment_jump = 1;
559: i386_load_segment_descriptor(CS);
560: m_eip = address;
561: CHANGE_PC(m_eip);
1.1 root 562: }
1.1.1.3 root 563: #elif defined(HAS_I286)
564: i80286_code_descriptor(selector, address, 1);
565: #else
566: SREG(CS) = selector;
567: i386_load_segment_descriptor(CS);
568: m_pc = (SREG_BASE(CS) + address) & m_a20_mask;
569: #endif
1.1 root 570: }
571:
572: /* ----------------------------------------------------------------------------
573: main
574: ---------------------------------------------------------------------------- */
575:
1.1.1.10 root 576: bool is_started_from_command_prompt()
577: {
1.1.1.18 root 578: bool ret = false;
579:
580: HMODULE hLibrary = LoadLibrary(_T("Kernel32.dll"));
581: if(hLibrary) {
582: typedef DWORD (WINAPI *GetConsoleProcessListFunction)(__out LPDWORD lpdwProcessList, __in DWORD dwProcessCount);
583: GetConsoleProcessListFunction lpfnGetConsoleProcessList;
584: lpfnGetConsoleProcessList = reinterpret_cast<GetConsoleProcessListFunction>(::GetProcAddress(hLibrary, "GetConsoleProcessList"));
585: if(lpfnGetConsoleProcessList) {
586: DWORD pl;
587: ret = (lpfnGetConsoleProcessList(&pl, 1) > 1);
588: FreeLibrary(hLibrary);
589: return(ret);
590: }
591: FreeLibrary(hLibrary);
592: }
593:
594: HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
595: if(hSnapshot != INVALID_HANDLE_VALUE) {
596: DWORD dwParentProcessID = 0;
597: PROCESSENTRY32 pe32;
598: pe32.dwSize = sizeof(PROCESSENTRY32);
599: if(Process32First(hSnapshot, &pe32)) {
600: do {
601: if(pe32.th32ProcessID == GetCurrentProcessId()) {
602: dwParentProcessID = pe32.th32ParentProcessID;
603: break;
604: }
605: } while(Process32Next(hSnapshot, &pe32));
606: }
607: CloseHandle(hSnapshot);
608: if(dwParentProcessID != 0) {
609: HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwParentProcessID);
610: if(hProcess != NULL) {
611: HMODULE hMod;
612: DWORD cbNeeded;
613: if(EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {
614: char module_name[MAX_PATH];
615: if(GetModuleBaseName(hProcess, hMod, module_name, sizeof(module_name))) {
616: ret = (_strnicmp(module_name, "cmd.exe", 7) == 0);
617: }
618: }
619: CloseHandle(hProcess);
620: }
621: }
622: }
623: return(ret);
1.1.1.14 root 624: }
625:
626: BOOL is_greater_windows_version(DWORD dwMajorVersion, DWORD dwMinorVersion, WORD wServicePackMajor, WORD wServicePackMinor)
627: {
628: //https://msdn.microsoft.com/en-us/library/windows/desktop/ms725491(v=vs.85).aspx
629: OSVERSIONINFOEX osvi;
630: DWORDLONG dwlConditionMask = 0;
631: int op = VER_GREATER_EQUAL;
632:
633: // Initialize the OSVERSIONINFOEX structure.
634: ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
635: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
636: osvi.dwMajorVersion = dwMajorVersion;
637: osvi.dwMinorVersion = dwMinorVersion;
638: osvi.wServicePackMajor = wServicePackMajor;
639: osvi.wServicePackMinor = wServicePackMinor;
640:
641: // Initialize the condition mask.
642: VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, op );
643: VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, op );
644: VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, op );
645: VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMINOR, op );
646:
647: // Perform the test.
648: return VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, dwlConditionMask);
649: }
650:
651: BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
652: {
653: if(dwCtrlType == CTRL_BREAK_EVENT || dwCtrlType == CTRL_C_EVENT) {
654: m_halted = 1;
655: return TRUE;
656: }
657: return FALSE;
658: }
659:
660: #ifdef USE_THREAD
661: DWORD WINAPI vram_thread(LPVOID)
662: {
663: while(!m_halted) {
664: EnterCriticalSection(&vram_crit_sect);
665: if(vram_length_char != 0 && vram_length_char == vram_last_length_char) {
666: vram_flush_char();
667: }
668: if(vram_length_attr != 0 && vram_length_attr == vram_last_length_attr) {
669: vram_flush_attr();
670: }
671: vram_last_length_char = vram_length_char;
672: vram_last_length_attr = vram_length_attr;
673: LeaveCriticalSection(&vram_crit_sect);
674: // this is about half the maximum keyboard repeat rate - any
675: // lower tends to be jerky, any higher misses updates
676: Sleep(15);
1.1.1.10 root 677: }
1.1.1.14 root 678: return 0;
1.1.1.10 root 679: }
1.1.1.14 root 680: #endif
1.1.1.10 root 681:
1.1.1.9 root 682: #define IS_NUMERIC(c) ((c) >= '0' && (c) <= '9')
683:
1.1 root 684: int main(int argc, char *argv[], char *envp[])
685: {
1.1.1.9 root 686: int arg_offset = 0;
687: int standard_env = 0;
1.1.1.14 root 688: int buf_width = 0, buf_height = 0;
1.1.1.15 root 689: BOOL bSuccess, bChangeScreenSize = FALSE;
1.1 root 690:
1.1.1.9 root 691: for(int i = 1; i < argc; i++) {
692: if(_strnicmp(argv[i], "-e", 2) == 0) {
693: standard_env = 1;
694: arg_offset++;
1.1.1.14 root 695: } else if(_strnicmp(argv[i], "-i", 2) == 0) {
696: ignore_illegal_insn = true;
697: arg_offset++;
698: } else if(_strnicmp(argv[i], "-m", 2) == 0) {
699: limit_max_memory = true;
700: arg_offset++;
701: } else if(_strnicmp(argv[i], "-d", 2) == 0) {
702: no_windows = true;
703: arg_offset++;
704: } else if(_strnicmp(argv[i], "-b", 2) == 0) {
705: stay_busy = true;
706: arg_offset++;
1.1.1.19 root 707: } else if(_strnicmp(argv[i], "-x", 2) == 0) {
708: UMB_TOP = EMS_TOP + EMS_SIZE;
709: support_ems = true;
710: #ifdef SUPPORT_XMS
711: support_xms = true;
712: #endif
713: arg_offset++;
1.1.1.14 root 714: } else if(_strnicmp(argv[i], "-n", 2) == 0) {
1.1.1.17 root 715: if(sscanf(argv[1] + 2, "%d,%d", &buf_height, &buf_width) != 2) {
716: buf_width = buf_height = 0;
717: }
718: if(buf_width <= 0 || buf_width > 0x7fff) {
719: buf_width = 80;
720: }
721: if(buf_height <= 0 || buf_height > 0x7fff) {
722: buf_height = 25;
723: }
1.1.1.14 root 724: arg_offset++;
1.1.1.9 root 725: } else if(_strnicmp(argv[i], "-v", 2) == 0) {
1.1.1.17 root 726: if(strlen(argv[i]) >= 5 && IS_NUMERIC(argv[i][2]) && argv[i][3] == '.' && IS_NUMERIC(argv[i][4]) && (argv[i][5] == '\0' || IS_NUMERIC(argv[i][5]))) {
1.1.1.9 root 727: major_version = argv[i][2] - '0';
1.1.1.17 root 728: minor_version = (argv[i][4] - '0') * 10 + (argv[i][5] ? (argv[i][5] - '0') : 0);
1.1.1.9 root 729: }
730: arg_offset++;
731: } else {
732: break;
733: }
734: }
735:
736: if(argc < 2 + arg_offset) {
1.1 root 737: #ifdef _WIN64
1.1.1.14 root 738: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32-x64 console\n\n");
1.1 root 739: #else
1.1.1.14 root 740: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32 console\n\n");
1.1 root 741: #endif
1.1.1.19 root 742: fprintf(stderr, "Usage: MSDOS [-b] [-d] [-e] [-i] [-m] [-n[L[,C]]] [-vX.XX] [-x] (command file) [options]\n"
1.1.1.14 root 743: "\n"
744: "\t-b\tstay busy during keyboard polling\n"
745: "\t-d\tpretend running under straight DOS, not Windows\n"
746: "\t-e\tuse a reduced environment block\n"
747: "\t-i\tignore invalid instructions\n"
748: "\t-m\trestrict free memory to 0x7FFF paragraphs\n"
749: "\t-n\tcreate a new buffer (25 lines, 80 columns by default)\n"
1.1.1.19 root 750: "\t-v\tset the DOS version\n"
751: #ifdef SUPPORT_XMS
752: "\t-x\tenable XMS/EMS\n"
753: #else
754: "\t-x\tenable EMS\n"
755: #endif
756: );
1.1.1.10 root 757:
758: if(!is_started_from_command_prompt()) {
759: fprintf(stderr, "\nStart this program from a command prompt!\n\nHit any key to quit...");
760: while(!_kbhit()) {
761: Sleep(10);
762: }
763: }
1.1.1.20 root 764: #ifdef _DEBUG
765: _CrtDumpMemoryLeaks();
766: #endif
1.1 root 767: return(EXIT_FAILURE);
768: }
769:
1.1.1.14 root 770: is_vista_or_later = is_greater_windows_version(6, 0, 0, 0);
771:
1.1 root 772: CONSOLE_SCREEN_BUFFER_INFO csbi;
1.1.1.14 root 773: CONSOLE_CURSOR_INFO ci;
1.1 root 774: hStdin = GetStdHandle(STD_INPUT_HANDLE);
775: hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.12 root 776: bSuccess = GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 777: GetConsoleCursorInfo(hStdout, &ci);
1.1 root 778:
1.1.1.14 root 779: for(int y = 0; y < SCR_BUF_WIDTH; y++) {
780: for(int x = 0; x < SCR_BUF_HEIGHT; x++) {
781: SCR_BUF(y,x).Char.AsciiChar = ' ';
782: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 783: }
784: }
1.1.1.12 root 785: if(bSuccess) {
786: scr_width = csbi.dwSize.X;
1.1.1.14 root 787: scr_height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
788:
789: // v-text shadow buffer size is 0x7ff0
790: if((scr_width > SCR_BUF_WIDTH) || (scr_height > SCR_BUF_HEIGHT) || (scr_width * scr_height * 2 > 0x7ff0) ||
791: (buf_width != 0 && buf_width != scr_width) || (buf_height != 0 && buf_height != scr_height)) {
792: scr_width = min(buf_width != 0 ? buf_width : scr_width, SCR_BUF_WIDTH);
793: scr_height = min(buf_height != 0 ? buf_height : scr_height, SCR_BUF_HEIGHT);
794: if(scr_width * scr_height * 2 > 0x7ff0) {
795: scr_width = 80;
796: scr_height = 25;
797: }
1.1.1.15 root 798: bChangeScreenSize = TRUE;
1.1.1.14 root 799: }
1.1.1.12 root 800: } else {
801: // for a proof (not a console)
802: scr_width = 80;
803: scr_height = 25;
804: }
1.1.1.14 root 805: scr_buf_size.X = scr_width;
806: scr_buf_size.Y = scr_height;
807: scr_buf_pos.X = scr_buf_pos.Y = 0;
808: scr_top = csbi.srWindow.Top;
1.1 root 809: cursor_moved = false;
810:
811: key_buf_char = new FIFO();
812: key_buf_scan = new FIFO();
813:
814: hardware_init();
815:
1.1.1.9 root 816: if(msdos_init(argc - (arg_offset + 1), argv + (arg_offset + 1), envp, standard_env)) {
1.1 root 817: retval = EXIT_FAILURE;
818: } else {
1.1.1.15 root 819: if(bChangeScreenSize) {
820: change_console_size(scr_width, scr_height);
821: }
1.1.1.14 root 822: #if defined(_MSC_VER) && _MSC_VER >= 1400
823: _set_invalid_parameter_handler((_invalid_parameter_handler)ignore_invalid_parameters);
824: #endif
825: SetConsoleCtrlHandler(ctrl_handler, TRUE);
826:
1.1.1.8 root 827: TIMECAPS caps;
828: timeGetDevCaps(&caps, sizeof(TIMECAPS));
829: timeBeginPeriod(caps.wPeriodMin);
1.1.1.14 root 830:
831: #ifdef USE_THREAD
832: InitializeCriticalSection(&vram_crit_sect);
833: CloseHandle(CreateThread(NULL, 4096, vram_thread, NULL, 0, NULL));
834: #endif
1.1 root 835: hardware_run();
1.1.1.14 root 836: #ifdef USE_THREAD
837: vram_flush();
838: DeleteCriticalSection(&vram_crit_sect);
839: #endif
840:
1.1.1.12 root 841: if(bSuccess) {
842: if(restore_console_on_exit) {
1.1.1.14 root 843: // window can't be bigger than buffer,
844: // buffer can't be smaller than window,
845: // so make a tiny window,
846: // set the required buffer,
847: // then set the required window
848: SMALL_RECT rect;
849: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
850: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.12 root 851: SetConsoleScreenBufferSize(hStdout, csbi.dwSize);
1.1.1.14 root 852: SET_RECT(rect, 0, 0, csbi.srWindow.Right - csbi.srWindow.Left, csbi.srWindow.Bottom - csbi.srWindow.Top);
1.1.1.12 root 853: SetConsoleWindowInfo(hStdout, TRUE, &rect);
854: }
1.1.1.14 root 855: // hStdout (and all handles) will close in msdos_finish()...
856: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
857: SetConsoleCursorInfo(hStdout, &ci);
1.1.1.12 root 858: }
1.1 root 859: msdos_finish();
1.1.1.14 root 860:
1.1.1.8 root 861: timeEndPeriod(caps.wPeriodMin);
1.1.1.14 root 862: SetConsoleCtrlHandler(ctrl_handler, FALSE);
1.1 root 863: }
864:
1.1.1.10 root 865: hardware_finish();
866:
1.1 root 867: delete key_buf_char;
868: delete key_buf_scan;
869:
1.1.1.12 root 870: // SetConsoleTextAttribute(hStdout, csbi.wAttributes);
1.1 root 871:
1.1.1.20 root 872: #ifdef _DEBUG
873: _CrtDumpMemoryLeaks();
874: #endif
1.1 root 875: return(retval);
876: }
877:
1.1.1.20 root 878: /* ----------------------------------------------------------------------------
879: console
880: ---------------------------------------------------------------------------- */
881:
1.1.1.14 root 882: void change_console_size(int width, int height)
1.1.1.12 root 883: {
884: CONSOLE_SCREEN_BUFFER_INFO csbi;
885: SMALL_RECT rect;
886: COORD co;
887:
888: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 889: if(csbi.srWindow.Top != 0 || csbi.dwCursorPosition.Y > height - 1) {
890: if(csbi.srWindow.Right - csbi.srWindow.Left + 1 == width && csbi.srWindow.Bottom - csbi.srWindow.Top + 1 == height) {
891: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &csbi.srWindow);
892: SET_RECT(rect, 0, 0, width - 1, height - 1);
893: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
894: } else if(csbi.dwCursorPosition.Y > height - 1) {
895: SET_RECT(rect, 0, csbi.dwCursorPosition.Y - (height - 1), width - 1, csbi.dwCursorPosition.Y);
896: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
897: SET_RECT(rect, 0, 0, width - 1, height - 1);
898: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1.1.12 root 899: }
900: }
1.1.1.14 root 901: if(csbi.dwCursorPosition.Y > height - 1) {
1.1.1.12 root 902: co.X = csbi.dwCursorPosition.X;
1.1.1.14 root 903: co.Y = min(height - 1, csbi.dwCursorPosition.Y - csbi.srWindow.Top);
1.1.1.12 root 904: SetConsoleCursorPosition(hStdout, co);
905: cursor_moved = true;
906: }
1.1.1.14 root 907:
908: // window can't be bigger than buffer,
909: // buffer can't be smaller than window,
910: // so make a tiny window,
911: // set the required buffer,
912: // then set the required window
913: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
1.1.1.12 root 914: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.14 root 915: co.X = width;
916: co.Y = height;
1.1.1.12 root 917: SetConsoleScreenBufferSize(hStdout, co);
1.1.1.14 root 918: SET_RECT(rect, 0, 0, width - 1, height - 1);
919: SetConsoleWindowInfo(hStdout, TRUE, &rect);
920:
921: scr_width = scr_buf_size.X = width;
922: scr_height = scr_buf_size.Y = height;
923: scr_top = 0;
924:
925: clear_scr_buffer(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
926:
927: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.15 root 928: text_vram_end_address = text_vram_top_address + regen;
929: shadow_buffer_end_address = shadow_buffer_top_address + regen;
930:
1.1.1.14 root 931: if(regen > 0x4000) {
932: regen = 0x8000;
933: vram_pages = 1;
934: } else if(regen > 0x2000) {
935: regen = 0x4000;
936: vram_pages = 2;
937: } else if(regen > 0x1000) {
938: regen = 0x2000;
939: vram_pages = 4;
940: } else {
941: regen = 0x1000;
942: vram_pages = 8;
943: }
1.1.1.15 root 944: *(UINT16 *)(mem + 0x44a) = scr_width;
945: *(UINT16 *)(mem + 0x44c) = regen;
946: *(UINT8 *)(mem + 0x484) = scr_height - 1;
947:
948: restore_console_on_exit = true;
1.1.1.14 root 949: }
950:
951: void clear_scr_buffer(WORD attr)
952: {
953: for(int y = 0; y < scr_height; y++) {
954: for(int x = 0; x < scr_width; x++) {
955: SCR_BUF(y,x).Char.AsciiChar = ' ';
956: SCR_BUF(y,x).Attributes = attr;
957: }
958: }
1.1.1.12 root 959: }
960:
1.1.1.14 root 961: bool update_key_buffer_tmp()
1.1 root 962: {
1.1.1.8 root 963: DWORD dwNumberOfEvents = 0;
1.1 root 964: DWORD dwRead;
965: INPUT_RECORD ir[16];
966:
1.1.1.8 root 967: if(GetNumberOfConsoleInputEvents(hStdin, &dwNumberOfEvents) && dwNumberOfEvents != 0) {
968: if(ReadConsoleInputA(hStdin, ir, 16, &dwRead)) {
969: for(int i = 0; i < dwRead; i++) {
970: if((ir[i].EventType & KEY_EVENT) && ir[i].Event.KeyEvent.bKeyDown) {
1.1.1.14 root 971: UINT8 chr = ir[i].Event.KeyEvent.uChar.AsciiChar;
972: UINT8 scn = ir[i].Event.KeyEvent.wVirtualScanCode & 0xff;
973: if(chr == 0) {
974: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
975: if(scn >= 0x3b && scn <= 0x44) {
976: scn += 0x68 - 0x3b; // F1 to F10
977: } else if(scn == 0x57 || scn == 0x58) {
978: scn += 0x8b - 0x57; // F11 & F12
979: } else if(scn >= 0x47 && scn <= 0x53) {
980: scn += 0x97 - 0x47; // edit/arrow clusters
981: } else if(scn == 0x35) {
982: scn = 0xa4; // keypad /
983: }
984: } else if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
985: if(scn == 0x07) {
986: chr = 0x1e; // Ctrl+^
987: } else if(scn == 0x0c) {
988: chr = 0x1f; // Ctrl+_
989: } else if(scn >= 0x35 && scn <= 0x58) {
990: static const UINT8 ctrl_map[] = {
991: 0x95, // keypad /
992: 0,
993: 0x96, // keypad *
994: 0, 0, 0,
995: 0x5e, // F1
996: 0x5f, // F2
997: 0x60, // F3
998: 0x61, // F4
999: 0x62, // F5
1000: 0x63, // F6
1001: 0x64, // F7
1002: 0x65, // F8
1003: 0x66, // F9
1004: 0x67, // F10
1005: 0,
1006: 0,
1007: 0x77, // Home
1008: 0x8d, // Up
1009: 0x84, // PgUp
1010: 0x8e, // keypad -
1011: 0x73, // Left
1012: 0x8f, // keypad center
1013: 0x74, // Right
1014: 0x90, // keyapd +
1015: 0x75, // End
1016: 0x91, // Down
1017: 0x76, // PgDn
1018: 0x92, // Insert
1019: 0x93, // Delete
1020: 0, 0, 0,
1021: 0x89, // F11
1022: 0x8a, // F12
1023: };
1024: scn = ctrl_map[scn - 0x35];
1025: }
1026: } else if(ir[i].Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
1027: if(scn >= 0x3b && scn <= 0x44) {
1028: scn += 0x54 - 0x3b; // F1 to F10
1029: } else if(scn == 0x57 || scn == 0x58) {
1030: scn += 0x87 - 0x57; // F11 & F12
1031: }
1032: } else if(scn == 0x57 || scn == 0x58) {
1033: scn += 0x85 - 0x57;
1034: }
1035: // ignore shift, ctrl, alt, win and menu keys
1036: if(scn != 0x1d && scn != 0x2a && scn != 0x36 && scn != 0x38 && (scn < 0x5b || scn > 0x5e)) {
1037: if(chr == 0) {
1038: key_buf_char->write(0x00);
1039: key_buf_scan->write(ir[i].Event.KeyEvent.dwControlKeyState & ENHANCED_KEY ? 0xe0 : 0x00);
1040: }
1041: key_buf_char->write(chr);
1042: key_buf_scan->write(scn);
1.1.1.8 root 1043: }
1044: } else {
1.1.1.14 root 1045: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
1046: chr = 0;
1047: if(scn >= 0x02 && scn <= 0x0e) {
1048: scn += 0x78 - 0x02; // 1 to 0 - =
1049: }
1050: }
1051: key_buf_char->write(chr);
1052: key_buf_scan->write(scn);
1053: }
1054: }
1055: }
1056: for(int i = dwRead; --i >= 0;) {
1057: if((ir[i].EventType & KEY_EVENT)) {
1058: kbd_data = ir[i].Event.KeyEvent.wVirtualScanCode & 0x7f;
1059: if(!ir[i].Event.KeyEvent.bKeyDown) {
1060: kbd_data |= 0x80;
1.1 root 1061: }
1.1.1.14 root 1062: return true;
1.1 root 1063: }
1064: }
1065: }
1066: }
1.1.1.14 root 1067: return false;
1.1.1.8 root 1068: }
1069:
1.1.1.14 root 1070: bool update_key_buffer()
1.1.1.8 root 1071: {
1072: int prev_count = key_buf_char->count();
1.1.1.14 root 1073: bool input = update_key_buffer_tmp();
1.1.1.8 root 1074: key_input += key_buf_char->count() - prev_count;
1.1.1.14 root 1075: return(input || key_buf_char->count() != 0);
1.1 root 1076: }
1077:
1.1.1.8 root 1078: int check_key_input()
1079: {
1080: if(key_input == 0) {
1081: int prev_count = key_buf_char->count();
1.1.1.14 root 1082: bool input = update_key_buffer_tmp();
1.1.1.8 root 1083: key_input = key_buf_char->count() - prev_count;
1.1.1.14 root 1084: if(key_input == 0 && input) {
1085: key_input = 1;
1086: }
1.1.1.8 root 1087: }
1088: int val = key_input;
1089: key_input = 0;
1090: return(val);
1091: }
1092:
1.1.1.20 root 1093: /* ----------------------------------------------------------------------------
1094: MS-DOS virtual machine
1095: ---------------------------------------------------------------------------- */
1096:
1097: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg);
1098: int msdos_psp_get_file_table(int fd, int psp_seg);
1099: void msdos_putch(UINT8 data);
1100:
1.1 root 1101: // process info
1102:
1103: process_t *msdos_process_info_create(UINT16 psp_seg)
1104: {
1105: for(int i = 0; i < MAX_PROCESS; i++) {
1106: if(process[i].psp == 0 || process[i].psp == psp_seg) {
1107: memset(&process[i], 0, sizeof(process_t));
1108: process[i].psp = psp_seg;
1109: return(&process[i]);
1110: }
1111: }
1112: fatalerror("too many processes\n");
1113: return(NULL);
1114: }
1115:
1116: process_t *msdos_process_info_get(UINT16 psp_seg)
1117: {
1118: for(int i = 0; i < MAX_PROCESS; i++) {
1119: if(process[i].psp == psp_seg) {
1120: return(&process[i]);
1121: }
1122: }
1123: fatalerror("invalid psp address\n");
1124: return(NULL);
1125: }
1126:
1.1.1.13 root 1127: // dta info
1128:
1129: void msdos_dta_info_init()
1130: {
1.1.1.14 root 1131: for(int i = 0; i < MAX_DTAINFO; i++) {
1.1.1.13 root 1132: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
1133: }
1134: }
1135:
1136: dtainfo_t *msdos_dta_info_get(UINT16 psp_seg, UINT32 dta_laddr)
1137: {
1138: dtainfo_t *free_dta = NULL;
1.1.1.14 root 1139: for(int i = 0; i < MAX_DTAINFO; i++) {
1140: if(dtalist[i].find_handle == INVALID_HANDLE_VALUE) {
1141: if(free_dta == NULL) {
1.1.1.13 root 1142: free_dta = &dtalist[i];
1143: }
1.1.1.14 root 1144: } else if(dta_laddr < LFN_DTA_LADDR && dtalist[i].dta == dta_laddr) {
1.1.1.13 root 1145: return(&dtalist[i]);
1146: }
1147: }
1.1.1.14 root 1148: if(free_dta) {
1.1.1.13 root 1149: free_dta->psp = psp_seg;
1150: free_dta->dta = dta_laddr;
1151: return(free_dta);
1152: }
1153: fatalerror("too many dta\n");
1154: return(NULL);
1155: }
1156:
1157: void msdos_dta_info_free(UINT16 psp_seg)
1158: {
1.1.1.14 root 1159: for(int i = 0; i < MAX_DTAINFO; i++) {
1160: if(dtalist[i].psp == psp_seg && dtalist[i].find_handle != INVALID_HANDLE_VALUE) {
1.1.1.13 root 1161: FindClose(dtalist[i].find_handle);
1162: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
1163: }
1164: }
1165: }
1166:
1.1 root 1167: void msdos_cds_update(int drv)
1168: {
1169: cds_t *cds = (cds_t *)(mem + CDS_TOP);
1170:
1171: memset(mem + CDS_TOP, 0, CDS_SIZE);
1172: sprintf(cds->path_name, "%c:\\", 'A' + drv);
1173: cds->drive_attrib = 0x4000; // physical drive
1174: cds->physical_drive_number = drv;
1175: }
1176:
1.1.1.17 root 1177: // nls information tables
1178:
1179: // uppercase table (func 6502h)
1180: void msdos_upper_table_update()
1181: {
1182: *(UINT16 *)(mem + UPPERTABLE_TOP) = 0x80;
1183: for(unsigned i=0; i<0x80; ++i) {
1184: UINT8 c[4];
1185: *(UINT32 *)c = 0; // reset internal conversion state
1186: CharUpperBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
1187: c[0] = 0x80 + i;
1188: DWORD rc = CharUpperBuffA((LPSTR)c, 1);
1189: mem[UPPERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
1190: }
1191: }
1192:
1193: // filename uppercase table (func 6504h)
1194: void msdos_filename_upper_table_init()
1195: {
1196: // depended on (file)system, not on active codepage
1197: // temporary solution: just filling data
1198: *(UINT16 *)(mem + FILENAME_UPPERTABLE_TOP) = 0x80;
1199: for(unsigned i=0; i<0x80; ++i) {
1200: mem[FILENAME_UPPERTABLE_TOP + 2 + i] = 0x80 + i;
1201: }
1202: }
1203:
1204: // filaname terminator table (func 6505h)
1205: void msdos_filename_terminator_table_init()
1206: {
1207: const char illegal_chars[] = ".\"/\\[]:|<>+=;,"; // for standard MS-DOS fs.
1208: UINT8 *data = mem + FILENAME_TERMINATOR_TOP;
1209:
1210: data[2] = 1; // marker? (permissible character value)
1211: data[3] = 0x00; // 00h...FFh
1212: data[4] = 0xff;
1213: data[5] = 0; // marker? (excluded character)
1214: data[6] = 0x00; // 00h...20h
1215: data[7] = 0x20;
1216: data[8] = 2; // marker? (illegal characters for filename)
1217: data[9] = (UINT8)strlen(illegal_chars);
1218: memcpy(data + 10, illegal_chars, data[9]);
1219:
1220: // total length
1221: *(UINT16 *)data = (10 - 2) + data[9];
1222: }
1223:
1224: // collating table (func 6506h)
1225: void msdos_collating_table_update()
1226: {
1227: // temporary solution: just filling data
1228: *(UINT16 *)(mem + COLLATING_TABLE_TOP) = 0x100;
1229: for(unsigned i=0; i<256; ++i) {
1230: mem[COLLATING_TABLE_TOP + 2 + i] = i;
1231: }
1232: }
1233:
1.1 root 1234: // dbcs
1235:
1236: void msdos_dbcs_table_update()
1237: {
1238: UINT8 dbcs_data[DBCS_SIZE];
1239: memset(dbcs_data, 0, sizeof(dbcs_data));
1240:
1241: CPINFO info;
1242: GetCPInfo(active_code_page, &info);
1243:
1244: if(info.MaxCharSize != 1) {
1245: for(int i = 0;; i += 2) {
1246: UINT8 lo = info.LeadByte[i + 0];
1247: UINT8 hi = info.LeadByte[i + 1];
1248: dbcs_data[2 + i + 0] = lo;
1249: dbcs_data[2 + i + 1] = hi;
1250: if(lo == 0 && hi == 0) {
1251: dbcs_data[0] = i + 2;
1252: break;
1253: }
1254: }
1255: } else {
1256: dbcs_data[0] = 2; // ???
1257: }
1258: memcpy(mem + DBCS_TOP, dbcs_data, sizeof(dbcs_data));
1259: }
1260:
1.1.1.17 root 1261: void msdos_dbcs_table_finish()
1262: {
1263: if(active_code_page != system_code_page) {
1264: _setmbcp(system_code_page);
1265: }
1266: }
1267:
1268: void msdos_nls_tables_init()
1.1 root 1269: {
1270: system_code_page = active_code_page = _getmbcp();
1.1.1.17 root 1271: msdos_upper_table_update();
1272: msdos_filename_terminator_table_init();
1273: msdos_filename_upper_table_init();
1274: msdos_collating_table_update();
1.1 root 1275: msdos_dbcs_table_update();
1276: }
1277:
1.1.1.17 root 1278: void msdos_nls_tables_update()
1.1 root 1279: {
1.1.1.17 root 1280: msdos_dbcs_table_update();
1281: msdos_upper_table_update();
1282: // msdos_collating_table_update();
1.1 root 1283: }
1284:
1285: int msdos_lead_byte_check(UINT8 code)
1286: {
1287: UINT8 *dbcs_table = mem + DBCS_TABLE;
1288:
1289: for(int i = 0;; i += 2) {
1290: UINT8 lo = dbcs_table[i + 0];
1291: UINT8 hi = dbcs_table[i + 1];
1292: if(lo == 0 && hi == 0) {
1293: break;
1294: }
1295: if(lo <= code && code <= hi) {
1296: return(1);
1297: }
1298: }
1299: return(0);
1300: }
1301:
1.1.1.20 root 1302: int msdos_ctrl_code_check(UINT8 code)
1303: {
1304: return (code >= 0x01 && code <= 0x1a && code != 0x08 && code != 0x09 && code != 0x0a && code != 0x0d);
1305: }
1306:
1.1 root 1307: // file control
1308:
1.1.1.14 root 1309: char *msdos_remove_double_quote(char *path)
1310: {
1311: static char tmp[MAX_PATH];
1312:
1313: memset(tmp, 0, sizeof(tmp));
1314: if(strlen(path) >= 2 && path[0] == '"' && path[strlen(path) - 1] == '"') {
1315: memcpy(tmp, path + 1, strlen(path) - 2);
1316: } else {
1317: strcpy(tmp, path);
1318: }
1319: return(tmp);
1320: }
1321:
1322: char *msdos_combine_path(char *dir, const char *file)
1323: {
1324: static char tmp[MAX_PATH];
1325: char *tmp_dir = msdos_remove_double_quote(dir);
1326:
1327: if(strlen(tmp_dir) == 0) {
1328: strcpy(tmp, file);
1329: } else if(tmp_dir[strlen(tmp_dir) - 1] == '\\') {
1330: sprintf(tmp, "%s%s", tmp_dir, file);
1331: } else {
1332: sprintf(tmp, "%s\\%s", tmp_dir, file);
1333: }
1334: return(tmp);
1335: }
1336:
1.1 root 1337: char *msdos_trimmed_path(char *path, int lfn)
1338: {
1339: static char tmp[MAX_PATH];
1340:
1341: if(lfn) {
1342: strcpy(tmp, path);
1343: } else {
1344: // remove space in the path
1345: char *src = path, *dst = tmp;
1346:
1347: while(*src != '\0') {
1348: if(msdos_lead_byte_check(*src)) {
1349: *dst++ = *src++;
1350: *dst++ = *src++;
1351: } else if(*src != ' ') {
1352: *dst++ = *src++;
1353: } else {
1354: src++; // skip space
1355: }
1356: }
1357: *dst = '\0';
1358: }
1.1.1.14 root 1359: if(_stricmp(tmp, "C:\\COMMAND.COM") == 0) {
1360: // redirect C:\COMMAND.COM to comspec_path
1361: strcpy(tmp, comspec_path);
1362: } else if(is_vista_or_later && _access(tmp, 0) != 0) {
1363: // redirect new files (without wildcards) in C:\ to %TEMP%, since C:\ is not usually writable
1364: static int root_drive_protected = -1;
1365: char temp[MAX_PATH], name[MAX_PATH], *name_temp = NULL;
1366: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
1367:
1368: if(GetFullPathName(tmp, MAX_PATH, temp, &name_temp) != 0 &&
1369: name_temp != NULL && strstr(name_temp, "?") == NULL && strstr(name_temp, "*") == NULL) {
1370: strcpy(name, name_temp);
1371: name_temp[0] = '\0';
1372:
1373: if((temp[0] == 'A' + dos_info->boot_drive - 1 || temp[0] == 'a' + dos_info->boot_drive - 1) &&
1374: (temp[1] == ':') && (temp[2] == '\\' || temp[2] == '/') && (temp[3] == '\0')) {
1375: if(root_drive_protected == -1) {
1376: FILE *fp = NULL;
1377:
1378: sprintf(temp, "%c:\\MS-DOS_Player.$$$", 'A' + dos_info->boot_drive - 1);
1379: root_drive_protected = 1;
1380: try {
1381: if((fp = fopen(temp, "w")) != NULL) {
1382: if(fprintf(fp, "TEST") == 4) {
1383: root_drive_protected = 0;
1384: }
1385: }
1386: } catch(...) {
1387: }
1388: if(fp != NULL) {
1389: fclose(fp);
1390: }
1391: if(_access(temp, 0) == 0) {
1392: remove(temp);
1393: }
1394: }
1395: if(root_drive_protected == 1) {
1396: if(GetEnvironmentVariable("TEMP", temp, MAX_PATH) != 0 ||
1397: GetEnvironmentVariable("TMP", temp, MAX_PATH) != 0) {
1398: strcpy(tmp, msdos_combine_path(temp, name));
1399: }
1400: }
1401: }
1402: }
1403: }
1.1 root 1404: return(tmp);
1405: }
1406:
1407: bool match(char *text, char *pattern)
1408: {
1409: //http://www.prefield.com/algorithm/string/wildcard.html
1.1.1.14 root 1410: switch(*pattern) {
1.1 root 1411: case '\0':
1412: return !*text;
1413: case '*':
1.1.1.14 root 1414: return match(text, pattern + 1) || (*text && match(text + 1, pattern));
1.1 root 1415: case '?':
1416: return *text && match(text + 1, pattern + 1);
1417: default:
1418: return (*text == *pattern) && match(text + 1, pattern + 1);
1419: }
1420: }
1421:
1422: bool msdos_match_volume_label(char *path, char *volume)
1423: {
1424: char *p;
1425:
1.1.1.14 root 1426: if(!*volume) {
1427: return false;
1428: } else if((p = my_strchr(path, ':')) != NULL) {
1.1 root 1429: return msdos_match_volume_label(p + 1, volume);
1430: } else if((p = my_strchr(path, '\\')) != NULL) {
1431: return msdos_match_volume_label(p + 1, volume);
1432: } else if((p = my_strchr(path, '.')) != NULL) {
1.1.1.14 root 1433: char tmp[MAX_PATH];
1434: sprintf(tmp, "%.*s%s", (int)(p - path), path, p + 1);
1435: return match(volume, tmp);
1.1 root 1436: } else {
1437: return match(volume, path);
1438: }
1439: }
1440:
1441: char *msdos_fcb_path(fcb_t *fcb)
1442: {
1443: static char tmp[MAX_PATH];
1444: char name[9], ext[4];
1445:
1446: memset(name, 0, sizeof(name));
1447: memcpy(name, fcb->file_name, 8);
1448: strcpy(name, msdos_trimmed_path(name, 0));
1449:
1450: memset(ext, 0, sizeof(ext));
1451: memcpy(ext, fcb->file_name + 8, 3);
1452: strcpy(ext, msdos_trimmed_path(ext, 0));
1453:
1454: if(name[0] == '\0' || strcmp(name, "????????") == 0) {
1455: strcpy(name, "*");
1456: }
1457: if(ext[0] == '\0') {
1458: strcpy(tmp, name);
1459: } else {
1460: if(strcmp(ext, "???") == 0) {
1461: strcpy(ext, "*");
1462: }
1463: sprintf(tmp, "%s.%s", name, ext);
1464: }
1465: return(tmp);
1466: }
1467:
1468: void msdos_set_fcb_path(fcb_t *fcb, char *path)
1469: {
1470: char *ext = my_strchr(path, '.');
1471:
1472: memset(fcb->file_name, 0x20, 8 + 3);
1473: if(ext != NULL && path[0] != '.') {
1474: *ext = '\0';
1475: memcpy(fcb->file_name + 8, ext + 1, strlen(ext + 1));
1476: }
1477: memcpy(fcb->file_name, path, strlen(path));
1478: }
1479:
1480: char *msdos_short_path(char *path)
1481: {
1482: static char tmp[MAX_PATH];
1483:
1484: GetShortPathName(path, tmp, MAX_PATH);
1485: my_strupr(tmp);
1486: return(tmp);
1487: }
1488:
1.1.1.13 root 1489: char *msdos_short_name(WIN32_FIND_DATA *fd)
1490: {
1491: static char tmp[MAX_PATH];
1492:
1.1.1.14 root 1493: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 1494: strcpy(tmp, fd->cAlternateFileName);
1495: } else {
1496: strcpy(tmp, fd->cFileName);
1497: }
1498: my_strupr(tmp);
1499: return(tmp);
1500: }
1501:
1.1 root 1502: char *msdos_short_full_path(char *path)
1503: {
1504: static char tmp[MAX_PATH];
1505: char full[MAX_PATH], *name;
1506:
1.1.1.14 root 1507: // Full works with non-existent files, but Short does not
1.1 root 1508: GetFullPathName(path, MAX_PATH, full, &name);
1.1.1.14 root 1509: *tmp = '\0';
1510: if(GetShortPathName(full, tmp, MAX_PATH) == 0 && name > path) {
1511: name[-1] = '\0';
1512: DWORD len = GetShortPathName(full, tmp, MAX_PATH);
1513: if(len == 0) {
1514: strcpy(tmp, full);
1515: } else {
1516: tmp[len++] = '\\';
1517: strcpy(tmp + len, name);
1518: }
1519: }
1.1 root 1520: my_strupr(tmp);
1521: return(tmp);
1522: }
1523:
1524: char *msdos_short_full_dir(char *path)
1525: {
1526: static char tmp[MAX_PATH];
1527: char full[MAX_PATH], *name;
1528:
1529: GetFullPathName(path, MAX_PATH, full, &name);
1530: name[-1] = '\0';
1531: GetShortPathName(full, tmp, MAX_PATH);
1532: my_strupr(tmp);
1533: return(tmp);
1534: }
1535:
1536: char *msdos_local_file_path(char *path, int lfn)
1537: {
1538: char *trimmed = msdos_trimmed_path(path, lfn);
1.1.1.14 root 1539: #if 0
1540: // I have forgotten the reason of this routine... :-(
1.1 root 1541: if(_access(trimmed, 0) != 0) {
1542: process_t *process = msdos_process_info_get(current_psp);
1543: static char tmp[MAX_PATH];
1544:
1545: sprintf(tmp, "%s\\%s", process->module_dir, trimmed);
1546: if(_access(tmp, 0) == 0) {
1547: return(tmp);
1548: }
1549: }
1.1.1.14 root 1550: #endif
1.1 root 1551: return(trimmed);
1552: }
1553:
1.1.1.11 root 1554: bool msdos_is_con_path(char *path)
1555: {
1556: char full[MAX_PATH], *name;
1557:
1558: GetFullPathName(path, MAX_PATH, full, &name);
1559: return(_stricmp(full, "\\\\.\\CON") == 0);
1560: }
1561:
1.1.1.14 root 1562: bool msdos_is_nul_path(char *path)
1.1.1.8 root 1563: {
1.1.1.14 root 1564: char full[MAX_PATH], *name;
1.1.1.8 root 1565:
1.1.1.14 root 1566: GetFullPathName(path, MAX_PATH, full, &name);
1567: return(_stricmp(full, "\\\\.\\NUL") == 0);
1.1.1.8 root 1568: }
1569:
1.1.1.9 root 1570: char *msdos_search_command_com(char *command_path, char *env_path)
1571: {
1572: static char tmp[MAX_PATH];
1573: char path[MAX_PATH], *file_name;
1574:
1575: if(GetFullPathName(command_path, MAX_PATH, tmp, &file_name) != 0) {
1576: sprintf(file_name, "COMMAND.COM");
1577: if(_access(tmp, 0) == 0) {
1578: return(tmp);
1579: }
1580: }
1581: if(GetModuleFileName(NULL, path, MAX_PATH) != 0 && GetFullPathName(path, MAX_PATH, tmp, &file_name) != 0) {
1582: sprintf(file_name, "COMMAND.COM");
1583: if(_access(tmp, 0) == 0) {
1584: return(tmp);
1585: }
1586: }
1587: if(GetFullPathName("COMMAND.COM", MAX_PATH, tmp, &file_name) != 0) {
1588: if(_access(tmp, 0) == 0) {
1589: return(tmp);
1590: }
1591: }
1592: char *token = my_strtok(env_path, ";");
1593: while(token != NULL) {
1.1.1.14 root 1594: if(strlen(token) != 0 && token[0] != '%') {
1.1.1.9 root 1595: strcpy(tmp, msdos_combine_path(token, "COMMAND.COM"));
1596: if(_access(tmp, 0) == 0) {
1597: return(tmp);
1598: }
1599: }
1600: token = my_strtok(NULL, ";");
1601: }
1602: return(NULL);
1603: }
1604:
1.1.1.14 root 1605: int msdos_drive_number(const char *path)
1.1 root 1606: {
1607: char tmp[MAX_PATH], *name;
1608:
1609: GetFullPathName(path, MAX_PATH, tmp, &name);
1610: if(tmp[0] >= 'a' && tmp[0] <= 'z') {
1611: return(tmp[0] - 'a');
1612: } else {
1613: return(tmp[0] - 'A');
1614: }
1615: }
1616:
1617: char *msdos_volume_label(char *path)
1618: {
1619: static char tmp[MAX_PATH];
1620: char volume[] = "A:\\";
1621:
1622: if(path[1] == ':') {
1623: volume[0] = path[0];
1624: } else {
1625: volume[0] = 'A' + _getdrive() - 1;
1626: }
1627: if(!GetVolumeInformation(volume, tmp, MAX_PATH, NULL, NULL, NULL, NULL, 0)) {
1628: memset(tmp, 0, sizeof(tmp));
1629: }
1630: return(tmp);
1631: }
1632:
1633: char *msdos_short_volume_label(char *label)
1634: {
1635: static char tmp[(8 + 1 + 3) + 1];
1636: char *src = label;
1637: int remain = strlen(label);
1638: char *dst_n = tmp;
1639: char *dst_e = tmp + 9;
1640:
1641: strcpy(tmp, " . ");
1642: for(int i = 0; i < 8 && remain > 0; i++) {
1643: if(msdos_lead_byte_check(*src)) {
1644: if(++i == 8) {
1645: break;
1646: }
1647: *dst_n++ = *src++;
1648: remain--;
1649: }
1650: *dst_n++ = *src++;
1651: remain--;
1652: }
1653: if(remain > 0) {
1654: for(int i = 0; i < 3 && remain > 0; i++) {
1655: if(msdos_lead_byte_check(*src)) {
1656: if(++i == 3) {
1657: break;
1658: }
1659: *dst_e++ = *src++;
1660: remain--;
1661: }
1662: *dst_e++ = *src++;
1663: remain--;
1664: }
1665: *dst_e = '\0';
1666: } else {
1667: *dst_n = '\0';
1668: }
1669: my_strupr(tmp);
1670: return(tmp);
1671: }
1672:
1.1.1.13 root 1673: errno_t msdos_maperr(unsigned long oserrno)
1674: {
1675: _doserrno = oserrno;
1.1.1.14 root 1676: switch(oserrno) {
1.1.1.13 root 1677: case ERROR_FILE_NOT_FOUND: // 2
1678: case ERROR_PATH_NOT_FOUND: // 3
1679: case ERROR_INVALID_DRIVE: // 15
1680: case ERROR_NO_MORE_FILES: // 18
1681: case ERROR_BAD_NETPATH: // 53
1682: case ERROR_BAD_NET_NAME: // 67
1683: case ERROR_BAD_PATHNAME: // 161
1684: case ERROR_FILENAME_EXCED_RANGE: // 206
1685: return ENOENT;
1686: case ERROR_TOO_MANY_OPEN_FILES: // 4
1687: return EMFILE;
1688: case ERROR_ACCESS_DENIED: // 5
1689: case ERROR_CURRENT_DIRECTORY: // 16
1690: case ERROR_NETWORK_ACCESS_DENIED: // 65
1691: case ERROR_CANNOT_MAKE: // 82
1692: case ERROR_FAIL_I24: // 83
1693: case ERROR_DRIVE_LOCKED: // 108
1694: case ERROR_SEEK_ON_DEVICE: // 132
1695: case ERROR_NOT_LOCKED: // 158
1696: case ERROR_LOCK_FAILED: // 167
1697: return EACCES;
1698: case ERROR_INVALID_HANDLE: // 6
1699: case ERROR_INVALID_TARGET_HANDLE: // 114
1700: case ERROR_DIRECT_ACCESS_HANDLE: // 130
1701: return EBADF;
1702: case ERROR_ARENA_TRASHED: // 7
1703: case ERROR_NOT_ENOUGH_MEMORY: // 8
1704: case ERROR_INVALID_BLOCK: // 9
1705: case ERROR_NOT_ENOUGH_QUOTA: // 1816
1706: return ENOMEM;
1707: case ERROR_BAD_ENVIRONMENT: // 10
1708: return E2BIG;
1709: case ERROR_BAD_FORMAT: // 11
1710: return ENOEXEC;
1711: case ERROR_NOT_SAME_DEVICE: // 17
1712: return EXDEV;
1713: case ERROR_FILE_EXISTS: // 80
1714: case ERROR_ALREADY_EXISTS: // 183
1715: return EEXIST;
1716: case ERROR_NO_PROC_SLOTS: // 89
1717: case ERROR_MAX_THRDS_REACHED: // 164
1718: case ERROR_NESTING_NOT_ALLOWED: // 215
1719: return EAGAIN;
1720: case ERROR_BROKEN_PIPE: // 109
1721: return EPIPE;
1722: case ERROR_DISK_FULL: // 112
1723: return ENOSPC;
1724: case ERROR_WAIT_NO_CHILDREN: // 128
1725: case ERROR_CHILD_NOT_COMPLETE: // 129
1726: return ECHILD;
1727: case ERROR_DIR_NOT_EMPTY: // 145
1728: return ENOTEMPTY;
1729: }
1.1.1.14 root 1730: if(oserrno >= ERROR_WRITE_PROTECT /* 19 */ &&
1.1.1.13 root 1731: oserrno <= ERROR_SHARING_BUFFER_EXCEEDED /* 36 */) {
1732: return EACCES;
1733: }
1.1.1.14 root 1734: if(oserrno >= ERROR_INVALID_STARTING_CODESEG /* 188 */ &&
1.1.1.13 root 1735: oserrno <= ERROR_INFLOOP_IN_RELOC_CHAIN /* 202 */) {
1736: return ENOEXEC;
1737: }
1738: return EINVAL;
1739: }
1740:
1741: int msdos_open(const char *filename, int oflag)
1742: {
1.1.1.14 root 1743: if((oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) != _O_RDONLY) {
1.1.1.13 root 1744: return _open(filename, oflag);
1745: }
1.1.1.14 root 1746:
1747: SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, !(oflag & _O_NOINHERIT) };
1.1.1.13 root 1748: DWORD disposition;
1.1.1.14 root 1749: switch(oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
1750: default:
1.1.1.13 root 1751: case _O_EXCL:
1752: disposition = OPEN_EXISTING;
1753: break;
1754: case _O_CREAT:
1755: disposition = OPEN_ALWAYS;
1756: break;
1757: case _O_CREAT | _O_EXCL:
1758: case _O_CREAT | _O_TRUNC | _O_EXCL:
1759: disposition = CREATE_NEW;
1760: break;
1761: case _O_TRUNC:
1762: case _O_TRUNC | _O_EXCL:
1763: disposition = TRUNCATE_EXISTING;
1764: break;
1765: case _O_CREAT | _O_TRUNC:
1766: disposition = CREATE_ALWAYS;
1767: break;
1768: }
1.1.1.14 root 1769:
1.1.1.13 root 1770: HANDLE h = CreateFile(filename, GENERIC_READ | FILE_WRITE_ATTRIBUTES,
1771: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
1772: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 1773: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 1774: // FILE_WRITE_ATTRIBUTES may not be granted for standard users.
1775: // Retry without FILE_WRITE_ATTRIBUTES.
1776: h = CreateFile(filename, GENERIC_READ,
1777: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
1778: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 1779: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 1780: errno = msdos_maperr(GetLastError());
1781: return -1;
1782: }
1783: }
1.1.1.14 root 1784:
1.1.1.13 root 1785: int fd = _open_osfhandle((intptr_t) h, oflag);
1.1.1.14 root 1786: if(fd == -1) {
1.1.1.13 root 1787: CloseHandle(h);
1788: }
1789: return fd;
1790: }
1791:
1.1.1.14 root 1792: void msdos_file_handler_open(int fd, const char *path, int atty, int mode, UINT16 info, UINT16 psp_seg)
1.1 root 1793: {
1794: static int id = 0;
1795: char full[MAX_PATH], *name;
1796:
1797: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1798: strcpy(file_handler[fd].path, full);
1799: } else {
1800: strcpy(file_handler[fd].path, path);
1801: }
1.1.1.14 root 1802: // isatty makes no distinction between CON & NUL
1803: // GetFileSize fails on CON, succeeds on NUL
1804: if(atty && (info != 0x80d3 || GetFileSize((HANDLE)_get_osfhandle(fd), NULL) == 0)) {
1805: info = 0x8084;
1806: atty = 0;
1807: } else if(!atty && info == 0x80d3) {
1808: info = msdos_drive_number(".");
1809: }
1.1 root 1810: file_handler[fd].valid = 1;
1811: file_handler[fd].id = id++; // dummy id for int 21h ax=71a6h
1812: file_handler[fd].atty = atty;
1813: file_handler[fd].mode = mode;
1814: file_handler[fd].info = info;
1815: file_handler[fd].psp = psp_seg;
1.1.1.21! root 1816:
! 1817: // init system file table
! 1818: if(fd < 20) {
! 1819: UINT8 *sft = mem + SFT_TOP + 6 + 0x3b * fd;
! 1820:
! 1821: memset(sft, 0, 0x3b);
! 1822:
! 1823: *(UINT16 *)(sft + 0x00) = 1;
! 1824: *(UINT16 *)(sft + 0x02) = file_handler[fd].mode;
! 1825: *(UINT8 *)(sft + 0x04) = GetFileAttributes(file_handler[fd].path) & 0xff;
! 1826: *(UINT16 *)(sft + 0x05) = file_handler[fd].info & 0xff;
! 1827:
! 1828: if(!(file_handler[fd].info & 0x80)) {
! 1829: *(UINT16 *)(sft + 0x07) = sizeof(dpb_t) * (file_handler[fd].info & 0x1f);
! 1830: *(UINT16 *)(sft + 0x09) = DPB_TOP >> 4;
! 1831:
! 1832: FILETIME time, local;
! 1833: HANDLE hHandle;
! 1834: WORD dos_date = 0, dos_time = 0;
! 1835: DWORD file_size = 0;
! 1836: if((hHandle = (HANDLE)_get_osfhandle(fd)) != INVALID_HANDLE_VALUE) {
! 1837: if(GetFileTime(hHandle, NULL, NULL, &time)) {
! 1838: FileTimeToLocalFileTime(&time, &local);
! 1839: FileTimeToDosDateTime(&local, &dos_date, &dos_time);
! 1840: }
! 1841: file_size = GetFileSize(hHandle, NULL);
! 1842: }
! 1843: *(UINT16 *)(sft + 0x0d) = dos_time;
! 1844: *(UINT16 *)(sft + 0x0f) = dos_date;
! 1845: *(UINT32 *)(sft + 0x11) = file_size;
! 1846: }
! 1847:
! 1848: char fname[MAX_PATH] = {0}, ext[MAX_PATH] = {0};
! 1849: _splitpath(file_handler[fd].path, NULL, NULL, fname, ext);
! 1850: my_strupr(fname);
! 1851: my_strupr(ext);
! 1852: memset(sft + 0x20, 0x20, 11);
! 1853: memcpy(sft + 0x20, fname, min(strlen(fname), 8));
! 1854: memcpy(sft + 0x28, ext + 1, min(strlen(ext + 1), 3));
! 1855:
! 1856: *(UINT16 *)(sft + 0x31) = psp_seg;
! 1857: }
1.1 root 1858: }
1859:
1860: void msdos_file_handler_dup(int dst, int src, UINT16 psp_seg)
1861: {
1862: strcpy(file_handler[dst].path, file_handler[src].path);
1863: file_handler[dst].valid = 1;
1864: file_handler[dst].id = file_handler[src].id;
1865: file_handler[dst].atty = file_handler[src].atty;
1866: file_handler[dst].mode = file_handler[src].mode;
1867: file_handler[dst].info = file_handler[src].info;
1868: file_handler[dst].psp = psp_seg;
1869: }
1870:
1.1.1.20 root 1871: void msdos_file_handler_close(int fd)
1.1 root 1872: {
1873: file_handler[fd].valid = 0;
1.1.1.21! root 1874:
! 1875: if(fd < 20) {
! 1876: memset(mem + SFT_TOP + 6 + 0x3b * fd, 0, 0x3b);
! 1877: }
1.1 root 1878: }
1879:
1.1.1.14 root 1880: inline int msdos_file_attribute_create(UINT16 new_attr)
1.1 root 1881: {
1.1.1.14 root 1882: return(new_attr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
1883: FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE |
1884: FILE_ATTRIBUTE_DIRECTORY));
1.1 root 1885: }
1886:
1887: // find file
1888:
1889: int msdos_find_file_check_attribute(int attribute, int allowed_mask, int required_mask)
1890: {
1891: if((allowed_mask & 0x08) && !(attribute & FILE_ATTRIBUTE_DIRECTORY)) {
1892: return(0); // search directory only !!!
1893: } else if(!(allowed_mask & 0x02) && (attribute & FILE_ATTRIBUTE_HIDDEN)) {
1894: return(0);
1895: } else if(!(allowed_mask & 0x04) && (attribute & FILE_ATTRIBUTE_SYSTEM)) {
1896: return(0);
1897: } else if(!(allowed_mask & 0x10) && (attribute & FILE_ATTRIBUTE_DIRECTORY)) {
1898: return(0);
1899: } else if((attribute & required_mask) != required_mask) {
1900: return(0);
1901: } else {
1902: return(1);
1903: }
1904: }
1905:
1.1.1.13 root 1906: int msdos_find_file_has_8dot3name(WIN32_FIND_DATA *fd)
1907: {
1.1.1.14 root 1908: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 1909: return 1;
1910: }
1911: size_t len = strlen(fd->cFileName);
1.1.1.14 root 1912: if(len > 12) {
1.1.1.13 root 1913: return 0;
1914: }
1915: const char *ext = strrchr(fd->cFileName, '.');
1.1.1.14 root 1916: if((ext ? ext - fd->cFileName : len) > 8) {
1.1.1.13 root 1917: return 0;
1918: }
1919: return 1;
1920: }
1921:
1.1 root 1922: void msdos_find_file_conv_local_time(WIN32_FIND_DATA *fd)
1923: {
1924: FILETIME local;
1925:
1926: FileTimeToLocalFileTime(&fd->ftCreationTime, &local);
1927: fd->ftCreationTime.dwLowDateTime = local.dwLowDateTime;
1928: fd->ftCreationTime.dwHighDateTime = local.dwHighDateTime;
1929:
1930: FileTimeToLocalFileTime(&fd->ftLastAccessTime, &local);
1931: fd->ftLastAccessTime.dwLowDateTime = local.dwLowDateTime;
1932: fd->ftLastAccessTime.dwHighDateTime = local.dwHighDateTime;
1933:
1934: FileTimeToLocalFileTime(&fd->ftLastWriteTime, &local);
1935: fd->ftLastWriteTime.dwLowDateTime = local.dwLowDateTime;
1936: fd->ftLastWriteTime.dwHighDateTime = local.dwHighDateTime;
1937: }
1938:
1939: // i/o
1940:
1941: void msdos_stdio_reopen()
1942: {
1943: if(!file_handler[0].valid) {
1944: _dup2(DUP_STDIN, 0);
1945: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
1946: }
1947: if(!file_handler[1].valid) {
1948: _dup2(DUP_STDOUT, 1);
1949: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
1950: }
1951: if(!file_handler[2].valid) {
1952: _dup2(DUP_STDERR, 2);
1953: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
1954: }
1.1.1.21! root 1955: if(!file_handler[3].valid) {
! 1956: _dup2(DUP_STDAUX, 3);
! 1957: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
! 1958: }
! 1959: if(!file_handler[4].valid) {
! 1960: _dup2(DUP_STDPRN, 4);
! 1961: msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0);
! 1962: }
! 1963: for(int i = 0; i < 5; i++) {
! 1964: if(msdos_psp_get_file_table(i, current_psp) == 0xff) {
! 1965: msdos_psp_set_file_table(i, i, current_psp);
! 1966: }
! 1967: }
1.1 root 1968: }
1969:
1970: int msdos_kbhit()
1971: {
1972: msdos_stdio_reopen();
1973:
1.1.1.20 root 1974: process_t *process = msdos_process_info_get(current_psp);
1975: int fd = msdos_psp_get_file_table(0, current_psp);
1976:
1977: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 1978: // stdin is redirected to file
1.1.1.20 root 1979: return(eof(fd) == 0);
1.1 root 1980: }
1981:
1982: // check keyboard status
1.1.1.5 root 1983: if(key_buf_char->count() != 0 || key_code != 0) {
1.1 root 1984: return(1);
1985: } else {
1986: return(_kbhit());
1987: }
1988: }
1989:
1990: int msdos_getch_ex(int echo)
1991: {
1992: static char prev = 0;
1993:
1994: msdos_stdio_reopen();
1995:
1.1.1.20 root 1996: process_t *process = msdos_process_info_get(current_psp);
1997: int fd = msdos_psp_get_file_table(0, current_psp);
1998:
1999: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 2000: // stdin is redirected to file
2001: retry:
2002: char data;
1.1.1.20 root 2003: if(_read(fd, &data, 1) == 1) {
1.1 root 2004: char tmp = data;
2005: if(data == 0x0a) {
2006: if(prev == 0x0d) {
2007: goto retry; // CRLF -> skip LF
2008: } else {
2009: data = 0x0d; // LF only -> CR
2010: }
2011: }
2012: prev = tmp;
2013: return(data);
2014: }
2015: return(EOF);
2016: }
2017:
2018: // input from console
1.1.1.5 root 2019: int key_char, key_scan;
2020: if(key_code != 0) {
2021: key_char = (key_code >> 0) & 0xff;
2022: key_scan = (key_code >> 8) & 0xff;
2023: key_code >>= 16;
2024: } else {
1.1.1.14 root 2025: while(key_buf_char->count() == 0 && !m_halted) {
2026: if(!update_key_buffer()) {
2027: Sleep(10);
2028: }
2029: }
2030: if(m_halted) {
2031: // ctrl-c pressed - insert CR to terminate input loops
2032: key_char = 0x0d;
2033: key_scan = 0;
2034: } else {
2035: key_char = key_buf_char->read();
2036: key_scan = key_buf_scan->read();
1.1.1.5 root 2037: }
1.1 root 2038: }
2039: if(echo && key_char) {
2040: msdos_putch(key_char);
2041: }
2042: return key_char ? key_char : (key_scan != 0xe0) ? key_scan : 0;
2043: }
2044:
2045: inline int msdos_getch()
2046: {
2047: return(msdos_getch_ex(0));
2048: }
2049:
2050: inline int msdos_getche()
2051: {
2052: return(msdos_getch_ex(1));
2053: }
2054:
2055: int msdos_write(int fd, const void *buffer, unsigned int count)
2056: {
2057: static int is_cr = 0;
2058:
2059: if(fd == 1 && !file_handler[1].atty) {
2060: // CR+LF -> LF
2061: UINT8 *buf = (UINT8 *)buffer;
2062: for(unsigned int i = 0; i < count; i++) {
2063: UINT8 data = buf[i];
2064: if(is_cr) {
2065: if(data != 0x0a) {
2066: UINT8 tmp = 0x0d;
2067: _write(1, &tmp, 1);
2068: }
2069: _write(1, &data, 1);
2070: is_cr = 0;
2071: } else if(data == 0x0d) {
2072: is_cr = 1;
2073: } else {
2074: _write(1, &data, 1);
2075: }
2076: }
2077: return(count);
2078: }
1.1.1.14 root 2079: vram_flush();
1.1 root 2080: return(_write(fd, buffer, count));
2081: }
2082:
2083: void msdos_putch(UINT8 data)
2084: {
2085: static int p = 0;
2086: static int is_kanji = 0;
2087: static int is_esc = 0;
2088: static int stored_x;
2089: static int stored_y;
2090: static WORD stored_a;
1.1.1.20 root 2091: static char tmp[64], out[64];
1.1 root 2092:
2093: msdos_stdio_reopen();
2094:
1.1.1.20 root 2095: process_t *process = msdos_process_info_get(current_psp);
2096: int fd = msdos_psp_get_file_table(1, current_psp);
2097:
2098: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 2099: // stdout is redirected to file
1.1.1.20 root 2100: msdos_write(fd, &data, 1);
1.1 root 2101: return;
2102: }
2103:
2104: // output to console
2105: tmp[p++] = data;
2106:
1.1.1.14 root 2107: vram_flush();
2108:
1.1 root 2109: if(is_kanji) {
2110: // kanji character
2111: is_kanji = 0;
2112: } else if(is_esc) {
2113: // escape sequense
2114: if((tmp[1] == ')' || tmp[1] == '(') && p == 3) {
2115: p = is_esc = 0;
2116: } else if(tmp[1] == '=' && p == 4) {
2117: COORD co;
2118: co.X = tmp[3] - 0x20;
1.1.1.14 root 2119: co.Y = tmp[2] - 0x20 + scr_top;
1.1 root 2120: SetConsoleCursorPosition(hStdout, co);
2121: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 2122: mem[0x451 + mem[0x462] * 2] = co.Y - scr_top;
1.1 root 2123: cursor_moved = false;
2124: p = is_esc = 0;
2125: } else if((data >= 'a' && data <= 'z') || (data >= 'A' && data <= 'Z') || data == '*') {
2126: CONSOLE_SCREEN_BUFFER_INFO csbi;
2127: COORD co;
2128: GetConsoleScreenBufferInfo(hStdout, &csbi);
2129: co.X = csbi.dwCursorPosition.X;
2130: co.Y = csbi.dwCursorPosition.Y;
2131: WORD wAttributes = csbi.wAttributes;
2132:
2133: if(tmp[1] == 'D') {
2134: co.Y++;
2135: } else if(tmp[1] == 'E') {
2136: co.X = 0;
2137: co.Y++;
2138: } else if(tmp[1] == 'M') {
2139: co.Y--;
2140: } else if(tmp[1] == '*') {
2141: SMALL_RECT rect;
1.1.1.14 root 2142: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2143: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2144: co.X = 0;
2145: co.Y = csbi.srWindow.Top;
1.1 root 2146: } else if(tmp[1] == '[') {
2147: int param[256], params = 0;
2148: memset(param, 0, sizeof(param));
2149: for(int i = 2; i < p; i++) {
2150: if(tmp[i] >= '0' && tmp[i] <= '9') {
2151: param[params] *= 10;
2152: param[params] += tmp[i] - '0';
2153: } else {
2154: params++;
2155: }
2156: }
2157: if(data == 'A') {
1.1.1.14 root 2158: co.Y -= (params == 0) ? 1 : param[0];
1.1 root 2159: } else if(data == 'B') {
1.1.1.14 root 2160: co.Y += (params == 0) ? 1 : param[0];
1.1 root 2161: } else if(data == 'C') {
1.1.1.14 root 2162: co.X += (params == 0) ? 1 : param[0];
1.1 root 2163: } else if(data == 'D') {
1.1.1.14 root 2164: co.X -= (params == 0) ? 1 : param[0];
1.1 root 2165: } else if(data == 'H' || data == 'f') {
1.1.1.14 root 2166: co.X = (param[1] == 0 ? 1 : param[1]) - 1;
2167: co.Y = (param[0] == 0 ? 1 : param[0]) - 1 + csbi.srWindow.Top;
1.1 root 2168: } else if(data == 'J') {
2169: SMALL_RECT rect;
1.1.1.14 root 2170: clear_scr_buffer(csbi.wAttributes);
1.1 root 2171: if(param[0] == 0) {
2172: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 2173: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2174: if(co.Y < csbi.srWindow.Bottom) {
2175: SET_RECT(rect, 0, co.Y + 1, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2176: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2177: }
2178: } else if(param[0] == 1) {
1.1.1.14 root 2179: if(co.Y > csbi.srWindow.Top) {
2180: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, co.Y - 1);
2181: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2182: }
2183: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 2184: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2185: } else if(param[0] == 2) {
1.1.1.14 root 2186: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2187: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2188: co.X = co.Y = 0;
2189: }
2190: } else if(data == 'K') {
2191: SMALL_RECT rect;
1.1.1.14 root 2192: clear_scr_buffer(csbi.wAttributes);
1.1 root 2193: if(param[0] == 0) {
2194: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 2195: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2196: } else if(param[0] == 1) {
2197: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 2198: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2199: } else if(param[0] == 2) {
2200: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 2201: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2202: }
2203: } else if(data == 'L') {
2204: SMALL_RECT rect;
1.1.1.14 root 2205: if(params == 0) {
2206: param[0] = 1;
1.1 root 2207: }
1.1.1.14 root 2208: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2209: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2210: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2211: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2212: clear_scr_buffer(csbi.wAttributes);
1.1 root 2213: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y + param[0] - 1);
1.1.1.14 root 2214: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2215: co.X = 0;
2216: } else if(data == 'M') {
2217: SMALL_RECT rect;
1.1.1.14 root 2218: if(params == 0) {
2219: param[0] = 1;
2220: }
2221: if(co.Y + param[0] > csbi.srWindow.Bottom) {
2222: clear_scr_buffer(csbi.wAttributes);
2223: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2224: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2225: } else {
1.1.1.14 root 2226: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2227: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2228: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2229: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2230: clear_scr_buffer(csbi.wAttributes);
1.1 root 2231: }
2232: co.X = 0;
2233: } else if(data == 'h') {
2234: if(tmp[2] == '>' && tmp[3] == '5') {
2235: CONSOLE_CURSOR_INFO cur;
2236: GetConsoleCursorInfo(hStdout, &cur);
2237: if(cur.bVisible) {
2238: cur.bVisible = FALSE;
1.1.1.14 root 2239: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 2240: }
2241: }
2242: } else if(data == 'l') {
2243: if(tmp[2] == '>' && tmp[3] == '5') {
2244: CONSOLE_CURSOR_INFO cur;
2245: GetConsoleCursorInfo(hStdout, &cur);
2246: if(!cur.bVisible) {
2247: cur.bVisible = TRUE;
1.1.1.14 root 2248: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 2249: }
2250: }
2251: } else if(data == 'm') {
2252: wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
2253: int reverse = 0, hidden = 0;
2254: for(int i = 0; i < params; i++) {
2255: if(param[i] == 1) {
2256: wAttributes |= FOREGROUND_INTENSITY;
2257: } else if(param[i] == 4) {
2258: wAttributes |= COMMON_LVB_UNDERSCORE;
2259: } else if(param[i] == 7) {
2260: reverse = 1;
2261: } else if(param[i] == 8 || param[i] == 16) {
2262: hidden = 1;
2263: } else if((param[i] >= 17 && param[i] <= 23) || (param[i] >= 30 && param[i] <= 37)) {
2264: wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
2265: if(param[i] >= 17 && param[i] <= 23) {
2266: param[i] -= 16;
2267: } else {
2268: param[i] -= 30;
2269: }
2270: if(param[i] & 1) {
2271: wAttributes |= FOREGROUND_RED;
2272: }
2273: if(param[i] & 2) {
2274: wAttributes |= FOREGROUND_GREEN;
2275: }
2276: if(param[i] & 4) {
2277: wAttributes |= FOREGROUND_BLUE;
2278: }
2279: } else if(param[i] >= 40 && param[i] <= 47) {
2280: wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
2281: if((param[i] - 40) & 1) {
2282: wAttributes |= BACKGROUND_RED;
2283: }
2284: if((param[i] - 40) & 2) {
2285: wAttributes |= BACKGROUND_GREEN;
2286: }
2287: if((param[i] - 40) & 4) {
2288: wAttributes |= BACKGROUND_BLUE;
2289: }
2290: }
2291: }
2292: if(reverse) {
2293: wAttributes &= ~0xff;
2294: wAttributes |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
2295: }
2296: if(hidden) {
2297: wAttributes &= ~0x0f;
2298: wAttributes |= (wAttributes >> 4) & 0x0f;
2299: }
2300: } else if(data == 'n') {
2301: if(param[0] == 6) {
2302: char tmp[16];
2303: sprintf(tmp, "\x1b[%d;%dR", co.Y + 1, co.X + 1);
2304: int len = strlen(tmp);
2305: for(int i = 0; i < len; i++) {
2306: key_buf_char->write(tmp[i]);
2307: key_buf_scan->write(0x00);
2308: }
2309: }
2310: } else if(data == 's') {
2311: stored_x = co.X;
2312: stored_y = co.Y;
2313: stored_a = wAttributes;
2314: } else if(data == 'u') {
2315: co.X = stored_x;
2316: co.Y = stored_y;
2317: wAttributes = stored_a;
2318: }
2319: }
2320: if(co.X < 0) {
2321: co.X = 0;
2322: } else if(co.X >= csbi.dwSize.X) {
2323: co.X = csbi.dwSize.X - 1;
2324: }
1.1.1.14 root 2325: if(co.Y < csbi.srWindow.Top) {
2326: co.Y = csbi.srWindow.Top;
2327: } else if(co.Y > csbi.srWindow.Bottom) {
2328: co.Y = csbi.srWindow.Bottom;
1.1 root 2329: }
2330: if(co.X != csbi.dwCursorPosition.X || co.Y != csbi.dwCursorPosition.Y) {
2331: SetConsoleCursorPosition(hStdout, co);
2332: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 2333: mem[0x451 + mem[0x462] * 2] = co.Y - csbi.srWindow.Top;
1.1 root 2334: cursor_moved = false;
2335: }
2336: if(wAttributes != csbi.wAttributes) {
2337: SetConsoleTextAttribute(hStdout, wAttributes);
2338: }
2339: p = is_esc = 0;
2340: }
2341: return;
2342: } else {
2343: if(msdos_lead_byte_check(data)) {
2344: is_kanji = 1;
2345: return;
2346: } else if(data == 0x1b) {
2347: is_esc = 1;
2348: return;
2349: }
2350: }
1.1.1.20 root 2351:
2352: DWORD q = 0, num;
2353: is_kanji = 0;
2354: for(int i = 0; i < p; i++) {
2355: UINT8 c = tmp[i];
2356: if(is_kanji) {
2357: is_kanji = 0;
2358: } else if(msdos_lead_byte_check(data)) {
2359: is_kanji = 1;
2360: } else if(msdos_ctrl_code_check(data)) {
2361: out[q++] = '^';
2362: c += 'A' - 1;
2363: }
2364: out[q++] = c;
2365: }
2366: WriteConsole(hStdout, out, q, &num, NULL);
1.1 root 2367: p = 0;
1.1.1.14 root 2368:
1.1.1.15 root 2369: if(!restore_console_on_exit) {
2370: CONSOLE_SCREEN_BUFFER_INFO csbi;
2371: GetConsoleScreenBufferInfo(hStdout, &csbi);
2372: scr_top = csbi.srWindow.Top;
2373: }
1.1 root 2374: cursor_moved = true;
2375: }
2376:
2377: int msdos_aux_in()
2378: {
1.1.1.21! root 2379: msdos_stdio_reopen();
! 2380:
1.1.1.20 root 2381: process_t *process = msdos_process_info_get(current_psp);
2382: int fd = msdos_psp_get_file_table(3, current_psp);
2383:
2384: if(fd < process->max_files && file_handler[fd].valid && !eof(fd)) {
1.1 root 2385: char data = 0;
1.1.1.20 root 2386: _read(fd, &data, 1);
1.1 root 2387: return(data);
2388: } else {
2389: return(EOF);
2390: }
2391: }
2392:
2393: void msdos_aux_out(char data)
2394: {
1.1.1.21! root 2395: msdos_stdio_reopen();
! 2396:
1.1.1.20 root 2397: process_t *process = msdos_process_info_get(current_psp);
2398: int fd = msdos_psp_get_file_table(3, current_psp);
2399:
2400: if(fd < process->max_files && file_handler[fd].valid) {
2401: msdos_write(fd, &data, 1);
1.1 root 2402: }
2403: }
2404:
2405: void msdos_prn_out(char data)
2406: {
1.1.1.21! root 2407: msdos_stdio_reopen();
! 2408:
1.1.1.20 root 2409: process_t *process = msdos_process_info_get(current_psp);
2410: int fd = msdos_psp_get_file_table(4, current_psp);
2411:
2412: if(fd < process->max_files && file_handler[fd].valid) {
2413: msdos_write(fd, &data, 1);
1.1 root 2414: }
2415: }
2416:
2417: // memory control
2418:
1.1.1.19 root 2419: mcb_t *msdos_mcb_create(int mcb_seg, UINT8 mz, UINT16 psp, int paragraphs)
1.1 root 2420: {
2421: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2422:
2423: mcb->mz = mz;
2424: mcb->psp = psp;
1.1.1.19 root 2425: mcb->paragraphs32 = paragraphs;
1.1 root 2426: return(mcb);
2427: }
2428:
2429: void msdos_mcb_check(mcb_t *mcb)
2430: {
2431: if(!(mcb->mz == 'M' || mcb->mz == 'Z')) {
2432: fatalerror("broken mcb\n");
2433: }
2434: }
2435:
2436: int msdos_mem_split(int seg, int paragraphs)
2437: {
2438: int mcb_seg = seg - 1;
2439: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2440: msdos_mcb_check(mcb);
2441:
1.1.1.19 root 2442: if(mcb->paragraphs() > paragraphs) {
1.1 root 2443: int new_seg = mcb_seg + 1 + paragraphs;
1.1.1.19 root 2444: int new_paragraphs = mcb->paragraphs() - paragraphs - 1;
1.1 root 2445:
2446: msdos_mcb_create(new_seg, mcb->mz, 0, new_paragraphs);
2447: mcb->mz = 'M';
1.1.1.19 root 2448: mcb->paragraphs32 = paragraphs;
1.1 root 2449: return(0);
2450: }
2451: return(-1);
2452: }
2453:
2454: void msdos_mem_merge(int seg)
2455: {
2456: int mcb_seg = seg - 1;
2457: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2458: msdos_mcb_check(mcb);
2459:
2460: while(1) {
2461: if(mcb->mz == 'Z') {
2462: break;
2463: }
1.1.1.19 root 2464: int next_seg = mcb_seg + 1 + mcb->paragraphs();
1.1 root 2465: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
2466: msdos_mcb_check(next_mcb);
2467:
2468: if(next_mcb->psp != 0) {
2469: break;
2470: }
2471: mcb->mz = next_mcb->mz;
1.1.1.19 root 2472: mcb->paragraphs32 = mcb->paragraphs() + 1 + next_mcb->paragraphs();
1.1 root 2473: }
2474: }
2475:
1.1.1.8 root 2476: int msdos_mem_alloc(int mcb_seg, int paragraphs, int new_process)
1.1 root 2477: {
2478: while(1) {
2479: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2480:
1.1.1.14 root 2481: if(mcb->psp == 0) {
2482: msdos_mem_merge(mcb_seg + 1);
2483: } else {
2484: msdos_mcb_check(mcb);
2485: }
1.1.1.8 root 2486: if(!(new_process && mcb->mz != 'Z')) {
1.1.1.19 root 2487: if(mcb->psp == 0 && mcb->paragraphs() >= paragraphs) {
1.1 root 2488: msdos_mem_split(mcb_seg + 1, paragraphs);
2489: mcb->psp = current_psp;
2490: return(mcb_seg + 1);
2491: }
2492: }
2493: if(mcb->mz == 'Z') {
2494: break;
2495: }
1.1.1.19 root 2496: mcb_seg += 1 + mcb->paragraphs();
1.1 root 2497: }
2498: return(-1);
2499: }
2500:
2501: int msdos_mem_realloc(int seg, int paragraphs, int *max_paragraphs)
2502: {
2503: int mcb_seg = seg - 1;
2504: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2505: msdos_mcb_check(mcb);
1.1.1.19 root 2506: int current_paragraphs = mcb->paragraphs();
1.1 root 2507:
2508: msdos_mem_merge(seg);
1.1.1.19 root 2509: if(paragraphs > mcb->paragraphs()) {
1.1.1.14 root 2510: if(max_paragraphs) {
1.1.1.19 root 2511: *max_paragraphs = mcb->paragraphs();
1.1.1.14 root 2512: }
1.1 root 2513: msdos_mem_split(seg, current_paragraphs);
2514: return(-1);
2515: }
2516: msdos_mem_split(seg, paragraphs);
2517: return(0);
2518: }
2519:
2520: void msdos_mem_free(int seg)
2521: {
2522: int mcb_seg = seg - 1;
2523: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2524: msdos_mcb_check(mcb);
2525:
2526: mcb->psp = 0;
2527: msdos_mem_merge(seg);
2528: }
2529:
1.1.1.8 root 2530: int msdos_mem_get_free(int mcb_seg, int new_process)
1.1 root 2531: {
2532: int max_paragraphs = 0;
2533:
2534: while(1) {
2535: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2536: msdos_mcb_check(mcb);
2537:
1.1.1.8 root 2538: if(!(new_process && mcb->mz != 'Z')) {
1.1.1.19 root 2539: if(mcb->psp == 0 && mcb->paragraphs() > max_paragraphs) {
2540: max_paragraphs = mcb->paragraphs();
1.1 root 2541: }
2542: }
2543: if(mcb->mz == 'Z') {
2544: break;
2545: }
1.1.1.19 root 2546: mcb_seg += 1 + mcb->paragraphs();
1.1 root 2547: }
1.1.1.14 root 2548: return(max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs);
1.1 root 2549: }
2550:
1.1.1.8 root 2551: int msdos_mem_get_last_mcb(int mcb_seg, UINT16 psp)
2552: {
2553: int last_seg = -1;
2554:
2555: while(1) {
2556: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2557: msdos_mcb_check(mcb);
2558:
1.1.1.14 root 2559: if(mcb->psp == psp) {
1.1.1.8 root 2560: last_seg = mcb_seg;
2561: }
1.1.1.14 root 2562: if(mcb->mz == 'Z') {
2563: break;
2564: }
1.1.1.19 root 2565: mcb_seg += 1 + mcb->paragraphs();
1.1.1.8 root 2566: }
2567: return(last_seg);
2568: }
2569:
1.1.1.19 root 2570: int msdos_mem_get_umb_linked()
2571: {
2572: int mcb_seg = first_mcb;
2573:
2574: while(1) {
2575: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2576: msdos_mcb_check(mcb);
2577:
2578: if(mcb->mz == 'Z') {
2579: if(mcb_seg >= (UMB_TOP >> 4)) {
2580: return(-1);
2581: }
2582: break;
2583: }
2584: mcb_seg += 1 + mcb->paragraphs();
2585: }
2586: return(0);
2587: }
2588:
2589: int msdos_mem_link_umb()
2590: {
2591: int mcb_seg = first_mcb;
2592:
2593: while(1) {
2594: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2595: msdos_mcb_check(mcb);
2596: mcb_seg += 1 + mcb->paragraphs();
2597:
2598: if(mcb->mz == 'Z') {
2599: if(mcb_seg == (MEMORY_END >> 4) - 1) {
2600: mcb->mz = 'M';
1.1.1.20 root 2601: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked |= 0x01;
1.1.1.19 root 2602: return(-1);
2603: }
2604: break;
2605: }
2606: }
2607: return(0);
2608: }
2609:
2610: int msdos_mem_unlink_umb()
2611: {
2612: int mcb_seg = first_mcb;
2613:
2614: while(1) {
2615: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2616: msdos_mcb_check(mcb);
2617: mcb_seg += 1 + mcb->paragraphs();
2618:
2619: if(mcb->mz == 'Z') {
2620: break;
2621: } else {
2622: if(mcb_seg == (MEMORY_END >> 4) - 1) {
2623: mcb->mz = 'Z';
1.1.1.20 root 2624: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked &= ~0x01;
1.1.1.19 root 2625: return(-1);
2626: }
2627: }
2628: }
2629: return(0);
2630: }
2631:
1.1 root 2632: // environment
2633:
2634: void msdos_env_set_argv(int env_seg, char *argv)
2635: {
2636: char *dst = (char *)(mem + (env_seg << 4));
2637:
2638: while(1) {
2639: if(dst[0] == 0) {
2640: break;
2641: }
2642: dst += strlen(dst) + 1;
2643: }
2644: *dst++ = 0; // end of environment
2645: *dst++ = 1; // top of argv[0]
2646: *dst++ = 0;
2647: memcpy(dst, argv, strlen(argv));
2648: dst += strlen(argv);
2649: *dst++ = 0;
2650: *dst++ = 0;
2651: }
2652:
2653: char *msdos_env_get_argv(int env_seg)
2654: {
2655: static char env[ENV_SIZE];
2656: char *src = env;
2657:
2658: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
2659: while(1) {
2660: if(src[0] == 0) {
2661: if(src[1] == 1) {
2662: return(src + 3);
2663: }
2664: break;
2665: }
2666: src += strlen(src) + 1;
2667: }
2668: return(NULL);
2669: }
2670:
2671: char *msdos_env_get(int env_seg, const char *name)
2672: {
2673: static char env[ENV_SIZE];
2674: char *src = env;
2675:
2676: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
2677: while(1) {
2678: if(src[0] == 0) {
2679: break;
2680: }
2681: int len = strlen(src);
2682: char *n = my_strtok(src, "=");
2683: char *v = src + strlen(n) + 1;
2684:
2685: if(_stricmp(name, n) == 0) {
2686: return(v);
2687: }
2688: src += len + 1;
2689: }
2690: return(NULL);
2691: }
2692:
2693: void msdos_env_set(int env_seg, char *name, char *value)
2694: {
2695: char env[ENV_SIZE];
2696: char *src = env;
2697: char *dst = (char *)(mem + (env_seg << 4));
2698: char *argv = msdos_env_get_argv(env_seg);
2699: int done = 0;
2700:
2701: memcpy(src, dst, ENV_SIZE);
2702: memset(dst, 0, ENV_SIZE);
2703: while(1) {
2704: if(src[0] == 0) {
2705: break;
2706: }
2707: int len = strlen(src);
2708: char *n = my_strtok(src, "=");
2709: char *v = src + strlen(n) + 1;
2710: char tmp[1024];
2711:
2712: if(_stricmp(name, n) == 0) {
2713: sprintf(tmp, "%s=%s", n, value);
2714: done = 1;
2715: } else {
2716: sprintf(tmp, "%s=%s", n, v);
2717: }
2718: memcpy(dst, tmp, strlen(tmp));
2719: dst += strlen(tmp) + 1;
2720: src += len + 1;
2721: }
2722: if(!done) {
2723: char tmp[1024];
2724:
2725: sprintf(tmp, "%s=%s", name, value);
2726: memcpy(dst, tmp, strlen(tmp));
2727: dst += strlen(tmp) + 1;
2728: }
2729: if(argv) {
2730: *dst++ = 0; // end of environment
2731: *dst++ = 1; // top of argv[0]
2732: *dst++ = 0;
2733: memcpy(dst, argv, strlen(argv));
2734: dst += strlen(argv);
2735: *dst++ = 0;
2736: *dst++ = 0;
2737: }
2738: }
2739:
2740: // process
2741:
1.1.1.8 root 2742: psp_t *msdos_psp_create(int psp_seg, UINT16 mcb_seg, UINT16 parent_psp, UINT16 env_seg)
1.1 root 2743: {
2744: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
2745:
2746: memset(psp, 0, PSP_SIZE);
2747: psp->exit[0] = 0xcd;
2748: psp->exit[1] = 0x20;
1.1.1.8 root 2749: psp->first_mcb = mcb_seg;
1.1 root 2750: psp->far_call = 0xea;
2751: psp->cpm_entry.w.l = 0xfff1; // int 21h, retf
2752: psp->cpm_entry.w.h = 0xf000;
2753: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
2754: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
2755: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
2756: psp->parent_psp = parent_psp;
1.1.1.20 root 2757: if(parent_psp == (UINT16)-1) {
2758: for(int i = 0; i < 20; i++) {
2759: if(file_handler[i].valid) {
2760: psp->file_table[i] = i;
2761: } else {
2762: psp->file_table[i] = 0xff;
2763: }
1.1 root 2764: }
1.1.1.20 root 2765: } else {
2766: memcpy(psp->file_table, ((psp_t *)(mem + (parent_psp << 4)))->file_table, 20);
1.1 root 2767: }
2768: psp->env_seg = env_seg;
2769: psp->stack.w.l = REG16(SP);
1.1.1.3 root 2770: psp->stack.w.h = SREG(SS);
1.1.1.14 root 2771: psp->file_table_size = 20;
2772: psp->file_table_ptr.w.l = 0x18;
2773: psp->file_table_ptr.w.h = psp_seg;
1.1 root 2774: psp->service[0] = 0xcd;
2775: psp->service[1] = 0x21;
2776: psp->service[2] = 0xcb;
2777: return(psp);
2778: }
2779:
1.1.1.20 root 2780: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg)
2781: {
2782: if(psp_seg && fd < 20) {
2783: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
2784: psp->file_table[fd] = value;
2785: }
2786: }
2787:
2788: int msdos_psp_get_file_table(int fd, int psp_seg)
2789: {
2790: if(psp_seg && fd < 20) {
2791: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
2792: fd = psp->file_table[fd];
2793: }
2794: return fd;
2795: }
2796:
1.1 root 2797: int msdos_process_exec(char *cmd, param_block_t *param, UINT8 al)
2798: {
2799: // load command file
2800: int fd = -1;
2801: int dos_command = 0;
1.1.1.4 root 2802: char command[MAX_PATH], path[MAX_PATH], opt[MAX_PATH], *name, name_tmp[MAX_PATH];
1.1 root 2803:
2804: int opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
2805: int opt_len = mem[opt_ofs];
2806: memset(opt, 0, sizeof(opt));
2807: memcpy(opt, mem + opt_ofs + 1, opt_len);
2808:
1.1.1.14 root 2809: if(strlen(cmd) >= 5 && _stricmp(&cmd[strlen(cmd) - 4], ".BAT") == 0) {
2810: // this is a batch file, run command.com
2811: char tmp[MAX_PATH];
2812: if(opt_len != 0) {
2813: sprintf(tmp, "/C %s %s", cmd, opt);
2814: } else {
2815: sprintf(tmp, "/C %s", cmd);
2816: }
2817: strcpy(opt, tmp);
2818: opt_len = strlen(opt);
2819: mem[opt_ofs] = opt_len;
2820: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
2821: strcpy(command, comspec_path);
2822: strcpy(name_tmp, "COMMAND.COM");
2823: } else {
2824: if(_stricmp(cmd, "C:\\COMMAND.COM") == 0) {
2825: // redirect C:\COMMAND.COM to comspec_path
2826: strcpy(command, comspec_path);
2827: } else {
2828: strcpy(command, cmd);
2829: }
2830: GetFullPathName(command, MAX_PATH, path, &name);
2831: memset(name_tmp, 0, sizeof(name_tmp));
2832: strcpy(name_tmp, name);
2833:
2834: // check command.com
2835: if(_stricmp(name, "COMMAND.COM") == 0 || _stricmp(name, "COMMAND") == 0) {
2836: if(opt_len == 0) {
2837: // process_t *current_process = msdos_process_info_get(current_psp);
2838: process_t *current_process = NULL;
2839: for(int i = 0; i < MAX_PROCESS; i++) {
2840: if(process[i].psp == current_psp) {
2841: current_process = &process[i];
2842: break;
2843: }
2844: }
2845: if(current_process != NULL) {
2846: param->cmd_line.dw = current_process->dta.dw;
2847: opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
2848: opt_len = mem[opt_ofs];
2849: memset(opt, 0, sizeof(opt));
2850: memcpy(opt, mem + opt_ofs + 1, opt_len);
2851: }
2852: }
2853: for(int i = 0; i < opt_len; i++) {
2854: if(opt[i] == ' ') {
2855: continue;
2856: }
2857: if(opt[i] == '/' && (opt[i + 1] == 'c' || opt[i + 1] == 'C') && opt[i + 2] == ' ') {
2858: for(int j = i + 3; j < opt_len; j++) {
2859: if(opt[j] == ' ') {
2860: continue;
2861: }
2862: char *token = my_strtok(opt + j, " ");
2863:
2864: if(strlen(token) >= 5 && _stricmp(&token[strlen(token) - 4], ".BAT") == 0) {
2865: // this is a batch file, okay to run command.com
2866: } else {
2867: // run program directly without command.com
2868: strcpy(command, token);
2869: char tmp[MAX_PATH];
2870: strcpy(tmp, token + strlen(token) + 1);
2871: strcpy(opt, tmp);
2872: opt_len = strlen(opt);
2873: mem[opt_ofs] = opt_len;
2874: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
2875: dos_command = 1;
2876: }
2877: break;
1.1 root 2878: }
2879: }
1.1.1.14 root 2880: break;
1.1 root 2881: }
2882: }
2883: }
2884:
2885: // load command file
2886: strcpy(path, command);
2887: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
2888: sprintf(path, "%s.COM", command);
2889: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
2890: sprintf(path, "%s.EXE", command);
2891: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
1.1.1.14 root 2892: sprintf(path, "%s.BAT", command);
2893: if(_access(path, 0) == 0) {
2894: // this is a batch file, run command.com
2895: char tmp[MAX_PATH];
2896: if(opt_len != 0) {
2897: sprintf(tmp, "/C %s %s", path, opt);
2898: } else {
2899: sprintf(tmp, "/C %s", path);
2900: }
2901: strcpy(opt, tmp);
2902: opt_len = strlen(opt);
2903: mem[opt_ofs] = opt_len;
2904: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
2905: strcpy(path, comspec_path);
2906: strcpy(name_tmp, "COMMAND.COM");
2907: fd = _open(path, _O_RDONLY | _O_BINARY);
2908: } else {
2909: // search path in parent environments
2910: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
2911: char *env = msdos_env_get(parent_psp->env_seg, "PATH");
2912: if(env != NULL) {
2913: char env_path[4096];
2914: strcpy(env_path, env);
2915: char *token = my_strtok(env_path, ";");
2916:
2917: while(token != NULL) {
2918: if(strlen(token) != 0) {
2919: sprintf(path, "%s", msdos_combine_path(token, command));
2920: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
2921: break;
2922: }
2923: sprintf(path, "%s.COM", msdos_combine_path(token, command));
2924: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
2925: break;
2926: }
2927: sprintf(path, "%s.EXE", msdos_combine_path(token, command));
2928: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
2929: break;
2930: }
2931: sprintf(path, "%s.BAT", msdos_combine_path(token, command));
2932: if(_access(path, 0) == 0) {
2933: // this is a batch file, run command.com
2934: char tmp[MAX_PATH];
2935: if(opt_len != 0) {
2936: sprintf(tmp, "/C %s %s", path, opt);
2937: } else {
2938: sprintf(tmp, "/C %s", path);
2939: }
2940: strcpy(opt, tmp);
2941: opt_len = strlen(opt);
2942: mem[opt_ofs] = opt_len;
2943: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
2944: strcpy(path, comspec_path);
2945: strcpy(name_tmp, "COMMAND.COM");
2946: fd = _open(path, _O_RDONLY | _O_BINARY);
2947: break;
2948: }
1.1.1.8 root 2949: }
1.1.1.14 root 2950: token = my_strtok(NULL, ";");
1.1 root 2951: }
2952: }
2953: }
2954: }
2955: }
2956: }
2957: if(fd == -1) {
2958: if(dos_command) {
2959: // may be dos command
2960: char tmp[MAX_PATH];
2961: sprintf(tmp, "%s %s", command, opt);
2962: system(tmp);
2963: return(0);
2964: } else {
2965: return(-1);
2966: }
2967: }
2968: _read(fd, file_buffer, sizeof(file_buffer));
2969: _close(fd);
2970:
2971: // copy environment
2972: int env_seg, psp_seg;
2973:
1.1.1.8 root 2974: if((env_seg = msdos_mem_alloc(first_mcb, ENV_SIZE >> 4, 1)) == -1) {
1.1 root 2975: return(-1);
2976: }
2977: if(param->env_seg == 0) {
2978: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
2979: memcpy(mem + (env_seg << 4), mem + (parent_psp->env_seg << 4), ENV_SIZE);
2980: } else {
2981: memcpy(mem + (env_seg << 4), mem + (param->env_seg << 4), ENV_SIZE);
2982: }
2983: msdos_env_set_argv(env_seg, msdos_short_full_path(path));
2984:
2985: // check exe header
2986: exe_header_t *header = (exe_header_t *)file_buffer;
1.1.1.8 root 2987: int paragraphs, free_paragraphs = msdos_mem_get_free(first_mcb, 1);
1.1 root 2988: UINT16 cs, ss, ip, sp;
2989:
2990: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
2991: // memory allocation
2992: int header_size = header->header_size * 16;
2993: int load_size = header->pages * 512 - header_size;
2994: if(header_size + load_size < 512) {
2995: load_size = 512 - header_size;
2996: }
2997: paragraphs = (PSP_SIZE + load_size) >> 4;
2998: if(paragraphs + header->min_alloc > free_paragraphs) {
2999: msdos_mem_free(env_seg);
3000: return(-1);
3001: }
3002: paragraphs += header->max_alloc ? header->max_alloc : header->min_alloc;
3003: if(paragraphs > free_paragraphs) {
3004: paragraphs = free_paragraphs;
3005: }
1.1.1.8 root 3006: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1 root 3007: msdos_mem_free(env_seg);
3008: return(-1);
3009: }
3010: // relocation
3011: int start_seg = psp_seg + (PSP_SIZE >> 4);
3012: for(int i = 0; i < header->relocations; i++) {
3013: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
3014: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
3015: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
3016: }
3017: memcpy(mem + (start_seg << 4), file_buffer + header_size, load_size);
3018: // segments
3019: cs = header->init_cs + start_seg;
3020: ss = header->init_ss + start_seg;
3021: ip = header->init_ip;
3022: sp = header->init_sp - 2; // for symdeb
3023: } else {
3024: // memory allocation
3025: paragraphs = free_paragraphs;
1.1.1.8 root 3026: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1 root 3027: msdos_mem_free(env_seg);
3028: return(-1);
3029: }
3030: int start_seg = psp_seg + (PSP_SIZE >> 4);
3031: memcpy(mem + (start_seg << 4), file_buffer, 0x10000 - PSP_SIZE);
3032: // segments
3033: cs = ss = psp_seg;
3034: ip = 0x100;
3035: sp = 0xfffe;
3036: }
3037:
3038: // create psp
1.1.1.3 root 3039: #if defined(HAS_I386)
3040: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_eip;
3041: #else
3042: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_pc - SREG_BASE(CS);
3043: #endif
3044: *(UINT16 *)(mem + 4 * 0x22 + 2) = SREG(CS);
1.1 root 3045: psp_t *psp = msdos_psp_create(psp_seg, psp_seg + paragraphs, current_psp, env_seg);
3046: memcpy(psp->fcb1, mem + (param->fcb1.w.h << 4) + param->fcb1.w.l, sizeof(psp->fcb1));
3047: memcpy(psp->fcb2, mem + (param->fcb2.w.h << 4) + param->fcb2.w.l, sizeof(psp->fcb2));
3048: memcpy(psp->buffer, mem + (param->cmd_line.w.h << 4) + param->cmd_line.w.l, sizeof(psp->buffer));
3049:
3050: mcb_t *mcb_env = (mcb_t *)(mem + ((env_seg - 1) << 4));
3051: mcb_t *mcb_psp = (mcb_t *)(mem + ((psp_seg - 1) << 4));
3052: mcb_psp->psp = mcb_env->psp = psp_seg;
3053:
1.1.1.4 root 3054: for(int i = 0; i < 8; i++) {
3055: if(name_tmp[i] == '.') {
3056: mcb_psp->prog_name[i] = '\0';
3057: break;
3058: } else if(i < 7 && msdos_lead_byte_check(name_tmp[i])) {
3059: mcb_psp->prog_name[i] = name_tmp[i];
3060: i++;
3061: mcb_psp->prog_name[i] = name_tmp[i];
3062: } else if(name_tmp[i] >= 'a' && name_tmp[i] <= 'z') {
3063: mcb_psp->prog_name[i] = name_tmp[i] - 'a' + 'A';
3064: } else {
3065: mcb_psp->prog_name[i] = name_tmp[i];
3066: }
3067: }
3068:
1.1 root 3069: // process info
3070: process_t *process = msdos_process_info_create(psp_seg);
3071: strcpy(process->module_dir, msdos_short_full_dir(path));
3072: process->dta.w.l = 0x80;
3073: process->dta.w.h = psp_seg;
3074: process->switchar = '/';
3075: process->max_files = 20;
3076: process->parent_int_10h_feh_called = int_10h_feh_called;
3077: process->parent_int_10h_ffh_called = int_10h_ffh_called;
1.1.1.14 root 3078: process->parent_ds = SREG(DS);
1.1 root 3079:
3080: current_psp = psp_seg;
3081:
3082: if(al == 0x00) {
3083: int_10h_feh_called = int_10h_ffh_called = false;
3084:
3085: // registers and segments
3086: REG16(AX) = REG16(BX) = 0x00;
3087: REG16(CX) = 0xff;
3088: REG16(DX) = psp_seg;
3089: REG16(SI) = ip;
3090: REG16(DI) = sp;
3091: REG16(SP) = sp;
1.1.1.3 root 3092: SREG(DS) = SREG(ES) = psp_seg;
3093: SREG(SS) = ss;
3094: i386_load_segment_descriptor(DS);
3095: i386_load_segment_descriptor(ES);
3096: i386_load_segment_descriptor(SS);
1.1 root 3097:
3098: *(UINT16 *)(mem + (ss << 4) + sp) = 0;
3099: i386_jmp_far(cs, ip);
3100: } else if(al == 0x01) {
3101: // copy ss:sp and cs:ip to param block
3102: param->sp = sp;
3103: param->ss = ss;
3104: param->ip = ip;
3105: param->cs = cs;
3106: }
3107: return(0);
3108: }
3109:
3110: void msdos_process_terminate(int psp_seg, int ret, int mem_free)
3111: {
3112: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
3113:
3114: *(UINT32 *)(mem + 4 * 0x22) = psp->int_22h.dw;
3115: *(UINT32 *)(mem + 4 * 0x23) = psp->int_23h.dw;
3116: *(UINT32 *)(mem + 4 * 0x24) = psp->int_24h.dw;
3117:
1.1.1.3 root 3118: SREG(SS) = psp->stack.w.h;
3119: i386_load_segment_descriptor(SS);
1.1 root 3120: REG16(SP) = psp->stack.w.l;
3121: i386_jmp_far(psp->int_22h.w.h, psp->int_22h.w.l);
3122:
3123: process_t *process = msdos_process_info_get(psp_seg);
3124: int_10h_feh_called = process->parent_int_10h_feh_called;
3125: int_10h_ffh_called = process->parent_int_10h_ffh_called;
1.1.1.14 root 3126: SREG(DS) = process->parent_ds;
3127: i386_load_segment_descriptor(DS);
1.1 root 3128:
3129: if(mem_free) {
1.1.1.8 root 3130: int mcb_seg;
3131: while((mcb_seg = msdos_mem_get_last_mcb(first_mcb, psp_seg)) != -1) {
3132: msdos_mem_free(mcb_seg + 1);
3133: }
3134: while((mcb_seg = msdos_mem_get_last_mcb(UMB_TOP >> 4, psp_seg)) != -1) {
3135: msdos_mem_free(mcb_seg + 1);
3136: }
1.1 root 3137:
3138: for(int i = 0; i < MAX_FILES; i++) {
3139: if(file_handler[i].valid && file_handler[i].psp == psp_seg) {
3140: _close(i);
1.1.1.20 root 3141: msdos_file_handler_close(i);
3142: msdos_psp_set_file_table(i, 0x0ff, psp_seg); // FIXME: consider duplicated file handles
1.1 root 3143: }
3144: }
1.1.1.13 root 3145: msdos_dta_info_free(psp_seg);
1.1 root 3146: }
1.1.1.14 root 3147: msdos_stdio_reopen();
1.1 root 3148:
3149: memset(process, 0, sizeof(process_t));
3150:
3151: current_psp = psp->parent_psp;
3152: retval = ret;
3153: }
3154:
3155: // drive
3156:
3157: int msdos_drive_param_block_update(int drive_num, UINT16 *seg, UINT16 *ofs, int force_update)
3158: {
3159: *seg = DPB_TOP >> 4;
3160: *ofs = sizeof(dpb_t) * drive_num;
3161: dpb_t *dpb = (dpb_t *)(mem + (*seg << 4) + *ofs);
3162:
3163: if(!force_update && dpb->free_clusters != 0) {
3164: return(dpb->bytes_per_sector ? 1 : 0);
3165: }
3166: memset(dpb, 0, sizeof(dpb_t));
3167:
3168: int res = 0;
3169: char dev[64];
3170: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
3171:
1.1.1.17 root 3172: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1.1 root 3173: if(hFile != INVALID_HANDLE_VALUE) {
3174: DISK_GEOMETRY geo;
3175: DWORD dwSize;
3176: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
3177: dpb->bytes_per_sector = (UINT16)geo.BytesPerSector;
3178: dpb->highest_sector_num = (UINT8)(geo.SectorsPerTrack - 1);
3179: dpb->highest_cluster_num = (UINT16)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1.1.14 root 3180: dpb->maximum_cluster_num = (UINT32)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1 root 3181: switch(geo.MediaType) {
3182: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
3183: dpb->media_type = 0xff;
3184: break;
3185: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
3186: dpb->media_type = 0xfe;
3187: break;
3188: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
3189: dpb->media_type = 0xfd;
3190: break;
3191: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
3192: dpb->media_type = 0xfc;
3193: break;
3194: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
3195: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
3196: dpb->media_type = 0xf9;
3197: break;
3198: case FixedMedia: // hard disk
3199: case RemovableMedia:
1.1.1.19 root 3200: case Unknown:
1.1 root 3201: dpb->media_type = 0xf8;
3202: break;
3203: default:
3204: dpb->media_type = 0xf0;
3205: break;
3206: }
3207: res = 1;
3208: }
3209: dpb->drive_num = drive_num;
3210: dpb->unit_num = drive_num;
3211: dpb->next_dpb_ofs = *ofs + sizeof(dpb_t);
3212: dpb->next_dpb_seg = *seg;
1.1.1.14 root 3213: dpb->info_sector = 0xffff;
3214: dpb->backup_boot_sector = 0xffff;
1.1 root 3215: dpb->free_clusters = 0xffff;
1.1.1.14 root 3216: dpb->free_search_cluster = 0xffffffff;
1.1 root 3217: CloseHandle(hFile);
3218: }
3219: return(res);
3220: }
3221:
3222: // pc bios
3223:
1.1.1.19 root 3224: UINT32 get_ticks_since_midnight(UINT32 cur_msec)
3225: {
3226: static unsigned __int64 start_msec_since_midnight = 0;
3227: static unsigned __int64 start_msec_since_hostboot = 0;
3228:
3229: if(start_msec_since_midnight == 0) {
3230: SYSTEMTIME time;
3231: GetLocalTime(&time);
3232: start_msec_since_midnight = ((time.wHour * 60 + time.wMinute) * 60 + time.wSecond) * 1000 + time.wMilliseconds;
3233: start_msec_since_hostboot = cur_msec;
3234: }
3235: unsigned __int64 msec = (start_msec_since_midnight + cur_msec - start_msec_since_hostboot) % (24 * 60 * 60 * 1000);
3236: unsigned __int64 tick = msec * 0x1800b0 / (24 * 60 * 60 * 1000);
3237: return (UINT32)tick;
3238: }
3239:
3240: void pcbios_update_daily_timer_counter(UINT32 cur_msec)
3241: {
3242: UINT32 prev_tick = *(UINT32 *)(mem + 0x46c);
3243: UINT32 next_tick = get_ticks_since_midnight(cur_msec);
3244:
3245: if(prev_tick > next_tick) {
3246: mem[0x470] = 1;
3247: }
3248: *(UINT32 *)(mem + 0x46c) = next_tick;
3249: }
3250:
1.1.1.14 root 3251: inline void pcbios_irq0()
3252: {
3253: //++*(UINT32 *)(mem + 0x46c);
1.1.1.19 root 3254: pcbios_update_daily_timer_counter(timeGetTime());
1.1.1.14 root 3255: }
3256:
1.1.1.16 root 3257: int pcbios_get_text_vram_address(int page)
1.1 root 3258: {
3259: if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 3260: return TEXT_VRAM_TOP;
1.1 root 3261: } else {
1.1.1.14 root 3262: return TEXT_VRAM_TOP + VIDEO_REGEN * (page % vram_pages);
1.1 root 3263: }
3264: }
3265:
1.1.1.16 root 3266: int pcbios_get_shadow_buffer_address(int page)
1.1 root 3267: {
1.1.1.14 root 3268: if(!int_10h_feh_called) {
1.1.1.16 root 3269: return pcbios_get_text_vram_address(page);
1.1.1.14 root 3270: } else if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 3271: return SHADOW_BUF_TOP;
3272: } else {
1.1.1.14 root 3273: return SHADOW_BUF_TOP + VIDEO_REGEN * (page % vram_pages);
1.1.1.8 root 3274: }
3275: }
3276:
1.1.1.16 root 3277: int pcbios_get_shadow_buffer_address(int page, int x, int y)
1.1.1.8 root 3278: {
1.1.1.16 root 3279: return pcbios_get_shadow_buffer_address(page) + (x + y * scr_width) * 2;
1.1 root 3280: }
3281:
1.1.1.16 root 3282: void pcbios_set_console_size(int width, int height, bool clr_screen)
1.1 root 3283: {
1.1.1.14 root 3284: // clear the existing screen, not just the new one
3285: int clr_height = max(height, scr_height);
3286:
1.1.1.16 root 3287: if(scr_width != width || scr_height != height) {
3288: change_console_size(width, height);
1.1.1.14 root 3289: }
3290: mem[0x462] = 0;
3291: *(UINT16 *)(mem + 0x44e) = 0;
3292:
1.1.1.16 root 3293: text_vram_top_address = pcbios_get_text_vram_address(0);
3294: text_vram_end_address = text_vram_top_address + width * height * 2;
3295: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(0);
3296: shadow_buffer_end_address = shadow_buffer_top_address + width * height * 2;
1.1 root 3297:
1.1.1.16 root 3298: if(clr_screen) {
1.1.1.14 root 3299: for(int ofs = shadow_buffer_top_address; ofs < shadow_buffer_end_address;) {
3300: mem[ofs++] = 0x20;
3301: mem[ofs++] = 0x07;
3302: }
3303:
3304: EnterCriticalSection(&vram_crit_sect);
3305: for(int y = 0; y < clr_height; y++) {
3306: for(int x = 0; x < scr_width; x++) {
3307: SCR_BUF(y,x).Char.AsciiChar = ' ';
3308: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 3309: }
3310: }
3311: SMALL_RECT rect;
1.1.1.14 root 3312: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + clr_height - 1);
3313: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3314: vram_length_char = vram_last_length_char = 0;
3315: vram_length_attr = vram_last_length_attr = 0;
3316: LeaveCriticalSection(&vram_crit_sect);
1.1 root 3317: }
1.1.1.14 root 3318: COORD co;
3319: co.X = 0;
3320: co.Y = scr_top;
3321: SetConsoleCursorPosition(hStdout, co);
3322: cursor_moved = true;
3323: SetConsoleTextAttribute(hStdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
1.1 root 3324: }
3325:
1.1.1.16 root 3326: inline void pcbios_int_10h_00h()
3327: {
3328: switch(REG8(AL) & 0x7f) {
3329: case 0x70: // v-text mode
3330: case 0x71: // extended cga v-text mode
3331: pcbios_set_console_size(scr_width, scr_height, !(REG8(AL) & 0x80));
3332: break;
3333: default:
3334: pcbios_set_console_size(80, 25, !(REG8(AL) & 0x80));
3335: break;
3336: }
3337: if(REG8(AL) & 0x80) {
3338: mem[0x487] |= 0x80;
3339: } else {
3340: mem[0x487] &= ~0x80;
3341: }
3342: mem[0x449] = REG8(AL) & 0x7f;
3343: }
3344:
1.1 root 3345: inline void pcbios_int_10h_01h()
3346: {
1.1.1.13 root 3347: mem[0x460] = REG8(CL);
3348: mem[0x461] = REG8(CH);
1.1.1.14 root 3349:
3350: CONSOLE_CURSOR_INFO ci;
3351: GetConsoleCursorInfo(hStdout, &ci);
3352: // ci.bVisible = !(REG8(CH) & 0x60) && REG8(CH) <= REG8(CL);
3353: // if(ci.bVisible) {
3354: int lines = max(8, REG8(CL) + 1);
3355: ci.dwSize = (REG8(CL) - REG8(CH) + 1) * 100 / lines;
3356: // }
3357: SetConsoleCursorInfo(hStdout, &ci);
1.1 root 3358: }
3359:
3360: inline void pcbios_int_10h_02h()
3361: {
1.1.1.14 root 3362: // continuously setting the cursor effectively stops it blinking
3363: if(mem[0x462] == REG8(BH) && (REG8(DL) != mem[0x450 + REG8(BH) * 2] || REG8(DH) != mem[0x451 + REG8(BH) * 2])) {
1.1 root 3364: COORD co;
3365: co.X = REG8(DL);
1.1.1.14 root 3366: co.Y = REG8(DH) + scr_top;
3367:
3368: // some programs hide the cursor by moving it off screen
3369: static bool hidden = false;
3370: CONSOLE_CURSOR_INFO ci;
3371: GetConsoleCursorInfo(hStdout, &ci);
3372:
3373: if(REG8(DH) >= scr_height || !SetConsoleCursorPosition(hStdout, co)) {
3374: if(ci.bVisible) {
3375: ci.bVisible = FALSE;
3376: // SetConsoleCursorInfo(hStdout, &ci);
3377: hidden = true;
3378: }
3379: } else if(hidden) {
3380: if(!ci.bVisible) {
3381: ci.bVisible = TRUE;
3382: // SetConsoleCursorInfo(hStdout, &ci);
3383: }
3384: hidden = false;
3385: }
1.1 root 3386: }
1.1.1.14 root 3387: mem[0x450 + (REG8(BH) % vram_pages) * 2] = REG8(DL);
3388: mem[0x451 + (REG8(BH) % vram_pages) * 2] = REG8(DH);
1.1 root 3389: }
3390:
3391: inline void pcbios_int_10h_03h()
3392: {
1.1.1.14 root 3393: REG8(DL) = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3394: REG8(DH) = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 3395: REG8(CL) = mem[0x460];
3396: REG8(CH) = mem[0x461];
3397: }
3398:
3399: inline void pcbios_int_10h_05h()
3400: {
1.1.1.14 root 3401: if(REG8(AL) >= vram_pages) {
3402: return;
3403: }
3404: if(mem[0x462] != REG8(AL)) {
3405: vram_flush();
3406:
1.1 root 3407: SMALL_RECT rect;
1.1.1.14 root 3408: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
3409: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3410:
1.1.1.16 root 3411: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(mem[0x462]); y < scr_height; y++) {
1.1.1.14 root 3412: for(int x = 0; x < scr_width; x++) {
3413: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
3414: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 3415: }
3416: }
1.1.1.16 root 3417: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(REG8(AL)); y < scr_height; y++) {
1.1.1.14 root 3418: for(int x = 0; x < scr_width; x++) {
3419: SCR_BUF(y,x).Char.AsciiChar = mem[ofs++];
3420: SCR_BUF(y,x).Attributes = mem[ofs++];
1.1 root 3421: }
3422: }
1.1.1.14 root 3423: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3424:
3425: COORD co;
1.1.1.14 root 3426: co.X = mem[0x450 + REG8(AL) * 2];
3427: co.Y = mem[0x451 + REG8(AL) * 2] + scr_top;
3428: if(co.Y < scr_top + scr_height) {
3429: SetConsoleCursorPosition(hStdout, co);
3430: }
1.1 root 3431: }
1.1.1.14 root 3432: mem[0x462] = REG8(AL);
3433: *(UINT16 *)(mem + 0x44e) = REG8(AL) * VIDEO_REGEN;
3434: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.16 root 3435: text_vram_top_address = pcbios_get_text_vram_address(mem[0x462]);
1.1.1.14 root 3436: text_vram_end_address = text_vram_top_address + regen;
1.1.1.16 root 3437: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(mem[0x462]);
1.1.1.14 root 3438: shadow_buffer_end_address = shadow_buffer_top_address + regen;
1.1 root 3439: }
3440:
3441: inline void pcbios_int_10h_06h()
3442: {
1.1.1.14 root 3443: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
3444: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
3445: return;
3446: }
3447: vram_flush();
3448:
1.1 root 3449: SMALL_RECT rect;
1.1.1.14 root 3450: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
3451: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3452:
3453: int right = min(REG8(DL), scr_width - 1);
3454: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 3455:
3456: if(REG8(AL) == 0) {
1.1.1.14 root 3457: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 3458: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 3459: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
3460: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3461: }
3462: }
3463: } else {
1.1.1.14 root 3464: for(int y = REG8(CH), y2 = min(REG8(CH) + REG8(AL), bottom + 1); y <= bottom; y++, y2++) {
1.1.1.16 root 3465: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 3466: if(y2 <= bottom) {
3467: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 3468: } else {
1.1.1.14 root 3469: SCR_BUF(y,x).Char.AsciiChar = ' ';
3470: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3471: }
1.1.1.14 root 3472: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
3473: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 3474: }
3475: }
3476: }
1.1.1.14 root 3477: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3478: }
3479:
3480: inline void pcbios_int_10h_07h()
3481: {
1.1.1.14 root 3482: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
3483: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
3484: return;
3485: }
3486: vram_flush();
3487:
1.1 root 3488: SMALL_RECT rect;
1.1.1.14 root 3489: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
3490: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3491:
3492: int right = min(REG8(DL), scr_width - 1);
3493: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 3494:
3495: if(REG8(AL) == 0) {
1.1.1.14 root 3496: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 3497: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 3498: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
3499: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3500: }
3501: }
3502: } else {
1.1.1.14 root 3503: for(int y = bottom, y2 = max(REG8(CH) - 1, bottom - REG8(AL)); y >= REG8(CH); y--, y2--) {
1.1.1.16 root 3504: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 3505: if(y2 >= REG8(CH)) {
3506: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 3507: } else {
1.1.1.14 root 3508: SCR_BUF(y,x).Char.AsciiChar = ' ';
3509: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3510: }
1.1.1.14 root 3511: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
3512: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 3513: }
3514: }
3515: }
1.1.1.14 root 3516: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3517: }
3518:
3519: inline void pcbios_int_10h_08h()
3520: {
3521: COORD co;
3522: DWORD num;
3523:
1.1.1.14 root 3524: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3525: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 3526:
3527: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 3528: co.Y += scr_top;
3529: vram_flush();
1.1 root 3530: ReadConsoleOutputCharacter(hStdout, scr_char, 1, co, &num);
3531: ReadConsoleOutputAttribute(hStdout, scr_attr, 1, co, &num);
3532: REG8(AL) = scr_char[0];
3533: REG8(AH) = scr_attr[0];
3534: } else {
1.1.1.16 root 3535: REG16(AX) = *(UINT16 *)(mem + pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y));
1.1 root 3536: }
3537: }
3538:
3539: inline void pcbios_int_10h_09h()
3540: {
3541: COORD co;
3542:
1.1.1.14 root 3543: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3544: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
3545:
1.1.1.16 root 3546: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
3547: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 3548:
3549: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 3550: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 3551: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 3552: while(dest < end) {
3553: write_text_vram_char(dest - vram, REG8(AL));
3554: mem[dest++] = REG8(AL);
3555: write_text_vram_attr(dest - vram, REG8(BL));
3556: mem[dest++] = REG8(BL);
1.1 root 3557: }
1.1.1.14 root 3558: LeaveCriticalSection(&vram_crit_sect);
1.1 root 3559: } else {
1.1.1.14 root 3560: while(dest < end) {
1.1 root 3561: mem[dest++] = REG8(AL);
3562: mem[dest++] = REG8(BL);
3563: }
3564: }
3565: }
3566:
3567: inline void pcbios_int_10h_0ah()
3568: {
3569: COORD co;
3570:
1.1.1.14 root 3571: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3572: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
3573:
1.1.1.16 root 3574: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
3575: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 3576:
3577: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 3578: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 3579: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 3580: while(dest < end) {
3581: write_text_vram_char(dest - vram, REG8(AL));
3582: mem[dest++] = REG8(AL);
3583: dest++;
1.1 root 3584: }
1.1.1.14 root 3585: LeaveCriticalSection(&vram_crit_sect);
1.1 root 3586: } else {
1.1.1.14 root 3587: while(dest < end) {
1.1 root 3588: mem[dest++] = REG8(AL);
3589: dest++;
3590: }
3591: }
3592: }
3593:
3594: inline void pcbios_int_10h_0eh()
3595: {
1.1.1.14 root 3596: DWORD num;
3597: COORD co;
3598:
3599: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3600: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
3601:
3602: if(REG8(AL) == 7) {
3603: //MessageBeep(-1);
3604: } else if(REG8(AL) == 8 || REG8(AL) == 10 || REG8(AL) == 13) {
3605: if(REG8(AL) == 10) {
3606: vram_flush();
3607: }
3608: WriteConsole(hStdout, ®8(AL), 1, &num, NULL);
3609: cursor_moved = true;
3610: } else {
1.1.1.16 root 3611: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
1.1.1.14 root 3612: if(mem[0x462] == REG8(BH)) {
3613: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 3614: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 3615: write_text_vram_char(dest - vram, REG8(AL));
3616: LeaveCriticalSection(&vram_crit_sect);
3617:
3618: if(++co.X == scr_width) {
3619: co.X = 0;
3620: if(++co.Y == scr_height) {
3621: vram_flush();
3622: WriteConsole(hStdout, "\n", 1, &num, NULL);
3623: cursor_moved = true;
3624: }
3625: }
3626: if(!cursor_moved) {
3627: co.Y += scr_top;
3628: SetConsoleCursorPosition(hStdout, co);
3629: cursor_moved = true;
3630: }
3631: }
3632: mem[dest] = REG8(AL);
3633: }
1.1 root 3634: }
3635:
3636: inline void pcbios_int_10h_0fh()
3637: {
3638: REG8(AL) = mem[0x449];
3639: REG8(AH) = mem[0x44a];
3640: REG8(BH) = mem[0x462];
3641: }
3642:
1.1.1.14 root 3643: inline void pcbios_int_10h_11h()
3644: {
3645: switch(REG8(AL)) {
1.1.1.16 root 3646: case 0x01:
1.1.1.14 root 3647: case 0x11:
1.1.1.16 root 3648: pcbios_set_console_size(80, 28, true);
1.1.1.14 root 3649: break;
1.1.1.16 root 3650: case 0x02:
1.1.1.14 root 3651: case 0x12:
1.1.1.16 root 3652: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 3653: break;
1.1.1.16 root 3654: case 0x04:
1.1.1.14 root 3655: case 0x14:
1.1.1.16 root 3656: pcbios_set_console_size(80, 25, true);
3657: break;
3658: case 0x18:
3659: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 3660: break;
3661: case 0x30:
3662: SREG(ES) = 0;
3663: i386_load_segment_descriptor(ES);
3664: REG16(BP) = 0;
3665: REG16(CX) = mem[0x485];
3666: REG8(DL) = mem[0x484];
3667: break;
3668: }
3669: }
3670:
3671: inline void pcbios_int_10h_12h()
3672: {
1.1.1.16 root 3673: switch(REG8(BL)) {
3674: case 0x10:
1.1.1.14 root 3675: REG16(BX) = 0x0003;
3676: REG16(CX) = 0x0009;
1.1.1.16 root 3677: break;
1.1.1.14 root 3678: }
3679: }
3680:
1.1 root 3681: inline void pcbios_int_10h_13h()
3682: {
1.1.1.3 root 3683: int ofs = SREG_BASE(ES) + REG16(BP);
1.1 root 3684: COORD co;
3685: DWORD num;
3686:
3687: co.X = REG8(DL);
1.1.1.14 root 3688: co.Y = REG8(DH) + scr_top;
3689:
3690: vram_flush();
1.1 root 3691:
3692: switch(REG8(AL)) {
3693: case 0x00:
3694: case 0x01:
3695: if(mem[0x462] == REG8(BH)) {
3696: CONSOLE_SCREEN_BUFFER_INFO csbi;
3697: GetConsoleScreenBufferInfo(hStdout, &csbi);
3698: SetConsoleCursorPosition(hStdout, co);
3699:
3700: if(csbi.wAttributes != REG8(BL)) {
3701: SetConsoleTextAttribute(hStdout, REG8(BL));
3702: }
1.1.1.14 root 3703: WriteConsole(hStdout, &mem[ofs], REG16(CX), &num, NULL);
3704:
1.1 root 3705: if(csbi.wAttributes != REG8(BL)) {
3706: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
3707: }
3708: if(REG8(AL) == 0x00) {
1.1.1.15 root 3709: if(!restore_console_on_exit) {
3710: GetConsoleScreenBufferInfo(hStdout, &csbi);
3711: scr_top = csbi.srWindow.Top;
3712: }
1.1.1.14 root 3713: co.X = mem[0x450 + REG8(BH) * 2];
3714: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 3715: SetConsoleCursorPosition(hStdout, co);
3716: } else {
3717: cursor_moved = true;
3718: }
3719: } else {
1.1.1.3 root 3720: m_CF = 1;
1.1 root 3721: }
3722: break;
3723: case 0x02:
3724: case 0x03:
3725: if(mem[0x462] == REG8(BH)) {
3726: CONSOLE_SCREEN_BUFFER_INFO csbi;
3727: GetConsoleScreenBufferInfo(hStdout, &csbi);
3728: SetConsoleCursorPosition(hStdout, co);
3729:
3730: WORD wAttributes = csbi.wAttributes;
3731: for(int i = 0; i < REG16(CX); i++, ofs += 2) {
3732: if(wAttributes != mem[ofs + 1]) {
3733: SetConsoleTextAttribute(hStdout, mem[ofs + 1]);
3734: wAttributes = mem[ofs + 1];
3735: }
1.1.1.14 root 3736: WriteConsole(hStdout, &mem[ofs], 1, &num, NULL);
1.1 root 3737: }
3738: if(csbi.wAttributes != wAttributes) {
3739: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
3740: }
3741: if(REG8(AL) == 0x02) {
1.1.1.14 root 3742: co.X = mem[0x450 + REG8(BH) * 2];
3743: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 3744: SetConsoleCursorPosition(hStdout, co);
3745: } else {
3746: cursor_moved = true;
3747: }
3748: } else {
1.1.1.3 root 3749: m_CF = 1;
1.1 root 3750: }
3751: break;
3752: case 0x10:
3753: case 0x11:
3754: if(mem[0x462] == REG8(BH)) {
3755: ReadConsoleOutputCharacter(hStdout, scr_char, REG16(CX), co, &num);
3756: ReadConsoleOutputAttribute(hStdout, scr_attr, REG16(CX), co, &num);
3757: for(int i = 0; i < num; i++) {
3758: mem[ofs++] = scr_char[i];
3759: mem[ofs++] = scr_attr[i];
3760: if(REG8(AL) == 0x11) {
3761: mem[ofs++] = 0;
3762: mem[ofs++] = 0;
3763: }
3764: }
3765: } else {
1.1.1.16 root 3766: 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 3767: mem[ofs++] = mem[src++];
3768: mem[ofs++] = mem[src++];
3769: if(REG8(AL) == 0x11) {
3770: mem[ofs++] = 0;
3771: mem[ofs++] = 0;
3772: }
1.1.1.14 root 3773: if(++co.X == scr_width) {
3774: if(++co.Y == scr_height) {
1.1 root 3775: break;
3776: }
3777: co.X = 0;
3778: }
3779: }
3780: }
3781: break;
3782: case 0x20:
3783: case 0x21:
3784: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 3785: int len = min(REG16(CX), scr_width * scr_height);
3786: for(int i = 0; i < len; i++) {
1.1 root 3787: scr_char[i] = mem[ofs++];
3788: scr_attr[i] = mem[ofs++];
3789: if(REG8(AL) == 0x21) {
3790: ofs += 2;
3791: }
3792: }
1.1.1.14 root 3793: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
3794: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 3795: } else {
1.1.1.16 root 3796: 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 3797: mem[dest++] = mem[ofs++];
3798: mem[dest++] = mem[ofs++];
3799: if(REG8(AL) == 0x21) {
3800: ofs += 2;
3801: }
1.1.1.14 root 3802: if(++co.X == scr_width) {
3803: if(++co.Y == scr_height) {
1.1 root 3804: break;
3805: }
3806: co.X = 0;
3807: }
3808: }
3809: }
3810: break;
3811: default:
1.1.1.3 root 3812: m_CF = 1;
1.1 root 3813: break;
3814: }
3815: }
3816:
1.1.1.14 root 3817: inline void pcbios_int_10h_1ah()
3818: {
3819: switch(REG8(AL)) {
3820: case 0x00:
3821: REG8(AL) = 0x1a;
3822: REG8(BL) = 0x08;
3823: REG8(BH) = 0x00;
3824: break;
3825: default:
3826: m_CF = 1;
3827: break;
3828: }
3829: }
3830:
1.1 root 3831: inline void pcbios_int_10h_1dh()
3832: {
3833: switch(REG8(AL)) {
3834: case 0x01:
3835: break;
3836: case 0x02:
3837: REG16(BX) = 0;
3838: break;
3839: default:
1.1.1.3 root 3840: m_CF = 1;
1.1 root 3841: break;
3842: }
3843: }
3844:
3845: inline void pcbios_int_10h_82h()
3846: {
3847: static UINT8 mode = 0;
3848:
3849: switch(REG8(AL)) {
3850: case 0:
3851: if(REG8(BL) != 0xff) {
3852: mode = REG8(BL);
3853: }
3854: REG8(AL) = mode;
3855: break;
3856: default:
1.1.1.3 root 3857: m_CF = 1;
1.1 root 3858: break;
3859: }
3860: }
3861:
3862: inline void pcbios_int_10h_feh()
3863: {
3864: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 3865: SREG(ES) = (SHADOW_BUF_TOP >> 4);
1.1.1.3 root 3866: i386_load_segment_descriptor(ES);
1.1.1.8 root 3867: REG16(DI) = (SHADOW_BUF_TOP & 0x0f);
1.1 root 3868: }
3869: int_10h_feh_called = true;
3870: }
3871:
3872: inline void pcbios_int_10h_ffh()
3873: {
3874: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
3875: COORD co;
3876: DWORD num;
3877:
1.1.1.14 root 3878: vram_flush();
3879:
3880: co.X = (REG16(DI) >> 1) % scr_width;
3881: co.Y = (REG16(DI) >> 1) / scr_width;
1.1.1.16 root 3882: int ofs = pcbios_get_shadow_buffer_address(0, co.X, co.Y);
3883: int end = min(ofs + REG16(CX) * 2, pcbios_get_shadow_buffer_address(0, 0, scr_height));
1.1.1.14 root 3884: int len;
3885: for(len = 0; ofs < end; len++) {
3886: scr_char[len] = mem[ofs++];
3887: scr_attr[len] = mem[ofs++];
3888: }
3889: co.Y += scr_top;
3890: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
3891: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 3892: }
3893: int_10h_ffh_called = true;
3894: }
3895:
1.1.1.14 root 3896: inline void pcbios_int_15h_10h()
3897: {
3898: if(REG8(AL) == 0) {
3899: Sleep(10);
3900: hardware_update();
3901: } else {
3902: REG8(AH) = 0x86;
3903: m_CF = 1;
3904: }
3905: }
3906:
1.1 root 3907: inline void pcbios_int_15h_23h()
3908: {
3909: switch(REG8(AL)) {
3910: case 0:
1.1.1.8 root 3911: REG8(CL) = cmos_read(0x2d);
3912: REG8(CH) = cmos_read(0x2e);
1.1 root 3913: break;
3914: case 1:
1.1.1.8 root 3915: cmos_write(0x2d, REG8(CL));
3916: cmos_write(0x2e, REG8(CH));
1.1 root 3917: break;
3918: default:
3919: REG8(AH) = 0x86;
1.1.1.3 root 3920: m_CF = 1;
1.1 root 3921: break;
3922: }
3923: }
3924:
3925: inline void pcbios_int_15h_24h()
3926: {
3927: switch(REG8(AL)) {
3928: case 0:
1.1.1.3 root 3929: i386_set_a20_line(0);
1.1 root 3930: REG8(AH) = 0;
3931: break;
3932: case 1:
1.1.1.3 root 3933: i386_set_a20_line(1);
1.1 root 3934: REG8(AH) = 0;
3935: break;
3936: case 2:
3937: REG8(AH) = 0;
1.1.1.3 root 3938: REG8(AL) = (m_a20_mask >> 20) & 1;
1.1 root 3939: REG16(CX) = 0;
3940: break;
3941: case 3:
3942: REG16(AX) = 0;
3943: REG16(BX) = 0;
3944: break;
3945: }
3946: }
3947:
3948: inline void pcbios_int_15h_49h()
3949: {
1.1.1.14 root 3950: REG8(AH) = 0;
3951: REG8(BL) = 0; // DOS/V
1.1 root 3952: }
3953:
3954: inline void pcbios_int_15h_86h()
3955: {
3956: UINT32 usec = (REG16(CX) << 16) | REG16(DX);
1.1.1.14 root 3957: UINT32 msec = usec / 1000;
3958:
3959: while(msec) {
3960: UINT32 tmp = min(msec, 100);
3961: if(msec - tmp < 10) {
3962: tmp = msec;
3963: }
3964: Sleep(tmp);
3965:
3966: if(m_halted) {
3967: return;
3968: }
3969: msec -= tmp;
3970: }
1.1 root 3971: }
3972:
3973: inline void pcbios_int_15h_87h()
3974: {
3975: // copy extended memory (from DOSBox)
3976: int len = REG16(CX) * 2;
1.1.1.3 root 3977: int ofs = SREG_BASE(ES) + REG16(SI);
1.1 root 3978: int src = (*(UINT32 *)(mem + ofs + 0x12) & 0xffffff); // + (mem[ofs + 0x16] << 24);
3979: int dst = (*(UINT32 *)(mem + ofs + 0x1a) & 0xffffff); // + (mem[ofs + 0x1e] << 24);
3980: memcpy(mem + dst, mem + src, len);
3981: REG16(AX) = 0x00;
3982: }
3983:
3984: inline void pcbios_int_15h_88h()
3985: {
1.1.1.17 root 3986: REG16(AX) = ((min(MAX_MEM, 0x4000000) - 0x100000) >> 10);
1.1 root 3987: }
3988:
3989: inline void pcbios_int_15h_89h()
3990: {
1.1.1.21! root 3991: #if defined(HAS_I286) || defined(HAS_I386)
1.1 root 3992: // switch to protected mode (from DOSBox)
3993: write_io_byte(0x20, 0x10);
3994: write_io_byte(0x21, REG8(BH));
3995: write_io_byte(0x21, 0x00);
3996: write_io_byte(0xa0, 0x10);
3997: write_io_byte(0xa1, REG8(BL));
3998: write_io_byte(0xa1, 0x00);
1.1.1.3 root 3999: i386_set_a20_line(1);
4000: int ofs = SREG_BASE(ES) + REG16(SI);
4001: m_gdtr.limit = *(UINT16 *)(mem + ofs + 0x08);
4002: m_gdtr.base = *(UINT32 *)(mem + ofs + 0x08 + 0x02) & 0xffffff;
4003: m_idtr.limit = *(UINT16 *)(mem + ofs + 0x10);
4004: m_idtr.base = *(UINT32 *)(mem + ofs + 0x10 + 0x02) & 0xffffff;
4005: #if defined(HAS_I386)
4006: m_cr[0] |= 1;
4007: #else
4008: m_msw |= 1;
4009: #endif
4010: SREG(DS) = 0x18;
4011: SREG(ES) = 0x20;
4012: SREG(SS) = 0x28;
4013: i386_load_segment_descriptor(DS);
4014: i386_load_segment_descriptor(ES);
4015: i386_load_segment_descriptor(SS);
1.1.1.21! root 4016: UINT16 offset = *(UINT16 *)(mem + SREG_BASE(SS) + REG16(SP));
1.1 root 4017: REG16(SP) += 6;
1.1.1.3 root 4018: #if defined(HAS_I386)
1.1.1.21! root 4019: UINT32 flags = get_flags();
! 4020: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
! 4021: set_flags(flags);
1.1.1.3 root 4022: #else
1.1.1.21! root 4023: UINT32 flags = CompressFlags();
! 4024: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
! 4025: ExpandFlags(flags);
1.1.1.3 root 4026: #endif
1.1 root 4027: REG16(AX) = 0x00;
1.1.1.21! root 4028: i386_jmp_far(0x30, /*REG16(CX)*/offset);
1.1 root 4029: #else
1.1.1.21! root 4030: // i86/i186/v30: protected mode is not supported
1.1 root 4031: REG8(AH) = 0x86;
1.1.1.3 root 4032: m_CF = 1;
1.1 root 4033: #endif
4034: }
4035:
1.1.1.21! root 4036: inline void pcbios_int_15h_8ah()
! 4037: {
! 4038: UINT32 size = MAX_MEM - 0x100000;
! 4039: REG16(AX) = size & 0xffff;
! 4040: REG16(DX) = size >> 16;
! 4041: }
! 4042:
1.1.1.3 root 4043: #if defined(HAS_I386)
1.1 root 4044: inline void pcbios_int_15h_c9h()
4045: {
4046: REG8(AH) = 0x00;
4047: REG8(CH) = cpu_type;
4048: REG8(CL) = cpu_step;
4049: }
1.1.1.3 root 4050: #endif
1.1 root 4051:
4052: inline void pcbios_int_15h_cah()
4053: {
4054: switch(REG8(AL)) {
4055: case 0:
4056: if(REG8(BL) > 0x3f) {
4057: REG8(AH) = 0x03;
1.1.1.3 root 4058: m_CF = 1;
1.1 root 4059: } else if(REG8(BL) < 0x0e) {
4060: REG8(AH) = 0x04;
1.1.1.3 root 4061: m_CF = 1;
1.1 root 4062: } else {
1.1.1.8 root 4063: REG8(CL) = cmos_read(REG8(BL));
1.1 root 4064: }
4065: break;
4066: case 1:
4067: if(REG8(BL) > 0x3f) {
4068: REG8(AH) = 0x03;
1.1.1.3 root 4069: m_CF = 1;
1.1 root 4070: } else if(REG8(BL) < 0x0e) {
4071: REG8(AH) = 0x04;
1.1.1.3 root 4072: m_CF = 1;
1.1 root 4073: } else {
1.1.1.8 root 4074: cmos_write(REG8(BL), REG8(CL));
1.1 root 4075: }
4076: break;
4077: default:
4078: REG8(AH) = 0x86;
1.1.1.3 root 4079: m_CF = 1;
1.1 root 4080: break;
4081: }
4082: }
4083:
1.1.1.17 root 4084: #if defined(HAS_I386)
4085: inline void pcbios_int_15h_e801h()
4086: {
4087: REG16(AX) = REG16(CX) = ((min(MAX_MEM, 0x1000000) - 0x100000) >> 10);
4088: REG16(BX) = REG16(DX) = ((max(MAX_MEM, 0x1000000) - 0x1000000) >> 16);
4089: }
4090: #endif
4091:
1.1.1.16 root 4092: UINT32 pcbios_get_key_code(bool clear_buffer)
1.1 root 4093: {
4094: UINT32 code = 0;
4095:
4096: if(key_buf_char->count() == 0) {
1.1.1.14 root 4097: if(!update_key_buffer()) {
4098: if(clear_buffer) {
4099: Sleep(10);
4100: } else {
4101: maybe_idle();
4102: }
4103: }
1.1 root 4104: }
4105: if(!clear_buffer) {
4106: key_buf_char->store_buffer();
4107: key_buf_scan->store_buffer();
4108: }
4109: if(key_buf_char->count() != 0) {
4110: code = key_buf_char->read() | (key_buf_scan->read() << 8);
4111: }
4112: if(key_buf_char->count() != 0) {
4113: code |= (key_buf_char->read() << 16) | (key_buf_scan->read() << 24);
4114: }
4115: if(!clear_buffer) {
4116: key_buf_char->restore_buffer();
4117: key_buf_scan->restore_buffer();
4118: }
4119: return code;
4120: }
4121:
4122: inline void pcbios_int_16h_00h()
4123: {
1.1.1.14 root 4124: while(key_code == 0 && !m_halted) {
1.1.1.16 root 4125: key_code = pcbios_get_key_code(true);
1.1 root 4126: }
4127: if((key_code & 0xffff) == 0x0000 || (key_code & 0xffff) == 0xe000) {
4128: if(REG8(AH) == 0x10) {
4129: key_code = ((key_code >> 8) & 0xff) | ((key_code >> 16) & 0xff00);
4130: } else {
4131: key_code = ((key_code >> 16) & 0xff00);
4132: }
4133: }
4134: REG16(AX) = key_code & 0xffff;
4135: key_code >>= 16;
4136: }
4137:
4138: inline void pcbios_int_16h_01h()
4139: {
1.1.1.5 root 4140: UINT32 key_code_tmp = key_code;
1.1 root 4141:
1.1.1.5 root 4142: if(key_code_tmp == 0) {
1.1.1.16 root 4143: key_code_tmp = pcbios_get_key_code(false);
1.1.1.5 root 4144: }
1.1.1.14 root 4145: if((key_code_tmp & 0xffff) == 0x0000 || (key_code_tmp & 0xffff) == 0xe000) {
4146: if(REG8(AH) == 0x11) {
4147: key_code_tmp = ((key_code_tmp >> 8) & 0xff) | ((key_code_tmp >> 16) & 0xff00);
4148: } else {
4149: key_code_tmp = ((key_code_tmp >> 16) & 0xff00);
1.1 root 4150: }
4151: }
1.1.1.5 root 4152: if(key_code_tmp != 0) {
4153: REG16(AX) = key_code_tmp & 0xffff;
1.1 root 4154: }
1.1.1.3 root 4155: #if defined(HAS_I386)
1.1.1.5 root 4156: m_ZF = (key_code_tmp == 0);
1.1.1.3 root 4157: #else
1.1.1.5 root 4158: m_ZeroVal = (key_code_tmp != 0);
1.1.1.3 root 4159: #endif
1.1 root 4160: }
4161:
4162: inline void pcbios_int_16h_02h()
4163: {
4164: REG8(AL) = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
4165: REG8(AL) |= (GetAsyncKeyState(VK_CAPITAL) & 0x0001) ? 0x40 : 0;
4166: REG8(AL) |= (GetAsyncKeyState(VK_NUMLOCK) & 0x0001) ? 0x20 : 0;
4167: REG8(AL) |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
4168: REG8(AL) |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
4169: REG8(AL) |= (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? 0x04 : 0;
4170: REG8(AL) |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
4171: REG8(AL) |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
4172: }
4173:
4174: inline void pcbios_int_16h_03h()
4175: {
4176: static UINT16 status = 0;
4177:
4178: switch(REG8(AL)) {
4179: case 0x05:
4180: status = REG16(BX);
4181: break;
4182: case 0x06:
4183: REG16(BX) = status;
4184: break;
4185: default:
1.1.1.3 root 4186: m_CF = 1;
1.1 root 4187: break;
4188: }
4189: }
4190:
4191: inline void pcbios_int_16h_05h()
4192: {
1.1.1.14 root 4193: key_buf_char->write(REG8(CL));
4194: key_buf_scan->write(REG8(CH));
1.1 root 4195: REG8(AL) = 0x00;
4196: }
4197:
4198: inline void pcbios_int_16h_12h()
4199: {
4200: pcbios_int_16h_02h();
4201:
4202: REG8(AH) = 0;//(GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x80 : 0;
4203: REG8(AH) |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
4204: REG8(AH) |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
4205: REG8(AH) |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
4206: REG8(AH) |= (GetAsyncKeyState(VK_RMENU ) & 0x8000) ? 0x08 : 0;
4207: REG8(AH) |= (GetAsyncKeyState(VK_RCONTROL) & 0x8000) ? 0x04 : 0;
4208: REG8(AH) |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
4209: REG8(AH) |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
4210: }
4211:
4212: inline void pcbios_int_16h_13h()
4213: {
4214: static UINT16 status = 0;
4215:
4216: switch(REG8(AL)) {
4217: case 0x00:
4218: status = REG16(DX);
4219: break;
4220: case 0x01:
4221: REG16(DX) = status;
4222: break;
4223: default:
1.1.1.3 root 4224: m_CF = 1;
1.1 root 4225: break;
4226: }
4227: }
4228:
4229: inline void pcbios_int_16h_14h()
4230: {
4231: static UINT8 status = 0;
4232:
4233: switch(REG8(AL)) {
4234: case 0x00:
4235: case 0x01:
4236: status = REG8(AL);
4237: break;
4238: case 0x02:
4239: REG8(AL) = status;
4240: break;
4241: default:
1.1.1.3 root 4242: m_CF = 1;
1.1 root 4243: break;
4244: }
4245: }
4246:
4247: inline void pcbios_int_1ah_00h()
4248: {
1.1.1.19 root 4249: pcbios_update_daily_timer_counter(timeGetTime());
4250: REG16(CX) = *(UINT16 *)(mem + 0x46e);
4251: REG16(DX) = *(UINT16 *)(mem + 0x46c);
4252: REG8(AL) = mem[0x470];
4253: mem[0x470] = 0;
1.1 root 4254: }
4255:
4256: inline int to_bcd(int t)
4257: {
4258: int u = (t % 100) / 10;
4259: return (u << 4) | (t % 10);
4260: }
4261:
4262: inline void pcbios_int_1ah_02h()
4263: {
4264: SYSTEMTIME time;
4265:
4266: GetLocalTime(&time);
4267: REG8(CH) = to_bcd(time.wHour);
4268: REG8(CL) = to_bcd(time.wMinute);
4269: REG8(DH) = to_bcd(time.wSecond);
4270: REG8(DL) = 0x00;
4271: }
4272:
4273: inline void pcbios_int_1ah_04h()
4274: {
4275: SYSTEMTIME time;
4276:
4277: GetLocalTime(&time);
4278: REG8(CH) = to_bcd(time.wYear / 100);
4279: REG8(CL) = to_bcd(time.wYear);
4280: REG8(DH) = to_bcd(time.wMonth);
4281: REG8(DL) = to_bcd(time.wDay);
4282: }
4283:
4284: inline void pcbios_int_1ah_0ah()
4285: {
4286: SYSTEMTIME time;
4287: FILETIME file_time;
4288: WORD dos_date, dos_time;
4289:
4290: GetLocalTime(&time);
4291: SystemTimeToFileTime(&time, &file_time);
4292: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time);
4293: REG16(CX) = dos_date;
4294: }
4295:
4296: // msdos system call
4297:
4298: inline void msdos_int_21h_00h()
4299: {
1.1.1.3 root 4300: msdos_process_terminate(SREG(CS), retval, 1);
1.1 root 4301: }
4302:
4303: inline void msdos_int_21h_01h()
4304: {
4305: REG8(AL) = msdos_getche();
1.1.1.8 root 4306: // some seconds may be passed in console
1.1 root 4307: hardware_update();
4308: }
4309:
4310: inline void msdos_int_21h_02h()
4311: {
4312: msdos_putch(REG8(DL));
4313: }
4314:
4315: inline void msdos_int_21h_03h()
4316: {
4317: REG8(AL) = msdos_aux_in();
4318: }
4319:
4320: inline void msdos_int_21h_04h()
4321: {
4322: msdos_aux_out(REG8(DL));
4323: }
4324:
4325: inline void msdos_int_21h_05h()
4326: {
4327: msdos_prn_out(REG8(DL));
4328: }
4329:
4330: inline void msdos_int_21h_06h()
4331: {
4332: if(REG8(DL) == 0xff) {
4333: if(msdos_kbhit()) {
4334: REG8(AL) = msdos_getch();
1.1.1.3 root 4335: #if defined(HAS_I386)
4336: m_ZF = 0;
4337: #else
4338: m_ZeroVal = 1;
4339: #endif
1.1 root 4340: } else {
4341: REG8(AL) = 0;
1.1.1.3 root 4342: #if defined(HAS_I386)
4343: m_ZF = 1;
4344: #else
4345: m_ZeroVal = 0;
4346: #endif
1.1.1.14 root 4347: maybe_idle();
1.1 root 4348: }
4349: } else {
4350: msdos_putch(REG8(DL));
4351: }
4352: }
4353:
4354: inline void msdos_int_21h_07h()
4355: {
4356: REG8(AL) = msdos_getch();
1.1.1.8 root 4357: // some seconds may be passed in console
1.1 root 4358: hardware_update();
4359: }
4360:
4361: inline void msdos_int_21h_08h()
4362: {
4363: REG8(AL) = msdos_getch();
1.1.1.8 root 4364: // some seconds may be passed in console
1.1 root 4365: hardware_update();
4366: }
4367:
4368: inline void msdos_int_21h_09h()
4369: {
1.1.1.21! root 4370: msdos_stdio_reopen();
! 4371:
1.1.1.20 root 4372: process_t *process = msdos_process_info_get(current_psp);
4373: int fd = msdos_psp_get_file_table(1, current_psp);
4374:
1.1.1.14 root 4375: char *str = (char *)(mem + SREG_BASE(DS) + REG16(DX));
4376: int len = 0;
1.1 root 4377:
1.1.1.14 root 4378: while(str[len] != '$' && len < 0x10000) {
4379: len++;
4380: }
1.1.1.20 root 4381: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4382: // stdout is redirected to file
1.1.1.20 root 4383: msdos_write(fd, str, len);
1.1 root 4384: } else {
4385: for(int i = 0; i < len; i++) {
1.1.1.14 root 4386: msdos_putch(str[i]);
1.1 root 4387: }
4388: }
4389: }
4390:
4391: inline void msdos_int_21h_0ah()
4392: {
1.1.1.3 root 4393: int ofs = SREG_BASE(DS) + REG16(DX);
1.1 root 4394: int max = mem[ofs] - 1;
4395: UINT8 *buf = mem + ofs + 2;
4396: int chr, p = 0;
4397:
4398: while((chr = msdos_getch()) != 0x0d) {
4399: if(chr == 0x00) {
4400: // skip 2nd byte
4401: msdos_getch();
4402: } else if(chr == 0x08) {
4403: // back space
4404: if(p > 0) {
4405: p--;
1.1.1.20 root 4406: if(msdos_ctrl_code_check(buf[p])) {
4407: msdos_putch(chr);
4408: msdos_putch(chr);
4409: msdos_putch(' ');
4410: msdos_putch(' ');
4411: msdos_putch(chr);
4412: msdos_putch(chr);
4413: } else {
4414: msdos_putch(chr);
4415: msdos_putch(' ');
4416: msdos_putch(chr);
4417: }
1.1 root 4418: }
4419: } else if(p < max) {
4420: buf[p++] = chr;
4421: msdos_putch(chr);
4422: }
4423: }
4424: buf[p] = 0x0d;
4425: mem[ofs + 1] = p;
1.1.1.8 root 4426: // some seconds may be passed in console
1.1 root 4427: hardware_update();
4428: }
4429:
4430: inline void msdos_int_21h_0bh()
4431: {
4432: if(msdos_kbhit()) {
4433: REG8(AL) = 0xff;
4434: } else {
4435: REG8(AL) = 0x00;
1.1.1.14 root 4436: maybe_idle();
1.1 root 4437: }
4438: }
4439:
4440: inline void msdos_int_21h_0ch()
4441: {
4442: // clear key buffer
1.1.1.21! root 4443: msdos_stdio_reopen();
! 4444:
1.1.1.20 root 4445: process_t *process = msdos_process_info_get(current_psp);
4446: int fd = msdos_psp_get_file_table(0, current_psp);
4447:
4448: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4449: // stdin is redirected to file
4450: } else {
4451: while(msdos_kbhit()) {
4452: msdos_getch();
4453: }
4454: }
4455:
4456: switch(REG8(AL)) {
4457: case 0x01:
4458: msdos_int_21h_01h();
4459: break;
4460: case 0x06:
4461: msdos_int_21h_06h();
4462: break;
4463: case 0x07:
4464: msdos_int_21h_07h();
4465: break;
4466: case 0x08:
4467: msdos_int_21h_08h();
4468: break;
4469: case 0x0a:
4470: msdos_int_21h_0ah();
4471: break;
4472: default:
4473: REG16(AX) = 0x01;
1.1.1.3 root 4474: m_CF = 1;
1.1 root 4475: break;
4476: }
4477: }
4478:
4479: inline void msdos_int_21h_0dh()
4480: {
4481: }
4482:
4483: inline void msdos_int_21h_0eh()
4484: {
4485: if(REG8(DL) < 26) {
4486: _chdrive(REG8(DL) + 1);
4487: msdos_cds_update(REG8(DL));
4488: }
4489: REG8(AL) = 26; // zdrive
4490: }
4491:
1.1.1.14 root 4492: inline void msdos_int_21h_0fh()
4493: {
4494: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4495: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4496: char *path = msdos_fcb_path(fcb);
4497: 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 4498:
1.1.1.14 root 4499: if(hFile == INVALID_HANDLE_VALUE) {
4500: REG8(AL) = 0xff;
4501: } else {
4502: REG8(AL) = 0;
4503: fcb->current_block = 0;
4504: fcb->record_size = 128;
4505: fcb->file_size = GetFileSize(hFile, NULL);
4506: fcb->handle = hFile;
4507: fcb->cur_record = 0;
4508: }
4509: }
4510:
4511: inline void msdos_int_21h_10h()
4512: {
4513: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4514: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4515:
4516: REG8(AL) = CloseHandle(fcb->handle) ? 0 : 0xff;
4517: }
4518:
1.1 root 4519: inline void msdos_int_21h_11h()
4520: {
1.1.1.3 root 4521: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4522: fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 4523:
4524: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 4525: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4526: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
4527: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 4528: char *path = msdos_fcb_path(fcb);
4529: WIN32_FIND_DATA fd;
4530:
1.1.1.13 root 4531: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
4532: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
4533: FindClose(dtainfo->find_handle);
4534: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 4535: }
4536: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 4537: dtainfo->allowable_mask = (ext_fcb->flag == 0xff) ? ext_fcb->attribute : 0x20;
4538: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 4539:
1.1.1.14 root 4540: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
4541: dtainfo->allowable_mask &= ~8;
1.1 root 4542: }
1.1.1.14 root 4543: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
4544: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 4545: !msdos_find_file_has_8dot3name(&fd)) {
4546: if(!FindNextFile(dtainfo->find_handle, &fd)) {
4547: FindClose(dtainfo->find_handle);
4548: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 4549: break;
4550: }
4551: }
4552: }
1.1.1.13 root 4553: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 4554: if(ext_fcb->flag == 0xff) {
4555: ext_find->flag = 0xff;
4556: memset(ext_find->reserved, 0, 5);
4557: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
4558: }
4559: find->drive = _getdrive();
1.1.1.13 root 4560: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 4561: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
4562: find->nt_res = 0;
4563: msdos_find_file_conv_local_time(&fd);
4564: find->create_time_ms = 0;
4565: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
4566: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
4567: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
4568: find->cluster_hi = find->cluster_lo = 0;
4569: find->file_size = fd.nFileSizeLow;
4570: REG8(AL) = 0x00;
1.1.1.14 root 4571: } else if(dtainfo->allowable_mask & 8) {
1.1 root 4572: if(ext_fcb->flag == 0xff) {
4573: ext_find->flag = 0xff;
4574: memset(ext_find->reserved, 0, 5);
4575: ext_find->attribute = 8;
4576: }
4577: find->drive = _getdrive();
4578: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
4579: find->attribute = 8;
4580: find->nt_res = 0;
4581: msdos_find_file_conv_local_time(&fd);
4582: find->create_time_ms = 0;
4583: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
4584: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
4585: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
4586: find->cluster_hi = find->cluster_lo = 0;
4587: find->file_size = 0;
1.1.1.14 root 4588: dtainfo->allowable_mask &= ~8;
1.1 root 4589: REG8(AL) = 0x00;
4590: } else {
4591: REG8(AL) = 0xff;
4592: }
4593: }
4594:
4595: inline void msdos_int_21h_12h()
4596: {
1.1.1.3 root 4597: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1.1.14 root 4598: // fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 4599:
4600: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 4601: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4602: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
4603: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 4604: WIN32_FIND_DATA fd;
4605:
1.1.1.13 root 4606: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
4607: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
4608: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 4609: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 4610: !msdos_find_file_has_8dot3name(&fd)) {
4611: if(!FindNextFile(dtainfo->find_handle, &fd)) {
4612: FindClose(dtainfo->find_handle);
4613: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 4614: break;
4615: }
4616: }
4617: } else {
1.1.1.13 root 4618: FindClose(dtainfo->find_handle);
4619: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 4620: }
4621: }
1.1.1.13 root 4622: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 4623: if(ext_fcb->flag == 0xff) {
4624: ext_find->flag = 0xff;
4625: memset(ext_find->reserved, 0, 5);
4626: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
4627: }
4628: find->drive = _getdrive();
1.1.1.13 root 4629: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 4630: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
4631: find->nt_res = 0;
4632: msdos_find_file_conv_local_time(&fd);
4633: find->create_time_ms = 0;
4634: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
4635: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
4636: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
4637: find->cluster_hi = find->cluster_lo = 0;
4638: find->file_size = fd.nFileSizeLow;
4639: REG8(AL) = 0x00;
1.1.1.14 root 4640: } else if(dtainfo->allowable_mask & 8) {
1.1 root 4641: if(ext_fcb->flag == 0xff) {
4642: ext_find->flag = 0xff;
4643: memset(ext_find->reserved, 0, 5);
4644: ext_find->attribute = 8;
4645: }
4646: find->drive = _getdrive();
4647: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
4648: find->attribute = 8;
4649: find->nt_res = 0;
4650: msdos_find_file_conv_local_time(&fd);
4651: find->create_time_ms = 0;
4652: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
4653: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
4654: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
4655: find->cluster_hi = find->cluster_lo = 0;
4656: find->file_size = 0;
1.1.1.14 root 4657: dtainfo->allowable_mask &= ~8;
1.1 root 4658: REG8(AL) = 0x00;
4659: } else {
4660: REG8(AL) = 0xff;
4661: }
4662: }
4663:
4664: inline void msdos_int_21h_13h()
4665: {
1.1.1.3 root 4666: if(remove(msdos_fcb_path((fcb_t *)(mem + SREG_BASE(DS) + REG16(DX))))) {
1.1 root 4667: REG8(AL) = 0xff;
4668: } else {
4669: REG8(AL) = 0x00;
4670: }
4671: }
4672:
1.1.1.16 root 4673: inline void msdos_int_21h_14h()
4674: {
4675: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4676: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4677: process_t *process = msdos_process_info_get(current_psp);
4678: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4679: DWORD num = 0;
4680:
4681: memset(mem + dta_laddr, 0, fcb->record_size);
4682: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
4683: REG8(AL) = 1;
4684: } else {
4685: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
4686: fcb->current_block = (position & 0xffffff) / fcb->record_size;
4687: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
4688: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
4689: }
4690: }
4691:
4692: inline void msdos_int_21h_15h()
1.1.1.14 root 4693: {
4694: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4695: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.16 root 4696: process_t *process = msdos_process_info_get(current_psp);
4697: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4698: DWORD num = 0;
1.1.1.14 root 4699:
1.1.1.16 root 4700: if(!WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
4701: REG8(AL) = 1;
4702: } else {
4703: fcb->file_size = GetFileSize(fcb->handle, NULL);
4704: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
4705: fcb->current_block = (position & 0xffffff) / fcb->record_size;
4706: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
4707: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
4708: }
4709: }
4710:
4711: inline void msdos_int_21h_16h()
4712: {
4713: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4714: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.14 root 4715: char *path = msdos_fcb_path(fcb);
4716: 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 4717:
1.1.1.14 root 4718: if(hFile == INVALID_HANDLE_VALUE) {
4719: REG8(AL) = 0xff;
4720: } else {
4721: REG8(AL) = 0;
4722: fcb->current_block = 0;
4723: fcb->record_size = 128;
4724: fcb->file_size = 0;
4725: fcb->handle = hFile;
4726: fcb->cur_record = 0;
4727: }
4728: }
4729:
1.1.1.16 root 4730: inline void msdos_int_21h_17h()
4731: {
4732: ext_fcb_t *ext_fcb_src = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4733: fcb_t *fcb_src = (fcb_t *)(ext_fcb_src + (ext_fcb_src->flag == 0xff ? 1 : 0));
4734: char *path_src = msdos_fcb_path(fcb_src);
4735: ext_fcb_t *ext_fcb_dst = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + 16);
4736: fcb_t *fcb_dst = (fcb_t *)(ext_fcb_dst + (ext_fcb_dst->flag == 0xff ? 1 : 0));
4737: char *path_dst = msdos_fcb_path(fcb_dst);
4738:
4739: if(rename(path_src, path_dst)) {
4740: REG8(AL) = 0xff;
4741: } else {
4742: REG8(AL) = 0;
4743: }
4744: }
4745:
1.1 root 4746: inline void msdos_int_21h_18h()
4747: {
4748: REG8(AL) = 0x00;
4749: }
4750:
4751: inline void msdos_int_21h_19h()
4752: {
4753: REG8(AL) = _getdrive() - 1;
4754: }
4755:
4756: inline void msdos_int_21h_1ah()
4757: {
4758: process_t *process = msdos_process_info_get(current_psp);
4759:
4760: process->dta.w.l = REG16(DX);
1.1.1.3 root 4761: process->dta.w.h = SREG(DS);
1.1 root 4762: }
4763:
4764: inline void msdos_int_21h_1bh()
4765: {
4766: int drive_num = _getdrive() - 1;
4767: UINT16 seg, ofs;
4768:
4769: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
4770: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
4771: REG8(AL) = dpb->highest_sector_num + 1;
4772: REG16(CX) = dpb->bytes_per_sector;
4773: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 4774: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 4775: } else {
4776: REG8(AL) = 0xff;
1.1.1.3 root 4777: m_CF = 1;
1.1 root 4778: }
4779:
4780: }
4781:
4782: inline void msdos_int_21h_1ch()
4783: {
4784: int drive_num = REG8(DL) ? (REG8(DL) - 1) : (_getdrive() - 1);
4785: UINT16 seg, ofs;
4786:
4787: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
4788: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
4789: REG8(AL) = dpb->highest_sector_num + 1;
4790: REG16(CX) = dpb->bytes_per_sector;
4791: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 4792: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 4793: } else {
4794: REG8(AL) = 0xff;
1.1.1.3 root 4795: m_CF = 1;
1.1 root 4796: }
4797:
4798: }
4799:
4800: inline void msdos_int_21h_1dh()
4801: {
4802: REG8(AL) = 0;
4803: }
4804:
4805: inline void msdos_int_21h_1eh()
4806: {
4807: REG8(AL) = 0;
4808: }
4809:
4810: inline void msdos_int_21h_1fh()
4811: {
4812: int drive_num = _getdrive() - 1;
4813: UINT16 seg, ofs;
4814:
4815: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
4816: REG8(AL) = 0;
1.1.1.3 root 4817: SREG(DS) = seg;
4818: i386_load_segment_descriptor(DS);
1.1 root 4819: REG16(BX) = ofs;
4820: } else {
4821: REG8(AL) = 0xff;
1.1.1.3 root 4822: m_CF = 1;
1.1 root 4823: }
4824: }
4825:
4826: inline void msdos_int_21h_20h()
4827: {
4828: REG8(AL) = 0;
4829: }
4830:
1.1.1.14 root 4831: inline void msdos_int_21h_21h()
4832: {
4833: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4834: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4835:
4836: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
4837: REG8(AL) = 1;
4838: } else {
4839: process_t *process = msdos_process_info_get(current_psp);
4840: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4841: memset(mem + dta_laddr, 0, fcb->record_size);
1.1.1.16 root 4842: DWORD num = 0;
1.1.1.14 root 4843: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
4844: REG8(AL) = 1;
4845: } else {
4846: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
4847: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 4848: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
1.1.1.14 root 4849: }
4850: }
4851: }
4852:
4853: inline void msdos_int_21h_22h()
4854: {
4855: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4856: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4857:
4858: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
4859: REG8(AL) = 0xff;
4860: } else {
4861: process_t *process = msdos_process_info_get(current_psp);
4862: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
1.1.1.16 root 4863: DWORD num = 0;
1.1.1.14 root 4864: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL);
4865: fcb->file_size = GetFileSize(fcb->handle, NULL);
4866: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
4867: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 4868: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
1.1.1.14 root 4869: }
4870: }
4871:
1.1.1.16 root 4872: inline void msdos_int_21h_23h()
4873: {
4874: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4875: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4876: char *path = msdos_fcb_path(fcb);
4877: HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
4878:
4879: if(hFile == INVALID_HANDLE_VALUE) {
4880: REG8(AL) = 0xff;
4881: } else {
4882: UINT32 size = GetFileSize(hFile, NULL);
4883: fcb->rand_record = size / fcb->record_size + ((size % fcb->record_size) != 0);
4884: REG8(AL) = 0;
4885: }
4886: }
4887:
4888: inline void msdos_int_21h_24h()
4889: {
4890: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4891: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4892:
4893: fcb->rand_record = fcb->current_block * fcb->record_size + fcb->cur_record;
4894: }
4895:
1.1 root 4896: inline void msdos_int_21h_25h()
4897: {
4898: *(UINT16 *)(mem + 4 * REG8(AL) + 0) = REG16(DX);
1.1.1.3 root 4899: *(UINT16 *)(mem + 4 * REG8(AL) + 2) = SREG(DS);
1.1 root 4900: }
4901:
4902: inline void msdos_int_21h_26h()
4903: {
4904: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
4905:
4906: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
4907: psp->first_mcb = REG16(DX) + 16;
4908: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
4909: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
4910: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
4911: psp->parent_psp = 0;
4912: }
4913:
1.1.1.16 root 4914: inline void msdos_int_21h_27h()
4915: {
4916: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4917: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4918:
4919: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
4920: REG8(AL) = 1;
4921: } else {
4922: process_t *process = msdos_process_info_get(current_psp);
4923: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4924: memset(mem + dta_laddr, 0, fcb->record_size * REG16(CX));
4925: DWORD num = 0;
4926: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL) || num == 0) {
4927: REG8(AL) = 1;
4928: } else {
4929: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
4930: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
4931: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
4932: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
4933: }
4934: }
4935: }
4936:
4937: inline void msdos_int_21h_28h()
4938: {
4939: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4940: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4941:
4942: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
4943: REG8(AL) = 0xff;
4944: } else {
4945: process_t *process = msdos_process_info_get(current_psp);
4946: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4947: DWORD num = 0;
4948: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL);
4949: fcb->file_size = GetFileSize(fcb->handle, NULL);
4950: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
4951: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
4952: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
4953: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
4954: }
4955: }
4956:
1.1 root 4957: inline void msdos_int_21h_29h()
4958: {
1.1.1.20 root 4959: int ofs = 0;//SREG_BASE(DS) + REG16(SI);
4960: char buffer[1024], name[MAX_PATH], ext[MAX_PATH];
1.1 root 4961: UINT8 drv = 0;
4962: char sep_chars[] = ":.;,=+";
4963: char end_chars[] = "\\<>|/\"[]";
4964: char spc_chars[] = " \t";
4965:
1.1.1.20 root 4966: memcpy(buffer, mem + SREG_BASE(DS) + REG16(SI), 1023);
4967: buffer[1023] = 0;
4968: memset(name, 0x20, sizeof(name));
4969: memset(ext, 0x20, sizeof(ext));
4970:
1.1 root 4971: if(REG8(AL) & 1) {
1.1.1.20 root 4972: ofs += strspn((char *)(buffer + ofs), spc_chars);
4973: if(my_strchr(sep_chars, buffer[ofs]) && buffer[ofs] != '\0') {
1.1 root 4974: ofs++;
4975: }
4976: }
1.1.1.20 root 4977: ofs += strspn((char *)(buffer + ofs), spc_chars);
1.1 root 4978:
4979: if(mem[ofs + 1] == ':') {
1.1.1.20 root 4980: if(mem[ofs] >= 'a' && mem[ofs] <= 'z') {
4981: drv = mem[ofs] - 'a' + 1;
4982: ofs += 2;
4983: } else if(mem[ofs] >= 'A' && mem[ofs] <= 'Z') {
4984: drv = mem[ofs] - 'A' + 1;
1.1 root 4985: ofs += 2;
4986: }
4987: }
1.1.1.20 root 4988: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
4989: UINT8 c = buffer[ofs];
4990: if(is_kanji) {
4991: is_kanji = 0;
4992: } else if(msdos_lead_byte_check(c)) {
4993: is_kanji = 1;
4994: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 4995: break;
4996: } else if(c >= 'a' && c <= 'z') {
4997: c -= 0x20;
4998: }
4999: ofs++;
5000: name[i] = c;
5001: }
1.1.1.20 root 5002: if(buffer[ofs] == '.') {
1.1 root 5003: ofs++;
1.1.1.20 root 5004: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
5005: UINT8 c = buffer[ofs];
5006: if(is_kanji) {
5007: is_kanji = 0;
5008: } else if(msdos_lead_byte_check(c)) {
5009: is_kanji = 1;
5010: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 5011: break;
5012: } else if(c >= 'a' && c <= 'z') {
5013: c -= 0x20;
5014: }
5015: ofs++;
5016: ext[i] = c;
5017: }
5018: }
1.1.1.20 root 5019: int si = REG16(SI) + ofs;
1.1.1.3 root 5020: int ds = SREG(DS);
1.1 root 5021: while(si > 0xffff) {
5022: si -= 0x10;
5023: ds++;
5024: }
5025: REG16(SI) = si;
1.1.1.3 root 5026: SREG(DS) = ds;
5027: i386_load_segment_descriptor(DS);
1.1 root 5028:
1.1.1.3 root 5029: UINT8 *fcb = mem + SREG_BASE(ES) + REG16(DI);
1.1.1.20 root 5030: if(!(REG8(AL) & 2) || drv != 0) {
5031: fcb[0] = drv;
5032: }
5033: if(!(REG8(AL) & 4) || name[0] != 0x20) {
5034: memcpy(fcb + 1, name, 8);
5035: }
5036: if(!(REG8(AL) & 8) || ext[0] != 0x20) {
5037: memcpy(fcb + 9, ext, 3);
5038: }
5039: for(int i = 1, found_star = 0; i < 1 + 8; i++) {
1.1 root 5040: if(fcb[i] == '*') {
5041: found_star = 1;
5042: }
5043: if(found_star) {
5044: fcb[i] = '?';
5045: }
5046: }
1.1.1.20 root 5047: for(int i = 9, found_star = 0; i < 9 + 3; i++) {
1.1 root 5048: if(fcb[i] == '*') {
5049: found_star = 1;
5050: }
5051: if(found_star) {
5052: fcb[i] = '?';
5053: }
5054: }
5055:
5056: if(drv == 0 || (drv > 0 && drv <= 26 && (GetLogicalDrives() & ( 1 << (drv - 1) )))) {
5057: if(memchr(fcb + 1, '?', 8 + 3)) {
5058: REG8(AL) = 0x01;
1.1.1.20 root 5059: } else {
5060: REG8(AL) = 0x00;
1.1 root 5061: }
5062: } else {
5063: REG8(AL) = 0xff;
5064: }
5065: }
5066:
5067: inline void msdos_int_21h_2ah()
5068: {
5069: SYSTEMTIME sTime;
5070:
5071: GetLocalTime(&sTime);
5072: REG16(CX) = sTime.wYear;
5073: REG8(DH) = (UINT8)sTime.wMonth;
5074: REG8(DL) = (UINT8)sTime.wDay;
5075: REG8(AL) = (UINT8)sTime.wDayOfWeek;
5076: }
5077:
5078: inline void msdos_int_21h_2bh()
5079: {
1.1.1.14 root 5080: REG8(AL) = 0xff;
1.1 root 5081: }
5082:
5083: inline void msdos_int_21h_2ch()
5084: {
5085: SYSTEMTIME sTime;
5086:
5087: GetLocalTime(&sTime);
5088: REG8(CH) = (UINT8)sTime.wHour;
5089: REG8(CL) = (UINT8)sTime.wMinute;
5090: REG8(DH) = (UINT8)sTime.wSecond;
1.1.1.14 root 5091: REG8(DL) = (UINT8)sTime.wMilliseconds / 10;
1.1 root 5092: }
5093:
5094: inline void msdos_int_21h_2dh()
5095: {
5096: REG8(AL) = 0x00;
5097: }
5098:
5099: inline void msdos_int_21h_2eh()
5100: {
5101: process_t *process = msdos_process_info_get(current_psp);
5102:
5103: process->verify = REG8(AL);
5104: }
5105:
5106: inline void msdos_int_21h_2fh()
5107: {
5108: process_t *process = msdos_process_info_get(current_psp);
5109:
5110: REG16(BX) = process->dta.w.l;
1.1.1.3 root 5111: SREG(ES) = process->dta.w.h;
5112: i386_load_segment_descriptor(ES);
1.1 root 5113: }
5114:
5115: inline void msdos_int_21h_30h()
5116: {
5117: // Version Flag / OEM
5118: if(REG8(AL) == 1) {
5119: REG8(BH) = 0x00; // not in ROM
5120: } else {
5121: REG8(BH) = 0xff; // OEM = Microsoft
5122: }
1.1.1.9 root 5123: REG8(AL) = major_version; // 7
5124: REG8(AH) = minor_version; // 10
1.1 root 5125: }
5126:
5127: inline void msdos_int_21h_31h()
5128: {
1.1.1.14 root 5129: msdos_mem_realloc(current_psp, REG16(DX), NULL);
1.1 root 5130: msdos_process_terminate(current_psp, REG8(AL) | 0x300, 0);
5131: }
5132:
5133: inline void msdos_int_21h_32h()
5134: {
5135: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
5136: UINT16 seg, ofs;
5137:
5138: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
5139: REG8(AL) = 0;
1.1.1.3 root 5140: SREG(DS) = seg;
5141: i386_load_segment_descriptor(DS);
1.1 root 5142: REG16(BX) = ofs;
5143: } else {
5144: REG8(AL) = 0xff;
1.1.1.3 root 5145: m_CF = 1;
1.1 root 5146: }
5147: }
5148:
5149: inline void msdos_int_21h_33h()
5150: {
5151: static UINT8 state = 0x00;
5152: char path[MAX_PATH];
5153:
5154: switch(REG8(AL)) {
5155: case 0x00:
5156: REG8(DL) = state;
5157: break;
5158: case 0x01:
5159: state = REG8(DL);
5160: break;
5161: case 0x05:
5162: GetSystemDirectory(path, MAX_PATH);
5163: if(path[0] >= 'a' && path[0] <= 'z') {
5164: REG8(DL) = path[0] - 'a' + 1;
5165: } else {
5166: REG8(DL) = path[0] - 'A' + 1;
5167: }
5168: break;
5169: case 0x06:
1.1.1.2 root 5170: // MS-DOS version (7.10)
1.1 root 5171: REG8(BL) = 7;
1.1.1.2 root 5172: REG8(BH) = 10;
1.1 root 5173: REG8(DL) = 0;
5174: REG8(DH) = 0x10; // in HMA
5175: break;
1.1.1.6 root 5176: case 0x07:
5177: if(REG8(DL) == 0) {
5178: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag &= ~0x20;
5179: } else if(REG8(DL) == 1) {
5180: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag |= 0x20;
5181: }
5182: break;
1.1 root 5183: default:
5184: REG16(AX) = 0x01;
1.1.1.3 root 5185: m_CF = 1;
1.1 root 5186: break;
5187: }
5188: }
5189:
5190: inline void msdos_int_21h_35h()
5191: {
5192: REG16(BX) = *(UINT16 *)(mem + 4 * REG8(AL) + 0);
1.1.1.3 root 5193: SREG(ES) = *(UINT16 *)(mem + 4 * REG8(AL) + 2);
5194: i386_load_segment_descriptor(ES);
1.1 root 5195: }
5196:
5197: inline void msdos_int_21h_36h()
5198: {
5199: struct _diskfree_t df = {0};
5200:
5201: if(_getdiskfree(REG8(DL), &df) == 0) {
5202: REG16(AX) = (UINT16)df.sectors_per_cluster;
5203: REG16(CX) = (UINT16)df.bytes_per_sector;
1.1.1.13 root 5204: REG16(BX) = df.avail_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.avail_clusters;
5205: REG16(DX) = df.total_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.total_clusters;
1.1 root 5206: } else {
5207: REG16(AX) = 0xffff;
5208: }
5209: }
5210:
5211: inline void msdos_int_21h_37h()
5212: {
5213: process_t *process = msdos_process_info_get(current_psp);
5214:
5215: switch(REG8(AL)) {
5216: case 0x00:
5217: REG8(AL) = 0x00;
5218: REG8(DL) = process->switchar;
5219: break;
5220: case 0x01:
5221: REG8(AL) = 0x00;
5222: process->switchar = REG8(DL);
5223: break;
5224: default:
5225: REG16(AX) = 1;
5226: break;
5227: }
5228: }
5229:
1.1.1.19 root 5230: int get_country_info(country_info_t *ci)
1.1.1.17 root 5231: {
5232: char LCdata[80];
5233:
1.1.1.19 root 5234: ZeroMemory(ci, offsetof(country_info_t, reserved));
1.1.1.17 root 5235: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRDIGITS, LCdata, sizeof(LCdata));
5236: ci->currency_dec_digits = atoi(LCdata);
5237: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRENCY, LCdata, sizeof(LCdata));
5238: ci->currency_format = *LCdata - '0';
5239: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDATE, LCdata, sizeof(LCdata));
5240: ci->date_format = *LCdata - '0';
5241: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SCURRENCY, LCdata, sizeof(LCdata));
5242: memcpy(&ci->currency_symbol, LCdata, 4);
5243: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDATE, LCdata, sizeof(LCdata));
5244: *ci->date_sep = *LCdata;
5245: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, LCdata, sizeof(LCdata));
5246: *ci->dec_sep = *LCdata;
5247: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLIST, LCdata, sizeof(LCdata));
5248: *ci->list_sep = *LCdata;
5249: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, LCdata, sizeof(LCdata));
5250: *ci->thou_sep = *LCdata;
5251: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIME, LCdata, sizeof(LCdata));
5252: *ci->time_sep = *LCdata;
5253: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, LCdata, sizeof(LCdata));
5254: if(strchr(LCdata, 'H') != NULL) {
5255: ci->time_format = 1;
5256: }
1.1.1.19 root 5257: ci->case_map.w.l = 0x000c;
5258: ci->case_map.w.h = 0xffff;
1.1.1.17 root 5259: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICOUNTRY, LCdata, sizeof(LCdata));
5260: return atoi(LCdata);
5261: }
5262:
1.1.1.14 root 5263: inline void msdos_int_21h_38h()
5264: {
5265: switch(REG8(AL)) {
5266: case 0x00:
1.1.1.19 root 5267: REG16(BX) = get_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1.1.14 root 5268: break;
5269: default:
5270: REG16(AX) = 2;
5271: m_CF = 1;
5272: break;
5273: }
5274: }
5275:
1.1 root 5276: inline void msdos_int_21h_39h(int lfn)
5277: {
1.1.1.3 root 5278: if(_mkdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 5279: REG16(AX) = errno;
1.1.1.3 root 5280: m_CF = 1;
1.1 root 5281: }
5282: }
5283:
5284: inline void msdos_int_21h_3ah(int lfn)
5285: {
1.1.1.3 root 5286: if(_rmdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 5287: REG16(AX) = errno;
1.1.1.3 root 5288: m_CF = 1;
1.1 root 5289: }
5290: }
5291:
5292: inline void msdos_int_21h_3bh(int lfn)
5293: {
1.1.1.3 root 5294: if(_chdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1.1.17 root 5295: REG16(AX) = 3; // must be 3 (path not found)
1.1.1.3 root 5296: m_CF = 1;
1.1 root 5297: }
5298: }
5299:
5300: inline void msdos_int_21h_3ch()
5301: {
1.1.1.3 root 5302: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 5303: int attr = GetFileAttributes(path);
5304: int fd = -1;
1.1.1.11 root 5305: UINT16 info;
1.1 root 5306:
1.1.1.11 root 5307: if(msdos_is_con_path(path)) {
5308: fd = _open("CON", _O_WRONLY | _O_BINARY);
5309: info = 0x80d3;
1.1.1.14 root 5310: } else if(msdos_is_nul_path(path)) {
5311: fd = _open("NUL", _O_WRONLY | _O_BINARY);
5312: info = 0x80d3;
1.1.1.20 root 5313: } else if(strncmp(path, "EMMXXXX0", 8) == 0) {
5314: fd = _open("NUL", _O_WRONLY | _O_BINARY);
5315: info = 0x80d3;
1.1 root 5316: } else {
5317: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 5318: info = msdos_drive_number(path);
1.1 root 5319: }
5320: if(fd != -1) {
5321: if(attr == -1) {
5322: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
5323: }
5324: SetFileAttributes(path, attr);
5325: REG16(AX) = fd;
1.1.1.11 root 5326: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp);
1.1.1.20 root 5327: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 5328: } else {
5329: REG16(AX) = errno;
1.1.1.3 root 5330: m_CF = 1;
1.1 root 5331: }
5332: }
5333:
5334: inline void msdos_int_21h_3dh()
5335: {
1.1.1.3 root 5336: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 5337: int mode = REG8(AL) & 0x03;
1.1.1.11 root 5338: int fd = -1;
5339: UINT16 info;
1.1 root 5340:
5341: if(mode < 0x03) {
1.1.1.11 root 5342: if(msdos_is_con_path(path)) {
1.1.1.13 root 5343: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 5344: info = 0x80d3;
1.1.1.14 root 5345: } else if(msdos_is_nul_path(path)) {
5346: fd = msdos_open("NUL", file_mode[mode].mode);
5347: info = 0x80d3;
1.1.1.20 root 5348: } else if(strncmp(path, "EMMXXXX0", 8) == 0) {
5349: fd = msdos_open("NUL", file_mode[mode].mode);
5350: info = 0x80d3;
1.1.1.11 root 5351: } else {
1.1.1.13 root 5352: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 5353: info = msdos_drive_number(path);
5354: }
1.1 root 5355: if(fd != -1) {
5356: REG16(AX) = fd;
1.1.1.11 root 5357: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp);
1.1.1.20 root 5358: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 5359: } else {
5360: REG16(AX) = errno;
1.1.1.3 root 5361: m_CF = 1;
1.1 root 5362: }
5363: } else {
5364: REG16(AX) = 0x0c;
1.1.1.3 root 5365: m_CF = 1;
1.1 root 5366: }
5367: }
5368:
5369: inline void msdos_int_21h_3eh()
5370: {
5371: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 5372: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 5373:
1.1.1.20 root 5374: if(fd < process->max_files && file_handler[fd].valid) {
5375: _close(fd);
5376: msdos_file_handler_close(fd);
5377: msdos_psp_set_file_table(REG16(BX), 0x0ff, current_psp);
1.1 root 5378: } else {
5379: REG16(AX) = 0x06;
1.1.1.3 root 5380: m_CF = 1;
1.1 root 5381: }
5382: }
5383:
5384: inline void msdos_int_21h_3fh()
5385: {
5386: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 5387: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 5388:
1.1.1.20 root 5389: if(fd < process->max_files && file_handler[fd].valid) {
5390: if(file_mode[file_handler[fd].mode].in) {
5391: if(file_handler[fd].atty) {
1.1 root 5392: // BX is stdin or is redirected to stdin
1.1.1.3 root 5393: UINT8 *buf = mem + SREG_BASE(DS) + REG16(DX);
1.1 root 5394: int max = REG16(CX);
5395: int p = 0;
5396:
5397: while(max > p) {
5398: int chr = msdos_getch();
5399:
5400: if(chr == 0x00) {
5401: // skip 2nd byte
5402: msdos_getch();
5403: } else if(chr == 0x0d) {
5404: // carriage return
5405: buf[p++] = 0x0d;
5406: if(max > p) {
5407: buf[p++] = 0x0a;
5408: }
1.1.1.14 root 5409: msdos_putch('\n');
1.1 root 5410: break;
5411: } else if(chr == 0x08) {
5412: // back space
5413: if(p > 0) {
5414: p--;
1.1.1.20 root 5415: if(msdos_ctrl_code_check(buf[p])) {
5416: msdos_putch(chr);
5417: msdos_putch(chr);
5418: msdos_putch(' ');
5419: msdos_putch(' ');
5420: msdos_putch(chr);
5421: msdos_putch(chr);
5422: } else {
5423: msdos_putch(chr);
5424: msdos_putch(' ');
5425: msdos_putch(chr);
5426: }
1.1 root 5427: }
5428: } else {
5429: buf[p++] = chr;
5430: msdos_putch(chr);
5431: }
5432: }
5433: REG16(AX) = p;
1.1.1.8 root 5434: // some seconds may be passed in console
1.1 root 5435: hardware_update();
5436: } else {
1.1.1.20 root 5437: REG16(AX) = _read(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 5438: }
5439: } else {
5440: REG16(AX) = 0x05;
1.1.1.3 root 5441: m_CF = 1;
1.1 root 5442: }
5443: } else {
5444: REG16(AX) = 0x06;
1.1.1.3 root 5445: m_CF = 1;
1.1 root 5446: }
5447: }
5448:
5449: inline void msdos_int_21h_40h()
5450: {
5451: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 5452: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 5453:
1.1.1.20 root 5454: if(fd < process->max_files && file_handler[fd].valid) {
5455: if(file_mode[file_handler[fd].mode].out) {
1.1 root 5456: if(REG16(CX)) {
1.1.1.20 root 5457: if(file_handler[fd].atty) {
1.1 root 5458: // BX is stdout/stderr or is redirected to stdout
5459: for(int i = 0; i < REG16(CX); i++) {
1.1.1.3 root 5460: msdos_putch(mem[SREG_BASE(DS) + REG16(DX) + i]);
1.1 root 5461: }
5462: REG16(AX) = REG16(CX);
5463: } else {
1.1.1.20 root 5464: REG16(AX) = msdos_write(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 5465: }
5466: } else {
1.1.1.20 root 5467: UINT32 pos = _tell(fd);
5468: _lseek(fd, 0, SEEK_END);
5469: UINT32 size = _tell(fd);
1.1 root 5470: REG16(AX) = 0;
1.1.1.12 root 5471: if(pos < size) {
1.1.1.20 root 5472: _lseek(fd, pos, SEEK_SET);
5473: SetEndOfFile((HANDLE)_get_osfhandle(fd));
1.1.1.12 root 5474: } else {
5475: for(UINT32 i = size; i < pos; i++) {
5476: UINT8 tmp = 0;
1.1.1.20 root 5477: REG16(AX) += msdos_write(fd, &tmp, 1);
1.1.1.12 root 5478: }
1.1.1.20 root 5479: _lseek(fd, pos, SEEK_SET);
1.1 root 5480: }
5481: }
5482: } else {
5483: REG16(AX) = 0x05;
1.1.1.3 root 5484: m_CF = 1;
1.1 root 5485: }
5486: } else {
5487: REG16(AX) = 0x06;
1.1.1.3 root 5488: m_CF = 1;
1.1 root 5489: }
5490: }
5491:
5492: inline void msdos_int_21h_41h(int lfn)
5493: {
1.1.1.3 root 5494: if(remove(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 5495: REG16(AX) = errno;
1.1.1.3 root 5496: m_CF = 1;
1.1 root 5497: }
5498: }
5499:
5500: inline void msdos_int_21h_42h()
5501: {
5502: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 5503: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 5504:
1.1.1.20 root 5505: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 5506: if(REG8(AL) < 0x03) {
5507: static int ptrname[] = { SEEK_SET, SEEK_CUR, SEEK_END };
1.1.1.20 root 5508: _lseek(fd, (REG16(CX) << 16) | REG16(DX), ptrname[REG8(AL)]);
5509: UINT32 pos = _tell(fd);
1.1 root 5510: REG16(AX) = pos & 0xffff;
5511: REG16(DX) = (pos >> 16);
5512: } else {
5513: REG16(AX) = 0x01;
1.1.1.3 root 5514: m_CF = 1;
1.1 root 5515: }
5516: } else {
5517: REG16(AX) = 0x06;
1.1.1.3 root 5518: m_CF = 1;
1.1 root 5519: }
5520: }
5521:
5522: inline void msdos_int_21h_43h(int lfn)
5523: {
1.1.1.3 root 5524: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn);
1.1 root 5525: int attr;
5526:
1.1.1.14 root 5527: if(!lfn && REG8(AL) > 2) {
5528: REG16(AX) = 0x01;
5529: m_CF = 1;
5530: return;
5531: }
5532: switch(REG8(lfn ? BL : AL)) {
1.1 root 5533: case 0x00:
5534: if((attr = GetFileAttributes(path)) != -1) {
1.1.1.14 root 5535: REG16(CX) = (UINT16)msdos_file_attribute_create((UINT16)attr);
5536: } else {
5537: REG16(AX) = (UINT16)GetLastError();
5538: m_CF = 1;
5539: }
5540: break;
5541: case 0x01:
5542: if(!SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)))) {
5543: REG16(AX) = (UINT16)GetLastError();
5544: m_CF = 1;
5545: }
5546: break;
5547: case 0x02:
5548: {
5549: DWORD size = GetCompressedFileSize(path, NULL);
5550: if(size != INVALID_FILE_SIZE) {
5551: if(size != 0 && size == GetFileSize(path, NULL)) {
5552: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
5553: // this isn't correct if the file is in the NTFS MFT
5554: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
5555: size = ((size - 1) | (sectors_per_cluster * bytes_per_sector - 1)) + 1;
5556: }
5557: }
5558: REG16(AX) = LOWORD(size);
5559: REG16(DX) = HIWORD(size);
5560: } else {
5561: REG16(AX) = (UINT16)GetLastError();
5562: m_CF = 1;
1.1 root 5563: }
1.1.1.14 root 5564: }
5565: break;
5566: case 0x03:
5567: case 0x05:
5568: case 0x07:
5569: {
5570: HANDLE hFile = CreateFile(path, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
5571: if(hFile != INVALID_HANDLE_VALUE) {
5572: FILETIME local, time;
5573: DosDateTimeToFileTime(REG16(DI), /*REG8(BL) == 5 ? 0 : */REG16(CX), &local);
5574: if(REG8(BL) == 7) {
5575: ULARGE_INTEGER hund;
5576: hund.LowPart = local.dwLowDateTime;
5577: hund.HighPart = local.dwHighDateTime;
5578: hund.QuadPart += REG16(SI) * 100000;
5579: local.dwLowDateTime = hund.LowPart;
5580: local.dwHighDateTime = hund.HighPart;
5581: }
5582: LocalFileTimeToFileTime(&local, &time);
5583: if(!SetFileTime(hFile, REG8(BL) == 0x07 ? &time : NULL,
5584: REG8(BL) == 0x05 ? &time : NULL,
5585: REG8(BL) == 0x03 ? &time : NULL)) {
5586: REG16(AX) = (UINT16)GetLastError();
5587: m_CF = 1;
5588: }
5589: CloseHandle(hFile);
5590: } else {
5591: REG16(AX) = (UINT16)GetLastError();
5592: m_CF = 1;
1.1 root 5593: }
1.1.1.14 root 5594: }
5595: break;
5596: case 0x04:
5597: case 0x06:
5598: case 0x08:
5599: {
5600: WIN32_FILE_ATTRIBUTE_DATA fad;
5601: if(GetFileAttributesEx(path, GetFileExInfoStandard, (LPVOID)&fad)) {
5602: FILETIME *time, local;
5603: time = REG8(BL) == 0x04 ? &fad.ftLastWriteTime :
5604: 0x06 ? &fad.ftLastAccessTime :
5605: &fad.ftCreationTime;
5606: FileTimeToLocalFileTime(time, &local);
5607: FileTimeToDosDateTime(&local, ®16(DI), ®16(CX));
5608: if(REG8(BL) == 0x08) {
5609: ULARGE_INTEGER hund;
5610: hund.LowPart = local.dwLowDateTime;
5611: hund.HighPart = local.dwHighDateTime;
5612: hund.QuadPart /= 100000;
5613: REG16(SI) = (UINT16)(hund.QuadPart % 200);
5614: }
5615: } else {
5616: REG16(AX) = (UINT16)GetLastError();
5617: m_CF = 1;
1.1 root 5618: }
1.1.1.14 root 5619: }
5620: break;
5621: default:
5622: REG16(AX) = 0x01;
5623: m_CF = 1;
5624: break;
5625: }
5626: }
5627:
5628: inline void msdos_int_21h_44h()
5629: {
1.1.1.20 root 5630: process_t *process = msdos_process_info_get(current_psp);
5631: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
5632:
1.1.1.14 root 5633: UINT32 val = DRIVE_NO_ROOT_DIR;
5634:
5635: switch(REG8(AL)) {
5636: case 0x00:
5637: case 0x01:
5638: case 0x02:
5639: case 0x03:
5640: case 0x04:
5641: case 0x05:
5642: case 0x06:
5643: case 0x07:
1.1.1.20 root 5644: if(fd >= process->max_files || !file_handler[fd].valid) {
5645: REG16(AX) = 0x06;
5646: m_CF = 1;
5647: return;
1.1.1.14 root 5648: }
5649: break;
5650: case 0x08:
5651: case 0x09:
5652: if(REG8(BL) >= ('Z' - 'A' + 1)) {
5653: // invalid drive number
5654: REG16(AX) = 0x0f;
5655: m_CF = 1;
5656: return;
5657: } else {
5658: if(REG8(BL) == 0) {
5659: val = GetDriveType(NULL);
5660: } else {
5661: char tmp[8];
5662: sprintf(tmp, "%c:\\", 'A' + REG8(BL) - 1);
5663: val = GetDriveType(tmp);
5664: }
5665: if(val == DRIVE_NO_ROOT_DIR) {
5666: // no drive
5667: REG16(AX) = 0x0f;
5668: m_CF = 1;
5669: return;
1.1 root 5670: }
5671: }
5672: break;
5673: }
5674: switch(REG8(AL)) {
5675: case 0x00: // get ioctrl data
1.1.1.20 root 5676: REG16(DX) = file_handler[fd].info;
1.1 root 5677: break;
5678: case 0x01: // set ioctrl data
1.1.1.20 root 5679: file_handler[fd].info |= REG8(DL);
1.1 root 5680: break;
5681: case 0x02: // recv from character device
5682: case 0x03: // send to character device
5683: case 0x04: // recv from block device
5684: case 0x05: // send to block device
5685: REG16(AX) = 0x05;
1.1.1.3 root 5686: m_CF = 1;
1.1 root 5687: break;
5688: case 0x06: // get read status
1.1.1.20 root 5689: if(file_mode[file_handler[fd].mode].in) {
5690: if(file_handler[fd].atty) {
1.1.1.14 root 5691: REG8(AL) = msdos_kbhit() ? 0xff : 0x00;
1.1 root 5692: } else {
1.1.1.20 root 5693: REG8(AL) = eof(fd) ? 0x00 : 0xff;
1.1 root 5694: }
1.1.1.14 root 5695: } else {
5696: REG8(AL) = 0x00;
1.1 root 5697: }
5698: break;
5699: case 0x07: // get write status
1.1.1.20 root 5700: if(file_mode[file_handler[fd].mode].out) {
1.1.1.14 root 5701: REG8(AL) = 0xff;
5702: } else {
5703: REG8(AL) = 0x00;
1.1 root 5704: }
5705: break;
5706: case 0x08: // check removable drive
1.1.1.14 root 5707: if(val == DRIVE_REMOVABLE || val == DRIVE_CDROM) {
5708: // removable drive
5709: REG16(AX) = 0x00;
1.1 root 5710: } else {
1.1.1.14 root 5711: // fixed drive
5712: REG16(AX) = 0x01;
1.1 root 5713: }
5714: break;
5715: case 0x09: // check remote drive
1.1.1.14 root 5716: if(val == DRIVE_REMOTE) {
5717: // remote drive
5718: REG16(DX) = 0x1000;
1.1 root 5719: } else {
1.1.1.14 root 5720: // local drive
5721: REG16(DX) = 0x00;
1.1 root 5722: }
5723: break;
1.1.1.21! root 5724: case 0x0a: // check remote handle
! 5725: REG16(DX) = 0x00; // FIXME
! 5726: break;
1.1 root 5727: case 0x0b: // set retry count
5728: break;
5729: default:
5730: REG16(AX) = 0x01;
1.1.1.3 root 5731: m_CF = 1;
1.1 root 5732: break;
5733: }
5734: }
5735:
5736: inline void msdos_int_21h_45h()
5737: {
5738: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 5739: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 5740:
1.1.1.20 root 5741: if(fd < process->max_files && file_handler[fd].valid) {
5742: int dup_fd = _dup(fd);
5743: if(dup_fd != -1) {
5744: REG16(AX) = dup_fd;
5745: msdos_file_handler_dup(dup_fd, fd, current_psp);
5746: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
5747: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 5748: } else {
5749: REG16(AX) = errno;
1.1.1.3 root 5750: m_CF = 1;
1.1 root 5751: }
5752: } else {
5753: REG16(AX) = 0x06;
1.1.1.3 root 5754: m_CF = 1;
1.1 root 5755: }
5756: }
5757:
5758: inline void msdos_int_21h_46h()
5759: {
5760: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 5761: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
5762: int dup_fd = REG16(CX);
5763: int tmp_fd = msdos_psp_get_file_table(REG16(CX), current_psp);
1.1 root 5764:
1.1.1.20 root 5765: if(REG16(BX) == REG16(CX)) {
5766: REG16(AX) = 0x06;
5767: m_CF = 1;
5768: } else if(fd < process->max_files && file_handler[fd].valid && dup_fd < process->max_files) {
5769: if(tmp_fd < process->max_files && file_handler[tmp_fd].valid) {
5770: _close(tmp_fd);
5771: msdos_file_handler_close(tmp_fd);
5772: msdos_psp_set_file_table(dup_fd, 0x0ff, current_psp);
5773: }
5774: if(_dup2(fd, dup_fd) != -1) {
5775: msdos_file_handler_dup(dup_fd, fd, current_psp);
5776: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
5777: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 5778: } else {
5779: REG16(AX) = errno;
1.1.1.3 root 5780: m_CF = 1;
1.1 root 5781: }
5782: } else {
5783: REG16(AX) = 0x06;
1.1.1.3 root 5784: m_CF = 1;
1.1 root 5785: }
5786: }
5787:
5788: inline void msdos_int_21h_47h(int lfn)
5789: {
5790: char path[MAX_PATH];
5791:
5792: if(_getdcwd(REG8(DL), path, MAX_PATH) != NULL) {
5793: if(path[1] == ':') {
5794: // the returned path does not include a drive or the initial backslash
1.1.1.3 root 5795: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), (lfn ? path : msdos_short_path(path)) + 3);
1.1 root 5796: } else {
1.1.1.3 root 5797: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn ? path : msdos_short_path(path));
1.1 root 5798: }
5799: } else {
5800: REG16(AX) = errno;
1.1.1.3 root 5801: m_CF = 1;
1.1 root 5802: }
5803: }
5804:
5805: inline void msdos_int_21h_48h()
5806: {
1.1.1.19 root 5807: int seg, umb_linked;
1.1 root 5808:
1.1.1.8 root 5809: if((malloc_strategy & 0xf0) == 0x00) {
1.1.1.19 root 5810: // unlink umb not to allocate memory in umb
5811: if((umb_linked = msdos_mem_get_umb_linked()) != 0) {
5812: msdos_mem_unlink_umb();
5813: }
1.1.1.8 root 5814: if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
5815: REG16(AX) = seg;
5816: } else {
5817: REG16(AX) = 0x08;
5818: REG16(BX) = msdos_mem_get_free(first_mcb, 0);
5819: m_CF = 1;
5820: }
1.1.1.19 root 5821: if(umb_linked != 0) {
5822: msdos_mem_link_umb();
5823: }
1.1.1.8 root 5824: } else if((malloc_strategy & 0xf0) == 0x40) {
5825: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
5826: REG16(AX) = seg;
5827: } else {
5828: REG16(AX) = 0x08;
5829: REG16(BX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
5830: m_CF = 1;
5831: }
5832: } else if((malloc_strategy & 0xf0) == 0x80) {
5833: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
5834: REG16(AX) = seg;
5835: } else if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
5836: REG16(AX) = seg;
5837: } else {
5838: REG16(AX) = 0x08;
5839: REG16(BX) = max(msdos_mem_get_free(UMB_TOP >> 4, 0), msdos_mem_get_free(first_mcb, 0));
5840: m_CF = 1;
5841: }
1.1 root 5842: }
5843: }
5844:
5845: inline void msdos_int_21h_49h()
5846: {
1.1.1.14 root 5847: int mcb_seg = SREG(ES) - 1;
5848: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5849:
5850: if(mcb->mz == 'M' || mcb->mz == 'Z') {
5851: msdos_mem_free(SREG(ES));
5852: } else {
5853: REG16(AX) = 9;
5854: m_CF = 1;
5855: }
1.1 root 5856: }
5857:
5858: inline void msdos_int_21h_4ah()
5859: {
1.1.1.14 root 5860: int mcb_seg = SREG(ES) - 1;
5861: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1 root 5862: int max_paragraphs;
5863:
1.1.1.14 root 5864: if(mcb->mz == 'M' || mcb->mz == 'Z') {
5865: if(msdos_mem_realloc(SREG(ES), REG16(BX), &max_paragraphs)) {
5866: REG16(AX) = 0x08;
5867: REG16(BX) = max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs;
5868: m_CF = 1;
5869: }
5870: } else {
5871: REG16(AX) = 7;
1.1.1.3 root 5872: m_CF = 1;
1.1 root 5873: }
5874: }
5875:
5876: inline void msdos_int_21h_4bh()
5877: {
1.1.1.3 root 5878: char *command = (char *)(mem + SREG_BASE(DS) + REG16(DX));
5879: param_block_t *param = (param_block_t *)(mem + SREG_BASE(ES) + REG16(BX));
1.1 root 5880:
5881: switch(REG8(AL)) {
5882: case 0x00:
5883: case 0x01:
5884: if(msdos_process_exec(command, param, REG8(AL))) {
5885: REG16(AX) = 0x02;
1.1.1.3 root 5886: m_CF = 1;
1.1 root 5887: }
5888: break;
1.1.1.14 root 5889: case 0x03:
5890: {
5891: int fd;
5892: if((fd = _open(command, _O_RDONLY | _O_BINARY)) == -1) {
5893: REG16(AX) = 0x02;
5894: m_CF = 1;
5895: break;
5896: }
5897: int size = _read(fd, file_buffer, sizeof(file_buffer));
5898: _close(fd);
5899:
5900: UINT16 *overlay = (UINT16 *)param;
5901:
5902: // check exe header
5903: exe_header_t *header = (exe_header_t *)file_buffer;
5904: int header_size = 0;
5905: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
5906: header_size = header->header_size * 16;
5907: // relocation
5908: int start_seg = overlay[1];
5909: for(int i = 0; i < header->relocations; i++) {
5910: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
5911: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
5912: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
5913: }
5914: }
5915: memcpy(mem + (overlay[0] << 4), file_buffer + header_size, size - header_size);
5916: }
5917: break;
1.1 root 5918: default:
5919: REG16(AX) = 0x01;
1.1.1.3 root 5920: m_CF = 1;
1.1 root 5921: break;
5922: }
5923: }
5924:
5925: inline void msdos_int_21h_4ch()
5926: {
5927: msdos_process_terminate(current_psp, REG8(AL), 1);
5928: }
5929:
5930: inline void msdos_int_21h_4dh()
5931: {
5932: REG16(AX) = retval;
5933: }
5934:
5935: inline void msdos_int_21h_4eh()
5936: {
5937: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 5938: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5939: find_t *find = (find_t *)(mem + dta_laddr);
1.1.1.3 root 5940: char *path = msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 5941: WIN32_FIND_DATA fd;
5942:
1.1.1.14 root 5943: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
5944: find->find_magic = FIND_MAGIC;
5945: find->dta_index = dtainfo - dtalist;
1.1 root 5946: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 5947: dtainfo->allowable_mask = REG8(CL);
5948: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 5949:
1.1.1.14 root 5950: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
5951: dtainfo->allowable_mask &= ~8;
1.1 root 5952: }
1.1.1.14 root 5953: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
5954: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 5955: !msdos_find_file_has_8dot3name(&fd)) {
5956: if(!FindNextFile(dtainfo->find_handle, &fd)) {
5957: FindClose(dtainfo->find_handle);
5958: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 5959: break;
5960: }
5961: }
5962: }
1.1.1.13 root 5963: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 5964: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
5965: msdos_find_file_conv_local_time(&fd);
5966: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
5967: find->size = fd.nFileSizeLow;
1.1.1.13 root 5968: strcpy(find->name, msdos_short_name(&fd));
1.1 root 5969: REG16(AX) = 0;
1.1.1.14 root 5970: } else if(dtainfo->allowable_mask & 8) {
1.1 root 5971: find->attrib = 8;
5972: find->size = 0;
5973: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 5974: dtainfo->allowable_mask &= ~8;
1.1 root 5975: REG16(AX) = 0;
5976: } else {
5977: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 5978: m_CF = 1;
1.1 root 5979: }
5980: }
5981:
5982: inline void msdos_int_21h_4fh()
5983: {
5984: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 5985: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5986: find_t *find = (find_t *)(mem + dta_laddr);
1.1 root 5987: WIN32_FIND_DATA fd;
5988:
1.1.1.14 root 5989: if(find->find_magic != FIND_MAGIC || find->dta_index >= MAX_DTAINFO) {
5990: REG16(AX) = 0x12;
5991: m_CF = 1;
5992: return;
5993: }
5994: dtainfo_t *dtainfo = &dtalist[find->dta_index];
1.1.1.13 root 5995: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
5996: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 5997: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 5998: !msdos_find_file_has_8dot3name(&fd)) {
5999: if(!FindNextFile(dtainfo->find_handle, &fd)) {
6000: FindClose(dtainfo->find_handle);
6001: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6002: break;
6003: }
6004: }
6005: } else {
1.1.1.13 root 6006: FindClose(dtainfo->find_handle);
6007: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6008: }
6009: }
1.1.1.13 root 6010: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 6011: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
6012: msdos_find_file_conv_local_time(&fd);
6013: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
6014: find->size = fd.nFileSizeLow;
1.1.1.13 root 6015: strcpy(find->name, msdos_short_name(&fd));
1.1 root 6016: REG16(AX) = 0;
1.1.1.14 root 6017: } else if(dtainfo->allowable_mask & 8) {
1.1 root 6018: find->attrib = 8;
6019: find->size = 0;
6020: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 6021: dtainfo->allowable_mask &= ~8;
1.1 root 6022: REG16(AX) = 0;
6023: } else {
6024: REG16(AX) = 0x12;
1.1.1.3 root 6025: m_CF = 1;
1.1 root 6026: }
6027: }
6028:
6029: inline void msdos_int_21h_50h()
6030: {
1.1.1.8 root 6031: if(current_psp != REG16(BX)) {
6032: process_t *process = msdos_process_info_get(current_psp);
6033: if(process != NULL) {
6034: process->psp = REG16(BX);
6035: }
6036: current_psp = REG16(BX);
6037: }
1.1 root 6038: }
6039:
6040: inline void msdos_int_21h_51h()
6041: {
6042: REG16(BX) = current_psp;
6043: }
6044:
6045: inline void msdos_int_21h_52h()
6046: {
1.1.1.3 root 6047: SREG(ES) = (DOS_INFO_BASE >> 4);
6048: i386_load_segment_descriptor(ES);
1.1 root 6049: REG16(BX) = (DOS_INFO_BASE & 0x0f);
6050: }
6051:
6052: inline void msdos_int_21h_54h()
6053: {
6054: process_t *process = msdos_process_info_get(current_psp);
6055:
6056: REG8(AL) = process->verify;
6057: }
6058:
6059: inline void msdos_int_21h_55h()
6060: {
6061: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
6062:
6063: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
6064: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
6065: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
6066: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
6067: psp->parent_psp = current_psp;
6068: }
6069:
6070: inline void msdos_int_21h_56h(int lfn)
6071: {
6072: char src[MAX_PATH], dst[MAX_PATH];
1.1.1.3 root 6073: strcpy(src, msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn));
6074: strcpy(dst, msdos_trimmed_path((char *)(mem + SREG_BASE(ES) + REG16(DI)), lfn));
1.1 root 6075:
6076: if(rename(src, dst)) {
6077: REG16(AX) = errno;
1.1.1.3 root 6078: m_CF = 1;
1.1 root 6079: }
6080: }
6081:
6082: inline void msdos_int_21h_57h()
6083: {
6084: FILETIME time, local;
1.1.1.14 root 6085: FILETIME *ctime, *atime, *mtime;
1.1.1.21! root 6086: HANDLE hHandle;
1.1 root 6087:
1.1.1.21! root 6088: if((hHandle = (HANDLE)_get_osfhandle(REG16(BX))) == INVALID_HANDLE_VALUE) {
1.1.1.14 root 6089: REG16(AX) = (UINT16)GetLastError();
6090: m_CF = 1;
6091: return;
6092: }
6093: ctime = atime = mtime = NULL;
6094:
1.1 root 6095: switch(REG8(AL)) {
6096: case 0x00:
1.1.1.6 root 6097: case 0x01:
1.1.1.14 root 6098: mtime = &time;
1.1.1.6 root 6099: break;
6100: case 0x04:
6101: case 0x05:
1.1.1.14 root 6102: atime = &time;
1.1 root 6103: break;
1.1.1.6 root 6104: case 0x06:
6105: case 0x07:
1.1.1.14 root 6106: ctime = &time;
6107: break;
6108: default:
6109: REG16(AX) = 0x01;
6110: m_CF = 1;
6111: return;
6112: }
6113: if(REG8(AL) & 1) {
1.1 root 6114: DosDateTimeToFileTime(REG16(DX), REG16(CX), &local);
6115: LocalFileTimeToFileTime(&local, &time);
1.1.1.21! root 6116: if(!SetFileTime(hHandle, ctime, atime, mtime)) {
1.1 root 6117: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 6118: m_CF = 1;
1.1 root 6119: }
1.1.1.14 root 6120: } else {
1.1.1.21! root 6121: if(!GetFileTime(hHandle, ctime, atime, mtime)) {
1.1.1.14 root 6122: // assume a device and use the current time
6123: GetSystemTimeAsFileTime(&time);
6124: }
6125: FileTimeToLocalFileTime(&time, &local);
6126: FileTimeToDosDateTime(&local, ®16(DX), ®16(CX));
1.1 root 6127: }
6128: }
6129:
6130: inline void msdos_int_21h_58h()
6131: {
6132: switch(REG8(AL)) {
6133: case 0x00:
1.1.1.7 root 6134: REG16(AX) = malloc_strategy;
6135: break;
6136: case 0x01:
6137: switch(REG16(BX)) {
6138: case 0x0000:
6139: case 0x0001:
6140: case 0x0002:
6141: case 0x0040:
6142: case 0x0041:
6143: case 0x0042:
6144: case 0x0080:
6145: case 0x0081:
6146: case 0x0082:
6147: malloc_strategy = REG16(BX);
6148: break;
6149: default:
6150: REG16(AX) = 0x01;
6151: m_CF = 1;
6152: break;
6153: }
6154: break;
6155: case 0x02:
1.1.1.19 root 6156: REG8(AL) = msdos_mem_get_umb_linked() ? 1 : 0;
1.1.1.7 root 6157: break;
6158: case 0x03:
6159: switch(REG16(BX)) {
6160: case 0x0000:
1.1.1.19 root 6161: msdos_mem_unlink_umb();
6162: break;
1.1.1.7 root 6163: case 0x0001:
1.1.1.19 root 6164: msdos_mem_link_umb();
1.1.1.7 root 6165: break;
6166: default:
6167: REG16(AX) = 0x01;
6168: m_CF = 1;
6169: break;
6170: }
1.1 root 6171: break;
6172: default:
6173: REG16(AX) = 0x01;
1.1.1.3 root 6174: m_CF = 1;
1.1 root 6175: break;
6176: }
6177: }
6178:
6179: inline void msdos_int_21h_59h()
6180: {
6181: REG16(AX) = error_code;
6182: switch(error_code) {
6183: case 4: // Too many open files
6184: case 8: // Insufficient memory
6185: REG8(BH) = 1; // Out of resource
6186: break;
6187: case 5: // Access denied
6188: REG8(BH) = 3; // Authorization
6189: break;
6190: case 7: // Memory control block destroyed
6191: REG8(BH) = 4; // Internal
6192: break;
6193: case 2: // File not found
6194: case 3: // Path not found
6195: case 15: // Invaid drive specified
6196: case 18: // No more files
6197: REG8(BH) = 8; // Not found
6198: break;
6199: case 32: // Sharing violation
6200: case 33: // Lock violation
6201: REG8(BH) = 10; // Locked
6202: break;
6203: // case 16: // Removal of current directory attempted
6204: case 19: // Attempted write on protected disk
6205: case 21: // Drive not ready
6206: // case 29: // Write failure
6207: // case 30: // Read failure
6208: // case 82: // Cannot create subdirectory
6209: REG8(BH) = 11; // Media
6210: break;
6211: case 80: // File already exists
6212: REG8(BH) = 12; // Already exist
6213: break;
6214: default:
6215: REG8(BH) = 13; // Unknown
6216: break;
6217: }
6218: REG8(BL) = 1; // Retry
6219: REG8(CH) = 1; // Unknown
6220: }
6221:
6222: inline void msdos_int_21h_5ah()
6223: {
1.1.1.3 root 6224: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 6225: int len = strlen(path);
6226: char tmp[MAX_PATH];
6227:
6228: if(GetTempFileName(path, "TMP", 0, tmp)) {
6229: int fd = _open(tmp, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
6230:
6231: SetFileAttributes(tmp, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
6232: REG16(AX) = fd;
6233: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 6234: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 6235:
6236: strcpy(path, tmp);
6237: int dx = REG16(DX) + len;
1.1.1.3 root 6238: int ds = SREG(DS);
1.1 root 6239: while(dx > 0xffff) {
6240: dx -= 0x10;
6241: ds++;
6242: }
6243: REG16(DX) = dx;
1.1.1.3 root 6244: SREG(DS) = ds;
6245: i386_load_segment_descriptor(DS);
1.1 root 6246: } else {
6247: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 6248: m_CF = 1;
1.1 root 6249: }
6250: }
6251:
6252: inline void msdos_int_21h_5bh()
6253: {
1.1.1.3 root 6254: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 6255:
6256: if(_access(path, 0) == 0) {
6257: // already exists
6258: REG16(AX) = 0x50;
1.1.1.3 root 6259: m_CF = 1;
1.1 root 6260: } else {
6261: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
6262:
6263: if(fd != -1) {
6264: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
6265: REG16(AX) = fd;
6266: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 6267: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 6268: } else {
6269: REG16(AX) = errno;
1.1.1.3 root 6270: m_CF = 1;
1.1 root 6271: }
6272: }
6273: }
6274:
6275: inline void msdos_int_21h_5ch()
6276: {
6277: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 6278: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 6279:
1.1.1.20 root 6280: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 6281: if(REG8(AL) == 0 || REG8(AL) == 1) {
6282: static int modes[2] = {_LK_LOCK, _LK_UNLCK};
1.1.1.20 root 6283: UINT32 pos = _tell(fd);
6284: _lseek(fd, (REG16(CX) << 16) | REG16(DX), SEEK_SET);
6285: if(_locking(fd, modes[REG8(AL)], (REG16(SI) << 16) | REG16(DI))) {
1.1 root 6286: REG16(AX) = errno;
1.1.1.3 root 6287: m_CF = 1;
1.1 root 6288: }
1.1.1.20 root 6289: _lseek(fd, pos, SEEK_SET);
1.1 root 6290: // some seconds may be passed in _locking()
6291: hardware_update();
6292: } else {
6293: REG16(AX) = 0x01;
1.1.1.3 root 6294: m_CF = 1;
1.1 root 6295: }
6296: } else {
6297: REG16(AX) = 0x06;
1.1.1.3 root 6298: m_CF = 1;
1.1 root 6299: }
6300: }
6301:
6302: inline void msdos_int_21h_60h(int lfn)
6303: {
1.1.1.14 root 6304: char full[MAX_PATH], *path;
6305:
1.1 root 6306: if(lfn) {
1.1.1.14 root 6307: char *name;
6308: *full = '\0';
1.1.1.3 root 6309: GetFullPathName((char *)(mem + SREG_BASE(DS) + REG16(SI)), MAX_PATH, full, &name);
1.1.1.14 root 6310: switch(REG8(CL)) {
6311: case 1:
6312: GetShortPathName(full, full, MAX_PATH);
6313: my_strupr(full);
6314: break;
6315: case 2:
6316: GetLongPathName(full, full, MAX_PATH);
6317: break;
6318: }
6319: path = full;
6320: } else {
6321: path = msdos_short_full_path((char *)(mem + SREG_BASE(DS) + REG16(SI)));
6322: }
6323: if(*path != '\0') {
6324: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path);
1.1 root 6325: } else {
1.1.1.14 root 6326: REG16(AX) = (UINT16)GetLastError();
6327: m_CF = 1;
1.1 root 6328: }
6329: }
6330:
6331: inline void msdos_int_21h_61h()
6332: {
6333: REG8(AL) = 0;
6334: }
6335:
6336: inline void msdos_int_21h_62h()
6337: {
6338: REG16(BX) = current_psp;
6339: }
6340:
6341: inline void msdos_int_21h_63h()
6342: {
6343: switch(REG8(AL)) {
6344: case 0x00:
1.1.1.3 root 6345: SREG(DS) = (DBCS_TABLE >> 4);
6346: i386_load_segment_descriptor(DS);
1.1 root 6347: REG16(SI) = (DBCS_TABLE & 0x0f);
6348: REG8(AL) = 0x00;
6349: break;
6350: default:
6351: REG16(AX) = 0x01;
1.1.1.3 root 6352: m_CF = 1;
1.1 root 6353: break;
6354: }
6355: }
6356:
6357: inline void msdos_int_21h_65h()
6358: {
6359: char tmp[0x10000];
6360:
6361: switch(REG8(AL)) {
1.1.1.17 root 6362: case 0x01:
6363: if(REG16(CX) >= 5) {
1.1.1.19 root 6364: UINT8 data[1 + 2 + 2 + 2 + sizeof(country_info_t)];
1.1.1.17 root 6365: if(REG16(CX) > sizeof(data)) // cx = actual transfer size
6366: REG16(CX) = sizeof(data);
6367: ZeroMemory(data, sizeof(data));
6368: data[0] = 0x01;
6369: *(UINT16 *)(data + 1) = REG16(CX) - 3;
1.1.1.19 root 6370: *(UINT16 *)(data + 3) = get_country_info((country_info_t*)(data + 7));
1.1.1.17 root 6371: *(UINT16 *)(data + 5) = active_code_page;
6372: memcpy(mem + SREG_BASE(ES) + REG16(DI), data, REG16(CX));
6373: REG16(AX) = active_code_page;
6374: } else {
6375: REG16(AX) = 1;
6376: m_CF = 1;
6377: }
6378: break;
6379: case 0x02:
6380: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
6381: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (UPPERTABLE_TOP & 0x0f);
6382: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (UPPERTABLE_TOP >> 4);
6383: REG16(AX) = active_code_page;
6384: REG16(CX) = 0x05;
6385: break;
6386: case 0x04:
6387: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x04;
6388: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_UPPERTABLE_TOP & 0x0f);
6389: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_UPPERTABLE_TOP >> 4);
6390: REG16(AX) = active_code_page;
6391: REG16(CX) = 0x05;
6392: break;
6393: case 0x05:
6394: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x05;
6395: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_TERMINATOR_TOP & 0x0f);
6396: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_TERMINATOR_TOP >> 4);
6397: REG16(AX) = active_code_page;
6398: REG16(CX) = 0x05;
6399: break;
6400: case 0x06:
6401: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x06;
6402: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (COLLATING_TABLE_TOP & 0x0f);
6403: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (COLLATING_TABLE_TOP >> 4);
6404: REG16(AX) = active_code_page;
6405: REG16(CX) = 0x05;
6406: break;
1.1 root 6407: case 0x07:
1.1.1.3 root 6408: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x07;
6409: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (DBCS_TOP & 0x0f);
6410: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (DBCS_TOP >> 4);
1.1.1.17 root 6411: REG16(AX) = active_code_page;
1.1 root 6412: REG16(CX) = 0x05;
6413: break;
6414: case 0x20:
1.1.1.19 root 6415: memset(tmp, 0, sizeof(tmp));
6416: tmp[0] = REG8(DL);
1.1 root 6417: my_strupr(tmp);
6418: REG8(DL) = tmp[0];
6419: break;
6420: case 0x21:
6421: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 6422: memcpy(tmp, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 6423: my_strupr(tmp);
1.1.1.3 root 6424: memcpy(mem + SREG_BASE(DS) + REG16(DX), tmp, REG16(CX));
1.1 root 6425: break;
6426: case 0x22:
1.1.1.3 root 6427: my_strupr((char *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1 root 6428: break;
6429: default:
6430: REG16(AX) = 0x01;
1.1.1.3 root 6431: m_CF = 1;
1.1 root 6432: break;
6433: }
6434: }
6435:
6436: inline void msdos_int_21h_66h()
6437: {
6438: switch(REG8(AL)) {
6439: case 0x01:
6440: REG16(BX) = active_code_page;
6441: REG16(DX) = system_code_page;
6442: break;
6443: case 0x02:
6444: if(active_code_page == REG16(BX)) {
6445: REG16(AX) = 0xeb41;
6446: } else if(_setmbcp(REG16(BX)) == 0) {
6447: active_code_page = REG16(BX);
1.1.1.17 root 6448: msdos_nls_tables_update();
1.1 root 6449: REG16(AX) = 0xeb41;
6450: } else {
6451: REG16(AX) = 0x25;
1.1.1.3 root 6452: m_CF = 1;
1.1 root 6453: }
6454: break;
6455: default:
6456: REG16(AX) = 0x01;
1.1.1.3 root 6457: m_CF = 1;
1.1 root 6458: break;
6459: }
6460: }
6461:
6462: inline void msdos_int_21h_67h()
6463: {
6464: process_t *process = msdos_process_info_get(current_psp);
6465:
6466: if(REG16(BX) <= MAX_FILES) {
6467: process->max_files = max(REG16(BX), 20);
6468: } else {
6469: REG16(AX) = 0x08;
1.1.1.3 root 6470: m_CF = 1;
1.1 root 6471: }
6472: }
6473:
6474: inline void msdos_int_21h_68h()
6475: {
6476: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 6477: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 6478:
1.1.1.20 root 6479: if(fd < process->max_files && file_handler[fd].valid) {
6480: // fflush(_fdopen(fd, ""));
1.1 root 6481: } else {
6482: REG16(AX) = 0x06;
1.1.1.3 root 6483: m_CF = 1;
1.1 root 6484: }
6485: }
6486:
6487: inline void msdos_int_21h_69h()
6488: {
1.1.1.3 root 6489: drive_info_t *info = (drive_info_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 6490: char path[] = "A:\\";
6491: char volume_label[MAX_PATH];
6492: DWORD serial_number = 0;
6493: char file_system[MAX_PATH];
6494:
6495: if(REG8(BL) == 0) {
6496: path[0] = 'A' + _getdrive() - 1;
6497: } else {
6498: path[0] = 'A' + REG8(BL) - 1;
6499: }
6500:
6501: switch(REG8(AL)) {
6502: case 0x00:
6503: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
6504: info->info_level = 0;
6505: info->serial_number = serial_number;
6506: memset(info->volume_label, 0x20, 11);
6507: memcpy(info->volume_label, volume_label, min(strlen(volume_label), 11));
6508: memset(info->file_system, 0x20, 8);
6509: memcpy(info->file_system, file_system, min(strlen(file_system), 8));
6510: } else {
6511: REG16(AX) = errno;
1.1.1.3 root 6512: m_CF = 1;
1.1 root 6513: }
6514: break;
6515: case 0x01:
6516: REG16(AX) = 0x03;
1.1.1.3 root 6517: m_CF = 1;
1.1 root 6518: }
6519: }
6520:
6521: inline void msdos_int_21h_6ah()
6522: {
6523: REG8(AH) = 0x68;
6524: msdos_int_21h_68h();
6525: }
6526:
6527: inline void msdos_int_21h_6bh()
6528: {
6529: REG8(AL) = 0;
6530: }
6531:
6532: inline void msdos_int_21h_6ch(int lfn)
6533: {
1.1.1.3 root 6534: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn);
1.1 root 6535: int mode = REG8(BL) & 0x03;
6536:
6537: if(mode < 0x03) {
1.1.1.20 root 6538: if(_access(path, 0) == 0 || strncmp(path, "EMMXXXX0", 8) == 0) {
1.1 root 6539: // file exists
6540: if(REG8(DL) & 1) {
1.1.1.11 root 6541: int fd = -1;
6542: UINT16 info;
1.1 root 6543:
1.1.1.11 root 6544: if(msdos_is_con_path(path)) {
1.1.1.13 root 6545: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 6546: info = 0x80d3;
1.1.1.14 root 6547: } else if(msdos_is_nul_path(path)) {
6548: fd = msdos_open("NUL", file_mode[mode].mode);
6549: info = 0x80d3;
1.1.1.20 root 6550: } else if(strncmp(path, "EMMXXXX0", 8) == 0) {
6551: fd = msdos_open("NUL", file_mode[mode].mode);
6552: info = 0x80d3;
1.1.1.11 root 6553: } else {
1.1.1.13 root 6554: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 6555: info = msdos_drive_number(path);
6556: }
1.1 root 6557: if(fd != -1) {
6558: REG16(AX) = fd;
6559: REG16(CX) = 1;
1.1.1.11 root 6560: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp);
1.1.1.20 root 6561: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 6562: } else {
6563: REG16(AX) = errno;
1.1.1.3 root 6564: m_CF = 1;
1.1 root 6565: }
6566: } else if(REG8(DL) & 2) {
6567: int attr = GetFileAttributes(path);
6568: int fd = -1;
1.1.1.11 root 6569: UINT16 info;
1.1 root 6570:
1.1.1.11 root 6571: if(msdos_is_con_path(path)) {
1.1.1.13 root 6572: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 6573: info = 0x80d3;
1.1.1.14 root 6574: } else if(msdos_is_nul_path(path)) {
6575: fd = msdos_open("NUL", file_mode[mode].mode);
6576: info = 0x80d3;
1.1.1.20 root 6577: } else if(strncmp(path, "EMMXXXX0", 8) == 0) {
6578: fd = msdos_open("NUL", file_mode[mode].mode);
6579: info = 0x80d3;
1.1 root 6580: } else {
6581: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 6582: info = msdos_drive_number(path);
1.1 root 6583: }
6584: if(fd != -1) {
6585: if(attr == -1) {
6586: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
6587: }
6588: SetFileAttributes(path, attr);
6589: REG16(AX) = fd;
6590: REG16(CX) = 3;
1.1.1.11 root 6591: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp);
1.1.1.20 root 6592: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 6593: } else {
6594: REG16(AX) = errno;
1.1.1.3 root 6595: m_CF = 1;
1.1 root 6596: }
6597: } else {
6598: REG16(AX) = 0x50;
1.1.1.3 root 6599: m_CF = 1;
1.1 root 6600: }
6601: } else {
6602: // file not exists
6603: if(REG8(DL) & 0x10) {
6604: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
6605:
6606: if(fd != -1) {
6607: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
6608: REG16(AX) = fd;
6609: REG16(CX) = 2;
6610: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 6611: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 6612: } else {
6613: REG16(AX) = errno;
1.1.1.3 root 6614: m_CF = 1;
1.1 root 6615: }
6616: } else {
6617: REG16(AX) = 0x02;
1.1.1.3 root 6618: m_CF = 1;
1.1 root 6619: }
6620: }
6621: } else {
6622: REG16(AX) = 0x0c;
1.1.1.3 root 6623: m_CF = 1;
1.1 root 6624: }
6625: }
6626:
6627: inline void msdos_int_21h_710dh()
6628: {
6629: // reset drive
6630: }
6631:
1.1.1.17 root 6632: inline void msdos_int_21h_7141h(int lfn)
6633: {
6634: if(REG16(SI) == 0) {
6635: msdos_int_21h_41h(lfn);
6636: return;
6637: }
6638: if(REG16(SI) != 1) {
6639: REG16(AX) = 5;
6640: m_CF = 1;
6641: }
6642: /* wild card and matching attributes... */
6643: char tmp[MAX_PATH * 2];
6644: // copy search pathname (and quick check overrun)
6645: ZeroMemory(tmp, sizeof(tmp));
6646: tmp[MAX_PATH - 1] = '\0';
6647: tmp[MAX_PATH] = 1;
6648: strncpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(DX)), MAX_PATH);
6649:
6650: if(tmp[MAX_PATH - 1] != '\0' || tmp[MAX_PATH] != 1) {
6651: REG16(AX) = 1;
6652: m_CF = 1;
6653: return;
6654: }
6655: for(char *s = tmp; *s; ++s) {
6656: if(*s == '/') {
6657: *s = '\\';
6658: }
6659: }
6660: char *tmp_name = (char *)_mbsrchr((unsigned char *)tmp, '\\');
6661: if(tmp_name) {
6662: ++tmp_name;
6663: } else {
6664: tmp_name = strchr(tmp, ':');
6665: tmp_name = tmp_name ? tmp_name + 1 : tmp;
6666: }
6667:
6668: WIN32_FIND_DATAA fd;
6669: HANDLE fh = FindFirstFileA(tmp, &fd);
6670: if(fh == INVALID_HANDLE_VALUE) {
6671: REG16(AX) = 2;
6672: m_CF = 1;
6673: return;
6674: }
6675: do {
6676: if(msdos_find_file_check_attribute(fd.dwFileAttributes, REG8(CL), REG8(CH)) && msdos_find_file_has_8dot3name(&fd)) {
6677: strcpy(tmp_name, fd.cFileName);
6678: if(remove(msdos_trimmed_path(tmp, lfn))) {
6679: REG16(AX) = 5;
6680: m_CF = 1;
6681: break;
6682: }
6683: }
6684: } while(FindNextFileA(fh, &fd));
6685: if(!m_CF) {
6686: if(GetLastError() != ERROR_NO_MORE_FILES) {
6687: m_CF = 1;
6688: REG16(AX) = 2;
6689: }
6690: }
6691: FindClose(fh);
6692: }
6693:
1.1 root 6694: inline void msdos_int_21h_714eh()
6695: {
6696: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 6697: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
6698: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 6699: WIN32_FIND_DATA fd;
6700:
1.1.1.13 root 6701: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
6702: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
6703: FindClose(dtainfo->find_handle);
6704: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6705: }
6706: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 6707: dtainfo->allowable_mask = REG8(CL);
6708: dtainfo->required_mask = REG8(CH);
6709: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 6710:
1.1.1.14 root 6711: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
6712: dtainfo->allowable_mask &= ~8;
1.1 root 6713: }
1.1.1.14 root 6714: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
6715: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 6716: if(!FindNextFile(dtainfo->find_handle, &fd)) {
6717: FindClose(dtainfo->find_handle);
6718: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6719: break;
6720: }
6721: }
6722: }
1.1.1.13 root 6723: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 6724: find->attrib = fd.dwFileAttributes;
6725: msdos_find_file_conv_local_time(&fd);
6726: if(REG16(SI) == 0) {
6727: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
6728: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
6729: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
6730: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
6731: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
6732: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
6733: } else {
6734: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
6735: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
6736: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
6737: }
6738: find->size_hi = fd.nFileSizeHigh;
6739: find->size_lo = fd.nFileSizeLow;
6740: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 6741: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 6742: REG16(AX) = dtainfo - dtalist + 1;
6743: } else if(dtainfo->allowable_mask & 8) {
1.1 root 6744: // volume label
6745: find->attrib = 8;
6746: find->size_hi = find->size_lo = 0;
6747: strcpy(find->full_name, process->volume_label);
6748: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 6749: dtainfo->allowable_mask &= ~8;
6750: REG16(AX) = dtainfo - dtalist + 1;
1.1 root 6751: } else {
6752: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 6753: m_CF = 1;
1.1 root 6754: }
6755: }
6756:
6757: inline void msdos_int_21h_714fh()
6758: {
6759: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 6760: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 6761: WIN32_FIND_DATA fd;
6762:
1.1.1.14 root 6763: if(REG16(BX) - 1u >= MAX_DTAINFO) {
6764: REG16(AX) = 6;
1.1.1.13 root 6765: m_CF = 1;
6766: return;
6767: }
1.1.1.14 root 6768: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 6769: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
6770: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 6771: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 6772: if(!FindNextFile(dtainfo->find_handle, &fd)) {
6773: FindClose(dtainfo->find_handle);
6774: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6775: break;
6776: }
6777: }
6778: } else {
1.1.1.13 root 6779: FindClose(dtainfo->find_handle);
6780: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6781: }
6782: }
1.1.1.13 root 6783: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 6784: find->attrib = fd.dwFileAttributes;
6785: msdos_find_file_conv_local_time(&fd);
6786: if(REG16(SI) == 0) {
6787: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
6788: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
6789: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
6790: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
6791: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
6792: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
6793: } else {
6794: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
6795: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
6796: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
6797: }
6798: find->size_hi = fd.nFileSizeHigh;
6799: find->size_lo = fd.nFileSizeLow;
6800: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 6801: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 6802: } else if(dtainfo->allowable_mask & 8) {
1.1 root 6803: // volume label
6804: find->attrib = 8;
6805: find->size_hi = find->size_lo = 0;
6806: strcpy(find->full_name, process->volume_label);
6807: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 6808: dtainfo->allowable_mask &= ~8;
1.1 root 6809: } else {
6810: REG16(AX) = 0x12;
1.1.1.3 root 6811: m_CF = 1;
1.1 root 6812: }
6813: }
6814:
6815: inline void msdos_int_21h_71a0h()
6816: {
6817: DWORD max_component_len, file_sys_flag;
6818:
1.1.1.14 root 6819: 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))) {
6820: REG16(BX) = (UINT16)file_sys_flag & (FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_VOLUME_IS_COMPRESSED);
6821: REG16(BX) |= 0x4000; // supports LFN functions
1.1 root 6822: REG16(CX) = (UINT16)max_component_len; // 255
6823: REG16(DX) = (UINT16)max_component_len + 5; // 260
6824: } else {
6825: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 6826: m_CF = 1;
1.1 root 6827: }
6828: }
6829:
6830: inline void msdos_int_21h_71a1h()
6831: {
1.1.1.14 root 6832: if(REG16(BX) - 1u >= MAX_DTAINFO) {
6833: REG16(AX) = 6;
1.1.1.13 root 6834: m_CF = 1;
6835: return;
6836: }
1.1.1.14 root 6837: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 6838: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
6839: FindClose(dtainfo->find_handle);
6840: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6841: }
6842: }
6843:
6844: inline void msdos_int_21h_71a6h()
6845: {
6846: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 6847: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
6848:
1.1.1.3 root 6849: UINT8 *buffer = (UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 6850: struct _stat64 status;
6851: DWORD serial_number = 0;
6852:
1.1.1.20 root 6853: if(fd < process->max_files && file_handler[fd].valid) {
6854: if(_fstat64(fd, &status) == 0) {
6855: if(file_handler[fd].path[1] == ':') {
1.1 root 6856: // NOTE: we need to consider the network file path "\\host\share\"
6857: char volume[] = "A:\\";
1.1.1.20 root 6858: volume[0] = file_handler[fd].path[1];
1.1 root 6859: GetVolumeInformation(volume, NULL, 0, &serial_number, NULL, NULL, NULL, 0);
6860: }
1.1.1.20 root 6861: *(UINT32 *)(buffer + 0x00) = GetFileAttributes(file_handler[fd].path);
1.1 root 6862: *(UINT32 *)(buffer + 0x04) = (UINT32)(status.st_ctime & 0xffffffff);
6863: *(UINT32 *)(buffer + 0x08) = (UINT32)((status.st_ctime >> 32) & 0xffffffff);
6864: *(UINT32 *)(buffer + 0x0c) = (UINT32)(status.st_atime & 0xffffffff);
6865: *(UINT32 *)(buffer + 0x10) = (UINT32)((status.st_atime >> 32) & 0xffffffff);
6866: *(UINT32 *)(buffer + 0x14) = (UINT32)(status.st_mtime & 0xffffffff);
6867: *(UINT32 *)(buffer + 0x18) = (UINT32)((status.st_mtime >> 32) & 0xffffffff);
6868: *(UINT32 *)(buffer + 0x1c) = serial_number;
6869: *(UINT32 *)(buffer + 0x20) = (UINT32)((status.st_size >> 32) & 0xffffffff);
6870: *(UINT32 *)(buffer + 0x24) = (UINT32)(status.st_size & 0xffffffff);
6871: *(UINT32 *)(buffer + 0x28) = status.st_nlink;
1.1.1.14 root 6872: // this is dummy id and it will be changed when it is reopened...
1.1 root 6873: *(UINT32 *)(buffer + 0x2c) = 0;
1.1.1.20 root 6874: *(UINT32 *)(buffer + 0x30) = file_handler[fd].id;
1.1 root 6875: } else {
6876: REG16(AX) = errno;
1.1.1.3 root 6877: m_CF = 1;
1.1 root 6878: }
6879: } else {
6880: REG16(AX) = 0x06;
1.1.1.3 root 6881: m_CF = 1;
1.1 root 6882: }
6883: }
6884:
6885: inline void msdos_int_21h_71a7h()
6886: {
6887: switch(REG8(BL)) {
6888: case 0x00:
1.1.1.3 root 6889: if(!FileTimeToDosDateTime((FILETIME *)(mem + SREG_BASE(DS) + REG16(SI)), ®16(DX), ®16(CX))) {
1.1 root 6890: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 6891: m_CF = 1;
1.1 root 6892: }
6893: break;
6894: case 0x01:
6895: // NOTE: we need to check BH that shows 10-millisecond untils past time in CX
1.1.1.3 root 6896: if(!DosDateTimeToFileTime(REG16(DX), REG16(CX), (FILETIME *)(mem + SREG_BASE(ES) + REG16(DI)))) {
1.1 root 6897: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 6898: m_CF = 1;
1.1 root 6899: }
6900: break;
6901: default:
6902: REG16(AX) = 0x01;
1.1.1.3 root 6903: m_CF = 1;
1.1 root 6904: break;
6905: }
6906: }
6907:
6908: inline void msdos_int_21h_71a8h()
6909: {
6910: if(REG8(DH) == 0) {
6911: char tmp[MAX_PATH], fcb[MAX_PATH];
1.1.1.3 root 6912: strcpy(tmp, msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 6913: memset(fcb, 0x20, sizeof(fcb));
6914: int len = strlen(tmp);
1.1.1.21! root 6915: for(int i = 0, pos = 0; i < len; i++) {
1.1 root 6916: if(tmp[i] == '.') {
6917: pos = 8;
6918: } else {
6919: if(msdos_lead_byte_check(tmp[i])) {
6920: fcb[pos++] = tmp[i++];
6921: }
6922: fcb[pos++] = tmp[i];
6923: }
6924: }
1.1.1.3 root 6925: memcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), fcb, 11);
1.1 root 6926: } else {
1.1.1.3 root 6927: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 6928: }
6929: }
6930:
1.1.1.14 root 6931: inline void msdos_int_21h_7300h()
6932: {
6933: if(REG8(AL) == 0) {
6934: REG8(AL) = REG8(CL);
6935: REG8(AH) = 0;
6936: } else {
6937: REG16(AX) = 0x01;
6938: m_CF = 1;
6939: }
6940: }
6941:
6942: inline void msdos_int_21h_7302h()
6943: {
6944: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
6945: UINT16 seg, ofs;
6946:
6947: if(REG16(CX) < 0x3f) {
6948: REG8(AL) = 0x18;
6949: m_CF = 1;
6950: } else if(!msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
6951: REG8(AL) = 0xff;
6952: m_CF = 1;
6953: } else {
6954: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 2, mem + (seg << 4) + ofs, sizeof(dpb_t));
6955: }
6956: }
6957:
1.1 root 6958: inline void msdos_int_21h_7303h()
6959: {
1.1.1.3 root 6960: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
6961: ext_space_info_t *info = (ext_space_info_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 6962: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
6963:
6964: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
6965: info->size_of_structure = sizeof(ext_space_info_t);
6966: info->structure_version = 0;
6967: info->sectors_per_cluster = sectors_per_cluster;
6968: info->bytes_per_sector = bytes_per_sector;
6969: info->available_clusters_on_drive = free_clusters;
6970: info->total_clusters_on_drive = total_clusters;
6971: info->available_sectors_on_drive = sectors_per_cluster * free_clusters;
6972: info->total_sectors_on_drive = sectors_per_cluster * total_clusters;
6973: info->available_allocation_units = free_clusters; // ???
6974: info->total_allocation_units = total_clusters; // ???
6975: } else {
6976: REG16(AX) = errno;
1.1.1.3 root 6977: m_CF = 1;
1.1 root 6978: }
6979: }
6980:
6981: inline void msdos_int_25h()
6982: {
6983: UINT16 seg, ofs;
6984: DWORD dwSize;
6985:
1.1.1.3 root 6986: #if defined(HAS_I386)
6987: I386OP(pushf)();
6988: #else
6989: PREFIX86(_pushf());
6990: #endif
1.1 root 6991:
6992: if(!(REG8(AL) < 26)) {
6993: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 6994: m_CF = 1;
1.1 root 6995: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
6996: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 6997: m_CF = 1;
1.1 root 6998: } else {
6999: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
7000: char dev[64];
7001: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
7002:
7003: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
7004: if(hFile == INVALID_HANDLE_VALUE) {
7005: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 7006: m_CF = 1;
1.1 root 7007: } else {
1.1.1.19 root 7008: UINT32 top_sector = REG16(DX);
7009: UINT16 sector_num = REG16(CX);
7010: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
7011:
7012: if(sector_num == 0xffff) {
7013: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
7014: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
7015: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
7016: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
7017: buffer_addr = (seg << 4) + ofs;
7018: }
7019: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
7020: // REG8(AL) = 0x02; // drive not ready
7021: // m_CF = 1;
7022: // } else
7023: if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 7024: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 7025: m_CF = 1;
1.1.1.19 root 7026: } else if(ReadFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 7027: REG8(AL) = 0x0b; // read error
1.1.1.3 root 7028: m_CF = 1;
1.1 root 7029: }
7030: CloseHandle(hFile);
7031: }
7032: }
7033: }
7034:
7035: inline void msdos_int_26h()
7036: {
7037: // this operation may cause serious damage for drives, so always returns error...
7038: UINT16 seg, ofs;
7039: DWORD dwSize;
7040:
1.1.1.3 root 7041: #if defined(HAS_I386)
7042: I386OP(pushf)();
7043: #else
7044: PREFIX86(_pushf());
7045: #endif
1.1 root 7046:
7047: if(!(REG8(AL) < 26)) {
7048: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 7049: m_CF = 1;
1.1 root 7050: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
7051: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 7052: m_CF = 1;
1.1 root 7053: } else {
7054: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
7055: char dev[64];
7056: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
7057:
7058: if(dpb->media_type == 0xf8) {
7059: // this drive is not a floppy
1.1.1.6 root 7060: // if(!(((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag & 0x40)) {
7061: // fatalerror("This application tried the absolute disk write to drive %c:\n", 'A' + REG8(AL));
7062: // }
1.1 root 7063: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 7064: m_CF = 1;
1.1 root 7065: } else {
7066: HANDLE hFile = CreateFile(dev, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
7067: if(hFile == INVALID_HANDLE_VALUE) {
7068: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 7069: m_CF = 1;
1.1 root 7070: } else {
1.1.1.19 root 7071: UINT32 top_sector = REG16(DX);
7072: UINT16 sector_num = REG16(CX);
7073: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
7074:
7075: if(sector_num == 0xffff) {
7076: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
7077: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
7078: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
7079: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
7080: buffer_addr = (seg << 4) + ofs;
7081: }
1.1 root 7082: if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
7083: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 7084: m_CF = 1;
1.1.1.19 root 7085: } else if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 7086: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 7087: m_CF = 1;
1.1.1.19 root 7088: } else if(WriteFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 7089: REG8(AL) = 0x0a; // write error
1.1.1.3 root 7090: m_CF = 1;
1.1 root 7091: }
7092: CloseHandle(hFile);
7093: }
7094: }
7095: }
7096: }
7097:
7098: inline void msdos_int_27h()
7099: {
1.1.1.14 root 7100: msdos_mem_realloc(SREG(CS), (REG16(DX) + 15) >> 4, NULL);
1.1.1.3 root 7101: msdos_process_terminate(SREG(CS), retval | 0x300, 0);
1.1.1.14 root 7102:
7103: // int_21h_4bh succeeded
7104: m_CF = 0;
1.1 root 7105: }
7106:
7107: inline void msdos_int_29h()
7108: {
1.1.1.14 root 7109: #if 1
7110: // need to check escape sequences
1.1 root 7111: msdos_putch(REG8(AL));
1.1.1.14 root 7112: #else
7113: DWORD num;
7114:
7115: vram_flush();
7116: WriteConsole(hStdout, ®8(AL), 1, &num, NULL);
7117: cursor_moved = true;
7118: #endif
1.1 root 7119: }
7120:
7121: inline void msdos_int_2eh()
7122: {
7123: char tmp[MAX_PATH], command[MAX_PATH], opt[MAX_PATH];
7124: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 7125: strcpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(SI)));
1.1 root 7126: char *token = my_strtok(tmp, " ");
7127: strcpy(command, token);
7128: strcpy(opt, token + strlen(token) + 1);
7129:
7130: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
7131: param->env_seg = 0;
7132: param->cmd_line.w.l = 44;
7133: param->cmd_line.w.h = (WORK_TOP >> 4);
7134: param->fcb1.w.l = 24;
7135: param->fcb1.w.h = (WORK_TOP >> 4);
7136: param->fcb2.w.l = 24;
7137: param->fcb2.w.h = (WORK_TOP >> 4);
7138:
7139: memset(mem + WORK_TOP + 24, 0x20, 20);
7140:
7141: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
7142: cmd_line->len = strlen(opt);
7143: strcpy(cmd_line->cmd, opt);
7144: cmd_line->cmd[cmd_line->len] = 0x0d;
7145:
7146: msdos_process_exec(command, param, 0);
7147: REG8(AL) = 0;
7148: }
7149:
1.1.1.21! root 7150: inline void msdos_int_2fh_12h()
! 7151: {
! 7152: switch(REG8(AL)) {
! 7153: // case 0x00:
! 7154: // REG8(AL) = 0xff;
! 7155: // break;
! 7156: case 0x16:
! 7157: if(REG16(BX) < 20) {
! 7158: SREG(ES) = SFT_TOP >> 4;
! 7159: i386_load_segment_descriptor(ES);
! 7160: REG16(DI) = 6 + 0x3b * REG16(BX);
! 7161:
! 7162: // update system file table
! 7163: UINT8* sft = mem + SFT_TOP + 6 + 0x3b * REG16(BX);
! 7164: if(file_handler[REG16(BX)].valid) {
! 7165: int count = 0;
! 7166: for(int i = 0; i < 20; i++) {
! 7167: if(msdos_psp_get_file_table(i, current_psp) == REG16(BX)) {
! 7168: count++;
! 7169: }
! 7170: }
! 7171: *(UINT16 *)(sft + 0x00) = count ? count : 0xffff;
! 7172: *(UINT32 *)(sft + 0x15) = _tell(REG16(BX));
! 7173: _lseek(REG16(BX), 0, SEEK_END);
! 7174: *(UINT32 *)(sft + 0x11) = _tell(REG16(BX));
! 7175: _lseek(REG16(BX), *(UINT32 *)(sft + 0x15), SEEK_SET);
! 7176: } else {
! 7177: memset(sft, 0, 0x3b);
! 7178: }
! 7179: } else {
! 7180: REG16(AX) = 0x06;
! 7181: m_CF = 1;
! 7182: }
! 7183: break;
! 7184: case 0x20:
! 7185: {
! 7186: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
! 7187:
! 7188: if(fd < 20) {
! 7189: SREG(ES) = current_psp;
! 7190: i386_load_segment_descriptor(ES);
! 7191: REG16(DI) = offsetof(psp_t, file_table) + fd;
! 7192: } else {
! 7193: REG16(AX) = 0x06;
! 7194: m_CF = 1;
! 7195: }
! 7196: }
! 7197: break;
! 7198: default:
! 7199: REG16(AX) = 0x01;
! 7200: m_CF = 1;
! 7201: break;
! 7202: }
! 7203: }
! 7204:
1.1 root 7205: inline void msdos_int_2fh_16h()
7206: {
7207: switch(REG8(AL)) {
7208: case 0x00:
1.1.1.14 root 7209: if(no_windows) {
7210: REG8(AL) = 0;
7211: } else {
1.1 root 7212: OSVERSIONINFO osvi;
7213: ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
7214: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
7215: GetVersionEx(&osvi);
7216: REG8(AL) = osvi.dwMajorVersion;
7217: REG8(AH) = osvi.dwMinorVersion;
7218: }
7219: break;
1.1.1.14 root 7220: case 0x80:
7221: Sleep(10);
7222: hardware_update();
7223: REG8(AL) = 0;
7224: break;
1.1.1.20 root 7225: case 0x8f:
7226: switch(REG8(DH)) {
7227: case 0x00:
7228: case 0x02:
7229: case 0x03:
7230: REG16(AX) = 0x00;
7231: break;
7232: case 0x01:
7233: REG16(AX) = 0x168f;
7234: break;
7235: }
7236: break;
1.1 root 7237: default:
7238: REG16(AX) = 0x01;
1.1.1.3 root 7239: m_CF = 1;
1.1 root 7240: break;
7241: }
7242: }
7243:
7244: inline void msdos_int_2fh_1ah()
7245: {
7246: switch(REG8(AL)) {
7247: case 0x00:
7248: // ansi.sys is installed
7249: REG8(AL) = 0xff;
7250: break;
7251: default:
7252: REG16(AX) = 0x01;
1.1.1.3 root 7253: m_CF = 1;
1.1 root 7254: break;
7255: }
7256: }
7257:
7258: inline void msdos_int_2fh_43h()
7259: {
7260: switch(REG8(AL)) {
7261: case 0x00:
1.1.1.19 root 7262: // xms is installed ?
7263: #ifdef SUPPORT_XMS
7264: if(support_xms) {
7265: REG8(AL) = 0x80;
7266: } else
7267: #endif
7268: REG8(AL) = 0x00;
7269: break;
7270: case 0x10:
7271: REG16(BX) = XMS_OFFSET;
7272: SREG(ES) = XMS_TOP >> 4;
7273: i386_load_segment_descriptor(ES);
1.1 root 7274: break;
7275: default:
7276: REG16(AX) = 0x01;
1.1.1.3 root 7277: m_CF = 1;
1.1 root 7278: break;
7279: }
7280: }
7281:
7282: inline void msdos_int_2fh_4ah()
7283: {
1.1.1.19 root 7284: // hma is not installed
1.1 root 7285: switch(REG8(AL)) {
7286: case 0x01:
7287: case 0x02:
1.1.1.19 root 7288: // hma is not used
1.1 root 7289: REG16(BX) = 0;
1.1.1.3 root 7290: SREG(ES) = 0xffff;
7291: i386_load_segment_descriptor(ES);
1.1 root 7292: REG16(DI) = 0xffff;
7293: break;
1.1.1.19 root 7294: case 0x03:
7295: // unable to allocate
7296: REG16(DI) = 0xffff;
7297: break;
7298: case 0x04:
7299: // function not supported, do not clear AX
7300: break;
1.1 root 7301: default:
7302: REG16(AX) = 0x01;
1.1.1.3 root 7303: m_CF = 1;
1.1 root 7304: break;
7305: }
7306: }
7307:
7308: inline void msdos_int_2fh_4fh()
7309: {
7310: switch(REG8(AL)) {
7311: case 0x00:
7312: REG16(AX) = 0;
7313: REG8(DL) = 1; // major version
7314: REG8(DH) = 0; // minor version
7315: break;
7316: case 0x01:
7317: REG16(AX) = 0;
7318: REG16(BX) = active_code_page;
7319: break;
7320: default:
7321: REG16(AX) = 0x01;
1.1.1.3 root 7322: m_CF = 1;
1.1 root 7323: break;
7324: }
7325: }
7326:
7327: inline void msdos_int_2fh_aeh()
7328: {
7329: switch(REG8(AL)) {
7330: case 0x00:
7331: REG8(AL) = 0;
7332: break;
7333: case 0x01:
7334: {
7335: char command[MAX_PATH];
7336: memset(command, 0, sizeof(command));
1.1.1.3 root 7337: memcpy(command, mem + SREG_BASE(DS) + REG16(SI) + 1, mem[SREG_BASE(DS) + REG16(SI)]);
1.1 root 7338:
7339: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
7340: param->env_seg = 0;
7341: param->cmd_line.w.l = 44;
7342: param->cmd_line.w.h = (WORK_TOP >> 4);
7343: param->fcb1.w.l = 24;
7344: param->fcb1.w.h = (WORK_TOP >> 4);
7345: param->fcb2.w.l = 24;
7346: param->fcb2.w.h = (WORK_TOP >> 4);
7347:
7348: memset(mem + WORK_TOP + 24, 0x20, 20);
7349:
7350: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
1.1.1.3 root 7351: cmd_line->len = mem[SREG_BASE(DS) + REG16(BX) + 1];
7352: memcpy(cmd_line->cmd, mem + SREG_BASE(DS) + REG16(BX) + 2, cmd_line->len);
1.1 root 7353: cmd_line->cmd[cmd_line->len] = 0x0d;
7354:
7355: if(msdos_process_exec(command, param, 0)) {
7356: REG16(AX) = 0x02;
1.1.1.3 root 7357: m_CF = 1;
1.1 root 7358: }
7359: }
7360: break;
7361: default:
7362: REG16(AX) = 0x01;
1.1.1.3 root 7363: m_CF = 1;
1.1 root 7364: break;
7365: }
7366: }
7367:
7368: inline void msdos_int_2fh_b7h()
7369: {
7370: switch(REG8(AL)) {
7371: case 0x00:
7372: // append is not installed
7373: REG8(AL) = 0;
7374: break;
7375: default:
7376: REG16(AX) = 0x01;
1.1.1.3 root 7377: m_CF = 1;
1.1 root 7378: break;
7379: }
7380: }
7381:
1.1.1.19 root 7382: inline void msdos_int_67h_40h()
7383: {
7384: if(!support_ems) {
7385: REG8(AH) = 0x84;
7386: } else {
7387: REG8(AH) = 0x00;
7388: }
7389: }
7390:
7391: inline void msdos_int_67h_41h()
7392: {
7393: if(!support_ems) {
7394: REG8(AH) = 0x84;
7395: } else {
7396: REG8(AH) = 0x00;
7397: REG16(BX) = EMS_TOP >> 4;
7398: }
7399: }
7400:
7401: inline void msdos_int_67h_42h()
7402: {
7403: if(!support_ems) {
7404: REG8(AH) = 0x84;
7405: } else {
7406: REG8(AH) = 0x00;
7407: REG16(BX) = free_ems_pages;
7408: REG16(DX) = MAX_EMS_PAGES;
7409: }
7410: }
7411:
7412: inline void msdos_int_67h_43h()
7413: {
7414: if(!support_ems) {
7415: REG8(AH) = 0x84;
7416: } else if(REG16(BX) > MAX_EMS_PAGES) {
7417: REG8(AH) = 0x87;
7418: } else if(REG16(BX) > free_ems_pages) {
7419: REG8(AH) = 0x88;
7420: } else if(REG16(BX) == 0) {
7421: REG8(AH) = 0x89;
7422: } else {
7423: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
7424: if(!ems_handles[i].allocated) {
7425: ems_allocate_pages(i, REG16(BX));
7426: REG8(AH) = 0x00;
7427: REG16(DX) = i;
7428: return;
7429: }
7430: }
7431: REG8(AH) = 0x85;
7432: }
7433: }
7434:
7435: inline void msdos_int_67h_44h()
7436: {
7437: if(!support_ems) {
7438: REG8(AH) = 0x84;
7439: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
7440: REG8(AH) = 0x83;
7441: } else if(!(REG16(BX) == 0xffff || REG16(BX) < ems_handles[REG16(DX)].pages)) {
7442: REG8(AH) = 0x8a;
7443: // } else if(!(REG8(AL) < 4)) {
7444: // REG8(AH) = 0x8b;
7445: } else if(REG16(BX) == 0xffff) {
7446: ems_unmap_page(REG8(AL) & 3);
7447: REG8(AH) = 0x00;
7448: } else {
7449: ems_map_page(REG8(AL) & 3, REG16(DX), REG16(BX));
7450: REG8(AH) = 0x00;
7451: }
7452: }
7453:
7454: inline void msdos_int_67h_45h()
7455: {
7456: if(!support_ems) {
7457: REG8(AH) = 0x84;
7458: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
7459: REG8(AH) = 0x83;
7460: } else {
7461: ems_release_pages(REG16(DX));
7462: REG8(AH) = 0x00;
7463: }
7464: }
7465:
7466: inline void msdos_int_67h_46h()
7467: {
7468: if(!support_ems) {
7469: REG8(AH) = 0x84;
7470: } else {
7471: REG16(AX) = 0x0032; // EMS 3.2
7472: // REG16(AX) = 0x0040; // EMS 4.0
7473: }
7474: }
7475:
7476: inline void msdos_int_67h_47h()
7477: {
7478: // NOTE: the map data should be stored in the specified ems page, not process data
7479: process_t *process = msdos_process_info_get(current_psp);
7480:
7481: if(!support_ems) {
7482: REG8(AH) = 0x84;
7483: // } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
7484: // REG8(AH) = 0x83;
7485: } else if(process->ems_pages_stored) {
7486: REG8(AH) = 0x8d;
7487: } else {
7488: for(int i = 0; i < 4; i++) {
7489: process->ems_pages[i].handle = ems_pages[i].handle;
7490: process->ems_pages[i].page = ems_pages[i].page;
7491: process->ems_pages[i].mapped = ems_pages[i].mapped;
7492: }
7493: process->ems_pages_stored = true;
7494: REG8(AH) = 0x00;
7495: }
7496: }
7497:
7498: inline void msdos_int_67h_48h()
7499: {
7500: // NOTE: the map data should be restored from the specified ems page, not process data
7501: process_t *process = msdos_process_info_get(current_psp);
7502:
7503: if(!support_ems) {
7504: REG8(AH) = 0x84;
7505: // } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
7506: // REG8(AH) = 0x83;
7507: } else if(!process->ems_pages_stored) {
7508: REG8(AH) = 0x8e;
7509: } else {
7510: for(int i = 0; i < 4; i++) {
7511: if(process->ems_pages[i].mapped) {
7512: ems_map_page(i, process->ems_pages[i].handle, process->ems_pages[i].page);
7513: } else {
7514: ems_unmap_page(i);
7515: }
7516: }
7517: process->ems_pages_stored = false;
7518: REG8(AH) = 0x00;
7519: }
7520: }
7521:
7522: inline void msdos_int_67h_4bh()
7523: {
7524: if(!support_ems) {
7525: REG8(AH) = 0x84;
7526: } else {
7527: REG8(AH) = 0x00;
7528: REG16(BX) = 0;
7529: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
7530: if(ems_handles[i].allocated) {
7531: REG16(BX)++;
7532: }
7533: }
7534: }
7535: }
7536:
7537: inline void msdos_int_67h_4ch()
7538: {
7539: if(!support_ems) {
7540: REG8(AH) = 0x84;
7541: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
7542: REG8(AH) = 0x83;
7543: } else {
7544: REG8(AH) = 0x00;
7545: REG16(BX) = ems_handles[REG16(DX)].pages;
7546: }
7547: }
7548:
7549: inline void msdos_int_67h_4dh()
7550: {
7551: if(!support_ems) {
7552: REG8(AH) = 0x84;
7553: } else {
7554: REG8(AH) = 0x00;
7555: REG16(BX) = 0;
7556: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
7557: if(ems_handles[i].allocated) {
7558: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 0) = i;
7559: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 2) = ems_handles[i].pages;
7560: REG16(BX)++;
7561: }
7562: }
7563: }
7564: }
7565:
1.1.1.20 root 7566: inline void msdos_int_67h_4eh()
7567: {
7568: if(!support_ems) {
7569: REG8(AH) = 0x84;
7570: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01 || REG8(AL) == 0x02) {
7571: if(REG8(AL) == 0x00 || REG8(AL) == 0x02) {
7572: // save page map
7573: for(int i = 0; i < 4; i++) {
7574: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = ems_pages[i].mapped ? ems_pages[i].handle : 0xffff;
7575: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = ems_pages[i].mapped ? ems_pages[i].page : 0xffff;
7576: }
7577: }
7578: if(REG8(AL) == 0x01 || REG8(AL) == 0x02) {
7579: // restore page map
7580: for(int i = 0; i < 4; i++) {
7581: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
7582: UINT16 page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
7583:
7584: if(handle < MAX_EMS_HANDLES && ems_handles[handle].allocated && page < ems_handles[handle].pages) {
7585: ems_map_page(i, handle, page);
7586: } else {
7587: ems_unmap_page(i);
7588: }
7589: }
7590: }
7591: REG8(AH) = 0x00;
7592: } else if(REG8(AL) == 0x03) {
7593: REG8(AH) = 0x00;
1.1.1.21! root 7594: REG8(AL) = 4 * 4;
! 7595: } else {
! 7596: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
! 7597: REG8(AH) = 0x8f;
! 7598: }
! 7599: }
! 7600:
! 7601: inline void msdos_int_67h_4fh()
! 7602: {
! 7603: if(!support_ems) {
! 7604: REG8(AH) = 0x84;
! 7605: } else if(REG8(AL) == 0x00) {
! 7606: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
! 7607:
! 7608: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI)) = count;
! 7609: for(int i = 0; i < count; i++) {
! 7610: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 2 * i);
! 7611: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
! 7612:
! 7613: // if(!(physical < 4)) {
! 7614: // REG8(AH) = 0x8b;
! 7615: // return;
! 7616: // }
! 7617: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 0) = segment;
! 7618: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 2) = ems_pages[physical & 3].handle;
! 7619: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 4) = ems_pages[physical & 3].mapped ? ems_pages[physical & 3].page : 0xffff;
! 7620: }
! 7621: REG8(AH) = 0x00;
! 7622: } else if(REG8(AL) == 0x01) {
! 7623: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
! 7624:
! 7625: for(int i = 0; i < count; i++) {
! 7626: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 0);
! 7627: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
! 7628: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 2);
! 7629: UINT16 logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 4);
! 7630:
! 7631: // if(!(physical < 4)) {
! 7632: // REG8(AH) = 0x8b;
! 7633: // return;
! 7634: // } else
! 7635: if(!(handle < MAX_EMS_HANDLES && ems_handles[handle].allocated)) {
! 7636: REG8(AH) = 0x83;
! 7637: return;
! 7638: } else if(logical == 0xffff) {
! 7639: ems_unmap_page(physical & 3);
! 7640: } else if(logical < ems_handles[handle].pages) {
! 7641: ems_map_page(physical & 3, handle, logical);
! 7642: } else {
! 7643: REG8(AH) = 0x8a;
! 7644: return;
! 7645: }
! 7646: }
! 7647: REG8(AH) = 0x00;
! 7648: } else if(REG8(AL) == 0x02) {
! 7649: REG8(AH) = 0x00;
! 7650: REG8(AL) = 2 + REG16(BX) * 6;
1.1.1.20 root 7651: } else {
7652: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
7653: REG8(AH) = 0x8f;
7654: }
7655: }
7656:
7657: inline void msdos_int_67h_50h()
7658: {
7659: if(!support_ems) {
7660: REG8(AH) = 0x84;
7661: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
7662: REG8(AH) = 0x83;
7663: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
7664: for(int i = 0; i < REG16(CX); i++) {
7665: int logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
7666: int physical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
7667:
7668: if(REG8(AL) == 0x01) {
7669: physical = ((physical << 4) - EMS_TOP) / 0x4000;
7670: }
7671: // if(!(physical < 4)) {
7672: // REG8(AH) = 0x8b;
7673: // return;
7674: // } else
7675: if(logical == 0xffff) {
7676: ems_unmap_page(physical & 3);
7677: } else if(logical < ems_handles[REG16(DX)].pages) {
7678: ems_map_page(physical & 3, REG16(DX), logical);
7679: } else {
7680: REG8(AH) = 0x8a;
7681: return;
7682: }
7683: }
7684: REG8(AH) = 0x00;
7685: } else {
7686: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
7687: REG8(AH) = 0x8f;
7688: }
7689: }
7690:
1.1.1.19 root 7691: inline void msdos_int_67h_51h()
7692: {
7693: if(!support_ems) {
7694: REG8(AH) = 0x84;
7695: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
7696: REG8(AH) = 0x83;
7697: } else if(REG16(BX) > MAX_EMS_PAGES) {
7698: REG8(AH) = 0x87;
7699: } else if(REG16(BX) > free_ems_pages + ems_handles[REG16(DX)].pages) {
7700: REG8(AH) = 0x88;
7701: } else {
7702: ems_reallocate_pages(REG16(DX), REG16(BX));
7703: REG8(AH) = 0x00;
7704: }
7705: }
7706:
1.1.1.20 root 7707: inline void msdos_int_67h_52h()
7708: {
7709: if(!support_ems) {
7710: REG8(AH) = 0x84;
7711: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
7712: REG8(AH) = 0x83;
7713: } else if(REG8(AL) == 0x00) {
7714: REG8(AL) = 0x00; // handle is volatile
7715: REG8(AH) = 0x00;
7716: } else if(REG8(AL) == 0x01) {
7717: if(REG8(BL) == 0x00) {
7718: REG8(AH) = 0x00;
7719: } else {
7720: REG8(AH) = 0x90; // undefined attribute type
7721: }
7722: } else if(REG8(AL) == 0x02) {
7723: REG8(AL) = 0x00; // only volatile handles supported
7724: REG8(AH) = 0x00;
7725: } else {
7726: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
7727: REG8(AH) = 0x8f;
7728: }
7729: }
7730:
1.1.1.19 root 7731: inline void msdos_int_67h_53h()
7732: {
7733: if(!support_ems) {
7734: REG8(AH) = 0x84;
7735: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
7736: REG8(AH) = 0x83;
7737: } else if(REG8(AL) == 0x00) {
7738: memcpy(mem + SREG_BASE(ES) + REG16(DI), ems_handles[REG16(DX)].name, 8);
7739: REG8(AH) = 0x00;
7740: } else if(REG8(AL) == 0x01) {
7741: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
7742: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
7743: REG8(AH) = 0xa1;
7744: return;
7745: }
7746: }
7747: REG8(AH) = 0x00;
7748: memcpy(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8);
7749: } else {
7750: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
1.1.1.20 root 7751: REG8(AH) = 0x8f;
1.1.1.19 root 7752: }
7753: }
7754:
7755: inline void msdos_int_67h_54h()
7756: {
7757: if(!support_ems) {
7758: REG8(AH) = 0x84;
7759: } else if(REG8(AL) == 0x00) {
7760: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
7761: if(ems_handles[i].allocated) {
7762: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, ems_handles[i].name, 10);
7763: } else {
7764: memset(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, 0, 10);
7765: }
7766: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 0) = i;
7767: }
7768: REG8(AH) = 0x00;
7769: REG8(AL) = MAX_EMS_HANDLES;
7770: } else if(REG8(AL) == 0x01) {
7771: REG8(AH) = 0xa0; // not found
7772: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
7773: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
7774: REG8(AH) = 0x00;
7775: REG16(DX) = i;
7776: break;
7777: }
7778: }
7779: } else if(REG8(AL) == 0x02) {
7780: REG8(AH) = 0x00;
7781: REG16(BX) = MAX_EMS_HANDLES;
7782: } else {
7783: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
1.1.1.20 root 7784: REG8(AH) = 0x8f;
7785: }
7786: }
7787:
7788: inline void msdos_int_67h_57h_tmp()
7789: {
7790: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
7791: UINT8 src_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
7792: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x05);
7793: UINT16 src_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07);
7794: UINT16 src_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x09);
7795: UINT8 dest_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0b);
7796: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
7797: UINT16 dest_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0e);
7798: UINT16 dest_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x10);
7799:
7800: UINT8 *src_buffer, *dest_buffer;
7801: UINT32 src_addr, dest_addr;
7802: UINT32 src_addr_max, dest_addr_max;
7803:
7804: if(src_type == 0) {
7805: src_buffer = mem;
7806: src_addr = (src_seg << 4) + src_ofs;
7807: src_addr_max = MAX_MEM;
7808: } else {
7809: if(!(src_handle < MAX_EMS_HANDLES && ems_handles[src_handle].allocated)) {
7810: REG8(AH) = 0x83;
7811: return;
7812: } else if(!(src_seg < ems_handles[src_handle].pages)) {
7813: REG8(AH) = 0x8a;
7814: return;
7815: }
7816: src_buffer = ems_handles[src_handle].buffer + 0x4000 * src_seg;
7817: src_addr = src_ofs;
7818: src_addr_max = 0x4000;
7819: }
7820: if(dest_type == 0) {
7821: dest_buffer = mem;
7822: dest_addr = (dest_seg << 4) + dest_ofs;
7823: dest_addr_max = MAX_MEM;
7824: } else {
7825: if(!(dest_handle < MAX_EMS_HANDLES && ems_handles[dest_handle].allocated)) {
7826: REG8(AH) = 0x83;
7827: return;
7828: } else if(!(dest_seg < ems_handles[dest_handle].pages)) {
7829: REG8(AH) = 0x8a;
7830: return;
7831: }
7832: dest_buffer = ems_handles[dest_handle].buffer + 0x4000 * dest_seg;
7833: dest_addr = dest_ofs;
7834: dest_addr_max = 0x4000;
7835: }
7836: for(int i = 0; i < copy_length; i++) {
7837: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
7838: if(REG8(AL) == 0x00) {
7839: dest_buffer[dest_addr++] = src_buffer[src_addr++];
7840: } else if(REG8(AL) == 0x01) {
7841: UINT8 tmp = dest_buffer[dest_addr];
7842: dest_buffer[dest_addr++] = src_buffer[src_addr];
7843: src_buffer[src_addr++] = tmp;
7844: }
7845: } else {
7846: REG8(AH) = 0x93;
7847: return;
7848: }
7849: }
7850: REG8(AH) = 0x80;
7851: }
7852:
7853: inline void msdos_int_67h_57h()
7854: {
7855: if(!support_ems) {
7856: REG8(AH) = 0x84;
7857: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
7858: struct {
7859: UINT16 handle;
7860: UINT16 page;
7861: bool mapped;
7862: } tmp_pages[4];
7863:
7864: // unmap pages to copy memory data to ems buffer
7865: for(int i = 0; i < 4; i++) {
7866: tmp_pages[i].handle = ems_pages[i].handle;
7867: tmp_pages[i].page = ems_pages[i].page;
7868: tmp_pages[i].mapped = ems_pages[i].mapped;
7869: ems_unmap_page(i);
7870: }
7871:
7872: // run move/exchange operation
7873: msdos_int_67h_57h_tmp();
7874:
7875: // restore unmapped pages
7876: for(int i = 0; i < 4; i++) {
7877: if(tmp_pages[i].mapped) {
7878: ems_map_page(i, tmp_pages[i].handle, tmp_pages[i].page);
7879: }
7880: }
7881: } else {
7882: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
7883: REG8(AH) = 0x8f;
7884: }
7885: }
7886:
7887: inline void msdos_int_67h_58h()
7888: {
7889: if(!support_ems) {
7890: REG8(AH) = 0x84;
7891: } else if(REG8(AL) == 0x00) {
7892: for(int i = 0; i < 4; i++) {
7893: *(UINT16 *)(mem +SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = (EMS_TOP + 0x4000 * i) >> 4;
7894: *(UINT16 *)(mem +SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = i;
7895: }
7896: REG8(AH) = 0x00;
7897: REG16(CX) = 4;
7898: } else if(REG8(AL) == 0x01) {
7899: REG8(AH) = 0x00;
7900: REG16(CX) = 4;
7901: } else {
7902: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
7903: REG8(AH) = 0x8f;
7904: }
7905: }
7906:
7907: inline void msdos_int_67h_5ah()
7908: {
7909: if(!support_ems) {
1.1.1.19 root 7910: REG8(AH) = 0x84;
1.1.1.20 root 7911: } else if(REG16(BX) > MAX_EMS_PAGES) {
7912: REG8(AH) = 0x87;
7913: } else if(REG16(BX) > free_ems_pages) {
7914: REG8(AH) = 0x88;
7915: // } else if(REG16(BX) == 0) {
7916: // REG8(AH) = 0x89;
7917: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
7918: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
7919: if(!ems_handles[i].allocated) {
7920: ems_allocate_pages(i, REG16(BX));
7921: REG8(AH) = 0x00;
7922: REG16(DX) = i;
7923: return;
7924: }
7925: }
7926: REG8(AH) = 0x85;
7927: } else {
7928: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
7929: REG8(AH) = 0x8f;
1.1.1.19 root 7930: }
7931: }
7932:
7933: #ifdef SUPPORT_XMS
7934:
7935: inline void msdos_call_xms_00h()
7936: {
7937: REG16(AX) = 0x0270; // V2.70
7938: REG16(BX) = 0x0000;
7939: // REG16(DX) = 0x0000; // hma does not exist
7940: REG16(DX) = 0x0001; // hma does exist
7941: }
7942:
7943: inline void msdos_call_xms_01h()
7944: {
7945: REG16(AX) = 0x0000;
7946: // REG8(BL) = 0x90; // hma does not exist
7947: REG8(BL) = 0x91; // hma is already used
7948: }
7949:
7950: inline void msdos_call_xms_02h()
7951: {
7952: REG16(AX) = 0x0000;
7953: // REG8(BL) = 0x90; // hma does not exist
7954: REG8(BL) = 0x91; // hma is already used
7955: }
7956:
7957: inline void msdos_call_xms_03h()
7958: {
7959: i386_set_a20_line(1);
7960: REG16(AX) = 0x0001;
7961: REG8(BL) = 0x00;
7962: }
7963:
7964: inline void msdos_call_xms_04h()
7965: {
1.1.1.21! root 7966: i386_set_a20_line(0);
! 7967: REG16(AX) = 0x0001;
! 7968: REG8(BL) = 0x00;
1.1.1.19 root 7969: }
7970:
7971: inline void msdos_call_xms_05h()
7972: {
7973: i386_set_a20_line(1);
7974: REG16(AX) = 0x0001;
7975: REG8(BL) = 0x00;
1.1.1.21! root 7976: xms_a20_local_enb_count++;
1.1.1.19 root 7977: }
7978:
7979: void msdos_call_xms_06h()
7980: {
1.1.1.21! root 7981: if(xms_a20_local_enb_count > 0) {
! 7982: xms_a20_local_enb_count--;
! 7983: }
! 7984: if(xms_a20_local_enb_count == 0) {
1.1.1.19 root 7985: i386_set_a20_line(0);
1.1.1.21! root 7986: }
! 7987: if((m_a20_mask >> 20) & 1) {
1.1.1.19 root 7988: REG16(AX) = 0x0000;
7989: REG8(BL) = 0x94;
1.1.1.21! root 7990: } else {
! 7991: REG16(AX) = 0x0001;
! 7992: REG8(BL) = 0x00;
1.1.1.19 root 7993: }
7994: }
7995:
7996: inline void msdos_call_xms_07h()
7997: {
7998: REG16(AX) = (m_a20_mask >> 20) & 1;
7999: REG8(BL) = 0x00;
8000: }
8001:
8002: inline void msdos_call_xms_08h()
8003: {
8004: REG16(AX) = REG16(DX) = 0x0000;
8005:
8006: int mcb_seg = EMB_TOP >> 4;
8007:
8008: while(1) {
8009: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
8010:
8011: if(mcb->psp == 0) {
8012: if(REG16(AX) < mcb->size_kb()) {
8013: REG16(AX) = mcb->size_kb();
8014: }
8015: REG16(DX) += mcb->size_kb();
8016: }
8017: if(mcb->mz == 'Z') {
8018: break;
8019: }
8020: mcb_seg += 1 + mcb->paragraphs();
8021: }
8022:
8023: if(REG16(AX) == 0 && REG16(DX) == 0) {
8024: REG8(BL) = 0xa0;
8025: } else {
8026: REG8(BL) = 0x00;
8027: }
8028: }
8029:
8030: inline void msdos_call_xms_09h()
8031: {
8032: for(int i = 1; i <= MAX_XMS_HANDLES; i++) {
8033: if(!xms_handles[i].allocated) {
8034: if((xms_handles[i].seg = msdos_mem_alloc(EMB_TOP >> 4, REG16(DX) * 64, 0)) != -1) {
8035: xms_handles[i].size_kb = REG16(DX);
8036: xms_handles[i].lock = 0;
8037: xms_handles[i].allocated = true;
8038:
8039: REG16(AX) = 0x0001;
8040: REG16(DX) = i;
8041: REG8(BL) = 0x00;
8042: } else {
8043: REG16(AX) = REG16(DX) = 0x0000;
8044: REG8(BL) = 0xa0;
8045: }
8046: return;
8047: }
8048: }
8049: REG16(AX) = REG16(DX) = 0x0000;
8050: REG8(BL) = 0xa1;
8051: }
8052:
8053: inline void msdos_call_xms_0ah()
8054: {
8055: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
8056: REG16(AX) = 0x0000;
8057: REG8(BL) = 0xa2;
8058: } else if(xms_handles[REG16(DX)].lock > 0) {
8059: REG16(AX) = 0x0000;
8060: REG8(BL) = 0xab;
8061: } else {
8062: msdos_mem_free(xms_handles[REG16(DX)].seg);
8063: xms_handles[REG16(DX)].allocated = false;
8064:
8065: REG16(AX) = 0x0001;
8066: REG8(BL) = 0x00;
8067: }
8068: }
8069:
8070: inline void msdos_call_xms_0bh()
8071: {
8072: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
8073: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
8074: UINT32 src_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06);
8075: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0a);
8076: UINT32 dest_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
8077:
8078: UINT8 *src_buffer, *dest_buffer;
8079: UINT32 src_addr_max, dest_addr_max;
8080:
8081: if(src_handle == 0) {
8082: src_buffer = mem;
8083: src_addr = (((src_addr >> 16) & 0xffff) << 4) + (src_addr & 0xffff);
8084: src_addr_max = MAX_MEM;
8085: } else {
8086: if(!(src_handle >= 1 && src_handle <= MAX_XMS_HANDLES && xms_handles[src_handle].allocated)) {
8087: REG16(AX) = 0x0000;
8088: REG8(BL) = 0xa3;
8089: return;
8090: }
8091: src_buffer = mem + (xms_handles[src_handle].seg << 4);
8092: src_addr_max = xms_handles[src_handle].size_kb * 1024;
8093: }
8094: if(dest_handle == 0) {
8095: dest_buffer = mem;
8096: dest_addr = (((dest_addr >> 16) & 0xffff) << 4) + (dest_addr & 0xffff);
8097: dest_addr_max = MAX_MEM;
8098: } else {
8099: if(!(dest_handle >= 1 && dest_handle <= MAX_XMS_HANDLES && xms_handles[dest_handle].allocated)) {
8100: REG16(AX) = 0x0000;
8101: REG8(BL) = 0xa5;
8102: return;
8103: }
8104: dest_buffer = mem + (xms_handles[dest_handle].seg << 4);
8105: dest_addr_max = xms_handles[dest_handle].size_kb * 1024;
8106: }
8107: for(int i = 0; i < copy_length; i++) {
8108: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
8109: dest_buffer[dest_addr++] = src_buffer[src_addr++];
8110: } else {
8111: break;
8112: }
8113: }
8114: REG16(AX) = 0x0001;
8115: REG8(BL) = 0x00;
8116: }
8117:
8118: inline void msdos_call_xms_0ch()
8119: {
8120: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
8121: REG16(AX) = 0x0000;
8122: REG8(BL) = 0xa2;
8123: } else {
8124: xms_handles[REG16(DX)].lock++;
8125: REG16(AX) = 0x0001;
8126: REG8(BL) = 0x00;
8127: UINT32 addr = xms_handles[REG16(DX)].seg << 4;
8128: REG16(DX) = (addr >> 16) & 0xffff;
8129: REG16(BX) = (addr ) & 0xffff;
8130: }
8131: }
8132:
8133: inline void msdos_call_xms_0dh()
8134: {
8135: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
8136: REG16(AX) = 0x0000;
8137: REG8(BL) = 0xa2;
8138: } else if(!(xms_handles[REG16(DX)].lock > 0)) {
8139: REG16(AX) = 0x0000;
8140: REG8(BL) = 0xaa;
8141: } else {
8142: xms_handles[REG16(DX)].lock--;
8143: REG16(AX) = 0x0001;
8144: REG8(BL) = 0x00;
8145: }
8146: }
8147:
8148: inline void msdos_call_xms_0eh()
8149: {
8150: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
8151: REG16(AX) = 0x0000;
8152: REG8(BL) = 0xa2;
8153: } else {
8154: REG16(AX) = 0x0001;
8155: REG8(BH) = xms_handles[REG16(DX)].lock;
8156: REG8(BL) = 0x00;
8157: for(int i = 1; i <= MAX_XMS_HANDLES; i++) {
8158: if(!xms_handles[i].allocated) {
8159: REG8(BL)++;
8160: }
8161: }
8162: REG16(DX) = xms_handles[REG16(DX)].size_kb;
8163: }
8164: }
8165:
8166: inline void msdos_call_xms_0fh()
8167: {
8168: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
8169: REG16(AX) = 0x0000;
8170: REG8(BL) = 0xa2;
8171: } else if(xms_handles[REG16(DX)].lock > 0) {
8172: REG16(AX) = 0x0000;
8173: REG8(BL) = 0xab;
8174: } else if(msdos_mem_realloc(xms_handles[REG16(DX)].seg, REG16(BX) * 64, NULL)) {
8175: REG16(AX) = 0x0000;
8176: REG8(BL) = 0xa0;
8177: } else {
8178: REG16(AX) = 0x0001;
8179: REG8(BL) = 0x00;
8180: }
8181: }
8182:
8183: inline void msdos_call_xms_10h()
8184: {
8185: int seg;
8186:
8187: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(DX), 0)) != -1) {
8188: REG16(AX) = 0x0001;
8189: REG16(BX) = seg;
8190: } else {
8191: REG16(AX) = 0x0000;
8192: REG8(BL) = 0xb0;
8193: REG16(DX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
8194: }
8195: }
8196:
8197: inline void msdos_call_xms_11h()
8198: {
8199: int mcb_seg = REG16(DX) - 1;
8200: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
8201:
8202: if(mcb->mz == 'M' || mcb->mz == 'Z') {
8203: msdos_mem_free(REG16(DX));
8204: REG16(AX) = 0x0001;
8205: REG8(BL) = 0x00;
8206: } else {
8207: REG16(AX) = 0x0000;
8208: REG8(BL) = 0xb2;
8209: }
8210: }
8211:
8212: inline void msdos_call_xms_12h()
8213: {
8214: int mcb_seg = REG16(DX) - 1;
8215: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
8216: int max_paragraphs;
8217:
8218: if(mcb->mz == 'M' || mcb->mz == 'Z') {
8219: if(!msdos_mem_realloc(REG16(DX), REG16(BX), &max_paragraphs)) {
8220: REG16(AX) = 0x0001;
8221: REG8(BL) = 0x00;
8222: } else {
8223: REG16(AX) = 0x0000;
8224: REG8(BL) = 0xb0;
8225: REG16(DX) = max_paragraphs;
8226: }
8227: } else {
8228: REG16(AX) = 0x0000;
8229: REG8(BL) = 0xb2;
8230: }
8231: }
8232:
8233: #endif
8234:
1.1 root 8235: void msdos_syscall(unsigned num)
8236: {
8237: switch(num) {
8238: case 0x00:
8239: error("division by zero\n");
8240: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
8241: break;
8242: case 0x04:
8243: error("overflow\n");
8244: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
8245: break;
8246: case 0x06:
8247: // NOTE: ish.com has illegal instruction...
1.1.1.14 root 8248: if(!ignore_illegal_insn) {
8249: error("illegal instruction\n");
8250: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
8251: } else {
8252: #if defined(HAS_I386)
8253: m_eip++;
8254: #else
8255: m_pc++;
8256: #endif
8257: }
1.1 root 8258: break;
1.1.1.8 root 8259: case 0x08:
1.1.1.14 root 8260: // pcbios_irq0(); // this causes too slow emulation...
1.1.1.8 root 8261: case 0x09:
8262: case 0x0a:
8263: case 0x0b:
8264: case 0x0c:
8265: case 0x0d:
8266: case 0x0e:
8267: case 0x0f:
8268: // EOI
8269: pic[0].isr &= ~(1 << (num - 0x08));
8270: pic_update();
8271: break;
1.1 root 8272: case 0x10:
8273: // PC BIOS - Video
1.1.1.14 root 8274: if(!restore_console_on_exit) {
1.1.1.15 root 8275: change_console_size(scr_width, scr_height);
1.1 root 8276: }
1.1.1.3 root 8277: m_CF = 0;
1.1 root 8278: switch(REG8(AH)) {
1.1.1.16 root 8279: case 0x00: pcbios_int_10h_00h(); break;
1.1 root 8280: case 0x01: pcbios_int_10h_01h(); break;
8281: case 0x02: pcbios_int_10h_02h(); break;
8282: case 0x03: pcbios_int_10h_03h(); break;
8283: case 0x05: pcbios_int_10h_05h(); break;
8284: case 0x06: pcbios_int_10h_06h(); break;
8285: case 0x07: pcbios_int_10h_07h(); break;
8286: case 0x08: pcbios_int_10h_08h(); break;
8287: case 0x09: pcbios_int_10h_09h(); break;
8288: case 0x0a: pcbios_int_10h_0ah(); break;
8289: case 0x0b: break;
8290: case 0x0c: break;
8291: case 0x0d: break;
8292: case 0x0e: pcbios_int_10h_0eh(); break;
8293: case 0x0f: pcbios_int_10h_0fh(); break;
8294: case 0x10: break;
1.1.1.14 root 8295: case 0x11: pcbios_int_10h_11h(); break;
8296: case 0x12: pcbios_int_10h_12h(); break;
1.1 root 8297: case 0x13: pcbios_int_10h_13h(); break;
8298: case 0x18: REG8(AL) = 0x86; break;
1.1.1.14 root 8299: case 0x1a: pcbios_int_10h_1ah(); break;
1.1.1.11 root 8300: case 0x1b: break;
1.1 root 8301: case 0x1c: REG8(AL) = 0x00; break;
8302: case 0x1d: pcbios_int_10h_1dh(); break;
8303: case 0x82: pcbios_int_10h_82h(); break;
1.1.1.11 root 8304: case 0xef: REG16(DX) = 0xffff; break;
1.1 root 8305: case 0xfe: pcbios_int_10h_feh(); break;
8306: case 0xff: pcbios_int_10h_ffh(); break;
8307: default:
1.1.1.14 root 8308: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
1.1 root 8309: break;
8310: }
8311: break;
8312: case 0x11:
8313: // PC BIOS - Get Equipment List
1.1.1.11 root 8314: #ifdef SUPPORT_FPU
8315: REG16(AX) = 0x22;
8316: #else
1.1 root 8317: REG16(AX) = 0x20;
1.1.1.11 root 8318: #endif
1.1 root 8319: break;
8320: case 0x12:
8321: // PC BIOS - Get Memory Size
8322: REG16(AX) = MEMORY_END / 1024;
8323: break;
8324: case 0x13:
8325: // PC BIOS - Disk
8326: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
8327: REG8(AH) = 0xff;
1.1.1.3 root 8328: m_CF = 1;
1.1 root 8329: break;
8330: case 0x14:
8331: // PC BIOS - Serial I/O
8332: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
8333: REG8(AH) = 0xff;
1.1.1.3 root 8334: m_CF = 1;
1.1 root 8335: break;
8336: case 0x15:
8337: // PC BIOS
1.1.1.3 root 8338: m_CF = 0;
1.1 root 8339: switch(REG8(AH)) {
1.1.1.14 root 8340: case 0x10: pcbios_int_15h_10h(); break;
1.1 root 8341: case 0x23: pcbios_int_15h_23h(); break;
8342: case 0x24: pcbios_int_15h_24h(); break;
8343: case 0x49: pcbios_int_15h_49h(); break;
8344: case 0x86: pcbios_int_15h_86h(); break;
8345: case 0x87: pcbios_int_15h_87h(); break;
8346: case 0x88: pcbios_int_15h_88h(); break;
8347: case 0x89: pcbios_int_15h_89h(); break;
1.1.1.21! root 8348: case 0x8a: pcbios_int_15h_8ah(); break;
1.1.1.3 root 8349: #if defined(HAS_I386)
1.1 root 8350: case 0xc9: pcbios_int_15h_c9h(); break;
1.1.1.3 root 8351: #endif
1.1 root 8352: case 0xca: pcbios_int_15h_cah(); break;
1.1.1.17 root 8353: case 0xe8:
8354: switch(REG8(AL)) {
8355: #if defined(HAS_I386)
8356: case 0x01: pcbios_int_15h_e801h(); break;
8357: #endif
8358: default:
8359: REG8(AH)=0x86;
8360: m_CF = 1;
8361: }
8362: break;
1.1 root 8363: default:
8364: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
8365: REG8(AH)=0x86;
1.1.1.3 root 8366: m_CF = 1;
1.1 root 8367: break;
8368: }
8369: break;
8370: case 0x16:
8371: // PC BIOS - Keyboard
1.1.1.3 root 8372: m_CF = 0;
1.1 root 8373: switch(REG8(AH)) {
8374: case 0x00: pcbios_int_16h_00h(); break;
8375: case 0x01: pcbios_int_16h_01h(); break;
8376: case 0x02: pcbios_int_16h_02h(); break;
8377: case 0x03: pcbios_int_16h_03h(); break;
8378: case 0x05: pcbios_int_16h_05h(); break;
8379: case 0x10: pcbios_int_16h_00h(); break;
8380: case 0x11: pcbios_int_16h_01h(); break;
8381: case 0x12: pcbios_int_16h_12h(); break;
8382: case 0x13: pcbios_int_16h_13h(); break;
8383: case 0x14: pcbios_int_16h_14h(); break;
8384: default:
1.1.1.14 root 8385: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
1.1 root 8386: break;
8387: }
8388: break;
8389: case 0x17:
8390: // PC BIOS - Printer
8391: fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
8392: break;
8393: case 0x1a:
8394: // PC BIOS - Timer
1.1.1.3 root 8395: m_CF = 0;
1.1 root 8396: switch(REG8(AH)) {
8397: case 0x00: pcbios_int_1ah_00h(); break;
8398: case 0x01: break;
8399: case 0x02: pcbios_int_1ah_02h(); break;
8400: case 0x03: break;
8401: case 0x04: pcbios_int_1ah_04h(); break;
8402: case 0x05: break;
8403: case 0x0a: pcbios_int_1ah_0ah(); break;
8404: case 0x0b: break;
1.1.1.14 root 8405: case 0x35: break; // Word Perfect Third Party Interface?
8406: case 0x36: break; // Word Perfect Third Party Interface
8407: case 0x70: break; // SNAP? (Simple Network Application Protocol)
1.1 root 8408: default:
8409: fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
8410: break;
8411: }
8412: break;
8413: case 0x20:
1.1.1.3 root 8414: msdos_process_terminate(SREG(CS), retval, 1);
1.1 root 8415: break;
8416: case 0x21:
8417: // MS-DOS System Call
1.1.1.3 root 8418: m_CF = 0;
1.1 root 8419: switch(REG8(AH)) {
8420: case 0x00: msdos_int_21h_00h(); break;
8421: case 0x01: msdos_int_21h_01h(); break;
8422: case 0x02: msdos_int_21h_02h(); break;
8423: case 0x03: msdos_int_21h_03h(); break;
8424: case 0x04: msdos_int_21h_04h(); break;
8425: case 0x05: msdos_int_21h_05h(); break;
8426: case 0x06: msdos_int_21h_06h(); break;
8427: case 0x07: msdos_int_21h_07h(); break;
8428: case 0x08: msdos_int_21h_08h(); break;
8429: case 0x09: msdos_int_21h_09h(); break;
8430: case 0x0a: msdos_int_21h_0ah(); break;
8431: case 0x0b: msdos_int_21h_0bh(); break;
8432: case 0x0c: msdos_int_21h_0ch(); break;
8433: case 0x0d: msdos_int_21h_0dh(); break;
8434: case 0x0e: msdos_int_21h_0eh(); break;
1.1.1.14 root 8435: case 0x0f: msdos_int_21h_0fh(); break;
8436: case 0x10: msdos_int_21h_10h(); break;
1.1 root 8437: case 0x11: msdos_int_21h_11h(); break;
8438: case 0x12: msdos_int_21h_12h(); break;
8439: case 0x13: msdos_int_21h_13h(); break;
1.1.1.16 root 8440: case 0x14: msdos_int_21h_14h(); break;
8441: case 0x15: msdos_int_21h_15h(); break;
1.1.1.14 root 8442: case 0x16: msdos_int_21h_16h(); break;
1.1.1.16 root 8443: case 0x17: msdos_int_21h_17h(); break;
1.1 root 8444: case 0x18: msdos_int_21h_18h(); break;
8445: case 0x19: msdos_int_21h_19h(); break;
8446: case 0x1a: msdos_int_21h_1ah(); break;
8447: case 0x1b: msdos_int_21h_1bh(); break;
8448: case 0x1c: msdos_int_21h_1ch(); break;
8449: case 0x1d: msdos_int_21h_1dh(); break;
8450: case 0x1e: msdos_int_21h_1eh(); break;
8451: case 0x1f: msdos_int_21h_1fh(); break;
8452: case 0x20: msdos_int_21h_20h(); break;
1.1.1.14 root 8453: case 0x21: msdos_int_21h_21h(); break;
8454: case 0x22: msdos_int_21h_22h(); break;
1.1.1.16 root 8455: case 0x23: msdos_int_21h_23h(); break;
8456: case 0x24: msdos_int_21h_24h(); break;
1.1 root 8457: case 0x25: msdos_int_21h_25h(); break;
8458: case 0x26: msdos_int_21h_26h(); break;
1.1.1.16 root 8459: case 0x27: msdos_int_21h_27h(); break;
8460: case 0x28: msdos_int_21h_28h(); break;
1.1 root 8461: case 0x29: msdos_int_21h_29h(); break;
8462: case 0x2a: msdos_int_21h_2ah(); break;
8463: case 0x2b: msdos_int_21h_2bh(); break;
8464: case 0x2c: msdos_int_21h_2ch(); break;
8465: case 0x2d: msdos_int_21h_2dh(); break;
8466: case 0x2e: msdos_int_21h_2eh(); break;
8467: case 0x2f: msdos_int_21h_2fh(); break;
8468: case 0x30: msdos_int_21h_30h(); break;
8469: case 0x31: msdos_int_21h_31h(); break;
8470: case 0x32: msdos_int_21h_32h(); break;
8471: case 0x33: msdos_int_21h_33h(); break;
8472: // 0x34: get address of indos flag
8473: case 0x35: msdos_int_21h_35h(); break;
8474: case 0x36: msdos_int_21h_36h(); break;
8475: case 0x37: msdos_int_21h_37h(); break;
1.1.1.14 root 8476: case 0x38: msdos_int_21h_38h(); break;
1.1 root 8477: case 0x39: msdos_int_21h_39h(0); break;
8478: case 0x3a: msdos_int_21h_3ah(0); break;
8479: case 0x3b: msdos_int_21h_3bh(0); break;
8480: case 0x3c: msdos_int_21h_3ch(); break;
8481: case 0x3d: msdos_int_21h_3dh(); break;
8482: case 0x3e: msdos_int_21h_3eh(); break;
8483: case 0x3f: msdos_int_21h_3fh(); break;
8484: case 0x40: msdos_int_21h_40h(); break;
8485: case 0x41: msdos_int_21h_41h(0); break;
8486: case 0x42: msdos_int_21h_42h(); break;
8487: case 0x43: msdos_int_21h_43h(0); break;
8488: case 0x44: msdos_int_21h_44h(); break;
8489: case 0x45: msdos_int_21h_45h(); break;
8490: case 0x46: msdos_int_21h_46h(); break;
8491: case 0x47: msdos_int_21h_47h(0); break;
8492: case 0x48: msdos_int_21h_48h(); break;
8493: case 0x49: msdos_int_21h_49h(); break;
8494: case 0x4a: msdos_int_21h_4ah(); break;
8495: case 0x4b: msdos_int_21h_4bh(); break;
8496: case 0x4c: msdos_int_21h_4ch(); break;
8497: case 0x4d: msdos_int_21h_4dh(); break;
8498: case 0x4e: msdos_int_21h_4eh(); break;
8499: case 0x4f: msdos_int_21h_4fh(); break;
8500: case 0x50: msdos_int_21h_50h(); break;
8501: case 0x51: msdos_int_21h_51h(); break;
8502: case 0x52: msdos_int_21h_52h(); break;
8503: // 0x53: translate bios parameter block to drive param bock
8504: case 0x54: msdos_int_21h_54h(); break;
8505: case 0x55: msdos_int_21h_55h(); break;
8506: case 0x56: msdos_int_21h_56h(0); break;
8507: case 0x57: msdos_int_21h_57h(); break;
8508: case 0x58: msdos_int_21h_58h(); break;
8509: case 0x59: msdos_int_21h_59h(); break;
8510: case 0x5a: msdos_int_21h_5ah(); break;
8511: case 0x5b: msdos_int_21h_5bh(); break;
8512: case 0x5c: msdos_int_21h_5ch(); break;
8513: // 0x5e: ms-network
8514: // 0x5f: ms-network
8515: case 0x60: msdos_int_21h_60h(0); break;
8516: case 0x61: msdos_int_21h_61h(); break;
8517: case 0x62: msdos_int_21h_62h(); break;
8518: case 0x63: msdos_int_21h_63h(); break;
8519: // 0x64: set device driver lockahead flag
8520: case 0x65: msdos_int_21h_65h(); break;
8521: case 0x66: msdos_int_21h_66h(); break;
8522: case 0x67: msdos_int_21h_67h(); break;
8523: case 0x68: msdos_int_21h_68h(); break;
8524: case 0x69: msdos_int_21h_69h(); break;
8525: case 0x6a: msdos_int_21h_6ah(); break;
8526: case 0x6b: msdos_int_21h_6bh(); break;
8527: case 0x6c: msdos_int_21h_6ch(0); break;
8528: // 0x6d: find first rom program
8529: // 0x6e: find next rom program
8530: // 0x6f: get/set rom scan start address
8531: // 0x70: windows95 get/set internationalization information
8532: case 0x71:
8533: // windows95 long filename functions
8534: switch(REG8(AL)) {
8535: case 0x0d: msdos_int_21h_710dh(); break;
8536: case 0x39: msdos_int_21h_39h(1); break;
8537: case 0x3a: msdos_int_21h_3ah(1); break;
8538: case 0x3b: msdos_int_21h_3bh(1); break;
1.1.1.17 root 8539: case 0x41: msdos_int_21h_7141h(1); break;
1.1 root 8540: case 0x43: msdos_int_21h_43h(1); break;
8541: case 0x47: msdos_int_21h_47h(1); break;
8542: case 0x4e: msdos_int_21h_714eh(); break;
8543: case 0x4f: msdos_int_21h_714fh(); break;
8544: case 0x56: msdos_int_21h_56h(1); break;
8545: case 0x60: msdos_int_21h_60h(1); break;
8546: case 0x6c: msdos_int_21h_6ch(1); break;
8547: case 0xa0: msdos_int_21h_71a0h(); break;
8548: case 0xa1: msdos_int_21h_71a1h(); break;
8549: case 0xa6: msdos_int_21h_71a6h(); break;
8550: case 0xa7: msdos_int_21h_71a7h(); break;
8551: case 0xa8: msdos_int_21h_71a8h(); break;
8552: // 0xa9: server create/open file
8553: // 0xaa: create/terminate SUBST
8554: default:
8555: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
8556: REG16(AX) = 0x7100;
1.1.1.3 root 8557: m_CF = 1;
1.1 root 8558: break;
8559: }
8560: break;
8561: // 0x72: Windows95 beta - LFN FindClose
8562: case 0x73:
8563: // windows95 fat32 functions
8564: switch(REG8(AL)) {
1.1.1.14 root 8565: case 0x00: msdos_int_21h_7300h(); break;
8566: // 0x01: set drive locking ???
8567: case 0x02: msdos_int_21h_7302h(); break;
1.1 root 8568: case 0x03: msdos_int_21h_7303h(); break;
8569: // 0x04: set dpb to use for formatting
8570: default:
8571: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
8572: REG16(AX) = 0x7300;
1.1.1.3 root 8573: m_CF = 1;
1.1 root 8574: break;
8575: }
8576: break;
8577: default:
8578: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
8579: REG16(AX) = 0x01;
1.1.1.3 root 8580: m_CF = 1;
1.1 root 8581: break;
8582: }
1.1.1.3 root 8583: if(m_CF) {
1.1 root 8584: error_code = REG16(AX);
8585: }
8586: break;
8587: case 0x22:
8588: fatalerror("int 22h (terminate address)\n");
8589: case 0x23:
8590: msdos_process_terminate(current_psp, (retval & 0xff) | 0x100, 1);
8591: break;
8592: case 0x24:
8593: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
8594: break;
8595: case 0x25:
8596: msdos_int_25h();
8597: break;
8598: case 0x26:
8599: msdos_int_26h();
8600: break;
8601: case 0x27:
8602: msdos_int_27h();
8603: break;
8604: case 0x28:
8605: Sleep(10);
8606: break;
8607: case 0x29:
8608: msdos_int_29h();
8609: break;
8610: case 0x2e:
8611: msdos_int_2eh();
8612: break;
8613: case 0x2f:
8614: // multiplex interrupt
8615: switch(REG8(AH)) {
1.1.1.21! root 8616: case 0x12: msdos_int_2fh_12h(); break;
1.1 root 8617: case 0x16: msdos_int_2fh_16h(); break;
8618: case 0x1a: msdos_int_2fh_1ah(); break;
8619: case 0x43: msdos_int_2fh_43h(); break;
8620: case 0x4a: msdos_int_2fh_4ah(); break;
8621: case 0x4f: msdos_int_2fh_4fh(); break;
8622: case 0xae: msdos_int_2fh_aeh(); break;
8623: case 0xb7: msdos_int_2fh_b7h(); break;
8624: }
8625: break;
1.1.1.19 root 8626: case 0x68:
8627: // dummy interrupt for EMS (int 67h)
8628: switch(REG8(AH)) {
8629: case 0x40: msdos_int_67h_40h(); break;
8630: case 0x41: msdos_int_67h_41h(); break;
8631: case 0x42: msdos_int_67h_42h(); break;
8632: case 0x43: msdos_int_67h_43h(); break;
8633: case 0x44: msdos_int_67h_44h(); break;
8634: case 0x45: msdos_int_67h_45h(); break;
8635: case 0x46: msdos_int_67h_46h(); break;
8636: case 0x47: msdos_int_67h_47h(); break;
8637: case 0x48: msdos_int_67h_48h(); break;
1.1.1.20 root 8638: // 0x49: LIM EMS - Reserved - Get I/O Port Address (Undocumented in EMS 3.2)
8639: // 0x4a: LIM EMS - Reserved - Get Translation Array (Undocumented in EMS 3.2)
1.1.1.19 root 8640: case 0x4b: msdos_int_67h_4bh(); break;
8641: case 0x4c: msdos_int_67h_4ch(); break;
8642: case 0x4d: msdos_int_67h_4dh(); break;
1.1.1.20 root 8643: case 0x4e: msdos_int_67h_4eh(); break;
1.1.1.21! root 8644: case 0x4f: msdos_int_67h_4fh(); break;
1.1.1.20 root 8645: case 0x50: msdos_int_67h_50h(); break;
1.1.1.19 root 8646: case 0x51: msdos_int_67h_51h(); break;
1.1.1.20 root 8647: case 0x52: msdos_int_67h_52h(); break;
1.1.1.19 root 8648: case 0x53: msdos_int_67h_53h(); break;
8649: case 0x54: msdos_int_67h_54h(); break;
1.1.1.20 root 8650: // 0x55: LIM EMS 4.0 - Alter Page Map And JUMP
8651: // 0x56: LIM EMS 4.0 - Alter Page Map And CALL
8652: case 0x57: msdos_int_67h_57h(); break;
8653: case 0x58: msdos_int_67h_58h(); break;
8654: // 0x59: LIM EMS 4.0 - Get Expanded Memory Hardware Information (for DOS Kernel)
8655: case 0x5a: msdos_int_67h_5ah(); break;
8656: // 0x5b: LIM EMS 4.0 - Alternate Map Register Set (for DOS Kernel)
8657: // 0x5c: LIM EMS 4.0 - Prepate Expanded Memory Hardware For Warm Boot
8658: // 0x5d: LIM EMS 4.0 - Enable/Disable OS Function Set Functions (for DOS Kernel)
1.1.1.19 root 8659: default:
8660: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", 0x67, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
8661: REG8(AH) = 0x84;
8662: break;
8663: }
8664: break;
8665: #ifdef SUPPORT_XMS
8666: case 0x69:
8667: // dummy interrupt for XMS (call far)
8668: switch(REG8(AH)) {
8669: case 0x00: msdos_call_xms_00h(); break;
8670: case 0x01: msdos_call_xms_01h(); break;
8671: case 0x02: msdos_call_xms_02h(); break;
8672: case 0x03: msdos_call_xms_03h(); break;
8673: case 0x04: msdos_call_xms_04h(); break;
8674: case 0x05: msdos_call_xms_05h(); break;
8675: case 0x06: msdos_call_xms_06h(); break;
8676: case 0x07: msdos_call_xms_07h(); break;
8677: case 0x08: msdos_call_xms_08h(); break;
8678: case 0x09: msdos_call_xms_09h(); break;
8679: case 0x0a: msdos_call_xms_0ah(); break;
8680: case 0x0b: msdos_call_xms_0bh(); break;
8681: case 0x0c: msdos_call_xms_0ch(); break;
8682: case 0x0d: msdos_call_xms_0dh(); break;
8683: case 0x0e: msdos_call_xms_0eh(); break;
8684: case 0x0f: msdos_call_xms_0fh(); break;
8685: case 0x10: msdos_call_xms_10h(); break;
8686: case 0x11: msdos_call_xms_11h(); break;
8687: case 0x12: msdos_call_xms_12h(); break;
8688: // 0x88: XMS 3.0 - Query free extended memory
8689: // 0x89: XMS 3.0 - Allocate any extended memory
8690: // 0x8e: XMS 3.0 - Get extended EMB handle information
8691: // 0x8f: XMS 3.0 - Reallocate any extended memory block
8692: default:
8693: // fatalerror("call XMS (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", REG16(AX), REG16(BX), REG16(CX), REG16(DX));
8694: REG16(AX) = 0x0000;
8695: REG8(BL) = 0x80;
8696: break;
8697: }
8698: break;
8699: #endif
8700: case 0x6a:
8701: // dummy interrupt for case map routine pointed in the country info
8702: if(REG8(AL) >= 0x80) {
8703: char tmp[2] = {0};
8704: tmp[0] = REG8(AL);
8705: my_strupr(tmp);
8706: REG8(AL) = tmp[0];
8707: }
8708: break;
1.1.1.8 root 8709: case 0x70:
8710: case 0x71:
8711: case 0x72:
8712: case 0x73:
8713: case 0x74:
8714: case 0x75:
8715: case 0x76:
8716: case 0x77:
8717: // EOI
8718: if((pic[1].isr &= ~(1 << (num - 0x70))) == 0) {
8719: pic[0].isr &= ~(1 << 2); // master
8720: }
8721: pic_update();
8722: break;
1.1 root 8723: default:
8724: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
8725: break;
8726: }
8727:
8728: // update cursor position
8729: if(cursor_moved) {
8730: CONSOLE_SCREEN_BUFFER_INFO csbi;
8731: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.15 root 8732: if(!restore_console_on_exit) {
8733: scr_top = csbi.srWindow.Top;
8734: }
1.1 root 8735: mem[0x450 + mem[0x462] * 2] = csbi.dwCursorPosition.X;
1.1.1.14 root 8736: mem[0x451 + mem[0x462] * 2] = csbi.dwCursorPosition.Y - scr_top;
1.1 root 8737: cursor_moved = false;
8738: }
8739: }
8740:
8741: // init
8742:
8743: int msdos_init(int argc, char *argv[], char *envp[], int standard_env)
8744: {
8745: // init file handler
8746: memset(file_handler, 0, sizeof(file_handler));
8747: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
8748: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
8749: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
1.1.1.21! root 8750: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 8751: if(_open("stdaux.txt", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
1.1.1.21! root 8752: #else
! 8753: if(_open("NUL", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
! 8754: #endif
! 8755: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
1.1 root 8756: }
1.1.1.21! root 8757: #ifdef MAP_PRN_DEVICE_TO_FILE
1.1 root 8758: if(_open("stdprn.txt", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
1.1.1.21! root 8759: #else
! 8760: if(_open("NUL", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
1.1 root 8761: #endif
1.1.1.21! root 8762: msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0);
! 8763: }
1.1 root 8764: _dup2(0, DUP_STDIN);
8765: _dup2(1, DUP_STDOUT);
8766: _dup2(2, DUP_STDERR);
1.1.1.21! root 8767: _dup2(3, DUP_STDAUX);
! 8768: _dup2(4, DUP_STDPRN);
1.1 root 8769:
8770: // init process
8771: memset(process, 0, sizeof(process));
8772:
1.1.1.13 root 8773: // init dtainfo
8774: msdos_dta_info_init();
8775:
1.1 root 8776: // init memory
8777: memset(mem, 0, sizeof(mem));
8778:
8779: // bios data area
8780: CONSOLE_SCREEN_BUFFER_INFO csbi;
8781: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 8782: CONSOLE_FONT_INFO cfi;
8783: GetCurrentConsoleFont(hStdout, FALSE, &cfi);
8784:
8785: int regen = min(scr_width * scr_height * 2, 0x8000);
8786: text_vram_top_address = TEXT_VRAM_TOP;
8787: text_vram_end_address = text_vram_top_address + regen;
8788: shadow_buffer_top_address = SHADOW_BUF_TOP;
8789: shadow_buffer_end_address = shadow_buffer_top_address + regen;
8790:
8791: if(regen > 0x4000) {
8792: regen = 0x8000;
8793: vram_pages = 1;
8794: } else if(regen > 0x2000) {
8795: regen = 0x4000;
8796: vram_pages = 2;
8797: } else if(regen > 0x1000) {
8798: regen = 0x2000;
8799: vram_pages = 4;
8800: } else {
8801: regen = 0x1000;
8802: vram_pages = 8;
8803: }
1.1 root 8804:
1.1.1.14 root 8805: #ifdef SUPPORT_FPU
8806: *(UINT16 *)(mem + 0x410) = 0x22;
8807: #else
1.1 root 8808: *(UINT16 *)(mem + 0x410) = 0x20;
1.1.1.14 root 8809: #endif
1.1 root 8810: *(UINT16 *)(mem + 0x413) = MEMORY_END / 1024;
8811: *(UINT8 *)(mem + 0x449) = 0x03;//0x73;
1.1.1.14 root 8812: *(UINT16 *)(mem + 0x44a) = csbi.dwSize.X;
8813: *(UINT16 *)(mem + 0x44c) = regen;
1.1 root 8814: *(UINT16 *)(mem + 0x44e) = 0;
8815: *(UINT8 *)(mem + 0x450) = csbi.dwCursorPosition.X;
1.1.1.14 root 8816: *(UINT8 *)(mem + 0x451) = csbi.dwCursorPosition.Y - scr_top;
1.1 root 8817: *(UINT8 *)(mem + 0x460) = 7;
8818: *(UINT8 *)(mem + 0x461) = 7;
8819: *(UINT8 *)(mem + 0x462) = 0;
8820: *(UINT16 *)(mem + 0x463) = 0x3d4;
1.1.1.19 root 8821: *(UINT8 *)(mem + 0x465) = 0x09;
8822: *(UINT32 *)(mem + 0x46c) = get_ticks_since_midnight(timeGetTime());
1.1.1.14 root 8823: *(UINT8 *)(mem + 0x484) = csbi.srWindow.Bottom - csbi.srWindow.Top;
8824: *(UINT8 *)(mem + 0x485) = cfi.dwFontSize.Y;
8825: *(UINT8 *)(mem + 0x487) = 0x60;
8826: *(UINT8 *)(mem + 0x496) = 0x10; // enhanced keyboard installed
8827:
8828: // initial screen
8829: SMALL_RECT rect;
8830: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
8831: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
8832: for(int y = 0, ofs1 = TEXT_VRAM_TOP, ofs2 = SHADOW_BUF_TOP; y < scr_height; y++) {
8833: for(int x = 0; x < scr_width; x++) {
8834: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Char.AsciiChar;
8835: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Attributes;
8836: }
8837: }
1.1 root 8838:
8839: // dos info
8840: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
1.1.1.19 root 8841: dos_info->magic_word = 1;
1.1 root 8842: dos_info->first_mcb = MEMORY_TOP >> 4;
8843: dos_info->first_dpb.w.l = 0;
8844: dos_info->first_dpb.w.h = DPB_TOP >> 4;
8845: dos_info->first_sft.w.l = 0;
1.1.1.21! root 8846: dos_info->first_sft.w.h = SFT_TOP >> 4;
1.1.1.19 root 8847: dos_info->max_sector_len = 512;
8848: dos_info->disk_buf_info.w.l = offsetof(dos_info_t, disk_buf_heads);
8849: dos_info->disk_buf_info.w.h = DOS_INFO_TOP >> 4;
1.1 root 8850: dos_info->cds.w.l = 0;
8851: dos_info->cds.w.h = CDS_TOP >> 4;
8852: dos_info->fcb_table.w.l = 0;
8853: dos_info->fcb_table.w.h = FCB_TABLE_TOP >> 4;
8854: dos_info->last_drive = 'Z' - 'A' + 1;
8855: dos_info->buffers_x = 20;
8856: dos_info->buffers_y = 0;
1.1.1.14 root 8857: dos_info->boot_drive = 'C' - 'A' + 1;
1.1.1.19 root 8858: dos_info->nul_device.next_driver = 0xffffffffU;
8859: dos_info->nul_device.attributes = 0x8004U;
8860: dos_info->nul_device.strategy = 0xffffU;
8861: dos_info->nul_device.interrupt = 0xffffU;
8862: memcpy(dos_info->nul_device.dev_name, "NUL ", 8);
8863: dos_info->disk_buf_heads.w.l = 0;
8864: dos_info->disk_buf_heads.w.h = DISK_BUF_TOP >> 4;
1.1.1.20 root 8865: dos_info->first_umb_fcb = UMB_TOP >> 4;
8866: dos_info->first_mcb_2 = MEMORY_TOP >> 4;
1.1.1.17 root 8867:
1.1 root 8868: char *env;
8869: if((env = getenv("LASTDRIVE")) != NULL) {
8870: if(env[0] >= 'A' && env[0] <= 'Z') {
8871: dos_info->last_drive = env[0] - 'A' + 1;
8872: } else if(env[0] >= 'a' && env[0] <= 'z') {
8873: dos_info->last_drive = env[0] - 'a' + 1;
8874: }
8875: }
8876: if((env = getenv("windir")) != NULL) {
8877: if(env[0] >= 'A' && env[0] <= 'Z') {
8878: dos_info->boot_drive = env[0] - 'A' + 1;
8879: } else if(env[0] >= 'a' && env[0] <= 'z') {
8880: dos_info->boot_drive = env[0] - 'a' + 1;
8881: }
8882: }
1.1.1.3 root 8883: #if defined(HAS_I386)
1.1 root 8884: dos_info->i386_or_later = 1;
1.1.1.3 root 8885: #else
8886: dos_info->i386_or_later = 0;
8887: #endif
1.1.1.17 root 8888: dos_info->ext_mem_size = (min(MAX_MEM, 0x4000000) - 0x100000) >> 10;
1.1 root 8889:
1.1.1.19 root 8890: // init mcb
1.1 root 8891: int seg = MEMORY_TOP >> 4;
1.1.1.19 root 8892:
8893: // iret table
8894: // note: int 2eh vector should address the routine in command.com,
8895: // and some softwares invite (int 2eh vector segment) - 1 must address the mcb of command.com.
8896: // so move iret table into allocated memory block
8897: // http://www5c.biglobe.ne.jp/~ecb/assembler2/2_6.html
8898: msdos_mcb_create(seg++, 'M', -1, IRET_SIZE >> 4);
8899: IRET_TOP = seg << 4;
8900: seg += IRET_SIZE >> 4;
8901: memset(mem + IRET_TOP, 0xcf, IRET_SIZE);
8902:
8903: // dummy xms/ems device
8904: msdos_mcb_create(seg++, 'M', -1, XMS_SIZE >> 4);
8905: XMS_TOP = seg << 4;
8906: seg += XMS_SIZE >> 4;
8907:
8908: // environment
1.1 root 8909: msdos_mcb_create(seg++, 'M', -1, ENV_SIZE >> 4);
8910: int env_seg = seg;
8911: int ofs = 0;
1.1.1.15 root 8912: char env_path[8192] = "", *path;
1.1 root 8913:
8914: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1.1.14 root 8915: if(_strnicmp(*p, "MSDOS_PATH=", 11) == 0) {
8916: sprintf(env_path, "%s;", *p + 11);
8917: break;
8918: }
8919: }
8920: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1.1.9 root 8921: if(_strnicmp(*p, "PATH=", 5) == 0) {
1.1.1.14 root 8922: strcat(env_path, *p + 5);
1.1.1.9 root 8923: break;
8924: }
8925: }
1.1.1.18 root 8926: if((path = getenv("MSDOS_COMSPEC")) != NULL ||
8927: (path = msdos_search_command_com(argv[0], env_path)) != NULL) {
1.1.1.15 root 8928: strcpy(comspec_path, path);
8929: }
8930:
1.1.1.9 root 8931: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1 root 8932: // lower to upper
8933: char tmp[ENV_SIZE], name[ENV_SIZE], value[ENV_SIZE];
8934: int value_pos = 0;
8935: strcpy(tmp, *p);
8936: for(int i = 0;; i++) {
8937: if(tmp[i] == '=') {
8938: tmp[i] = '\0';
8939: sprintf(name, ";%s;", tmp);
8940: strcpy(value, tmp + (value_pos = i + 1));
8941: tmp[i] = '=';
8942: break;
8943: } else if(tmp[i] >= 'a' && tmp[i] <= 'z') {
8944: tmp[i] = tmp[i] - 'a' + 'A';
8945: }
8946: }
1.1.1.18 root 8947: if(strncmp(tmp, "MSDOS_COMSPEC=", 14) == 0) {
8948: // ignore MSDOS_COMSPEC
8949: } else if(standard_env && strstr(";COMSPEC;INCLUDE;LIB;PATH;PROMPT;TEMP;TMP;TZ;", name) == NULL) {
8950: // ignore non standard environments
8951: } else {
1.1 root 8952: if(strncmp(tmp, "COMSPEC=", 8) == 0) {
1.1.1.14 root 8953: strcpy(tmp, "COMSPEC=C:\\COMMAND.COM");
1.1 root 8954: } else if(strncmp(tmp, "PATH=", 5) == 0 || strncmp(tmp, "TEMP=", 5) == 0 || strncmp(tmp, "TMP=", 4) == 0) {
8955: tmp[value_pos] = '\0';
8956: char *token = my_strtok(value, ";");
8957: while(token != NULL) {
8958: if(strlen(token) != 0) {
1.1.1.8 root 8959: char *path = msdos_remove_double_quote(token), tmp_path[MAX_PATH];
8960: if(strlen(path) != 0) {
8961: GetShortPathName(path, tmp_path, MAX_PATH);
8962: strcat(tmp, tmp_path);
8963: strcat(tmp, ";");
1.1 root 8964: }
8965: }
8966: token = my_strtok(NULL, ";");
8967: }
8968: tmp[strlen(tmp) - 1] = '\0';
8969: my_strupr(tmp);
8970: }
8971: int len = strlen(tmp);
1.1.1.14 root 8972: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) {
1.1 root 8973: fatalerror("too many environments\n");
8974: }
8975: memcpy(mem + (seg << 4) + ofs, tmp, len);
8976: ofs += len + 1;
8977: }
8978: }
8979: seg += (ENV_SIZE >> 4);
8980:
8981: // psp
8982: msdos_mcb_create(seg++, 'M', -1, PSP_SIZE >> 4);
8983: current_psp = seg;
1.1.1.14 root 8984: msdos_psp_create(seg, seg + (PSP_SIZE >> 4), -1, env_seg);
1.1 root 8985: seg += (PSP_SIZE >> 4);
8986:
1.1.1.19 root 8987: // first free mcb in conventional memory
8988: msdos_mcb_create(seg, 'Z', 0, (MEMORY_END >> 4) - seg - 2);
1.1.1.8 root 8989: first_mcb = seg;
8990:
1.1.1.19 root 8991: // dummy mcb to link to umb
8992: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', -1, (UMB_TOP >> 4) - (MEMORY_END >> 4));
8993:
8994: // first free mcb in upper memory block
1.1.1.8 root 8995: msdos_mcb_create(UMB_TOP >> 4, 'Z', 0, (UMB_END >> 4) - (UMB_TOP >> 4) - 1);
1.1 root 8996:
1.1.1.19 root 8997: #ifdef SUPPORT_XMS
8998: // first free mcb in extended memory block
8999: msdos_mcb_create(EMB_TOP >> 4, 'Z', 0, (EMB_END >> 4) - (EMB_TOP >> 4) - 1);
9000: #endif
9001:
9002: // interrupt vector
9003: for(int i = 0; i < 0x80; i++) {
9004: *(UINT16 *)(mem + 4 * i + 0) = i;
9005: *(UINT16 *)(mem + 4 * i + 2) = (IRET_TOP >> 4);
9006: }
9007: *(UINT16 *)(mem + 4 * 0x08 + 0) = 0x0005; // irq0
9008: *(UINT16 *)(mem + 4 * 0x08 + 2) = 0xffff;
9009: *(UINT16 *)(mem + 4 * 0x22 + 0) = 0x0000; // boot
9010: *(UINT16 *)(mem + 4 * 0x22 + 2) = 0xffff;
9011: *(UINT16 *)(mem + 4 * 0x67 + 0) = 0x0000; // ems
9012: *(UINT16 *)(mem + 4 * 0x67 + 2) = XMS_TOP >> 4;
9013:
9014: // ems (int 67h) and xms (call far)
9015: mem[XMS_TOP + 0] = 0xcd; // int 68h (dummy)
9016: mem[XMS_TOP + 1] = 0x68;
9017: mem[XMS_TOP + 2] = 0xcf; // iret
9018: #ifdef SUPPORT_XMS
9019: if(support_xms) {
9020: mem[XMS_TOP + 4] = 0xcd; // int 69h (dummy)
9021: mem[XMS_TOP + 5] = 0x69;
9022: mem[XMS_TOP + 6] = 0xcb; // retf
9023: } else
9024: #endif
9025: mem[XMS_TOP + 4] = 0xcb; // retf
9026: memcpy(mem + XMS_TOP + 0x0a, "EMMXXXX0", 8);
9027:
9028: // case map routine (call far)
9029: mem[0xffffc] = 0xcd; // int 6ah (dummy)
9030: mem[0xffffd] = 0x6a;
9031: mem[0xffffe] = 0xcb; // retf
9032:
1.1.1.14 root 9033: // have irq0 call system timer tick
1.1.1.19 root 9034: mem[0xffff5] = 0xcd; // int 1ch
9035: mem[0xffff6] = 0x1c;
9036: mem[0xffff7] = 0xea; // jmp (IRET_TOP >> 4):0008
9037: mem[0xffff8] = 0x08;
9038: mem[0xffff9] = 0x00;
9039: mem[0xffffa] = ((IRET_TOP >> 4) ) & 0xff;
9040: mem[0xffffb] = ((IRET_TOP >> 4) >> 8) & 0xff;
1.1.1.14 root 9041:
1.1 root 9042: // boot
9043: mem[0xffff0] = 0xf4; // halt
9044: mem[0xffff1] = 0xcd; // int 21h
9045: mem[0xffff2] = 0x21;
9046: mem[0xffff3] = 0xcb; // retf
9047:
9048: // param block
9049: // + 0: param block (22bytes)
9050: // +24: fcb1/2 (20bytes)
9051: // +44: command tail (128bytes)
9052: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
9053: param->env_seg = 0;
9054: param->cmd_line.w.l = 44;
9055: param->cmd_line.w.h = (WORK_TOP >> 4);
9056: param->fcb1.w.l = 24;
9057: param->fcb1.w.h = (WORK_TOP >> 4);
9058: param->fcb2.w.l = 24;
9059: param->fcb2.w.h = (WORK_TOP >> 4);
9060:
9061: memset(mem + WORK_TOP + 24, 0x20, 20);
9062:
9063: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
9064: if(argc > 1) {
9065: sprintf(cmd_line->cmd, " %s", argv[1]);
9066: for(int i = 2; i < argc; i++) {
9067: char tmp[128];
9068: sprintf(tmp, "%s %s", cmd_line->cmd, argv[i]);
9069: strcpy(cmd_line->cmd, tmp);
9070: }
9071: cmd_line->len = (UINT8)strlen(cmd_line->cmd);
9072: } else {
9073: cmd_line->len = 0;
9074: }
9075: cmd_line->cmd[cmd_line->len] = 0x0d;
9076:
9077: // system file table
1.1.1.21! root 9078: *(UINT32 *)(mem + SFT_TOP + 0) = 0xffffffff;
! 9079: *(UINT16 *)(mem + SFT_TOP + 4) = 20;
1.1 root 9080:
1.1.1.19 root 9081: // disk buffer header (from DOSBox)
9082: *(UINT16 *)(mem + DISK_BUF_TOP + 0) = 0xffff; // forward ptr
9083: *(UINT16 *)(mem + DISK_BUF_TOP + 2) = 0xffff; // backward ptr
9084: *(UINT8 *)(mem + DISK_BUF_TOP + 4) = 0xff; // not in use
9085: *(UINT8 *)(mem + DISK_BUF_TOP + 10) = 0x01; // number of FATs
9086: *(UINT32 *)(mem + DISK_BUF_TOP + 13) = 0xffffffff; // pointer to DPB
9087:
1.1 root 9088: // current directory structure
9089: msdos_cds_update(_getdrive() - 1);
9090:
9091: // fcb table
9092: *(UINT32 *)(mem + FCB_TABLE_TOP + 0) = 0xffffffff;
1.1.1.14 root 9093: *(UINT16 *)(mem + FCB_TABLE_TOP + 4) = 0;
1.1 root 9094:
1.1.1.17 root 9095: // nls stuff
9096: msdos_nls_tables_init();
1.1 root 9097:
9098: // execute command
9099: if(msdos_process_exec(argv[0], param, 0)) {
9100: fatalerror("'%s' not found\n", argv[0]);
9101: }
9102: retval = 0;
9103: return(0);
9104: }
9105:
9106: #define remove_std_file(path) { \
9107: int fd = _open(path, _O_RDONLY | _O_BINARY); \
9108: if(fd != -1) { \
9109: _lseek(fd, 0, SEEK_END); \
9110: int size = _tell(fd); \
9111: _close(fd); \
9112: if(size == 0) { \
9113: remove(path); \
9114: } \
9115: } \
9116: }
9117:
9118: void msdos_finish()
9119: {
9120: for(int i = 0; i < MAX_FILES; i++) {
9121: if(file_handler[i].valid) {
9122: _close(i);
9123: }
9124: }
1.1.1.21! root 9125: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 9126: remove_std_file("stdaux.txt");
1.1.1.21! root 9127: #endif
! 9128: #ifdef MAP_PRN_DEVICE_TO_FILE
1.1 root 9129: remove_std_file("stdprn.txt");
9130: #endif
9131: msdos_dbcs_table_finish();
9132: }
9133:
9134: /* ----------------------------------------------------------------------------
9135: PC/AT hardware emulation
9136: ---------------------------------------------------------------------------- */
9137:
9138: void hardware_init()
9139: {
1.1.1.3 root 9140: CPU_INIT_CALL(CPU_MODEL);
1.1 root 9141: CPU_RESET_CALL(CPU_MODEL);
1.1.1.14 root 9142: m_IF = 1;
1.1.1.3 root 9143: #if defined(HAS_I386)
1.1 root 9144: cpu_type = (REG32(EDX) >> 8) & 0x0f;
9145: cpu_step = (REG32(EDX) >> 0) & 0x0f;
1.1.1.3 root 9146: #endif
9147: i386_set_a20_line(0);
1.1.1.14 root 9148:
1.1.1.19 root 9149: ems_init();
1.1 root 9150: pic_init();
1.1.1.8 root 9151: #ifdef PIT_ALWAYS_RUNNING
9152: pit_init();
9153: #else
1.1 root 9154: pit_active = 0;
9155: #endif
1.1.1.8 root 9156: cmos_init();
9157: kbd_init();
1.1 root 9158: }
9159:
1.1.1.10 root 9160: void hardware_finish()
9161: {
9162: #if defined(HAS_I386)
9163: vtlb_free(m_vtlb);
9164: #endif
1.1.1.19 root 9165: ems_finish();
1.1.1.10 root 9166: }
9167:
1.1 root 9168: void hardware_run()
9169: {
9170: int ops = 0;
9171:
1.1.1.3 root 9172: while(!m_halted) {
1.1 root 9173: #ifdef SUPPORT_DISASSEMBLER
9174: if(dasm) {
9175: char buffer[256];
1.1.1.3 root 9176: #if defined(HAS_I386)
1.1.1.19 root 9177: UINT32 eip = m_eip;
1.1.1.3 root 9178: #else
1.1.1.19 root 9179: UINT32 eip = m_pc - SREG_BASE(CS);
1.1.1.3 root 9180: #endif
9181: UINT8 *oprom = mem + SREG_BASE(CS) + eip;
1.1 root 9182:
1.1.1.3 root 9183: #if defined(HAS_I386)
9184: if(m_operand_size) {
1.1 root 9185: CPU_DISASSEMBLE_CALL(x86_32);
1.1.1.3 root 9186: } else
9187: #endif
9188: CPU_DISASSEMBLE_CALL(x86_16);
1.1.1.12 root 9189: fprintf(stderr, "%04x:%04x\t%s\n", SREG(CS), (unsigned)eip, buffer);
1.1 root 9190: }
9191: #endif
1.1.1.3 root 9192: #if defined(HAS_I386)
9193: m_cycles = 1;
1.1 root 9194: CPU_EXECUTE_CALL(i386);
1.1.1.3 root 9195: #else
9196: CPU_EXECUTE_CALL(CPU_MODEL);
9197: #endif
1.1.1.14 root 9198: #if defined(HAS_I386)
9199: if(m_eip != m_prev_eip) {
9200: #else
9201: if(m_pc != m_prevpc) {
9202: #endif
9203: iops++;
9204: }
1.1.1.8 root 9205: if(++ops == 16384) {
1.1 root 9206: hardware_update();
9207: ops = 0;
9208: }
9209: }
9210: }
9211:
9212: void hardware_update()
9213: {
1.1.1.8 root 9214: static UINT32 prev_time = 0;
9215: UINT32 cur_time = timeGetTime();
9216:
9217: if(prev_time != cur_time) {
9218: // update pit and raise irq0
9219: #ifndef PIT_ALWAYS_RUNNING
9220: if(pit_active)
9221: #endif
9222: {
9223: if(pit_run(0, cur_time)) {
9224: pic_req(0, 0, 1);
9225: }
9226: pit_run(1, cur_time);
9227: pit_run(2, cur_time);
9228: }
9229: // check key input and raise irq1
1.1.1.14 root 9230: static UINT32 prev_tick = 0;
9231: UINT32 cur_tick = cur_time / 32;
9232: if(prev_tick != cur_tick) {
9233: // update keyboard flags
9234: UINT8 state;
9235: state = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
9236: state |= (GetAsyncKeyState(VK_CAPITAL) & 0x0001) ? 0x40 : 0;
9237: state |= (GetAsyncKeyState(VK_NUMLOCK) & 0x0001) ? 0x20 : 0;
9238: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
9239: state |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
9240: state |= (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? 0x04 : 0;
9241: state |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
9242: state |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
9243: mem[0x417] = state;
9244: state = (GetAsyncKeyState(VK_INSERT ) & 0x8000) ? 0x80 : 0;
9245: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
9246: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
9247: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
9248: // state |= (GetAsyncKeyState(VK_PAUSE ) & 0x0001) ? 0x08 : 0;
9249: // state |= (GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x04 : 0;
9250: state |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
9251: state |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
9252: mem[0x418] = state;
9253:
9254: // update keyboard input
1.1.1.8 root 9255: if(check_key_input()) {
9256: pic_req(0, 1, 1);
9257: }
1.1.1.14 root 9258: prev_tick = cur_tick;
1.1.1.8 root 9259: }
1.1.1.19 root 9260: // update daily timer counter
9261: pcbios_update_daily_timer_counter(cur_time);
1.1.1.8 root 9262: prev_time = cur_time;
1.1 root 9263: }
9264: }
9265:
1.1.1.19 root 9266: // ems
9267:
9268: void ems_init()
9269: {
9270: memset(ems_handles, 0, sizeof(ems_handles));
9271: memset(ems_pages, 0, sizeof(ems_pages));
9272: free_ems_pages = MAX_EMS_PAGES;
9273: }
9274:
9275: void ems_finish()
9276: {
9277: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
9278: if(ems_handles[i].buffer) {
9279: free(ems_handles[i].buffer);
9280: ems_handles[i].buffer = NULL;
9281: }
9282: }
9283: }
9284:
9285: void ems_allocate_pages(int handle, int pages)
9286: {
9287: if(pages > 0) {
9288: ems_handles[handle].buffer = (UINT8 *)calloc(1, 0x4000 * pages);
9289: } else {
9290: ems_handles[handle].buffer = NULL;
9291: }
9292: ems_handles[handle].pages = pages;
9293: ems_handles[handle].allocated = true;
9294: free_ems_pages -= pages;
9295: }
9296:
9297: void ems_reallocate_pages(int handle, int pages)
9298: {
9299: if(ems_handles[handle].allocated) {
9300: if(ems_handles[handle].pages != pages) {
9301: UINT8 *new_buffer = NULL;
9302:
9303: if(pages > 0) {
9304: new_buffer = (UINT8 *)calloc(1, 0x4000 * pages);
9305: }
9306: if(ems_handles[handle].buffer) {
9307: if(new_buffer) {
9308: if(pages > ems_handles[handle].pages) {
9309: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * ems_handles[handle].pages);
9310: } else {
9311: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * pages);
9312: }
9313: }
9314: free(ems_handles[handle].buffer);
9315: ems_handles[handle].buffer = NULL;
9316: }
9317: free_ems_pages += ems_handles[handle].pages;
9318:
9319: ems_handles[handle].buffer = new_buffer;
9320: ems_handles[handle].pages = pages;
9321: free_ems_pages -= pages;
9322: }
9323: } else {
9324: ems_allocate_pages(handle, pages);
9325: }
9326: }
9327:
9328: void ems_release_pages(int handle)
9329: {
9330: if(ems_handles[handle].allocated) {
9331: if(ems_handles[handle].buffer) {
9332: free(ems_handles[handle].buffer);
9333: ems_handles[handle].buffer = NULL;
9334: }
9335: free_ems_pages += ems_handles[handle].pages;
9336: ems_handles[handle].allocated = false;
9337: }
9338: }
9339:
9340: void ems_map_page(int physical, int handle, int logical)
9341: {
9342: if(ems_pages[physical].mapped) {
9343: if(ems_pages[physical].handle == handle && ems_pages[physical].page == logical) {
9344: return;
9345: }
9346: ems_unmap_page(physical);
9347: }
9348: if(ems_handles[handle].allocated && ems_handles[handle].buffer && logical < ems_handles[handle].pages) {
9349: memcpy(mem + EMS_TOP + 0x4000 * physical, ems_handles[handle].buffer + 0x4000 * logical, 0x4000);
9350: }
9351: ems_pages[physical].handle = handle;
9352: ems_pages[physical].page = logical;
9353: ems_pages[physical].mapped = true;
9354: }
9355:
9356: void ems_unmap_page(int physical)
9357: {
9358: if(ems_pages[physical].mapped) {
9359: int handle = ems_pages[physical].handle;
9360: int logical = ems_pages[physical].page;
9361:
9362: if(ems_handles[handle].allocated && ems_handles[handle].buffer && logical < ems_handles[handle].pages) {
9363: memcpy(ems_handles[handle].buffer + 0x4000 * logical, mem + EMS_TOP + 0x4000 * physical, 0x4000);
9364: }
9365: ems_pages[physical].mapped = false;
9366: }
9367: }
9368:
1.1 root 9369: // pic
9370:
9371: void pic_init()
9372: {
1.1.1.8 root 9373: memset(pic, 0, sizeof(pic));
9374: pic[0].imr = pic[1].imr = 0xff;
1.1 root 9375:
9376: // from bochs bios
9377: pic_write(0, 0, 0x11); // icw1 = 11h
9378: pic_write(0, 1, 0x08); // icw2 = 08h
9379: pic_write(0, 1, 0x04); // icw3 = 04h
9380: pic_write(0, 1, 0x01); // icw4 = 01h
9381: pic_write(0, 1, 0xb8); // ocw1 = b8h
9382: pic_write(1, 0, 0x11); // icw1 = 11h
9383: pic_write(1, 1, 0x70); // icw2 = 70h
9384: pic_write(1, 1, 0x02); // icw3 = 02h
9385: pic_write(1, 1, 0x01); // icw4 = 01h
9386: }
9387:
9388: void pic_write(int c, UINT32 addr, UINT8 data)
9389: {
9390: if(addr & 1) {
9391: if(pic[c].icw2_r) {
9392: // icw2
9393: pic[c].icw2 = data;
9394: pic[c].icw2_r = 0;
9395: } else if(pic[c].icw3_r) {
9396: // icw3
9397: pic[c].icw3 = data;
9398: pic[c].icw3_r = 0;
9399: } else if(pic[c].icw4_r) {
9400: // icw4
9401: pic[c].icw4 = data;
9402: pic[c].icw4_r = 0;
9403: } else {
9404: // ocw1
9405: pic[c].imr = data;
9406: }
9407: } else {
9408: if(data & 0x10) {
9409: // icw1
9410: pic[c].icw1 = data;
9411: pic[c].icw2_r = 1;
9412: pic[c].icw3_r = (data & 2) ? 0 : 1;
9413: pic[c].icw4_r = data & 1;
9414: pic[c].irr = 0;
9415: pic[c].isr = 0;
9416: pic[c].imr = 0;
9417: pic[c].prio = 0;
9418: if(!(pic[c].icw1 & 1)) {
9419: pic[c].icw4 = 0;
9420: }
9421: pic[c].ocw3 = 0;
9422: } else if(data & 8) {
9423: // ocw3
9424: if(!(data & 2)) {
9425: data = (data & ~1) | (pic[c].ocw3 & 1);
9426: }
9427: if(!(data & 0x40)) {
9428: data = (data & ~0x20) | (pic[c].ocw3 & 0x20);
9429: }
9430: pic[c].ocw3 = data;
9431: } else {
9432: // ocw2
9433: int level = 0;
9434: if(data & 0x40) {
9435: level = data & 7;
9436: } else {
9437: if(!pic[c].isr) {
9438: return;
9439: }
9440: level = pic[c].prio;
9441: while(!(pic[c].isr & (1 << level))) {
9442: level = (level + 1) & 7;
9443: }
9444: }
9445: if(data & 0x80) {
9446: pic[c].prio = (level + 1) & 7;
9447: }
9448: if(data & 0x20) {
9449: pic[c].isr &= ~(1 << level);
9450: }
9451: }
9452: }
9453: pic_update();
9454: }
9455:
9456: UINT8 pic_read(int c, UINT32 addr)
9457: {
9458: if(addr & 1) {
9459: return(pic[c].imr);
9460: } else {
9461: // polling mode is not supported...
9462: //if(pic[c].ocw3 & 4) {
9463: // return ???;
9464: //}
9465: if(pic[c].ocw3 & 1) {
9466: return(pic[c].isr);
9467: } else {
9468: return(pic[c].irr);
9469: }
9470: }
9471: }
9472:
9473: void pic_req(int c, int level, int signal)
9474: {
9475: if(signal) {
9476: pic[c].irr |= (1 << level);
9477: } else {
9478: pic[c].irr &= ~(1 << level);
9479: }
9480: pic_update();
9481: }
9482:
9483: int pic_ack()
9484: {
9485: // ack (INTA=L)
9486: pic[pic_req_chip].isr |= pic_req_bit;
9487: pic[pic_req_chip].irr &= ~pic_req_bit;
9488: if(pic_req_chip > 0) {
9489: // update isr and irr of master
9490: UINT8 slave = 1 << (pic[pic_req_chip].icw3 & 7);
9491: pic[pic_req_chip - 1].isr |= slave;
9492: pic[pic_req_chip - 1].irr &= ~slave;
9493: }
9494: //if(pic[pic_req_chip].icw4 & 1) {
9495: // 8086 mode
9496: int vector = (pic[pic_req_chip].icw2 & 0xf8) | pic_req_level;
9497: //} else {
9498: // // 8080 mode
9499: // UINT16 addr = (UINT16)pic[pic_req_chip].icw2 << 8;
9500: // if(pic[pic_req_chip].icw1 & 4) {
9501: // addr |= (pic[pic_req_chip].icw1 & 0xe0) | (pic_req_level << 2);
9502: // } else {
9503: // addr |= (pic[pic_req_chip].icw1 & 0xc0) | (pic_req_level << 3);
9504: // }
9505: // vector = 0xcd | (addr << 8);
9506: //}
9507: if(pic[pic_req_chip].icw4 & 2) {
9508: // auto eoi
9509: pic[pic_req_chip].isr &= ~pic_req_bit;
9510: }
9511: return(vector);
9512: }
9513:
9514: void pic_update()
9515: {
9516: for(int c = 0; c < 2; c++) {
9517: UINT8 irr = pic[c].irr;
9518: if(c + 1 < 2) {
9519: // this is master
9520: if(pic[c + 1].irr & (~pic[c + 1].imr)) {
9521: // request from slave
9522: irr |= 1 << (pic[c + 1].icw3 & 7);
9523: }
9524: }
9525: irr &= (~pic[c].imr);
9526: if(!irr) {
9527: break;
9528: }
9529: if(!(pic[c].ocw3 & 0x20)) {
9530: irr |= pic[c].isr;
9531: }
9532: int level = pic[c].prio;
9533: UINT8 bit = 1 << level;
9534: while(!(irr & bit)) {
9535: level = (level + 1) & 7;
9536: bit = 1 << level;
9537: }
9538: if((c + 1 < 2) && (pic[c].icw3 & bit)) {
9539: // check slave
9540: continue;
9541: }
9542: if(pic[c].isr & bit) {
9543: break;
9544: }
9545: // interrupt request
9546: pic_req_chip = c;
9547: pic_req_level = level;
9548: pic_req_bit = bit;
1.1.1.3 root 9549: i386_set_irq_line(INPUT_LINE_IRQ, HOLD_LINE);
1.1 root 9550: return;
9551: }
1.1.1.3 root 9552: i386_set_irq_line(INPUT_LINE_IRQ, CLEAR_LINE);
1.1.1.2 root 9553: }
1.1 root 9554:
9555: // pit
9556:
9557: #define PIT_FREQ 1193182
9558: #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)
9559:
9560: void pit_init()
9561: {
1.1.1.8 root 9562: memset(pit, 0, sizeof(pit));
1.1 root 9563: for(int ch = 0; ch < 3; ch++) {
9564: pit[ch].count = 0x10000;
9565: pit[ch].ctrl_reg = 0x34;
9566: pit[ch].mode = 3;
9567: }
9568:
9569: // from bochs bios
9570: pit_write(3, 0x34);
9571: pit_write(0, 0x00);
9572: pit_write(0, 0x00);
9573: }
9574:
9575: void pit_write(int ch, UINT8 val)
9576: {
1.1.1.8 root 9577: #ifndef PIT_ALWAYS_RUNNING
1.1 root 9578: if(!pit_active) {
9579: pit_active = 1;
9580: pit_init();
9581: }
1.1.1.8 root 9582: #endif
1.1 root 9583: switch(ch) {
9584: case 0:
9585: case 1:
9586: case 2:
9587: // write count register
9588: if(!pit[ch].low_write && !pit[ch].high_write) {
9589: if(pit[ch].ctrl_reg & 0x10) {
9590: pit[ch].low_write = 1;
9591: }
9592: if(pit[ch].ctrl_reg & 0x20) {
9593: pit[ch].high_write = 1;
9594: }
9595: }
9596: if(pit[ch].low_write) {
9597: pit[ch].count_reg = val;
9598: pit[ch].low_write = 0;
9599: } else if(pit[ch].high_write) {
9600: if((pit[ch].ctrl_reg & 0x30) == 0x20) {
9601: pit[ch].count_reg = val << 8;
9602: } else {
9603: pit[ch].count_reg |= val << 8;
9604: }
9605: pit[ch].high_write = 0;
9606: }
9607: // start count
1.1.1.8 root 9608: if(!pit[ch].low_write && !pit[ch].high_write) {
9609: if(pit[ch].mode == 0 || pit[ch].mode == 4 || pit[ch].prev_time == 0) {
9610: pit[ch].count = PIT_COUNT_VALUE(ch);
9611: pit[ch].prev_time = timeGetTime();
9612: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 9613: }
9614: }
9615: break;
9616: case 3: // ctrl reg
9617: if((val & 0xc0) == 0xc0) {
9618: // i8254 read-back command
9619: for(ch = 0; ch < 3; ch++) {
9620: if(!(val & 0x10) && !pit[ch].status_latched) {
9621: pit[ch].status = pit[ch].ctrl_reg & 0x3f;
9622: pit[ch].status_latched = 1;
9623: }
9624: if(!(val & 0x20) && !pit[ch].count_latched) {
9625: pit_latch_count(ch);
9626: }
9627: }
9628: break;
9629: }
9630: ch = (val >> 6) & 3;
9631: if(val & 0x30) {
9632: static int modes[8] = {0, 1, 2, 3, 4, 5, 2, 3};
9633: pit[ch].mode = modes[(val >> 1) & 7];
9634: pit[ch].count_latched = 0;
9635: pit[ch].low_read = pit[ch].high_read = 0;
9636: pit[ch].low_write = pit[ch].high_write = 0;
9637: pit[ch].ctrl_reg = val;
9638: // stop count
1.1.1.8 root 9639: pit[ch].prev_time = pit[ch].expired_time = 0;
1.1 root 9640: pit[ch].count_reg = 0;
9641: } else if(!pit[ch].count_latched) {
9642: pit_latch_count(ch);
9643: }
9644: break;
9645: }
9646: }
9647:
9648: UINT8 pit_read(int ch)
9649: {
1.1.1.8 root 9650: #ifndef PIT_ALWAYS_RUNNING
1.1 root 9651: if(!pit_active) {
9652: pit_active = 1;
9653: pit_init();
9654: }
1.1.1.8 root 9655: #endif
1.1 root 9656: switch(ch) {
9657: case 0:
9658: case 1:
9659: case 2:
9660: if(pit[ch].status_latched) {
9661: pit[ch].status_latched = 0;
9662: return(pit[ch].status);
9663: }
9664: // if not latched, through current count
9665: if(!pit[ch].count_latched) {
9666: if(!pit[ch].low_read && !pit[ch].high_read) {
9667: pit_latch_count(ch);
9668: }
9669: }
9670: // return latched count
9671: if(pit[ch].low_read) {
9672: pit[ch].low_read = 0;
9673: if(!pit[ch].high_read) {
9674: pit[ch].count_latched = 0;
9675: }
9676: return(pit[ch].latch & 0xff);
9677: } else if(pit[ch].high_read) {
9678: pit[ch].high_read = 0;
9679: pit[ch].count_latched = 0;
9680: return((pit[ch].latch >> 8) & 0xff);
9681: }
9682: }
9683: return(0xff);
9684: }
9685:
1.1.1.8 root 9686: int pit_run(int ch, UINT32 cur_time)
1.1 root 9687: {
1.1.1.8 root 9688: if(pit[ch].expired_time != 0 && cur_time >= pit[ch].expired_time) {
1.1 root 9689: pit[ch].count = PIT_COUNT_VALUE(ch);
1.1.1.8 root 9690: pit[ch].prev_time = pit[ch].expired_time;
9691: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
9692: if(cur_time >= pit[ch].expired_time) {
9693: pit[ch].prev_time = cur_time;
9694: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 9695: }
1.1.1.8 root 9696: return(1);
1.1 root 9697: }
1.1.1.8 root 9698: return(0);
1.1 root 9699: }
9700:
9701: void pit_latch_count(int ch)
9702: {
1.1.1.8 root 9703: UINT32 cur_time = timeGetTime();
9704:
9705: if(pit[ch].expired_time != 0) {
9706: pit_run(ch, cur_time);
9707: UINT32 tmp = (pit[ch].count * (pit[ch].expired_time - cur_time)) / (pit[ch].expired_time - pit[ch].prev_time);
9708: pit[ch].latch = (tmp != 0) ? (UINT16)tmp : 1;
9709: } else {
9710: pit[ch].latch = (UINT16)pit[ch].count;
1.1 root 9711: }
9712: pit[ch].count_latched = 1;
9713: if((pit[ch].ctrl_reg & 0x30) == 0x10) {
9714: // lower byte
9715: pit[ch].low_read = 1;
9716: pit[ch].high_read = 0;
9717: } else if((pit[ch].ctrl_reg & 0x30) == 0x20) {
9718: // upper byte
9719: pit[ch].low_read = 0;
9720: pit[ch].high_read = 1;
9721: } else {
9722: // lower -> upper
1.1.1.14 root 9723: pit[ch].low_read = pit[ch].high_read = 1;
1.1 root 9724: }
9725: }
9726:
1.1.1.8 root 9727: int pit_get_expired_time(int ch)
1.1 root 9728: {
1.1.1.8 root 9729: UINT32 val = (1000 * pit[ch].count) / PIT_FREQ;
9730: return((val > 0) ? val : 1);
9731: }
9732:
9733: // cmos
9734:
9735: void cmos_init()
9736: {
9737: memset(cmos, 0, sizeof(cmos));
9738: cmos_addr = 0;
1.1 root 9739:
1.1.1.8 root 9740: // from DOSBox
9741: cmos_write(0x0a, 0x26);
9742: cmos_write(0x0b, 0x02);
9743: cmos_write(0x0d, 0x80);
1.1 root 9744: }
9745:
1.1.1.8 root 9746: void cmos_write(int addr, UINT8 val)
1.1 root 9747: {
1.1.1.8 root 9748: cmos[addr & 0x7f] = val;
9749: }
9750:
9751: #define CMOS_GET_TIME() { \
9752: UINT32 cur_sec = timeGetTime() / 1000 ; \
9753: if(prev_sec != cur_sec) { \
9754: GetLocalTime(&time); \
9755: prev_sec = cur_sec; \
9756: } \
1.1 root 9757: }
1.1.1.8 root 9758: #define CMOS_BCD(v) ((cmos[0x0b] & 4) ? (v) : to_bcd(v))
1.1 root 9759:
1.1.1.8 root 9760: UINT8 cmos_read(int addr)
1.1 root 9761: {
1.1.1.8 root 9762: static SYSTEMTIME time;
9763: static UINT32 prev_sec = 0;
1.1 root 9764:
1.1.1.8 root 9765: switch(addr & 0x7f) {
9766: case 0x00: CMOS_GET_TIME(); return(CMOS_BCD(time.wSecond));
9767: case 0x02: CMOS_GET_TIME(); return(CMOS_BCD(time.wMinute));
9768: case 0x04: CMOS_GET_TIME(); return(CMOS_BCD(time.wHour));
9769: case 0x06: CMOS_GET_TIME(); return(time.wDayOfWeek + 1);
9770: case 0x07: CMOS_GET_TIME(); return(CMOS_BCD(time.wDay));
9771: case 0x08: CMOS_GET_TIME(); return(CMOS_BCD(time.wMonth));
9772: case 0x09: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear));
9773: // case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 2 ? 0x80 : 0)); // 2msec
9774: case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 20 ? 0x80 : 0)); // precision of timeGetTime() may not be 1msec
9775: case 0x15: return((MEMORY_END >> 10) & 0xff);
9776: case 0x16: return((MEMORY_END >> 18) & 0xff);
9777: case 0x17: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
9778: case 0x18: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
9779: case 0x30: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
9780: case 0x31: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
9781: case 0x32: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear / 100));
1.1 root 9782: }
1.1.1.8 root 9783: return(cmos[addr & 0x7f]);
1.1 root 9784: }
9785:
1.1.1.7 root 9786: // kbd (a20)
9787:
9788: void kbd_init()
9789: {
1.1.1.8 root 9790: kbd_data = kbd_command = 0;
1.1.1.7 root 9791: kbd_status = 0x18;
9792: }
9793:
9794: UINT8 kbd_read_data()
9795: {
1.1.1.8 root 9796: kbd_status &= ~1;
1.1.1.7 root 9797: return(kbd_data);
9798: }
9799:
9800: void kbd_write_data(UINT8 val)
9801: {
9802: switch(kbd_command) {
9803: case 0xd1:
9804: i386_set_a20_line((val >> 1) & 1);
9805: break;
9806: }
9807: kbd_command = 0;
1.1.1.8 root 9808: kbd_status &= ~8;
1.1.1.7 root 9809: }
9810:
9811: UINT8 kbd_read_status()
9812: {
9813: return(kbd_status);
9814: }
9815:
9816: void kbd_write_command(UINT8 val)
9817: {
9818: switch(val) {
9819: case 0xd0:
9820: kbd_data = ((m_a20_mask >> 19) & 2) | 1;
1.1.1.8 root 9821: kbd_status |= 1;
1.1.1.7 root 9822: break;
9823: case 0xdd:
9824: i386_set_a20_line(0);
9825: break;
9826: case 0xdf:
9827: i386_set_a20_line(1);
9828: break;
9829: case 0xf0:
9830: case 0xf1:
9831: case 0xf2:
9832: case 0xf3:
9833: case 0xf4:
9834: case 0xf5:
9835: case 0xf6:
9836: case 0xf7:
9837: case 0xf8:
9838: case 0xf9:
9839: case 0xfa:
9840: case 0xfb:
9841: case 0xfc:
9842: case 0xfd:
9843: case 0xfe:
9844: case 0xff:
9845: if(!(val & 1)) {
1.1.1.8 root 9846: if((cmos[0x0f] & 0x7f) == 5) {
1.1.1.7 root 9847: // reset pic
9848: pic_init();
9849: pic[0].irr = pic[1].irr = 0x00;
9850: pic[0].imr = pic[1].imr = 0xff;
9851: }
9852: CPU_RESET_CALL(CPU_MODEL);
9853: i386_jmp_far(0x40, 0x67);
9854: }
9855: i386_set_a20_line((val >> 1) & 1);
9856: break;
9857: }
9858: kbd_command = val;
1.1.1.8 root 9859: kbd_status |= 8;
1.1.1.7 root 9860: }
9861:
1.1.1.9 root 9862: // vga
9863:
9864: UINT8 vga_read_status()
9865: {
9866: // 60hz
9867: static const int period[3] = {16, 17, 17};
9868: static int index = 0;
9869: UINT32 time = timeGetTime() % period[index];
9870:
9871: index = (index + 1) % 3;
1.1.1.14 root 9872: return((time < 4 ? 0x08 : 0) | (time == 0 ? 0 : 0x01));
1.1.1.9 root 9873: }
9874:
1.1 root 9875: // i/o bus
9876:
9877: UINT8 read_io_byte(offs_t addr)
9878: {
9879: switch(addr) {
9880: case 0x20:
9881: case 0x21:
9882: return(pic_read(0, addr));
9883: case 0x40:
9884: case 0x41:
9885: case 0x42:
9886: case 0x43:
9887: return(pit_read(addr & 0x03));
1.1.1.7 root 9888: case 0x60:
9889: return(kbd_read_data());
1.1.1.9 root 9890: case 0x61:
9891: return(system_port);
1.1.1.7 root 9892: case 0x64:
9893: return(kbd_read_status());
1.1 root 9894: case 0x71:
1.1.1.8 root 9895: return(cmos_read(cmos_addr));
1.1 root 9896: case 0x92:
1.1.1.3 root 9897: return((m_a20_mask >> 19) & 2);
1.1 root 9898: case 0xa0:
9899: case 0xa1:
9900: return(pic_read(1, addr));
1.1.1.9 root 9901: case 0x3ba:
9902: case 0x3da:
9903: return(vga_read_status());
1.1 root 9904: default:
9905: // error("inb %4x\n", addr);
9906: break;
9907: }
9908: return(0xff);
9909: }
9910:
9911: UINT16 read_io_word(offs_t addr)
9912: {
9913: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8));
9914: }
9915:
9916: UINT32 read_io_dword(offs_t addr)
9917: {
9918: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8) | (read_io_byte(addr + 2) << 16) | (read_io_byte(addr + 3) << 24));
9919: }
9920:
9921: void write_io_byte(offs_t addr, UINT8 val)
9922: {
9923: switch(addr) {
9924: case 0x20:
9925: case 0x21:
9926: pic_write(0, addr, val);
9927: break;
9928: case 0x40:
9929: case 0x41:
9930: case 0x42:
9931: case 0x43:
9932: pit_write(addr & 0x03, val);
9933: break;
1.1.1.7 root 9934: case 0x60:
9935: kbd_write_data(val);
9936: break;
1.1.1.9 root 9937: case 0x61:
9938: if((system_port & 3) != 3 && (val & 3) == 3) {
9939: // beep on
9940: // MessageBeep(-1);
9941: } else if((system_port & 3) == 3 && (val & 3) != 3) {
9942: // beep off
9943: }
9944: system_port = val;
9945: break;
1.1 root 9946: case 0x64:
1.1.1.7 root 9947: kbd_write_command(val);
1.1 root 9948: break;
9949: case 0x70:
9950: cmos_addr = val;
9951: break;
9952: case 0x71:
1.1.1.8 root 9953: cmos_write(cmos_addr, val);
1.1 root 9954: break;
9955: case 0x92:
1.1.1.7 root 9956: i386_set_a20_line((val >> 1) & 1);
1.1 root 9957: break;
9958: case 0xa0:
9959: case 0xa1:
9960: pic_write(1, addr, val);
9961: break;
9962: default:
9963: // error("outb %4x,%2x\n", addr, val);
9964: break;
9965: }
9966: }
9967:
9968: void write_io_word(offs_t addr, UINT16 val)
9969: {
9970: write_io_byte(addr + 0, (val >> 0) & 0xff);
9971: write_io_byte(addr + 1, (val >> 8) & 0xff);
9972: }
9973:
9974: void write_io_dword(offs_t addr, UINT32 val)
9975: {
9976: write_io_byte(addr + 0, (val >> 0) & 0xff);
9977: write_io_byte(addr + 1, (val >> 8) & 0xff);
9978: write_io_byte(addr + 2, (val >> 16) & 0xff);
9979: write_io_byte(addr + 3, (val >> 24) & 0xff);
9980: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.